/* Simple Invoice - designed for a phone first, then widened for desktop. */

:root {
  --bg: #f5f6f8;
  --surface: #ffffff;
  --border: #e3e6ea;
  --text: #191c22;
  --muted: #667085;
  --primary: #2f5bea;
  --primary-dark: #1e42b8;
  --primary-soft: #eef2fe;
  --success: #12805c;
  --danger: #b42318;
  --danger-soft: #fef3f2;
  --warn: #b54708;
  --radius: 10px;
  --shadow: 0 1px 2px rgba(16, 24, 40, .06), 0 1px 3px rgba(16, 24, 40, .04);
  --nav-h: 64px;

  /* Everything below has a dark counterpart further down this file. */
  --link: #2f5bea;
  --series-invoiced: #2f5bea;
  --series-collected: #12805c;
  --input-border: #cfd4dc;
  --hover: #fafbfc;
  --subtle: #fcfcfd;
  --neutral-soft: #f2f4f7;
  --neutral-text: #475467;
  --neutral-faint: #98a2b3;
  --primary-border: #c7d5fc;
  --success-soft: #ecfdf3;
  --success-border: #a6f4c5;
  --warn-soft: #fffaeb;
  --warn-border: #fedf89;
  --danger-border: #fda29b;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
}

/* The app's own typeface, served with it: the same on every computer and
   phone rather than whatever each one has. One file carries every weight
   from 100 to 900, so the in-between weights the app uses (500, 550, 600,
   650) are drawn as designed instead of being rounded to regular or bold.
   Named apart from "Inter" in fonts.css, which is the invoices' lettering
   and is read by the PDF maker; that stays as it is. SIL Open Font License,
   from rsms.me/inter. */
@font-face {
  font-family: "InterVariable";
  src: url("../fonts/InterVariable.2bf3d951bf9d.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

body {
  background: var(--bg);
  color: var(--text);
  font-family: "InterVariable", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  font-optical-sizing: auto;
  /* Inter's clearer letters: an l with a tail and an I with bars, so "Il1"
     and codes like INV-0011 can never be misread. */
  font-feature-settings: "cv05", "cv08";
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--link); }

/* Buttons and boxes use the page's typeface, not the browser's own. */
button, input, select, textarea { font-family: inherit; }

h1 { font-size: 1.5rem; line-height: 1.25; margin: 0 0 .25rem; letter-spacing: -.02em; font-weight: 700; }
h2 { font-size: 1.125rem; margin: 0 0 .75rem; letter-spacing: -.01em; font-weight: 650; }

.muted { color: var(--muted); }
.small { font-size: .875rem; }

/* ---------- Signed-out pages (sign in, sign up, password reset) ---------- */

.auth-wrap {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 2rem 1rem;
}

.auth-card {
  width: 100%;
  max-width: 400px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  box-shadow: var(--shadow);
  padding: 1.75rem;
}

.brand {
  display: flex;
  align-items: center;
  gap: .5rem;
  font-weight: 650;
  letter-spacing: -.01em;
  margin-bottom: 1.5rem;
  color: var(--text);
  text-decoration: none;
}

.brand-mark {
  font-feature-settings: normal;   /* a plain I in the logo */
  width: 28px;
  height: 28px;
  border-radius: 7px;
  background: var(--primary);
  color: #fff;
  display: grid;
  place-items: center;
  font-size: .8rem;
  font-weight: 700;
}

.auth-alt {
  margin-top: 1.25rem;
  text-align: center;
  font-size: .9rem;
  color: var(--muted);
}

/* ---------- Signed-in layout ---------- */

.topbar {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  height: 56px;
  padding: 0 1rem;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}

.content {
  padding: 1.25rem 1rem calc(var(--nav-h) + 2rem);
  max-width: 1080px;
  margin: 0 auto;
}

/* The Branding page, which has a live preview beside the controls and so
   has a use for a wide screen. Every other page keeps the narrower measure,
   which is easier to read. */
.content-wide { max-width: 1480px; }

.page-head { margin-bottom: 1.25rem; }

/* Bottom tab bar on phones */
.nav {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 30;
  display: grid;
  /* Counts itself rather than being told how many items there are, so adding
     one to the markup cannot leave the last one hanging off the end. */
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  background: var(--surface);
  border-top: 1px solid var(--border);
  padding-bottom: env(safe-area-inset-bottom);
}

.nav a {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  height: var(--nav-h);
  font-size: .7rem;
  font-weight: 550;
  color: var(--muted);
  text-decoration: none;
}

.nav a svg { width: 21px; height: 21px; stroke-width: 1.8; }

/* Seven items across a narrow phone. The label has to give up a little to keep
   "Dashboard" on one line at 360px. */
@media (max-width: 420px) {
  .nav a { font-size: .56rem; gap: 2px; }
  .nav a svg { width: 19px; height: 19px; }
}
.nav a.active { color: var(--primary); }

/* ---------- Cards and summary tiles ---------- */

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 1.25rem;
}

.tiles {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: .75rem;
  margin-bottom: 1.25rem;
}

.tile {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: .9rem 1rem;
}

.tile-label {
  font-size: .78rem;
  font-weight: 550;
  color: var(--muted);
  display: block;
  margin-bottom: .3rem;
}

.tile-value {
  display: block;
  font-size: 1.35rem;
  font-weight: 650;
  letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
}

.tile.is-overdue .tile-value { color: var(--danger); }
.tile.is-collected .tile-value { color: var(--success); }

/* Several currencies stack, so they sit a little smaller than a lone figure. */
.tile .tile-value ~ .tile-value { font-size: 1.05rem; }
.tile-value.is-quiet { font-size: 1rem; font-weight: 550; color: var(--muted); }
.tile.is-collected .tile-value.is-quiet { color: var(--muted); }

/* ---------- Empty states ---------- */

.empty {
  text-align: center;
  padding: 2.5rem 1.25rem;
}

.empty-icon {
  width: 44px;
  height: 44px;
  margin: 0 auto .9rem;
  border-radius: 12px;
  background: var(--primary-soft);
  color: var(--primary);
  display: grid;
  place-items: center;
}

.empty h2 { margin-bottom: .35rem; }
.empty p { color: var(--muted); margin: 0 auto 1.25rem; max-width: 34ch; }

/* ---------- Forms ---------- */

.field { margin-bottom: 1rem; }

.field label,
.field .label {
  display: block;
  font-size: .875rem;
  font-weight: 550;
  margin-bottom: .35rem;
}

/* Not checkboxes or radios. A tick stretched to the full width of the form
   is what made the old "Clear" control on the logo field unreadable: a bar
   the width of the page with a tiny tick adrift at the far end of it. */
.field input:not([type="checkbox"]):not([type="radio"]):not([type="color"]) {
  width: 100%;
  padding: .625rem .75rem;
  font-size: 1rem;
  font-family: inherit;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--input-border);
  border-radius: 8px;
}

.field input:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-soft);
}

.help {
  font-size: .8rem;
  color: var(--muted);
  margin-top: .3rem;
}

.field .help ul { margin: .2rem 0 0; padding-left: 1.1rem; }

.field-error input { border-color: var(--danger); }


/* ---------- Image uploads ----------

   The stock widget showed a stored path, a bare tick labelled "Clear" and a
   second file box labelled "Change". This shows the picture. */

.image-upload-current {
  display: flex;
  align-items: flex-start;
  gap: .9rem;
  padding: .75rem;
  margin-bottom: .6rem;
  background: var(--subtle);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

.image-upload-preview {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 92px;
  height: 64px;
  padding: 4px;
  overflow: hidden;
  /* White behind it whatever the theme: these are images made to sit on a
     printed invoice, and a logo drawn in dark ink vanishes on a dark panel. */
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 6px;
}

.image-upload-preview img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

.image-upload-actions { min-width: 0; }

.image-upload-note {
  margin: 0 0 .45rem;
  font-size: .82rem;
  color: var(--muted);
}

/* The whole thing is the label, so the words are part of the hit target
   rather than a tick you have to aim at. */
.image-upload-remove {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  margin: 0;
  font-size: .85rem;
  font-weight: 550;
  color: var(--danger);
  cursor: pointer;
}

.image-upload-remove input { margin: 0; cursor: pointer; accent-color: var(--danger); }

.error {
  font-size: .82rem;
  color: var(--danger);
  margin-top: .3rem;
}

/* Messages and warnings: a solid bar down the left edge in the message's
   own colour, and slightly larger, heavier text, so they are not missed. */
.alert {
  border-radius: 8px;
  padding: .8rem 1rem;
  font-size: .99rem;
  font-weight: 500;
  line-height: 1.5;
  margin-bottom: 1rem;
  border: 1px solid transparent;
  border-left-width: 5px;
}

.alert-error {
  background: var(--danger-soft);
  border-color: var(--danger-border);
  border-left-color: var(--danger);
  color: var(--danger);
}

.alert-success {
  background: var(--success-soft);
  border-color: var(--success-border);
  border-left-color: var(--success);
  color: var(--success);
}

.alert-info {
  background: var(--primary-soft);
  border-color: var(--primary-border);
  border-left-color: var(--primary);
  color: var(--primary-dark);
}

/* ---------- Buttons ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .4rem;
  padding: .625rem 1.1rem;
  font-size: .95rem;
  font-family: inherit;
  font-weight: 600;
  border-radius: 8px;
  border: 1px solid transparent;
  cursor: pointer;
  text-decoration: none;
  transition: background .12s ease;
}

.btn-primary { background: var(--primary); color: #fff; }
.btn-primary:hover { background: var(--primary-dark); }

.btn-secondary {
  background: var(--surface);
  border-color: var(--input-border);
  color: var(--text);
}
.btn-secondary:hover { background: var(--bg); }

.btn-block { width: 100%; }

.btn-small { padding: .38rem .7rem; font-size: .82rem; }

.btn-danger { background: var(--danger); color: #fff; }
.btn-danger:hover { filter: brightness(.93); }

.btn-link {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  font-size: .875rem;
  color: var(--muted);
  cursor: pointer;
  text-decoration: underline;
}

.badge {
  display: inline-block;
  font-size: .76rem;
  font-weight: 600;
  padding: .22rem .6rem;
  border-radius: 999px;
  background: var(--primary-soft);
  color: var(--primary-dark);
}

.badge-good { background: var(--success-soft); color: var(--success); }
.badge-warn { background: var(--warn-soft); color: var(--warn); }

/* ---------- Settings: Account ---------- */

.account-email {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .5rem .75rem;
  margin-bottom: 1.25rem;
}
.account-address { font-size: 1.05rem; overflow-wrap: anywhere; }
.account-pending p { margin: 0 0 .6rem; }
.account-pending-actions { display: flex; flex-wrap: wrap; gap: .5rem; }
.account-note { margin: 0 0 .25rem; }

/* The address on the Business page, shown rather than typed into. */
.field-static {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .4rem .75rem;
  padding: .55rem 0 .1rem;
}

/* ---------- Wider screens: swap the tab bar for a sidebar ---------- */

@media (min-width: 900px) {
  body.app {
    display: grid;
    grid-template-columns: 232px 1fr;
    grid-template-rows: auto 1fr;
    min-height: 100vh;
  }

  .topbar {
    grid-column: 2;
    padding: 0 2rem;
  }

  .nav {
    position: sticky;
    top: 0;
    grid-row: 1 / 3;
    grid-column: 1;
    align-self: start;
    height: 100vh;
    display: flex;
    flex-direction: column;
    gap: 2px;
    border-top: none;
    border-right: 1px solid var(--border);
    padding: 1rem .75rem;
  }

  .nav .brand { padding: .25rem .5rem 1.25rem; margin: 0; }

  .nav a {
    flex-direction: row;
    justify-content: flex-start;
    gap: .7rem;
    height: 40px;
    padding: 0 .7rem;
    border-radius: 7px;
    font-size: .9rem;
  }

  .nav a:hover { background: var(--bg); }
  .nav a.active { background: var(--primary-soft); }

  .content {
    grid-column: 2;
    padding: 1.75rem 2rem 3rem;
    width: 100%;
  }

  .tiles { grid-template-columns: repeat(4, 1fr); }
  h1 { font-size: 1.75rem; }
}

@media (max-width: 899px) {
  .nav .brand { display: none; }
}

/* =========================================================================
   Phase 1: clients, invoices, settings
   ========================================================================= */

.page-head-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 1.25rem;
  flex-wrap: wrap;
}

.section { margin-bottom: 1.5rem; }

.section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: .75rem;
}

.section-head h2 { margin: 0; }

/* ---------- Search and filter bar ---------- */

.toolbar {
  display: flex;
  gap: .5rem;
  flex-wrap: wrap;
  margin-bottom: 1rem;
}

/* ---------- Dropdowns ----------

   Every select in the app, in one place. The native control is switched off
   and a chevron drawn instead: left alone, a dropdown renders differently on
   every platform and on Windows arrives as a hard black rectangle that
   belongs to nothing else on the page.

   Kept here, above the rules that size them, so a toolbar or a compact
   filter can still change the padding and the type size without having to
   restate everything.

   Anything that opens as a list rather than a menu - a multiple select, or
   one with a size - keeps the browser's own scrolling and loses the arrow,
   which would otherwise sit over the first row. */

select {
  appearance: none;
  -webkit-appearance: none;
  padding: .625rem 2.1rem .625rem .75rem;
  font-family: inherit;
  font-size: 1rem;
  line-height: 1.4;
  color: var(--text);
  background-color: var(--surface);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23667085' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6l4 4 4-4'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right .7rem center;
  background-size: 15px;
  border: 1px solid var(--input-border);
  border-radius: 8px;
  cursor: pointer;
  transition: border-color .12s ease, box-shadow .12s ease;
}

select:hover:not(:disabled) { border-color: var(--neutral-faint); }

select:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-soft);
}

select:disabled {
  color: var(--muted);
  background-color: var(--neutral-soft);
  cursor: not-allowed;
}

select[multiple],
select[size]:not([size="1"]) {
  background-image: none;
  padding-right: .75rem;
  cursor: default;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) select { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%2395a0b2' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6l4 4 4-4'/%3E%3C/svg%3E"); }
}

:root[data-theme="dark"] select { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%2395a0b2' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6l4 4 4-4'/%3E%3C/svg%3E"); }

.toolbar input[type="search"],
.toolbar select {
  padding: .5rem .7rem;
  /* The arrow needs the room on the right; the search box beside it does
     not, and is put back below. */
  font-size: .9rem;
  font-family: inherit;
  border: 1px solid var(--input-border);
  border-radius: 8px;
  /* Not the `background` shorthand - it resets background-image, and the
     dropdown's chevron is a background image. */
  background-color: var(--surface);
  color: var(--text);
}

.toolbar select { padding-right: 2rem; background-position: right .6rem center; }
.toolbar input[type="search"] { flex: 1 1 200px; min-width: 0; }

.chips { display: flex; gap: .35rem; flex-wrap: wrap; margin-bottom: 1rem; }

.chip {
  padding: .3rem .7rem;
  font-size: .82rem;
  font-weight: 550;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--muted);
  text-decoration: none;
}

.chip.active { background: var(--primary); border-color: var(--primary); color: #fff; }

/* ---------- Record lists ---------- */

.rows { display: flex; flex-direction: column; }

.row-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: .85rem 1.1rem;
  border-bottom: 1px solid var(--border);
  text-decoration: none;
  color: inherit;
}

.row-item:last-child { border-bottom: none; }
.row-item:hover { background: var(--hover); }

.row-main { min-width: 0; }
.row-title { font-weight: 600; display: block; }

.row-sub {
  font-size: .83rem;
  color: var(--muted);
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.row-side { text-align: right; flex-shrink: 0; }

.row-amount {
  font-weight: 650;
  font-variant-numeric: tabular-nums;
  display: block;
}

.card-flush { padding: 0; overflow: hidden; }

/* ---------- Status badges ---------- */

.badge-draft { background: var(--neutral-soft); color: var(--neutral-text); }
.badge-sent { background: var(--primary-soft); color: var(--primary-dark); }
.badge-paid { background: var(--success-soft); color: var(--success); }
.badge-partially-paid { background: var(--warn-soft); color: var(--warn); }
.badge-overdue { background: var(--danger-soft); color: var(--danger); }
.badge-cancelled { background: var(--neutral-soft); color: var(--neutral-faint); text-decoration: line-through; }

/* ---------- Forms ---------- */

.form-grid { display: grid; grid-template-columns: 1fr; gap: 0 1rem; }

.field textarea,
.field select {
  width: 100%;
  padding: .625rem .75rem;
}

/* Back to the room the arrow needs - the shared rule above set it, and the
   line above just took it away again. */
.field select { padding-right: 2.1rem; }

.field textarea,
.field select {
  font-size: 1rem;
  font-family: inherit;
  color: var(--text);
  /* Not the `background` shorthand - it resets background-image, and the
     dropdown's chevron is a background image. */
  background-color: var(--surface);
  border: 1px solid var(--input-border);
  border-radius: 8px;
}

.field textarea:focus,
.field select:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-soft);
}

.field-checkbox { display: flex; align-items: center; gap: .5rem; }
.field-checkbox input { width: auto; }
.field-checkbox label { margin: 0; }

.form-actions {
  display: flex;
  gap: .6rem;
  align-items: center;
  flex-wrap: wrap;
  margin-top: 1.25rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--border);
}

.form-actions .spacer { flex: 1; }

fieldset {
  border: none;
  margin: 0 0 1.5rem;
  padding: 0;
}

fieldset legend {
  font-weight: 650;
  font-size: .95rem;
  padding: 0;
  margin-bottom: .1rem;
}

.fieldset-note { font-size: .83rem; color: var(--muted); margin: 0 0 1rem; }

/* ---------- Invoice line items ---------- */

.line-items { display: flex; flex-direction: column; gap: .6rem; }

.line-item {
  display: grid;
  grid-template-columns: 1fr;
  gap: .5rem;
  padding: .85rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--subtle);
}

.line-item .field { margin: 0; }
.line-item.removed { display: none; }

.line-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
}

.line-total {
  font-weight: 650;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* A small button rather than a word. As plain red text it was readable but
   easy to miss, and did not look like something to press. Same light red
   box as the other remove controls, so every "remove" in the app looks the
   same. */
.line-remove {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  padding: .35rem .65rem;
  border: 1px solid var(--danger-border);
  border-radius: 6px;
  background: var(--danger-soft);
  color: var(--danger);
  font: inherit;
  font-size: .85rem;
  font-weight: 600;
  line-height: 1.2;
  white-space: nowrap;
  cursor: pointer;
}

.line-remove svg { width: 14px; height: 14px; flex: none; }

.line-remove:hover { border-color: var(--danger); }

.line-remove:focus-visible {
  outline: 2px solid var(--danger);
  outline-offset: 2px;
}

/* ---------- Totals ---------- */

.totals { margin-left: auto; max-width: 340px; width: 100%; }

.totals-row {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding: .35rem 0;
  font-size: .92rem;
}

.totals-row.grand {
  border-top: 1px solid var(--border);
  margin-top: .35rem;
  padding-top: .65rem;
  font-size: 1.1rem;
  font-weight: 700;
}

.totals-row span:last-child { font-variant-numeric: tabular-nums; }
.totals-row.muted-row { color: var(--muted); font-size: .84rem; }

/* ---------- Invoice preview ---------- */

.paper {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 1.5rem 1.25rem;
}

.paper-head {
  display: flex;
  justify-content: space-between;
  gap: 1.5rem;
  flex-wrap: wrap;
  margin-bottom: 1.75rem;
}

/* display:block matters: an img is inline by default, which would put the
   business name on the same line as the logo. */
.paper-logo {
  display: block;
  max-height: 56px;
  max-width: 200px;
  width: auto;
  height: auto;
  margin-bottom: .6rem;
}
.paper-title { font-size: 1.5rem; font-weight: 700; letter-spacing: -.02em; margin: 0; }

.paper-parties {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.25rem;
  margin-bottom: 1.75rem;
}

.paper-label {
  font-size: .72rem;
  font-weight: 650;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--muted);
  display: block;
  margin-bottom: .3rem;
}

.paper-lines { width: 100%; border-collapse: collapse; margin-bottom: 1.25rem; }

.paper-lines th {
  text-align: left;
  font-size: .72rem;
  font-weight: 650;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--muted);
  padding: 0 .5rem .5rem 0;
  border-bottom: 1px solid var(--border);
}

.paper-lines th.num, .paper-lines td.num { text-align: right; padding-right: 0; }

.paper-lines td {
  padding: .65rem .5rem .65rem 0;
  border-bottom: 1px solid var(--border);
  font-size: .92rem;
  vertical-align: top;
}

.paper-lines td.num { font-variant-numeric: tabular-nums; white-space: nowrap; }

.paper-note {
  white-space: pre-wrap;
  font-size: .88rem;
  color: var(--muted);
  margin: 0;
}

.paper-foot {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.25rem;
  margin-top: 1.5rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--border);
}

.meta-list { display: grid; gap: .3rem; font-size: .88rem; }
.meta-list div { display: flex; justify-content: space-between; gap: 1rem; }
.meta-list dt, .meta-list .k { color: var(--muted); }

.history { font-size: .85rem; }
.history li { margin-bottom: .35rem; color: var(--muted); }

.actions-bar {
  display: flex;
  gap: .5rem;
  flex-wrap: wrap;
  margin-bottom: 1.25rem;
}

/* Where an invoice stands, in words, under its number. */
.status-line {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .35rem .6rem;
  margin: .35rem 0 0;
}
.status-line .badge { font-size: .8rem; padding: .28rem .65rem; }
.status-line strong { font-size: 1.05rem; }

/* The invoice page's buttons wrap among themselves; "More" keeps its place
   at the right of the first line. */
.invoice-actions { flex-wrap: nowrap; align-items: flex-start; }
.invoice-actions .actions-main { display: flex; flex-wrap: wrap; gap: .5rem; flex: 1; min-width: 0; }

/* "More": the rarely wanted actions, kept out of the way of a slip. */
.more-menu { position: relative; margin-left: auto; flex: none; }
.more-menu > summary { list-style: none; cursor: pointer; }
.more-menu > summary::-webkit-details-marker { display: none; }
.more-list {
  position: absolute;
  right: 0;
  top: calc(100% + 4px);
  z-index: 20;
  min-width: 190px;
  padding: .3rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 8px 24px rgba(16, 24, 40, .14);
}
.more-list button,
.more-list a {
  display: block;
  width: 100%;
  padding: .55rem .7rem;
  border: 0;
  border-radius: 6px;
  background: none;
  color: var(--text);
  font: inherit;
  font-size: .92rem;
  text-align: left;
  cursor: pointer;
}
.more-list button:hover,
.more-list a:hover { background: var(--hover); }
.more-list a { text-decoration: none; }
.more-list button.is-danger { color: var(--danger); }

.warn-box {
  background: var(--warn-soft);
  border: 1px solid var(--warn-border);
  border-left: 5px solid var(--warn);
  color: var(--warn);
  border-radius: 8px;
  padding: .8rem 1rem;
  font-size: .97rem;
  font-weight: 500;
  line-height: 1.5;
  margin-bottom: 1rem;
}

/* A small symbol at the start of each message, drawn in the message's own
   colour, so its kind is clear before it is read: a triangle for a
   warning, an "i" for a notice, a tick for done, a "!" for a problem. */
.alert,
.warn-box {
  position: relative;
  padding-left: 2.75rem;
}

.alert::before,
.warn-box::before {
  content: "";
  position: absolute;
  left: .9rem;
  top: calc(.8rem + .75em - .625rem);
  width: 1.25rem;
  height: 1.25rem;
  background-color: currentColor;
  -webkit-mask: var(--message-symbol) center / contain no-repeat;
  mask: var(--message-symbol) center / contain no-repeat;
}

.warn-box { --message-symbol: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 9v4'/%3E%3Cpath d='M10.363 3.591l-8.106 13.534a1.914 1.914 0 0 0 1.636 2.871h16.214a1.914 1.914 0 0 0 1.636 -2.87l-8.106 -13.536a1.914 1.914 0 0 0 -3.274 0z'/%3E%3Cpath d='M12 16h.01'/%3E%3C/svg%3E"); }
.alert-info { --message-symbol: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 8h.01'/%3E%3Cpath d='M11 12h1v4h1'/%3E%3C/svg%3E"); }
.alert-success { --message-symbol: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M9 12l2 2l4 -4'/%3E%3C/svg%3E"); }
.alert-error { --message-symbol: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 8v4'/%3E%3Cpath d='M12 16h.01'/%3E%3C/svg%3E"); }

@media (min-width: 700px) {
  .form-grid { grid-template-columns: 1fr 1fr; }
  .form-grid .full { grid-column: 1 / -1; }

  /* The last column is sized by its own content rather than given a fixed
     width. It used to be 40px, which is narrower than the word "Remove" -
     so the word overflowed its button and hung off the right edge of the
     row. */
  .line-item {
    grid-template-columns: 1fr 100px 130px 130px auto;
    align-items: end;
    gap: .75rem;
  }

  .line-foot { display: contents; }
  .line-total { text-align: right; padding-bottom: .6rem; }
  /* Lined up with the middle of the boxes beside it. This used to take the
     button's right padding away - left over from when Remove was plain
     text - which squashed the word against the button's edge. */
  .line-remove { justify-self: end; margin-bottom: .45rem; }

  .paper { padding: 2.25rem; }
  .paper-parties { grid-template-columns: 1fr 1fr; }
  .paper-foot { grid-template-columns: 1.2fr 1fr; }
}

/* =========================================================================
   Dark mode
   -------------------------------------------------------------------------
   Follows whatever the computer is set to. The button in the top bar
   overrides that, and the choice is remembered in the browser.

   The invoice document itself is deliberately NOT themed - see document.css.
   ========================================================================= */

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;

    --bg: #0f1217;
    --surface: #171b22;
    --border: #272d37;
    --text: #e7eaef;
    --muted: #95a0b2;

    --primary: #3b6bee;
    --primary-dark: #5583f7;
    --primary-soft: #1a2440;

    --success: #3ddc97;
    --danger: #ff9d93;
    --danger-soft: #2b1a19;
    --warn: #f0b45f;

    --link: #85a7fb;
    --series-invoiced: #3d6ef5;
    --series-collected: #22a873;
    --input-border: #39414e;
    --hover: #1d222a;
    --subtle: #1b2027;
    --neutral-soft: #242a34;
    --neutral-text: #b3bccb;
    --neutral-faint: #7d8799;
    --primary-border: #2c3c66;
    --success-soft: #11291f;
    --success-border: #1d4d38;
    --warn-soft: #2a2115;
    --warn-border: #574126;
    --danger-border: #5d2f2b;

    --shadow: 0 1px 2px rgba(0, 0, 0, .4), 0 1px 3px rgba(0, 0, 0, .3);
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;

  --bg: #0f1217;
  --surface: #171b22;
  --border: #272d37;
  --text: #e7eaef;
  --muted: #95a0b2;

  --primary: #3b6bee;
  --primary-dark: #5583f7;
  --primary-soft: #1a2440;

  --success: #3ddc97;
  --danger: #ff9d93;
  --danger-soft: #2b1a19;
  --warn: #f0b45f;

  --link: #85a7fb;
  --series-invoiced: #3d6ef5;
  --series-collected: #22a873;
  --input-border: #39414e;
  --hover: #1d222a;
  --subtle: #1b2027;
  --neutral-soft: #242a34;
  --neutral-text: #b3bccb;
  --neutral-faint: #7d8799;
  --primary-border: #2c3c66;
  --success-soft: #11291f;
  --success-border: #1d4d38;
  --warn-soft: #2a2115;
  --warn-border: #574126;
  --danger-border: #5d2f2b;

  --shadow: 0 1px 2px rgba(0, 0, 0, .4), 0 1px 3px rgba(0, 0, 0, .3);
}

/* ---------- The light / dark button ---------- */

.theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  color: var(--muted);
  cursor: pointer;
}

.theme-toggle:hover { background: var(--hover); color: var(--text); }
.theme-toggle svg { width: 17px; height: 17px; }

.theme-toggle .icon-sun { display: none; }
.theme-toggle .icon-moon { display: block; }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle .icon-sun { display: block; }
  :root:not([data-theme="light"]) .theme-toggle .icon-moon { display: none; }
}

:root[data-theme="dark"] .theme-toggle .icon-sun { display: block; }
:root[data-theme="dark"] .theme-toggle .icon-moon { display: none; }
:root[data-theme="light"] .theme-toggle .icon-sun { display: none; }
:root[data-theme="light"] .theme-toggle .icon-moon { display: block; }

.topbar-right { display: flex; align-items: center; gap: .75rem; }

.auth-top {
  position: absolute;
  top: 1rem;
  right: 1rem;
}

/* =========================================================================
   Phase 4: the Income page
   ========================================================================= */

.tile-foot {
  display: block;
  margin-top: .3rem;
  font-size: .74rem;
  color: var(--muted);
}

.range-fields { display: flex; gap: .5rem; }
.range-fields.is-hidden { display: none; }

.range-fields input[type="date"] {
  padding: .5rem .7rem;
  font-size: .9rem;
  font-family: inherit;
  border: 1px solid var(--input-border);
  border-radius: 8px;
  background: var(--surface);
  color: var(--text);
}

/* ---------- Tables of figures ---------- */

table.data {
  width: 100%;
  border-collapse: collapse;
  margin-top: 1rem;
  font-size: .9rem;
}

table.data th {
  text-align: left;
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted);
  padding: 0 .75rem .5rem 0;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}

table.data td {
  padding: .6rem .75rem .6rem 0;
  border-bottom: 1px solid var(--border);
}

table.data tr:last-child td { border-bottom: none; }

table.data th.num,
table.data td.num {
  text-align: right;
  padding-right: 0;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* ---------- Legend ----------
   Two series always carry a legend, so identity is never colour alone. */

.legend {
  display: flex;
  gap: 1rem;
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: .82rem;
  color: var(--muted);
}

.legend li { display: flex; align-items: center; gap: .4rem; }

.swatch {
  width: 10px;
  height: 10px;
  border-radius: 3px;
  display: inline-block;
}

.swatch-invoiced { background: var(--series-invoiced); }
.swatch-collected { background: var(--series-collected); }

/* ---------- Month by month ----------
   Thin marks, rounded tops anchored to the baseline, a recessive baseline
   rather than a grid, and a gap between the two bars of a month so the
   shapes stay separable without relying on colour. */

.chart {
  margin: 1.25rem 0 .5rem;
  padding-bottom: .25rem;
  border-bottom: 1px solid var(--border);
  overflow-x: auto;
  overflow-y: hidden;  /* see .subnav */
}

.chart-months {
  display: flex;
  align-items: flex-end;
  gap: 10px;
  list-style: none;
  margin: 0;
  padding: 0;
  min-width: min-content;
  height: 190px;
}

.chart-month {
  flex: 1 1 0;
  min-width: 34px;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  height: 100%;
}

.chart-pair {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: 2px;
  height: 100%;
}

.bar {
  position: relative;
  width: 11px;
  min-height: 2px;
  border-radius: 4px 4px 0 0;
  transition: filter .12s ease;
}

.bar-invoiced { background: var(--series-invoiced); }
.bar-collected { background: var(--series-collected); }
.bar:hover { filter: brightness(1.15); }

.bar-tip {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%);
  z-index: 5;
  display: none;
  white-space: nowrap;
  background: var(--text);
  color: var(--surface);
  font-size: .76rem;
  line-height: 1.4;
  padding: .4rem .55rem;
  border-radius: 6px;
  pointer-events: none;
}

.bar:hover .bar-tip,
.bar:focus-visible .bar-tip { display: block; }

.chart-label {
  text-align: center;
  font-size: .7rem;
  color: var(--muted);
  padding-top: .45rem;
}

.chart-year {
  text-align: center;
  font-size: .64rem;
  font-weight: 650;
  color: var(--muted);
}

@media (max-width: 699px) {
  .chart-months { gap: 6px; }
  .chart-month { min-width: 26px; }
  .bar { width: 9px; }
  table.data { font-size: .82rem; }
}

/* A currency symbol alone is ambiguous across borders - A$ and S$ and $ are
   all "dollars" to someone. The ISO code sits beside the amount that matters. */
.paper-title .code {
  font-size: .5em;
  font-weight: 650;
  letter-spacing: .06em;
  color: var(--muted);
  vertical-align: middle;
}

/* A failed email has to look like a problem, not like a log line. */
.error-text { color: var(--danger); }

.verify-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}

.verify-bar > span { flex: 1 1 20rem; }
.verify-bar .btn-link { color: inherit; white-space: nowrap; }

/* A table of five money columns cannot shrink to phone width without becoming
   unreadable, so it scrolls inside its card instead. The page itself never
   scrolls sideways (product spec, section 40). */
.table-scroll { overflow-x: auto; overflow-y: hidden; }  /* see .subnav */
.table-scroll table.data { min-width: 460px; }

@media (max-width: 560px) {
  /* Let a legend drop below its heading rather than squeezing it. */
  .section-head { flex-wrap: wrap; }
  .section-head h2 { flex: 1 1 100%; }
}

/* =========================================================================
   Invoice branding, in Settings
   ========================================================================= */

.presets {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: .6rem;
  margin-top: .5rem;
}

.preset {
  display: flex;
  align-items: center;
  gap: .6rem;
  padding: .7rem .8rem;
  text-align: left;
  font: inherit;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  cursor: pointer;
}

.preset:hover { background: var(--hover); border-color: var(--input-border); }
.preset strong { display: block; font-size: .9rem; }
.preset em { display: block; font-style: normal; font-size: .76rem; color: var(--muted); }



.swatches { display: flex; flex-wrap: wrap; gap: .4rem; align-items: center; }

.swatch-btn {
  width: 30px;
  height: 30px;
  border-radius: 8px;
  border: 1px solid rgba(0, 0, 0, .12);
  cursor: pointer;
  padding: 0;
}

.swatch-btn:hover { transform: scale(1.08); }

.swatches input[type="color"] {
  width: 46px;
  height: 30px;
  padding: 2px;
  border: 1px solid var(--input-border);
  border-radius: 8px;
  background: var(--surface);
  cursor: pointer;
}

/* ---------- The preview sketch ----------
   Deliberately not the real invoice: made-up figures, simplified layout. It
   answers "what colour is that" without a save and a reload each time. */

/* ---------- The Branding page's two columns ----------

   The preview used to sit at the bottom, so changing a colour at the top
   meant scrolling to the end to find out what it did - the one thing a
   preview exists to avoid. It has a column of its own now and stays in view
   while the controls scroll past.

   Narrow screens put it above the controls instead, for the same reason:
   see it first, change things underneath. */

.branding-layout { display: grid; gap: 1.25rem; }

/* The sketch sizes itself from this column's width - see .brand-preview. */
.branding-preview-col { min-width: 0; }

@media (min-width: 1100px) {
  .branding-layout {
    /* Wider than it was. The sketch is the point of the page, and 320px
       made it read as a thumbnail rather than an invoice. */
    /* The preview takes the extra width a wide screen has to offer -
       two fifths of the page, between 400 and 600 pixels. */
    grid-template-columns: minmax(0, 1fr) minmax(400px, min(40%, 600px));
    align-items: start;
  }

  .branding-controls { grid-column: 1; grid-row: 1; min-width: 0; }

  .branding-preview-col {
    grid-column: 2;
    grid-row: 1;
    position: sticky;
    /* Clear of the top bar, so it never hides behind it. */
    top: 1rem;
    /* A bigger sketch is a taller one. On a short laptop screen it scrolls
       inside its own column rather than running off the bottom, where the
       page scrolling past would never bring it into view. */
    max-height: calc(100vh - 2rem);
    overflow-y: auto;
  }
}

.brand-preview {
  --bp-accent: #2f5bea;
  --bp-paper: #ffffff;
  --bp-soft: #eef2fd;
  --bp-edge: #c3d0f8;
  --bp-deep: #264ac0;
  --bp-font: system-ui, sans-serif;

  font-family: var(--bp-font);
  /* Close to the size an invoice is printed at. The extra width a wide
     screen gives the preview is used to show more of the invoice - the
     dates, the client, the columns, the payment details - rather than to
     draw the same few lines larger. */
  font-size: .875rem;
  background: var(--bp-paper);
  color: #191c22;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1.1em 1.2em 1.2em;
  margin-top: .5em;
  /* Always light: it is standing in for a printed document. */
  color-scheme: light;
}

.bp-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 1.5em;
  padding-bottom: .7em;
  border-bottom: 2px solid var(--bp-accent);
}

.bp-name { font-size: 1em; display: block; }

.bp-line {
  display: block;
  height: .375em;
  width: 7.375em;
  border-radius: 3px;
  background: #eceef2;
  margin-top: .4em;
}

.bp-line.short { width: 4.75em; }
.bp-mark { text-align: right; }

.bp-title {
  display: block;
  font-size: 1.7em;
  font-weight: 700;
  letter-spacing: -.02em;
  color: var(--bp-accent);
  line-height: 1.1;
}

.bp-number { font-size: .76em; color: #6b7280; }

.bp-rows { margin: .75em 0 .2em; font-size: .84em; }

.bp-row {
  display: flex;
  justify-content: space-between;
  padding: .35em 0;
  border-bottom: 1px solid #eceef2;
  font-variant-numeric: tabular-nums;
}

.bp-due {
  display: flex;
  justify-content: space-between;
  margin-top: .6em;
  padding: .5em .65em;
  border-radius: 6px;
  background: var(--bp-soft);
  color: var(--bp-deep);
  font-weight: 700;
  font-size: .9em;
}

.bp-footer {
  margin: .8em 0 0;
  font-size: .8em;
  color: #6b7280;
}

.bp-footer:empty { display: none; }

.bp-thanks {
  margin: .45em 0 0;
  font-size: .76em;
  color: var(--bp-deep);
  text-align: right;
}

.bp-thanks:empty { display: none; }

/* The three closing styles, mirrored from document.css. */
.brand-preview[data-closing-style="centered"] .bp-footer {
  text-align: center;
  font-size: .95em;
  color: var(--bp-deep);
}

.brand-preview[data-closing-style="block"] .bp-closing {
  margin-top: .8em;
  padding: .55em .7em;
  background: var(--bp-soft);
  border-left: 3px solid var(--bp-accent);
  border-radius: 6px;
}

.brand-preview[data-closing-style="block"] .bp-links {
  margin: 0;
  padding: 0;
  border-top: none;
}

.brand-preview[data-closing-style="block"] .bp-footer {
  margin-top: .4em;
  color: var(--bp-deep);
  font-weight: 500;
}

/* Nothing to put in the panel - no links, closing line or signature - so
   no panel. */
.brand-preview[data-closing-style="block"] .bp-closing:not(:has(.bp-links, .bp-signature)):has(.bp-footer:empty) {
  display: none;
}

.brand-preview[data-closing-style="centered"] .bp-signoff {
  flex-direction: column;
  align-items: center;
  gap: .6em;
}

.brand-preview[data-closing-style="centered"] .bp-signature { text-align: center; }
.brand-preview[data-closing-style="centered"] .bp-signature img { margin-left: auto; margin-right: auto; }

/* The header layouts, mirrored from document.css */
.brand-preview.bp-centered .bp-head {
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: .5em;
}
.brand-preview.bp-centered .bp-mark { text-align: center; }
.brand-preview.bp-centered .bp-line { margin-left: auto; margin-right: auto; }

.brand-preview.bp-bold .bp-name { font-size: 1.35em; color: var(--bp-accent); }
.brand-preview.bp-bold .bp-title { font-size: .95em; color: #6b7280; font-weight: 600; }

.brand-preview.bp-minimal .bp-head { border-bottom-width: 1px; }
.brand-preview.bp-minimal .bp-title { color: #191c22; font-size: 1.15em; }

/* The banner in the Settings preview. Reaches the edges of the card the same
   way it reaches the edges of the invoice. */
.bp-banner {
  margin: -1.1em -1.2em .9em;
  overflow: hidden;
  border-radius: var(--radius) var(--radius) 0 0;
}

.bp-banner img { display: block; width: 100%; height: auto; }

/* Cropped here to the strip shape the server crops it to on saving
   (core/images.py, 8 wide to 1 high, from the middle), so a file that has
   just been chosen looks in the preview the way it will on the invoice. */
.bp-banner img { aspect-ratio: 8 / 1; object-fit: cover; }
.bp-banner[hidden] { display: none; }
.bp-signature[hidden] { display: none; }
.bp-role:empty { display: none; }

/* ---- The rest of the invoice, drawn small ----

   Mirrors document.css section by section. The details are the real ones
   where they exist, so this reads as the invoice about to be sent. */

.bp-address {
  display: block;
  margin-top: .3em;
  white-space: pre-line;
  line-height: 1.4;
  font-size: .86em;
  color: #5b6472;
}

.bp-label {
  display: block;
  margin-bottom: .3em;
  font-size: .72em;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: #5b6472;
}

.bp-strip {
  display: flex;
  flex-wrap: wrap;
  gap: .6em 1.8em;
  padding: .75em 0;
  border-bottom: 1px solid #eceef2;
  font-size: .9em;
}

.bp-strip small { font-size: .75em; color: #5b6472; font-weight: 700; }

.bp-billto { padding: .75em 0; border-bottom: 1px solid #eceef2; }
.bp-billto strong { display: block; }

.bp-table {
  width: 100%;
  margin-top: .6em;
  border-collapse: collapse;
  font-size: .86em;
  font-variant-numeric: tabular-nums;
}

.bp-table th {
  padding: 0 0 .45em;
  font-size: .8em;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  text-align: right;
  color: #5b6472;
  border-bottom: 1px solid var(--bp-edge);
}

.bp-table td {
  padding: .55em 0;
  text-align: right;
  border-bottom: 1px solid #eceef2;
  white-space: nowrap;
}

.bp-table th:first-child,
.bp-table td:first-child { text-align: left; white-space: normal; }

.bp-table th + th,
.bp-table td + td { padding-left: .9em; }

.bp-sums {
  width: min(100%, 17em);
  margin: .7em 0 0 auto;
  font-variant-numeric: tabular-nums;
}

.bp-sum {
  display: flex;
  justify-content: space-between;
  padding: .2em 0;
  font-size: .9em;
}

.bp-total {
  margin-top: .3em;
  padding-top: .45em;
  border-top: 2px solid var(--bp-accent);
  font-size: 1.1em;
  font-weight: 700;
}

.bp-blocks {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.2em;
  margin-top: .8em;
  padding-top: .8em;
  border-top: 1px solid #eceef2;
}

.bp-blocks .bp-address { margin-top: 0; }

.bp-pay {
  display: flex;
  gap: .6em;
  align-items: flex-start;
  justify-content: space-between;
  padding: .6em .7em;
  border: 1px solid #eceef2;
  border-radius: 6px;
  background: color-mix(in srgb, var(--bp-paper) 94%, var(--bp-accent));
}

.bp-qr { width: 3.6em; height: 3.6em; flex: none; }

.bp-signoff {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1.5em;
}

.bp-signature {
  flex: none;
  text-align: right;
  font-size: .74em;
  color: #5b6472;
}

.bp-signature img {
  display: block;
  max-height: 2.8em;
  max-width: 9em;
  margin: .6em 0 .2em auto;
}

.bp-signature span { display: block; }

/* The logo, in the preview. The same three shapes and sizes the invoice
   offers; the page script sets which. */
/* Only as wide as the logo itself. Stretched to the width of the text
   beside it, the picture sat at the left of that box, and in the centred
   layout the logo was off to one side of the name under it. */
.bp-logo { display: block; width: fit-content; margin-bottom: .5em; }
.bp-logo[hidden] { display: none; }
.bp-logo img { display: block; max-height: var(--bp-logo-h, 2.9em); max-width: 11em; }
.bp-logo.is-small { --bp-logo-h: 2em; }
.bp-logo.is-large { --bp-logo-h: 4em; }

.bp-logo.is-rounded,
.bp-logo.is-circle {
  width: var(--bp-logo-h, 2.9em);
  height: var(--bp-logo-h, 2.9em);
  overflow: hidden;
}

.bp-logo.is-rounded img,
.bp-logo.is-circle img { width: 100%; height: 100%; max-width: none; object-fit: cover; }

.bp-logo.is-rounded { border-radius: 18%; }
.bp-logo.is-circle { border-radius: 50%; }

.brand-preview.bp-centered .bp-logo { margin-left: auto; margin-right: auto; }

.bp-links {
  margin: .5em 0 0;
  padding-top: .5em;
  border-top: 1px solid #eceef2;
  font-size: .74em;
  color: #6b7280;
}

/* ---------- Settings tabs ----------

   A second row of navigation, under the page title. The main navigation is
   left alone on purpose: the product spec asks for no more than the five
   items it has, and a sixth would not fit the phone tab bar at a readable
   size. */

.subnav {
  display: flex;
  gap: .25rem;
  overflow-x: auto;
  /* Asking for sideways scrolling turns on up-and-down scrolling as well,
     unless it is switched off here. The row of tabs is one pixel taller than
     the space it sits in, which was enough for the browser to draw a tiny
     scrollbar beside it - a pair of little arrows floating next to the
     tabs, with nothing to scroll. */
  overflow-y: hidden;
  margin-bottom: 1.5rem;
  border-bottom: 1px solid var(--border);
}

.subnav a {
  padding: .6rem .9rem;
  font-size: .92rem;
  font-weight: 550;
  color: var(--muted);
  text-decoration: none;
  white-space: nowrap;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}

.subnav a:hover { color: var(--text); }

.subnav a.active {
  color: var(--primary);
  border-bottom-color: var(--primary);
}

/* A payment method's QR, shown small beside it in the list so it is obvious
   at a glance which ones have one. */
.method-side { display: flex; align-items: center; gap: .75rem; }

.qr-thumb {
  width: 34px;
  height: 34px;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: #fff;
  padding: 2px;
}


/* =========================================================================
   Time tracking
   -------------------------------------------------------------------------
   A timer somebody starts when they sit down, and a week they can read
   afterwards. The running entry is kept visually apart from the week's
   figures below it, because it is the one thing on the page that is still
   changing.
   ========================================================================= */

.timer-bar {
  display: flex;
  gap: .6rem;
  align-items: center;
  padding: .75rem;
  margin-bottom: 1.25rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}

.timer-bar input[type="text"] {
  flex: 1 1 auto;
  min-width: 0;
  padding: .55rem .75rem;
  font-size: 1rem;
  font-family: inherit;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--input-border);
  border-radius: 8px;
}

.timer-bar select { flex: 0 0 auto; max-width: 11rem; }

.timer-running {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  padding: .85rem 1rem;
  margin-bottom: 1.25rem;
  background: var(--primary-soft);
  border: 1px solid var(--primary);
  border-radius: var(--radius);
}

.timer-label {
  display: block;
  font-size: .75rem;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--primary);
}

.timer-what { display: block; font-size: 1.05rem; }

.timer-side { display: flex; align-items: center; gap: .9rem; }

.timer-clock {
  font-size: 1.5rem;
  font-weight: 650;
  font-variant-numeric: tabular-nums;
  /* Fixed width, so a ticking clock does not shove the Stop button about. */
  min-width: 6.5rem;
  text-align: right;
}

.week-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: .75rem;
}

.week-head h2 { margin: 0; }
.week-nav { display: flex; gap: .4rem; flex-wrap: wrap; align-items: center; }

.week-filter { margin: 0; }
.week-filter select {
  padding: .38rem 1.85rem .38rem .6rem;
  font-size: .85rem;
  background-position: right .5rem center;
  background-size: 13px;
}

.filter-note {
  margin: -.4rem 0 1rem;
  font-size: .85rem;
  color: var(--muted);
}

.day { border-bottom: 1px solid var(--border); }
.day:last-child { border-bottom: none; }

.day-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: .6rem 1.1rem;
  background: var(--subtle);
}

.day-name { font-size: .85rem; font-weight: 600; }

.day-total {
  font-size: .85rem;
  font-weight: 650;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
}

.day.is-today .day-head { background: var(--primary-soft); }

.day-empty {
  margin: 0;
  padding: .7rem 1.1rem;
  font-size: .85rem;
  color: var(--muted);
}

.day .row-item { padding-left: 1.1rem; }

.row-side form { display: inline-block; margin-top: .35rem; }

@media (max-width: 560px) {
  .timer-bar { flex-wrap: wrap; }
  .timer-bar select, .timer-bar button { flex: 1 1 auto; }
  .timer-clock { min-width: 5rem; font-size: 1.25rem; }
}


/* ---------- Opened by the client ----------

   The answer to the question behind every unpaid invoice: did it arrive, or
   is it in a spam folder. Quiet until it is good news. */

.seen-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  padding: .75rem 1rem;
  margin-bottom: 1rem;
  background: var(--subtle);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

.seen-bar strong { display: block; font-size: .95rem; }
.seen-bar .muted { display: block; max-width: 58ch; }

.seen-bar.is-seen {
  background: var(--success-soft, var(--subtle));
  border-color: var(--success);
}

.seen-bar.is-seen strong { color: var(--success); }

/* "Opened": a small grey eye and the word, beside the status rather than
   competing with it. The status is what matters; this is a detail. */
.seen-dot {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  margin-left: .45rem;
  font-size: .75rem;
  font-weight: 500;
  color: var(--muted);
}
.seen-dot::before {
  content: "";
  width: .85em;
  height: .85em;
  background-color: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7S2 12 2 12z'/%3E%3Ccircle cx='12' cy='12' r='3'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7S2 12 2 12z'/%3E%3Ccircle cx='12' cy='12' r='3'/%3E%3C/svg%3E") center / contain no-repeat;
}


/* =========================================================================
   The bell
   -------------------------------------------------------------------------
   A panel anchored to the top bar. It holds at most eight rows, so it never
   needs to scroll on a desktop; on a phone it takes the width of the screen
   rather than hanging off the right edge.
   ========================================================================= */

.bell { position: relative; }

.bell-button {
  position: relative;
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  padding: 0;
  color: var(--muted);
  background: none;
  border: 1px solid transparent;
  border-radius: 8px;
  cursor: pointer;
}

.bell-button:hover { color: var(--text); background: var(--hover); }
.bell-button svg { width: 19px; height: 19px; stroke-width: 1.8; }

.bell-count {
  position: absolute;
  top: 2px;
  right: 2px;
  min-width: 16px;
  padding: 0 4px;
  font-size: .65rem;
  font-weight: 700;
  line-height: 16px;
  text-align: center;
  color: #fff;
  background: var(--danger);
  border-radius: 999px;
}

.bell-panel {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  z-index: 40;
  width: 360px;
  max-width: calc(100vw - 24px);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: 0 12px 32px rgba(16, 24, 40, .16);
  overflow: hidden;
}

.bell-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: .7rem .9rem;
  border-bottom: 1px solid var(--border);
}

.bell-head form { margin: 0; }
.bell-head .btn-link { font-size: .8rem; }

.bell-list { max-height: 60vh; overflow-y: auto; }

.bell-item {
  display: block;
  padding: .7rem .9rem;
  border-bottom: 1px solid var(--border);
  text-decoration: none;
  color: inherit;
}

.bell-item:last-child { border-bottom: none; }
.bell-item:hover { background: var(--hover); }

/* Unread is a bar down the side rather than a coloured background: it stays
   legible in dark mode and does not fight the text. */
.bell-item.is-unread {
  border-left: 3px solid var(--primary);
  padding-left: calc(.9rem - 3px);
}

.bell-item.is-bad.is-unread { border-left-color: var(--danger); }

.bell-item-title { display: block; font-size: .88rem; font-weight: 600; }
.bell-item.is-bad .bell-item-title { color: var(--danger); }

.bell-item-body {
  display: block;
  margin-top: .15rem;
  font-size: .82rem;
  color: var(--muted);
}

.bell-item-when {
  display: block;
  margin-top: .25rem;
  font-size: .75rem;
  color: var(--muted);
}

.bell-foot {
  padding: .6rem .9rem;
  text-align: center;
  font-size: .82rem;
  background: var(--subtle);
}

.bell-empty {
  margin: 0;
  padding: 1rem .9rem;
  font-size: .82rem;
  color: var(--muted);
}

/* The same unread bar on the full page. */
.row-item.is-unread {
  border-left: 3px solid var(--primary);
  padding-left: calc(1.1rem - 3px);
}

.unread-dot {
  display: inline-block;
  width: 7px;
  height: 7px;
  margin-right: .35rem;
  vertical-align: middle;
  background: var(--primary);
  border-radius: 999px;
}

@media (max-width: 480px) {
  .bell-panel { width: calc(100vw - 24px); right: -8px; }
}


/* Hours and minutes, side by side and only as wide as they need to be.
   Stretching a list of "0 h" to "12 h" across half the form makes a small
   choice look like a big one. */
.field .duration-pair {
  display: flex;
  gap: .5rem;
  align-items: center;
}

.field .duration-pair select {
  flex: 0 0 auto;
  width: auto;
  min-width: 5.5rem;
}


/* ---------- Choosing how the app looks ---------- */

.themes {
  display: grid;
  gap: .6rem;
  grid-template-columns: 1fr;
}

@media (min-width: 640px) {
  .themes { grid-template-columns: 1fr 1fr; }
}

.theme-option {
  display: flex;
  align-items: center;
  gap: .75rem;
  margin: 0;
  padding: .75rem .85rem;
  background: var(--surface);
  border: 1px solid var(--input-border);
  border-radius: var(--radius);
  cursor: pointer;
}

.theme-option:hover { background: var(--hover); }

.theme-option.is-chosen {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-soft);
}

.theme-option input { flex: 0 0 auto; margin: 0; accent-color: var(--primary); }

/* Three stacked bands - page, panel, accent - which is enough to tell the
   options apart without pretending to be a screenshot. */
.theme-swatch {
  flex: 0 0 auto;
  display: flex;
  width: 40px;
  height: 28px;
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: 5px;
}

.theme-swatch i { flex: 1 1 0; }

.theme-body { min-width: 0; }
.theme-name { display: block; font-size: .9rem; }

.theme-note {
  display: block;
  font-size: .78rem;
  line-height: 1.35;
  color: var(--muted);
}


/* The three little actions on a recurring schedule. Forms, so they sit
   inline rather than each starting a new line. */
.schedule-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  flex-wrap: wrap;
  gap: .6rem;
  margin-top: .3rem;
}

.schedule-actions form { display: inline; margin: 0; }
.schedule-actions .btn-link { font-size: .83rem; }


/* The client picker, wherever it appears. Sits on its own line under the
   other controls rather than crowding into them, because it is the widest
   of them and the one most likely to hold a long name. */

.toolbar select[name="client"] { max-width: 16rem; }


/* ---------- Choosing the mark ---------- */

.mark-choices { display: flex; flex-wrap: wrap; gap: .5rem; }

.mark-choice {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  margin: 0;
  padding: .5rem .8rem;
  font-size: .9rem;
  background: var(--surface);
  border: 1px solid var(--input-border);
  border-radius: 999px;
  cursor: pointer;
}

.mark-choice:hover { background: var(--hover); }
.mark-choice input { margin: 0; accent-color: var(--primary); }

.monogram-samples { display: flex; gap: .9rem; align-items: center; margin-bottom: 1rem; }

/* The same three fills offered on the invoice, drawn from the colour in the
   box above so the sample answers "what will this look like" without saving.
   The chosen one is ringed rather than made bigger, so the three stay
   comparable. */
.monogram-sample {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 54px;
  height: 54px;
  font-size: 1.25rem;
  font-weight: 650;
  letter-spacing: .02em;
  color: #fff;
  background: var(--sample-accent, var(--primary));
}

.monogram-sample.is-soft {
  color: var(--sample-accent, var(--primary));
  background: color-mix(in srgb, var(--sample-accent, var(--primary)) 12%, #fff);
}

.monogram-sample.is-outline {
  color: var(--sample-accent, var(--primary));
  background: transparent;
  border: 2px solid color-mix(in srgb, var(--sample-accent, var(--primary)) 35%, #fff);
}

.monogram-sample.is-chosen {
  box-shadow: 0 0 0 2px var(--surface), 0 0 0 4px var(--primary);
}


/* ---------- Colour sets ----------

   Each button is the page colour with the two ink colours on it, which is
   what the invoice actually looks like in miniature - more use than three
   squares in a row. */

.palettes {
  display: grid;
  /* Wide enough for the longest name. At 112px "Champagne" was cut off at
     the edge of its own button. */
  grid-template-columns: repeat(auto-fill, minmax(152px, 1fr));
  gap: .5rem;
  margin-top: .35rem;
}

.palette {
  display: flex;
  align-items: center;
  gap: .55rem;
  padding: .5rem .6rem;
  font: inherit;
  font-size: .85rem;
  color: var(--text);
  text-align: left;
  background: var(--surface);
  border: 1px solid var(--input-border);
  border-radius: var(--radius);
  cursor: pointer;
}

.palette:hover { background: var(--hover); }

.preset.is-chosen,
.palette.is-chosen {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-soft);
}

.palette-swatch {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 3px;
  width: 38px;
  height: 26px;
  border: 1px solid var(--border);
  border-radius: 5px;
}

.palette-swatch i { width: 9px; height: 9px; border-radius: 50%; }
/* If a longer name is ever added, it wraps rather than being cut in half. */
.palette-name { min-width: 0; overflow-wrap: anywhere; }

.papers { display: flex; flex-wrap: wrap; gap: .4rem; align-items: center; }

.paper-swatch {
  width: 30px;
  height: 30px;
  padding: 0;
  border: 1px solid var(--input-border);
  border-radius: 6px;
  cursor: pointer;
}

.paper-swatch.is-chosen {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-soft);
}


/* The initials, in the preview. The same three fills the invoice offers,
   drawn to the same scale as everything else in the sketch - 14mm on the
   invoice. They were drawn at about a third of that, so small the letters
   could hardly be read, while the logo beside them was to scale. */
.bp-monogram {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.6em;
  height: 2.6em;
  margin-bottom: .375em;
  font-size: 1em;
  font-weight: 650;
  line-height: 1;
  color: #fff;
  background: var(--bp-accent);
}

/* The three sizes. The whole mark is measured from its own letter size,
   so scaling the letters scales the box with them. */
.bp-monogram.size-small { font-size: .714em; }
.bp-monogram.size-large { font-size: 1.357em; }

/* Without this the box always showed, empty, whatever the chosen mark -
   the display rule above outranks the browser's own rule for "hidden". */
.bp-monogram[hidden] { display: none; }

.bp-monogram.is-soft { color: var(--bp-deep); background: var(--bp-soft); }

.bp-monogram.is-outline {
  color: var(--bp-deep);
  background: transparent;
  border: 1.5px solid var(--bp-edge);
}


/* Suggestions under a text box: tap one to fill it in, or ignore them and
   type. Small and quiet, because they are a shortcut rather than the
   control itself. */
.title-suggestions {
  display: flex;
  flex-wrap: wrap;
  gap: .35rem;
  margin-top: .45rem;
}

.chip-button {
  padding: .25rem .6rem;
  font: inherit;
  font-size: .78rem;
  color: var(--neutral-text);
  background: var(--neutral-soft);
  border: 1px solid transparent;
  border-radius: 999px;
  cursor: pointer;
}

.chip-button:hover { color: var(--text); border-color: var(--input-border); }


/* ---------- Time: list or calendar ---------- */

.view-switch {
  display: inline-flex;
  border: 1px solid var(--input-border);
  border-radius: 8px;
  overflow: hidden;
}

.view-switch a {
  padding: .3rem .75rem;
  font-size: .85rem;
  font-weight: 600;
  color: var(--muted);
  text-decoration: none;
}

.view-switch a + a { border-left: 1px solid var(--input-border); }
.view-switch a.is-chosen { background: var(--primary-soft); color: var(--primary-dark); }

/* ---------- Time: the calendar ----------

   One hour is 48 pixels tall; every position below is worked out from that
   and from minutes after midnight, so a block and the hour lines behind it
   cannot drift apart. */

.cal {
  --hour: 48px;
  --gutter: 58px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  overflow: hidden;
}

/* The whole day scrolls inside the card; it opens at the start of the
   working day rather than at midnight (see the script). */
.cal-scroll { max-height: min(70vh, 680px); overflow: auto; }

/* Seven usable columns need some width. A phone scrolls sideways rather
   than squeezing a day into forty pixels. */
.cal-inner { min-width: 720px; }

.cal-row {
  display: grid;
  grid-template-columns: var(--gutter) repeat(7, minmax(0, 1fr));
}

.cal-sticky {
  position: sticky;
  top: 0;
  z-index: 3;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}

.cal-day-head {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: .35rem;
  padding: .55rem .25rem;
  font-size: .8rem;
  color: var(--muted);
  border-left: 1px solid var(--border);
}

.cal-day-num { font-size: 1rem; color: var(--text); }
.cal-day-total { font-size: .72rem; }
.cal-day-head.is-today { color: var(--primary-dark); background: var(--primary-soft); }
.cal-day-head.is-today .cal-day-num { color: var(--primary-dark); }

.cal-untimed { border-top: 1px solid var(--border); }
.cal-untimed-label {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  padding: .3rem .4rem;
  font-size: .66rem;
  line-height: 1.2;
  text-align: right;
  color: var(--muted);
}

.cal-untimed-day {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 3px;
  min-width: 0;
  border-left: 1px solid var(--border);
}

.cal-chip {
  display: block;
  padding: .15rem .35rem;
  border-radius: 4px;
  background: var(--neutral-soft);
  color: var(--text);
  font-size: .7rem;
  text-decoration: none;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.cal-grid { height: calc(24 * var(--hour)); }

.cal-hours {
  display: grid;
  grid-template-rows: repeat(24, var(--hour));
}

.cal-hour {
  padding: 0 .45rem 0 0;
  font-size: .68rem;
  color: var(--muted);
  text-align: right;
  transform: translateY(-.45em);
}

.cal-hour:first-child { visibility: hidden; }

.cal-col {
  position: relative;
  border-left: 1px solid var(--border);
  /* A line on every hour. */
  background-image: linear-gradient(to bottom, var(--border) 1px, transparent 1px);
  background-size: 100% var(--hour);
  cursor: crosshair;
  /* Fingers scroll the calendar; a tap adds time (see the script). */
  touch-action: manipulation;
  user-select: none;
}

.cal-col.is-today { background-color: color-mix(in srgb, var(--primary-soft) 45%, transparent); }

.cal-block {
  position: absolute;
  top: calc(var(--top) * var(--hour) / 60);
  height: calc(var(--height) * var(--hour) / 60 - 2px);
  left: calc(var(--lane) / var(--lanes) * 100% + 2px);
  width: calc(100% / var(--lanes) - 4px);
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: .2rem .35rem;
  /* A project's colour when it has one; the app's blue otherwise. The fill
     is the colour washed nearly to the background, so the text on it stays
     the ordinary, readable text colour in light and dark mode alike. */
  border-left: 3px solid var(--block, var(--primary));
  border-radius: 5px;
  background: color-mix(in srgb, var(--block, var(--primary)) 16%, var(--surface));
  color: var(--text);
  font-size: .7rem;
  line-height: 1.25;
  text-decoration: none;
  overflow: hidden;
  cursor: pointer;
}

.cal-block strong,
.cal-block span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cal-block span { color: var(--muted); }
.cal-block:hover { filter: brightness(.97); box-shadow: 0 1px 4px rgba(16, 24, 40, .15); }

/* A block too short for every line shows fewer, rather than slicing the
   last one through: under an hour just the name, under an hour and a half
   the name and the times. The whole entry is a click away. */
.cal-block.is-short { justify-content: center; padding-top: 0; padding-bottom: 0; }
.cal-block.is-short span { display: none; }
.cal-block.is-medium span ~ span { display: none; }

/* Billed time is finished with: greyed, with the invoice named on it. */
.cal-block.is-billed { background: var(--neutral-soft); border-left-color: var(--neutral-faint); }
.cal-block.is-unbillable { border-left-style: dashed; }

/* The stretch being marked out, while the mouse is down. */
.cal-selection {
  position: absolute;
  left: 2px;
  right: 2px;
  z-index: 2;
  padding: .2rem .35rem;
  border: 1px solid var(--primary);
  border-radius: 5px;
  background: color-mix(in srgb, var(--primary) 18%, transparent);
  color: var(--primary-dark);
  font-size: .72rem;
  font-weight: 600;
  pointer-events: none;
}

.cal-help { margin-top: .5rem; }

/* ---------- Time: the "Add time" box ---------- */

.cal-dialog {
  width: min(560px, calc(100vw - 32px));
  padding: 1.4rem 1.5rem 1.2rem;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--surface);
  color: var(--text);
  box-shadow: 0 20px 50px rgba(16, 24, 40, .25);
}

.cal-dialog::backdrop { background: rgba(16, 24, 40, .45); }
.cal-dialog h2 { margin: 0 0 .2rem; }
.cal-dialog .form-grid { margin-top: .8rem; }
.cal-duration { margin: .55rem 0 0; font-weight: 650; }
.cal-billable { align-self: end; padding-bottom: .6rem; }


/* A project's colour, as a small dot beside its name. */
.project-dot {
  display: inline-block;
  width: .6em;
  height: .6em;
  margin-right: .35em;
  border-radius: 50%;
  background: var(--dot, var(--primary));
  vertical-align: baseline;
}

.cal-chip[style*="--block"] { border-left: 3px solid var(--block); }
.timer-bar select[hidden] { display: none; }
[data-client-field][hidden], [data-cal-client-row][hidden] { display: none; }
.cal-dialog .field[hidden], #time-form .full[hidden] { display: none; }


/* ---------- Projects ---------- */

.project-dot-big { width: .55em; height: .55em; vertical-align: .12em; }
.project-name { font-weight: 600; color: var(--text); text-decoration: none; }
.project-name:hover { text-decoration: underline; }
.project-notes { margin: -.5rem 0 1rem; color: var(--muted); max-width: 70ch; }

.project-table { width: 100%; border-collapse: collapse; font-size: .9rem; }
.project-table th {
  padding: .6rem .9rem;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  text-align: left;
  color: var(--muted);
  border-bottom: 1px solid var(--border);
}
.project-table td { padding: .7rem .9rem; border-bottom: 1px solid var(--border); vertical-align: middle; }
.project-table tr:last-child td { border-bottom: none; }
.project-table .num { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }

.project-cards { display: none; }
.project-card {
  display: flex;
  flex-direction: column;
  gap: .3rem;
  margin-bottom: .75rem;
  border-left: 4px solid var(--dot, var(--primary));
  color: var(--text);
  text-decoration: none;
}
.project-card-head { display: flex; align-items: center; justify-content: space-between; gap: .5rem; }
.project-card .project-dot { display: none; }
.project-card-figures { display: flex; flex-wrap: wrap; gap: .25rem 1rem; font-size: .88rem; }

@media (max-width: 760px) {
  .project-table-wrap { display: none; }
  .project-cards { display: block; }
}

.badge-status-active { background: var(--success-soft, var(--primary-soft)); color: var(--success, var(--primary-dark)); }
.badge-status-paused { background: var(--warn-soft); color: var(--warn); }
.badge-status-completed { background: var(--primary-soft); color: var(--primary-dark); }
.badge-status-archived { background: var(--neutral-soft); color: var(--neutral-text); }

/* The budget, as a bar that fills. Red once it is spent. */
.budget-card { margin: 1rem 0; }
.budget-head { display: flex; justify-content: space-between; gap: 1rem; flex-wrap: wrap; margin-bottom: .5rem; font-size: .9rem; }
.budget-bar, .budget-mini {
  display: block;
  height: 8px;
  border-radius: 99px;
  background: var(--neutral-soft);
  overflow: hidden;
}
.budget-bar span, .budget-mini span { display: block; height: 100%; background: var(--primary); border-radius: inherit; }
.budget-bar.is-over span, .budget-mini.is-over span { background: var(--danger); }
.budget-mini { width: 90px; height: 5px; margin-top: .35rem; }

.project-status-actions { display: flex; flex-wrap: wrap; gap: .5rem; }

/* The colour choice on the project form: a row of round swatches. */
.colour-choices { display: flex; flex-wrap: wrap; gap: .5rem; }
.colour-choice {
  position: relative;
  width: 30px;
  height: 30px;
  margin: 0;
  border-radius: 50%;
  background: var(--dot);
  cursor: pointer;
}
.colour-choice input { position: absolute; opacity: 0; inset: 0; margin: 0; cursor: pointer; }
.colour-choice:has(input:checked) { box-shadow: 0 0 0 2px var(--surface), 0 0 0 4px var(--dot); }
.colour-choice:has(input:focus-visible) { outline: 2px solid var(--primary); outline-offset: 4px; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}
[data-billing][hidden], [data-billing-help][hidden] { display: none; }

/* ---------- Dashboard: needs your attention ---------- */

.attention {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 1rem;
  align-items: start;
}
.attention-card { padding: 1rem 1.15rem .5rem; }
.attention-title {
  margin: 0 0 .35rem;
  font-size: .75rem;
  font-weight: 650;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--muted);
}
.attention-row {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 1rem;
  padding: .6rem 0;
  border-top: 1px solid var(--border);
  font-size: .92rem;
}
.attention-title + .attention-row { border-top: none; }
.attention-main { color: var(--text); text-decoration: none; min-width: 0; }
.attention-main:hover strong { text-decoration: underline; }
.attention-late,
.attention-sub { display: block; font-size: .78rem; margin-top: .1rem; }
.attention-late { color: var(--danger); font-weight: 600; }
.attention-sub { color: var(--muted); }
.attention-side {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: .1rem;
  text-align: right;
  white-space: nowrap;
}
.attention-side a,
.attention-side .btn-link { font-size: .8rem; }
.attention-more {
  display: block;
  padding: .5rem 0 .6rem;
  border-top: 1px solid var(--border);
  font-size: .82rem;
}

/* ---------- Clients list: what each one owes ---------- */

.client-balance { text-align: right; }
.client-settled { display: block; color: var(--muted); font-weight: 500; }
.client-when { display: block; margin-top: .1rem; font-size: .78rem; color: var(--muted); white-space: nowrap; }
.client-late { color: var(--danger); font-weight: 600; }

/* On a phone the small line may wrap, so it does not squeeze the client's
   name and email down to a few letters. */
@media (max-width: 600px) {
  .client-balance { max-width: 46%; }
  .client-when { white-space: normal; }
}

/* What a project's budget bar measures, said under it. */
.budget-note { display: block; margin-top: .2rem; font-size: .74rem; color: var(--muted); }
.budget-note.is-over { color: var(--danger); font-weight: 600; }

/* ---------- A client's details: small headings over their answers ---------- */

.detail-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 1.1rem 1.5rem;
  margin: 0;
}
.detail-grid > div { min-width: 0; }
.detail-grid dt {
  margin: 0 0 .2rem;
  font-size: .72rem;
  font-weight: 650;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--muted);
}
.detail-grid dd { margin: 0; font-size: .92rem; overflow-wrap: anywhere; }
.detail-grid .is-wide { grid-column: span 2; }
.detail-grid .is-address { white-space: pre-line; }
@media (max-width: 480px) {
  .detail-grid .is-wide { grid-column: 1 / -1; }
}

/* =========================================================================
   Help: the "?" in the top bar, the panel it opens, and the Help Centre.
   ========================================================================= */

/* A labelled button rather than a bare icon, so it is plain where help
   lives. On a narrow phone the word goes and the icon stays. */
.help-button {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  height: 38px;
  padding: 0 .85rem 0 .65rem;
  color: var(--primary-dark);
  background: var(--primary-soft);
  border: 1px solid var(--primary-border);
  border-radius: 999px;
  font: inherit;
  font-size: .92rem;
  font-weight: 600;
  cursor: pointer;
}
.help-button:hover,
.help-button[aria-expanded="true"] { background: var(--surface); border-color: var(--primary); }
.help-button svg { width: 22px; height: 22px; stroke-width: 2; flex: none; }
@media (max-width: 480px) {
  .help-button { width: 40px; height: 40px; padding: 0; justify-content: center; }
  .help-button-label { display: none; }
}

.help-drawer { position: fixed; inset: 0; z-index: 60; }
.help-drawer[hidden] { display: none; }
.help-scrim { position: absolute; inset: 0; background: rgba(16, 24, 40, .28); }
.help-sheet {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  display: flex;
  flex-direction: column;
  width: min(440px, 100%);
  background: var(--surface);
  border-left: 1px solid var(--border);
  box-shadow: -12px 0 32px rgba(16, 24, 40, .16);
  animation: help-slide .18s ease-out;
}
@keyframes help-slide { from { transform: translateX(24px); opacity: 0; } to { transform: none; opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .help-sheet { animation: none; } }
body.help-open { overflow: hidden; }

.help-sheet-head {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .8rem 1rem;
  border-bottom: 1px solid var(--border);
}
.help-sheet-head h2 { margin: 0; font-size: 1.05rem; flex: 1; }
.help-back[hidden] + h2 { margin-left: 0; }
.help-back,
.help-close {
  padding: .3rem .55rem;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: .85rem;
  cursor: pointer;
}
.help-close { font-size: 1.2rem; line-height: 1; padding: .2rem .55rem; }
.help-back:hover, .help-close:hover { background: var(--hover); }
.help-sheet-content { flex: 1; overflow-y: auto; padding: 1rem; }

.help-search {
  width: 100%;
  padding: .6rem .8rem;
  margin-bottom: 1rem;
  font: inherit;
  font-size: .95rem;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--input-border);
  border-radius: 8px;
}
.help-search:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-soft); }

.help-group-title {
  margin: 0 0 .4rem;
  font-size: .72rem;
  font-weight: 650;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--muted);
}
.help-group, .help-here { margin-bottom: 1.2rem; }
.help-here .help-list { background: var(--primary-soft); border-color: var(--primary-border); }
.help-list { list-style: none; margin: 0; padding: 0; border: 1px solid var(--border); border-radius: 10px; overflow: hidden; }
.help-list li + li { border-top: 1px solid var(--border); }
.help-list li[hidden] { display: none; }
.help-list a { display: block; padding: .6rem .8rem; color: var(--text); text-decoration: none; }
.help-list a:hover { background: var(--hover); }
.help-item-title { display: block; font-weight: 600; font-size: .92rem; }
.help-item-summary { display: block; margin-top: .1rem; font-size: .8rem; color: var(--muted); }
.help-has-clip { font-size: .7rem; color: var(--primary); vertical-align: 1px; }
.help-none { color: var(--muted); font-size: .9rem; }
.help-footer { margin: 1rem 0 0; font-size: .85rem; }

/* One answer. */
.help-kicker { margin: 0 0 .2rem; font-size: .72rem; font-weight: 650; letter-spacing: .05em; text-transform: uppercase; color: var(--muted); }
.help-title { margin: 0 0 .4rem; font-size: 1.3rem; line-height: 1.3; }
.help-summary { margin: 0 0 1rem; color: var(--muted); }
.help-article p { line-height: 1.6; }
.help-steps { margin: 0 0 1rem; padding-left: 1.3rem; line-height: 1.6; }
.help-steps li { margin-bottom: .45rem; padding-left: .2rem; }
.help-clip { margin: 0 0 1.2rem; }
.help-clip video { display: block; width: 100%; border-radius: 10px; border: 1px solid var(--border); background: #000; }
.help-clip figcaption { margin-top: .35rem; font-size: .78rem; color: var(--muted); }
.help-related { margin-top: 1.4rem; padding-top: 1rem; border-top: 1px solid var(--border); }
.help-related h2 { margin: 0 0 .4rem; font-size: .8rem; letter-spacing: .05em; text-transform: uppercase; color: var(--muted); }
.help-related ul { margin: 0; padding-left: 1.1rem; }
.help-related li { margin-bottom: .3rem; }

/* The Help Centre page. */
.help-centre { max-width: 760px; }
.help-page { max-width: 760px; }
