:root {
  --bg: #f4f5f7;
  --panel: #ffffff;
  --ink: #1a2233;
  --muted: #66708a;
  --line: #e3e6ec;
  --accent: #2456e6;
  --accent-soft: #e8eeff;
  --green: #14804a;
  --green-soft: #e1f4ea;
  --amber: #9a6700;
  --amber-soft: #fff3d1;
  --red: #b42318;
  --red-soft: #fde8e6;
  --radius: 10px;
  --shadow: 0 1px 3px rgba(20,30,60,.08);
  font-size: 15px;
}
* { box-sizing: border-box; }
body { margin: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background: var(--bg); color: var(--ink); }

#app { display: flex; min-height: 100vh; }
#sidebar { width: 210px; background: #101828; color: #cdd5e4; padding: 20px 14px; display: flex; flex-direction: column; position: fixed; top: 0; bottom: 0; }
/* Now an anchor to the dashboard, so it needs the underline taken off and a hover that says
   it is pressable. display: block keeps the original margins doing what they did. */
/* The logo. The OZ is painted with the anchor's own colour, so this one drawing is the
   light-background version on a white card and the dark-background version here, simply by
   setting `color`. The blue never changes — it is the same in both of the designed files. */
.brand-mark { display: block; height: auto; }
.brand-mark-name { fill: currentColor; }
.brand-mark-accent { fill: #3155de; }

/* The gap below is deliberately large. It is what separates the mark from the navigation, and
   at 26px the two read as one stack; the logo needs to sit apart from the list to look like a
   mark rather than the first item in it. */
#sidebar .logo { display: block; color: #fff; margin: 4px 8px 78px; text-decoration: none; }
#sidebar .logo .brand-mark { width: 120px; }
#sidebar .logo:hover { opacity: .85; }
#sidebar .logo:focus-visible { outline: 2px solid #7c9aff; outline-offset: 4px; border-radius: 5px; }
#sidebar nav { display: flex; flex-direction: column; gap: 2px; }
.nav-link { color: #cdd5e4; text-decoration: none; padding: 9px 12px; border-radius: 8px; font-size: 14.5px; }
.nav-link:hover { background: rgba(255,255,255,.07); }
.nav-link.active { background: var(--accent); color: #fff; }
/* Business / user area, pinned to the bottom of the sidebar */
.biz-area {
  margin-top: auto; position: relative; display: flex; align-items: center; gap: 9px;
  padding: 8px 8px 8px 9px; border-radius: 10px;
  background: rgba(255,255,255,.05); border: 1px solid transparent;
}
.biz-area.active { background: rgba(36,86,230,.22); border-color: rgba(124,154,255,.4); }
.biz-avatar {
  width: 30px; height: 30px; border-radius: 8px; flex: 0 0 30px;
  background: linear-gradient(140deg, #3b5bdb, #7c9aff);
  display: flex; align-items: center; justify-content: center;
  color: #fff; font-weight: 700; font-size: 12px; letter-spacing: .02em;
}
.biz-avatar.sm { width: 26px; height: 26px; flex: 0 0 26px; font-size: 10.5px; border-radius: 7px; }
.biz-text { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.biz-name { color: #eef2fa; font-size: 13px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.biz-sub { color: #6d7c96; font-size: 11px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* the only clickable part — a chevron that opens the menu upward */
.biz-toggle {
  flex: 0 0 26px; width: 26px; height: 26px; padding: 0; border: none; border-radius: 7px;
  background: transparent; color: #7d8ca6; cursor: pointer;
  display: flex; align-items: center; justify-content: center; transition: transform .18s, color .15s, background .15s;
}
.biz-toggle:hover { background: rgba(255,255,255,.1); color: #eef2fa; }
.biz-toggle:focus-visible { outline: 2px solid #7c9aff; outline-offset: 1px; }
.biz-area.open .biz-toggle { transform: rotate(180deg); background: rgba(255,255,255,.12); color: #fff; }

/* popup menu */
.biz-menu {
  position: absolute; bottom: calc(100% + 8px); left: 0; width: 258px; z-index: 80;
  background: #fff; border: 1px solid var(--line); border-radius: 12px; padding: 6px;
  box-shadow: 0 14px 40px rgba(10,15,30,.28); animation: bizIn .13s ease-out;
}
@keyframes bizIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
.biz-menu-head { display: flex; align-items: center; gap: 9px; padding: 8px 9px 10px; border-bottom: 1px solid var(--line); margin-bottom: 5px; }
.biz-menu-head > span:last-child { display: flex; flex-direction: column; min-width: 0; }
.biz-menu-name { font-size: 13.5px; font-weight: 700; color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.biz-menu-mail { font-size: 11.5px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.biz-menu-item {
  display: flex; flex-direction: column; gap: 1px; width: 100%; text-align: left;
  padding: 7px 9px; border: none; background: none; border-radius: 8px; cursor: pointer;
  font-size: 13.5px; color: var(--ink);
}
.biz-menu-item:hover { background: var(--accent-soft); color: var(--accent); }
.biz-menu-hint { font-size: 11px; color: var(--muted); }
.biz-menu-item:hover .biz-menu-hint { color: #6a86d8; }
.biz-menu-sep { height: 1px; background: var(--line); margin: 5px 4px; }
.biz-menu-foot { font-size: 10.5px; color: var(--muted); text-align: center; padding: 8px 6px 4px; border-top: 1px solid var(--line); margin-top: 5px; }

/* highlight the card you jumped to */
.card.flash { animation: cardFlash 1.2s ease-out; }
@keyframes cardFlash { 0%, 40% { box-shadow: 0 0 0 3px var(--accent-soft), var(--shadow); } 100% { box-shadow: var(--shadow); } }

#main { flex: 1; margin-left: 210px; padding: 28px 34px 60px; width: calc(100% - 210px); max-width: 1600px; }

h1 { font-size: 22px; margin: 0 0 4px; }
h2 { font-size: 16px; margin: 0 0 12px; }
.sub { color: var(--muted); font-size: 13.5px; margin-bottom: 22px; }
.view-head { display: flex; align-items: flex-start; justify-content: space-between; margin-bottom: 20px; gap: 12px; flex-wrap: wrap; }
.view-head .actions { display: flex; gap: 8px; }
/* Financial-year switcher, top right of the Dashboard */
.fy-switch { display: inline-flex; align-items: center; gap: 6px; }
/* The chevron sizing below is deliberately tight, so it must only reach the switcher's own
   buttons — a sibling with a word in it inherited height:30px and padding:0 and rendered as a
   squashed blob. */
.view-head .actions { display: flex; align-items: center; gap: 10px; }
.fy-switch .fy-today {
  height: 30px; padding: 0 12px; margin-right: 6px; font-size: 13px; font-weight: 600;
  color: var(--accent); background: var(--accent-soft); border-color: transparent;
  display: inline-flex; align-items: center; white-space: nowrap;
}
.fy-switch .fy-today:hover { background: #dbe5ff; border-color: transparent; }
.fy-switch button { min-width: 30px; height: 30px; padding: 0; font-size: 16px; line-height: 1; display: inline-flex; align-items: center; justify-content: center; color: var(--muted); }
.fy-switch button:hover:not(:disabled) { color: var(--ink); border-color: #c8cdd8; }
.fy-switch button:disabled { opacity: .3; }
.fy-switch .fy-year { font-size: 17px; font-weight: 700; letter-spacing: .01em; min-width: 108px; text-align: center; font-variant-numeric: tabular-nums; }

.card { background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow); padding: 18px 20px; }
.grid { display: grid; gap: 14px; }
.grid.kpis { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); margin-bottom: 20px; }
/* Five of them, which auto-fit handles badly: at anything under a 1440px window it drops to
   four columns and leaves the fifth stranded on a row by itself, looking like a mistake. The
   counts are set explicitly instead, so it breaks 5, then 3+2, then 2+2+1 — always a wrap that
   looks deliberate rather than a leftover. */
.grid.kpis.five { grid-template-columns: repeat(5, 1fr); }
@media (max-width: 1400px) { .grid.kpis.five { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 900px)  { .grid.kpis.five { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px)  { .grid.kpis.five { grid-template-columns: 1fr; } }
.kpi .label { font-size: 12.5px; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }
.kpi .value { font-size: 24px; font-weight: 700; margin-top: 6px; }
.kpi .hint { font-size: 12.5px; color: var(--muted); margin-top: 4px; }

table { width: 100%; border-collapse: collapse; font-size: 14px; }
th { text-align: left; color: var(--muted); font-weight: 600; font-size: 12.5px; text-transform: uppercase; letter-spacing: .03em; padding: 8px 10px; border-bottom: 1px solid var(--line); }
td { padding: 10px; border-bottom: 1px solid var(--line); vertical-align: middle; }
tr:last-child td { border-bottom: none; }
tr.clickable { cursor: pointer; }
tr.clickable:hover { background: #f7f9ff; }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }
/* A column of status chips sitting at the end of a row of figures. Right-aligned like the
   numbers it follows, so the row has one edge rather than two — but not .num, because a chip
   is a word and tabular figures would space it oddly. */
td.chip-col, th.chip-col { text-align: right; white-space: nowrap; }

/* ---------- The row menu ----------

   Every row had its rare actions spelled out in full, which meant the common ones — the pay
   controls you use every week — were competing for width with a Print button you press twice a
   year. The rare ones move behind a ⋯ at the end of the row, and what the menu offers depends
   on the state of the thing: you cannot void a draft, and reinstating only makes sense on
   something already void.

   The cell has to be position: relative for the menu to hang off it, and the row above needs a
   higher stacking order than the rows below, or the menu opens underneath the next one. */
td.menu-col { width: 46px; text-align: right; position: relative; }
tr:has(.row-menu.open) { position: relative; z-index: 30; }
.menu-dots { width: 30px; height: 30px; padding: 0; border-radius: 8px; line-height: 1;
  font-size: 17px; color: var(--muted); background: transparent; border-color: transparent;
  display: inline-flex; align-items: center; justify-content: center; }
.menu-dots:hover { background: #eef1f7; color: var(--ink); border-color: transparent; }
.row-menu.open .menu-dots { background: var(--accent-soft); color: var(--accent); }
.row-menu { position: relative; display: inline-block; }
.row-menu-panel { display: none; position: absolute; right: 0; top: calc(100% + 4px); z-index: 40;
  min-width: 210px; background: var(--panel); border: 1px solid var(--line); border-radius: 10px;
  padding: 5px; box-shadow: 0 12px 34px rgba(10,15,30,.18); text-align: left; }
.row-menu.open .row-menu-panel { display: block; }
/* Near the bottom of a long list a menu would fall off the page, so it opens upward instead. */
.row-menu.up .row-menu-panel { top: auto; bottom: calc(100% + 4px); }
.row-menu-panel button { display: block; width: 100%; text-align: left; border: none;
  background: none; padding: 8px 10px; border-radius: 7px; font-size: 13.5px; color: var(--ink);
  white-space: nowrap; }
.row-menu-panel button:hover { background: var(--accent-soft); color: var(--accent); }
.row-menu-panel button.danger:hover { background: var(--red-soft); color: var(--red); }
.row-menu-panel .sep { height: 1px; background: var(--line); margin: 4px 5px; }
.row-menu-panel .note { padding: 5px 10px 7px; font-size: 11.5px; color: var(--muted); }

.badge { display: inline-block; padding: 3px 9px; border-radius: 20px; font-size: 12px; font-weight: 600; }
.badge.draft { background: #eef0f4; color: var(--muted); }
.badge.sent { background: var(--accent-soft); color: var(--accent); }
.badge.paid { background: var(--green-soft); color: var(--green); }
.badge.overdue { background: var(--red-soft); color: var(--red); }
/* money still owed to a supplier — the same amber used for spending on the chart */
.badge.outstanding { background: var(--amber-soft); color: var(--amber); }
/* A void document is still in the books, so it is shown — just plainly, and struck through so
   it can never be mistaken for a live one at a glance. */
.badge.void { background: #eef0f4; color: var(--muted); }
tr.is-void td { color: var(--muted); }
tr.is-void td strong, tr.is-void td .num { text-decoration: line-through; }
.void-note { background: #eef0f4; border: 1px solid var(--line); border-radius: var(--radius);
  padding: 10px 14px; margin-bottom: 16px; font-size: 13.5px; color: var(--muted); }
.void-note strong { color: var(--ink); }
.badge.cur { background: #eef0f4; color: var(--ink); font-weight: 500; }
/* A bill nobody has recorded yet. Deliberately not a colour: it is not late, not paid and not
   due — it is missing, and an outline reads as an empty slot rather than a state. */
.badge.outline { background: transparent; color: var(--muted); border: 1px dashed var(--line-strong, #c8cede); }
.badge.muted { background: transparent; color: var(--muted); font-weight: 500; }
/* A chip you can press. Same shape as the badge beside it so the row reads as one thing, but
   it lifts on hover so it is clear which of the two does something. */
button.badge { border: 0; cursor: pointer; font-family: inherit; line-height: 1.35; }
button.badge:hover { filter: brightness(0.94); }
button.badge.outline { border: 1px dashed var(--line-strong, #c8cede); }

/* ---------- The roster ----------

   The first attempt at this was a card whose contents simply flowed, and at a narrow column
   width everything went where it liked: two badges stacked one per line, the meta line wrapped
   to two, and the action button — centred against a body that had grown tall — ended up
   floating in the middle of the card. Flow is not layout.

   So the card is three fixed regions, and nothing can leave the one it belongs to:

     identity   avatar, name, one line of facts, status, chevron — one row, never wraps
     metrics    three equal columns, labels above figures, aligned across every card
     actions    a footer, right-aligned, present only when there is something to press

   Two rules keep it honest. The name and the meta line truncate rather than wrap, because a
   card that changes height with the length of a job title makes a grid of them ragged. And
   only one badge is ever shown — the thing that needs doing — because a row of chips is where
   the first version fell apart. Attributes like "director" are facts, so they live in the meta
   line as words.

   The column is 460px because six pieces of information need the room; below that the grid
   drops to one per row rather than squeezing. */
.people-grid { display: grid; gap: 12px; grid-template-columns: repeat(auto-fill, minmax(460px, 1fr)); }

.person-card { display: block; width: 100%; text-align: left; padding: 0; overflow: hidden;
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  cursor: pointer; font: inherit; color: inherit; }
.person-card:hover { border-color: var(--accent); }
.person-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.person-card.gone { opacity: .7; }
/* Selecting someone does not leave the page — the panel below becomes theirs. So the card has
   to say "this is the one you are looking at" and stay saying it, which a hover state cannot
   do once the pointer moves away. */
.person-card.selected { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.person-card.selected .person-id { background: var(--accent-soft); }
.person-card.selected .chev { transform: rotate(90deg); color: var(--accent); }
.person-card .chev { display: inline-block; transition: transform .15s; }
/* Clicking the empty part of the roster clears the selection, so it needs to feel like a
   surface rather than dead space. */
.roster-surface { min-height: 8px; }

/* identity — one row, fixed shape */
.person-id { display: flex; align-items: center; gap: 13px; padding: 14px 16px; }
.person-avatar { width: 42px; height: 42px; flex: 0 0 42px; border-radius: 50%;
  background: var(--accent-soft); color: var(--accent); display: flex; align-items: center;
  justify-content: center; font-weight: 700; font-size: 14px; letter-spacing: .02em; }
.person-card.gone .person-avatar { background: #eef0f4; color: var(--muted); }
.person-id .naming { flex: 1; min-width: 0; }
.person-id .naming b { display: block; font-size: 15px; font-weight: 600;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.person-id .naming span { display: block; font-size: 12.5px; color: var(--muted); margin-top: 2px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.person-id .flag { flex: 0 0 auto; display: flex; align-items: center; gap: 9px; }
.person-id .chev { color: var(--muted); font-size: 19px; line-height: 1; }
.person-card:hover .chev { color: var(--accent); }

/* metrics — three equal columns, so figures line up across the whole grid */
.person-metrics { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  border-top: 1px solid var(--line); }
/* Direct children only. Without the ">" this also matched the label and the value inside each
   column, giving them 10px of padding each and prising them ~20px apart — a label and the
   figure it names have to read as one thing. */
.person-metrics > div { padding: 10px 16px; min-width: 0; }
.person-metrics .k { font-size: 11.5px; color: var(--muted); white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; }
.person-metrics .v { font-size: 14px; font-weight: 600; margin-top: 3px;
  font-variant-numeric: tabular-nums; white-space: nowrap; }
.person-metrics .v.none { color: var(--muted); font-weight: 400; }
.person-metrics .v em { font-style: normal; font-weight: 400; color: var(--muted); }

/* actions — a footer, so a button can never end up in the middle of anything */
.person-do { display: flex; justify-content: flex-end; gap: 8px;
  padding: 9px 16px; border-top: 1px solid var(--line); background: #fbfcfe; }

.person-head { display: flex; align-items: flex-start; gap: 14px; margin-bottom: 16px; }
.person-head .who { flex: 1; min-width: 0; }
.person-head h2 { margin: 0 0 4px; }
.back-link { display: inline-block; margin-bottom: 12px; color: var(--muted); font-size: 13px; }
.back-link:hover { color: var(--accent); }

/* ---------- The pay run window ----------

   Six number boxes in a flat grid gave every figure the same weight, when only one of them is
   typed and the other five follow from it. These rules put that back: gross pay leads, and the
   rest are grouped by the thing that decides everything downstream — whether a figure comes
   OUT of the employee's pay or is paid ON TOP by the company. */
.sub-head { grid-column: 1 / -1; font-size: 11.5px; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--muted); margin: 6px 0 -4px; }
.sub-head .why { text-transform: none; letter-spacing: 0; font-weight: 400; margin-left: 8px; }
.field.lead input { font-size: 19px; font-weight: 600; padding-top: 9px; padding-bottom: 9px; }
.field.lead > label { font-size: 13.5px; color: var(--ink); }

/* What the pay run comes to, as a statement rather than three floating lines. */
.pay-summary { margin-top: 18px; border: 1px solid var(--line); border-radius: var(--radius);
  overflow: hidden; }
.pay-summary .line { display: flex; justify-content: space-between; align-items: baseline;
  gap: 16px; padding: 9px 14px; font-size: 13.5px; }
.pay-summary .line + .line { border-top: 1px solid var(--line); }
.pay-summary .line span:last-child { font-variant-numeric: tabular-nums; white-space: nowrap; }
.pay-summary .line.sub { color: var(--muted); background: #fbfcfe; font-size: 13px; }
.pay-summary .line.strong { font-weight: 600; }
.pay-summary .line.grand { background: var(--accent-soft); font-weight: 700; font-size: 15px;
  color: var(--accent); }
.pay-summary .line.warn { background: var(--red-soft); color: var(--red); font-weight: 600; }

/* The PAYE block at the foot of the pay run window. It is a different kind of thing from the
   fields above it — a bill rather than a figure you type — so it is boxed rather than ruled. */
.paye-panel { margin-top: 6px; border: 1px solid var(--line); border-radius: var(--radius);
  background: #fbfcfe; padding: 14px 16px; }
.paye-panel.settled { background: var(--green-soft); border-color: #bfe3cd; }
.paye-panel.late { background: var(--red-soft); border-color: #f2c9c9; }
.paye-panel .top { display: flex; align-items: flex-start; justify-content: space-between; gap: 14px; }
.paye-panel .what { font-weight: 600; }
.paye-panel .when { color: var(--muted); font-size: 12.5px; margin-top: 2px; }
.paye-panel .figures { display: flex; gap: 22px; margin: 12px 0 0; flex-wrap: wrap; }
.paye-panel .figures div { font-size: 12.5px; color: var(--muted); }
.paye-panel .figures strong { display: block; font-size: 15px; color: var(--ink);
  font-variant-numeric: tabular-nums; }
/* flex-end aligns the MARGIN box, and .field carries 16px of bottom margin — so without
   clearing it the inputs float 16px above the button they are supposed to sit level with.
   That is the whole reason the button looked dropped. */
.paye-panel .act { margin-top: 14px; display: flex; gap: 10px; align-items: flex-end; flex-wrap: wrap; }
.paye-panel .act .field { flex: 0 0 150px; margin-bottom: 0; }
.paye-panel .act > button { margin-bottom: 0; height: 38px; padding: 0 16px; }
.paye-panel .covers { margin-top: 10px; font-size: 12.5px; color: var(--muted); }
.paye-panel .receipt { margin-top: 10px; font-size: 13px; }
.status-cell { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.status-cell .paid-on { color: var(--muted); font-size: 12.5px; white-space: nowrap; }

button, .btn { font: inherit; border: 1px solid var(--line); background: var(--panel); color: var(--ink); padding: 8px 14px; border-radius: 8px; cursor: pointer; font-size: 14px; }
button:hover, .btn:hover { border-color: #c8cdd8; }
/* The variants apply to .btn as well as <button>, because a control nested inside another
   control cannot be a <button> — the HTML is invalid and the click never reaches the inner one.
   "Run pay" inside a person card is exactly that case, so it is a span carrying these classes. */
button.primary, .btn.primary { background: var(--accent); border-color: var(--accent); color: #fff; }
button.primary:hover, .btn.primary:hover { background: #1d48c6; }
button.danger, .btn.danger { color: var(--red); }
button.small, .btn.small { padding: 4px 10px; font-size: 12.5px; }
button:disabled, .btn.disabled { opacity: .45; cursor: not-allowed; }
.btn { display: inline-block; white-space: nowrap; }
/* Inline "mark paid" controls — one consistent height, never wrapping */
.pay-inline { display: inline-flex; align-items: stretch; gap: 5px; vertical-align: middle; }
td .pay-inline + button, .pay-inline ~ button { vertical-align: middle; }
.row-actions { display: flex; align-items: stretch; justify-content: flex-end; gap: 5px; flex-wrap: nowrap; }
.row-actions > *, .pay-inline > * {
  height: 30px; line-height: 1; padding: 0 9px; font-size: 12.5px;
  border-radius: 7px; white-space: nowrap; box-sizing: border-box;
}
.row-actions button, .pay-inline button { display: inline-flex; align-items: center; }
input.small-date, select.small-date { width: auto; }
select.small-date { padding-right: 22px; }
.row-actions input.pay-amt { width: 92px; text-align: right; font-variant-numeric: tabular-nums; }
.row-actions input.pay-amt.over { border-color: var(--red); background: var(--red-soft); color: var(--red); }

input, select, textarea { font: inherit; padding: 8px 10px; border: 1px solid var(--line); border-radius: 8px; width: 100%; background: #fff; color: var(--ink); }
input:focus, select:focus, textarea:focus { outline: 2px solid var(--accent-soft); border-color: var(--accent); }
/* Only ever taller, never wider — dragging a textarea sideways breaks the grid */
textarea { resize: vertical; line-height: 1.45; min-height: 64px; }
/* Grows to fit what's in it, so nothing is hidden behind a scrollbar */
textarea.grow { overflow-y: hidden; resize: none; }
label { font-size: 12.5px; font-weight: 600; color: var(--muted); display: block;
  margin-bottom: 6px; line-height: 18px; }
.field { margin-bottom: 16px; }
.row { display: flex; gap: 18px; align-items: flex-start; }
.row > * { flex: 1; min-width: 0; }

/* Every field is the same three stacked blocks — label, control, hint — each a known height,
   so the controls in a row line up because they are all the same distance from the top. An
   earlier version let the label stretch to fill the field and pushed the control to the
   bottom, which lined things up only while every field had the same amount of text under it;
   add a hint to some and not others and the controls drifted apart down the row.
   Both [hidden] rules are load-bearing: the browser hides that attribute with a plain
   element selector, which any class selector here would outrank, so hiding a field or a row
   would otherwise do nothing at all. */
.row[hidden], .row .field[hidden] { display: none; }
.row .field { display: block; }
.row .field > label { height: 18px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.field .hint { font-size: 11.5px; color: var(--muted); line-height: 16px; margin-top: 6px; }

/* Modal */
#modal-root:empty { display: none; }
.modal-overlay { position: fixed; inset: 0; background: rgba(10,15,30,.45); display: flex; align-items: flex-start; justify-content: center; padding: 40px 16px; overflow-y: auto; z-index: 50; }
.modal { background: #fff; border-radius: 14px; padding: 24px 26px; width: 100%; max-width: 640px; box-shadow: 0 20px 60px rgba(0,0,0,.25); }
.modal.wide { max-width: 860px; }
.modal h2 { margin-bottom: 18px; font-size: 18px; }
/* Grouped form sections. A long form of bare fields reads as one undifferentiated wall; a
   quiet rule and a small heading every few fields turn it into three short questions —
   what did you buy, how much was it, and has it been paid. */
.form-section + .form-section { margin-top: 22px; }
.form-section-title {
  font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .07em;
  color: var(--muted); padding-bottom: 7px; margin-bottom: 14px;
  border-bottom: 1px solid var(--line);
  /* A section may carry one action on its right — "work this out for me" and the like.
     Bare text still sits where it always did, because a lone child in a flex row with
     space-between stays at the start. */
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
}
.form-section-title button { text-transform: none; letter-spacing: 0; }
/* Three across is the widest a row gets; a field may take two of those shares when what goes
   in it is prose rather than a number. */
.field.w-wide { flex: 2; }

.modal-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 20px;
  padding-top: 18px; border-top: 1px solid var(--line); }
.modal-actions .left { margin-right: auto; }

/* Invoice items editor */
.items-table input { padding: 6px 8px; }
.items-table td { padding: 6px 4px; border-bottom: none; }
.items-table .num input { text-align: right; }

/* Payments block — give it room to breathe */
.pay-block { margin: 26px 0 22px; padding: 16px 18px 14px; background: #fafbfd; border: 1px solid var(--line); border-radius: var(--radius); }
.pay-block > label { margin-bottom: 10px; }
.pay-table { margin-bottom: 6px; }
.pay-table th { padding-bottom: 6px; }
.pay-table td { padding: 5px 5px; }
.pay-table input, .pay-table select { padding: 7px 9px; background: #fff; }
.pay-foot { display: flex; align-items: center; gap: 14px; margin-top: 10px; flex-wrap: wrap; }
.totals-box { text-align: right; margin-top: 10px; font-size: 14.5px; }
.totals-box .grand { font-size: 18px; font-weight: 700; }

/* Dropzone */
.dropzone { border: 2px dashed #c3cbe0; border-radius: var(--radius); padding: 26px; text-align: center; color: var(--muted); cursor: pointer; transition: all .15s; background: #fbfcff; }
.dropzone:hover, .dropzone.drag { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); }
.dropzone .big { font-size: 15px; font-weight: 600; margin-bottom: 4px; }
.dropzone.slim { padding: 14px; font-size: 12.5px; }
.dropzone.slim .big { font-size: 14px; margin-bottom: 2px; }

.scan-result { background: var(--green-soft); border: 1px solid #bfe6d2; border-radius: var(--radius); padding: 12px 14px; margin: 12px 0; font-size: 13.5px; }
.scan-result.warn { background: var(--amber-soft); border-color: #ecd9a0; }
.match-suggest { background: var(--accent-soft); border: 1px solid #c8d8ff; border-radius: var(--radius); padding: 12px 14px; margin: 12px 0; font-size: 13.5px; }
.match-suggest button { margin-top: 8px; }

/* Combobox (type-ahead) */
.combo-drop { position: absolute; top: 100%; left: 0; right: 0; background: #fff; border: 1px solid var(--line); border-radius: 8px; box-shadow: 0 8px 24px rgba(20,30,60,.15); max-height: 260px; overflow-y: auto; z-index: 60; }
.combo-item { padding: 9px 12px; cursor: pointer; font-size: 14px; border-bottom: 1px solid #f0f2f6; }
.combo-item:last-child { border-bottom: none; }
.combo-item:hover { background: var(--accent-soft); }

/* Toast */
#toast-root { position: fixed; bottom: 20px; right: 20px; display: flex; flex-direction: column; gap: 8px; z-index: 100; }
.toast { background: #101828; color: #fff; padding: 11px 16px; border-radius: 10px; font-size: 14px; box-shadow: 0 6px 20px rgba(0,0,0,.25); animation: slideIn .2s ease; }
.toast.error { background: var(--red); }
@keyframes slideIn { from { transform: translateY(8px); opacity: 0; } to { transform: none; opacity: 1; } }

.empty { text-align: center; color: var(--muted); padding: 40px 20px; font-size: 14px; }
/* Long-form document pages (About, Terms & Privacy) */
.doc { max-width: 820px; display: flex; flex-direction: column; gap: 16px; }
.doc .card { padding: 22px 24px; }
.doc h2 { font-size: 17px; margin-bottom: 10px; }
.doc h3 { font-size: 14px; margin: 18px 0 6px; color: var(--ink); }
.doc h3:first-of-type { margin-top: 10px; }
.doc p { margin: 0 0 10px; line-height: 1.62; font-size: 14px; color: #333c4f; }
.doc p:last-child { margin-bottom: 0; }
.doc ul { margin: 0 0 10px; padding-left: 20px; }
.doc li { margin-bottom: 7px; line-height: 1.58; font-size: 14px; color: #333c4f; }
.doc code { background: #eef0f4; padding: 1px 5px; border-radius: 4px; font-size: 12.5px; }
#legal-summary, #about-intro { background: var(--accent-soft); border-color: #c8d8ff; }
#legal-summary li, #about-intro p { color: #24304a; }
#about-intro h2 { color: var(--ink); }

/* Currency picker */
.cur-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 2px 12px; margin-top: 4px; }
.cur-pick { display: flex; align-items: center; gap: 7px; padding: 5px 6px; border-radius: 7px; cursor: pointer; font-size: 13px; font-weight: 400; color: var(--ink); margin: 0; }
.cur-pick:hover { background: var(--accent-soft); }
.cur-pick input { width: auto; margin: 0; flex: 0 0 auto; }
.cur-pick input:disabled + span { color: var(--muted); }
.cur-pick span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.setup-list { padding-left: 20px; margin: 0 0 14px; }
.setup-list li { margin-bottom: 14px; line-height: 1.55; }
.setup-list button { margin-top: 6px; }
.muted { color: var(--muted); }
.small-text { font-size: 12.5px; }
.filters { display: flex; gap: 8px; margin-bottom: 14px; flex-wrap: wrap; }
.filters select, .filters input { width: auto; }
.link { color: var(--accent); cursor: pointer; text-decoration: underline; background: none; border: none; padding: 0; font-size: inherit; }

/* align-items: start so each card is only as tall as its own content — otherwise a short
   card (Financial year) stretches to match a tall neighbour and leaves a block of empty space */
.two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; align-items: start; }
@media (max-width: 900px) {
  .two-col { grid-template-columns: 1fr; }
  #sidebar { width: 64px; }
  #main { margin-left: 64px; width: calc(100% - 64px); }
  /* The rail is 64px, and the whole lockup at that width would be 12px tall and unreadable.
     So it is cropped to the OZ: the drawing is drawn oversized and the anchor clips it, the
     OZ being the leftmost 44% of the viewBox. Widening the anchor again reveals the rest. */
  #sidebar .logo { width: 36px; margin: 4px auto 20px; overflow: hidden; }
  #sidebar .logo .brand-mark { width: 82px; }
  .biz-area { padding: 6px; flex-direction: column; gap: 4px; }
  .biz-text { display: none; }
  .biz-menu { left: calc(100% + 8px); bottom: 0; }
}

/* ---------- Month-by-month chart ----------
   Income and spending differ by an order of magnitude — a good month invoices £6,000 and
   spends £200. Drawn on one scale, every expense bar collapses to the same sliver and the
   difference between a £48 month and a £397 one is lost.

   So spending gets its own lane underneath, with its own scale, the way trading volume sits
   under a price. Each lane is honest within itself, the two are never confused, and the
   spending months become comparable with each other, which is the question being asked. */
.chart-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.chart-head h2 { margin-bottom: 2px; }

.legend { display: flex; gap: 14px; font-size: 12.5px; color: var(--muted); flex-wrap: wrap; }
.legend .dot { display: inline-block; width: 9px; height: 9px; border-radius: 3px; margin-right: 6px; vertical-align: 0; }

/* The gap has to clear more than it looks: the top scale label is nudged up half its own
   height to centre on the £6k line, so it reaches above the plot and closes on the subtitle.
   38px leaves a clear band between the heading and the chart. */
.chart { display: flex; gap: 10px; margin-top: 38px; }
.chart-axis { flex: 0 0 auto; display: flex; flex-direction: column; gap: 8px; }
.chart-main { flex: 1; min-width: 0; position: relative; }

/* the money scale beside the income lane */
.chart-scale {
  display: flex; flex-direction: column; justify-content: space-between;
  height: 168px; text-align: right;
  font-size: 11px; color: var(--muted); font-variant-numeric: tabular-nums;
}
.chart-scale span { line-height: 1; transform: translateY(-50%); white-space: nowrap; }

/* the spending lane's own top figure, so it is never mistaken for the same scale */
.spend-scale {
  height: 46px; display: flex; flex-direction: column; justify-content: space-between;
  text-align: right; font-size: 10.5px; color: var(--amber);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.spend-scale span:first-child { opacity: .5; transform: translateY(-2px); }
.spend-scale span:last-child { font-weight: 600; }

.chart-plot { position: relative; height: 168px; pointer-events: none; }
.chart-grid { position: absolute; inset: 0; pointer-events: none; }
.chart-grid i { position: absolute; left: 0; right: 0; height: 1px; background: var(--line); }
.chart-grid i.base { background: #cfd4de; }

.chart-cols { position: absolute; inset: 0; display: flex; align-items: flex-end; gap: 2px; }
/* height: 100% is load-bearing. The bars are sized in per cent, and a percentage height only
   resolves against a parent with a definite height. align-items: flex-end above stops these
   columns from stretching, so without this they would be auto-height and every bar in the
   chart would collapse to nothing. */
.chart-cols > div { flex: 1; min-width: 0; height: 100%;
  display: flex; align-items: flex-end; justify-content: center; }

.chart-bar { width: 46%; max-width: 22px; display: flex; flex-direction: column;
  justify-content: flex-end; border-radius: 4px 4px 0 0; overflow: hidden; }
.chart-bar .seg { width: 100%; }
.chart-bar .seg.paid { background: var(--accent); }
.chart-bar .seg.owed { background: #9db9f7; }

/* The spending lane hangs down from the line, so a deeper bar reads as more spent. */
.chart-spend { position: relative; height: 46px; margin-top: 8px;
  border-top: 1px solid var(--line); pointer-events: none; }
.chart-spend .chart-cols { align-items: flex-start; }
.chart-spend .chart-cols > div { align-items: flex-start; }
.chart-spend .chart-bar {
  border-radius: 0 0 4px 4px; justify-content: flex-start;
  min-height: 3px;   /* a real amount always leaves a mark, however small the month */
}
.chart-spend .chart-bar .seg { background: var(--amber); }

/* The caption that used to sit under the chart is gone. This holds open the space below the
   month labels so the card's bottom edge does not ride up against them — a little less than
   the caption itself took, which was more air than the chart needed. */
.chart-tail { height: 17px; }

/* a month with nothing in it reads as deliberate rather than missing */
.chart-empty { width: 22px; height: 2px; border-radius: 2px; background: var(--line); }

.chart-labels { display: flex; gap: 2px; margin-top: 7px; position: relative; pointer-events: none; }
.chart-labels span { flex: 1; text-align: center; font-size: 11px; color: var(--muted);
  white-space: nowrap; overflow: hidden; min-width: 0; }
.chart-labels span.now { color: var(--accent); font-weight: 700; }

/* One band of hit areas spanning both lanes, so hovering anywhere in a month lights the
   whole column and shows one panel. It sits behind the bars — the lanes above it ignore the
   pointer — so the highlight never washes over the colours it is meant to explain. */
.chart-hit { position: absolute; left: 0; right: 0; top: 0; height: 222px;
  display: flex; gap: 2px; }
/* a year with no spending yet drops the lane rather than leaving an empty strip */
.chart.no-spend .chart-hit { height: 168px; }
.chart-hit i { flex: 1; min-width: 0; border-radius: 6px; transition: background .12s; }
.chart-hit i:hover { background: rgba(36,86,230,.07); }
.chart-hit i.now { background: rgba(36,86,230,.05); }

/* hover panel */
.chart-tip {
  position: fixed; z-index: 90; pointer-events: none; opacity: 0; transition: opacity .1s;
  background: #101828; color: #fff; border-radius: 10px; padding: 10px 12px;
  font-size: 12.5px; line-height: 1.5; box-shadow: 0 10px 30px rgba(10,15,30,.32);
  min-width: 200px;
}
.chart-tip.on { opacity: 1; }
.chart-tip b { display: block; font-size: 13px; margin-bottom: 6px; white-space: nowrap; }
.chart-tip .row { display: flex; align-items: baseline; justify-content: space-between;
  gap: 18px; white-space: nowrap; }
.chart-tip .row > span:first-child { color: #aab6cc; }
.chart-tip .row > span:last-child { font-variant-numeric: tabular-nums; }
.chart-tip .row.total { border-top: 1px solid rgba(255,255,255,.16); margin-top: 5px; padding-top: 5px; }
.chart-tip .row.total > span:last-child { font-weight: 700; }
.chart-tip .k { display: inline-block; width: 8px; height: 8px; border-radius: 2px;
  margin-right: 7px; vertical-align: 0; }

@media (max-width: 720px) {
  .chart-labels span { font-size: 10px; }
  .chart-scale, .chart-plot { height: 132px; }
  .chart-hit { height: 186px; }
  .chart.no-spend .chart-hit { height: 132px; }
}

/* ---------- Reports ----------
   Two cards side by side where there is room, stacking on a narrow screen. */
.report-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-bottom: 14px; }
@media (max-width: 900px) { .report-grid { grid-template-columns: 1fr; } }
.report-grid .card { margin: 0; }

/* A proportional bar behind each row. The eye reads concentration off the bar lengths long
   before it reads the numbers, which is the point — one client at 40% of turnover should be
   obvious without arithmetic. */
.share-table { width: 100%; }
.share-table td { border-bottom: 1px solid var(--line); padding: 8px 10px 8px 0; vertical-align: middle; }
.share-table tr:last-child td { border-bottom: none; }
.share-name { font-size: 14px; max-width: 190px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.share-bar { width: 45%; padding-right: 12px !important; }
.share-bar span { display: block; height: 8px; border-radius: 4px; background: var(--accent); opacity: .8; min-width: 2px; }
.share-pct { color: var(--muted); font-size: 12.5px; width: 54px; }
.share-table td.num { font-variant-numeric: tabular-nums; white-space: nowrap; }

.total-row td { border-top: 2px solid var(--line); border-bottom: none; }
td.neg { color: var(--red); }

/* A plain-English aside under a figure — what it is built from, or what to be careful of. */
.report-note { margin-top: 14px; padding: 12px 14px; background: #f7f9fd; border: 1px solid var(--line);
  border-radius: var(--radius); font-size: 13px; line-height: 1.55; color: #46506a; }
.report-note.warn { background: var(--amber-soft); border-color: #f0dfae; color: #6b4b06; }
.report-note strong { color: var(--ink); }
.report-note.warn strong { color: #5a3f05; }

.settled { font-size: 12.5px; color: var(--green); white-space: nowrap; }

/* The profit and loss column: sub-lines indented under what they add up to */
.pl td { padding: 8px 10px 8px 0; }
.pl .sub-row td { color: var(--muted); padding-left: 16px; font-size: 13px; }
.pl .sub-row td:first-child { padding-left: 16px; }
.pl .link { margin-left: 8px; }

.handover { margin-top: 14px; }
.handover table td { font-size: 15px; padding: 9px 10px; }
.handover table td.num { font-size: 16px; }

/* Change against last year, beside the figure rather than under it */
.delta { font-size: 12.5px; font-weight: 700; padding: 2px 7px; border-radius: 20px; vertical-align: 3px; margin-left: 6px; }
.delta.up { background: var(--green-soft); color: var(--green); }
.delta.down { background: var(--red-soft); color: var(--red); }
.delta.flat { background: #eef0f4; color: var(--muted); }

/* The report is meant to be printed and handed over, so it gets a proper header on paper and
   loses everything that only makes sense on screen. */
.print-head { display: none; }
@media print {
  #sidebar, .no-print, .view-head { display: none !important; }
  #main { margin: 0 !important; width: 100% !important; padding: 0 !important; max-width: none !important; }
  body { background: #fff; }
  .print-head { display: block; margin-bottom: 18px; border-bottom: 2px solid var(--ink); padding-bottom: 10px; }
  .print-head h1 { font-size: 20px; margin: 0 0 2px; }
  .print-head div { font-size: 13px; color: var(--muted); }
  .card { break-inside: avoid; box-shadow: none; border: 1px solid #ccc; margin-bottom: 12px; }
  .report-grid { display: block; }
  .report-grid .card { margin-bottom: 12px; }
  /* auto-fit rather than a fixed four: the reports overview carries five of these and a
     hardcoded four left the fifth stranded on a row of its own when printed. */
  .kpis { display: grid !important;
    grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)) !important; }
  .share-bar span { background: #888 !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  .delta { border: 1px solid #ccc; background: none !important; color: #333 !important; }
}

/* Print (invoice PDF) */
@media print {
  body > #app, #toast-root, #modal-root { display: none !important; }
  #print-root { display: block !important; }
  body { background: #fff; }
}
#print-root { display: none; }
.inv-print { font-size: 14px; color: #111; max-width: 720px; margin: 0 auto; padding: 30px 10px; }
.inv-print header { display: flex; justify-content: space-between; margin-bottom: 34px; }
.inv-print .biz-name { font-size: 22px; font-weight: 700; }
.inv-print .inv-title { font-size: 28px; font-weight: 300; letter-spacing: .1em; color: #555; text-align: right; }
.inv-print .meta { text-align: right; font-size: 13px; color: #444; margin-top: 6px; }
.inv-print .parties { display: flex; justify-content: space-between; gap: 30px; margin-bottom: 24px; font-size: 13px; }
.inv-print .parties > div { flex: 1; }
.inv-print .meta-table { background: #f5f5f5; font-size: 13px; }
.inv-print .meta-table td { border-bottom: 1px solid #fff; padding: 7px 12px; }
.inv-print table { margin: 10px 0 6px; }
.inv-print th { border-bottom: 2px solid #222; color: #222; }
.inv-print td { border-bottom: 1px solid #e5e5e5; }
.inv-print .totals { margin-left: auto; width: 260px; font-size: 14px; margin-top: 12px; }
.inv-print .totals div { display: flex; justify-content: space-between; padding: 4px 0; }
.inv-print .totals .grand { border-top: 2px solid #222; font-weight: 700; font-size: 16px; padding-top: 8px; margin-top: 4px; }
.inv-print .foot { margin-top: 36px; font-size: 12.5px; color: #555; white-space: pre-wrap; }
/* ---------- The landing page ----------
   Separation here comes from surface and space, not from lines. The first version drew a 1px
   border around everything — cards, screenshots, the strip, each FAQ row — and a page fenced
   into compartments like that reads as a decade old however good the words are. So: almost no
   borders, soft tinted grounds, one layered shadow, and larger radii. Where a boundary really
   is needed it is a single hairline between sections, not a box around every item.

   Its own variables, deliberately. The app's palette is tuned for dense tables read all day;
   a page somebody sees once wants deeper ink, more air and a wider type scale. */
.lp {
  --ink: #0d1424;
  --body: #59627a;
  --faint: #8a93a8;
  --line: #e9ecf3;
  --wash: #f6f8fc;
  --tint: #edf2ff;
  --blue: #2456e6;
  --blue-deep: #1a3fb4;
  --soft: 0 1px 2px rgba(13,20,36,.04), 0 10px 26px rgba(13,20,36,.055);
  --lift: 0 2px 6px rgba(13,20,36,.05), 0 30px 70px rgba(13,20,36,.11);
  color: var(--body);
  line-height: 1.62;
  -webkit-font-smoothing: antialiased;
}
body.on-landing { background: #fff; }
body.on-landing #app { display: block; }

/* :where() so these count for nothing in the cascade. Written plainly as `.lp p`, the reset
   was more specific than `.lp-micro` and `.lp-lede` and quietly beat both of them — their
   margins were in the file, and had never once applied. A reset should be the thing every
   other rule wins against, which is exactly what zero specificity buys. */
.lp :where(h1, h2, h3) { color: var(--ink); margin: 0; font-weight: 700; }
.lp h1 { font-size: clamp(37px, 6vw, 62px); line-height: 1.03; letter-spacing: -.035em; }
.lp h2 { font-size: clamp(26px, 3.4vw, 38px); line-height: 1.12; letter-spacing: -.028em; }
.lp h3 { font-size: 17.5px; line-height: 1.3; letter-spacing: -.015em; }
.lp :where(p) { margin: 0; }
.lp-icon { width: 21px; height: 21px; display: block; }

/* One loud button, repeated. The glow under it is the accent colour itself at low opacity,
   so it reads as the button lifting off the page rather than a grey drop shadow. */
.lp-primary, .lp-ghost, .lp-quiet, .lp-navlink, .lp-linkish {
  font: inherit; cursor: pointer; box-shadow: none;
  transition: background .16s, border-color .16s, color .16s, transform .16s, box-shadow .16s;
}
.lp-primary { background: var(--blue); color: #fff; border: 0; padding: 16px 30px;
  border-radius: 12px; font-size: 17px; font-weight: 600; letter-spacing: -.012em;
  box-shadow: 0 2px 6px rgba(36,86,230,.22), 0 14px 30px rgba(36,86,230,.24); }
.lp-primary:hover { background: var(--blue-deep); transform: translateY(-1px);
  box-shadow: 0 3px 8px rgba(36,86,230,.26), 0 18px 38px rgba(36,86,230,.28); }
.lp-primary:active { transform: translateY(0); }
.lp-primary.sm { padding: 9px 17px; font-size: 14px; border-radius: 10px;
  box-shadow: 0 1px 3px rgba(36,86,230,.2), 0 6px 16px rgba(36,86,230,.2); }
/* Matched to the primary, including the border in the padding sum, so the two sit on exactly
   the same baseline and stand the same height. */
.lp-ghost { background: #fff; color: var(--ink); border: 1px solid var(--line);
  padding: 15px 27px; border-radius: 12px; font-size: 17px; font-weight: 600;
  letter-spacing: -.012em; }
.lp-ghost:hover { background: var(--wash); border-color: #dbe0ea; }
.lp-quiet { background: none; border: 0; color: var(--ink); font-size: 14.5px; font-weight: 600;
  padding: 9px 13px; border-radius: 9px; }
.lp-quiet:hover { background: var(--wash); }
.lp-linkish { background: none; border: 0; padding: 0; color: var(--blue); font-weight: 600;
  font-size: inherit; }
.lp-linkish:hover { color: var(--blue-deep); }

.lp-nav { position: sticky; top: 0; z-index: 40; background: rgba(255,255,255,.72);
  backdrop-filter: saturate(180%) blur(16px); -webkit-backdrop-filter: saturate(180%) blur(16px);
  border-bottom: 1px solid transparent; transition: border-color .2s, background .2s; }
.lp-nav.stuck { border-bottom-color: var(--line); background: rgba(255,255,255,.88); }
.lp-nav-in { max-width: 1140px; margin: 0 auto; padding: 14px 28px;
  display: flex; align-items: center; gap: 22px; }
/* Scoped under .lp deliberately. The same element carries .auth-brand, whose rules live in the
   signed-out section further down the file and match with the same weight — so on a plain
   `.lp-logo` selector the later rule won, keeping the anchor inline-block and the drawing at
   the sign-in card's 132px. An inline box also reserves room beneath for descenders an SVG
   does not have, which is what pushed the logo above the line of everything beside it. */
.lp .lp-logo { display: flex; align-items: center; margin: 0; flex: 0 0 auto; color: var(--ink); }
.lp .lp-logo .brand-mark { width: 104px; }
.lp-nav-links { display: flex; gap: 2px; margin-left: 10px; flex: 1; }
.lp-navlink { background: none; border: 0; color: var(--body); font-size: 14.5px;
  font-weight: 500; padding: 9px 13px; border-radius: 9px; }
.lp-navlink:hover { color: var(--ink); background: var(--wash); }
.lp-nav-cta { display: flex; align-items: center; gap: 8px; }

/* A tinted glow behind the hero rather than a flat band — it gives the top of the page depth
   without drawing an edge anywhere, and fades out before it meets the tiles. */
.lp-hero { position: relative; max-width: 1140px; margin: 0 auto; padding: 84px 28px 0;
  text-align: center; }
.lp-hero::before { content: ''; position: absolute; inset: -140px -20% auto; height: 620px;
  background: radial-gradient(ellipse 60% 100% at 50% 0%, var(--tint), transparent 70%);
  z-index: -1; pointer-events: none; }
.lp-hero-in { max-width: 760px; margin: 0 auto; }
.lp-eyebrow { display: inline-flex; align-items: center; gap: 8px; margin-bottom: 26px;
  background: #fff; border: 1px solid var(--line); color: var(--ink);
  font-size: 13.5px; font-weight: 500; padding: 7px 15px 7px 12px; border-radius: 100px;
  box-shadow: var(--soft); }
.lp-eyebrow i { width: 7px; height: 7px; border-radius: 50%; background: #16a34a;
  box-shadow: 0 0 0 3px rgba(22,163,74,.16); }
.lp-lede { font-size: clamp(16.5px, 1.9vw, 19px); margin: 24px auto 0; max-width: 620px; }
.lp-cta-row { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; margin-top: 34px; }
/* 42px, which is more than it looks. The primary button throws a coloured glow roughly 30px
   below its own box, so the gap the eye actually sees is the measurement minus the glow —
   set to the usual 16px it read as a caption stuck to the button. */
.lp-micro { font-size: 13.5px; color: var(--faint); margin-top: 42px; }

/* The screenshot sits on a stage: a tinted, rounded ground with the image inset inside it,
   which reads as a considered presentation rather than a bordered rectangle. The hero one is
   cropped at the bottom so it looks like a window onto something larger. */
.lp-hero-stage, .lp-stage { margin: 0; background: linear-gradient(180deg, #eef2fa, #e7ecf7);
  border-radius: 20px; padding: 12px; box-shadow: var(--lift); }
.lp-hero-stage { margin-top: 62px; border-radius: 22px 22px 0 0; padding: 14px 14px 0;
  max-height: 470px; overflow: hidden; }
.lp-hero-stage img, .lp-stage img { display: block; width: 100%; height: auto;
  border-radius: 12px; box-shadow: 0 1px 3px rgba(13,20,36,.10); }
.lp-hero-stage img { border-radius: 12px 12px 0 0; }

/* Tiles, not a divider bar. Separate objects with air between them and no fencing. */
.lp-tiles { list-style: none; max-width: 1140px; margin: 78px auto 0; padding: 0 28px;
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; }
.lp-tiles li { background: var(--wash); border-radius: 16px; padding: 24px 22px 22px; }
.lp-tile-ic { display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; border-radius: 11px; background: #fff; color: var(--blue);
  box-shadow: var(--soft); margin-bottom: 15px; }
.lp-tiles strong { display: block; color: var(--ink); font-size: 15.5px; letter-spacing: -.012em; }
.lp-tile-sub { display: block; font-size: 13.5px; color: var(--faint); margin-top: 3px; }

.lp-feature { max-width: 1140px; margin: 0 auto; padding: 104px 28px;
  display: grid; grid-template-columns: 1fr 1.1fr; gap: 64px; align-items: center; }
.lp-feature.flip .lp-feature-text { order: 2; }
.lp-feature h2 { margin: 14px 0 0; }
.lp-feature > div > p { font-size: 17px; margin-top: 16px; max-width: 46ch; }
.lp-tag { display: inline-block; font-size: 12px; font-weight: 600; letter-spacing: .09em;
  text-transform: uppercase; color: var(--blue); }
.lp-list { list-style: none; margin: 26px 0 0; padding: 0; display: grid; gap: 13px; }
.lp-list li { position: relative; padding-left: 30px; font-size: 15.5px; }
/* The tick is a rotated corner rather than a glyph or an image: it cannot fail to load, and a
   screen reader does not read it aloud in the middle of the sentence it decorates. */
.lp-list li::before { content: ''; position: absolute; left: 0; top: 3px; width: 19px; height: 19px;
  border-radius: 50%; background: var(--tint); }
.lp-list li::after { content: ''; position: absolute; left: 7px; top: 7px; width: 4.5px; height: 8.5px;
  border: solid var(--blue); border-width: 0 2px 2px 0; transform: rotate(43deg); }
.lp-list-lg li { font-size: 16px; }

.lp-band { background: var(--wash); padding: 104px 28px; }
.lp-band > h2 { max-width: 900px; margin: 0 auto 44px; text-align: center; }
.lp-grid { max-width: 1084px; margin: 0 auto; display: grid; gap: 16px;
  grid-template-columns: repeat(auto-fit, minmax(232px, 1fr)); }
.lp-card { background: #fff; border-radius: 18px; padding: 28px 26px; box-shadow: var(--soft); }
.lp-card p { font-size: 14.5px; margin-top: 10px; }

.lp-split { max-width: 1140px; margin: 0 auto; padding: 104px 28px;
  display: grid; grid-template-columns: 1fr 1.12fr; gap: 64px; align-items: start; }
.lp-split h2 { margin: 14px 0 0; }
.lp-split > div > p { font-size: 17px; margin-top: 16px; }

/* Rules between questions, not a box around each one. */
.lp-faq-list { max-width: 780px; margin: 0 auto; background: #fff; border-radius: 20px;
  padding: 6px 30px; box-shadow: var(--soft); }
.lp-faq details { border-bottom: 1px solid var(--line); }
.lp-faq details:last-child { border-bottom: 0; }
.lp-faq summary { cursor: pointer; color: var(--ink); font-weight: 600; font-size: 16.5px;
  letter-spacing: -.015em; padding: 22px 0; list-style: none;
  display: flex; justify-content: space-between; align-items: center; gap: 18px; }
.lp-faq summary::-webkit-details-marker { display: none; }
.lp-faq summary:hover { color: var(--blue); }
.lp-faq summary::after { content: ''; flex: 0 0 auto; width: 9px; height: 9px; margin-right: 3px;
  border: solid var(--faint); border-width: 0 1.8px 1.8px 0;
  transform: rotate(45deg) translate(-3px, -3px); transition: transform .2s; }
.lp-faq details[open] summary::after { transform: rotate(-135deg) translate(-2px, -2px); }
.lp-faq details p { font-size: 15.5px; padding: 0 0 24px; max-width: 62ch; }

/* The closing call to action gets the tinted ground, so the page ends on the brand rather
   than trailing off into white. */
.lp-end { position: relative; text-align: center; padding: 116px 28px; overflow: hidden; }
.lp-end::before { content: ''; position: absolute; inset: 0;
  background: radial-gradient(ellipse 70% 90% at 50% 55%, var(--tint), transparent 72%);
  z-index: -1; }
.lp-end h2 { max-width: 620px; margin: 0 auto; }
.lp-end > p { font-size: 17.5px; margin: 18px auto 32px; max-width: 520px; }
.lp-end .lp-micro { margin-top: 20px; }

.lp-foot { border-top: 1px solid var(--line); }
.lp-foot-in { max-width: 1140px; margin: 0 auto; padding: 40px 28px; text-align: center; }
.lp-foot-line { font-size: 13.5px; color: var(--faint); margin-top: 14px; }
.lp-foot-links { font-size: 13.5px; margin-top: 7px; }
.lp-foot-links a { color: var(--body); text-decoration: none; }
.lp-foot-links a:hover { color: var(--blue); text-decoration: underline; }

/* Sections rise a little as they arrive. Applied by script and only once seen, so if the
   script never runs the page is simply already in its finished state — the content is never
   hidden by a rule that something has to come along and undo. */
.lp-rise { opacity: 0; transform: translateY(18px); }
.lp-rise.seen { opacity: 1; transform: none; transition: opacity .6s ease, transform .6s cubic-bezier(.2,.7,.3,1); }
@media (prefers-reduced-motion: reduce) {
  .lp-rise, .lp-rise.seen { opacity: 1; transform: none; transition: none; }
  .lp-primary, .lp-primary:hover { transform: none; }
}

@media (max-width: 900px) {
  /* One column, and the picture always lands under the words it illustrates — including the
     flipped rows, where source order would otherwise put it above them. */
  .lp-feature, .lp-split { grid-template-columns: 1fr; gap: 34px; padding: 68px 22px; }
  .lp-feature.flip .lp-feature-text { order: 0; }
  .lp-tiles { grid-template-columns: 1fr 1fr; gap: 12px; margin-top: 56px; padding: 0 22px; }
  .lp-hero { padding: 54px 22px 0; }
  .lp-hero-stage { margin-top: 42px; max-height: 300px; }
  .lp-band, .lp-end { padding: 68px 22px; }
  .lp-faq-list { padding: 4px 22px; border-radius: 16px; }
  .lp-nav-links { display: none; }     /* three links are not worth a hamburger menu */
  .lp-nav-in { gap: 12px; padding: 12px 20px; }
  .lp-nav-cta { margin-left: auto; }
  .lp-cta-row { margin-top: 28px; }
  .lp-cta-row .lp-primary, .lp-cta-row .lp-ghost { flex: 1 1 250px; }
}
.lp-narrow { display: none; }
@media (max-width: 520px) {
  .lp-tiles { grid-template-columns: 1fr; }
  /* Signing in used to be dropped here to make room, on the reasoning that the logo was the
     way back. It is not — the logo returns to this page. That left anybody who already had an
     account scrolling the entire page to find the way in, on the device most likely to be
     used one-handed. Everything shrinks instead, and the sign-up button says less. */
  .lp-wide { display: none; }
  .lp-narrow { display: inline; }
  .lp .lp-logo .brand-mark { width: 84px; }
  .lp-nav-in { gap: 8px; padding: 10px 16px; }
  .lp-nav-cta { gap: 4px; }
  .lp-quiet { padding: 8px 7px; font-size: 14px; }
  .lp-primary.sm { padding: 8px 14px; font-size: 14px; }
}

/* ---------- Signed-out screens ---------- */
/* The halftone city sits behind the sign-in card. It is a busy image, and the card, the
   wordmark and the legal line all have to stay readable on top of it — so a soft white
   ellipse is laid over the middle where the content goes, fading out to leave the pattern
   showing at the edges. The flat --bg underneath is what shows if the image fails to load,
   which keeps the screen usable rather than transparent. */
/* It goes on .auth-wrap and not on the body, so it appears behind the sign-in, sign-up and
   password screens but not behind About and Terms — those are long pages of prose with no
   card behind them, and a halftone under running text is unreadable. */
.auth-wrap {
  background-color: var(--bg);
  background-image:
    radial-gradient(ellipse 640px 500px at 50% 47%,
      rgba(255,255,255,.94) 0%, rgba(255,255,255,.80) 42%, rgba(255,255,255,0) 76%),
    url('/img/ozac-background.png');
  background-repeat: no-repeat, no-repeat;
  background-position: center, center;
  background-size: cover, cover;
}
/* Lifted off the pattern — the default 1px shadow disappears against the dots. */
.auth-wrap .auth-card { box-shadow: 0 6px 28px rgba(20,30,60,.14); }
/* #app is a flex row for the sidebar layout. Signed out there is no sidebar, so it becomes a
   plain block — otherwise the card is a flex item and sits hard against the left edge. */
body.signed-out #app { display: block; }
.auth-wrap { min-height: 100vh; width: 100%; display: flex; flex-direction: column;
  align-items: center; justify-content: center; padding: 32px 20px; gap: 14px; }
.auth-card { background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: 30px 32px 26px; width: 100%; max-width: 400px; }
/* The wordmark is a link everywhere it appears — the way back from a screen that is otherwise
   a dead end. It must not look like body copy with an underline, so the anchor is stripped
   back to what the old <div> looked like and only lifts on hover. */
.auth-brand { display: inline-block; margin-bottom: 22px; color: #000; text-decoration: none; }
.auth-brand .brand-mark { width: 132px; }
a.auth-brand { cursor: pointer; }
a.auth-brand:hover { opacity: .78; }
a.auth-brand:focus-visible { outline: 2px solid var(--accent-soft); outline-offset: 3px; border-radius: 4px; }
/* 12px, doubled from 6px — the title sat almost on top of the first field. Where there is a
   subtitle it is pulled back up, because a subtitle belongs against its heading, not adrift
   between the heading and the form. */
.auth-card h1 { font-size: 20px; margin: 0 0 12px; }
.auth-card h1 + .auth-intro { margin-top: -6px; }
.auth-intro { color: var(--muted); font-size: 13.5px; margin: 0 0 18px; line-height: 1.5; }
/* Something went wrong, said in place rather than in a toast that vanishes. Used where the
   person needs to still be reading it while they decide what to do — a failed restore, say. */
.err-text { color: var(--red); }

/* How much of the allowance these books have used. A bar rather than a number alone, because
   "184 MB of 250 MB" needs arithmetic and a bar does not. */
.storage-track { height: 7px; background: #eef0f4; border-radius: 4px; overflow: hidden; }
.storage-track span { display: block; height: 100%; background: var(--accent); border-radius: 4px;
  transition: width .3s; min-width: 2px; }
.storage-track span.high { background: var(--amber); }
.storage-track span.full { background: var(--red); }

/* Prose where a form would normally be — the "sign-ups are shut" explanation. Slightly
   darker than .auth-intro because this is the message, not a subtitle above one. */
.auth-note { color: var(--ink); font-size: 13.5px; line-height: 1.6; margin: 0 0 14px; }
.auth-note a { color: var(--accent); }
.auth-field { display: block; margin-bottom: 14px; }
.auth-field > span { display: block; font-size: 13px; font-weight: 600; margin-bottom: 5px; }
.auth-field small { display: block; color: var(--muted); font-size: 12px; margin-top: 5px; line-height: 1.4; }
.auth-pw { position: relative; display: block; }
.auth-pw input { padding-right: 62px; }
.auth-eye { position: absolute; right: 5px; top: 50%; transform: translateY(-50%);
  background: none; border: 0; color: var(--muted); font-size: 12.5px; font-weight: 600;
  padding: 5px 8px; cursor: pointer; box-shadow: none; }
.auth-eye:hover { color: var(--accent); background: none; }
.auth-submit { width: 100%; margin-top: 6px; justify-content: center; }
.auth-foot { margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--line);
  font-size: 13px; color: var(--muted); text-align: center; }
.auth-foot a { color: var(--accent); text-decoration: none; font-weight: 600; }
.auth-foot a:hover { text-decoration: underline; }
.auth-sep { margin: 0 6px; opacity: .5; }
.auth-msg { font-size: 13px; line-height: 1.5; padding: 10px 12px; border-radius: 8px; margin-bottom: 16px;
  background: var(--accent-soft); color: var(--ink); border: 1px solid var(--line); }
.auth-msg.error { background: #fdeceb; border-color: #f3c4c0; color: #8a2018; }
.auth-msg.ok { background: #eaf6ef; border-color: #bfe3cd; color: #14603a; }
.auth-locallink { display: inline-block; margin-top: 8px; font-weight: 600; color: var(--accent); }
.auth-legal { font-size: 12.5px; color: var(--muted); text-align: center; margin: 0; }
.auth-legal a { color: var(--muted); text-decoration: underline; }

/* This line used to sit on the background underneath the card, which meant small grey text
   over a halftone — unreadable, and no amount of adjusting the image behind it would have
   fixed that. It belongs to the card instead: a ledge across the foot of it, on its own
   quiet band, reaching the full width by pulling out through the card's padding. The links
   go on their own centred line so that neither they nor the sentence has to be squeezed. */
.auth-ledge {
  margin: 22px -32px -26px;                 /* out to the card's edges and down to its base */
  padding: 13px 22px 15px;
  border-top: 1px solid var(--line);
  border-radius: 0 0 var(--radius) var(--radius);
  background: #f7f8fb;
  text-align: center;
  font-size: 12.5px;
  line-height: 1.65;
  color: var(--muted);
}
.auth-ledge > span { display: block; }      /* the sentence, then the links, each on its own line */
.auth-ledge a { color: var(--muted); text-decoration: underline; }
.auth-ledge a:hover { color: var(--accent); }

/* Business switcher inside the account menu */
.biz-switch { padding: 4px 0; }
.biz-switch-label { font-size: 11px; text-transform: uppercase; letter-spacing: .05em;
  color: var(--muted); padding: 6px 12px 4px; font-weight: 600; }
.biz-menu-item.current { color: var(--accent); font-weight: 600; }

/* ---------- Tabs ---------- */
.tabs { display: flex; gap: 2px; border-bottom: 1px solid var(--line); margin: -6px 0 18px; }
a.tab { text-decoration: none; }
.tab {
  appearance: none; background: none; border: 0; box-shadow: none;
  padding: 9px 16px; margin-bottom: -1px; cursor: pointer;
  font-size: 14px; font-weight: 600; color: var(--muted);
  border-bottom: 2px solid transparent; border-radius: 8px 8px 0 0;
}
.tab:hover { color: var(--ink); background: rgba(36,86,230,.05); }
.tab.active { color: var(--accent); border-bottom-color: var(--accent); background: none; }
.tab:focus-visible { outline: 2px solid var(--accent-soft); outline-offset: -2px; }
.tab-actions { margin-top: 16px; }

/* Settings columns: cards stack in the column they were put in, rather than being
   auto-placed by the grid and leaving ragged gaps between them. */
.two-col > .col { display: flex; flex-direction: column; gap: 14px; min-width: 0; }

/* A field that has been complained about, and where the complaint appears */
.auth-field.bad input { border-color: #d9534f; }
.auth-field.bad input:focus { outline-color: #fbdad8; border-color: #d9534f; }
.auth-field.bad > span { color: #8a2018; }
.auth-err { display: block; color: #8a2018; font-size: 12.5px; margin-top: 5px; line-height: 1.4; }
.auth-hint { display: block; color: var(--muted); font-size: 12px; margin-top: 5px; line-height: 1.4; }

/* ---------- Setting up a new business ---------- */
.auth-card.wide { max-width: 620px; }
.setup-progress { display: flex; align-items: center; gap: 6px; margin-bottom: 16px; }
.setup-dot { width: 26px; height: 4px; border-radius: 2px; background: var(--line); }
.setup-dot.done { background: #9db9f7; }
.setup-dot.now { background: var(--accent); }
.setup-count { margin-left: 8px; font-size: 12px; color: var(--muted); font-weight: 600; }
.setup-body { margin-bottom: 4px; }
.setup-body .row { display: flex; gap: 12px; flex-wrap: wrap; }
.setup-body .row > .auth-field { flex: 1; min-width: 180px; }
.setup-body .cur-grid { max-height: 260px; overflow-y: auto; padding: 2px; }
.setup-nav {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  margin-top: 22px; padding-top: 16px; border-top: 1px solid var(--line);
}
.setup-nav-right { display: flex; gap: 8px; align-items: center; }

/* A card for something you cannot undo */
.danger-card { border-color: #f0c8c4; }
.danger-card h2 { color: var(--red); }
.doc a { color: var(--accent); }

/* About and Terms read by someone who has not signed in */
.public-wrap { max-width: 760px; margin: 0 auto; padding: 24px 20px 60px; }
.public-head { display: flex; align-items: center; justify-content: space-between;
  gap: 12px; margin-bottom: 22px; }
.public-head .auth-brand { margin: 0; }
.public-body .view-head { margin-bottom: 18px; }
.public-body .doc { display: flex; flex-direction: column; gap: 14px; }
.public-wrap .auth-legal { margin-top: 26px; }
