/* Settings (#view-settings), the Activity page (#view-activity), and the account dialogs. */

/* The per-property choices a merge offers. A section of its own, below the comparison:
   the cards report what is, this decides what will be, and a control sitting among
   reported values invites reading a choice as a fact. */
.merge-choices {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  padding: 0.875rem 1rem;
  background: var(--bg-card);
  border: 1px solid var(--tint-blue-border);
  border-radius: var(--radius-md);
}

.merge-choices-title {
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.merge-choice {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
}

.merge-choice-heading {
  font-size: var(--fs-meta);
  font-weight: 600;
  color: var(--text-primary);
}

.merge-choice-value {
  font-size: var(--fs-meta);
  color: var(--text-primary);
}

.merge-choice-hint {
  margin: 0;
  font-size: var(--fs-label);
  line-height: 1.45;
  color: var(--text-muted);
  max-width: 60ch;
}

.merge-choice-options {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

/* Each option is the whole hit area, not just the dot beside it. */
.merge-choice-option {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.4rem 0.7rem;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-full);
  font-size: var(--fs-meta);
  color: var(--text-secondary);
  cursor: pointer;
  transition: border-color 0.15s, background 0.15s;
}

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

.merge-choice-option:has(input:checked) {
  border-color: var(--accent-blue);
  background: var(--tint-blue-bg);
  color: var(--text-primary);
  font-weight: 500;
}

.merge-choice-option:has(input:focus-visible) {
  outline: 2px solid var(--accent-blue);
  outline-offset: 2px;
}

/* The duplicate-account question. Neutral rather than a warning colour: nothing is
   broken, the app is asking which of two things is true. */
.merge-review {
  border: 1px solid var(--line);
  background: var(--sunk);
  border-radius: var(--radius-md);
  padding: 1.125rem 1.25rem;
  margin-bottom: 1.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.merge-review-title {
  font-family: var(--font-display);
  margin: 0;
  font-size: var(--fs-body);
  font-weight: 600;
  color: var(--text-primary);
}

.merge-review-lede {
  margin: 0;
  font-size: var(--fs-meta);
  line-height: 1.55;
  color: var(--text-secondary);
  max-width: 62ch;
}

.merge-review-pair {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--line);
}

/* The explanations and the two decision buttons, held apart. They were siblings of the
   comparison cards under one space-between row, so each line of explanation took a share
   of the spare space and pushed the buttons further from the edge they belong on. */
.merge-review-decide {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  flex-wrap: wrap;
  gap: 0.75rem 1.5rem;
}

.merge-review-notes {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  min-width: 0;
}

/* The sizing belongs to the banner's horizontal row, not to the block itself: it grows
   into the space the buttons leave and may shrink past its content so a long explanation
   wraps rather than shoving them aside.
   Scoped, because the account modal stacks the same block in a *column*, where a
   flex-basis is a height — 22rem of reserved blank space under the comparison no matter
   how little the notes had to say. */
.merge-review-decide .merge-review-notes {
  flex: 1 1 22rem;
}

/* margin-left: auto as well as the row's space-between: the notes block can render with
   nothing in it (matching balances, no nicknames set), and space-between alone would then
   park a lone button group on the left. */
.merge-review-actions {
  flex: 0 0 auto;
  margin-left: auto;
}

.merge-review-cards {
  display: grid;
  gap: 0.75rem;
  width: 100%;
}

@media (min-width: 620px) {
  .merge-review-cards {
    grid-template-columns: 1fr 1fr;
  }
}

.merge-review-card {
  background: var(--bg-card);
  border: 1px solid var(--tint-blue-border);
  border-radius: var(--radius-md);
  padding: 0.75rem 0.875rem;
}

.merge-review-card-heading {
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 0.25rem;
}

.merge-review-card-name {
  font-size: var(--fs-body-sm);
  font-weight: 600;
  color: var(--text-primary);
  margin-bottom: 0.5rem;
}

.merge-review-fact {
  display: flex;
  justify-content: space-between;
  gap: 0.75rem;
  font-size: var(--fs-label);
  line-height: 1.7;
}

.merge-review-fact-label {
  color: var(--text-muted);
}

.merge-review-fact-value {
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
}

/* The three verdicts a comparison row can carry.
   Neutral is the default above: a row that is not evidence, or one where a value is
   missing on a side. The other two are what let a difference be found by looking rather
   than by reading both columns and holding them in mind. Colour is never the only carrier
   — each row also states its verdict for a screen reader, and the summary beneath names
   every property that disagrees. */
.merge-fact-match .merge-review-fact-label,
.merge-fact-match .merge-review-fact-value {
  color: var(--tint-green-fg);
}

.merge-fact-differ {
  background: var(--tint-amber-bg);
  border-radius: var(--radius-sm);
  margin: 0 -0.375rem;
  padding: 0 0.375rem;
}

.merge-fact-differ .merge-review-fact-label,
.merge-fact-differ .merge-review-fact-value {
  color: var(--tint-amber-fg);
  font-weight: 600;
}

.merge-review-verdict {
  margin: 0;
  font-size: var(--fs-meta);
  line-height: 1.5;
  color: var(--text-secondary);
  max-width: 64ch;
}

/* The one line that can stop someone merging two accounts that are not the same. */
.merge-review-verdict-warn {
  color: var(--tint-amber-fg);
  font-weight: 500;
}

/* An aggregator's own error text, shown under a failed sync's result. Wrapped and
   monospaced because these are machine messages that carry provider error codes, and
   truncating one hides the part worth reading. */
.sync-run-detail {
  margin-top: 0.375rem;
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  line-height: 1.45;
  color: var(--text-secondary);
  white-space: pre-wrap;
  word-break: break-word;
  max-width: 34rem;
}

/* What a known provider error means, in a sentence. The provider's own text follows it
   as a quieter detail. */
.sync-run-message {
  margin-top: 0.375rem;
  font-size: var(--fs-meta);
  line-height: 1.45;
  color: var(--text-primary);
  max-width: 34rem;
}

/* One of "3 accounts, 3 balances, 4 transactions": the line breaks between counts. */
.sync-count {
  white-space: nowrap;
}

.sync-run-message + .sync-run-detail {
  margin-top: 0.125rem;
  color: var(--text-muted);
}

/* The service an account syncs through: a quiet name, not a badge, since it is the
   same for most rows and rarely what someone is looking for. */
.provider-name {
  font-size: var(--fs-meta);
  color: var(--text-secondary);
}

.lifecycle-detail {
  margin: 0;
  font-size: var(--fs-meta);
  color: var(--text-secondary);
  line-height: 1.5;
}

.lifecycle-actions {
  flex-wrap: wrap;
}

/* The comparison the account modal draws once a merge target is picked. Narrower than the
   review banner's, so the two cards stack rather than squeeze inside a 520px panel. */
.merge-preview {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  margin-top: 1rem;
}

.merge-preview .merge-review-cards {
  grid-template-columns: 1fr;
}

.merge-preview .merge-review-card {
  border-color: var(--border-subtle);
}

.lifecycle-hint {
  margin: 0;
  font-size: var(--fs-label);
  color: var(--text-muted);
  line-height: 1.5;
}

/* ============================================================================
   Crypto exchange connections (Settings): the key form in each exchange's card.
   ============================================================================ */
.exchange-connect-form {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.exchange-field {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

.exchange-field .form-input {
  width: 100%;
  min-width: 0;
}

.exchange-secret {
  font-family: var(--font-mono);
  font-size: var(--fs-meta);
  resize: vertical;
}

.exchange-help {
  margin: 0;
}

/* A Plaid bank's card: the accounts it feeds, folded under their count. */
.plaid-item-accounts li {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-2);
}

.plaid-item-mask {
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}

.plaid-item-account-status {
  color: var(--attn);
}


/* The account window's "Leave out of net worth" box, and the tag that marks such an
   account in lists. */
.net-worth-exclude-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: var(--fs-body-sm);
  font-weight: 500;
  color: var(--text-primary);
  cursor: pointer;
}

/* The account page's sections and the dialogs opened from it. Each section says in its heading how its controls take effect —
   Save, right away, or permanently — because that difference is what the reader needs
   to pick the right button. */
.acc-modal {
  max-width: 560px;
}

.acc-modal-header {
  align-items: flex-start;
  margin-bottom: 1.25rem;
}

.acc-modal-heading .modal-title {
  font-size: var(--fs-title);
  line-height: 1.35;
  word-break: break-word;
}

.acc-modal-subtitle {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.35rem;
  font-size: var(--fs-meta);
  color: var(--text-secondary);
}

.acc-modal-subtitle:empty {
  display: none;
}

.acc-status-label {
  font-size: var(--fs-body-sm);
  font-weight: 500;
}

.acc-section {
  display: flex;
  flex-direction: column;
  gap: 0.875rem;
  margin-top: 1.5rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--border-subtle);
}

.acc-section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
}

.acc-section-title {
  font-family: var(--font-display);
  margin: 0;
  font-size: var(--fs-body);
  font-weight: 600;
  color: var(--text-primary);
}

.acc-section-note {
  font-size: var(--fs-label);
  color: var(--text-muted);
  white-space: nowrap;
}

.acc-section-danger .acc-section-note {
  color: var(--accent-red);
}

.acc-danger-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

.acc-danger-row[hidden] {
  display: none;
}

.acc-danger-row .btn {
  flex: 0 0 auto;
}

/* Date, amount and the button that records them, on one line where there is room. */
.acc-history-form {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto;
  align-items: end;
  gap: 0.75rem;
}

.acc-history-help {
  margin-top: 0;
}

.acc-history-form-actions {
  display: flex;
  gap: 0.5rem;
}

/* No scroll box of its own: the window already scrolls, and two nested scrollers fight
   over every swipe on a phone. Long histories are cut short with "Show all" instead. */
.acc-history-list {
  list-style: none;
  margin: 0;
  padding: 0;
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-sm);
}

/* The day Save would overwrite. */
.acc-history-row.is-editing {
  background: var(--tint-blue-bg);
  box-shadow: inset 3px 0 0 var(--accent-blue);
}

.acc-history-replace-note {
  margin-top: 0;
  color: var(--text-secondary);
}

.acc-history-more {
  padding: 0.5rem 0.75rem;
  border-top: 1px solid var(--border-subtle);
}

.acc-history-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.5rem 0.75rem;
  font-size: var(--fs-body-sm);
}

.acc-history-row + .acc-history-row {
  border-top: 1px solid var(--border-subtle);
}

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

.acc-history-amount {
  margin-left: auto;
  font-variant-numeric: tabular-nums;
  color: var(--text-primary);
}

.acc-history-actions {
  display: flex;
  gap: 0.375rem;
  flex: 0 0 auto;
}

.acc-history-empty {
  padding: 0.75rem;
  font-size: var(--fs-meta);
  color: var(--text-muted);
}

.acc-type-flip-note {
  color: var(--accent-amber);
}

/* The card's main action: the only way to add what no bank connection covers. */
.btn-add-manual {
  gap: 0.45rem;
}

.btn-add-manual .btn-icon {
  width: 1.05em;
  height: 1.05em;
}

.manual-acc-fields {
  display: flex;
  flex-direction: column;
  gap: 0.875rem;
  margin-top: 1rem;
}

.manual-acc-amount-help {
  margin-top: -0.5rem;
}

.manual-acc-currency {
  max-width: 6rem;
  text-transform: uppercase;
}

@media (max-width: 600px) {
  .acc-history-form {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  }

  .acc-history-form-actions {
    grid-column: 1 / -1;
  }

  .acc-history-form-actions .btn {
    flex: 1;
  }

  .acc-history-row {
    flex-wrap: wrap;
  }

  /* Edit at one end and Remove at the other, so a thumb aimed at one does not land on
     the other. */
  .acc-history-actions {
    width: 100%;
    justify-content: space-between;
  }
}

/* Below this a date box beside another field is too narrow to show its own year. */
@media (max-width: 360px) {
  .acc-history-form,
  .manual-acc-amount-row {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* A finger needs about 44px; the compact buttons are sized for a mouse pointer. */
@media (pointer: coarse) {
  #btn-add-manual-acc,
  #manual-acc-modal .modal-footer .btn,
  .acc-history-form-actions .btn,
  .acc-history-actions .btn,
  .acc-history-more .btn {
    min-height: 44px;
    min-width: 44px;
  }
}

.acc-tech-details {
  margin-top: 1.5rem;
  padding-top: 1rem;
  border-top: 1px solid var(--border-subtle);
}

.acc-tech-details > summary {
  cursor: pointer;
  font-size: var(--fs-meta);
  font-weight: 500;
  color: var(--text-secondary);
}

.acc-tech-body {
  display: flex;
  flex-direction: column;
  gap: 0.875rem;
  margin-top: 0.875rem;
}

/* Drawn above the account window it was opened from, and below the confirmation it asks. */
.acc-merge-backdrop {
  z-index: 150;
}

.acc-merge-picker {
  margin-top: 1rem;
}

/* A <select> sizes itself to its widest option, so one long account name would push the
   picker past the window's edge; capped, it gives way and truncates instead. */
.acc-merge-picker .form-input {
  min-width: 0;
  max-width: 100%;
  text-overflow: ellipsis;
}


/* ============================================================================
   Settings and Activity pages (#view-settings, #view-activity)

   One readable column, like the Accounts list: a large title, then sections, each a
   card of its own. Settings is setup (connections, notifications, adding an account by
   hand); Activity is the logs, day by day.
   ============================================================================ */
.settings-page {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  max-width: 46rem;
  margin: 0 auto;
}

/* ---- Settings as a list (settingsnav.js) ----
   The list of what can be set, and the page of the row picked: one at a time on a phone,
   the list first, and side by side from 600pt, the list in a column of its own, as the
   Accounts list stands beside an account. It scrolls with the page: with the Admin group
   it is taller than a laptop's window, and held in place it scrolled inside itself. */
.settings-layout {
  max-width: 46rem;
  margin: 0 auto;
}

.settings-nav {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.settings-nav-groups {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.settings-nav-group {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.settings-nav-head {
  margin: 0;
  padding: 0 var(--space-3);
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.settings-nav-list {
  list-style: none;
  margin: 0;
  padding: 0;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-card);
  overflow: hidden;
}

.settings-nav-list > li + li {
  border-top: 1px solid var(--line);
}

/* A row: its icon, its name, how it stands, and a chevron; the whole row the link. */
.settings-row {
  display: grid;
  grid-template-columns: 1.125rem auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--space-3);
  min-height: 3rem;
  padding: var(--space-2) var(--space-3) var(--space-2) var(--space-4);
  color: var(--ink);
  text-decoration: none;
}

a.settings-row:hover {
  background: var(--sunk);
}

a.settings-row:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: -2px;
}

.settings-row[aria-current="page"] {
  background: var(--sunk);
}

.settings-row[aria-current="page"] .settings-row-name {
  font-weight: 600;
}

.settings-row-icon {
  width: 1.125rem;
  height: 1.125rem;
  color: var(--ink-3);
}

.settings-row-attn .settings-row-icon {
  color: var(--attn);
}

/* A name keeps its line, and in a narrow column what it says gives way. */
.settings-row-name {
  font-size: var(--fs-body-sm);
  font-weight: 500;
  white-space: nowrap;
}

.settings-row-attn .settings-row-name {
  white-space: normal;
}

.settings-row-value {
  display: inline-flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-1);
  min-width: 0;
  overflow: hidden;
  font-size: var(--fs-meta);
  color: var(--ink-3);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.settings-row-chevron {
  width: 1rem;
  height: 1rem;
  color: var(--ink-3);
}

/* Appearance chooses in its row: its name, then the choice the width of the row. */
.settings-row-inline {
  grid-template-columns: 1.125rem minmax(0, 1fr);
  row-gap: var(--space-2);
  padding-block: var(--space-3);
}

.settings-row-inline .settings-theme {
  grid-column: 1 / -1;
}

/* A page's own title says what the card under it is, so the card's heading is for
   screen readers alone. */
.settings-pane > .settings-section > .settings-section-head > .settings-section-title {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

.settings-slot {
  display: contents;
}

.settings-slot[hidden] {
  display: none;
}

#settings-page-title:focus {
  outline: none;
}

@media (max-width: 599px) {
  /* The list, or a page in its place. */
  .settings-layout:not(.has-page) > .settings-pane,
  .settings-layout.has-page > .settings-nav {
    display: none;
  }
}

@media (min-width: 600px) {
  .settings-layout {
    display: grid;
    grid-template-columns: minmax(12rem, 16rem) minmax(0, 1fr);
    gap: var(--space-6);
    align-items: start;
    max-width: 68rem;
  }

  .settings-layout > .settings-pane {
    width: 100%;
  }

  /* The list beside a page is the way back from it. */
  .settings-layout .activity-top {
    display: none;
  }
}

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

.settings-title {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--fs-title);
  font-weight: 650;
  letter-spacing: -0.01em;
  color: var(--ink);
}

.settings-section {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-4) var(--space-4);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-card);
}

.settings-section-head {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.settings-section-title {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--fs-body);
  font-weight: 600;
  color: var(--ink);
}

.settings-section-sub {
  margin: 0;
  font-size: var(--fs-meta);
  line-height: 1.45;
  color: var(--ink-3);
}

.settings-section-sub[hidden] {
  display: none;
}

/* On a phone the schedule's two sentences take a line each, loaded and loading alike. Run
   on, they wrapped wherever the wording fell, and the line grew past its one-line
   skeleton when the words landed, moving everything below it. */
@media (max-width: 600px) {
  .settings-schedule-next {
    display: block;
  }
}

/* A line asking for a decision that lives elsewhere: amber, because something is
   waiting on the person. */
.settings-attn {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2) var(--space-4);
  margin: 0;
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  background: var(--attn-soft);
  color: var(--ink);
  font-size: var(--fs-body-sm);
}

.settings-attn[hidden] {
  display: none;
}

.settings-attn-link {
  color: var(--ink);
  font-weight: 600;
  text-underline-offset: 2px;
}

/* ---- Connections ---- */
.conn-list-all,
.conn-group,
.conn-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.conn-list:empty,
.conn-list-all:not(:has(.conn-card)),
.conn-group:not(:has(.conn-card)) {
  display: none;
}

/* Where a SimpleFIN or exchange card sits, among the connections or in the Add list
   (placeConnection in settings.js): no box of its own. */
.conn-slot {
  display: contents;
}

/* One connection: its name and health, what it feeds and when it last synced, and
   what can be done about it. */
.conn-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  background: var(--surface);
}

.conn-card.is-attn {
  border-color: color-mix(in srgb, var(--attn) 45%, var(--line));
}

.conn-card.is-crit {
  border-color: color-mix(in srgb, var(--crit) 45%, var(--line));
}

/* A card's line: its name and what it feeds, its health at the end, the whole of it a
   button that opens and folds the card (toggleConnection). */
.conn-title {
  margin: 0;
  font: inherit;
}

.conn-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-3);
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.conn-head:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: 4px;
  border-radius: var(--radius-sm);
}

.conn-heading {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

/* Among the connections the line ends in a chevron, pointing down while the card is
   folded. */
#settings-conn-list .conn-head {
  position: relative;
  padding-right: 1.5rem;
}

#settings-conn-list .conn-head::after {
  content: "";
  position: absolute;
  right: 0.2rem;
  top: 0.45em;
  width: 0.45rem;
  height: 0.45rem;
  border-right: 1.5px solid var(--ink-3);
  border-bottom: 1.5px solid var(--ink-3);
  transform: rotate(-135deg);
  transform-origin: 60% 60%;
  transition: transform 150ms ease;
}

#settings-conn-list .conn-card.is-folded .conn-head::after {
  transform: rotate(45deg);
}

/* Until the page knows whether a card is folded, its line has no chevron, rather than one
   that turns as the card folds when the connections arrive. */
#settings-conn-list .conn-card:not([data-conn-state]) .conn-head::after {
  display: none;
}

/* Folded, a card is its line alone. */
.conn-card.is-folded > :not(.conn-title) {
  display: none;
}

.conn-name {
  display: block;
  margin: 0;
  font-size: var(--fs-body);
  font-weight: 600;
  color: var(--ink);
  overflow-wrap: anywhere;
}

.conn-meta {
  display: block;
  margin-top: 2px;
  font-size: var(--fs-meta);
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}

.conn-meta:empty {
  display: none;
}

.conn-status {
  flex: 0 0 auto;
}

/* The health is words with a dot, not a chip: ink for working, amber for something to
   do, red for broken, grey for not set up. */
.conn-state {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--fs-meta);
  font-weight: 500;
  color: var(--ink-2);
  white-space: nowrap;
}

.conn-state::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent);
  flex: 0 0 auto;
}

.conn-state-attn { color: var(--attn); }
.conn-state-attn::before { background: var(--attn); }
.conn-state-crit { color: var(--crit); }
.conn-state-crit::before { background: var(--crit); }
.conn-state-off { color: var(--ink-3); }
.conn-state-off::before { background: transparent; border: 1.5px solid var(--ink-3); }
/* Set up and not yet synced, or reconnected and syncing: nothing to do, nothing known. */
.conn-state-wait::before { background: var(--ink-3); }

.conn-why[hidden] {
  display: none;
}

.conn-why {
  margin: 0;
  font-size: var(--fs-meta);
  line-height: 1.45;
  color: var(--ink-2);
}

/* An account named in the line, linking to its page. */
.conn-why a {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 2px;
}

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

.conn-connected[hidden],
.conn-offer[hidden],
.conn-form[hidden] {
  display: none;
}

.conn-detail {
  margin: 0;
  min-width: 0;
  font-size: var(--fs-meta);
  color: var(--ink-3);
  overflow-wrap: anywhere;
}

.conn-detail-sep {
  margin: 0 2px;
}

/* Disconnect ends every card's action row at its right edge, whatever comes before it. */
.conn-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-left: auto;
}

.conn-actions > .btn-danger-text {
  margin-left: auto;
}

/* The accounts a bank feeds, folded under their count. */
.conn-accounts {
  font-size: var(--fs-meta);
  color: var(--ink-2);
}

.conn-accounts > summary {
  cursor: pointer;
  color: var(--ink-2);
  width: fit-content;
}

.conn-accounts ul {
  list-style: none;
  margin: var(--space-2) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.conn-accounts a {
  color: var(--ink);
  text-decoration: none;
}

.conn-accounts a:hover {
  text-decoration: underline;
}

.conn-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding-top: var(--space-3);
  border-top: 1px solid var(--line);
}

.conn-token-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.conn-form-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.conn-token-row .form-input {
  flex: 1 1 14rem;
  min-width: 0;
}

/* Every way to add something, under the connections: a list of lines, each with its
   button at the end, rather than boxes that would read as more connections. A service not
   connected yet is its card, drawn as one of these lines, its form opening under it. */
.conn-add {
  display: flex;
  flex-direction: column;
}

.conn-list-all:has(.conn-card) + .conn-add {
  padding-top: var(--space-2);
}

.conn-add-title {
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.conn-add-list {
  display: flex;
  flex-direction: column;
}

.conn-add-row,
.conn-add-list .conn-card {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2) var(--space-4);
  padding: var(--space-3) 0;
  border: 0;
  border-bottom: 1px solid var(--line);
  border-radius: 0;
  background: none;
}

.conn-add-list > :last-child {
  border-bottom: 0;
  padding-bottom: 0;
}

.conn-add-main,
.conn-add-list .conn-title {
  display: flex;
  flex-direction: column;
  flex: 1 1 14rem;
  min-width: 0;
}

.conn-add-name,
.conn-add-list .conn-name {
  font-size: var(--fs-body-sm);
  font-weight: 500;
  color: var(--ink);
}

.conn-add-text {
  font-size: var(--fs-meta);
  color: var(--ink-3);
}

/* Not connected says itself by where the card is. */
.conn-add-list .conn-status {
  display: none;
}

.conn-add-list .conn-form,
.conn-add-row > .action-error,
.conn-add-list .conn-card > .action-error {
  flex: 1 1 100%;
}

.conn-add-row > .action-error {
  margin-top: 0;
}

/* Where a token or key comes from, under its form. */
.conn-help a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
}

.btn-conn-add {
  gap: 0.45rem;
}

.btn-conn-add .btn-icon {
  width: 1.05em;
  height: 1.05em;
}


/* ---- A row that goes to another page ---- */
.settings-link-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-4);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-card);
  color: var(--ink);
  text-decoration: none;
  min-height: 44px;
}

.settings-link-row:hover {
  background: var(--sunk);
}

.settings-link-main {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.settings-link-title {
  font-family: var(--font-display);
  font-size: var(--fs-body);
  font-weight: 600;
}

.settings-link-sub {
  font-size: var(--fs-meta);
  color: var(--ink-3);
}

.settings-link-sub.is-attn {
  color: var(--attn);
}

.settings-link-chevron {
  width: 20px;
  height: 20px;
  flex: 0 0 auto;
  color: var(--ink-3);
}

/* ---- Notifications ---- */
/* The alerts against where each goes, a switch in each cell. This device's column shows
   once notifications are on here (push.js sets has-device). */
.notif-grid-wrap {
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  overflow: hidden;
}

.notif-grid {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-body-sm);
}

.notif-grid th,
.notif-grid td {
  padding: var(--space-2) var(--space-3);
  border-bottom: 1px solid var(--line);
  text-align: center;
  vertical-align: middle;
}

.notif-grid tr:last-child > * {
  border-bottom: 0;
}

.notif-grid thead th {
  font-size: var(--fs-meta);
  font-weight: 500;
  color: var(--ink-3);
  white-space: nowrap;
}

.notif-grid th[scope="row"],
.notif-grid .notif-grid-what {
  text-align: left;
  font-weight: 400;
  color: var(--ink);
}

.notif-grid .notif-grid-what {
  color: var(--ink-3);
}

.notif-grid td {
  width: 5.5rem;
}

.notif-grid-wrap:not(.has-device) .notif-col-device {
  display: none;
}

@media (max-width: 600px) {
  .notif-grid th,
  .notif-grid td {
    padding-inline: var(--space-2);
  }

  .notif-grid td {
    width: 4.5rem;
  }
}

/* One row per place notifications go, drawn like a connection: a box of its own, headed
   by an icon and the place's name, so this device's choices and Discord's are never read
   as one form. */
.notif-channel {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding: var(--space-4);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  background: var(--surface);
}

.notif-channel[hidden] {
  display: none;
}

/* A saved Discord webhook, masked, with Replace and Remove after it. */
.discord-webhook-saved {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
}

.discord-webhook-saved:not([hidden]) + #discord-webhook-entry {
  margin-top: var(--space-3);
}

.notif-channel-head {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
}

.notif-channel-icon {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: var(--radius-md);
  background: var(--accent-soft);
  color: var(--accent);
}

.notif-channel-icon svg {
  width: 1.25rem;
  height: 1.25rem;
}

.notif-channel-heading {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  padding-top: 1px;
}

.notif-channel-name {
  margin: 0;
  font-size: var(--fs-body);
  font-weight: 600;
  color: var(--ink);
}

.notif-channel-sub {
  margin: 0;
  font-size: var(--fs-meta);
  line-height: 1.45;
  color: var(--ink-3);
}

.notif-channel-sub:empty {
  display: none;
}

/* Where this browser can't take notifications, the row's status line is all it has: its
   choices and buttons are all hidden, and the empty form would leave a gap under it. */
.notif-channel:not(:has(.settings-form > :not([hidden], .settings-form-actions), .settings-form-actions > :not([hidden]))) > .settings-form {
  display: none;
}

/* ---- Forms ---- */
.settings-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.settings-checks {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

/* The notification choices are a fieldset, so the two boxes are read with their
   caption. */
fieldset.settings-checks {
  margin: 0;
  padding: 0;
  border: 0;
  min-width: 0;
}

fieldset.settings-checks > legend {
  padding: 0;
}

.settings-form-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

/* The Cash flow section: each checking and savings account, whether it counts, and an
   amount to keep of its own beside it. */
.cs-account-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

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

/* Whether the account is counted, its switch first, then its name. */
.cs-account-name {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex: 1 1 auto;
  min-width: 0;
  min-height: 44px;
  font-size: var(--fs-body-sm);
  color: var(--ink);
  overflow-wrap: anywhere;
  cursor: pointer;
}

.cs-account-head {
  display: flex;
  justify-content: space-between;
  gap: var(--space-3);
  font-size: var(--fs-meta);
  color: var(--ink-3);
}

.cs-account-keep .form-input {
  width: 9rem;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.cs-currency {
  color: var(--ink-3);
  font-size: var(--fs-meta);
}

/* ---- Activity ---- */
.activity-top {
  display: flex;
}

.activity-back {
  gap: var(--space-1);
  padding-left: var(--space-2);
}

/* What the history is heading towards, set apart above it on a tinted strip. */
.activity-next {
  margin: 0;
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  background: var(--sunk);
  font-size: var(--fs-body-sm);
  line-height: 1.5;
  color: var(--ink-2);
}

.activity-next[hidden] {
  display: none;
}

.activity-next strong {
  font-size: var(--fs-body);
  font-weight: 600;
  color: var(--ink);
  white-space: nowrap;
}

.activity-next-schedule {
  display: block;
  color: var(--ink-2);
}

.activity-head {
  flex-direction: row;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-3);
}

/* Problems or everything: a two-way segmented control. */
.seg-toggle {
  display: inline-flex;
  padding: 3px;
  gap: 2px;
  border-radius: var(--radius-full);
  background: var(--sunk);
}

.seg-toggle-btn {
  min-height: 32px;
  padding: 0 var(--space-3);
  border: 0;
  border-radius: var(--radius-full);
  background: transparent;
  color: var(--ink-2);
  font: inherit;
  font-size: var(--fs-meta);
  font-weight: 500;
  cursor: pointer;
}

.seg-toggle-btn[aria-pressed="true"] {
  background: var(--surface);
  color: var(--ink);
  box-shadow: var(--shadow-card);
}

.night-list {
  display: flex;
  flex-direction: column;
}

.night + .night {
  border-top: 1px solid var(--line);
}

.night {
  padding: var(--space-3) 0;
}

.night:first-child {
  padding-top: 0;
}

.night-title {
  margin: 0 0 var(--space-2);
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.night-date,
.night-sep {
  color: var(--ink-3);
}

.night-items {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.act-item {
  min-width: 0;
}

.act-line {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
}

.act-name {
  min-width: 0;
  font-size: var(--fs-body-sm);
  font-weight: 500;
  color: var(--ink);
  overflow-wrap: anywhere;
}

.act-result {
  flex: 0 0 auto;
  font-size: var(--fs-meta);
  font-weight: 500;
  white-space: nowrap;
}

.act-ok { color: var(--ink-3); }
.act-attn { color: var(--attn); }
.act-crit { color: var(--crit); }

.act-meta {
  margin-top: 2px;
  font-size: var(--fs-meta);
  color: var(--ink-3);
  overflow-wrap: anywhere;
}

.act-item .sync-run-message {
  margin: var(--space-1) 0 0;
}

/* Under a push, what each device it went to said back (deliveries.js). */
.act-item .push-device {
  margin: 2px 0 0;
}
.act-item .push-device[data-device-state="not-shown"] {
  color: var(--attn);
}

/* The transactions a sync found stored twice, one a line under the sentence saying what
   it did with them. */
.sync-run-dups {
  margin: 2px 0 0;
  padding-left: 1.1rem;
  font-size: var(--fs-meta);
  color: var(--ink-2);
  overflow-wrap: anywhere;
}

.act-details {
  margin-top: var(--space-1);
  font-size: var(--fs-meta);
}

.act-details > summary {
  cursor: pointer;
  width: fit-content;
  color: var(--ink-3);
}

/* The way to fix a problem that is still going on, under what it says. */
.act-fix {
  margin-top: var(--space-2);
}

/* "Needs you now": the accounts the last sync left with a problem, each with its fix. An
   entry may offer two ways out, side by side. */
.act-needs .act-fix {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.act-acct-link {
  color: inherit;
}

.act-acct-detail {
  font-weight: 400;
  color: var(--ink-3);
}

@media (pointer: coarse) {
  .act-acct-link {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    min-width: 44px;
  }
}

.night-fine {
  font-size: var(--fs-meta);
  color: var(--ink-3);
}

.activity-empty {
  margin: 0;
  font-size: var(--fs-body-sm);
  color: var(--ink-3);
}

.activity-more {
  align-self: flex-start;
}

.activity-more[hidden] {
  display: none;
}

@media (max-width: 600px) {
  .settings-page {
    gap: var(--space-3);
  }

  .settings-section {
    padding: var(--space-4) var(--space-3);
  }

  /* Inside the Connections card, each connection is a row split by a rule rather than a
     box of its own: a box in a box spends the narrow screen on borders and padding. */
  .conn-card {
    padding: var(--space-3) 0 0;
    border: 0;
    border-top: 1px solid var(--line);
    border-radius: 0;
  }

  .conn-card.is-attn,
  .conn-card.is-crit {
    border-color: var(--line);
  }

  /* The same for the places notifications go. */
  .notif-channel {
    padding: var(--space-4) 0 0;
    border: 0;
    border-top: 1px solid var(--line);
    border-radius: 0;
  }

  .conn-group,
  .conn-list {
    gap: var(--space-3);
  }

  /* The buttons are a row of their own under the "Linked on" line in every card, so
     Disconnect is in the same place whether a card has one button or three. */
  .conn-connected {
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-2);
  }

  .conn-actions {
    margin-left: 0;
  }

  .seg-toggle-btn {
    min-height: 40px;
  }
}

/* Touch screens: the Problems / Show all toggle and each account link under a bank are
   44pt targets. */
@media (pointer: coarse) {
  .seg-toggle-btn {
    min-height: 44px;
  }

  .plaid-item-accounts li {
    align-items: center;
  }

  .plaid-item-accounts .acc-row-link {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }
}

/* Loading: the connections' skeleton (drawSettingsSkeleton in settings.js). The forms
   and the connected details wait unseen, since which of them a card shows is what is
   being looked up; a line and a button's block stand in their place. */
#view-settings[aria-busy="true"] :is(.conn-form, .conn-offer, .conn-connected) {
  display: none;
}

/* Loading: the notifications' switches are each person's own, so until fillNotifForm
   has put them in, each shows as a block in its place and the grid takes no input
   (settings.js sets inert with is-unknown): a flip then would save the opposite of a
   choice not shown yet. The blocks pulse while the page is busy and hold still once it
   isn't, which after a failed load leaves the grid locked beneath the error banner rather
   than showing defaults as if they were the settings. */
#notif-grid.is-unknown .switch-track {
  background: var(--line);
}

#notif-grid.is-unknown .switch-track::before {
  opacity: 0;
}

#view-settings[aria-busy="true"] #notif-grid.is-unknown .switch-track {
  animation: skel-appear 200ms var(--ease-out) 150ms both, skel-pulse 1.6s ease-in-out 350ms infinite;
}

@media (prefers-reduced-motion: reduce) {
  #view-settings[aria-busy="true"] #notif-grid.is-unknown .switch-track {
    animation: skel-appear 200ms var(--ease-out) 150ms both;
  }
}

/* A finger needs about 44px: a connection's line opens its card. */
@media (pointer: coarse) {
  .conn-head {
    min-height: 44px;
  }
}

/* Loading: the Activity page's nights (nightsSkeletonHTML in syncactivity.js), each a
   heading over a few entries, spaced as the nights are. */
.skel-night {
  padding: var(--space-3) 0;
}

.skel-night:first-child {
  padding-top: 0;
}

.skel-night + .skel-night {
  border-top: 1px solid var(--line);
}

.skel-night-head {
  display: flex;
  align-items: center;
  min-height: 1.4706em;
  margin-bottom: var(--space-2);
  font-size: var(--fs-label);
}

.skel-night-items {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin: 0;
  padding: 0;
}

.skel-night-items .skel-row {
  min-height: 2.5rem;
  padding: 0;
}

.skel-night-items .skel-row + .skel-row {
  border-top: 0;
}

/* ----------------------------------------------------------------------------
   Rules (#rules, js/rules.js): the user's rules and what was learned, each a row
   saying what it matches, what it files under in the accent, and why.
   ---------------------------------------------------------------------------- */
/* The heading's words take the room, and Add a rule stays beside them. */
.rules-head {
  flex-wrap: nowrap;
}

.rules-head > div {
  flex: 1 1 auto;
  min-width: 0;
}

.rules-head > .btn {
  flex: none;
}

.rules-status {
  margin: 0;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  background: var(--sunk);
  font-size: var(--fs-body-sm);
  color: var(--ink);
}

.rules-status[hidden] {
  display: none;
}

/* Ask now, with how many merchants wait beside it. */
.ai-ask {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
}

.ai-ask[hidden] {
  display: none;
}

.ai-ask .field-help {
  margin: 0;
}

.rules-search {
  min-height: 36px;
  padding: 0 var(--space-3);
  border-radius: var(--radius-full);
}

.rule-rows {
  margin: 0;
  padding: 0;
  list-style: none;
}

.rule-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) 0;
}

.rule-row + .rule-row {
  border-top: 1px solid var(--line);
}

.rule-row-main {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.rule-row-when {
  font-size: var(--fs-body-sm);
  font-weight: 500;
  color: var(--ink);
  overflow-wrap: anywhere;
}

.rule-row-then {
  font-size: var(--fs-body-sm);
  color: var(--accent);
}

.rule-row-then::before {
  content: "→ ";
  color: var(--ink-3);
}

.rule-row-then.is-varies {
  color: var(--attn);
}

.rule-row-meta {
  font-size: var(--fs-meta);
  color: var(--ink-3);
}

.rule-row-actions {
  display: flex;
  flex: none;
  gap: var(--space-2);
}

/* How many of the user's transactions a learned merchant covers. */
.rule-row-count {
  flex: none;
  min-width: 2ch;
  font: 500 var(--fs-meta)/1 var(--font-mono);
  color: var(--ink-3);
  text-align: right;
}

.rule-way {
  margin-left: var(--space-2);
  padding: 1px var(--space-2);
  border-radius: var(--radius-full);
  background: var(--sunk);
  font-size: var(--fs-label);
  font-weight: 500;
  color: var(--ink-2);
  white-space: nowrap;
}

/* Every category by group: each group's name over its subcategories, one to a line, the
   groups flowing down columns, two on a phone and more as the card widens. */
.cat-tree {
  columns: 2;
  column-gap: var(--space-4);
}

@media (min-width: 620px) {
  .cat-tree {
    columns: 3;
    column-gap: var(--space-6);
  }
}

@media (min-width: 900px) {
  .cat-tree {
    columns: 4;
  }
}

.cat-group {
  break-inside: avoid;
  padding-bottom: var(--space-4);
}

.cat-group-name {
  margin: 0 0 var(--space-1);
  font-family: var(--font-display);
  font-size: var(--fs-body);
  font-weight: 600;
  color: var(--ink);
}

.cat-subs {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: var(--fs-body-sm);
  line-height: 1.4;
  color: var(--ink-2);
}

.cat-none {
  margin: 0;
  font-size: var(--fs-body-sm);
  color: var(--ink-3);
}

.rule-skel {
  margin: 0;
  padding: 0;
  list-style: none;
}

/* The rule editor: a sentence down the dialog, "When a transaction is from …, has the
   text …, moves money …, file it as …", each part a label beside its control. */
.rule-modal {
  max-width: 34rem;
}

.rule-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.rule-form[hidden],
.rule-preview[hidden],
.rule-saved[hidden],
.rule-field[hidden] {
  display: none;
}

/* What saving did, once it is saved. */
.rule-saved {
  margin: 0;
  font-size: var(--fs-body-sm);
  font-weight: 600;
  color: var(--ink);
}

.rule-lead {
  margin: var(--space-1) 0 0;
  font: 600 var(--fs-label)/1.2 var(--font-mono);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.rule-field {
  display: grid;
  grid-template-columns: 7.5rem minmax(0, 1fr);
  align-items: center;
  gap: var(--space-3);
}

.rule-field > :last-child {
  justify-self: start;
  max-width: 100%;
}

/* "File it as" has no label of its own beside it: its chip takes the whole row. */
.rule-field > :only-child {
  grid-column: 1 / -1;
}

/* A chip shows its whole choice, on two lines if it has to. */
.rule-field .chip-select {
  max-width: 100%;
  padding-block: var(--space-1);
  line-height: 1.25;
  white-space: normal;
  text-align: left;
}

/* So does a same-named account's, its detail kept on the line it ends. */
.rule-field .chip-select-text.choice-split,
.rule-field .choice-name {
  display: inline;
  white-space: normal;
}

.rule-field .form-input {
  width: 100%;
  min-height: 36px;
}

.rule-label {
  font-size: var(--fs-body-sm);
  color: var(--ink-2);
}

.rule-merchant {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-height: 36px;
  padding: 0 var(--space-1) 0 var(--space-3);
  border: 1px solid var(--ink);
  border-radius: var(--radius-full);
  background: var(--sunk);
  font-size: var(--fs-meta);
  font-weight: 600;
  color: var(--ink);
}

.rule-merchant-clear {
  display: inline-grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border: 0;
  border-radius: var(--radius-full);
  background: none;
  color: var(--ink-3);
  font-size: 1.1rem;
  cursor: pointer;
}

.rule-merchant-clear:hover {
  background: var(--surface);
  color: var(--ink);
}

/* Under the text box, a rule made from a transaction shows that transaction's own text,
   to copy a part from. Bank text can be one long run with no spaces. */
.rule-text-box {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  min-width: 0;
}

.rule-text-hint {
  font-size: var(--fs-meta);
  color: var(--ink-3);
  overflow-wrap: anywhere;
}

.rule-text-hint[hidden] {
  display: none;
}

/* Its label stays level with the box, not with the box and the text under it. */
.rule-field:has(.rule-text-box) {
  align-items: start;
}

.rule-field:has(.rule-text-box) > .rule-label {
  display: flex;
  align-items: center;
  min-height: 36px;
}

.rule-amounts {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  width: 100%;
  color: var(--ink-3);
  font-size: var(--fs-meta);
}

.rule-amounts .form-input {
  flex: 1 1 0;
  min-width: 0;
}

.rule-field:has(.rule-amounts) > :last-child,
.rule-field:has(.form-input) > :last-child {
  justify-self: stretch;
}

/* What saving would change. */
.rule-preview-lead {
  margin: 0 0 var(--space-3);
  font-size: var(--fs-body-sm);
  font-weight: 600;
  color: var(--ink);
}

.rule-preview-list {
  max-height: min(50dvh, 22rem);
  margin: 0;
  padding: 0;
  overflow-y: auto;
  list-style: none;
  border-top: 1px solid var(--line);
}

.rule-preview-list li {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 2px var(--space-3);
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--line);
  font-size: var(--fs-meta);
}

.rule-preview-what {
  overflow: hidden;
  color: var(--ink);
  white-space: nowrap;
  text-overflow: ellipsis;
}

.rule-preview-amount {
  font-family: var(--font-mono);
  color: var(--ink-2);
  white-space: nowrap;
}

.rule-preview-change {
  grid-column: 1 / -1;
  color: var(--ink-3);
}

.rule-preview-list .rule-preview-more {
  display: block;
  color: var(--ink-3);
}

.rule-preview-note {
  margin: var(--space-3) 0 0;
  font-size: var(--fs-meta);
  color: var(--ink-2);
}

.rule-preview-refile {
  margin-top: var(--space-3);
  color: var(--ink);
}

.rule-preview-list[hidden],
.rule-preview-note[hidden] {
  display: none;
}

/* The rule offered after a pick in the transaction detail: the rule in a sentence, then
   what it would change and what it would leave, each a list as the editor's preview has. */
.rule-offer-lead {
  margin: 0 0 var(--space-4);
  font-size: var(--fs-body-sm);
  color: var(--ink-2);
}

.rule-offer-part + .rule-offer-part {
  margin-top: var(--space-6);
}

.rule-offer-part[hidden] {
  display: none;
}

.rule-offer-part .rule-preview-list {
  max-height: min(30dvh, 14rem);
}

.rule-offer-why {
  margin: calc(-1 * var(--space-2)) 0 var(--space-3);
}

@media (pointer: coarse), (max-width: 600px) {
  .rules-search,
  .rule-field .form-input,
  .rule-field:has(.rule-text-box) > .rule-label {
    min-height: 44px;
  }

  .rule-merchant-clear {
    width: 44px;
    height: 44px;
  }

  #rule-direction .seg-toggle-btn {
    min-width: 44px;
  }
}

@media (max-width: 600px) {
  /* A label over its control, so the controls keep the width. */
  .rule-field {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-1);
  }

  .rule-field:has(.rule-text-box) > .rule-label {
    min-height: 0;
  }

  /* A rule's buttons go under it; a learned merchant's count stays beside it. */
  .rule-row:not(.is-learned) {
    flex-wrap: wrap;
  }

  .rule-row-actions {
    width: 100%;
  }
}

/* The Household section (household.js): each person, their name to change and the way
   to remove them; the invitations out; and the box to invite someone. */
.hh-members,
.hh-invites {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* A person: their name box with Save name beside it, Make owner, Remove or Leave at the
   card's right edge, and their email under the box. Rows have different buttons, so Save
   name and the rest sit in columns of their own, which line up from row to row. */
.hh-member {
  display: grid;
  grid-template-columns: minmax(0, 18rem) 1fr auto;
  column-gap: var(--space-3);
  row-gap: 4px;
  align-items: center;
}

.hh-member .hh-name-actions {
  grid-column: 2;
  grid-row: 1;
  display: flex;
}

.hh-name {
  grid-column: 1;
  grid-row: 1;
}

/* Someone else's name, which only the owner changes. */
.hh-name-text {
  font-size: var(--fs-body);
  font-weight: 600;
  color: var(--ink);
  overflow-wrap: anywhere;
}

.hh-owner-note {
  margin-top: var(--space-3);
}

.hh-member .hh-member-actions {
  grid-column: 3;
  grid-row: 1;
}

.hh-member > .hh-member-email {
  grid-column: 1 / -1;
  grid-row: 2;
}

/* Room around the invitation, taken back by the margin, for its glow once Allow has
   worked. */
.hh-invite {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-2);
  margin: calc(-1 * var(--space-2));
  border-radius: var(--radius-md);
}

.hh-member-main {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  flex: 1 1 auto;
}

/* Leave, Remove and Cancel, last on their lines, take one width, so the buttons stand
   in columns down the section. */
.hh-end-action {
  min-width: 6.25rem;
  justify-content: center;
}

.hh-member-email,
.hh-invite-email {
  font-size: var(--fs-meta);
  color: var(--ink-3);
  overflow-wrap: anywhere;
}

.hh-invite-email {
  font-size: var(--fs-body-sm);
  color: var(--ink);
}

.hh-invite-blocked {
  color: var(--attn);
}

.hh-member-actions {
  display: flex;
  gap: var(--space-2);
  flex: none;
}

.hh-invites-title {
  margin-top: var(--space-4);
}

.hh-invite-form {
  margin-top: var(--space-4);
}

.hh-invite-row {
  display: flex;
  gap: var(--space-2);
  max-width: 28rem;
}

.hh-invite-row .form-input {
  flex: 1;
  min-width: 0;
}

.acc-owner-me {
  color: var(--ink-3);
}

@media (max-width: 600px) {
  /* The buttons go under the email, Save name at the start and the rest at the end, and
     the name box keeps the width. */
  .hh-member {
    grid-template-columns: auto minmax(0, 1fr);
  }

  .hh-member .hh-name,
  .hh-member > .hh-member-email {
    grid-column: 1 / -1;
  }

  .hh-member .hh-name-actions,
  .hh-member .hh-member-actions {
    grid-row: 3;
    margin-top: var(--space-1);
  }

  .hh-member .hh-name-actions {
    grid-column: 1;
  }

  .hh-member .hh-member-actions {
    grid-column: 2;
    justify-self: end;
  }

  .hh-invite {
    flex-wrap: wrap;
  }

  /* At the line's end, as each person's are: Allow, first, goes once it has worked
     without the buttons after it moving. */
  .hh-invite .hh-member-actions {
    margin-left: auto;
  }
}
