:root {
  --canvas: #f4f2eb;
  --canvas-deep: #ebe9df;
  --surface: #fffefa;
  --surface-muted: #f8f7f1;
  --ink: #17221c;
  --ink-soft: #334039;
  --muted: #68736c;
  --line: #dddfd7;
  --line-strong: #cdd1c8;
  --accent: #2e6d50;
  --accent-dark: #22533c;
  --accent-soft: #dcece2;
  --danger: #a14137;
  --danger-soft: #f7e4e1;
  --notice: #2e6d50;
  --notice-soft: #e1eee5;
  --shadow: 0 18px 50px rgb(35 48 40 / 8%);
  --radius-sm: 10px;
  --radius-md: 16px;
  --radius-lg: 24px;
}

* {
  box-sizing: border-box;
}

html {
  background: var(--canvas);
  color: var(--ink);
  font-family: Inter, ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  font-feature-settings: "tnum" 1, "ss01" 1;
  line-height: 1.5;
}

body {
  margin: 0;
  min-height: 100vh;
}

button,
input {
  font: inherit;
}

a {
  color: var(--accent);
  text-underline-offset: 3px;
}

a:hover {
  color: var(--accent-dark);
}

:focus-visible {
  outline: 3px solid rgb(46 109 80 / 24%);
  outline-offset: 3px;
}

.app-shell {
  min-height: 100vh;
}

.sidebar {
  background: var(--ink);
  color: #f8f7f1;
  display: flex;
  flex-direction: column;
  inset: 0 auto 0 0;
  padding: 28px 20px 22px;
  position: fixed;
  width: 264px;
  z-index: 20;
}

.brand {
  align-items: center;
  color: inherit;
  display: inline-flex;
  font-family: "Iowan Old Style", Charter, Georgia, serif;
  font-size: 1.35rem;
  font-weight: 700;
  gap: 11px;
  letter-spacing: -0.02em;
  text-decoration: none;
}

.brand:hover {
  color: inherit;
}

.brand-mark {
  align-items: center;
  background: var(--accent-soft);
  border-radius: 9px;
  color: var(--accent-dark);
  display: inline-flex;
  font-family: "Iowan Old Style", Charter, Georgia, serif;
  font-size: 1.1rem;
  font-weight: 800;
  height: 34px;
  justify-content: center;
  width: 34px;
}

/* Sized to fit rather than to scroll. Thirteen destinations under four headings is a tall
   list, and the sidebar is fixed to the viewport, so anything past the bottom of one was not
   merely below the fold but out of reach entirely -- there was nothing to scroll, and the
   last destinations could not be got to at all.

   So the rows below are as close together as a pointer wants them, which is most of the
   answer, and the list will still scroll on a window too short for even that. The bar itself
   is hidden: a menu is not a document, and a household reading one down the side of every
   page should not be given something to drag. What it costs is an affordance on the windows
   too short to fit, which is why the rows were tightened first rather than instead.

   min-height is nought because a flex item will not shrink below its own content without it,
   which is the whole of why a taller list overflowed instead of scrolling. */
.sidebar-nav {
  flex: 1;
  margin-top: 34px;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: none;
}

.sidebar-nav::-webkit-scrollbar {
  display: none;
}

.nav-label {
  color: #99a29c;
  font-size: 0.69rem;
  font-weight: 700;
  letter-spacing: 0.13em;
  margin: 0 12px 8px;
  text-transform: uppercase;
}

.nav-label-secondary {
  margin-top: 22px;
}

.nav-link {
  align-items: center;
  border-radius: 10px;
  color: #d9dedb;
  display: flex;
  font-size: 0.91rem;
  font-weight: 600;
  gap: 12px;
  margin: 2px 0;

  /* Shorter than the forty-four a thumb wants: this sidebar is hidden below 900px, where the
     mobile menu takes over with rows sized for one, so nothing here is ever tapped. */
  min-height: 38px;
  padding: 7px 12px;
  text-decoration: none;
}

.nav-link:hover {
  background: rgb(255 255 255 / 6%);
  color: #fff;
}

.nav-link.active {
  background: rgb(220 236 226 / 12%);
  color: #fff;
}

.nav-link.disabled {
  color: #7f8a83;
  cursor: default;
}

.nav-icon {
  align-items: center;
  display: inline-flex;
  font-size: 1.08rem;
  height: 22px;
  justify-content: center;
  width: 22px;
}

.nav-soon {
  background: rgb(255 255 255 / 7%);
  border-radius: 999px;
  font-size: 0.59rem;
  letter-spacing: 0.07em;
  margin-left: auto;
  padding: 3px 7px;
  text-transform: uppercase;
}

.sidebar-footer {
  border-top: 1px solid rgb(255 255 255 / 10%);
  margin-top: auto;
  padding-top: 20px;
}

.signed-in-user {
  align-items: center;
  display: flex;
  gap: 11px;
  min-width: 0;
}

.user-avatar,
.mobile-user {
  align-items: center;
  background: var(--accent);
  border-radius: 50%;
  color: #fff;
  display: inline-flex;
  flex: 0 0 auto;
  font-size: 0.76rem;
  font-weight: 800;
  height: 34px;
  justify-content: center;
  overflow: hidden;
  width: 34px;
}

.user-details {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.user-details strong {
  font-size: 0.76rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.user-details span {
  color: #9fa8a2;
  font-size: 0.7rem;
}

.text-button {
  background: none;
  border: 0;
  color: #b7bfba;
  cursor: pointer;
  font-size: 0.75rem;
  margin: 13px 0 0 45px;
  padding: 0;
}

.text-button:hover {
  color: #fff;
}

.main-content {
  margin-left: 264px;
  min-height: 100vh;
  padding: 42px 46px 64px;
}

.page-container {
  margin: 0 auto;
  max-width: 1160px;
}

.page-container-narrow {
  max-width: 900px;
}

.page-header {
  align-items: flex-start;
  display: flex;
  gap: 32px;
  justify-content: space-between;
  margin-bottom: 32px;
}

.eyebrow {
  color: var(--accent);
  font-size: 0.7rem;
  font-weight: 800;
  letter-spacing: 0.14em;
  margin: 0 0 10px;
  text-transform: uppercase;
}

h1,
h2 {
  color: var(--ink);
  font-family: "Iowan Old Style", Charter, Georgia, serif;
  letter-spacing: -0.035em;
  line-height: 1.08;
  margin-top: 0;
}

h1 {
  font-size: clamp(2.15rem, 4vw, 3.5rem);
  margin-bottom: 12px;
}

h2 {
  font-size: clamp(1.45rem, 2.4vw, 2rem);
  margin-bottom: 12px;
}

.page-intro,
.auth-intro {
  color: var(--muted);
  font-size: 0.98rem;
  margin: 0;
  max-width: 600px;
}

.privacy-chip {
  align-items: center;
  background: rgb(255 254 250 / 72%);
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--ink-soft);
  display: flex;
  flex: 0 0 auto;
  font-size: 0.75rem;
  font-weight: 700;
  gap: 8px;
  margin-top: 7px;
  padding: 8px 12px;
}

.privacy-indicator,
.flash-dot {
  background: var(--accent);
  border-radius: 50%;
  height: 7px;
  width: 7px;
}

/* Two by two, which is what four cards want at the width a desktop actually gives them. The
   sidebar is 264px whatever the window, so at 1100px the grid has about 800px to divide and
   a card in a row of four is under 200px -- narrower than a figure like €7,325.00 set in the
   serif these cards use. Four abreast is for a window wide enough to mean it, and the media
   query below says which. */
.metric-grid {
  display: grid;
  gap: 16px;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  margin-bottom: 20px;
}

.metric-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  box-shadow: 0 4px 18px rgb(35 48 40 / 3%);
  min-height: 154px;
  padding: 23px 24px;
}

.metric-card p {
  color: var(--muted);
  font-size: 0.79rem;
  font-weight: 700;
  margin: 0;
}

.metric-card span {
  color: var(--muted);
  display: block;
  font-size: 0.75rem;
  margin-top: 7px;
}

.metric-value {
  display: block;
  font-family: "Iowan Old Style", Charter, Georgia, serif;
  font-size: 2.15rem;
  line-height: 1;
  margin-top: 19px;
}

/* Planning past an income that will not cover it. Red for the same reason an overspent
   category is, and by the same rule -- see BudgetMonth#planned_short?, which both pages ask
   rather than each deciding for itself. */
.metric-value-short {
  color: var(--danger);
}

/* A state rather than a figure. The serif at full size is for numbers; words that long at
   that size read as a headline the household is meant to do something about. */
.metric-value-quiet {
  font-size: 1.35rem;
}

.metric-card-accent {
  background: var(--accent-dark);
  border-color: var(--accent-dark);
  color: #fff;
}

.metric-card-accent p,
.metric-card-accent span,
.metric-card-accent .metric-value {
  color: #fff;
}

.metric-card-accent span {
  opacity: 0.68;
}

/* The line under the list of kinds: what they come to together. Sits outside the record list
   rather than as a last row of it, because a total is not another account. */
.position-total {
  align-items: baseline;
  display: flex;
  font-size: 0.95rem;
  gap: 16px;
  justify-content: space-between;
  margin: 16px 0 0;
}

.position-total strong {
  font-variant-numeric: tabular-nums;
}

.status-badge,
.role-badge {
  background: var(--accent-soft);
  border-radius: 999px;
  color: var(--accent-dark);
  display: inline-block;
  font-size: 0.68rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  margin-bottom: 18px;
  padding: 6px 10px;
  text-transform: uppercase;
}

.button {
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  cursor: pointer;
  display: inline-flex;
  font-size: 0.85rem;
  font-weight: 750;
  justify-content: center;
  min-height: 44px;
  padding: 11px 17px;
  text-decoration: none;
}

.button:disabled {
  cursor: wait;
  opacity: 0.65;
}

.button-primary {
  background: var(--accent);
  color: #fff;
}

.button-primary:hover {
  background: var(--accent-dark);
  color: #fff;
}

.button-secondary {
  background: var(--surface-muted);
  border-color: var(--line-strong);
  color: var(--ink-soft);
}

.button-secondary:hover {
  background: var(--canvas-deep);
  color: var(--ink);
}

.button-danger {
  background: var(--danger);
  color: #fff;
}

.button-danger:hover {
  background: #83362f;
  color: #fff;
}

.button-full {
  width: 100%;
}

.settings-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: clamp(26px, 5vw, 46px);
}

.settings-stack {
  display: grid;
  gap: 20px;
}

/* A grid item's min-width is min-content, so a card holding a long unwrappable line -- a
   record detail is one, being nowrap and ellipsized -- would rather push the page wider than
   shrink. Letting it shrink is what puts the ellipsis back in charge. */
.settings-stack > * {
  min-width: 0;
}

.settings-heading {
  align-items: flex-start;
  display: flex;
  gap: 24px;
  justify-content: space-between;
}

.settings-heading h2 {
  font-family: inherit;
  font-size: 1.05rem;
  letter-spacing: -0.01em;
}

.settings-copy {
  color: var(--muted);
  font-size: 0.85rem;
  margin: 0;
  max-width: 620px;
}

.role-badge {
  margin: 0;
}

.settings-heading .status-badge {
  margin: 0;
}

.settings-list {
  border-top: 1px solid var(--line);
  margin: 20px 0 0;
}

.settings-list div {
  display: grid;
  gap: 24px;
  grid-template-columns: 150px minmax(0, 1fr);
  padding: 19px 0;
}

.settings-list div:not(:last-child) {
  border-bottom: 1px solid var(--line);
}

.settings-list dt {
  color: var(--muted);
  font-size: 0.78rem;
  font-weight: 700;
}

.settings-list dd {
  color: var(--ink-soft);
  font-size: 0.85rem;
  margin: 0;
}

.credential-list {
  border-bottom: 1px solid var(--line);
  border-top: 1px solid var(--line);
  list-style: none;
  margin: 24px 0 0;
  padding: 0;
}

.credential-list > li {
  align-items: flex-start;
  display: flex;
  gap: 24px;
  justify-content: space-between;
  padding: 18px 0;
}

.credential-list > li:not(:last-child) {
  border-bottom: 1px solid var(--line);
}

.credential-details strong,
.credential-details span {
  display: block;
}

.credential-details strong {
  color: var(--ink-soft);
  font-size: 0.88rem;
}

.credential-details span {
  color: var(--muted);
  font-size: 0.72rem;
  margin-top: 4px;
}

.credential-removal {
  flex: 0 0 240px;
}

.credential-removal summary,
.recovery-option summary {
  color: var(--accent);
  cursor: pointer;
  font-size: 0.77rem;
  font-weight: 700;
  text-align: right;
}

.security-confirmation-form {
  display: grid;
  gap: 9px;
  margin-top: 13px;
}

.security-confirmation-form label {
  color: var(--muted);
  font-size: 0.72rem;
  font-weight: 700;
}

.security-confirmation-form input[type="password"] {
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  min-height: 42px;
  padding: 9px 11px;
  width: 100%;
}

.account-group {
  align-items: baseline;
  color: var(--muted);
  display: flex;
  font-size: 0.7rem;
  font-weight: 800;
  gap: 16px;
  justify-content: space-between;
  letter-spacing: 0.14em;
  margin: 26px 0 0;
  text-transform: uppercase;
}

/* What a section comes to, sitting over the column of balances it totals. Not uppercase and
   not letter-spaced: it is a number, and it should read like the ones under it. */
.account-group-total {
  color: var(--ink-soft);
  font-size: 0.85rem;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0;
  text-transform: none;
  white-space: nowrap;
}

.account-group + .record-list {
  margin-top: 10px;
}

.record-list {
  border-top: 1px solid var(--line);
  list-style: none;
  margin: 24px 0 0;
  padding: 0;
}

.record-list > li {
  align-items: center;
  border-bottom: 1px solid var(--line);
  display: flex;
  gap: 16px;
  padding: 14px 0;
}

.member-avatar {
  align-items: center;
  background: var(--accent-soft);
  border-radius: 50%;
  color: var(--accent-dark);
  display: inline-flex;
  flex: 0 0 auto;
  font-size: 0.85rem;
  font-weight: 800;
  height: 40px;
  justify-content: center;
  overflow: hidden;
  width: 40px;
}

/* Fills whichever circle holds it, cropping rather than squashing an off-square photo. */
.avatar-photo {
  display: block;
  height: 100%;
  object-fit: cover;
  width: 100%;
}

.member-avatar-you {
  background: var(--accent);
  color: #fff;
}

.record-identity {
  flex: 1 1 auto;
  min-width: 0;
}

.record-name {
  align-items: center;
  color: var(--ink);
  display: flex;
  flex-wrap: wrap;
  font-size: 0.92rem;
  font-weight: 700;
  gap: 8px;
  margin: 0;
}

.member-you {
  background: var(--accent-soft);
  border-radius: 999px;
  color: var(--accent-dark);
  font-size: 0.62rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  padding: 3px 8px;
  text-transform: uppercase;
}

.record-detail {
  color: var(--muted);
  font-size: 0.76rem;
  margin: 3px 0 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* A fund note is prose the household wrote, not a one-line summary assembled from fields, so
   it wraps over the row instead of being cut off at the end of the first line. overflow-wrap
   keeps an unbroken run -- a pasted link, say -- inside the card. */
.record-detail-prose {
  overflow-wrap: anywhere;
  text-overflow: clip;
  white-space: normal;
}

.member-claim {
  align-items: center;
  background: none;
  border: 0;
  border-radius: 50%;
  color: var(--line-strong);
  cursor: pointer;
  display: inline-flex;
  justify-content: center;
  opacity: 0.7;
  padding: 9px;
  transition: color 0.12s ease, opacity 0.12s ease, background 0.12s ease;
}

.member-claim:hover {
  background: var(--accent-soft);
  color: var(--accent);
  opacity: 1;
}

/* The member you sign in as: the one row that reads in full accent. */
.member-claim-you,
.member-claim-you:hover {
  color: var(--accent);
  opacity: 1;
}

/* Held by another login, so there is nothing to claim here. */
.member-claim-taken,
.member-claim-taken:hover {
  background: none;
  color: var(--line-strong);
  cursor: default;
  opacity: 0.45;
}

.member-claim-icon {
  display: block;
  /* The icon is drawn with fill:none, so let clicks fall through to the button itself
     rather than hit-testing against the stroke. */
  pointer-events: none;
}

.record-actions {
  align-items: center;
  display: flex;
  flex: 0 0 auto;
  gap: 4px;
  justify-content: flex-end;
}

.record-actions .member-claim {
  margin-right: 6px;
}

.record-action {
  background: none;
  border: 0;
  border-radius: var(--radius-sm);
  color: var(--muted);
  cursor: pointer;
  font-size: 0.78rem;
  font-weight: 650;
  padding: 8px 11px;
  text-decoration: none;
}

.record-action:hover {
  background: var(--surface-muted);
  color: var(--ink);
}

.record-action-danger:hover {
  background: var(--danger-soft);
  color: var(--danger);
}

.empty-state {
  background: var(--surface-muted);
  border: 1px dashed var(--line-strong);
  border-radius: var(--radius-sm);
  color: var(--muted);
  font-size: 0.82rem;
  margin: 24px 0 0;
  padding: 18px;
}

/* The day a transaction_entry happened, in the column an avatar takes on the lists that have one, so
   a page of transaction_entries reads down its dates the way a statement does. */
.record-date {
  align-items: center;
  color: var(--muted);
  display: flex;
  flex: 0 0 auto;
  flex-direction: column;
  font-size: 0.62rem;
  font-weight: 700;
  justify-content: center;
  letter-spacing: 0.06em;
  line-height: 1.2;
  text-transform: uppercase;
  width: 34px;
}

.record-date > span:first-child {
  color: var(--ink-soft);
  font-size: 1rem;
  letter-spacing: 0;
}

.record-amount {
  flex: 0 0 auto;
  font-size: 0.92rem;
  font-weight: 700;
  margin: 0;
  text-align: right;
  white-space: nowrap;
}

/* Money arriving is the only one worth a colour. Money leaving is the ordinary case and red
   is kept for genuine problems; money that only changed hands inside the household is
   neither, and says so by receding. */
.record-amount-in {
  color: var(--accent);
}

/* The third of these is a line naming a loan its transaction never touched: it counts for
   nothing, and the figure recedes to say so rather than sitting in the column as though it had
   moved something. One rule for all three, so a change to how a receding figure looks cannot
   reach two of them and miss the last. */
.record-amount-inside,
.record-amount-unsettled,
.record-amount-uncounted {
  color: var(--muted);
  font-weight: 650;
}

/* Settled and out of the way. The page is about what is still to come, so what the household
   has already dealt with recedes rather than leaving. */
.record-settled .record-identity,
.record-settled .record-date,
.record-settled .record-amount {
  opacity: 0.55;
}

/* What happened to an occurrence, beside its name. Nothing is said about one that is merely
   due -- that is what everything on the page is -- so only three of these are ever drawn. */
.status-chip {
  background: var(--surface-muted);
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  color: var(--muted);
  font-size: 0.62rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  margin-left: 8px;
  padding: 3px 8px;
  text-transform: uppercase;
  vertical-align: middle;
}

.status-chip-paid {
  background: var(--accent-soft);
  border-color: transparent;
  color: var(--accent-dark);
}

/* The one genuine problem the page can report: a date that has passed with nothing said
   about it. Red is kept for exactly this. */
.status-chip-overdue {
  background: var(--danger-soft);
  border-color: transparent;
  color: var(--danger);
}

/* The transaction that settled an occurrence, and the one the page is offering for it. The
   first is a fact and reads as the row's own; the second is a question and recedes until the
   household answers it. */
.record-settlement {
  color: var(--ink-soft);
}

.record-suggestion {
  color: var(--muted);
  font-style: italic;
}

/* Choosing among the transactions that could have settled one obligation. The radio sits
   where the date does on the due list, so the two pages read down the same column. */
.choice-list > li {
  cursor: pointer;
}

.choice-list input[type="radio"] {
  accent-color: var(--accent);
  flex: 0 0 auto;
  height: 18px;
  margin: 0;
  width: 18px;
}

.choice-list .record-identity {
  cursor: pointer;
}

.choice-list .record-identity span {
  display: block;
}

/* Paging from one month to the next, in the corner of the card the other pages give to
   their one primary action. */
.month-pager {
  display: flex;
  flex: 0 0 auto;
  gap: 6px;
}

.month-step {
  align-items: center;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  color: var(--ink-soft);
  display: inline-flex;
  font-size: 0.95rem;
  font-weight: 700;
  height: 34px;
  justify-content: center;
  text-decoration: none;
  width: 34px;
}

.month-step:hover {
  background: var(--surface-muted);
  border-color: var(--accent);
  color: var(--accent-dark);
}

.month-step-wide {
  font-size: 0.75rem;
  letter-spacing: 0.04em;
  padding: 0 12px;
  width: auto;
}

/* A month of the budget: a category, what it is planned at, and the two figures that follow
   from it. The planned amount is a field rather than a figure because the household is
   reading and deciding in the same pass -- there is no separate page to go and edit it on. */
.budget-list > li {
  gap: 12px;
}

/* One width for every column on this page, whether the row holds a field, a figure, or
   nothing at all. Without it each row sets its own and the eye is asked to measure: Expected
   would sit a little left of Planned, and the comparison further left again. */
.budget-list,
.budget-total,
.budget-comparison {
  --budget-column: 96px;
}

.budget-field {
  display: grid;
  flex: 0 0 auto;
  gap: 3px;
  width: var(--budget-column);
}

.budget-field-label,
.budget-figure > span {
  color: var(--muted);
  font-size: 0.62rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.budget-input {
  font-variant-numeric: tabular-nums;
  padding: 7px 10px;
  text-align: right;
  width: 100%;
}

.budget-input-error {
  border-color: var(--danger);
}

.budget-figure {
  display: grid;
  flex: 0 0 auto;
  gap: 3px;
  margin: 0;
  text-align: right;
  width: var(--budget-column);
}

.budget-figure > strong {
  font-size: 0.92rem;
  font-variant-numeric: tabular-nums;
  font-weight: 700;
}

/* What is left, which is the figure the household came to the page for. The rest of the row
   is what it was worked out from. */
.budget-figure-left > strong {
  color: var(--accent-dark);
}

/* Spent past what was planned. The one genuine problem a budget row can report, so the one
   place it is allowed to be red. */
.budget-row-overspent .budget-figure-left > strong {
  color: var(--danger);
}

/* The Used figure, which hovering or focusing opens up into the transactions it is made of.
   The figure itself anchors the popover, so the list opens under the number it explains. */
.budget-used {
  position: relative;
}

.budget-used:focus-visible {
  border-radius: var(--radius-sm);
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

.budget-used-popover {
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow);
  display: none;
  min-width: 260px;
  padding: 10px 12px;
  position: absolute;
  right: 0;
  text-align: left;
  top: calc(100% + 6px);
  z-index: 5;
}

.budget-used:hover .budget-used-popover,
.budget-used:focus-within .budget-used-popover {
  display: block;
}

.budget-used-popover > ul {
  display: grid;
  gap: 5px;
  list-style: none;
  margin: 0;
  padding: 0;
}

.budget-used-popover li {
  align-items: baseline;
  display: flex;
  font-size: 0.8rem;
  font-weight: 500;
  gap: 8px;
}

.budget-used-day {
  color: var(--muted);
  flex: 0 0 auto;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.budget-used-name {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Who the line was for, where the household said. Kept whole beside the name, which is the
   part that gives way when the row is short of room. */
.budget-used-member {
  color: var(--muted);
  flex: 0 0 auto;
  white-space: nowrap;
}

.budget-used-amount {
  flex: 0 0 auto;
  font-variant-numeric: tabular-nums;
  font-weight: 700;
}

/* The month itself, under the categories it is made of, laid out down the same columns. */
.budget-total {
  align-items: center;
  border-top: 2px solid var(--line-strong);
  display: flex;
  gap: 12px;
  padding: 14px 0;
}

.budget-total .record-name {
  flex: 1 1 auto;
}

/* How much of what has gone nothing accounts for. A line rather than a row of its own: one
   figure, and it belongs to what has gone rather than beside the categories it is not one
   of. */
.budget-uncounted {
  margin-top: 10px;
  position: relative;
}

/* The uncounted figure sits at the start of a sentence rather than in a column, so its list
   hangs from the sentence's left edge instead of off the figure's right, where it would run
   out of the card. */
.budget-uncounted .budget-used {
  font-weight: 700;
  position: static;
}

.budget-uncounted .budget-used-popover {
  left: 0;
  right: auto;
}

/* Whether the month adds up, in both tenses. A summary of everything above it, so it takes
   the heavy rule the month's own total takes and the rows inside it take none. */
.budget-comparison {
  border-top: 2px solid var(--line-strong);
  margin: 4px 0 16px;
  padding-top: 14px;
}

.budget-comparison-heading {
  color: var(--muted);
  font-size: 0.62rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  margin: 0 0 4px;
  text-transform: uppercase;
}

.budget-comparison-row {
  border-top: 0;
  padding: 8px 0;
}

/* Spent past what reached the household. Red for the same reason an overspent category is:
   it is a genuine problem rather than a figure that happens to be negative. */
.budget-figure-short > span,
.budget-figure-short > strong {
  color: var(--danger);
}

.budget-actions {
  flex-wrap: wrap;
  margin-top: 6px;
}

/* One salary's stretch, read back: what came in and what went out on what, each row a name and
   one figure, with what is left under both. */
.pay-period-figure {
  flex: 0 0 auto;
  font-size: 0.92rem;
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  margin: 0 0 0 auto;
  text-align: right;
}

/* A name and one figure fit a phone line, so the row keeps them side by side where every other
   record list gives its name the whole line. */
.pay-period-list .record-identity {
  flex: 1 1 0;
  min-width: 0;
}

.pay-period-left {
  align-items: baseline;
  border-top: 2px solid var(--line-strong);
  display: flex;
  gap: 16px;
  justify-content: space-between;
  margin: 24px 0 0;
  padding-top: 14px;
}

.pay-period-left > span {
  font-weight: 700;
}

.pay-period-left > strong {
  color: var(--accent-dark);
  font-size: 1.1rem;
  font-variant-numeric: tabular-nums;
}

.pay-period-short > span,
.pay-period-short > strong {
  color: var(--danger);
}

/* A fact on a form: something the record already says, shown where a field would be. What
   the bank recorded is not the household's to edit, so it is not offered as a field -- but it
   still belongs where they are reading the rest of the movement. */
.field-label {
  color: var(--ink-soft);
  font-size: 0.78rem;
  font-weight: 700;
  margin: 0 0 6px;
}

.field-fact {
  color: var(--ink);
  font-size: 0.95rem;
  font-variant-numeric: tabular-nums;
  font-weight: 650;
  margin: 0;
}

/* The question the review asks before anything else, where the line names somebody Tally
   cannot place. Above the form rather than under it, because the answer fills the form in. */
.far-end-question {
  background: var(--surface-muted);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  margin-top: 0;
  padding: 18px;
}

.far-end-question h3 {
  margin-top: 0;
}

.split-rows {
  display: grid;
  gap: 14px;
}

/* Each field keeps its own height. Stretched to the row's, a field-group's own grid spreads
   its two rows to fill it, which leaves the label at the top, the input at the bottom, and a
   gap between them the size of whatever the tallest neighbour happens to be. */
.split-row {
  align-items: start;
  background: var(--surface-muted);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  display: grid;
  gap: 14px;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  padding: 16px;
}

/* Ticked for removal: still there, still submitted, plainly on its way out. */
.split-row-removed {
  opacity: 0.45;
}

/* Runs the width of the row, the way the remove tick below it does. What goes in it is a
   sentence rather than a figure, and a column sized for "What is left" is not a line to write
   one on. */
.split-row-note {
  grid-column: 1 / -1;
}

.split-row-remove {
  align-items: center;
  color: var(--muted);
  cursor: pointer;
  display: flex;
  font-size: 0.76rem;
  gap: 8px;
  grid-column: 1 / -1;
}

.split-row-remove input[type="checkbox"] {
  height: 16px;
  margin: 0;
  width: 16px;
}
/* An obligation this payment could be answering for. Ticked rather than chosen, because one
   payment can answer for several -- a round of coins discharges an allowance and four tax
   euros at once. */
.settles-row {
  align-items: center;
  background: var(--surface-muted);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  color: var(--ink);
  font-size: 0.85rem;
  padding: 12px 14px;
}


.split-actions {
  margin-top: 14px;
}

.security-form-section {
  margin-top: 28px;
}

.security-form-section h3 {
  color: var(--ink-soft);
  font-size: 0.9rem;
  margin: 0 0 15px;
}

.security-form {
  display: grid;
  gap: 16px;
}

.security-form-inline {
  align-items: end;
  grid-template-columns: minmax(220px, 1fr) auto;
  margin-top: 20px;
}

.security-form-actions {
  align-items: center;
  display: flex;
  gap: 14px;
}

.form-status {
  color: var(--muted);
  font-size: 0.76rem;
  margin: 0;
}

.form-status:empty {
  display: none;
}

.form-status-error {
  color: var(--danger);
}

.recovery-codes-card {
  border-color: #b8d3c0;
}

.recovery-code-list {
  display: grid;
  gap: 8px;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  list-style: none;
  margin: 24px 0 0;
  padding: 0;
}

.recovery-code-list li {
  background: var(--surface-muted);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 9px 12px;
  text-align: center;
}

.recovery-code-list code {
  color: var(--ink);
  font-size: 0.8rem;
  letter-spacing: 0.05em;
}

.flash {
  align-items: center;
  border: 1px solid;
  border-radius: var(--radius-sm);
  display: flex;
  font-size: 0.82rem;
  font-weight: 650;
  gap: 10px;
  margin: 0 auto 22px;
  max-width: 1160px;
  padding: 11px 14px;
}

.flash-alert {
  background: var(--danger-soft);
  border-color: #eac4bf;
  color: var(--danger);
}

.flash-alert .flash-dot {
  background: var(--danger);
}

.flash-notice {
  background: var(--notice-soft);
  border-color: #c5dfcd;
  color: var(--notice);
}

.authentication-frame {
  background:
    radial-gradient(circle at 10% 10%, rgb(46 109 80 / 12%), transparent 34%),
    radial-gradient(circle at 88% 82%, rgb(179 147 86 / 10%), transparent 30%),
    var(--canvas);
}

.auth-page {
  align-items: center;
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: 100vh;
  padding: 42px 20px;
}

.auth-brand {
  align-items: center;
  display: flex;
  font-family: "Iowan Old Style", Charter, Georgia, serif;
  font-size: 1.45rem;
  font-weight: 700;
  gap: 11px;
  margin-bottom: 28px;
}

.auth-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  max-width: 440px;
  padding: clamp(28px, 6vw, 46px);
  width: 100%;
}

.auth-card h1 {
  font-size: clamp(2rem, 7vw, 2.7rem);
}

.auth-form {
  display: grid;
  gap: 20px;
  margin-top: 30px;
}

.auth-card-compact .auth-form {
  margin-top: 0;
}

.field-group {
  display: grid;
  gap: 7px;
}

/* The grid above outranks the browser's rule for [hidden], so a field put away by the
   account form would otherwise stay on screen. */
.field-group[hidden] {
  display: none;
}

.field-group label {
  color: var(--ink-soft);
  font-size: 0.77rem;
  font-weight: 750;
}

.password-field {
  grid-template-areas:
    "label help"
    "input input";
  grid-template-columns: 1fr auto;
}

.password-field label {
  grid-area: label;
}

.password-field input {
  grid-area: input;
}

.field-help-link {
  font-size: 0.72rem;
  font-weight: 650;
  grid-area: help;
  justify-self: end;
  text-decoration: none;
}

.photo-field {
  align-items: center;
  display: flex;
  gap: 16px;
}

.photo-preview {
  align-items: center;
  background: var(--accent-soft);
  border-radius: 50%;
  color: var(--accent-dark);
  display: inline-flex;
  flex: 0 0 auto;
  font-size: 1.15rem;
  font-weight: 800;
  height: 64px;
  justify-content: center;
  overflow: hidden;
  width: 64px;
}

.photo-field-controls {
  display: grid;
  gap: 7px;
  min-width: 0;
  width: 100%;
}

.field-group .photo-field-controls input[type="file"] {
  background: var(--surface-muted);
  font-size: 0.8rem;
  min-height: 44px;
  padding: 10px 11px;
}

.field-hint {
  color: var(--muted);
  font-size: 0.72rem;
  margin: 0;
}

/* Two of these under one heading are two things to know, not one paragraph that ran on. */
.field-hint + .field-hint {
  margin-top: 6px;
}

.field-group .photo-remove {
  align-items: center;
  color: var(--muted);
  display: flex;
  font-size: 0.77rem;
  font-weight: 600;
  gap: 8px;
}

.field-group .photo-remove input[type="checkbox"] {
  accent-color: var(--accent);
  height: 16px;
  min-height: 0;
  width: 16px;
}

.field-group input,
.field-group select,
.field-group textarea {
  background: #fff;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  color: var(--ink);
  min-height: 48px;
  padding: 11px 13px;
  width: 100%;
}

/* A textarea does not inherit the page's font the way the inputs beside it do, and would
   otherwise be drawn in the browser's monospace default. Resizing stays vertical so a wide
   drag cannot push the card out of shape. */
.field-group textarea {
  font: inherit;
  line-height: 1.5;
  resize: vertical;
}

/* Drops the platform control so the field matches the text inputs beside it, which means
   drawing the chevron here. Inlined rather than linked: the stylesheet is served under a
   CSP that allows no external image host. */
.field-group select {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none' stroke='%2368736c' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M1 1.75 6 6.25 11 1.75'/%3E%3C/svg%3E");
  background-position: right 15px center;
  background-repeat: no-repeat;
  cursor: pointer;
  padding-right: 40px;
}

/* A required select with nothing chosen is the placeholder case: Rails gives it a blank
   option, and this keeps its prompt as quiet as a placeholder until a choice is made. */
.field-group select:required:invalid {
  color: #a1aaa4;
}

.field-group select option {
  color: var(--ink);
}

.field-group textarea::placeholder,
.field-group input::placeholder {
  color: #a1aaa4;
}

.field-group input:focus,
.field-group select:focus,
.field-group textarea:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgb(46 109 80 / 10%);
  outline: none;
}

.auth-back-link {
  background: none;
  border: 0;
  color: inherit;
  cursor: pointer;
  display: inline-block;
  font-size: 0.78rem;
  font-weight: 650;
  margin-top: 24px;
  padding: 0;
  text-decoration: none;
}

.recovery-option {
  border-top: 1px solid var(--line);
  margin-top: 26px;
  padding-top: 18px;
}

.recovery-option summary {
  text-align: left;
}

.recovery-form.auth-form {
  margin-top: 18px;
}

.mobile-header,
.mobile-nav {
  display: none;
}

.mobile-header-actions {
  align-items: center;
  display: flex;
  gap: 13px;
}

/* Covers the screen rather than sliding a narrow rail over it: on a phone the menu is the
   whole view for as long as it is open, which is why it needs no dimmed backdrop. */
.mobile-menu {
  background: var(--canvas);
  display: flex;
  flex-direction: column;
  inset: 0;
  overflow-y: auto;
  padding: max(18px, env(safe-area-inset-top)) max(20px, env(safe-area-inset-right))
    max(20px, env(safe-area-inset-bottom)) max(20px, env(safe-area-inset-left));
  position: fixed;
  z-index: 60;
}

/* The flex above outranks the browser's rule for [hidden], the same trap .field-group[hidden]
   documents, so without this the menu would sit open over the app from the first render. */
.mobile-menu[hidden] {
  display: none;
}

/* The menu belongs to the narrow screens. Left open across a resize to desktop it would
   otherwise cover an app that already has its sidebar back. */
@media (min-width: 901px) {
  .mobile-menu {
    display: none;
  }
}

.mobile-menu-bar {
  align-items: center;
  display: flex;
  justify-content: space-between;
  padding-bottom: 12px;
}

.mobile-menu-close {
  background: none;
  border: 0;
  border-radius: 50%;
  color: var(--muted);
  cursor: pointer;
  font-size: 1.9rem;
  line-height: 1;
  /* A 44px box: the smallest thing a thumb should have to find. */
  min-height: 44px;
  min-width: 44px;
}

.mobile-menu-close:hover {
  color: var(--ink);
}

.mobile-menu-nav {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding-top: 10px;
}

.mobile-menu-label {
  color: var(--muted);
  font-size: 0.69rem;
  font-weight: 700;
  letter-spacing: 0.13em;
  margin: 22px 4px 8px;
  text-transform: uppercase;
}

.mobile-menu-label:first-child {
  margin-top: 4px;
}

/* Roomy on purpose. A sidebar row is aimed at with a cursor; this one is hit with a thumb,
   so it is taller than it looks like it needs to be and the whole row is the target. */
.mobile-menu-link {
  align-items: center;
  border-radius: var(--radius-sm);
  color: var(--ink);
  display: flex;
  font-size: 1.02rem;
  font-weight: 650;
  gap: 15px;
  min-height: 56px;
  padding: 0 14px;
  text-decoration: none;
}

.mobile-menu-link.active {
  background: var(--accent-soft);
  color: var(--accent-dark);
}

.mobile-menu-link.disabled {
  color: #9aa39c;
}

.mobile-menu-icon {
  align-items: center;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 11px;
  display: inline-flex;
  flex: 0 0 auto;
  font-size: 1.1rem;
  height: 40px;
  justify-content: center;
  width: 40px;
}

.mobile-menu-link.active .mobile-menu-icon {
  background: var(--surface);
  border-color: transparent;
}

.mobile-menu-soon {
  background: var(--canvas-deep);
  border-radius: 999px;
  color: var(--muted);
  font-size: 0.6rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  margin-left: auto;
  padding: 4px 9px;
  text-transform: uppercase;
}

/* Pinned to the bottom of the screen by margin-top rather than position, so a menu longer
   than the viewport pushes it down the scroll instead of sitting over the last row. */
.mobile-menu-account {
  align-items: center;
  border-top: 1px solid var(--line);
  display: flex;
  gap: 12px;
  margin-top: auto;
  padding-top: 18px;
}

.mobile-menu-identity {
  display: flex;
  flex-direction: column;
  line-height: 1.3;
  min-width: 0;
}

.mobile-menu-identity strong {
  font-size: 0.9rem;
}

.mobile-menu-identity span {
  color: var(--muted);
  font-size: 0.75rem;
}

.mobile-menu-signout {
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  color: var(--ink-soft);
  cursor: pointer;
  font-size: 0.78rem;
  font-weight: 700;
  margin-left: auto;
  min-height: 44px;
  padding: 0 18px;
}

.mobile-menu-signout:hover {
  border-color: var(--accent);
  color: var(--accent);
}

.mobile-menu-toggle {
  background: none;
  border: 0;
  color: var(--ink);
  cursor: pointer;
  font-size: 1.3rem;
  line-height: 1;
  padding: 4px 2px;
}

/* Wide enough for the four of them in a row, sidebar and all. */
@media (min-width: 1280px) {
  .metric-grid {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

@media (max-width: 900px) {
  .sidebar {
    display: none;
  }

  .main-content {
    margin-left: 0;
    padding: 0 24px 96px;
  }

  .mobile-header {
    align-items: center;
    border-bottom: 1px solid var(--line);
    display: flex;
    justify-content: space-between;
    margin: 0 -24px 30px;
    padding: 16px 24px;
  }

  .mobile-header .brand {
    color: var(--ink);
  }

  .mobile-nav {
    background: rgb(255 254 250 / 94%);
    border-top: 1px solid var(--line);
    bottom: 0;
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    left: 0;
    padding: 8px max(10px, env(safe-area-inset-right)) calc(8px + env(safe-area-inset-bottom)) max(10px, env(safe-area-inset-left));
    position: fixed;
    right: 0;
    z-index: 30;
  }

  .mobile-nav-link {
    align-items: center;
    color: var(--muted);
    display: flex;
    flex-direction: column;
    font-size: 0.62rem;
    font-weight: 700;
    gap: 2px;
    padding: 4px 2px;
    text-decoration: none;
  }

  .mobile-nav-link > span:first-child {
    font-size: 1.05rem;
  }

  .mobile-nav-link.active {
    color: var(--accent);
  }

  .mobile-nav-link.disabled {
    color: #a7aea9;
  }

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

  .metric-card:last-child:nth-child(odd) {
    grid-column: 1 / -1;
  }
}

@media (max-width: 600px) {
  .main-content {
    padding-left: 17px;
    padding-right: 17px;
  }

  .mobile-header {
    margin-left: -17px;
    margin-right: -17px;
    padding-left: 17px;
    padding-right: 17px;
  }

  .page-header {
    display: block;
  }

  .privacy-chip {
    display: inline-flex;
    margin-top: 18px;
  }

  .metric-grid {
    grid-template-columns: 1fr;
  }

  .metric-card:last-child:nth-child(odd) {
    grid-column: auto;
  }

  .metric-card {
    min-height: 138px;
  }

  .settings-heading {
    display: block;
  }

  .role-badge {
    margin-top: 6px;
  }

  .settings-list div {
    gap: 5px;
    grid-template-columns: 1fr;
  }

  .record-list > li {
    flex-wrap: wrap;
  }

  .record-identity,
  .record-actions {
    flex-basis: 100%;
  }

  .record-actions {
    justify-content: flex-start;
  }

  /* Only a members row leads with an avatar, so only a members row indents past one: 56px is
     the avatar and its gap, which lines the actions up under the name. */
  .member-list .record-identity,
  .member-list .record-actions {
    flex-basis: calc(100% - 56px);
  }

  .member-list .record-actions {
    margin-left: 56px;
  }

  /* A transactions row leads with a date and ends with an amount, so wrapping it the way an
     accounts row wraps puts both on lines of their own and costs a phone screen three rows.
     Laid out as a statement is read instead: when, what, how much, with the actions under it. */
  .transaction-list > li {
    align-items: start;
    display: grid;
    gap: 4px 12px;
    grid-template-areas:
      "date identity amount"
      ". actions actions";
    grid-template-columns: 34px minmax(0, 1fr) auto;
  }

  .transaction-list .record-date {
    grid-area: date;
  }

  .transaction-list .record-identity {
    grid-area: identity;
  }

  .transaction-list .record-amount {
    grid-area: amount;
  }

  .transaction-list .record-actions {
    grid-area: actions;
    margin-left: -11px;
  }

  /* A budget row is a name and three numbers, which will not sit on one phone line. Laid out
     as the household reads it instead: the category, then its figures under it in a row of
     their own, so the columns still line up down the page. */
  .budget-list > li,
  .budget-total {
    align-items: end;
    display: grid;
    gap: 10px 12px;
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .budget-list .record-identity,
  .budget-total .record-identity,
  .budget-total .record-name {
    grid-column: 1 / -1;
  }

  /* The columns are a third of the phone each here, which is narrower than the width they
     hold to on a wider screen. Left at that width they overflow the card rather than share
     the row out. */
  .budget-field,
  .budget-figure {
    width: auto;
  }

  /* The Used column is the middle third of a phone row, so a list hung off its right edge
     would run off the card. Hung from its middle instead, held inside the screen. */
  .budget-used-popover,
  .budget-uncounted .budget-used-popover {
    left: 50%;
    max-width: calc(100vw - 48px);
    min-width: 220px;
    right: auto;
    transform: translateX(-50%);
  }

  .credential-list > li,
  .security-form-actions {
    align-items: stretch;
    flex-direction: column;
  }

  .credential-removal {
    flex-basis: auto;
  }

  .credential-removal summary {
    text-align: left;
  }

  .security-form-inline,
  .recovery-code-list {
    grid-template-columns: 1fr;
  }
}

body.menu-open {
  overflow: hidden;
}

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