/*
 * app.css — layout and components. Uses ONLY the custom properties from tokens.css
 * (no raw colors, fonts, sizes, radii or shadows here). Media queries must repeat the two
 * breakpoints literally: 768px (--bp-md) and 992px (--bp-lg).
 *
 * Sections: base · tones · shell (sidebar, top bar, bottom bar, sheet, popovers) · page header ·
 * cards · money · badges · buttons · forms (money input, Thai date picker) · tables · dialogs ·
 * feedback · dashboard · expenses · component gallery · charts · sample review · the money pages of
 * phases 2–5 · phase 6 (PWA update message, offline page, quick entry, API tokens) · motion
 */

/* ================================================================== base */
html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scroll-padding-top: calc(var(--topbar-h-compact) + env(safe-area-inset-top) + var(--sp-4));
  /* Keyboard focus scrolled into view must not end up behind the fixed bottom bar */
  scroll-padding-bottom: calc(var(--bottom-nav-h) + env(safe-area-inset-bottom) + var(--sp-4));
}

/* Style-sample pages: also clear the review dock button that floats above the bottom bar */
html:has(.review-dock) {
  scroll-padding-bottom: calc(var(--bottom-nav-h) + env(safe-area-inset-bottom) + var(--sp-3) + var(--touch-min) + var(--sp-4));
}

@media (min-width: 992px) {
  html {
    scroll-padding-top: calc(var(--topbar-h) + var(--sp-4));
    scroll-padding-bottom: 0;
  }

  html:has(.review-dock) {
    scroll-padding-bottom: calc(var(--sp-5) + var(--touch-min) + var(--sp-4));
  }
}

body {
  background-color: var(--c-bg);
  color: var(--c-text);
  font-family: var(--font-body);
  font-size: var(--fs-base);
  line-height: var(--lh-body);
}

a {
  color: var(--c-link);
  text-underline-offset: 0.2em;
}

a:hover {
  color: var(--c-link);
}

h1, h2, h3, h4 {
  color: inherit;
  line-height: var(--lh-heading);
}

code {
  color: var(--c-brand-fg);
}

:focus-visible {
  outline: var(--focus-w) solid var(--c-focus);
  outline-offset: var(--focus-offset);
}

.bi {
  display: inline-block;
  flex-shrink: 0;
  width: 1em;
  height: 1em;
  fill: currentColor;
  vertical-align: -0.125em;
}

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

.skip-link {
  position: absolute;
  top: var(--sp-3);
  left: var(--sp-3);
  z-index: var(--z-toast);
  display: inline-flex;
  align-items: center;
  min-height: var(--touch-min);
  padding: var(--sp-2) var(--sp-4);
  border-radius: var(--radius-md);
  background: var(--c-surface);
  color: var(--c-text);
  font-weight: var(--fw-bold);
  box-shadow: var(--shadow-raised);
  transform: translateY(-300%);
}

.skip-link:focus {
  transform: none;
}

/* ================================================================== tones */
/* Every colored component reads --tone-*; body / cards / buttons pick the tone with .tone-X */
:root,
.tone-brand {
  --tone-fg: var(--c-brand-fg);
  --tone-bg: var(--c-brand-bg);
  --tone-solid: var(--c-brand-solid);
  --tone-solid-text: var(--c-brand-solid-text);
}
.tone-income {
  --tone-fg: var(--c-income-fg);
  --tone-bg: var(--c-income-bg);
  --tone-solid: var(--c-income-solid);
  --tone-solid-text: var(--c-income-solid-text);
}
.tone-expense {
  --tone-fg: var(--c-expense-fg);
  --tone-bg: var(--c-expense-bg);
  --tone-solid: var(--c-expense-solid);
  --tone-solid-text: var(--c-expense-solid-text);
}
.tone-debt {
  --tone-fg: var(--c-debt-fg);
  --tone-bg: var(--c-debt-bg);
  --tone-solid: var(--c-debt-solid);
  --tone-solid-text: var(--c-debt-solid-text);
}
.tone-asset {
  --tone-fg: var(--c-asset-fg);
  --tone-bg: var(--c-asset-bg);
  --tone-solid: var(--c-asset-solid);
  --tone-solid-text: var(--c-asset-solid-text);
}
.tone-loan {
  --tone-fg: var(--c-loan-fg);
  --tone-bg: var(--c-loan-bg);
  --tone-solid: var(--c-loan-solid);
  --tone-solid-text: var(--c-loan-solid-text);
}
.tone-neutral {
  --tone-fg: var(--c-neutral-fg);
  --tone-bg: var(--c-neutral-bg);
  --tone-solid: var(--c-neutral-solid);
  --tone-solid-text: var(--c-neutral-solid-text);
}

.icon-tile {
  display: inline-grid;
  flex-shrink: 0;
  place-items: center;
  width: var(--icon-tile);
  height: var(--icon-tile);
  border-radius: var(--radius-md);
  background: var(--tone-bg);
  color: var(--tone-fg);
  font-size: var(--icon-md);
}

.icon-tile--solid {
  background: var(--tone-solid);
  color: var(--tone-solid-text);
}

/* A solid fill placed on a tinted band (page header, wallet card, band demo) gets an edge in the
   tone's -fg color. In light mode -fg equals -solid, so nothing changes; in dark mode the edge keeps
   the tile / button outline at 3:1 or more against the band (docs/CONTRAST.md). */
.page-header .icon-tile--solid,
.wallet-card .icon-tile--solid,
.band-demo .icon-tile--solid {
  box-shadow: inset 0 0 0 var(--border-w) var(--tone-fg);
}

.icon-tile--lg {
  width: var(--icon-tile-lg);
  height: var(--icon-tile-lg);
  font-size: var(--icon-lg);
}

/* ================================================================== shell */
.app-shell {
  min-height: 100vh;
  min-height: 100dvh;
}

.app-main {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 100vh;
  min-height: 100dvh;
}

.app-content {
  flex: 1;
  width: 100%;
  max-width: var(--content-max);
  margin-inline: auto;
  padding-top: var(--sp-4);
  padding-right: max(var(--sp-4), env(safe-area-inset-right));
  padding-bottom: calc(var(--bottom-nav-h) + env(safe-area-inset-bottom) + var(--sp-6));
  padding-left: max(var(--sp-4), env(safe-area-inset-left));
}

.app-content:focus {
  outline: none;
}

body:has(.review-dock) .app-content {
  padding-bottom: calc(var(--bottom-nav-h) + env(safe-area-inset-bottom) + var(--sp-7) + var(--sp-6));
}

@media (min-width: 768px) {
  .app-content {
    padding-right: max(var(--sp-5), env(safe-area-inset-right));
    padding-left: max(var(--sp-5), env(safe-area-inset-left));
  }
}

@media (min-width: 992px) {
  .app-shell {
    display: grid;
    grid-template-columns: var(--sidebar-w) minmax(0, 1fr);
  }

  .app-content,
  body:has(.review-dock) .app-content {
    padding: var(--sp-5) var(--sp-6) var(--sp-7);
  }
}

/* ---------- sidebar (desktop) */
.sidebar {
  display: none;
}

@media (min-width: 992px) {
  .sidebar {
    position: sticky;
    top: 0;
    z-index: var(--z-sidebar);
    display: flex;
    flex-direction: column;
    height: 100vh;
    height: 100dvh;
    padding: var(--sp-4) var(--sp-3);
    overflow-y: auto;
    border-right: var(--border-w) solid var(--c-border);
    background: var(--c-surface);
  }
}

.sidebar__brand {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  min-height: var(--touch-min);
  margin-bottom: var(--sp-4);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--radius-md);
  color: var(--c-text);
  font-size: var(--fs-lg);
  font-weight: var(--fw-bold);
  text-decoration: none;
}

.sidebar__brand:hover {
  color: var(--c-text);
}

.sidebar__logo {
  display: inline-grid;
  place-items: center;
  width: var(--icon-tile);
  height: var(--icon-tile);
  border-radius: var(--radius-md);
  background: var(--c-brand-solid);
  color: var(--c-brand-solid-text);
  font-size: var(--icon-md);
}

.side-nav__group + .side-nav__group {
  margin-top: var(--sp-4);
}

.side-nav__heading {
  margin: 0 0 var(--sp-1);
  padding: 0 var(--sp-3);
  color: var(--c-muted);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
}

.side-nav__list {
  display: grid;
  gap: var(--sp-1);
  margin: 0;
  padding: 0;
  list-style: none;
}

.side-link {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  min-height: var(--touch-min);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--radius-md);
  color: var(--c-text);
  font-weight: var(--fw-medium);
  text-decoration: none;
}

.side-link:hover {
  background: var(--c-surface-2);
  color: var(--c-text);
}

.side-link__icon {
  display: inline-grid;
  place-items: center;
  width: var(--icon-lg);
  color: var(--tone-fg);
  font-size: var(--icon-md);
}

.side-link.is-active {
  background: var(--tone-bg);
  color: var(--tone-fg);
  font-weight: var(--fw-bold);
}

.side-link.is-active::before {
  position: absolute;
  top: var(--sp-2);
  bottom: var(--sp-2);
  left: 0;
  width: var(--accent-w);
  border-radius: var(--radius-pill);
  background: var(--tone-fg);
  content: "";
}

/* ---------- top bar */
.topbar {
  position: sticky;
  top: 0;
  z-index: var(--z-topbar);
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  height: calc(var(--topbar-h-compact) + env(safe-area-inset-top));
  padding-top: env(safe-area-inset-top);
  padding-right: max(var(--sp-2), env(safe-area-inset-right));
  padding-left: max(var(--sp-4), env(safe-area-inset-left));
  border-bottom: var(--border-w) solid var(--c-border);
  background: var(--c-surface);
}

.topbar__title {
  display: flex;
  flex: 1;
  align-items: center;
  gap: var(--sp-2);
  min-width: 0;
  margin: 0;
  color: var(--tone-fg);
  font-size: var(--fs-md);
  font-weight: var(--fw-bold);
}

.topbar__title-icon {
  display: inline-flex;
  font-size: var(--icon-md);
}

.topbar__title-text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.topbar__search {
  display: none;
}

.topbar__actions {
  display: flex;
  align-items: center;
  gap: var(--sp-1);
  margin-left: auto;
}

.topbar__user {
  display: none;
}

.theme-toggle__label {
  position: absolute;
  width: var(--border-w);
  height: var(--border-w);
  margin: calc(var(--border-w) * -1);
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

@media (min-width: 992px) {
  .topbar {
    gap: var(--sp-4);
    height: var(--topbar-h);
    padding: 0 var(--sp-6);
  }

  .topbar__title,
  .topbar__search-btn {
    display: none;
  }

  .topbar__search {
    position: relative;
    display: flex;
    flex: 1;
    align-items: center;
    max-width: var(--search-w);
  }

  .topbar__user {
    display: block;
  }

  .theme-toggle__label {
    position: static;
    width: auto;
    height: auto;
    margin: 0;
    overflow: visible;
    clip: auto;
  }
}

.topbar__search-icon {
  position: absolute;
  left: var(--sp-4);
  display: inline-flex;
  color: var(--c-muted);
  pointer-events: none;
}

.topbar__search .form-control {
  min-height: var(--touch-min);
  padding-left: calc(var(--sp-4) + var(--icon-sm) + var(--sp-3));
  border-radius: var(--radius-pill);
  background-color: var(--c-bg);
}

.env-chip {
  display: none;
}

@media (min-width: 768px) {
  .env-chip {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-1);
    padding: var(--sp-1) var(--sp-3);
    border-radius: var(--radius-pill);
    background: var(--c-debt-bg);
    color: var(--c-debt-fg);
    font-size: var(--fs-sm);
    font-weight: var(--fw-semibold);
    white-space: nowrap;
  }
}

.icon-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  min-width: var(--touch-min);
  min-height: var(--touch-min);
  padding: 0 var(--sp-2);
  border: 0;
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--c-text);
  font: inherit;
  font-weight: var(--fw-medium);
  text-decoration: none;
}

.icon-btn > .bi {
  font-size: var(--icon-md);
}

.icon-btn:hover {
  background: var(--c-surface-2);
  color: var(--c-text);
}

.icon-btn[aria-expanded="true"],
.theme-toggle[aria-pressed="true"] {
  background: var(--c-brand-bg);
  color: var(--c-brand-fg);
}

.icon-btn__count {
  position: absolute;
  top: var(--sp-1);
  right: var(--sp-1);
  min-width: var(--counter-size);
  height: var(--counter-size);
  padding: 0 var(--sp-1);
  border-radius: var(--radius-pill);
  background: var(--c-expense-solid);
  color: var(--c-expense-solid-text);
  font-size: var(--fs-counter);
  font-weight: var(--fw-bold);
  line-height: var(--counter-size);
  text-align: center;
}

.user-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: var(--touch-min);
  padding: 0 var(--sp-3);
  border: var(--border-w) solid var(--c-border);
  border-radius: var(--radius-pill);
  background: var(--c-surface);
  color: var(--c-text);
  font: inherit;
  font-weight: var(--fw-semibold);
}

.user-btn > .bi:first-child {
  font-size: var(--icon-lg);
}

.user-btn:hover,
.user-btn[aria-expanded="true"] {
  background: var(--c-surface-2);
}

/* ---------- popovers (notifications, user menu) */
.popover-anchor {
  position: relative;
}

.popover-panel {
  position: absolute;
  top: calc(100% + var(--sp-2));
  right: 0;
  z-index: var(--z-popover);
  width: var(--popover-w);
  max-width: calc(100vw - 2 * var(--sp-3));
  padding: var(--sp-4);
  border: var(--border-w) solid var(--c-border);
  border-radius: var(--radius-card);
  background: var(--c-surface);
  color: var(--c-text);
  box-shadow: var(--shadow-raised);
}

@media (max-width: 991.98px) {
  .popover-panel {
    position: fixed;
    top: calc(var(--topbar-h-compact) + env(safe-area-inset-top) + var(--sp-2));
    right: var(--sp-3);
    left: var(--sp-3);
    width: auto;
    max-width: none;
  }
}

.popover-panel__title {
  margin: 0 0 var(--sp-3);
  font-size: var(--fs-md);
  font-weight: var(--fw-bold);
}

.popover-panel__empty {
  margin: 0;
  color: var(--c-muted);
}

.notif-list {
  display: grid;
  gap: var(--sp-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.notif-item {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--radius-md);
  background: var(--tone-bg);
}

.notif-item__icon {
  display: inline-flex;
  padding-top: var(--sp-1);
  color: var(--tone-fg);
  font-size: var(--icon-md);
}

.notif-item__text {
  display: grid;
  font-weight: var(--fw-semibold);
}

.notif-item__meta {
  color: var(--c-muted);
  font-size: var(--fs-sm);
  font-weight: var(--fw-regular);
}

.theme-choice {
  margin: 0 0 var(--sp-3);
  padding: 0;
  border: 0;
}

.theme-choice__legend {
  float: none;
  margin-bottom: var(--sp-2);
  color: var(--c-muted);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
}

.theme-choice__options {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--sp-2);
}

.theme-choice__options .btn {
  flex-direction: column;
  gap: var(--sp-1);
  --bs-btn-padding-x: var(--sp-2);
}

.popover-links {
  margin: 0 0 var(--sp-2);
  padding: var(--sp-2) 0 0;
  border-top: var(--border-w) solid var(--c-border);
  list-style: none;
}

.popover-links a {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  min-height: var(--touch-min);
  padding: 0 var(--sp-2);
  border-radius: var(--radius-md);
  color: var(--c-text);
  text-decoration: none;
}

.popover-links a:hover {
  background: var(--c-surface-2);
}

.popover-logout {
  width: 100%;
  justify-content: flex-start;
}

/* ---------- bottom bar (mobile) */
.bottom-nav {
  position: fixed;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: var(--z-bottom-nav);
  padding-right: env(safe-area-inset-right);
  padding-bottom: env(safe-area-inset-bottom);
  padding-left: env(safe-area-inset-left);
  border-top: var(--border-w) solid var(--c-border);
  background: var(--c-surface);
  box-shadow: var(--shadow-bar);
}

@media (min-width: 992px) {
  .bottom-nav {
    display: none;
  }
}

.bottom-nav__list {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  align-items: end;
  min-height: var(--bottom-nav-h);
  margin: 0;
  padding: 0;
  list-style: none;
}

.bottom-nav__item {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  gap: var(--sp-1);
  width: 100%;
  min-height: var(--bottom-nav-h);
  padding: var(--sp-2) var(--sp-1);
  border: 0;
  background: transparent;
  color: var(--c-muted);
  font: inherit;
  font-size: var(--fs-nav);
  font-weight: var(--fw-medium);
  line-height: var(--lh-tight);
  text-align: center;
  text-decoration: none;
}

.bottom-nav__item:hover {
  color: var(--c-text);
}

.bottom-nav__icon {
  display: inline-grid;
  place-items: center;
  min-width: var(--sp-7);
  height: var(--sp-6);
  border-radius: var(--radius-pill);
  font-size: var(--icon-lg);
}

.bottom-nav__item.is-active {
  color: var(--tone-fg);
  font-weight: var(--fw-bold);
}

.bottom-nav__item.is-active .bottom-nav__icon {
  background: var(--tone-bg);
}

.bottom-nav__item--quick {
  color: var(--tone-fg);
  font-weight: var(--fw-bold);
}

.bottom-nav__item--quick .bottom-nav__icon {
  width: var(--quick-btn);
  min-width: var(--quick-btn);
  height: var(--quick-btn);
  margin-top: calc(var(--quick-btn) / -2);
  border: var(--accent-w) solid var(--c-surface);
  border-radius: var(--radius-pill);
  background: var(--tone-solid);
  color: var(--tone-solid-text);
  box-shadow: var(--shadow-raised);
}

.bottom-nav__item--quick.is-active .bottom-nav__icon {
  background: var(--tone-solid);
}

/* ---------- menu sheet (mobile "เมนู") */
.sheet {
  width: 100%;
  max-width: 100%;
  max-height: var(--sheet-max-h);
  margin: auto 0 0;
  padding: 0;
  border: 0;
  border-radius: var(--radius-card) var(--radius-card) 0 0;
  background: var(--c-surface);
  color: var(--c-text);
  box-shadow: var(--shadow-raised);
}

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

.sheet__panel {
  padding: var(--sp-2) max(var(--sp-4), env(safe-area-inset-right)) calc(var(--sp-4) + env(safe-area-inset-bottom)) max(var(--sp-4), env(safe-area-inset-left));
}

.sheet__handle {
  display: block;
  width: var(--sp-7);
  height: var(--sp-1);
  margin: 0 auto var(--sp-2);
  border-radius: var(--radius-pill);
  background: var(--c-control-border);
}

.sheet__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
}

.sheet__title {
  margin: 0;
  font-size: var(--fs-lg);
  font-weight: var(--fw-bold);
}

.sheet__group-title {
  margin: var(--sp-4) 0 var(--sp-2);
  color: var(--c-muted);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
}

.sheet__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(var(--tile-min), 1fr));
  gap: var(--sp-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.sheet-link {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-2);
  height: 100%;
  min-height: calc(var(--touch-min) * 2);
  padding: var(--sp-3) var(--sp-2);
  border: var(--border-w) solid transparent;
  border-radius: var(--radius-md);
  background: var(--c-surface-2);
  color: var(--c-text);
  font-weight: var(--fw-medium);
  line-height: var(--lh-tight);
  text-align: center;
  text-decoration: none;
}

.sheet-link:hover {
  color: var(--c-text);
}

.sheet-link.is-active {
  border-color: var(--tone-fg);
  background: var(--tone-bg);
  color: var(--tone-fg);
  font-weight: var(--fw-bold);
}

.sheet__footer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  margin-top: var(--sp-5);
  padding-top: var(--sp-3);
  border-top: var(--border-w) solid var(--c-border);
}

.sheet__user {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  font-weight: var(--fw-semibold);
}

@media (min-width: 992px) {
  .sheet {
    max-width: var(--dialog-w);
    margin: auto;
    border-radius: var(--radius-card);
  }
}

/* ---------- toasts */
.toast-region {
  position: fixed;
  bottom: calc(var(--bottom-nav-h) + env(safe-area-inset-bottom) + var(--sp-3));
  left: 50%;
  z-index: var(--z-toast);
  display: grid;
  gap: var(--sp-2);
  width: min(var(--dialog-w), calc(100vw - 2 * var(--sp-4)));
  transform: translateX(-50%);
  pointer-events: none;
}

@media (min-width: 992px) {
  .toast-region {
    bottom: var(--sp-5);
  }
}

.toast-msg {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--radius-md);
  background: var(--c-text);
  color: var(--c-surface);
  font-weight: var(--fw-medium);
  box-shadow: var(--shadow-raised);
}

.toast-msg .bi {
  margin-top: var(--sp-1);
}

/* ================================================================== page header */
.page-header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  margin-bottom: var(--sp-5);
  padding: var(--sp-4);
  border-left: var(--accent-w) solid var(--tone-fg);
  border-radius: var(--radius-card);
  background: var(--tone-bg);
}

@media (min-width: 768px) {
  .page-header {
    padding: var(--sp-5);
  }
}

.page-header__main {
  display: flex;
  flex: 1 1 auto;
  align-items: flex-start;
  gap: var(--sp-3) var(--sp-4);
  min-width: 0;
}

.page-header__text {
  flex: 1 1 0%;
  min-width: 0;
}

.page-header__tag {
  margin: var(--sp-2) 0 0;
}

.page-header__title {
  margin: 0;
  color: var(--tone-fg);
  font-size: var(--fs-xl);
  font-weight: var(--fw-bold);
}

@media (min-width: 768px) {
  .page-header__title {
    font-size: var(--fs-2xl);
  }
}

.page-header__lead {
  margin: var(--sp-1) 0 0;
  color: var(--c-text);
}

.page-header__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
}

@media (max-width: 767.98px) {
  .page-header__actions {
    flex-direction: column;
    width: 100%;
  }
}

.sample-tag {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  padding: var(--sp-1) var(--sp-3);
  border: var(--border-w) dashed var(--c-control-border);
  border-radius: var(--radius-pill);
  background: var(--c-surface);
  color: var(--c-text);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  white-space: nowrap;
}

/* ================================================================== layout helpers */
.page-stack {
  display: grid;
  gap: var(--sp-5);
}

.page-section {
  display: grid;
  gap: var(--sp-3);
}

.section-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
}

.section-title {
  margin: 0;
  font-size: var(--fs-lg);
  font-weight: var(--fw-bold);
}

.section-note {
  margin: 0;
  color: var(--c-muted);
}

.sub-title {
  margin: var(--sp-2) 0 0;
  font-size: var(--fs-md);
  font-weight: var(--fw-bold);
}

.grid {
  display: grid;
  gap: var(--sp-4);
}

.grid--2,
.grid--split {
  grid-template-columns: repeat(auto-fit, minmax(min(var(--grid-min-wide), 100%), 1fr));
}

.grid--3 {
  grid-template-columns: repeat(auto-fit, minmax(min(var(--grid-min), 100%), 1fr));
}

.stack {
  display: grid;
  gap: var(--sp-3);
}

.inline-form {
  display: inline-flex;
  margin: 0;
}

/* ================================================================== cards */
.card {
  --bs-card-bg: var(--c-surface);
  --bs-card-color: var(--c-text);
  --bs-card-border-color: var(--c-border);
  --bs-card-border-radius: var(--radius-card);
  --bs-card-spacer-x: var(--sp-5);
  --bs-card-spacer-y: var(--sp-5);
  box-shadow: var(--shadow-card);
}

.ui-card {
  gap: var(--sp-4);
  padding: var(--sp-4);
}

@media (min-width: 768px) {
  .ui-card {
    padding: var(--sp-5);
  }
}

.ui-card > p {
  margin: 0;
}

.card.ui-card[class*="tone-"] {
  border-top: var(--accent-w) solid var(--tone-fg);
}

.ui-card__header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2) var(--sp-3);
}

.ui-card__title {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin: 0;
  font-size: var(--fs-lg);
  font-weight: var(--fw-bold);
}

.ui-card__icon {
  color: var(--tone-fg);
  font-size: var(--icon-md);
}

.ui-card__link {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  min-height: var(--touch-min);
  font-weight: var(--fw-semibold);
}

.ui-card__figure {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--sp-1) var(--sp-3);
}

.ui-card__figure-note {
  color: var(--c-muted);
}

.stat-card,
.wallet-card {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding: var(--sp-4);
  border: var(--border-w) solid var(--c-border);
  border-radius: var(--radius-card);
  background: var(--c-surface);
  box-shadow: var(--shadow-card);
}

@media (min-width: 768px) {
  .stat-card,
  .wallet-card {
    padding: var(--sp-5);
  }
}

.stat-card--tinted {
  background: var(--tone-bg);
}

.stat-card__head,
.wallet-card__head {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
}

.stat-card__label,
.wallet-card__name {
  margin: 0;
  font-size: var(--fs-md);
  font-weight: var(--fw-semibold);
}

.stat-card__value,
.wallet-card__balance {
  margin: var(--sp-1) 0 0;
}

.stat-card__trend {
  margin: 0;
}

.stat-card__meta {
  margin: 0;
  color: var(--c-muted);
  font-size: var(--fs-sm);
}

.wallet-card {
  border-left: var(--accent-w) solid var(--tone-fg);
  background: var(--tone-bg);
}

.wallet-card__balance {
  color: var(--tone-fg);
}

.wallet-card__note {
  margin: 0;
}

.wallet-card__meta {
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
  margin: 0;
  color: var(--c-muted);
  font-size: var(--fs-sm);
}

/* ================================================================== money */
.money {
  font-variant-numeric: tabular-nums;
  font-weight: var(--fw-semibold);
  white-space: nowrap;
}

.money--table {
  font-size: var(--fs-money-table);
}

.money--md {
  font-size: var(--fs-money-md);
  font-weight: var(--fw-bold);
}

.money--lg,
.money--xl {
  font-weight: var(--fw-bold);
  line-height: var(--lh-tight);
}

.money--lg {
  font-size: var(--fs-money-lg);
}

.money--xl {
  font-size: var(--fs-money-xl);
}

.money--lg .money__unit,
.money--xl .money__unit,
.money--lg .money__sym,
.money--xl .money__sym {
  font-size: var(--money-unit-scale);
  font-weight: var(--fw-semibold);
}

.money--pos {
  color: var(--c-income-fg);
}

.money--neg {
  color: var(--c-expense-fg);
}

/* Amounts are never smaller than body text, even inside a smaller caption line */
.stat-card__meta .money,
.item__meta .money {
  font-size: var(--fs-base);
}

/* Unit choice: "1,234.50 บาท" (default) or "฿1,234.50" */
html:not([data-unit="symbol"]) .money__sym,
html:not([data-unit="symbol"]) .money-input__sym,
html[data-unit="symbol"] .money__unit,
html[data-unit="symbol"] .money-input__unit {
  display: none;
}

.money__word {
  display: inline-block;
  margin-left: var(--sp-1);
  padding: 0 var(--sp-2);
  border-radius: var(--radius-pill);
  background: var(--c-expense-bg);
  color: var(--c-expense-fg);
  font-size: var(--fs-sm);
  font-weight: var(--fw-bold);
  line-height: var(--lh-body);
  vertical-align: middle;
}

.money__word--pos {
  background: var(--c-income-bg);
  color: var(--c-income-fg);
}

/* ================================================================== badges, tags, trends */
.status-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  padding: var(--sp-1) var(--sp-3);
  border: var(--border-w) solid transparent;
  border-radius: var(--radius-pill);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-tight);
  white-space: nowrap;
}

.status-badge > .bi {
  font-size: var(--icon-sm);
}

.status-badge--paid {
  background: var(--c-income-bg);
  color: var(--c-income-fg);
}

.status-badge--due-soon {
  background: var(--c-debt-bg);
  color: var(--c-debt-fg);
}

.status-badge--overdue {
  background: var(--c-expense-solid);
  color: var(--c-expense-solid-text);
}

.status-badge--upcoming {
  border-color: var(--c-brand-fg);
  background: var(--c-surface);
  color: var(--c-brand-fg);
}

.status-badge--closed {
  background: var(--c-neutral-bg);
  color: var(--c-muted);
}

.tag {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  padding: 0 var(--sp-2);
  border-radius: var(--radius-sm);
  background: var(--tone-bg);
  color: var(--tone-fg);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-body);
  white-space: nowrap;
}

.tag-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-4);
  margin: 0;
}

.trend {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  font-weight: var(--fw-semibold);
}

.trend--good {
  color: var(--c-income-fg);
}

.trend--bad {
  color: var(--c-expense-fg);
}

.trend--flat {
  color: var(--c-muted);
}

/* ================================================================== buttons */
.btn {
  --bs-btn-font-family: var(--font-body);
  --bs-btn-font-size: var(--fs-base);
  --bs-btn-font-weight: var(--fw-semibold);
  --bs-btn-line-height: var(--lh-tight);
  --bs-btn-padding-x: var(--sp-4);
  --bs-btn-padding-y: var(--sp-2);
  --bs-btn-border-width: var(--border-w-strong);
  --bs-btn-border-radius: var(--radius-md);
  --bs-btn-focus-box-shadow: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  min-height: var(--touch-min);
}

.btn:focus-visible {
  outline: var(--focus-w) solid var(--c-focus);
  outline-offset: var(--focus-offset);
  box-shadow: none;
}

.btn-main {
  --bs-btn-padding-x: var(--sp-5);
  --bs-btn-font-size: var(--fs-md);
  min-height: var(--control-h);
}

@media (max-width: 767.98px) {
  .btn-main {
    width: 100%;
  }
}

.btn-icon {
  --bs-btn-padding-x: 0;
  min-width: var(--touch-min);
}

.btn-icon > .bi {
  font-size: var(--icon-md);
}

/* Solid fill in the current tone (menu color) */
.btn-tone,
.btn-paid {
  --bs-btn-color: var(--btn-text);
  --bs-btn-bg: var(--btn-fill);
  --bs-btn-border-color: var(--btn-fill);
  --bs-btn-hover-color: var(--btn-text);
  --bs-btn-hover-bg: var(--btn-fill);
  --bs-btn-hover-border-color: var(--btn-fill);
  --bs-btn-active-color: var(--btn-text);
  --bs-btn-active-bg: var(--btn-fill);
  --bs-btn-active-border-color: var(--btn-fill);
  --bs-btn-disabled-color: var(--btn-text);
  --bs-btn-disabled-bg: var(--btn-fill);
  --bs-btn-disabled-border-color: var(--btn-fill);
}

.btn-tone {
  --btn-fill: var(--tone-solid);
  --btn-text: var(--tone-solid-text);
}

/* On a tinted band the solid button's border uses -fg (see .icon-tile--solid above) */
.page-header .btn-tone,
.band-demo .btn-tone {
  --bs-btn-border-color: var(--tone-fg);
  --bs-btn-hover-border-color: var(--tone-fg);
  --bs-btn-active-border-color: var(--tone-fg);
  --bs-btn-disabled-border-color: var(--tone-fg);
}

/* "จ่ายแล้ว" is always green with a check icon, in every menu */
.btn-paid {
  --btn-fill: var(--c-income-solid);
  --btn-text: var(--c-income-solid-text);
}

.btn-tone:hover,
.btn-tone:active,
.btn-paid:hover,
.btn-paid:active {
  background-image: linear-gradient(var(--c-solid-hover), var(--c-solid-hover));
}

/* Outline in the current tone (secondary add action) */
.btn-tone-outline {
  --bs-btn-color: var(--tone-fg);
  --bs-btn-bg: var(--c-surface);
  --bs-btn-border-color: var(--tone-fg);
  --bs-btn-hover-color: var(--tone-fg);
  --bs-btn-hover-bg: var(--tone-bg);
  --bs-btn-hover-border-color: var(--tone-fg);
  --bs-btn-active-color: var(--tone-fg);
  --bs-btn-active-bg: var(--tone-bg);
  --bs-btn-active-border-color: var(--tone-fg);
}

/* Delete: red outline + trash icon (never solid, so it is not confused with a red "+ เพิ่ม") */
.btn-delete {
  --bs-btn-color: var(--c-expense-fg);
  --bs-btn-bg: transparent;
  --bs-btn-border-color: var(--c-expense-fg);
  --bs-btn-hover-color: var(--c-expense-fg);
  --bs-btn-hover-bg: var(--c-expense-bg);
  --bs-btn-hover-border-color: var(--c-expense-fg);
  --bs-btn-active-color: var(--c-expense-fg);
  --bs-btn-active-bg: var(--c-expense-bg);
  --bs-btn-active-border-color: var(--c-expense-fg);
}

.btn-quiet {
  --bs-btn-color: var(--c-text);
  --bs-btn-bg: var(--c-surface);
  --bs-btn-border-color: var(--c-control-border);
  --bs-btn-hover-color: var(--c-text);
  --bs-btn-hover-bg: var(--c-surface-2);
  --bs-btn-hover-border-color: var(--c-control-border);
  --bs-btn-active-color: var(--c-text);
  --bs-btn-active-bg: var(--c-surface-2);
  --bs-btn-active-border-color: var(--c-control-border);
  --bs-btn-border-width: var(--border-w);
}

.btn-quiet[aria-pressed="true"] {
  --bs-btn-color: var(--c-brand-fg);
  --bs-btn-bg: var(--c-brand-bg);
  --bs-btn-border-color: var(--c-brand-fg);
  --bs-btn-hover-color: var(--c-brand-fg);
  --bs-btn-hover-bg: var(--c-brand-bg);
  --bs-btn-hover-border-color: var(--c-brand-fg);
  font-weight: var(--fw-bold);
}

.btn-ghost {
  --bs-btn-color: var(--c-link);
  --bs-btn-bg: transparent;
  --bs-btn-border-color: transparent;
  --bs-btn-hover-color: var(--c-link);
  --bs-btn-hover-bg: var(--c-surface-2);
  --bs-btn-hover-border-color: transparent;
  --bs-btn-active-color: var(--c-link);
  --bs-btn-active-bg: var(--c-surface-2);
  --bs-btn-active-border-color: transparent;
}

.button-demo {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-3);
}

/* ================================================================== forms */
.field {
  display: grid;
  align-content: start;
  gap: var(--sp-1);
  min-width: 0;
}

.form-label {
  margin: 0;
  font-weight: var(--fw-semibold);
}

.field-required {
  color: var(--c-muted);
  font-size: var(--fs-sm);
  font-weight: var(--fw-regular);
}

.field-help,
.field-hint,
.field-error {
  margin: 0;
}

.field-help {
  color: var(--c-muted);
  font-size: var(--fs-sm);
}

/* What the owner must read before saving (the interpreted date, errors) stays at body size */
.field-hint,
.field-error {
  font-size: var(--fs-base);
}

.field-hint {
  color: var(--c-text);
  font-weight: var(--fw-medium);
}

.field-hint:empty {
  display: none;
}

.field-hint.is-error,
.field-error {
  display: flex;
  align-items: baseline;
  gap: var(--sp-1);
  color: var(--c-expense-fg);
  font-weight: var(--fw-semibold);
}

.form-control,
.form-select {
  min-height: var(--control-h);
  border: var(--border-w) solid var(--c-control-border);
  border-radius: var(--radius-md);
  background-color: var(--c-surface);
  color: var(--c-text);
  font-size: var(--fs-base);
}

.form-control::placeholder {
  color: var(--c-muted);
}

.form-control:focus,
.form-select:focus {
  border-color: var(--c-focus);
  background-color: var(--c-surface);
  color: var(--c-text);
  outline: var(--focus-w) solid var(--c-focus);
  outline-offset: 0;
  box-shadow: none;
}

.form-control.is-invalid,
.form-select.is-invalid {
  border-color: var(--c-expense-fg);
  background-image: none;
}

.form-control.is-invalid:focus {
  border-color: var(--c-expense-fg);
  box-shadow: none;
}

textarea.form-control {
  min-height: calc(var(--control-h) * 2);
}

.form-control[type="file"] {
  padding: var(--sp-2) var(--sp-3);
}

.form-check {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  min-height: var(--touch-min);
  margin: 0;
  padding-left: 0;
}

.form-check .form-check-input {
  flex-shrink: 0;
  float: none;
  width: var(--icon-md);
  height: var(--icon-md);
  margin: 0;
  border: var(--border-w-strong) solid var(--c-control-border);
  background-color: var(--c-surface);
}

.form-switch .form-check-input {
  width: calc(var(--icon-md) * 2);
  margin-left: 0;
}

.form-check-input:checked {
  border-color: var(--c-brand-solid);
  background-color: var(--c-brand-solid);
}

.form-check-input:focus {
  border-color: var(--c-focus);
  outline: var(--focus-w) solid var(--c-focus);
  outline-offset: var(--focus-offset);
  box-shadow: none;
}

.form-check-label {
  flex: 1;
}

.form-grid,
.filters__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(var(--filter-min), 100%), 1fr));
  gap: var(--sp-4);
}

.filters__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
}

.check-demo {
  display: grid;
  margin: 0;
  padding: 0;
  border: 0;
}

.check-demo legend {
  float: none;
  margin-bottom: var(--sp-1);
  font-size: var(--fs-base);
}

/* ---------- money input */
.money-input {
  position: relative;
  max-width: var(--field-max);
}

.money-input .form-control {
  font-size: var(--fs-md);
  font-variant-numeric: tabular-nums;
  font-weight: var(--fw-semibold);
  text-align: right;
}

html:not([data-unit="symbol"]) .money-input .form-control {
  padding-right: var(--money-input-pad);
}

html[data-unit="symbol"] .money-input .form-control {
  padding-left: var(--sp-6);
}

.money-input__sym,
.money-input__unit {
  position: absolute;
  top: 0;
  bottom: 0;
  display: flex;
  align-items: center;
  color: var(--c-muted);
  font-weight: var(--fw-semibold);
  pointer-events: none;
}

.money-input__sym {
  left: var(--sp-3);
}

.money-input__unit {
  right: var(--sp-3);
}

/* ---------- Thai Buddhist-era date picker (date-picker.js) */
.thai-date {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  max-width: var(--field-max);
}

.thai-date .form-control {
  flex: 1 1 0;
  min-width: 0;
  font-variant-numeric: tabular-nums;
}

.thai-date__popup {
  position: absolute;
  top: calc(100% + var(--sp-2));
  left: 0;
  z-index: var(--z-popover);
  width: var(--picker-w);
  max-width: calc(100vw - 2 * var(--sp-4));
  padding: var(--sp-3);
  border: var(--border-w) solid var(--c-border);
  border-radius: var(--radius-card);
  background: var(--c-surface);
  color: var(--c-text);
  box-shadow: var(--shadow-raised);
}

/* Inside dialogs (tablet and desktop) it opens inline, so the dialog never clips it */
.dialog .thai-date__popup {
  position: static;
  flex-basis: 100%;
  width: 100%;
  max-width: none;
  box-shadow: none;
}

/* Phones: a full-width sheet at the bottom of the screen (also inside dialogs), so the 7 day
   columns always get the 44px touch width, even on a 320px screen */
@media (max-width: 767.98px) {
  .thai-date__popup,
  .dialog .thai-date__popup {
    position: fixed;
    top: auto;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: var(--z-picker-sheet);
    width: auto;
    max-width: none;
    max-height: var(--sheet-max-h);
    overflow-y: auto;
    padding: var(--sp-3) max(var(--sp-1), env(safe-area-inset-right)) calc(var(--sp-3) + env(safe-area-inset-bottom)) max(var(--sp-1), env(safe-area-inset-left));
    border-width: var(--border-w) 0 0;
    border-radius: var(--radius-card) var(--radius-card) 0 0;
    box-shadow: var(--shadow-raised);
  }

  .thai-date__head,
  .thai-date__foot {
    padding-inline: var(--sp-2);
  }
}

.thai-date__head {
  display: flex;
  align-items: center;
  gap: var(--sp-1);
  margin-bottom: var(--sp-2);
}

.thai-date__label {
  flex: 1;
  margin: 0;
  font-size: var(--fs-base);
  font-weight: var(--fw-bold);
  text-align: center;
}

.thai-date__grid {
  width: 100%;
  border-collapse: collapse;
  table-layout: fixed;
}

.thai-date__grid th {
  padding: var(--sp-1) 0;
  color: var(--c-muted);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  text-align: center;
}

.thai-date__grid td {
  padding: 0;
  text-align: center;
}

.thai-date__day {
  width: 100%;
  min-width: var(--touch-min);
  min-height: var(--touch-min);
  border: var(--border-w-strong) solid transparent;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--c-text);
  font: inherit;
  font-variant-numeric: tabular-nums;
}

.thai-date__day:hover {
  background: var(--c-surface-2);
}

.thai-date__day.is-outside {
  color: var(--c-muted);
}

.thai-date__day.is-today {
  border-color: var(--c-brand-fg);
  font-weight: var(--fw-bold);
}

.thai-date__day[aria-pressed="true"] {
  border-color: var(--c-brand-solid);
  background: var(--c-brand-solid);
  color: var(--c-brand-solid-text);
  font-weight: var(--fw-bold);
}

.thai-date__day:focus-visible {
  outline-offset: 0;
}

.thai-date__foot {
  display: flex;
  justify-content: space-between;
  gap: var(--sp-2);
  margin-top: var(--sp-2);
}

/* ================================================================== tables */
.data-table {
  --sticky-top: calc(var(--topbar-h-compact) + env(safe-area-inset-top));
  --bs-table-bg: var(--c-surface);
  --bs-table-color: var(--c-text);
  --bs-table-border-color: var(--c-border);
  margin: 0;
}

@media (min-width: 992px) {
  .data-table {
    --sticky-top: var(--topbar-h);
  }
}

.data-table > :not(caption) > * > * {
  padding: var(--sp-3);
  vertical-align: middle;
}

.data-table thead th {
  position: sticky;
  top: var(--sticky-top);
  z-index: var(--z-sticky);
  border-bottom: var(--border-w-strong) solid var(--c-control-border);
  background: var(--c-surface);
  font-weight: var(--fw-semibold);
  white-space: nowrap;
}

.data-table > tbody > tr:nth-of-type(even) > * {
  --bs-table-bg: var(--c-surface-2);
}

.data-table .num {
  text-align: right;
}

.data-table tfoot th,
.data-table tfoot td {
  border-top: var(--border-w-strong) solid var(--c-control-border);
  border-bottom: 0;
  font-weight: var(--fw-bold);
}

.data-table--compact > :not(caption) > * > * {
  padding: var(--sp-2) var(--sp-3);
}

.cell-muted {
  color: var(--c-muted);
}

.cell-actions {
  width: 1%;
  text-align: right;
  white-space: nowrap;
}

.table-link {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  min-height: var(--touch-min);
}

/* Below 768px every row becomes a card of "label: value" pairs (data-label) */
@media (max-width: 767.98px) {
  .data-table,
  .data-table tbody,
  .data-table tfoot {
    display: block;
  }

  .data-table thead {
    position: absolute;
    width: var(--border-w);
    height: var(--border-w);
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
  }

  .data-table tr {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: var(--sp-2) var(--sp-3);
    margin-bottom: var(--sp-3);
    padding: var(--sp-3) var(--sp-4);
    border: var(--border-w) solid var(--c-border);
    border-radius: var(--radius-card);
    background: var(--c-surface);
    box-shadow: var(--shadow-card);
  }

  .data-table tfoot tr {
    margin-bottom: 0;
    background: var(--c-surface-2);
  }

  .data-table > :not(caption) > * > *,
  .data-table--compact > :not(caption) > * > * {
    padding: 0;
    border: 0;
    background: transparent;
    box-shadow: none;
  }

  /* flex-wrap + auto margin: a long value (e.g. "−2,550.00 บาท ขาดทุน" on a
     320px phone) drops below its label, still right-aligned, instead of
     overflowing the cell. */
  .data-table td,
  .data-table th[scope="row"] {
    display: flex;
    flex-wrap: wrap;
    grid-column: 1 / -1;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--sp-1) var(--sp-3);
    text-align: right;
  }

  .data-table td:not(.cell-main) > *,
  .data-table th[scope="row"]:not(.cell-main) > * {
    margin-inline-start: auto;
  }

  .data-table td::before,
  .data-table th[scope="row"][data-label]::before {
    flex-shrink: 0;
    color: var(--c-muted);
    font-weight: var(--fw-medium);
    text-align: left;
    content: attr(data-label);
  }

  .data-table .cell-main {
    grid-row: 1;
    grid-column: 1;
    justify-content: flex-start;
    font-size: var(--fs-md);
    font-weight: var(--fw-bold);
    text-align: left;
  }

  .data-table .cell-amount {
    grid-row: 1;
    grid-column: 2;
  }

  .data-table .cell-main::before,
  .data-table .cell-amount::before,
  .data-table .cell-actions::before {
    content: none;
  }

  .data-table .cell-amount .money {
    font-size: var(--fs-money-md);
  }

  .data-table .cell-actions {
    justify-content: flex-end;
    width: auto;
  }

  .data-table .cell-empty {
    display: none;
  }
}

/* Wide tables (many columns) do not fit a tablet either: same card layout up to 992px.
   Keep in sync with the block above. */
@media (min-width: 768px) and (max-width: 991.98px) {
  .data-table--wide,
  .data-table--wide tbody,
  .data-table--wide tfoot {
    display: block;
  }

  .data-table--wide thead {
    position: absolute;
    width: var(--border-w);
    height: var(--border-w);
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
  }

  .data-table--wide tr {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: var(--sp-2) var(--sp-3);
    margin-bottom: var(--sp-3);
    padding: var(--sp-3) var(--sp-4);
    border: var(--border-w) solid var(--c-border);
    border-radius: var(--radius-card);
    background: var(--c-surface);
    box-shadow: var(--shadow-card);
  }

  .data-table--wide tfoot tr {
    margin-bottom: 0;
    background: var(--c-surface-2);
  }

  .data-table--wide > :not(caption) > * > * {
    padding: 0;
    border: 0;
    background: transparent;
    box-shadow: none;
  }

  .data-table--wide td,
  .data-table--wide th[scope="row"] {
    display: flex;
    flex-wrap: wrap;
    grid-column: 1 / -1;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--sp-1) var(--sp-3);
    text-align: right;
  }

  .data-table--wide td:not(.cell-main) > *,
  .data-table--wide th[scope="row"]:not(.cell-main) > * {
    margin-inline-start: auto;
  }

  .data-table--wide td::before,
  .data-table--wide th[scope="row"][data-label]::before {
    flex-shrink: 0;
    color: var(--c-muted);
    font-weight: var(--fw-medium);
    text-align: left;
    content: attr(data-label);
  }

  .data-table--wide .cell-main {
    grid-row: 1;
    grid-column: 1;
    justify-content: flex-start;
    font-size: var(--fs-md);
    font-weight: var(--fw-bold);
    text-align: left;
  }

  .data-table--wide .cell-amount {
    grid-row: 1;
    grid-column: 2;
  }

  .data-table--wide .cell-main::before,
  .data-table--wide .cell-amount::before,
  .data-table--wide .cell-actions::before {
    content: none;
  }

  .data-table--wide .cell-amount .money {
    font-size: var(--fs-money-md);
  }

  .data-table--wide .cell-actions {
    justify-content: flex-end;
    width: auto;
  }

  .data-table--wide .cell-empty {
    display: none;
  }
}

/* Wrapper of every data table. Deliberately no overflow-x: a scroll container would stop the
   sticky header from sticking to the page. Tables too wide for a tablet use .data-table--wide. */
.table-wrap {
  display: block;
  min-width: 0;
  max-width: 100%;
}

/* ================================================================== dialogs */
.dialog {
  width: min(var(--dialog-w), calc(100vw - 2 * var(--sp-4)));
  max-height: var(--dialog-max-h);
  padding: 0;
  border: 0;
  border-radius: var(--radius-card);
  background: var(--c-surface);
  color: var(--c-text);
  box-shadow: var(--shadow-raised);
}

.dialog[open] {
  display: flex;
  flex-direction: column;
}

.dialog__panel {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  min-height: 0;
}

.dialog__header {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-4) var(--sp-3) var(--sp-5);
  border-bottom: var(--border-w) solid var(--c-border);
}

.dialog__heading {
  flex: 1;
  min-width: 0;
}

.dialog__title {
  margin: 0;
  font-size: var(--fs-lg);
  font-weight: var(--fw-bold);
}

.dialog__subtitle {
  margin: 0;
  color: var(--c-muted);
  font-weight: var(--fw-semibold);
}

.dialog__body {
  display: grid;
  gap: var(--sp-4);
  padding: var(--sp-4) var(--sp-5);
  overflow-y: auto;
}

.dialog__body p {
  margin: 0;
}

.dialog__footer {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-5) var(--sp-4);
  border-top: var(--border-w) solid var(--c-border);
}

@media (max-width: 767.98px) {
  .dialog {
    width: 100%;
    max-width: 100%;
    margin: auto 0 0;
    border-radius: var(--radius-card) var(--radius-card) 0 0;
  }

  .dialog__footer {
    flex-direction: column-reverse;
    padding-bottom: calc(var(--sp-4) + env(safe-area-inset-bottom));
  }
}

.pay-summary {
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--radius-md);
  background: var(--c-surface-2);
}

.confirm-item strong {
  font-size: var(--fs-md);
}

.confirm-detail {
  font-weight: var(--fw-medium);
}

/* The children box of the confirmation dialog: red for a delete (tone-expense), the action's tone
   otherwise (e.g. green for a restore); confirm-danger.js sets the tone class. */
.confirm-step {
  display: grid;
  gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-4);
  border: var(--border-w) solid var(--tone-fg);
  border-radius: var(--radius-md);
  background: var(--tone-bg);
}

.confirm-step__warn {
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
  color: var(--tone-fg);
  font-weight: var(--fw-bold);
}

/* Optional camera input only on touch devices (desktop gets the file picker) */
@media (pointer: fine) {
  .field--touch-only {
    display: none;
  }
}

/* ================================================================== feedback */
.callout {
  display: flex;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  border-left: var(--accent-w) solid var(--tone-fg);
  border-radius: var(--radius-md);
  background: var(--tone-bg);
  color: var(--c-text);
}

.callout__icon {
  display: inline-flex;
  padding-top: var(--sp-1);
  color: var(--tone-fg);
  font-size: var(--icon-md);
}

.callout__title {
  margin: 0;
  color: var(--tone-fg);
  font-weight: var(--fw-bold);
}

.callout__text {
  margin: 0;
}

.empty-state {
  display: grid;
  justify-items: center;
  gap: var(--sp-2);
  padding: var(--sp-6) var(--sp-4);
  border: var(--border-w-strong) dashed var(--c-border);
  border-radius: var(--radius-card);
  text-align: center;
}

.empty-state__icon {
  display: grid;
  place-items: center;
  width: var(--icon-tile-lg);
  height: var(--icon-tile-lg);
  border-radius: var(--radius-pill);
  background: var(--tone-bg);
  color: var(--tone-fg);
  font-size: var(--icon-lg);
}

.empty-state__title {
  margin: 0;
  font-size: var(--fs-md);
  font-weight: var(--fw-bold);
}

.empty-state__text {
  max-width: var(--field-max);
  margin: 0;
  color: var(--c-muted);
}

/* ---------- progress */
.progress-field {
  display: grid;
  gap: var(--sp-1);
}

.progress-field__head {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--sp-1) var(--sp-3);
  font-weight: var(--fw-medium);
}

.progress-field__value {
  color: var(--c-muted);
}

/* The track's edge (--c-control-border, ≥ 3:1 on cards) shows the full length of the bar; the pale
   track fill alone would not (docs/CONTRAST.md). */
.meter-bar {
  display: block;
  width: 100%;
  height: var(--progress-h);
  overflow: hidden;
  border: var(--border-w) solid var(--c-control-border);
  border-radius: var(--radius-pill);
  background: var(--c-track);
  color: var(--tone-fg);
  -webkit-appearance: none;
  appearance: none;
}

.meter-bar::-webkit-progress-bar {
  border-radius: var(--radius-pill);
  background: var(--c-track);
}

.meter-bar::-webkit-progress-value {
  border-radius: var(--radius-pill);
  background: var(--tone-fg);
}

.meter-bar::-moz-progress-bar {
  border-radius: var(--radius-pill);
  background: var(--tone-fg);
}

.step-bar {
  height: var(--progress-h);
  overflow: hidden;
  border: var(--border-w) solid var(--c-control-border);
  border-radius: var(--radius-pill);
  background: var(--c-track);
}

.step-bar__fill {
  display: block;
  width: 0;
  height: 100%;
  border-radius: var(--radius-pill);
  background: var(--tone-fg);
}

.step-bar__fill--5 { width: 5%; }
.step-bar__fill--10 { width: 10%; }
.step-bar__fill--15 { width: 15%; }
.step-bar__fill--20 { width: 20%; }
.step-bar__fill--25 { width: 25%; }
.step-bar__fill--30 { width: 30%; }
.step-bar__fill--35 { width: 35%; }
.step-bar__fill--40 { width: 40%; }
.step-bar__fill--45 { width: 45%; }
.step-bar__fill--50 { width: 50%; }
.step-bar__fill--55 { width: 55%; }
.step-bar__fill--60 { width: 60%; }
.step-bar__fill--65 { width: 65%; }
.step-bar__fill--70 { width: 70%; }
.step-bar__fill--75 { width: 75%; }
.step-bar__fill--80 { width: 80%; }
.step-bar__fill--85 { width: 85%; }
.step-bar__fill--90 { width: 90%; }
.step-bar__fill--95 { width: 95%; }
.step-bar__fill--100 { width: 100%; }

/* ================================================================== dashboard */
.networth__total {
  margin: 0;
}

.breakdown {
  display: grid;
  margin: 0;
  padding: 0;
  list-style: none;
}

.breakdown__row {
  display: grid;
  grid-template-columns: var(--sp-4) var(--icon-md) minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-3) 0;
  border-top: var(--border-w) solid var(--c-border);
}

.breakdown__op {
  color: var(--c-muted);
  font-size: var(--fs-lg);
  font-weight: var(--fw-bold);
  text-align: center;
}

.breakdown__icon {
  display: inline-flex;
  color: var(--tone-fg);
  font-size: var(--icon-md);
}

.breakdown__label {
  display: grid;
  font-weight: var(--fw-semibold);
}

.breakdown__note {
  color: var(--c-muted);
  font-size: var(--fs-sm);
  font-weight: var(--fw-regular);
}

.breakdown__amount {
  text-align: right;
}

.breakdown__row--total {
  border-top: var(--border-w-strong) solid var(--c-text);
  font-weight: var(--fw-bold);
}

.breakdown__row--total .breakdown__label {
  grid-column: 2 / 4;
  font-weight: var(--fw-bold);
}

.bill-list,
.item-list {
  display: grid;
  margin: 0;
  padding: 0;
  list-style: none;
}

.bill-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2) var(--sp-3);
  padding: var(--sp-3) 0;
  border-top: var(--border-w) solid var(--c-border);
}

.bill-row:first-child,
.item:first-child {
  border-top: 0;
  padding-top: 0;
}

.bill-row__main {
  display: grid;
  flex: 1 1 0;
  min-width: 0;
}

.bill-row__name {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-1) var(--sp-2);
  font-weight: var(--fw-semibold);
}

/* A name that opens its record is a 44px touch target (PLAN 7.9, WCAG 2.5.8); a plain name is not */
a.bill-row__name {
  min-height: var(--touch-min);
}

.bill-row__meta {
  color: var(--c-muted);
  font-size: var(--fs-sm);
}

.bill-row__side {
  display: grid;
  justify-items: end;
  gap: var(--sp-1);
  margin-left: auto;
  text-align: right;
}

.item {
  display: grid;
  gap: var(--sp-2);
  padding: var(--sp-3) 0;
  border-top: var(--border-w) solid var(--c-border);
}

.item__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2);
}

.item__name {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  font-weight: var(--fw-semibold);
}

/* As a link (the record's name in a card list) it is a 44px touch target, like a.bill-row__name */
a.item__name {
  min-height: var(--touch-min);
}

.item__name > .bi {
  color: var(--tone-fg);
}

.item__meta {
  margin: 0;
  color: var(--c-muted);
  font-size: var(--fs-sm);
}

.item__overdue {
  color: var(--c-expense-fg);
}

/* ================================================================== expenses */
.summary-strip {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(var(--summary-min), 100%), 1fr));
  gap: var(--sp-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.summary-item {
  display: grid;
  align-content: start;
  gap: var(--sp-1);
  padding: var(--sp-3) var(--sp-4);
  border: var(--border-w) solid var(--c-border);
  border-top: var(--accent-w) solid var(--tone-fg);
  border-radius: var(--radius-card);
  background: var(--c-surface);
  box-shadow: var(--shadow-card);
}

.summary-item__label {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  color: var(--c-muted);
  font-weight: var(--fw-semibold);
}

.summary-item__label > .bi {
  color: var(--tone-fg);
}

.summary-item__count {
  color: var(--tone-fg);
  font-size: var(--fs-money-summary);
  font-weight: var(--fw-bold);
  line-height: var(--lh-tight);
}

/* Summary numbers are 28–36px (1A decision). On a 360px phone two columns leave about 130px per
   card, so the padding and gap shrink a little and the unit may wrap under the number. */
.money--summary {
  font-size: var(--fs-money-summary);
  font-weight: var(--fw-bold);
  line-height: var(--lh-tight);
}

.money--summary .money__unit,
.money--summary .money__sym {
  font-size: var(--money-unit-scale);
  font-weight: var(--fw-semibold);
}

.summary-item .money--summary {
  white-space: normal;
}

.summary-item .money--summary .money__num {
  white-space: nowrap;
}

@media (max-width: 767.98px) {
  .summary-strip {
    gap: var(--sp-2);
  }

  .summary-item {
    padding: var(--sp-3);
  }
}

.summary-item__text {
  font-size: var(--fs-md);
  font-weight: var(--fw-bold);
}

.summary-item__meta {
  color: var(--c-muted);
  font-size: var(--fs-sm);
}

.summary-item__link {
  display: inline-flex;
  align-items: center;
  justify-self: start;
  min-height: var(--touch-min);
  font-weight: var(--fw-semibold);
}

.bill-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(var(--bill-min), 100%), 1fr));
  gap: var(--sp-4);
  margin: 0;
  padding: 0;
  list-style: none;
}

.bill-grid > li {
  display: flex;
}

.bill-card {
  --status-line: var(--c-brand-fg);
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: var(--sp-3);
  padding: var(--sp-4);
  border: var(--border-w) solid var(--c-border);
  border-top: var(--accent-w) solid var(--status-line);
  border-radius: var(--radius-card);
  background: var(--c-surface);
  box-shadow: var(--shadow-card);
}

.bill-card--overdue { --status-line: var(--c-expense-fg); }
.bill-card--due-soon { --status-line: var(--c-debt-fg); }
.bill-card--upcoming { --status-line: var(--c-brand-fg); }
.bill-card--paid { --status-line: var(--c-income-fg); }
.bill-card--skipped,
.bill-card--closed { --status-line: var(--c-neutral-fg); }

.bill-card__head {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
}

.bill-card__title {
  display: grid;
  flex: 1;
  gap: var(--sp-1);
  min-width: 0;
}

.bill-card__name {
  margin: 0;
  font-size: var(--fs-md);
  font-weight: var(--fw-bold);
}

.bill-card__tags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1);
  margin: 0;
}

/* Flex instead of a fixed 2-column grid: a fact never shrinks below its
   content, so a long amount wraps to its own line on 320px phones instead of
   running into the due-date column. */
.bill-card__facts {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-4);
  margin: 0;
}

.bill-card__fact {
  flex: 1 1 0;
  min-width: max-content;
}

.bill-card__fact dt {
  color: var(--c-muted);
  font-size: var(--fs-sm);
  font-weight: var(--fw-regular);
}

.bill-card__fact dd {
  margin: 0;
  font-weight: var(--fw-semibold);
}

.bill-card__fact--wide {
  flex-basis: 100%;
  min-width: 0;
}

.bill-card__actions {
  display: grid;
  gap: var(--sp-2);
  margin-top: auto;
  padding-top: var(--sp-3);
  border-top: var(--border-w) solid var(--c-border);
}

.bill-card__primary {
  width: 100%;
}

.bill-card__more {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2);
}

.bill-card__note {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: var(--touch-min);
  margin: 0;
  color: var(--c-muted);
}

/* ================================================================== component gallery */
.toc__list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.toc__list a {
  display: inline-flex;
  align-items: center;
  min-height: var(--touch-min);
  padding: 0 var(--sp-3);
  border-radius: var(--radius-pill);
  background: var(--c-surface-2);
  color: var(--c-text);
  font-weight: var(--fw-medium);
  text-decoration: none;
}

.toc__list a:hover {
  background: var(--c-brand-bg);
  color: var(--c-brand-fg);
}

.swatch-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(var(--swatch-min), 100%), 1fr));
  gap: var(--sp-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.swatch {
  display: grid;
  overflow: hidden;
  border: var(--border-w) solid var(--c-border);
  border-radius: var(--radius-card);
}

.swatch__solid {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: var(--swatch-h);
  padding: var(--sp-3);
  background: var(--tone-solid);
  color: var(--tone-solid-text);
  font-weight: var(--fw-bold);
}

.swatch__tint {
  padding: var(--sp-3);
  background: var(--tone-bg);
  color: var(--tone-fg);
  font-weight: var(--fw-semibold);
}

.swatch__label {
  display: grid;
  gap: var(--sp-1);
  padding: var(--sp-3);
  background: var(--c-surface);
}

.swatch__label code {
  font-size: var(--fs-sm);
}

.band-demo-list {
  display: grid;
  gap: var(--sp-2);
}

.band-demo {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  border-left: var(--accent-w) solid var(--tone-fg);
  border-radius: var(--radius-md);
  background: var(--tone-bg);
}

.band-demo__title {
  flex: 1;
  color: var(--tone-fg);
  font-size: var(--fs-md);
  font-weight: var(--fw-bold);
}

.type-specimen {
  display: grid;
  gap: var(--sp-2);
}

.type-specimen p {
  margin: 0;
}

.type-specimen__h1 {
  font-size: var(--fs-2xl);
  font-weight: var(--fw-bold);
  line-height: var(--lh-heading);
}

.type-specimen__h2 {
  font-size: var(--fs-lg);
  font-weight: var(--fw-bold);
}

.type-specimen__h3 {
  font-size: var(--fs-md);
  font-weight: var(--fw-bold);
}

.type-specimen__muted {
  color: var(--c-muted);
  font-size: var(--fs-sm);
}

.money-demo,
.status-demo {
  display: grid;
  margin: 0;
}

.money-demo__row,
.money-sizes p,
.status-demo__row {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-2) var(--sp-3);
  margin: 0;
  padding: var(--sp-2) 0;
  border-top: var(--border-w) solid var(--c-border);
}

.money-demo dt,
.status-demo dt {
  font-weight: var(--fw-medium);
}

.money-demo dd,
.status-demo dd {
  margin: 0;
}

.status-demo__row {
  align-items: center;
  justify-content: flex-start;
}

.status-demo dt {
  min-width: var(--label-col);
}

.status-demo dd,
.money-sizes__label {
  color: var(--c-muted);
}

/* ================================================================== charts */
.chart {
  display: grid;
  gap: var(--sp-3);
  margin: 0;
}

/* Grid items default to min-width: auto, which would keep the canvas at Chart.js's initial 300px
   and push narrow phones (320px) into horizontal scrolling. */
.chart > * {
  min-width: 0;
}

.chart__canvas > canvas {
  max-width: 100%;
}

.chart__caption {
  display: grid;
  gap: var(--sp-1);
}

.chart__title {
  margin: 0;
  font-size: var(--fs-lg);
  font-weight: var(--fw-bold);
}

.chart__summary {
  margin: 0;
  color: var(--c-muted);
}

.chart-legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-5);
  margin: 0;
  padding: 0;
  list-style: none;
}

.chart-legend__item {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  font-weight: var(--fw-medium);
}

.legend-swatch {
  display: inline-block;
  width: var(--sp-5);
  height: var(--sp-3);
  border-radius: var(--radius-sm);
  background: var(--tone-fg);
}

.legend-swatch--bar-hatch {
  border: var(--border-w-strong) solid var(--tone-fg);
  background: repeating-linear-gradient(45deg, var(--tone-fg) 0 var(--border-w-strong), var(--c-surface) var(--border-w-strong) var(--sp-1));
}

.legend-swatch--line {
  height: 0;
  border-top: var(--focus-w) dashed var(--tone-fg);
  border-radius: 0;
  background: none;
}

.chart__canvas {
  position: relative;
  height: var(--chart-h-compact);
}

@media (min-width: 768px) {
  .chart__canvas {
    height: var(--chart-h);
  }
}

.chart__data > summary,
.chart__data summary {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: var(--touch-min);
  color: var(--c-link);
  font-weight: var(--fw-semibold);
  cursor: pointer;
}

.chart__data[open] > summary {
  margin-bottom: var(--sp-2);
}

/* ================================================================== sample pages */
.sample-notice {
  display: grid;
  gap: var(--sp-3);
  margin-bottom: var(--sp-5);
  padding: var(--sp-3) var(--sp-4);
  border: var(--border-w) dashed var(--c-asset-fg);
  border-radius: var(--radius-card);
  background: var(--c-asset-bg);
}

.sample-notice__text {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  margin: 0;
}

.sample-notice__text > .bi {
  margin-top: var(--sp-1);
  color: var(--c-asset-fg);
  font-size: var(--icon-md);
}

.sample-notice__nav {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
}

.sample-notice__link {
  display: inline-flex;
  align-items: center;
  min-height: var(--touch-min);
  padding: 0 var(--sp-4);
  border: var(--border-w) solid var(--c-asset-fg);
  border-radius: var(--radius-pill);
  background: var(--c-surface);
  color: var(--c-asset-fg);
  font-weight: var(--fw-semibold);
  text-decoration: none;
}

.sample-notice__link:hover {
  color: var(--c-asset-fg);
  text-decoration: underline;
}

.sample-notice__link[aria-current="page"] {
  /* -fg edge on the tinted notice (equals -solid in light mode), see .icon-tile--solid */
  border-color: var(--c-asset-fg);
  background: var(--c-asset-solid);
  color: var(--c-asset-solid-text);
}

.review-dock {
  position: fixed;
  right: max(var(--sp-4), env(safe-area-inset-right));
  bottom: calc(var(--bottom-nav-h) + env(safe-area-inset-bottom) + var(--sp-3));
  z-index: var(--z-dock);
  display: flex;
  flex-direction: column;
  align-items: flex-end;
}

@media (min-width: 992px) {
  .review-dock {
    right: var(--sp-5);
    bottom: var(--sp-5);
  }
}

.review-dock__toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: var(--touch-min);
  padding: 0 var(--sp-4);
  border-radius: var(--radius-pill);
  background: var(--c-asset-solid);
  color: var(--c-asset-solid-text);
  font-weight: var(--fw-bold);
  list-style: none;
  box-shadow: var(--shadow-raised);
  cursor: pointer;
}

.review-dock__toggle::-webkit-details-marker {
  display: none;
}

.review-dock__panel {
  position: absolute;
  right: 0;
  bottom: calc(100% + var(--sp-2));
  display: grid;
  gap: var(--sp-3);
  width: var(--popover-w);
  max-width: calc(100vw - 2 * var(--sp-4));
  max-height: calc(100dvh - var(--bottom-nav-h) - var(--topbar-h) - var(--sp-6));
  padding: var(--sp-4);
  overflow-y: auto;
  border: var(--border-w) solid var(--c-border);
  border-radius: var(--radius-card);
  background: var(--c-surface);
  color: var(--c-text);
  box-shadow: var(--shadow-raised);
}

.review-dock__title {
  margin: 0;
  font-size: var(--fs-md);
  font-weight: var(--fw-bold);
}

.review-group {
  margin: 0;
  padding: 0;
  border: 0;
}

.review-group legend {
  display: flex;
  float: none;
  align-items: center;
  gap: var(--sp-2);
  margin: 0;
  font-size: var(--fs-base);
  font-weight: var(--fw-bold);
}

.review-summary {
  margin: 0;
  color: var(--c-muted);
  font-size: var(--fs-sm);
}

.font-preview--sarabun {
  font-family: var(--font-sarabun);
}

.font-preview--plex {
  font-family: var(--font-plex);
}

/* ================================================================== sign-in and settings (1B) */
.flash-stack {
  display: grid;
  gap: var(--sp-2);
  margin-bottom: var(--sp-5);
}

.page-narrow {
  width: 100%;
  max-width: var(--page-narrow);
}

.page-stack.page-narrow > .flash-stack {
  margin-bottom: 0;
}

.field--narrow {
  max-width: var(--field-max);
}

.form-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-3);
  margin: 0;
}

.callout__action {
  margin: var(--sp-2) 0 0;
}

.sub-title + .form-check {
  margin-top: calc(var(--sp-2) * -1);
}

/* Help of a switch: under its label, outside it (the label stays the short name) */
.switch-help {
  display: block;
  margin: 0;
}

.help-steps {
  display: grid;
  gap: var(--sp-2);
  margin: 0;
  padding-left: var(--sp-5);
}

/* ---------- sign-in pages (layouts/auth.twig) */
.auth-page {
  min-height: 100vh;
  min-height: 100dvh;
}

.auth-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  padding: max(var(--sp-3), env(safe-area-inset-top)) max(var(--sp-4), env(safe-area-inset-right)) var(--sp-3) max(var(--sp-4), env(safe-area-inset-left));
}

.auth-brand {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3);
  color: var(--c-brand-fg);
  font-size: var(--fs-md);
  font-weight: var(--fw-bold);
}

.auth-main {
  display: grid;
  gap: var(--sp-4);
  width: 100%;
  max-width: var(--auth-w);
  margin: 0 auto;
  padding: var(--sp-4) max(var(--sp-4), env(safe-area-inset-right)) calc(var(--sp-7) + env(safe-area-inset-bottom)) max(var(--sp-4), env(safe-area-inset-left));
}

.auth-main:focus {
  outline: none;
}

/* The one-time web installer (layouts/install.twig): forms and command lines need a wider column */
.auth-main--wide {
  max-width: var(--page-narrow);
}

.install-progress {
  justify-content: center;
}

.auth-main > .flash-stack {
  margin-bottom: 0;
}

@media (min-width: 768px) {
  .auth-main {
    padding-top: var(--sp-6);
  }
}

.auth-heading {
  display: grid;
  justify-items: center;
  gap: var(--sp-2);
  text-align: center;
}

.auth-heading__title {
  margin: 0;
  color: var(--c-text);
  font-size: var(--fs-xl);
  font-weight: var(--fw-bold);
}

.auth-heading__lead {
  margin: 0;
  color: var(--c-muted);
}

.auth-card {
  gap: var(--sp-4);
}

.auth-submit {
  width: 100%;
}

.auth-alt {
  margin: 0;
  text-align: center;
}

.auth-alt a {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: var(--touch-min);
  font-weight: var(--fw-semibold);
}

.auth-cancel {
  display: flex;
  justify-content: center;
  margin: 0;
}

/* Block, not flex: the lock icon stays inline at the start of the text when it wraps on a phone */
.auth-note {
  margin: 0;
  color: var(--c-muted);
  font-size: var(--fs-sm);
  text-align: center;
  text-wrap: balance;
}

.auth-note .bi {
  margin-right: var(--sp-1);
}

/* ---------- 2FA set-up and recovery codes */
.setup-2fa {
  display: grid;
  gap: var(--sp-4);
}

.step-num {
  display: inline-grid;
  flex-shrink: 0;
  place-items: center;
  width: var(--icon-tile);
  height: var(--icon-tile);
  border-radius: var(--radius-pill);
  background: var(--tone-bg);
  color: var(--tone-fg);
  font-weight: var(--fw-bold);
}

.setup-apps {
  display: grid;
  gap: var(--sp-2);
  margin: 0;
  padding-left: var(--sp-5);
}

.qr-box {
  display: grid;
  justify-items: center;
  gap: var(--sp-2);
  margin: 0;
  text-align: center;
}

/* The QR keeps its own white background (scanners need dark-on-light) with a quiet zone, in both themes */
.qr-box__img {
  width: var(--qr-size);
  max-width: 100%;
  height: auto;
  padding: var(--sp-2);
  border: var(--border-w) solid var(--c-border);
  border-radius: var(--radius-md);
  background: var(--c-on-solid);
}

/* Setting up on the phone that holds the authenticator (cannot scan its own screen) */
.same-device {
  display: grid;
  gap: var(--sp-2);
  padding-top: var(--sp-3);
  border-top: var(--border-w) solid var(--c-border);
}

.same-device__text {
  margin: 0;
}

/* display: inline-flex removes the native disclosure triangle, so the summary shows its own chevron */
.manual-secret summary {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: var(--touch-min);
  color: var(--c-link);
  font-weight: var(--fw-semibold);
  list-style: none;
  cursor: pointer;
}

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

.manual-secret__chevron {
  transform: rotate(-90deg);
}

.manual-secret[open] .manual-secret__chevron {
  transform: none;
}

.manual-secret__list {
  display: grid;
  gap: var(--sp-2);
  margin: var(--sp-2) 0 0;
}

.manual-secret__list dt {
  color: var(--c-muted);
  font-size: var(--fs-sm);
  font-weight: var(--fw-regular);
}

.manual-secret__list dd {
  margin: 0;
  font-weight: var(--fw-semibold);
}

.secret-code,
.code-list__code {
  color: var(--c-text);
  font-family: var(--font-code);
  font-size: var(--fs-md);
  font-weight: var(--fw-semibold);
  letter-spacing: 0.05em;
  overflow-wrap: anywhere;
}

.code-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(var(--code-min), 100%), 1fr));
  gap: var(--sp-2) var(--sp-4);
  margin: 0;
  padding: var(--sp-3) var(--sp-4) var(--sp-3) var(--sp-6);
  border: var(--border-w) dashed var(--c-control-border);
  border-radius: var(--radius-md);
  background: var(--c-surface-2);
}

.code-list li::marker {
  color: var(--c-muted);
}

/* ---------- settings */
.settings-list {
  display: grid;
  gap: var(--sp-3);
  max-width: var(--page-narrow);
  margin: 0;
  padding: 0;
  list-style: none;
}

.settings-link {
  display: flex;
  align-items: center;
  gap: var(--sp-3) var(--sp-4);
  min-height: calc(var(--touch-min) * 1.5);
  padding: var(--sp-4);
  border: var(--border-w) solid var(--c-border);
  border-radius: var(--radius-card);
  background: var(--c-surface);
  color: var(--c-text);
  text-decoration: none;
  box-shadow: var(--shadow-card);
}

.settings-link:hover {
  border-color: var(--tone-fg);
  color: var(--c-text);
}

.settings-link__text {
  display: grid;
  flex: 1;
  gap: var(--sp-1);
  min-width: 0;
}

.settings-link__title {
  font-size: var(--fs-md);
  font-weight: var(--fw-bold);
}

.settings-link__desc {
  color: var(--c-muted);
}

.settings-link__chevron {
  color: var(--c-muted);
  font-size: var(--icon-md);
}

.twofa-status {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2) var(--sp-3);
}

.theme-options {
  display: grid;
  gap: var(--sp-2);
  margin: 0;
  padding: 0;
  border: 0;
}

.theme-option {
  position: relative;
  align-items: flex-start;
  padding: var(--sp-3);
  border: var(--border-w) solid var(--c-border);
  border-radius: var(--radius-md);
}

/* The label covers the whole card, so tapping the help text below it still picks the option */
.theme-option__label::after {
  position: absolute;
  inset: 0;
  content: "";
}

.theme-option__help {
  margin: var(--sp-1) 0 0;
}

.theme-option:has(.form-check-input:checked) {
  border-color: var(--c-brand-fg);
  background: var(--c-brand-bg);
}

.theme-option .form-check-input {
  margin-top: var(--sp-1);
}

.theme-option__label {
  display: grid;
  gap: var(--sp-1);
}

.theme-option__name {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  font-weight: var(--fw-bold);
}

/* Mobile "เมนู" sheet: the theme choice at the end, before the account row */
.sheet__theme .theme-choice {
  margin: var(--sp-2) 0 0;
}

/* ================================================================== money pages (phase 2) */
/* Menus of later phases: a quiet note next to the label (the toast explains on tap) */
.side-link__soon,
.sheet-link__soon {
  display: block;
  color: var(--c-muted);
  font-size: var(--fs-nav);
  font-weight: var(--fw-regular);
  line-height: var(--lh-tight);
}

/* Tabs inside a menu */
.sub-nav__list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.sub-nav__link {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: var(--touch-min);
  padding: var(--sp-2) var(--sp-4);
  border: var(--border-w) solid var(--c-border);
  border-radius: var(--radius-pill);
  background: var(--c-surface);
  color: var(--c-text);
  font-weight: var(--fw-medium);
  text-decoration: none;
}

.sub-nav__link:hover {
  background: var(--c-surface-2);
  color: var(--c-text);
}

.sub-nav__link.is-active {
  border-color: var(--tone-fg);
  background: var(--tone-bg);
  color: var(--tone-fg);
  font-weight: var(--fw-bold);
}

/* Month navigation of the expense page */
.month-nav {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2) var(--sp-3);
}

.month-nav__current {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  margin: 0;
  font-size: var(--fs-lg);
  font-weight: var(--fw-bold);
}

.bill-card__link,
.bill-row__name {
  color: inherit;
}

/* The record name in a card heading opens the record: a 44px touch target like every other link
   (PLAN 7.9, WCAG 2.5.8), centered on the card's icon tile. */
.bill-card__link {
  display: inline-flex;
  align-items: center;
  min-height: var(--touch-min);
  text-decoration: none;
}

.bill-card__link:hover {
  color: inherit;
  text-decoration: underline;
}

/* Bell: each notification opens its page and is marked read */
.notif-item__form {
  flex: 1;
  margin: 0;
}

.notif-item__open {
  display: grid;
  width: 100%;
  min-height: var(--touch-min);
  padding: 0;
  border: 0;
  background: none;
  color: var(--c-text);
  font-weight: var(--fw-semibold);
  text-align: left;
}

.notif-item__open:hover {
  text-decoration: underline;
}

.notif-panel__all {
  margin: var(--sp-3) 0 0;
}

/* Attachments */
.attachment-list {
  display: grid;
  gap: var(--sp-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.attachment {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: var(--sp-2) var(--sp-3);
  padding: var(--sp-3);
  border: var(--border-w) solid var(--c-border);
  border-radius: var(--radius-md);
  background: var(--c-surface-2);
}

.attachment__thumb {
  display: block;
  width: var(--tile-min);
  height: var(--tile-min);
  border-radius: var(--radius-sm);
  object-fit: cover;
}

.attachment__main {
  display: grid;
  min-width: 0;
}

.attachment__name {
  font-weight: var(--fw-semibold);
  overflow-wrap: anywhere;
}

.attachment__meta {
  color: var(--c-muted);
  font-size: var(--fs-sm);
}

.attachment__actions {
  display: flex;
  flex-wrap: wrap;
  grid-column: 1 / -1;
  gap: var(--sp-2);
}

@media (min-width: 768px) {
  .attachment {
    grid-template-columns: auto minmax(0, 1fr) auto;
  }

  .attachment__actions {
    grid-column: auto;
    justify-content: flex-end;
  }
}

.attachment-upload {
  display: grid;
  gap: var(--sp-3);
  margin: 0;
}

/* Person field with "เพิ่มบุคคลด่วน" */
.person-field {
  display: grid;
  align-content: start;
  gap: var(--sp-2);
}

.person-field__add {
  justify-self: start;
}

/* Summary strips with real wallet balances (6–7 digits fit at the summary size; phones stack them) */
.summary-strip--wide {
  grid-template-columns: repeat(auto-fit, minmax(min(var(--summary-min-wide), 100%), 1fr));
}

/* The expense menu's month strip: the approved 2 × 2 on phones (monthly amounts fit at 375px), and
   room for 6-digit amounts from 768px, where the approved minimum is too narrow. */
@media (min-width: 768px) {
  .summary-strip--tablet-wide {
    grid-template-columns: repeat(auto-fit, minmax(min(var(--summary-min-wide), 100%), 1fr));
  }
}

/* A table cell with the item and its details on muted lines below */
.cell-stack {
  display: grid;
  gap: var(--sp-1);
  font-weight: var(--fw-regular);
}

.cell-stack > .table-link {
  font-weight: var(--fw-semibold);
}

/* Legends of the money forms' radio groups read like the other field labels */
.field > legend.form-label,
.alloc > legend.form-label,
.confirm-box > legend.form-label {
  float: none;
  width: auto;
  margin-bottom: var(--sp-2);
  font-size: var(--fs-base);
}

/* A check, radio or switch with its help on the line below, aligned with the label */
.form-check:has(> .switch-help) {
  flex-wrap: wrap;
  row-gap: 0;
}

.form-check > .switch-help {
  flex-basis: 100%;
  padding-left: calc(var(--icon-md) + var(--sp-3));
}

.form-switch > .switch-help {
  padding-left: calc(var(--icon-md) * 2 + var(--sp-3));
}

/* Long lists */
.pager {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
}

.pager__info {
  margin: 0;
  color: var(--c-muted);
}

.pager__links {
  display: flex;
  gap: var(--sp-2);
}

/* Confirmations after a refusal (wallet below zero, locked period) */
.confirm-box {
  display: grid;
  gap: var(--sp-2);
  margin: 0;
  padding: var(--sp-3) var(--sp-4);
  border: var(--border-w) solid var(--c-debt-fg);
  border-radius: var(--radius-md);
  background: var(--c-debt-bg);
}

/* Income form: the split into the two wallets and the stock warning */
.alloc {
  display: grid;
  gap: var(--sp-2);
  margin: 0;
  padding: var(--sp-3) var(--sp-4);
  border: var(--border-w) solid var(--c-border);
  border-radius: var(--radius-md);
}

.alloc__preview {
  margin: 0 0 var(--sp-2);
  padding-left: var(--sp-6);
}

.alloc__manual[hidden] {
  display: none;
}

.stock-check {
  display: grid;
  gap: var(--sp-2);
}

.stock-check p {
  margin: 0;
}

.stock-check__warning {
  padding: var(--sp-3) var(--sp-4);
  border-left: var(--accent-w) solid var(--tone-fg);
  border-radius: var(--radius-md);
  background: var(--tone-bg);
  color: var(--c-text);
  font-weight: var(--fw-semibold);
}

/* Detail rows (person page) */
.detail-list {
  display: grid;
  gap: var(--sp-2);
  margin: 0;
}

.detail-list__row {
  display: grid;
  grid-template-columns: minmax(0, var(--label-col)) minmax(0, 1fr);
  gap: var(--sp-3);
}

.detail-list__row dt {
  color: var(--c-muted);
  font-weight: var(--fw-medium);
}

.detail-list__row dd {
  margin: 0;
}

/* Reconcile results (settings) */
.check-list {
  display: grid;
  gap: var(--sp-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.check-list__item {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
}

.check-list__icon {
  display: inline-flex;
  padding-top: var(--sp-1);
  color: var(--tone-fg);
}

.check-list__text {
  display: grid;
  gap: var(--sp-1);
}

.check-list__note,
.check-list__problem {
  color: var(--c-muted);
  font-size: var(--fs-sm);
}

/* ================================================================== debts, assets, money lent (phase 3) */
/* Cards of the three menus reuse .bill-card; the top line is the menu color (status cards keep theirs) */
.bill-card--debt { --status-line: var(--c-debt-fg); }
.bill-card--asset { --status-line: var(--c-asset-fg); }
.bill-card--loan { --status-line: var(--c-loan-fg); }

/* "+ เพิ่มหนี้" / "+ เพิ่มเงินปล่อยกู้": one form in numbered steps */
.wizard-step {
  display: grid;
  gap: var(--sp-4);
  min-width: 0;
  margin: 0;
  padding: var(--sp-4);
  border: var(--border-w) solid var(--c-border);
  border-radius: var(--radius-md);
}

/* Floated (Bootstrap's legend rule): a grid item inside the step's border instead of on it */
.wizard-step > .wizard-step__title {
  display: flex;
  float: left;
  align-items: center;
  gap: var(--sp-3);
  width: 100%;
  margin: 0;
  font-size: var(--fs-md);
  font-weight: var(--fw-bold);
}

.field-group {
  display: grid;
  align-content: start;
  gap: var(--sp-3);
}

/* The plain-Thai explanation of the chosen interest method / loan type */
.method-help {
  display: grid;
  gap: var(--sp-2);
}

.method-help__text {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  margin: 0;
  padding: var(--sp-3) var(--sp-4);
  border-left: var(--accent-w) solid var(--tone-fg);
  border-radius: var(--radius-md);
  background: var(--tone-bg);
}

.method-help__text > .bi {
  flex-shrink: 0;
  margin-top: var(--sp-1);
  color: var(--tone-fg);
}

/* Live schedule of a form (schedule-preview.js) */
.preview-box {
  display: grid;
  gap: var(--sp-3);
  padding: var(--sp-4);
  border: var(--border-w) dashed var(--c-control-border);
  border-radius: var(--radius-md);
  background: var(--c-surface-2);
}

.preview-box__title {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin: 0;
  font-size: var(--fs-md);
  font-weight: var(--fw-bold);
}

.preview-box__title > .bi,
.split-box__title > .bi {
  color: var(--tone-fg);
}

.preview-box p {
  margin: 0;
}

/* Interest / principal split of a payment (split-preview.js) */
.split-box {
  display: grid;
  gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-4);
  border: var(--border-w) solid var(--c-border);
  border-radius: var(--radius-md);
  background: var(--c-surface-2);
}

.split-box__title {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin: 0;
  font-weight: var(--fw-semibold);
}

.split-box__parts {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-5);
  margin: 0;
}

.split-box__part dt {
  color: var(--c-muted);
  font-size: var(--fs-sm);
  font-weight: var(--fw-regular);
}

.split-box__part dd {
  margin: 0;
  font-variant-numeric: tabular-nums;
  font-weight: var(--fw-bold);
}

.split-box__note {
  margin: 0;
  color: var(--c-muted);
}

.split-box__fields[hidden] {
  display: none;
}

/* Rows of a contract schedule paid before the go-live date */
.row-muted > td,
.row-muted > th {
  color: var(--c-muted);
}

/* Gain / loss preview of a sale */
.gain-preview {
  display: grid;
  gap: var(--sp-1);
  margin: 0;
}

/* ================================================================== people and accountant documents (phase 4) */
/* The person page header: the photo (or the person icon) next to the name and contact details */
.person-hero {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: start;
  gap: var(--sp-3) var(--sp-4);
}

.person-hero__photo {
  display: block;
  width: var(--tile-min);
  height: var(--tile-min);
  border-radius: var(--radius-card);
  object-fit: cover;
}

.person-hero__name {
  margin: 0;
  font-size: var(--fs-xl);
  font-weight: var(--fw-bold);
  line-height: var(--lh-heading);
  overflow-wrap: anywhere;
}

.person-hero__tags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin: var(--sp-2) 0 0;
}

/* A list whose rows can be ticked for the actions of .bulk-bar (a narrow first column on wide
   screens; a "เลือก" line of the card below 992px, where .data-table--wide becomes cards) */
@media (min-width: 992px) {
  .cell-check {
    width: 1%;
  }
}

/* The tick box: the design-system border (3:1 against the card and the striped rows, PLAN 7.1)
   and the whole label as the tap target (44px, PLAN 7.9); "เลือก" is its visible text on a phone
   card and visually hidden in the wide table, where the column says it. */
.cell-check__hit {
  display: flex;
  flex: 1 1 auto;
  align-items: center;
  gap: var(--sp-3);
  min-width: var(--touch-min);
  min-height: var(--touch-min);
  margin: 0;
  cursor: pointer;
}

.cell-check .form-check-input {
  flex-shrink: 0;
  float: none;
  width: var(--icon-lg);
  height: var(--icon-lg);
  margin: 0;
  border: var(--border-w-strong) solid var(--c-control-border);
  background-color: var(--c-surface);
}

.cell-check .form-check-input:checked {
  border-color: var(--c-brand-solid);
  background-color: var(--c-brand-solid);
}

.cell-check .form-check-input:focus {
  border-color: var(--c-focus);
}

.data-table .cell-check::before {
  content: none;
}

@media (min-width: 992px) {
  .cell-check__hit {
    justify-content: center;
  }

  .cell-check__label {
    position: absolute;
    width: var(--border-w);
    height: var(--border-w);
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
  }
}

.bulk-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2) var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  border: var(--border-w) dashed var(--c-control-border);
  border-radius: var(--radius-md);
  background: var(--c-surface-2);
}

.bulk-bar__count {
  margin: 0;
  font-weight: var(--fw-semibold);
}

.bulk-bar__all[hidden] {
  display: none;
}

/* The paths inside the accountant zip, as the folders will be on the computer */
.zip-entries {
  display: grid;
  gap: var(--sp-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.zip-entries__item {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-1) var(--sp-3);
  padding: var(--sp-2) var(--sp-3);
  border: var(--border-w) solid var(--c-border);
  border-radius: var(--radius-sm);
  background: var(--c-surface-2);
}

.zip-entries__path {
  font-weight: var(--fw-medium);
  overflow-wrap: anywhere;
}

/* Accountant documents of a person, by year then month */
.doc-year {
  display: grid;
  gap: var(--sp-3);
}

.doc-year + .doc-year {
  margin-top: var(--sp-5);
}

.doc-year__title {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin: 0;
  font-size: var(--fs-md);
  font-weight: var(--fw-bold);
}

.doc-preview {
  display: block;
  max-width: 100%;
  max-height: var(--preview-max-h);
  border: var(--border-w) solid var(--c-border);
  border-radius: var(--radius-md);
  object-fit: contain;
}

/* ================================================================== phase 5: import / export / backup */
/* Where the import wizard stands (1 เลือกข้อมูล … 6 ผล): number + label, the current step bold,
   finished steps with a check (text says it too, never color only) */
.wizard-progress {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-4);
  margin: 0;
  padding: 0;
  list-style: none;
}

.wizard-progress__item {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  color: var(--c-muted);
  font-size: var(--fs-sm);
}

.wizard-progress__item .step-num {
  background: var(--c-surface-2);
  color: var(--c-muted);
}

.wizard-progress__item.is-current {
  color: var(--c-text);
  font-weight: var(--fw-bold);
}

.wizard-progress__item.is-current .step-num,
.wizard-progress__item.is-done .step-num {
  background: var(--tone-bg);
  color: var(--tone-fg);
}

/* "ส่งออกและนำเข้า" of a list page: one row per data set, the buttons wrap under the name on phones */
.data-tools {
  display: grid;
  gap: var(--sp-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.data-tools__row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2) var(--sp-4);
  padding-top: var(--sp-3);
  border-top: var(--border-w) solid var(--c-border);
}

.data-tools__row:first-child {
  padding-top: 0;
  border-top: 0;
}

.data-tools__name {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  margin: 0;
  font-weight: var(--fw-semibold);
}

.data-tools__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
  margin: 0;
}

/* A value as the import read it, under the cell text of the preview ("→ 3 ต.ค. 2569") */
.cell-read {
  color: var(--c-muted);
  font-size: var(--fs-sm);
}

/* The cells of one imported row as "column: value" pairs (import preview): as many columns of
   pairs as fit the cell, so a file with 25 columns never widens the page past the screen */
.field-pairs {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(var(--pair-min), 100%), 1fr));
  gap: var(--sp-2) var(--sp-4);
  margin: 0;
}

.field-pairs__item {
  min-width: 0;
}

.field-pairs dt {
  color: var(--c-muted);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
}

.field-pairs dd {
  margin: 0;
  overflow-wrap: anywhere;
}

/* The pairs take the room the other columns leave; the Thai reasons keep a readable width */
@media (min-width: 768px) {
  .data-table .cell-pairs {
    width: 100%;
  }

  .data-table .cell-notes {
    min-width: var(--filter-min);
  }
}

/* On a phone card the pairs go under their label, left-aligned, after the reasons (which stay
   near the top of the card) */
@media (max-width: 767.98px) {
  .data-table td.cell-pairs {
    display: block;
    order: 1;
    text-align: left;
  }

  .data-table td.cell-pairs::before {
    display: block;
    margin-bottom: var(--sp-1);
  }
}

/* The one-time command lines of the restore and backup pages (copy as shown, never a secret) */
.command-line {
  display: block;
  padding: var(--sp-2) var(--sp-3);
  border: var(--border-w) solid var(--c-border);
  border-radius: var(--radius-sm);
  background: var(--c-surface-2);
  overflow-wrap: anywhere;
}

/* ================================================================== phase 6: PWA, quick entry, API tokens */
/* The service worker's "new version" message (app.js): stays until used or closed */
.toast-msg--action {
  flex-wrap: wrap;
  align-items: center;
  pointer-events: auto;
}

.toast-msg--action .bi {
  margin-top: 0;
}

.toast-msg__text {
  flex: 1 1 0;
  min-width: 0;
}

.toast-msg__close {
  color: inherit;
}

.toast-msg :focus-visible {
  outline-color: var(--c-surface);
}

/* The page public/sw.js shows when the network cannot be reached (public/offline.html) */
.offline-page__icon {
  width: var(--app-icon);
  height: auto;
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
}

/* ---------- quick entry (/quick, question 17 (ก)) */
.quick-form {
  display: grid;
}

.quick-kind {
  display: grid;
  gap: var(--sp-3);
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

.quick-kind__legend {
  float: none;
  width: auto;
  margin: 0;
  font-size: var(--fs-lg);
  font-weight: var(--fw-bold);
}

.quick-kind__options {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sp-3);
}

/* The radios stay in the page for keyboards and screen readers; the cards are their labels */
.quick-kind__input,
.chip-input {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  pointer-events: none;
}

.quick-kind__choice {
  display: grid;
  align-content: center;
  justify-items: center;
  gap: var(--sp-1);
  min-height: var(--quick-choice-h);
  padding: var(--sp-4) var(--sp-3);
  border: var(--border-w-strong) solid var(--tone-fg);
  border-radius: var(--radius-card);
  background: var(--tone-bg);
  color: var(--c-text);
  text-align: center;
  cursor: pointer;
}

.quick-kind__icon {
  display: inline-grid;
  place-items: center;
  width: var(--icon-tile-lg);
  height: var(--icon-tile-lg);
  border-radius: var(--radius-pill);
  background: var(--tone-solid);
  color: var(--tone-solid-text);
  font-size: var(--icon-lg);
}

.quick-kind__name {
  color: var(--tone-fg);
  font-size: var(--fs-xl);
  font-weight: var(--fw-bold);
  line-height: var(--lh-tight);
}

.quick-kind__hint {
  color: var(--c-muted);
  font-size: var(--fs-sm);
  line-height: var(--lh-tight);
}

/* Chosen: solid fill (not color alone: fill, raised edge, and the rest of the form appears) */
.quick-kind__input:checked + .quick-kind__choice {
  background: var(--tone-solid);
  box-shadow: var(--shadow-raised);
}

.quick-kind__input:checked + .quick-kind__choice .quick-kind__name,
.quick-kind__input:checked + .quick-kind__choice .quick-kind__hint {
  color: var(--tone-solid-text);
}

.quick-kind__input:checked + .quick-kind__choice .quick-kind__icon {
  background: var(--tone-solid-text);
  color: var(--tone-solid);
}

.quick-kind__input:focus-visible + .quick-kind__choice,
.chip-input:focus-visible + .chip {
  outline: var(--focus-w) solid var(--c-focus);
  outline-offset: var(--focus-offset);
}

/* Before a kind is chosen only the two choices show (also without JavaScript where :has() works) */
.quick-form:not(:has(.quick-kind__input:checked)) .quick-details,
.quick-form:has(#quick-kind-expense:checked) [data-quick-for="income"],
.quick-form:has(#quick-kind-income:checked) [data-quick-for="expense"] {
  display: none;
}

.quick-details {
  display: grid;
  gap: var(--sp-4);
  margin-top: var(--sp-4);
}

.quick-date {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin: 0;
  color: var(--c-muted);
  font-weight: var(--fw-medium);
}

.quick-amount .money-input {
  max-width: none;
}

.quick-amount .money-input .form-control {
  min-height: calc(var(--control-h) * 1.25);
  font-size: var(--fs-money-lg);
  font-weight: var(--fw-bold);
}

.quick-chips {
  display: grid;
  gap: var(--sp-2);
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

.quick-chips > legend.form-label {
  float: none;
  width: auto;
  margin-bottom: var(--sp-1);
  font-size: var(--fs-base);
}

.chip-list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: var(--touch-min);
  padding: var(--sp-1) var(--sp-4);
  border: var(--border-w) solid var(--c-control-border);
  border-radius: var(--radius-pill);
  background: var(--c-surface);
  color: var(--c-text);
  font-weight: var(--fw-medium);
  line-height: var(--lh-tight);
  cursor: pointer;
}

.chip:hover {
  border-color: var(--tone-fg);
}

.chip__icon {
  color: var(--tone-fg);
}

.chip__check {
  display: none;
}

/* Chosen chip: solid fill and a check mark */
.chip-input:checked + .chip {
  border-color: var(--tone-solid);
  background: var(--tone-solid);
  color: var(--tone-solid-text);
  font-weight: var(--fw-bold);
}

.chip-input:checked + .chip .chip__icon {
  color: var(--tone-solid-text);
}

.chip-input:checked + .chip .chip__check {
  display: inline-block;
}

.quick-more summary {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: var(--touch-min);
  color: var(--c-link);
  font-weight: var(--fw-semibold);
  list-style: none;
  cursor: pointer;
}

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

.quick-more__chevron {
  transform: rotate(-90deg);
}

.quick-more[open] .quick-more__chevron {
  transform: none;
}

.quick-more > .chip-list {
  margin-top: var(--sp-2);
}

/* The slip: camera (touch devices) and "a photo or file already saved" side by side when they fit */
.quick-slip {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--slip-min)), 1fr));
  gap: var(--sp-3);
}

.quick-slip > .field {
  min-width: 0;
}

.quick-slip-preview {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2) var(--sp-3);
  padding: var(--sp-3);
  border: var(--border-w) solid var(--c-border);
  border-radius: var(--radius-md);
  background: var(--c-surface-2);
}

.quick-slip-preview__img {
  display: block;
  width: var(--slip-thumb);
  height: var(--slip-thumb);
  border-radius: var(--radius-sm);
  object-fit: cover;
}

/* The name keeps a real width; the remove button wraps under it on narrow screens */
.quick-slip-preview__name {
  flex: 1 1 var(--slip-min);
  min-width: 0;
  font-weight: var(--fw-semibold);
  overflow-wrap: anywhere;
}

/* Phones and tablets: the save button (it names the kind and category) stays in view just above the
   bottom bar, so after the amount and the slip it never needs scrolling */
@media (max-width: 991.98px) {
  .quick-actions {
    position: sticky;
    bottom: calc(var(--bottom-nav-h) + env(safe-area-inset-bottom));
    z-index: var(--z-sticky);
    margin: 0 calc(var(--sp-4) * -1) calc(var(--sp-4) * -1);
    padding: var(--sp-3) var(--sp-4);
    border-top: var(--border-w) solid var(--c-border);
    border-radius: 0 0 var(--radius-card) var(--radius-card);
    background: var(--c-surface);
  }

  /* The page header repeats the top bar's "บันทึกด่วน", and the two big cards say what they are:
     both hidden visually, kept for screen readers */
  .quick-kind__legend,
  .page-header--mobile-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }
}

@media (min-width: 768px) and (max-width: 991.98px) {
  .quick-actions {
    margin: 0 calc(var(--sp-5) * -1) calc(var(--sp-5) * -1);
    padding: var(--sp-3) var(--sp-5);
  }
}

.quick-feedback:empty,
.quick-saved:empty {
  display: none;
}

.quick-feedback {
  margin-bottom: var(--sp-4);
}

.quick-feedback:focus {
  outline: none;
}

/* The lasting "saved" line, on top of the form (where the page scrolls back after a save) */
.quick-saved {
  margin-bottom: var(--sp-4);
  padding: var(--sp-3) var(--sp-4);
  border-left: var(--accent-w) solid var(--c-income-fg);
  border-radius: var(--radius-md);
  background: var(--c-income-bg);
}

.quick-saved__text {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--sp-1) var(--sp-2);
  margin: 0;
  font-weight: var(--fw-semibold);
}

.quick-saved__text > .bi {
  color: var(--c-income-fg);
}

.quick-offline {
  margin: 0;
}

/* ---------- API tokens of the iOS app (/settings/api-tokens) */
.scope-options {
  display: grid;
  gap: var(--sp-2);
  margin: 0;
  padding: 0;
  border: 0;
}

.scope-options > legend.form-label {
  float: none;
  width: auto;
  margin-bottom: var(--sp-1);
  font-size: var(--fs-base);
}

.token-list {
  display: grid;
  gap: var(--sp-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.token-item {
  display: grid;
  gap: var(--sp-3);
  padding: var(--sp-4);
  border: var(--border-w) solid var(--c-border);
  border-radius: var(--radius-md);
  background: var(--c-surface-2);
}

.token-item__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2) var(--sp-3);
}

.token-item__name {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  margin: 0;
  font-size: var(--fs-md);
  font-weight: var(--fw-bold);
  overflow-wrap: anywhere;
}

.token-item.is-ended {
  background: var(--c-surface);
  color: var(--c-muted);
}

.token-secret {
  display: block;
  padding: var(--sp-3) var(--sp-4);
  border: var(--border-w) dashed var(--c-control-border);
  border-radius: var(--radius-md);
  background: var(--c-surface-2);
}

/* ================================================================== phase 7: planning, reports, tools */
.grid--4 {
  grid-template-columns: repeat(auto-fit, minmax(min(var(--summary-min-wide), 100%), 1fr));
}

/* A row of labelled figures (budget month, calendar month) */
.figure-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(var(--summary-min-wide), 100%), 1fr));
  gap: var(--sp-3);
  margin: 0;
}

.figure-row__item {
  display: grid;
  gap: var(--sp-1);
  padding: var(--sp-3);
  border-radius: var(--radius-md);
  background: var(--c-surface-2);
}

.figure-row__item dt {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  color: var(--c-muted);
  font-weight: var(--fw-medium);
}

.figure-row__item[class*="tone-"] dt > .bi {
  color: var(--tone-fg);
}

.figure-row__item dd {
  margin: 0;
}

.figure-row__count {
  font-size: var(--fs-money-md);
  font-weight: var(--fw-bold);
}

/* <meter> of the budget month (the <progress> bars use .meter-bar above) */
meter.meter-bar::-webkit-meter-bar {
  height: 100%;
  border: 0;
  border-radius: var(--radius-pill);
  background: var(--c-track);
}

meter.meter-bar::-webkit-meter-optimum-value,
meter.meter-bar::-webkit-meter-suboptimum-value,
meter.meter-bar::-webkit-meter-even-less-good-value {
  border-radius: var(--radius-pill);
  background: var(--tone-fg);
}

meter.meter-bar::-moz-meter-bar {
  border-radius: var(--radius-pill);
  background: var(--tone-fg);
}

/* Budget lines */
.plan-list {
  display: grid;
  margin: 0;
  padding: 0;
  list-style: none;
}

.plan-item {
  display: grid;
  gap: var(--sp-2);
  padding: var(--sp-4) 0;
  border-top: var(--border-w) solid var(--c-border);
}

.plan-item:first-child {
  padding-top: 0;
  border-top: 0;
}

.plan-item__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2) var(--sp-3);
}

.plan-item__name {
  flex: 1;
  min-width: 0;
  margin: 0;
  font-size: var(--fs-md);
  font-weight: var(--fw-bold);
}

.plan-item__figures,
.plan-item__meta {
  margin: 0;
}

.plan-item__meta {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  color: var(--c-muted);
}

.plan-item__over {
  color: var(--c-expense-fg);
}

.plan-item__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
}

/* Savings goal cards */
.goal-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(var(--grid-min-wide), 100%), 1fr));
  gap: var(--sp-4);
  margin: 0;
  padding: 0;
  list-style: none;
}

.goal-card {
  display: grid;
  gap: var(--sp-3);
  height: 100%;
  padding: var(--sp-4);
  border: var(--border-w) solid var(--c-border);
  border-top: var(--accent-w) solid var(--tone-fg);
  border-radius: var(--radius-card);
  background: var(--c-surface);
  box-shadow: var(--shadow-card);
}

.goal-card__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2) var(--sp-3);
}

.goal-card__name {
  flex: 1;
  min-width: 0;
  margin: 0;
  font-size: var(--fs-md);
  font-weight: var(--fw-bold);
}

.goal-card__name a {
  display: inline-flex;
  align-items: center;
  min-height: var(--touch-min);
  color: inherit;
}

.goal-card__figure {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--sp-1) var(--sp-2);
  margin: 0;
}

.goal-card__of {
  color: var(--c-muted);
}

.goal-card__facts {
  display: grid;
  gap: var(--sp-1);
  margin: 0;
  padding: 0;
  list-style: none;
  color: var(--c-muted);
}

.goal-card__facts li {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
}

.goal-card__facts .bi {
  flex-shrink: 0;
  margin-top: var(--sp-1);
}

.goal-card__per-month {
  color: var(--c-text);
  font-weight: var(--fw-semibold);
}

.entry-form {
  display: grid;
  gap: var(--sp-3);
  padding: var(--sp-4);
  border: var(--border-w) solid var(--c-border);
  border-radius: var(--radius-md);
  background: var(--c-surface-2);
}

/* Money calendar: the month grid (computer) and the list by date (phone) */
.cal-tools {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
}

.cal-legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-4);
  margin: 0;
  padding: 0;
  list-style: none;
}

.cal-legend__item {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
}

.cal-legend__item > .bi {
  color: var(--tone-fg);
}

.cal-grid {
  width: 100%;
  min-width: calc(var(--cal-col-min) * 7);
  table-layout: fixed;
  border-collapse: collapse;
}

.cal-grid th {
  padding: var(--sp-2);
  border-bottom: var(--border-w-strong) solid var(--c-border);
  color: var(--c-muted);
  font-weight: var(--fw-semibold);
  text-align: center;
}

.cal-day {
  height: var(--cal-cell-h);
  padding: var(--sp-1);
  border: var(--border-w) solid var(--c-border);
  vertical-align: top;
}

.cal-day--outside {
  background: var(--c-surface-2);
}

.cal-day--today {
  box-shadow: inset 0 0 0 var(--border-w-strong) var(--c-brand-fg);
}

.cal-day__num {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-1);
  margin: 0 0 var(--sp-1);
  font-weight: var(--fw-bold);
}

.cal-day__today {
  padding: 0 var(--sp-2);
  border-radius: var(--radius-pill);
  background: var(--c-brand-solid);
  color: var(--c-brand-solid-text);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
}

.cal-events {
  display: grid;
  gap: var(--sp-1);
  margin: 0;
  padding: 0;
  list-style: none;
}

.cal-event__link {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  min-height: var(--touch-min);
  padding: var(--sp-1) var(--sp-2);
  border-left: var(--accent-w) solid var(--tone-fg);
  border-radius: var(--radius-sm);
  background: var(--tone-bg);
  color: var(--c-text);
  text-decoration: none;
}

a.cal-event__link:hover {
  color: var(--c-text);
  text-decoration: underline;
}

.cal-event--projected .cal-event__link {
  border-left-style: dashed;
}

.cal-event__icon {
  flex-shrink: 0;
  color: var(--tone-fg);
}

.cal-event__body {
  display: grid;
  min-width: 0;
}

.cal-event__title {
  overflow-wrap: anywhere;
  font-weight: var(--fw-semibold);
}

.cal-event__meta,
.cal-event__status {
  color: var(--c-muted);
  font-size: var(--fs-sm);
}

.cal-event__status {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
}

.cal-event__status > .bi {
  color: var(--tone-fg);
}

.cal-agenda__days {
  display: grid;
  gap: var(--sp-4);
  margin: 0;
  padding: 0;
  list-style: none;
}

.cal-agenda__day {
  display: grid;
  gap: var(--sp-2);
}

.cal-agenda__date {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
  margin: 0;
  font-size: var(--fs-md);
  font-weight: var(--fw-bold);
}

/* Phone: the list by date; computer: the month grid */
.cal-grid-card {
  display: none;
}

@media (min-width: 992px) {
  .cal-grid-card {
    display: grid;
  }

  .cal-agenda {
    display: none;
  }

  /* A day column is narrow: the event wraps inside it (the amount may break before "บาท"). */
  .cal-grid .cal-event__link {
    gap: var(--sp-1);
    min-height: 0;
    padding: var(--sp-1);
  }

  .cal-grid .money {
    white-space: normal;
  }
}

.cal-events > li {
  min-width: 0;
}

/* Choices shown as a row of pills (forecast 3 / 6 months, average income) */
.choice-bar__list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.choice-bar__link {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: var(--touch-min);
  padding: var(--sp-2) var(--sp-4);
  border: var(--border-w) solid var(--c-border);
  border-radius: var(--radius-pill);
  background: var(--c-surface);
  color: var(--c-text);
  font-weight: var(--fw-medium);
  text-decoration: none;
}

.choice-bar__link:hover {
  background: var(--c-surface-2);
  color: var(--c-text);
}

.choice-bar__link.is-active {
  border-color: var(--tone-fg);
  background: var(--tone-bg);
  color: var(--tone-fg);
  font-weight: var(--fw-bold);
}

.callout__list {
  margin: var(--sp-1) 0 0;
  padding-left: var(--sp-5);
}

/* An expandable block (forecast lines of a month, the diff of a log entry) */
.detail-block {
  border-top: var(--border-w) solid var(--c-border);
}

.detail-block > summary {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: var(--touch-min);
  padding: var(--sp-2) 0;
  color: var(--c-link);
  font-weight: var(--fw-semibold);
  list-style: none;
  cursor: pointer;
}

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

.detail-block > summary > .bi {
  flex-shrink: 0;
  transform: rotate(-90deg);
}

.detail-block[open] > summary > .bi {
  transform: none;
}

/* Reports */
.download-bar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
}

.data-table .row-strong > * {
  font-weight: var(--fw-bold);
}

/* Global search: what matched is marked (background + underline, not color only) */
mark {
  padding: 0;
  background: var(--c-debt-bg);
  color: var(--c-text);
  font-weight: var(--fw-semibold);
  text-decoration: underline;
  text-decoration-thickness: var(--border-w);
}

.search-summary {
  margin: 0;
  font-weight: var(--fw-semibold);
}

.search-group__count {
  color: var(--c-muted);
}

.search-list {
  display: grid;
  margin: 0;
  padding: 0;
  list-style: none;
}

.search-hit + .search-hit {
  border-top: var(--border-w) solid var(--c-border);
}

.search-hit__link {
  display: grid;
  gap: var(--sp-1);
  min-height: var(--touch-min);
  padding: var(--sp-3) 0;
  color: var(--c-text);
  text-decoration: none;
}

.search-hit__link:hover .search-hit__title {
  text-decoration: underline;
}

.search-hit__title {
  color: var(--c-link);
  font-weight: var(--fw-semibold);
  overflow-wrap: anywhere;
}

.search-hit__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-1) var(--sp-3);
  color: var(--c-muted);
}

.search-hit__date {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
}

/* Audit log */
.log-list {
  display: grid;
  margin: 0;
  padding: 0;
  list-style: none;
}

.log-item {
  display: grid;
  gap: var(--sp-2);
  padding: var(--sp-3) 0;
}

.log-item + .log-item {
  border-top: var(--border-w) solid var(--c-border);
}

.log-item__head {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
}

.log-item__main {
  display: grid;
  gap: var(--sp-1);
  min-width: 0;
}

.log-item__action {
  margin: 0;
  font-weight: var(--fw-bold);
}

.log-item__code {
  color: var(--c-muted);
  font-size: var(--fs-sm);
  font-weight: var(--fw-regular);
}

.log-item__meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1) var(--sp-3);
  margin: 0;
  color: var(--c-muted);
}

.diff-table td,
.diff-table th {
  overflow-wrap: anywhere;
}

.diff-old {
  color: var(--c-muted);
  text-decoration: line-through;
}

.diff-new {
  font-weight: var(--fw-semibold);
}

/* Signed-in devices */
.device-list {
  display: grid;
  margin: 0;
  padding: 0;
  list-style: none;
}

.device-item {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-3) 0;
}

.device-item + .device-item {
  border-top: var(--border-w) solid var(--c-border);
}

.device-item__main {
  display: grid;
  flex: 1;
  gap: var(--sp-1);
  min-width: min(var(--grid-min), 100%);
}

.device-item__name {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
  margin: 0;
  font-weight: var(--fw-bold);
}

.device-item__meta {
  margin: 0;
  color: var(--c-muted);
}

/* ================================================================== list sorting (audit C007) */
/* A sortable column header (components/table.twig sort_th): the whole label is a 44px link; the
   arrow shows the order (up = ascending, down = descending, both = not sorted by this column) and
   the link's hidden text and aria-sort say it in words, never by colour alone */
.data-table thead th.th-sort {
  padding-top: 0;
  padding-bottom: 0;
}

.sort-link {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  min-height: var(--touch-min);
  color: inherit;
  font-weight: inherit;
  text-decoration: none;
}

.sort-link:hover {
  color: inherit;
  text-decoration: underline;
}

.th-sort.num .sort-link {
  justify-content: flex-end;
}

.sort-link__icon--idle {
  color: var(--c-muted);
}

/* "เรียงตาม" above a list (partials/sort-bar.twig): the select and its button on one line where
   they fit. Next to a table it is for the phone cards: hidden where the column headers show. */
.sort-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--sp-3);
}

.sort-bar__field {
  flex: 1 1 var(--filter-min);
  max-width: calc(var(--filter-min) * 1.5);
}

@media (min-width: 992px) {
  .sort-bar--wide {
    display: none;
  }
}

@media (min-width: 768px) {
  .sort-bar--table {
    display: none;
  }
}

/* ================================================================== motion */
@media (prefers-reduced-motion: no-preference) {
  html {
    scroll-behavior: smooth;
  }

  .btn,
  .side-link,
  .icon-btn,
  .sheet-link,
  .bottom-nav__item,
  .toc__list a,
  .chip,
  .quick-kind__choice {
    transition: background-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
  }

  .sheet[open] {
    animation: pa-sheet-in var(--dur) var(--ease);
  }

  .toast-msg {
    animation: pa-fade-in var(--dur) var(--ease);
  }

  @keyframes pa-sheet-in {
    from { transform: translateY(100%); }
    to { transform: none; }
  }

  @keyframes pa-fade-in {
    from { opacity: 0; }
    to { opacity: 1; }
  }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
    transition-duration: 0.01ms !important;
  }
}
