/* ===========================
   isnotus — South Wind, v2 (Aegean)
   Named for Notus, Greek god of
   the warm south wind, with a
   cool register for Metis admin.
   =========================== */

@import url('https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,400;9..144,500;9..144,600&family=Inter:wght@400;500;600&display=swap');

:root {
  /* warm register — Notus / chat / homeschool / photos */
  --wind-sky: #FBF8F3;
  --wind-sand: #F3EDE4;
  --wind-dune: #E8DFD2;
  --wind-shore: #D6CDBF;
  --wind-drift: #B8AD9C;
  --wind-stone: #8A7E6E;
  --wind-earth: #5C5346;
  --wind-deep: #3B352C;
  --wind-amber: #C4892E;
  --wind-amber-hover: #B07A25;
  --wind-amber-light: rgba(196, 137, 46, 0.10);
  /* #155 — text on amber surfaces (primary buttons). Amber stays a light color
     in BOTH themes, so this NON-flipping dark brown is defined once (no dark
     override) — white failed AA (3.02/2.19); this hits 5.28 (light) / 7.29 (dark). */
  --wind-on-amber: #2A2018;
  --wind-sunset: #C47A4A;
  --wind-terracotta: #B5654A;
  --wind-green: #5E9E5E;
  --wind-green-light: #EDF5ED;
  --wind-red: #B85454;
  --wind-red-light: #F5EDED;
  --wind-mine-bubble: #EDE5D6;
  --wind-white: #FFFFFF;
  --wind-white-rgb: 255 255 255;  /* Phase 7e A0 — for rgba(var(--wind-white-rgb) / α) glass primitives */

  /* cool register — Metis / financial / DITL / data viz */
  --sea-mist:  #EEF3F2;
  --sea-glass: #C9DDD9;
  --sea-shoal: #86AEB0;
  --sea-tide:  #4A7A85;
  --sea-deep:  #1F4652;
  --sea-ink:   #0F2A33;

  /* Phase 14f tokens — shadows + ink + status + banners. Dark equivalents
     live under [data-theme="dark"] below. See
     docs/plans/phase-14f-dark-mode-adr.md for the full taxonomy. */

  /* Shadow family — flips to higher alpha on dark surfaces (audit: 0.08
     vanishes against #1A1612). */
  --shadow-subtle:     0 1px 3px rgba(90, 80, 65, 0.06);
  --shadow-card:       0 1px 3px rgba(90, 80, 65, 0.08);
  --shadow-card-hover: 0 4px 12px rgba(90, 80, 65, 0.12);
  --shadow-elevated:   0 6px 18px rgba(0, 0, 0, 0.12);
  --shadow-modal:      0 20px 60px rgba(0, 0, 0, 0.25);

  /* Ink — high-contrast text on light surfaces (chat bubbles, legal copy). */
  --ink-deep: #000;

  /* Status palette — banner backgrounds + text on success/danger surfaces. */
  --status-success-bg:     #EFF6EA;
  --status-success-border: #BFD4A6;
  --status-success-text:   #4A6B2E;
  --status-danger-bg:      #FFF4F2;
  --status-danger-border:  #E0BFB8;
  --status-danger-text:    #B33A2A;
  --status-danger-stroke:  #E0BFBF;

  /* Banner / paper gradients (ADR exceptions #3 + #4) — gradient on light;
     flat darker color on dark. */
  --banner-notice-bg:     linear-gradient(180deg, #f5eacd 0%, #ead9b1 100%);
  --banner-notice-border: #d4bf8a;
  --banner-notice-text:   #4a3820;
  --banner-notice-accent: #8a5a2b;
  --paper-bg:             linear-gradient(180deg, #f5eacd 0%, #ead9b1 100%);
  --paper-border:         #d4bf8a;
  --paper-text:           #4a3820;
  --paper-accent:         #8a5a2b;

  /* Backdrop scrims for modals + overlays. */
  --scrim-modal: rgba(20, 16, 12, 0.4);
  --scrim-light: rgba(0, 0, 0, 0.05);

  /* Borders + dividers + surface tints. wind-deep tinted at 4 alpha steps for
     borders and one for surface overlays. Used by Metis chat, financial cards,
     proposal cards, DITL event rows, and the preview-table family. Flip to
     white-based in dark mode under [data-theme="dark"]. */
  --border-hairline: rgba(74, 57, 40, 0.06);
  --border-soft:     rgba(74, 57, 40, 0.08);
  --border-card:     rgba(74, 57, 40, 0.10);
  --border-emphatic: rgba(74, 57, 40, 0.12);
  --surface-subtle:  rgba(74, 57, 40, 0.04);

  /* Wind-amber deeper variant — text on amber tints (proposal-kind monospace
     pill, where regular --wind-amber lacks contrast on the amber-tint bg). */
  --wind-amber-deep: #A66F1B;

  /* type scale */
  --text-xs:   0.78rem;
  --text-sm:   0.875rem;
  --text-base: 1rem;
  --text-lg:   1.125rem;
  --text-xl:   1.375rem;
  --text-2xl:  1.75rem;
  --text-3xl:  2.25rem;
  --text-hero: 3.5rem;
  --line-tight: 1.15;
  --line-body:  1.55;
  --line-ui:    1.35;

  /* font stacks */
  --font-display: "Fraunces", Georgia, serif;
  --font-ui: "Inter", -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}

/* Phase 14f — dark theme.
   Pure token swap (Q1 from parent plan). Component-level overrides are
   forbidden except for ADR-listed exceptions; every divergence lands here.

   Palette is the parent-plan starting draft + minor tightening from the
   audit. James 2am eye-test on iPad Pro 11" refines values before prod.
   See docs/plans/phase-14f-dark-mode.md §"Dark palette". */
[data-theme="dark"] {
  /* Tells the browser to paint native chrome (select dropdowns, date pickers,
     scrollbars, autofill) in dark mode. Without this declaration, native form
     controls render in OS-default light chrome on top of our dark surfaces —
     stark white-on-black popovers that punch out of the page. Single biggest
     dark-mode-polish win for the smallest amount of CSS. */
  color-scheme: dark;

  /* warm register — page bg + surfaces */
  --wind-sky:    #1A1612;
  --wind-sand:   #221C16;
  --wind-dune:   #2C251D;
  --wind-shore:  #3A3128;
  --wind-drift:  #524539;
  --wind-stone:  #9C8E7C;
  --wind-earth:  #C8B9A2;
  --wind-deep:   #E6D9BF;
  --wind-amber:  #E0A455;
  --wind-amber-hover: #F0B469;
  --wind-amber-light: rgba(224, 164, 85, 0.16);
  --wind-sunset: #DC916E;
  --wind-terracotta: #D88B70;
  --wind-green:        #7FBE7F;
  --wind-green-light:  rgba(127, 190, 127, 0.14);
  --wind-red:          #E07A7A;
  --wind-red-light:    rgba(224, 122, 122, 0.14);
  --wind-mine-bubble:  #2C251D;
  --wind-white:        #1A1612;     /* "white" surfaces stay surface-colored on dark */

  /* cool register */
  --sea-mist:  #15201F;
  --sea-glass: #1F3835;
  --sea-shoal: #4F7D7F;
  --sea-tide:  #7BB0B4;
  --sea-deep:  #B8DDDD;
  --sea-ink:   #D8E8E8;

  /* shadows — counter-intuitive but correct: dark surfaces need higher alpha
     to render shadow at all. */
  --shadow-subtle:     0 1px 3px rgba(0, 0, 0, 0.30);
  --shadow-card:       0 2px 8px rgba(0, 0, 0, 0.40);
  --shadow-card-hover: 0 6px 16px rgba(0, 0, 0, 0.50);
  --shadow-elevated:   0 8px 22px rgba(0, 0, 0, 0.55);
  --shadow-modal:      0 24px 64px rgba(0, 0, 0, 0.60);

  /* ink */
  --ink-deep: #FFFFFF;

  /* status — desaturated pastels on dark backgrounds */
  --status-success-bg:     rgba(127, 190, 127, 0.12);
  --status-success-border: rgba(127, 190, 127, 0.40);
  --status-success-text:   #B8DAB8;
  --status-danger-bg:      rgba(224, 122, 122, 0.12);
  --status-danger-border:  rgba(224, 122, 122, 0.40);
  --status-danger-text:    #E8A0A0;
  --status-danger-stroke:  rgba(224, 122, 122, 0.40);

  /* banner / paper — gradients flatten to darker solid colors */
  --banner-notice-bg:     #2A2218;
  --banner-notice-border: #3E3320;
  --banner-notice-text:   #E2C99A;
  --banner-notice-accent: #D4A45C;
  --paper-bg:             #2A2218;
  --paper-border:         #3E3320;
  --paper-text:           #E2C99A;
  --paper-accent:         #D4A45C;

  /* scrims — match the new pure-black headroom */
  --scrim-modal: rgba(0, 0, 0, 0.65);
  --scrim-light: rgba(255, 255, 255, 0.05);

  /* borders flip to white-tinted on dark surfaces */
  --border-hairline: rgba(255, 255, 255, 0.06);
  --border-soft:     rgba(255, 255, 255, 0.08);
  --border-card:     rgba(255, 255, 255, 0.10);
  --border-emphatic: rgba(255, 255, 255, 0.12);
  --surface-subtle:  rgba(255, 255, 255, 0.04);

  --wind-amber-deep: #DCB46B;
}

/* Base typography — body sans, headings serif */
h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 500;
  line-height: var(--line-tight);
  letter-spacing: -0.01em;
  font-variation-settings: "opsz" 48, "SOFT" 50;
}
h1 { font-variation-settings: "opsz" 64, "SOFT" 50; letter-spacing: -0.015em; }

.hero-num {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--text-hero);
  font-variation-settings: "opsz" 96, "SOFT" 50;
  line-height: 1.05;
  letter-spacing: -0.025em;
  color: var(--sea-deep);
}
.hero-num .unit {
  font-size: 0.45em;
  letter-spacing: 0;
  color: var(--wind-earth);
  font-weight: 400;
}

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

/* Phase 14e — global motion guard.
   When the user prefers reduced motion (OS-level setting), collapse every
   animation + transition to ~0ms. Keeps state changes instant rather than
   animated; preserves accessibility without per-rule hand-coverage.
   See docs/motion-rules.md for the full rules + animation inventory. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* The HTML `hidden` attribute should always hide the element. Browser default
   for `[hidden]` is `display: none` at user-agent stylesheet specificity, which
   any author rule (e.g. `.homeschool-toolbar { display: flex }`) overrides.
   This global rule re-asserts the contract so [hidden] always wins. */
[hidden] { display: none !important; }

html, body {
  width: 100%;
  height: 100%;
  /* Phase 14f-followup: default body background uses the token so any gap
     between sticky/sticky-adjacent surfaces (e.g. .agent-strip on /us/minx
     and /us/dice) shows the page color, not pure black. The slideshow page
     overrides to #000 below — its hero is a black-letterboxed image. */
  background: var(--wind-sky);
  color: var(--wind-earth);
  font-family: var(--font-ui);
  font-size: var(--text-base);
  line-height: var(--line-body);
}

/* ===== Slideshow (public homepage) ===== */

.slideshow-page body,
body.slideshow-page {
  overflow: hidden;
  /* Public homepage is full-bleed photography — black letterbox is intentional. */
  background: #000;
}

.slideshow-page #slideshow {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
}

.slideshow-page .slide {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  opacity: 0;
  transition: opacity 1.5s ease-in-out;
}

.slideshow-page .slide.active {
  opacity: 1;
}

/* ===== Landing page (pre-login /us/) ===== */

/* ===== Login page ===== */

.login-page {
  background: var(--wind-sky);
  background-image: radial-gradient(ellipse at 50% 100%, rgba(196, 137, 46, 0.08) 0%, transparent 60%);
  color: var(--wind-earth);
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
}

.login-container {
  width: 100%;
  max-width: 380px;
  padding: 40px 24px;
}

.login-container h1 {
  font-size: 2rem;
  font-weight: 700;
  color: var(--wind-deep);
  margin-bottom: 4px;
  letter-spacing: 0.02em;
}

.login-subtitle {
  font-size: 1rem;
  color: var(--wind-stone);
  margin-bottom: 32px;
}

.form-group {
  margin-bottom: 20px;
}

.form-group label {
  display: block;
  font-size: 0.9rem;
  color: var(--wind-stone);
  margin-bottom: 6px;
}

.form-group input[type="text"],
.form-group input[type="password"],
.form-group input[type="email"] {
  width: 100%;
  padding: 12px 14px;
  font-size: 1rem;
  background: var(--wind-white);
  border: 1px solid var(--wind-shore);
  border-radius: 8px;
  color: var(--wind-deep);
  outline: none;
  transition: border-color 0.2s;
}

/* ===== Minimal-mode login (Phase 95-style) =====
   When in magic-link mode, just the input + status messages render — chrome
   (h1, subtitle, label, button text, password toggle link) lives in the DOM
   for E2E parity but is .visually-hidden. Add `?password=1` to /us/ to reach
   the password fallback. */
.login-page--minimal .login-container {
  padding: 60px 24px;
}

.login-page--minimal #magic-form .form-group {
  margin-bottom: 0;
}

.login-page--minimal #magic-form input[type="email"] {
  font-size: 1.1rem;
  padding: 16px 18px;
  text-align: center;
}

.login-page--minimal .error-msg,
.login-page--minimal .success-msg {
  margin-top: 16px;
  font-size: 0.9rem;
  text-align: center;
}

.form-group input:focus {
  border-color: var(--wind-amber);
  box-shadow: 0 0 0 3px var(--wind-amber-light);
}

.checkbox-group label {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 0.9rem;
  color: var(--wind-earth);
  cursor: pointer;
}

.checkbox-group input[type="checkbox"] {
  width: 18px;
  height: 18px;
  accent-color: var(--wind-amber);
}

#submit-btn {
  width: 100%;
  padding: 12px;
  font-size: 1rem;
  font-weight: 600;
  background: var(--wind-amber);
  color: var(--wind-white);
  border: none;
  border-radius: 8px;
  cursor: pointer;
  transition: background 0.2s;
  margin-top: 8px;
}

#submit-btn:hover {
  background: var(--wind-amber-hover);
}

#submit-btn:disabled {
  background: var(--wind-shore);
  color: var(--wind-drift);
  cursor: not-allowed;
}

.error-msg {
  background: var(--wind-red-light);
  border: 1px solid var(--status-danger-stroke);
  color: var(--wind-red);
  padding: 10px 14px;
  border-radius: 8px;
  font-size: 0.9rem;
  margin-bottom: 20px;
}

.success-msg {
  background: var(--status-success-bg);
  border: 1px solid var(--status-success-border);
  color: var(--status-success-text);
  padding: 10px 14px;
  border-radius: 8px;
  font-size: 0.9rem;
  margin-bottom: 20px;
}

.login-toggle {
  text-align: center;
  font-size: 0.9rem;
  margin-top: 16px;
}
.login-toggle a {
  color: var(--wind-amber);
  text-decoration: none;
}
.login-toggle a:hover {
  text-decoration: underline;
}

/* ===== Home page ===== */

/* #117 slice 4: inner-scroll 100dvh shell (mirrors .chat-page/.photos-today-page).
   The body locks to the visual viewport; .home-scroll scrolls; the tab bar is a
   flex child — so the lightbox body-lock can't strand it on iPad (#144). */
.home-page {
  background: var(--wind-sky);
  color: var(--wind-earth);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  height: 100vh;
  height: 100dvh;
}

.home {
  max-width: 640px;
  margin: 0 auto;
  padding: 24px 16px 64px;
}

/* .home-header / .home-header-right deleted Phase 14a — use .page-header. */
.me-avatar-link {
  /* 44pt minimum touch target (Phase 14f follow-up — iPad pass turned up that
     a 36px circle is below Apple's recommended hit-area on touchscreens, which
     is also why the link "didn't open" on touch — Safari's tap-cancel on
     too-small interactive elements). Visual size stays small via the disc;
     padding extends the click box without shifting layout. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: var(--wind-amber);
  color: #fff;
  font-weight: 600;
  font-size: 0.95rem;
  text-decoration: none;
  overflow: hidden;
  border: 1px solid var(--wind-dune);
  cursor: pointer;
  /* Skip the 300ms double-tap-zoom delay on iOS — confirms tap immediately. */
  touch-action: manipulation;
  -webkit-tap-highlight-color: rgba(196, 137, 46, 0.18);
}
.me-avatar-link img { width: 100%; height: 100%; object-fit: cover; }
.me-avatar-link:hover { filter: brightness(0.95); }
.me-avatar-link:active { filter: brightness(0.88); }

.admin-section {
  margin-top: 32px;
  padding-top: 24px;
  border-top: 1px solid var(--wind-dune);
  /* Phase 14h: tables inside admin sections (Users with Email column,
     Active sessions with device strings, etc.) have intrinsic min-content
     wider than narrow viewports. Tables cannot shrink below their content,
     so let the section itself scroll horizontally rather than push the
     page wider. */
  overflow-x: auto;
}

.admin-section h2 {
  font-size: 1rem;
  font-weight: 600;
  color: var(--wind-stone);
  margin-bottom: 12px;
}

.admin-card {
  border: 1px solid var(--wind-dune);
}

/* ===== Admin page tables ===== */
.admin-page .chores-container { max-width: 820px; }
.admin-table {
  width: 100%;
  border-collapse: collapse;
  background: var(--wind-white);
  border: 1px solid var(--wind-dune);
  border-radius: 8px;
  overflow: hidden;
  font-size: 0.9rem;
}
.admin-table thead {
  background: var(--wind-sand);
  color: var(--wind-stone);
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}
.admin-table th,
.admin-table td {
  padding: 10px 12px;
  text-align: left;
  border-bottom: 1px solid var(--wind-dune);
}
.admin-table tr:last-child td { border-bottom: none; }
.admin-table td.empty { color: var(--wind-drift); font-style: italic; text-align: center; }
.admin-table .revoke-btn {
  background: transparent;
  border: 1px solid var(--wind-red);
  color: var(--wind-red);
  font-size: 0.8rem;
  padding: 4px 10px;
  border-radius: 6px;
  cursor: pointer;
}
.admin-table .revoke-btn:hover {
  background: var(--wind-red-light);
}

.admin-form-row {
  display: flex;
  gap: 12px;
  align-items: center;
  flex-wrap: wrap;
  margin-bottom: 16px;
}
.admin-form-row label { font-size: 0.9rem; color: var(--wind-stone); }
.admin-form-row .checkbox-label { display: flex; gap: 6px; align-items: center; }
.admin-form-row select { min-width: 220px; }

.admin-page form#magic-form {
  display: flex;
  gap: 10px;
  align-items: center;
  flex-wrap: wrap;
}
.admin-page form#magic-form label {
  font-size: 0.9rem;
  color: var(--wind-earth);
}
.admin-page form#magic-form select {
  padding: 8px 10px;
  border-radius: 6px;
  border: 1px solid var(--wind-dune);
  background: var(--wind-white);
  font-size: 0.9rem;
}
.admin-page form#magic-form button {
  background: var(--wind-amber);
  color: #fff;
  border: none;
  padding: 8px 14px;
  border-radius: 6px;
  cursor: pointer;
  font-weight: 600;
}
.magic-result {
  margin-top: 14px;
  padding: 12px;
  background: var(--wind-sand);
  border-radius: 8px;
  border: 1px solid var(--wind-dune);
}
.magic-result p { margin: 0 0 8px; font-size: 0.9rem; }
.magic-result .magic-link-value {
  width: 100%;
  padding: 6px 8px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.8rem;
  border: 1px solid var(--wind-dune);
  border-radius: 4px;
  box-sizing: border-box;
}
.magic-result__actions {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 8px;
  flex-wrap: wrap;
}
.magic-result__actions button {
  padding: 6px 12px;
  background: var(--wind-deep);
  color: #fff;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 0.8rem;
}
.magic-result__actions button:hover { filter: brightness(1.1); }
.magic-result__status {
  font-size: 0.8rem;
  color: var(--wind-stone);
  font-style: italic;
}

/* Admin "add memory" form */
#add-memory-form {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 8px 12px;
  align-items: start;
  max-width: 560px;
}
#add-memory-form label {
  font-size: 0.85rem;
  color: var(--wind-earth);
  padding-top: 6px;
}
#add-memory-form select,
#add-memory-form input[type="text"],
#add-memory-form textarea {
  padding: 8px 10px;
  border: 1px solid var(--wind-dune);
  border-radius: 6px;
  background: var(--wind-white);
  font-family: inherit;
  font-size: 0.9rem;
  width: 100%;
  box-sizing: border-box;
}
#add-memory-form textarea { resize: vertical; }
#add-memory-form button {
  grid-column: 2;
  justify-self: start;
  background: var(--wind-amber);
  color: #fff;
  border: none;
  padding: 8px 14px;
  border-radius: 6px;
  cursor: pointer;
  font-weight: 600;
  font-size: 0.9rem;
}

/* ===== Chat page ===== */

.chat-page {
  background: var(--wind-sand);
  color: var(--wind-earth);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  /* Phase 14h-B: lock the chat shell to the visual viewport so iOS Safari's
     keyboard doesn't push the page-header off-screen. `html, body` above sets
     `height: 100%` which on iOS resolves to the LAYOUT viewport (always full
     window — doesn't shrink when keyboard opens). With body at full window
     and the composer as the last flex child, the keyboard covers the
     composer AND scrolls the layout viewport up, hiding the header.
     `100dvh` = small viewport height when keyboard is up, large otherwise —
     it adapts. `100vh` fallback for browsers older than iOS 15.4 / Chrome 108
     (~Mar 2022). The existing flex-column rules above hold the structure:
     header (flex 0), .messages-container (flex 1, internal scroll), composer
     (flex 0), tab-bar (flex 0). All four reposition together as body shrinks. */
  height: 100vh;
  height: 100dvh;
}

/* .chat-header / .chores-header / .chat-nav / .nav-btn deleted Phase 14a — use .page-header + .btn-secondary. */

/* ===== Phase 14a: unified page chrome ===== */

.page-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 16px;
  background: var(--wind-white);
  border-bottom: 1px solid var(--wind-dune);
  flex-shrink: 0;
}

.page-header__titles {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.page-header__eyebrow {
  font-size: 0.7rem;
  font-weight: 500;
  color: var(--wind-stone);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-bottom: 2px;
}

.page-header__title {
  font-family: 'Fraunces', Georgia, serif;
  font-size: 1.4rem;
  font-weight: 500;
  color: var(--wind-deep);
  letter-spacing: -0.01em;
  line-height: 1.15;
  margin: 0;
}

.page-header__menu {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-shrink: 0;
  /* margin-left: auto so the avatar always sits at the far right of the
     header, even on map-header / page-header--map where the flex layout
     doesn't use justify-content: space-between (the map adds floor pills
     and a list-view link in the middle, so we can't anchor the right edge
     via space-between without disrupting them). */
  margin-left: auto;
}

@media (min-width: 1024px) {
  .page-header {
    padding: 16px 24px;
  }
  .page-header__title {
    font-size: 1.6rem;
  }
}

/* Map-specific page header preserved as a modifier — DITL compass rose. */
.page-header--map {
  background: var(--wind-sand);
  border-bottom: 1px solid var(--wind-shore);
  padding: 16px 20px;
}

/* ===== Phase 14a: native <dialog> primitive ===== */

.dialog-base {
  border: none;
  border-radius: 12px;
  padding: 1.5rem;
  max-width: 520px;
  width: 90%;
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.18);
  color: var(--wind-earth);
  background: var(--wind-white);
}

.dialog-base::backdrop {
  background: rgba(20, 16, 12, 0.4);
}

.dialog-base form {
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
}

.dialog-base h2 {
  font-family: 'Fraunces', Georgia, serif;
  font-weight: 500;
  font-size: 1.4rem;
  color: var(--wind-deep);
  letter-spacing: -0.01em;
  margin: 0 0 0.5rem;
}

.dialog-base label {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  font-size: 0.85rem;
  color: var(--wind-earth);
}

.dialog-base input,
.dialog-base select,
.dialog-base textarea {
  font: inherit;
  padding: 0.5rem;
  border: 1px solid var(--wind-dune);
  border-radius: 6px;
  background: var(--wind-white);
  color: var(--wind-earth);
}

.dialog-base textarea {
  resize: vertical;
  min-height: 60px;
}

.dialog-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.5rem;
  margin-top: 0.5rem;
}

/* Wraps an <input> + sibling clear button on one row.
   Needed because iOS Safari <input type="date"> has no native clear control. */
.input-with-clear {
  display: flex;
  gap: 0.5rem;
  align-items: stretch;
}
.input-with-clear > input { flex: 1; }
.input-with-clear > .btn-secondary { min-height: auto; padding: 0.4rem 0.75rem; }

.dialog-close-btn {
  background: transparent;
  border: none;
  font-size: 1.4rem;
  line-height: 1;
  padding: 0.2rem 0.5rem;
  cursor: pointer;
  color: var(--wind-stone);
  border-radius: 4px;
}

.dialog-close-btn:hover {
  color: var(--wind-deep);
  background: var(--wind-sand);
}

/* ===== Phase 14a: floating action button + agent popover ===== */

.fab {
  position: fixed;
  width: 3.6rem;
  height: 3.6rem;
  border-radius: 999px;
  border: none;
  cursor: pointer;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.18);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: 'Fraunces', Georgia, serif;
  font-size: 1.4rem;
  z-index: 100;
  transition: transform 150ms cubic-bezier(0.2, 0.7, 0.2, 1), box-shadow 150ms;
}

.fab:hover {
  transform: translateY(-1px);
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.22);
}

.fab--agent {
  background: var(--agent-tint, var(--sea-deep, var(--wind-deep)));
  color: white;
}

/* Phase 10-IA Slice 1: bottom-right anchor for the agent FAB on admin
   financial pages (DICE / billpay / lending / financial). Bottom offset
   clears the fixed tab-bar (.has-tab-bar adds 64px padding-bottom; FAB
   sits 88px from the viewport edge to leave a comfortable gap). */
.fab--agent-br {
  right: 16px;
  bottom: 88px;
}
@media (min-width: 1024px) {
  .fab--agent-br {
    right: 24px;
    bottom: 96px;
  }
}

/* Phase 10-IA Slice 1: sub-page rail on /us/dice glance — cards linking to
   admin financial sub-pages (billpay, lending, family cash-flow). Reuses
   the .topic-group / .home-card visual register. */
.sub-page-rail {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.75rem;
  margin: 0.75rem 0 1.25rem;
}
@media (min-width: 700px) {
  .sub-page-rail { grid-template-columns: repeat(3, 1fr); }
}
.sub-page-rail__card {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  padding: 0.85rem 1rem;
  background: var(--wind-white);
  border: 1px solid var(--wind-dune);
  border-radius: 10px;
  text-decoration: none;
  color: var(--wind-deep);
  transition: border-color 150ms, box-shadow 150ms, transform 150ms;
}
.sub-page-rail__card:hover,
.sub-page-rail__card:focus-visible {
  border-color: var(--sea-deep, var(--wind-stone));
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.06);
  transform: translateY(-1px);
  outline: none;
}
.sub-page-rail__title {
  font-family: 'Fraunces', Georgia, serif;
  font-size: 1.05rem;
  font-weight: 500;
}
.sub-page-rail__hint {
  font-size: 0.8rem;
  color: var(--wind-stone);
}

/* Agent popover (Hestia + Metis share this — was metis-popover-*). */
.agent-popover {
  border: none;
  border-radius: 12px;
  padding: 0;
  max-width: 520px;
  width: 95%;
  max-height: 80vh;
  max-height: 80dvh;  /* #117 slice 1: shrink with the iOS keyboard */
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.25);
  background: var(--wind-white);
}

.agent-popover::backdrop {
  background: rgba(20, 16, 12, 0.4);
}

.agent-popover__inner {
  display: flex;
  flex-direction: column;
  height: 70vh;
  /* #117 slice 1: dvh so the popover (header / thread / composer) shrinks with
     the iOS keyboard instead of leaving the composer hidden below it. */
  height: 70dvh;
}

.agent-popover__header {
  padding: 0.85rem 1.25rem;
  border-bottom: 1px solid var(--wind-dune);
  display: flex;
  align-items: center;
  gap: 0.75rem;
  background: var(--sea-mist, var(--wind-sand));
  border-radius: 12px 12px 0 0;
}

.agent-popover__title {
  font-family: 'Fraunces', Georgia, serif;
  font-size: 1.2rem;
  flex: 1;
  color: var(--wind-deep);
}

.agent-popover__thread {
  flex: 1;
  overflow-y: auto;
  padding: 1rem 1.25rem;
}

.agent-popover__form {
  border-top: 1px solid var(--wind-dune);
  padding: 0.75rem 1rem;
  display: flex;
  gap: 0.5rem;
  align-items: end;
}

.agent-popover__input {
  flex: 1;
  resize: none;
  padding: 0.5rem;
  border: 1px solid var(--wind-dune);
  border-radius: 6px;
  font: inherit;
}

/* ===== Phase 14d: agent strip (sticky-top headline interaction) =====
   Replaces the floating .fab pattern on dashboard surfaces (/us/minx, /us/ditl)
   so the agent input is always reachable in zero scroll. Tap the avatar to
   expand into the full-thread .agent-popover dialog. */

.agent-strip {
  position: sticky;
  top: 0;
  z-index: 5;
  background: var(--sea-mist, var(--wind-sand));
  border-bottom: 1px solid var(--wind-dune);
  padding: 0.65rem 1rem;
  display: flex;
  align-items: center;
  gap: 0.65rem;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
  margin-bottom: 0.75rem;
}

.agent-strip__expand {
  width: 2.4rem;
  height: 2.4rem;
  border-radius: 999px;
  background: var(--agent-tint, var(--sea-deep, var(--wind-deep)));
  color: white;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: 'Fraunces', Georgia, serif;
  font-size: 1.2rem;
  font-weight: 500;
  border: none;
  cursor: pointer;
  flex-shrink: 0;
  transition: transform 150ms cubic-bezier(0.2, 0.7, 0.2, 1), box-shadow 150ms;
  padding: 0;
}

.agent-strip__expand:hover,
.agent-strip__expand:focus-visible {
  transform: scale(1.05);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  outline: none;
}

.agent-strip__form {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex: 1;
  min-width: 0;
  margin: 0;
}

.agent-strip__input {
  flex: 1;
  min-width: 0;
  resize: none;
  padding: 0.55rem 0.75rem;
  border: 1px solid var(--wind-dune);
  border-radius: 8px;
  background: var(--wind-white);
  font: inherit;
  font-size: 0.95rem;
  min-height: 2.4rem;
  max-height: 5rem;
  color: var(--wind-earth);
}

.agent-strip__input:focus-visible {
  outline: 2px solid var(--agent-tint, var(--wind-amber));
  outline-offset: 1px;
  border-color: var(--agent-tint, var(--wind-amber));
}

.agent-strip__send {
  flex-shrink: 0;
}

@media (max-width: 743px) {
  .agent-strip {
    flex-wrap: wrap;
  }
  .agent-strip__form {
    flex: 1 1 100%;
    order: 3;
    margin-top: 0.5rem;
  }
}

.messages-container {
  flex: 1;
  overflow-y: auto;
  padding: 16px;
  display: flex;
  flex-direction: column;
}

#message-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  flex: 1;
  justify-content: flex-end;
}

.message {
  max-width: 80%;
  display: flex;
  align-items: flex-start;
  gap: 8px;
  animation: none;
}
.message .msg-avatar {
  margin-top: 2px;
  width: 32px;
  height: 32px;
}
.message .msg-bubble-wrap {
  flex: 1;
  padding: 8px 12px;
  background: var(--wind-white);
  border-radius: 12px;
  box-shadow: 0 1px 2px rgba(90, 80, 65, 0.06);
  min-width: 0;
}

.message.mine {
  align-self: flex-end;
  flex-direction: row-reverse;
}
.message.mine .msg-bubble-wrap {
  background: var(--wind-mine-bubble);
}

.message.msg-new {
  animation: fadeIn 0.2s ease-in;
}

/* Figure bubble — historical voice (Phase 6a). Distinct parchment treatment
   so a kid instantly sees "this isn't Notus" without reading the name. */
.message.figure-bubble .msg-body {
  background: var(--paper-bg);
  border: 1px solid var(--paper-border);
  border-radius: 10px;
  padding: 10px 14px;
  color: var(--paper-text);
  font-family: Georgia, 'Times New Roman', serif;
  box-shadow: 0 2px 6px rgba(120, 90, 50, 0.10);
}
.message.figure-bubble .msg-name {
  color: var(--paper-accent) !important;
  font-variant: small-caps;
  letter-spacing: 0.05em;
  font-weight: 700;
}

/* Homeschool file library (Phase 6c) */
.files-filters {
  display: flex;
  gap: 16px;
  align-items: center;
  margin-bottom: 16px;
  flex-wrap: wrap;
}
.files-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 12px;
}
.file-card {
  background: var(--wind-white);
  border: 1px solid var(--wind-dune);
  border-radius: 10px;
  padding: 14px 16px;
  display: block;
  text-decoration: none;
  color: var(--wind-deep);
  position: relative;
  transition: box-shadow 0.15s ease;
}
.file-card:hover { box-shadow: 0 4px 12px rgba(90, 80, 65, 0.08); }
.file-card.archived { opacity: 0.6; }
.file-kind-badge {
  display: inline-block;
  background: var(--wind-sand);
  color: var(--wind-earth);
  border-radius: 4px;
  padding: 2px 8px;
  font-size: 0.75rem;
  margin-bottom: 8px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}
.file-title {
  font-size: 1rem;
  font-weight: 600;
  margin-bottom: 6px;
  line-height: 1.3;
}
.file-meta {
  display: flex;
  gap: 8px;
  font-size: 0.8rem;
  color: var(--wind-drift);
  flex-wrap: wrap;
}
.file-admin-actions {
  margin-top: 10px;
  display: flex;
  gap: 10px;
}
.file-body {
  max-width: 720px;
  margin: 0 auto;
  padding: 24px;
  background: var(--wind-white);
  border-radius: 10px;
  border: 1px solid var(--wind-dune);
  line-height: 1.6;
}
.file-body h1, .file-body h2, .file-body h3 {
  color: var(--wind-deep);
  margin-top: 1.2em;
}
.file-body h1 { page-break-after: avoid; }
.file-body table { border-collapse: collapse; margin: 12px 0; }
.file-body th, .file-body td {
  border: 1px solid var(--wind-dune);
  padding: 6px 10px;
  text-align: left;
}
.file-body pre {
  background: var(--wind-sand);
  padding: 12px;
  border-radius: 6px;
  overflow-x: auto;
  page-break-inside: avoid;
}
.file-body code {
  background: var(--wind-sand);
  padding: 2px 6px;
  border-radius: 4px;
  font-size: 0.9em;
}
.file-body pre code { background: none; padding: 0; }
.file-body ul, .file-body ol { margin: 8px 0 12px; padding-left: 24px; }
.file-body blockquote {
  border-left: 3px solid var(--wind-dune);
  margin: 12px 0;
  padding: 4px 12px;
  color: var(--wind-earth);
  font-style: italic;
}
.file-empty, .file-loading {
  text-align: center;
  padding: 40px;
  color: var(--wind-drift);
}

/* Sheet music (Phase 6d) — server-rendered SVG from abcjs */
.sheet-music, .sheet-music-inline {
  background: #fff;
  padding: 12px;
  border-radius: 6px;
  border: 1px solid var(--wind-dune);
  margin: 8px 0;
}
.sheet-music-svg svg,
.sheet-music-inline svg {
  width: 100%;
  height: auto;
  display: block;
  max-width: 100%;
}
.sheet-music-inline { max-height: 50vh; overflow-y: auto; }
.sheet-music-abc { margin-top: 16px; font-size: 0.9rem; color: var(--wind-earth); }
.sheet-music-abc summary { cursor: pointer; color: var(--wind-drift); padding: 6px 0; }
.sheet-music-abc pre { background: var(--wind-sand); padding: 10px; border-radius: 6px; overflow-x: auto; font-size: 0.85rem; }
@media print { .sheet-music-abc { display: none; } }

/* Notus chat: file pill rendered in reply when Notus includes a /us/homeschool/files/... URL */
.file-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--wind-sand);
  border: 1px solid var(--wind-dune);
  border-radius: 999px;
  padding: 4px 12px;
  color: var(--wind-deep);
  text-decoration: none;
  font-size: 0.9rem;
  margin: 2px 0;
}
.file-pill:hover { background: var(--wind-dune); }

/* Homeschool — curriculum tracker (Phase 6b) */
.homeschool-toolbar {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 16px;
  flex-wrap: wrap;
}
.subject-pills {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  flex: 1;
}
.subject-pills .pill {
  background: var(--wind-white);
  border: 1px solid var(--wind-dune);
  color: var(--wind-earth);
  padding: 6px 12px;
  border-radius: 999px;
  font-size: 0.85rem;
  cursor: pointer;
}
.subject-pills .pill.active {
  background: var(--wind-amber);
  color: white;
  border-color: var(--wind-amber);
}
.topics-groups {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.topic-group {
  background: var(--wind-white);
  border: 1px solid var(--wind-dune);
  border-radius: 10px;
  padding: 4px 14px;
}
.topic-group summary {
  font-weight: 600;
  padding: 10px 0;
  cursor: pointer;
  color: var(--wind-deep);
}
.topic-group summary .count {
  color: var(--wind-drift);
  font-weight: 400;
}
.topic-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 4px 0 12px;
}
.topic-card {
  background: var(--wind-sand);
  border-radius: 8px;
  padding: 10px 14px;
  border: 1px solid var(--wind-dune);
}
.topic-head {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  font-size: 0.82rem;
  color: var(--wind-drift);
  margin-bottom: 4px;
}
.topic-subject { font-weight: 600; color: var(--wind-earth); }
.topic-title {
  font-size: 1rem;
  font-weight: 600;
  color: var(--wind-deep);
  margin-bottom: 4px;
}
.topic-meta {
  font-size: 0.85rem;
  color: var(--wind-drift);
  margin-bottom: 6px;
}
.topic-actions {
  display: flex;
  gap: 14px;
  flex-wrap: wrap;
  font-size: 0.85rem;
}
.hint-inline {
  color: var(--wind-drift);
  font-weight: 400;
  font-size: 0.85em;
}
.error-msg {
  color: var(--wind-red);
  font-size: 0.9rem;
  margin-top: 8px;
}

/* Admin recent-figure-turns panel */
.figure-turns-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.figure-turn {
  background: var(--paper-bg);
  border: 1px solid var(--paper-border);
  border-radius: 8px;
  padding: 10px 14px;
  font-size: 0.9rem;
}
.figure-turn-head {
  margin-bottom: 6px;
}
.figure-turn-name {
  color: var(--paper-accent);
  font-variant: small-caps;
  letter-spacing: 0.05em;
  font-weight: 700;
}
.figure-turn-body {
  color: var(--paper-text);
  font-family: Georgia, 'Times New Roman', serif;
  line-height: 1.45;
  white-space: pre-wrap;
}

@keyframes fadeIn {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: translateY(0); }
}

@keyframes gentleBreeze {
  0%, 100% { opacity: 0.5; }
  50% { opacity: 1; }
}

.msg-header {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin-bottom: 4px;
}

.msg-name {
  font-size: 0.8rem;
  font-weight: 600;
}

.msg-time {
  font-size: 0.7rem;
  color: var(--wind-drift);
}

.msg-body {
  font-size: 0.95rem;
  line-height: 1.45;
  color: var(--wind-deep);
  white-space: pre-wrap;
  word-break: break-word;
}
.msg-body p {
  margin: 0 0 0.6em;
}
.msg-body p:last-child {
  margin-bottom: 0;
}
.msg-body strong {
  font-weight: 600;
  color: var(--wind-deeper, var(--wind-deep));
}
.msg-body em {
  font-style: italic;
}
.msg-body code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.88em;
  background: rgba(0,0,0,0.05);
  padding: 1px 5px;
  border-radius: 4px;
}
.msg-body pre {
  background: rgba(0,0,0,0.05);
  padding: 10px 12px;
  border-radius: 6px;
  overflow-x: auto;
  margin: 0.4em 0;
}
.msg-body pre code {
  background: none;
  padding: 0;
  font-size: 0.85em;
}

.msg-image {
  max-width: 280px;
  max-height: 280px;
  border-radius: 8px;
  margin-top: 4px;
  cursor: pointer;
}

.typing-indicator {
  font-size: 0.8rem;
  color: var(--wind-drift);
  padding: 4px 0;
  font-style: italic;
  animation: gentleBreeze 2.5s ease-in-out infinite;
}

.load-more {
  text-align: center;
  padding: 12px;
}

.load-more button {
  background: var(--wind-white);
  color: var(--wind-stone);
  border: 1px solid var(--wind-shore);
  border-radius: 8px;
  padding: 8px 16px;
  font-size: 0.85rem;
  cursor: pointer;
  transition: background 0.15s;
}

.load-more button:hover {
  background: var(--wind-dune);
}

.chat-input-area {
  display: flex;
  align-items: flex-end;
  gap: 8px;
  padding: 12px 16px;
  background: var(--wind-white);
  border-top: 1px solid var(--wind-dune);
  flex-shrink: 0;
}

.chat-input-area textarea {
  flex: 1;
  background: var(--wind-sky);
  border: 1px solid var(--wind-shore);
  border-radius: 20px;
  padding: 10px 16px;
  font-size: 1rem;
  color: var(--wind-deep);
  resize: none;
  outline: none;
  max-height: 120px;
  line-height: 1.4;
  font-family: inherit;
}

.chat-input-area textarea:focus {
  border-color: var(--wind-amber);
  box-shadow: 0 0 0 3px var(--wind-amber-light);
}

.attach-btn,
.send-btn {
  background: none;
  border: none;
  color: var(--wind-drift);
  cursor: pointer;
  padding: 8px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  transition: background 0.15s, color 0.15s;
}

.send-btn {
  color: var(--wind-amber);
}

.send-btn:disabled {
  color: var(--wind-shore);
  cursor: default;
}

.attach-btn:hover,
.send-btn:hover:not(:disabled) {
  background: var(--wind-sand);
}

/* ===== Push notification prompt ===== */

.push-prompt {
  position: fixed;
  bottom: 80px;
  left: 50%;
  transform: translateX(-50%);
  background: var(--wind-white);
  border: 1px solid var(--wind-dune);
  border-radius: 12px;
  padding: 12px 20px;
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: 0.9rem;
  color: var(--wind-earth);
  z-index: 1000;
  box-shadow: 0 4px 20px rgba(90, 80, 65, 0.15);
}

.push-prompt button {
  padding: 6px 14px;
  border-radius: 6px;
  border: none;
  cursor: pointer;
  font-size: 0.85rem;
}

#push-yes {
  background: var(--wind-amber);
  color: var(--wind-white);
}

#push-no {
  background: var(--wind-sand);
  color: var(--wind-stone);
}

/* ===== Chores page ===== */

.chores-page {
  background: var(--wind-sky);
  color: var(--wind-earth);
  overflow-y: auto;
  min-height: 100vh;
}

.chores-container {
  max-width: 640px;
  margin: 0 auto;
  padding: 16px;
}

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

.chore-card {
  background: var(--wind-white);
  border-radius: 12px;
  padding: 16px;
  box-shadow: var(--shadow-card);
}

.chore-card.status-pending {
  border-left: 3px solid var(--wind-amber);
}

.chore-card.status-done {
  border-left: 3px solid var(--wind-sunset);
}

.chore-card.status-verified {
  border-left: 3px solid var(--wind-green);
}

.chore-card.status-rejected {
  border-left: 3px solid var(--wind-red);
}

.chore-card.review {
  border-left: 3px solid var(--wind-sunset);
}

.chore-card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 8px;
}

.chore-card-header h3 {
  font-size: 1rem;
  font-weight: 600;
  color: var(--wind-deep);
}

.chore-status {
  font-size: 0.75rem;
  color: var(--wind-stone);
  background: var(--wind-sand);
  padding: 2px 8px;
  border-radius: 4px;
}

.chore-badge {
  font-size: 0.75rem;
  color: var(--wind-stone);
}

.chore-desc {
  font-size: 0.9rem;
  color: var(--wind-earth);
  margin-bottom: 8px;
  line-height: 1.4;
}

.chore-meta {
  display: flex;
  gap: 16px;
  font-size: 0.8rem;
  color: var(--wind-drift);
}

.chore-user {
  font-size: 0.85rem;
  font-weight: 600;
}

.admin-note {
  font-size: 0.85rem;
  color: var(--wind-sunset);
  margin-top: 8px;
  font-style: italic;
}

.btn-complete {
  margin-top: 12px;
  width: 100%;
  padding: 10px;
  font-size: 0.95rem;
  font-weight: 600;
  background: var(--wind-green);
  color: var(--wind-white);
  border: none;
  border-radius: 8px;
  cursor: pointer;
  transition: background 0.15s;
}

.btn-complete:hover {
  filter: brightness(0.95);
}

/* ===== Phase 14a: canonical button family =====
   Source of truth: replaces the older .btn-primary/.btn-secondary
   (full-width chores style) and the parallel .primary-btn/.secondary-btn
   inline pattern. .btn-block carries forward the full-width affordance
   for forms that need it (e.g. chores create form). */

.btn-primary,
.btn-secondary,
.btn-danger {
  min-height: 44px;
  padding: 0.5rem 1rem;
  border-radius: 6px;
  font: inherit;
  font-weight: 500;
  cursor: pointer;
  border: 1px solid transparent;
  transition: filter 0.15s, background 0.15s, box-shadow 0.15s;
}

.btn-primary {
  background: var(--wind-amber);
  color: var(--wind-on-amber);
  border-color: var(--wind-amber-deep);
}

.btn-primary:hover:not([disabled]) { filter: brightness(0.95); }
.btn-primary[disabled] { opacity: 0.5; cursor: not-allowed; }

.btn-secondary {
  background: var(--wind-white);
  color: var(--wind-deep);
  border-color: var(--wind-dune);
}

.btn-secondary:hover { background: var(--wind-cream, var(--wind-sand)); }

/* Segment toggle active state — used by .debt-tab on /us/dice/debt.
   Filled amber when selected so the active segment is unambiguous; without
   this rule the .active class on .debt-tab buttons does nothing. */
.btn-secondary.active,
.btn-secondary[aria-selected="true"] {
  background: var(--wind-amber);
  color: var(--wind-white);
  border-color: var(--wind-amber);
}
.btn-secondary.active:hover,
.btn-secondary[aria-selected="true"]:hover {
  background: var(--wind-amber-hover);
  border-color: var(--wind-amber-hover);
}

/* /us/dice/debt tab group — reads more clearly as a "Show:" filter than the
   prior two-independent-buttons treatment. Per James 2026-05-23: "I did not
   see that as a filter." Containing the buttons inside a labelled pill-group
   gives them tab-of-a-set affordance instead of standalone-CTA affordance. */
.debt-tab-group {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}
.debt-tab-label {
  font-size: 0.85rem;
  color: var(--wind-stone);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 600;
}
.debt-tab-pills {
  display: inline-flex;
  border: 1px solid var(--border-soft);
  border-radius: 8px;
  overflow: hidden;
  background: var(--surface-subtle);
}
.debt-tab-pills .debt-tab {
  background: transparent;
  border: 0;
  border-radius: 0;
  padding: 6px 14px;
  cursor: pointer;
  color: var(--wind-stone);
  font-weight: 500;
  font-family: inherit;
  font-size: 0.95rem;
  transition: background 0.1s, color 0.1s;
}
.debt-tab-pills .debt-tab + .debt-tab {
  border-left: 1px solid var(--border-soft);
}
.debt-tab-pills .debt-tab:hover {
  background: var(--wind-amber-light);
  color: var(--wind-amber);
}
.debt-tab-pills .debt-tab.active,
.debt-tab-pills .debt-tab[aria-selected="true"] {
  background: var(--wind-amber);
  color: var(--wind-white);
  border-color: transparent;
}
.debt-tab-pills .debt-tab.active:hover,
.debt-tab-pills .debt-tab[aria-selected="true"]:hover {
  background: var(--wind-amber-hover);
  color: var(--wind-white);
}

.btn-danger {
  background: var(--wind-white);
  color: var(--status-danger-text);
  border-color: var(--status-danger-border);
}

.btn-danger:hover { background: var(--status-danger-bg); }

.btn-primary:focus-visible,
.btn-secondary:focus-visible,
.btn-danger:focus-visible {
  outline: 2px solid var(--wind-amber);
  outline-offset: 2px;
}

/* Full-width modifier — used by the chores Create Chore form. */
.btn-block {
  width: 100%;
  padding: 12px;
  font-size: 1rem;
  font-weight: 600;
  margin-top: 12px;
  border-radius: 8px;
  min-height: auto;
}

/* Admin tabs */
.admin-tabs {
  display: flex;
  gap: 4px;
  margin-bottom: 16px;
  overflow-x: auto;
}

.tab-btn {
  padding: 8px 16px;
  font-size: 0.85rem;
  font-weight: 500;
  background: var(--wind-white);
  color: var(--wind-stone);
  border: 1px solid var(--wind-dune);
  border-radius: 8px;
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.15s;
}

.tab-btn.active {
  background: var(--wind-amber);
  color: var(--wind-white);
  border-color: var(--wind-amber);
}

.tab-content {
  display: none;
}

.tab-content.active {
  display: block;
}

/* Chore create form */
.chore-form {
  background: var(--wind-white);
  border-radius: 12px;
  padding: 20px;
  box-shadow: var(--shadow-card);
}

.chore-form label {
  display: block;
  font-size: 0.9rem;
  color: var(--wind-stone);
  margin-bottom: 16px;
}

.chore-form input[type="text"],
.chore-form input[type="number"],
.chore-form input[type="date"],
.chore-form textarea,
.chore-form select {
  display: block;
  width: 100%;
  margin-top: 4px;
  padding: 10px 12px;
  font-size: 0.95rem;
  background: var(--wind-sky);
  border: 1px solid var(--wind-shore);
  border-radius: 8px;
  color: var(--wind-deep);
  outline: none;
  font-family: inherit;
}

.chore-form input:focus,
.chore-form textarea:focus,
.chore-form select:focus {
  border-color: var(--wind-amber);
  box-shadow: 0 0 0 3px var(--wind-amber-light);
}

.chore-form fieldset {
  border: 1px solid var(--wind-shore);
  border-radius: 8px;
  padding: 12px;
  margin-bottom: 16px;
}

.chore-form fieldset legend {
  font-size: 0.9rem;
  color: var(--wind-stone);
  padding: 0 8px;
}

.chore-form fieldset label {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 8px;
  color: var(--wind-earth);
}

.chore-form fieldset input[type="checkbox"] {
  width: 18px;
  height: 18px;
  accent-color: var(--wind-amber);
}

#custom-days {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 12px;
  margin-bottom: 16px;
  padding: 8px 12px;
}

#custom-days label {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: 0.85rem;
  color: var(--wind-earth);
  margin-bottom: 0;
}

.form-msg {
  margin-top: 12px;
  padding: 8px 12px;
  border-radius: 8px;
  font-size: 0.85rem;
}

.form-msg.error {
  background: var(--wind-red-light);
  color: var(--wind-red);
}

.form-msg.success {
  background: var(--wind-green-light);
  color: var(--wind-green);
}

/* Review actions */
.review-actions {
  display: flex;
  gap: 8px;
  align-items: center;
  margin-top: 12px;
}

.review-note {
  flex: 1;
  padding: 8px 12px;
  font-size: 0.85rem;
  background: var(--wind-sky);
  border: 1px solid var(--wind-shore);
  border-radius: 8px;
  color: var(--wind-deep);
  outline: none;
}

.btn-approve {
  padding: 8px 16px;
  font-size: 0.85rem;
  font-weight: 600;
  background: var(--wind-green);
  color: var(--wind-white);
  border: none;
  border-radius: 8px;
  cursor: pointer;
}

.btn-reject {
  padding: 8px 16px;
  font-size: 0.85rem;
  font-weight: 600;
  background: var(--wind-red);
  color: var(--wind-white);
  border: none;
  border-radius: 8px;
  cursor: pointer;
}

/* Points table */
.points-table {
  width: 100%;
  border-collapse: collapse;
  margin-top: 12px;
}

.points-table th,
.points-table td {
  padding: 10px 12px;
  text-align: left;
  font-size: 0.9rem;
}

.points-table th {
  color: var(--wind-stone);
  border-bottom: 1px solid var(--wind-dune);
  font-weight: 500;
}

.points-table td {
  color: var(--wind-earth);
  border-bottom: 1px solid var(--wind-sand);
}

.empty-msg {
  color: var(--wind-drift);
  font-size: 0.95rem;
  text-align: center;
  padding: 32px 16px;
}

/* ===== Bottom tab bar ===== */
.tab-bar {
  display: flex;
  align-items: stretch;
  justify-content: space-around;
  background: var(--wind-white);
  border-top: 1px solid var(--wind-dune);
  box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.04);
  padding-bottom: env(safe-area-inset-bottom);
  z-index: 50;
}

/* On scrollable pages, fix the tab bar to the viewport bottom */
body.has-tab-bar:not(.chat-page):not(.app-shell) {
  padding-bottom: calc(64px + env(safe-area-inset-bottom));
  /* scroll-padding so scrollIntoView / anchor jumps clear the fixed bar — fixes #31 */
  scroll-padding-bottom: calc(64px + env(safe-area-inset-bottom));
}

/* #31 v3: scroll-padding-bottom + scroll-margin-bottom both ignored by
   Playwright's scrollIntoViewIfNeeded under our chores-page overflow setup.
   Workaround that actually works: forms in tab-bar pages get 80px of bottom
   padding so the last button (typically a submit) sits 80px above the form
   end — clear of the fixed tab bar regardless of scroll position. */
body.has-tab-bar:not(.chat-page):not(.app-shell) form {
  padding-bottom: calc(80px + env(safe-area-inset-bottom));
}
body.has-tab-bar:not(.chat-page):not(.app-shell) .modal form,
body.has-tab-bar:not(.chat-page):not(.app-shell) dialog form {
  padding-bottom: 0;
}
body.has-tab-bar:not(.chat-page):not(.app-shell) .tab-bar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  /* #144: iOS Safari defers re-rasterizing position:fixed elements during a
     momentum-scroll gesture, so the bar appears to drift upward off the
     bottom edge mid-scroll and snaps back when scrolling stops (Erin, iPad,
     /us/photos). Promoting the bar to its own GPU compositor layer keeps it
     pinned during the gesture. translateZ(0) does NOT change the element's own
     fixed positioning — a transform on the fixed element itself still resolves
     `bottom: 0` against the viewport (only a transform on an *ancestor* would
     capture it). The definitive cure is the inner-scroll 100dvh shell (#117),
     deferred here because it collides with the lightbox body-scroll-lock
     (photo-lightbox.js) and needs on-device verification. */
  transform: translateZ(0);
  -webkit-transform: translateZ(0);
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
}

/* On inner-scroll flex-column shells (chat/notus via .chat-page; the #117
   .app-shell opt-in pages — photos-today/favorites), the tab bar is a normal
   flex child pinned at the column bottom. No position:fixed → no GPU layer to
   strand → the #144 iPad strand is structurally impossible here. Its own
   unconditional `padding-bottom: env(safe-area-inset-bottom)` (.tab-bar above)
   still clears the home indicator. */
body.chat-page.has-tab-bar .tab-bar,
body.app-shell.has-tab-bar .tab-bar {
  flex-shrink: 0;
}

.tab-bar .tab {
  flex: 1;
  position: relative; /* Phase 10-IA Slice 2: anchors .tab-badge */
  /* Phase 14h: required so flex children (.tab-label) cannot push the tab
     wider than its 1fr share. Without this, admin's 10-tab nav at 390px
     phone width overflows the viewport because labels like "Calendar" are
     intrinsically wider than ~39px. */
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  padding: 8px 4px 6px;
  text-decoration: none;
  color: var(--wind-drift);
  font-size: 0.72rem;
  font-weight: 500;
  border-top: 2px solid transparent;
  transition: color 0.15s ease, border-color 0.15s ease;
  -webkit-tap-highlight-color: transparent;
}

.tab-bar .tab:hover {
  color: var(--wind-earth);
}

.tab-bar .tab.active {
  color: var(--wind-amber);
  border-top-color: var(--wind-amber);
}

/* Phase 10-IA Slice 2: per-tab count badge (e.g. DICE inbox has N items).
   Sits top-right of the tab; small pill with high-contrast accent. */
.tab-bar .tab-badge {
  position: absolute;
  top: 4px;
  right: 4px;
  min-width: 1.1rem;
  height: 1.1rem;
  padding: 0 0.35rem;
  border-radius: 999px;
  background: var(--wind-amber, #C4892E);
  color: var(--wind-white, #fff);
  font-size: 0.66rem;
  font-weight: 600;
  line-height: 1.1rem;
  text-align: center;
  pointer-events: none;
}

.tab-bar .tab-icon {
  font-size: 1.35rem;
  line-height: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.tab-bar .tab-icon svg {
  width: 22px;
  height: 22px;
  color: currentColor;
}

.tab-bar .tab-label {
  font-size: 0.7rem;
  letter-spacing: 0.01em;
  /* Phase 14h: truncate if container is narrower than the label. Pairs
     with min-width: 0 on .tab so very-narrow viewports (e.g. phone with
     all 10 admin tabs visible) clip rather than overflow the viewport. */
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* #76 P2-8 — two-column form row for grouping related inputs (e.g. Source +
   Amount in the Bill Pay composer modal) so the modal compresses vertically
   instead of stacking every field. Each column auto-sizes label + input as
   block children; the row stacks under 480px to stay readable on phones. */
.form-row {
  display: flex;
  gap: 12px;
  align-items: flex-start;
}
.form-row__col {
  flex: 1;
  min-width: 0;
}
@media (max-width: 480px) {
  .form-row { flex-direction: column; gap: 0; }
}

/* #78 — Bill Pay recipient cards as <details>/<summary>. Default collapsed
   to a single-row chip showing display name + category badge + archived
   badge + chevron; expanding reveals address + account_number + sync
   timestamp + Edit/Archive buttons. Native <details> gets keyboard +
   accessibility for free; toggle event in billpay.js persists open state
   across data-refresh re-renders. Closes 81-recipient wall-of-text. */
.recipient-row {
  border: 1px solid var(--border-soft);
  border-radius: 8px;
  margin-bottom: 6px;
  background: var(--wind-white);
}
.recipient-row > summary.recipient-summary {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 14px;
  cursor: pointer;
  list-style: none;
  user-select: none;
}
.recipient-row > summary.recipient-summary::-webkit-details-marker {
  display: none;
}
.recipient-row > summary.recipient-summary > strong {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.recipient-row .recipient-chevron {
  display: inline-block;
  font-size: 1.2rem;
  color: var(--wind-stone);
  transition: transform 0.15s ease;
  margin-left: auto;
}
.recipient-row[open] .recipient-chevron {
  transform: rotate(90deg);
}
.recipient-row > summary.recipient-summary:hover {
  background: var(--wind-sand);
}
.recipient-row[open] > summary.recipient-summary {
  border-bottom: 1px solid var(--border-soft);
}
.recipient-row .recipient-body {
  padding: 10px 14px 12px;
}
.recipient-row .badge {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 0.72rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  background: var(--wind-sand);
  color: var(--wind-earth);
  vertical-align: middle;
}
.recipient-row .badge-category {
  background: var(--wind-amber-light);
  color: var(--wind-deep);
}
.recipient-row .badge-canceled {
  background: var(--wind-dune);
  color: var(--wind-stone);
}

/* .lending-row — shared card primitive for stacked-list rows on
   /us/dice/billpay (Scheduled, Recent activity) + /us/dice/lending (loans).
   Mirrors .recipient-row above so the two list types sit visually consistent
   on the billpay page. Without this rule, .lending-row had no border, padding,
   or gap and three+ rows collapsed into a wall of text. */
.lending-row {
  border: 1px solid var(--border-soft);
  border-radius: 8px;
  padding: 10px 14px;
  margin-bottom: 6px;
  background: var(--wind-white);
}
/* Recipient rows compose .lending-row + .recipient-row on the same <details>;
   their summary + body already pad themselves, so drop the parent padding. */
.lending-row.recipient-row { padding: 0; }
.lending-row-header {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.lending-row-body {
  margin-top: 0.35rem;
  color: var(--wind-stone);
  font-size: 0.9rem;
}
.lending-row-actions {
  margin-top: 0.6rem;
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}

/* Phase 7d Slice C1 — Photos of the Day section on /us/home.
   Year-grouped grid; native <dialog> for full-resolution viewing. Lives
   below the 2-col home grid, above the utility row. iPad-mini-first sizing:
   thumbnails are 1fr in a 3-col grid at narrow viewports, expanding to 5-col
   at ≥720px. Aspect-ratio preserved via padding-bottom on a wrapper would be
   prettier — but `aspect-ratio: 1` is widely supported and keeps the markup
   simpler.

   Untrusted-content note (SEC-7): asset filenames in this section come from
   iCloud / human-set device labels. All renders escape via esc() in
   photos-of-the-day.js. Do not move to innerHTML interpolation. */
.home-photos-today {
  padding: 0 1rem;
  margin: 1rem auto 1.5rem;
  max-width: 1200px;
}
.photos-today__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 0.75rem;
  flex-wrap: wrap;
}
.photos-today__title {
  font-family: 'Fraunces', Georgia, serif;
  font-weight: 500;
  font-size: 1.2rem;
  color: var(--wind-deep);
  margin: 0;
  letter-spacing: -0.01em;
}
.photos-today__date {
  font-size: 0.85rem;
  color: var(--wind-deep);
}
.photos-today__empty {
  color: var(--wind-deep);
  font-size: 0.9rem;
  font-style: italic;
  margin: 0;
}

/* Phase 7d adult hero — 3×2 photo grid replacing the Metis/Hestia agent
   strip (2026-05-18 evening). The whole card is a tap-anywhere <a> to
   /us/photos/today; no per-thumbnail modal here (deliberately different
   affordance from the kid teaser-below-grid). */
.home-hero--adult-photos {
  display: block;
  text-decoration: none;
  color: inherit;
  background: var(--wind-white);
  border: 1px solid var(--wind-dune);
  border-radius: 14px;
  padding: 18px 20px 16px;
  box-shadow: var(--shadow-subtle);
  transition: transform 0.12s ease, box-shadow 0.12s ease;
}
.home-hero--adult-photos:hover {
  transform: translateY(-1px);
  box-shadow: var(--shadow-medium, var(--shadow-subtle));
}
.adult-photos-hero__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 12px;
  flex-wrap: wrap;
}
.adult-photos-hero__title {
  font-family: 'Fraunces', Georgia, serif;
  font-weight: 500;
  font-size: 1.2rem;
  color: var(--wind-deep);
  margin: 0;
  letter-spacing: -0.01em;
}
.adult-photos-hero__date {
  font-size: 0.85rem;
  color: var(--wind-stone);
}
.adult-photos-hero__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 6px;
}
.adult-photos-hero__grid img {
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: 6px;
  background: var(--wind-sand);
  display: block;
}
/* Phase 7e Slice C4 — cell wrapper holds an img + a heart sibling so the
   heart can absolute-position against the cell. img keeps its existing
   sizing rules above. */
.adult-photos-hero__cell {
  position: relative;
  display: block;
}

/* Hide the below-grid teaser section on admin home — the 3×2 hero
   already shows photos of the day in prime real estate. Kids
   (data-role="member") still get the teaser below the grid. */
body[data-role="admin"] #photos-today { display: none; }

/* Home teaser — single horizontal row of up to 6 photos sampled across
   years. Lives only on /us/home; the full per-year grid lives on
   /us/photos/today. Tiles are 1:1 with a soft cap so even on iPad the
   row never grows past hero-card height. */
.photos-teaser__row {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 6px;
  margin-bottom: 0.75rem;
}
@media (max-width: 720px) {
  /* On phones, drop to 4 across so each tile stays tappable (~80px+). */
  .photos-teaser__row { grid-template-columns: repeat(4, 1fr); }
  .photos-teaser__row .photo-card:nth-child(n+5) { display: none; }
}
.photos-teaser__chip {
  display: inline-block;
  font-size: 0.9rem;
  color: var(--wind-amber);
  text-decoration: none;
  padding: 2px 0;
}
.photos-teaser__chip:hover {
  color: var(--wind-amber-hover, var(--wind-amber));
  text-decoration: underline;
}

/* #117 Phase 14h-B: the scroll root inside the .photos-today-page shell
   (overrides the .home-photos-today max-width/margin on this element via
   source order). Full-width so the scrollbar sits at the viewport edge; the
   1200px reading column moves to the direct children below. min-height:0 lets
   the flex child shrink so it scrolls instead of growing to content height. */
.photos-today--full {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 1rem;
  max-width: none;
  margin: 0;
}
/* Center each rendered block (year sections, head, empty/error states) at the
   reading width — works for /us/photos/today and /us/photos/favorites, both of
   which render direct-child blocks into the scroll root. */
.photos-today--full > * {
  max-width: 1200px;
  margin-inline: auto;
}

/* #117 Phase 14h-B: inner-scroll shell (mirrors .chat-page:690). Was the
   body-scroll model (overflow-y:auto; min-height:100vh) shared with
   .chores-page — but on /us/photos/today + /us/photos/favorites the photo
   lightbox's body-scroll-lock toggles body{position:fixed}, which stranded the
   position:fixed tab bar mid-grid on iPad (#144). Locking the body to the
   visual viewport (overflow:hidden; 100dvh) with an inner <main data-scroll-root>
   that scrolls makes the tab bar a flex child (.app-shell rule) — no fixed
   element → no strand possible. The lightbox lock now targets the inner root,
   not the body (photo-lightbox.js getScrollRoot). */
.photos-today-page {
  background: var(--wind-sky);
  color: var(--wind-earth);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  height: 100vh;
  height: 100dvh;
}
.photos-today__back {
  font-size: 0.9rem;
  color: var(--wind-amber);
  text-decoration: none;
}
.photos-today__back:hover {
  color: var(--wind-amber-hover, var(--wind-amber));
  text-decoration: underline;
}

/* Phase 7e Slice A6 — memory-card chrome per year section.
   Reuses the .home-hero--adult-photos pattern at :2309-2319: white bg,
   subtle border, soft shadow, rounded 14px. Polish #7: amber-dot
   chapter-divider ornament between years (replaces the original
   solid border-top stripe — reads as hand-stitched not printed). */
.photos-year {
  background: var(--wind-white);
  border: 1px solid var(--wind-dune);
  border-radius: 14px;
  box-shadow: var(--shadow-subtle);
  padding: 22px 18px 14px;
  margin-bottom: 1rem;
  position: relative;
}
.photos-year::before {
  content: "";
  position: absolute;
  top: 0;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--wind-amber);
  box-shadow:
    -22px 0 0 -2px var(--wind-dune),
     22px 0 0 -2px var(--wind-dune);
}
.photos-year__head {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  margin-bottom: 0.6rem;
}
.photos-year__year {
  font-family: 'Fraunces', Georgia, serif;
  font-weight: 500;
  font-size: var(--text-lg);
  letter-spacing: -0.01em;
  color: var(--wind-deep);
}
.photos-year__hint {
  font-size: var(--text-sm);
  color: var(--wind-stone);
}

/* Phase 7e Slice A5 — hero card at the top of the grid. Anchor of the
   slice per design audit (pop-per-hour rank #1). Random year selection
   per Q7 (not oldest); years-ago badge computed from the chosen photo's
   year. Two-layer overlay for legibility against any photo; year glyph
   in Fraunces at --text-hero. */
.photos-today__hero {
  position: relative;
  display: block;
  width: 100%;
  border: 0;
  padding: 0;
  background: var(--wind-sand);
  border-radius: 16px;
  overflow: hidden;
  cursor: pointer;
  aspect-ratio: 16 / 9;
  margin-bottom: 1.25rem;
  box-shadow: var(--shadow-card);
  transition: transform 0.18s ease, box-shadow 0.18s ease;
}
.photos-today__hero:hover,
.photos-today__hero:focus-visible {
  transform: translateY(-1px);
  box-shadow: var(--shadow-card-hover);
  outline: none;
}
.photos-today__hero:focus-visible {
  outline: 2px solid var(--wind-amber);
  outline-offset: 2px;
}
.photos-today__hero img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.photos-today__hero-overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    to top,
    rgba(0, 0, 0, 0.55) 0%,
    rgba(0, 0, 0, 0.15) 35%,
    transparent 55%
  );
  pointer-events: none;
}
.photos-today__hero-badge {
  position: absolute;
  top: 14px;
  left: 14px;
  display: inline-flex;
  align-items: center;
  padding: 4px 10px;
  border-radius: 999px;
  /* Phase 7e polish #1 — "found polaroid" badge feel. Inner highlight + soft
     shadow makes it read printed-on, not stamped-on. Fraunces for the
     emotional weight on the most resonant element on the page. */
  background: linear-gradient(180deg,
    rgb(var(--wind-white-rgb) / 0.92),
    rgb(var(--wind-white-rgb) / 0.78));
  box-shadow:
    0 1px 0 rgb(255 255 255 / 0.35) inset,
    0 8px 24px rgba(0, 0, 0, 0.18);
  color: var(--wind-deep);
  font-family: 'Fraunces', Georgia, serif;
  font-size: var(--text-sm);
  font-weight: 500;
  letter-spacing: 0.005em;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.photos-today__hero-year {
  position: absolute;
  bottom: 12px;
  left: 18px;
  /* Phase 7e polish #6 — italic Fraunces at display optical size is
     exquisite; the slight slant adds movement without motion. */
  font-family: 'Fraunces', Georgia, serif;
  font-weight: 500;
  font-style: italic;
  font-variation-settings: "opsz" 144;
  font-size: var(--text-hero);
  color: #fff;
  letter-spacing: -0.02em;
  line-height: 1;
  text-shadow: 0 2px 12px rgba(0, 0, 0, 0.4);
  transition: transform 0.4s cubic-bezier(0.2, 0.8, 0.2, 1);
}
.photos-today__hero:hover .photos-today__hero-year { transform: translateY(-3px); }
@media (prefers-reduced-motion: reduce) {
  .photos-today__hero-year { transition: none; }
  .photos-today__hero:hover .photos-today__hero-year { transform: none; }
}
@media (max-width: 480px) {
  .photos-today__hero { aspect-ratio: 4 / 3; }
  .photos-today__hero-year { font-size: var(--text-3xl); bottom: 10px; left: 14px; }
}
@media (prefers-reduced-motion: reduce) {
  .photos-today__hero { transition: none; }
}
.photos-year__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 6px;
}
@media (min-width: 540px) {
  .photos-year__grid { grid-template-columns: repeat(4, 1fr); }
}
@media (min-width: 720px) {
  .photos-year__grid { grid-template-columns: repeat(5, 1fr); }
}
@media (min-width: 960px) {
  .photos-year__grid { grid-template-columns: repeat(6, 1fr); }
}

.photo-card {
  border: 0;
  padding: 0;
  background: var(--wind-sand);
  border-radius: 6px;
  overflow: hidden;
  cursor: pointer;
  aspect-ratio: 1;
  transition: transform 0.12s ease, box-shadow 0.12s ease;
}
.photo-card:hover {
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
  outline: none;
}
.photo-card:focus-visible {
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
  outline: 2px solid var(--wind-deep);
  outline-offset: 2px;
}
.photo-card img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Phase 7e Slice A — visual fundamentals.
   A1: removed `position: relative` to restore native :modal centering
       (position:fixed from UA :modal sheet is itself the containing block
        for the absolutely-positioned chevrons + close button).
   A2: edge-to-edge image (90vh/95vw), blurred photo backdrop driven by
       a CSS custom property set per-photo by photo-lightbox.js, with a
       dominant-color tint layered over the blur.
   A7: scale-in transition via @starting-style + transition-behavior:
       allow-discrete; respects reduced-motion. */
.photo-modal {
  /* Phase 7e A1 fix 2 — explicit translate-based centering. The UA :modal
     stylesheet sets `inset-block: 0 0` + `margin: auto`, which is supposed
     to auto-center via the absolute-centering trick — but in some browsers
     it stretches the dialog vertically to the viewport instead of
     auto-sizing to content (observed on prod 2026-05-20: image at top,
     chevrons at viewport edges, footer hanging off the bottom cut off).
     Override with translate-based positioning for predictable behavior.

     Fill-the-viewport fix (2026-05-21): the previous `width: auto;
     height: auto` sized the dialog to the image's intrinsic dimensions,
     which on iPad reads as a small floating panel when the photo is small
     or the preview path returns a downscaled file. Switch to an explicit
     95vw × 95vh flex container so the modal always fills the viewport;
     the image stays aspect-correct via flex + object-fit on the img rule
     below. `dvh`/`dvw` (where supported) handles the iOS Safari URL-bar
     collapse so the modal doesn't jump when the bar hides/shows. */
  inset: auto;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  margin: 0;
  width: 95vw;
  height: 95vh;
  max-width: 95vw;
  max-height: 95vh;
  /* `display: flex` lives in the [open] rule below — putting it on the
     base .photo-modal selector overrides the UA `dialog:not([open]) {
     display: none }` rule (author CSS beats UA across the cascade) and
     causes the closed dialog to render the close/chevron buttons over
     whatever page is active. */
  padding: 0;
  /* A2: transparent modal bg so the blurred ::backdrop shows around the
     photo edges. The footer keeps its own white bg for caption legibility. */
  background: transparent;
  border-radius: 12px;
  overflow: hidden;
  box-shadow: var(--shadow-modal);
}
/* Only flex-layout when open — otherwise the UA `dialog:not([open])` rule
   correctly hides the dialog. */
.photo-modal[open] {
  display: flex;
  flex-direction: column;
}
@supports (height: 95dvh) {
  .photo-modal {
    width: 95dvw;
    height: 95dvh;
    max-width: 95dvw;
    max-height: 95dvh;
  }
}

/* A7 — open/close transitions. Translate must be preserved through the
   scale-in transition so the modal stays centered while it grows. */
@media (prefers-reduced-motion: no-preference) {
  .photo-modal,
  .photo-modal::backdrop {
    transition:
      opacity 180ms ease-out,
      transform 180ms ease-out,
      overlay 180ms ease-out allow-discrete,
      display 180ms ease-out allow-discrete;
  }
  @starting-style {
    .photo-modal[open] {
      opacity: 0;
      transform: translate(-50%, -50%) scale(0.96);
    }
    .photo-modal[open]::backdrop {
      opacity: 0;
    }
  }
}

/* A2 — `::backdrop` background image driven by CSS custom property set
   from JS (dialog.style.setProperty('--lightbox-bg-url', 'url(...)')).
   Iteration history:
   - v1 backdrop-filter (wrong filter): photo showed unblurred. Replaced.
   - v2 filter:blur + 62% solid tint: green-grass photo washed solid green.
     Killed.
   - v3 filter:blur + flat rgba(0,0,0,0.42): safe, generic.
   - v4 18→42% dominant-color gradient: produced a broken-modal screenshot.
     Reverted because the gradient + scrim layers were too transparent;
     we suspected the photo bg-image was failing for some photos.
   - v5 flat black + opaque #1A1612 safety net: safe but generic.
   - v6 (this, retry of v4 after SW cache v15 bump): the v4 broken-modal
     turned out to be a SW cache mismatch (stale v14 style.css against
     new HTML markup), NOT the gradient transparency. v6 re-introduces
     the dominant-color gradient ON TOP of the opaque #1A1612 safety net
     from v5 — so even if photo bg-image fails or canvas extraction
     throws, the opaque bottom layer prevents page bleed. Best of both. */
.photo-modal::backdrop {
  background:
    linear-gradient(
      rgb(var(--lightbox-tint, 20 16 12) / 0.18),
      rgb(var(--lightbox-tint, 20 16 12) / 0.42)
    ),
    var(--lightbox-bg-url, none) center/cover,
    #1A1612;
  filter: blur(80px) saturate(115%);
  -webkit-filter: blur(80px) saturate(115%);
}
@supports not (backdrop-filter: blur(1px)) {
  .photo-modal::backdrop {
    background-image: none;
    background-color: var(--scrim-modal);
  }
}

.photo-modal img {
  display: block;
  /* Flex into the modal: take the full image area between the absolute-
     positioned action bar (top) and the .photo-modal__footer (bottom).
     `min-height: 0` lets the flex item shrink past intrinsic; without it
     a large natural-size image will push the footer out of view.
     `object-fit: contain` preserves aspect ratio while filling. */
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  margin: 0;
  /* Click-half navigation — cursor stays default; we don't signal "split"
     with cursor changes because it conflicts with user zoom expectations. */
  cursor: default;
}
.photo-modal__footer { flex-shrink: 0; }

/* A3 — Caption footer restructured. Primary line: Fraunces --text-lg
   "5 years ago today" (carries the emotional weight). Secondary line:
   Inter --text-sm muted "May 21, 2020". Drop the truncation — captions
   may wrap to multi-line on narrow viewports. Counter stays right. */
.photo-modal__footer {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.75rem 1rem 0.85rem;
  background: var(--wind-white);  /* keeps caption legible against any photo */
}
.photo-modal__caption {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
}
.photo-modal__caption-primary {
  font-family: 'Fraunces', Georgia, serif;
  font-weight: 500;
  font-size: var(--text-lg);
  color: var(--wind-deep);
  letter-spacing: -0.01em;
  line-height: 1.25;
}
.photo-modal__caption-secondary {
  font-size: var(--text-sm);
  color: var(--wind-stone);
  line-height: 1.3;
}
/* Phase 7e Slices D + E — people caption line.
   - Pre-v3.3 (no peopleTags): rendered as plain text by Slice D's helper
     ("Charlie was 4, Remy was 7") in Fraunces italic amber.
   - Post-v3.3 (peopleTags present): rendered as Slice E people pills
     (.people-pill children) — tappable to filter the carousel. */
.photo-modal__caption-people {
  font-family: 'Fraunces', Georgia, serif;
  font-size: var(--text-sm);
  font-style: italic;
  color: var(--wind-amber-deep, var(--wind-amber));
  line-height: 1.3;
  margin-top: 0.2rem;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.photo-modal__caption-people:empty { display: none; }

/* People pill — Slice E2 + E3. Tap to filter the carousel to that person.
   Active state has a deeper amber background; uses --wind-amber-light token
   for the resting state so it reads as a chip on the otherwise-italic line. */
.people-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 10px;
  border-radius: 999px;
  background: var(--wind-amber-light);
  color: var(--wind-amber-deep, var(--wind-amber));
  border: 1px solid transparent;
  font-family: 'Fraunces', Georgia, serif;
  font-size: var(--text-sm);
  font-style: normal;
  cursor: pointer;
  transition: background 0.12s ease;
}
/* Slice E polish — brand-color dot before the name. Pulls from the
   --pill-dot CSS variable set inline by the renderer. */
.people-pill__dot {
  display: inline-block;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--pill-dot, var(--wind-stone));
  flex-shrink: 0;
}
.people-pill--active .people-pill__dot {
  /* on active state, the dot stays the brand color but gets a subtle
     ring for legibility against the deeper amber background. */
  box-shadow: 0 0 0 1.5px rgba(255, 255, 255, 0.7);
}
/* Polish #8 — soft brand-color ring on hover. Recognition cue, especially
   for kids tapping each other's pills. */
.people-pill:hover .people-pill__dot {
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--pill-dot) 25%, transparent);
  transition: box-shadow 0.18s ease;
}
@media (prefers-reduced-motion: reduce) {
  .people-pill:hover .people-pill__dot { transition: none; }
}
.people-pill:hover,
.people-pill:focus-visible {
  background: var(--wind-dune);
  outline: none;
}
.people-pill:focus-visible {
  outline: 2px solid var(--wind-amber);
  outline-offset: 1px;
}
.people-pill--active {
  background: var(--wind-amber);
  color: #fff;
  border-color: var(--wind-amber-hover, var(--wind-amber));
}
/* "Clear filter" affordance — shown on the people row when a filter is
   active. Tapping clears the filter. */
.people-pill--clear {
  background: transparent;
  color: var(--wind-stone);
  border: 1px solid var(--wind-dune);
  font-style: italic;
}
@media (prefers-reduced-motion: reduce) {
  .people-pill { transition: none; }
}
.photo-modal__counter {
  font-size: var(--text-sm);
  color: var(--wind-stone);
  flex-shrink: 0;
  font-variant-numeric: tabular-nums;
  padding-top: 0.15rem;
}
@media (max-width: 480px) {
  .photo-modal__footer {
    flex-direction: column;
    align-items: stretch;
    gap: 0.25rem;
  }
  .photo-modal__counter { text-align: right; }
}

.photo-modal__close {
  position: absolute;
  top: 0.4rem;
  right: 0.4rem;
  z-index: 3;
  background: rgba(20, 16, 12, 0.45);
  color: #fff;
  border: 0;
  border-radius: 999px;
  width: 44px;
  height: 44px;
  font-size: 1.5rem;
  line-height: 1;
  padding: 0;
  cursor: pointer;
}

/* Phase 7e Slice B1 — glass action bar (top-right; bottom strip on mobile).
   Lives to the LEFT of the close button on desktop, on its own row at the
   bottom on phones to free up the top-right for the close target. */
.photo-modal__actions {
  position: absolute;
  top: 0.4rem;
  right: calc(0.4rem + 44px + 0.4rem);  /* sit to the left of the close pill */
  z-index: 3;
  display: flex;
  gap: 4px;
  padding: 4px;
  border-radius: 999px;
  background: rgb(var(--wind-white-rgb) / 0.16);
  backdrop-filter: blur(20px) saturate(150%);
  -webkit-backdrop-filter: blur(20px) saturate(150%);
}
.photo-modal__action {
  width: 36px;
  height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  color: #fff;
  border: 0;
  border-radius: 999px;
  cursor: pointer;
  transition: background 0.12s ease;
}
.photo-modal__action:hover,
.photo-modal__action:focus-visible {
  background: rgb(var(--wind-white-rgb) / 0.18);
  outline: none;
}
.photo-modal__action:focus-visible {
  outline: 2px solid var(--wind-amber);
  outline-offset: 2px;
}
.photo-modal__action svg { display: block; }
/* Phase 7e Slice F polish — Notus action button has an amber tint so it
   stands apart from share/download/heart as the "magic / new thing." */
.photo-modal__action--notus svg {
  stroke: var(--wind-amber);
  fill: rgb(196 137 46 / 0.15);
}
.photo-modal__action--notus:hover svg,
.photo-modal__action--notus[aria-pressed="true"] svg {
  fill: rgb(196 137 46 / 0.35);
}
/* Action bar stays at top-right across all viewports. The previous mobile
   override pushed it to the bottom via `bottom: calc(100% - 90vh + 8px)`
   — that math assumed the dialog auto-sized to the image (pre-2026-05-21
   layout). With the new flex 95vh modal, the action bar's natural
   top-right slot is unambiguous and fits even on 320px screens (close
   button 44px + 4 action buttons × 36px + gaps ≈ 220px from the right). */

/* Phase 7e Slice B — share popover, slides in below the action bar.
   Positioned absolute relative to the modal; uses the same glass style as
   the action bar for visual continuity. */
/* Phase 7e Slice B — share popover.
   Solid white bg (not translucent — translucent + warm photo backdrop
   produced beige-on-beige low-contrast text on staging). Dark, high-
   contrast text. Dark-mode override below flips bg + text. */
.photo-modal__share-popover {
  position: absolute;
  top: calc(0.4rem + 44px + 6px);
  right: 0.4rem;
  z-index: 4;
  min-width: 220px;
  padding: 6px;
  border-radius: 12px;
  background: #FFFFFF;
  color: #1A1612;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.35);
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.photo-modal__share-popover[hidden] { display: none; }
.share-popover__opt {
  display: block;
  width: 100%;
  padding: 11px 14px;
  background: transparent;
  color: inherit;
  border: 0;
  border-radius: 8px;
  text-align: left;
  font-size: var(--text-sm);
  font-weight: 500;
  cursor: pointer;
  transition: background 0.1s ease;
}
.share-popover__opt:hover,
.share-popover__opt:focus-visible {
  background: #F3EDE4;       /* wind-sand value at light-mode baseline */
  outline: none;
}
.share-popover__opt:focus-visible {
  outline: 2px solid var(--wind-amber);
  outline-offset: -1px;
}
[data-theme="dark"] .photo-modal__share-popover {
  background: #221C16;       /* wind-sand value at dark-mode baseline */
  color: #FFFFFF;
}
[data-theme="dark"] .share-popover__opt:hover,
[data-theme="dark"] .share-popover__opt:focus-visible {
  background: #2C251D;       /* wind-dune value at dark-mode baseline */
}

/* Phase 7e Slice B3 — chat-share composer overlay on the photo bottom.
   Replaces the footer briefly while user types a caption, then hides on
   send or cancel. */
.photo-modal__chat-composer {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 4;
  padding: 12px 16px 14px;
  background: rgb(var(--wind-white-rgb) / 0.96);
  backdrop-filter: blur(24px) saturate(160%);
  -webkit-backdrop-filter: blur(24px) saturate(160%);
  display: flex;
  flex-direction: column;
  gap: 8px;
  border-top: 1px solid var(--wind-dune);
}
.photo-modal__chat-composer[hidden] { display: none; }
.photo-modal__chat-composer-label {
  font-size: var(--text-sm);
  color: var(--wind-stone);
}
.photo-modal__chat-composer textarea {
  font: inherit;
  font-size: var(--text-sm);
  padding: 8px 10px;
  border: 1px solid var(--wind-dune);
  border-radius: 8px;
  background: var(--wind-white);
  color: var(--wind-earth);
  resize: vertical;
  min-height: 44px;
}
.photo-modal__chat-composer-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
}

/* Phase 7e Slice C4 — shared heart button.
   Two visual modes:
   - On overlay surfaces (grid thumbs, adult hero, kid teaser): floats
     top-right, glass pill, white outline on hover, fills warm-red when
     active. The hosting surface positions it via .photo-heart's parent
     having position: relative.
   - In the lightbox action bar: looks like a sibling of the share +
     download buttons (white on glass). Selectors below scope styling
     by ancestor (.photo-card .photo-heart vs .photo-modal__actions
     .photo-heart). */
.photo-heart {
  width: 32px;
  height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: rgb(20 16 12 / 0.45);
  color: #fff;
  cursor: pointer;
  transition: background 0.12s ease, transform 0.12s ease;
}
.photo-heart:hover,
.photo-heart:focus-visible {
  background: rgb(20 16 12 / 0.62);
  outline: none;
}
.photo-heart:focus-visible {
  outline: 2px solid var(--wind-amber);
  outline-offset: 2px;
}
.photo-heart svg {
  display: block;
  transition: fill 0.15s ease, transform 0.18s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.photo-heart--filled svg {
  fill: var(--wind-terracotta);
  stroke: var(--wind-terracotta);
}
.photo-heart:active {
  transform: scale(0.88);
}
/* Phase 7e Slice C4 polish — pop-scale on fill so a tap reads as a real
   moment. The keyframes overshoot then settle. Polish-pass #4 adds a
   fleeting terracotta glow via drop-shadow so the heart breathes color,
   not just size — feels like a real moment, not a checkbox. */
.photo-heart--just-filled svg {
  animation: photo-heart-pop 380ms cubic-bezier(0.34, 1.56, 0.64, 1) both;
}
@keyframes photo-heart-pop {
  0%   { transform: scale(1);    filter: drop-shadow(0 0 0  rgb(181 101 74 / 0)); }
  35%  { transform: scale(1.28); filter: drop-shadow(0 0 12px rgb(181 101 74 / 0.55)); }
  60%  { transform: scale(0.95); filter: drop-shadow(0 0 6px  rgb(181 101 74 / 0.30)); }
  100% { transform: scale(1);    filter: drop-shadow(0 0 0  rgb(181 101 74 / 0)); }
}
@media (prefers-reduced-motion: reduce) {
  .photo-heart--just-filled svg { animation: none; }
  .photo-heart svg { transition: fill 0.15s ease; }
}
.photo-heart--small {
  width: 28px;
  height: 28px;
}
.photo-heart--small svg {
  width: 16px;
  height: 16px;
}

/* Wrapper around each tap-to-open card so the floating heart can absolute-
   position against it without being nested inside the <button>. The wrap
   has display: contents-ish behavior in the grid — but we need it to
   actually be a sized box for the heart to anchor against, so we make it
   the layout box itself (grid children become .photo-card-wrap, the
   button inside fills it). */
.photo-card-wrap,
.photos-today__hero-wrap {
  position: relative;
  display: block;
}
.photo-card-wrap .photo-card,
.photos-today__hero-wrap .photos-today__hero {
  width: 100%;
}
.photo-heart--overlay {
  position: absolute;
  top: 6px;
  right: 6px;
  z-index: 2;
  /* Faint by default; full opacity on hover/focus or persistent on
     touch (no-hover) devices. */
  opacity: 0.85;
}
@media (hover: hover) and (pointer: fine) {
  .photo-heart--overlay:not(.photo-heart--filled) {
    opacity: 0;
    transition: opacity 0.12s ease;
  }
  .photo-card-wrap:hover .photo-heart--overlay,
  .photos-today__hero-wrap:hover .photo-heart--overlay,
  .photo-heart--overlay:focus-visible {
    opacity: 1;
  }
}
@media (prefers-reduced-motion: reduce) {
  .photo-heart,
  .photo-heart--overlay { transition: none; }
}

/* Heart in the lightbox action bar — inherits .photo-modal__action's
   glass background, just smaller/inline. */
.photo-modal__actions .photo-heart {
  width: 36px;
  height: 36px;
  background: transparent;
}
.photo-modal__actions .photo-heart:hover,
.photo-modal__actions .photo-heart:focus-visible {
  background: rgb(var(--wind-white-rgb) / 0.18);
}
.photo-modal__actions .photo-heart--filled svg {
  fill: var(--wind-terracotta);
  stroke: var(--wind-terracotta);
}

/* Phase 7e Slice E (post-ship UX gap) — quick-jump chips on /us/photos
   so users can reach the on-this-day surface + favorites page from the
   gallery without typing the URL. Sits next to the New album button. */
.photos-actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px;
}
.photos-actions__chip {
  display: inline-flex;
  align-items: center;
  padding: 8px 14px;
  border-radius: 999px;
  background: var(--wind-sand);
  color: var(--wind-deep);
  font-size: var(--text-sm);
  font-weight: 500;
  text-decoration: none;
  border: 1px solid var(--wind-dune);
  transition: background 0.12s ease, transform 0.12s ease;
}
.photos-actions__chip:hover,
.photos-actions__chip:focus-visible {
  background: var(--wind-dune);
  outline: none;
}
.photos-actions__chip:focus-visible {
  outline: 2px solid var(--wind-amber);
  outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
  .photos-actions__chip { transition: none; }
}

/* Phase 7e Slice C3 — "snapshot pending" badge on favorites cards.
   Photo is reachable via live-gateway proxy until the snapshot worker
   lands the JPEG in Storage; the badge signals "this might 404 if the
   gateway is offline." Subtle — bottom-left, low opacity. */
.favorites-card__pending {
  position: absolute;
  bottom: 6px;
  left: 6px;
  z-index: 2;
  padding: 2px 6px;
  border-radius: 4px;
  background: rgb(20 16 12 / 0.55);
  color: #fff;
  font-size: 0.65rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  opacity: 0.85;
}

/* Phase 7e Slice F3 — info panel. Bottom-anchored card (mirrors the
   chat-share composer's footprint) with Notus narration text + Ask
   Notus CTA. Closes on tap outside or photo navigation. */
.photo-modal__info-panel {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 4;
  background: rgb(var(--wind-white-rgb) / 0.97);
  backdrop-filter: blur(24px) saturate(160%);
  -webkit-backdrop-filter: blur(24px) saturate(160%);
  padding: 14px 18px 18px;
  border-top: 1px solid var(--wind-dune);
  color: var(--wind-deep);
}
.photo-modal__info-panel[hidden] { display: none; }
.info-panel__inner {
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-width: 640px;
  margin: 0 auto;
}
.info-panel__narration {
  font-family: 'Fraunces', Georgia, serif;
  font-size: var(--text-base);
  line-height: 1.4;
  color: var(--wind-deep);
}
.info-panel__narration:empty { display: none; }
.info-panel__ask {
  align-self: center;
  min-width: 240px;
}
.info-panel__hint {
  font-size: var(--text-sm);
  color: var(--wind-stone);
  text-align: center;
}
.info-panel__hint:empty { display: none; }
[data-theme="dark"] .photo-modal__info-panel {
  background: rgb(34 28 22 / 0.97);
  color: #FFFFFF;
  border-top-color: #3A3128;
}
[data-theme="dark"] .info-panel__narration {
  color: #FFFFFF;
}
[data-theme="dark"] .info-panel__hint {
  color: var(--wind-drift, #B8AD9C);
}

/* Phase 7e Slice B — toast (copy success, send success, errors). */
.photo-modal__toast {
  position: absolute;
  bottom: 16px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 5;
  padding: 8px 14px;
  border-radius: 999px;
  background: rgb(20 16 12 / 0.85);
  color: #fff;
  font-size: var(--text-sm);
  pointer-events: none;
}
.photo-modal__toast[hidden] { display: none; }

/* #123 — Prev/Next chevrons. 44x44 minimum touch target per Phase 14f
   a11y rules. On coarse pointers (touch/iPad) the buttons stay at 40%
   opacity so users always see the affordance; fade to 0% on fine
   pointers and reveal on hover/focus. Backdrop pill works against
   either light or dark photo content. */
.photo-modal__nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(20, 16, 12, 0.45);
  color: #fff;
  border: 0;
  border-radius: 999px;
  font-size: 1.8rem;
  line-height: 1;
  padding: 0 0 4px;  /* visual nudge so the chevron glyph is optically centered */
  cursor: pointer;
  /* Default visibility — replaced below by pointer-media queries. */
  opacity: 0.4;
  transition: opacity 0.15s ease;
}
.photo-modal__nav--prev { left: 0.6rem; }
.photo-modal__nav--next { right: 0.6rem; }
.photo-modal__nav:hover,
.photo-modal__nav:focus-visible {
  opacity: 1;
}
.photo-modal__nav:focus-visible {
  outline: 2px solid var(--wind-amber);
  outline-offset: 2px;
}
@media (hover: hover) and (pointer: fine) {
  /* Mouse: chevrons fade out until the user hovers the modal area. */
  .photo-modal__nav { opacity: 0; }
  .photo-modal:hover .photo-modal__nav,
  .photo-modal__nav:focus-visible { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .photo-card { transition: none; }
  .photo-modal__nav { transition: none; }
}

/* Phase 10-IA P0-5 — Tab-bar overflow at narrow viewports.
   Admin's 10 tabs cram unreadably below ~720px (labels truncate to 2-3
   chars at 375px). Solution: per-user primary tabs stay visible; rest move
   to a "More" popover triggered by the rightmost cell. CSS hides the More
   tab on wide viewports (full bar fits) and hides overflow tabs on narrow
   viewports (replaced by More). The .tab--more cell uses the same .tab
   styles for visual parity. */
.tab--more {
  background: transparent;
  border: 0;
  cursor: pointer;
  font-family: inherit;
}
@media (max-width: 720px) {
  .tab-bar .tab[data-priority="overflow"] { display: none; }
}
@media (min-width: 721px) {
  .tab-bar .tab[data-priority="more"] { display: none; }
}

.tab-more-menu {
  /* Bottom-anchored sheet on narrow viewports. Browsers with native [popover]
     support default to display:none until showPopover() is called; browsers
     without support get display:none via the global [hidden]{display:none
     !important} rule plus the nav.js fallback path that toggles [hidden]
     directly. Either way, the closed state is invisible — never override it
     with a forced display:block here, or the sheet will overlay the page
     and intercept clicks (regression caught in dad-list + map-authoring
     smoke tests at desktop 1280px during deploy 68 prep). */
  background: var(--wind-white);
  border: 1px solid var(--wind-dune);
  border-width: 1px 0 0 0;
  border-radius: 14px 14px 0 0;
  box-shadow: 0 -8px 24px rgba(0, 0, 0, 0.12);
  padding: 10px 0 calc(10px + env(safe-area-inset-bottom));
  margin: 0;
  /* Bottom-anchored when the browser puts this in the top layer (native
     [popover] open state) or when the fallback JS removes [hidden]. The
     `inset` overrides the browser's default centered popover positioning;
     `position: fixed` covers the fallback path where the element isn't
     auto-promoted to top-layer. Closed state stays display:none either
     way (native via :not(:popover-open), fallback via [hidden]). */
  position: fixed;
  inset: auto 0 0 0;
  width: 100%;
  max-width: 100%;
  z-index: 60;
}
.tab-more-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 18px;
  text-decoration: none;
  color: var(--wind-deep);
  font-size: 1rem;
  border-bottom: 1px solid var(--border-soft);
}
.tab-more-item:last-child { border-bottom: 0; }
.tab-more-item:hover,
.tab-more-item:focus-visible {
  background: var(--wind-sand);
  outline: none;
}
.tab-more-item.is-active {
  color: var(--wind-amber);
  font-weight: 600;
}
.tab-more-item__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
}
.tab-more-item__icon svg {
  width: 22px;
  height: 22px;
  color: currentColor;
}

/* ===== iOS install banner ===== */
.ios-install-banner {
  position: fixed;
  left: 12px;
  right: 12px;
  bottom: calc(76px + env(safe-area-inset-bottom));
  background: var(--wind-white);
  border: 1px solid var(--wind-dune);
  border-radius: 12px;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.08);
  padding: 12px 14px;
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 0.88rem;
  color: var(--wind-earth);
  z-index: 60;
}
.ios-install-body {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.ios-install-body strong { color: var(--wind-deep); }
.ios-install-body svg { vertical-align: -2px; color: var(--wind-amber); }
.ios-install-body em { font-style: normal; font-weight: 600; color: var(--wind-deep); }
.ios-install-dismiss {
  background: none;
  border: none;
  font-size: 1.4rem;
  line-height: 1;
  color: var(--wind-drift);
  padding: 0 6px;
  cursor: pointer;
}
.ios-install-dismiss:hover { color: var(--wind-deep); }

/* ===== Photos page ===== */
.photos-container {
  max-width: 960px;
  margin: 0 auto;
  padding: 16px;
}
.photos-actions { margin: 16px 0 22px; }
/* .primary-btn / .secondary-btn deleted Phase 14a — use .btn-primary / .btn-secondary. */

/* ===== Phase 14a: MINX dashboard (extracted from inline <style>) ===== */
.minx-container { max-width: 720px; margin: 0 auto; padding: 1rem; padding-bottom: 2rem; }

/* Phase 14e — 2-column dashboard at wide viewports. Hero stays full-width;
   columns split below. LEFT = money mechanics, RIGHT = operational reality.
   At narrow viewports (<1024) the columns naturally stack and the page
   reads as single-column. align-items: start so the LEFT column (typically
   shorter) doesn't stretch to match the taller RIGHT column. */
.minx-cols { display: flex; flex-direction: column; }
.minx-col { display: flex; flex-direction: column; }
@media (min-width: 1024px) {
  .minx-container { max-width: 1180px; }
  /* Asymmetric 2:3 grid — LEFT column is a money-summary sidebar
     (Forecast + Saving for…), RIGHT carries the activity feed
     (Since Friday's + planner + wishes + reminders + calendar). The
     wider right column absorbs the natural height imbalance from the
     long uncategorized list without leaving the sidebar feeling empty. */
  .minx-cols { display: grid; grid-template-columns: 2fr 3fr; column-gap: 1.5rem; align-items: start; }
}

/* Phase 14e — dark-mode lift for category-bar + fund-progress fills. The
   color hex values stored in taxonomy_values.color (and the SWATCHES picker
   defaults) are tuned for light mode against #F3EDE4 sand. In dark mode
   the same hex against #221C16 sand collapses contrast (several seeded
   colors drop below WCAG AA 3:1). A blanket brightness+saturation lift
   pulls all fills into a viable range without picking 8 hand-tuned
   dark-mode overrides per category. Honest about the data (same hex
   identity), legible on the screen. */
[data-theme="dark"] .minx-section .category-bar-fill,
[data-theme="dark"] .minx-section .fund-progress-fill { filter: brightness(1.35) saturate(1.2); }
/* Lighter track in dark mode so the fills have something to push against. */
[data-theme="dark"] .minx-section .category-bar-track { background: rgba(255, 255, 255, 0.06); }
[data-theme="dark"] .minx-section .fund-progress-track { background: rgba(255, 255, 255, 0.08); }

/* Reduced-motion: drop the width transitions on progress fills. */
@media (prefers-reduced-motion: reduce) {
  .minx-section .category-bar-fill,
  .minx-section .fund-progress-fill { transition: none; }
}
/* #156 — global reduced-motion safety net. Honors prefers-reduced-motion app-wide
   (dialog open/close, hovers, sparkline draws, progress fills): near-instant
   transitions + animations, no smooth scroll. 0.01ms (not 0) so transitionend
   still fires for code that awaits it. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
.minx-section { background: var(--wind-white); border-radius: 10px; padding: 1.25rem; margin-bottom: 1rem; box-shadow: 0 2px 8px rgba(0,0,0,0.04); }
.minx-section h2 { margin: 0 0 0.6rem; font-size: 1.05rem; color: var(--sea-deep, var(--wind-deep)); font-family: Inter, system-ui, sans-serif; font-weight: 600; letter-spacing: 0.02em; text-transform: uppercase; }

.minx-section .hero-card { background: var(--sea-mist, var(--wind-sand)); border-radius: 12px; padding: 1.5rem; }
.minx-section .hero-eyebrow { font-size: 0.85rem; color: var(--wind-earth); margin-bottom: 0.25rem; }
.minx-section .hero-num { font-family: 'Fraunces', Georgia, serif; font-size: 2.4rem; line-height: 1.1; color: var(--sea-ink, var(--wind-deep)); }
.minx-section .hero-meta { font-size: 0.85rem; color: var(--wind-earth); margin-top: 0.4rem; }
.minx-section .sparkline { width: 100%; height: 56px; margin-top: 0.6rem; }
/* Slice D follow-up — chart legend so the sparkline reads as "actual (solid)
   → projected (dashed), split at today" instead of an unlabeled squiggle.
   Swatch colors mirror the SVG strokes drawn in minx.js (renderSparkline). */
.minx-section .sparkline-legend { display: flex; flex-wrap: wrap; gap: 0.3rem 1rem; margin-top: 0.5rem; font-size: 0.72rem; color: var(--wind-earth); }
.minx-section .sparkline-legend .legend-item { display: inline-flex; align-items: center; gap: 0.4rem; }
.minx-section .sparkline-legend .legend-line { display: inline-block; width: 18px; height: 0; border-top: 2px solid var(--sea-deep, var(--wind-deep)); }
.minx-section .sparkline-legend .legend-line--projected { border-top-style: dashed; opacity: 0.85; }
.minx-section .sparkline-legend .legend-tick { display: inline-block; width: 0; height: 12px; border-left: 1px dashed var(--wind-earth); }

/* Phase 14e Slice C — Moms companion stat. Side-by-side on wide viewports,
   stacked-under on iPad portrait (810) and mobile (<=820). Mint-tinted to
   match the Moms band in the stacked-area chart below. Visually smaller
   than the MINX primary balance — Moms is a companion, not a peer. */
.minx-section .hero-balances { display: flex; align-items: flex-start; justify-content: space-between; gap: 1.5rem; flex-wrap: wrap; }
.minx-section .hero-primary { flex: 1 1 auto; min-width: 0; }
.minx-section .hero-companion { flex: 0 0 auto; text-align: right; }
.minx-section .hero-companion-eyebrow { font-size: 0.8rem; color: var(--wind-earth); margin-bottom: 0.25rem; letter-spacing: 0.02em; }
.minx-section .hero-companion-num { font-family: 'Fraunces', Georgia, serif; font-size: 1.5rem; line-height: 1.1; color: var(--sea-tide, var(--sea-deep)); }
.minx-section .hero-companion-meta { font-size: 0.78rem; color: var(--wind-earth); margin-top: 0.3rem; }
/* Tether MINX ↔ Moms visually at side-by-side widths (audit P1 #5). */
@media (min-width: 821px) {
  .minx-section .hero-companion { padding-left: 1.5rem; border-left: 1px solid rgba(140, 130, 110, 0.25); }
}
@media (max-width: 820px) {
  .minx-section .hero-balances { flex-direction: column; gap: 0.75rem; }
  .minx-section .hero-companion { text-align: left; }
}

/* Sparkline chart bands (Slice C): Moms is the bottom filled band rising in
   stair-steps; MINX float stacks on top. Outline stroke on the combined top
   edge gives the eye a single line to follow. */
.minx-section .sparkline .fc-band-moms { fill: var(--sea-glass, #C9DDD9); fill-opacity: 0.65; }
.minx-section .sparkline .fc-band-minx { fill: var(--sea-shoal, #86AEB0); fill-opacity: 0.42; }

/* Phase 14e Slice D/E section header — heading + actions on one row,
   collapses on narrow viewports. */
.minx-section .section-header { display: flex; align-items: baseline; justify-content: space-between; gap: 0.75rem; flex-wrap: wrap; margin-bottom: 0.5rem; }
.minx-section .section-header h2 { margin: 0; }
.minx-section .section-meta { font-size: 0.8rem; color: var(--wind-earth); }
/* Audit P1 #4 — section-header__actions for multi-button right slots. The
   old .section-actions div lived below the h2 and wasted a row; the new
   pattern keeps actions inline with the heading. */
.minx-section .section-header__actions { display: inline-flex; gap: 0.5rem; flex-wrap: wrap; align-items: baseline; }

/* Slice D — "Since Friday's deposit" category bars */
.minx-section .category-bars { list-style: none; padding: 0; margin: 0 0 1rem; display: flex; flex-direction: column; gap: 0.45rem; }
.minx-section .category-bar-row { display: grid; grid-template-columns: 6rem 1fr 5rem; align-items: center; gap: 0.5rem; cursor: pointer; padding: 0.15rem 0.25rem; border-radius: 6px; transition: background 120ms ease; }
.minx-section .category-bar-row:hover { background: rgba(140, 130, 110, 0.08); }
.minx-section .category-bar-row:focus-visible { outline: 2px solid var(--sea-tide, var(--wind-amber)); outline-offset: 2px; }
.minx-section .category-bar-row.is-selected { background: rgba(140, 130, 110, 0.14); }
.minx-section .category-clear-btn { background: transparent; border: 0; color: var(--sea-tide, var(--wind-amber)); cursor: pointer; text-decoration: underline; font-size: 0.78rem; padding: 0 0.5rem 0 0; }
.minx-section .category-bar-label { font-size: 0.85rem; color: var(--sea-ink, var(--wind-deep)); }
.minx-section .category-bar-track { background: var(--wind-sand); border-radius: 6px; height: 14px; overflow: hidden; }
.minx-section .category-bar-fill { height: 100%; border-radius: 6px; transition: width 200ms ease; }
.minx-section .category-bar-amount { font-family: 'Fraunces', Georgia, serif; font-size: 0.95rem; text-align: right; color: var(--sea-ink, var(--wind-deep)); }
.minx-section .uncategorized-block { background: var(--wind-sand); border-radius: 8px; padding: 0.75rem 0.85rem; }
.minx-section .uncategorized-header { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 0.45rem; }
.minx-section .uncategorized-title { font-size: 0.85rem; color: var(--wind-earth); text-transform: uppercase; letter-spacing: 0.04em; }
.minx-section .uncategorized-meta { font-size: 0.8rem; color: var(--wind-earth); }
.minx-section .uncategorized-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 0.35rem; }
.minx-section .uncategorized-row { display: grid; grid-template-columns: 1fr auto auto; align-items: center; gap: 0.5rem; padding: 0.4rem 0; border-bottom: 1px solid rgba(140, 130, 110, 0.18); }
.minx-section .uncategorized-row:last-child { border-bottom: 0; }
.minx-section .uncategorized-desc { font-size: 0.85rem; color: var(--sea-ink, var(--wind-deep)); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.minx-section .uncategorized-amount { font-family: 'Fraunces', Georgia, serif; font-size: 0.95rem; color: var(--wind-red); }
.minx-section .tag-pill-btn { background: transparent; border: 1px solid var(--wind-shore); border-radius: 999px; padding: 0.25rem 0.7rem; font-size: 0.78rem; cursor: pointer; color: var(--sea-ink, var(--wind-deep)); }
.minx-section .tag-pill-btn:hover { background: var(--wind-sand); }

/* Slice D — tag picker dialog */
#tag-dialog .tag-dialog-subhead { font-size: 0.85rem; color: var(--wind-earth); margin-bottom: 0.8rem; }
#tag-dialog .tag-chip-grid { display: flex; flex-wrap: wrap; gap: 0.45rem; margin-bottom: 0.75rem; }
#tag-dialog .tag-chip { display: inline-flex; align-items: center; gap: 0.35rem; padding: 0.4rem 0.7rem; border-radius: 999px; border: 0; cursor: pointer; font-size: 0.85rem; color: var(--sea-ink, var(--wind-deep)); background: var(--wind-sand); }
#tag-dialog .tag-chip:hover { filter: brightness(0.96); }
#tag-dialog .tag-chip .swatch { width: 10px; height: 10px; border-radius: 50%; display: inline-block; }
#tag-dialog .tag-chip--new { border: 1px dashed var(--wind-drift); background: transparent; }
#tag-dialog .new-category-form { display: flex; flex-direction: column; gap: 0.5rem; padding: 0.6rem; background: var(--wind-sand); border-radius: 6px; margin-bottom: 0.75rem; }
#tag-dialog .new-category-form input[type="text"] { padding: 0.4rem 0.6rem; border: 1px solid var(--wind-shore); border-radius: 6px; font-family: Inter, sans-serif; }
#tag-dialog .color-swatches { display: flex; gap: 0.35rem; }
#tag-dialog .color-swatches button { width: 22px; height: 22px; border-radius: 50%; border: 2px solid transparent; cursor: pointer; padding: 0; }
#tag-dialog .color-swatches button.is-active { border-color: var(--sea-ink, var(--wind-deep)); }
#tag-dialog .dialog-footer { display: flex; justify-content: space-between; align-items: center; margin-top: 0.5rem; gap: 0.5rem; flex-wrap: wrap; }
#tag-dialog .link-btn { background: transparent; border: 0; color: var(--sea-tide, var(--wind-amber)); cursor: pointer; text-decoration: underline; font-size: 0.85rem; padding: 0; }
/* Audit P2 #10 — manage view back-link sits top-left (close-X position),
   matching where users instinctively look for the dismiss/back affordance. */
#tag-dialog .tag-dialog-back-top { display: block; margin-bottom: 0.5rem; padding: 0.25rem 0; font-size: 0.9rem; }
#tag-dialog .manage-list { list-style: none; padding: 0; margin: 0 0 0.8rem; display: flex; flex-direction: column; gap: 0.4rem; }
#tag-dialog .manage-row { display: grid; grid-template-columns: auto 1fr auto auto; align-items: center; gap: 0.5rem; padding: 0.4rem 0; border-bottom: 1px solid rgba(140, 130, 110, 0.18); }
#tag-dialog .manage-row .swatch { width: 14px; height: 14px; border-radius: 50%; }
#tag-dialog .manage-row .label { font-size: 0.9rem; }
#tag-dialog .manage-row .manage-action-btn { background: transparent; border: 1px solid var(--wind-shore); border-radius: 6px; padding: 0.25rem 0.55rem; font-size: 0.75rem; cursor: pointer; color: var(--sea-ink, var(--wind-deep)); }
#tag-dialog .manage-row .system-tag { font-size: 0.7rem; color: var(--wind-earth); text-transform: uppercase; letter-spacing: 0.04em; }
/* #147 — inline category editor (label + color) replaces the grid layout while editing */
#tag-dialog .manage-row.is-editing { display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem; }
#tag-dialog .manage-edit-label { flex: 1 1 100%; padding: 0.4rem 0.6rem; border: 1px solid var(--wind-shore); border-radius: 6px; font-family: Inter, sans-serif; font-size: 0.9rem; }
#tag-dialog .manage-row.is-editing .manage-edit-swatches { flex: 1 1 auto; flex-wrap: wrap; }

/* Slice E — Saving for… section */
.minx-section .funds-meta { font-size: 0.85rem; color: var(--wind-earth); margin-bottom: 0.55rem; }
.minx-section .funds-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 0.5rem; }
.minx-section .fund-row { display: grid; grid-template-columns: 1fr auto; gap: 0.5rem 0.75rem; align-items: center; padding: 0.6rem 0.75rem; background: var(--wind-sand); border-radius: 8px; }
.minx-section .fund-row .fund-row-head { display: inline-flex; align-items: baseline; gap: 0.4rem; }
.minx-section .fund-row .fund-name { font-size: 0.95rem; color: var(--sea-ink, var(--wind-deep)); font-weight: 500; }
/* #156 — 44×44 tap target (WCAG 2.5.5). Hit area padded around the glyph; the
   ✎ itself stays 0.85rem (transparent button, so the area is invisible). */
.minx-section .fund-row .fund-rename-btn { background: transparent; border: 0; padding: 0; cursor: pointer; color: var(--wind-earth); font-size: 0.85rem; line-height: 1; min-width: 44px; min-height: 44px; display: inline-flex; align-items: center; justify-content: center; }
.minx-section .fund-row .fund-rename-btn:hover { color: var(--sea-tide, var(--wind-amber)); }
.minx-section .fund-row .fund-stat { font-family: 'Fraunces', Georgia, serif; font-size: 0.95rem; color: var(--sea-ink, var(--wind-deep)); }
.minx-section .fund-row .fund-progress { grid-column: 1 / 3; display: grid; grid-template-columns: 1fr auto; gap: 0.5rem; align-items: center; }
.minx-section .fund-progress-track { background: rgba(140, 130, 110, 0.2); border-radius: 6px; height: 10px; overflow: hidden; }
.minx-section .fund-progress-fill { background: var(--sea-glass, #C9DDD9); height: 100%; transition: width 200ms ease; }
.minx-section .fund-progress-fill.is-complete { background: var(--wind-green, #5E9E5E); }
.minx-section .fund-row .fund-allocate-btn { background: transparent; border: 1px solid var(--wind-shore); border-radius: 6px; padding: 0.25rem 0.6rem; font-size: 0.8rem; cursor: pointer; color: var(--sea-ink, var(--wind-deep)); }
.minx-section .fund-row .fund-allocate-btn:hover { background: var(--wind-sand); filter: brightness(0.95); }

#allocate-dialog .dialog-subhead { font-size: 0.85rem; color: var(--wind-earth); margin-bottom: 0.6rem; }

/* Phase 14e Slice A: forecast header + 30/60/90 window toggle */
.forecast-header { display: flex; align-items: baseline; justify-content: space-between; gap: 0.75rem; margin-bottom: 0.4rem; flex-wrap: wrap; }
.forecast-header h2 { margin: 0; }
.forecast-window-toggle { display: inline-flex; gap: 0; background: var(--wind-sand); border-radius: 8px; padding: 2px; font-family: Inter, sans-serif; }
.forecast-window-toggle .window-btn { background: transparent; border: 0; padding: 0.3rem 0.7rem; font-size: 0.8rem; color: var(--wind-earth); border-radius: 6px; cursor: pointer; font-family: inherit; }
.forecast-window-toggle .window-btn:hover { color: var(--sea-ink, var(--wind-deep)); }
/* #156 — active pill bg was var(--surface,#fff): --surface is undefined, so it
   forced #fff, and the text token flips light in dark mode → light-on-light
   (1.26:1). --wind-white is theme-aware (#fff light / #1A1612 dark), so the pill
   inverts with the text and clears AA in both themes. */
.forecast-window-toggle .window-btn.is-active { background: var(--wind-white); color: var(--sea-ink, var(--wind-deep)); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08); }

.forecast-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.75rem; }
/* Slice A: 3-tier layout (lbl / val / when). Row height locked so cells
   don't bounce when the date string updates as the window toggles. */
.forecast-cell { background: var(--wind-sand); border-radius: 8px; padding: 0.6rem 0.7rem; font-family: Inter, sans-serif; min-height: 5.4rem; display: flex; flex-direction: column; justify-content: flex-start; gap: 0.15rem; }
.forecast-cell .lbl { font-size: 0.7rem; color: var(--wind-earth); text-transform: uppercase; letter-spacing: 0.04em; }
.forecast-cell .val { font-family: 'Fraunces', Georgia, serif; font-size: 1.3rem; line-height: 1.15; }
.forecast-cell .when { font-size: 0.8rem; color: var(--wind-earth); line-height: 1.2; min-height: 1rem; }
.forecast-cell.breach .val { color: var(--wind-red); }
/* Audit P1 #7 — breach state needs a non-color cue too (WCAG 1.4.1). The
   ⚠ prefix on the value and breach-warning text gives shape redundancy
   for users who can't perceive the red. */
.forecast-cell.breach .val::before { content: "⚠ "; font-family: Inter, sans-serif; }
.breach-warning::before { content: "⚠ "; }
/* legacy class kept for back-compat with any other surface that uses it */
.forecast-cell .val.breach { color: var(--wind-red); }
.breach-warning { color: var(--wind-red); font-size: 0.85rem; margin-top: 0.6rem; }

/* Slice A: sparkline today-tick + event-dot are styled inline on the SVG
   (stroke/fill use tokens). Class hooks below let themes override if needed. */
.minx-section .sparkline .fc-today-tick { /* token via inline stroke; class anchors test selectors */ }
.minx-section .sparkline .fc-event-dot { /* token via inline fill; class anchors test selectors */ }

.planner-list { list-style: none; padding: 0; margin: 0; }
.planner-row { display: flex; justify-content: space-between; align-items: baseline; padding: 0.6rem 0; border-bottom: 1px solid var(--wind-dune); }
.planner-row:last-child { border-bottom: none; }
.planner-title { color: var(--sea-deep, var(--wind-deep)); font-weight: 500; }
.planner-cat { font-size: 0.75rem; color: var(--wind-earth); margin-left: 0.5rem; text-transform: uppercase; letter-spacing: 0.04em; }
.planner-cost { font-family: 'Fraunces', Georgia, serif; color: var(--sea-deep, var(--wind-deep)); }
.planner-link { display: flex; justify-content: space-between; align-items: baseline; gap: 0.5rem; width: 100%; color: inherit; text-decoration: none; }
.planner-link:hover { color: var(--wind-amber); }

.minx-page .empty-msg { color: var(--wind-earth); font-style: italic; padding: 0.6rem 0; }

.wish-row { padding: 0.6rem 0; border-bottom: 1px solid var(--wind-dune); }
.wish-row:last-child { border-bottom: none; }
.wish-title { color: var(--sea-deep, var(--wind-deep)); font-weight: 500; }
.wish-note { color: var(--wind-earth); font-size: 0.85rem; margin-top: 0.2rem; }
.wish-actions { margin-top: 0.5rem; display: flex; gap: 0.4rem; flex-wrap: wrap; }
.wish-btn { background: var(--wind-sand); border: 1px solid var(--wind-dune); border-radius: 999px; padding: 0.3rem 0.7rem; font-size: 0.8rem; cursor: pointer; }
.wish-btn:hover { background: var(--sea-mist); }

.placeholder-block { color: var(--wind-earth); font-style: italic; font-size: 0.85rem; padding: 0.5rem 0; }
.section-actions { display: flex; gap: 0.5rem; margin-bottom: 1rem; flex-wrap: wrap; }
.wishes-count { color: var(--wind-earth); font-weight: normal; }

/* MINX planner page extracted styles */
.planner-container { max-width: 720px; margin: 0 auto; padding: 1rem; }
.planner-container .filters { display: flex; gap: 0.5rem; margin-bottom: 1rem; flex-wrap: wrap; }
.item-card { background: var(--wind-white); border-radius: 10px; padding: 1rem; margin-bottom: 0.75rem; box-shadow: 0 2px 6px rgba(0,0,0,0.04); }
.item-head { display: flex; justify-content: space-between; align-items: baseline; gap: 0.5rem; }
.item-title { font-family: 'Fraunces', Georgia, serif; font-size: 1.1rem; color: var(--sea-deep, var(--wind-deep)); }
.item-cost { font-family: 'Fraunces', Georgia, serif; color: var(--sea-deep, var(--wind-deep)); }
.item-meta { font-size: 0.8rem; color: var(--wind-earth); margin-top: 0.25rem; }
.item-actions { display: flex; gap: 0.5rem; margin-top: 0.5rem; flex-wrap: wrap; }

.status-pill { font-size: 0.75rem; padding: 0.15rem 0.5rem; border-radius: 999px; font-weight: 500; }
.status-pending { background: var(--wind-sand); color: var(--wind-earth); }
.status-deferred { background: var(--wind-dune); color: var(--wind-earth); }
.status-purchased { background: var(--wind-green-light); color: var(--status-success-text); }
.status-cancelled { background: var(--wind-red-light); color: var(--status-danger-text); }
.status-active { background: var(--wind-green-light); color: var(--status-success-text); }
.status-expired { background: var(--wind-dune); color: var(--wind-earth); }
.status-revoked { background: var(--wind-red-light); color: var(--status-danger-text); }

/* MINX settings page extracted styles */
.settings-container { max-width: 720px; margin: 0 auto; padding: 1rem; }
.settings-section { background: var(--wind-white); border-radius: 10px; padding: 1.25rem; margin-bottom: 1rem; box-shadow: 0 2px 8px rgba(0,0,0,0.04); }
.priority-list { list-style: none; padding: 0; margin: 0; }
.priority-row {
  display: flex; align-items: center; gap: 0.75rem;
  background: var(--wind-sand);
  padding: 0.6rem 0.8rem;
  border-radius: 8px;
  margin-bottom: 0.4rem;
  cursor: grab;
  transition: background 0.15s;
}
.priority-row[draggable="true"]:hover { background: var(--sea-mist, var(--wind-sand)); }
.priority-row.dragging { opacity: 0.5; cursor: grabbing; }
.priority-row.drop-target { box-shadow: 0 0 0 2px var(--sea-deep, var(--wind-deep)); }
.priority-num {
  font-family: 'Fraunces', Georgia, serif;
  font-size: 1.2rem;
  width: 1.6rem; text-align: center;
  color: var(--sea-deep, var(--wind-deep));
}
.priority-name { flex: 1; color: var(--sea-deep, var(--wind-deep)); }
.priority-controls { display: flex; gap: 0.25rem; }
.priority-controls button {
  background: transparent;
  border: 1px solid var(--wind-dune);
  width: 2rem; height: 2rem;
  border-radius: 6px;
  cursor: pointer;
  font-size: 1rem;
  line-height: 1;
  min-height: auto;
  padding: 0;
}
.priority-controls button:hover:not(:disabled) { background: var(--wind-white); }
.priority-controls button:disabled { opacity: 0.3; cursor: not-allowed; }
.save-row { display: flex; gap: 0.5rem; margin-top: 0.8rem; align-items: center; }
.save-status { font-size: 0.85rem; color: var(--wind-earth); margin-left: auto; }
.save-status.saved { color: var(--status-success-text); }
.save-status.error { color: var(--wind-red); }
.floor-display { font-family: 'Fraunces', Georgia, serif; font-size: 1.5rem; color: var(--sea-deep, var(--wind-deep)); }
.settings-section h2 { font-family: Inter, system-ui, sans-serif; font-size: 1rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--sea-deep, var(--wind-deep)); margin: 0 0 0.5rem; }
.settings-section p.help { color: var(--wind-earth); font-size: 0.85rem; margin: 0 0 0.8rem; }
.filters select { padding: 0.4rem; border: 1px solid var(--wind-dune); border-radius: 6px; background: var(--wind-white); }
.item-meta .chip { display: inline-block; background: var(--wind-sand); padding: 0.15rem 0.5rem; border-radius: 999px; margin-right: 0.4rem; font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.04em; }
.item-actions a, .item-actions button { background: transparent; border: 1px solid var(--wind-dune); padding: 0.3rem 0.7rem; border-radius: 6px; font-size: 0.85rem; color: var(--sea-deep, var(--wind-deep)); text-decoration: none; cursor: pointer; min-height: auto; }

/* ===== Phase 14a: /us/adults cross-surface card grid ===== */
.adults-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 12px;
  margin: 16px 0 24px;
}

.adults-card {
  display: flex;
  flex-direction: column;
  gap: 4px;
  background: var(--wind-white);
  border: 1px solid var(--wind-dune);
  border-radius: 12px;
  padding: 18px 20px;
  text-decoration: none;
  color: inherit;
  box-shadow: var(--shadow-subtle);
  transition: transform 150ms cubic-bezier(0.2, 0.7, 0.2, 1), box-shadow 150ms;
}

.adults-card:hover {
  transform: translateY(-1px);
  box-shadow: var(--shadow-card-hover);
}

.adults-card__eyebrow {
  font-size: 0.7rem;
  font-weight: 500;
  color: var(--wind-stone);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.adults-card__title {
  font-family: 'Fraunces', Georgia, serif;
  font-size: 1.4rem;
  font-weight: 500;
  color: var(--wind-deep);
  letter-spacing: -0.01em;
  line-height: 1.15;
}

.adults-card__hint {
  font-size: 0.85rem;
  color: var(--wind-earth);
  margin-top: 2px;
}

/* ===== Phase 14c: figure picker dialog ===== */

.figure-picker {
  max-width: 720px;
  width: 92%;
  padding: 1.25rem 1.25rem 1.5rem;
}

.figure-picker__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 1rem;
}

.figure-picker__head h2 {
  margin: 0;
  /* Inherits Fraunces from .dialog-base h2 */
}

.picker-grid {
  display: grid;
  /* Mobile/portrait: 2-up. iPad/desktop: 4-up. */
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
}

@media (min-width: 744px) {
  .picker-grid {
    grid-template-columns: repeat(4, 1fr);
    gap: 14px;
  }
}

.picker-tile {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  text-decoration: none;
  color: inherit;
  background: var(--wind-white);
  border: 1px solid var(--wind-dune);
  border-radius: 12px;
  padding: 14px 10px 12px;
  box-shadow: var(--shadow-subtle);
  transition: transform 150ms cubic-bezier(0.2, 0.7, 0.2, 1), box-shadow 150ms, border-color 150ms;
}

.picker-tile:hover,
.picker-tile:focus-visible {
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(90, 80, 65, 0.14);
  border-color: var(--tile-tint, var(--wind-amber));
  outline: none;
}

.picker-tile__portrait {
  width: 88px;
  height: 88px;
  border-radius: 50%;
  background: var(--wind-sand);
  border: 2px solid var(--tile-tint, var(--wind-amber));
  display: inline-flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  margin-bottom: 8px;
}

.picker-tile__portrait img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.picker-tile__initial {
  font-family: 'Fraunces', Georgia, serif;
  font-size: 2.4rem;
  color: var(--tile-tint, var(--wind-amber));
}

.picker-tile__name {
  font-family: 'Fraunces', Georgia, serif;
  font-size: 1.05rem;
  color: var(--wind-deep);
  letter-spacing: -0.01em;
  margin-top: 2px;
}

.picker-tile__eyebrow {
  font-size: 0.7rem;
  color: var(--wind-stone);
  letter-spacing: 0.02em;
  margin-top: 2px;
}

.picker-tile__hook {
  font-size: 0.85rem;
  color: var(--wind-earth);
  line-height: 1.35;
  margin-top: 6px;
}

.link-btn {
  background: none;
  border: none;
  color: var(--wind-amber);
  cursor: pointer;
  text-decoration: underline;
  font-size: 0.88rem;
  padding: 4px 8px;
}
.link-btn.revoke { color: var(--wind-red); }

/* Albums grid */
.albums-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 14px;
}
.album-card {
  background: var(--wind-white);
  border: 1px solid var(--wind-dune);
  border-radius: 10px;
  overflow: hidden;
  text-decoration: none;
  color: inherit;
  display: flex;
  flex-direction: column;
  cursor: pointer;
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.album-card:hover {
  transform: translateY(-1px);
  box-shadow: var(--shadow-card-hover);
}
.album-card .album-cover {
  aspect-ratio: 4 / 3;
  background: var(--wind-dune);
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
}
.album-card .album-cover img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.album-card .album-placeholder {
  width: 56px;
  height: 56px;
  color: var(--wind-drift);
  display: flex;
  align-items: center;
  justify-content: center;
}
.album-card .album-placeholder svg {
  width: 100%;
  height: 100%;
}
.album-card .album-meta {
  padding: 10px 12px 12px;
}
.album-card .album-title {
  font-weight: 600;
  font-size: 0.98rem;
  color: var(--wind-deep);
  margin-bottom: 3px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.album-card .album-sub {
  font-size: 0.78rem;
  color: var(--wind-drift);
}

/* Album detail */
.album-detail-head {
  margin: 8px 0 22px;
}
.album-detail-head h2 {
  margin: 8px 0 4px;
  color: var(--wind-deep);
}
.album-detail-head .album-desc {
  color: var(--wind-earth);
  font-size: 0.95rem;
  margin: 0 0 16px;
  line-height: 1.5;
}
.album-detail-actions {
  display: flex;
  gap: 10px;
  margin-bottom: 14px;
  flex-wrap: wrap;
}
.photos-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: 8px;
  min-height: 180px;
  border-radius: 8px;
  transition: background-color 0.15s ease, outline 0.15s ease;
}
.photos-grid.drag-over {
  background-color: var(--wind-sand);
  outline: 2px dashed var(--wind-amber);
  outline-offset: -8px;
}
.photos-grid.drag-over::before {
  content: 'Drop photos to upload';
  grid-column: 1 / -1;
  text-align: center;
  padding: 40px 20px;
  color: var(--wind-amber);
  font-weight: 600;
}
.photo-tile {
  position: relative;
  aspect-ratio: 1 / 1;
  background: var(--wind-dune);
  border-radius: 6px;
  overflow: hidden;
  cursor: pointer;
}
.photo-tile img,
.photo-tile video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.photo-tile.is-video .video-badge {
  position: absolute;
  inset: auto 8px 8px auto;
  /* Translucent overlay on photo media — semantic overlay color, not a
     theme token; legible on any background image in both light/dark. */
  background: rgba(0, 0, 0, 0.55);
  color: white;
  border-radius: 999px;
  padding: 4px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}
.photo-tile.is-video .video-badge svg {
  width: 18px;
  height: 18px;
}
#lb-video {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}
.upload-hint {
  color: var(--wind-drift);
  font-size: 0.85rem;
  margin-left: 10px;
}

/* Inline-editable album title + description (Phase 6 sibling — photos UX) */
.editable-text {
  cursor: text;
  border-radius: 4px;
  padding: 2px 4px;
  margin: -2px -4px;
  transition: background-color 0.12s ease;
}
.editable-text:hover {
  background-color: var(--wind-amber-light);
  outline: 1px dashed var(--wind-amber);
  outline-offset: -1px;
}
.editable-text.placeholder {
  color: var(--wind-drift);
  font-style: italic;
}
.inline-edit-input {
  width: 100%;
  font-family: inherit;
  font-size: inherit;
  color: var(--wind-deep);
  background: var(--wind-white);
  border: 1px solid var(--wind-amber);
  border-radius: 4px;
  padding: 4px 6px;
  margin: -5px -7px;
  box-sizing: border-box;
  box-shadow: 0 0 0 3px var(--wind-amber-light);
  outline: none;
  resize: vertical;
}
textarea.inline-edit-input {
  line-height: 1.4;
  font-size: 0.95rem;
}
.photo-tile .photo-delete {
  position: absolute;
  top: 4px;
  right: 4px;
  /* 44pt iOS minimum touch target — was 24px pre-15a. The visible SVG is
     sized to ~18px inside; the rest is invisible padding for tap area. */
  width: 44px;
  height: 44px;
  padding: 0;
  /* Translucent media overlay — see .video-badge note. */
  background: rgba(0, 0, 0, 0.55);
  color: #fff;
  border: none;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.15s;
}
.photo-tile .photo-delete svg {
  width: 18px;
  height: 18px;
}
.photo-tile:hover .photo-delete { opacity: 1; }
/* Touch devices have no hover — keep the delete affordance always visible
   so it's reachable. Slight opacity reduction so it doesn't dominate. */
@media (hover: none) {
  .photo-tile .photo-delete { opacity: 0.85; }
}

.upload-status {
  margin-top: 14px;
  padding: 10px 12px;
  background: var(--wind-sand);
  border-radius: 6px;
  font-size: 0.88rem;
  color: var(--wind-earth);
}

.empty-state {
  text-align: center;
  padding: 40px 20px;
  color: var(--wind-drift);
  font-size: 0.95rem;
}

/* Share links panel */
.share-links-list {
  margin-top: 10px;
  padding: 12px 14px;
  background: var(--wind-sand);
  border: 1px solid var(--wind-dune);
  border-radius: 8px;
}
.share-links-list h4 {
  margin: 0 0 8px;
  font-size: 0.85rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--wind-stone);
}
.share-link-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 6px 0;
  font-size: 0.88rem;
  border-top: 1px dashed var(--wind-dune);
}
.share-link-row:first-of-type { border-top: none; }

/* Modal */
.modal {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.35);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  z-index: 200;
}
.modal[hidden] { display: none; }
.modal-content {
  background: var(--wind-white);
  padding: 24px;
  border-radius: 12px;
  width: 100%;
  max-width: 420px;
}
.modal-content h3 {
  margin: 0 0 16px;
  color: var(--wind-deep);
}
.modal-content label {
  display: block;
  margin-bottom: 12px;
  font-size: 0.9rem;
  color: var(--wind-earth);
}
.modal-content input,
.modal-content textarea,
.modal-content select {
  width: 100%;
  padding: 8px 10px;
  margin-top: 4px;
  border: 1px solid var(--wind-dune);
  border-radius: 6px;
  font-size: 0.95rem;
  font-family: inherit;
  box-sizing: border-box;
  background: var(--wind-white);
  color: var(--wind-deep);
}
.modal-content textarea {
  min-height: 60px;
  resize: vertical;
}
.modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  margin-top: 6px;
}

/* ===== Profile page ===== */
.profile-container { max-width: 560px; }
.profile-section {
  margin: 22px 0;
  padding: 18px 20px;
  background: var(--wind-white);
  border: 1px solid var(--wind-dune);
  border-radius: 10px;
}
.profile-section h2 {
  margin: 0 0 12px;
  font-size: 1rem;
  color: var(--wind-deep);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-weight: 600;
}
.profile-section .hint {
  font-size: 0.85rem;
  color: var(--wind-drift);
  margin: 8px 0 14px;
}
.profile-section input[type="text"] {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--wind-dune);
  border-radius: 6px;
  font-size: 1rem;
  font-family: inherit;
  margin-bottom: 10px;
  box-sizing: border-box;
}

.avatar-row {
  display: flex;
  align-items: center;
  gap: 20px;
  margin-bottom: 8px;
}
.avatar-preview-big {
  width: 96px;
  height: 96px;
  border-radius: 50%;
  background: var(--wind-amber);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 2.4rem;
  font-weight: 600;
  flex-shrink: 0;
  overflow: hidden;
}
.avatar-preview-big img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.avatar-actions {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.color-row {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
}
.color-row input[type="color"] {
  width: 56px;
  height: 44px;
  border: 1px solid var(--wind-dune);
  border-radius: 6px;
  cursor: pointer;
  background: none;
  padding: 2px;
}
.color-row .color-value {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.9rem;
  color: var(--wind-stone);
}

.status-banner {
  margin: 14px 0;
  padding: 10px 14px;
  border-radius: 6px;
  font-size: 0.9rem;
}
.status-banner.info { background: var(--wind-sand); color: var(--wind-earth); }
.status-banner.success { background: var(--status-success-bg); color: var(--status-success-text); border: 1px solid var(--status-success-border); }
.status-banner.error { background: var(--wind-red-light); color: var(--wind-red); border: 1px solid var(--status-danger-stroke); }

/* Small avatar bubble (for chat, admin, etc.) */
.avatar-mini {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-weight: 600;
  font-size: 0.85rem;
  overflow: hidden;
  flex-shrink: 0;
}
.avatar-mini img { width: 100%; height: 100%; object-fit: cover; }

/* ===== Notus memory page ===== */
.memory-container { max-width: 680px; }
.memory-intro {
  color: var(--wind-earth);
  font-size: 0.95rem;
  line-height: 1.5;
  margin: 8px 0 18px;
}
.memory-filters {
  margin-bottom: 14px;
  font-size: 0.88rem;
  color: var(--wind-stone);
}
.memory-filters input { margin-right: 6px; }

.memory-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.memory-card {
  background: var(--wind-white);
  border: 1px solid var(--wind-dune);
  border-radius: 10px;
  padding: 14px 16px;
}
.memory-head {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 6px;
  font-size: 0.78rem;
  color: var(--wind-stone);
}
.mem-category {
  background: var(--wind-sand);
  padding: 2px 8px;
  border-radius: 999px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-weight: 600;
  color: var(--wind-deep);
}
.mem-subject {
  color: var(--wind-amber);
  font-weight: 600;
}
.mem-badge.expired {
  background: var(--wind-dune);
  color: var(--wind-stone);
  padding: 2px 8px;
  border-radius: 999px;
  text-transform: uppercase;
  font-size: 0.7rem;
}
.mem-salience {
  margin-left: auto;
  font-style: italic;
  color: var(--wind-drift);
}
.memory-fact {
  color: var(--wind-deep);
  font-size: 0.98rem;
  line-height: 1.45;
  margin-bottom: 8px;
}
.memory-meta {
  font-size: 0.78rem;
  color: var(--wind-drift);
  margin-bottom: 6px;
}
.memory-actions {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
}

/* Lightbox (shared with share viewer) */
.lightbox {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.9);
  display: none;
  align-items: center;
  justify-content: center;
  z-index: 100;
  padding: 20px;
}
.lightbox.open { display: flex; }
.lightbox img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}
.lightbox .lb-close {
  position: absolute;
  top: 18px;
  right: 22px;
  /* 44pt iOS minimum touch target — was font-size:2.2rem text-only pre-15a. */
  width: 44px;
  height: 44px;
  color: #fff;
  background: none;
  border: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.lightbox .lb-close svg {
  width: 28px;
  height: 28px;
}

/* ---------------------------------------------------------------------------
   Dad's List (Phase 9a) — deferred decisions queue + gates + expected events
   (originally "surprise log"; renamed Phase 10O Slice E 2026-05-24)
   --------------------------------------------------------------------------- */

.dad-list-page .dad-list-container { padding-bottom: 120px; }

.dad-list-toolbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  margin: 12px 0 8px;
  flex-wrap: wrap;
}

.member-hint {
  background: var(--wind-amber-light);
  border-left: 3px solid var(--wind-amber);
  padding: 10px 14px;
  border-radius: 6px;
  color: var(--wind-deep);
  margin-bottom: 12px;
  font-size: 0.95rem;
}

.urgency-badge {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 10px;
  font-size: 0.75rem;
  font-weight: 600;
  margin-right: 6px;
  text-transform: uppercase;
  letter-spacing: 0.02em;
}
.urgency-badge.urgency-critical { background: var(--wind-red); color: var(--wind-white); }
.urgency-badge.urgency-high     { background: var(--wind-amber); color: var(--wind-white); }
.urgency-badge.urgency-low      { background: var(--wind-shore); color: var(--wind-earth); }
/* Inferred-pattern status pills (/us/dice/inbox). Defined, theme-aware token
   pairs — the old inline styles used undefined --accent-soft/--accent-strong and
   rendered pale-on-pale in dark mode (#160). shore/earth + earth/sky both invert
   to keep WCAG-AA contrast in light and dark. */
.urgency-badge.urgency-candidate { background: var(--wind-shore); color: var(--wind-earth); }
.urgency-badge.urgency-confirmed { background: var(--wind-earth); color: var(--wind-sky); }

.zone-chip {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 10px;
  font-size: 0.75rem;
  background: var(--border-card);
  color: var(--wind-deep);
  margin-right: 6px;
}

.gate-summary {
  margin-top: 6px;
  padding: 6px 10px;
  background: var(--status-danger-bg);
  border-left: 2px solid var(--status-danger-text);
  border-radius: 4px;
  font-size: 0.88rem;
  color: var(--status-danger-text);
}

.hint-inline {
  font-weight: normal;
  font-size: 0.85rem;
  color: var(--wind-stone);
}

.cost-range-row {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
}
.cost-range-row input[type="number"] { flex: 1 1 80px; min-width: 80px; }
.cost-range-row select { flex: 0 1 auto; }

/* -----------------------------------------------------------------------
   .modal-card — new modal pattern (Phase 9a onward).
   Original .modal-content pattern above (pre-9a) uses a narrower fixed
   420px card; this card scales up for the denser forms introduced with
   Dad's List / admin-financial / admin-metis.
   ----------------------------------------------------------------------- */
.modal-card {
  background: var(--wind-white);
  padding: 22px 24px;
  border-radius: 12px;
  width: 100%;
  max-width: 480px;
  max-height: 90vh;
  overflow-y: auto;
  box-shadow: var(--shadow-modal);
}
.modal-card h2 {
  margin: 0 0 14px;
  color: var(--wind-deep);
  font-size: 1.2rem;
}
.modal-card label {
  display: block;
  margin: 10px 0 4px;
  font-size: 0.88rem;
  color: var(--wind-earth);
  font-weight: 500;
}
.modal-card input[type="text"],
.modal-card input[type="number"],
.modal-card input[type="date"],
.modal-card input[type="datetime-local"],
.modal-card input[type="email"],
.modal-card select,
.modal-card textarea {
  display: block;
  width: 100%;
  padding: 8px 10px;
  border: 1px solid var(--wind-dune);
  border-radius: 6px;
  font-size: 0.95rem;
  font-family: inherit;
  box-sizing: border-box;
  background: var(--wind-white);
  color: var(--wind-deep);
}
.modal-card textarea {
  min-height: 60px;
  resize: vertical;
}
.modal-card .hint-inline {
  font-weight: 400;
  font-size: 0.8rem;
  color: var(--wind-stone);
}
/* Phase 10O Slice F — read-only field display (event-type in the edit modal,
   any other field that's structurally locked rather than disabled). Visually
   matches an input box so the form layout stays consistent, but inert. */
.modal-card .readonly-field {
  padding: 8px 10px;
  border: 1px solid var(--wind-dune);
  border-radius: 6px;
  background: var(--wind-cream, var(--wind-sand));
  color: var(--wind-stone);
  font-size: 0.95rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-weight: 600;
}

/* Phase 10j Slice D — wider modal for the Mercury outflow picker (denser
   rows than a single-column form). */
.modal-card--wide { max-width: 640px; }

.link-tx-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  max-height: 50vh;
  overflow-y: auto;
  margin: 8px 0 12px;
}
.link-tx-row {
  text-align: left;
  background: var(--wind-white);
  border: 1px solid var(--wind-dune);
  border-radius: 8px;
  padding: 10px 12px;
  cursor: pointer;
  font: inherit;
  color: inherit;
}
.link-tx-row:hover { background: var(--wind-cream, var(--wind-sand)); }
.link-tx-row__head { display: flex; gap: 0.5rem; align-items: center; flex-wrap: wrap; }
.link-tx-row__body { font-size: 0.85rem; color: var(--wind-stone); margin-top: 2px; }
.link-tx-row .badge-amber {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 0.72rem;
  font-weight: 500;
  background: var(--wind-amber);
  color: var(--wind-white);
}
.link-tx-row .badge-warn {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 0.72rem;
  font-weight: 500;
  background: var(--wind-sand);
  color: var(--wind-amber-deep);
  border: 1px solid var(--wind-amber-deep);
}
/* #100 — account-name badge on cross-account fallback rows in the picker */
.link-tx-row .badge-info {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 0.72rem;
  font-weight: 500;
  background: var(--wind-cloud, var(--wind-cream));
  color: var(--wind-stone);
  border: 1px solid var(--wind-stone-light, var(--wind-stone));
}
/* #100 — warn-shaped hint above the candidate list when cross-account
   fallback rows are present, signaling the source-account was likely wrong.
   General-purpose: not scoped to .modal-card so it can warn in batch previews
   (paystub upload, etc.) too. */
.hint--warn {
  padding: 8px 12px;
  border-radius: 6px;
  background: var(--wind-sand);
  color: var(--wind-amber-deep);
  border: 1px solid var(--wind-amber-deep);
  margin: 8px 0;
}
/* Rows that should remain inline (cost range, labor hours+type, checkbox labels) */
.modal-card .cost-range-row,
.modal-card .checkbox-row {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
}
.modal-card .cost-range-row input,
.modal-card .cost-range-row select {
  flex: 1 1 100px;
  min-width: 100px;
  display: inline-block;
  width: auto;
}
.modal-card .checkbox-row input[type="checkbox"] {
  width: auto;
  display: inline-block;
}
.modal-card .modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  margin-top: 16px;
  padding-top: 12px;
  border-top: 1px solid var(--border-soft);
}
.modal-card.wide { max-width: 720px; }

.gates-section,
.cost-amendments-section { margin: 12px 0; }
.gates-section h3,
.cost-amendments-section h3 {
  font-size: 1rem;
  margin: 0 0 8px;
  color: var(--wind-deep);
}

.gates-list,
.cost-amendments-list {
  list-style: none;
  padding: 0;
  margin: 0 0 8px;
}
.gate-item,
.cost-amendments-list li {
  padding: 6px 10px;
  background: var(--wind-amber-light);
  border-radius: 6px;
  margin-bottom: 4px;
  font-size: 0.92rem;
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}
.gate-item.cleared {
  opacity: 0.5;
  text-decoration: line-through;
}
.gate-type {
  font-size: 0.75rem;
  background: var(--border-card);
  padding: 1px 6px;
  border-radius: 8px;
  color: var(--wind-earth);
  text-transform: uppercase;
}
.gate-item .gate-act { margin-left: auto; }
.gate-item .gate-act + .gate-act { margin-left: 4px; }

.add-gate-form {
  display: flex;
  gap: 6px;
  align-items: center;
  flex-wrap: wrap;
  margin-top: 6px;
}
.add-gate-form select,
.add-gate-form input { flex: 1 1 120px; min-width: 120px; }
.add-gate-form button { flex: 0 0 auto; }

.admin-section {
  margin-top: 32px;
  padding-top: 20px;
  border-top: 1px dashed var(--border-emphatic);
}

/* #76 P2-1 — drop the dashed separator inside admin financial pages
   (/us/dice glance, /us/dice/billpay, /us/dice/lending, /us/financial,
   etc.). With 6+ summary cards stacked, the rules read as a busy ladder;
   whitespace + the cards' own surface contrast carry the rhythm cleanly.
   Other admin surfaces (/us/admin/users, /us/adults, /us/profile) keep
   their solid divider via the line-471 rule. */
.admin-financial-container .admin-section,
.dad-list-container .admin-section {
  border-top: 0;
  padding-top: 8px;
}

.events-list { margin-top: 10px; }
.event-row {
  display: grid;
  /* date / type / amount / account / desc / delete (right-aligned) */
  grid-template-columns: 110px 90px 100px 110px 1fr auto;
  gap: 8px;
  padding: 6px 10px;
  align-items: center;
  border-bottom: 1px solid var(--border-soft);
  font-size: 0.92rem;
}
/* /us/dice/expected — columnar variant. Outer row is flex (main + actions);
   inner .event-row-main holds the columnar grid so badge + confidence chip
   live in a dedicated flags column instead of shoving the type/amount/account
   cells out of alignment. Replaces the original direct-children grid that
   broke whenever a row had badges or extra action buttons (cause of the
   "× migrates around" + "Drop in freezer in the date column" bug, 2026-05-24). */
.event-row.event-row--cols {
  display: flex;
  align-items: stretch;
  flex-wrap: wrap;
  gap: 8px;
}
.event-row.event-row--cols .event-row-main {
  display: grid;
  /* date / flags / type / amount / account / desc */
  grid-template-columns: 120px 130px 90px 100px 110px 1fr;
  gap: 8px;
  align-items: center;
  flex: 1 1 auto;
  min-width: 0;
}
.event-row.event-row--cols .event-row-actions {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: flex-end;
  gap: 6px;
  flex-shrink: 0;
}
.event-row.event-row--cols .recommendation-result {
  flex-basis: 100%;
  width: 100%;
}
.event-row.event-row--cols .recommendation-result[hidden] { display: none; }
/* Inferred-pattern cards (/us/dice/inbox) have only two children — main + actions
   — so the base .event-row 6-col grid jammed .event-row-main into the 110px date
   column and the meta text wrapped one word per line (#160). Lay them out as flex:
   main grows, actions sit at the end and wrap below on narrow viewports. */
.event-row.inferred-card {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px;
}
.event-row.inferred-card .event-row-main { flex: 1 1 240px; min-width: 0; }
.event-row.inferred-card .event-row-actions { display: flex; gap: 8px; flex-shrink: 0; }
.event-row-flags {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px;
}
.event-row .event-date { white-space: nowrap; }
.event-row .event-account {
  font-family: var(--font-ui);
  font-size: 0.85rem;
  color: var(--wind-stone);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.event-row .event-delete { justify-self: end; }
/* #76 P2-5: tinted pill for the event-type column instead of plain
   colored text. Same color hierarchy (red=out, green=in, amber=correction)
   but rendered as a bordered chip so the column visually parses as a
   category label, not a free-floating word. */
.event-row .event-type {
  display: inline-block;
  padding: 1px 8px;
  border-radius: 999px;
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  text-align: center;
}
.event-row .event-type-outflow {
  color: var(--wind-red);
  background: var(--wind-red-light);
}
.event-row .event-type-inflow {
  color: var(--wind-green);
  background: var(--wind-green-light);
}
.event-row .event-type-transfer {
  color: var(--wind-deep);
  background: var(--wind-sand);
}
.event-row .event-type-correction {
  color: var(--wind-amber);
  background: var(--wind-amber-light);
}

/* Phase 10O Slice A — status badge + confidence chip for expected events.
   Posted rows render no badge/chip (would be visual noise on the dominant
   case). Expected rows pick up a dashed border + softer background so the
   row visually reads as "not yet real." */
.event-row--expected {
  background: var(--wind-sand-light, rgba(196, 137, 46, 0.06));
  border-left: 3px solid var(--wind-amber, #c4892e);
  padding-left: 8px;
}
.event-row--unscheduled {
  background: var(--wind-mist, rgba(132, 150, 168, 0.08));
  border-left: 3px solid var(--wind-mist-deep, #8496a8);
  padding-left: 8px;
}
.event-row--cancelled {
  opacity: 0.55;
  text-decoration: line-through;
}
.event-row .event-badge {
  display: inline-block;
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: 2px 6px;
  border-radius: 3px;
  background: var(--wind-amber-light, rgba(196, 137, 46, 0.15));
  color: var(--wind-amber, #c4892e);
}
.event-row .event-badge--expected {
  background: var(--wind-amber-light, rgba(196, 137, 46, 0.15));
  color: var(--wind-amber, #c4892e);
}
.event-row .event-badge--unscheduled {
  background: var(--wind-mist, rgba(132, 150, 168, 0.15));
  color: var(--wind-mist-deep, #6b7d8f);
}
.event-row .event-badge--cancelled {
  background: var(--wind-soft, rgba(0, 0, 0, 0.08));
  color: var(--wind-deep, #4a5568);
}
.event-row .event-conf {
  display: inline-block;
  font-size: 0.7rem;
  font-weight: 500;
  padding: 2px 6px;
  border-radius: 10px;
  text-transform: lowercase;
}
.event-row .event-conf--committed {
  border: 1px solid var(--wind-deep, #4a5568);
  color: var(--wind-deep, #4a5568);
}
.event-row .event-conf--likely {
  border: 1px dashed var(--wind-amber, #c4892e);
  color: var(--wind-amber, #c4892e);
}
.event-row .event-conf--discretionary {
  border: 1px dotted var(--wind-mist-deep, #8496a8);
  color: var(--wind-mist-deep, #8496a8);
  opacity: 0.85;
}
.events-section-heading {
  font-size: 0.85rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted, #6b7280);
  margin: 16px 0 8px;
}
.events-section-heading:first-child { margin-top: 0; }

/* Phase 10O Slice D — recommendation card surfaced inline below an
   unscheduled event row when "Find best date" is clicked. */
.recommendation-result {
  grid-column: 1 / -1;
  margin-top: 8px;
}
.recommendation-card {
  background: var(--wind-sand-light, rgba(196, 137, 46, 0.08));
  border-left: 4px solid var(--wind-amber, #c4892e);
  padding: 12px 16px;
  border-radius: 4px;
  line-height: 1.5;
}
.recommendation-card--no-window {
  background: var(--wind-mist, rgba(132, 150, 168, 0.08));
  border-left-color: var(--wind-mist-deep, #8496a8);
}
.find-date-btn {
  font-size: 0.85rem;
  padding: 4px 10px;
}

/* Phase 10O Slice B — reconciliation suggestions in /us/dice/inbox.
   Group = one expected event + its candidate Mercury txs. */
.reconciliation-group {
  border: 1px solid var(--wind-deep-mist, rgba(132, 150, 168, 0.25));
  border-radius: 4px;
  padding: 10px 14px;
  margin-bottom: 10px;
  background: var(--wind-sand-light, rgba(196, 137, 46, 0.04));
}
.reconciliation-group__header {
  margin-bottom: 6px;
  padding-bottom: 6px;
  border-bottom: 1px dashed var(--wind-deep-mist, rgba(132, 150, 168, 0.25));
}
.reconciliation-candidate {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 6px 0;
}
.reconciliation-candidate__line {
  flex: 1;
}
.reconciliation-candidate .btn-primary {
  font-size: 0.85rem;
  padding: 4px 10px;
}

/* Phase 10O Slice C — retro reason labels in the Mercury tx drawer. */
.retro-tag-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 0;
}
.retro-tag-text {
  flex: 1;
  padding: 4px 8px;
  background: var(--wind-sand-light, rgba(196, 137, 46, 0.06));
  border-left: 3px solid var(--wind-amber, #c4892e);
  border-radius: 3px;
  font-size: 0.9rem;
}

/* ---------------------------------------------------------------------------
   Admin financial page (Phase 9b-1)
   --------------------------------------------------------------------------- */

.admin-financial-container {
  padding-bottom: 120px;
  /* Phase 10-IA Slice 7 — wide-viewport density.
     Body content tile widens at md+/lg+/xl+ so the page no longer floats
     in a narrow center column on desktop / iPad-landscape. Mobile + tablet-
     portrait stay at the existing comfortable reading width. */
  margin-left: auto;
  margin-right: auto;
}
@media (min-width: 768px)  { .admin-financial-container { max-width: 760px; } }
@media (min-width: 1024px) { .admin-financial-container { max-width: 960px; } }
@media (min-width: 1440px) { .admin-financial-container { max-width: 1200px; } }
@media (min-width: 1880px) { .admin-financial-container { max-width: 1400px; } }

/* Phase 11c — dashboard hero (Phase 10-IA Slice 7: 4-card variant on /us/dice) */
.dashboard-hero {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
  margin: 8px 0 24px;
}
@media (max-width: 720px) { .dashboard-hero { grid-template-columns: 1fr; } }
/* 4-card variant tiles 2x2 at tablet, 4-across at desktop, 1-col on phones.
   The narrow-viewport stack avoids the 2x2 + eyebrow-wrap bug at 375px
   (cards ~187px wide can't fit "14-DAY TRAJECTORY" / "OUTSTANDING LOANS"
   without wrapping). Hover-linkable cards (debt + loans) get the same
   hover affordance as .sub-page-rail__card. */
.dashboard-hero--4col { grid-template-columns: 1fr 1fr; }
@media (max-width: 500px) { .dashboard-hero--4col { grid-template-columns: 1fr; } }
@media (min-width: 1024px) { .dashboard-hero--4col { grid-template-columns: repeat(4, 1fr); } }
/* 3-card variant (2026-05-23 — outstanding-loans card removed). Stack on
   phone + tablet portrait, 3-up only at narrow-desktop+ (>=960px). The
   prior 720px breakpoint busted at kids-mini (744) and ipad-portrait (810)
   because 7-digit debt + 14-day chart img + "−$6,800 · Mortgage (auto)"
   subtitle each need ~300-320px per card to render without overflow. #145. */
.dashboard-hero--3col { grid-template-columns: 1fr; }
@media (min-width: 960px) { .dashboard-hero--3col { grid-template-columns: repeat(3, 1fr); } }
.hero-card--debt:hover,
.hero-card--debt:focus-visible,
.hero-card--loans:hover,
.hero-card--loans:focus-visible {
  border-color: var(--sea-deep, var(--wind-stone));
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.06);
  outline: none;
}
.hero-card {
  background: var(--sea-mist);
  border-radius: 14px;
  padding: 24px 28px 20px;
  border: 1px solid var(--border-soft);
}
.hero-card .hero-eyebrow {
  font-family: var(--font-ui);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--sea-tide);
  font-weight: 500;
  margin-bottom: 8px;
}
.hero-card .hero-num {
  margin-bottom: 4px;
}
.hero-card .hero-meta {
  font-family: var(--font-ui);
  font-size: var(--text-sm);
  color: var(--wind-earth);
  margin-top: 6px;
  line-height: var(--line-ui);
}
.hero-card .hero-meta .meta-label {
  color: var(--wind-stone);
  margin-right: 4px;
}
.hero-card--trajectory .hero-spark {
  margin: 8px 0 4px;
  height: 80px;
  display: block;
}
.hero-card--trajectory .hero-spark svg {
  width: 100%;
  height: 100%;
}

/* Phase 11c — upcoming-30d timeline */
.upcoming-timeline {
  display: grid;
  gap: 4px;
  margin: 12px 0;
}
.timeline-row {
  display: grid;
  grid-template-columns: 64px 1fr auto 120px;
  gap: 12px;
  align-items: baseline;
  padding: 10px 12px;
  border-radius: 8px;
  background: var(--wind-white);
  border: 1px solid var(--border-soft);
  font-size: var(--text-sm);
}
.timeline-row .timeline-date {
  color: var(--wind-stone);
  font-variant-numeric: tabular-nums;
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.timeline-row .timeline-label { color: var(--wind-deep); font-weight: 500; }
.timeline-row .timeline-amount {
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}
.timeline-out .timeline-amount { color: var(--wind-terracotta); }
.timeline-in  .timeline-amount { color: var(--wind-green); }
.timeline-row .timeline-account { color: var(--wind-stone); font-size: var(--text-xs); text-align: right; }
@media (max-width: 720px) {
  .timeline-row {
    grid-template-columns: 56px 1fr auto;
    grid-template-rows: auto auto;
  }
  .timeline-row .timeline-account {
    grid-column: 2 / 4;
    text-align: left;
  }
}

.balances-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 12px;
  margin: 8px 0 12px;
}
.account-tile {
  background: var(--wind-white);
  border: 1px solid var(--border-card);
  border-radius: 8px;
  padding: 14px 16px;
  box-shadow: var(--shadow-subtle);
}
.account-name {
  font-size: 0.9rem;
  color: var(--wind-earth);
  margin-bottom: 4px;
}
.account-balance {
  font-size: 1.6rem;
  font-weight: 700;
  color: var(--wind-deep);
  font-variant-numeric: tabular-nums;
}
.account-asof {
  font-size: 0.78rem;
  color: var(--wind-stone);
  margin-top: 2px;
}
.account-floor {
  font-size: 0.78rem;
  color: var(--wind-amber);
  margin-top: 4px;
  font-weight: 600;
}

.snapshot-history-controls {
  display: flex;
  gap: 8px;
  align-items: center;
  margin: 8px 0;
}
.snapshot-history { margin: 6px 0; }
.snapshot-list { list-style: none; padding: 0; margin: 0; }
.snapshot-list li {
  padding: 4px 8px;
  border-bottom: 1px solid var(--border-hairline);
  font-size: 0.9rem;
  display: flex;
  align-items: center;
  gap: 4px;
}
.snapshot-date    { color: var(--wind-earth); min-width: 160px; }
.snapshot-balance { font-weight: 600; font-variant-numeric: tabular-nums; }

.commitments-list { margin: 8px 0; }
.commitment-row {
  background: var(--wind-white);
  border: 1px solid var(--border-soft);
  border-radius: 6px;
  padding: 10px 12px;
  margin-bottom: 6px;
}
.commitment-head {
  display: flex;
  align-items: center;
  gap: 6px;
}
.commitment-label {
  font-weight: 600;
  color: var(--wind-deep);
}
.commitment-meta {
  font-size: 0.85rem;
  color: var(--wind-stone);
  margin-top: 3px;
  font-variant-numeric: tabular-nums;
}
.commitment-notes { margin-top: 3px; }

.checkbox-row {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 6px 0;
}
.checkbox-row input[type="checkbox"] { width: auto; }

/* Upload preview tables (Phase 9b-2) */
.comp-preview {
  background: var(--wind-white);
  border: 1px solid var(--border-card);
  border-radius: 8px;
  padding: 14px 18px;
  margin: 10px 0;
}
.comp-preview h3 { margin: 0 0 8px; color: var(--wind-deep); font-size: 1rem; }
.preview-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.9rem;
}
.preview-table th {
  text-align: left;
  padding: 4px 10px 4px 0;
  color: var(--wind-earth);
  font-weight: 600;
}
.preview-table td {
  padding: 4px 10px;
  font-variant-numeric: tabular-nums;
}
.preview-table tr + tr th,
.preview-table tr + tr td {
  border-top: 1px solid var(--border-hairline);
}
.preview-table .section-hd {
  padding-top: 12px;
  color: var(--wind-amber);
  text-transform: uppercase;
  font-size: 0.78rem;
  letter-spacing: 0.05em;
}

/* ---------------------------------------------------------------------------
   Metis admin chat (Phase 9c)
   --------------------------------------------------------------------------- */

.metis-page { background: var(--wind-sky); }
.metis-body { padding: 16px; padding-bottom: 180px; max-width: 900px; margin: 0 auto; }

.metis-disclaimer {
  background: var(--wind-amber-light);
  border-left: 3px solid var(--wind-amber);
  padding: 10px 14px;
  border-radius: 6px;
  margin-bottom: 14px;
  font-size: 0.9rem;
  line-height: 1.35;
}

/* #117 slice 1: dvh so the message strip shrinks with the iOS keyboard
   (vh = layout viewport, stays tall → evicted the composer below it). */
.metis-messages { margin: 10px 0 16px; max-height: 70vh; max-height: 70dvh; overflow-y: auto; }
.metis-turn {
  background: var(--wind-white);
  border: 1px solid var(--border-card);
  border-radius: 8px;
  padding: 10px 14px;
  margin-bottom: 8px;
}
.metis-turn-user { background: var(--wind-amber-light); }
.metis-turn-assistant { background: var(--wind-white); }
.metis-turn-system { background: var(--surface-subtle); font-style: italic; }
.metis-turn-head { font-size: 0.75rem; color: var(--wind-stone); margin-bottom: 4px; text-transform: uppercase; letter-spacing: 0.04em; }
.metis-turn-body { font-size: 0.95rem; line-height: 1.45; color: var(--wind-deep); white-space: normal; }
.metis-summary { font-size: 0.85rem; color: var(--wind-earth); padding: 6px 0; }

.chat-compose textarea {
  width: 100%; padding: 10px 12px; border: 1px solid var(--border-emphatic); border-radius: 8px; resize: vertical;
  font-family: inherit; font-size: 0.95rem;
}
.chat-compose { display: flex; gap: 8px; align-items: flex-end; padding: 6px 0; }
.chat-compose textarea { flex: 1; }
.chat-compose button { flex: 0 0 auto; height: 44px; }

.metis-sidepanel {
  margin-top: 28px;
  padding: 12px 14px;
  background: var(--surface-subtle);
  border-radius: 8px;
}
.metis-sidepanel summary {
  cursor: pointer; font-weight: 600; color: var(--wind-deep);
}
.metis-memories { margin-top: 10px; }
.metis-memory {
  background: var(--wind-white);
  border: 1px solid var(--border-soft);
  border-radius: 6px;
  padding: 8px 12px;
  margin-bottom: 6px;
}
.metis-memory-expired { opacity: 0.5; }
.metis-memory-head { font-size: 0.8rem; color: var(--wind-earth); margin-bottom: 3px; }
.metis-memory-fact { font-size: 0.92rem; color: var(--wind-deep); }
.metis-memory-meta { margin-top: 3px; font-size: 0.75rem; }

/* Metis proposal cards (9e-4b accept/reject UI) */
.metis-proposals {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 10px;
}
.proposal-card {
  background: var(--wind-white);
  border: 1px solid var(--border-emphatic);
  border-left: 4px solid var(--wind-amber);
  border-radius: 6px;
  padding: 10px 12px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.proposal-card.proposal-status-accepted { border-left-color: var(--wind-green); }
.proposal-card.proposal-status-executed {
  border-left-color: var(--wind-green);
  background: var(--surface-subtle);
}
.proposal-card.proposal-status-rejected {
  border-left-color: var(--wind-red);
  opacity: 0.7;
}
.proposal-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
}
.proposal-kind {
  font-family: ui-monospace, SFMono-Regular, monospace;
  font-size: 0.75rem;
  background: var(--wind-amber-light);
  color: var(--wind-amber-deep);
  padding: 2px 6px;
  border-radius: 3px;
  font-weight: 600;
}
.proposal-status {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--wind-earth);
}
.proposal-summary {
  font-size: 0.95rem;
  color: var(--wind-deep);
  line-height: 1.4;
}
.proposal-reasoning {
  font-size: 0.85rem;
  color: var(--wind-earth);
  font-style: italic;
  padding-left: 10px;
  border-left: 2px solid var(--wind-dune);
}
.proposal-response {
  font-size: 0.85rem;
  color: var(--wind-stone);
  padding: 4px 8px;
  background: var(--surface-subtle);
  border-radius: 3px;
}
.proposal-meta {
  font-size: 0.72rem;
  color: var(--wind-stone);
}
.proposal-actions {
  display: flex;
  gap: 8px;
  margin-top: 4px;
}
.proposal-actions .btn-primary,
.proposal-actions .btn-secondary {
  min-height: 36px;
  padding: 6px 14px;
  font-size: 0.88rem;
}
.proposal-error {
  font-size: 0.85rem;
  color: var(--status-danger-text);
  background: var(--status-danger-bg);
  border: 1px solid var(--status-danger-border);
  padding: 6px 8px;
  border-radius: 4px;
}

/* ---------------------------------------------------------------------------
   Phase 9e-2c — Home Depot mode (narrow viewport list view)

   The /us/dad-list/list surface is the default on iPhone (per ADR-9e-3)
   and serves as the "shopping list / what do I need to grab" view. On
   narrow viewports we enlarge tap targets, stack action buttons, and
   make the "Show on map" action prominent.

   "Degraded" relative to the full design spec: no per-project grouping,
   no purchase sub-task checklists, no receipt-capture. Those land when
   9e-3 (projects) + 9e-4b (Metis purchase sub-tasks) ship. What we get
   here is a thumb-friendly flat list James can drive one-handed from
   a Home Depot cart.
   --------------------------------------------------------------------------- */

@media (max-width: 640px) {
  .dad-list-page .topic-card {
    padding: 12px 14px;
    margin-bottom: 10px;
  }
  .dad-list-page .topic-title {
    font-size: 1.05rem;
    line-height: 1.35;
  }
  .dad-list-page .topic-meta {
    font-size: 0.88rem;
    line-height: 1.5;
  }
  .dad-list-page .topic-actions {
    flex-direction: column;
    align-items: stretch;
    gap: 4px;
    margin-top: 10px;
    border-top: 1px solid var(--wind-dune);
    padding-top: 10px;
  }
  .dad-list-page .topic-actions .link-btn {
    min-height: 44px;
    padding: 10px 12px;
    text-align: left;
    text-decoration: none;
    border-radius: 6px;
    font-size: 0.95rem;
  }
  .dad-list-page .topic-actions .link-btn:hover,
  .dad-list-page .topic-actions .link-btn:focus-visible {
    background: rgba(196, 137, 46, 0.08);
    text-decoration: underline;
  }
  /* "Show on map" stands out — map icon prefix + weight. */
  .dad-list-page .topic-actions .link-btn.show-on-map {
    font-weight: 600;
  }
  .dad-list-page .topic-actions .link-btn.show-on-map::before {
    content: '🗺️  ';
  }

  /* Zone pills: larger touch targets */
  .dad-list-page .subject-pills .subject-pill,
  .dad-list-page .subject-pills .zone-pill {
    min-height: 40px;
    padding: 8px 14px;
  }

  /* Modal: full-screen-ish on narrow */
  .dad-list-page .modal-card {
    width: 100%;
    max-width: none;
    max-height: calc(100vh - 24px);
    overflow-y: auto;
    margin: 12px;
    padding: 16px;
    box-sizing: border-box;
  }
  .dad-list-page .modal-card.wide {
    max-width: none;
  }

  /* New-item button full-width */
  .dad-list-page .dad-list-toolbar #new-item-btn {
    width: 100%;
    min-height: 48px;
    font-size: 1rem;
  }
}

/* Always — outside narrow media — make "Show on map" distinguishable */
.show-on-map { font-weight: 500; }

/* ==========================================================================
   Phase 14c — /us/home rebuild.
   Server-rendered shell on <body class="home-page--14c">. The old generic
   .home-grid / .home-card / .coming-soon / .landing styles were deleted in
   Phase 15a-α (they were orphaned after the 14c rebuild deleted landing.html).
   ========================================================================== */

.home-page--14c {
  background: var(--wind-sky);
  color: var(--wind-earth);
}
/* #117 slice 4: the scroll region inside the .home-page shell. Carries the
   centered 1180px content column + side gutters that used to live on the body;
   the body is now a full-width flex column so the tab bar spans edge-to-edge.
   The old 96px bottom tab-bar clearance is gone — the bar is a flex child that
   takes real layout space now. */
.home-scroll {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  width: 100%;
  max-width: 1180px;
  margin: 0 auto;
  padding: 0 16px 24px;
}

/* Wordmark + wind streak ----------------------------------------------- */
.home-wordmark {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 24px 4px 12px;
}

.home-wordmark__streak {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.home-wordmark__text {
  font-family: 'Fraunces', Georgia, serif;
  font-size: 2.5rem;
  font-weight: 400;
  line-height: 1;
  color: var(--wind-deep);
  letter-spacing: -0.01em;
  position: relative;
  z-index: 1;
}

/* Joke band ------------------------------------------------------------ */
.home-joke {
  background: var(--wind-white);
  border: 1px solid var(--wind-dune);
  border-radius: 14px;
  padding: 20px 24px 18px;
  margin: 4px 0 20px;
  box-shadow: var(--shadow-subtle);
}

.home-joke__text {
  font-family: 'Fraunces', Georgia, serif;
  font-size: 1.45rem;
  line-height: 1.35;
  color: var(--wind-deep);
  margin: 0 0 10px;
}

/* Joke meta row: sig left + chip right, single row to reclaim vertical
   space. Replaces the old layout where sig and chip stacked on rows 3+4. */
.home-joke__meta {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
}

.home-joke__sig {
  font-size: 0.85rem;
  color: var(--wind-stone);
  font-style: italic;
}

.home-joke__chip {
  font-size: 0.85rem;
  color: var(--wind-amber);
  text-decoration: none;
  white-space: nowrap;
}
.home-joke__chip:hover { color: var(--wind-amber-hover, var(--wind-amber)); text-decoration: underline; }

/* 2-column grid (iPad landscape and up) -------------------------------- */
.home-grid-2col {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
  align-items: start;
  margin-bottom: 18px;
}

.home-grid-2col__left,
.home-grid-2col__right {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

/* Hero ----------------------------------------------------------------- */
.home-hero {
  background: var(--wind-white);
  border: 1px solid var(--wind-dune);
  border-radius: 14px;
  padding: 28px 24px;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  text-decoration: none;
  color: inherit;
  box-shadow: var(--shadow-subtle);
  flex: 1;
  --hero-tint: var(--wind-amber);
}

a.home-hero:hover { box-shadow: var(--shadow-card-hover); }

.home-hero__disc {
  width: 120px;
  height: 120px;
  border-radius: 50%;
  background: var(--hero-tint);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 18px;
  flex-shrink: 0;
  border: none;
  cursor: pointer;
  padding: 0;
  transition: transform 150ms cubic-bezier(0.2, 0.7, 0.2, 1), box-shadow 150ms;
}

.home-hero__disc:hover,
.home-hero__disc:focus-visible {
  transform: scale(1.04);
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.12);
  outline: none;
}

.home-hero__initial {
  font-family: 'Fraunces', Georgia, serif;
  font-size: 2.5rem;
  font-weight: 500;
  color: var(--wind-deep);
  line-height: 1;
}

.home-hero__name {
  font-family: 'Fraunces', Georgia, serif;
  font-size: 1.25rem;
  color: var(--wind-deep);
  margin-bottom: 6px;
}

.home-hero__hook {
  font-size: 0.95rem;
  color: var(--wind-stone);
  line-height: 1.4;
  max-width: 28ch;
}

.home-hero__see-all {
  margin-top: 18px;
  font-size: 0.85rem;
  background: transparent;
  border: 1px solid var(--wind-dune);
  border-radius: 999px;
  padding: 6px 14px;
  color: var(--wind-earth);
  cursor: pointer;
}
.home-hero__see-all:hover { background: var(--wind-sand); }

/* Adult hero — agent strip at hero size. Reuses .agent-strip primitive. */
.home-hero--adult.agent-strip--hero {
  position: static;
  flex-direction: column;
  gap: 0;
  padding: 28px 24px;
  background: var(--wind-white);
  border-bottom: none;
  margin-bottom: 0;
}

.home-hero--adult .home-hero__disc {
  --agent-tint: var(--hero-tint);
  background: var(--hero-tint);
  color: var(--wind-deep);
}

.home-hero--adult .home-hero__form {
  display: flex;
  width: 100%;
  align-items: stretch;
  gap: 8px;
  margin-top: 16px;
}

/* Right-column cards --------------------------------------------------- */
.home-card--chore,
.home-card--chat,
.home-card--next-up {
  background: var(--wind-white);
  border: 1px solid var(--wind-dune);
  border-radius: 14px;
  padding: 16px 18px;
  text-decoration: none;
  color: inherit;
  display: block;
  box-shadow: var(--shadow-subtle);
}

a.home-card--chore:hover,
a.home-card--chat:hover,
a.home-card--next-up:hover { box-shadow: var(--shadow-card-hover); }

.home-card__label {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--wind-stone);
  margin-bottom: 8px;
}

.home-card__title {
  font-family: 'Fraunces', Georgia, serif;
  font-size: 1.15rem;
  color: var(--wind-deep);
}

.home-card__empty {
  font-size: 0.9rem;
  color: var(--wind-stone);
  font-style: italic;
  min-height: 2.4em;
  display: flex;
  align-items: center;
}

.chat-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 4px;
}

.chat-row__avatar {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 0.75rem;
  color: white;
  font-weight: 600;
}

.chat-row__name {
  font-size: 0.85rem;
  color: var(--wind-deep);
  font-weight: 600;
}

.chat-row__time {
  font-size: 0.8rem;
  color: var(--wind-stone);
}

.chat-row__preview {
  font-size: 0.9rem;
  color: var(--wind-earth);
  line-height: 1.4;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Next-up card (Phase 14g — replaces presence row) -------------------- */
.next-up__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.next-up__row {
  display: grid;
  /* Phase 14h #52: was `64px 60px 1fr auto` — 64px wasn't wide enough for
     `TOMORROW` (needs ~81px), causing the day label to bleed into the time
     column. Auto-sizing the day + time columns sizes them to the widest
     content found across all rows in the grid, so TODAY/TOMORROW rows
     stay aligned and the label cannot overflow into the time. */
  grid-template-columns: auto auto 1fr auto;
  align-items: center;
  gap: 8px;
  font-size: 0.9rem;
  color: var(--wind-deep);
  min-width: 0;
}

.next-up__day {
  font-size: 0.78rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--wind-stone);
}

.next-up__time {
  font-size: 0.85rem;
  color: var(--wind-earth);
  font-variant-numeric: tabular-nums;
}

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

.next-up__pill {
  font-size: 0.7rem;
  border-radius: 4px;
  padding: 1px 6px;
  white-space: nowrap;
}

.next-up__see-all {
  margin-top: 8px;
  font-size: 0.85rem;
  color: var(--wind-amber);
}

/* Utility row ---------------------------------------------------------- */
.home-utility {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 10px;
  margin-top: 4px;
}

.home-utility__item {
  background: var(--wind-white);
  border: 1px solid var(--wind-dune);
  border-radius: 12px;
  padding: 16px 8px;
  text-decoration: none;
  color: var(--wind-deep);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  font-size: 0.85rem;
  font-weight: 500;
  box-shadow: var(--shadow-subtle);
}

.home-utility__item:hover { box-shadow: var(--shadow-card-hover); }

.home-utility__icon { color: var(--wind-amber); display: inline-flex; }
.home-utility__icon svg { width: 24px; height: 24px; }

/* iPad portrait + iPhone collapse to single column --------------------- */
@media (max-width: 1023px) {
  .home-grid-2col { grid-template-columns: 1fr; }
  /* Phase 14h #1: in 2-col landscape the hero takes flex: 1 to match the
     right column's stack height. In 1-col there is no tall sibling, so
     flex: 1 stretches the hero to fill all leftover viewport space —
     producing a tall hero with a void below the disc. Reset to auto
     sizing in single-column. */
  .home-hero { flex: 0 1 auto; }
}

@media (max-width: 743px) {
  .home-scroll { padding: 0 12px 24px; }
  .home-wordmark__text { font-size: 2rem; }
  .home-joke__text { font-size: 1.25rem; }
  .home-hero { padding: 22px 18px; }
  .home-hero__disc { width: 96px; height: 96px; }
  .home-hero__initial { font-size: 2rem; }
}

/* ==========================================================================
   Phase 14f — theme toggle UI (profile radio + home footer button) +
   accessibility utility.
   ========================================================================== */

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

.theme-radio {
  border: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.theme-radio label {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 0.95rem;
  color: var(--wind-deep);
  cursor: pointer;
  padding: 8px 10px;
  border-radius: 8px;
  border: 1px solid var(--wind-dune);
  background: var(--wind-white);
  transition: background 0.15s, border-color 0.15s;
}
.theme-radio label:hover { background: var(--wind-sand); }
.theme-radio input[type="radio"] {
  accent-color: var(--wind-amber);
  width: 18px;
  height: 18px;
}

/* Avatar popover menu (Phase 14g) -------------------------------------- */
.me-menu-wrap {
  position: relative;
  display: inline-flex;
}

.me-menu {
  /* Inherits [popover] positioning from the user agent. We anchor visually
     to the avatar via margin + a top arrow and rely on the page-header
     placing the avatar in the top-right corner. */
  margin: 0;
  padding: 8px;
  border: 1px solid var(--wind-dune);
  border-radius: 12px;
  background: var(--wind-white);
  box-shadow: var(--shadow-card-hover);
  min-width: 220px;
  max-width: 280px;
  color: var(--wind-deep);
  font-size: 0.95rem;
  /* Native [popover] elements inset to viewport center by default; we
     position to the top-right of the screen so the menu lands under the
     avatar regardless of header layout. */
  inset: auto 16px auto auto;
  top: 64px;
}

.me-menu__item {
  display: block;
  padding: 10px 12px;
  border-radius: 8px;
  text-decoration: none;
  color: inherit;
  background: transparent;
  border: 0;
  width: 100%;
  text-align: left;
  font: inherit;
  cursor: pointer;
}
.me-menu__item:hover,
.me-menu__item:focus-visible {
  background: var(--wind-sand);
  outline: none;
}
.me-menu__item--danger { color: var(--wind-stone); }
.me-menu__item--danger:hover { background: var(--wind-sand); color: var(--wind-deep); }

.me-menu__divider {
  border: 0;
  border-top: 1px solid var(--wind-dune);
  margin: 6px 4px;
}

.me-menu__group {
  padding: 6px 4px;
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}

.me-menu__group-label {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--wind-stone);
  width: 100%;
  padding: 0 8px 4px;
}

.me-menu__theme {
  flex: 1 1 auto;
  min-height: 36px;
  padding: 0 10px;
  border-radius: 8px;
  border: 1px solid var(--wind-dune);
  background: var(--wind-white);
  color: var(--wind-deep);
  font: inherit;
  font-size: 0.85rem;
  cursor: pointer;
  white-space: nowrap;
}
.me-menu__theme:hover { background: var(--wind-sand); }
.me-menu__theme.is-active {
  background: var(--wind-amber);
  color: #fff;
  border-color: var(--wind-amber);
}

/* ===========================================================================
 * Phase 17a/b-lite — kid finances page (/us/me/finances)
 * Minimal additions: forecaster sliders, portfolio table, summary rows.
 * Reuses .dashboard-hero / .hero-card / .hero-num / .chores-container.
 * =========================================================================== */

.me-finances-container {
  max-width: 920px;
  padding-bottom: 6rem;
}

.me-finances-page .page-header {
  position: relative;
}

.page-header__back {
  position: absolute;
  top: 0.6rem;
  left: 1rem;
  font-size: 0.85rem;
  color: var(--wind-deep);
  opacity: 0.7;
  text-decoration: none;
}

.page-header__back:hover { opacity: 1; }

.me-section {
  background: var(--surface-1, var(--wind-white));
  border: 1px solid var(--surface-border, rgba(0, 0, 0, 0.06));
  border-radius: 14px;
  padding: 1.25rem 1.5rem;
  margin-bottom: 1.25rem;
}

.me-section h2 {
  font-size: 1.1rem;
  margin: 0 0 0.5rem 0;
  color: var(--wind-deep);
}

.forecaster {
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
  margin-top: 1rem;
}

.forecaster-row {
  display: grid;
  grid-template-columns: 9rem 1fr 6rem;
  align-items: center;
  gap: 0.75rem;
}

.forecaster-row label {
  font-weight: 600;
  font-size: 0.95rem;
}

.forecaster-row input[type="range"] {
  accent-color: var(--wind-amber);
}

.forecaster-val {
  text-align: right;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  color: var(--wind-deep);
}

.forecaster-result {
  margin-top: 1rem;
  padding-top: 1rem;
  border-top: 1px dashed var(--surface-border, rgba(0, 0, 0, 0.1));
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.forecaster-final {
  display: flex;
  align-items: baseline;
  gap: 0.75rem;
}

.forecaster-eyebrow {
  font-size: 0.7rem;
  letter-spacing: 0.08em;
  font-weight: 700;
  color: var(--wind-deep);
  opacity: 0.6;
}

.forecaster-num {
  font-family: var(--font-display, serif);
  font-size: 1.85rem;
  color: var(--wind-amber);
  font-variant-numeric: tabular-nums;
}

.forecaster-breakdown {
  font-size: 0.85rem;
  color: var(--wind-deep);
  opacity: 0.75;
}

@media (max-width: 540px) {
  .forecaster-row {
    grid-template-columns: 1fr 5rem;
    grid-template-areas:
      "label val"
      "input input";
    row-gap: 0.4rem;
  }
  .forecaster-row label { grid-area: label; }
  .forecaster-row input[type="range"] { grid-area: input; }
  .forecaster-val { grid-area: val; }
}

/* Portfolio summary + table */

.portfolio-summary {
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem;
  margin-bottom: 1rem;
}

.portfolio-summary-row {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}

.portfolio-summary-label {
  font-size: 0.7rem;
  letter-spacing: 0.08em;
  font-weight: 700;
  color: var(--wind-deep);
  opacity: 0.6;
}

.portfolio-summary-val {
  font-family: var(--font-display, serif);
  font-size: 1.1rem;
  font-variant-numeric: tabular-nums;
}

.portfolio-summary-val.pos { color: #2f7a3a; }
.portfolio-summary-val.neg { color: #b94f3f; }

.portfolio-kind-heading {
  font-size: 0.95rem;
  margin: 1.25rem 0 0.5rem 0;
  font-weight: 600;
  color: var(--wind-deep);
  opacity: 0.85;
}

.portfolio-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.9rem;
}

.portfolio-table th,
.portfolio-table td {
  padding: 0.5rem 0.75rem;
  text-align: left;
  border-bottom: 1px solid var(--surface-border, rgba(0, 0, 0, 0.05));
}

.portfolio-table th {
  font-weight: 700;
  font-size: 0.7rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--wind-deep);
  opacity: 0.6;
}

.portfolio-table .num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.portfolio-table .pos { color: #2f7a3a; }
.portfolio-table .neg { color: #b94f3f; }

.portfolio-symbol {
  font-weight: 700;
  letter-spacing: 0.02em;
}

.portfolio-name {
  color: var(--wind-deep);
  opacity: 0.75;
  max-width: 14rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

@media (max-width: 540px) {
  .portfolio-table { font-size: 0.8rem; }
  .portfolio-table th,
  .portfolio-table td { padding: 0.4rem 0.4rem; }
  .portfolio-name { max-width: 6rem; }
}

.me-finances-empty {
  text-align: center;
  margin-top: 3rem;
  color: var(--wind-deep);
  opacity: 0.6;
}

/* Phase 17a-fu — admin kid-portfolios page (/us/adults/kid-portfolios) */

.kid-portfolios-container {
  max-width: 1100px;
  padding-bottom: 6rem;
}

.kid-section-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-bottom: 0.75rem;
}

.kid-section-header h2 {
  margin: 0;
}

.kid-section-actions {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.admin-portfolio-table th,
.admin-portfolio-table td {
  font-size: 0.85rem;
}

.admin-portfolio-table .row-actions {
  text-align: right;
  white-space: nowrap;
}

.btn-text {
  background: transparent;
  border: none;
  color: var(--wind-amber);
  cursor: pointer;
  font-size: 0.85rem;
  padding: 0.25rem 0.5rem;
  font-weight: 600;
}

.btn-text:hover { text-decoration: underline; }

.btn-text--danger {
  color: #b94f3f;
}

.admin-portfolio-table .stale {
  color: #b9803f;
  font-style: italic;
}

@media (max-width: 720px) {
  .admin-portfolio-table { font-size: 0.78rem; }
  .admin-portfolio-table th,
  .admin-portfolio-table td {
    padding: 0.35rem 0.35rem;
  }
  .admin-portfolio-table .portfolio-name {
    max-width: 6rem;
  }
}

/* Modal form rows */
.kid-portfolios-page .modal-card label {
  display: block;
  margin-bottom: 0.75rem;
  font-weight: 600;
}

.kid-portfolios-page .modal-card label input,
.kid-portfolios-page .modal-card label select {
  display: block;
  width: 100%;
  margin-top: 0.3rem;
  padding: 0.5rem;
  border-radius: 6px;
  border: 1px solid var(--surface-border, rgba(0, 0, 0, 0.15));
  font-size: 1rem;
  color: var(--wind-deep);
  background: var(--wind-white);
}

.kid-portfolios-page .modal-card .form-row {
  display: flex;
  gap: 0.75rem;
}

.kid-portfolios-page .modal-card .form-row__col {
  flex: 1;
}

.kid-portfolios-page .modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.5rem;
  margin-top: 1rem;
}

/* ---------------------------------------------------------------------------
   Phase 10L Slice 0 — /us/dice/taxonomy
   --------------------------------------------------------------------------- */

.tax-row {
  display: grid;
  grid-template-columns: 24px 1fr auto;
  gap: 12px;
  padding: 10px 12px;
  align-items: start;
  border-bottom: 1px solid var(--border-soft);
}

.tax-row__handle {
  cursor: grab;
  color: var(--wind-stone);
  user-select: none;
  font-size: 1.1rem;
  line-height: 1.4;
  letter-spacing: -0.2em;
  padding-top: 2px;
}
.tax-row[draggable="false"] .tax-row__handle { cursor: default; opacity: 0.3; }
.tax-row--dragging { opacity: 0.5; }
.tax-row--drop-above { border-top: 2px solid var(--wind-amber); }
.tax-row--drop-below { border-bottom: 2px solid var(--wind-amber); }

.tax-row__main { min-width: 0; }
.tax-row__top {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
}
.tax-row__slug {
  font-family: var(--font-ui);
  font-size: 0.78rem;
  background: var(--wind-sand);
  color: var(--wind-stone);
  padding: 1px 6px;
  border-radius: 4px;
}
.tax-row__desc {
  margin-top: 4px;
  font-size: 0.88rem;
  color: var(--wind-stone);
}
.tax-row__meta {
  margin-top: 4px;
  font-size: 0.78rem;
}

.tax-row__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-self: center;
}
.tax-row__actions button {
  padding: 4px 10px;
  font-size: 0.85rem;
}
.tax-row__up, .tax-row__down {
  min-width: 32px;
  padding: 4px 8px;
}

.tax-row--archived {
  opacity: 0.55;
  background: var(--wind-sand);
}
.tax-row--archived .tax-row__slug { text-decoration: line-through; }

.tax-pill {
  display: inline-block;
  padding: 1px 8px;
  border-radius: 999px;
  font-size: 0.68rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  background: var(--wind-amber-light);
  color: var(--wind-amber);
}
.tax-pill--archived {
  background: var(--wind-sand);
  color: var(--wind-stone);
}

.tax-color-swatch {
  display: inline-block;
  width: 14px;
  height: 14px;
  border-radius: 3px;
  border: 1px solid var(--border-soft);
  vertical-align: middle;
}

/* ---------------------------------------------------------------------------
   Phase 10L Slice A — /us/dice/mercury-transactions
   New register-table primitive. Documented in docs/design-system.md.
   --------------------------------------------------------------------------- */

/* Failed-status warning banner */
/* Per-account tab strip on /us/dice/mercury-transactions. Account is the
   primary axis when scanning the register; defaulting to one account keeps
   the visual model "you are looking at THIS account" rather than dumping a
   mixed stream. The Account filter dropdown was removed in favor of these
   tabs (post-10c v2 design rework). */
.register-tabs {
  display: flex;
  gap: 4px;
  margin: 0 0 12px 0;
  border-bottom: 1px solid var(--border-soft);
  overflow-x: auto;
  scrollbar-width: thin;
}
.register-tab {
  appearance: none;
  background: transparent;
  border: 0;
  border-bottom: 2px solid transparent;
  padding: 8px 14px;
  margin: 0;
  font: inherit;
  font-size: 0.9rem;
  color: var(--wind-stone);
  cursor: pointer;
  white-space: nowrap;
  transition: color 0.12s, border-color 0.12s, background 0.12s;
}
.register-tab:hover {
  color: var(--wind-deep);
  background: var(--surface-subtle);
}
.register-tab.is-active {
  color: var(--wind-deep);
  border-bottom-color: var(--wind-amber);
  font-weight: 600;
}
.register-tab--all {
  margin-left: auto; /* push "All accounts" to the right end of the strip */
}
.register-tab:focus-visible {
  outline: 2px solid var(--wind-amber);
  outline-offset: -2px;
}

.failed-banner {
  display: flex;
  gap: 8px;
  align-items: center;
  padding: 8px 12px;
  margin: 0 0 12px 0;
  background: var(--wind-amber-light);
  color: var(--wind-amber);
  border: 1px solid var(--border-soft);
  border-radius: 6px;
  font-size: 0.9rem;
}
.failed-banner__count {
  display: inline-block;
  min-width: 28px;
  padding: 1px 8px;
  border-radius: 999px;
  background: var(--wind-amber);
  color: white;
  font-weight: 700;
  text-align: center;
}

/* Collapsible filter panel */
.filter-panel {
  border: 1px solid var(--border-soft);
  border-radius: 8px;
  margin: 0 0 12px 0;
  background: var(--surface-subtle);
}
.filter-panel > summary {
  list-style: none;
  cursor: pointer;
  padding: 10px 14px;
  display: flex;
  gap: 12px;
  align-items: center;
}
.filter-panel > summary::-webkit-details-marker { display: none; }
.filter-panel > summary::after {
  content: '▾';
  margin-left: auto;
  color: var(--wind-stone);
  transition: transform 0.15s;
}
.filter-panel[open] > summary::after { transform: rotate(180deg); }
.filter-panel__label { font-weight: 600; }

.filter-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 10px;
  padding: 0 14px 14px;
}
.filter-field { display: flex; flex-direction: column; gap: 4px; }
.filter-field--wide { grid-column: 1 / -1; }
.filter-field label { font-size: 0.78rem; color: var(--wind-stone); }
.filter-field select, .filter-field input {
  padding: 6px 10px;
  font-size: 0.92rem;
  border: 1px solid var(--border-emphatic);
  border-radius: 4px;
  background: var(--surface-subtle);
  color: var(--wind-earth);
}
.filter-actions {
  grid-column: 1 / -1;
  display: flex;
  justify-content: flex-end;
  gap: 8px;
}

/* Register-table toolbar (sort + count) */
.register-toolbar {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 12px 0 6px 0;
  font-size: 0.9rem;
}
.register-toolbar__spacer { flex: 1; }

/* Register table */
.register {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.92rem;
}
.register thead th {
  text-align: left;
  font-size: 0.74rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--wind-stone);
  padding: 6px 10px;
  border-bottom: 1px solid var(--border-emphatic);
}
.register tbody tr {
  cursor: pointer;
  border-bottom: 1px solid var(--border-hairline);
}
.register tbody tr:hover { background: var(--surface-subtle); }
.register tbody td { padding: 8px 10px; vertical-align: middle; }
.register__amt { text-align: right; font-variant-numeric: tabular-nums; }
.register__amt--in { color: var(--wind-green); }
.register__amt--out { color: var(--wind-red); }

.register-cp { font-weight: 500; }
.register-cp__sub { display: block; font-size: 0.78rem; color: var(--wind-stone); font-weight: 400; }

.register-pill {
  display: inline-block;
  padding: 1px 8px;
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  border-radius: 999px;
  background: var(--wind-sand);
  color: var(--wind-stone);
}
.register-pill--failed { background: var(--wind-amber-light); color: var(--wind-amber); }
.register-pill--pending { background: var(--surface-subtle); color: var(--wind-stone); border: 1px dashed var(--border-soft); }
/* #149 — 'excluded' (failed/cancelled/reversed, $0 moved): muted, de-emphasized. */
.register-pill--excluded { background: transparent; color: var(--text-muted, #6b7280); border: 1px dashed var(--border-soft); text-transform: none; }

.register-classify {
  font-size: 0.85rem;
  padding: 3px 8px;
  border: 1px solid var(--border-soft);
  border-radius: 4px;
  background: var(--surface-subtle);
}

.register-pagination {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 12px;
  justify-content: center;
}

/* Mobile: card-stack at <768px (per kickoff lock #3) */
@media (max-width: 767px) {
  .register thead { display: none; }
  .register, .register tbody, .register tr, .register td { display: block; width: 100%; }
  .register tbody tr {
    padding: 10px 12px;
    border: 1px solid var(--border-soft);
    border-radius: 8px;
    margin-bottom: 8px;
  }
  .register tbody td {
    padding: 4px 0;
    display: grid;
    grid-template-columns: 110px 1fr;
    gap: 8px;
  }
  .register tbody td::before {
    content: attr(data-label);
    font-size: 0.74rem;
    color: var(--wind-stone);
    text-transform: uppercase;
    letter-spacing: 0.04em;
  }
  .register__amt { text-align: left; }
}

/* Slide-in detail drawer (right-anchored modal dialog) */
.detail-drawer {
  margin: 0 0 0 auto;
  padding: 0;
  border: none;
  width: min(560px, 100vw);
  height: 100vh;
  max-height: 100vh;
  max-width: 100vw;
  background: var(--bg-primary, white);
  color: var(--wind-earth);
}
.detail-drawer::backdrop {
  background: rgba(0,0,0,0.35);
}
.detail-drawer[open] { animation: slide-in-right 0.2s ease-out; }
@keyframes slide-in-right {
  from { transform: translateX(100%); }
  to { transform: translateX(0); }
}
@media (prefers-reduced-motion: reduce) {
  .detail-drawer[open] { animation: none; }
}
.detail-drawer__inner { display: flex; flex-direction: column; height: 100%; }
.detail-drawer__header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  padding: 16px 18px 12px;
  border-bottom: 1px solid var(--border-soft);
}
.detail-drawer__eyebrow { margin: 0 0 2px 0; }
.detail-drawer__header h2 { margin: 0; font-size: 1.1rem; }
.detail-drawer__body {
  flex: 1;
  overflow-y: auto;
  padding: 16px 18px 80px;
}
.detail-section { margin-bottom: 18px; }
.detail-section h3 {
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--wind-stone);
  margin: 0 0 6px 0;
}
.detail-grid {
  display: grid;
  grid-template-columns: 130px 1fr;
  row-gap: 4px;
  column-gap: 12px;
  margin: 0;
  font-size: 0.9rem;
}
.detail-grid dt { color: var(--wind-stone); }
/* Phase 10N Slice C — soften value text in dark mode. Default body color
   (--wind-deep in dark) ran near-white against the dark drawer bg; user
   2026-05-23 PM: "this is very bright." Stepped down to --wind-earth for
   a meaningful contrast reduction without losing legibility. */
.detail-grid dd { color: var(--wind-earth); margin: 0; }
.detail-grid dd { margin: 0; word-break: break-word; }

.detail-classify-row {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
}
.detail-bridge {
  padding: 6px 10px;
  margin-bottom: 6px;
  border: 1px solid var(--border-soft);
  border-radius: 4px;
  font-size: 0.88rem;
}
.detail-bridge a { color: var(--wind-deep); text-decoration: underline; }

.detail-audit-entry {
  padding: 6px 0;
  border-bottom: 1px solid var(--border-hairline);
  font-size: 0.85rem;
}
.detail-audit-entry:last-child { border-bottom: none; }
.detail-audit-entry__meta { color: var(--wind-stone); font-size: 0.78rem; }

.detail-raw {
  font-size: 0.78rem;
  background: var(--surface-subtle);
  padding: 10px;
  border-radius: 4px;
  overflow-x: auto;
  white-space: pre-wrap;
  word-break: break-word;
}

/* ---------------------------------------------------------------------------
   Phase 10L Slice C — /us/dice/lending kind chips + kind badge
   --------------------------------------------------------------------------- */

.kind-chip {
  font-size: 0.85rem;
  padding: 4px 10px;
}

/* Kind badge used inline on lending rows. Subdued tint so it sits next to
   the bolder status badge without competing. */
.lending-list .badge-kind,
.badge-kind {
  display: inline-block;
  padding: 1px 8px;
  border-radius: 999px;
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  background: var(--wind-sand);
  color: var(--wind-stone);
}

/* ---------------------------------------------------------------------------
   Phase 10L Slice B — Closed accordions on /us/dice/debt + closed-row tone.
   --------------------------------------------------------------------------- */

.closed-accordion {
  margin-top: 1rem;
  border: 1px solid var(--border-soft);
  border-radius: 8px;
  background: var(--surface-subtle);
}
.closed-accordion > summary {
  cursor: pointer;
  padding: 8px 12px;
  font-weight: 600;
  list-style: none;
  display: flex;
  gap: 8px;
  align-items: center;
}
.closed-accordion > summary::-webkit-details-marker { display: none; }
.closed-accordion > summary::after {
  content: '▾';
  margin-left: auto;
  color: var(--wind-stone);
  transition: transform 0.15s;
}
.closed-accordion[open] > summary::after { transform: rotate(180deg); }
.closed-accordion > p,
.closed-accordion > .events-list {
  padding: 0 12px 8px;
}

/* Subdued tone on closed cards/loans so they read as historical without
   disappearing entirely. */
.event-row.is-closed {
  opacity: 0.65;
}
.event-row.is-closed .event-title { text-decoration: line-through; text-decoration-color: var(--wind-stone); }

/* /us/dice/debt — credit-card-row + installment-loan-row override the .event-row
   grid (which was sized for the /us/dice/expected page: 6 narrow columns). Debt
   rows have only 2 children (.event-row-main flex-grows; .event-row-actions
   stays inline-row), so override to flex. Without this the row inherits the
   6-column grid template, the action buttons stack vertically, and the title
   wraps every few characters. Pre-existed before Phase 10N Slice A; surfaced
   2026-05-23 when James loaded /us/dice/debt after Slice A landed.
   Bug-class: shared .event-row CSS reused across surfaces with different
   child structure (sister to #76 P2-5 inbox-row split). */
.event-row.credit-card-row,
.event-row.installment-loan-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  padding: 8px 12px;
}
.event-row.credit-card-row .event-row-main,
.event-row.installment-loan-row .event-row-main {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.event-row.credit-card-row .event-title,
.event-row.installment-loan-row .event-title {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  font-weight: 600;
}
.event-row.credit-card-row .event-meta,
.event-row.installment-loan-row .event-meta {
  font-size: 0.85rem;
  color: var(--wind-stone);
}
.event-row.credit-card-row .event-row-actions,
.event-row.installment-loan-row .event-row-actions {
  display: flex;
  flex-direction: row;
  gap: 6px;
  flex-shrink: 0;
  flex-wrap: wrap;
}

/* Phase 10N Slice A.3 — per-row visibility pills (M for Metis, H for Hestia).
   Click to toggle the visible_to_* flag without opening the edit modal.
   Sized small + monospaced so two pills next to a row title don't take
   meaningful space. Uses design-system color tokens so dark mode works. */
.visibility-pill {
  display: inline-block;
  padding: 0 6px;
  border-radius: 8px;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  line-height: 1.5;
  cursor: pointer;
  user-select: none;
  border: 1px solid transparent;
  transition: background 0.1s, border-color 0.1s;
}
.visibility-pill[data-current="0"] {
  background: transparent;
  color: var(--wind-stone);
  border-color: var(--border-soft);
}
.visibility-pill[data-current="0"]:hover {
  border-color: var(--wind-stone);
}
.visibility-pill[data-current="1"][data-axis="metis"] {
  background: var(--wind-green-light);
  color: var(--wind-green);
  border-color: var(--wind-green);
}
.visibility-pill[data-current="1"][data-axis="hestia"] {
  background: var(--wind-amber-light);
  color: var(--wind-amber);
  border-color: var(--wind-amber);
}

/* /us/dice/inbox — needs-review row.
   The original surfaces page reused .event-row's 6-column grid for this
   row, but the inbox renders 7 children with different intent (date /
   account / amount / desc / classify-select / status). The shared grid
   pinned the description column at 110px and gave the select 1fr — a
   11/10 footgun. This grid sizes for the inbox's actual content: desc
   is the elastic column, classify-select is fixed-width.
   Auto-save on change replaces the per-row Save button (Phase post-10c v2). */
.inbox-row {
  display: grid;
  grid-template-columns: 80px 100px 90px 1fr 220px 70px;
  gap: 10px;
  padding: 8px 10px;
  align-items: center;
  border-bottom: 1px solid var(--border-soft);
  font-size: 0.92rem;
}
.inbox-row__date { white-space: nowrap; color: var(--wind-stone); font-size: 0.85rem; }
.inbox-row__account {
  font-family: var(--font-ui);
  font-size: 0.85rem;
  color: var(--wind-stone);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.inbox-row__amt {
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.inbox-row__amt.outflow { color: var(--wind-red); }
.inbox-row__amt.inflow { color: var(--wind-green); }
.inbox-row__desc { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.inbox-row .row-classify {
  width: 100%;
  padding: 6px 8px;
  border: 1px solid var(--border-emphatic);
  border-radius: 4px;
  background: var(--surface-subtle);
  color: var(--wind-earth);
  font-size: 0.88rem;
}
.inbox-row .row-status {
  font-size: 0.78rem;
  color: var(--wind-stone);
  white-space: nowrap;
}

/* Mobile: stack the row as a card. */
@media (max-width: 767px) {
  .inbox-row {
    grid-template-columns: auto 1fr;
    grid-template-areas:
      "date    amount"
      "account amount"
      "desc    desc"
      "select  select"
      "status  status";
    row-gap: 4px;
  }
  .inbox-row__date    { grid-area: date; }
  .inbox-row__account { grid-area: account; }
  .inbox-row__amt     { grid-area: amount; }
  .inbox-row__desc    { grid-area: desc; }
  .inbox-row .row-classify { grid-area: select; }
  .inbox-row .row-status   { grid-area: status; }
}
