/* ============================================================================
   Mailo Mobile V2 — components.

   Written mobile-first at 375px. Every horizontal dimension is logical
   (inline-start / inline-end), so the whole product flips to RTL by setting
   dir on <html> and nothing here has to know which direction it is in.
   ========================================================================== */

/* ---------------------------------------------------------------- base ---- */
*, *::before, *::after { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--v2-bg);
  color: var(--v2-ink);
  font-family: var(--v2-font);
  font-size: var(--v2-fs-md);
  line-height: var(--v2-lh-body);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* The app never scrolls sideways. If something inside is too wide it scrolls
   inside its own box; the page itself does not. */
html, body { overflow-x: hidden; }

h1, h2, h3, h4 { margin: 0; font-weight: 600; line-height: var(--v2-lh-tight); letter-spacing: -0.011em; }
p { margin: 0; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; }
img, svg { max-width: 100%; }
ul, ol { margin: 0; padding: 0; list-style: none; }

/* Focus is visible everywhere, and only for keyboard users. Hiding it for
   mouse users is fine; hiding it entirely locks out keyboard navigation. */
:focus { outline: none; }
:focus-visible {
  outline: 2px solid var(--v2-accent);
  outline-offset: 2px;
  border-radius: var(--v2-r-xs);
}

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

/* Numbers align in columns and do not reflow as they change. */
.v2-num { font-variant-numeric: tabular-nums; }

/* Money and identifiers stay left-to-right inside a Hebrew sentence. An
   isolate is enough; forcing dir would drag the surrounding punctuation with
   it and put the shekel sign on the wrong side of the phrase. */
.v2-ltr { unicode-bidi: isolate; direction: ltr; }

/* ---------------------------------------------------------------- shell --- */
.v2-app {
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  max-width: var(--v2-max-w);
  margin-inline: auto;
  background: var(--v2-bg);
  position: relative;
}

.v2-header {
  position: sticky;
  top: 0;
  z-index: 40;
  padding-top: var(--v2-safe-t);
  background: color-mix(in oklab, var(--v2-bg) 88%, transparent);
  backdrop-filter: saturate(1.4) blur(14px);
  -webkit-backdrop-filter: saturate(1.4) blur(14px);
  border-bottom: 1px solid transparent;
  transition: border-color var(--v2-dur) var(--v2-ease);
}
.v2-header.is-stuck { border-bottom-color: var(--v2-line); }

.v2-header-in {
  min-height: var(--v2-header-h);
  display: flex;
  align-items: center;
  gap: var(--v2-sp-3);
  padding-inline: var(--v2-gutter);
  padding-block: var(--v2-sp-2);
}
.v2-header-title { font-size: var(--v2-fs-xl); font-weight: 600; letter-spacing: -0.02em; }
.v2-header-sub { font-size: var(--v2-fs-xs); color: var(--v2-ink-faint); margin-top: 1px; }
.v2-header-end { margin-inline-start: auto; display: flex; align-items: center; gap: var(--v2-sp-2); }

/* A back control that is a real 40px target while looking like a 20px glyph. */
.v2-back {
  width: 40px; height: 40px;
  margin-inline-start: -8px;
  display: grid; place-items: center;
  border: 0; background: transparent; cursor: pointer;
  border-radius: var(--v2-r-full);
  color: var(--v2-ink);
}
.v2-back:active { background: var(--v2-bg-sunken); }
/* The chevron points at the start edge in both directions. */
[dir="rtl"] .v2-back svg { transform: scaleX(-1); }

.v2-main {
  flex: 1;
  padding-inline: var(--v2-gutter);
  padding-bottom: calc(var(--v2-nav-h) + var(--v2-safe-b) + var(--v2-sp-8));
}

/* --------------------------------------------------------------- bottom --- */
.v2-nav {
  position: fixed;
  inset-inline: 0;
  bottom: 0;
  z-index: 50;
  margin-inline: auto;
  max-width: var(--v2-max-w);
  background: color-mix(in oklab, var(--v2-surface) 92%, transparent);
  backdrop-filter: saturate(1.5) blur(18px);
  -webkit-backdrop-filter: saturate(1.5) blur(18px);
  box-shadow: var(--v2-shadow-nav);
  padding-bottom: var(--v2-safe-b);
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  align-items: stretch;
}

.v2-tab {
  /* The badge is absolutely positioned inside a tab. Without this it resolves
     against .v2-nav instead and every badge lands on the centre button. */
  position: relative;
  min-height: var(--v2-nav-h);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  border: 0;
  background: transparent;
  cursor: pointer;
  color: var(--v2-ink-faint);
  font-size: var(--v2-fs-2xs);
  font-weight: 500;
  padding: 0 2px;
  transition: color var(--v2-dur-fast) var(--v2-ease);
  -webkit-tap-highlight-color: transparent;
}
.v2-tab svg { width: 23px; height: 23px; stroke-width: 1.6; transition: stroke-width var(--v2-dur-fast) var(--v2-ease); }
/* The active tab is carried by weight and a tint behind the icon, not by
   colour alone. Colour alone is invisible at arm's length and to anyone who
   does not separate this blue from this grey. */
.v2-tab[aria-current="page"] { color: var(--v2-accent); font-weight: 600; }
.v2-tab[aria-current="page"] svg { stroke-width: 2.2; }
.v2-tab-icon {
  display: grid; place-items: center;
  width: 46px; height: 27px;
  border-radius: var(--v2-r-full);
  transition: background var(--v2-dur-fast) var(--v2-ease);
}
.v2-tab[aria-current="page"] .v2-tab-icon { background: var(--v2-accent-tint); }
.v2-tab-label { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* The centre action. Prominent because it is the one thing every user does
   every day, but seated in the bar rather than hovering above it — a floating
   pill competes with the bar it belongs to. */
.v2-tab-center { position: relative; }
.v2-fab {
  width: 46px; height: 46px;
  margin-top: -14px;
  border-radius: var(--v2-r-full);
  background: var(--v2-accent);
  color: var(--v2-accent-ink);
  display: grid; place-items: center;
  box-shadow: var(--v2-shadow-accent);
  transition: transform var(--v2-dur-fast) var(--v2-ease), background var(--v2-dur-fast) var(--v2-ease);
}
.v2-fab svg { width: 24px; height: 24px; stroke-width: 2.2; }
.v2-tab-center:active .v2-fab { transform: scale(0.94); background: var(--v2-accent-press); }
.v2-tab-center .v2-tab-label { margin-top: -1px; }

/* A count that must be noticed without shouting. */
.v2-tab-badge {
  position: absolute;
  top: 6px;
  inset-inline-start: calc(50% + 6px);
  min-width: 17px; height: 17px;
  padding-inline: 4px;
  border-radius: var(--v2-r-full);
  background: var(--v2-negative);
  color: #fff;
  font-size: var(--v2-fs-2xs); font-weight: 600; line-height: 17px;
  text-align: center;
  border: 2px solid var(--v2-surface);
  box-sizing: content-box;
}

/* ----------------------------------------------------------------- card --- */
.v2-card {
  background: var(--v2-surface);
  border-radius: var(--v2-r-lg);
  box-shadow: var(--v2-shadow-sm);
  overflow: hidden;
}
.v2-card-pad { padding: var(--v2-sp-4); }

/* Sections are separated by SPACE and a quiet heading, not by another box.
   Version A wrapped every block in its own white rounded card, which meant a
   raised surface no longer said "this matters" — it just said "this is a
   block". Here exactly one surface per screen is raised (the money), and
   everything else sits on the ground and is grouped by rhythm. */
.v2-section { margin-top: var(--v2-sp-7); }
.v2-section:first-child { margin-top: var(--v2-sp-2); }
.v2-section-head {
  display: flex; align-items: baseline; gap: var(--v2-sp-3);
  margin-bottom: var(--v2-sp-2);
  padding-inline: 2px;
}
.v2-section-title {
  font-size: var(--v2-fs-xs);
  font-weight: 500;
  letter-spacing: 0.02em;
  color: var(--v2-ink-faint);
}
.v2-section-link {
  margin-inline-start: auto;
  font-size: var(--v2-fs-sm); font-weight: 500;
  color: var(--v2-accent);
  border: 0; background: transparent; cursor: pointer;
  /* A 40px hit area pulled back with negative margin, so the target grows
     without the heading row growing with it. */
  display: inline-flex; align-items: center;
  min-height: 40px; padding-inline: 6px;
  margin-block: -10px;
}

/* -------------------------------------------------------------- finance --- */
/* One surface, three figures. Not three coloured tiles: tiles of equal weight
   say the three numbers are equally important, and they are not — income and
   expenses are the inputs, profit is the answer. */
.v2-fin {
  background: var(--v2-surface);
  border-radius: var(--v2-r-lg);
  box-shadow: var(--v2-shadow-md);
  padding: var(--v2-sp-5) var(--v2-sp-5) var(--v2-sp-4);
}
.v2-fin-rows { display: grid; gap: var(--v2-sp-4); }
/* space-between, NOT an auto margin on the value. The value carries .v2-ltr,
   which sets direction:ltr on that element — and `margin-inline-start` on a
   flex item resolves against the item's OWN direction, so an auto margin there
   pushes the number back toward the label in an RTL row instead of away from
   it. Justification belongs to the container, which stays RTL. */
.v2-fin-row { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--v2-sp-3); }
.v2-fin-label {
  font-size: var(--v2-fs-sm);
  color: var(--v2-ink-soft);
  font-weight: 500;
  padding-bottom: 3px;
}
.v2-fin-value {
  font-size: var(--v2-fs-2xl);
  font-weight: 600;
  letter-spacing: -0.025em;
  line-height: 1.1;
}
.v2-fin-row.is-profit { border-top: 1px solid var(--v2-line-faint); padding-top: var(--v2-sp-4); }
.v2-fin-row.is-profit .v2-fin-label { font-weight: 600; color: var(--v2-ink); font-size: var(--v2-fs-md); }
.v2-fin-row.is-profit .v2-fin-value { font-size: var(--v2-fs-3xl); }
.v2-fin-value.is-pos { color: var(--v2-positive); }
.v2-fin-value.is-neg { color: var(--v2-negative); }
/* A zero is still shown exactly; it just stops competing with a real figure. */
.v2-fin-value.is-zero { color: var(--v2-ink-faint); font-weight: 500; }
.v2-fin-sub { font-size: var(--v2-fs-xs); color: var(--v2-ink-faint); margin-top: 2px; }
.v2-fin-note {
  margin-top: var(--v2-sp-4);
  padding-top: var(--v2-sp-3);
  border-top: 1px solid var(--v2-line-faint);
  font-size: var(--v2-fs-xs);
  color: var(--v2-ink-faint);
  display: flex; gap: var(--v2-sp-2); align-items: flex-start;
  line-height: 1.45;
}
.v2-fin-note svg { width: 14px; height: 14px; flex: none; margin-top: 2px; }

/* Period control. A row of pills that scrolls, with the custom range last
   because it is the rarest and the widest. */
.v2-period {
  display: flex; gap: var(--v2-sp-2);
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  margin-inline: calc(var(--v2-gutter) * -1);
  padding-inline: var(--v2-gutter);
  padding-block: var(--v2-sp-1);
  margin-bottom: var(--v2-sp-3);
}
.v2-period::-webkit-scrollbar { display: none; }
.v2-pill {
  flex: none;
  /* 34px looked right and was too small to hit reliably with a thumb on a
     moving bus. 40px keeps the pill compact while clearing the practical
     minimum. */
  min-height: 40px;
  padding: 0 var(--v2-sp-4);
  border-radius: var(--v2-r-full);
  border: 1px solid var(--v2-line);
  background: var(--v2-surface);
  color: var(--v2-ink-soft);
  font-size: var(--v2-fs-sm); font-weight: 500;
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--v2-dur-fast) var(--v2-ease), color var(--v2-dur-fast) var(--v2-ease), border-color var(--v2-dur-fast) var(--v2-ease);
}
/* Quieter than Version A, where five solid-bordered pills across the full
   width read as a filter toolbar. The unselected pills now have no border at
   all; only the chosen period is drawn. */
.v2-period .v2-pill { border-color: transparent; background: transparent; }
.v2-period .v2-pill[aria-pressed="false"]:active { background: var(--v2-bg-sunken); }
.v2-pill[aria-pressed="true"] {
  background: var(--v2-accent);
  border-color: var(--v2-accent);
  color: var(--v2-accent-ink);
}
.v2-period .v2-pill[aria-pressed="true"] { background: var(--v2-accent); border-color: var(--v2-accent); }

/* Trend bars. Drawn only where real per-period values exist. */
/* Six months, income and expenses side by side. A single bar would have to
   pick one of the two, and a profit bar cannot show a loss without inventing
   a baseline — this business currently issues nothing, so every profit bar
   would point the wrong way off the bottom of the chart. */
.v2-trend {
  margin-top: var(--v2-sp-5);
  padding-top: var(--v2-sp-4);
  border-top: 1px solid var(--v2-line-faint);
}
.v2-trend-head {
  display: flex; align-items: center; gap: var(--v2-sp-3);
  margin-bottom: var(--v2-sp-3);
  font-size: var(--v2-fs-xs); color: var(--v2-ink-faint);
}
.v2-trend-legend { margin-inline-start: auto; display: flex; gap: var(--v2-sp-3); }
.v2-trend-key { display: inline-flex; align-items: center; gap: 5px; }
.v2-trend-swatch { width: 8px; height: 8px; border-radius: 2px; background: var(--v2-accent); }
.v2-trend-swatch.is-out { background: color-mix(in oklab, var(--v2-accent) 38%, var(--v2-bg)); }

.v2-trend-plot { display: flex; align-items: flex-end; gap: 4px; height: 52px; }
.v2-trend-month { flex: 1; display: flex; align-items: flex-end; justify-content: center; gap: 2px; height: 100%; }
/* The expenses bar is a mid-tone, not the palest tint. At --v2-accent-tint-2
   it read as a disabled control rather than as the only populated series on a
   chart where income happens to be zero. */
.v2-trend-bar { width: 7px; border-radius: 2px 2px 0 0; min-height: 2px; background: color-mix(in oklab, var(--v2-accent) 38%, var(--v2-bg)); }
.v2-trend-bar.is-in { background: var(--v2-accent); }
.v2-trend-month.is-current .v2-trend-bar { outline: 1px solid var(--v2-accent-tint-2); outline-offset: 1px; }

.v2-trend-labels { display: flex; gap: 4px; margin-top: 7px; }
.v2-trend-labels span { flex: 1; text-align: center; font-size: var(--v2-fs-2xs); color: var(--v2-ink-faint); }
.v2-trend-labels span.is-current { color: var(--v2-ink-soft); font-weight: 500; }

/* ----------------------------------------------------------------- rows --- */
/* One row language for documents, suppliers, customers and employees.
   Building three different list idioms is how a product starts feeling
   assembled out of parts. */
/* Flat by default: rows on the ground, separated by hairlines. `.is-raised`
   brings the old card back for the rare place a list really is the subject of
   the screen. */
.v2-list {
  background: transparent;
  border-radius: 0;
  box-shadow: none;
  border-top: 1px solid var(--v2-line-faint);
}
.v2-list.is-raised {
  background: var(--v2-surface);
  border: 0;
  border-radius: var(--v2-r-lg);
  box-shadow: var(--v2-shadow-sm);
  overflow: hidden;
}
.v2-row {
  display: flex;
  align-items: center;
  gap: var(--v2-sp-3);
  width: 100%;
  min-height: 64px;
  padding: var(--v2-sp-3) 0;
  border: 0;
  background: transparent;
  text-align: start;
  cursor: pointer;
  position: relative;
  -webkit-tap-highlight-color: transparent;
  transition: background var(--v2-dur-fast) var(--v2-ease);
}
/* The separator starts where the text starts, so the avatar column reads as a
   continuous rail rather than as a series of boxed cells. */
.v2-row + .v2-row::before {
  content: '';
  position: absolute;
  top: 0;
  inset-inline-start: calc(40px + var(--v2-sp-3));
  inset-inline-end: 0;
  border-top: 1px solid var(--v2-line-faint);
}
.v2-row.no-avatar + .v2-row.no-avatar::before { inset-inline-start: 0; }
/* On the ground there is no white row to darken, so the press state tints the
   full-bleed width instead. */
.v2-row:active {
  background: var(--v2-bg-sunken);
  box-shadow: -12px 0 0 var(--v2-bg-sunken), 12px 0 0 var(--v2-bg-sunken);
  border-radius: var(--v2-r-xs);
}
.v2-list.is-raised .v2-row { padding-inline: var(--v2-sp-4); }
.v2-list.is-raised .v2-row + .v2-row::before { inset-inline-start: calc(var(--v2-sp-4) + 40px + var(--v2-sp-3)); }
.v2-list.is-raised .v2-row:active { background: var(--v2-surface-sunken); box-shadow: none; border-radius: 0; }
.v2-row-body { min-width: 0; flex: 1; }
/* These are spans inside a span. Without an explicit block display the title
   and the subtitle share a line, and `overflow: hidden` silently does nothing
   on an inline box, so long names overflow instead of truncating. */
.v2-row-title, .v2-row-sub, .v2-row-amount, .v2-row-meta { display: block; }
.v2-row-title {
  font-size: var(--v2-fs-md);
  font-weight: 500;
  letter-spacing: -0.008em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Long Hebrew business names are the norm here, not the exception. Two lines
   then clamp: truncating at one line loses exactly the part that separates
   one branch of a chain from the next. */
.v2-row-title.is-2line {
  white-space: normal;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  line-height: 1.3;
}
.v2-row-sub {
  font-size: var(--v2-fs-xs);
  color: var(--v2-ink-faint);
  margin-top: 2px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.v2-row-end { margin-inline-start: auto; text-align: end; flex: none; padding-inline-start: var(--v2-sp-2); }
.v2-row-amount { font-size: var(--v2-fs-md); font-weight: 600; letter-spacing: -0.02em; white-space: nowrap; }
.v2-row-meta { font-size: var(--v2-fs-2xs); color: var(--v2-ink-faint); margin-top: 2px; white-space: nowrap; }
/* A 5px amber dot after the subtitle. A chip on every awaiting row would put a
   coloured badge on a third of the list and stop meaning anything; a dot is
   noticed while scanning and ignored otherwise. */
.v2-dot-flag {
  display: inline-block;
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--v2-warning);
  margin-inline-start: 6px;
  vertical-align: 1px;
}
.v2-row-chev { flex: none; color: var(--v2-ink-ghost); width: 18px; height: 18px; }
[dir="rtl"] .v2-row-chev { transform: scaleX(-1); }

/* --------------------------------------------------------------- avatar --- */
.v2-avatar {
  width: 40px; height: 40px;
  flex: none;
  border-radius: var(--v2-r-sm);
  display: grid; place-items: center;
  background: var(--v2-accent-tint);
  color: var(--v2-accent);
  font-size: var(--v2-fs-sm);
  font-weight: 600;
  letter-spacing: -0.01em;
  overflow: hidden;
}
.v2-avatar.is-round { border-radius: var(--v2-r-full); }
.v2-avatar.is-lg { width: 64px; height: 64px; font-size: var(--v2-fs-xl); border-radius: var(--v2-r-md); }
.v2-avatar.is-doc { background: var(--v2-surface-sunken); color: var(--v2-ink-faint); }
.v2-avatar.is-warn { background: var(--v2-warning-tint); color: var(--v2-warning); }
.v2-avatar svg { width: 20px; height: 20px; }
.v2-avatar.is-lg svg { width: 28px; height: 28px; }

/* ---------------------------------------------------------------- chips --- */
.v2-chip {
  display: inline-flex; align-items: center; gap: 4px;
  height: 22px;
  padding-inline: 8px;
  border-radius: var(--v2-r-full);
  background: var(--v2-surface-sunken);
  color: var(--v2-ink-soft);
  font-size: var(--v2-fs-2xs);
  font-weight: 500;
  white-space: nowrap;
}
.v2-chip.is-accent  { background: var(--v2-accent-tint);   color: var(--v2-accent); }
.v2-chip.is-pos     { background: var(--v2-positive-tint); color: var(--v2-positive); }
.v2-chip.is-warn    { background: var(--v2-warning-tint);  color: var(--v2-warning); }
.v2-chip.is-neg     { background: var(--v2-negative-tint); color: var(--v2-negative); }
.v2-chip-dot { width: 5px; height: 5px; border-radius: 50%; background: currentColor; flex: none; }

/* -------------------------------------------------------------- buttons --- */
.v2-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--v2-sp-2);
  min-height: 46px;
  padding-inline: var(--v2-sp-5);
  border-radius: var(--v2-r-sm);
  border: 1px solid transparent;
  background: var(--v2-accent);
  color: var(--v2-accent-ink);
  font-size: var(--v2-fs-md);
  font-weight: 500;
  cursor: pointer;
  transition: background var(--v2-dur-fast) var(--v2-ease), transform var(--v2-dur-fast) var(--v2-ease);
  -webkit-tap-highlight-color: transparent;
}
.v2-btn:active { transform: scale(0.985); background: var(--v2-accent-press); }
.v2-btn[disabled] { opacity: 0.45; pointer-events: none; }
.v2-btn.is-block { width: 100%; }
.v2-btn.is-quiet { background: var(--v2-surface); color: var(--v2-ink); border-color: var(--v2-line); }
.v2-btn.is-quiet:active { background: var(--v2-surface-sunken); }
.v2-btn.is-ghost { background: transparent; color: var(--v2-accent); }
.v2-btn.is-sm { min-height: 36px; font-size: var(--v2-fs-sm); padding-inline: var(--v2-sp-4); }
.v2-btn svg { width: 18px; height: 18px; }

/* ------------------------------------------------------------ attention --- */
/* The only place on Home allowed a tint, because it is the only place that is
   genuinely a call to act. */
/* Flat, like every other list on the screen. Version A put these rows in their
   own card directly above a flat activity list, so two adjacent sections were
   styled by different rules for no reason a reader could infer. The tinted
   icon still marks them as things to act on. */
.v2-attn { display: grid; border-top: 1px solid var(--v2-line-faint); }
.v2-attn-item {
  display: flex; align-items: center; gap: var(--v2-sp-3);
  min-height: 56px;
  padding: var(--v2-sp-3) 0;
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--v2-line-faint);
  width: 100%; text-align: start; cursor: pointer;
}
.v2-attn-item:active {
  background: var(--v2-bg-sunken);
  box-shadow: -12px 0 0 var(--v2-bg-sunken), 12px 0 0 var(--v2-bg-sunken);
}
.v2-attn-icon {
  width: 30px; height: 30px; flex: none;
  border-radius: var(--v2-r-xs);
  display: grid; place-items: center;
  background: var(--v2-warning-tint); color: var(--v2-warning);
}
.v2-attn-icon svg { width: 16px; height: 16px; }
.v2-attn-icon.is-accent { background: var(--v2-accent-tint); color: var(--v2-accent); }
.v2-attn-icon.is-neg { background: var(--v2-negative-tint); color: var(--v2-negative); }
.v2-attn-text { flex: 1; min-width: 0; font-size: var(--v2-fs-sm); font-weight: 500; }
.v2-attn-cta { font-size: var(--v2-fs-xs); color: var(--v2-accent); font-weight: 500; flex: none; }

/* --------------------------------------------------------------- search --- */
.v2-search { position: relative; margin-bottom: var(--v2-sp-3); }
.v2-search input {
  width: 100%;
  min-height: 44px;
  padding-inline: 42px var(--v2-sp-4);
  border-radius: var(--v2-r-sm);
  border: 1px solid var(--v2-line);
  background: var(--v2-surface);
  color: var(--v2-ink);
  font-family: var(--v2-font);
  font-size: var(--v2-fs-md);
}
.v2-search input::placeholder { color: var(--v2-ink-faint); }
.v2-search input:focus { border-color: var(--v2-accent); box-shadow: 0 0 0 3px var(--v2-accent-ring); }
.v2-search-icon {
  position: absolute;
  inset-inline-start: 13px;
  top: 50%;
  transform: translateY(-50%);
  width: 18px; height: 18px;
  color: var(--v2-ink-faint);
  pointer-events: none;
}

/* Segmented filter, scrollable. */
.v2-seg {
  display: flex; gap: var(--v2-sp-2);
  overflow-x: auto; scrollbar-width: none;
  margin-inline: calc(var(--v2-gutter) * -1);
  padding-inline: var(--v2-gutter);
  padding-block: 2px;
  margin-bottom: var(--v2-sp-3);
}
.v2-seg::-webkit-scrollbar { display: none; }

/* ---------------------------------------------------------------- sheet --- */
.v2-sheet-ov {
  position: fixed; inset: 0; z-index: 100;
  background: rgba(23, 28, 34, 0.42);
  display: flex; align-items: flex-end; justify-content: center;
  animation: v2-fade var(--v2-dur) var(--v2-ease);
}
.v2-sheet {
  width: 100%;
  max-width: var(--v2-max-w);
  background: var(--v2-surface);
  border-radius: var(--v2-r-xl) var(--v2-r-xl) 0 0;
  padding: var(--v2-sp-3) var(--v2-gutter) calc(var(--v2-sp-5) + var(--v2-safe-b));
  max-height: 88dvh;
  overflow-y: auto;
  animation: v2-rise var(--v2-dur-sheet) var(--v2-ease);
}
.v2-sheet-grip { width: 36px; height: 4px; border-radius: var(--v2-r-xs); background: var(--v2-line-strong); margin: 0 auto var(--v2-sp-4); }
.v2-sheet-title { font-size: var(--v2-fs-lg); font-weight: 600; margin-bottom: var(--v2-sp-3); }
/* Seven flat rows spanning three unrelated kinds of action needed reading.
   Grouped under quiet headings they can be scanned. */
.v2-sheet-group { margin-top: var(--v2-sp-4); }
.v2-sheet-group:first-of-type { margin-top: var(--v2-sp-1); }
.v2-sheet-group-title {
  font-size: var(--v2-fs-xs);
  font-weight: 500;
  letter-spacing: 0.02em;
  color: var(--v2-ink-faint);
  padding-inline: var(--v2-sp-2);
  margin-bottom: var(--v2-sp-1);
}
/* The sheet takes focus itself. Focusing the first ITEM painted a focus ring
   on it, so the sheet opened looking as though something was already chosen. */
.v2-sheet:focus { outline: none; }
.v2-sheet-item {
  display: flex; align-items: center; gap: var(--v2-sp-3);
  width: 100%; min-height: 54px;
  padding: var(--v2-sp-2);
  border: 0; background: transparent; cursor: pointer; text-align: start;
  border-radius: var(--v2-r-sm);
}
.v2-sheet-item:active { background: var(--v2-surface-sunken); }
.v2-sheet-icon {
  width: 38px; height: 38px; flex: none;
  border-radius: var(--v2-r-xs);
  background: var(--v2-accent-tint); color: var(--v2-accent);
  display: grid; place-items: center;
}
.v2-sheet-icon svg { width: 19px; height: 19px; }
/* Block, for the same reason as the list rows: these are spans inside a span,
   and left inline the label and its description share a line. */
.v2-sheet-label { display: block; font-size: var(--v2-fs-md); font-weight: 500; }
.v2-sheet-desc { display: block; font-size: var(--v2-fs-xs); color: var(--v2-ink-faint); margin-top: 1px; }

@keyframes v2-fade { from { opacity: 0 } to { opacity: 1 } }
@keyframes v2-rise { from { transform: translateY(14px); opacity: 0.6 } to { transform: none; opacity: 1 } }
@keyframes v2-pop  { from { transform: scale(0.97); opacity: 0 } to { transform: none; opacity: 1 } }

/* On a wide screen a sheet is a dialog, not a sheet — a strip glued to the
   bottom of a 1400px window is a phone pattern misapplied. */
@media (min-width: 560px) and (min-height: 560px) {
  .v2-sheet-ov { align-items: center; }
  .v2-sheet {
    border-radius: var(--v2-r-xl);
    max-width: 460px;
    padding-bottom: var(--v2-sp-5);
    animation: v2-pop var(--v2-dur) var(--v2-ease);
  }
}

/* --------------------------------------------------------------- states --- */
.v2-empty {
  text-align: center;
  padding: var(--v2-sp-8) var(--v2-sp-5);
  background: var(--v2-surface);
  border-radius: var(--v2-r-lg);
  box-shadow: var(--v2-shadow-sm);
}
.v2-empty-icon {
  width: 52px; height: 52px;
  margin: 0 auto var(--v2-sp-4);
  border-radius: var(--v2-r-md);
  background: var(--v2-accent-tint);
  color: var(--v2-accent);
  display: grid; place-items: center;
}
.v2-empty-icon svg { width: 24px; height: 24px; }
.v2-empty-title { font-size: var(--v2-fs-lg); font-weight: 600; margin-bottom: var(--v2-sp-2); }
/* An empty state exists to say what happens next. A shrug in a box is worse
   than nothing, so this text is always a sentence about the next event. */
.v2-empty-text { font-size: var(--v2-fs-sm); color: var(--v2-ink-soft); line-height: 1.5; max-width: 34ch; margin: 0 auto; }
.v2-empty-actions { margin-top: var(--v2-sp-5); display: flex; gap: var(--v2-sp-2); justify-content: center; flex-wrap: wrap; }

.v2-skel {
  background: linear-gradient(100deg, var(--v2-bg-sunken) 30%, var(--v2-surface-sunken) 50%, var(--v2-bg-sunken) 70%);
  background-size: 220% 100%;
  animation: v2-shimmer 1.4s linear infinite;
  border-radius: var(--v2-r-xs);
}
@keyframes v2-shimmer { from { background-position: 180% 0 } to { background-position: -20% 0 } }
@media (prefers-reduced-motion: reduce) { .v2-skel { animation: none; } }
.v2-skel-card { height: 190px; border-radius: var(--v2-r-lg); }

.v2-error {
  text-align: center;
  padding: var(--v2-sp-7) var(--v2-sp-5);
  background: var(--v2-surface);
  border-radius: var(--v2-r-lg);
  box-shadow: var(--v2-shadow-sm);
}
.v2-error-title { font-size: var(--v2-fs-md); font-weight: 600; margin-bottom: var(--v2-sp-2); }
.v2-error-text { font-size: var(--v2-fs-sm); color: var(--v2-ink-soft); margin-bottom: var(--v2-sp-4); }

/* ---------------------------------------------------------------- toast --- */
.v2-toast {
  position: fixed;
  inset-inline: var(--v2-gutter);
  bottom: calc(var(--v2-nav-h) + var(--v2-safe-b) + var(--v2-sp-3));
  z-index: 120;
  margin-inline: auto;
  max-width: 420px;
  background: var(--v2-surface-inverse);
  color: var(--v2-ink-on-dark);
  padding: var(--v2-sp-3) var(--v2-sp-4);
  border-radius: var(--v2-r-sm);
  font-size: var(--v2-fs-sm);
  box-shadow: var(--v2-shadow-lg);
  animation: v2-rise var(--v2-dur) var(--v2-ease);
}

/* -------------------------------------------------------------- profile --- */
/* No card. The identity block IS the top of the screen — wrapping it in a
   surface only put a box around the page title. */
.v2-profile-head {
  display: flex; align-items: center; gap: var(--v2-sp-4);
  padding: var(--v2-sp-2) 0 var(--v2-sp-5);
}
.v2-profile-name { font-size: var(--v2-fs-xl); font-weight: 600; letter-spacing: -0.02em; line-height: 1.2; }
.v2-profile-meta { font-size: var(--v2-fs-sm); color: var(--v2-ink-faint); margin-top: 3px; }
.v2-profile-chips { display: flex; gap: var(--v2-sp-2); margin-top: var(--v2-sp-2); flex-wrap: wrap; }

/* A definition list that stays readable when a value is long. Flat, with
   hairlines — the same rhythm as the row lists, so facts and documents on the
   same screen belong to one language. */
.v2-facts { display: grid; border-top: 1px solid var(--v2-line-faint); }
.v2-fact {
  display: flex; gap: var(--v2-sp-4);
  padding: var(--v2-sp-3) 0;
  font-size: var(--v2-fs-sm);
  border-bottom: 1px solid var(--v2-line-faint);
}
.v2-card .v2-facts { border-top: 0; }
.v2-card .v2-fact { padding-inline: var(--v2-sp-4); }
.v2-card .v2-fact:last-child { border-bottom: 0; }
.v2-fact-k { color: var(--v2-ink-faint); flex: none; min-width: 34%; }
.v2-fact-v { margin-inline-start: auto; text-align: end; font-weight: 500; min-width: 0; overflow-wrap: anywhere; }

/* The one raised surface on a profile screen: what this relationship is
   worth, how much of it there is, and when it last moved. Everything else on
   the screen sits on the ground, so this reads as the answer to "what
   matters?" rather than as one more block. */
.v2-stats {
  display: grid; grid-template-columns: repeat(3, 1fr);
  background: var(--v2-surface);
  border-radius: var(--v2-r-lg);
  box-shadow: var(--v2-shadow-md);
  overflow: hidden;
}
.v2-stats.is-2 { grid-template-columns: repeat(2, 1fr); }
.v2-stat { padding: var(--v2-sp-4) var(--v2-sp-3); text-align: center; border-inline-start: 1px solid var(--v2-line-faint); }
.v2-stat:first-child { border-inline-start: 0; }
.v2-stat-v { display: block; font-size: var(--v2-fs-lg); font-weight: 600; letter-spacing: -0.02em; line-height: 1.2; }
/* The money cell leads. The other two are context for it. */
.v2-stat.is-lead .v2-stat-v { font-size: var(--v2-fs-2xl); letter-spacing: -0.03em; }
.v2-stat-k { display: block; font-size: var(--v2-fs-2xs); color: var(--v2-ink-faint); margin-top: 3px; }

/* Business hub tiles. */
.v2-hub { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--v2-sp-3); }
.v2-hub-tile {
  background: var(--v2-surface);
  border-radius: var(--v2-r-lg);
  box-shadow: var(--v2-shadow-sm);
  padding: var(--v2-sp-4);
  border: 0; text-align: start; cursor: pointer;
  display: flex; flex-direction: column; gap: var(--v2-sp-3);
  min-height: 108px;
}
.v2-hub-tile:active { background: var(--v2-surface-sunken); }
.v2-hub-icon { width: 34px; height: 34px; border-radius: var(--v2-r-xs); background: var(--v2-accent-tint); color: var(--v2-accent); display: grid; place-items: center; }
.v2-hub-icon svg { width: 18px; height: 18px; }
.v2-hub-name { font-size: var(--v2-fs-md); font-weight: 500; display: block; }
/* block, not inline: as an inline span the count ran straight into the label
   and "91 suppliers" rendered as "ספקים91". */
.v2-hub-count { font-size: var(--v2-fs-xs); color: var(--v2-ink-faint); margin-top: 2px; display: block; }

/* -------------------------------------------------------- document money -- */
/* The total is the reason the screen exists. In Version A it was rendered
   identically to its own components — before-VAT and VAT sat above it at the
   same size and weight, so nothing on the screen answered "how much was
   this?" faster than reading three rows. */
.v2-amount {
  background: var(--v2-surface);
  border-radius: var(--v2-r-lg);
  box-shadow: var(--v2-shadow-md);
  padding: var(--v2-sp-5);
}
.v2-amount-k { font-size: var(--v2-fs-sm); color: var(--v2-ink-soft); font-weight: 500; }
.v2-amount-v {
  display: block;
  margin-top: var(--v2-sp-1);
  font-size: var(--v2-fs-4xl);
  font-weight: 600;
  letter-spacing: -0.035em;
  line-height: 1.05;
}
/* The breakdown is support, not a peer. */
.v2-amount-parts {
  display: flex; gap: var(--v2-sp-5);
  margin-top: var(--v2-sp-4);
  padding-top: var(--v2-sp-3);
  border-top: 1px solid var(--v2-line-faint);
}
.v2-amount-part { font-size: var(--v2-fs-xs); color: var(--v2-ink-faint); }
.v2-amount-part b {
  display: block;
  font-size: var(--v2-fs-sm);
  font-weight: 500;
  color: var(--v2-ink-soft);
  margin-top: 1px;
}

/* ------------------------------------------------------------- timeline --- */
.v2-tl { position: relative; padding-inline-start: var(--v2-sp-6); }
.v2-tl::before {
  content: ''; position: absolute;
  inset-inline-start: 9px; top: 8px; bottom: 8px;
  width: 1px; background: var(--v2-line);
}
.v2-tl-item { position: relative; padding-block: var(--v2-sp-3); }
.v2-tl-item::before {
  content: ''; position: absolute;
  inset-inline-start: calc(var(--v2-sp-6) * -1 + 6px);
  top: 20px;
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--v2-accent-quiet);
  box-shadow: 0 0 0 3px var(--v2-surface);
}
.v2-tl-title { font-size: var(--v2-fs-sm); font-weight: 500; }
.v2-tl-sub { font-size: var(--v2-fs-xs); color: var(--v2-ink-faint); margin-top: 1px; }

/* ------------------------------------------------------------ utilities --- */
.v2-stack   { display: grid; gap: var(--v2-sp-3); }
.v2-stack-2 { display: grid; gap: var(--v2-sp-2); }
.v2-mt-4    { margin-top: var(--v2-sp-4); }
.v2-muted   { color: var(--v2-ink-faint); }
.v2-small   { font-size: var(--v2-fs-xs); }
.v2-hr      { height: 1px; background: var(--v2-line-faint); border: 0; margin: var(--v2-sp-4) 0; }

/* ------------------------------------------------------------ disclosure -- */
/* "Technical details" is a real affordance, not a link. It gets a row-sized
   target and a marker that says which way it opens. */
.v2-disclosure {
  cursor: pointer;
  list-style: none;
  display: flex; align-items: center; gap: var(--v2-sp-2);
  min-height: 44px;
  font-size: var(--v2-fs-sm);
  font-weight: 500;
  color: var(--v2-ink-soft);
}
.v2-disclosure::-webkit-details-marker { display: none; }
.v2-disclosure::after {
  content: '';
  width: 7px; height: 7px;
  border-inline-end: 1.6px solid var(--v2-ink-ghost);
  border-bottom: 1.6px solid var(--v2-ink-ghost);
  transform: translateY(-2px) rotate(45deg);
  transition: transform var(--v2-dur) var(--v2-ease);
}
details[open] > .v2-disclosure::after { transform: translateY(1px) rotate(-135deg); }

/* --------------------------------------------------------- review fields -- */
/* One card per open question, because each is a separate decision the user
   makes and dismisses. A fact row would imply it is only information. */
.v2-rev-field {
  background: var(--v2-surface);
  border-radius: var(--v2-r-md);
  box-shadow: var(--v2-shadow-sm);
  padding: var(--v2-sp-4);
}
.v2-rev-field-k { font-size: var(--v2-fs-xs); color: var(--v2-ink-faint); }
.v2-rev-field-v {
  font-size: var(--v2-fs-lg);
  font-weight: 500;
  letter-spacing: -0.015em;
  margin-top: 3px;
  overflow-wrap: anywhere;
}
.v2-rev-field-actions { display: flex; gap: var(--v2-sp-2); margin-top: var(--v2-sp-4); }
.v2-rev-field-actions .v2-btn { flex: 1; }

/* A quiet pencil on an accepted fact: correctable, without inviting it. */
.v2-fact-edit {
  flex: none;
  width: 32px; height: 32px;
  margin: -6px -6px -6px var(--v2-sp-2);
  border: 0; background: transparent; cursor: pointer;
  color: var(--v2-ink-faint);
  display: grid; place-items: center;
  border-radius: var(--v2-r-xs);
}
.v2-fact-edit:active { background: var(--v2-bg-sunken); color: var(--v2-accent); }
.v2-fact-edit svg { width: 15px; height: 15px; }

/* ==========================================================================
   ADAPTIVE — document workspace, and the desktop posture of the shell.

   Everything above this line is the phone. Everything below it is the same
   product deciding, at three widths, how much room it actually has.

   The rule the rest of this file follows: information architecture does not
   change with width. The same routes, the same destinations, the same
   endpoints. Only the presentation adapts.
   ========================================================================== */

/* ---------------------------------------------------- document workspace ---
   One component serves the document screen and the review screen at every
   width, because they are the same task seen from two directions: "what is
   this document" and "what does Mailo still need". Mobile stacks the panes;
   desktop puts them side by side so the eye can compare the source against
   the extracted values without a navigation in between. */
.v2-ws { display: block; }

.v2-ws-src { margin-bottom: var(--v2-sp-5); }

/* The frame is a fixed box the source fills, rather than a box that grows to
   whatever the source happens to be. A 14-page PDF and a phone photo of a
   receipt have to occupy the same slot or the screen reflows under the user
   every time they open a different document. */
.v2-srcframe {
  position: relative;
  height: var(--v2-src-h);
  min-height: 200px;
  border: 1px solid var(--v2-line);
  border-radius: var(--v2-r-md);
  overflow: hidden;
  background: var(--v2-bg-sunken);
}
.v2-srcframe > iframe,
.v2-srcframe > img {
  width: 100%; height: 100%;
  border: 0; display: block;
}
/* contain, never cover: a cropped invoice is a wrong invoice. */
.v2-srcframe > img {
  object-fit: contain;
  background: var(--v2-surface);
  transition: transform var(--v2-dur) var(--v2-ease);
  transform-origin: center center;
}
.v2-srcframe.is-zoomed { overflow: auto; }
.v2-srcframe.is-zoomed > img { object-fit: none; object-position: center; }

/* Quiet controls. The document is the content; the controls are not. */
.v2-src-bar {
  display: flex;
  align-items: center;
  gap: var(--v2-sp-2);
  padding: var(--v2-sp-2) 0 0;
  flex-wrap: wrap;
}
.v2-src-bar-end { margin-inline-start: auto; display: flex; gap: var(--v2-sp-2); }

.v2-iconbtn {
  width: 36px; height: 36px;
  display: grid; place-items: center;
  border: 1px solid var(--v2-line);
  background: var(--v2-surface);
  color: var(--v2-ink-soft);
  border-radius: var(--v2-r-sm);
  cursor: pointer;
  transition: background var(--v2-dur-fast) var(--v2-ease), color var(--v2-dur-fast) var(--v2-ease);
}
.v2-iconbtn:hover { background: var(--v2-bg-sunken); color: var(--v2-ink); }
.v2-iconbtn:disabled { opacity: 0.4; cursor: default; }
.v2-iconbtn svg { width: 18px; height: 18px; }
.v2-src-page {
  font-size: var(--v2-fs-xs);
  color: var(--v2-ink-faint);
  font-variant-numeric: tabular-nums;
  min-width: 4ch; text-align: center;
}

/* Preview that could not be shown. The details must stay usable, so this is a
   panel inside the workspace and never an error state for the whole screen. */
.v2-src-fallback {
  height: 100%;
  display: grid; place-content: center; justify-items: center;
  gap: var(--v2-sp-3);
  padding: var(--v2-sp-6);
  text-align: center;
  color: var(--v2-ink-faint);
}
.v2-src-fallback svg { width: 28px; height: 28px; }
.v2-src-fallback-text { font-size: var(--v2-fs-sm); max-width: 30ch; line-height: var(--v2-lh-body); }

/* --------------------------------------------------------- field rows ----- */
/* A value, and the one control that changes it. The warning that belongs to a
   field lives ON the field — a banner at the top of the screen tells the user
   that something is wrong and then makes them hunt for it. */
.v2-fields { display: block; }

.v2-fieldrow {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--v2-sp-3);
  padding: 12px 12px;
  border-radius: var(--v2-r-sm);
  border: 1px solid transparent;
  transition: background var(--v2-dur-fast) var(--v2-ease);
}
.v2-fieldrow + .v2-fieldrow { box-shadow: inset 0 1px 0 var(--v2-line-faint); }
.v2-fieldrow:hover { background: var(--v2-surface-sunken); }
/* Key over value, not key beside value: these are spans, so without an
   explicit block they collapse onto one line and the label runs into the
   number it labels. */
.v2-fieldrow-k {
  display: block;
  font-size: var(--v2-fs-xs);
  color: var(--v2-ink-faint);
  margin-bottom: 3px;
}
.v2-fieldrow-v {
  display: block;
  font-size: var(--v2-fs-md);
  font-weight: 500;
  overflow-wrap: anywhere;
}
.v2-fieldrow-v.is-missing { color: var(--v2-ink-faint); font-weight: 400; }
.v2-fieldrow-actions { display: flex; gap: var(--v2-sp-2); align-items: center; }

/* The field Mailo is unsure about. Amber edge plus a sentence, so the reason
   and the field are one object rather than two things to correlate. */
.v2-fieldrow.is-attn {
  background: var(--v2-warning-tint);
  border-color: color-mix(in oklab, var(--v2-warning) 22%, transparent);
  box-shadow: none;
}
.v2-fieldrow.is-attn + .v2-fieldrow { box-shadow: none; }
.v2-fieldrow-note {
  grid-column: 1 / -1;
  display: flex; align-items: flex-start; gap: 7px;
  font-size: var(--v2-fs-xs);
  color: var(--v2-warning);
  line-height: 1.45;
  margin-top: 2px;
}
.v2-fieldrow-note svg { width: 15px; height: 15px; flex: none; margin-top: 1px; }

/* Inline editor. Replaces the value in place: the user keeps looking at the
   same row, beside the same source document. */
.v2-fieldedit { grid-column: 1 / -1; display: grid; gap: var(--v2-sp-3); }
.v2-input {
  width: 100%;
  font: inherit;
  font-size: var(--v2-fs-md);
  color: var(--v2-ink);
  background: var(--v2-surface);
  border: 1px solid var(--v2-line-strong);
  border-radius: var(--v2-r-sm);
  padding: 11px 13px;
}
.v2-input:focus { outline: 2px solid var(--v2-accent-ring); outline-offset: 1px; border-color: var(--v2-accent); }
select.v2-input { appearance: auto; }
.v2-fieldedit-row { display: flex; gap: var(--v2-sp-2); flex-wrap: wrap; }
.v2-fieldedit-hint { font-size: var(--v2-fs-2xs); color: var(--v2-ink-faint); }

/* ------------------------------------------------------------ full screen -- */
.v2-fs {
  position: fixed; inset: 0; z-index: 90;
  background: rgba(23, 28, 34, 0.94);
  display: flex; flex-direction: column;
}
.v2-fs-bar {
  display: flex; align-items: center; gap: var(--v2-sp-3);
  padding: var(--v2-sp-3) var(--v2-sp-4);
  padding-top: calc(var(--v2-safe-t) + var(--v2-sp-3));
  color: #fff;
}
.v2-fs-title {
  font-size: var(--v2-fs-sm); font-weight: 500;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  min-width: 0;
}
.v2-fs-bar .v2-iconbtn {
  background: rgba(255, 255, 255, 0.12);
  border-color: rgba(255, 255, 255, 0.22);
  color: #fff;
}
.v2-fs-bar .v2-iconbtn:hover { background: rgba(255, 255, 255, 0.2); color: #fff; }
.v2-fs-body { flex: 1; min-height: 0; position: relative; overflow: auto; }
.v2-fs-body > iframe { width: 100%; height: 100%; border: 0; display: block; background: #fff; }
.v2-fs-body > img { display: block; margin: auto; max-width: 100%; max-height: 100%; object-fit: contain; }

/* ------------------------------------------------------- workspace header -- */
/* Identity, and the actions that apply to the whole document. Deliberately
   lighter than the old screen, where one solid full-width button outweighed
   the document it acted on. */
.v2-ws-head { display: flex; align-items: flex-start; gap: var(--v2-sp-3); margin-bottom: var(--v2-sp-4); }
.v2-ws-actions { display: flex; gap: var(--v2-sp-2); flex-wrap: wrap; margin-top: var(--v2-sp-5); }
.v2-ws-locked {
  display: flex; align-items: center; gap: var(--v2-sp-2);
  font-size: var(--v2-fs-xs); color: var(--v2-ink-faint);
  padding: 10px 12px;
  background: var(--v2-bg-sunken);
  border-radius: var(--v2-r-sm);
}
.v2-ws-locked svg { width: 16px; height: 16px; flex: none; }

/* Previous / next while working through the review queue. */
.v2-ws-nav { display: flex; align-items: center; gap: var(--v2-sp-2); }
.v2-ws-nav-pos { font-size: var(--v2-fs-xs); color: var(--v2-ink-faint); font-variant-numeric: tabular-nums; }

/* ======================================================= 768px and up ======
   Still one column and still a bottom bar — a tablet is held, not driven by a
   mouse — but the column stops being phone-width and the source gets room. */
@media (min-width: 768px) {
  :root {
    --v2-max-w: 900px;
    --v2-gutter: 28px;
    --v2-src-h: 52dvh;
  }
}

/* ======================================================= 1024px and up =====
   Desktop posture. The bottom bar becomes a side rail, and the workspace
   becomes two panes. */
@media (min-width: 1024px) {
  :root { --v2-src-h: calc(100dvh - var(--v2-header-h) - 132px); }

  /* The app stops being a centred phone column. It takes the window, minus
     the rail, and each screen decides its own comfortable measure below. */
  .v2-app {
    max-width: none;
    margin-inline: 0;
    padding-inline-start: var(--v2-rail-w);
  }

  /* Ordinary screens keep a readable measure. The workspace opts out. */
  .v2-header-in,
  .v2-main > * { max-width: var(--v2-content-w); margin-inline: auto; }
  /* Gutters earn their width. On a 1024 laptop they are the difference
     between a readable source pane and a cramped one. */
  .v2-main { padding-inline: var(--v2-sp-5); padding-bottom: var(--v2-sp-9); }
  .v2-header-in { width: 100%; padding-inline: var(--v2-sp-5); }

  /* -------------------------------------------------------------- rail --- */
  /* Same five destinations, same handlers, same routes — presented for a
     mouse and a tall screen instead of a thumb. */
  .v2-nav {
    inset-block: 0;
    bottom: auto;
    inset-inline-start: 0;
    inset-inline-end: auto;
    width: var(--v2-rail-w);
    max-width: none;
    margin-inline: 0;
    height: 100dvh;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 2px;
    padding: var(--v2-sp-5) var(--v2-sp-3);
    padding-bottom: var(--v2-sp-6);
    background: var(--v2-surface);
    border-inline-end: 1px solid var(--v2-line);
    box-shadow: none;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }

  .v2-tab {
    flex-direction: row;
    justify-content: flex-start;
    align-items: center;
    gap: 11px;
    min-height: 42px;
    padding-inline: 11px;
    border-radius: var(--v2-r-sm);
    font-size: var(--v2-fs-sm);
    text-align: start;
  }
  .v2-tab:hover { background: var(--v2-bg-sunken); color: var(--v2-ink); }
  .v2-tab[aria-current="page"] { background: var(--v2-accent-tint); }
  .v2-tab[aria-current="page"] .v2-tab-icon { background: transparent; }
  .v2-tab-icon { width: 22px; height: 22px; flex: none; }
  .v2-tab-label { flex: 1; }

  /* The New action leads the rail rather than sitting in its middle: on a
     desktop there is no thumb reach to design around, and a primary action
     belongs at the top of a vertical list. */
  .v2-tab-center {
    order: -1;
    margin-bottom: var(--v2-sp-4);
    background: var(--v2-accent);
    color: var(--v2-accent-ink);
    min-height: 42px;
    border-radius: var(--v2-r-sm);
  }
  .v2-tab-center:hover { background: var(--v2-accent-hover); color: var(--v2-accent-ink); }
  .v2-tab-center .v2-fab {
    width: 22px; height: 22px;
    margin-top: 0;
    background: transparent;
    box-shadow: none;
    color: inherit;
  }
  .v2-tab-center .v2-fab svg { width: 20px; height: 20px; }
  .v2-tab-center .v2-tab-label { margin-top: 0; font-weight: 600; }
  .v2-tab-center:active .v2-fab { transform: none; background: transparent; }

  /* In a vertical rail the badge belongs at the end of its row, not centred
     over an icon. */
  .v2-tab-badge {
    position: static;
    inset-inline-start: auto;
    top: auto;
    border: 0;
    margin-inline-start: auto;
  }

  /* ---------------------------------------------------------- workspace -- */
  /* Roughly 56 / 44, expressed as a RATIO rather than as a floor on the
     details pane. A floor of 380px looked right at 1440 and inverted the whole
     layout at 1024: the rail and the gutters take their cut first, and what
     was left went to the details, leaving the source — the pane the screen
     exists for — narrower than the list beside it. A ratio degrades in
     proportion instead, and the 300px floor only ever engages on the narrowest
     two-pane window. */
  .v2-main > .v2-ws { max-width: var(--v2-ws-w); }

  .v2-ws {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(300px, 0.78fr);
    gap: var(--v2-ws-gap);
    align-items: start;
  }

  /* The source stays put while the fields scroll. It is the reference the
     user keeps looking back at, so it is the half that must not move. */
  .v2-ws-src {
    position: sticky;
    top: calc(var(--v2-header-h) + var(--v2-sp-4));
    margin-bottom: 0;
  }
  .v2-ws-info { min-width: 0; }
  .v2-ws-info > .v2-section:first-child { margin-top: 0; }
}

/* ======================================================= 1280px and up ===== */
@media (min-width: 1280px) {
  .v2-main { padding-inline: var(--v2-sp-7); }
  .v2-header-in { padding-inline: var(--v2-sp-7); }
}

/* ======================================================= 1440px and up ===== */
@media (min-width: 1440px) {
  :root { --v2-rail-w: 248px; --v2-ws-gap: 32px; }
  .v2-main { padding-inline: var(--v2-sp-8); }
  .v2-header-in { padding-inline: var(--v2-sp-8); }
}

/* A mouse gets hover affordances; a touch screen must not keep them stuck on
   after a tap. */
@media (hover: none) {
  .v2-fieldrow:hover { background: transparent; }
  .v2-iconbtn:hover { background: var(--v2-surface); color: var(--v2-ink-soft); }
}

/* Placeholder inside the collapsed technical disclosure. Deliberately NOT
   .v2-skel: the screenshot harness treats a skeleton anywhere on the page as
   "still loading", and a permanently-present one inside a closed <details>
   would make every capture report a timeout on a fully rendered screen. */
.v2-techph { border-radius: var(--v2-r-sm); background: var(--v2-bg-sunken); }

/* The linked financial group. The three numbers sit together so the eye can
   check them against the source in one pass, and the group carries ONE pair of
   actions instead of three. */
.v2-amtgroup .v2-amt-lines { display: block; margin-top: 2px; }
.v2-amt-line {
  display: flex; align-items: baseline; gap: var(--v2-sp-3);
  padding: 3px 0;
}
.v2-amt-k { font-size: var(--v2-fs-xs); color: var(--v2-ink-faint); min-width: 7ch; }
.v2-amt-v { font-size: var(--v2-fs-md); font-weight: 500; margin-inline-start: auto; }
.v2-amt-v.is-missing { color: var(--v2-ink-faint); font-weight: 400; font-size: var(--v2-fs-sm); }
/* The total is the line people look for. */
.v2-amt-line:last-child .v2-amt-v { font-weight: 600; }
.v2-amt-line:last-child { border-top: 1px solid color-mix(in oklab, var(--v2-warning) 20%, transparent); padding-top: 6px; margin-top: 3px; }

/* An inline text control inside a caption line — the way out of a scoped view. */
.v2-linkbtn {
  border: 0; background: none; padding: 0; cursor: pointer;
  font: inherit; color: var(--v2-accent); text-decoration: underline;
}

/* ---------------------------------------------------------- connections ----
   One card shape for every integration: mark, name with its state chip, one
   plain sentence, and at most one action. The card is a grid rather than a row
   so the action sits below the text on a phone and beside it on a desktop —
   the same card, not a second layout. */
.v2-conn {
  display: grid;
  gap: var(--v2-sp-3);
  padding: var(--v2-sp-4);
  border: 1px solid var(--v2-line-faint);
  border-radius: var(--v2-r-md);
  background: var(--v2-surface);
}
.v2-conn.is-attn { border-color: var(--v2-warning); background: var(--v2-warning-tint); }
.v2-conn-top { display: flex; gap: var(--v2-sp-3); align-items: flex-start; }
.v2-conn-id { display: grid; gap: 2px; min-width: 0; }
.v2-conn-name {
  display: flex; gap: var(--v2-sp-2); align-items: center; flex-wrap: wrap;
  font-weight: 600; font-size: var(--v2-fs-sm);
}
.v2-conn-desc { font-size: var(--v2-fs-sm); color: var(--v2-text-soft); }
.v2-conn-meta { word-break: break-word; }
.v2-conn-act { display: flex; justify-content: flex-start; }

@media (min-width: 640px) {
  /* Wide enough for the action to sit on the same line as the identity. */
  .v2-conn { grid-template-columns: minmax(0, 1fr) auto; align-items: center; }
  .v2-conn-act { justify-content: flex-end; }
}

/* ----------------------------------------------------- relevance question --
   Is this file business paperwork at all? The first question on an ambiguous
   document, and the only one worth asking until it is answered.

   It gets its own block rather than reusing `.v2-fieldrow`. That was the first
   attempt and it broke at 375px: a field row is a two-column grid (value,
   control), so the buttons were placed into the auto column, collapsed to zero
   width and overlapped the sentence below them. A document-level decision is
   not a field row — it is a stacked card — so it says so. */
.v2-relq {
  display: grid;
  gap: var(--v2-sp-3);
  padding: 12px;
  border-radius: var(--v2-r-sm);
  border: 1px solid var(--v2-warning);
  background: var(--v2-warning-tint);
}
.v2-relq-note {
  display: flex; align-items: flex-start; gap: 7px;
  font-size: var(--v2-fs-xs);
  color: var(--v2-warning);
  line-height: 1.45;
}
.v2-relq-note svg { width: 15px; height: 15px; flex: none; margin-top: 1px; }
/* Two real answers, side by side, wrapping to two rows only if they must. */
.v2-relq-actions { display: flex; gap: var(--v2-sp-2); flex-wrap: wrap; margin: 0; }
.v2-relq-actions .v2-btn { flex: 1 1 auto; justify-content: center; }
.v2-relq-after { font-size: var(--v2-fs-xs); color: var(--v2-ink-faint); line-height: 1.45; }

/* The already-excluded variant: a statement plus one way back, no alarm tint. */
.v2-relq.is-settled {
  border-color: var(--v2-line-faint);
  background: var(--v2-bg-sunken);
}
.v2-relq.is-settled .v2-relq-note { color: var(--v2-ink-soft); }

/* Why a field was NOT questioned. The positive counterpart of the amber
   attention note: same placement, calm colour, and only ever shown where the
   server said an official identifier proved the identity. */
.v2-fieldrow-proof {
  grid-column: 1 / -1;
  display: flex; align-items: flex-start; gap: 7px;
  font-size: var(--v2-fs-xs);
  color: var(--v2-positive);
  line-height: 1.45;
  margin-top: 2px;
}
.v2-fieldrow-proof svg { width: 14px; height: 14px; flex: none; margin-top: 1px; }

/* ------------------------------------------------- document numbering ------
   One card per series that can still be configured. Stacked rather than a
   row-with-control, because the input needs a full line at 375px and the live
   "Mailo will issue N next" line has to sit directly under what it answers. */
.v2-seq {
  display: grid;
  gap: var(--v2-sp-3);
  padding: var(--v2-sp-4);
  border: 1px solid var(--v2-line-faint);
  border-radius: var(--v2-r-md);
  background: var(--v2-surface);
}
.v2-seq-head { display: flex; gap: var(--v2-sp-2); align-items: center; flex-wrap: wrap; }
.v2-seq-name { font-weight: 600; font-size: var(--v2-fs-sm); }
.v2-seq-field { display: grid; gap: 4px; }
.v2-seq-act { display: flex; justify-content: flex-start; }
@media (min-width: 640px) { .v2-seq-act { justify-content: flex-end; } }

/* ============================================================== ISSUING ====
   Mobile is a stepped form with a sticky action; desktop puts the form beside
   a live preview of the real document. Same data, same endpoints — what
   changes is how much of the decision is on screen at once. */
.v2-iss { display: grid; gap: var(--v2-sp-4); }
.v2-iss-form { min-width: 0; }
.v2-iss-side { min-width: 0; display: grid; gap: var(--v2-sp-4); align-content: start; }

/* The step rail. Numbered because the flow is ordered, and tappable because a
   user who wants to go back to the customer should not have to step there. */
.v2-iss-steps {
  display: flex; gap: var(--v2-sp-2); overflow-x: auto;
  padding: 2px 2px var(--v2-sp-3);
  scrollbar-width: none;
}
.v2-iss-steps::-webkit-scrollbar { display: none; }
.v2-iss-step {
  display: flex; align-items: center; gap: 6px; flex: none;
  padding: 6px 10px; border-radius: 999px;
  border: 1px solid var(--v2-line-faint);
  background: var(--v2-surface); color: var(--v2-ink-soft);
  font-size: var(--v2-fs-xs); cursor: pointer;
}
.v2-iss-step.is-now { border-color: var(--v2-accent); color: var(--v2-accent); font-weight: 600; }
.v2-iss-step.is-done { color: var(--v2-positive); border-color: var(--v2-positive); }
.v2-iss-step-n {
  display: grid; place-items: center; width: 18px; height: 18px;
  border-radius: 50%; background: currentColor; color: var(--v2-surface);
  font-size: 10px; font-weight: 700;
}

.v2-iss-field { display: grid; gap: 4px; margin-bottom: var(--v2-sp-3); }
.v2-iss-grid { display: grid; gap: var(--v2-sp-3); }

/* A line: description on its own row, then the numbers in a row that can wrap
   without the price field becoming unusable at 375px. */
.v2-iss-line {
  position: relative;
  padding: var(--v2-sp-4);
  border: 1px solid var(--v2-line-faint);
  border-radius: var(--v2-r-md);
  background: var(--v2-surface);
}
.v2-iss-line-nums {
  display: grid; gap: var(--v2-sp-3);
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr);
  align-items: end;
}
.v2-iss-line-sum {
  grid-column: 1 / -1;
  font-weight: 600; text-align: start;
}
.v2-iss-line-del { position: absolute; inset-inline-end: 6px; inset-block-start: 6px; }

/* The real document, in a frame. The PDF route sets frame-ancestors 'self'
   precisely so this works. */
.v2-iss-preview {
  border: 1px solid var(--v2-line-faint);
  border-radius: var(--v2-r-md);
  overflow: hidden; background: var(--v2-surface);
}
.v2-iss-preview-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--v2-sp-2); padding: var(--v2-sp-3) var(--v2-sp-4);
  border-bottom: 1px solid var(--v2-line-faint);
}
.v2-iss-frame { display: block; width: 100%; height: 420px; border: 0; background: var(--v2-bg-sunken); }

.v2-iss-totals {
  display: grid; gap: 2px;
  padding: var(--v2-sp-4);
  border: 1px solid var(--v2-line-faint);
  border-radius: var(--v2-r-md);
  background: var(--v2-surface);
}
.v2-iss-totals .v2-fact.is-total {
  border-top: 1px solid var(--v2-line-faint);
  margin-top: var(--v2-sp-2); padding-top: var(--v2-sp-3);
  font-size: var(--v2-fs-lg); font-weight: 700;
}

/* The primary action stays reachable with a thumb while the form scrolls. */
.v2-iss-sticky {
  position: sticky; bottom: 0; z-index: 3;
  display: flex; align-items: center; gap: var(--v2-sp-3);
  padding: var(--v2-sp-3) var(--v2-sp-4);
  margin: var(--v2-sp-4) calc(var(--v2-sp-4) * -1) 0;
  background: var(--v2-surface);
  border-top: 1px solid var(--v2-line-faint);
}
.v2-iss-sticky-sum { display: grid; margin-inline-end: auto; line-height: 1.2; }
.v2-iss-sticky .v2-btn { flex: none; }

.v2-iss-done { display: flex; align-items: center; gap: var(--v2-sp-3); padding: 4px 2px; }

@media (min-width: 640px) {
  .v2-iss-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .v2-iss-line-nums { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto; }
  .v2-iss-line-sum { grid-column: auto; text-align: end; }
}

@media (min-width: 1024px) {
  /* FORM | LIVE PREVIEW. The desktop advantage is reading the actual document
     while editing it, so the preview gets real width rather than a sidebar
     sliver — and the form never becomes a phone column in a wide window. */
  .v2-iss { grid-template-columns: minmax(0, 1fr) minmax(360px, 0.85fr); align-items: start; }
  .v2-iss-frame { height: 560px; }
  .v2-iss-side { position: sticky; top: var(--v2-sp-4); }
}

/* =========================================================== ROLE PICKER ===
   Choosing what an invited person may do.

   A segmented control was the obvious reach, and wrong: each option needs a
   sentence saying what the role actually grants, and a pill cannot carry one.
   Getting this choice wrong hands a bookkeeper the ability to issue legal
   documents, so the description is not decoration — it is the decision.

   Radio semantics via aria-pressed on buttons, which is what the rest of the
   shell already uses for exclusive choices (.v2-seg/.v2-pill).
   ========================================================================= */
.v2-rolelist { display: grid; gap: var(--v2-sp-2); }

.v2-rolecard {
  display: grid;
  gap: 3px;
  width: 100%;
  text-align: start;
  padding: var(--v2-sp-3) var(--v2-sp-4);
  border: 1px solid var(--v2-line);
  border-radius: var(--v2-r-md);
  background: var(--v2-surface);
  color: inherit;
  font: inherit;
  cursor: pointer;
  /* The selected state changes the border colour and adds an inner ring rather
     than filling the card: the description must stay readable when chosen, and
     a tinted fill at these text sizes loses contrast. */
  transition: border-color .12s ease, box-shadow .12s ease;
}
.v2-rolecard:active { background: var(--v2-surface-sunken); }
.v2-rolecard.is-on {
  border-color: var(--v2-accent);
  box-shadow: inset 0 0 0 1px var(--v2-accent);
}
.v2-rolecard-t { font-weight: 600; font-size: var(--v2-fs-sm); }
.v2-rolecard.is-on .v2-rolecard-t { color: var(--v2-accent); }
.v2-rolecard-d { font-size: var(--v2-fs-xs); color: var(--v2-ink-soft); line-height: 1.45; }

/* Two across once there is room for a sentence per column. */
@media (min-width: 640px) {
  .v2-rolelist { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* A refusal shown next to the control that caused it. */
.v2-inline-err {
  margin: var(--v2-sp-3) 0 0;
  font-size: var(--v2-fs-xs);
  line-height: 1.45;
  color: var(--v2-negative);
}

/* A required field, marked where the eye already is. */
.v2-req { color: var(--v2-negative); font-weight: 600; }

/* An export refusal, in place under the button that caused it. */
.v2-export-refusal { color: var(--v2-warning); line-height: 1.5; }

/* ================================================================== HELP ===
   Native <details> for the FAQ: keyboard-operable, correctly announced as
   expanded/collapsed, and zero script. A hand-rolled accordion would be
   strictly worse for exactly the users who need the help.
   ========================================================================= */
.v2-faq { display: grid; gap: var(--v2-sp-2); }
.v2-faq-item {
  border: 1px solid var(--v2-line-faint);
  border-radius: var(--v2-r-md);
  background: var(--v2-surface);
  overflow: hidden;
}
.v2-faq-q {
  padding: var(--v2-sp-3) var(--v2-sp-4);
  font-weight: 600;
  font-size: var(--v2-fs-sm);
  cursor: pointer;
  list-style: none;
  /* A comfortable target on a phone. */
  min-height: 44px;
  display: flex;
  align-items: center;
}
.v2-faq-q::-webkit-details-marker { display: none; }
.v2-faq-q::after {
  content: '+';
  margin-inline-start: auto;
  font-weight: 400;
  font-size: 18px;
  color: var(--v2-ink-soft);
  line-height: 1;
}
.v2-faq-item[open] .v2-faq-q::after { content: '−'; }
.v2-faq-a {
  margin: 0;
  padding: 0 var(--v2-sp-4) var(--v2-sp-4);
  font-size: var(--v2-fs-xs);
  line-height: 1.6;
  color: var(--v2-ink-soft);
}

/* ============================================================== BRANDING === */
.v2-brand-logo { display: flex; align-items: center; gap: var(--v2-sp-4); flex-wrap: wrap; }
.v2-brand-logo-box {
  width: 108px; height: 76px;
  display: flex; align-items: center; justify-content: center;
  border: 1px dashed var(--v2-line);
  border-radius: var(--v2-r-sm);
  background: #fff;           /* the paper the logo is printed on */
  overflow: hidden; flex: none;
}
.v2-brand-logo-box img { max-width: 100%; max-height: 100%; object-fit: contain; }
.v2-brand-logo-acts { display: flex; gap: var(--v2-sp-2); flex-wrap: wrap; }

.v2-brand-colour { display: flex; align-items: center; gap: var(--v2-sp-2); }
.v2-brand-colour input[type="color"] {
  inline-size: 44px; block-size: 44px;   /* a real touch target, not a swatch */
  padding: 0; border: 1px solid var(--v2-line);
  border-radius: var(--v2-r-sm); background: none; cursor: pointer; flex: none;
}
.v2-brand-colour .v2-input { flex: 1; min-width: 0; }

/* ======================================================= DOCUMENT SOURCE ===
   What came IN vs what went OUT. An underlined tab pair rather than pills,
   because this is a change of CONTENT, not a filter over one list — and the
   filters below it are pills, so two identical controls stacked would read as
   one confusing six-item row.
   ========================================================================= */
.v2-srcseg {
  display: flex;
  gap: var(--v2-sp-4);
  border-bottom: 1px solid var(--v2-line-faint);
  margin-bottom: var(--v2-sp-3);
}
.v2-srctab {
  appearance: none; background: none; border: 0;
  font: inherit; font-weight: 600; font-size: var(--v2-fs-sm);
  color: var(--v2-ink-soft);
  padding: var(--v2-sp-3) 2px;
  min-height: 44px;                 /* a real touch target */
  cursor: pointer;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}
.v2-srctab[aria-selected="true"] { color: var(--v2-accent); border-bottom-color: var(--v2-accent); }

/* The Add control above a list of people or businesses. */
.v2-listadd { display: flex; justify-content: flex-start; padding: 0 0 var(--v2-sp-3); }

/* A financial row that is also a way in. It must still read as a row of the
   same table — a button that looked like a button here would turn a summary
   into a toolbar. */
.v2-fin-row.is-drill {
  appearance: none; background: none; border: 0; font: inherit; color: inherit;
  width: 100%; text-align: start; cursor: pointer; min-height: 44px;
}
.v2-fin-row.is-drill:active { background: var(--v2-surface-sunken); }
.v2-fin-row.is-drill .v2-row-chev { opacity: .45; margin-inline-start: var(--v2-sp-2); }

/* Why a pinned list is showing what it is showing. */
.v2-drillnote {
  display: flex; align-items: center; gap: 7px; flex-wrap: wrap;
  font-size: var(--v2-fs-xs); color: var(--v2-ink-soft);
  padding: var(--v2-sp-3) 2px;
}
.v2-drillnote svg { width: 15px; height: 15px; flex: none; }

/* ===========================================================================
   ONBOARDING WIZARD

   One column, one decision per screen, the same at 375 and at 1440 — the
   column is capped rather than stretched, because a nine-field form spread
   across a desktop canvas is harder to read than the same form at phone width,
   not easier. What the desktop gets is breathing room and a larger type scale,
   not more columns.
   ========================================================================= */
.v2-ob {
  max-width: 560px;
  margin: 0 auto;
  padding: var(--v2-sp-5) var(--v2-sp-4) var(--v2-sp-10);
}
/* The bottom bar is hidden during onboarding, so the page reclaims its space. */
body.is-onboarding .v2-main { padding-bottom: var(--v2-sp-6); }

.v2-ob-prog {
  height: 4px; border-radius: var(--v2-r-full);
  background: var(--v2-line-faint); overflow: hidden; margin-bottom: var(--v2-sp-6);
}
.v2-ob-prog > span {
  display: block; height: 100%; background: var(--v2-accent);
  border-radius: var(--v2-r-full); transition: width .25s ease;
}
@media (prefers-reduced-motion: reduce) { .v2-ob-prog > span { transition: none; } }

.v2-ob-h   { font-size: var(--v2-fs-2xl); font-weight: 600; margin: 0 0 var(--v2-sp-2); }
.v2-ob-sub { font-size: var(--v2-fs-sm); color: var(--v2-ink-soft); margin: 0 0 var(--v2-sp-5); }

.v2-ob-fs { border: 0; padding: 0; margin: var(--v2-sp-5) 0 0; }
.v2-ob-fs legend { padding: 0 0 var(--v2-sp-3); }

.v2-ob-legal { margin-top: var(--v2-sp-5); line-height: 1.6; }
.v2-ob-legal a { color: var(--v2-accent); }

.v2-ob-target {
  font-size: var(--v2-fs-md); font-weight: 500;
  background: var(--v2-surface-sunken); border: 1px solid var(--v2-line);
  border-radius: var(--v2-r-sm); padding: var(--v2-sp-3) var(--v2-sp-4);
  margin: 0 0 var(--v2-sp-3); overflow-wrap: anywhere;
}

.v2-ob-actions {
  display: flex; gap: var(--v2-sp-3); flex-wrap: wrap;
  margin-top: var(--v2-sp-6);
}
/* Touch targets stay at 44px even when a button is marked small. */
.v2-ob-actions .v2-btn { min-height: 44px; }

.v2-ob-wait, .v2-ob-sign {
  border: 1px solid var(--v2-line); border-radius: var(--v2-r-md);
  background: var(--v2-surface); padding: var(--v2-sp-4);
  margin-top: var(--v2-sp-4);
}
.v2-ob-wait      { background: var(--v2-warning-tint);  border-color: transparent; }
.v2-ob-wait.is-bad { background: var(--v2-negative-tint); }
.v2-ob-sign.is-ok  { background: var(--v2-positive-tint); border-color: transparent; }
.v2-ob-wait-t { font-weight: 600; margin-bottom: var(--v2-sp-1); }
.v2-ob-wait-d { font-size: var(--v2-fs-sm); color: var(--v2-ink-soft); line-height: 1.55; }
.v2-ob-wait-n {
  margin-top: var(--v2-sp-3); padding-top: var(--v2-sp-3);
  border-top: 1px solid var(--v2-line-strong);
  font-size: var(--v2-fs-sm);
}

.v2-ob-conn {
  border: 1px solid var(--v2-line); border-radius: var(--v2-r-md);
  padding: var(--v2-sp-4); margin-top: var(--v2-sp-4); background: var(--v2-surface);
}
.v2-ob-conn-h { display: flex; align-items: center; gap: var(--v2-sp-2); }
.v2-ob-conn-t { font-weight: 600; }
.v2-ob-conn-d { font-size: var(--v2-fs-sm); color: var(--v2-ink-soft); margin: var(--v2-sp-2) 0 0; line-height: 1.55; }
.v2-ob-conn .v2-ob-actions { margin-top: var(--v2-sp-3); }

.v2-ob-bizname {
  margin-top: var(--v2-sp-2);
  font-size: 1.15em;
  font-weight: 600;
  overflow-wrap: anywhere;
}
.v2-ob-sum { margin-top: var(--v2-sp-2); }
.v2-ob-sumrow {
  display: flex; gap: var(--v2-sp-3); align-items: flex-start;
  padding: var(--v2-sp-3) 0; border-bottom: 1px solid var(--v2-line-faint);
  font-size: var(--v2-fs-sm); color: var(--v2-ink-soft);
}
.v2-ob-sumrow:last-child { border-bottom: 0; }
.v2-ob-sumrow.is-ok { color: var(--v2-ink); }
.v2-ob-tick {
  flex: none; width: 20px; text-align: center; font-weight: 700;
  color: var(--v2-ink-faint);
}
.v2-ob-sumrow.is-ok .v2-ob-tick { color: var(--v2-positive); }

/* Desktop: more air, slightly larger heading. Still one column. */
@media (min-width: 900px) {
  .v2-ob { padding-top: var(--v2-sp-9); }
  .v2-ob-h { font-size: var(--v2-fs-3xl, var(--v2-fs-2xl)); }
}

/* The blocked-issuing explanation, shown BEFORE the form rather than after
   the last step fails. */
.v2-iss-blocked {
  border: 1px solid var(--v2-line); border-radius: var(--v2-r-md);
  background: var(--v2-warning-tint); border-color: transparent;
  padding: var(--v2-sp-4); margin: var(--v2-sp-4) 0;
}
.v2-iss-blocked-t { font-weight: 600; margin-bottom: var(--v2-sp-1); }
.v2-iss-blocked-d { font-size: var(--v2-fs-sm); color: var(--v2-ink-soft); line-height: 1.55; }

/* The bar is hidden during onboarding. `.v2-nav` sets its own display, which
   beats the reset's [hidden] rule on specificity — so `nav.hidden = true` alone
   left the bar drawn and tappable, found on the first screenshot of the wizard. */
.v2-nav[hidden], body.is-onboarding .v2-nav { display: none !important; }

/* Visible keyboard focus in the wizard. The live audit found the focused input
   computing `outline: none` and no shadow: a keyboard user could not see where
   they were. A ring, not a colour change alone, and only for keyboard focus. */
.v2-ob input:focus-visible,
.v2-ob button:focus-visible,
.v2-ob a:focus-visible,
.v2-ob label.v2-btn:focus-within {
  outline: 3px solid var(--v2-accent);
  outline-offset: 2px;
  box-shadow: 0 0 0 5px var(--v2-accent-ring);
}

/* REDUCED MOTION, APPLIED TO THE WHOLE V2 SURFACE.
   An audit for the accessibility statement found only two rules honouring
   prefers-reduced-motion (skeleton shimmer, onboarding progress) while V2 uses
   five animations and twelve transitions — sheets rise, pop and fade. A person
   who has asked their device for less motion gets none of it here. State still
   changes; it simply does so instantly. */
@media (prefers-reduced-motion: reduce) {
  .v2-app *, .v2-app *::before, .v2-app *::after,
  .v2-nav, .v2-nav *,
  body > * {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
