/* Memento — the household dashboard's entire stylesheet.
 *
 * Everything visual lives here. The production CSP is `default-src 'self'`, and
 * tests/test_dashboard.py parses every rendered page and fails on a <style> tag, a <script> tag or
 * a single style="" attribute — so there is no second place styling could go, and no JavaScript
 * anywhere in this dashboard. Every interaction the Memento design expressed with state (tabs,
 * filters, month navigation, expanding a row) is either a link the server re-renders or a native
 * <details> element.
 *
 * Fonts are self-hosted under /static/fonts for the same CSP reason: fonts.googleapis.com is a
 * cross-origin subresource and would simply not load in production.
 *
 * Layout is mobile-first. Three breakpoints, each a real change of shape:
 *   <768px   phone      bottom navigation, one column
 *   >=768px  tablet     icon rail sidebar, two-column grids
 *   >=1200px desktop    full sidebar with labels, three-column grids, calendar beside its day list
 * plus 480px, where the card grids earn a second column before the sidebar appears.
 */

/* --- Self-hosted type ------------------------------------------------------------------------ */

@font-face {
  font-family: "Baloo 2";
  src: url("/static/fonts/baloo2-var.woff2") format("woff2");
  font-weight: 600 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Nunito Sans";
  src: url("/static/fonts/nunitosans-var.woff2") format("woff2");
  font-weight: 400 800;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Quicksand";
  src: url("/static/fonts/quicksand-var.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
/* C8 (2026-08-22): the React app's own type, reused here for `.auth-refresh` only (see below) —
   same files, same weight ranges as `frontend/src/index.css`, so the two declarations can never
   silently drift apart. */
@font-face {
  font-family: "Hanken Grotesk";
  src: url("/static/fonts/hanken-grotesk-var.woff2") format("woff2");
  font-weight: 300 800;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Sora";
  src: url("/static/fonts/sora-var.woff2") format("woff2");
  font-weight: 400 800;
  font-style: normal;
  font-display: swap;
}

/* --- Tokens ---------------------------------------------------------------------------------- */

:root {
  /* Surfaces */
  --bg: #fffcf5;
  --surface: #ffffff;
  --surface-sunk: #f8f4eb;
  --surface-quiet: #f3efe6;
  --border: #ebe5d9;
  --border-strong: #e3dcce;
  --hairline: #f2eee5;

  /* Ink */
  --text: #2b2823;
  --text-muted: #665d53;
  --text-faint: #c0b4a2;

  /* Brand */
  --primary: #6c5cd1;
  --primary-hover: #5b4ca3;
  --primary-fg: #ffffff;
  --brand-violet: #8b7de0;
  --brand-coral: #fa7c6b;

  /* Record categories. Each is a bg / fg / soft-bg / accent quartet, applied by a modifier class
     so a template never needs a colour of its own. */
  --ev-bg: #dcd6f5;
  --ev-fg: #4c3fa8;
  --ev-soft: #f1eefb;
  --ev-accent: #6c5cd1;

  --rem-bg: #f8d8de;
  --rem-fg: #7c2f45;
  --rem-soft: #fceff2;
  --rem-accent: #d4667f;

  --task-bg: #cfe7d5;
  --task-fg: #235940;
  --task-soft: #eaf3ec;
  --task-accent: #47996a;

  --pay-bg: #d3e3f2;
  --pay-fg: #1e4e75;
  --pay-soft: #edf3f9;
  --pay-accent: #3e82b8;

  --doc-bg: #f7dcc0;
  --doc-fg: #7a431e;
  --doc-soft: #fbf0e2;
  --doc-accent: #d97e3f;

  /* Person and household_fact own their own quartet rather than reusing event's violet — a Persona
     drawer or review card must read as its own category, not as a Momento (2026-08-15). */
  --per-bg: #f3e3b8;
  --per-fg: #7a5c10;
  --per-soft: #fbf6e7;
  --per-accent: #c79a2e;

  --fact-bg: #cfe8e4;
  --fact-fg: #1f5c52;
  --fact-soft: #eaf5f3;
  --fact-accent: #3d9186;

  /* Status */
  --danger-bg: #fbebe7;
  --danger-fg: #b85541;
  --danger-border: #efd4cc;
  --warn-bg: #fbf8f2;
  --warn-border: #e6dcc8;
  --warn-fg: #7a431e;
  --ok-bg: #e7f2ea;
  --ok-fg: #235940;
  --ok-border: #cfe7d5;

  /* Type */
  --font-display: "Baloo 2", "Nunito Sans", -apple-system, BlinkMacSystemFont, sans-serif;
  --font-body: "Nunito Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --font-memento-voice: "Quicksand", ui-rounded, system-ui, sans-serif;

  /* Geometry */
  --radius-sm: 8px;
  --radius: 14px;
  --radius-lg: 20px;
  --radius-xl: 26px;
  --radius-pill: 99px;
  --tap: 44px;

  /* Prose measure. The app shell itself is full-width, but every block of running text — an empty
     state, an error, Memento's welcome, a callout — is held to this so it stays readable. */
  --content-max-width: 640px;

  --sidebar-rail: 84px;
  --sidebar-full: 248px;
  --shadow-card: 0 1px 2px rgba(60, 50, 40, 0.05);
  --shadow-drawer: 0 18px 40px -22px rgba(70, 58, 45, 0.45);
}

/* --- Reset ----------------------------------------------------------------------------------- */

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

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

a {
  color: var(--primary);
  text-decoration: none;
}

a:hover {
  color: var(--primary-hover);
}

p {
  margin: 0;
}

ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

svg {
  flex: none;
}

:focus-visible {
  outline: 2.5px solid var(--primary);
  outline-offset: 2px;
  border-radius: 10px;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  padding: 12px 18px;
  background: var(--primary);
  color: var(--primary-fg);
  font-weight: 700;
  border-radius: 0 0 var(--radius) 0;
}

.skip-link:focus {
  left: 0;
  color: var(--primary-fg);
}

/* Visually hidden, still in the accessibility tree — a label a sighted user does not need to see
   because the placeholder already says it, but a screen reader still needs to name the field. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.sprite {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}

/* Icons inherit their colour from the element they sit in; only the size varies. */
.icon {
  width: 19px;
  height: 19px;
  flex: none;
}

.icon--sm {
  width: 15px;
  height: 15px;
}

.icon--lg {
  width: 24px;
  height: 24px;
}

/* The Memento product icon. Present wherever the design gives the product a voice.
   The aspect ratio has to be stated: these are <svg><use href="#ic-memento"></svg> wrappers with no
   viewBox of their own, so `height: auto` would otherwise stretch to the flex line's height. */
.ic-memento {
  aspect-ratio: 200 / 152;
  height: auto;
  flex: none;
}

.ic-memento--xs {
  width: 32px;
}
.ic-memento--sm {
  width: 44px;
}
.ic-memento--md {
  width: 62px;
}
.ic-memento--lg {
  width: 84px;
}

/* Memento's own conversational voice — a short, spoken line, distinct from --font-display (titles)
   and --font-body (everything read for information). A dense or factual answer stays in
   --font-body even when Memento is the one saying it, so this class is applied selectively by the
   template, never unconditionally on every line Memento authors. */
.memento-voice {
  font-family: var(--font-memento-voice);
  font-weight: 600;
}

.memento-note {
  font-size: 17px;
  line-height: 1.3;
}

/* --- Shell ----------------------------------------------------------------------------------- */

.shell {
  display: flex;
  min-height: 100vh;
  position: relative;
}

.sidebar {
  display: none;
}

.main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  padding-bottom: 84px; /* clears the bottom navigation on phones */
}

.topbar {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  padding: 18px 16px 14px;
  border-bottom: 1px solid var(--border);
  background: var(--bg);
}

/* Nothing visible to carry: collapse the bar, keep the (hidden) h1 in the accessibility tree. */
.topbar--bare {
  padding: 0;
  border-bottom: none;
  min-height: 0;
}

.topbar__titles {
  display: flex;
  flex-direction: column;
  gap: 5px;
  min-width: 0;
}

.page-title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 28px;
  line-height: 1.22;
  margin: 0;
  letter-spacing: -0.01em;
}

/* Inicio leads with Memento's welcome card instead of a heading, but the page still
   needs exactly one h1 for screen readers and for the accessibility test. */
.page-title--quiet {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.page-sub {
  font-size: 14px;
  color: var(--text-muted);
  font-weight: 500;
}

.topbar__actions {
  display: flex;
  align-items: center;
  gap: 9px;
  flex: none;
}

.content {
  flex: 1;
  padding: 20px 16px 8px;
  display: flex;
  flex-direction: column;
  gap: 26px;
}

.site-footer {
  padding: 24px 16px 8px;
  font-size: 12.5px;
  color: var(--text-muted);
  font-weight: 600;
}

/* --- Buttons and links that look like buttons ------------------------------------------------ */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  padding: 12px 16px;
  border-radius: var(--radius-pill);
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text-muted);
  font-size: 14px;
  font-weight: 600;
  min-height: var(--tap);
  white-space: nowrap;
  cursor: pointer;
}

.btn:hover {
  border-color: var(--border-strong);
  color: var(--text);
}

.btn--primary {
  background: var(--primary);
  border-color: var(--primary);
  color: var(--primary-fg);
  font-weight: 700;
  padding: 12px 18px;
}

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

.btn__label {
  display: none;
}

/* --- Navigation ------------------------------------------------------------------------------ */

.bottom-nav {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 30;
  background: rgba(246, 242, 235, 0.96);
  backdrop-filter: blur(8px);
  border-top: 1px solid var(--border-strong);
  padding: 8px 6px calc(12px + env(safe-area-inset-bottom));
}

.bottom-nav__list {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
}

.bottom-nav__link {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 6px 2px;
  min-height: 52px;
  color: var(--text-muted);
  font-size: 11px;
  font-weight: 600;
  /* The labels are sentences now ("Lo que sigue"), so they wrap rather than truncate. */
  text-align: center;
  line-height: 1.15;
  hyphens: none;
}

.bottom-nav__link[aria-current="page"] {
  color: var(--text);
  font-weight: 800;
}

/* The "Más" sheet: a disclosure, not a modal, so it needs no focus trap and no script. */
.more-sheet > summary {
  list-style: none;
  cursor: pointer;
}

.more-sheet > summary::-webkit-details-marker {
  display: none;
}

.more-sheet__panel {
  position: absolute;
  left: 8px;
  right: 8px;
  bottom: calc(100% + 8px);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-drawer);
  padding: 16px 18px 10px;
}

.more-sheet__title {
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 700;
  margin-bottom: 6px;
}

.more-sheet__link {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 0;
  min-height: var(--tap);
  border-bottom: 1px solid var(--hairline);
  color: var(--text);
}

.more-sheet > .more-sheet__panel li:last-child .more-sheet__link {
  border-bottom: none;
}

.more-sheet__body {
  flex: 1;
  display: flex;
  flex-direction: column;
}

.more-sheet__label {
  font-size: 15.5px;
  font-weight: 600;
}

.more-sheet__sub {
  font-size: 13px;
  color: var(--text-muted);
  margin-top: 2px;
}

.more-sheet__link[aria-current="page"] .more-sheet__label {
  color: var(--primary);
  font-weight: 700;
}

/* "Cerrar sesión" in the Más sheet (2026-08-18, persistent-copilot checkpoint spec §15) — the
   list item is a <form>, not an <a>, so it reuses .more-sheet__link's row layout but ends in a
   real submit button instead of a chevron. */
.more-sheet__link--form {
  border: none;
  width: 100%;
  background: none;
  font: inherit;
  text-align: left;
}

.more-sheet__submit {
  padding: 8px 14px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--text);
  font-size: 13.5px;
  font-weight: 600;
}

.sidebar__brand {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 2px 8px 0;
}

.brand-mark {
  width: 36px;
  height: auto;
  flex: none;
}

.brand-word {
  height: 22px;
  width: auto;
  display: block;
}

.nav-list {
  display: flex;
  flex-direction: column;
  gap: 3px;
  margin-top: 26px;
}

.nav-link {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px;
  border-radius: 12px;
  min-height: var(--tap);
  color: var(--text-muted);
  font-size: 14.5px;
  font-weight: 500;
}

.nav-link:hover {
  color: var(--text);
  background: rgba(255, 255, 255, 0.6);
}

.nav-link[aria-current="page"] {
  background: var(--surface);
  box-shadow: var(--shadow-card);
  color: var(--text);
  font-weight: 700;
}

.nav-link__label {
  flex: 1;
}

/* Configuración sits apart from the rest of the rail, the way the reference sets it slightly off
   from the primary destinations — its own short list, pushed down against the profile card. */
.nav-list--settings {
  margin-top: auto;
  padding-top: 14px;
  border-top: 1px solid var(--hairline);
}

.sidebar__foot {
  margin-top: 14px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.profile {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 10px;
  border-radius: var(--radius);
  background: var(--surface);
  border: 1px solid var(--border);
}

.profile__avatar {
  width: 32px;
  height: 32px;
  border-radius: var(--radius-pill);
  background: var(--ev-bg);
  color: var(--ev-fg);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  font-weight: 800;
  flex: none;
}

.profile__name {
  font-size: 13.5px;
  font-weight: 700;
}

.profile__sub {
  font-size: 11.5px;
  color: var(--text-muted);
  font-weight: 600;
}

/* The profile menu (2026-08-18, persistent-copilot checkpoint spec §15) — a native <details>, no
   JS: Configuración/Seguridad/Cerrar sesión, one tap from the sidebar rather than two taps behind
   Configuración. Opens UPWARD (`.profile` sits at the bottom of the sidebar, so there is rarely
   room below it) — the same floating-panel shape `.memento-menu__panel` already uses. */
.profile-menu {
  position: relative;
}

.profile-menu summary.profile {
  cursor: pointer;
  list-style: none;
}

.profile-menu summary.profile::-webkit-details-marker,
.profile-menu summary.profile::marker {
  display: none;
  content: "";
}

.profile-menu__panel {
  position: absolute;
  bottom: calc(100% + 6px);
  left: 0;
  right: 0;
  z-index: 5;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: 0 12px 28px -10px rgba(70, 58, 45, 0.35);
  padding: 6px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.profile-menu__link {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 10px;
  border: none;
  background: none;
  border-radius: var(--radius-sm);
  color: var(--text);
  font-size: 14px;
  font-weight: 600;
  text-align: left;
  font: inherit;
}

.profile-menu__link:hover {
  background: var(--surface-sunk);
}

.profile-menu__link--form button {
  border: none;
  background: none;
  color: inherit;
  font: inherit;
  padding: 0;
  cursor: pointer;
}

/* --- The welcome card ------------------------------------------------------------------------ */

/* Memento speaking, before any list. Soft violet rather than white, so the first thing on the screen
   reads as a person talking to you and not as the first row of a table. */
.welcome {
  display: flex;
  align-items: flex-start;
  gap: 20px;
  flex-wrap: wrap;
  background: linear-gradient(160deg, var(--ev-soft) 0%, #fdfaf3 100%);
  border: 1px solid var(--ev-bg);
  border-radius: 32px;
  padding: 26px 26px 24px;
}

.ic-memento--hero {
  width: 58px;
}

.welcome__body {
  flex: 1;
  min-width: 240px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.welcome__hello {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 32px;
  line-height: 1.2;
  color: var(--text);
}

.welcome__date {
  font-size: 13.5px;
  font-weight: 600;
  color: var(--text-muted);
}

@media (min-width: 768px) {
  .welcome {
    gap: 26px;
    padding: 32px 34px 30px;
  }

  .ic-memento--hero {
    width: 66px;
  }

  .welcome__hello {
    font-size: 40px;
  }
}

.dot {
  width: 10px;
  height: 10px;
  border-radius: 3px;
  flex: none;
  background: currentColor;
}

/* --- Sections -------------------------------------------------------------------------------- */

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

.section__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
}

.section__title {
  font-family: var(--font-display);
  font-size: 17px;
  font-weight: 600;
  line-height: 1.35;
  margin: 0;
  color: var(--text);
}

.section__title--big {
  font-size: 19.5px;
  font-weight: 700;
}

.section__sub {
  font-size: 13px;
  color: var(--text-muted);
  font-weight: 600;
  flex: none;
}

.section__link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13.5px;
  font-weight: 700;
  color: var(--primary);
  min-height: var(--tap);
  flex: none;
}

/* --- Row cards ------------------------------------------------------------------------------- */

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 22px;
  padding: 6px 18px;
  display: flex;
  flex-direction: column;
}

.row {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 15px 0;
  border-bottom: 1px solid var(--hairline);
  min-height: 56px;
  text-align: left;
}

.card > .row:last-child,
.card > .row-details:last-child {
  border-bottom: none;
}

.row__icon {
  width: 18px;
  height: 18px;
  flex: none;
  color: var(--ev-fg);
}

.row__icon--task {
  color: var(--task-fg);
}
.row__icon--pay {
  color: var(--pay-fg);
}
.row__icon--rem {
  color: var(--rem-fg);
}
.row__icon--doc {
  color: var(--doc-fg);
}
.row__icon--per {
  color: var(--per-fg);
}
.row__icon--fact {
  color: var(--fact-fg);
}

.row__body {
  display: flex;
  flex-direction: column;
  gap: 2px;
  flex: 1;
  min-width: 0;
}

.row__title {
  font-size: 15.5px;
  font-weight: 600;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* This line now carries the date as a sentence ("El martes pasado, 9:00 a. m. · Cancha La Loma"),
   so it wraps instead of truncating — clipping it mid-word was the ledger habit, not a layout need. */
.row__meta {
  font-size: 12.5px;
  color: var(--text-muted);
  font-weight: 600;
  line-height: 1.45;
  text-wrap: pretty;
}

.row__amount {
  font-size: 14.5px;
  font-weight: 700;
  flex: none;
  font-variant-numeric: tabular-nums;
}

.row--done .row__title {
  color: var(--text-muted);
  text-decoration: line-through;
}

/* A row with more to say expands in place. <details> is the whole mechanism — the design's
   right-hand drawer, minus the JavaScript this dashboard is not allowed to ship. */
.row-details {
  border-bottom: 1px solid var(--hairline);
}

.card > .row-details:last-child {
  border-bottom: none;
}

.row-details > summary {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 15px 0;
  min-height: 56px;
  cursor: pointer;
  list-style: none;
}

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

/* The summary already carries .row; the border belongs to the <details> so it does not double up
   when the row is closed. */
.row-details > summary.row {
  border-bottom: none;
}

.row-details__chevron {
  width: 16px;
  height: 16px;
  flex: none;
  color: var(--text-faint);
}

.row-details[open] .row-details__chevron {
  transform: rotate(180deg);
}

.row-details__body {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 2px 0 18px;
}

.field {
  display: flex;
  gap: 12px;
  align-items: flex-start;
}

.field__icon {
  width: 17px;
  height: 17px;
  color: var(--text-muted);
  flex: none;
  margin-top: 3px;
}

.field__label {
  font-size: 12.5px;
  font-weight: 700;
  color: var(--text-muted);
}

.field__value {
  font-size: 14.5px;
  color: var(--text);
  line-height: 1.5;
  margin-top: 2px;
  text-wrap: pretty;
}

/* --- Collapsible section ---------------------------------------------------------------------- */

.fold > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 4px 0 12px;
  min-height: var(--tap);
  cursor: pointer;
  list-style: none;
  font-family: var(--font-display);
  font-size: 17px;
  font-weight: 600;
}

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

.fold__chevron {
  width: 16px;
  height: 16px;
  color: var(--text-muted);
  transform: rotate(-90deg);
}

.fold[open] .fold__chevron {
  transform: rotate(0deg);
}

/* --- Chips (filters, rendered as links the server re-reads) ---------------------------------- */

.chip-bar {
  display: flex;
  gap: 22px;
  flex-wrap: wrap;
  align-items: center;
}

.chip-group {
  display: flex;
  gap: 7px;
  flex-wrap: wrap;
  align-items: center;
}

.chip-group__label {
  font-size: 13.5px;
  font-weight: 700;
  color: var(--text-muted);
  margin-right: 2px;
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  white-space: nowrap;
  padding: 9px 14px;
  border-radius: var(--radius-pill);
  font-size: 13.5px;
  min-height: 38px;
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text-muted);
  font-weight: 600;
}

.chip:hover {
  border-color: var(--border-strong);
  color: var(--text);
}

.chip[aria-current="true"] {
  background: var(--primary);
  border-color: var(--primary);
  color: var(--primary-fg);
  font-weight: 700;
}

.tabs {
  display: inline-flex;
  padding: 4px;
  border-radius: var(--radius-pill);
  background: var(--surface-quiet);
  gap: 4px;
}

.tab {
  padding: 10px 20px;
  border-radius: var(--radius-pill);
  font-size: 14px;
  min-height: var(--tap);
  display: inline-flex;
  align-items: center;
  font-weight: 600;
  color: var(--text-muted);
}

.tab[aria-current="true"] {
  background: var(--surface);
  box-shadow: var(--shadow-card);
  font-weight: 700;
  color: var(--text);
}

/* --- Calendar -------------------------------------------------------------------------------- */

.agenda-controls {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
}

.month-nav {
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 4px;
  border-radius: var(--radius-pill);
  background: var(--surface);
  border: 1px solid var(--border);
}

.month-nav__btn {
  width: 36px;
  height: 36px;
  border-radius: var(--radius-pill);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--text-muted);
}

.month-nav__btn:hover {
  background: var(--surface-quiet);
}

.month-nav__label {
  font-size: 14px;
  font-weight: 700;
  padding: 0 6px;
  min-width: 112px;
  text-align: center;
}

.cal-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 18px;
  align-items: start;
}

.cal {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 22px;
  padding: 12px;
  min-width: 0;
}

.cal__weekdays,
.cal__grid {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 6px;
}

.cal__weekdays {
  margin-bottom: 6px;
}

.cal__weekday {
  font-size: 12px;
  color: var(--text-muted);
  font-weight: 700;
  text-align: center;
  padding: 6px 0;
}

.cal__cell {
  min-height: 52px;
  border-radius: var(--radius);
  padding: 5px;
  display: flex;
  flex-direction: column;
  gap: 3px;
  align-items: stretch;
  min-width: 0;
  background: var(--surface);
  border: 1px solid var(--surface-sunk);
  color: var(--text-muted);
}

.cal__cell--outside {
  background: #faf7f1;
  border-color: transparent;
  color: var(--text-faint);
}

.cal__cell--selected {
  border: 1.5px solid var(--primary);
  box-shadow: 0 0 0 3px rgba(139, 125, 224, 0.16);
}

.cal__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.cal__num {
  width: 25px;
  height: 25px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 12.5px;
  font-weight: 700;
  flex: none;
}

.cal__cell--today .cal__num {
  border-radius: var(--radius-pill);
  background: var(--brand-violet);
  color: var(--primary-fg);
  font-weight: 800;
}

.cal__dots {
  display: flex;
  align-items: center;
  flex: none;
}

.cal__dot {
  width: 5px;
  height: 5px;
  border-radius: var(--radius-pill);
  margin-left: 2px;
  background: var(--ev-fg);
}

.cal__dot--pay {
  background: var(--pay-fg);
}
.cal__dot--task {
  background: var(--task-fg);
}

.cal__pill {
  display: none;
  align-items: center;
  gap: 4px;
  padding: 3px 5px;
  border-radius: 7px;
  font-size: 11px;
  font-weight: 700;
  min-width: 0;
  background: var(--ev-bg);
  color: var(--ev-fg);
}

.cal__pill-text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}

.cal__more {
  display: none;
  font-size: 10.5px;
  font-weight: 700;
  color: var(--text-muted);
  padding-left: 4px;
}

.day-panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 18px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.day-panel__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}

.day-panel__title {
  font-size: 16.5px;
  font-weight: 700;
  margin: 0;
}

.day-panel__count {
  font-size: 12.5px;
  color: var(--text-muted);
  font-weight: 700;
}

.day-panel__empty {
  font-size: 14.5px;
  color: var(--text-muted);
  padding: 4px 0 8px;
}

/* --- Card grids: people, facts ---------------------------------------------------------------- */

.card-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 14px;
}

.person-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 18px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  align-items: flex-start;
  /* Personas cards on Inicio open the person's own edit drawer (reference-parity interactivity
     pass, 2026-08-15); the dedicated /dashboard/people page still uses this same class on a plain
     <article> with its own pill buttons, so the anchor reset only ever affects the link version. */
  text-decoration: none;
  color: inherit;
}

a.person-card:hover {
  border-color: var(--border-strong);
  box-shadow: var(--shadow-card);
}

.person-card__head {
  display: flex;
  align-items: center;
  gap: 11px;
  width: 100%;
}

.person-card__avatar {
  width: 38px;
  height: 38px;
  border-radius: var(--radius-pill);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  background: var(--rem-soft);
  color: var(--rem-fg);
}

.person-card__avatar--provider {
  background: var(--pay-soft);
  color: var(--pay-fg);
}

.person-card__name {
  font-size: 15.5px;
  font-weight: 700;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  margin: 0;
}

.person-card__role {
  font-size: 12.5px;
  color: var(--text-muted);
  font-weight: 600;
  margin-top: 2px;
}

.person-card__lines {
  display: flex;
  flex-direction: column;
  gap: 9px;
  width: 100%;
}

.person-card__line {
  display: flex;
  gap: 9px;
  align-items: flex-start;
  font-size: 14px;
  color: var(--text-muted);
  line-height: 1.5;
}

.person-card__line .icon--sm {
  margin-top: 4px;
}

.fact-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  padding: 20px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  align-items: flex-start;
  /* Tu memoria cards on Inicio open the fact's own edit drawer, same reasoning as .person-card
     above — /dashboard/memory's own <article> version is untouched by the anchor reset. */
  text-decoration: none;
  color: inherit;
}

a.fact-card:hover {
  border-color: var(--border-strong);
  box-shadow: var(--shadow-card);
}

.fact-card__pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 10.5px;
  font-weight: 800;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 6px 11px;
  border-radius: var(--radius-pill);
  background: var(--ev-bg);
  color: var(--ev-fg);
}

.fact-card__pill--out {
  background: var(--doc-bg);
  color: var(--doc-fg);
}

.fact-card__pill--in {
  background: var(--pay-bg);
  color: var(--pay-fg);
}

.fact-card__pill .dot {
  width: 8px;
  height: 8px;
  border-radius: 2px;
}

.fact-card__text {
  font-family: var(--font-display);
  font-size: 18.5px;
  font-weight: 600;
  line-height: 1.3;
  color: var(--text);
  margin: 0;
}

.fact-card__details {
  font-size: 14px;
  color: var(--text-muted);
  line-height: 1.5;
}

.fact-card__foot {
  display: flex;
  align-items: center;
  gap: 9px;
  width: 100%;
  margin-top: auto;
}

.fact-card__sub {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-muted);
}

.fact-card__amount {
  font-size: 15px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}

/* --- Badges ---------------------------------------------------------------------------------- */

.badge {
  font-size: 11.5px;
  font-weight: 800;
  padding: 5px 11px;
  border-radius: var(--radius-pill);
  flex: none;
  white-space: nowrap;
  background: var(--surface-quiet);
  color: var(--text-muted);
}

.badge--overdue {
  background: var(--danger-bg);
  color: var(--danger-fg);
}

.badge--done {
  background: var(--ok-bg);
  color: var(--ok-fg);
}

/* The reference's category pill on the right of every row (reference-parity pass, 2026-08-15). */
.row__chip {
  font-size: 11.5px;
  font-weight: 800;
  padding: 5px 11px;
  border-radius: var(--radius-pill);
  flex: none;
  white-space: nowrap;
}

.row__chip--ev {
  background: var(--ev-bg);
  color: var(--ev-fg);
}
.row__chip--task {
  background: var(--task-bg);
  color: var(--task-fg);
}
.row__chip--pay {
  background: var(--pay-bg);
  color: var(--pay-fg);
}
.row__chip--rem {
  background: var(--rem-bg);
  color: var(--rem-fg);
}
.row__chip--doc {
  background: var(--doc-bg);
  color: var(--doc-fg);
}
.row__chip--per {
  background: var(--per-bg);
  color: var(--per-fg);
}
.row__chip--fact {
  background: var(--fact-bg);
  color: var(--fact-fg);
}

/* --- The WhatsApp hand-off ------------------------------------------------------------------- */

/* Every action the design offered that would change data lands here instead: a sentence and, when
   the bot's number is configured, a link into the conversation where the change is actually made. */
.wa-callout {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  background: var(--ok-bg);
  border: 1px solid var(--ok-border);
  border-radius: var(--radius-xl);
  padding: 18px 20px;
}

.wa-callout__body {
  flex: 1;
  min-width: 200px;
  max-width: var(--content-max-width);
}

.wa-callout__title {
  font-size: 15px;
  font-weight: 700;
  color: var(--ok-fg);
}

.wa-callout__text {
  font-size: 13.5px;
  color: var(--ok-fg);
  line-height: 1.55;
  margin-top: 3px;
  text-wrap: pretty;
}

.wa-callout .btn {
  background: var(--surface);
  border-color: var(--ok-border);
  color: var(--ok-fg);
  font-weight: 700;
}

.wa-inline {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  font-weight: 700;
  color: var(--ok-fg);
  background: var(--ok-bg);
  padding: 10px 14px;
  border-radius: var(--radius-pill);
  min-height: var(--tap);
  align-self: flex-start;
}

.wa-inline:hover {
  color: var(--ok-fg);
  background: var(--ok-border);
}

.wa-inline--muted {
  background: var(--surface-quiet);
  color: var(--text-muted);
}

/* --- Empty, error ---------------------------------------------------------------------------- */

.empty-state {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 22px;
  padding: 38px 24px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  text-align: center;
}

.empty-state__title {
  font-size: 16.5px;
  font-weight: 700;
  margin: 0;
}

.empty-state__text {
  font-size: 14px;
  color: var(--text-muted);
  line-height: 1.55;
  max-width: 340px;
}

.empty-state__voice {
  margin-top: 4px;
  color: var(--ev-fg);
}

/* "This bucket is empty" inside an otherwise full screen — a sentence from Memento, not a blank card. */
.quiet-note {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 4px 2px 16px;
  font-size: 14.5px;
  font-weight: 600;
  color: var(--text-muted);
}

.error-page {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 22px;
  padding: 48px 28px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  text-align: center;
  max-width: var(--content-max-width);
  margin: 32px auto;
}

.error-page__icon {
  width: 56px;
  height: 56px;
  border-radius: var(--radius-pill);
  background: var(--danger-bg);
  color: var(--danger-fg);
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.error-page__title {
  font-family: var(--font-display);
  font-size: 24px;
  font-weight: 700;
  line-height: 1.3;
  margin: 0;
}

.error-page__text {
  font-size: 15px;
  color: var(--text-muted);
  line-height: 1.55;
  max-width: 380px;
}

/* --- Auth pages: signup/login/forgot-restablecer (2026-08-16, MEMENTO_EMAIL_PASSWORD_AUTH) ----
   Rendered without a session — no sidebar, no shell — the same reasoning `.error-page` documents
   for itself. Reuses `.form-card`/`.field-row`/`.input`/`.btn` verbatim for the form itself, so this
   block is only the centered single-column page wrapper those partials do not already provide. */

.auth-page {
  max-width: var(--content-max-width);
  margin: 40px auto;
  padding: 0 20px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.auth-page__brand {
  display: flex;
  justify-content: center;
}

.auth-page__title {
  font-family: var(--font-display);
  font-size: 22px;
  font-weight: 700;
  text-align: center;
  margin: 0;
}

.auth-page__lede {
  font-size: 14px;
  color: var(--text-muted);
  text-align: center;
  margin: 0 0 4px;
}

.auth-page__links {
  display: flex;
  flex-direction: column;
  gap: 8px;
  font-size: 14px;
  text-align: center;
}

.auth-page__note {
  font-size: 13px;
  color: var(--text-muted);
  text-align: center;
}

/* --- Auth visual refresh (C8, 2026-08-22) -----------------------------------------------------
   Login, signup, verify-email, forgot/reset password and step-up now carry `.auth-refresh`
   alongside their existing class (`.auth-page` on the standalone pages, `.section` on step-up,
   which stays inside `shell.html` rather than becoming a sixth standalone page). It changes
   nothing about the auth *contract* — same routes, same CSRF, same rate limiting, same fields —
   only which values four tokens resolve to underneath it.

   This is a re-scope, not a rewrite: `.form-card`, `.input`, `.btn--primary`, `.field-row` and
   every other rule already in this file read `var(--primary)`/`var(--font-display)`/
   `var(--font-body)`, so redefining those four custom properties on `.auth-refresh` cascades to
   every one of them automatically — a login page, a signup page and step-up's embedded form all
   pick up the same brand from one place, and nothing outside `.auth-refresh` (onboarding included,
   which reuses these same base classes) is touched. The background stays `var(--bg)` — Memento's
   cream is already both surfaces' shared background, not something to override. */
.auth-refresh {
  --font-display: "Sora", "Hanken Grotesk", -apple-system, BlinkMacSystemFont, sans-serif;
  --font-body: "Hanken Grotesk", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --primary: #5b72ff;
  --primary-hover: #3e51e0;

  /* The accent family that goes WITH that primary (2026-09-01). Kipi's periwinkle is
     `--color-memblue`/`--color-memdeep` in `frontend/src/index.css`; these two tints are its
     `--color-sky`/`--color-lavender` counterparts, kept in the same relationship.

     They exist because the first draft of these screens reached for `--ev-*` — the EVENT record
     category, which is violet — for its selected states, icons and card accents. That is how a
     surface ends up two-toned: periwinkle buttons with lilac selections. Anything tinted on an
     auth or onboarding screen now derives from the primary, and a record-category token is only
     ever correct on something that actually represents that record type. */
  --accent-soft: #eaf2ff;
  --accent-tint: #dbe6ff;
  --accent-deep: #3a5bd0;
}

/* Mobile inputs must read at 16px or larger, or iOS Safari zooms the whole page on focus — the
   base `.input` rule is 15px, tuned for the rest of the dashboard's denser forms. Unconditional
   (not just `<768px`): 16px reads just as well at desktop and this rule only ever reaches the
   six auth surfaces above. */
.auth-refresh .input {
  font-size: 16px;
}

/* --- Auth split-screen shell (C8 QA round 2, 2026-08-22 — the "Easy Peasy" reference direction)
   ----------------------------------------------------------------------------------------------
   Wraps the five standalone auth pages (login, signup, forgot/reset password, verify email —
   never step-up, which lives inside the already-branded dashboard shell, not a blank canvas).

   Below 900px: one column. The brand block ("reduce", not "oculta") sits compact above the form
   — logo, headline, one line of explanation, no benefits list, no gradient panel — then the real
   `.auth-page` form beneath it, full width, no dead margin.

   At and above 900px: two columns. The brand block becomes the full left panel (soft
   lavender-to-cream gradient, the three benefits shown), the form fills the right column.

   `.auth-page` keeps every one of its own rules untouched; this block only removes the extra
   top/bottom margin that made sense when it stood alone on an empty page and now sits inside a
   column that already centers it. */
.auth-shell {
  min-height: 100vh;
  display: grid;
  grid-template-columns: 1fr;
  background: var(--bg);
}

/* Mobile QA round 2 (2026-09-01): `flex-direction: column` (not the implicit row default) is load
   -bearing now that `.auth-lang` sits in normal flow below 900px (see `.auth-shell__form .auth-lang`
   further down) — a row direction put the language pill and the form side by side as two flex
   items, both vertically centered as a group, which squeezed the pill off to the left edge instead
   of stacking it above the form. `align-items: stretch` (flex's own default, stated explicitly
   here since the row-direction version relied on `center`) lets `.auth-lang`'s own
   `justify-content: flex-end` push the pill to the actual right edge of the column, not just the
   right edge of its own shrink-wrapped size. */
.auth-shell__form {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-content: center;
  padding: 8px 20px 32px;
}

.auth-shell__form .auth-page {
  margin: 0;
  width: 100%;
}

/* Mobile QA round 2 (2026-09-01): `_auth_brand.html`'s own docstring already claimed this panel was
   "hidden below `auth-shell--900`", but no such class, and no `display: none`, ever existed in this
   file — `.auth-shell`'s single-column grid (below) just stacked the brand panel directly above the
   form, so every phone saw the full marketing hero (logo, headline, lede) before the actual
   Crear cuenta / Iniciar sesión task. `display: none` here is the fix the comment already described;
   restored to `flex` only inside `@media (min-width: 900px)` below, where the two-column layout has
   room for it. */
.auth-shell__brand {
  display: none;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 12px;
  padding: 40px 20px 8px;
}

.auth-shell__brand-logo {
  width: 40px;
  height: 40px;
}

.auth-shell__brand-name {
  font-family: var(--font-display);
  font-size: 15.5px;
  font-weight: 700;
  letter-spacing: 0.01em;
  color: var(--primary);
  margin: 0;
}

.auth-shell__brand-title {
  font-family: var(--font-display);
  font-size: 24px;
  font-weight: 800;
  line-height: 1.2;
  color: var(--text);
  max-width: 380px;
  margin: 0;
}

.auth-shell__brand-lede {
  font-size: 14px;
  line-height: 1.5;
  color: var(--text-muted);
  max-width: 340px;
  margin: 0;
}

.auth-shell__brand-benefits {
  display: none;
}

@media (min-width: 900px) {
  .auth-shell {
    grid-template-columns: 1fr 1fr;
  }
  .auth-shell__brand {
    display: flex;
    align-items: flex-start;
    text-align: left;
    justify-content: center;
    gap: 22px;
    padding: 64px;
    background: linear-gradient(180deg, #efeafb 0%, #fdfbf5 100%);
    border-right: 1px solid var(--border);
  }
  .auth-shell__brand-logo {
    width: 44px;
    height: 44px;
  }
  .auth-shell__brand-title {
    /* 30px, not 34: at 34 the two-line promise wrapped to four lines inside a 64px-padded half
       column, which read as a paragraph rather than a headline. */
    font-size: 30px;
    max-width: 460px;
  }
  .auth-shell__brand-lede {
    font-size: 15px;
    max-width: 380px;
  }
  .auth-shell__brand-benefits {
    display: flex;
    flex-direction: column;
    gap: 13px;
    margin: 8px 0 0;
    padding: 0;
    list-style: none;
  }
  .auth-shell__brand-benefit {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 13.5px;
    font-weight: 700;
    color: var(--text);
  }
  .auth-shell__brand-benefit .icon {
    width: 18px;
    height: 18px;
    flex-shrink: 0;
    color: var(--primary);
  }
  .auth-shell__form {
    padding: 32px;
  }
}

/* --- Onboarding (2026-08-18, Task 7 of MEMENTO_ONBOARDING_V1) --------------------------------
   Reuses `.auth-page`/`.form-card`/`.field-row`/`.input`/`.select-wrap`/`.btn`/`.form-error`
   verbatim (same "no session-shell yet" reasoning `.auth-page` already documents for itself) —
   this block only adds what onboarding's own screens need and nothing else did: a checkbox row
   for the three consent controls, the already-added-people list, and the "listo" screen's example
   prompts. */

.checkbox-row {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  font-size: 14px;
  line-height: 1.5;
  cursor: pointer;
}

.checkbox-row input[type="checkbox"] {
  width: 24px;
  height: 24px;
  min-width: 24px;
  min-height: 24px;
  margin: 0;
  accent-color: var(--primary);
}

.onboarding-people-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
  max-width: var(--content-max-width);
}

.onboarding-people-list__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 12px 15px;
  font-size: 14.5px;
}

.onboarding-people-list__name {
  font-weight: 700;
}

.onboarding-people-list__relation {
  color: var(--text-muted);
  font-size: 13px;
}

.onboarding-examples {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
  max-width: var(--content-max-width);
}

.onboarding-examples__item {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 12px 15px;
  font-size: 14.5px;
  font-style: italic;
  color: var(--text);
}

/* --- Onboarding: step-progress indicator + sticky CTA (2026-08-18, Task 8 of
   MEMENTO_ONBOARDING_V1) — the discreet step counter shown on hogar/personas/privacidad/listo
   (never on bienvenida, which has none — it is step 0) and the sticky-footer pattern that keeps a
   step's primary CTA reachable when the on-screen keyboard is open, per checkpoint section 8. */

.onboarding-progress {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
}

.onboarding-progress__label {
  font-size: 13px;
  font-weight: 700;
  color: var(--text-muted);
}

.onboarding-progress__dots {
  display: flex;
  gap: 6px;
}

.onboarding-progress__dot {
  width: 8px;
  height: 8px;
  border-radius: var(--radius-pill);
  background: var(--border-strong);
}

.onboarding-progress__dot--done {
  background: var(--brand-violet);
}

/* The completed-dot colour is `--brand-violet` for the legacy screens that still use this partial.
   On the refreshed steps it must match the primary those screens actually render, or the progress
   indicator is the one lilac thing on a periwinkle page. Scoped, not replaced. */
.onboarding .onboarding-progress__dot--done {
  background: var(--primary);
  opacity: 0.55;
}

.onboarding-progress__dot--current {
  width: 20px;
  background: var(--primary);
}

/* Keeps the step's advancing CTA reachable when the mobile keyboard eats the bottom of the
   viewport — sticks the whole form (not just the button) to the bottom of the nearest scrolling
   ancestor, so its own card background/shadow read as a small footer bar rather than the button
   jumping loose from its own form. Applied to exactly one <form> per screen (the one that advances
   the step) — `people.html`'s standalone "Agregar persona" button is deliberately NOT sticky, so
   two sticky elements never compete for the same strip of screen. Harmless on desktop/when the
   page does not scroll: a sticky element with nothing to stick against just renders in its normal
   flow position. */
.onboarding-form--sticky-cta {
  position: sticky;
  bottom: max(12px, env(safe-area-inset-bottom));
  z-index: 5;
  box-shadow: var(--shadow-drawer);
}

/* --- 480px: the card grids earn a second column ---------------------------------------------- */

@media (min-width: 480px) {
  .card-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .btn--primary .btn__label {
    display: inline;
  }
}

/* --- 768px: the sidebar rail replaces the bottom navigation ---------------------------------- */

@media (min-width: 768px) {
  .sidebar {
    display: flex;
    flex-direction: column;
    width: var(--sidebar-rail);
    flex: none;
    background: var(--surface-sunk);
    border-right: 1px solid var(--border-strong);
    padding: 24px 14px;
    position: sticky;
    top: 0;
    height: 100vh;
  }

  .sidebar .nav-link,
  .sidebar .profile {
    justify-content: center;
  }

  .brand-word,
  .nav-link__label,
  .profile__text {
    display: none;
  }

  .bottom-nav {
    display: none;
  }

  .main {
    padding-bottom: 0;
  }

  .topbar {
    padding: 26px 28px 18px;
    position: sticky;
    top: 0;
    z-index: 20;
  }

  .content {
    padding: 26px 28px 8px;
  }

  .site-footer {
    padding: 24px 28px 32px;
  }

  .page-title {
    font-size: 35px;
  }

  .cal__cell {
    min-height: 84px;
    padding: 7px;
  }

  .cal__pill {
    display: flex;
  }

  .cal__more {
    display: block;
  }

  .btn__label {
    display: inline;
  }
}

/* --- 1200px: full sidebar, three columns, calendar beside its day ---------------------------- */

@media (min-width: 1200px) {
  .sidebar {
    width: var(--sidebar-full);
  }

  .sidebar .nav-link,
  .sidebar .profile {
    justify-content: flex-start;
  }

  .brand-word,
  .nav-link__label,
  .profile__text {
    display: block;
  }

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

  .cal-layout {
    grid-template-columns: minmax(0, 1fr) 352px;
  }

  .cal__cell {
    min-height: 104px;
  }

  .content {
    padding: 30px 34px 8px;
  }

  .topbar {
    padding: 26px 34px 18px;
  }
}

/* --- Motion ---------------------------------------------------------------------------------- */

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

/* --- Mutations: row actions, forms, confirmation ---------------------------------------------- */

/* Actions live inside an expanded row, never on the collapsed line — a household scanning the list
   is reading, and a row full of buttons is the CRM look this design exists to avoid. */
.row-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  padding-top: 4px;
}

.row-action {
  margin: 0;
  display: contents;
}

.pill-btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 10px 15px;
  border-radius: var(--radius-pill);
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text-muted);
  font: inherit;
  font-size: 13.5px;
  font-weight: 700;
  min-height: var(--tap);
  cursor: pointer;
  white-space: nowrap;
}

.pill-btn:hover {
  border-color: var(--border-strong);
  color: var(--text);
}

.pill-btn--go {
  background: var(--ok-bg);
  border-color: var(--ok-border);
  color: var(--ok-fg);
}

.pill-btn--go:hover {
  background: var(--ok-border);
  color: var(--ok-fg);
}

.pill-btn--quiet {
  color: var(--text-muted);
  border-style: dashed;
}

.pill-btn--quiet:hover {
  color: var(--danger-fg);
  border-color: var(--danger-border);
}

.btn--danger {
  background: var(--danger-fg);
  border-color: var(--danger-fg);
  color: #fffcf5;
  font-weight: 700;
}

.btn--danger:hover {
  background: #8f3527;
  border-color: #8f3527;
  color: #fffcf5;
}

/* --- The correction form ---------------------------------------------------------------------- */

.form-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 22px;
  padding: 24px;
  display: flex;
  flex-direction: column;
  gap: 18px;
  max-width: var(--content-max-width);
}

.field-row {
  display: flex;
  flex-direction: column;
  gap: 7px;
}

.field-row__label {
  font-size: 13px;
  font-weight: 700;
  color: var(--text-muted);
}

.input {
  font: inherit;
  font-size: 15px;
  color: var(--text);
  background: var(--bg);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  padding: 13px 15px;
  min-height: var(--tap);
  width: 100%;
}

.input:focus-visible {
  border-color: var(--primary);
}

textarea.input {
  resize: vertical;
  line-height: 1.5;
}

/* A native <select> keeps its platform chrome unless appearance is reset, which would leave the
   one control in the drawer that does not look like the others. The chevron is drawn in CSS
   rather than fetched: the CSP is `default-src 'self'`, so a background image URL is one more
   thing that can silently fail in production. */
.select-wrap {
  position: relative;
  display: block;
}

.select-wrap select.input {
  appearance: none;
  padding-right: 40px;
  cursor: pointer;
}

.select-wrap::after {
  content: "";
  position: absolute;
  top: 50%;
  right: 17px;
  width: 8px;
  height: 8px;
  margin-top: -6px;
  border-right: 2px solid var(--text-muted);
  border-bottom: 2px solid var(--text-muted);
  transform: rotate(45deg);
  pointer-events: none;
}

/* Country picker (2026-08-17/18, Task 6 of MEMENTO_ONBOARDING_V1) — `static/country-picker.js`'s
   progressive enhancement over `.select-wrap select[name="pais"]`. The native select stays in the
   DOM and posted; only its visibility changes, and only via a class the script adds itself, so a
   script that fails partway through never leaves a `display:none` select with no replacement
   visible. */
.country-picker__native--hidden {
  display: none;
}

.country-picker {
  position: relative;
}

.country-picker__flag {
  position: absolute;
  left: 15px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 18px;
  line-height: 1;
  pointer-events: none;
}

.country-picker__input {
  padding-left: 44px;
}

.country-picker__listbox {
  position: absolute;
  z-index: 40;
  top: calc(100% + 6px);
  left: 0;
  right: 0;
  max-height: 260px;
  overflow-y: auto;
  margin: 0;
  padding: 6px;
  list-style: none;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-drawer);
}

.country-picker__listbox[hidden] {
  display: none;
}

.country-picker__option {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  min-height: var(--tap);
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: 15px;
}

.country-picker__option-flag {
  font-size: 16px;
  line-height: 1;
}

.country-picker__option--active {
  background: var(--surface-quiet);
}

.country-picker__option--selected {
  font-weight: 700;
}

.form-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
}

.form-actions form {
  margin: 0;
}

.form-error {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--danger-bg);
  color: var(--danger-fg);
  border-radius: var(--radius);
  padding: 14px 18px;
  font-size: 14.5px;
  font-weight: 600;
  max-width: var(--content-max-width);
}

/* Field-level error (e.g. the signup form's phone field) — sits directly under its own input,
   tied to it via aria-describedby, rather than the form-wide banner above. */
.field-row__error {
  color: var(--danger-fg);
  font-size: 13px;
  font-weight: 600;
}

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

.form-note {
  display: flex;
  align-items: center;
  gap: 11px;
  font-size: 13.5px;
  color: var(--text-muted);
  max-width: var(--content-max-width);
  line-height: 1.5;
}

/* --- Delete confirmation ----------------------------------------------------------------------- */

.confirm {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 26px;
  padding: 40px 28px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  text-align: center;
  max-width: var(--content-max-width);
  margin: 0 auto;
}

.confirm__title {
  font-family: var(--font-display);
  font-size: 25px;
  font-weight: 700;
  margin: 0;
}

.confirm__subject {
  font-size: 17px;
  font-weight: 700;
  color: var(--text);
}

.confirm__text {
  font-size: 14.5px;
  color: var(--text-muted);
  line-height: 1.55;
  max-width: 400px;
  text-wrap: pretty;
}

/* --- "Listo" confirmation after a mutation ----------------------------------------------------- */

.did {
  display: flex;
  align-items: center;
  gap: 12px;
  background: var(--ok-bg);
  border: 1px solid var(--ok-border);
  border-radius: var(--radius-xl);
  padding: 14px 20px;
  color: var(--ok-fg);
  font-size: 14.5px;
  font-weight: 700;
}

/* --- The drawer -------------------------------------------------------------------------------- */

/* The design's right-hand panel, driven by the URL rather than by script: a row's "Corregir" is a
   link to `?editar=tipo:id` on the same screen, and closing it is a link back without the param.
   That keeps the zero-JavaScript rule, and it means a half-finished correction survives a refresh
   and can be bookmarked or shared between the household's own devices.

   Geometry is lifted from the source design: 440px, left border, soft shadow, bottom sheet on a
   phone. */
.drawer-scrim {
  position: fixed;
  inset: 0;
  z-index: 40;
  background: rgba(43, 40, 35, 0.28);
}

.drawer {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 50;
  max-height: 88vh;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border-radius: 26px 26px 0 0;
  padding: 12px 20px calc(20px + env(safe-area-inset-bottom));
  box-shadow: 0 -20px 50px -24px rgba(70, 58, 45, 0.4);
}

/* The phone sheet's grab handle. Decorative — the close button is the real control. */
.drawer__grab {
  width: 42px;
  height: 4px;
  border-radius: var(--radius-pill);
  background: var(--border-strong);
  align-self: center;
  margin-bottom: 10px;
  flex: none;
}

.drawer__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 14px;
  flex: none;
}

.drawer__chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 7px 13px;
  border-radius: var(--radius-pill);
  font-size: 12.5px;
  font-weight: 800;
  white-space: nowrap;
  background: var(--ev-bg);
  color: var(--ev-fg);
}

.drawer__chip--task {
  background: var(--task-bg);
  color: var(--task-fg);
}
.drawer__chip--pay {
  background: var(--pay-bg);
  color: var(--pay-fg);
}
.drawer__chip--rem {
  background: var(--rem-bg);
  color: var(--rem-fg);
}
.drawer__chip--doc {
  background: var(--doc-bg);
  color: var(--doc-fg);
}
.drawer__chip--per {
  background: var(--per-bg);
  color: var(--per-fg);
}
.drawer__chip--fact {
  background: var(--fact-bg);
  color: var(--fact-fg);
}
.drawer__chip--danger {
  background: var(--danger-bg);
  color: var(--danger-fg);
}
.drawer__chip--done {
  background: var(--ok-bg);
  color: var(--ok-fg);
}

.drawer__close {
  width: 40px;
  height: 40px;
  border-radius: var(--radius-pill);
  background: var(--surface-quiet);
  color: var(--text-muted);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
}

.drawer__close:hover {
  background: var(--border);
  color: var(--text);
}

.drawer__body {
  flex: 1;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 18px;
  margin-top: 18px;
  min-height: 0;
}

.drawer__title {
  font-size: 22px;
  font-weight: 700;
  line-height: 1.25;
  margin: 0;
}

.drawer__sub {
  font-size: 14.5px;
  color: var(--text-muted);
  line-height: 1.5;
  text-wrap: pretty;
}

.drawer__footer {
  display: flex;
  align-items: center;
  gap: 10px;
  padding-top: 18px;
  margin-top: 14px;
  border-top: 1px solid var(--surface-sunk);
  flex: none;
}

.drawer__footer form {
  margin: 0;
  flex: 1;
}

.drawer__footer .btn--primary,
.drawer__footer .btn--danger,
.drawer__footer .pill-btn {
  width: 100%;
  justify-content: center;
}

/* `.btn__label` is hidden below 480px by default (the compact icon-only topbar buttons) and only
   `.btn--primary` earns it back there; a drawer's Guardar/Eliminar are never icon-only, on any
   screen size, so they opt back in unconditionally rather than through that breakpoint. */
.drawer__footer .btn__label {
  display: inline;
}

/* Inside the drawer the form is the whole panel, so it drops the card chrome. */
.drawer .form-card {
  background: none;
  border: none;
  border-radius: 0;
  padding: 0;
  max-width: none;
}

@media (min-width: 768px) {
  .drawer {
    top: 0;
    left: auto;
    width: min(440px, 92vw);
    max-height: none;
    border-radius: 0;
    border-left: 1px solid var(--border);
    padding: 24px 26px;
    box-shadow: -24px 0 60px -30px rgba(70, 58, 45, 0.4);
  }

  .drawer__grab {
    display: none;
  }
}

/* Wide enough to show both at once: the page slides over instead of hiding under the panel, and
   the scrim is unnecessary because nothing is covered. */
@media (min-width: 1320px) {
  .shell--drawer .main {
    margin-right: min(440px, 92vw);
  }

  .shell--drawer .drawer-scrim {
    display: none;
  }
}

/* Fecha and Hora sit side by side, as the design pairs them. */
.field-pair {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
}

.field-pair .field-row {
  flex: 1;
  min-width: 130px;
}

.drawer__note {
  font-size: 13px;
  color: var(--text-muted);
  line-height: 1.5;
  text-wrap: pretty;
}

/* --- Para revisar ----------------------------------------------------------------------------
   The one screen where Memento asks instead of tells. Cards, never rows: a question deserves more
   room than a list item, and the stack reads as "a few things", which is what it should ever be. */

.review-grid {
  display: grid;
  gap: 14px;
  grid-template-columns: 1fr;
}

@media (min-width: 700px) {
  .review-grid {
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  }
}

.review-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
  padding: 20px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-card);
}

.review-card__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  width: 100%;
}

.review-card__when {
  font-size: 12.5px;
  color: var(--text-faint);
}

.review-card__title {
  font-family: var(--font-display);
  font-size: 19.5px;
  font-weight: 600;
  line-height: 1.25;
  color: var(--text);
}

.review-card__says {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  font-size: 14px;
  color: var(--text-muted);
}

.review-card__says .icon {
  flex: none;
  margin-top: 2px;
  color: var(--primary);
}

.btn--sm {
  min-height: 38px;
  padding: 0 16px;
  font-size: 14px;
}

/* Memento's own question, at the top of the panel. .memento-voice is applied by the template only when
   the text itself is short and conversational — see templating.py's `memento_voice` test. */
.memento-says {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 6px;
  padding: 14px 16px;
  background: var(--ev-bg);
  border-radius: var(--radius-xl);
  font-size: 20px;
  line-height: 1.3;
  color: var(--ev-fg);
}

/* What Memento understood, read back as label/value rather than as a form. */
.detail-list {
  display: flex;
  flex-direction: column;
  margin: 16px 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  overflow: hidden;
}

.detail-list__row {
  display: flex;
  gap: 14px;
  justify-content: space-between;
  padding: 12px 16px;
  border-bottom: 1px solid var(--hairline);
}

.detail-list__row:last-child {
  border-bottom: 0;
}

.detail-list__label {
  font-size: 13px;
  font-weight: 700;
  color: var(--text-muted);
}

.detail-list__value {
  font-size: 14.5px;
  color: var(--text);
  text-align: right;
}

/* "Así llegó a tu memoria" — the household's own words, quoted back. */
.provenance {
  margin: 16px 0;
  padding: 16px;
  background: var(--ok-bg);
  border-radius: var(--radius-xl);
}

.provenance__label {
  margin-bottom: 6px;
  font-size: 12.5px;
  font-weight: 800;
  letter-spacing: 0.02em;
  color: var(--ok-fg);
}

.provenance__quote {
  font-size: 15px;
  line-height: 1.5;
  color: var(--text);
}

/* The candidates of a "which one?" question. Each is a link to the real record. */
.choice-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 14px 0;
}

.choice {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-height: var(--tap);
  padding: 12px 16px;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  color: var(--text);
  text-decoration: none;
}

.choice:hover {
  border-color: var(--primary);
}

.choice__label {
  font-size: 15px;
  font-weight: 600;
}

/* Each footer action is its own form, so they must not stack vertically. */
.review-form {
  display: contents;
}

.nav-badge {
  margin-left: auto;
  min-width: 21px;
  padding: 0 6px;
  border-radius: 99px;
  background: var(--primary);
  color: #fff;
  font-size: 12px;
  font-weight: 800;
  line-height: 21px;
  text-align: center;
}

/* --- Greeting: count line and status pill (handoff 05 §1.1) ---------------------------------- */

.welcome__count {
  font-size: 16.5px;
  font-weight: 600;
  color: var(--text-muted);
}

.welcome__count strong {
  font-weight: 800;
  color: var(--text);
}

/* "2 cosas para revisar" is a link into the queue; "Todo está en su lugar" is a statement, so it
   is a <p> and never picks up the link affordances. */
.status-pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  align-self: flex-start;
  min-height: 38px;
  margin-top: 4px;
  padding: 0 16px;
  border-radius: var(--radius-pill);
  font-size: 13px;
  font-weight: 700;
  text-decoration: none;
}

.status-pill--todo {
  background: var(--doc-bg);
  color: var(--doc-fg);
}

.status-pill--ok {
  background: var(--ok-bg);
  color: var(--ok-fg);
}

/* --- Search (shell + home reference-parity pass, 2026-08-15) --------------------------------- */

.search-form {
  display: flex;
  gap: 10px;
  align-items: center;
}

.search-form__input {
  flex: 1;
  min-width: 0;
  min-height: var(--tap);
  padding: 0 16px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: 15px;
}

.search-form__input::placeholder {
  color: var(--text-faint);
}

.search-form__input:focus-visible {
  border-color: var(--primary);
}

/* A row made clickable in full, for screens (Buscar, Configuración) where the row itself is the
   navigation rather than an expandable detail — unlike `.row-details`, this just goes somewhere. */
.row-link {
  display: block;
  color: inherit;
}

.row-link:hover {
  color: inherit;
  background: var(--surface-quiet);
  border-radius: var(--radius);
}

.row-link .row {
  padding: 12px 10px;
}

.settings-row {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  padding: 14px 10px;
  border-bottom: 1px solid var(--hairline);
}

.settings-row:last-child {
  border-bottom: none;
}

/* --- Home (reference-parity pass, 2026-08-15): highlight cards, review summary, day cards ---- */

.highlight-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 14px;
}

.highlight-card {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 20px;
  border-radius: var(--radius-xl);
  /* Every one of these opens the record it names (reference-parity interactivity pass,
     2026-08-15) — reset the anchor defaults so it still reads as a card, not a link. */
  text-decoration: none;
  color: inherit;
  border: 1px solid transparent;
}

.highlight-card:hover {
  color: inherit;
  border-color: rgba(43, 40, 35, 0.18);
}

.highlight-card--pay {
  background: var(--pay-bg);
  color: var(--pay-fg);
}
.highlight-card--ev {
  background: var(--ev-bg);
  color: var(--ev-fg);
}
.highlight-card--task {
  background: var(--task-bg);
  color: var(--task-fg);
}

.highlight-card__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.highlight-card__label {
  font-size: 11.5px;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  opacity: 0.75;
}

.highlight-card__badge {
  padding: 4px 11px;
  border-radius: var(--radius-pill);
  background: rgba(255, 255, 255, 0.62);
  font-size: 12px;
  font-weight: 700;
}

.highlight-card__title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 19.5px;
  line-height: 1.25;
}

.highlight-card__meta {
  font-size: 14px;
  font-weight: 600;
  opacity: 0.85;
}

.highlight-card__note {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin-top: 2px;
  font-size: 14.5px;
  line-height: 1.3;
}

/* --- Review summary (Inicio's compact card, vs. the full review_card on /dashboard/revisar) -- */

.review-summary {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 20px;
  border-radius: var(--radius-xl);
  background: var(--warn-bg);
  border: 1px solid var(--warn-border);
}

.review-summary__head {
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--warn-fg);
}

.review-summary__title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 19.5px;
}

.review-summary__list {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.review-summary__row {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 6px;
  margin: -6px;
  border-radius: var(--radius);
  text-decoration: none;
  color: inherit;
}

.review-summary__row:hover {
  color: inherit;
  background: rgba(255, 255, 255, 0.5);
}

.review-summary__icon {
  width: 17px;
  height: 17px;
  color: var(--warn-fg);
  flex: none;
  margin-top: 3px;
}

.review-summary__row-title {
  display: block;
  font-weight: 700;
  font-size: 14.5px;
}

.review-summary__row-why {
  display: block;
  font-size: 13px;
  color: var(--text-muted);
  margin-top: 1px;
}

.review-summary .btn--primary {
  align-self: flex-start;
}

/* --- Momentos que vienen: the three-day preview -------------------------------------------- */

.day-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 12px;
}

.day-card {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 16px;
  border-radius: var(--radius-lg);
  background: var(--surface);
  border: 1px solid var(--border);
}

.day-card__head {
  display: flex;
  align-items: baseline;
  gap: 8px;
}

.day-card__label {
  font-weight: 700;
  font-size: 14.5px;
}

.day-card__count {
  font-size: 12.5px;
  color: var(--text-muted);
  font-weight: 600;
}

.day-card__lines {
  display: flex;
  flex-direction: column;
  gap: 9px;
}

.day-card__line {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  font-size: 13.5px;
  line-height: 1.4;
  color: var(--text);
  text-decoration: none;
  border-radius: var(--radius-sm);
  padding: 3px 4px;
  margin: -3px -4px;
}

.day-card__line:hover {
  color: var(--text);
  background: var(--surface-quiet);
}

.day-card__line svg {
  width: 15px;
  height: 15px;
  color: var(--text-muted);
  flex: none;
  margin-top: 2px;
}

.day-card__empty {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13.5px;
  color: var(--text-muted);
  font-style: italic;
}

@media (min-width: 480px) {
  .highlight-grid,
  .day-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 1200px) {
  .highlight-grid,
  .day-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* --- "Hablar con Memento" floating bubble + panel (2026-08-15, Phase 4) --------------------------

   A genuinely conversational surface, not a dedicated page: the bubble sits fixed bottom-right on
   every screen; the panel it opens is visually distinct from the side drawer (a floating card, not
   a full-height slide-in) so a chat reads as a chat. Above the drawer's own z-index (50) when open,
   since it's the active thing the household is looking at; the bubble itself sits above the bottom
   nav (30) but below any open drawer/panel, so a drawer never gets a stray bubble floating on it. */

.memento-fab {
  position: fixed;
  right: 20px;
  bottom: calc(84px + env(safe-area-inset-bottom));
  z-index: 45;
  width: 56px;
  height: 56px;
  border-radius: var(--radius-pill);
  background: var(--primary);
  color: var(--primary-fg);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 12px 28px -10px rgba(108, 92, 209, 0.55);
}

/* The panel is already open (`shell--memento`, same modifier pattern as `shell--drawer`) — kept in
   the markup (its accessible name still renders) but visually redundant: on mobile the panel
   already covers it, on desktop it would otherwise float on top of the docked sidecar's own
   content (2026-08-18, MEMENTO_CONVERSATIONAL_QUALITY_PERSISTENT_COPILOT_V1). */
.shell--memento .memento-fab {
  display: none;
}

.memento-fab:hover {
  background: var(--primary-hover);
}

.memento-fab .icon {
  width: 24px;
  height: 24px;
}

/* Mobile: a real app screen, not a bottom sheet (2026-08-18, MEMENTO_MOBILE_FIRST_CHAT_V1) — fills
   the viewport edge to edge, respecting safe areas top and bottom. `100dvh` (not `100vh`) tracks
   the visual viewport as the on-screen keyboard opens/closes, so the composer never ends up
   pinned below the fold behind it. Widened to `min-width: 768px` below for the desktop floating-
   panel treatment, which keeps its own bottom-right placement and rounded corners. */
.memento-float {
  position: fixed;
  z-index: 55;
  inset: 0;
  height: 100dvh;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  padding: max(12px, env(safe-area-inset-top)) 18px calc(12px + env(safe-area-inset-bottom));
  box-shadow: none;
}

/* The full-width chat screen (`memento_full.html`, §16) — same internal layout as the
   overlay/docked sidecar (still `.memento-float`, so `.memento-float__body`'s own scroll rules
   apply unchanged), but a normal in-flow card inside `<main>`, never an overlay, at any viewport
   width. The combined selector's higher specificity wins over both the mobile base rule above and
   the desktop dock rule below regardless of source order (2026-08-18, persistent-copilot
   checkpoint). */
.memento-float.memento-float--full {
  position: static;
  inset: auto;
  z-index: auto;
  height: min(720px, 74vh);
  border-radius: 20px;
  border: 1px solid var(--border);
  box-shadow: none;
  padding: 14px 18px;
}

.memento-float__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex: none;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--surface-sunk);
}

.memento-float__identity {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 16px;
}

/* Header actions + "Borrar conversación" menu (2026-08-18, MEMENTO_MOBILE_FIRST_CHAT_V1) — reuses
   .drawer__close's own pill-button treatment for the menu trigger, so the two header controls read
   as one family rather than two different button styles. */
.memento-float__actions {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: none;
}

.memento-menu {
  position: relative;
}

.memento-menu__trigger {
  width: 40px;
  height: 40px;
  border-radius: var(--radius-pill);
  background: var(--surface-quiet);
  color: var(--text-muted);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: none;
  cursor: pointer;
}

.memento-menu__trigger:hover {
  background: var(--border);
  color: var(--text);
}

.memento-menu__panel {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 5;
  min-width: 200px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: 0 12px 28px -10px rgba(70, 58, 45, 0.35);
  padding: 6px;
}

.memento-menu__panel button {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 10px 10px;
  border: none;
  background: none;
  border-radius: var(--radius-sm);
  color: var(--danger-fg);
  font-size: 14.5px;
  text-align: left;
  cursor: pointer;
}

.memento-menu__panel button:hover {
  background: var(--surface-sunk);
}

.memento-confirm {
  flex: none;
  margin: 10px 0;
  padding: 12px 14px;
  background: var(--surface-sunk);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.memento-confirm[hidden] {
  display: none;
}

.memento-confirm p {
  margin: 0;
  font-size: 14.5px;
  line-height: 1.5;
}

.memento-confirm__actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
}

/* Offline banner (2026-08-18, MEMENTO_MOBILE_FIRST_CHAT_V1) — a neutral, non-alarming surface
   (not `.form-error`'s danger colors): being offline is a normal, expected state, not a failure. */
.memento-offline-banner {
  flex: none;
  margin: 10px 0 0;
  padding: 8px 12px;
  background: var(--surface-sunk);
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  font-size: 13.5px;
  font-weight: 600;
  text-align: center;
}

.memento-float__body {
  flex: 1;
  overflow-y: auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 14px 0;
}

/* Empty state + chips (2026-08-18, MEMENTO_MOBILE_FIRST_CHAT_V1) — fills the whole scroll area
   when there's nothing to show yet, so a fresh conversation reads as an inviting starting point
   rather than a blank box. Chips reuse the existing `.chip` pill, just without the filter-tab
   `aria-current` state, since these are one-shot fill actions, not a persistent selection. */
.memento-empty {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 8px;
  padding: 24px 16px;
}

.memento-empty__title {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 20px;
}

.memento-empty__text {
  margin: 0;
  color: var(--text-muted);
  font-size: 14.5px;
}

.memento-empty__chips {
  margin-top: 12px;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: center;
}

.memento-load-previous {
  align-self: center;
  margin-bottom: 4px;
  padding: 8px 16px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text-muted);
  font-size: 13.5px;
  font-weight: 600;
}

.memento-load-previous:hover {
  border-color: var(--border-strong);
  color: var(--text);
}

/* Three-dot typing indicator (2026-08-18, MEMENTO_MOBILE_FIRST_CHAT_V1) — replaces the old
   changing-text "Lo estoy pensando…"/"...organizando." line. The blanket
   `@media (prefers-reduced-motion: reduce) { * { animation: none !important; } }` rule already in
   this file's Motion section covers this animation too, so no separate override is needed here. */
.memento-typing {
  display: inline-flex;
  align-items: center;
  padding: 8px 12px;
}

.memento-typing__dots {
  display: inline-flex;
  gap: 4px;
}

.memento-typing__dots span {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--text-muted);
  animation: memento-typing-bounce 1.2s infinite ease-in-out;
}

.memento-typing__dots span:nth-child(2) {
  animation-delay: 0.15s;
}

.memento-typing__dots span:nth-child(3) {
  animation-delay: 0.3s;
}

@keyframes memento-typing-bounce {
  0%,
  60%,
  100% {
    transform: translateY(0);
    opacity: 0.5;
  }
  30% {
    transform: translateY(-4px);
    opacity: 1;
  }
}

.memento-turn--household {
  align-self: flex-end;
  max-width: 85%;
  background: var(--surface-sunk);
  border-radius: var(--radius-xl) var(--radius-xl) 4px var(--radius-xl);
  padding: 10px 14px;
  font-size: 14.5px;
  line-height: 1.5;
  margin: 0;
}

.memento-turn--memento {
  align-self: flex-start;
  max-width: 90%;
  margin: 0;
}

/* A chat bubble reads smaller than the drawer's leading question — .memento-says' own size is tuned
   for that more prominent context. */
.memento-says.memento-turn--memento {
  font-size: 15px;
}

/* The confirmation card (2026-08-16, MEMENTO_CONVERSATIONAL_CORE_V1). It is not another chat
   bubble: it reports a record that now exists, so it gets a visible edge and a calmer surface —
   the same "this is a real thing you can act on" weight the row cards elsewhere carry. Uses the
   existing tokens only; no new palette. */
.memento-card {
  align-self: flex-start;
  max-width: 92%;
  background: var(--surface-sunk);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 12px 14px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.memento-card__head {
  margin: 0;
  font-size: 13px;
  color: var(--text-muted);
}

.memento-card__title {
  margin: 0;
  font-size: 15.5px;
  font-weight: 600;
  line-height: 1.35;
}

.memento-card__when {
  margin: 0;
  font-size: 14px;
  color: var(--text-muted);
}

.memento-card__items {
  margin: 2px 0 0;
  padding-left: 18px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: 14.5px;
}

/* The reminder default-hour policy, stated where the household reads the result. Quiet, but never
   hidden: a defaulted time the household cannot see is an invented one. */
.memento-card__note {
  margin: 0;
  font-size: 13px;
  color: var(--text-muted);
  font-style: italic;
}

.memento-card__actions {
  margin: 4px 0 0;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.memento-failed {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
}

/* Person disambiguation card (2026-08-18, persistent-copilot checkpoint spec §8) — one row per
   real candidate, "no vincular"/"agregar persona" below. Reuses `.memento-card`'s own surface. */
.memento-person-picker {
  gap: 10px;
}

/* Contextual suggestion chips (2026-08-18, persistent-copilot completion checkpoint spec §8.1) —
   at most 2, each a real link or a real one-tap send form; the form is styled to look identical to
   the link so neither reads as more "confirmed" than the other before the household taps it. */
.memento-suggestions {
  margin: 4px 0 0;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.memento-suggestions__form {
  display: contents;
}

.pill-btn--suggestion {
  background: var(--surface-quiet);
  border: 1px solid var(--border);
}

.memento-person-picker__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.memento-person-picker__name {
  display: flex;
  flex-direction: column;
  font-size: 14.5px;
  font-weight: 600;
  min-width: 0;
}

.memento-person-picker__role {
  font-size: 12.5px;
  font-weight: 400;
  color: var(--text-muted);
}

.memento-person-picker__add {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  padding-top: 8px;
  border-top: 1px solid var(--border);
}

.memento-person-picker__add .input {
  flex: 1 1 140px;
  min-width: 0;
}

.memento-failed__text {
  margin: 0;
  font-size: 14.5px;
  color: var(--text-muted);
}

/* Sticky at the bottom of the panel's flex column — the transcript body scrolls above it, the
   composer never does, and it stays visible above the on-screen keyboard on mobile since the
   panel's own height already tracks `100dvh`. `.memento-float`'s own bottom padding already
   reserves the safe-area inset for the whole panel, so this doesn't add a second one. */
.memento-float__form {
  flex: none;
  display: flex;
  gap: 10px;
  align-items: flex-end;
  padding-top: 10px;
  border-top: 1px solid var(--surface-sunk);
  background: var(--surface);
  position: sticky;
  bottom: 0;
}

.memento-float__form .input {
  flex: 1;
  resize: none;
}

.memento-float__form .btn {
  flex: none;
}

/* "New messages ↓" pill (2026-08-18, MEMENTO_MOBILE_FIRST_CHAT_V1) — floats just above the
   composer, centered, only shown while the household has scrolled up and a swap just arrived. */
.memento-new-messages {
  align-self: center;
  margin: 0 auto 8px;
  padding: 8px 16px;
  border-radius: var(--radius-pill);
  border: none;
  background: var(--primary);
  color: var(--primary-fg);
  font-size: 13.5px;
  font-weight: 700;
  box-shadow: 0 8px 20px -8px rgba(108, 92, 209, 0.55);
}

@media (min-width: 768px) {
  .memento-fab {
    bottom: 28px;
  }

  /* Persistent-copilot sidecar (2026-08-18, MEMENTO_CONVERSATIONAL_QUALITY_PERSISTENT_COPILOT_V1):
     a docked flex column beside `.main` inside `.shell` — not an overlay — so the dashboard stays
     fully interactive beside it (both are siblings sharing the same row) and no backdrop is needed.
     `position: sticky` + `align-self: flex-start` (overriding `.shell`'s default `stretch`) pins it
     to the viewport instead of growing to `.shell`'s full document height on a long/scrolling
     screen — the composer must stay visible, not scroll away below a long list. Width is the
     checkpoint's own bracket (~400–440px, never below 360px), fluid rather than fixed so it doesn't
     eat the whole viewport on a narrower "desktop" window right at the 768px edge. */
  .memento-float {
    position: sticky;
    top: 0;
    align-self: flex-start;
    flex: 0 0 clamp(360px, 30vw, 440px);
    inset: auto;
    height: 100dvh;
    border-radius: 0;
    box-shadow: none;
    border-left: 1px solid var(--border);
    padding: 14px 18px calc(14px + env(safe-area-inset-bottom));
  }
}

/* --- "Agregar manualmente" category tabs (2026-08-15, Phase 4) --------------------------------

   One pill per category, colored with the exact same tokens the drawer chip/rows already use —
   no new colors invented. */

.agregar-tabs {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 4px;
}

.agregar-tab {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 9px 16px;
  border-radius: var(--radius-pill);
  font-size: 13.5px;
  font-weight: 700;
  border: 1px solid transparent;
  color: var(--text-muted);
  background: var(--surface-sunk);
}

.agregar-tab__icon {
  color: inherit;
}

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

.agregar-tab.is-active.agregar-tab--ev {
  background: var(--ev-bg);
  color: var(--ev-fg);
}
.agregar-tab.is-active.agregar-tab--rem {
  background: var(--rem-bg);
  color: var(--rem-fg);
}
.agregar-tab.is-active.agregar-tab--task {
  background: var(--task-bg);
  color: var(--task-fg);
}
.agregar-tab.is-active.agregar-tab--pay {
  background: var(--pay-bg);
  color: var(--pay-fg);
}
.agregar-tab.is-active.agregar-tab--persona {
  /* Same pairing .person-card__avatar already uses — no new color token for one tab. */
  background: var(--rem-bg);
  color: var(--rem-fg);
}

.drawer__title--head {
  margin: 0;
  font-size: 19.5px;
}

/* --- Tu memoria (2026-08-19, QA manual P0 #2) ------------------------------------------------
   The memory screen reuses `.section`, `.card-grid`, `.fact-card`, `.chip` and `.input` wholesale;
   only the four things that had no existing equivalent are defined here. `.memory-lock` in
   particular is the one new visual idea on the screen — "this is here, and it is protected" — and
   deliberately reads as calm information, not as an error or a warning. */

.memory-filters {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
  margin-bottom: 14px;
}

.memory-filters__input {
  flex: 1 1 240px;
  min-width: 0;
}

.memory-chips {
  display: flex;
  gap: 7px;
  flex-wrap: wrap;
  align-items: center;
  margin-bottom: 22px;
}

.memory-lock {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--text-muted);
  font-weight: 600;
}

/* The detail/edit panel is a single card on its own screen rather than one of a grid, so it is not
   capped to a grid column's width. */
.fact-card--wide {
  max-width: 560px;
}

.memory-edit-form {
  display: flex;
  flex-direction: column;
  gap: 14px;
  margin: 14px 0;
}

/* ==============================================================================================
   KIPI AUTH + ONBOARDING REFRESH V1 (2026-08-31)
   ==============================================================================================
   The front door (`GET /`), the refreshed credential forms, and the four first-run steps.

   Built ON the C8 `.auth-refresh` block above, not beside it: every screen below carries that
   class, so all of this inherits its Sora/Hanken Grotesk type and its `--primary` from one place.
   There is no second design system here and no new palette — the only new tokens are the two
   spacing rhythms these screens need, and they resolve against the same scale everything else uses.

   Mobile-first throughout. The one breakpoint that earns itself is 560px, where the six choice
   cards stop being a list and become a two-column grid; below that a single column keeps each
   option's title and description on one readable measure. */

.auth-refresh {
  /* The vertical rhythm of a first-run screen: roomier than a dense dashboard form, which is the
     whole point — these screens hold one idea each. */
  --fr-gap: 20px;
  --fr-gap-lg: 28px;
}

/* Mobile QA Blocker B (2026-09-01): `.btn__label` is hidden below 480px by default (the compact
   icon-only topbar buttons) and only `.btn--primary` earns it back there — see the `.btn__label`
   rule near the top of this file and its `@media (min-width: 480px)` counterpart. A `.btn--quiet`
   CTA on an auth/onboarding screen (real examples: "Ya tengo cuenta" on the front door, "Agregar
   persona" on Personas, "Continuar sin activarlas" on Privacidad) inherited that rule and rendered
   as a correctly-sized, correctly-colored, completely label-less rectangle on any phone under
   480px CSS width — nearly every phone in portrait. None of these buttons are ever icon-only, on
   any screen size, exactly the reasoning `.drawer__footer .btn__label` already states below — so
   every screen in this checkpoint opts back in unconditionally rather than through that
   breakpoint. */
.auth-refresh .btn__label {
  display: inline;
}

/* Mobile QA round 2 (2026-09-01): signup's País/Teléfono row reuses `.field-pair` from the
   dashboard's Fecha/Hora pattern (`.field-pair .field-row { min-width: 130px }`), but on a real
   iPhone that left too little room for a "🇵🇦 Panamá +507" label — the country picker's own flag
   icon adds 44px of left padding on top — plus a phone number field, and the pair read as cramped
   rather than broken. Scoped to `.auth-refresh` so the dashboard's own Fecha/Hora pair (out of
   scope for this checkpoint) is untouched: a wider `min-width` here means the two fields wrap to
   their own full-width rows on a narrow phone (flex-wrap, already on `.field-pair`, does the rest)
   while staying side by side once there is comfortably enough room — no new dependency. */
.auth-refresh .field-pair .field-row {
  min-width: 240px;
}

/* --- The language toggle, shared by every anonymous screen ----------------------------------- */

.auth-lang {
  display: flex;
  justify-content: flex-end;
  padding: 14px 20px 0;
}

/* Inside the two-column form shell, `.auth-shell__form` centres its single child — so dropping the
   toggle in as a second flex child parked it halfway down the column, next to nothing. Pinning it
   to the top-right of that column puts it where it already sits on the entry screen, so the control
   does not move between the two screens a visitor sees back to back.

   Mobile QA round 2 (2026-09-01): that absolute positioning is desktop-only, restored inside
   `@media (min-width: 900px)` below. Below that width `.auth-shell__form .auth-page`'s own
   `margin: 0` (above) leaves no reserved gutter for an absolutely-positioned control, so a long or
   bilingual-switched heading (`.auth-page__title`, centered, full column width on a phone) ran
   straight under the "English"/"Español" pill — real iPhone QA saw "Qué bueno verte de nuevo"
   clipped behind the language link. Left in normal flow, `.auth-lang`'s own base rule (this file,
   just above) renders it as its own right-aligned row ahead of the title — it always owns its own
   space and can never overlap anything, on any narrow width. */
.auth-shell__form {
  position: relative;
}

@media (min-width: 900px) {
  .auth-shell__form .auth-lang {
    position: absolute;
    top: 0;
    right: 0;
    padding: 12px 16px 0;
    z-index: 1;
  }
}

.auth-lang__link {
  font-size: 13px;
  font-weight: 700;
  color: var(--text-muted);
  text-decoration: none;
  padding: 8px 12px;
  min-height: var(--tap);
  display: inline-flex;
  align-items: center;
  border-radius: var(--radius-pill);
  border: 1px solid var(--border);
  background: var(--surface);
}

.auth-lang__link:hover,
.auth-lang__link:focus-visible {
  color: var(--text);
  border-color: var(--border-strong);
}

/* --- GET / — the front door ------------------------------------------------------------------
   Deliberately NOT the two-column `.auth-shell` the forms use: a split screen whose second column
   holds two buttons reads as a form that failed to load. One centered column at every width. */

.auth-entry {
  min-height: 100vh;
  min-height: 100dvh; /* keeps the CTAs above a mobile browser's collapsing toolbar */
  display: flex;
  flex-direction: column;
  background: var(--bg);
  padding-bottom: env(safe-area-inset-bottom);
}

.auth-entry__inner {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--fr-gap);
  width: 100%;
  max-width: 500px;
  margin: 0 auto;
  padding: 32px 20px 40px;
  text-align: center;
}

.auth-entry__mark {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
}

.auth-entry__logo {
  width: 52px;
  height: 52px;
}

.auth-entry__wordmark {
  font-family: var(--font-display);
  font-size: 16.5px;
  font-weight: 700;
  letter-spacing: 0.02em;
  color: var(--primary);
  margin: 0;
}

/* Each of the two lines is one phrase and must stay on one line — "Menos cosas / en tu cabeza."
   splits the sentence where it does not want to split. Sora (the `.auth-refresh` display face) sets
   wider than the face this was first sized against, so the size and the measure are tuned to the
   longer of the two lines rather than to a round number. */
.auth-entry__title {
  font-family: var(--font-display);
  font-size: 27px;
  line-height: 1.18;
  font-weight: 800;
  letter-spacing: -0.01em;
  color: var(--text);
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
  /* Balanced wrapping keeps a two-line Spanish headline from breaking one word onto its own line;
     browsers without support simply wrap normally. */
  text-wrap: balance;
}

/* The second line carries the promise rather than the problem, so it lifts rather than shouts. */
.auth-entry__title-line--soft {
  color: var(--primary);
}

.auth-entry__lede {
  font-size: 16px;
  line-height: 1.55;
  color: var(--text-muted);
  margin: 0;
  /* Wide enough that "conecta lo importante de tu vida" does not break after "lo" — a two-line
     lede should split on a phrase, not mid-thought. `pretty` prevents an orphaned last word where
     it is supported and is inert everywhere else. */
  max-width: 38ch;
  margin-inline: auto;
  text-wrap: pretty;
}

.auth-entry__actions {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 12px;
  margin-bottom: 4px;
}

/* `--text-muted`, not `--text-faint`: #C0B4A2 on the cream background is about 2.1:1, which fails
   WCAG AA for body text. This line explains the shape of the product to a first-time visitor — it
   is quiet by size and placement, and it does not need to be quiet by being hard to read. */
.auth-entry__note {
  font-size: 13px;
  line-height: 1.5;
  color: var(--text-muted);
  margin: 0;
}

@media (min-width: 768px) {
  .auth-entry__title {
    /* 32, not 34: at 34 the longer line measured 560px inside a 560px content box — it fit, with
       nothing to spare, which is the width at which a font-rendering difference on someone else's
       machine becomes a wrapped headline. */
    font-size: 32px;
  }
  .auth-entry__inner {
    max-width: 600px;
  }
}

/* --- Brand panel: two-line headline (shared with the entry screen's copy) --------------------- */

.auth-shell__brand-title-line {
  display: block;
}

.auth-shell__brand-title-line--soft {
  color: var(--primary);
}

/* --- Buttons: the two modifiers these screens add --------------------------------------------- */

/* Full-width, and tall enough to be the obvious thing to press on a phone. */
.btn--block {
  display: flex;
  width: 100%;
  padding: 15px 18px;
  font-size: 15.5px;
}

/* The honest secondary. Used for "Ya tengo una cuenta" and, load-bearingly, for "Continuar sin
   activarlas" on the consent step: AI-off is a fully supported Kipi state, so it gets a real
   button with real contrast — never a muted, half-disabled-looking one (checkpoint §25). */
.btn--quiet {
  background: var(--surface);
  border-color: var(--border-strong);
  color: var(--text);
  font-weight: 700;
}

.btn--quiet:hover {
  background: var(--surface-quiet);
  border-color: var(--text-faint);
  color: var(--text);
}

/* Set by kipi-auth.js between submit and navigation. Communicates "working", never "broken". */
.btn--pending {
  opacity: 0.72;
  cursor: progress;
}

/* --- Password field: hint + the script-created reveal button ---------------------------------- */

.field-row__hint {
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--text-muted);
  margin-top: 2px;
}

.password-wrap {
  display: block;
  position: relative;
}

/* Only padded once the button actually exists — with JavaScript off there is nothing to make room
   for, and reserving the space anyway would leave an unexplained gap. */
.password-wrap--enhanced .input {
  padding-right: 50px;
}

.password-toggle {
  position: absolute;
  top: 50%;
  right: 4px;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--tap);
  height: var(--tap);
  padding: 0;
  border: 0;
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
}

.password-toggle:hover {
  color: var(--text);
}

.password-toggle[aria-pressed="true"] {
  color: var(--primary);
}

/* --- A neutral notice (the Closed Alpha recovery screen) -------------------------------------- */

.auth-page__notice {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 14px 16px;
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--text);
  text-align: left;
}

.auth-page__notice .icon {
  flex-shrink: 0;
  margin-top: 2px;
  color: var(--text-muted);
}

/* --- The four first-run steps ------------------------------------------------------------------
   One shell for all of them, so step 1 and step 4 cannot drift apart visually. */

/* The shared progress indicator centres itself, which was right when it sat above centred
   `.auth-page` copy. The refreshed steps are left-aligned, so a centred "Paso 1 de 4" floated free
   of the headline underneath it. Scoped to `.onboarding` so the legacy `/onboarding/hogar` and
   `/onboarding/listo` screens keep the alignment they were designed with. */
.onboarding .onboarding-progress {
  align-items: flex-start;
}

.onboarding {
  width: 100%;
  max-width: 560px;
  margin: 0 auto;
  padding: 20px 20px calc(32px + env(safe-area-inset-bottom));
  display: flex;
  flex-direction: column;
  gap: var(--fr-gap);
}

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

.onboarding__title {
  font-family: var(--font-display);
  font-size: 25px;
  line-height: 1.22;
  font-weight: 800;
  letter-spacing: -0.01em;
  color: var(--text);
  margin: 0;
  text-wrap: balance;
}

.onboarding__lede {
  font-size: 15.5px;
  line-height: 1.55;
  color: var(--text-muted);
  margin: 0;
  max-width: 42ch;
}

.onboarding__form {
  display: flex;
  flex-direction: column;
  gap: var(--fr-gap);
  margin: 0;
}

.onboarding__actions {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.onboarding__note {
  font-size: 13px;
  line-height: 1.5;
  color: var(--text-muted);
  text-align: center;
  margin: 0;
}

/* Same reasoning as `.auth-entry__note` above — quiet by hierarchy, never by failing contrast. */
.onboarding__note--quiet {
  color: var(--text-muted);
  opacity: 0.85;
}

@media (min-width: 768px) {
  .onboarding {
    padding-top: 40px;
  }
  .onboarding__title {
    font-size: 29px;
  }
}

/* --- Step 1: the six mental-load cards ---------------------------------------------------------
   Native checkboxes. The `<input>` is visually hidden but never `display:none` — it must stay
   focusable and stay in the accessibility tree, because it IS the selected state a screen reader
   announces. Everything below styles its `:checked`/`:focus-visible` siblings. */

.choice-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 10px;
  border: 0;
  padding: 0;
  margin: 0;
  min-width: 0; /* a <fieldset> refuses to shrink inside a grid without this */
}

.choice-grid__legend {
  /* Visually hidden: the <h1> already asks the question out loud, and repeating it on screen would
     be noise — but the legend is what makes the six inputs one named group in the a11y tree. */
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.choice-card {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 15px 44px 15px 16px;
  background: var(--surface);
  border: 1.5px solid var(--border);
  border-radius: var(--radius-lg);
  cursor: pointer;
  min-height: var(--tap);
}

.choice-card:hover {
  border-color: var(--border-strong);
}

/* The canonical visually-hidden pattern — the same one `.choice-grid__legend` above uses — rather
   than `opacity: 0`. Both keep the checkbox focusable, but a zero-opacity control is treated as
   invisible by some tooling, and this is the state a screen reader announces: it must never be in
   any doubt. Never `display: none` or `visibility: hidden`, either of which would take the checkbox
   out of the tab order and leave the card unusable by keyboard. */
.choice-card__input {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: 0;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.choice-card__body {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
}

.choice-card__title {
  font-size: 15px;
  font-weight: 700;
  color: var(--text);
}

.choice-card__text {
  font-size: 13.5px;
  line-height: 1.45;
  color: var(--text-muted);
}

/* The tick is the only thing that appears on selection — the card itself changes weight, it does
   not grow, so a grid of six does not reflow as you choose. */
.choice-card__tick {
  position: absolute;
  top: 15px;
  right: 15px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: var(--radius-pill);
  border: 1.5px solid var(--border-strong);
  background: var(--surface);
  color: transparent;
}

.choice-card__tick .icon {
  width: 14px;
  height: 14px;
}

.choice-card__input:checked ~ .choice-card__tick {
  background: var(--primary);
  border-color: var(--primary);
  color: var(--primary-fg);
}

.choice-card:has(.choice-card__input:checked) {
  border-color: var(--primary);
  background: var(--accent-soft);
}

/* Focus lands on the hidden input, so the ring has to be drawn on the card. */
.choice-card:has(.choice-card__input:focus-visible) {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

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

/* --- Step 1's conditional time-zone question --------------------------------------------------
   Rendered only when signup could not resolve the zone safely, so most households never see it.
   Styled as a quiet aside rather than a second headline: it is a correction, not a chapter. */

.tz-confirm {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 16px;
  background: var(--surface-sunk);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
}

.tz-confirm__title {
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 700;
  color: var(--text);
  margin: 0;
}

.tz-confirm__lede {
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--text-muted);
  margin: 0;
}

/* --- Step 3: the demonstration ---------------------------------------------------------------- */

.demo {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 18px 16px;
  background: var(--surface-sunk);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
}

/* Says "example" before anyone reads the exchange, so nothing on this screen can be mistaken for a
   record that was just created (checkpoint §23). */
.demo__badge {
  align-self: flex-start;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  padding: 4px 10px;
  margin: 0;
}

.demo-bubble {
  display: flex;
  flex-direction: column;
  gap: 4px;
  max-width: 88%;
  padding: 12px 15px;
  border-radius: var(--radius-lg);
}

.demo-bubble--user {
  align-self: flex-end;
  background: var(--primary);
  color: var(--primary-fg);
  border-bottom-right-radius: var(--radius-sm);
}

.demo-bubble--kipi {
  align-self: flex-start;
  background: var(--surface);
  border: 1px solid var(--border);
  border-bottom-left-radius: var(--radius-sm);
}

/* The speaker is named in text, so the exchange survives being read linearly by a screen reader
   rather than depending on which side a bubble sits on. */
.demo-bubble__who {
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  opacity: 0.72;
}

.demo-bubble__text {
  font-size: 14.5px;
  line-height: 1.5;
  margin: 0;
}

/* Deliberately quieter than a real action card on `/app`: it illustrates the shape of a saved
   thing without impersonating one. */
.demo-card {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 13px 15px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--primary);
  border-radius: var(--radius);
}

.demo-card__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  flex-shrink: 0;
  border-radius: var(--radius-pill);
  background: var(--accent-tint);
  color: var(--accent-deep);
}

.demo-card__body {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.demo-card__title {
  font-size: 14.5px;
  font-weight: 700;
  color: var(--text);
}

.demo-card__meta {
  font-size: 12.5px;
  color: var(--text-muted);
}

.demo__footnote {
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--text-muted);
  margin: 0;
}

/* --- Step 4: the trust card and the two consent checkboxes ------------------------------------ */

.trust-card {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 18px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-card);
}

.trust-card__title {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font-display);
  font-size: 16.5px;
  font-weight: 700;
  color: var(--text);
  margin: 0;
}

.trust-card__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  flex-shrink: 0;
  border-radius: var(--radius-pill);
  background: var(--accent-soft);
  color: var(--primary);
}

.trust-card__body {
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--text-muted);
  margin: 0;
}

/* The informed-consent disclosure under the card's friendly framing. Smaller and muted because it
   is detail, never because it is meant to be skipped — it stays at `--text-muted` (about 7:1 on
   this background), not `--text-faint`. */
.trust-card__detail {
  font-size: 13px;
  line-height: 1.55;
  color: var(--text-muted);
  margin: 4px 0 0;
  padding-top: 12px;
  border-top: 1px solid var(--hairline);
}

/* `.checkbox-row` sets `display: flex`, and any author `display` declaration beats the user-agent's
   `[hidden] { display: none }` — so a row toggled with `el.hidden = true` stays on screen. This is
   the author-level rule that makes `hidden` mean hidden for it; `[hidden]` raises specificity above
   the bare class, so no `!important` is needed. Used by the guardianship acknowledgement on the
   people step (`static/kipi-auth.js`). */
.checkbox-row[hidden] {
  display: none;
}

.consent-checks {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 4px 2px;
}

/* --- Motion ------------------------------------------------------------------------------------
   One transition, on the two things a finger touches. Nothing animates on load, nothing delays a
   signup, and `prefers-reduced-motion` removes even this. */

.choice-card,
.btn {
  transition:
    border-color 120ms ease,
    background-color 120ms ease,
    color 120ms ease;
}

@media (prefers-reduced-motion: reduce) {
  .choice-card,
  .btn {
    transition: none;
  }
}
