/* The Inbox card — the epicenter component; adapts to its container
   (inbox_design.md). */
.card {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-4);
  align-items: center;
  justify-content: space-between;
  border: 1px solid var(--border);
  border-radius: var(--radius-2);
  background: var(--card-surface);
  box-shadow: var(--shadow-1);
  padding: var(--space-3) var(--space-4);
}
.card > .card-body { flex: 1 1 20rem; min-inline-size: 0; }

/* The reading order is the hierarchy: status badge first, then what and
   when on one quiet line above the title. */
.card-topline { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: center; }

/* Amount above actions in a right-hand column; wraps below the body when
   the container narrows — rows on a desktop, a stack on a phone, same
   markup (ui_principles.md #9). */
.card > .card-side {
  flex: 0 1 auto;
  display: grid;
  gap: var(--space-2);
  justify-items: end;
  min-inline-size: 0;
  margin-inline-start: auto;
}
.card-side .card-actions { display: grid; gap: var(--space-2); justify-items: end; }
.card .title { font-weight: 600; overflow-wrap: anywhere; }
.card .amount { font-size: var(--text-4); font-weight: 600; }
.card:has(.badge-danger) { border-color: var(--border-danger); }

.card form { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: center; }
.card select, .card input[type="text"] {
  padding: var(--space-1) var(--space-2);
  max-inline-size: 100%;
}

/* Secondary card actions live behind the shared details.menu disclosure:
   one visible action per card, escape hatches on demand. */
.card-menu > summary { font-size: var(--text-5); line-height: 1.6; }

/* The inbox item: a header and a body, each split left/right
   (inbox_design.md). The item is a card that stacks instead of centring
   — the header's identity and the body's work read as two rows, not as
   one line of competing things. */
.card.item {
  /* The top half is the page's own paper: identity on white, work on
     the tint below it. The card still reads as a card — its border and
     shadow do that, not a shade of grey. */
  background: var(--paper);
  display: grid;
  gap: var(--space-3);
  align-items: stretch;
  justify-content: stretch;
  /* A tone stripe inside the left border, one glance wide: what kind of
     attention this item wants. It is redundant by design — the badge
     says the same in words (design_system.md). Inset rather than a
     border so it follows the card's radius and costs no layout. */
  box-shadow: var(--shadow-1), inset var(--tone-width, 4px) 0 0 var(--tone, transparent);
  padding-inline-start: calc(var(--space-4) + var(--tone-width, 4px));
}
.item-tone-ok { --tone: var(--ok); }
.item-tone-warn { --tone: var(--warn); }
.item-tone-danger { --tone: var(--danger); }
.item-tone-neutral { --tone: var(--muted-faint); }

/* Left: date, title, kind · description. Right: the amount and one
   short flag. The identity absorbs the slack so the amount stays put. */
/* A rule under the header: identity above, work below. The app's own
   border weight — anything lighter disappeared against the wash below
   it, and the card's outline is a different line doing a different job. */
.item-header {
  /* The rule runs the card's full width — it separates two halves, not
     two paragraphs — so the header cancels the card's inline padding and
     puts it back as its own. The inline start keeps the tone stripe's
     4 px, exactly as the lower half does. */
  margin-inline: calc(-1 * var(--space-4));
  padding-inline: var(--space-4);
  border-block-end: 1px solid var(--border);
  padding-block-end: var(--space-3);
}

.item-header,
.item-body {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-4);
  align-items: start;
  justify-content: space-between;
}

/* The whole lower half sits on the kind of paper the item came from: a
   wash of colour telling a receipt from an invoice from a statement down
   a long queue. It bleeds to the card's edges, cancelling the card's own
   padding — except on the inline start, where the tone stripe keeps its
   4 px. The card cannot clip to its radius (the ⋯ panel escapes it), so
   the bottom corners are rounded here instead. */
.item-lower {
  margin-block: calc(-1 * var(--space-3));
  margin-inline: calc(-1 * var(--space-4));
  padding: var(--space-3) var(--space-4);
  display: grid;
  gap: var(--space-3);
  background: var(--kind-tint, var(--tint-plain));
  border-end-start-radius: calc(var(--radius-2) - var(--tone-width, 4px));
  border-end-end-radius: var(--radius-2);
}
.item-kind-receipt { --kind-tint: var(--tint-receipt); --kind-ink: var(--ink-receipt); }
.item-kind-purchase_invoice { --kind-tint: var(--tint-purchase); --kind-ink: var(--ink-purchase); }
.item-kind-sales_invoice { --kind-tint: var(--tint-sales); --kind-ink: var(--ink-sales); }
.item-kind-bank_statement { --kind-tint: var(--tint-statement); --kind-ink: var(--ink-statement); }
.item-identity { flex: 1 1 18rem; min-inline-size: 0; }
.item-identity > p { margin: 0; }
/* The flag beside the amount, sharing its baseline, the figure last so
   it ends at the card's edge where every amount in the app ends. */
.item-summary {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: baseline;
  justify-content: end;
  text-align: end;
}

/* Said in full, once, above the work it explains. No panel of its own:
   it already sits on the item's wash, and a chip inside a tinted half
   was two backgrounds arguing. The icon and the colour of the words
   carry it. */
.item-notice {
  display: flex;
  gap: var(--space-2);
  align-items: start;
  margin: 0;
  background: transparent;
  font-size: var(--text-3);
}
/* The words take the item's own hue where it has one — the notice
   belongs to this piece of paper. Severity is not lost with it: the ⚠/ⓘ
   icon, the badge and the tone stripe all still say it. An item with no
   kind of its own (a transaction, an unread file) falls back to the
   severity colour. */
.item-notice-warn { color: var(--kind-ink, var(--warn)); }
.item-notice-info { color: var(--kind-ink, var(--muted)); }

/* The item's own form on the left, the voucher and the actions that
   lead on the right. Empty on either side is normal: a transaction has
   no voucher, a finished reading has nothing left to correct. */
.item-form { flex: 1 1 18rem; min-inline-size: 0; display: grid; gap: var(--space-2); }
.item-form > p { margin: 0; }

/* The voucher, the action that leads, and the rest: one row, in that
   reading order, ending at the card's edge. Wraps only when the
   container leaves no room for them side by side. */
.item-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: center;
  justify-content: end;
}
.item-actions > p { margin: 0; }

/* Fields carry their own labels, beside the control rather than above
   it: a row of "Tili [select]" pairs, wrapping when they run out of
   room. Above-the-control stacking made a two-field form three rows
   tall for no reading gained. */
.item-fields { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-3); align-items: center; }
.item-fields label { display: flex; align-items: center; gap: var(--space-2); }
.item-fields .meta { margin: 0; white-space: nowrap; }
.item-inline-form { display: inline; }

/* Facts, not a sentence: label and value in two columns, so the eye can
   run down the labels and compare against the document. */
.item-facts {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--space-1) var(--space-3);
  margin: 0;
  font-size: var(--text-3);
}
.item-facts dt { color: var(--muted); white-space: nowrap; }
.item-facts dd { margin: 0; }
/* One invoice line per row, though: its five fields belong together,
   and two lines side by side would read as one. */
.reading-line {
  flex: 1 1 100%;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-3);
  align-items: center;
  border: 0;
  margin: 0;
  padding: 0;
}
.reading-line .amount { inline-size: 7rem; }
.reading-line .is-fullwidth { flex: 1 1 14rem; }

/* The voucher opens beside its item; the dialog is the app's only one
   and never opens itself (design_system.md). */
/* Takes the room the window offers: 92 % of it, up to a ceiling wide
   enough for an A4 page at full height on a large display. The pages are
   drawn to this width when the dialog opens (dialog_controller.js), so a
   wide window gets a large canvas rather than an enlarged small one. */
.voucher-dialog {
  inline-size: min(92vw, 88rem);
  block-size: min(92vh, 64rem);
  border: 0;
  border-radius: var(--radius-2);
  padding: 0;
}
.voucher-dialog::backdrop { background: rgb(0 0 0 / 0.5); }
.voucher-dialog-head {
  display: flex;
  gap: var(--space-3);
  align-items: center;
  justify-content: space-between;
  padding: var(--space-2) var(--space-3);
  border-block-end: 1px solid var(--border);
}
/* The pages stack and scroll inside the dialog; each is drawn to the
   dialog's width and keeps its own aspect. */
.voucher-dialog-body {
  display: block;
  block-size: calc(100% - 3rem);
  overflow: auto;
  padding: var(--space-3);
  background: var(--surface);
}
/* Canvases pdf.js draws into: sized by CSS, resolution by the device's
   pixel ratio (dialog_controller.js). */
.voucher-page {
  display: block;
  block-size: auto;
  margin-block-end: var(--space-3);
  background: var(--paper);
  box-shadow: var(--shadow-1);
}
.voucher-page:last-child { margin-block-end: 0; }
