/* Firmdesk's stylesheet. No build step: this file is what the browser gets.

   1. Tokens       the values everything else is made of: colour, type, radius, shadow
   2. Base         the page, links, headings
   3. App shell    sidebar, phone top bar, menus
   4. Pages        one section per part of the app (deadlines, tasks, time, billing, portal...)
   5. Components   buttons, fields, tables, badges, tabs, page headers, filters, search

   Colours come from tokens, so the light and dark themes are each a list of values; one typed by hand is the same in
   both (a file type's label, the sidebar's whites). The theme follows the computer's setting unless someone picks
   one (the user menu; kept in this browser): <html data-theme="light|dark">. The rules behind the look, for the
   website too: docs/design.md. */

@font-face {
  font-family: "Inter Variable"; font-style: normal; font-display: swap; font-weight: 100 900;
  src: url("../fonts/inter-latin-ext-wght-normal.1ad231aac0a8.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Inter Variable"; font-style: normal; font-display: swap; font-weight: 100 900;
  src: url("../fonts/inter-latin-wght-normal.260c81a4759b.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* The wordmark's face: the name "Firmdesk" beside the mark, and nothing else (.wordmark) */
@font-face {
  font-family: "Schibsted Grotesk"; font-style: normal; font-display: swap; font-weight: 400 900;
  src: url("../fonts/schibsted-grotesk-latin-wght-normal.ba4038fc5cb5.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* --- 1. Tokens ---------------------------------------------------------------------------------------- */
:root {
  color-scheme: light;

  /* Type */
  --font: "Inter Variable", Inter, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --font-wordmark: "Schibsted Grotesk", "Inter Variable", Inter, system-ui, sans-serif;  /* the name only */
  --text-2xs: 0.6875rem; --text-xs: 0.75rem; --text-sm: 0.8125rem; --text-base: 0.875rem; --text-md: 0.9375rem; --text-lg: 1.0625rem;
  --text-xl: 1.25rem; --text-2xl: 1.5rem; --text-3xl: 1.875rem;

  /* Shape */
  --radius-sm: 4px; --radius-md: 6px; --radius: 8px; --radius-lg: 12px; --radius-full: 999px;
  --control-height: 34px;
  --control-height-sm: 28px;  /* a small button, a compact select, a chip: one size for all of them */
  --touch-target: 44px;

  /* Space: every margin, padding and gap is one of these (docs/design.md). 6 and 10 are the half steps a control's
     own padding uses; a layout's gaps keep to the 4px steps. */
  --space-0-5: 2px; --space-1: 4px; --space-1-5: 6px; --space-2: 8px; --space-2-5: 10px; --space-3: 12px;
  --space-4: 16px; --space-5: 20px; --space-6: 24px; --space-7: 28px; --space-8: 32px; --space-9: 36px;
  --space-10: 40px; --space-12: 48px;
  --stack-gap: var(--space-5);  /* between blocks stacked on a page: cards, notices, a header and what follows */
  --cell-pad-x: var(--space-2-5);  /* a table's cells, side to side, in every table */
  --page-gutter: var(--space-9);

  /* Widths: a form, a document (an invoice, a letter), a page of reading */
  --width-form: 640px;
  --width-doc: 820px;
  --width-read: 720px;
  --width-name-cell: 140px;  /* a row's name in a list that scrolls sideways on a phone: a few words a line, not one */

  /* Surfaces and text */
  --bg: #f6f7f9;
  --surface: #ffffff;
  --surface-2: #f9fafb;
  --surface-3: #f1f3f6;
  --text: #182230;
  --text-2: #344054;
  --muted: #5d6b82;
  --border: #e4e7ec;
  --border-strong: #cfd4dc;  /* buttons, separators: decorative or labelled, so 1.5:1 is enough */
  --control-border: #838d9c;  /* a field's edge and a chosen segment's ring: 3.4:1 on surface, the 3:1 a control needs */
  --control-off: #838d9c;  /* the switch's track when off, 3.4:1 */

  /* Brand and links */
  --primary: #2458d6;
  --primary-hover: #1c47b0;
  --primary-soft: #e8effd;
  --on-primary: #ffffff;
  --link: #2458d6;
  --focus-ring: rgba(36, 88, 214, 0.32);

  /* Status: what the colour means, the same everywhere */
  --danger: #c93434;  /* overdue, errors, destructive */
  --danger-solid: #c93434;
  --danger-bg: #fdecec;
  --danger-border: #f1b5b5;
  --warning: #c27a10;  /* due soon, needs a look: 3.5:1 on surface as a mark; text uses --warning-text */
  --warning-text: #8f4d00;
  --warning-bg: #fdf0dc;
  --warning-bg-soft: #fffaf2;
  --warning-border: #c27a10;
  --warning-border-soft: #f0cf9b;
  --success: #1d8a52;  /* done, paid, approved */
  --success-text: #1d6b3f;
  --success-bg: #e8f6ee;
  --success-border: #a8dbbd;
  --info-text: #2458d6;  /* in progress, new */
  --info-bg: #e7eefc;
  --info-border: #b9ccf5;
  --purple: #8a5cf6;  /* waiting on the client, meetings */
  --purple-text: #6d3fd6;
  --purple-bg: #efe9fe;
  --error-bg: var(--danger-bg);

  /* The sidebar keeps its own dark surface in both themes */
  --sidebar-bg: #131c2b;
  --sidebar-text: #b9c3d3;
  --sidebar-heading: #8492a8;
  --sidebar-active: #22304a;
  --sidebar-hover: #1b2740;
  --sidebar-border: rgba(255, 255, 255, 0.08);
  --sidebar-edge: transparent;

  /* Depth */
  --shadow-xs: 0 1px 2px rgba(16, 24, 40, 0.05);
  --shadow-sm: 0 1px 3px rgba(16, 24, 40, 0.08), 0 1px 2px rgba(16, 24, 40, 0.04);
  --shadow-md: 0 8px 24px rgba(16, 24, 40, 0.12);
  --shadow-lg: 0 20px 48px rgba(16, 24, 40, 0.18);
  --backdrop: rgba(16, 22, 32, 0.45);

  /* Charts */
  --series-1: #2a78d6; --series-2: #eb6834; --chart-grid: #eceef1; --chart-base: #c3c8d0;

  /* Illustrations (includes/illustrations.html): the line, the shape behind, the object's faces, the one accent.
     The wash and the accent follow the primary colour, so a firm's portal colour (portal/branding.py) applies too. */
  --ill-line: #475467; --ill-wash: var(--primary-soft); --ill-paper: var(--surface); --ill-accent: var(--primary);
  --ill-ground: var(--border-strong);

  /* Tooltips (static/js/app.js): dark on light, light on dark */
  --tooltip-bg: #182230; --tooltip-text: #ffffff;
}

/* The dark theme, chosen in the user menu. The same list follows for computers set to dark. Both are for screens
   only: paper is white, so a printed page keeps the light values above, whatever the theme. */
@media screen {
  :root[data-theme="dark"] {
    color-scheme: dark;
    --bg: #0e1116; --surface: #161a21; --surface-2: #1b2029; --surface-3: #232935;
    --text: #e6e9ee; --text-2: #c9cfd9; --muted: #98a2b3; --border: #2a303b; --border-strong: #3d4554;
    --control-border: #677284; --control-off: #677284;
    --primary: #2f5fd6; --primary-hover: #3b6ae0; --primary-soft: #1a2744; --link: #8fb0ff;
    --focus-ring: rgba(143, 176, 255, 0.4);
    --danger: #ef6464; --danger-solid: #c93434; --danger-bg: #3a1c1c; --danger-border: #6b2c2c;
    --warning: #e0a040; --warning-text: #f3c27a; --warning-bg: #3a2a14; --warning-bg-soft: #241c10;
    --warning-border: #a86a14; --warning-border-soft: #5a4220;
    --success: #4cc38a; --success-text: #8fd9ad; --success-bg: #173324; --success-border: #2a5a40;
    --info-text: #9bb8f5; --info-bg: #1c2a47; --info-border: #2c3f66;
    --purple: #a78bfa; --purple-text: #c4b0fb; --purple-bg: #2a2145;
    --sidebar-bg: #0a0d12; --sidebar-active: #1c2638; --sidebar-hover: #141b28;
    --sidebar-edge: var(--border);  /* the sidebar is near the page's own dark: a line says where it ends */
    --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.4);
    --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.45);
    --shadow-md: 0 8px 24px rgba(0, 0, 0, 0.5);
    --shadow-lg: 0 20px 48px rgba(0, 0, 0, 0.6);
    --backdrop: rgba(0, 0, 0, 0.6);
    --series-1: #3987e5; --series-2: #d95926; --chart-grid: #262e3a; --chart-base: #3a4452;
    --ill-line: #aab4c3; --ill-accent: var(--link);
    --tooltip-bg: #e6e9ee; --tooltip-text: #0e1116;
  }
}
@media screen and (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --bg: #0e1116; --surface: #161a21; --surface-2: #1b2029; --surface-3: #232935;
    --text: #e6e9ee; --text-2: #c9cfd9; --muted: #98a2b3; --border: #2a303b; --border-strong: #3d4554;
    --control-border: #677284; --control-off: #677284;
    --primary: #2f5fd6; --primary-hover: #3b6ae0; --primary-soft: #1a2744; --link: #8fb0ff;
    --focus-ring: rgba(143, 176, 255, 0.4);
    --danger: #ef6464; --danger-solid: #c93434; --danger-bg: #3a1c1c; --danger-border: #6b2c2c;
    --warning: #e0a040; --warning-text: #f3c27a; --warning-bg: #3a2a14; --warning-bg-soft: #241c10;
    --warning-border: #a86a14; --warning-border-soft: #5a4220;
    --success: #4cc38a; --success-text: #8fd9ad; --success-bg: #173324; --success-border: #2a5a40;
    --info-text: #9bb8f5; --info-bg: #1c2a47; --info-border: #2c3f66;
    --purple: #a78bfa; --purple-text: #c4b0fb; --purple-bg: #2a2145;
    --sidebar-bg: #0a0d12; --sidebar-active: #1c2638; --sidebar-hover: #141b28;
    --sidebar-edge: var(--border);  /* the sidebar is near the page's own dark: a line says where it ends */
    --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.4);
    --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.45);
    --shadow-md: 0 8px 24px rgba(0, 0, 0, 0.5);
    --shadow-lg: 0 20px 48px rgba(0, 0, 0, 0.6);
    --backdrop: rgba(0, 0, 0, 0.6);
    --series-1: #3987e5; --series-2: #d95926; --chart-grid: #262e3a; --chart-base: #3a4452;
    --ill-line: #aab4c3; --ill-accent: var(--link);
    --tooltip-bg: #e6e9ee; --tooltip-text: #0e1116;
  }
}

/* --- 2. Base ------------------------------------------------------------------------------------------ */
* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  font: var(--text-base)/1.5 var(--font);
  font-feature-settings: "cv11", "ss01";  /* Inter: single-storey a, open digits */
  background: var(--bg);
  color: var(--text);
  -webkit-font-smoothing: antialiased;
}

a { color: var(--link); text-decoration: none; }
a:hover { text-decoration: underline; }
h1, h2, h3 { color: var(--text); letter-spacing: -0.011em; }
h1 { font-size: var(--text-2xl); font-weight: 650; line-height: 1.25; margin: 0; }
h2 { font-size: var(--text-lg); font-weight: 600; margin: 0 0 var(--space-3); }
h3 { font-size: var(--text-md); font-weight: 600; margin: var(--space-5) 0 var(--space-2); }
strong, b { font-weight: 600; }
code { font-family: var(--font-mono); font-size: 0.92em; }
:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
::selection { background: var(--primary-soft); }

/* --- 3. App shell: sidebar (a slide-in drawer below 900px), phone top bar, main content ------------------- */
.layout { display: flex; min-height: 100vh; }
.content { flex: 1; min-width: 0; padding: var(--space-7) var(--page-gutter) var(--space-12); max-width: 1240px; }
/* A page that is one form, one question or one document is as wide as its card, so the header's buttons end where
   the card does (block main_class in the page's template). */
.content.is-form-page { max-width: calc(var(--width-form) + 2 * var(--page-gutter)); }
.content.is-doc-page { max-width: calc(var(--width-doc) + 2 * var(--page-gutter)); }
.content:focus { outline: none; }  /* focused by the skip link */
.skip-link { position: absolute; left: 12px; top: -60px; z-index: 100; padding: var(--space-2) var(--space-4); border-radius: var(--radius-md); background: #1c47b0; color: #fff; }
.skip-link:focus { top: 12px; }

.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
.icon { width: 18px; height: 18px; flex-shrink: 0; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.icon-button {
  display: inline-flex; align-items: center; justify-content: center; width: 36px; height: 36px; padding: 0;
  border: 0; border-radius: var(--radius-md); background: none; color: inherit; cursor: pointer;
}
.icon-button:hover { background: rgba(127, 137, 150, 0.16); }
.icon-button .icon { width: 20px; height: 20px; }
.sidebar .icon-button:hover, .topbar .icon-button:hover { background: rgba(255, 255, 255, 0.1); }

.sidebar {
  width: 244px; flex-shrink: 0; position: sticky; top: 0; height: 100vh; overflow-y: auto;
  display: flex; flex-direction: column; gap: var(--space-1-5); padding: var(--space-3) var(--space-3) var(--space-2-5);
  background: var(--sidebar-bg); color: var(--sidebar-text); font-size: var(--text-sm); border-right: 1px solid var(--sidebar-edge);
  scrollbar-width: thin; scrollbar-color: rgba(255, 255, 255, 0.15) transparent;
}
.sidebar-top { display: flex; align-items: center; justify-content: space-between; min-height: 40px; padding: 0 0 0 var(--space-2); }
.brand { display: inline-flex; align-items: center; gap: var(--space-2); color: #fff; font-size: var(--text-lg); }
.brand:hover { text-decoration: none; }
.brand-mark { width: 24px; height: 24px; border-radius: 6px; flex-shrink: 0; }
/* The wordmark: the name "Firmdesk" in its own face, wherever it stands beside the mark */
.wordmark { font-family: var(--font-wordmark); font-weight: 800; letter-spacing: -0.02em; }
.sidebar-close, .sidebar-toggle { display: none; }
/* Wider screens: the menu button beside the brand hides the sidebar down to a strip that keeps just
   that button (static/js/app.js; base.html's <head> script brings the choice back on every page). */
@media (min-width: 900px) {
  .js .sidebar-toggle { display: inline-flex; }
  /* Collapsed: a rail of icons (each link keeps its name as a tooltip), without the names and headings. */
  .sidebar-hidden .sidebar { width: 64px; padding-left: var(--space-2-5); padding-right: var(--space-2-5); }
  .sidebar-hidden .brand, .sidebar-hidden .nav-heading, .sidebar-hidden .menu-button .chevron,
  .sidebar-hidden .search-button kbd { display: none; }
  /* Names stay for screen readers and tooltips (static/js/app.js): out of sight, not display:none. */
  .sidebar-hidden .nav a > span:not(.nav-badge), .sidebar-hidden .menu-button-text, .sidebar-hidden .search-button span {
    position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
  }
  .sidebar-hidden .sidebar-top { padding: 0; justify-content: center; }
  .sidebar-hidden .nav a, .sidebar-hidden .menu-button, .sidebar-hidden .search-button { justify-content: center; padding-left: 0; padding-right: 0; }
  .sidebar-hidden .nav-group + .nav-group { border-top: 1px solid var(--sidebar-border); padding-top: var(--space-2); }
  .sidebar-hidden .menu-panel { left: 0; right: auto; min-width: 240px; }
}

.nav { display: flex; flex-direction: column; gap: var(--space-0-5); }
.nav a { display: flex; align-items: center; gap: var(--space-2-5); min-height: var(--control-height); padding: var(--space-1-5) var(--space-2-5); border-radius: var(--radius-md); color: var(--sidebar-text); font-weight: 500; }
.nav a .icon { width: 17px; height: 17px; opacity: 0.85; }
.nav a:hover { background: var(--sidebar-hover); text-decoration: none; color: #fff; }
.nav a.active { background: var(--sidebar-active); color: #fff; font-weight: 600; }
.nav a.active .icon { opacity: 1; color: #8fb0ff; }
.nav a:focus-visible, .menu-button:focus-visible, .search-button:focus-visible { outline: 2px solid #8fb0ff; outline-offset: 1px; }
.sidebar .nav { flex: 1; gap: var(--space-3); margin-top: var(--space-1); }
.nav-group { display: flex; flex-direction: column; gap: 1px; }
.nav-live { display: contents; }  /* a part of the menu that refreshes itself: its link is the group's */
.nav-heading { padding: 0 var(--space-2-5) var(--space-1); font-size: var(--text-2xs); font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--sidebar-heading); }
.nav-bottom { margin-top: auto; padding-top: var(--space-3); border-top: 1px solid var(--sidebar-border); }  /* the same space each side of its line as between the groups above */

/* Search: a button that looks like a field; it opens the search box (Ctrl+K) */
.search-button {
  display: flex; align-items: center; gap: var(--space-2-5); width: 100%; min-height: var(--control-height); padding: var(--space-1-5) var(--space-2-5); margin: var(--space-0-5) 0 var(--space-1);
  border: 1px solid var(--sidebar-border); border-radius: var(--radius-md); background: rgba(255, 255, 255, 0.04);
  color: var(--sidebar-text); font: inherit; text-align: left; cursor: pointer;
}
.search-button:hover { background: rgba(255, 255, 255, 0.08); color: #fff; text-decoration: none; }
.search-button .icon { width: 16px; height: 16px; }
.search-button span { flex: 1; }
.search-button kbd, .kbd {
  padding: 1px var(--space-1-5); border: 1px solid var(--sidebar-border); border-radius: var(--radius-sm); background: rgba(255, 255, 255, 0.06);
  font: 500 var(--text-2xs)/1.5 var(--font); color: var(--sidebar-heading);
}

/* Menu panels: <details class="menu"> (static/js/app.js closes them on an outside click or Escape) */
.menu { position: relative; }
.menu > summary { list-style: none; }
.menu > summary::-webkit-details-marker { display: none; }
.menu-button { display: flex; align-items: center; gap: var(--space-2-5); min-height: var(--control-height); padding: var(--space-1-5) var(--space-2-5); border-radius: var(--radius-md); cursor: pointer; color: #fff; }  /* the nav's padding: its icons, marks and avatar start at one edge */
.menu-button:hover, .menu[open] > .menu-button { background: var(--sidebar-hover); }
.menu-button-text { flex: 1; min-width: 0; display: flex; flex-direction: column; line-height: 1.25; }
.menu-button .chevron { width: 15px; height: 15px; opacity: 0.6; transition: transform 0.15s; }
.menu[open] > .menu-button .chevron { transform: rotate(180deg); }
.sidebar-workspace-name, .user-name, .user-email { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sidebar-workspace-name { font-weight: 600; font-size: var(--text-base); }
.user-name { font-weight: 600; }
.user-email { font-size: var(--text-xs); color: var(--sidebar-heading); }
.workspace-mark {
  width: 28px; height: 28px; flex-shrink: 0; display: grid; place-items: center; border-radius: 7px;
  background: var(--primary); color: var(--on-primary); font-weight: 700; font-size: var(--text-sm); object-fit: contain;
}
img.workspace-mark { background: #fff; padding: var(--space-0-5); }
.avatar {
  width: 28px; height: 28px; flex-shrink: 0; display: grid; place-items: center; border-radius: 50%;
  background: #334463; color: #fff; font-size: var(--text-2xs); font-weight: 700; letter-spacing: 0.02em;
}
.menu-panel {
  position: absolute; left: 0; right: 0; top: calc(100% + 4px); z-index: 20; padding: var(--space-1);
  border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); color: var(--text);
  box-shadow: var(--shadow-md); font-size: var(--text-base);
}
.user-menu .menu-panel { top: auto; bottom: calc(100% + 4px); }
.menu form { margin: 0; }
.menu-item {
  display: flex; align-items: center; gap: var(--space-2-5); width: 100%; min-height: var(--control-height); padding: var(--space-1-5) var(--space-2-5); border: 0; border-radius: var(--radius-md);
  background: none; color: var(--text); font: inherit; text-align: left; cursor: pointer; white-space: nowrap;
}
.menu-item:hover { background: var(--surface-3); text-decoration: none; }
.menu-item:focus-visible { background: var(--surface-3); outline: 2px solid var(--primary); outline-offset: -2px; }
.menu-item .icon { width: 16px; height: 16px; color: var(--muted); }
.menu-item.is-current { font-weight: 600; cursor: default; }
.menu-item.is-current:hover { background: none; }
.menu-item.is-current .icon { color: var(--primary); }
.menu-item.is-danger, .menu-item.is-danger .icon { color: var(--danger); }
.menu-item.is-danger:hover { background: var(--danger-bg); }
.menu-heading { padding: var(--space-2) var(--space-2-5) var(--space-1); font-size: var(--text-xs); font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted); }
.menu-divider { height: 1px; margin: var(--space-1) var(--space-1); background: var(--border); }
.workspace-menu { margin-bottom: var(--space-0-5); }
.user-menu { margin-top: auto; }  /* at the bottom even when there's no nav (no workspace yet) */
.help-menu { margin-top: auto; }  /* then Help is the first thing at the bottom, the user menu under it */
.help-menu + .user-menu { margin-top: 0; }
.help-menu .menu-panel { top: auto; bottom: calc(100% + 4px); }
.help-menu .menu-button { color: var(--sidebar-text); font-weight: 500; }
.help-menu .menu-button > .icon { width: 17px; height: 17px; opacity: 0.85; }
.help-menu .menu-item { white-space: normal; }

/* Theme: system, light or dark (static/js/app.js) */
.theme-switch { display: flex; gap: var(--space-0-5); margin: var(--space-0-5) var(--space-1) var(--space-1); padding: var(--space-0-5); border-radius: var(--radius-md); background: var(--surface-3); }
.theme-switch button {
  flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: var(--space-1); min-height: var(--control-height-sm); padding: var(--space-1) var(--space-1-5); border: 0;
  border-radius: var(--radius-sm); background: none; color: var(--muted); font: 500 var(--text-xs)/1 var(--font); cursor: pointer;
}
.theme-switch button .icon { width: 14px; height: 14px; }
.theme-switch button:hover { color: var(--text); }
.theme-switch button[aria-pressed="true"] { background: var(--surface); color: var(--text); font-weight: 600; box-shadow: 0 0 0 1px var(--control-border), var(--shadow-xs); }
.no-js .theme-switch { display: none; }

.topbar, .nav-backdrop { display: none; }
.nav-backdrop { cursor: pointer; }  /* iOS only sends taps on clickable-looking elements */

@media (max-width: 899px) {
  .layout { flex-direction: column; }
  .content { --page-gutter: var(--space-4); padding: var(--space-5) var(--page-gutter) var(--space-10); }
  .nav a, .menu-item { min-height: var(--touch-target); }  /* a finger's width */
  .sidebar { font-size: var(--text-base); }

  /* Without JS the sidebar is a block at the top of the page. */
  .no-js .sidebar { position: static; width: auto; height: auto; overflow: visible; }
  .no-js .nav { flex-direction: row; flex-wrap: wrap; }
  .no-js .nav-bottom { margin: 0; padding: 0; border: 0; }
  .no-js .user-menu, .no-js .help-menu { margin-top: 0; }

  /* With JS it's a drawer, opened from the top bar. */
  .js .topbar {
    display: flex; align-items: center; gap: var(--space-1-5); position: sticky; top: 0; z-index: 30;
    height: 56px; padding: 0 var(--space-2); background: var(--sidebar-bg); color: #fff;
  }
  .topbar .icon-button { width: var(--touch-target); height: var(--touch-target); }
  .topbar-brand { color: #fff; font-size: var(--text-lg); }
  .topbar-brand:hover { text-decoration: none; }
  .topbar-workspace {
    margin-left: auto; max-width: 40%; overflow: hidden; text-overflow: ellipsis;
    white-space: nowrap; font-size: var(--text-sm); color: var(--sidebar-text);
  }
  .js .sidebar {
    position: fixed; top: 0; bottom: 0; left: 0; z-index: 50; width: min(300px, 86vw); height: auto;
    transform: translateX(-100%); visibility: hidden; box-shadow: 0 0 40px rgba(0, 0, 0, 0.3);
  }
  .js.nav-open .sidebar { transform: none; visibility: visible; }
  /* Slide only while opening or closing (app.js sets nav-animate), not when the layout changes. */
  .js.nav-animate .sidebar { transition: transform 0.2s ease, visibility 0s linear 0.2s; }
  .js.nav-animate.nav-open .sidebar { transition: transform 0.2s ease; }
  .js .sidebar-close { display: inline-flex; }
  .js.nav-open .nav-backdrop { display: block; position: fixed; inset: 0; z-index: 40; background: rgba(10, 15, 25, 0.5); }
  .js { scroll-padding-top: 64px; }  /* links to #sections land below the sticky top bar */
  .js.nav-open body { overflow: hidden; }
}
@media (prefers-reduced-motion: reduce) {
  .sidebar, .menu-button .chevron { transition: none !important; }
  * { scroll-behavior: auto !important; }
}

/* --- 4. Pages ----------------------------------------------------------------------------------------- */
/* Deadlines (the tracker) */
.content.wide { max-width: none; }
/* One segmented control for the whole app, the theme switch's quiet track: the chosen segment is raised in white with
   a 3:1 ring and a heavier weight, so blue stays for the page's one main action. */
.segmented { display: inline-flex; gap: var(--space-0-5); min-height: var(--control-height); padding: var(--space-0-5); border-radius: var(--radius-md); background: var(--surface-3); }
.segmented > a, .segmented > label { display: inline-flex; align-items: center; }  /* as tall as a button beside it, wherever it stands */
.segmented a { padding: var(--space-1) var(--space-3); border-radius: var(--radius-sm); color: var(--text-2); font-size: var(--text-sm); font-weight: 500; }
.segmented a:hover { text-decoration: none; background: rgba(127, 137, 150, 0.16); color: var(--text); }
.segmented a.active { background: var(--surface); color: var(--text); font-weight: 600; box-shadow: 0 0 0 1px var(--control-border), var(--shadow-xs); }
.tracker-nav { display: flex; gap: var(--space-1-5); align-items: center; }
.tracker-nav .btn.active { border-color: var(--primary); color: var(--link); }
.range-label { margin-left: var(--space-1-5); font-weight: 600; }
.tracker-filters input[type="search"] { min-width: 200px; }
@media (max-width: 720px) {  /* two filters per row */
  .tracker-filters { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .tracker-filters input[type="search"] { grid-column: 1 / -1; min-width: 0; }
  .tracker-filters select { width: 100%; min-width: 0; }
}
.check { display: inline-flex; gap: var(--space-1-5); align-items: center; font-size: var(--text-base); white-space: nowrap; }
.count { display: inline-block; min-width: 1.4em; padding: 0 var(--space-1-5); border-radius: var(--radius-full); background: var(--border); color: var(--muted); font-size: var(--text-xs); text-align: center; font-weight: 600; }

.board { display: flex; gap: var(--space-3); overflow-x: auto; padding-bottom: var(--space-2); align-items: flex-start; }
.board > .board-column { flex: 1 0 240px; min-width: 0; }
/* A week with nothing due folds to a narrow rail, its name up the rail; a click opens it (app.js). Overdue stays
   pinned at the left while the board scrolls, with a soft shadow so the weeks slide under it. */
.js .board > .board-column.is-empty { flex: 0 0 46px; display: flex; justify-content: center; }  /* its button: 44px, a finger's width */
.js .board-column.is-empty > :not(.board-rail), .board-rail { display: none; }
.js .board-column.is-empty > .board-rail {
  display: flex; align-items: center; justify-content: flex-end; gap: var(--space-2); width: 100%; min-height: 180px; padding: var(--space-3) 0; border: 0;
  border-radius: var(--radius); background: none;
  color: var(--muted); font: 600 var(--text-sm)/1.2 var(--font); writing-mode: vertical-rl; transform: rotate(180deg); white-space: nowrap; cursor: pointer;
}
.js .board-column.is-empty > .board-rail:hover { color: var(--text); background: var(--surface-2); }
.board-rail .count { writing-mode: horizontal-tb; }
.board > .board-column.overdue { position: sticky; left: 0; z-index: 3; box-shadow: 8px 0 12px -10px rgba(16, 24, 40, 0.35); }
@media (max-width: 720px) {  /* one column at a time, swiped; the rails still fold, so a swipe skips empty weeks */
  .board { scroll-snap-type: x mandatory; }
  .board > .board-column { flex: 0 0 86%; scroll-snap-align: start; }
  .board > .board-column.overdue { position: static; box-shadow: none; }
}
.board-column { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); }
.board-column.overdue .column-title { color: var(--danger); }
.board-column.current { border-color: var(--primary); }
.column-header { padding: var(--space-2-5) var(--space-3); border-bottom: 1px solid var(--border); }
.column-title { font-weight: 600; }
.column-sub { font-size: var(--text-sm); color: var(--muted); }
.column-items { padding: var(--space-2); display: flex; flex-direction: column; gap: var(--space-2); }
.column-empty { margin: var(--space-1); }

/* A card has no coloured edge: a 3px accent bends round a rounded corner, and the due pill already says the state. */
.deadline-card { border: 1px solid var(--border); border-radius: var(--radius-md); padding: var(--space-2) var(--space-2-5); background: var(--bg); font-size: var(--text-sm); line-height: 1.4; }  /* the one build of a board's card */
/* A deadline the client files itself is quiet, and says why (the "Client files it" tag): muted words, never see-through ones */
.client-handled, .client-handled a:not(.btn), .client-handled .due-date { color: var(--muted); }
.is-done .card-title { text-decoration: line-through; }
.card-entity { display: block; font-weight: 600; margin-top: var(--space-0-5); }
.card-title { margin: var(--space-0-5) 0 var(--space-1-5); }
.card-badges { display: flex; flex-wrap: wrap; gap: var(--space-1); margin-bottom: var(--space-1-5); }
.overdue-text { color: var(--danger); font-weight: 600; }

/* Tags: what an item is (Filing, Payment, Contractual, Meeting, Task, Client files it). A quiet label, its icon and its
   name with no box: red, amber, green, blue and purple only ever say a state, never a kind. */
.tags { display: inline-flex; flex-wrap: wrap; gap: var(--space-0-5) var(--space-2-5); vertical-align: middle; }
.tag { display: inline-flex; align-items: center; gap: var(--space-1); color: var(--muted); font-size: var(--text-xs); font-weight: 500; line-height: 18px; white-space: nowrap; }
.tag .icon { width: 12px; height: 12px; flex-shrink: 0; }

/* When something is due, as one piece (templates/includes/due.html): the date, then how soon in a pill whose tone is
   the state. It isn't small text, so compact rows keep it. */
.due { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 3px var(--space-1-5); font-variant-numeric: tabular-nums; }
.due-date { color: var(--text); font-weight: 600; white-space: nowrap; }
.due-when {
  display: inline-flex; align-items: center; min-height: 18px; padding: 0 var(--space-2); border-radius: var(--radius-full); white-space: nowrap;
  background: var(--surface-3); color: var(--text-2); font-size: var(--text-xs); font-weight: 600; line-height: 18px;
}
.due.is-late .due-when { background: var(--danger-bg); color: var(--danger); }
.due.is-soon .due-when { background: var(--warning-bg); color: var(--warning-text); }
.due.is-done .due-when { background: var(--success-bg); color: var(--success-text); }
.due.is-later .due-when, .due.is-skipped .due-when { padding: 0; background: none; color: var(--muted); font-weight: 500; }
.due.is-stacked { flex-direction: column; align-items: flex-start; gap: var(--space-0-5); }  /* a list's When column: the pill under the date */
.due.is-stacked.is-later .due-when, .due.is-stacked.is-skipped .due-when { min-height: 0; line-height: 1.35; }

/* A deadline's tasks, one segment each: done green, overdue red, still open a 3:1 outline; the words beside it */
.segs { display: inline-flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-2); }
.segs-bar { display: flex; flex: none; gap: var(--space-0-5); width: 84px; }
.segs-bar > i { flex: 1 1 0; min-width: 3px; height: 8px; border-radius: 2px; box-shadow: inset 0 0 0 1px var(--control-border); }
.segs-bar > i.is-done { background: var(--success); box-shadow: none; }
.segs-bar > i.is-late { background: var(--danger); box-shadow: none; }
.segs-text { color: var(--muted); font-size: var(--text-sm); white-space: nowrap; }
.segs-text .is-late { color: var(--danger); font-weight: 600; }
.segs-text.is-done { color: var(--success-text); font-weight: 600; }

/* A deadline's status as a pill you open to set any of its stages (engagements/_status_menu.html). The dot's
   shape says the stage as well as its colour: an empty ring, half full, three quarters (in review), a ring with its
   centre in (ready to go), full, a dash. */
.status-menu { position: relative; display: inline-block; }
.status-menu > summary, .status-pill {
  display: inline-flex; align-items: center; gap: var(--space-1-5); min-height: 24px; padding: 1px var(--space-2); list-style: none;
  border: 1px solid transparent; border-radius: var(--radius-full); background: var(--surface-3); color: var(--text-2);
  font-size: var(--text-xs); font-weight: 600; line-height: 1.2; white-space: nowrap;
}
.status-menu > summary { padding-right: var(--space-1-5); cursor: pointer; }
.status-menu > summary::-webkit-details-marker { display: none; }
.status-menu > summary .icon { width: 12px; height: 12px; opacity: 0.7; }
.status-menu > summary:hover, .status-menu[open] > summary { border-color: var(--control-border); }
.status-pill.is-in_progress, .status-menu.is-in_progress > summary { background: var(--info-bg); color: var(--info-text); }
.status-pill.is-in_review, .status-menu.is-in_review > summary, .badge-stage.is-in_review { background: var(--warning-bg); color: var(--warning-text); }
.status-menu.is-ready > summary, .status-pill.is-ready, .badge-stage.is-ready { background: var(--success-bg); color: var(--success-text); }
.status-menu.is-done > summary, .status-pill.is-done { background: var(--success-bg); color: var(--success-text); }
.status-menu.is-not_required > summary, .status-pill.is-not_required, .status-pill.is-skipped { background: none; border-color: var(--border); color: var(--muted); }
.status-menu .menu-panel { left: auto; right: 0; min-width: 190px; }
.status-menu .menu-item.is-current { font-weight: 600; }
.status-dot { display: inline-block; width: 10px; height: 10px; flex-shrink: 0; border: 2px solid currentColor; border-radius: 50%; }
.status-dot.is-in_progress { background: linear-gradient(90deg, currentColor 50%, transparent 50%); }
.status-dot.is-in_review { background: conic-gradient(currentColor 75%, transparent 0); }
.status-dot.is-ready { background: radial-gradient(currentColor 38%, transparent 42%); }
.status-dot.is-done { background: currentColor; }
.status-dot.is-not_required, .status-dot.is-skipped { width: 10px; height: 2px; border: 0; border-radius: 1px; background: currentColor; }
.menu-item .status-dot { color: var(--muted); }
.menu-item .status-dot.is-in_progress { color: var(--info-text); }
.menu-item .status-dot.is-in_review { color: var(--warning-text); }
.menu-item .status-dot.is-ready, .menu-item .status-dot.is-done { color: var(--success); }
.task-line { display: flex; align-items: center; gap: var(--space-2); }

.group-row th { background: var(--bg); color: var(--text); text-transform: none; letter-spacing: 0; font-size: var(--text-base); }
.group-row.overdue th, .group-row.overdue th .muted { color: var(--danger); }  /* by client the name is a link: "2 overdue" says it */
.group-row.current th { color: var(--link); }
/* A list row's edge (a square side, so it doesn't bend) says how late it is: red overdue, amber due within 3 days */
.tracker-table tr.is-late td:first-child { box-shadow: inset 3px 0 0 var(--danger); }
.tracker-table tr.is-soon td:first-child { box-shadow: inset 3px 0 0 var(--warning); }

/* Tasks */
/* A round tick marks something done; a square box selects a row */
.tick {
  width: 18px; height: 18px; padding: 0; border: 1.5px solid var(--muted); border-radius: 50%;
  background: var(--surface); color: var(--on-primary); font-size: 12px; line-height: 1; cursor: pointer; flex-shrink: 0;
}
.tick:hover { border-color: var(--primary); }
.tick.done { background: var(--primary); border-color: var(--primary); }
/* The tick's form is a flex box one text line tall, the tick in its middle: level with the title's (first) line
   beside it, in a row or at the top of a cell. Inline, the tick sat on the line's baseline, about 2px off. */
form.inline:has(> .tick) { display: flex; align-items: center; min-height: 1lh; }
.task-progress { margin: var(--space-1) 0 var(--space-1-5); font-size: var(--text-sm); }
.next-task { display: flex; align-items: center; gap: var(--space-1-5); margin-top: var(--space-1); min-width: 0; }
.next-task-title { flex: 1; min-width: 0; max-width: 16rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text); }
.tracker-table .next-task-title { max-width: 9rem; }  /* in the list the room goes to the client's and the deadline's names */
.card-for { margin: -4px 0 var(--space-1-5); }
.who { display: inline-flex; gap: 3px; flex-wrap: wrap; }
.who-chip {
  display: inline-block; min-width: 1.9em; padding: 1px var(--space-1); border-radius: var(--radius-full); text-align: center;
  background: var(--border); color: var(--text); font-size: var(--text-xs); font-weight: 700;
}
.task-table td { vertical-align: top; }
.tick-cell { width: 28px; }
.task-row.is-done .task-title { text-decoration: line-through; color: var(--muted); }
.task-row.skipped { opacity: 0.55; }
a.task-title { font-weight: 600; color: var(--text); }
a.task-title:hover { color: var(--link); }
.task-for { margin-top: var(--space-0-5); }
.link-action { background: none; border: 0; padding: 0; font: inherit; font-size: var(--text-sm); color: var(--muted); cursor: pointer; }
.link-action:hover { color: var(--text); text-decoration: underline; }
.later-tasks { margin-top: var(--space-2); }
/* A task list's last row (tasks/_quick_add.html): type a task, press Enter. The date and the person show as chips
   while the row is in use; otherwise it's one quiet row. */
.quick-add { margin: var(--space-1-5) 0 0; }
.quick-add-row {
  display: flex; align-items: center; gap: var(--space-2-5); margin: 0 -10px; padding: 3px var(--space-2-5); border-radius: var(--radius-md);
  color: var(--muted); cursor: text;
}
.quick-add-row:hover, .quick-add.is-adding .quick-add-row { background: var(--surface-2); }
.quick-add-row > .icon { width: 16px; height: 16px; flex: none; }
.quick-add-row input, .quick-add-row input:hover, .quick-add-row input:focus {
  flex: 1; min-width: 0; max-width: none; padding: var(--space-1) 0; border: 0; background: none; box-shadow: none;
}
.quick-add-row:focus-within { background: var(--surface); box-shadow: inset 0 0 0 1px var(--primary), 0 0 0 3px var(--focus-ring); }
.quick-add-chips { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1-5) var(--space-2); padding: var(--space-2) 0 var(--space-0-5) 26px; }
.js .quick-add:not(.is-adding) .quick-add-chips { display: none; }
.quick-add-chips .btn { margin-left: auto; }
.quick-add-more { color: var(--link); }
.qchip {
  display: inline-flex; align-items: center; gap: var(--space-1); min-height: var(--control-height-sm); padding: 0 var(--space-0-5) 0 var(--space-2);
  border: 1px solid var(--control-border); border-radius: var(--radius-full); background: var(--surface); color: var(--muted);
}
.qchip:hover { border-color: var(--muted); }
.qchip:focus-within { border-color: var(--primary); box-shadow: 0 0 0 3px var(--focus-ring); }
.qchip > .icon { width: 14px; height: 14px; flex: none; }
.qchip input, .qchip select, .qchip input:focus, .qchip select:focus {
  width: auto; max-width: 210px; min-height: 0; height: calc(var(--control-height-sm) - 2px); padding: 0 var(--space-1-5) 0 var(--space-0-5); border: 0; background-color: transparent;
  box-shadow: none; color: var(--text-2); font-size: var(--text-sm);
}
.qchip input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):not(.switch) { min-height: 0; }  /* outranks the field rule's min-height, as .qchip select already does */
.task-list-box > .quick-add { margin: 0; padding: var(--space-1-5) var(--space-3) var(--space-2); border-top: 1px solid var(--border); }
.task-list-box > .quick-add .quick-add-row { margin: 0 -6px; padding-left: var(--space-1-5); padding-right: var(--space-1-5); }
.later-tasks summary { cursor: pointer; color: var(--muted); font-size: var(--text-base); margin: var(--space-2) 0; }
.card > details > table th:first-child, .card > details > table td:first-child { padding-left: 0; }
.card > details > table th:last-child, .card > details > table td:last-child { padding-right: 0; }

/* My work */
.work-filters input[type="search"] { flex: 1; min-width: 200px; }
.filter-group { display: inline-flex; align-items: center; gap: var(--space-2); }
.filter-label { font-size: var(--text-sm); color: var(--muted); white-space: nowrap; }
.segmented a { white-space: nowrap; }
/* Radio segmented controls (My work filters): the radio is hidden, its label is the button. */
.segmented label { position: relative; padding: var(--space-1) var(--space-3); border-radius: var(--radius-sm); color: var(--text-2); font-size: var(--text-sm); font-weight: 500; cursor: pointer; white-space: nowrap; }
.segmented label:hover { background: rgba(127, 137, 150, 0.16); color: var(--text); }
.segmented label.active, .segmented label:has(input:checked) { background: var(--surface); color: var(--text); font-weight: 600; box-shadow: 0 0 0 1px var(--control-border), var(--shadow-xs); }
.segmented label:has(input:focus-visible) { outline: 2px solid var(--primary); outline-offset: 1px; }
.segmented input[type="radio"] { position: absolute; inset: 0; opacity: 0; margin: 0; pointer-events: none; }
.segmented .count { margin-left: var(--space-0-5); }
.work-list .task-table td { padding-top: var(--space-3); padding-bottom: var(--space-3); }
.work-list .task-main { min-width: 200px; }
.work-list .task-for-cell { min-width: 180px; }
.more-later { margin: 0 0 var(--stack-gap); padding: var(--space-3) var(--space-5); border: 1px dashed var(--border); border-radius: var(--radius); background: var(--surface); }
.filter-group { flex-wrap: wrap; }

@media (max-width: 720px) { .segmented a, .segmented label { padding: var(--space-1) var(--space-2-5); } }
@media (max-width: 360px) { .segmented a, .segmented label { padding: var(--space-1) var(--space-2); } }

/* A narrow task list (tasks/_task_row.html rows in a .task-list inside a .task-list-box) shows each
   task as a small card: phones, and small laptops where the sidebar takes room. */
.task-list-box { container: task-list / inline-size; }
@container task-list (max-width: 760px) {
  .task-list, .task-list tbody { display: block; }
  .task-list thead { display: none; }  /* a card has no columns to name */
  .task-list tr.group-row, .task-list tr.group-row th { display: block; }
  /* The box that ticks a row (where the list has one, and it shows), the round tick, the task; who it's for and its
     buttons keep to the right, so the title has the row's width less the initials. */
  .task-list tr.task-row {
    display: grid; grid-template-columns: auto auto minmax(0, 1fr) auto auto; row-gap: var(--space-0-5);
    padding: var(--space-3) var(--space-4); border-bottom: 1px solid var(--border);
  }
  /* beats .table-wrap's first/last-cell padding, and a data table's cells (theirs stay put, and take the row's colour) */
  .task-list-box table.task-list tr.task-row > td { position: static; height: auto; padding: 0; border: 0; background: none; box-shadow: none; }  /* not a compact row's fixed height: a card's line is as tall as its words */
  table.task-list td.select-cell { grid-column: 1; grid-row: 1 / 4; }
  table.task-list td.tick-cell { grid-column: 2; grid-row: 1 / 4; width: 36px; }
  .task-list .task-main { grid-column: 3 / 5; min-width: 0; }
  .task-list-box table.task-list tr.task-row > td.who-cell { grid-column: 5; grid-row: 1; padding-left: var(--space-2); }
  .task-list .task-for-cell { grid-column: 3 / 6; min-width: 0; }
  .task-list .due-cell { grid-column: 3; white-space: normal; }  /* beside the timer and Not needed buttons */
  .task-list .due-cell div { display: inline; }
  .task-list .due-cell div::before { content: " · "; }
  .task-list-box table.task-list tr.task-row > td.actions-cell { grid-column: 4 / 6; padding-left: var(--space-2); }
  @media (max-width: 720px) {  /* a phone, once Select is pressed: the box has the tick's place */
    .is-selecting .task-list .tick-cell { display: none; }
  }
  .data-table.task-list tbody tr.task-row:hover, .data-table.task-list tbody tr.task-row:focus-within { background: var(--surface-2); }
  .data-table.task-list tbody tr.task-row.is-selected { background: var(--primary-soft); }
  .card:not(.table-wrap) > .task-list tr.task-row, .card > details > .task-list tr.task-row { padding-left: 0; padding-right: 0; }  /* the card pads it */
}

/* Time: the timer bar (on every page while a timer runs), timer buttons, the timesheet and the report */
#timer-bar { position: sticky; top: 0; z-index: 26; }  /* over a client's slim bar, which moves down under it (.record-bar) */
#timer-bar:has(.timer-bar) { margin-top: -8px; padding-top: var(--space-2); background: var(--bg); }  /* nothing shows through above it */
@media (max-width: 899px) { .js #timer-bar { top: 56px; } }  /* below the phone top bar */
.timer-bar {
  display: flex; align-items: center; gap: var(--space-2) var(--space-3); flex-wrap: wrap; margin-bottom: var(--space-4); padding: var(--space-2) var(--space-3);
  border: 1px solid var(--primary); border-radius: var(--radius); background: var(--surface);
  box-shadow: var(--shadow-md); font-size: var(--text-base);
}
.timer-dot { width: 9px; height: 9px; flex-shrink: 0; border-radius: 50%; background: var(--danger); animation: timer-pulse 1.6s ease-in-out infinite; }
@keyframes timer-pulse { 50% { opacity: 0.3; } }
.timer-clock { font-weight: 700; font-variant-numeric: tabular-nums; }
.timer-what { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.timer-actions { display: flex; align-items: center; gap: var(--space-3); margin-left: auto; }
@media (prefers-reduced-motion: reduce) { .timer-dot { animation: none; } }

.icon.icon-fill { fill: currentColor; stroke: none; }
.timer-toggle {
  display: inline-grid; place-items: center; width: var(--control-height-sm); height: var(--control-height-sm); padding: 0; vertical-align: middle;
  border: 1px solid var(--border); border-radius: 50%; background: var(--surface); color: var(--muted); cursor: pointer;
}
.timer-toggle .icon { width: 11px; height: 11px; }
.timer-toggle:not(.is-running) .icon { margin-left: var(--space-0-5); }  /* the triangle looks centred */
.timer-toggle:hover { color: var(--link); border-color: var(--primary); }
.timer-toggle.is-running { background: var(--danger); border-color: var(--danger); color: #fff; }
.timer-toggle:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.actions-cell .timer-toggle { margin-right: var(--space-2-5); }

.time-toolbar > .tabs { flex: 1 0 100%; margin-bottom: var(--space-3); }  /* the tabs take the row and their rule crosses the page, as on the other tabs' pages; the filters go under it */
.time-totals { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-1) var(--space-5); margin-bottom: var(--space-2); }
.time-totals a { margin-left: auto; font-size: var(--text-base); }

/* Week grid: hours per client (rows) and day (columns); the client column stays put while a phone scrolls the days. */
.week-grid th, .week-grid td { padding: var(--space-2) var(--cell-pad-x); }
.week-grid tbody th, .week-grid tbody td { vertical-align: middle; }  /* a name, a total and a dash on the hour boxes' centre line */
.week-grid thead th { text-align: right; white-space: nowrap; }
.week-grid thead th:first-child { text-align: left; }
.week-grid abbr { text-decoration: none; }
.week-grid th[scope="row"] { min-width: 170px; text-transform: none; letter-spacing: 0; font-size: var(--text-base); font-weight: 600; color: var(--text); }
.week-grid th:first-child { position: sticky; left: 0; z-index: 1; background: var(--surface); }
.table-wrap .week-grid thead th:first-child { background: var(--surface-2); }  /* the header is one band: its first cell too (still opaque, so the days scroll under it) */
.week-grid .today { background: rgba(59, 106, 224, 0.08); }
.week-grid thead .today { color: var(--link); }
.week-grid .total { font-weight: 700; }
@media (max-width: 560px) {  /* more room for the days: a long name takes a second line instead of running over Monday */
  .week-grid th[scope="row"] { min-width: 110px; max-width: 150px; font-size: var(--text-sm); white-space: normal; overflow-wrap: break-word; }
  .week-grid:not(.rates-grid) th[scope="row"] { min-width: 150px; }  /* a client's name, on two lines at most */
  .week-grid th, .week-grid td { padding: var(--space-2); }
}

/* Entries by day (timesheet), and on a client's or task's page */
.day-list { padding-top: var(--space-1-5); padding-bottom: var(--space-1-5); }
.day + .day { border-top: 1px solid var(--border); }
.day-header { display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-1-5) var(--space-3); padding: var(--space-2-5) 0; }
.day-title { margin: 0; font-size: var(--text-md); }
.day-total { margin-left: auto; font-weight: 700; font-variant-numeric: tabular-nums; }
.entry-list { list-style: none; margin: 0 0 var(--space-1-5); padding: 0; }
.entry { display: flex; align-items: flex-start; gap: var(--space-3); padding: var(--space-2) 0; border-top: 1px solid var(--border); }  /* a row is one rule, as a table's */
.entry-hours { flex: 0 0 3rem; font-weight: 700; font-variant-numeric: tabular-nums; }  /* at the card's edge, where the tables under it start */
.entry-main { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.entry-main .badge { margin-left: var(--space-1); }
.entry-actions { display: flex; align-items: center; gap: var(--space-2); flex-shrink: 0; }

/* Report */
.report-filters .report-dates { display: none; }
.report-filters:has(select[name="period"] option[value="custom"]:checked) .report-dates { display: inline-flex; }
.report-table th[scope="row"] { text-transform: none; letter-spacing: 0; font-size: var(--text-md); font-weight: 600; color: var(--text); }
.report-table .report-subline th[scope="row"] { padding-left: var(--space-9); font-weight: normal; color: var(--muted); }
.report-subline td { color: var(--muted); }
@media (max-width: 720px) {  /* a phone: a long name takes more lines, so the hours and the amounts are on the screen */
  .report-table th[scope="row"] { min-width: 110px; white-space: normal; overflow-wrap: break-word; }
}

/* Approvals: a row holds buttons and badges, so its words are on their centre line, as a data table's. On a phone
   each row is a block: the name, then the week and the figures with their column's name, then the buttons. */
.approvals-table tbody th, .approvals-table tbody td { vertical-align: middle; }
.at-once-everything { margin: var(--space-3) 0 0; }
.at-once-groups { display: grid; grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); gap: var(--space-4) var(--space-5); margin: var(--space-4) 0 var(--space-3); }
.at-once-kinds { display: grid; gap: var(--space-2); align-content: start; margin: 0; padding: 0; border: 0; min-width: 0; }
.at-once-kinds legend { padding: 0; margin-bottom: var(--space-2); font-size: var(--text-sm); font-weight: 600; color: var(--text-2); }
.change-text { max-height: 50vh; margin-top: var(--space-2); overflow: auto; white-space: pre-wrap; overflow-wrap: anywhere; font-size: var(--text-sm); }  /* an approval's long text, as it will be (agents/actions/change_settings.html) */  /* Connected apps' Without approval: a tick a line */
@media (max-width: 720px) {
  .approvals-table, .approvals-table tbody { display: block; }
  .approvals-table thead { display: none; }
  .approvals-table tr { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-4); padding: var(--space-3) var(--space-5); border-bottom: 1px solid var(--border); }
  .approvals-table tbody tr:last-child { border-bottom: 0; }
  .table-wrap table.approvals-table tr > :is(th, td) { display: block; padding: 0; border: 0; text-align: left; }
  .approvals-table th[scope="row"] { flex: 1 1 100%; }
  .approvals-table td[data-label]::before { content: attr(data-label) " "; color: var(--muted); }
  .approvals-table td.right { margin-left: auto; }
}

/* Typing hours into the week grid. The table scrolls sideways on its own, above the grid's buttons. */
.card.week-grid-card { overflow: visible; }  /* beats .table-wrap's */
.grid-scroll { overflow-x: auto; border-radius: var(--radius) var(--radius) 0 0; }
.week-grid td:has(.hours-input) { padding-left: var(--space-1); padding-right: var(--space-1); }
.hours-input {
  width: 4.2em; padding: var(--space-1) var(--space-1-5); text-align: right; font-variant-numeric: tabular-nums;
  border-color: transparent; background: var(--bg);
}
.hours-input:hover { border-color: var(--border); }
.hours-input:focus { background: var(--surface); }
.week-grid td.has-error .hours-input { border-color: var(--danger); background: var(--error-bg); }
.cell-error { display: block; max-width: 7em; margin-top: var(--space-0-5); margin-left: auto; font-size: var(--text-xs); line-height: 1.2; color: var(--danger); white-space: normal; }
.grid-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); padding: var(--space-3) var(--space-5); border-top: 1px solid var(--border); }  /* its buttons are full size, as tall as the select beside them */
.grid-add { flex-wrap: wrap; }
.grid-add select { max-width: 280px; }
.grid-dirty { display: none; color: var(--warning-text); font-weight: 600; }
.week-grid-card.is-dirty .grid-dirty { display: inline; }
.grid-note { flex-basis: 100%; margin: 0; }  /* the grid's how-to, in its card under its buttons */

/* Settings, Billing rates (timesheets/rates.html): the week grid's look, with dollars in the boxes; the usual rate's
   column set apart from the services' */
.card.rates-grid-card { overflow: visible; }
.rates-grid thead th { white-space: normal; min-width: 6.5em; vertical-align: bottom; }
.rates-grid thead th:first-child { min-width: 0; }
.rates-grid .rates-usual { border-right: 2px solid var(--border); }
.rates-grid .rate-input { width: 6.5em; }
.rates-grid .rate-input::placeholder { color: var(--muted); opacity: 0.7; }
.rates-apply { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-2) var(--space-4); }
.rates-apply p { margin: 0; }

/* Where the week's timesheet stands (not submitted, submitted, approved, returned) */
.week-status {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-2) var(--space-4);
  margin-bottom: var(--stack-gap); padding: var(--space-3) var(--space-5); border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface);
}
.week-status-text { margin: 0; flex: 1; min-width: 220px; }
.week-status.is-submitted { border-color: var(--primary); }
.week-status.is-approved { border-color: var(--success-border); background: var(--success-bg); }
.week-status.is-returned { border-color: var(--warning-border-soft); background: var(--warning-bg); }
.return-week > summary { list-style: none; }
.return-week > summary::-webkit-details-marker { display: none; }
/* Opened, "Return…" takes a line of its own for the note (a popover would run off a phone's screen). */
.week-status .actions:has(.return-week[open]), .return-week[open] { flex-basis: 100%; }
.return-form { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-2); }
.return-form input { flex: 1; min-width: 180px; }

.form-notice { padding: var(--space-2-5) var(--space-4); border: 1px solid var(--warning-border-soft); border-radius: var(--radius); background: var(--warning-bg); color: var(--text); }
.form-notice.is-danger { border-color: var(--danger-border); background: var(--danger-bg); }  /* nothing was saved */
fieldset.form-grid { border: 0; padding: 0; margin: 0; min-width: 0; }
.badge.badge-billed { background: var(--success-bg); color: var(--success-text); }
.badge.badge-returned { background: var(--warning-bg); color: var(--warning-text); }
.unrated { margin-left: var(--space-0-5); color: var(--warning-text); cursor: help; }
.table-card-heading { margin: 0; padding: var(--space-4) var(--space-5) var(--space-1); }
.table-card-empty { margin: 0; padding: var(--space-2) var(--space-5) var(--space-5); }

/* Log time form: "Non-billable" only means something for client time. */
.time-form:has(select[name="time-entity"] option[value=""]:checked) .field-non-billable { display: none; }
.field-non-billable { column-gap: var(--space-3); }
.actions .push-right { margin-left: auto; }

/* Modal dialog (static/js/app.js) */
.modal {
  padding: 0; border: 1px solid var(--border); border-radius: var(--radius-lg);
  background: var(--surface); color: var(--text);
  width: min(640px, calc(100vw - 32px)); max-height: calc(100vh - 48px);
  box-shadow: var(--shadow-lg);
}
.modal::backdrop { background: var(--backdrop); }
.modal-card { padding: var(--space-5) var(--space-6) var(--space-6); }
.modal-header { display: flex; justify-content: space-between; align-items: center; gap: var(--space-3); margin-bottom: var(--space-3); }
.modal-header h2 { margin: 0; font-size: var(--text-xl); }
.modal-close { background: none; border: 0; font-size: var(--text-2xl); line-height: 1; color: var(--muted); cursor: pointer; padding: var(--space-0-5) var(--space-2); border-radius: var(--radius-md); }
.modal-close:hover { background: var(--bg); color: var(--text); }

/* Task form: two columns, the client/engagement/deadline block re-rendered when it changes */
.task-form { max-width: none; }
.form-grid, .task-links, .time-links { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); column-gap: var(--space-4); align-items: start; }  /* help goes under a box (forms/field.html), so two fields on a row keep their labels and their boxes level */
.form-grid .span-2 { grid-column: span 2; }
.task-links noscript, .time-links noscript { grid-column: 1 / -1; }  /* the no-JS hint spans however many columns there are */
.task-page-form { max-width: var(--width-form); }
@media (max-width: 560px) {
  .form-grid, .task-links, .time-links { grid-template-columns: minmax(0, 1fr); }
  .form-grid .span-2 { grid-column: auto; }
}
.missing-steps { display: flex; gap: var(--space-2-5); align-items: center; flex-wrap: wrap; margin: var(--space-3) 0; }
.progress-cell { min-width: 160px; }
/* The checklist is a part of the service form, not a box in it: its heading is a card's h3 and its fields start at
   the form's one left edge */
.checklist { border: 0; padding: 0; margin: var(--space-5) 0 var(--space-4); }
.checklist > legend { padding: 0; margin-bottom: var(--space-2); font-size: var(--text-md); font-weight: 600; color: var(--text); }
.checklist-table th, .checklist-table td { padding: var(--space-1-5); }
.checklist-table :is(th, td):first-child { padding-left: 0; }
.checklist-table :is(th, td):last-child { padding-right: 0; }
.checklist-table input[type="text"] { width: 100%; min-width: 180px; }
.checklist-table .days input { width: 5rem; }
.checklist-table select { max-width: 220px; }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.checklist { min-width: 0; }  /* a fieldset otherwise grows to fit its table */
.checklist-rows { container: checklist / inline-size; overflow-x: auto; }
@media (min-width: 721px) {
  .sr-only-wide { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
}
/* A narrow checklist (phones, small laptops) shows each step as a stack of labelled fields. */
@container checklist (max-width: 840px) {
  .checklist-table thead { display: none; }
  .checklist-table, .checklist-table tbody, .checklist-table tr, .checklist-table td { display: block; }
  .checklist-table tr { padding: var(--space-2-5) 0; border-bottom: 1px solid var(--border); }
  .checklist-table tbody tr:last-child { border-bottom: 0; }
  .checklist-table td, .card > .checklist-table td:first-child { padding: var(--space-1) 0; border: 0; text-align: left; }
  .checklist-table td[data-label]::before { content: attr(data-label); display: block; margin-bottom: var(--space-0-5); font-size: var(--text-sm); font-weight: 600; color: var(--muted); }
  .checklist-table input[type="text"], .checklist-table select { width: 100%; max-width: none; min-width: 0; }
}

/* Workspace picker */
.workspace-list { list-style: none; margin: var(--space-4) 0 0; padding: 0; max-width: var(--width-form); }
.workspace-card { display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); margin-bottom: var(--space-3); padding: var(--space-4) var(--space-5); }
.workspace-card.current { border-color: var(--primary); }
.workspace-name { font-weight: 600; font-size: var(--text-lg); }
.workspace-info { flex: 1; min-width: 0; }
.workspace-logo { width: 44px; height: 44px; object-fit: contain; border-radius: var(--radius-md); background: #fff; border: 1px solid var(--border); padding: 3px; }

/* Settings pages */
.settings-form { max-width: var(--width-form); }
.settings-form .card { scroll-margin-top: 16px; }
.item-list { list-style: none; margin: 0; padding: 0; }
.item-list .item { display: flex; justify-content: space-between; align-items: flex-start; gap: var(--space-4); padding: var(--space-3) 0; border-bottom: 1px solid var(--border); }
.item-list .item:last-child { border-bottom: 0; }
/* The card's padding is the space round the list: its first row starts there and its last ends there */
.item-list:not(.logo-grid) > .item:first-child { padding-top: 0; }
.item-list:not(.logo-grid) > .item:last-child { padding-bottom: 0; }
.item-list .item > .btn, .item-list .item > .item-actions, .item-list .item > form { flex-shrink: 0; }  /* a row's buttons keep their words; the text beside them wraps */
.item-title { font-weight: 600; }
.item-actions { display: flex; gap: var(--space-1-5); align-items: center; flex-wrap: wrap; justify-content: flex-end; }
.logo-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: var(--space-3); }  /* Make default, Edit and Delete on one line */
.logo-grid .item { flex-direction: column; justify-content: flex-start; align-items: stretch; border: 1px solid var(--border); border-radius: var(--radius); padding: var(--space-3); }
.logo-grid .item:last-child { border-bottom: 1px solid var(--border); }
.logo-grid .item.is-default { border-color: var(--primary); }
.logo-grid .item-actions { justify-content: flex-start; margin-top: auto; }  /* at the foot of every card in a row */
@media (max-width: 720px) {  /* a phone: a row's buttons go on a line of their own under its words, which keep the width */
  .item-list:not(.logo-grid) > .item:has(> .item-actions) { flex-wrap: wrap; row-gap: var(--space-2); }
  .item-list:not(.logo-grid) > .item > .item-actions { flex-basis: 100%; justify-content: flex-start; }
}
.logo-thumb { width: 100%; height: 80px; object-fit: contain; background: #fff; border-radius: var(--radius-md); }

/* A logo's editor (workspaces/_logo_editor.html, static/js/logo-editor.js): the picture to crop on the left, as large
   as the modal allows, the boxes on the right; on a phone, one above the other. Without the script there's no
   picture, and the boxes are a plain form. The part kept is a box over the picture, the rest dimmed around it (its
   shadow, cut at the picture's edge), with square handles inside its corners and sides; the picture stands on a
   chequerboard, so what's transparent shows as such. */
.modal:has(.logo-editor-card) { width: min(1120px, calc(100vw - 32px)); }
.logo-editor.form { max-width: none; }
.logo-editor [hidden] { display: none !important; }  /* buttons and fields have a display of their own */
.logo-editor-layout { display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: var(--space-5); align-items: start; }
.logo-editor-layout:has(> .logo-workspace[hidden]) { grid-template-columns: minmax(0, var(--width-form)); }
.logo-workspace { display: flex; flex-direction: column; gap: var(--space-2); min-width: 0; }
.logo-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1-5) var(--space-3); }
.logo-toolbar-group { display: flex; gap: var(--space-1-5); }
.logo-toolbar-gap { flex: 1; }
.logo-stage { height: min(56vh, 520px); display: grid; place-items: center; overflow: hidden; background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius); }
.logo-frame {
  --handle: 10px; --reach: 4px;
  position: relative; overflow: hidden; touch-action: none; cursor: crosshair;
  background: repeating-conic-gradient(var(--surface-3) 0 25%, var(--surface) 0 50%) 0 0 / 16px 16px;
}
.logo-canvas { display: block; width: 100%; height: 100%; }
.logo-crop { position: absolute; cursor: move; outline: 1px solid #fff; box-shadow: 0 0 0 1px rgba(15, 23, 42, 0.55), 0 0 0 100vmax rgba(15, 23, 42, 0.45); }
.logo-crop:focus-visible { outline: 2px solid var(--primary); outline-offset: 0; }
/* Resize: the box is the logo's own edge, nothing dimmed round it, and only its handles do anything. */
.logo-stage[data-mode="resize"] .logo-frame, .logo-stage[data-mode="resize"] .logo-crop { cursor: default; }
.logo-stage[data-mode="resize"] .logo-crop { box-shadow: 0 0 0 1px rgba(15, 23, 42, 0.55); }
.logo-handle { position: absolute; width: var(--handle); height: var(--handle); background: #fff; border: 1px solid rgba(15, 23, 42, 0.7); border-radius: 2px; }
.logo-handle::before { content: ""; position: absolute; inset: calc(var(--reach) * -1); }  /* more to catch than to see */
.logo-handle[data-handle="nw"] { left: 0; top: 0; cursor: nwse-resize; }
.logo-handle[data-handle="n"] { left: calc(50% - var(--handle) / 2); top: 0; cursor: ns-resize; }
.logo-handle[data-handle="ne"] { right: 0; top: 0; cursor: nesw-resize; }
.logo-handle[data-handle="e"] { right: 0; top: calc(50% - var(--handle) / 2); cursor: ew-resize; }
.logo-handle[data-handle="se"] { right: 0; bottom: 0; cursor: nwse-resize; }
.logo-handle[data-handle="s"] { left: calc(50% - var(--handle) / 2); bottom: 0; cursor: ns-resize; }
.logo-handle[data-handle="sw"] { left: 0; bottom: 0; cursor: nesw-resize; }
.logo-handle[data-handle="w"] { left: 0; top: calc(50% - var(--handle) / 2); cursor: ew-resize; }
@media (pointer: coarse) { .logo-frame { --reach: 12px; } }  /* a finger's reach */
.logo-readout { margin: 0; min-height: 1.5em; font-size: var(--text-sm); }
.logo-controls { min-width: 0; }
.logo-editor.form .field .logo-angle-row input[type="number"] { width: 5.5rem; flex: none; }  /* not .form's 100% */
.logo-angle-row { display: flex; align-items: center; gap: var(--space-2); }
.logo-angle-row input[type="range"] { flex: 1; min-width: 0; accent-color: var(--primary); }
.logo-size { border: 0; padding: 0; margin: 0 0 var(--space-4); }
.logo-size legend { padding: 0; margin-bottom: var(--space-2); font-weight: 600; font-size: var(--text-sm); color: var(--text-2); }
.logo-size .form-grid { column-gap: var(--space-3); }
.logo-size .field { margin-bottom: var(--space-2); }
.logo-keep { display: inline-flex; align-items: center; gap: var(--space-2); font-size: var(--text-sm); }
.logo-exact { margin-bottom: var(--space-4); }
.logo-exact summary { cursor: pointer; font-weight: 600; font-size: var(--text-sm); color: var(--text-2); }
.logo-exact[open] summary { margin-bottom: var(--space-2); }
.logo-exact > p { margin: 0 0 var(--space-3); font-size: var(--text-sm); }
.logo-exact .field { margin-bottom: var(--space-3); }
/* How it shows: the result in the frames the sidebar, an invoice and the portal's top bar give it, on their
   backgrounds, at the size they show it. */
.logo-previews { display: grid; gap: var(--space-2-5); padding-top: var(--space-4); border-top: 1px solid var(--border); }
.logo-previews h3 { margin: 0; font-size: var(--text-sm); color: var(--text-2); }
.logo-preview { display: flex; align-items: center; gap: var(--space-3); font-size: var(--text-sm); color: var(--muted); }
.logo-preview > :first-child { flex: none; display: flex; align-items: center; width: 196px; padding: var(--space-2); border: 1px solid var(--border); border-radius: var(--radius-md); }
.logo-preview-side { gap: var(--space-2); background: var(--sidebar-bg); color: var(--sidebar-text); font-weight: 600; }
.logo-preview-side span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.logo-preview-sheet { height: 86px; background: #fff; }
.logo-preview-sheet .inv-logo { margin: 0; }
.logo-preview-bar { height: 54px; background: var(--surface); }
.logo-editor .actions { margin-top: var(--space-5); }
.logo-editor .actions .logo-restore { margin-left: auto; }
@media (max-width: 860px) {
  .logo-editor-layout { grid-template-columns: minmax(0, 1fr); }
  .logo-stage { height: min(46vh, 360px); }
}

/* Settings: a menu panel beside the section being edited (a row of chips on smaller screens) */
.settings-layout { display: grid; grid-template-columns: 236px minmax(0, 1fr); gap: var(--space-7); align-items: start; }
.settings-menu {
  position: sticky; top: 20px; display: flex; flex-direction: column; gap: var(--space-3); padding: var(--space-2-5);
  border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface);
}
.settings-menu-group { display: flex; flex-direction: column; gap: var(--space-0-5); }
.settings-menu-heading { padding: var(--space-1) var(--space-2-5); font-size: var(--text-xs); font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted); }
.settings-menu a { display: flex; align-items: center; gap: var(--space-2-5); padding: var(--space-2) var(--space-2-5); border-radius: var(--radius-md); color: var(--text); font-size: var(--text-md); }
.settings-menu a .icon { width: 16px; height: 16px; color: var(--muted); }
.settings-menu a:hover { background: var(--bg); text-decoration: none; }
.settings-menu a.active { background: var(--info-bg); color: var(--info-text); font-weight: 600; }
.settings-menu a.active .icon { color: var(--info-text); }
.settings-body { min-width: 0; max-width: var(--width-read); }
.settings-body > h2, .settings-body > .section-header h2 { font-size: var(--text-xl); margin-bottom: var(--space-1); }  /* also when it shares its line with a button */
.settings-body > .section-header { align-items: flex-end; }  /* as a page's header: a long intro wraps beside the button, which stays on its line */
.settings-body > .section-header > div:first-child { flex: 1 1 320px; min-width: 0; }
.settings-body > .section-intro { margin: 0 0 var(--space-4); }
/* A section's heading stands 16px over its first card, with an intro line or without, and with a button beside it */
.settings-body > h2:not(:has(+ .section-intro)) { margin-bottom: var(--space-4); }
.settings-body > .section-header { margin-bottom: var(--space-4); }
.settings-body > .section-header h2:last-child { margin-bottom: 0; }
.settings-body .form { max-width: none; }  /* as wide as the list cards */
.settings-body > .form-notice { margin: 0 0 var(--stack-gap); }  /* a notice over a section's cards is one of the stack */
.card-heading { margin: 0 0 var(--space-3); font-size: var(--text-lg); }  /* a card's title, as an h2 or an h3: one size */
.item-with-icon { display: flex; flex: 1; gap: var(--space-3); align-items: flex-start; min-width: 0; overflow-wrap: anywhere; }
.item-with-icon > .icon { margin-top: 3px; color: var(--muted); }
@media (max-width: 1100px) {
  .settings-layout { grid-template-columns: minmax(0, 1fr); gap: var(--space-4); }
  .settings-menu { position: static; flex-direction: row; flex-wrap: wrap; gap: var(--space-1-5); padding: 0; border: 0; background: none; }
  .settings-menu-group { flex-direction: row; flex-wrap: wrap; gap: var(--space-1-5); }
  .settings-menu-heading { display: none; }
  .settings-menu a { white-space: nowrap; min-height: var(--control-height); padding: var(--space-1-5) var(--space-3); border: 1px solid var(--border); border-radius: var(--radius-full); background: var(--surface); }
  .settings-menu a.active { border-color: var(--primary); }
}
/* On a phone the sections fold behind one button, so a settings page starts with its own section (app.js opens them) */
.settings-menu .settings-menu-toggle { display: none; }
.settings-menu .settings-menu-toggle .icon { width: 14px; height: 14px; margin: 0 0 0 var(--space-1); }
.settings-menu .settings-menu-toggle[aria-expanded="true"] .icon { transform: rotate(180deg); }
@media (max-width: 720px) {
  .js .settings-menu .settings-menu-toggle { display: inline-flex; }
  .js .settings-menu:not(.is-open) .settings-menu-group { display: none; }
}

/* Sign-in and invite pages */
.auth-page { max-width: 420px; margin: 9vh auto var(--space-10); padding: 0 var(--space-4); }
.auth-brand { display: flex; align-items: center; justify-content: center; gap: var(--space-2-5); margin-bottom: var(--space-5); font-size: var(--text-2xl); font-weight: 650; letter-spacing: -0.02em; }
.auth-brand img { border-radius: 9px; }
.auth-card h1 { font-size: var(--text-xl); margin-bottom: var(--space-4); }
.auth-links { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: var(--space-1) var(--space-4); margin-top: var(--space-4); font-size: var(--text-sm); color: var(--muted); }  /* centred: on a phone the language's button is a finger tall, and the links beside it keep its line */
.auth-links a { color: var(--muted); }
.auth-links .auth-powered { flex-basis: 100%; text-align: center; }  /* the client portal's "Powered by Firmdesk": a line of its own, under the links */
.auth-card .form { max-width: none; }
/* The consent page an assistant sends the person to (agents/templates/agents/authorize.html): the two marks, one
   line under the name, who and which firm in one box, a row a module, the two promises, then the buttons. */
.consent h1 { margin-bottom: var(--space-1); text-align: center; }
.consent-marks { display: flex; align-items: center; justify-content: center; gap: var(--space-3); margin-bottom: var(--space-4); }
.consent-mark { width: 48px; height: 48px; border: 1px solid var(--border); border-radius: var(--radius-lg); }
.consent-mark-app { display: grid; place-items: center; background: var(--surface-2); color: var(--text); font-size: var(--text-lg); font-weight: 650; }
img.consent-mark { padding: var(--space-2); background: var(--surface); }
.consent-arrow { color: var(--muted); }
.consent-source { display: flex; align-items: center; justify-content: center; gap: var(--space-1-5); margin: 0; color: var(--muted); font-size: var(--text-sm); }
.consent-source .icon { width: 16px; height: 16px; color: var(--success); }
.consent .form { margin-top: var(--space-5); }
.consent .errorlist { margin-top: var(--space-4); text-align: center; }
.consent-who { margin-bottom: var(--space-5); border: 1px solid var(--border); border-radius: var(--radius); }
.consent-row, .consent-scope { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-2-5) var(--space-3); }
.consent-row + .consent-row { border-top: 1px solid var(--border); }
.consent-row .avatar { width: 28px; height: 28px; }
.consent-row-icon { margin: 0 5px; color: var(--muted); }  /* 18px, centred under the 28px avatar */
.consent-row-text { display: flex; flex: 1; flex-direction: column; min-width: 0; font-size: var(--text-sm); line-height: 1.35; overflow-wrap: anywhere; }
.consent-row-text .muted { font-size: var(--text-xs); }
.consent-row select { flex: 1; min-width: 0; }
.consent-note { margin: 0; padding: var(--space-2) var(--space-3); border-top: 1px solid var(--border); color: var(--muted); font-size: var(--text-xs); line-height: 1.4; }
.consent-scopes { margin: 0 0 var(--space-4); padding: 0; border: 0; }
.consent-scopes legend { margin-bottom: var(--space-1); padding: 0; font-size: var(--text-sm); font-weight: 600; }
.consent-scope { padding-inline: 0; cursor: pointer; }
.consent-scope + .consent-scope { border-top: 1px solid var(--border); }
.consent-scope input { flex: none; }
.consent-promises { margin: 0 0 var(--space-5); padding: var(--space-3); border-radius: var(--radius); background: var(--surface-2); list-style: none; color: var(--text-2); font-size: var(--text-sm); }
.consent-promises li { display: flex; align-items: flex-start; gap: var(--space-2); }
.consent-promises li + li { margin-top: var(--space-1-5); }
.consent-promises .icon { width: 16px; height: 16px; margin-top: 1px; color: var(--muted); }
.consent-actions { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-2); }
.consent-actions .btn-primary { order: 2; }  /* first in the form, so it's the one Enter presses; on the right, where it usually is */
.consent-after { margin: var(--space-3) 0 0; color: var(--muted); font-size: var(--text-xs); text-align: center; }
.auth-card > p:has(+ .app-sheet) { margin-bottom: 0; }  /* the portal's sign-in: the app sheet that comes last is fixed, out of the flow, so this sentence ends the card */
.btn-block { width: 100%; }
.card.notice { border-color: var(--primary); }
.invite-link { display: flex; gap: var(--space-2); margin-top: var(--space-2); }
.invite-link input { flex: 1; min-width: 0; font-family: ui-monospace, monospace; font-size: var(--text-sm); }

/* --- 5. Components ------------------------------------------------------------------------------------ */

/* Page header: where you are (breadcrumb), the title, one line about it, then one main action and a menu
   for the rest. Every page starts with one. */
.page-header {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-3) var(--space-4);
  flex-wrap: wrap;
  margin-bottom: var(--space-5);
}
.page-header > div:first-child { min-width: 0; flex: 1 1 320px; }
.page-header h1 { overflow-wrap: anywhere; padding-block: var(--space-0-5); }  /* a line of 30px and this: a button's height, so the title stands at one place with a subtitle or without */
.page-header h1 .badge { vertical-align: middle; }
.page-header p { margin: var(--space-1) 0 0; }
.page-header > div:first-child > a.muted.small {
  display: inline-block; margin-bottom: var(--space-1); font-weight: 500;
}
.breadcrumb { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-0-5) var(--space-1); margin: 0 0 var(--space-1); font-size: var(--text-sm); color: var(--muted); }
.breadcrumb a { color: var(--muted); font-weight: 500; }
.breadcrumb a:hover { color: var(--text); text-decoration: none; }
.breadcrumb .sep { width: 14px; height: 14px; margin: 0; flex-shrink: 0; color: var(--border-strong); }
.breadcrumb [aria-current] { color: var(--text-2); }
.page-subtitle { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-2-5); margin: var(--space-1) 0 0; color: var(--muted); }
/* Pieces parted by a dot: each piece is its own element and the dot ends the one before, so it sits midway between
   them and a wrapped line never starts with one. None next to a pill. */
.page-subtitle.has-dots > :not(.badge, .field-head):has(+ :not(.badge, .field-head))::after {
  content: "·"; display: inline-block; margin-left: var(--space-2-5); color: var(--muted); font-weight: 400;
}
.page-header .actions { flex-shrink: 0; }
.page-header:has(> .actions > .more-menu:only-child) > div:first-child { flex-basis: 0; }  /* a lone menu stays beside the title */

/* The rest of a page's actions, behind a "more" button */
.more-menu .menu-panel { left: auto; right: 0; min-width: 210px; z-index: 30; }
.more-menu > summary { cursor: pointer; }
.more-menu > summary.btn { display: inline-flex; align-items: center; justify-content: center; padding-left: var(--space-2); padding-right: var(--space-2); }
.more-menu > summary .icon { margin: 0; width: 16px; height: 16px; }
.more-menu[open] > summary.btn { border-color: var(--border-strong); background: var(--surface-3); }

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: var(--space-5);
  margin-bottom: var(--stack-gap);
  box-shadow: var(--shadow-xs);
}
/* A card's padding is its only inner gap: what starts or ends it adds no margin of its own. A sentence that opens a
   card after a form's hidden inputs is named too, and .field and .toggle-row so they outweigh .form's rules for them.
   These stay here: later in the file they would also flatten the nudges that come after (.portal-welcome > .icon). */
.card > :first-child, .card > form > p:first-child, .card > input[type="hidden"] + p, .card > form > input[type="hidden"] + p { margin-top: 0; }
.card > :last-child, .card > .field:last-child, .card > .toggle-row:last-child { margin-bottom: 0; }

.muted { color: var(--muted); }
.small { font-size: var(--text-sm); }
.right { text-align: right; }
.plain-list { list-style: none; margin: 0; padding: 0; }
.plain-list li { padding: var(--space-1) 0; }  /* spacing parts a list's rows; lines are for panes, sections and tables */

.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--stack-gap); }
.stats > .card { margin-bottom: 0; }  /* the grid's gap parts the cards; the row's own class sets the space under it */
.stat { display: flex; flex-direction: column; color: var(--text); }
a.stat:hover { text-decoration: none; border-color: var(--primary); }
.stat-value { font-size: var(--text-3xl); font-weight: 650; letter-spacing: -0.02em; line-height: 1.2; font-variant-numeric: tabular-nums; }
.stat-label { color: var(--muted); }

/* Buttons: primary (one per page), secondary (the default), ghost, danger */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  vertical-align: middle;  /* in a line of text an icon-led button and a text-only one stay level */
  min-height: var(--control-height);
  padding: var(--space-1) var(--space-3);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
  background: var(--surface);
  color: var(--text);
  font: 500 var(--text-base)/1.4 var(--font);
  cursor: pointer;
  white-space: nowrap;
  box-shadow: var(--shadow-xs);
  transition: background 0.12s, border-color 0.12s, box-shadow 0.12s;
}
.btn:hover { text-decoration: none; background: var(--surface-2); border-color: var(--muted); }
.btn:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.btn:active { box-shadow: none; }
.btn-primary { background: var(--primary); border-color: var(--primary); color: var(--on-primary); }
.btn-primary:hover { background: var(--primary-hover); border-color: var(--primary-hover); }
.btn-ghost { background: none; border-color: transparent; box-shadow: none; color: var(--text-2); }
.btn-ghost:hover { background: var(--surface-3); border-color: transparent; }
.btn-danger { background: var(--danger-solid); border-color: var(--danger-solid); color: #fff; }
.btn-danger:hover { background: #a92a2a; border-color: #a92a2a; }
.btn-danger-outline { color: var(--danger); }
.btn-danger-outline:hover { border-color: var(--danger); background: var(--danger-bg); }
.btn-small { min-height: var(--control-height-sm); padding: var(--space-0-5) var(--space-2-5); font-size: var(--text-sm); }
.btn:disabled, .btn[aria-disabled="true"] { opacity: 0.5; cursor: not-allowed; }
.btn .icon { width: 15px; height: 15px; margin-right: var(--space-1-5); }
.btn.icon-only .icon { margin-right: 0; }
.actions { display: flex; gap: var(--space-2); align-items: center; flex-wrap: wrap; }
@media (prefers-reduced-motion: reduce) { .btn { transition: none; } }

/* Tables */
.table-wrap { padding: 0; overflow-x: auto; }
table { width: 100%; border-collapse: collapse; }
th, td { text-align: left; padding: 10px var(--cell-pad-x); border-bottom: 1px solid var(--border); vertical-align: top; }
th { font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); font-weight: 600; white-space: nowrap; }
thead th { background: var(--surface-2); }
.card:not(.table-wrap) > table thead th, .card:not(.table-wrap) > .table-scroll > table thead th, .card > details > table thead th,
.card > details > .table-scroll > table thead th { background: none; }  /* in a card that pads itself the column names are plain; a .table-wrap card keeps the band */
tbody tr:last-child td, tbody tr:last-child th { border-bottom: 0; }
/* A table's total row (its tfoot), one build: the name in the words' size and colour like its figures, bold, on their
   baseline; a rule above, none below. A printed invoice (.inv-lines) keeps its own. */
:where(table:not(.inv-lines) > tfoot) th, :where(table:not(.inv-lines) > tfoot) td { border-bottom: 0; font-weight: 700; color: var(--text); vertical-align: baseline; }
:where(table:not(.inv-lines) > tfoot) th { font-size: inherit; text-transform: none; letter-spacing: 0; }
:where(table:not(.inv-lines) > tfoot > tr:first-child) > th, :where(table:not(.inv-lines) > tfoot > tr:first-child) > td { border-top: 2px solid var(--border); }
.card > table th:first-child, .card > table td:first-child { padding-left: 0; }
.card > table th:last-child, .card > table td:last-child { padding-right: 0; }
.table-wrap table th:first-child, .table-wrap table td:first-child { padding-left: var(--space-5); }
.table-wrap table th:last-child, .table-wrap table td:last-child { padding-right: var(--space-5); }
/* A card that pads itself: its table's first and last cells start at the padding (not a .table-wrap card's, which has none) */
.card:not(.table-wrap) > .table-scroll > table th:first-child, .card:not(.table-wrap) > .table-scroll > table td:first-child,
.card > details > .table-scroll > table th:first-child, .card > details > .table-scroll > table td:first-child { padding-left: 0; }
.card:not(.table-wrap) > .table-scroll > table th:last-child, .card:not(.table-wrap) > .table-scroll > table td:last-child,
.card > details > .table-scroll > table th:last-child, .card > details > .table-scroll > table td:last-child { padding-right: 0; }
@media (max-width: 720px) { .hide-sm { display: none; } }
/* A table wider than a phone scrolls sideways in its box: a shade at the box's right edge says there is more, and
   goes once the table is scrolled to its end (a cover the table's own background carries along covers it). */
@media (max-width: 720px) {
  .table-wrap, .table-scroll {
    background-image: linear-gradient(var(--surface), var(--surface)), linear-gradient(to left, var(--border-strong), transparent);
    background-position: right center, right center; background-repeat: no-repeat; background-size: var(--space-3) 100%, var(--space-3) 100%;
    background-attachment: local, scroll;
  }
}

/* The table component: <div class="card table-wrap data-table-box"><table class="data-table">.
   Sticky column names, a row that lights up under the pointer, its actions showing on hover or focus, columns
   that sort (links in the header), and a first column that stays put when a phone scrolls sideways.
   Density: "compact" on <html data-density="compact">, the firm app's default (templates/base.html); "comfortable"
   without it, when chosen in the user menu. */
.data-table-box { position: relative; }
.data-table thead th { position: sticky; top: 0; z-index: 2; background: var(--surface-2); box-shadow: inset 0 -1px 0 var(--border); border-bottom: 0; }
.data-table tbody tr:hover > td, .data-table tbody tr:focus-within > td { background: var(--surface-2); }
.data-table tbody tr.is-selected > td { background: var(--primary-soft); }
.data-table td { vertical-align: middle; }
.data-table .row-actions { text-align: right; white-space: nowrap; }
@media (hover: hover) and (min-width: 900px) {
  .data-table .row-actions > * { opacity: 0; transition: opacity 0.1s; }
  .data-table tr:hover .row-actions > *, .data-table tr:focus-within .row-actions > *, .data-table .row-actions > [open] { opacity: 1; }
}
/* On a laptop a list with many columns (Clients) keeps none for buttons that show only under the pointer: they lie over
   the end of their own row (.row-actions.is-over, its buttons in a .row-actions-set) */
@media (hover: hover) and (min-width: 900px) and (max-width: 1439px) {
  .data-table .row-actions.is-over { width: 0; padding-left: 0; padding-right: var(--space-2-5); }
  .data-table td.row-actions.is-over { position: relative; }
  .data-table .row-actions-set { position: absolute; top: 50%; right: 12px; transform: translateY(-50%); padding-left: var(--space-2); background: inherit; }
  .data-table tr:focus-within:not(:hover) .row-actions.is-over > .row-actions-set:not(:focus-within) { opacity: 0; }
}
.data-table .select-cell { width: 36px; padding-right: 0; }
/* A block box with a text line's height around it, as the tick has: on the row's middle beside the tick, or on the
   first line in a card. vertical-align: middle put it 2px low. */
.data-table .select-cell input { display: block; width: 16px; height: 16px; margin: calc((1lh - 16px) / 2) 0; accent-color: var(--primary); }
th.sortable { padding: 0; }
th.sortable > a { display: flex; align-items: center; gap: var(--space-1); padding: 10px var(--cell-pad-x); color: inherit; }
.table-wrap table th.sortable:first-child { padding-left: 0; }
.table-wrap table th.sortable:first-child > a { padding-left: var(--space-5); }
th.sortable > a:hover { color: var(--text); text-decoration: none; }
th.sortable.num > a { justify-content: flex-end; }
th.sortable .sort-mark { width: 12px; height: 12px; opacity: 0.35; }
th.sortable[aria-sort] > a { color: var(--text); }
th.sortable[aria-sort] .sort-mark { opacity: 1; color: var(--primary); }
th.sortable[aria-sort="descending"] .sort-mark { transform: rotate(180deg); }
:root[data-density="compact"] th, :root[data-density="compact"] td { padding-top: var(--space-1); padding-bottom: var(--space-1); }
:root[data-density="compact"] th.sortable { padding-top: 0; padding-bottom: 0; }
:root[data-density="compact"] th.sortable > a { padding-top: var(--space-1); padding-bottom: var(--space-1); }
/* Every row of a compact list is as tall as one whose buttons show (a small button and the row's padding), so rows
   with actions and rows without are one height. */
:root[data-density="compact"] .data-table tbody td { height: calc(var(--control-height-sm) + 10px); }
/* Compact hides a cell's second lines (inside it), never a cell itself: that would pull its row's columns left.
   Not the line that says why an email didn't go: it's what the reader came for. */
:root[data-density="compact"] .data-table td .small:not(.email-error, .kept-until) { display: none; }
/* On a phone the boxes are hidden (a tap opens a row) until Select shows them */
.select-toggle { display: none; }
@media (max-width: 720px) {
  .data-table th:first-child:not(.select-cell), .data-table td:first-child:not(.select-cell),
  .data-table .select-cell + th, .data-table .select-cell + td {
    position: sticky; left: 0; z-index: 1; background: var(--surface); box-shadow: 1px 0 0 var(--border);
  }
  /* The column name that stays put is part of the header's band: its tint, and the line under it with the divider */
  .data-table thead th:first-child:not(.select-cell), .data-table thead .select-cell + th { z-index: 3; background: var(--surface-2); box-shadow: inset 0 -1px 0 var(--border), 1px 0 0 var(--border); }
  .data-table .select-cell { display: none; }  /* a tap opens a row; Select shows the boxes and the bar */
  /* The row's edge was on the hidden box's cell: the next cell, the one that stays put, carries it (with its divider) */
  .tracker-table tr.is-late > .select-cell + td { box-shadow: inset 3px 0 0 var(--danger), 1px 0 0 var(--border); }
  .tracker-table tr.is-soon > .select-cell + td { box-shadow: inset 3px 0 0 var(--warning), 1px 0 0 var(--border); }
  .todo-table tr.has-new > .select-cell + td { box-shadow: inset 3px 0 0 var(--primary), 1px 0 0 var(--border); }
  .is-selecting :is(.tracker-table, .todo-table) tr > .select-cell + td { box-shadow: 1px 0 0 var(--border); }
  .select-toggle { display: inline-flex; }
  .is-selecting .data-table .select-cell { display: table-cell; }
  .data-table td.primary-cell { min-width: var(--width-name-cell); }  /* the name that stays put keeps a few words a line */
}
/* A short table whose rows hold buttons, or whose columns can't all fit a phone, stacks there: <table class="table-stack">. Below 720 each row is a block, its
   cells one under the other at the row's left edge, so no button is ever behind the card's edge. The column names
   go: a cell says what it is in its own words, or gives its column's name in data-label ("Amount" shows before
   "$120.00"); an empty cell takes no room. A list with nothing to press scrolls sideways instead, its first column
   kept in sight (.data-table). The class is doubled where it must outweigh that sticky first column and a compact
   list's row height. */
@media (max-width: 720px) {
  .table-stack, .table-stack > :is(tbody, tfoot), .table-stack > :is(tbody, tfoot) > tr { display: block; }
  .table-stack > thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  /* A list that sorts by its column names keeps them, as a row of links over the stacked rows: the only way to sort it */
  .table-stack > thead:has(th.sortable) { position: static; display: block; width: auto; height: auto; overflow: visible; clip: auto; }
  .table-stack > thead:has(th.sortable) > tr { display: flex; flex-wrap: wrap; align-items: center; column-gap: var(--space-2); }
  .table-stack.table-stack > thead > tr > th.sortable:not(.hide-sm) { position: static; display: block; background: none; box-shadow: none; }
  .table-stack.table-stack > thead > tr > th:not(.sortable) { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .table-wrap .table-stack > thead:has(th.sortable) { background: var(--surface-2); box-shadow: inset 0 -1px 0 var(--border); }
  .table-stack > :is(tbody, tfoot) > tr { padding: var(--space-3) 0; border-bottom: 1px solid var(--border); }
  .table-stack > tbody > tr:last-child { border-bottom: 0; }
  .table-stack > tfoot { border-top: 2px solid var(--border); }  /* a total under the rows, as in the wide table */
  .table-stack > tfoot > tr:last-child { padding-bottom: 0; border-bottom: 0; }
  :root .table-stack.table-stack > tfoot > tr > :is(td, th) { display: block; padding: 0; border: 0; text-align: left; }
  .table-stack > tfoot > tr > :is(td, th) + :is(td, th) { margin-top: var(--space-1-5); }
  .card:not(.table-wrap) > :is(.table-scroll > .table-stack, .table-stack) > tbody:first-of-type > tr:first-child { padding-top: 0; }  /* the card pads it */
  .card:not(.table-wrap) > :is(.table-scroll > .table-stack, .table-stack) > tbody:last-of-type > tr:last-child { padding-bottom: 0; }
  .table-wrap .table-stack > :is(tbody, tfoot) > tr { padding-inline: var(--space-5); }
  .table-stack > tbody > tr { box-shadow: inset 3px 0 0 var(--row-edge, transparent); }  /* a state row's edge is the row's */
  .card:not(.table-wrap) > .table-scroll > .table-stack > tbody > tr:is(.needs-amount, .has-new, .is-new, .is-failed) { padding-left: var(--space-2-5); }  /* off the edge */
  .card:not(.table-wrap) > .table-scroll > .table-stack.table-stack > tbody > tr > td:first-child { padding-left: 0; }  /* the row is off the edge, not its first cell */
  :root .table-stack.table-stack > tbody > tr > :is(td, th):not(.select-cell, .hide-sm, :empty) {
    display: block; position: static; height: auto; padding: 0; border: 0; background: none; box-shadow: none; text-align: left; white-space: normal;
  }
  .table-stack > tbody > tr > :empty { display: none; }
  .table-stack > tbody > tr > :is(td, th) + :is(td, th) { margin-top: var(--space-1-5); }
  .table-stack .nowrap { white-space: normal; }
  .table-stack.table-stack > tbody > tr > :is(td, th) { overflow-wrap: anywhere; }  /* a long email breaks rather than run past the card */
  .table-stack .due.is-stacked { flex-direction: row; align-items: center; gap: var(--space-1) var(--space-1-5); }  /* the row has the width: the pill goes back beside its date */
  /* A cell of buttons wraps them in rows, a gap apart */
  :root .table-stack.table-stack > tbody > tr > td:has(> form.inline, > .inline-form, > .btn):not(.hide-sm) { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1-5); }
}
/* A state row names its edge's colour, and the row at the foot of a table card draws the edge itself, stopping where
   the card's corner starts: an accent edge is straight */
.tracker-table tr.is-late, .email-table tr.is-failed, .activity-table tr.is-alert, .run-table tr.is-failed { --row-edge: var(--danger); }
.tracker-table tr.is-soon, .reminder-table tr.needs-amount { --row-edge: var(--warning); }
.doc-row.is-new, .todo-table tr.has-new { --row-edge: var(--primary); }
:where(.table-wrap > :last-child tbody:last-child > tr:last-child) > td:first-child { position: relative; }  /* weightless, so a phone's sticky first column stays sticky */
.table-wrap > :last-child tbody:last-child > tr:last-child:is(.is-late, .is-soon, .is-new, .has-new, .is-failed, .needs-amount, .is-alert) > td:first-child { box-shadow: none; }
.table-wrap > :last-child tbody:last-child > tr:last-child > td:first-child::before { content: ""; position: absolute; left: 0; top: 0; bottom: var(--radius); width: 3px; background: var(--row-edge, transparent); }
@media (max-width: 720px) {  /* the same at the foot of the two lists whose edge is on the next cell (it is sticky, so the edge has its box) */
  .table-wrap :is(.tracker-table, .todo-table) > tbody:last-child > tr:last-child > .select-cell + td { box-shadow: 1px 0 0 var(--border); }
  .table-wrap :is(.tracker-table, .todo-table) > tbody:last-child > tr:last-child > .select-cell + td::before { content: ""; position: absolute; left: 0; top: 0; bottom: var(--radius); width: 3px; background: var(--row-edge, transparent); }
  .is-selecting .table-wrap :is(.tracker-table, .todo-table) > tbody:last-child > tr:last-child > .select-cell + td::before { content: none; }
}
@media (max-width: 720px) {  /* a stacked table's column names (.table-stack, above): here, after the edge a table card's last row draws on its first cell, which they outweigh */
  :root .table-stack.table-stack > :is(tbody, tfoot) > tr > td[data-label][data-label]::before {
    content: attr(data-label) " "; position: static; width: auto; background: none; color: var(--muted);
  }
}

/* What the ticked rows can do: a bar that shows once one is ticked (static/js/app.js) */
.bulk-bar {
  position: sticky; bottom: 16px; z-index: 20; display: none; align-items: center; gap: var(--space-2) var(--space-3); flex-wrap: wrap;
  width: fit-content; max-width: 100%; margin: var(--space-3) auto 0; padding: var(--space-2) var(--space-2-5) var(--space-2) var(--space-4);
  border-radius: var(--radius-lg); background: var(--text); color: var(--surface); box-shadow: var(--shadow-lg);
}
.bulk-bar.is-active { display: flex; }
/* "All 25 clients on this page are selected. Select all 112 that match": a band at the top of the ticked table */
.select-banner { margin: 0; padding: var(--space-2) var(--space-4); border-bottom: 1px solid var(--border); background: var(--primary-soft); color: var(--text); font-size: var(--text-sm); text-align: center; }
.select-banner[hidden] { display: none; }
.select-banner .link-button { font-weight: 600; }
.bulk-bar .bulk-count { font-weight: 600; margin-right: var(--space-1); }
.bulk-bar .btn { background: transparent; border-color: rgba(127, 137, 150, 0.5); color: inherit; box-shadow: none; }
.bulk-bar .btn:hover { background: rgba(127, 137, 150, 0.25); }
.bulk-bar select, .pdf-toolbar select { min-height: var(--control-height-sm); padding: var(--space-0-5) 26px var(--space-0-5) var(--space-2); font-size: var(--text-sm); }
.no-js .bulk-bar, .no-js .select-cell { display: none; }
@media (max-width: 720px) {  /* a phone: one line that scrolls sideways, so the list stays in sight above it */
  .bulk-bar {
    flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; padding-right: var(--space-7);
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent);
    mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent);  /* more is to the right */
  }
  .bulk-bar > * { flex: none; white-space: nowrap; }
}

.badge {
  display: inline-flex;
  align-items: center;
  padding: 1px var(--space-2);
  border-radius: var(--radius-full);
  font-size: var(--text-xs);
  font-weight: 600;
  line-height: 1.5;
  background: var(--surface-3);
  color: var(--text-2);
  white-space: nowrap;
}
.badge-active { background: var(--success-bg); color: var(--success-text); }
.badge-prospect, .badge-stage { background: var(--info-bg); color: var(--info-text); }  /* a deadline under way: its stage */
.badge-inactive { background: var(--surface-3); color: var(--muted); }
.badge-overdue { background: var(--danger-bg); color: var(--danger); }
.badge-soon { background: var(--warning-bg); color: var(--warning-text); }
.badge-client { background: var(--purple-bg); color: var(--purple-text); }
.badge-done { background: var(--success-bg); color: var(--success-text); }

.details { display: grid; grid-template-columns: 180px 1fr; gap: var(--space-2-5) var(--space-4); margin: 0; }
.details dt { color: var(--muted); }
.details dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }
@media (max-width: 720px) { .details { grid-template-columns: 1fr; gap: var(--space-0-5); } .details dd { margin-bottom: var(--space-2-5); } }

/* Forms */
.filters input[type="search"] { flex: 1; min-width: 200px; }

input, select, textarea {
  font: inherit;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--control-border);
  border-radius: var(--radius-md);
  padding: var(--space-1) var(--space-2-5);  /* with its line and its edge, --control-height: the height of a button beside it */
}
input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):not(.switch), select { min-height: var(--control-height); }
/* Chrome and Safari pad the parts of a date (Chrome round all of them, Safari round each): without these a date or
   time field is 2 to 4px taller than the field beside it */
input::-webkit-datetime-edit-fields-wrapper { padding: 0; }
input::-webkit-datetime-edit, input::-webkit-datetime-edit-year-field, input::-webkit-datetime-edit-month-field,
input::-webkit-datetime-edit-day-field, input::-webkit-datetime-edit-hour-field, input::-webkit-datetime-edit-minute-field,
input::-webkit-datetime-edit-meridiem-field { padding-block: 0; }
input::placeholder, textarea::placeholder { color: var(--muted); opacity: 0.85; }
input:hover, select:hover, textarea:hover { border-color: var(--muted); }
input:focus, select:focus, textarea:focus { outline: 0; border-color: var(--primary); box-shadow: 0 0 0 3px var(--focus-ring); }
input[type="checkbox"], input[type="radio"] { flex-shrink: 0; accent-color: var(--primary); width: 16px; height: 16px; min-height: 0; padding: 0; margin-block: 0; margin-inline-start: 0; vertical-align: middle; box-shadow: none; }  /* never squeezed by a long label beside it; its left edge is the label column's (the browser's own margin only stays after it) */
input[type="checkbox"]:focus-visible, input[type="radio"]:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; box-shadow: none; }
/* An unticked box or radio wears the fields' surface and edge (the input rule above gives them); ticked, it stays the browser's, in the accent colour. 2px is the browser's own corner, so a box keeps its shape when ticked. */
input[type="checkbox"]:not(:checked):not(:indeterminate):not(.switch), input[type="radio"]:not(:checked) { -webkit-appearance: none; appearance: none; border-radius: 2px; }
input[type="radio"]:not(:checked) { border-radius: 50%; }
/* Some ticked (a list's select-all box) is drawn by the page too: the browser's dash is dark on the dark theme's blue.
   The one-colour gradient only paints the dash. */
input[type="checkbox"]:indeterminate { -webkit-appearance: none; appearance: none; border-color: var(--primary); border-radius: 2px; background: linear-gradient(var(--on-primary), var(--on-primary)) center / 8px 2px no-repeat, var(--primary); }
input[type="search"] { -webkit-appearance: none; appearance: none; }
select {
  max-width: 100%;  /* long options (client names) can't widen the page */
  overflow: hidden;  /* nor can a long chosen one's words: Safari draws them past the box, and the page scrolls to them */
  -webkit-appearance: none; appearance: none; padding-right: 30px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%237b8798' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 9px center;
}
select[multiple] { background-image: none; padding-right: var(--space-2-5); }
input:disabled, select:disabled, textarea:disabled { background: var(--surface-3); color: var(--muted); cursor: not-allowed; }

.form { max-width: var(--width-form); }  /* every form: one width, so a card's right edge is at one place from form to form */
.form .field { display: flex; flex-direction: column; gap: var(--space-1-5); margin-bottom: var(--space-4); }
.form .field input:not([type="checkbox"]):not([type="radio"]), .form .field select, .form .field textarea { width: 100%; }
/* Radio groups (rendered by Django as a fieldset) */
.field fieldset { border: 0; padding: 0; margin: 0; }
.field fieldset legend { font-weight: 600; font-size: var(--text-sm); color: var(--text-2); padding: 0; margin-bottom: var(--space-1-5); }  /* a field's label: its size, colour and gap to what it names */
.field fieldset label { display: inline-flex; gap: var(--space-2); align-items: center; font-weight: normal; font-size: var(--text-base); }
.field fieldset > div > div { margin: 3px 0; }
.field label { font-weight: 600; font-size: var(--text-sm); color: var(--text-2); }
.field .helptext { color: var(--muted); font-size: var(--text-sm); }
.field:has(input[type="checkbox"]) { flex-direction: row; align-items: center; flex-wrap: wrap; gap: var(--space-1-5) var(--space-2); }
.field:has(> input[type="checkbox"]) > .helptext { order: 1; flex-basis: 100%; }  /* a tick box shares its label's line, and its help goes under both */

.inline-form { display: flex; gap: var(--space-3); align-items: flex-end; flex-wrap: wrap; }
.inline-form .field { display: flex; flex-direction: column; gap: var(--space-1-5); min-width: 0; max-width: 100%; margin: 0; }  /* in a .form too: its button stands level with the field, not with the field's margin */
.inline-form .field:has(> input[type="checkbox"]) { min-height: var(--control-height); }  /* a tick box and its label sit on the row's centre line, not on its foot */
/* Inline forms use placeholders instead; help text would misalign the row. */
.inline-form > .field-head { min-height: var(--control-height); }  /* a tick box with its (?), outside a .field (a client's Add a contact): on the same centre line */
.inline-form .helptext { display: none; }
@media (max-width: 720px) {  /* on a phone the fields stack, each as wide as the form: one right edge (a tick box keeps its own line's width) */
  .inline-form .field:not(:has(> input[type="checkbox"])) { flex: 1 1 100%; }
  .inline-form .field > input:not([type="checkbox"]):not([type="radio"]), .inline-form .field > select, .inline-form .field .combo { width: 100%; }
}

/* Entity form: the household fields only for an individual */
.form:has([name="entity_type"]) .field:not(.has-error):has([name="household_head"], [name="household_role"]) { display: none; }
.form:has(select[name="entity_type"] option[value="individual"]:checked, input[name="entity_type"][value="individual"]:checked) .field:has([name="household_head"], [name="household_role"]) { display: flex; }

/* A searchable client picker (app.js "Client pickers"): type a few letters of any part of a name, recent clients
   first; the <select> stays underneath without JavaScript. A row is the name alone. */
.combo { position: relative; }
.combo-input { position: relative; }
.combo-input > .icon { position: absolute; left: 10px; top: 50%; width: 16px; height: 16px; transform: translateY(-50%); color: var(--muted); pointer-events: none; }
.combo-input input { width: 100%; padding-left: var(--space-8); }
.combo-list {
  position: absolute; left: 0; right: 0; top: calc(100% + 4px); z-index: 40; max-height: 300px; margin: 0; padding: var(--space-1); overflow-y: auto;
  list-style: none; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); box-shadow: var(--shadow-md);
}
.combo-list[hidden] { display: none; }
.combo-group { padding: var(--space-2) var(--space-2-5) var(--space-1); font-size: var(--text-xs); font-weight: 600; letter-spacing: 0.05em; text-transform: uppercase; color: var(--muted); }
.combo-option { display: flex; align-items: center; gap: var(--space-2-5); min-height: var(--control-height); padding: var(--space-1-5) var(--space-2-5); border-radius: var(--radius-md); color: var(--text); cursor: pointer; }
.combo-option:hover, .combo-option.is-active { background: var(--surface-3); }
.combo-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.combo-name mark { background: none; color: inherit; font-weight: 700; text-decoration: underline; text-underline-offset: 2px; }
.combo-check { width: 16px; height: 16px; color: var(--primary); visibility: hidden; }
.combo-option[aria-selected="true"] .combo-check { visibility: visible; }
.combo-foot { margin: var(--space-1) -4px -4px; padding: var(--space-2) var(--space-4); border-top: 1px solid var(--border); color: var(--muted); font-size: var(--text-sm); }
.combo-empty { padding: var(--space-2-5); color: var(--muted); font-size: var(--text-sm); }
@media (max-width: 899px), (pointer: coarse) { .combo-option { min-height: var(--touch-target); } }

/* Choice cards (hello/forms.py ChoiceCards): a choice whose options each need a sentence. The radio stays in sight
   (its own edge says it's a control); a border and no shadow; the chosen card takes a primary border. */
.choices { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: var(--space-2); }
.field .choices label.choice {
  display: grid; grid-template-columns: 18px minmax(0, 1fr); gap: var(--space-0-5) var(--space-2-5); align-content: start; align-items: start;
  padding: var(--space-2-5) var(--space-3); border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface);
  color: var(--text); font-size: var(--text-base); font-weight: 400; cursor: pointer;
}
.choice input[type="radio"] { grid-row: 1 / 3; margin: var(--space-0-5) 0 0; }
.choice-title { font-weight: 600; }
.choice-help { grid-column: 2; color: var(--muted); font-size: var(--text-sm); line-height: 1.45; }
.field .choices label.choice:hover { border-color: var(--control-border); }
.field .choices label.choice:has(input:checked) { border-color: var(--primary); box-shadow: inset 0 0 0 1px var(--primary); }
/* A service's checklist (tasks/_checklist.html): starting from another checklist hides the blank rows until it's saved */
.checklist-copy-note { display: none; }
.checklist:has(select[name="checklist-source"] option:checked:not([value=""])) .checklist-own { display: none; }
.checklist:has(select[name="checklist-source"] option:checked:not([value=""])) .checklist-copy-note { display: block; }
/* Add a task list (tasks/_task_list_form.html): the chosen list's tasks show under its cards, dated, with who */
.task-list-form .choices { grid-template-columns: repeat(auto-fill, minmax(168px, 1fr)); }
.task-list-preview { display: none; }
.task-list-form:has(input[value="acceptance"]:checked) .task-list-preview[data-list="acceptance"],
.task-list-form:has(input[value="onboarding"]:checked) .task-list-preview[data-list="onboarding"],
.task-list-form:has(input[value="offboarding"]:checked) .task-list-preview[data-list="offboarding"] { display: block; }
.task-list-preview h3 { margin: 0 0 var(--space-1-5); font-size: var(--text-base); }
.task-list-steps { margin: 0 0 var(--space-1-5); padding: 0; list-style: none; border: 1px solid var(--border); border-radius: var(--radius); }
.task-list-steps li { display: flex; justify-content: space-between; gap: var(--space-3); padding: var(--space-2) var(--space-3); border-top: 1px solid var(--border); }
.task-list-steps li:first-child { border-top: 0; }
.task-list-steps li > span:last-child { flex: none; white-space: nowrap; }
@media (max-width: 560px) { .task-list-steps li { flex-direction: column; gap: var(--space-0-5); } }
/* Service form: the anniversary date only for a return that follows it */
.form:has(select[name="period_basis"]) .field-anniversary:not(.has-error) { display: none; }
.form:has(select[name="period_basis"] option[value="anniversary"]:checked) .field-anniversary { display: flex; }

/* Share register entry form: show From/To only for the types that use them */
.txn-form .field-from_party, .txn-form .field-to_party { display: none; }
.txn-form:has(select[name="transaction_type"] option[value="issue"]:checked) .field-to_party,
.txn-form:has(select[name="transaction_type"] option[value="transfer"]:checked) .field-from_party,
.txn-form:has(select[name="transaction_type"] option[value="transfer"]:checked) .field-to_party,
.txn-form:has(select[name="transaction_type"] option[value="redemption"]:checked) .field-from_party { display: flex; }
.txn-form input[type="number"] { width: 8rem; }

.section-header { display: flex; justify-content: space-between; align-items: center; gap: var(--space-3); flex-wrap: wrap; margin-bottom: var(--space-3); }
.section-header h2, .section-header .filters { margin: 0; }
.section-header .section-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.section-header .filters { align-items: center; }
.num { text-align: right; font-variant-numeric: tabular-nums; }
.nowrap { white-space: nowrap; }
.tabular, time, .deadline-day { font-variant-numeric: tabular-nums; }
.table-scroll { overflow-x: auto; }
tr.future { opacity: 0.45; }
form.inline { display: inline; }
details.past { margin-top: var(--space-3); }
details.past summary { cursor: pointer; color: var(--muted); margin-bottom: var(--space-2); }

.warning { color: var(--warning-text); }

/* A guarded form's own Save row floats at the bottom of the window once something has changed (app.js marks it
   is-dirty and adds "Unsaved changes"); with the end of the form in view, it sits where it always was. A field that
   takes the keyboard scrolls clear of the row: the browser counts what's under a sticky row as in view. */
form[data-unsaved-guard].is-dirty > .actions:last-child {
  position: sticky; bottom: 16px; z-index: 20; margin-top: var(--space-5); padding: var(--space-2-5) var(--space-3) var(--space-2-5) var(--space-4);
  border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--surface); box-shadow: var(--shadow-lg);
}
html:has(form[data-unsaved-guard].is-dirty) { scroll-padding-bottom: 96px; }
.form-state { display: inline-flex; align-items: center; gap: var(--space-2); margin-right: auto; color: var(--text); font-weight: 500; white-space: nowrap; }
.form-state::before { content: ""; width: 8px; height: 8px; flex-shrink: 0; border-radius: 50%; background: var(--warning); }
form:not(.is-dirty) .form-state { display: none; }
@media (max-width: 560px) {  /* a phone: "Unsaved", Save and Cancel on one line; a row with more buttons takes two */
  form[data-unsaved-guard].is-dirty > .actions:last-child { padding: var(--space-2) var(--space-2-5) var(--space-2) var(--space-3); }
  html:has(form[data-unsaved-guard].is-dirty) { scroll-padding-bottom: 152px; }
  .form-state { gap: var(--space-1-5); }
  .form-state-more { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
}

.errorlist { list-style: none; margin: 0; padding: 0; color: var(--danger); font-size: var(--text-sm); }
.has-error input, .has-error select, .has-error textarea { border-color: var(--danger); }

/* A new password's rules (security/passwords.py): a dot for each until typing starts, then a green tick for a rule
   that's met and a red cross for one that isn't (app.js, "New passwords"). The last rule is checked on sending,
   so it keeps its dot. The second box says whether the two match. */
.password-rules { list-style: none; margin: var(--space-1) 0 0; padding: 0; display: grid; gap: var(--space-0-5); }
.password-rules li, .password-match { display: flex; align-items: center; gap: var(--space-1-5); font-size: var(--text-sm); color: var(--muted); }
.password-rules li::before, .password-match::before {
  content: ""; flex: none; width: 14px; height: 14px; background: currentColor;
  -webkit-mask: var(--rule-mark) center / contain no-repeat; mask: var(--rule-mark) center / contain no-repeat;
  --rule-mark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'%3E%3Ccircle cx='7' cy='7' r='2.5'/%3E%3C/svg%3E");
}
.password-rules li.is-met, .password-match.is-met { color: var(--success-text); }
.password-rules li.is-unmet, .password-match.is-unmet { color: var(--danger); }
.password-rules li.is-met::before, .password-match.is-met::before {
  --rule-mark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E");
}
.password-rules li.is-unmet::before, .password-match.is-unmet::before {
  --rule-mark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='6' x2='6' y2='18'/%3E%3Cline x1='6' y1='6' x2='18' y2='18'/%3E%3C/svg%3E");
}
.password-match { margin: var(--space-1-5) 0 0; }
.password-match[hidden] { display: none; }
.copy-inline { vertical-align: middle; margin-left: var(--space-1); }

/* Messages: toasts in the corner, so they show wherever the page is scrolled (includes/messages.html, and
   showMessage() in static/js/app.js). An icon for the kind, the words, maybe one action, and Dismiss. Success and
   information fade after 6 seconds, but not while the pointer or the keyboard is on them; errors, warnings and the
   word that a long job is over stay until dismissed. With a dialog open they show inside it (.dialog-messages), above its backdrop. */
#messages, .dialog-messages { position: fixed; right: 20px; bottom: 20px; z-index: 60; width: min(420px, calc(100vw - 32px)); pointer-events: none; }
.messages { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-2); }
.message {
  display: flex; align-items: flex-start; gap: var(--space-2-5);
  padding: var(--space-2-5) var(--space-2) var(--space-2-5) var(--space-3); border-radius: var(--radius); background: var(--success-bg); color: var(--success-text);
  border: 1px solid var(--success-border); box-shadow: var(--shadow-md); pointer-events: auto; font-weight: 500;
}
.message > .icon { width: 18px; height: 18px; flex-shrink: 0; margin-top: 1px; }
.message-text { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.message-action {
  flex-shrink: 0; padding: 0 var(--space-1); border: 0; background: none; color: inherit; font: inherit; font-weight: 650;
  text-decoration: underline; text-underline-offset: 2px; cursor: pointer;
}
.message-close {
  display: inline-grid; place-items: center; flex-shrink: 0; width: 24px; height: 24px; margin: -2px 0 -2px var(--space-0-5); padding: 0;
  border: 0; border-radius: var(--radius-sm); background: none; color: inherit; opacity: 0.7; cursor: pointer;
}
.message-close:hover, .message-close:focus-visible { opacity: 1; background: rgba(127, 137, 150, 0.16); }
.message-close .icon { width: 16px; height: 16px; }
.message-success { animation: message-out 0.4s ease 6s forwards; }
.message-error { background: var(--danger-bg); color: var(--danger); border-color: var(--danger-border); }
.message-info { background: var(--surface); color: var(--text); border-color: var(--border); animation: message-out 0.4s ease 6s forwards; }
.message-warning { background: var(--warning-bg); color: var(--warning-text); border-color: var(--warning-border-soft); }
.message-stay { animation: none; }  /* a long job that's over (app.js, "Long jobs"): there until it's closed */
.message:hover, .message:focus-within { animation-play-state: paused; }
@keyframes message-out { to { opacity: 0; visibility: hidden; } }
@media (max-width: 720px) { #messages, .dialog-messages { right: 16px; bottom: 16px; } }
/* While a bar floats at the bottom of the window (the ticked rows' actions, a changed form's Save row), the toasts
   stand over it, not on its buttons */
body:has(.bulk-bar.is-active) #messages { bottom: 104px; }
body:has(form[data-unsaved-guard].is-dirty) #messages { bottom: 80px; }
@media (max-width: 720px) {
  body:has(.bulk-bar.is-active) #messages { bottom: 84px; }
  body:has(form[data-unsaved-guard].is-dirty) #messages { bottom: 142px; }
}
@media (max-width: 560px) {  /* a phone: the action goes under the words, which keep the width */
  .message { flex-wrap: wrap; }
  .message-text { flex-basis: 0; }
  .message-close { order: 1; }
  .message-action { order: 2; flex-basis: 100%; padding: var(--space-1) 0 var(--space-0-5) var(--space-7); text-align: left; }
}
@media (prefers-reduced-motion: reduce) { .message-success, .message-info { animation-duration: 0s; } }

/* A part of a page that didn't load (static/js/app.js): says so where it failed, with Try again */
.load-error {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-2) var(--space-3); margin: 0 0 var(--space-3); padding: var(--space-2-5) var(--space-4);
  border: 1px solid var(--danger-border); border-radius: var(--radius); background: var(--danger-bg); color: var(--text);
}
.load-error > .icon { width: 18px; height: 18px; color: var(--danger); }
.load-error > span { flex: 1; min-width: 12em; }

/* A button at work (static/js/app.js): a spinner after a moment, so a quick answer doesn't flicker, and no
   second press. It isn't disabled (that would drop its name and value), only marked. */
.spinner {
  display: inline-block; flex-shrink: 0; width: 14px; height: 14px; margin-right: var(--space-1-5); border: 2px solid currentColor;
  border-right-color: transparent; border-radius: 50%; opacity: 0; animation: spinner-in 0s linear 0.3s forwards, spin 0.8s linear 0.3s infinite;
}
@keyframes spinner-in { to { opacity: 1; } }
@keyframes spin { to { transform: rotate(360deg); } }
.btn.is-busy, .menu-item.is-busy { opacity: 1; cursor: progress; }
@media (prefers-reduced-motion: reduce) { .spinner { animation: spinner-in 0s linear 0.3s forwards, spin 2.4s linear 0.3s infinite; } }

/* htmx: what's being replaced dims while the request is on its way, and a bar runs along the top of the page */
.results { transition: opacity 150ms; }
.results.htmx-request, .htmx-request.results { opacity: 0.55; }
.htmx-indicator { opacity: 0; transition: opacity 0.2s; }
.htmx-request .htmx-indicator, .htmx-request.htmx-indicator { opacity: 1; }
#loading-bar {
  position: fixed; top: 0; left: 0; right: 0; z-index: 100; height: 2px; pointer-events: none; opacity: 0;
  background: linear-gradient(90deg, transparent, var(--primary) 40%, #8fb0ff 60%, transparent); background-size: 50% 100%;
  background-repeat: no-repeat;
}
.is-loading #loading-bar { opacity: 1; animation: loading-bar 1.1s linear infinite; }
@keyframes loading-bar { from { background-position: -50% 0; } to { background-position: 150% 0; } }
@media (prefers-reduced-motion: reduce) { .is-loading #loading-bar { animation: none; background: var(--primary); } }

/* A grey shape where content is on its way (tabs loading) */
.skeleton { display: block; border-radius: var(--radius-md); background: var(--surface-3); color: transparent; animation: skeleton 1.4s ease-in-out infinite; }
.skeleton-line { height: 12px; margin: var(--space-2-5) 0; }
.skeleton-line.is-short { width: 40%; }
@keyframes skeleton { 50% { opacity: 0.5; } }
@media (prefers-reduced-motion: reduce) { .skeleton { animation: none; } }

/* Nothing here yet: what this is for, and the way to start */
.empty {
  display: flex; flex-direction: column; align-items: center; gap: var(--space-1-5); padding: var(--space-9) var(--space-5); text-align: center; color: var(--muted);
}
.empty > .icon { width: 32px; height: 32px; stroke-width: 1.5; color: var(--border-strong); margin-bottom: var(--space-1); }
.empty h2, .empty h3 { margin: 0; font-size: var(--text-md); color: var(--text); }
.empty p { max-width: 460px; margin: 0; }
.empty .actions { margin-top: var(--space-2-5); justify-content: center; }
.empty > .illustration { margin-bottom: var(--space-0-5); }
.empty > .illustration + h2, .empty > .illustration + h3 { margin-top: var(--space-1); }

/* Where someone is in a flow of several pages ({% steps %}): done, this one, still to come */
.steps { display: grid; grid-template-columns: repeat(auto-fit, minmax(90px, 1fr)); gap: var(--space-1-5); margin: var(--space-1) 0 var(--space-5); padding: 0; list-style: none; counter-reset: step; font-size: var(--text-sm); color: var(--muted); }
.steps li { padding-top: var(--space-2); border-top: 3px solid var(--border); counter-increment: step; }
.steps li::before { content: counter(step) ". "; }
.steps li.is-done { border-top-color: var(--success); color: var(--text-2); }
.steps li.is-current { border-top-color: var(--primary); color: var(--text); font-weight: 600; }
.auth-card .steps { grid-template-columns: repeat(auto-fit, minmax(60px, 1fr)); }  /* four steps in the card's 316px on a phone */

/* Illustrations (templates/includes/illustrations.html, {% illustration %}): 96px on empty states and first visits,
   132px on whole-page states. The accent is blue; green for done, amber for expired or needing a look; never red. */
.illustration { width: 96px; height: 96px; fill: none; stroke: var(--ill-line); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; flex-shrink: 0; }
.illustration.is-large { width: 132px; height: 132px; }
.illustration.is-success { --ill-accent: var(--success); }
.illustration.is-warning { --ill-accent: var(--warning); }
.ill-wash { fill: var(--ill-wash); stroke: none; }
.ill-paper { fill: var(--ill-paper); }
.ill-accent { stroke: var(--ill-accent); }
.ill-accent-fill { fill: var(--ill-accent); stroke: none; }
.ill-dot { fill: var(--ill-line); stroke: none; }
.ill-ground { stroke: var(--ill-ground); }
.ill-thick { stroke-width: 3.5; }

/* Error pages (config/errors.py): what happened, what to do, and a way back */
.error-page { max-width: 480px; text-align: center; }
.error-card { display: flex; flex-direction: column; align-items: center; gap: var(--space-1-5); padding: var(--space-8) var(--space-7) var(--space-6); }
.error-card h1 { margin: var(--space-2-5) 0 0; font-size: var(--text-xl); }
.error-card > p { max-width: 380px; margin: 0; color: var(--text-2); }
.error-card .actions { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--space-2-5); margin-top: var(--space-3); }
.error-card .error-foot { margin-top: var(--space-3); }

/* Tooltips (static/js/app.js): a control's name, over it, on hover or keyboard focus. One element, in the top layer
   (a popover), so no box that scrolls can clip it; placed through CSSOM. */
.tooltip {
  position: fixed; inset: auto; margin: 0; z-index: 90; max-width: 260px; padding: var(--space-1) var(--space-2); border: 0; border-radius: var(--radius-md);
  background: var(--tooltip-bg); color: var(--tooltip-text); box-shadow: var(--shadow-md); overflow: visible;
  font: 500 var(--text-xs)/1.4 var(--font); text-align: center; white-space: normal;
}
.tooltip[hidden] { display: none; }
.tooltip kbd { margin-left: var(--space-2); padding: 0 var(--space-1); border-radius: var(--radius-sm); background: rgba(127, 137, 150, 0.3); font: inherit; }

/* (?) hints ({% hint %}, hello/hints.py): a small button beside a label or a heading; its panel says what the label
   doesn't. A popover: the browser opens and closes it; static/js/app.js places it and adds a peek on hover. */
.hint {
  position: relative; display: inline-grid; place-items: center; width: 20px; height: 20px; margin: 0 0 0 3px; padding: 0;
  vertical-align: -4px; border: 0; border-radius: 50%; background: none; color: var(--muted); cursor: pointer; flex-shrink: 0;
}
.hint .icon { width: 15px; height: 15px; }
.hint:hover, .hint:focus-visible, .hint:has(+ .hint-panel:popover-open) { color: var(--primary); background: var(--primary-soft); }
.hint::after { content: ""; position: absolute; inset: -6px; }  /* a bigger target than it looks */
.field-head { display: inline-flex; align-items: center; flex-wrap: wrap; gap: 0 var(--space-0-5); }
.hint-panel { display: block; margin-top: var(--space-0-5); color: var(--muted); font-size: var(--text-sm); }  /* a browser without popovers: plain help */
.hint-title { display: none; }
@supports selector(:popover-open) {
  .hint-panel {
    position: fixed; inset: auto; margin: 0; z-index: 80; width: min(300px, calc(100vw - 24px)); padding: var(--space-3) var(--space-4);
    border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); color: var(--text);
    box-shadow: var(--shadow-md); font-weight: normal; line-height: 1.5; text-align: left; text-transform: none; letter-spacing: 0;
  }
  .js .hint-panel:not(.is-placed) { visibility: hidden; }
  .hint-panel a { display: inline-block; margin-top: var(--space-1); font-weight: 500; }
  /* Phones: a sheet at the bottom of the screen, with the label it's about on top */
  @media (max-width: 560px) {
    .hint-panel:popover-open { inset: auto 12px 12px; width: auto; padding: var(--space-4); box-shadow: var(--shadow-lg); }
    .hint-panel .hint-title { display: block; margin-bottom: var(--space-1); font-weight: 650; }
  }
}
@supports not selector(:popover-open) { .hint { display: none; } }
@media (max-width: 899px), (pointer: coarse) { .hint::after { inset: -12px; } }  /* a finger's width on a phone */
/* A group of choices (a fieldset) has its (?) beside its legend, which is otherwise a line of its own. */
fieldset > legend:has(+ .hint) { float: left; margin-right: var(--space-0-5); }
fieldset > legend:has(+ .hint) ~ :not(.hint, .hint-panel) { clear: left; }

/* Asking first (static/js/app.js): the question, what else changes, then Cancel and the verb */
.confirm-dialog { width: min(440px, calc(100vw - 32px)); }
.confirm-dialog h2 { margin: 0 0 var(--space-2); font-size: var(--text-lg); }
.confirm-dialog p { margin: 0 0 var(--space-5); color: var(--text-2); }
.confirm-dialog h2 + .actions { margin-top: var(--space-4); }
.confirm-dialog .actions { display: flex; justify-content: flex-end; flex-wrap: wrap; gap: var(--space-2); }

.pagination { display: flex; gap: var(--space-3); align-items: center; justify-content: center; flex-wrap: wrap; }
.pagination .page-size { display: inline-flex; align-items: center; gap: var(--space-1-5); margin-left: var(--space-2); }
.pagination .page-size select { min-height: var(--control-height-sm); padding: var(--space-0-5) 26px var(--space-0-5) var(--space-2); font-size: var(--text-sm); }
.load-more { display: flex; justify-content: center; align-items: center; gap: var(--space-3); padding: var(--space-3); }

/* Tabs: sections of one record, each with its own address */
.tabs {
  display: flex; gap: var(--space-0-5); margin: 0 0 var(--space-5); padding: 0; border-bottom: 1px solid var(--border); overflow-x: auto;
  scrollbar-width: none; list-style: none;
}
.tabs::-webkit-scrollbar { display: none; }
.tabs > a {
  position: relative; display: inline-flex; align-items: center; gap: var(--space-2); min-height: 40px; padding: var(--space-2) var(--space-3); margin-bottom: -1px;
  border-bottom: 2px solid transparent; color: var(--muted); font-weight: 500; white-space: nowrap;
}
.tabs > a:hover { color: var(--text); text-decoration: none; border-bottom-color: var(--border-strong); }
.tabs > a.active, .tabs > a[aria-current] { color: var(--text); font-weight: 600; border-bottom-color: var(--primary); }
.tabs > a:focus-visible { outline-offset: -2px; }
/* The same inside the other boxes that clip what is drawn outside their items: the Inbox's tabs and rows, a list's column names */
.inbox-filters a:focus-visible, .inbox-row-link:focus-visible, th.sortable > a:focus-visible { outline-offset: -2px; }
.tabs .count { font-size: var(--text-xs); }
.tabs.has-more { overflow: visible; }  /* app.js folds the tabs that don't fit under More */
.tabs [data-tab][hidden] { display: none; }
.tabs-more { position: relative; flex-shrink: 0; }
.tabs-more[hidden] { display: none; }
.tabs-more > summary {
  display: inline-flex; align-items: center; gap: var(--space-1); min-height: 40px; padding: var(--space-2) var(--space-3); margin-bottom: -1px; list-style: none;
  border-bottom: 2px solid transparent; color: var(--muted); font-weight: 500; white-space: nowrap; cursor: pointer;
}
.tabs-more > summary::-webkit-details-marker { display: none; }
.tabs-more > summary .icon { width: 14px; height: 14px; }
.tabs-more > summary:hover { color: var(--text); border-bottom-color: var(--border-strong); }
.tabs-more.has-current > summary { color: var(--text); font-weight: 600; border-bottom-color: var(--primary); }
.tabs-more .menu-panel { left: auto; right: 0; min-width: 220px; }
.tabs-more .menu-item[aria-current] { font-weight: 600; }
.tabs-more .menu-item .count { margin-left: auto; }
.tabs .count.is-alert { background: var(--danger-bg); color: var(--danger); }
@media (max-width: 899px) { .tabs > a, .tabs-more > summary { min-height: var(--touch-target); } }

/* Filters: a search box, a Filters button that opens the rest, what's in force as chips that come off,
   and the views someone saved. All of it is in the address, so a filtered list can be bookmarked and shared. */
/* Every filter bar is this one row: a search box, selects, segmented controls, chips, one height and one gap, and the
   same space under it. The page-specific classes only add what is theirs. */
.toolbar, .filters, .portal-filters, .tracker-filters, .work-filters, .time-toolbar, .tracker-toolbar, .calendar-toolbar {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); margin-bottom: var(--space-4);
}
.toolbar input[type="search"] { flex: 1 1 240px; min-width: 0; max-width: 420px; }
.toolbar .push-right { margin-left: auto; }
.search-field { position: relative; flex: 1 1 240px; min-width: 0; max-width: 420px; }
.search-field > .icon { position: absolute; left: 10px; top: 50%; width: 16px; height: 16px; transform: translateY(-50%); color: var(--muted); pointer-events: none; }
.search-field input[type="search"] { width: 100%; max-width: none; padding-left: var(--space-8); }
/* What shares a toolbar's row is one height (--control-height): fields, selects and segmented controls are that tall
   everywhere; the small buttons beside them gain theirs. A Copy button is as tall as its field. */
.tracker-toolbar .tracker-nav .btn-small, .time-toolbar .tracker-nav .btn-small, .copy-field .btn { min-height: var(--control-height); }
.filter-menu .menu-panel {
  left: 0; right: auto; z-index: 30; width: min(340px, calc(100vw - 32px)); padding: var(--space-3);
  display: grid; gap: var(--space-2-5);
}
.filter-menu > summary { cursor: pointer; }
.menu.opens-left > .menu-panel { left: auto; right: 0; }
.filter-menu[open] > summary.btn { border-color: var(--primary); color: var(--link); }
.filter-menu .field { display: flex; flex-direction: column; gap: var(--space-1); margin: 0; }
.filter-menu .field label, .filter-menu .field-label { font-size: var(--text-xs); font-weight: 600; color: var(--muted); text-transform: uppercase; letter-spacing: 0.04em; }
.filter-menu select, .filter-menu input[type="text"], .filter-menu input[type="date"] { width: 100%; }
.filter-menu .check { white-space: normal; }
.filter-menu .actions { justify-content: space-between; margin-top: var(--space-0-5); padding-top: var(--space-2-5); border-top: 1px solid var(--border); }
/* The filter bar's chips (includes/filter_menu.html): a filter in force is a chip that opens its own field; the
   dashed "Filter" chip holds the ones not in use */
.fchip > summary {
  display: inline-flex; align-items: center; gap: var(--space-1); min-height: var(--control-height); padding: var(--space-0-5) var(--space-2) var(--space-0-5) var(--space-3); list-style: none;
  border: 1px solid var(--control-border); border-radius: var(--radius-full); background: var(--surface);
  color: var(--text-2); font-size: var(--text-sm); font-weight: 500; white-space: nowrap;
}
.fchip > summary::-webkit-details-marker { display: none; }
.fchip > summary .icon { width: 14px; height: 14px; color: var(--muted); }
.fchip > summary:hover { border-color: var(--muted); }
.fchip.is-set > summary { border-color: var(--primary); background: var(--primary-soft); color: var(--info-text); }
.fchip.is-set > summary .icon { color: var(--info-text); }
.fchip.is-add > summary { border-style: dashed; }
.fchip[open] > summary { box-shadow: 0 0 0 3px var(--focus-ring); }
.filter-chips { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1-5); margin: 0 0 var(--space-4); padding: 0; list-style: none; }
.filter-chip {
  display: inline-flex; align-items: center; gap: var(--space-1); min-height: var(--control-height-sm); padding: var(--space-0-5) var(--space-1) var(--space-0-5) var(--space-2-5); border-radius: var(--radius-full);
  background: var(--primary-soft); color: var(--info-text); font-size: var(--text-sm); font-weight: 500;
}
.filter-chip a { display: inline-grid; place-items: center; width: 20px; height: 20px; border-radius: 50%; color: inherit; }
.filter-chip a:hover { background: var(--info-border); text-decoration: none; }
.filter-chip a .icon { width: 12px; height: 12px; }
.toolbar .clear-all, .filter-chips .clear-all { font-size: var(--text-sm); margin-left: var(--space-1); align-self: center; }
.saved-views { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1-5); margin: 0 0 var(--space-4); padding: 0; list-style: none; }
.saved-views .chip.is-current { border-color: var(--primary); color: var(--link); font-weight: 600; }

/* Recent on the Clients and Contacts pages: the clients or contacts someone opened lately, linked cards above the
   list. One row, as many as fit a name (six, four, three); two rows of two on a phone. The search box's Recent lists
   more clients. */
.recent-row { margin-bottom: var(--stack-gap); container: recent / inline-size; }
.recent-title { margin: 0 0 var(--space-2); font-size: var(--text-xs); font-weight: 600; letter-spacing: 0.05em; text-transform: uppercase; color: var(--muted); }
.recent-cards { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: var(--space-3); margin: 0; padding: 0; list-style: none; }
.recent-card { display: flex; flex-direction: column; gap: var(--space-0-5); height: 100%; margin: 0; padding: var(--space-2-5) var(--space-3); color: var(--text); }
a.recent-card:hover { text-decoration: none; border-color: var(--primary); }
.recent-name { overflow: hidden; font-weight: 600; text-overflow: ellipsis; white-space: nowrap; }
a.recent-card:hover .recent-name { color: var(--link); }
.recent-meta { color: var(--muted); font-size: var(--text-sm); }
.recent-due { white-space: nowrap; }
.recent-at { display: flex; min-width: 0; }  /* a contact's client, cut short, and how many others: "+2" */
.recent-client { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.recent-more { flex: none; margin-left: var(--space-1); }
@container recent (max-width: 1239px) {
  .recent-cards { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .recent-cards > li:nth-child(n+5) { display: none; }
}
@container recent (max-width: 759px) {
  .recent-cards { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .recent-cards > li:nth-child(n+4) { display: none; }
}
@container recent (max-width: 539px) {
  .recent-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-2); }
  .recent-cards > li:nth-child(4) { display: block; }
  .recent-dot { display: none; }
  .recent-due { display: block; }  /* its own line, not a dot left at the end of one */
}

/* Print: just the page content */
@media print {
  .topbar, .sidebar, .skip-link, .nav-backdrop, #messages, #timer-bar, #loading-bar, .bulk-bar, .toolbar, .filter-chips,
  .saved-views, .recent-row, .pagination, .page-header .actions, .tabs, .row-actions, .select-cell { display: none !important; }
  .layout { display: block; }
  .content, .content.is-form-page, .content.is-doc-page { max-width: none; padding: 0; }
  body { background: #fff; color: #000; font-size: 11pt; }
  .card { border: 0; box-shadow: none; padding: 0; break-inside: avoid; }
  .data-table thead th { position: static; }
  a { color: inherit; text-decoration: none; }
  .print-only { display: block !important; }
}
.print-only { display: none; }

/* Links that look like text, a label that isn't a <label> */
.plain-link { color: var(--text); }
.plain-link:hover { color: var(--link); }
.plain-link.overdue-text { color: var(--danger); }  /* late stays red (the Clients list's next deadline) */
.field-label { font-weight: 600; font-size: var(--text-sm); color: var(--text-2); }  /* a field's label where there is no <label> for it: the same words */
form.is-dirty .grid-dirty { display: inline; }  /* forms with data-unsaved-guard (static/js/app.js) */

/* --- Billing ------------------------------------------------------------------------------------ */
.billing-stats { margin-bottom: var(--stack-gap); }
.billing-stats .stat-value { font-size: var(--text-2xl); }  /* the same tile as the portal's (.attention-stat) */
.billing-notes {
  display: flex; flex-direction: column; gap: var(--space-1); list-style: none; margin: 0 0 var(--stack-gap); padding: var(--space-3) var(--space-5);
  border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); font-size: var(--text-base);
}
.billing-source { display: flex; align-items: center; gap: var(--space-2); margin: -8px 0 var(--space-4); color: var(--muted); font-size: var(--text-base); }
.billing-source .icon { width: 16px; height: 16px; }
h1 .badge { vertical-align: middle; font-size: var(--text-sm); }
.payment-row { display: flex; justify-content: space-between; align-items: center; gap: var(--space-3); }
/* Recurring invoices: the stopped ones in the list, a schedule's page, the {fields} under its form's fees */
.recurring-table tr.is-stopped td { color: var(--muted); }
.recurring-note { max-width: 420px; white-space: normal; }
.recurring-fields ul li { padding: 0; border: 0; }
.billing-subhead { margin-top: var(--space-4); }
.billing-subhead h3 { margin: 0; }
.recurring-page { max-width: var(--width-doc); }
.recurring-facts { display: grid; grid-template-columns: max-content 1fr; gap: var(--space-1) var(--space-4); margin: 0 0 var(--space-3); }
.recurring-facts dt { color: var(--muted); }
.recurring-facts dd { margin: 0; }
.recurring-lines { margin-bottom: var(--space-2-5); font-variant-numeric: tabular-nums; }
.recurring-lines tfoot th { text-align: right; }
.recurring-fields { margin: var(--space-1) 0 var(--space-4); }
.recurring-fields p { margin: 0 0 var(--space-1); }
.recurring-fields ul { display: flex; flex-wrap: wrap; gap: var(--space-0-5) var(--space-4); }
/* Online payments: the settings page's steps and Stripe's needs; payments made online on an invoice's page */
.payment-steps, .payment-needs { margin: 0 0 var(--space-3); padding-left: var(--space-5); }
.payment-steps li + li, .payment-needs li + li { margin-top: var(--space-1); }
.online-payment { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: var(--space-1) var(--space-3); }
.online-payment-note { flex-basis: 100%; }
.portal-pay { display: inline-flex; }
.portal-invoices .portal-pay { margin-left: var(--space-2); }
/* The overview's unpaid invoices: the balance and Pay online stay together, at the end of the row (on a phone too) */
.portal-invoice-list .portal-invoice-due { display: inline-flex; align-items: center; gap: var(--space-2); margin-left: auto; }
/* Who an invoice was emailed to, and how each went (invoice.html) */
.invoice-email { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: var(--space-1) var(--space-3); }
.invoice-email-note { flex-basis: 100%; }
.invoice-table td, .payment-table td { vertical-align: middle; }

/* Where an invoice stands (models.Invoice.state) */
.badge-inv-unpaid { background: var(--info-bg); color: var(--info-text); }
.badge-inv-partly_paid { background: var(--warning-bg); color: var(--warning-text); }
.badge-inv-overdue { background: var(--error-bg); color: var(--danger); }
.badge-inv-paid { background: var(--success-bg); color: var(--success-text); }
.badge-inv-void { text-decoration: line-through; }

/* Billed and received by month: two series in the reference palette's first two slots, checked with the
   dataviz palette validator against this app's light and dark card surfaces. */
.rev-card .is-billed { --series: var(--series-1); }
.rev-card .is-received { --series: var(--series-2); }
.rev-legend { display: flex; flex-wrap: wrap; gap: var(--space-1) var(--space-4); list-style: none; margin: 0; padding: 0; font-size: var(--text-base); }
.rev-legend li { display: inline-flex; align-items: center; gap: var(--space-1-5); }
.rev-key { width: 10px; height: 10px; border-radius: 2px; background: var(--series); }
.rev-plot { position: relative; height: 240px; margin-top: var(--space-4); }
.rev-grid { position: absolute; top: 0; right: 0; bottom: 26px; left: 52px; display: flex; flex-direction: column; justify-content: space-between; }
.rev-gridline { position: relative; border-top: 1px solid var(--chart-grid); }
.rev-gridline:last-child { border-top-color: var(--chart-base); }
.rev-tick {
  position: absolute; right: calc(100% + 8px); top: -0.55em; font-size: var(--text-xs); line-height: 1; color: var(--muted);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.rev-months {
  position: absolute; top: 0; right: 0; bottom: 0; left: 52px; display: grid; grid-template-columns: repeat(12, minmax(0, 1fr));
  list-style: none; margin: 0; padding: 0;
}
.rev-month { position: relative; display: grid; grid-template-rows: minmax(0, 1fr) 26px; border-radius: var(--radius-md); outline: none; cursor: default; }
.rev-bars { display: flex; align-items: flex-end; justify-content: center; gap: var(--space-0-5); min-height: 0; border-radius: var(--radius-md) var(--radius-md) 0 0; }
.rev-bar { width: min(18px, 36%); border-radius: var(--radius-sm) var(--radius-sm) 0 0; background: var(--series); }
.rev-month-label { align-self: center; text-align: center; font-size: var(--text-xs); color: var(--muted); }
/* A phone's twelve columns are narrower than a month's name: every other one is named (the bars, the label on a tap and the table give all twelve) */
@media (max-width: 560px) { .rev-months:has(> :nth-child(12)) .rev-month:nth-child(even) .rev-month-label { visibility: hidden; } }
.rev-month:hover .rev-bars, .rev-month:focus-visible .rev-bars { background: rgba(127, 137, 150, 0.12); }
.rev-month:focus-visible { box-shadow: inset 0 0 0 2px var(--primary); }
.rev-tip {
  position: absolute; top: -6px; left: 50%; z-index: 5; display: none; flex-direction: column; gap: 3px; min-width: 170px;
  padding: var(--space-2) var(--space-2-5); transform: translate(-50%, -100%); border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface); box-shadow: var(--shadow-md); font-size: var(--text-sm); white-space: nowrap; pointer-events: none;
}
.rev-month:hover .rev-tip, .rev-month:focus-visible .rev-tip { display: flex; }
.rev-month:nth-child(-n+2) .rev-tip { left: 0; transform: translate(0, -100%); }
.rev-month:nth-last-child(-n+2) .rev-tip { left: auto; right: 0; transform: translate(0, -100%); }
.rev-tip-title { font-weight: 600; color: var(--muted); }
.rev-tip strong { margin-right: var(--space-1); color: var(--text); font-variant-numeric: tabular-nums; }
.rev-line { display: inline-block; width: 12px; height: 2px; margin-right: var(--space-1-5); vertical-align: middle; background: var(--series); }
.rev-table { margin-top: var(--space-3); }
.rev-table summary { cursor: pointer; color: var(--link); font-size: var(--text-base); }
.rev-table table { margin-top: var(--space-2); }

/* An invoice as the client sees it (and prints) */
.invoice-doc { --doc-pad-y: var(--space-10); --doc-pad-x: 44px; max-width: var(--width-doc); padding: var(--doc-pad-y) var(--doc-pad-x); }  /* the page's margin: below */
.inv-head { display: flex; justify-content: space-between; gap: var(--space-6); flex-wrap: wrap; margin-bottom: var(--space-7); }
.inv-firm { font-size: var(--text-base); line-height: 1.45; color: var(--muted); }
.inv-logo { display: block; max-width: 180px; max-height: 70px; margin-bottom: var(--space-2-5); object-fit: contain; }
.inv-firm-name { font-size: var(--text-lg); font-weight: 700; color: var(--text); }
.inv-meta { margin-left: auto; text-align: right; }
.inv-title { margin-bottom: var(--space-2); font-size: 1.7rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; }
.inv-stamp {
  display: inline-block; margin-left: var(--space-2); padding: 1px var(--space-2); border: 2px solid var(--danger); border-radius: var(--radius-md);
  color: var(--danger); font-size: var(--text-base); letter-spacing: 0.08em; vertical-align: middle;
}
.inv-meta dl { display: grid; grid-template-columns: auto auto; justify-content: end; gap: var(--space-0-5) var(--space-3); margin: 0; font-size: var(--text-base); }
.inv-meta dt { color: var(--muted); }
.inv-meta dd { margin: 0; font-weight: 600; text-align: right; }
.inv-to { margin-bottom: var(--space-6); }
.inv-label { margin-bottom: var(--space-1); font-size: var(--text-xs); font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); }
.inv-client { font-weight: 700; }
.inv-lines { margin-bottom: var(--space-5); font-variant-numeric: tabular-nums; }
.inv-lines th, .inv-lines td { padding: var(--space-2) var(--space-2); }
.inv-lines thead th { border-bottom: 2px solid var(--text); color: var(--text); }
.inv-lines tfoot th, .inv-lines tfoot td { padding-top: var(--space-1); padding-bottom: var(--space-1); border-bottom: 0; }
.inv-lines tfoot th { text-align: right; text-transform: none; letter-spacing: 0; font-size: var(--text-md); font-weight: 500; color: var(--text); }
.inv-lines tfoot tr:first-child th, .inv-lines tfoot tr:first-child td { padding-top: var(--space-3); }
.inv-lines .inv-total th, .inv-lines .inv-total td { border-top: 1px solid var(--text); font-weight: 700; }
.inv-lines .inv-balance th, .inv-lines .inv-balance td { font-weight: 700; }
.inv-notes { margin-bottom: var(--space-4); }
.inv-footer { font-size: var(--text-sm); color: var(--muted); }  /* each footer; their rule is the footers' (.inv-footers) */
.inv-lines .inv-date, .inv-lines .inv-tax { white-space: nowrap; }
/* Who did the work (BillingSettings.show_people): initials beside each time line, then a summary by person. */
.inv-lines .inv-by { width: 1%; white-space: nowrap; }
.inv-people { max-width: 520px; margin-left: auto; }
.inv-people caption { padding-bottom: var(--space-1-5); text-align: left; font-size: var(--text-xs); font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); }
.inv-muted { color: var(--muted); }
/* The time detail page after an invoice (billing/_time_detail.html): on screen a sheet of its own under the invoice's,
   on paper a page of its own. A block per invoice line: its words, its entries, then its total. */
.invoice-doc.is-time-detail { margin-top: var(--space-4); }
.invoice-form-detail, .picker-detail { max-width: 28rem; }  /* the time detail page's choice: a short select, its note under it */
.inv-detail-head { margin-bottom: var(--space-6); }
.inv-detail-head .inv-title { margin: 0 0 var(--space-1); }
.inv-detail-of { margin: 0; font-size: var(--text-base); color: var(--muted); }
.inv-detail-lines .inv-detail-group th {
  padding-top: var(--space-5); border-bottom: 1px solid var(--border); font-size: var(--text-md); font-weight: 700;
  text-transform: none; letter-spacing: 0; color: var(--text); white-space: normal;
}
.inv-detail-lines tbody:first-of-type .inv-detail-group th { padding-top: var(--space-3); }
.inv-detail-lines .inv-detail-by { white-space: nowrap; }
.inv-detail-adjust td { color: var(--muted); }
.inv-detail-lines .inv-detail-sum th, .inv-detail-lines .inv-detail-sum td { border-bottom: 0; font-weight: 600; }
.inv-detail-lines .inv-detail-sum th { text-align: right; text-transform: none; letter-spacing: 0; font-size: var(--text-md); color: var(--text); }
.inv-detail-lines tfoot th { text-align: right; }
/* The firm's invoice colour (billing/documents.py, accent_sheet): its rules and title in every layout, its band in
   Modern. A tint of it behind the Modern headings, mixed into the card so it suits either theme. */
.inv-branded { --inv-soft: color-mix(in srgb, var(--inv-accent) 14%, var(--surface)); }
.inv-branded .inv-title { color: var(--inv-accent-text); }
.inv.inv-branded .inv-lines thead th { border-bottom-color: var(--inv-accent); }
.inv.inv-branded .inv-lines .inv-total th, .inv.inv-branded .inv-lines .inv-total td { border-top-color: var(--inv-accent); }
.inv-modern.inv-branded .inv-title { color: inherit; }
/* On the dark page the shade made for white would be too dark: the title is the page's ink, the labels a light tint. */
@media screen {
  [data-theme="dark"] .inv-branded:not(.inv-modern) .inv-title { color: var(--text); }
  [data-theme="dark"] .inv-modern.inv-branded .inv-label { color: color-mix(in srgb, var(--inv-accent) 55%, #fff); }
}
@media screen and (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .inv-branded:not(.inv-modern) .inv-title { color: var(--text); }
  :root:not([data-theme="light"]) .inv-modern.inv-branded .inv-label { color: color-mix(in srgb, var(--inv-accent) 55%, #fff); }
}

/* Billing reports (billing/reports.html): the filters in two rows, the table's totals ruled off */
.card.report-filters { display: grid; gap: var(--space-3); }  /* the billing reports' card of filters, in two rows (not Time's report, a filter bar) */
.report-filter-row { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--space-2-5) var(--space-4); }
.report-filter-row .field { margin: 0; min-width: 160px; }
.report-when { font-size: var(--text-md); font-weight: 500; }
.report-table { font-variant-numeric: tabular-nums; }
.report-table td.num, .report-table th.num { white-space: nowrap; }
.report-table tbody td:first-child { min-width: 12rem; }
.report-table td.num.muted { color: var(--muted); }

/* An invoice's page: its client's credit, to apply */
.credit-apply { margin: 0 0 var(--space-3); padding: var(--space-2-5) var(--space-3); border: 1px solid var(--info-border); border-radius: var(--radius); background: var(--info-bg); }
.credit-apply p { margin: 0 0 var(--space-1-5); }
.credit-apply-row { display: flex; gap: var(--space-2); align-items: center; }
.credit-apply-row input { width: 9rem; text-align: right; }

/* A client's statement of account (billing/_statement_doc.html): the period's figures in a row, then its lines */
.statement-period { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: var(--space-3) var(--space-5); max-width: var(--width-doc); }
.statement-dates { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--space-2-5); }
.statement-dates .field { margin: 0; }
.statement-summary { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0; margin: 0 0 var(--space-6); border: 1px solid var(--border); border-radius: var(--radius); }
.statement-summary > div { padding: var(--space-2-5) var(--space-4); border-left: 1px solid var(--border); }
.statement-summary > div:first-child { border-left: 0; }
.statement-summary dt { font-size: var(--text-xs); font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); }
.statement-summary dd { margin: var(--space-0-5) 0 0; font-size: var(--text-lg); font-weight: 600; font-variant-numeric: tabular-nums; }
.statement-summary .statement-due dd { font-weight: 800; }
.statement-lines .statement-opening td { color: var(--muted); }
.statement-lines td.num { white-space: nowrap; }
.statement-heading { margin: var(--space-2) 0 var(--space-1-5); font-size: var(--text-lg); }
.statement-aging th, .statement-aging td { white-space: nowrap; }
@media (max-width: 720px) {
  .statement-summary { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .statement-summary > div:nth-child(3) { border-left: 0; }
  .statement-summary > div:nth-child(n+3) { border-top: 1px solid var(--border); }
}

/* The invoice layouts (BillingSettings.layout). Classic is the rules above; the others change them. */
/* Service date: an itemized statement, each line on its date, the rows ruled and the totals boxed */
.inv-service_date .inv-lines tbody td { border-bottom: 1px solid var(--border); }
.inv-service_date .inv-lines thead th { background: var(--surface-2, #f2f4f7); border-bottom: 1px solid var(--text); }
.inv-service_date .inv-lines .inv-date { width: 1%; color: var(--text); font-weight: 600; }
.inv-service_date .inv-lines .inv-total th, .inv-service_date .inv-lines .inv-total td { border-top: 2px solid var(--text); font-size: var(--text-lg); }
/* Modern: the firm and the invoice's details on a coloured band, the lines striped, the total stands out */
.inv-modern .inv-head { margin: 0 0 var(--space-7); padding: var(--space-5) var(--space-6); border-radius: var(--radius); background: var(--inv-accent, var(--primary)); color: var(--inv-on-accent, var(--on-primary)); }
.inv-modern .inv-firm, .inv-modern .inv-firm-name, .inv-modern .inv-meta dt, .inv-modern .inv-meta dd { color: inherit; }
.inv-modern .inv-meta dt { opacity: 0.8; }
.inv-modern .inv-logo { padding: var(--space-1); border-radius: var(--radius-md); background: #fff; }
.inv-modern .inv-stamp { border-color: currentColor; color: inherit; }
.inv-modern .inv-label { color: var(--inv-accent-text, var(--primary)); }
.inv-modern .inv-lines thead th { border-bottom: 0; background: var(--inv-soft, var(--primary-soft)); text-transform: uppercase; letter-spacing: 0.04em; font-size: var(--text-xs); }
.inv-modern .inv-lines tbody tr:nth-child(even) td { background: var(--surface-2, #f8f9fb); }
.inv-modern .inv-lines .inv-total th, .inv-modern .inv-lines .inv-total td { border-top: 0; background: var(--inv-soft, var(--primary-soft)); font-size: var(--text-lg); }
/* Compact: smaller type and tighter rows, so a long invoice fits on a page */
.inv-compact { font-size: var(--text-sm); }
.inv-compact .inv-head { margin-bottom: var(--space-4); }
.inv-compact .inv-title { font-size: 1.3rem; }
.inv-compact .inv-to { margin-bottom: var(--space-3); }
.inv-compact .inv-lines th, .inv-compact .inv-lines td { padding: var(--space-1) var(--space-1-5); }
.inv-compact .inv-lines tfoot th { font-size: var(--text-sm); }

/* Letterhead: the firm across the top, its logo on the left and its name, address and contact on the right, over a
   rule; then the client on the left and the invoice's details on the right. A grid, so the same markup as the other
   layouts takes this shape: the head's two parts become cells of it, and everything after spans both columns. */
.inv-letterhead { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); column-gap: var(--space-8); }
.inv-letterhead > * { grid-column: 1 / -1; }
.inv-letterhead > .inv-head { display: contents; }
.inv-letterhead .inv-firm { grid-column: 1 / -1; grid-row: 1; display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-6);
  margin-bottom: var(--space-5); padding-bottom: var(--space-4); border-bottom: 2px solid var(--inv-accent, var(--text)); }
.inv-letterhead .inv-logo { margin-bottom: 0; }
.inv-letterhead .inv-firm-details { margin-left: auto; text-align: right; }
.inv-letterhead > .inv-to { grid-column: 1; grid-row: 2; }
.inv-letterhead .inv-meta { grid-column: 2; grid-row: 2; margin: 0 0 var(--space-6); }
.inv-letterhead .inv-title { font-size: 1.45rem; }

/* The header's options (billing/documents.py, look): the logo centred above the firm's details, or larger. */
.inv-logo-centre:not(.inv-letterhead) .inv-head { flex-direction: column; align-items: stretch; }
.inv-logo-centre .inv-firm { text-align: center; }
.inv-logo-centre .inv-logo { margin-left: auto; margin-right: auto; }
.inv-letterhead.inv-logo-centre .inv-firm { flex-direction: column; align-items: center; }
.inv-letterhead.inv-logo-centre .inv-firm-details { margin-left: 0; text-align: center; }
.inv-logo-large .inv-logo { max-width: 260px; max-height: 110px; }

/* Text size: small (but not as tight as Compact's rows) or large. */
.inv-size-small, .inv-size-small .inv-firm, .inv-size-small .inv-meta dl { font-size: 0.75rem; }
.inv-size-small .inv-firm-name { font-size: var(--text-base); }
.inv-size-small .inv-lines, .inv-size-small .inv-lines tfoot th { font-size: 0.75rem; }
.inv-size-small .inv-lines th, .inv-size-small .inv-lines td { padding-top: var(--space-2); padding-bottom: var(--space-2); }
.inv-size-small .inv-title { font-size: 1.45rem; }
.inv-size-large { font-size: 1.0625rem; }
.inv-size-large .inv-firm, .inv-size-large .inv-meta dl { font-size: var(--text-md); }
.inv-size-large .inv-firm-name { font-size: 1.2rem; }
.inv-size-large .inv-lines { font-size: 1.0625rem; }
.inv-size-large .inv-lines tfoot th { font-size: 1.0625rem; }
.inv-size-large .inv-label { font-size: var(--text-sm); }

/* The sections a firm adds to its invoices (BillingSettings.sections): its own words, how to pay, a line across.
   In the Letterhead layout the client sits beside the invoice's details only while it comes first. */
.inv-text, .inv-payment { margin-bottom: var(--space-5); }
.inv-divider { padding: var(--space-1) 0 var(--space-5); }
.inv-divider hr { margin: 0; border: 0; border-top: 1px solid var(--border); }
.inv-letterhead > .inv-to.is-apart { grid-column: 1 / -1; grid-row: auto; }

/* The page (_invoice_doc.html, and a credit note's and a statement's): its bands, the document, then the footers.
   Where the page has a height of its own (the designer's sheet, paper) the footers go to its foot. */
.inv-page { display: flex; flex-direction: column; }
.inv-page > .inv { flex: none; }
.inv-footers { display: grid; gap: var(--space-2) var(--space-6); margin-top: auto; padding-top: var(--space-3); border-top: 1px solid var(--border); }
.inv-footers.is-side_by_side { grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); }

/* The page's margin (BillingSettings.page_margin), narrower or wider than the usual: the document's padding, and on
   paper the page's own margins (a named page, below) */
.invoice-doc:has(> .inv-margin-narrow) { --doc-pad-y: var(--space-6); --doc-pad-x: var(--space-7); }
.invoice-doc:has(> .inv-margin-wide) { --doc-pad-y: var(--space-12); --doc-pad-x: calc(var(--space-12) + var(--space-4)); }

/* The bands (BillingSettings.band_top, band_bottom): the invoice colour across the page's top and bottom edges. The
   page's corners are square on a band's side: an edge in a colour never bends round a corner. */
.inv-band { flex: none; height: var(--space-1-5); background: var(--inv-accent, var(--primary)); print-color-adjust: exact; -webkit-print-color-adjust: exact; }
.inv-band.is-thick { height: var(--space-4); }
.inv-band.is-top { margin: calc(-1 * var(--doc-pad-y, 0px)) calc(-1 * var(--doc-pad-x, 0px)) max(var(--doc-pad-y, 0px), var(--space-6)); }
.inv-band.is-bottom { margin: max(var(--doc-pad-y, 0px), var(--space-6)) calc(-1 * var(--doc-pad-x, 0px)) calc(-1 * var(--doc-pad-y, 0px)); }
.invoice-doc:has(> .inv-page > .inv-band.is-top) { border-top-left-radius: 0; border-top-right-radius: 0; }
.invoice-doc:has(> .inv-page > .inv-band.is-bottom) { border-bottom-left-radius: 0; border-bottom-right-radius: 0; }

/* The logo on the right (BillingSettings.logo_position): the firm on the right, the invoice's details on the left;
   in the Letterhead layout the firm's details on the left, across from the logo */
.inv-logo-right:not(.inv-letterhead) .inv-head { flex-direction: row-reverse; }
.inv-logo-right:not(.inv-letterhead) .inv-firm { text-align: right; }
.inv-logo-right:not(.inv-letterhead) .inv-logo { margin-left: auto; }
.inv-logo-right:not(.inv-letterhead) .inv-meta { margin-left: 0; margin-right: auto; text-align: left; }
.inv-logo-right:not(.inv-letterhead) .inv-meta dl { justify-content: start; }
.inv-logo-right:not(.inv-letterhead) .inv-meta dd { text-align: left; }
.inv-letterhead.inv-logo-right .inv-firm { flex-direction: row-reverse; }
.inv-letterhead.inv-logo-right .inv-firm-details { margin-left: 0; margin-right: auto; text-align: left; }

/* Each part's own style (the designer's Style: billing/documents.py, STYLES): its space above and below, its
   padding, a box and that box's corners, and its alignment, each a step of the scale. After the layouts' rules and
   as strong, so a part's own style has the last word; the Modern layout's header keeps its band for a box. */
.inv-page .inv-box-tint { padding: var(--space-4) var(--space-5); border-radius: var(--radius-md); background: var(--inv-soft, var(--primary-soft)); }
.inv-page .inv-box-outline { padding: var(--space-4) var(--space-5); border: 1px solid var(--border); border-radius: var(--radius-md); }
.inv-page .inv-box-none { border: 0; background: none; }
.inv-modern .inv-head.inv-box-tint, .inv-modern .inv-head.inv-box-outline, .inv-modern .inv-head.inv-box-none { border: 0; background: var(--inv-accent, var(--primary)); }
.inv-page .inv-padding-none { padding: 0; }
.inv-page .inv-padding-s { padding: var(--space-2); }
.inv-page .inv-padding-m { padding: var(--space-4); }
.inv-page .inv-padding-l { padding: var(--space-6); }
.inv-page .inv-padding-xl { padding: var(--space-10); }
.inv-page .inv-corners-square { border-radius: 0; }
.inv-page .inv-corners-small { border-radius: var(--radius-sm); }
.inv-page .inv-corners-round { border-radius: var(--radius); }
.inv-page .inv-above-none { margin-top: 0; }
.inv-page .inv-above-s { margin-top: var(--space-2); }
.inv-page .inv-above-m { margin-top: var(--space-4); }
.inv-page .inv-above-l { margin-top: var(--space-6); }
.inv-page .inv-above-xl { margin-top: var(--space-10); }
.inv-page .inv-below-none { margin-bottom: 0; }
.inv-page .inv-below-s { margin-bottom: var(--space-2); }
.inv-page .inv-below-m { margin-bottom: var(--space-4); }
.inv-page .inv-below-l { margin-bottom: var(--space-6); }
.inv-page .inv-below-xl { margin-bottom: var(--space-10); }
.inv-page .inv-align-left { text-align: left; }
.inv-page .inv-align-centre { text-align: center; }
.inv-page .inv-align-right { text-align: right; }
.inv-page .inv-meta.inv-align-left dl { justify-content: start; }
.inv-page .inv-meta.inv-align-centre dl { justify-content: center; }
.inv-page .inv-meta.inv-align-right dl { justify-content: end; }
.inv-page .inv-meta.inv-align-left dd, .inv-page .inv-meta.inv-align-centre dd { text-align: left; }
.inv-page .inv-meta.inv-align-right dd { text-align: right; }
.inv-fees > :last-child { margin-bottom: 0; }  /* the fees' own space below is the section's */
.inv-fees { margin-bottom: var(--space-5); }

/* Invoice settings: how the invoices look, in a line, and the way to the designer */
.design-card { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-3) var(--space-4); }
.design-card-text { flex: 1 1 280px; min-width: 0; }
.design-card .card-heading { margin-bottom: var(--space-1); }
.design-card p { margin: 0; }

/* The invoice designer (billing/design.html): a bar, then three panes with the invoice in the middle, drawn at its
   true size and shrunk to fit (static/js/invoice-designer.js). The page fills the screen and each pane scrolls on
   its own. Under 1200px the two side panes share a column behind tabs; under 900 it all stacks and the page scrolls. */
.content.is-designer-page { display: flex; flex-direction: column; height: 100dvh; padding: var(--space-4) var(--space-5); }
.form.designer { flex: 1; min-height: 0; max-width: none; display: flex; flex-direction: column; gap: var(--space-3); }  /* the page's width, not a form's */
.designer:not(.is-live) [data-designer-live], .designer:not(.is-live) .designer-start { display: none !important; }
.designer [hidden], .designer-menu[hidden] { display: none !important; }  /* badges, buttons and panels have a display of their own */
.designer-bar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-4); }
.designer-heading { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-3); min-width: 0; }
.designer-heading h1 { margin: 0; font-size: var(--text-xl); }
.designer-back { display: inline-flex; align-items: center; gap: var(--space-1); color: var(--muted); font-size: var(--text-sm); }
.designer-back .icon { width: 16px; height: 16px; }
.designer-tools { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); }
.designer-select { display: inline-flex; align-items: center; gap: var(--space-1-5); color: var(--muted); font-size: var(--text-sm); }
.designer-select select { max-width: 12rem; }
.designer-actions { display: flex; align-items: center; gap: var(--space-2); margin-left: auto; }
.designer-errors { margin: 0; }
.designer-errors p, .designer-errors ul { margin: 0; }
.designer-errors ul { padding-left: var(--space-5); }

.designer-work {
  flex: 1; min-height: 0; display: grid; gap: var(--space-3);
  grid-template-columns: 272px minmax(0, 1fr) 320px; grid-template-areas: "design desk inspect";
}
.designer-tabs { display: none; }
.designer-pane { min-width: 0; min-height: 0; overflow: auto; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); }
.designer-design { grid-area: design; }
.designer-inspector { grid-area: inspect; }
.designer.is-previewing .designer-work { grid-template-columns: minmax(0, 1fr); grid-template-areas: "desk"; }
.designer.is-previewing .designer-pane, .designer.is-previewing .designer-tabs { display: none; }

/* The desk: the invoice on its sheet, a Letter page wide (or a phone's), and the marks over it */
.designer-stage { grid-area: desk; min-width: 0; min-height: 0; display: flex; flex-direction: column; gap: var(--space-2); }
.designer-desk {
  flex: 1; min-width: 0; min-height: 0; overflow: auto; display: flex; flex-direction: column; align-items: center;
  gap: var(--space-3); padding: var(--space-5); border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface-3);
}
.designer-fit { position: relative; flex: none; width: 100%; max-width: var(--width-doc); }
.designer-sheet { container: invoice-sheet / inline-size; }
.designer.is-live .designer-sheet { position: absolute; top: 0; left: 0; width: var(--width-doc); transform-origin: 0 0; }
.designer.is-live .designer-sheet.is-phone { width: 390px; }
.designer-sheet .invoice-doc { max-width: none; margin: 0; }
.designer.is-live .designer-sheet:not(.is-phone) .invoice-doc { display: flex; flex-direction: column; min-height: 1061px; }  /* 8.5 × 11 in at the sheet's width */
.designer-sheet .invoice-doc > .inv-page { flex: 1 0 auto; }  /* the footers at the sheet's foot, as on paper */
.designer-note { max-width: var(--width-doc); margin: 0; color: var(--muted); font-size: var(--text-sm); text-align: center; }
.designer-sheet .invoice-doc.is-time-detail { margin-top: var(--space-6); }  /* the time detail page: the next sheet */
.designer-sheet-note { margin: var(--space-5) auto 0; }

.designer-overlay { position: absolute; inset: 0; z-index: 2; pointer-events: none; }
.designer-box { position: absolute; display: none; }
.designer-box.is-hover { border: 1px dashed var(--primary); }
.designer-box.is-selected { border: 2px solid var(--primary); }
.designer-tag, .designer-tools-bar {
  position: absolute; bottom: 100%; display: flex; align-items: center; height: 24px;
  border-radius: var(--radius-sm) var(--radius-sm) 0 0; background: var(--primary); color: var(--on-primary);
}
.designer-tag { left: -2px; padding: 0 var(--space-2); font-size: var(--text-xs); font-weight: 600; white-space: nowrap; }
.designer-box.is-hover .designer-tag { left: -1px; }
.designer-tools-bar { right: -2px; padding: 0 var(--space-0-5); pointer-events: auto; }
.designer-tools-bar:empty { display: none; }
.designer-tools-bar button {
  display: grid; place-items: center; width: 26px; height: 24px; padding: 0; border: 0; border-radius: var(--radius-sm);
  background: none; color: inherit; cursor: pointer;
}
.designer-tools-bar button:hover { background: rgba(255, 255, 255, 0.18); }  /* on the primary blue, in either theme */
.designer-tools-bar button:focus-visible { outline: 2px solid var(--on-primary); outline-offset: -2px; }
.designer-tools-bar button:disabled { opacity: 0.45; cursor: default; }
.designer-tools-bar .icon { width: 14px; height: 14px; }
.designer-tools-bar [data-act="drag"] { cursor: grab; touch-action: none; }
.designer-box.is-inside .designer-tag, .designer-box.is-inside .designer-tools-bar { bottom: auto; top: 0; }
.designer-box.is-inside .designer-tag { left: 0; border-radius: 0 0 var(--radius-sm) 0; }
.designer-box.is-inside .designer-tools-bar { right: 0; border-radius: 0 0 0 var(--radius-sm); }
.designer-drop { position: absolute; display: none; height: 3px; margin-top: -1px; border-radius: 2px; background: var(--primary); pointer-events: none; }
.is-dragging, .is-dragging * { cursor: grabbing !important; user-select: none !important; }

/* On the invoice, while editing: each part answers a click, each word can be typed over */
.designer.is-editing [data-part] { cursor: pointer; }
.designer.is-editing [data-words] { cursor: text; }
.designer.is-editing [data-words]:hover { text-decoration: underline dotted; text-underline-offset: 3px; }
.designer.is-editing [data-words]:focus { outline: 2px dashed currentColor; outline-offset: 3px; text-decoration: none; }
.designer.is-editing [data-placeholder]:empty::before { content: attr(data-placeholder); color: var(--muted); font-style: italic; }

/* The side panes */
.designer-group { display: grid; gap: var(--space-3); padding: var(--space-4); border-bottom: 1px solid var(--border); }
.designer-group:last-child { border-bottom: 0; }
.designer-group h2, .designer-group h3 { margin: 0; font-size: var(--text-xs); font-weight: 600; letter-spacing: 0.05em; text-transform: uppercase; color: var(--muted); }
.designer-group .field { margin: 0; }
.designer-group > .toggle-row { padding: 0; }
.designer-group > .toggle-row + .toggle-row { padding-top: var(--space-3); }
.designer-hint { margin: calc(-1 * var(--space-1)) 0 0; color: var(--muted); font-size: var(--text-sm); }
.designer-group-link { padding: 0; border: 0; background: none; color: inherit; font: inherit; letter-spacing: inherit; text-transform: inherit; cursor: pointer; }  /* a group's heading that selects its part */
.designer-group-link:hover { color: var(--text); }
.designer-full { display: flex; }
.designer-full > label { flex: 1; justify-content: center; }
.designer-detail > label { flex: 1 1 auto; padding-inline: var(--space-2); white-space: normal; text-align: center; line-height: 1.25; }  /* each as wide as its words: Hours and amounts on one line, or two in a narrow pane */
.designer-detail + .designer-hint { margin-top: var(--space-2); }

.designer-layouts { display: grid; gap: var(--space-2); }
.designer-layout {
  position: relative; display: grid; grid-template-columns: 58px minmax(0, 1fr); align-items: center; gap: var(--space-2-5);
  padding: var(--space-1-5) var(--space-2-5) var(--space-1-5) var(--space-1-5); border: 1px solid var(--border);
  border-radius: var(--radius-md); cursor: pointer;
}
.designer-layout:hover { border-color: var(--border-strong); }
.designer-layout:has(input:checked) { border-color: var(--primary); box-shadow: 0 0 0 1px var(--primary); }
.designer-layout:has(input:focus-visible) { outline: 2px solid var(--primary); outline-offset: 2px; }
.designer-layout input { position: absolute; inset: 0; margin: 0; opacity: 0; pointer-events: none; }
.designer-thumb { position: relative; width: 58px; height: 75px; overflow: hidden; border-radius: var(--radius-sm); background: var(--surface); box-shadow: 0 0 0 1px var(--border-strong); }
.designer-thumb-page { position: absolute; top: 0; left: 0; width: var(--width-doc); padding: var(--space-10) 44px; transform: scale(0.0707); transform-origin: 0 0; pointer-events: none; }
.designer-layout-name { display: block; font-size: var(--text-sm); font-weight: 600; }
.designer-layout-note { display: block; color: var(--muted); font-size: var(--text-xs); line-height: 1.4; }

.designer-swatches { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: var(--space-1-5); }  /* the default and six */
.designer-swatch { aspect-ratio: 1; max-width: 100%; padding: 0; border: 1px solid var(--border-strong); border-radius: var(--radius-md); background: var(--primary); cursor: pointer; }
.designer-swatch[aria-pressed="true"] { box-shadow: 0 0 0 2px var(--surface), 0 0 0 4px var(--primary); }

.designer-sections { position: relative; display: grid; gap: var(--space-1); margin: 0; padding: 0; list-style: none; }
.designer-section {
  display: flex; align-items: center; gap: var(--space-1-5); min-height: var(--control-height); padding: 0 var(--space-2) 0 var(--space-1);
  border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--surface);
}
.designer-section.is-selected { border-color: var(--primary); background: var(--primary-soft); }
.designer-section-grip, .designer-section-lock { display: grid; place-items: center; flex: none; width: 24px; height: 28px; color: var(--muted); }
.designer-section-grip { padding: 0; border: 0; border-radius: var(--radius-sm); background: none; cursor: grab; touch-action: none; }
.designer-section-grip:hover { background: var(--surface-3); color: var(--text); }
.designer-section-grip .icon, .designer-section-lock .icon { width: 14px; height: 14px; }
.designer-section-name {
  flex: 0 1 auto; min-width: 0; padding: var(--space-1-5) 0; border: 0; background: none; color: var(--text); font: inherit;
  font-size: var(--text-sm); font-weight: 500; text-align: left; overflow-wrap: anywhere;
}
button.designer-section-name { cursor: pointer; }
.designer-section-note { flex: 1 1 0; min-width: 0; overflow: hidden; color: var(--muted); font-size: var(--text-xs); text-overflow: ellipsis; white-space: nowrap; }  /* its first words, to tell two apart */
.designer-sections .designer-drop { left: 0; right: 0; }

.designer-menu.menu-panel { position: fixed; right: auto; width: 288px; max-width: calc(100vw - 32px); }
.designer-menu .menu-item { align-items: flex-start; white-space: normal; }
.designer-menu .menu-item .icon { margin-top: var(--space-0-5); }
.designer-menu .menu-item > span { display: grid; gap: 1px; }
.designer-menu .menu-item strong { font-weight: 600; }
.designer-menu .menu-item > span > span { color: var(--muted); font-size: var(--text-xs); }

.designer.is-live .designer-panel:not(.is-current) { display: none; }
.designer-panel-head { padding: var(--space-4) var(--space-4) var(--space-3); border-bottom: 1px solid var(--border); }
.designer-panel-head h2 { margin: 0; font-size: var(--text-lg); }
.designer-panel-head p { margin: var(--space-1) 0 0; color: var(--muted); font-size: var(--text-sm); }
.designer-start { display: grid; justify-items: start; gap: var(--space-2); padding: var(--space-5) var(--space-4); }
.designer-start h2 { margin: var(--space-1) 0 0; font-size: var(--text-lg); }
.designer-start p { margin: 0; color: var(--muted); }
.designer-parts { width: 100%; margin: var(--space-2) 0 0; padding: 0; list-style: none; }
.designer-section-actions .btn-row { display: flex; flex-wrap: wrap; gap: var(--space-2); }

/* A phone's width, on the designer's sheet: the invoice's own rules under 720px, as a phone shows them */
@container invoice-sheet (max-width: 720px) {
  .invoice-doc, .invoice-doc:has(> .inv-page) { --doc-pad-y: var(--space-5); --doc-pad-x: var(--space-5); }
  .inv-footers.is-side_by_side { grid-auto-flow: row; }
  .inv-meta { margin-left: 0; text-align: left; }
  .inv-letterhead { grid-template-columns: minmax(0, 1fr); }
  .inv-letterhead .inv-meta { grid-column: 1; grid-row: 3; }
  .inv-letterhead:has(> .inv-to.is-apart) .inv-meta { grid-row: 2; }
  .inv-meta dl { justify-content: start; }
  .inv-meta dd { text-align: left; }
  .inv-lines { font-size: var(--text-sm); }
  .inv-lines th, .inv-lines td { padding-left: var(--space-1-5); padding-right: var(--space-1-5); }
  .inv-lines thead th, .inv-lines tfoot th { white-space: normal; }
  .inv-lines .num { white-space: nowrap; }
  .inv-lines .hide-sm { display: none; }
  .inv-lines .show-sm { display: block; font-size: var(--text-xs); }
  .inv-lines .hide-sm:first-child + * { padding-left: 0; }
}

@media (max-width: 1199px) {
  .designer.is-live .designer-work {
    grid-template-columns: minmax(0, 1fr) 320px; grid-template-rows: auto minmax(0, 1fr);
    grid-template-areas: "desk tabs" "desk side";
  }
  .designer.is-live .designer-tabs { display: flex; grid-area: tabs; }
  .designer-tabs > label { flex: 1; justify-content: center; }
  .designer.is-live .designer-design, .designer.is-live .designer-inspector { grid-area: side; }
  .designer[data-panel="design"] .designer-inspector, .designer[data-panel="selected"] .designer-design { display: none; }
  .designer:not(.is-live) .designer-work { display: block; }
}
@media (max-width: 899px) {
  .content.is-designer-page { height: auto; padding: var(--space-4); }
  .designer.is-live .designer-work { grid-template-columns: minmax(0, 1fr); grid-template-rows: none; grid-template-areas: "desk" "tabs" "side"; }
  .designer-desk, .designer-pane { overflow: visible; }
  .designer-desk { padding: var(--space-3); }
}
.invoice-extras { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 0 var(--space-5); max-width: var(--width-doc); }
@media (max-width: 899px) { .invoice-extras { grid-template-columns: minmax(0, 1fr); } }
@media (max-width: 720px) {
  .invoice-doc, .invoice-doc:has(> .inv-page) { --doc-pad-y: var(--space-5); --doc-pad-x: var(--space-5); }  /* as the cards under it */
  .inv-footers.is-side_by_side { grid-auto-flow: row; }
  .inv-meta { margin-left: 0; text-align: left; }
  .inv-letterhead { grid-template-columns: minmax(0, 1fr); }
  .inv-letterhead .inv-meta { grid-column: 1; grid-row: 3; }
  .inv-letterhead:has(> .inv-to.is-apart) .inv-meta { grid-row: 2; }  /* the client moved down: the details follow the firm */
  .inv-meta dl { justify-content: start; }
  .inv-meta dd { text-align: left; }
}

/* The invoice form: its fees as rows, totalled as they're typed (static/js/app.js) */
.invoice-form { max-width: 1180px; }
.invoice-form-heading { margin: var(--space-2) 0 var(--space-1-5); font-size: var(--text-lg); }
.invoice-lines { min-width: 860px; }
.invoice-lines th, .invoice-lines td { padding: var(--space-1-5); border-bottom: 0; }
/* A long column name wraps, and each field fills its column, so a name and its field share both edges. The fields
   are at least as wide as these. */
.invoice-lines th { white-space: normal; vertical-align: bottom; }
.invoice-lines td > input, .invoice-lines td > select { width: 100%; }
.invoice-lines td:not(.invoice-line-description) { width: 1%; }  /* the room to spare goes to the description */
.invoice-line-description input { min-width: 9.5rem; }
.invoice-line-date input { min-width: 8.5rem; }
.invoice-line-service select { min-width: 8rem; }
.invoice-lines input[type="number"] { min-width: 5.5rem; text-align: right; -moz-appearance: textfield; appearance: textfield; }
.invoice-lines input[type="number"]::-webkit-inner-spin-button { display: none; }  /* an amount is typed, not stepped: its digits get the room */
.invoice-line-tax select { min-width: 7.5rem; }
/* Hours times the rate makes the amount (static/js/app.js): it reads as worked out, not as a field to type in */
.invoice-lines input[readonly] { border-style: dashed; background: transparent; color: var(--text); }
.invoice-line.has-error input { border-color: var(--danger); }
.invoice-lines .errorlist { margin: var(--space-0-5) 0 0; font-size: var(--text-sm); }
.invoice-line-until { display: flex; align-items: center; gap: var(--space-1-5); margin-top: var(--space-1-5); }  /* a recurring line's discount: "until [date]" under its percent */
.invoice-line-until input { flex: 1 1 auto; min-width: 8.5rem; }
/* Under the lines, outside their scrolling box so they're always in sight: Add lines on the left, the totals on the
   right at the card's edge (the total row is every table's, see tfoot). */
.invoice-lines-foot { display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: var(--space-3) var(--space-6); margin: var(--space-2) 0 var(--space-4); }
.invoice-line-buttons { display: flex; flex-wrap: wrap; gap: var(--space-1-5); }
.invoice-totals { width: auto; margin-left: auto; font-variant-numeric: tabular-nums; }
.invoice-totals th, .invoice-totals td { padding: var(--space-1) 0 var(--space-1) var(--space-6); border-bottom: 0; text-align: right; vertical-align: baseline; }
.invoice-totals tbody th { font-size: inherit; font-weight: 400; text-transform: none; letter-spacing: 0; color: var(--muted); }
.invoice-totals td { min-width: 7rem; white-space: nowrap; }
.invoice-discount-inputs { display: inline-flex; align-items: center; gap: var(--space-1-5); }
.invoice-discount-inputs input { width: 6rem; text-align: right; }
.invoice-discount-inputs select { width: 4.5rem; }
@media (max-width: 720px) {  /* a phone: each line is a stack of labelled fields, two to a row, as a narrow checklist's */
  .invoice-lines { min-width: 0; }
  .invoice-lines thead { display: none; }
  .invoice-lines, .invoice-lines tbody { display: block; }
  .invoice-lines tr.invoice-line { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); grid-auto-flow: row dense; gap: var(--space-2) var(--space-3); padding: var(--space-3) 0; border-bottom: 1px solid var(--border); }
  .invoice-lines tr.invoice-line > td { display: block; width: auto; padding: 0; text-align: left; }
  .invoice-lines .invoice-line-description, .invoice-lines .invoice-line-discount, .invoice-lines .letter-fee-terms { grid-column: 1 / -1; min-width: 0; }
  .invoice-lines td[data-label]::before { content: attr(data-label); display: block; margin-bottom: var(--space-0-5); font-size: var(--text-sm); font-weight: 600; color: var(--muted); }
  .invoice-lines input, .invoice-lines select { width: 100%; min-width: 0; max-width: none; }
  .invoice-totals { width: 100%; }
  .invoice-totals th, .invoice-totals td { padding-left: var(--space-3); }
  .invoice-totals td { min-width: 0; }
  .invoice-discount-inputs input { width: 4.5rem; }
}

@media print {
  .invoice-page-header, .invoice-extras, .billing-source { display: none !important; }
  .invoice-doc { max-width: none; margin: 0; padding: 0; border: 0; background: #fff; }
  .invoice-doc, .invoice-doc:has(> .inv-page) { --doc-pad-y: 0px; --doc-pad-x: 0px; }  /* the paper's margins instead */
  .inv-margin-narrow { page: invoice-narrow; }
  .inv-margin-wide { page: invoice-wide; }
  .invoice-doc > .inv-page { min-height: 100vh; }  /* a page tall: the footers at its foot (a longer invoice's, after the fees on its last page) */
  .invoice-doc.is-time-detail { margin-top: 0; break-before: page; }  /* the time detail: a page of its own */
  .inv-lines .show-sm { display: none; }  /* the date has its column on paper */
  .invoice-doc, .invoice-doc th, .invoice-doc td, .invoice-doc dt, .invoice-doc .inv-firm, .invoice-doc .inv-label, .invoice-doc .inv-footer { color: #000; }
  /* The modern layout's band and shading print as they show */
  .inv-modern { print-color-adjust: exact; -webkit-print-color-adjust: exact; }
  .inv-modern .inv-head, .inv-modern .inv-head * { color: var(--inv-on-accent, #fff); }
}

/* Billing overview: last year's figure under the Billed and Received cards, the two breakdown cards side
   by side, the row for the chosen client type; the invoice form's service column. */
.stat-change { color: var(--muted); font-size: var(--text-sm); margin-top: var(--space-0-5); }
.stat-delta.is-up { color: var(--success-text); font-weight: 600; }
.stat-delta.is-down { color: var(--danger); font-weight: 600; }
.report-pair { display: grid; grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); gap: var(--stack-gap); margin-bottom: var(--stack-gap); }
.report-pair > .card { margin-bottom: 0; }
.report-pair .report-table th[scope="row"] { white-space: normal; }  /* a long name takes a second line, so the money columns stay inside the half-width card */
.report-table tr.is-selected th, .report-table tr.is-selected td { background: var(--bg); }
.overview-pagination { padding: var(--space-2) var(--space-5) var(--space-4); }
.overview-filters { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-4); }  /* Year, then Client type */

/* Time on invoices: the picker (billing/_time_picker_form.html, wider than other dialogs), an invoice's own time, and
   the invoice form's note under a line made from time */
.modal:has(.time-picker) { width: min(1000px, calc(100vw - 32px)); }
.time-picker-page { max-width: 1000px; }
.form.time-picker { max-width: none; }
/* The dates and the filters are one set of columns (Find takes two), so each field sits under the one above */
.picker-dates, .picker-filters { display: grid; grid-template-columns: repeat(auto-fill, minmax(8.5rem, 1fr)); align-items: end; gap: var(--space-2) var(--space-3); }
.picker-dates { margin-bottom: var(--space-3); }
.picker-dates .field { margin: 0; }
.picker-dates .field:first-child { grid-column: span 2; }  /* over Find, so Include time up to is over From */
.picker-filters { margin-bottom: var(--space-3); }
.picker-filter { display: flex; flex-direction: column; gap: var(--space-1-5); min-width: 0; }
.picker-filter label { font-size: var(--text-sm); font-weight: 600; }
.picker-filter input, .picker-filter select { width: 100%; min-width: 0; }
.picker-filter-q { grid-column: span 2; }
.picker-tools { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin-bottom: var(--space-2); }
.picker-tools[hidden] { display: none; }
/* The rows sit bare in the card, as an invoice's own time does; the words at the card's edge, a ticked row's tint
   reaching past them into its padding. In a dialog they scroll under their sticky column names. */
.picker-rows { max-height: min(48vh, 460px); overflow: auto; margin: 0 calc(-1 * var(--cell-pad-x)); }
.time-picker-page .picker-rows { max-height: none; }
.picker-table thead th { position: sticky; top: 0; z-index: 1; background: var(--surface); }
.picker-table tbody tr:last-child td { border-bottom: 0; }
.picker-table .picker-tick { width: 1%; padding-right: var(--space-0-5); }
.picker-table label { cursor: pointer; font-weight: 400; }
.picker-table tr:has(input:checked) td { background: var(--primary-soft); }
.picker-work { min-width: 220px; overflow-wrap: anywhere; }
.picker-work .small, .invoice-time-work { display: block; }
.picker-who { white-space: nowrap; }
.picker-total { margin: var(--space-2-5) 0 var(--space-3); }
.invoice-extras .invoice-time { grid-column: 1 / -1; }
.invoice-time-table td { vertical-align: middle; }
.invoice-line-time { display: block; margin-top: var(--space-0-5); }
.picker-who-inline { display: none; }
@media (max-width: 560px) {  /* the person goes under the work, so the hours and value fit beside it */
  .picker-rows { max-height: 44vh; margin: 0 calc(-1 * var(--space-1-5)); }
  .picker-table th, .picker-table td { padding: var(--space-1-5); }
  .picker-table .picker-who { display: none; }
  .picker-who-inline { display: inline; }
  .picker-work { min-width: 80px; }
  .modal:has(.time-picker) .modal-card { padding-left: var(--space-4); padding-right: var(--space-4); }
}

/* --- Client portal: the firm's pages ------------------------------------------------------------- */
/* The sidebar's count of documents that need the firm (new from clients, changes asked for) */
.nav-badge {
  margin-left: auto; min-width: 1.6em; padding: 0 var(--space-1-5); border-radius: var(--radius-full); background: var(--primary); color: var(--on-primary);
  font-size: var(--text-xs); font-weight: 700; line-height: 1.6; text-align: center;
}
/* Folded (900px and wider): the count sits on the icon's corner, small. */
@media (min-width: 900px) {
  .sidebar-hidden .nav a { position: relative; }
  .sidebar-hidden .nav-badge { position: absolute; top: 1px; right: 6px; min-width: 16px; height: 16px; padding: 0 var(--space-1); font-size: 0.625rem; line-height: 16px; }
}

/* What needs attention: counts that filter the list */
.attention-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: var(--stack-gap); margin-bottom: var(--stack-gap); }  /* six fit a laptop's width in one row */
.attention-stat { margin-bottom: 0; }  /* a card like Billing's stats; the number carries the state's colour, not an edge */
.attention-stat .stat-value { font-size: var(--text-2xl); line-height: 1.2; }
.attention-stat .stat-label { font-size: var(--text-base); }
.attention-stat:is(.is-new, .is-todo-new, .is-todo-review, .is-reminder-soon):not(.is-zero) .stat-value { color: var(--link); }
.attention-stat:is(.is-changes, .is-todo-overdue):not(.is-zero) .stat-value { color: var(--danger); }
.attention-stat:is(.is-waiting, .is-todo-waiting, .is-reminder-amount):not(.is-zero) .stat-value { color: var(--warning-text); }
.attention-stat.is-to_sign:not(.is-zero) .stat-value { color: var(--purple-text); }
.attention-stat.is-zero .stat-value { color: var(--muted); }
.attention-stat.is-selected { border-color: var(--primary); box-shadow: inset 0 0 0 1px var(--primary); }
.attention-chips { display: flex; flex-wrap: wrap; gap: var(--space-1-5); list-style: none; margin: 0 0 var(--space-4); padding: 0; }
.chip {
  display: inline-flex; align-items: center; gap: var(--space-1); padding: 3px var(--space-3); border: 1px solid var(--border); border-radius: var(--radius-full);
  background: var(--surface); color: var(--text); font-size: var(--text-base);
}
.chip:hover { text-decoration: none; border-color: var(--muted); }
.chip.is-waiting { border-color: var(--warning-border); color: var(--warning-text); }
.chip.is-changes { border-color: var(--danger); color: var(--danger); }
.chip.is-new { border-color: var(--primary); color: var(--link); }

/* Where a document stands */
.badge.badge-new, .badge.badge-portal, .badge.badge-progress { background: var(--info-bg); color: var(--info-text); }
.badge.badge-waiting { background: var(--warning-bg); color: var(--warning-text); }
.badge.badge-you { background: none; box-shadow: inset 0 0 0 1px var(--border); color: var(--text); }
.badge.badge-past-due { background: var(--error-bg); color: var(--danger); }
.badge.badge-approved { background: var(--success-bg); color: var(--success-text); }
.badge.badge-changes { background: var(--error-bg); color: var(--danger); }
.badge.badge-invited { background: var(--purple-bg); color: var(--purple-text); }
.badge .icon { width: 12px; height: 12px; margin-right: 3px; vertical-align: -1px; }
.vis { display: inline-flex; align-items: center; gap: var(--space-1); font-size: var(--text-base); font-weight: 600; white-space: nowrap; }
.vis .icon { width: 15px; height: 15px; }
.vis-shared { color: var(--success-text); }
.vis-firm { color: var(--muted); }
.vis-client { color: var(--link); }
.vis-date { display: block; }

/* A file: its type as a coloured label, then its name */
.file-badge {
  display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; min-width: 38px; height: 22px;
  padding: 0 var(--space-1); border-radius: var(--radius-sm); background: #667085; color: #fff; font-size: 0.66rem; font-weight: 800;
  letter-spacing: 0.04em; line-height: 1;
}
.file-badge.file-pdf { background: #c8372d; }
.file-badge.file-sheet { background: #1e7e45; }
.file-badge.file-doc { background: #2b579a; }
.file-badge.file-image { background: #7c4ddb; }
.file-badge.file-mail { background: #a35f00; }

/* The firm's list of documents; narrow, each document becomes a small card */
.doc-list-box { container: doc-list / inline-size; }
.select-hit { display: flex; align-items: center; justify-content: center; cursor: pointer; }  /* inline, it sat on the baseline */
.doc-table td { vertical-align: middle; }
.doc-table .badge { white-space: nowrap; }
.doc-main { min-width: 240px; }
.doc-title-line { display: inline-flex; align-items: center; gap: var(--space-2); max-width: 100%; }
.doc-title { font-weight: 600; color: var(--text); overflow-wrap: anywhere; }
.doc-title:hover { color: var(--link); }
.doc-meta { margin-top: 3px; }
.doc-note, .doc-opened { display: flex; align-items: flex-start; gap: var(--space-1-5); margin-top: var(--space-1); }
.doc-note .icon, .doc-opened .icon { width: 14px; height: 14px; margin-top: var(--space-0-5); flex-shrink: 0; color: var(--muted); }
.doc-note { color: var(--text); }
.doc-actions { text-align: right; white-space: nowrap; }
.doc-actions .btn-slot { visibility: hidden; }  /* a missing button keeps its place: the ones before it stand where they do on the rows that have it */
/* Nothing on the page can be ticked (only the client's own documents): no column of boxes, and no box to tick them all */
.doc-table:not(:has(> tbody .select-cell input)) .select-cell { display: none; }
.btn-share { border-color: var(--success-text); color: var(--success-text); }
.btn-share:hover { border-color: var(--success-text); background: var(--success-bg); }
.doc-row.is-new td:first-child { box-shadow: inset 3px 0 0 var(--primary); }
/* In a card that pads itself a row starts at the padding, with no room of its own: the edge stands in the padding, off
   the tick box and the words, as .review-item.is-new's does */
:where(.card:not(.table-wrap) > .doc-list-box .doc-row.is-new) > td:first-child { position: relative; }
.card:not(.table-wrap) > .doc-list-box .doc-row.is-new > td:first-child { box-shadow: none; }
.card:not(.table-wrap) > .doc-list-box .doc-row.is-new > td:first-child::before { content: ""; position: absolute; left: -10px; top: 0; bottom: 0; width: 3px; background: var(--row-edge); }
@container doc-list (max-width: 760px) {
  .doc-table thead { display: none; }
  .doc-actions .btn-slot { display: none; }  /* the buttons start the line: none is out of place */
  .doc-table, .doc-table tbody { display: block; }
  .doc-table tr.doc-row {
    display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--space-1-5); padding: var(--space-3) var(--space-5); border-bottom: 1px solid var(--border);
  }
  .doc-table tbody tr.doc-row:last-child { border-bottom: 0; }
  .doc-list-box table.doc-table tr.doc-row > td { position: static; height: auto; padding: 0; border: 0; min-width: 0; background: none; box-shadow: none; }
  /* A ticked row, or the one under the pointer, is coloured whole, not cell by cell */
  .data-table.doc-table tbody tr.doc-row:hover, .data-table.doc-table tbody tr.doc-row:focus-within { background-color: var(--surface-2); }
  .data-table.doc-table tbody tr.doc-row.is-selected { background-color: var(--primary-soft); }
  .doc-table .doc-vis .vis-date { display: inline; margin-left: var(--space-1-5); }
  .doc-table .doc-actions { text-align: left; margin-top: var(--space-1); }
  /* A new document's small card draws the edge itself, and stops it where the list card's corners start */
  .doc-table tr.doc-row.is-new { position: relative; }
  .doc-table tr.doc-row.is-new::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px; background: var(--row-edge); }
  .table-wrap > .doc-list-box:first-child tbody > tr.doc-row.is-new:first-child::before { top: var(--radius); }
  .table-wrap > .doc-list-box:last-child tbody > tr.doc-row.is-new:last-child::before { bottom: var(--radius); }
  .card:not(.table-wrap) > .doc-list-box .doc-table tr.doc-row.is-new::before { left: -10px; }
  .table-wrap > .doc-list-box table.doc-table tr.doc-row > td:first-child::before,
  .card:not(.table-wrap) > .doc-list-box table.doc-table tr.doc-row.is-new > td:first-child::before { content: none; }  /* the card draws it, not its first cell */
  .doc-table tr.doc-row.is-new td:first-child { box-shadow: none; }
  .card:not(.table-wrap) > .doc-list-box .doc-table tr.doc-row { padding-left: 0; padding-right: 0; }  /* the card pads it */
  /* A box to tick the row: beside the document, the rest of the card under it */
  .doc-table tr.doc-row:has(> .select-cell) { grid-template-columns: auto minmax(0, 1fr); column-gap: 0; }
  .doc-table tr.doc-row:has(> .select-cell) > td:not(.select-cell) { grid-column: 2; }
  .doc-list-box table.doc-table tr.doc-row > td.select-cell { grid-row: 1; width: auto; min-width: 32px; }  /* a row with no box lines up with the others */
  .doc-table .select-hit { min-width: var(--touch-target); min-height: var(--touch-target); margin: -11px 0 -11px -12px; }
}
.card:not(.table-wrap) > .doc-list-box .doc-table th:first-child, .card:not(.table-wrap) > .doc-list-box .doc-table td:first-child { padding-left: 0; }
.card:not(.table-wrap) > .doc-list-box .doc-table th:last-child, .card:not(.table-wrap) > .doc-list-box .doc-table td:last-child { padding-right: 0; }

/* The folder browser (portal/staff/folders/_browser.html): a client's documents in Permanent and by year, the folders
   in them, and the documents at one place; on a page as a card, or in the modal */
.folder-head { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: var(--space-2) var(--space-4); margin-bottom: var(--space-3); }
.folder-heading { min-width: 0; }
.folder-heading h2 { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1-5) var(--space-2); margin: 0; overflow-wrap: anywhere; }
.folder-heading h2 > .icon { color: var(--primary); }
.folder-trail { margin-bottom: var(--space-0-5); }
.folder-actions { flex-wrap: wrap; align-items: center; }
.folder-menu > summary.btn { display: inline-flex; align-items: center; }
.folder-menu[open] > summary.btn { border-color: var(--border-strong); background: var(--surface-3); }
.folder-menu .menu-panel { left: auto; right: 0; width: min(320px, calc(100vw - 48px)); z-index: 30; padding: var(--space-3) var(--space-4); }
.folder-form .field { margin-bottom: var(--space-2); }
.folder-form .field input, .folder-form .field select { width: 100%; }
.folder-form p { margin: 0 0 var(--space-2-5); }
.folder-form .actions { justify-content: flex-end; }
.folder-tiles {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: var(--space-2-5); list-style: none; margin: 0 0 var(--space-4); padding: 0;
}
.folder-tile {
  display: flex; align-items: center; gap: var(--space-3); height: 100%; padding: var(--space-3) var(--space-4); border: 1px solid var(--border);
  border-radius: var(--radius); background: var(--surface-2); color: var(--text);
}
.folder-tile:hover { border-color: var(--primary); background: var(--primary-soft); text-decoration: none; }
.folder-tile > .icon { flex-shrink: 0; width: 22px; height: 22px; color: var(--primary); }
.folder-tile-text { display: flex; flex-direction: column; min-width: 0; }
.folder-tile-name { font-weight: 600; overflow-wrap: anywhere; }
.folder-tile-count { font-size: var(--text-xs); color: var(--muted); }
.folder-subtitle { display: flex; align-items: center; gap: var(--space-2); margin: var(--space-4) 0 var(--space-1); font-size: var(--text-md); color: var(--text-2); }
.folder-head + .folder-subtitle, .folder-tiles + .folder-subtitle { margin-top: 0; }
.folder-empty { margin: var(--space-1) 0 0; }
.modal:has(.folder-modal) { width: min(900px, calc(100vw - 32px)); }
.folder-modal .folder-head .modal-close { margin-left: var(--space-1); }

/* A client's page: the portal section */
.portal-signin-line { display: flex; align-items: flex-start; gap: var(--space-2); margin: 0 0 var(--space-3); }
.portal-signin-line .icon { margin-top: 3px; color: var(--muted); }
.recent-docs { display: grid; grid-template-columns: minmax(0, 1fr) auto auto auto; column-gap: var(--space-3); }  /* the place, who sees it and when: each in its own column */
.recent-docs li { display: grid; grid-column: 1 / -1; grid-template-columns: subgrid; align-items: center; }
.recent-docs .vis-date { text-align: right; }
@media (max-width: 720px) {  /* a phone keeps today's wrap */
  .recent-docs { display: block; }
  .recent-docs li { display: flex; flex-wrap: wrap; gap: var(--space-1) var(--space-3); }
}
.recent-docs .doc-title-line { flex: 1 1 260px; min-width: 0; }

/* Who can sign in; copying invite links */
.access-table td { vertical-align: middle; }
.copy-field { display: flex; gap: var(--space-2); align-items: center; margin: var(--space-1-5) 0 var(--space-1); max-width: var(--width-form); }
.copy-field input { flex: 1; min-width: 0; font-family: ui-monospace, monospace; font-size: var(--text-sm); }
.portal-link-card .item-with-icon { align-items: flex-start; }
.portal-link-card .item-with-icon > div { flex: 1; min-width: 0; }
.portal-closed-notice { display: flex; align-items: flex-start; gap: var(--space-2); margin-bottom: var(--space-4); }
.portal-closed-notice .icon { margin-top: var(--space-0-5); }

/* Uploading: a box to choose files or drop them on */
.dropzone {
  position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--space-1);
  min-height: 112px; padding: var(--space-4); border: 2px dashed var(--border); border-radius: var(--radius); background: var(--bg);
  color: var(--muted); text-align: center; cursor: pointer; font-weight: normal;
}
.dropzone:hover, .dropzone.is-dragging { border-color: var(--primary); color: var(--text); }
.dropzone.is-dragging { background: var(--primary-soft); }
.dropzone:focus-within { outline: 2px solid var(--primary); outline-offset: 2px; }
.dropzone .icon { width: 26px; height: 26px; color: var(--primary); }
.dropzone-text strong { color: var(--link); }
.dropzone-files { color: var(--text); font-size: var(--text-base); font-weight: 600; overflow-wrap: anywhere; }
.dropzone.has-files { border-style: solid; border-color: var(--primary); }
.dropzone input[type="file"] { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; }
.has-error .dropzone { border-color: var(--danger); }
.upload-form { max-width: none; }
.doc-links { margin-bottom: var(--space-1); }
.visibility-field fieldset > div { display: flex; flex-wrap: wrap; gap: var(--space-1) var(--space-4); }
.upload-page { max-width: var(--width-form); }

/* Yes/no settings: what it is and what it does, with a switch (portal/_toggle.html) */
.toggle-row { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-4); padding: var(--space-3) 0; }
.toggle-row + .toggle-row { border-top: 1px solid var(--border); }
.toggle-text { display: flex; flex-direction: column; gap: var(--space-0-5); min-width: 0; cursor: pointer; }
.toggle-label { font-weight: 600; font-size: var(--text-md); }
.toggle-help { color: var(--muted); font-size: var(--text-sm); font-weight: normal; }
input.switch {
  -webkit-appearance: none; appearance: none; position: relative; flex-shrink: 0; width: 40px; height: 23px; margin: 1px 0 0;
  padding: 0; border: 0; border-radius: var(--radius-full); background: var(--control-off); cursor: pointer; transition: background 0.15s;
}
input.switch::before {
  content: ""; position: absolute; top: 3px; left: 3px; width: 17px; height: 17px; border-radius: 50%; background: #fff;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3); transition: transform 0.15s;
}
input.switch:checked { background: var(--primary); }
input.switch:checked::before { transform: translateX(17px); }
input.switch:focus { outline: none; }
input.switch:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) { input.switch, input.switch::before { transition: none; } }
.form .toggle-row { margin-bottom: var(--space-1); }
.portal-settings .sub-fields { margin: 0 0 var(--space-1-5) var(--space-4); padding: var(--space-0-5) 0 var(--space-0-5) var(--space-4); }
.portal-settings .sub-fields .field { margin: var(--space-2) 0 var(--space-1); }
/* The Emails card: a label that follows a field or an indented group stands off it, nearer its own field */
.portal-settings .reminder-summary { margin-top: var(--space-4); }
.portal-settings .sub-fields + .field { margin-top: var(--space-4); }
.portal-settings:has(#id_show_deadlines:not(:checked)) .sub-fields { opacity: 0.5; }

/* A document's page, the portal settings */
.client-note { margin: var(--space-2) 0 0; padding: var(--space-2) var(--space-3); border-left: 3px solid var(--border); background: var(--bg); border-radius: 0 var(--radius-md) var(--radius-md) 0; }
.compact-list li { padding: var(--space-1) 0; }
.approval-actions { margin-top: var(--space-2); }
.sub-fields { margin: -6px 0 var(--space-3) 26px; padding-left: var(--space-3); border-left: 2px solid var(--border); }
.portal-settings .card { max-width: none; }

/* Setting up services for many clients (engagements/bulk_views.py) */
.bulk-filters { margin-bottom: var(--space-3); }
.bulk-problems { margin-bottom: var(--space-3); }
.bulk-problems p { margin: 0; }
.bulk-clients summary { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-1) var(--space-3); cursor: pointer; }
.bulk-clients summary .card-heading { display: inline; margin: 0; }
.bulk-clients .table-scroll { margin-top: var(--space-3); }
.bulk-client-table { max-height: none; }
.bulk-preset-list { display: grid; gap: var(--space-2); margin: 0; padding: 0; list-style: none; }
.bulk-preset-list li { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-2); }
.bulk-preset-actions { display: flex; gap: var(--space-1-5); }
.bulk-group { margin-top: var(--space-5); }
.bulk-service { margin-bottom: var(--space-2); padding: var(--space-3) var(--space-4); }
.bulk-service-head { display: flex; align-items: flex-start; gap: var(--space-2-5); cursor: pointer; font-weight: normal; }
.bulk-service-head input { flex: none; margin-top: 3px; }
.bulk-service-rule { display: block; margin-top: var(--space-0-5); }
.bulk-service-fields { margin: var(--space-3) 0 0 26px; }
.bulk-service-fields > .field:last-child { margin-bottom: 0; }  /* a ticked service's last question ends at its box's padding */
.bulk-service:not(:has(.bulk-service-toggle:checked)) .bulk-service-fields { display: none; }
.bulk-service:has(.bulk-service-toggle:checked) { border-color: var(--primary); }
.bulk-grid td, .bulk-grid th { white-space: nowrap; }
.bulk-grid th[scope="row"] { text-transform: none; letter-spacing: 0; font-size: var(--text-sm); font-weight: 600; color: var(--text); }
.bulk-cell.is-add { font-weight: 600; color: var(--success-text); }
.bulk-grid tfoot th, .bulk-grid tfoot td { border-top: 2px solid var(--border); font-weight: 600; }
.bulk-bar-actions {
  position: sticky; bottom: 0; z-index: 2; display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2);
  margin-top: var(--space-4); padding: var(--space-3) 0; border-top: 1px solid var(--border); background: var(--bg);
}
.bulk-save { display: flex; flex-wrap: wrap; gap: var(--space-1-5); margin-left: auto; }
.bulk-save input { min-width: 200px; }
@media (max-width: 720px) { .bulk-save { margin-left: 0; } .bulk-service-fields { margin-left: 0; } }

/* Request templates, and requests and invites for many clients at once (portal/template_views.py, bulk_views.py) */
.template-list { display: grid; gap: var(--stack-gap); margin: 0; padding: 0; list-style: none; }  /* cards in a stack, as anywhere */
.template-card { margin: 0; }  /* a card's own padding */
.template-card-head { display: grid; gap: var(--space-2-5); }
.template-card-head p { margin: var(--space-0-5) 0 0; }
.template-card-head .actions { justify-content: flex-start; }
.template-name { margin: 0; font-size: var(--text-lg); }
.template-items { margin-top: var(--space-2); }
.template-items summary { cursor: pointer; color: var(--link); }
.template-items ol { margin: var(--space-2) 0 var(--space-1); padding-left: var(--space-6); }
.template-items li { margin-bottom: var(--space-0-5); }
.todo-template-pick { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); padding: var(--space-3) var(--space-5); }  /* a card's side padding: its label starts where the fields under it do */
.todo-template-pick label { font-weight: 600; }
.todo-template-pick select { width: auto; max-width: 100%; }
.bulk-request { max-width: none; margin-bottom: var(--space-4); }
.template-choice { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--space-2) var(--space-3); margin-bottom: var(--space-2); }
.template-choice .field { flex: 1 1 260px; margin-bottom: 0; }
.template-choice .btn { margin-bottom: var(--space-0-5); }
.bulk-request .template-items { margin: 0 0 var(--space-3); }
.filed-under { align-self: end; margin: 0 0 var(--space-3); }
.bulk-clients > .card-heading { margin-bottom: var(--space-1); }
.bulk-clients > p { margin: 0 0 var(--space-2); }
.invite-table .badge { margin-left: var(--space-1); }
.invite-note { max-width: none; margin-top: var(--space-4); }
.email-preview-box { margin: var(--space-1-5) 0 var(--space-2-5); padding: var(--space-3) var(--space-4); border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface-2); }
.email-preview-box p { margin: 0 0 var(--space-1); }
.email-preview-text { margin-top: var(--space-2-5); padding-top: var(--space-2-5); border-top: 1px solid var(--border); white-space: pre-wrap; overflow-wrap: anywhere; font-size: var(--text-sm); }

/* Importing clients and contacts (firmdata/import_views.py) */
.import-layout { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--space-4); align-items: start; margin-bottom: var(--space-4); }
@media (max-width: 899px) { .import-layout { grid-template-columns: minmax(0, 1fr); } }
.import-layout .card { margin: 0; }
.import-tips { margin: 0 0 var(--space-3); padding-left: var(--space-5); }
.import-tips li { margin-bottom: var(--space-1); }
.import-columns select { width: 100%; min-width: 180px; max-width: 320px; }
.import-columns tbody th {
  color: var(--text); font-size: var(--text-sm); font-weight: 600; letter-spacing: normal; text-transform: none;
  white-space: normal;
}
.import-columns tbody th label { color: inherit; font-size: inherit; }
.import-columns .import-sample { overflow: hidden; max-width: 260px; text-overflow: ellipsis; white-space: nowrap; }
.import-columns tr.is-refused th, .import-columns tr.is-refused td { color: var(--muted); }
.import-columns .show-sm { display: none; }
@media (max-width: 720px) { .import-columns .show-sm { display: block; } }
.import-problems p { margin: 0; }
.import-problems { margin-bottom: var(--space-3); }
.import-counts { display: flex; flex-wrap: wrap; gap: var(--space-1-5); margin: 0 0 var(--space-3); }
.import-options { display: grid; gap: var(--space-1-5); margin: 0 0 var(--space-3); }
.check-row { display: flex; align-items: flex-start; gap: var(--space-2); font-size: var(--text-sm); }
.check-row input { flex: none; margin-top: var(--space-0-5); }
.check-row .check-row-help { font-weight: 400; }
.import-households .check-row { margin: var(--space-1-5) 0; }
.import-rows select { min-width: 150px; }
.import-rows .import-details { min-width: 240px; max-width: 420px; }
.import-rows .import-reason { margin-top: var(--space-1); }
.import-warnings { margin: var(--space-1) 0 0; padding-left: var(--space-4); color: var(--warning-text); }
.import-check:has(.import-only-notes:checked) .import-rows tbody tr:not(.has-notes) { display: none; }
.import-bar {
  position: sticky; bottom: 0; z-index: 2; display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-3); padding: var(--space-3) 0;
  border-top: 1px solid var(--border); background: var(--bg);
}
.import-numbers { display: grid; grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); gap: var(--space-3); margin: 0 0 var(--space-4); }
.import-numbers div { padding: var(--space-2-5) var(--space-3); border: 1px solid var(--border); border-radius: var(--radius); }
.import-numbers dt { color: var(--muted); font-size: var(--text-sm); }
.import-numbers dd { margin: var(--space-0-5) 0 0; font-size: var(--text-2xl); font-weight: 600; }
.import-next { margin: 0; padding-left: var(--space-5); }

/* Settings as a phone lists them (Your account, Two-factor sign-in): rows in one rounded group, each an icon, a title
   with a line under it, and on the right the state (In use, ticked) or what tapping does (Switch, Set up). The chosen
   row's own action sits under it, indented to its text. */
.setting-group-label {
  margin: var(--space-4) 0 var(--space-1-5); font-size: var(--text-xs); font-weight: 600; letter-spacing: 0.04em;
  text-transform: uppercase; color: var(--muted);
}
.setting-list { list-style: none; margin: 0; padding: 0; border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; background: var(--surface); }
.setting-list > li + li, .setting-row + .setting-row { border-top: 1px solid var(--border); }
.setting-list-last { margin-top: var(--space-4); }
.setting-row { display: flex; align-items: center; gap: var(--space-3); min-height: 56px; padding: var(--space-2-5) var(--space-3); color: inherit; text-decoration: none; }
a.setting-row:hover { background: var(--surface-2); text-decoration: none; }
a.setting-row:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }
.setting-icon { flex: none; display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; border-radius: var(--radius-md); background: var(--surface-3); color: var(--text-2); }
.setting-icon .icon { width: 18px; height: 18px; }
.setting-row.is-selected .setting-icon { background: var(--primary-soft); color: var(--primary); }
.setting-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.setting-title { font-weight: 600; color: var(--text); }
.setting-sub { font-size: var(--text-sm); color: var(--muted); font-variant-numeric: tabular-nums; }
.setting-sub.is-warning { color: var(--warning-text); }
.setting-end { flex: none; display: inline-flex; align-items: center; gap: var(--space-1); font-size: var(--text-sm); color: var(--muted); }
.setting-end .icon { width: 16px; height: 16px; }
.setting-state { color: var(--success-text); font-weight: 600; }
.setting-action { color: var(--link); font-weight: 500; }
.setting-row.is-sub { min-height: 44px; padding-left: calc(var(--space-3) + 32px + var(--space-3)); border-top: 1px dashed var(--border); }
.setting-row.is-danger .setting-title { color: var(--danger); font-weight: 500; }
.setting-note { margin: var(--space-2) 0 0; }

/* Phone numbers in Canada and the US: +1 inside the box, on the left (twofactor/forms.py, PhoneInput) */
.phone-field { position: relative; display: block; width: 100%; }
.phone-field input { width: 100%; padding-left: 3.25rem; font-variant-numeric: tabular-nums; }
.phone-prefix {
  position: absolute; top: 1px; bottom: 1px; left: 1px; display: inline-flex; align-items: center;
  padding: 0 var(--space-2-5); border-right: 1px solid var(--border); border-radius: var(--radius-md) 0 0 var(--radius-md);
  background: var(--surface-2); color: var(--text-2); font-variant-numeric: tabular-nums; pointer-events: none;
}

/* Password fields: the show/hide button inside the field, on the right (static/js/app.js) */
.password-field { position: relative; display: block; width: 100%; }
.password-field input { width: 100%; padding-right: 44px; }
.password-toggle {
  position: absolute; top: 50%; right: 4px; transform: translateY(-50%); display: inline-flex; align-items: center;
  justify-content: center; width: 36px; height: 36px; padding: 0; border: 0; border-radius: var(--radius-md);
  background: none; color: var(--muted); cursor: pointer;
}
.password-toggle:hover { color: var(--text); }
.password-toggle:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }
.password-toggle .icon { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
@media (max-width: 899px), (pointer: coarse) { .password-toggle::after { content: ""; position: absolute; inset: -4px; } }  /* a finger's width */

/* Settings, Portal address: the name on the app's domain, the firm's own domain and its DNS record */
.address-form { max-width: var(--width-form); }
.address-input { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-1-5); }
.address-input input { flex: 1 1 160px; min-width: 0; font-family: ui-monospace, monospace; }
.address-part { font-family: ui-monospace, monospace; font-size: var(--text-sm); }
.domain-status { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1-5) var(--space-2-5); margin-bottom: var(--space-2); }
.domain-name { font-family: ui-monospace, monospace; overflow-wrap: anywhere; }
.domain-problem { display: flex; align-items: flex-start; gap: var(--space-2); margin: 0 0 var(--space-3); }
.domain-problem .icon { flex: none; margin-top: var(--space-0-5); }
.dns-record {
  display: grid; grid-template-columns: max-content minmax(0, 1fr); align-items: center; gap: var(--space-1-5) var(--space-3);
  margin: var(--space-2) 0 var(--space-3); padding: var(--space-3) var(--space-4); border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface-2);
}
.dns-record dt { font-size: var(--text-sm); font-weight: 600; color: var(--text-2); }
.dns-record dd { min-width: 0; margin: 0; }
.dns-record .copy-field { max-width: none; margin: 0; }
@media (max-width: 560px) {
  .dns-record { grid-template-columns: minmax(0, 1fr); gap: var(--space-0-5); }
  .dns-record dd + dt { margin-top: var(--space-2); }
}
.domain-optional { margin: var(--space-3) 0 var(--space-1); }
.domain-optional summary { cursor: pointer; color: var(--text-2); font-size: var(--text-sm); }
.sending-local { margin-top: var(--space-4); padding-top: var(--space-4); border-top: 1px solid var(--border); }

/* --- Client portal: what the client sees ------------------------------------------------------- */
body.portal-page { min-height: 100vh; display: flex; flex-direction: column; }
.portal-preview-bar {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); padding: var(--space-2) var(--space-5); background: var(--warning-bg); color: var(--warning-text);
  font-size: var(--text-base); border-bottom: 1px solid var(--warning-border-soft);
}
.portal-preview-bar > span { flex: 1; min-width: 220px; }

.portal-header { position: sticky; top: 0; z-index: 30; background: var(--surface); border-bottom: 1px solid var(--border); }
.portal-bar { display: flex; align-items: center; gap: var(--space-4); max-width: 1040px; margin: 0 auto; padding: var(--space-2-5) var(--space-5); }
.portal-brand { display: inline-flex; align-items: center; gap: var(--space-2-5); color: var(--text); font-weight: 700; font-size: var(--text-lg); flex-shrink: 0; }
.portal-brand:hover { text-decoration: none; }
.portal-logo { display: block; max-height: 38px; max-width: 170px; object-fit: contain; }
/* On the dark page the firm's logo stands on a light plate, as in the sidebar (img.workspace-mark): most logos are
   dark words on nothing, which the dark page would swallow. On the sign-in page and on an invoice too. */
@media screen {
  [data-theme="dark"] .portal-logo, [data-theme="dark"] .portal-auth-logo, [data-theme="dark"] .inv-logo { padding: var(--space-1); border-radius: var(--radius-md); background: #fff; }
}
@media screen and (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .portal-logo, :root:not([data-theme="light"]) .portal-auth-logo, :root:not([data-theme="light"]) .inv-logo { padding: var(--space-1); border-radius: var(--radius-md); background: #fff; }
}
.portal-client { flex: 1; min-width: 0; display: flex; }
.client-name { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding-left: var(--space-4); border-left: 1px solid var(--border); }
.client-button {
  display: flex; align-items: center; gap: var(--space-2-5); max-width: 100%; padding: var(--space-1) var(--space-2-5); border: 1px solid var(--border);
  border-radius: var(--radius-md); cursor: pointer; color: var(--text);
}
.client-button:hover, .client-menu[open] > .client-button { border-color: var(--muted); }
.client-button-text { display: flex; flex-direction: column; min-width: 0; line-height: 1.2; }
.client-button-label { font-size: var(--text-2xs); font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted); }
.client-button-name { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.client-button .chevron { width: 16px; height: 16px; color: var(--muted); transition: transform 0.15s; }
.client-menu[open] .chevron { transform: rotate(180deg); }
.client-menu { min-width: 0; }
.client-menu .menu-panel { right: auto; min-width: 260px; max-width: calc(100vw - 32px); }
.account-button { cursor: pointer; }
.account-button:focus-visible, .client-button:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.portal-page .avatar { background: var(--primary); color: var(--on-primary); }
.account-menu { flex-shrink: 0; }
.account-menu .menu-panel { left: auto; right: 0; min-width: 220px; }

.portal-nav { border-top: 1px solid var(--border); }
.portal-nav-inner { display: flex; gap: var(--space-5); max-width: 1040px; margin: 0 auto; padding: 0 var(--space-5); overflow-x: auto; scrollbar-width: none; }
.portal-nav a {
  position: relative; display: inline-flex; align-items: center; gap: var(--space-2); padding: var(--space-3) 0 var(--space-2); border-bottom: 2px solid transparent;
  color: var(--muted); font-weight: 500; white-space: nowrap;
}
.portal-nav a .icon { width: 17px; height: 17px; }
.portal-nav a:hover { color: var(--text); text-decoration: none; }
.portal-nav a.active { color: var(--text); font-weight: 600; border-bottom-color: var(--primary); }
.portal-nav a.active .icon { color: var(--link); }  /* the firm's colour where it reads: a pale one would lose the icon */
.portal-nav a:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }  /* inside the tab: the row scrolls sideways and clips what is outside */
@media (min-width: 721px) { .portal-nav a:focus-visible { margin-inline: -8px; padding-inline: var(--space-2); } }  /* room for the ring: these tabs have no side padding */
.nav-count {
  min-width: 1.5em; padding: 0 var(--space-1-5); border-radius: var(--radius-full); background: var(--primary); color: var(--on-primary);
  font-size: var(--text-2xs); font-weight: 700; line-height: 1.6; text-align: center;
}

.portal-main { flex: 1; width: 100%; max-width: 1040px; margin: 0 auto; padding: var(--space-6) var(--space-5) var(--space-10); }
.portal-main:focus { outline: none; }
.portal-main .page-header.invoice-page-header { max-width: var(--width-doc); }  /* over an invoice, a credit note or a statement: its buttons end where the document does */
.portal-footer { border-top: 1px solid var(--border); color: var(--muted); font-size: var(--text-sm); }
.portal-footer-inner { display: flex; flex-wrap: wrap; gap: var(--space-1) var(--space-4); max-width: 1040px; margin: 0 auto; padding: var(--space-4) var(--space-5); }
.portal-footer strong { color: var(--text); }

/* Overview */
.portal-welcome { display: flex; gap: var(--space-3); align-items: flex-start; }
.portal-welcome > .icon { color: var(--primary); margin-top: var(--space-0-5); }
.portal-welcome p { margin: 0 0 var(--space-2); }
.portal-welcome p:last-child { margin-bottom: 0; }
.portal-callout { display: flex; align-items: center; gap: var(--space-2); }
.portal-columns { display: grid; grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr); gap: 0 var(--space-5); align-items: start; }
@media (max-width: 899px) { .portal-columns { grid-template-columns: minmax(0, 1fr); } }
.portal-narrow { max-width: var(--width-form); }

/* Documents */
.portal-filters input[type="search"] { flex: 1; min-width: 200px; }
.portal-callout { margin: 0 0 var(--space-4); padding: var(--space-2-5) var(--space-4); border: 1px solid var(--warning-border-soft); border-radius: var(--radius); background: var(--warning-bg); color: var(--text); }
.portal-callout > .icon { color: var(--warning-text); }
/* A note that leads to what it's about (Documents: what waits for a signature or an approval): all of it is the link */
a.portal-callout { min-height: var(--touch-target); }
a.portal-callout:hover { text-decoration: none; border-color: var(--warning-text); }
a.portal-callout:hover > span { text-decoration: underline; }
.portal-callout > .callout-go { width: 16px; height: 16px; margin-left: auto; }
.portal-year-title { display: flex; align-items: center; gap: var(--space-2); font-size: var(--text-xl); margin-bottom: var(--space-1); }
.portal-section-title {
  margin: var(--space-4) 0 0; padding-top: var(--space-3); border-top: 1px solid var(--border); font-size: var(--text-xs); font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted);
}
.portal-year-title + .portal-section-title { border-top: 0; margin-top: var(--space-2); padding-top: 0; }
.portal-year-note { margin: 0 0 var(--space-2); }
/* The firm's folders in a year: each opens to its documents (portal/_folder.html) */
.portal-folders { margin: var(--space-2) 0 var(--space-1); }
.portal-folder { margin: var(--space-2) 0; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); }
.portal-folders:last-child > .portal-folder:last-child { margin-bottom: 0; }  /* a year that ends with its folders ends at the card's padding */
.portal-folder > summary {
  display: flex; align-items: center; gap: var(--space-2); padding: var(--space-2-5) var(--space-3); font-weight: 600; cursor: pointer; list-style: none;
}
.portal-folder > summary::-webkit-details-marker { display: none; }
.portal-folder > summary > .icon { width: 18px; height: 18px; color: var(--primary); }
.portal-folder[open] > summary { border-bottom: 1px solid var(--border); }
.portal-folder-name { overflow-wrap: anywhere; }
.portal-folder-body { padding: 0 var(--space-3); }
.portal-folder-body > .portal-folder:first-child { margin-top: var(--space-3); }
.portal-folder-body > .portal-folder:last-child { margin-bottom: var(--space-3); }
.portal-doc-list { list-style: none; margin: 0; padding: 0; }
.portal-doc {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: var(--space-1) var(--space-3); align-items: start; padding: var(--space-3) 0;
  border-bottom: 1px solid var(--border); scroll-margin-top: 130px;
}
.portal-doc:last-child { border-bottom: 0; }
.portal-doc > .file-badge { margin-top: 1px; }
.portal-doc-heading { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-2); }
.portal-doc-title { font-weight: 600; color: var(--text); overflow-wrap: anywhere; }
.portal-doc-title:hover { color: var(--link); }
.portal-doc-meta { margin-top: var(--space-0-5); }
.portal-doc-main > p { margin: var(--space-1) 0 0; }
.portal-doc-message { display: flex; gap: var(--space-2); margin: var(--space-2) 0 0; padding: var(--space-2) var(--space-3); border-radius: var(--radius-md); background: var(--bg); }
.portal-doc-message .icon { width: 15px; height: 15px; margin-top: 3px; color: var(--muted); }
.portal-doc-actions { display: flex; gap: var(--space-1-5); }
.portal-received { display: flex; align-items: flex-start; gap: var(--space-1-5); margin: var(--space-1) 0 0; color: var(--success-text); }
.portal-received .icon { width: 14px; height: 14px; margin-top: 3px; }
/* A document's box to sign or approve: under its words and its buttons, the width of the row (not squeezed beside the
   buttons); what it holds is parted by one gap */
.approve-box {
  grid-column: 2 / -1; margin-top: var(--space-1-5); padding: var(--space-2-5) var(--space-3); border: 1px solid var(--warning-border-soft); border-radius: var(--radius); background: var(--warning-bg-soft);
}
.approve-box > * { margin: 0; }
.approve-box > * + * { margin-top: var(--space-2); }
.approve-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: flex-start; }
.changes-box > summary { list-style: none; }
.changes-box > summary::-webkit-details-marker { display: none; }
.changes-box[open] { flex-basis: 100%; }
.changes-form { max-width: none; margin-top: var(--space-2); display: flex; flex-direction: column; gap: var(--space-1-5); }
.changes-form label { font-weight: 600; font-size: var(--text-base); }
.changes-form textarea { width: 100%; }

/* Deadlines */
.deadline-month-title {
  margin: var(--space-4) 0 var(--space-1); font-size: var(--text-xs); font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted);
}
.deadline-month-title:first-of-type { margin-top: var(--space-1); }
.deadline-list, .done-list, .deadline-docs, .team-list, .firm-lines, .service-list, .people-list { list-style: none; margin: 0; padding: 0; }
.deadline { display: flex; gap: var(--space-3); padding: var(--space-3) 0; border-bottom: 1px solid var(--border); }
.deadline:last-child { border-bottom: 0; }
.deadline-date {
  display: flex; flex-direction: column; align-items: center; justify-content: center; flex-shrink: 0; width: 50px; height: 52px;
  border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); line-height: 1.1;
}
.deadline-month { font-size: var(--text-2xs); font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted); }
.deadline-day { font-size: var(--text-xl); font-weight: 700; font-variant-numeric: tabular-nums; }
.deadline.is-client .deadline-date { border-style: dashed; }
.deadline-main { flex: 1; min-width: 0; }
.deadline-title { font-weight: 600; overflow-wrap: anywhere; }
.deadline-meta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-2); margin-top: 3px; }
.deadline-docs { margin-top: var(--space-1-5); }
.deadline-docs li { padding: var(--space-0-5) 0; }
.deadline-docs a { display: inline-flex; align-items: center; gap: var(--space-1-5); font-size: var(--text-base); }
.deadline-docs .icon { width: 14px; height: 14px; }
.is-compact .deadline-date { width: 44px; height: 46px; }
.is-compact .deadline-day { font-size: var(--text-lg); }
.done-item { display: flex; gap: var(--space-3); padding: var(--space-3) 0; border-bottom: 1px solid var(--border); }
.done-item:last-child { border-bottom: 0; }
.done-mark {
  display: inline-grid; place-items: center; width: 26px; height: 26px; flex-shrink: 0; border-radius: 50%;
  background: var(--success-bg); color: var(--success-text);
}
.done-mark .icon { width: 14px; height: 14px; }
.done-main { flex: 1; min-width: 0; }
.done-title { font-weight: 600; overflow-wrap: anywhere; }

/* Deadlines: calendar view */
.calendar-toolbar { justify-content: space-between; }
.calendar-title { margin: 0; }
.tracker-nav .btn.is-disabled { opacity: 0.4; cursor: default; }
.calendar-grid { border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }
.calendar-weekdays, .calendar-week { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); }
.calendar-weekday {
  padding: var(--space-1-5) var(--space-1); text-align: center; font-size: var(--text-xs); font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.05em; color: var(--muted); background: var(--bg); border-bottom: 1px solid var(--border);
}
.calendar-week + .calendar-week { border-top: 1px solid var(--border); }
.calendar-day { min-height: 92px; padding: var(--space-1-5); border-left: 1px solid var(--border); min-width: 0; }
.calendar-day:first-child { border-left: 0; }
.calendar-day.is-outside { background: var(--bg); }
.calendar-day.is-outside .calendar-day-number { color: var(--muted); opacity: 0.6; }
.calendar-day-number { font-size: var(--text-sm); font-weight: 600; font-variant-numeric: tabular-nums; }
/* Every day's number is one line box, so each day's items start at one height. Today's sits on a pill whose padding
   hangs out to the left, so its digits stay in the column of the other days' */
.calendar-day-number span[aria-hidden] { display: inline-block; height: var(--space-6); line-height: var(--space-6); }
.calendar-day.is-today .calendar-day-number span[aria-hidden] {
  min-width: var(--space-6); margin-left: calc(-1 * var(--space-1-5)); padding: 0 var(--space-1-5); border-radius: var(--radius-full);
  background: var(--primary); color: var(--on-primary); text-align: center;
}
.calendar-items { list-style: none; margin: var(--space-1-5) 0 0; padding: 0; display: flex; flex-direction: column; gap: 3px; }
.calendar-item {
  display: flex; align-items: center; gap: var(--space-1); padding: var(--space-0-5) var(--space-1-5); border-radius: var(--radius-sm); font-size: var(--text-xs); line-height: 1.3;
  background: var(--primary); color: var(--on-primary); border: 1px solid transparent;
}
.calendar-item-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.calendar-item.is-client { background: transparent; color: var(--text); border: 1px dashed var(--primary); }
.calendar-item.is-past-due { border-color: var(--danger); color: var(--danger); }
.calendar-item.is-done { background: var(--success-bg); color: var(--success-text); }
.calendar-item-mark { display: inline-grid; flex-shrink: 0; }
.calendar-item-mark .icon { width: 11px; height: 11px; }
.calendar-legend { display: flex; flex-wrap: wrap; gap: var(--space-1-5) var(--space-4); margin: var(--space-2-5) 0 0; }
.calendar-key { display: inline-flex; align-items: center; gap: var(--space-1-5); }
.calendar-key::before { content: ""; width: 12px; height: 12px; border-radius: var(--radius-sm); border: 1px solid transparent; }
.calendar-key.is-firm::before { background: var(--primary); }
.calendar-key.is-client::before { border: 1px dashed var(--primary); }
.calendar-key.is-done::before { background: var(--success-bg); border-color: var(--success-text); }
@media (max-width: 560px) {  /* an agenda: only the days with something on them */
  .calendar-weekdays { display: none; }
  .calendar-week { grid-template-columns: 1fr; }
  .calendar-week + .calendar-week { border-top: 0; }
  .calendar-day { border-left: 0; border-top: 1px solid var(--border); min-height: 0; }
  .calendar-day.is-empty, .calendar-day.is-outside { display: none; }
  .calendar-week:first-child .calendar-day:first-of-type { border-top: 0; }
  .calendar-day-number { font-size: var(--text-sm); }
  .calendar-day.is-today .calendar-day-number span[aria-hidden]::after { content: " · Today"; }
  .calendar-day.is-today .calendar-day-number span[aria-hidden] { min-width: 0; padding: 0 var(--space-1-5); }
  .calendar-item { font-size: var(--text-sm); padding: var(--space-1) var(--space-2); }
  .calendar-item-title { white-space: normal; overflow-wrap: anywhere; }
}

/* Team, the firm's details, services, people */
.team-person { display: flex; gap: var(--space-3); padding: var(--space-3) 0; border-bottom: 1px solid var(--border); }
.team-person:last-child { border-bottom: 0; }
.team-person .avatar { width: 36px; height: 36px; font-size: var(--text-sm); }
.team-person-text { min-width: 0; }
.team-name { font-weight: 600; }
.team-reach { display: flex; flex-wrap: wrap; gap: var(--space-0-5) var(--space-3); margin-top: var(--space-0-5); }
.team-reach a, .firm-lines li { display: inline-flex; align-items: center; gap: var(--space-1-5); overflow-wrap: anywhere; }
.team-reach .icon { width: 14px; height: 14px; }
.firm-lines li { display: flex; align-items: flex-start; padding: var(--space-1) 0; }
.firm-lines .icon { width: 16px; height: 16px; margin-top: 3px; color: var(--muted); flex-shrink: 0; }
.firm-card .btn-block { margin-top: var(--space-3); text-align: center; }
.service-list li, .people-list li { padding: var(--space-3) 0; border-bottom: 1px solid var(--border); }
.service-list li:last-child, .people-list li:last-child { border-bottom: 0; }
.service-name, .people-name { font-weight: 600; }
/* A card's list of rows: one padding parts its rows, and none is outside the first and the last. The heading's gap
   is the space over the list and the card's padding the space under it, as in Your details (Overview, Profile). */
.card > :is(h2:not(.portal-year-title), .section-header) + :is(.portal-doc-list, .deadline-list, .done-list, .team-list, .service-list, .people-list, .firm-lines, .todo-overview) > li:first-child,
.portal-approvals > h3 + :is(.portal-doc-list, .todo-overview) > li:first-child { padding-top: 0; }
.card > :is(.portal-doc-list, .deadline-list, .done-list, .team-list, .service-list, .people-list, .firm-lines, .todo-overview, .portal-invoice-list):last-child > li:last-child,
.card > .portal-approvals:last-child > :last-child > li:last-child { padding-bottom: 0; }

/* Invoices */
.portal-invoices td { vertical-align: middle; }
/* A row's number, where it stands and (on a phone) its date are one link: all of it opens the invoice */
.portal-invoice-link { display: inline-flex; flex-wrap: wrap; align-items: center; align-content: center; gap: var(--space-0-5) var(--space-1-5); color: var(--text); }
.portal-invoice-link:hover { text-decoration: none; }
.portal-invoice-number { color: var(--link); }
.portal-invoice-link:hover .portal-invoice-number { text-decoration: underline; }
.portal-invoice-link > .show-sm { flex-basis: 100%; }
.show-sm { display: none; }

/* Sign-in pages */
.portal-auth-brand { display: flex; justify-content: center; margin-bottom: var(--space-5); }
.portal-auth-logo { display: block; max-height: 56px; max-width: 180px; object-fit: contain; }  /* a wide logo is half a phone's card */
.portal-auth .auth-card h1 { margin-bottom: var(--space-2); }

/* Phones: the sections move to a bar at the bottom of the screen, in reach of a thumb */
@media (max-width: 720px) {
  .portal-header { position: static; }
  .portal-bar { gap: var(--space-2-5); padding: var(--space-2-5) var(--space-4); }
  .portal-logo { max-height: 32px; max-width: 120px; }
  .portal-brand .portal-firm { display: none; }
  .client-name { padding-left: var(--space-2-5); font-size: var(--text-md); }
  .portal-nav {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 40; border-top: 1px solid var(--border);
    background: var(--surface);
  }
  /* Equal tabs, but none narrower than its own name: with six of them on a narrow phone the names would run together */
  .portal-nav-inner { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(min-content, 1fr); gap: 0; padding: 0 4px env(safe-area-inset-bottom); }
  .portal-nav a {
    flex-direction: column; gap: var(--space-0-5); padding: var(--space-2) var(--space-0-5) var(--space-2); border-bottom: 0; border-top: 2px solid transparent;
    font-size: var(--text-2xs); font-weight: 500;
  }
  .portal-nav a .icon { width: 21px; height: 21px; }
  .portal-nav a.active { border-top-color: var(--primary); color: var(--link); }
  .portal-nav .nav-count { position: absolute; top: 4px; left: calc(50% + 6px); }
  .portal-main { padding: var(--space-4) var(--space-4) var(--space-8); }
  .portal-footer-inner { padding-bottom: 84px; }  /* clears the bar, for the page above it too */
  .portal-doc { grid-template-columns: auto minmax(0, 1fr); }
  .portal-doc-actions { grid-column: 2; }
  .show-sm { display: block; }
  .portal-preview-bar { padding: var(--space-2) var(--space-4); }
  .portal-page #messages { bottom: 84px; }  /* above the bar */
}

@media print {
  .portal-header, .portal-nav, .portal-footer, .portal-preview-bar { display: none !important; }
  .portal-main { max-width: none; padding: 0; }
}

/* --- Client portal: to-dos ------------------------------------------------------------------------ */
/* How much is done */
.todo-progress { display: inline-flex; align-items: center; gap: var(--space-2); white-space: nowrap; }
.todo-progress progress { width: 90px; height: 8px; accent-color: var(--success-text); }
.todo-summary-progress .todo-progress progress { width: 220px; height: 10px; }
.todo-summary-progress .todo-progress .small { font-size: var(--text-md); font-weight: 600; }
.todo-summary p { margin: var(--space-2) 0 0; }

/* The firm's lists of to-dos */
.todo-table td { vertical-align: middle; }
.todo-table:not(.data-table) .todo-cell-main { min-width: 180px; }  /* a client's own requests, in a narrow card: the table scrolls sideways rather than stand the title a word a line */
.todo-title { font-weight: 600; color: var(--text); }
.todo-title:hover { color: var(--link); }
.todo-status .badge { margin: var(--space-0-5) var(--space-1) var(--space-0-5) 0; white-space: nowrap; }
.todo-table tr.has-new td:first-child { box-shadow: inset 3px 0 0 var(--primary); }
.card:not(.table-wrap) > .table-scroll > .todo-table tr.has-new td:first-child { padding-left: var(--space-2-5); }  /* off the new-answers bar */
.chip.is-todo-new { border-color: var(--primary); color: var(--link); }
.chip.is-todo-overdue { border-color: var(--danger); color: var(--danger); }

/* Making a to-do: one row per item */
.todo-form { max-width: 980px; }
.todo-editor { min-width: 0; margin: 0 0 var(--space-4); padding: 0; border: 0; }  /* a field like the others: its rows start at the form's edge */
.todo-editor legend { margin-bottom: var(--space-1-5); padding: 0; font-weight: 600; font-size: var(--text-sm); color: var(--text-2); }  /* as a field's label */
.todo-editor > p { margin: 0 0 var(--space-2-5); }
.todo-rows { container: todo-rows / inline-size; }
.todo-row {
  display: grid; grid-template-columns: 150px minmax(0, 1.4fr) minmax(0, 1fr) 9rem 64px; gap: var(--space-2); align-items: start;  /* fixed columns, so the names row and every item row share their edges; the answer's column fits "Dollar amount" */
  padding: var(--space-1-5) 0; border-bottom: 1px dashed var(--border);
}
.todo-row > div { min-width: 0; }
.todo-row input[type="text"], .todo-row select { width: 100%; }
.todo-row-head { padding-top: 0; border-bottom: 1px solid var(--border); font-size: var(--text-xs); font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); }
.todo-row-remove { display: flex; align-items: center; justify-content: flex-end; min-height: var(--control-height); }  /* the box on its row's centre line, at the column's right as its name */
.todo-row-head > :last-child { text-align: right; }
.todo-row .todo-row-format { visibility: hidden; }
.todo-row:has(select[name$="-kind"] option[value="information"]:checked) .todo-row-format { visibility: visible; }
.todo-row-errors { grid-column: 1 / -1; }
.todo-row.has-error input[type="text"]:invalid, .todo-row.has-error .errorlist + input { border-color: var(--danger); }
.todo-row .errorlist { margin: var(--space-1) 0 0; font-size: var(--text-sm); }
.todo-editor-more { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); margin: var(--space-2-5) 0 var(--space-2); }
@container todo-rows (max-width: 700px) {
  .todo-row { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); padding: var(--space-2-5) 0; }
  .todo-row-head { display: none; }
  .todo-row-label, .todo-row-details { grid-column: 1 / -1; }
  .todo-row .todo-row-format { display: none; }
  .todo-row:has(select[name$="-kind"] option[value="information"]:checked) .todo-row-format { display: block; }
  .todo-row-remove { grid-column: 2; grid-row: 1; }  /* every row one shape: the box beside the type, whatever is under them */
}

/* A to-do on the firm's side: each item with what the client gave */
.review-list, .todo-items, .review-files, .todo-overview { list-style: none; margin: 0; padding: 0; }
.review-item { display: grid; grid-template-columns: 26px minmax(0, 1fr) auto; gap: var(--space-1-5) var(--space-3); padding: var(--space-3) 0; border-bottom: 1px solid var(--border); scroll-margin-top: 20px; }
.review-item:last-child { border-bottom: 0; }
.review-item.is-new { box-shadow: inset 3px 0 0 var(--primary); padding-left: var(--space-2-5); margin-left: -10px; }
.review-head { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-2-5); }
.review-label { font-weight: 600; overflow-wrap: anywhere; }
.review-response { margin-top: var(--space-2); padding: var(--space-2) var(--space-3); border-radius: var(--radius-md); background: var(--bg); }
.review-files li { padding: 3px 0; }
.review-actions { display: flex; flex-wrap: wrap; gap: var(--space-1-5); align-items: flex-start; align-content: flex-start; justify-content: flex-end; }  /* its line is as tall as its buttons, not as the item's text */
.send-back > summary { list-style: none; }
.send-back > summary::-webkit-details-marker { display: none; }
.send-back-form { max-width: none; width: min(340px, 80vw); margin-top: var(--space-2); }
.send-back-form .field { margin-bottom: var(--space-2); }
.send-back-form textarea { width: 100%; }
.todo-returned-note { display: flex; align-items: flex-start; gap: var(--space-1-5); margin-top: var(--space-1-5); color: var(--warning-text); }
.todo-returned-note .icon { width: 14px; height: 14px; margin-top: 3px; flex-shrink: 0; }
/* What the firm writes on an item: one box under its thread while it's to review (Accept, Send back, Send message),
   else behind "Write to …" */
.review-note { max-width: var(--width-form); margin-top: var(--space-3); }
.review-note .field { margin-bottom: var(--space-2); }
.review-note textarea { width: 100%; }
.review-note .actions { display: flex; flex-wrap: wrap; gap: var(--space-1-5); margin-top: 0; }
.review-write { margin-top: var(--space-2); }
.review-write > summary { display: inline-flex; align-items: center; gap: var(--space-1-5); list-style: none; color: var(--link); }
.review-write > summary::-webkit-details-marker { display: none; }
.review-write > summary .icon { width: 14px; height: 14px; }
.review-write .review-note { margin-top: var(--space-2); }
@media (max-width: 720px) {
  .review-item { grid-template-columns: 26px minmax(0, 1fr); }
  .review-actions { grid-column: 2; justify-content: flex-start; }
}

/* Where an item stands (portal/_todo_check.html): its kind's icon on a quiet circle while it's to do (a mark, not a
   box to tick: no edge), a green tick once done, a cross when it's not needed */
.todo-check {
  display: inline-grid; place-items: center; width: 24px; height: 24px; flex-shrink: 0; margin-top: 1px;
  border-radius: 50%; background: var(--bg); color: var(--muted);
}
.todo-check .icon { width: 13px; height: 13px; }
.is-done > .todo-check { background: var(--success-text); color: var(--surface); }
.is-done > .todo-check .icon, .is-not_needed > .todo-check .icon { stroke-width: 3; }
.is-not_needed .todo-item-label, .is-not_needed .review-label { color: var(--muted); text-decoration: line-through; }
.todo-kind { display: inline-flex; align-items: center; gap: var(--space-1); color: var(--muted); font-size: var(--text-sm); white-space: nowrap; }
.todo-kind .icon { width: 13px; height: 13px; }
.todo-answer { overflow-wrap: anywhere; }

/* The client's to-dos */
.todo-card { scroll-margin-top: 130px; }
.todo-card.is-overdue { border-color: var(--danger); }
.todo-card-head { display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: var(--space-2) var(--space-5); }
.todo-card-title { min-width: 0; flex: 1 1 280px; }
.todo-card-title h2 { margin: 0 0 var(--space-1-5); font-size: var(--text-lg); }
.todo-card-meta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-2-5); }
.todo-card > .portal-doc-message { margin-top: var(--space-3); }
.todo-items { margin-top: var(--space-2); }
.todo-item { display: flex; gap: var(--space-3); padding: var(--space-3) 0; border-top: 1px solid var(--border); scroll-margin-top: 130px; }
.todo-item-main { flex: 1; min-width: 0; }
.todo-item-head { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-2-5); }
.todo-item-label { font-weight: 600; overflow-wrap: anywhere; }
.todo-item-details { margin: var(--space-0-5) 0 0; }
.todo-response { max-width: var(--width-form); margin-top: var(--space-2-5); }
.todo-response .field { margin-bottom: var(--space-2-5); }
.todo-response textarea { width: 100%; }
.todo-response input[type="date"], .todo-response input[type="number"] { max-width: 240px; }
.todo-response fieldset > div { display: flex; flex-wrap: wrap; gap: var(--space-1) var(--space-5); }
.todo-response .actions { margin-top: var(--space-0-5); }
.dropzone.dropzone-compact { flex-direction: row; flex-wrap: wrap; min-height: 64px; padding: var(--space-3) var(--space-4); gap: var(--space-1) var(--space-2-5); }
.dropzone-compact .icon { width: 20px; height: 20px; }
.dropzone-compact .dropzone-files { flex-basis: 100%; }
.dropzone-compact .dropzone-files:empty { display: none; }
.todo-change { margin-top: var(--space-1-5); }
.todo-attach { margin: -2px 0 var(--space-2-5); }
.todo-attach > summary { display: inline-flex; align-items: center; gap: var(--space-1-5); list-style: none; color: var(--link); }
.todo-attach > summary::-webkit-details-marker { display: none; }
.todo-attach > summary .icon { width: 14px; height: 14px; }
.todo-attach[open] > summary { margin-bottom: var(--space-2); }
.todo-change > summary { display: inline-block; list-style: none; }
.todo-change > summary::-webkit-details-marker { display: none; }
.todo-change > summary.link-action { color: var(--link); }
.todo-item-head .badge[hidden] { display: none; }  /* "Not sent yet", until there's something (portal-todos.js) */
/* Once an item is done: more for it, or a message about it, each behind its link; the one opened takes the line */
.todo-more { display: flex; flex-wrap: wrap; gap: 0 var(--space-4); }
.todo-more > details[open] { flex-basis: 100%; order: 1; }

/* An item's thread (portal/_thread.html), oldest first: each step on a line, the client's as rings, the firm's as
   dots, amber when it sent the item back, green when it accepted it. The client's reply is its next step. */
.item-thread { list-style: none; margin: var(--space-3) 0 0; padding: 0; }
.item-step { position: relative; padding: 0 0 var(--space-3) var(--space-6); }
.item-step::before, .item-reply::before {
  content: ""; position: absolute; left: 0; top: 5px; width: 10px; height: 10px; box-sizing: border-box;
  border: 2px solid var(--control-off); border-radius: 50%; background: var(--surface);
}
.item-step::after { content: ""; position: absolute; left: 4px; top: 17px; bottom: 0; width: 2px; background: var(--border); }
.item-step:last-child { padding-bottom: 0; }
.item-step:last-child::after { display: none; }
.item-step.is-firm::before { border: 0; background: var(--muted); }
.item-step.step-sent_back::before { background: var(--warning); }
.item-step.step-accepted::before, .item-step.step-done::before { background: var(--success); }
.item-step-head { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-2); color: var(--text-2); font-size: var(--text-sm); }
.item-step-answer { width: fit-content; max-width: 100%; box-sizing: border-box; margin-top: var(--space-1); padding: var(--space-1-5) var(--space-2-5); border-radius: var(--radius-md); background: var(--bg); overflow-wrap: anywhere; }
.item-step-text { margin: var(--space-1) 0 0; overflow-wrap: anywhere; }
.item-step-text.is-sent-back { padding: var(--space-1-5) var(--space-2-5); border-radius: var(--radius-md); background: var(--warning-bg); color: var(--warning-text); font-size: var(--text-sm); }
.item-step.is-replaced .item-step-answer, .item-step.is-replaced .item-step-text { color: var(--muted); }
.item-step-files { list-style: none; margin: var(--space-1) 0 0; padding: 0; }
.item-step-files li { display: flex; flex-wrap: wrap; align-items: center; gap: 0 var(--space-2); padding: 3px 0; }
.item-step-files a { display: inline-flex; align-items: center; gap: var(--space-2); overflow-wrap: anywhere; }
.item-thread-fold { margin-top: var(--space-2); }
.item-thread-fold > summary { list-style: none; color: var(--text-2); font-size: var(--text-sm); cursor: pointer; }
.item-thread-fold > summary::-webkit-details-marker { display: none; }
.item-thread-fold > summary .link-action { color: var(--link); }
.item-thread-fold + .item-thread { margin-top: var(--space-3); }
.item-reply { position: relative; margin-top: var(--space-3); padding-left: var(--space-6); }
.item-reply::after { content: ""; position: absolute; left: 4px; top: calc(-1 * var(--space-3)); height: calc(var(--space-3) + 5px); width: 2px; background: var(--border); }
.item-reply-label { font-size: var(--text-sm); font-weight: 600; }
.item-reply .todo-response { margin-top: var(--space-2); }
/* What the client added to an item and hasn't sent: a row a file under its box, × to take one back */
.todo-files-field .dropzone + .errorlist { margin-top: var(--space-1-5); }
.draft-files { margin: var(--space-2) 0 0; padding: 0; list-style: none; border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--surface); }
.draft-files:empty { display: none; }
.draft-file {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto auto; align-items: center; gap: var(--space-0-5) var(--space-2-5);
  min-height: 42px; padding: var(--space-1) var(--space-1) var(--space-1) var(--space-2-5);
}
.draft-file + .draft-file { border-top: 1px solid var(--border); }
.draft-file-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--text-sm); font-weight: 500; }
.draft-file-meta { color: var(--muted); font-size: var(--text-sm); white-space: nowrap; }
.draft-file-progress { width: 96px; height: 6px; accent-color: var(--primary); }
.draft-file-remove { grid-column: 4; grid-row: 1; width: 32px; height: 32px; color: var(--muted); }
.draft-file-remove:hover { color: var(--text); }
.draft-file-remove .icon { width: 16px; height: 16px; }
.draft-file.is-going > :not(.draft-file-remove) { opacity: 0.6; }
.draft-file.is-failed .draft-file-name { color: var(--muted); }
.draft-file-error { grid-column: 2 / 4; grid-row: 2; padding-bottom: var(--space-1); color: var(--danger); font-size: var(--text-sm); }
/* Send all: floats at the bottom of the window while the to-do is in view and an item holds something not sent */
.todo-send-bar {
  position: sticky; bottom: 16px; z-index: 20; display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: var(--space-2) var(--space-3); margin-top: var(--space-3); padding: var(--space-2) var(--space-2) var(--space-2) var(--space-4);
  border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--surface); box-shadow: var(--shadow-lg);
}
.todo-send-bar[hidden] { display: none; }
.todo-send-bar form { margin: 0; }
.todo-send-state { display: inline-flex; align-items: center; gap: var(--space-2); font-weight: 500; }
.todo-send-state::before { content: ""; width: 8px; height: 8px; flex-shrink: 0; border-radius: 50%; background: var(--warning); }  /* as a changed form's "Unsaved" */
body:has(.todo-send-bar:not([hidden])) #messages { bottom: 80px; }
@media (max-width: 720px) {
  .todo-send-bar { bottom: calc(72px + env(safe-area-inset-bottom)); }  /* over the portal's bar of sections */
  .portal-page:has(.todo-send-bar:not([hidden])) #messages { bottom: 140px; }
}
.done-todo > summary { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-2-5); padding: var(--space-2-5) 0; list-style: none; cursor: pointer; border-top: 1px solid var(--border); }
.done-todo > summary::-webkit-details-marker { display: none; }
.done-todo:first-of-type > summary { border-top: 0; }
.done-todo-title { font-weight: 600; }
.done-todo[open] > summary .done-todo-title { color: var(--link); }

/* The overview: the to-dos still open */
.todo-overview li { display: grid; grid-template-columns: minmax(0, 1fr) auto auto; gap: var(--space-1-5) var(--space-4); align-items: center; padding: var(--space-3) 0; border-top: 1px solid var(--border); }
.todo-overview li:first-child { border-top: 0; }
.todo-overview-title { font-weight: 600; color: var(--text); overflow-wrap: anywhere; }
.todo-overview-title:hover { color: var(--link); }
@media (max-width: 720px) {
  .todo-overview li { grid-template-columns: minmax(0, 1fr) auto; }
  .todo-overview li .todo-progress { grid-column: 1; grid-row: 2; }
  .todo-overview li .btn { grid-column: 2; grid-row: 1 / 3; }
  .todo-progress progress { width: 70px; }
}

/* --- E-signature (signing/): the states in the lists, the firm's document page, the client's Sign page ----------- */
.badge.badge-sign { background: var(--purple-bg); color: var(--purple-text); }
.badge.badge-signed { background: var(--success-bg); color: var(--success-text); }
.badge.badge-declined { background: var(--error-bg); color: var(--danger); }
.chip.is-to_sign { border-color: var(--purple); color: var(--purple-text); }
.doc-signature { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-1-5); margin-top: var(--space-1); }
.kept-until { display: inline-flex; align-items: center; gap: var(--space-1); }
.kept-until .icon { width: 13px; height: 13px; }
.kept-notice { display: flex; gap: var(--space-2); align-items: flex-start; }
/* A notice with its icon before the words (signing's pages, deleting a client) */
.form-notice:has(> .icon) { display: flex; gap: var(--space-2); align-items: flex-start; }
.form-notice > .icon { flex-shrink: 0; margin-top: var(--space-0-5); color: var(--warning-text); }
.form-notice.is-danger > .icon { color: var(--danger); }
.signature-complete { display: flex; gap: var(--space-1-5); align-items: flex-start; margin: 0 0 var(--space-3); }
.signature-complete .icon { width: 16px; height: 16px; margin-top: var(--space-0-5); color: var(--success-text); }
.signature-list > li + li { margin-top: var(--space-3); padding-top: var(--space-3); border-top: 1px solid var(--border); }
.signature-head { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1-5) var(--space-2); }
.signature-signed { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1-5) var(--space-3); margin-top: var(--space-2); }
.signed-time-field { max-width: 260px; }
.signature-actions { margin-top: var(--space-2); }
.signature-trail { margin-top: var(--space-2); }
.signature-trail > summary { display: inline-block; cursor: pointer; }
.signature-trail table { margin-top: var(--space-1-5); font-size: var(--text-sm); }
.hashes code { font-size: var(--text-xs); overflow-wrap: anywhere; }
/* The Sign page, a phone's width first */
.sign-page { max-width: var(--width-form); }
.sign-page.has-document { max-width: var(--width-doc); }  /* the document is on the page: a document's width, as an invoice's */
.sign-page.has-document .sign-step:not(#read) > *, .sign-page.has-document .sign-decline > * { max-width: var(--width-form); }  /* the cards share the page's edges; their words keep a reading width */
.settings-form.ask-page { max-width: var(--width-doc); }  /* the document to mark is on the page: a document's width */
.ask-page .form { max-width: none; }
.ask-page .form > .field:not(.places-field), .ask-page .form > p, .ask-page .form > .toggle-row { max-width: var(--width-form); }  /* one right edge for its fields, its words and its switch; only the document is wider */

/* A PDF shown in the page, with the places to sign marked on it (static/js/pdf-places.js): the Sign page's step 1
   and the Ask page's "Where they sign". The pages are paper whatever the theme, so the marks keep their own colours:
   a highlighter's yellow for a place to fill in, the signature's ink once it shows what it will hold. */
.pdf-viewer[hidden] { display: none; }
.pdf-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1-5) var(--space-2); margin: var(--space-2) 0; }
.pdf-toolbar-end { display: inline-flex; flex-wrap: wrap; align-items: center; gap: var(--space-1-5); margin-left: auto; }
/* When the PDF can't be shown, what needs it goes: the toolbar, the frame, the field's own help, and the two fields
   that mean nothing without places (kept when one carries an error, so its message is never hidden). */
.pdf-viewer.is-failed .pdf-toolbar, .pdf-viewer.is-failed .pdf-pages, .pdf-viewer.is-failed .places-summary,
.pdf-viewer.is-failed > .helptext, .pdf-viewer.is-failed .places-save:not(.has-error), .pdf-viewer.is-failed > p:first-child,
.pdf-viewer:not(.is-ready) .pdf-toolbar { display: none; }
.pdf-pages {
  --pdf-zoom: 1; max-height: min(78vh, 900px); overflow: auto; padding: var(--space-2-5); border: 1px solid var(--border-strong);
  border-radius: var(--radius); background: var(--surface-3); overscroll-behavior-x: contain;
}
.pdf-pages:empty { display: none; }
.pdf-pages:focus-visible { outline-offset: 1px; }
.pdf-page { position: relative; width: calc(100% * var(--pdf-zoom)); background: #fff; box-shadow: var(--shadow-sm); }
.pdf-page > canvas { display: block; width: 100%; height: 100%; }
/* A page being drawn says so, once it has been at it for a moment: a page drawn at once shows no words, a scanned
   one can take many seconds (static/js/pdf-places.js: is-drawing while it's drawn, is-failed when it can't be).
   A page waiting out of view has no words: it isn't being drawn, and they'd be read out for it all the same.
   A sheet is often taller than the frame it scrolls in, so the words stay in the part of it that shows: 30% down
   the frame (above its middle, where a mark is brought), or at the sheet's top or bottom edge when that's all
   there is of it. Their line takes no room: the canvas goes back up over it. The sheet is white in either theme,
   so they keep one grey. The marks go over them. */
.pdf-page.is-drawing:not(.is-drawn)::before, .pdf-page.is-failed:not(.is-drawn)::before {
  content: "Drawing this page…"; position: sticky; top: 30%; display: block; height: 20px; padding: 0 8%;
  font-size: var(--text-sm); line-height: 20px; color: #5d6b82; text-align: center; opacity: 0;
}
.pdf-page.is-drawing:not(.is-drawn) > canvas, .pdf-page.is-failed:not(.is-drawn) > canvas { margin-top: -20px; }
.pdf-page.is-drawing:not(.is-drawn)::before { animation: pdf-page-words 0.2s linear 0.5s forwards; }
.pdf-page.is-failed:not(.is-drawn)::before { content: "This page couldn't be shown here."; opacity: 1; }
/* The client's Sign page in French (docs/french.md). */
.pdf-page.is-drawing:not(.is-drawn):lang(fr)::before { content: "Affichage de la page…"; }
.pdf-page.is-failed:not(.is-drawn):lang(fr)::before { content: "Cette page n’a pas pu s’afficher ici."; }
@keyframes pdf-page-words { to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .pdf-page.is-drawing:not(.is-drawn)::before { animation-duration: 0s; } }
.pdf-page-number { margin: var(--space-1) 0 var(--space-3); font-size: var(--text-xs); color: var(--muted); text-align: center; }
.pdf-page-number:last-child { margin-bottom: 0; }
.pdf-marks { position: absolute; inset: 0; }
.pdf-mark {
  position: absolute; display: flex; align-items: center; min-width: 0; container-type: size;
  border: 1.5px solid #b98500; border-radius: 3px; background: rgba(255, 214, 51, 0.5); color: #3d2c00;
  line-height: 1; white-space: nowrap;
}
/* The firm's own signature is a kind of mark: the states below (filled, someone else's) win over it. */
.pdf-mark.is-firm_signature { border-color: #2f6fb3; background: rgba(86, 156, 230, 0.32); color: #0d2f55; }
a.pdf-mark:hover { background: rgba(255, 214, 51, 0.75); text-decoration: none; }
.pdf-mark:focus-visible { outline: 2px solid #2458d6; outline-offset: 2px; }
.pdf-mark-text { padding-left: 3cqw; font-size: 0.7rem; font-weight: 600; overflow: hidden; }
.pdf-mark.is-filled { border-style: dashed; border-color: #7d8fc4; background: rgba(36, 88, 214, 0.06); color: #1c2330; }
a.pdf-mark.is-filled:hover { background: rgba(36, 88, 214, 0.12); }  /* its own tint, not the yellow of a place still to fill */
.pdf-mark.is-filled .pdf-mark-text { padding-left: 0; font-weight: 400; }
.pdf-mark.is-filled .pdf-mark-text.is-script { font-family: "Great Vibes", "Times New Roman", Times, serif; color: #14285a; line-height: 1.25; }
.pdf-mark.is-filled img { max-width: 100%; max-height: 100%; align-self: flex-end; }
.pdf-mark.is-other { border-style: dashed; border-color: #8a8f99; background: rgba(120, 126, 138, 0.18); color: #40454f; pointer-events: none; }
.pdf-mark.is-editable { cursor: move; touch-action: none; user-select: none; }
.pdf-mark.is-editable:focus, .pdf-mark.is-moving { outline: 2px solid #2458d6; outline-offset: 1px; z-index: 1; }
.pdf-mark-remove {
  position: absolute; top: -11px; right: -11px; display: none; width: 20px; height: 20px; padding: 0; border: 0;
  border-radius: 50%; background: #1c2330; color: #fff; font: 700 14px/20px var(--font); cursor: pointer;
}
.pdf-mark-resize {
  position: absolute; right: -6px; bottom: -6px; display: none; width: 12px; height: 12px; border: 2px solid #fff;
  border-radius: 50%; background: #2458d6; cursor: nwse-resize;
}
.pdf-mark.is-editable:hover > .pdf-mark-remove, .pdf-mark.is-editable:focus-within > .pdf-mark-remove,
.pdf-mark.is-editable:hover > .pdf-mark-resize, .pdf-mark.is-editable:focus-within > .pdf-mark-resize { display: block; }
.pdf-viewer.is-placing .pdf-page { cursor: crosshair; }
.places-title { font-weight: 600; font-size: var(--text-sm); color: var(--text-2); }
.places-title .muted { font-weight: 400; }
.places-who { display: inline-flex; align-items: center; gap: var(--space-1-5); }
.places-who[hidden], .pdf-toolbar .btn[hidden] { display: none; }
.form .field .places-who select { width: auto; }
.places-kinds { display: inline-flex; flex-wrap: wrap; gap: var(--space-1-5); }
@media (max-width: 720px) {  /* a phone: what goes on the page is one row that scrolls sideways, the zoom at its end, so the page stays in sight */
  .places-kinds { flex: 1 1 0; flex-wrap: nowrap; min-width: 0; overflow-x: auto; scrollbar-width: none; padding: var(--space-1); margin: calc(-1 * var(--space-1)) 0 calc(-1 * var(--space-1)) calc(-1 * var(--space-1)); }  /* room inside the scroll for a focus ring */
  .places-kinds > .btn { flex: none; }
  .pdf-toolbar > .places-who { flex-basis: 100%; }  /* whose places: a line of its own over them */
  .pdf-toolbar-end { flex-wrap: nowrap; }
}
.places-kinds .btn[aria-pressed="true"] { border-color: var(--primary); background: var(--primary-soft); color: var(--info-text); }
.places-field > p { margin: var(--space-1-5) 0 0; }  /* every line under the document, one gap */
.places-save { display: flex; flex-direction: column; gap: var(--space-1); margin-top: var(--space-3); }
.form .field .places-save input, .form .field .places-save select { max-width: 320px; }
.letter-doc .pdf-viewer { margin-bottom: var(--space-1); }
span.pdf-mark { pointer-events: none; }
/* A team member's signature picture, on their page: on paper, whatever the theme. */
.member-signature { display: block; max-width: min(100%, 320px); max-height: 110px; padding: var(--space-2) var(--space-3); border: 1px solid var(--border); border-radius: var(--radius); background: #fff; }
.member-signature-form { margin-top: var(--space-2-5); }
@media (pointer: coarse) {
  /* For a finger: the x on the corner across from the resize handle, so on a short mark one never lies on the other;
     each takes the taps around it, away from the mark */
  .pdf-mark-remove { top: -15px; right: auto; left: -15px; width: 28px; height: 28px; font-size: 18px; line-height: 28px; }
  .pdf-mark-resize { right: -10px; bottom: -10px; width: 20px; height: 20px; }
  .pdf-mark-remove::after { content: ""; position: absolute; inset: -16px 0 0 -16px; }
  .pdf-mark-resize::after { content: ""; position: absolute; inset: 0 -26px -26px 0; }
}
.sign-kicker { margin: var(--space-1-5) 0 0; font-size: var(--text-xs); font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase; color: var(--muted); }
.sign-steps { list-style: none; margin: 0; padding: 0; }
.sign-step h2 { display: flex; align-items: center; gap: var(--space-2-5); font-size: var(--text-lg); }
.step-number {
  display: inline-flex; align-items: center; justify-content: center; width: 26px; height: 26px; flex-shrink: 0;
  border-radius: 50%; background: var(--primary); color: var(--on-primary); font-size: var(--text-sm); font-weight: 700;
}
.sign-step.is-done .step-number { background: var(--success-text); color: var(--surface); }
.sign-open { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); }
.sign-open .icon { width: 14px; height: 14px; }
.sign-open a:not(.btn) { display: inline-flex; align-items: center; gap: var(--space-1-5); }  /* "Open it as a PDF", its arrow off the words */
.sign-unopened { display: flex; gap: var(--space-1-5); align-items: flex-start; }
.sign-unopened[hidden] { display: none; }  /* taken away once the document is shown or opened */
.sign-check { align-items: flex-start; white-space: normal; font-size: var(--text-md); }
.sign-check input { margin-top: 3px; flex-shrink: 0; }
.signature-draw { margin-bottom: var(--space-4); }
.signature-draw[hidden] { display: none; }
/* "Draw it too" and "Decline to sign" open what's under them: each has an arrow that turns, and the first, which
   adds to the signature, is in the link colour with its pen. Declining stays quiet. */
.signature-draw > summary, .sign-decline > summary { display: inline-flex; align-items: center; gap: var(--space-1-5); cursor: pointer; }
.signature-draw > summary { margin-bottom: var(--space-1-5); color: var(--link); }
.signature-draw > summary .icon, .sign-decline > summary .icon { width: 14px; height: 14px; }
.signature-draw > summary .chevron, .sign-decline > summary .chevron { width: 16px; height: 16px; transition: transform 0.15s; }
.signature-draw[open] > summary .chevron, .sign-decline[open] > summary .chevron { transform: rotate(180deg); }
.signature-canvas {
  display: block; width: 100%; height: 180px; margin: var(--space-1-5) 0 var(--space-2); border: 1px dashed var(--border-strong, var(--border));
  border-radius: var(--radius); background: #fff; touch-action: none; cursor: crosshair;
}
.signature-preview { display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-0-5); margin: 0 0 var(--space-3); padding: var(--space-3) var(--space-4); border-radius: var(--radius); background: var(--bg); }
.signature-preview img { max-width: 100%; max-height: 90px; background: #fff; border-radius: var(--radius-sm); }
/* The typed signature as the signed copy sets it (signing/pdf.py, script_font): Great Vibes, the same file
   (signing/static/signing/fonts/README.md). The browser loads it only on a page that shows a typed signature. */
@font-face { font-family: "Great Vibes"; src: url("../signing/fonts/GreatVibes-Regular.d1358c495233.ttf") format("truetype"); font-display: swap; }
.signature-typed { font-family: "Great Vibes", "Times New Roman", Times, serif; font-style: normal; font-size: 1.9rem; line-height: 1.3; color: #14285a; }
@media screen { [data-theme="dark"] .signature-typed { color: #b9c8f5; } }
@media screen and (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .signature-typed { color: #b9c8f5; } }
.sign-code-form input[name="code"] { max-width: 180px; font-size: 1.3rem; letter-spacing: 4px; }
.sign-resend { margin-top: var(--space-2-5); }
.sign-decline[open] > summary { margin-bottom: var(--space-2); }
.sign-result h2 { display: flex; align-items: center; gap: var(--space-2); }
.sign-result.is-signed h2 .icon { color: var(--success-text); }
.sign-result.is-declined h2 .icon { color: var(--danger); }
.portal-signatures h3 .icon { color: var(--purple); }
.portal-signatures + .portal-approvals { margin-top: var(--space-3); padding-top: var(--space-3); border-top: 1px solid var(--border); }

/* --- Emails ---------------------------------------------------------------------------------------------- */
/* "Email the client about it" only means something once the document is shared */
.form:has(.visibility-field input[value="firm"]:checked) .shared-only { display: none; }

/* Shared documents, or items sent back, that the client hasn't been emailed about yet */
.email-pending { border-color: var(--info-border); }
.email-pending-head { display: flex; align-items: flex-start; gap: var(--space-3); }
.email-pending-head h2 { margin: 0 0 var(--space-0-5); font-size: var(--text-lg); }
.email-pending-head p { margin: 0; }
.email-pending-icon {
  display: inline-grid; place-items: center; width: 34px; height: 34px; flex-shrink: 0; border-radius: 50%;
  background: var(--info-bg); color: var(--info-text);
}
.email-pending-icon .icon { width: 17px; height: 17px; }
.email-pending-list { margin: var(--space-2-5) 0 var(--space-1-5) 46px; padding: 0; list-style: none; }
.email-pending-list li { padding: var(--space-0-5) 0; overflow-wrap: anywhere; }
.email-pending-form { margin-left: 46px; }
.email-pending-form .actions { margin-top: var(--space-2); }
.email-note > summary { display: inline-block; list-style: none; color: var(--link); }
.email-note > summary::-webkit-details-marker { display: none; }
.email-note textarea { display: block; width: 100%; max-width: 620px; margin-top: var(--space-1-5); }
@media (max-width: 720px) { .email-pending-list, .email-pending-form { margin-left: 0; } }

/* How emails go out (settings, the email log) */
.email-setup-notice, .email-failed-notice { display: flex; align-items: flex-start; gap: var(--space-2); margin-bottom: var(--space-4); }
.email-setup-notice .icon, .email-failed-notice .icon { margin-top: var(--space-0-5); flex-shrink: 0; }
.email-setup-notice code { font-size: 0.85em; }
.reminder-fields { min-width: 0; margin: var(--space-1) 0 var(--space-3); padding: 0; border: 0; }
.reminder-fields legend { margin-bottom: var(--space-1-5); padding: 0; }
.reminder-fields .field-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 0 var(--space-4); align-items: end; }
.reminder-fields p { margin: 0; }

/* The email log */
.email-table td { vertical-align: top; }
.email-table tr.is-failed td:first-child { box-shadow: inset 3px 0 0 var(--danger); }
.email-to, .email-subject { overflow-wrap: anywhere; }
/* On a phone the log scrolls sideways (.table-wrap) rather than break a name letter by letter */
.email-table .email-to { min-width: 120px; }
.email-table .email-subject { min-width: 180px; }
.email-subject a { color: var(--text); }
.email-subject a:hover { color: var(--link); }
.email-error { color: var(--danger); overflow-wrap: anywhere; }
.email-error.small, .email-table .email-error { max-width: 320px; margin-top: var(--space-1); }
.email-table .email-error { min-width: 200px; }

/* A to-do's emails: sending it with an email, when the next reminder goes, what was sent */
.todo-send-form { display: inline-flex; align-items: center; gap: var(--space-2-5); }
.todo-form-emails { margin: var(--space-1) 0 var(--space-2); }
.todo-reminders { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-2); margin-top: var(--space-3); color: var(--muted); }
.todo-reminders > .icon { width: 14px; height: 14px; flex-shrink: 0; }
.todo-reminders form { display: inline; }
.todo-tasks { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-2-5); margin-top: var(--space-3); }
.todo-tasks > .icon { width: 14px; height: 14px; flex-shrink: 0; color: var(--muted); }
.email-history { margin: 0; padding: 0; list-style: none; }
.email-history li { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-0-5) var(--space-3); padding: var(--space-2) 0; border-bottom: 1px solid var(--border); }
.email-history li:last-child { border-bottom: 0; }
.email-history-when { min-width: 110px; }
.invite-email-form { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1-5) var(--space-2-5); margin-bottom: var(--space-2-5); }

/* --- Reminders ------------------------------------------------------------------------------------------- */
/* A client's reminders, on its portal page */
.reminders-summary { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-1) var(--space-3); margin-bottom: var(--space-2); }
.reminders-summary p { margin: 0; }
.reminders-setup { margin-top: var(--space-3); }
.reminders-setup > summary { display: inline-flex; list-style: none; }
.reminders-setup > summary::-webkit-details-marker { display: none; }
.reminders-setup[open] > summary { margin-bottom: var(--space-3); }
.reminders-form { max-width: 780px; }
.reminders-form fieldset { min-width: 0; margin: 0 0 var(--space-3); padding: 0; border: 0; }
.reminders-form legend { margin-bottom: var(--space-1-5); padding: 0; }
.reminders-form .field-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 0 var(--space-4); align-items: end; }
.recipients-field label { display: flex; align-items: center; gap: var(--space-2); padding: 3px 0; font-weight: 400; overflow-wrap: anywhere; }
.recipients-field input[type="checkbox"] { flex-shrink: 0; }
.reminders-past { margin-top: var(--space-2-5); }
.reminders-past > summary { display: inline-block; list-style: none; color: var(--link); }
.reminders-past > summary::-webkit-details-marker { display: none; }
.reminders-past[open] > summary { margin-bottom: var(--space-2); }
.reminders-clients { margin-top: var(--space-3); }
.reminder-summary p { margin: var(--space-0-5) 0 0; }

/* Lists of reminders */
.reminder-table td { vertical-align: middle; }  /* its words stand on the centre line of the row's buttons */
.reminder-table tr.needs-amount td:first-child { box-shadow: inset 3px 0 0 var(--warning); }
.card:not(.table-wrap) .reminder-table tr.needs-amount td:first-child { padding-left: var(--space-2-5); }  /* off the bar, as the requests' */
.reminder-about { min-width: 180px; }  /* on a phone the table scrolls sideways rather than break a word letter by letter */
.reminder-about a { font-weight: 600; color: var(--text); overflow-wrap: break-word; }
.reminder-about a:hover { color: var(--link); }
.reminder-table tr.is-skipped .reminder-about a { color: var(--muted); text-decoration: line-through; }
.reminder-about .icon { width: 12px; height: 12px; margin-right: 3px; color: var(--success-text); vertical-align: -1px; }

/* One reminder: the form, and what they'll read */
.reminder-layout { display: grid; grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr); gap: var(--stack-gap); align-items: start; }
.reminder-layout > .card { margin-bottom: 0; }  /* the grid's gap parts the cards, side by side or stacked */
@media (max-width: 1100px) { .reminder-layout { grid-template-columns: minmax(0, 1fr); } }
.reminder-form textarea, .template-grid textarea { width: 100%; font-family: inherit; }
.fields-help { margin: -4px 0 var(--space-3); }
.fields-help > summary { display: inline-block; list-style: none; color: var(--link); }
.fields-help > summary::-webkit-details-marker { display: none; }
.fields-list { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: var(--space-1) var(--space-3); margin: var(--space-2) 0; font-size: var(--text-sm); }
.fields-list dt, .fields-list dd { margin: 0; }
.fields-list dd { color: var(--muted); }
.reminder-preview h2 { margin: 0 0 var(--space-1); font-size: var(--text-lg); }
.preview-subject { margin: var(--space-3) 0 var(--space-2); font-weight: 700; overflow-wrap: anywhere; }
.preview-body { padding: var(--space-3) var(--space-4); border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--bg); overflow-wrap: anywhere; }
.preview-body p { margin: 0 0 var(--space-2-5); }
.preview-body p:last-child { margin-bottom: 0; }
.preview-facts { display: grid; grid-template-columns: max-content 1fr; gap: var(--space-0-5) var(--space-3); margin: var(--space-2-5) 0 0; padding: var(--space-2-5) var(--space-4); border-radius: var(--radius-md); background: var(--bg); }
.preview-facts dt { color: var(--muted); }
.preview-facts dd { margin: 0; font-weight: 600; }

/* The templates (settings) */
.template-grid { display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr); gap: var(--space-4); }
.template-grid + .actions { margin-top: var(--space-4); }  /* Settings, Reminders: the Save in the last card, a field's gap over it */
@media (max-width: 899px) { .template-grid { grid-template-columns: minmax(0, 1fr); } }
.template-preview { align-self: start; padding: var(--space-3) var(--space-4); border: 1px dashed var(--border); border-radius: var(--radius-md); background: var(--bg); font-size: var(--text-base); overflow-wrap: anywhere; }
.template-preview p { margin: 0 0 var(--space-2); }
.template-preview p:last-child { margin-bottom: 0; }

/* Two-factor sign-in: setup steps, the QR code, recovery codes */
.setup-steps { padding-left: var(--space-5); margin: var(--space-4) 0; display: grid; gap: var(--space-3); }
.qr { margin: var(--space-3) auto; padding: var(--space-2); background: #fff; border-radius: var(--radius); display: block; width: fit-content; line-height: 0; }
.qr svg { width: 232px; height: 232px; display: block; }
.secret-key { margin-top: var(--space-1-5); font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: var(--text-md); letter-spacing: 0.04em; color: var(--text); word-break: break-all; }
.recovery-codes { list-style: none; padding: var(--space-4); margin: var(--space-4) 0; display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--space-2) var(--space-6); background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius); }
.recovery-codes code { font-size: var(--text-lg); letter-spacing: 0.06em; }
@media print { .auth-brand, .actions, .messages { display: none; } }

/* --- Home ------------------------------------------------------------------------------------------------ */
/* One surface in two panes: the work, and beside it the context that's otherwise a card away (what clients sent,
   money, the team). A hairline parts the panes; a heading and space part the sections; nothing else has a box. */
.today-frame {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(280px, 330px); align-items: stretch;
  border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface);
}
.today-main { min-width: 0; padding: var(--space-5); }  /* a card's inset, the same in both panes */
.today-panel { min-width: 0; padding: var(--space-2-5) var(--space-5) var(--space-1-5); border-left: 1px solid var(--border); }  /* with its sections' own 10px and 14px, 20px over the first heading and under the last line */
.today-section + .today-section { margin-top: var(--space-7); }
.today-section .section-header, .panel-section .section-header { margin-bottom: var(--space-1-5); }
.today-section .section-header h2 { display: flex; align-items: center; gap: var(--space-2); }
.panel-section { padding: var(--space-2-5) 0 var(--space-3); }
.panel-section + .panel-section { border-top: 1px solid var(--border); padding-top: var(--space-4); }
.panel-section h2 { font-size: var(--text-md); }
.today-links { display: flex; flex-wrap: wrap; gap: var(--space-1) var(--space-3); }
.today-more { margin: var(--space-2) 0 0; }
.count.is-alert { background: var(--danger-bg); color: var(--danger); }
.count.is-waiting { background: var(--warning-bg); color: var(--warning-text); }  /* the portal: what waits on the reader, with nothing late */
/* The four numbers at the top: a line of figures, each a link to its list (no tiles) */
.figures { display: flex; flex-wrap: wrap; gap: var(--space-2) 44px; margin: 0 0 var(--stack-gap); }
.figure { display: flex; flex-direction: column; color: var(--text); }
.figure:hover { text-decoration: none; }
.figure:hover .figure-name { color: var(--link); }
.figure-number { font-size: var(--text-2xl); font-weight: 650; letter-spacing: -0.02em; line-height: 1.2; font-variant-numeric: tabular-nums; }
.figure-name { color: var(--muted); font-size: var(--text-sm); }
.figure.is-alert .figure-number { color: var(--danger); }
.figure.is-new .figure-number { color: var(--link); }
@media (max-width: 1100px) {
  .today-frame { grid-template-columns: minmax(0, 1fr); }
  .today-panel { border-left: 0; border-top: 1px solid var(--border); }
}
@media (max-width: 720px) {
  .today-main { padding: var(--space-4); }
  .today-panel { padding: var(--space-2) var(--space-4) var(--space-4); }
  .figures { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-3); }
}

/* The week strip over "Due in the next 7 days": seven quiet days, each with what's due on it; a day narrows the list */
.week-strip { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: var(--space-1-5); margin: var(--space-1) 0 var(--space-2-5); padding: 0; list-style: none; }
.week-day {
  display: flex; flex-direction: column; align-items: center; gap: 1px; padding: var(--space-2) var(--space-1) var(--space-1-5);
  border: 1px solid transparent; border-radius: var(--radius); background: var(--surface-2); color: var(--text-2);
}
.week-day:hover { background: var(--surface-3); text-decoration: none; }
.week-day[aria-current] { border-color: var(--primary); background: var(--primary-soft); }
.week-name { font-size: var(--text-xs); font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; color: var(--muted); }
.week-num { font-size: var(--text-lg); font-weight: 650; line-height: 1.3; color: var(--text); font-variant-numeric: tabular-nums; }
.week-day.is-today .week-num { color: var(--link); }
.week-day.is-weekend:not(.is-today) .week-num { color: var(--muted); font-weight: 500; }
.week-count { min-width: 22px; min-height: 18px; padding: 0 var(--space-1-5); border-radius: var(--radius-full); color: var(--text-2); font-size: var(--text-xs); font-weight: 600; line-height: 18px; text-align: center; }
.week-count:not(:empty) { background: var(--surface); box-shadow: inset 0 0 0 1px var(--border); }
@media (max-width: 560px) { .week-strip { gap: 3px; } .week-name { font-size: 0.625rem; letter-spacing: 0; } }

/* Deadlines and tasks in one list. A list's rows are parted by space, not lines (a line only parts panes, sections
   and a data table's rows); the pointer lights the row it is on. */
.work-rows { list-style: none; margin: 0 -10px; padding: 0; }
.work-row {
  display: grid; grid-template-columns: 126px minmax(0, 1fr) auto; gap: var(--space-1) var(--space-3); align-items: start;
  padding: var(--space-2) var(--space-2-5); border-radius: var(--radius-md);
}
.work-row:hover { background: var(--surface-2); }
.work-when { display: flex; flex-direction: column; line-height: 1.35; white-space: nowrap; }
.work-line { display: flex; align-items: center; gap: var(--space-2); }
.work-title { font-weight: 600; color: var(--text); overflow-wrap: anywhere; }
.work-title:hover { color: var(--link); }
.work-for a { color: var(--muted); }
.work-for a:hover { color: var(--link); }
.work-tags { display: flex; flex-wrap: wrap; gap: var(--space-1); justify-content: flex-end; align-items: center; padding-top: 1px; }
@media (max-width: 560px) {
  .work-row { grid-template-columns: 116px minmax(0, 1fr); }
  .work-tags { grid-column: 2; justify-content: flex-start; }
}

/* A number and what it counts, each a link to the list behind it; the pointer lights the row */
.fact-list { list-style: none; margin: 0 -8px; padding: 0; }
.fact-list a { display: flex; align-items: baseline; gap: var(--space-2); padding: var(--space-1) var(--space-2); border-radius: var(--radius-md); color: var(--text-2); }
.fact-list a:hover { background: var(--surface-2); color: var(--text); text-decoration: none; }
.fact-number { min-width: 1.8em; font-weight: 650; color: var(--text); font-variant-numeric: tabular-nums; white-space: nowrap; }
.fact-number.is-alert { color: var(--danger); }
.fact-number.is-new { color: var(--link); }
.fact-list + .plain-list { margin-top: var(--space-2); padding-top: var(--space-2); border-top: 1px solid var(--border); }
.activity-list { list-style: none; margin: var(--space-3) 0 0; padding: var(--space-3) 0 0; border-top: 1px solid var(--border); display: grid; gap: var(--space-3); }
.activity-list li { display: flex; gap: var(--space-2-5); min-width: 0; }
.activity-list li > div { min-width: 0; overflow-wrap: anywhere; }
.activity-icon {
  display: inline-grid; place-items: center; width: 28px; height: 28px; flex-shrink: 0; border-radius: 50%;
  background: var(--primary-soft); color: var(--info-text);
}
.activity-icon .icon { width: 14px; height: 14px; }
.activity-list a { color: var(--text); }
.activity-list a strong { font-weight: 600; }
.empty.is-quiet { flex-direction: row; justify-content: flex-start; align-items: flex-start; gap: var(--space-2); padding: 0; text-align: left; }  /* a sentence in its card like any other: at the card's edge, the icon starting its first line */
.empty.is-quiet > .icon { flex: none; width: 18px; height: 18px; margin: var(--space-0-5) 0 0; color: var(--muted); }
.empty.is-quiet.is-done > .icon { color: var(--success); }  /* all done: the only green one */

/* Getting started on Home (hello/started.py): a new firm's first steps, a bar that fills as they're done */
.getting-started { margin-bottom: var(--space-5); }
.getting-started .section-header { align-items: flex-start; flex-wrap: nowrap; margin-bottom: 0; }
.getting-started .section-header p { margin: var(--space-0-5) 0 0; }
.start-progress { display: flex; gap: var(--space-1); margin: var(--space-3) 0 var(--space-1); }
.start-progress span { flex: 1; height: 6px; border-radius: var(--radius-full); background: var(--border); }
.start-progress .is-done { background: var(--success); }
.start-steps { list-style: none; margin: var(--space-2) 0 0; padding: 0; }
.start-step { display: grid; grid-template-columns: 24px minmax(0, 1fr) auto; gap: var(--space-1-5) var(--space-3); align-items: start; padding: var(--space-3) 0; border-top: 1px solid var(--border); }
.start-step:first-child { border-top: 0; }
.start-step.is-done { padding: var(--space-2) 0; }
.start-text p { margin: var(--space-0-5) 0 0; max-width: 60ch; }
.start-title { font-weight: 600; color: var(--text); }
.start-step.is-done .start-title { font-weight: 500; color: var(--muted); }
.start-actions { display: flex; flex-direction: column; align-items: flex-end; gap: var(--space-1); }
.start-actions a:not(.btn) { font-size: var(--text-sm); }
@media (max-width: 720px) {
  .start-step { grid-template-columns: 24px minmax(0, 1fr); }
  .start-actions { grid-column: 2; flex-direction: row; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-4); }
}

/* A sample firm (hello/demo.py): a banner on every page, and the offers to make one */
.sample-banner { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); margin: 0 0 var(--space-4); padding: var(--space-2-5) var(--space-4); border: 1px solid var(--info-border); border-radius: var(--radius); background: var(--info-bg); color: var(--text); }
.sample-banner > .icon { flex: none; color: var(--info-text); }
.sample-banner p { flex: 1 1 320px; margin: 0; font-size: var(--text-sm); }
.sample-banner-actions { display: flex; flex-wrap: wrap; gap: var(--space-1-5); }
/* Firmdesk's notice (ops/notices.py): planned maintenance, or a problem being worked on */
.service-notice { display: flex; align-items: flex-start; gap: var(--space-2-5); margin: 0 0 var(--space-4); padding: var(--space-2-5) var(--space-4); border: 1px solid var(--info-border); border-radius: var(--radius); background: var(--info-bg); color: var(--text); }
.service-notice > .icon { flex: none; margin-top: var(--space-0-5); color: var(--info-text); }
.service-notice p { margin: 0; font-size: var(--text-sm); }
.service-notice.is-problem { border-color: var(--warning-border-soft); background: var(--warning-bg); }
.service-notice.is-problem > .icon { color: var(--warning-text); }
.sample-offer { margin: var(--space-4) 0 0; padding-top: var(--space-4); border-top: 1px solid var(--border); }
.sample-offer p { margin: 0 0 var(--space-2); }
.start-sample { margin: var(--space-3) 0 0; padding-top: var(--space-3); border-top: 1px solid var(--border); }
.start-sample .link-button { margin: 0 var(--space-0-5); }
.start-call { display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-2) var(--space-2-5); margin: var(--space-3) 0 0; padding-top: var(--space-3); border-top: 1px solid var(--border); }
.start-came { margin: var(--space-1) 0 var(--space-1); padding: 0 0 var(--space-3); border-top: 0; border-bottom: 1px solid var(--border); }
.start-came:last-child { padding-bottom: 0; border-bottom: 0; }
.start-call > .icon { flex-shrink: 0; color: var(--muted); }
.start-call > span { flex: 1 1 14rem; }

.firm-setup #id_team_size { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 0 var(--space-3); }
.signed-in-as { margin: var(--space-4) 0 0; }
.link-button { background: none; border: 0; padding: 0; font: inherit; color: var(--link); cursor: pointer; }
.link-button:hover { text-decoration: underline; }
@media (max-width: 899px), (pointer: coarse) {
  .link-button { min-height: var(--touch-target); }
}

/* --- Settings: data; deleting ---------------------------------------------------------------------------- */
.danger-zone { border-color: var(--danger-border); }
.danger-zone .card-heading { color: var(--danger); }
.deletion-banner {
  display: flex; align-items: flex-start; gap: var(--space-2-5); margin: 0 0 var(--space-4); padding: var(--space-2-5) var(--space-4); border: 1px solid var(--danger-border);
  border-radius: var(--radius); background: var(--danger-bg); color: var(--text);
}
.deletion-banner .icon { margin-top: var(--space-0-5); color: var(--danger); }
.export-table td { vertical-align: middle; }
.card > .actions + .table-scroll { margin-top: var(--space-4); }  /* Export everything: its button, then the exports, a field's gap apart */
.fact-list.is-plain { margin-inline: 0; }  /* no row lights up under the pointer, so the list keeps the card's edges */
.fact-list.is-plain li { display: flex; align-items: baseline; gap: var(--space-2); padding: var(--space-2) 0; }

/* --- Plan and billing (the plans app): the banner, the plans to choose from, the trial's countdown ----------------- */
.plan-banner {
  display: flex; align-items: flex-start; gap: var(--space-2-5); margin: 0 0 var(--space-4); padding: var(--space-2-5) var(--space-4); border: 1px solid var(--warning-border-soft);
  border-radius: var(--radius); background: var(--warning-bg); color: var(--text);
}
.plan-banner .icon { margin-top: var(--space-0-5); color: var(--warning-text); }
.plan-banner.is-info { border-color: var(--info-border); background: var(--info-bg); }
.plan-banner.is-info .icon { color: var(--info-text); }
.plan-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: var(--space-3); list-style: none; margin: var(--space-3) 0 0; padding: 0; }
.plan-card { display: flex; flex-direction: column; gap: var(--space-2); margin: 0; padding: var(--space-4) var(--space-5); }
.plan-card h3 { margin: 0; font-size: var(--text-md); }
.plan-card p { margin: 0; }
.plan-price { font-size: var(--text-xl); font-weight: 600; }
.plan-card form, .plan-card-actions { display: flex; flex-direction: column; gap: var(--space-1-5); margin-top: auto; }
.plan-card.is-current { border-color: var(--primary); }
.plan-card .btn.is-static { cursor: default; color: var(--muted); background: var(--surface-3); border-color: transparent; }
.storage-meter { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; margin: var(--space-1) 0 var(--space-2); }
.storage-meter progress { width: min(260px, 100%); height: 10px; accent-color: var(--primary); }
.storage-meter progress.is-near { accent-color: var(--warning-border); }
.storage-meter progress.is-full { accent-color: var(--danger); }
.storage-form .field input[type="number"] { max-width: 120px; }
.storage-notice { display: flex; align-items: flex-start; gap: var(--space-2); margin-bottom: var(--space-4); }
.storage-notice .icon { margin-top: var(--space-0-5); }
tr.is-flagged td:first-child { box-shadow: inset 3px 0 0 var(--warning); }
.trial-countdown {
  margin: auto 0 var(--space-2); padding: var(--space-2) var(--space-2-5); border: 1px solid var(--sidebar-border); border-radius: var(--radius);
  color: var(--sidebar-text); font-size: var(--text-sm);
}
.trial-countdown a { color: inherit; font-weight: 600; }
.trial-countdown + .help-menu { margin-top: 0; }
.sidebar-hidden .trial-countdown { display: none; }

/* --- Settings: the activity log ---------------------------------------------------------------------------- */
.settings-body.is-wide { max-width: none; }
.settings-body .section-header .section-intro { margin: 0; }
.activity-filters select { flex: 0 1 180px; min-width: 0; }  /* one width each, so the filters wrap into even rows */
.activity-filters .activity-dates { display: none; gap: var(--space-2); }
.activity-filters:has(select[name="period"] option[value="custom"]:checked) .activity-dates { display: inline-flex; }
.activity-table td { vertical-align: top; }
.activity-table tr.is-alert td:first-child { box-shadow: inset 3px 0 0 var(--danger); }
.activity-what { overflow-wrap: anywhere; min-width: 220px; }

/* --- Settings: automations (automations/rules.html, rule_form.html) ------------------------------------------ */
.rule-list { list-style: none; margin: 0 0 var(--stack-gap); padding: 0; }  /* a card like the others: the stack's gap under it */
.card.rule-list { padding: var(--space-1) var(--space-5); }
.rule-row { display: flex; align-items: flex-start; gap: var(--space-3); padding: var(--space-3) 0; }
.rule-row + .rule-row { border-top: 1px solid var(--border); }
.rule-switch { display: flex; align-items: center; gap: var(--space-1-5); margin: 1px 0 0; }
.rule-text { flex: 1; min-width: 0; }
.rule-name { font-weight: 600; }
.rule-text p { margin: var(--space-0-5) 0 0; overflow-wrap: anywhere; }
.rule-row.is-off .rule-sentence { color: var(--muted); }
.rule-suggestions .rule-list { margin: 0; }
.runs-heading { display: flex; align-items: center; gap: var(--space-0-5); margin: var(--space-2) 0; }
.runs-heading h3 { margin: 0; }
.run-table td { vertical-align: top; }
.run-about, .run-note { overflow-wrap: anywhere; min-width: 180px; }
.run-what, .run-client { margin-top: var(--space-0-5); font-size: var(--text-sm); }  /* shown whatever the table's density */
.run-table tr.is-failed td:first-child { box-shadow: inset 3px 0 0 var(--danger); }
.badge.badge-run-done { background: var(--success-bg); color: var(--success-text); }
.badge.badge-run-scheduled, .badge.badge-run-running { background: var(--info-bg); color: var(--info-text); }
.badge.badge-run-skipped { background: var(--surface-3); color: var(--muted); }
.badge.badge-run-failed { background: var(--error-bg); color: var(--danger); }
/* A fieldset is spaced like a field (16px under it); what it holds adds nothing at its ends: the grid parts its own
   fields, the last one keeps no margin, and the words under a legend start at the legend's gap */
.rule-form fieldset { min-width: 0; margin: 0 0 var(--space-4); padding: 0; border: 0; }
.rule-form legend { margin-bottom: var(--space-1-5); padding: 0; font-weight: 600; }
.rule-form legend + p { margin-top: 0; }
.rule-form fieldset .form-grid { row-gap: var(--space-4); }
.rule-form fieldset .form-grid > .field { margin-bottom: 0; }
.rule-form .action-fields { padding: var(--space-3) var(--space-4); border: 1px solid var(--border); border-radius: var(--radius); }
.rule-form .action-fields > :last-child { margin-bottom: 0; }
.js .rule-form .action-fields:not(.is-chosen), .js .rule-form .task-only:not(.is-shown) { display: none; }
.rule-form textarea { width: 100%; font-family: inherit; }
.rule-wait input { max-width: 120px; }

/* --- Engagement letters (letters/): the states, a letter as its client reads it, its page and its form ------------ */
.badge.badge-letter-sent { background: var(--purple-bg); color: var(--purple-text); }  /* waiting on the client */
.badge.badge-letter-signed { background: var(--success-bg); color: var(--success-text); }
.badge.badge-letter-declined { background: var(--error-bg); color: var(--danger); }
.badge.badge-letter-withdrawn, .badge.badge-letter-expired { background: var(--surface-3); color: var(--muted); }
.letter-plan p { margin: 0 0 var(--space-2); }
.letter-plan p:last-child { margin: 0; }
.letter-page { display: grid; grid-template-columns: minmax(0, 1fr) minmax(240px, 300px); gap: 0 var(--space-5); align-items: start; max-width: 1180px; }
@media (max-width: 1100px) { .letter-page { grid-template-columns: minmax(0, 1fr); } }
/* The letter as words is set in from the card's edge like paper; its PDF has the card's own padding, the zoom
   buttons at the top of it and the pages at the edges the side cards' words have */
.letter-doc { max-width: var(--width-doc); padding: var(--space-8) var(--space-10); }
.letter-doc:has(> .pdf-viewer:not(.is-failed)) { padding: var(--space-5); }
.letter-doc .pdf-toolbar { margin-top: 0; }
@media (max-width: 720px) { .letter-doc { padding: var(--space-5); } }
.letter-title { margin: 0 0 var(--space-3); font-size: 1.35rem; }
.letter-preview-note { display: flex; align-items: center; gap: var(--space-1-5); margin: 0 0 var(--space-3); }
.letter-body { line-height: 1.6; overflow-wrap: anywhere; }
.letter-body p { margin: 0 0 var(--space-3); }
.letter-body ul { margin: 0 0 var(--space-3); padding-left: 1.4em; }
.letter-body li { margin: 0 0 var(--space-1); }
.letter-heading { margin: var(--space-5) 0 var(--space-1-5); font-size: 1rem; }
.letter-fees { width: 100%; margin: var(--space-1) 0 var(--space-1-5); border-collapse: collapse; }
.letter-fees th, .letter-fees td { padding: var(--space-1-5) var(--space-2) var(--space-1-5) 0; border-bottom: 1px solid var(--border); text-align: left; vertical-align: top; }
.letter-fees .num { text-align: right; padding-right: 0; }
.letter-fees tfoot th, .letter-fees tfoot td { border-bottom: 0; vertical-align: baseline; }  /* a total a frequency: no rule between them (the total row is every table's, under Tables) */
.letter-fee-notes { display: block; }
.letter-fee-discount td:first-child { padding-left: var(--space-4); }
.letter-message { margin-top: var(--space-4); padding: var(--space-2) var(--space-3); border-radius: var(--radius-md); background: var(--bg); }
/* What happened and when: the dates are one column and the words another, so a second line stays under its words.
   A line's words are bare text after the date (one cell): wrap them in a span if a link or bold ever goes in.
   The facts under it (Who signs…) have the same label column and gaps, so all the card's words start at one edge. */
.letter-history, .letter-facts { display: grid; grid-template-columns: 7rem minmax(0, 1fr); gap: var(--space-1-5) var(--space-3); }
.letter-history { margin: 0 0 var(--space-3); }
.letter-history li { display: grid; grid-template-columns: subgrid; grid-column: 1 / -1; padding: 0; }
.letter-history .muted { display: block; }
.letter-facts { margin: var(--space-3) 0 0; }
.letter-facts dt { color: var(--muted); }
.letter-facts dd { margin: 0; overflow-wrap: anywhere; }
.letter-will-do { margin: 0; padding-left: 1.2em; }
.letter-will-do li { margin: 0 0 var(--space-1-5); }
.letter-will-do > li:last-child { margin-bottom: 0; }  /* the list ends at its card's padding */
.letter-form { max-width: 1100px; }
.letter-words { display: grid; grid-template-columns: minmax(0, 1fr) minmax(220px, 300px); gap: 0 var(--space-6); align-items: start; }
@media (max-width: 899px) { .letter-words { grid-template-columns: minmax(0, 1fr); } }
.letter-words textarea { width: 100%; font-family: inherit; }
.letter-fields h3 { margin: 0 0 var(--space-1-5); font-size: var(--text-md); }
.letter-fields p { margin: 0 0 var(--space-2); }
.letter-fields li { padding: var(--space-0-5) 0; border: 0; overflow-wrap: anywhere; }
.letter-fee-rows select { max-width: 200px; }
.letter-fee-every select { min-width: 7.5rem; }
.letter-fee-terms { min-width: 230px; }
.letter-fee-terms select { width: 100%; max-width: none; }
.letter-fee-term { display: flex; align-items: center; gap: var(--space-1-5); margin-top: var(--space-1-5); white-space: nowrap; }
.invoice-lines .letter-fee-term input { width: 4rem; }  /* beats the fee grid's number width; both rows' boxes start at the same edge */
.letter-fee-months { display: contents; }
/* Only the terms a fee's frequency can have: months of discount for a recurring one, instalments for a one-time one. */
tr:has(select[name$="-every"] option[value="0"]:checked) .letter-fee-months { display: none; }
tr:has(select[name$="-every"] option:not([value="0"]):checked) .letter-fee-plan { display: none; }
.recurring-increase { min-width: 0; margin: var(--space-4) 0 0; padding: 0; border: 0; }
.form-grid + .recurring-increase { margin-top: 0; }  /* the field above keeps its own margin in a grid: one gap, not two */
.recurring-increase legend { padding: 0; margin-bottom: var(--space-1); font-size: var(--text-sm); font-weight: 600; }  /* as a field's legend (Each new invoice, under it) */
.letter-services { margin-top: var(--space-2-5); }
.letter-services h3 { margin: var(--space-3) 0 var(--space-1-5); font-size: var(--text-base); color: var(--muted); }
.letter-services > .service-group:last-child, .letter-services > .service-group:last-child > .bulk-service:last-child { margin-bottom: 0; }  /* the last group of services ends at its card's padding */
.letter-service-note { display: block; margin-top: var(--space-0-5); }
.bulk-service.is-blocked { opacity: 0.75; }
.bulk-service.is-blocked .bulk-service-head { cursor: default; }
.letter-billing-start { max-width: 260px; margin: 0 0 var(--space-3); }
.letter-start { max-width: var(--width-form); }
.sign-letter { margin: 0 0 var(--space-3); }
.sign-letter .letter-title { font-size: 1.15rem; }

/* --- The policies (legal/): pages anyone can read ------------------------------------------------------------ */
body.legal-page { background: var(--surface); }
.legal-header { position: sticky; top: 0; z-index: 30; border-bottom: 1px solid var(--border); background: var(--surface); }
.legal-bar { display: flex; align-items: center; gap: var(--space-3) var(--space-6); flex-wrap: wrap; max-width: 960px; margin: 0 auto; padding: var(--space-2-5) var(--space-5); }
.legal-brand { display: inline-flex; align-items: center; gap: var(--space-2); color: var(--text); font-weight: 650; font-size: var(--text-lg); letter-spacing: -0.015em; }
.legal-brand:hover { text-decoration: none; }
.legal-brand img { border-radius: 7px; }
.legal-nav { display: flex; flex-wrap: wrap; gap: var(--space-0-5) var(--space-1); flex: 1; }
.legal-nav a { padding: var(--space-1-5) var(--space-2-5); border-radius: var(--radius-md); color: var(--muted); font-weight: 500; }
.legal-nav a:hover { color: var(--text); background: var(--surface-3); text-decoration: none; }
.legal-nav a.active { color: var(--text); background: var(--surface-3); font-weight: 600; }
.legal-main { max-width: 960px; margin: 0 auto; padding: var(--space-9) var(--space-5) 64px; }
.legal-main:focus { outline: none; }
.legal-text { max-width: 720px; font-size: var(--text-md); line-height: 1.65; }
.legal-text h1 { font-size: var(--text-3xl); margin-bottom: var(--space-3); }
.legal-text h2 { margin: var(--space-9) 0 var(--space-2-5); font-size: var(--text-xl); scroll-margin-top: 72px; }
.legal-text p { margin: 0 0 var(--space-3); }
.legal-text ul { margin: 0 0 var(--space-4); padding-left: var(--space-6); }
.legal-text li { margin-bottom: var(--space-2); }
.legal-lead { font-size: var(--text-lg); color: var(--text-2); }
.legal-summary { margin: var(--space-6) 0 var(--space-2); padding: var(--space-4) var(--space-6) var(--space-2); border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface-2); }
.legal-summary h2 { margin: 0 0 var(--space-2-5); font-size: var(--text-md); text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted); }
.legal-table { margin: var(--space-1) 0 var(--space-4); font-size: var(--text-base); line-height: 1.5; }
.legal-table th, .legal-table td { padding: var(--space-2-5) var(--space-3) var(--space-2-5) 0; vertical-align: top; }
.legal-table thead th { background: none; }
.legal-table tbody th { text-transform: none; letter-spacing: 0; font-size: inherit; color: var(--text); white-space: nowrap; }
.legal-text .table-scroll { max-width: 100%; }
.legal-text .legal-table { min-width: 560px; }
.legal-footer { max-width: 720px; margin-top: var(--space-12); padding-top: var(--space-4); border-top: 1px solid var(--border); color: var(--muted); font-size: var(--text-sm); }
.legal-footer p { margin: 0 0 var(--space-1-5); }
/* What's new (/changelog/): on the policies' layout */
.legal-text .changelog-version h2 { margin-bottom: var(--space-0-5); }
.legal-text .changelog-date { margin-bottom: var(--space-2); color: var(--muted); font-size: var(--text-sm); }
.portal-footer-legal { margin-left: auto; }
.portal-footer-legal a { color: var(--muted); }
/* English · Français (languages/_switch.html): one of the links at the foot of the portal's pages, on their line and
   in their colour */
.language-switch { display: inline; }
.language-switch .link-button { color: inherit; }
@media (max-width: 720px) {
  .legal-header { position: static; }
  /* On a phone the links get a row of their own, under the name and the buttons: beside them they had a third of
     the width, and stacked one per line. One line, which slides sideways on the narrowest phones. */
  .legal-bar { gap: var(--space-1-5) var(--space-2-5); padding: var(--space-2-5) var(--space-4) var(--space-1-5); }
  .legal-brand { margin-right: auto; }
  .legal-nav { order: 1; flex: 1 0 100%; flex-wrap: nowrap; gap: var(--space-0-5); margin: 0 -8px; overflow-x: auto; scrollbar-width: none; }
  .legal-nav a { padding: var(--space-1-5) var(--space-2); white-space: nowrap; font-size: var(--text-sm); }
  .legal-main { padding: var(--space-6) var(--space-4) var(--space-12); }
  .legal-text h1 { font-size: var(--text-2xl); }
  .portal-footer-legal { margin-left: 0; }
}
@media print { .legal-header { display: none; } .legal-main { padding: 0; } }

/* A contact whose emails bounced */
.email-stopped { margin: 0 0 var(--space-4); }
.email-stopped p { margin: 0 0 var(--space-2-5); }
.email-stopped > :last-child { margin-bottom: 0; }  /* without its buttons (someone who can't manage the team) the words end the box */

/* --- A client's record: header, facts, tabs, the overview's two columns ---------------------------------------- */
.record-title { display: flex; align-items: flex-start; gap: var(--space-3); }
.record-mark {
  display: grid; place-items: center; width: 46px; height: 46px; flex-shrink: 0; margin-top: var(--space-0-5); border-radius: var(--radius-lg);
  background: var(--primary-soft); color: var(--info-text); font-weight: 700; font-size: var(--text-md); letter-spacing: 0.02em;
}
.record-mark.is-individual { border-radius: 50%; background: var(--purple-bg); color: var(--purple-text); }
.record-mark.is-trust, .record-mark.is-non_profit, .record-mark.is-charity { background: var(--success-bg); color: var(--success-text); }
.record-mark.is-partnership, .record-mark.is-sole_prop { background: var(--warning-bg); color: var(--warning-text); }
.record-header .page-subtitle { gap: var(--space-1) var(--space-3); }
/* Once the header has scrolled away, a slim bar keeps the client in sight: sticky, and taking no room in the page
   (its negative margin) until it shows (app.js). */
.record-bar {
  position: sticky; top: 0; z-index: 25; display: flex; align-items: center; gap: var(--space-2-5); height: 52px; margin-bottom: -52px; padding: 0 var(--space-3);
  border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); box-shadow: var(--shadow-md);
  visibility: hidden; opacity: 0; transition: opacity 0.12s;
}
.record-bar.is-shown { visibility: visible; opacity: 1; }
.record-bar .record-mark { width: 30px; height: 30px; margin: 0; border-radius: var(--radius-md); font-size: var(--text-xs); }
.record-bar-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 650; }
.record-bar .actions { margin-left: auto; flex-wrap: nowrap; }
.record-bar a.due:hover { text-decoration: none; }
@media (max-width: 899px) { .js .record-bar { top: 64px; } .record-bar .btn-small:not(.btn-primary) { display: none; } }
/* While a timer runs the slim bar sits under the timer bar, not over it: that bar is 46px tall, 62px where its buttons
   are a finger tall, with 8px over it and 8px between the two */
body:has(#timer-bar > .timer-bar) .record-bar { top: 62px; }
@media (max-width: 899px), (pointer: coarse) { body:has(#timer-bar > .timer-bar) .record-bar { top: 78px; } }
@media (max-width: 899px) { .js body:has(#timer-bar > .timer-bar) .record-bar { top: 134px; } }
@media print { .record-bar { display: none; } }
.add-menu > summary .icon { width: 14px; height: 14px; margin-left: var(--space-0-5); }
/* The facts: one frame, and space between them (no rules, no shadow) */
.record-facts {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: var(--space-2) var(--space-6); margin: 0 0 var(--stack-gap); padding: var(--space-3) var(--space-5);
  border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface);
}
.record-facts > div { min-width: 0; }
.record-facts dt { font-size: var(--text-xs); font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); }
.record-facts dd { margin: var(--space-0-5) 0 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.record-facts .who-chip:hover { text-decoration: none; background: var(--border-strong); }
.record-grid { display: grid; grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr); gap: var(--space-5); align-items: start; }
.rail-card .section-header { margin-bottom: var(--space-2); }  /* a card like the ones beside it: the same padding, gap and heading */
.rail-list, .rail-people, .attention-list, .timeline { list-style: none; margin: 0; padding: 0; }
.rail-list li { display: flex; gap: var(--space-3); padding: var(--space-1-5) 0; }  /* space parts the rows; a line only parts sections */
.rail-list li:first-child, .rail-people li:first-child { padding-top: 0; }
.rail-date {
  display: flex; flex-direction: column; align-items: center; justify-content: center; flex-shrink: 0; width: 42px; height: 44px;
  border: 1px solid var(--border); border-radius: var(--radius-md); line-height: 1.1;
}
.rail-date.is-overdue { border-color: var(--danger-border); background: var(--danger-bg); }
.rail-month { font-size: 0.625rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted); }
.rail-date.is-overdue .rail-month { color: var(--danger); }  /* red only says late */
.rail-meta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-0-5) var(--space-2); margin-top: var(--space-0-5); }
.rail-day { font-size: var(--text-lg); font-weight: 650; font-variant-numeric: tabular-nums; }
.rail-text { display: flex; flex-direction: column; min-width: 0; overflow-wrap: anywhere; }
.rail-text a { color: var(--text); font-weight: 500; }
.rail-text a:hover { color: var(--link); }
.rail-people li { padding: var(--space-1-5) 0; overflow-wrap: anywhere; }
.rail-people li > a { font-weight: 500; }
.rail-notes { margin: 0; overflow-wrap: anywhere; }
.attention-card { border-color: var(--warning-border-soft); }  /* a full border goes round; an edge would bend */
.attention-list li + li { border-top: 1px solid var(--border); }
.attention-list a { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-2) 0; color: var(--text); }
.attention-list a:hover { text-decoration: none; color: var(--link); }
.attention-icon { display: inline-grid; place-items: center; width: 30px; height: 30px; flex-shrink: 0; border-radius: 50%; }
.attention-icon .icon { width: 15px; height: 15px; }
.attention-icon.is-danger { background: var(--danger-bg); color: var(--danger); }
.attention-icon.is-warning { background: var(--warning-bg); color: var(--warning-text); }
.attention-icon.is-info { background: var(--info-bg); color: var(--info-text); }
.household-table td { vertical-align: middle; }
.household-table tr.is-selected td { background: var(--primary-soft); }  /* this client: chosen's tint, its name in line with the others' */
@media (max-width: 720px) {  /* a phone: the name and role a line each, not a word a line; a column's name may take two lines so the three fit */
  .household-table td:first-child { min-width: var(--width-name-cell); }
  .household-table th { white-space: normal; }
}
.timeline li { display: grid; grid-template-columns: 92px minmax(0, 1fr); gap: var(--space-3); padding: var(--space-2-5) 0; border-top: 1px solid var(--border); }  /* the client's activity and the emails sent about it: one row */
.timeline li:first-child { border-top: 0; padding-top: 0; }
.timeline-when, .timeline-what { display: flex; flex-direction: column; line-height: 1.4; }
.timeline-when time { font-weight: 600; font-variant-numeric: tabular-nums; }
.timeline-what { overflow-wrap: anywhere; }
@media (max-width: 1100px) { .record-grid { grid-template-columns: minmax(0, 1fr); } }
@media (max-width: 720px) {
  .record-facts { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  /* A finger has no tooltip, so nothing ends in "…": a fact takes the lines it needs, the contact's phone under the name */
  .record-facts dd, .record-facts .fact-sub { white-space: normal; overflow-wrap: break-word; }
  .record-facts .fact-more { display: block; }
  .record-facts .fact-dot { display: none; }
  .record-mark { width: 40px; height: 40px; }
  .timeline li { grid-template-columns: 76px minmax(0, 1fr); }
}

/* --- Adding a service to a client: the cards to choose from, the form and what it will add ------------------------ */
.service-group { margin-bottom: var(--space-7); }
.service-group > h2 { margin-bottom: var(--space-2-5); font-size: var(--text-sm); text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted); }
.service-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: var(--space-3); list-style: none; margin: 0; padding: 0; }
.service-card { display: flex; flex-direction: column; justify-content: space-between; gap: var(--space-3); margin: 0; padding: var(--space-4) var(--space-5); }
.service-card h3 { margin: 0 0 var(--space-1); font-size: var(--text-md); }
.service-card p { margin: 0; }
.service-card-action { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.service-card:not(.is-unavailable):not(.is-added):hover { border-color: var(--primary); }
.service-card.is-added { background: var(--surface-2); }
.service-card.is-unavailable { background: none; box-shadow: none; border-style: dashed; }
.service-card.is-unavailable h3 { color: var(--muted); }
.engagement-layout { display: grid; grid-template-columns: minmax(0, 1.5fr) minmax(280px, 1fr); gap: var(--space-5); align-items: start; }
.engagement-form { max-width: none; }
.engagement-form > .field { max-width: 620px; }
/* A custom service's questions follow how often it's done: its date only one time; no due rule or dates to run
   between one time or as needed (engagements/services.py, SCHEDULE_FIELDS). */
.engagement-form:not(:has(#id_frequency option[value="once"]:checked)) > .field-due_on,
.engagement-form:has(#id_frequency :is(option[value="once"], option[value="as_needed"]):checked) > :is(.field-period_basis, .field-due_rule, .field-due_n, .field-due_day, .field-track_from, .field-end_date) { display: none; }
.engagement-side { position: sticky; top: 20px; }
.preview-summary { margin: 0 0 var(--space-2-5); }
.preview-list { list-style: none; margin: 0; padding: 0; }
.preview-list li { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-2) 0; border-top: 1px solid var(--border); }
.preview-list .rail-text { flex: 1; }
.preview-list .tags { flex-shrink: 0; }
#deadline-preview.htmx-request { opacity: 0.55; }
#deadline-preview > :last-child { margin-bottom: 0; }  /* the preview's last line ends at its card's padding */
@media (max-width: 1100px) {
  .engagement-layout { grid-template-columns: minmax(0, 1fr); }
  .engagement-side { position: static; }
}

/* --- Search everywhere (Ctrl+K) ---------------------------------------------------------------------------- */
.search-dialog {
  width: min(640px, calc(100vw - 24px)); max-height: min(560px, calc(100vh - 80px)); margin: 10vh auto auto; padding: 0;
  border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--surface); color: var(--text);
  box-shadow: var(--shadow-lg); overflow: hidden;
}
.search-dialog[open] { display: flex; flex-direction: column; }
.search-dialog::backdrop { background: var(--backdrop); }
.search-dialog form { display: flex; flex-direction: column; min-height: 0; margin: 0; }
.search-input { display: flex; align-items: center; gap: var(--space-2-5); padding: var(--space-3) var(--space-4); border-bottom: 1px solid var(--border); }
.search-input .icon { width: 18px; height: 18px; color: var(--muted); }
.search-input input {
  flex: 1; min-width: 0; min-height: 0; padding: var(--space-1) 0; border: 0; background: none; font-size: var(--text-lg); box-shadow: none;
}
.search-input input:focus { box-shadow: none; }
.search-input input::-webkit-search-cancel-button { display: none; }
.search-esc, .search-hints kbd {
  padding: 1px var(--space-1-5); border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface-2);
  font: 500 var(--text-2xs)/1.5 var(--font); color: var(--muted);
}
.search-results { overflow-y: auto; padding: var(--space-1-5) var(--space-2) var(--space-2); min-height: 80px; }
.search-group h3 { margin: var(--space-2-5) var(--space-2) var(--space-1); font-size: var(--text-xs); font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted); }
.search-group ul { list-style: none; margin: 0; padding: 0; }
.search-hit { display: flex; align-items: center; gap: var(--space-3); min-height: 40px; padding: var(--space-1-5) var(--space-2); border-radius: var(--radius-md); color: var(--text); }
.search-hit:hover { text-decoration: none; background: var(--surface-3); }
.search-hit[aria-selected="true"] { background: var(--primary-soft); text-decoration: none; }
.search-hit:focus-visible { outline-offset: -2px; }
.search-hit-icon { display: inline-grid; place-items: center; width: 28px; height: 28px; flex-shrink: 0; border-radius: var(--radius-md); background: var(--surface-3); color: var(--muted); }
.search-hit[aria-selected="true"] .search-hit-icon { background: var(--surface); color: var(--info-text); }
.search-hit-icon .icon { width: 15px; height: 15px; }
.search-hit-text { display: flex; flex-direction: column; flex: 1; min-width: 0; line-height: 1.35; }
.search-hit-title { font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.search-hit-detail { font-size: var(--text-sm); color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.search-more { display: block; margin: var(--space-0-5) var(--space-2) var(--space-1-5) var(--space-12); font-size: var(--text-sm); }
.search-empty { margin: 0; padding: var(--space-6) var(--space-4); text-align: center; }
.search-hints { display: flex; flex-wrap: wrap; gap: var(--space-1) var(--space-4); padding: var(--space-2) var(--space-4); border-top: 1px solid var(--border); background: var(--surface-2); font-size: var(--text-xs); color: var(--muted); }
.search-hints kbd { margin-right: 3px; }
/* The search page (no JavaScript, or the address opened): a card like any list's. Its rows' tint reaches into the
   card's padding, so their icons and the group names start at the card's edge. */
.search-page-results .search-group ul { margin-inline: calc(-1 * var(--space-2)); }
.search-page-results .search-group h3 { margin-inline: 0; }
.search-page-results .search-group:first-child h3 { margin-top: 0; }
.search-page-results .search-more { margin-left: calc(var(--space-7) + var(--space-3)); }  /* under the rows' words: past the icon and its gap */
.no-js .search-button kbd { display: none; }
@media (max-width: 720px) {
  .search-dialog { margin-top: var(--space-3); max-height: calc(100vh - 24px); }
  .search-hints { display: none; }
  .search-hit { min-height: var(--touch-target); }
}

/* --- Lists: the toolbar's pieces, saved views, rows per page --------------------------------------------------- */
.list-region { position: relative; }
.list-region.htmx-request > .card, .list-region.htmx-request > .board { opacity: 0.55; transition: opacity 150ms; }
.toolbar .segmented { flex-shrink: 0; }
.toolbar .check { white-space: nowrap; }
.toolbar-note { color: var(--muted); font-size: var(--text-sm); }
.saved-views .chip { gap: var(--space-1-5); }
.saved-views .chip .icon { width: 13px; height: 13px; color: var(--muted); }
.saved-views form.chip { margin: 0; padding-right: var(--space-1); }
.saved-views .chip.is-current .icon { color: var(--primary); }
.chip-remove {
  display: inline-grid; place-items: center; width: 20px; height: 20px; padding: 0; border: 0; border-radius: 50%;
  background: none; color: inherit; cursor: pointer;
}
.chip-remove:hover { background: var(--surface-3); }
.chip-remove .icon { width: 12px; height: 12px; }
.save-view-menu .menu-panel { width: min(300px, calc(100vw - 32px)); }
.save-view-menu p { margin: 0; }
.save-view-menu > summary .icon { width: 13px; height: 13px; margin-right: var(--space-1); }
.page-size-choice { min-width: 28px; padding: var(--space-0-5) var(--space-1-5); border-radius: var(--radius-sm); text-align: center; font-size: var(--text-sm); color: var(--muted); }
.page-size-choice:hover { background: var(--surface-3); text-decoration: none; color: var(--text); }
.page-size-choice.is-current { background: var(--surface-3); color: var(--text); font-weight: 600; }
.row-actions .btn-small { padding-left: var(--space-2); padding-right: var(--space-2); }
.row-actions .btn.icon-only { padding-left: var(--space-1-5); padding-right: var(--space-1-5); }
.data-table td.primary-cell a { font-weight: 500; }
.data-table .group-row th { position: static; background: var(--surface-2); text-transform: none; letter-spacing: 0; font-size: var(--text-sm); }  /* the colour stays .group-row's: by state */
.bulk-bar .field-inline { display: inline-flex; align-items: center; gap: var(--space-1-5); }
.bulk-bar select { background-color: var(--surface); color: var(--text); }
@media (max-width: 720px) {
  .toolbar .search-field, .toolbar input[type="search"] { flex-basis: 100%; max-width: none; }
  .pagination .page-size { margin-left: 0; }
}
.avatar-stack { display: inline-flex; align-items: center; }
.avatar-small { width: 24px; height: 24px; font-size: 0.625rem; box-shadow: 0 0 0 2px var(--surface); }
.primary-cell > .avatar { display: inline-grid; vertical-align: middle; margin-right: var(--space-1-5); }  /* beside the name (Team), not above it */
.avatar-stack .avatar + .avatar { margin-left: -2px; }  /* the next one's ring stops short of these initials */
.avatar-stack .muted { margin-left: var(--space-1-5); }
.data-table tr:hover .avatar-small { box-shadow: 0 0 0 2px var(--surface-2); }

/* --- Deadlines: tighter cards, the board by client -------------------------------------------------------------- */
.tracker-toolbar .segmented a { display: inline-flex; align-items: center; gap: var(--space-1-5); }
.tracker-toolbar .segmented .icon { width: 14px; height: 14px; }
.tracker-nav .icon { width: 14px; height: 14px; }
.board { gap: var(--space-2-5); }
.column-header { position: sticky; top: 0; z-index: 1; padding: var(--space-2) var(--space-2-5); border-radius: var(--radius) var(--radius) 0 0; background: var(--surface); }
.column-title { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); }
.column-title a { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.column-items { padding: var(--space-1-5); gap: var(--space-1-5); }
.card-top { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-2); }
.deadline-card .due-date { font-size: var(--text-xs); }
.deadline-card .due { min-width: 0; }  /* a narrow card puts the pill under the date */
.card-done { flex-shrink: 0; line-height: 1; }
.deadline-card .card-entity { margin-top: 1px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.deadline-card .card-title { display: block; margin: 1px 0 var(--space-1); }
.deadline-card .card-badges { margin-bottom: 0; align-items: center; }
.deadline-card .card-badges .who { margin-left: auto; }
.deadline-card .task-progress { margin: var(--space-1-5) 0 0; }
.deadline-card .card-for { margin: -3px 0 var(--space-1); }
.deadline-card.client-handled { background: none; border-style: dashed; }
.client-handled .card-title, .client-handled .card-entity { color: var(--muted); }
.board.by-client > .board-column { flex: 0 0 260px; }
.board-column.overdue .column-sub { color: var(--danger); font-weight: 600; }
.tracker-table .row-actions .btn .icon { margin-right: var(--space-1); }
.btn-secondary { background: var(--surface); }
.card-moved { margin-top: var(--space-1); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* My work: what's always in sight (open or completed, how far ahead) beside the Filters button */
.work-controls { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); }
.work-filters .search-field { flex: 1 1 220px; max-width: 320px; }
.data-table .tick-cell { width: 30px; padding-right: 0; }
.sr-only-head th { padding-top: var(--space-1-5); padding-bottom: var(--space-1-5); }

/* --- Fingers: on a phone or a tablet, everything to tap is 44 px or more ------------------------------------------ */
@media (max-width: 899px), (pointer: coarse) {
  :root { --control-height: 44px; }
  .segmented { padding: 0; }  /* its segments are a finger tall, so the track is too: no taller than the buttons beside it */
  .btn-small, .chip, .filter-chip, .segmented a, .segmented label, .tabs > a, .tabs-more .menu-item, .tabs-more > summary, .link-action,
  .page-size-choice, .check, .search-more, .breadcrumb a { min-height: var(--touch-target); }
  .btn.icon-only, .more-menu > summary.btn, .page-size-choice { min-width: var(--touch-target); }
  .segmented a, .segmented label, .link-action, .chip, .page-size-choice, .breadcrumb a, .search-more {
    display: inline-flex; align-items: center; justify-content: center;
  }
  .filter-chip a, .chip-remove { width: 36px; height: 44px; }
  .bulk-bar select, .pdf-toolbar select { min-height: var(--touch-target); }
  /* The quick-add's date and person: the chip is a finger tall and its field fills it (the four stay together, or a
     focused field goes back to 26px) */
  .qchip { min-height: var(--touch-target); }
  .qchip input, .qchip select, .qchip input:focus, .qchip select:focus { height: calc(var(--touch-target) - 2px); }
  .select-cell input, .check input { width: 20px; height: 20px; }
  /* A small mark takes the taps around it */
  .tick, .timer-toggle { position: relative; }
  .tick::after { content: ""; position: absolute; inset: -13px; }
  .timer-toggle::after { content: ""; position: absolute; inset: -9px; }
  .rule-switch input.switch::after { content: ""; position: absolute; inset: -11px; }  /* the automations' on/off */
  .status-menu > summary { position: relative; }  /* a list's status pill stays its size */
  .status-menu > summary::after { content: ""; position: absolute; inset: -10px 0; }
  /* The time picker: a row's date is its box's label, a finger tall */
  .picker-table .picker-tick input { width: 20px; height: 20px; }
  .picker-table td.nowrap > label[for^="pick-entry-"] {
    display: inline-flex; align-items: center; min-height: var(--touch-target); min-width: var(--touch-target);
  }
  .page-header .actions { flex-shrink: 1; min-width: 0; max-width: 100%; }
  /* The menu of the rest never wraps alone onto a row: the button before it holds the menu's room as a margin, and
     the menu takes that room back, so the two go to the next row together. A choice of whose work takes a row. */
  .page-header .actions > :has(+ .more-menu) { margin-right: calc(var(--touch-target) + var(--space-2)); }
  .page-header .actions > :has(+ .more-menu) + .more-menu { margin-left: calc(-1 * (var(--touch-target) + var(--space-2))); }
  .page-header .actions > .segmented { flex: 1 0 100%; }
  .page-header .actions > .segmented > a { flex: 1; justify-content: center; }
  .toolbar .segmented { max-width: 100%; overflow-x: auto; }
  /* The client portal's small links that open things are a finger tall too. One with room around it (over a title,
     beside a heading, at a card's edge) takes that room, so the page is no longer for it; the team's addresses, the
     firm's and the footer's sit one under the other, so each has its own height. */
  .portal-page .page-header > div:first-child > a.muted.small, .portal-block .section-header > a, .sign-open a:not(.btn),
  .portal-send-actions > a.small, .portal-invoice-list li > a, .portal-invoice-link, .team-reach a, .firm-lines a,
  .portal-footer a { display: inline-flex; align-items: center; min-height: var(--touch-target); }
  .portal-page .page-header > div:first-child > a.muted.small { column-gap: var(--space-1); margin-block: -12px -8px; }
  .portal-block .section-header > a, .sign-open a:not(.btn) { margin-block: -12px; }
  .portal-send-actions > a.small { margin-block: -10px -14px; }
  .portal-invoice-list li > a { margin-block: -9px; }
  .portal-invoice-link { display: flex; }
  .team-person { padding-bottom: 0; }
  .team-reach { gap: 0 var(--space-3); margin-top: 0; }
  .firm-lines li:has(> a) { align-items: center; padding-block: 0; }
  .firm-lines li:has(> a) > .icon { margin-top: 0; }
  .portal-footer-inner { align-items: center; row-gap: 0; }
  /* A document's state that leads somewhere ("Waiting for your signature", to its Sign page) stays its size and takes
     the taps on the line under it, which holds only words; its title, over it, keeps its own */
  .portal-doc-heading a.badge { position: relative; }
  .portal-doc-heading a.badge::after { content: ""; position: absolute; inset: -2px 0 -22px; }
}

/* Counts read on their grey, in a chosen segment too */
.count { color: var(--text-2); }
.search-button kbd { color: var(--sidebar-text); }

/* A box that scrolls sideways holds what's positioned inside it: a label for screen readers in a wide table
   would widen the page otherwise. */
.table-wrap, .table-scroll, .doc-list-box, .board, .tabs, .segmented { position: relative; }

@media (max-width: 899px), (pointer: coarse) {
  .field:has(> input[type="checkbox"]) > label, .field:has(> input[type="checkbox"]) > .field-head > label,
  .field fieldset label, .toggle-text { min-height: var(--touch-target); }
  .field:has(> input[type="checkbox"]) > label, .field:has(> input[type="checkbox"]) > .field-head > label,
  .field fieldset label { display: inline-flex; align-items: center; min-width: var(--touch-target); }
  .message-close { position: relative; }
  .message-close::after { content: ""; position: absolute; inset: -10px; }  /* a finger's width around the × */
  .toggle-text { justify-content: center; }
  .filter-chip a, .chip-remove { width: var(--touch-target); }
  .segmented a, .segmented label, .btn-small { min-width: var(--touch-target); }
  details:not(.menu) > summary { padding-block: var(--space-3); }
  input[type="file"] { min-height: var(--touch-target); }
}
@media (max-width: 720px) {
  .check { white-space: normal; }
  .inv-lines { font-size: var(--text-sm); }
  .inv-lines th, .inv-lines td { padding-left: var(--space-1-5); padding-right: var(--space-1-5); }
  /* The headings, the descriptions and the totals' names wrap, so the amounts stay on the page, each on one line.
     A line's date goes under its description (.show-sm), as an invoice's time has its date and person under the work. */
  .inv-lines thead th, .inv-lines tfoot th { white-space: normal; }
  .inv-lines .num { white-space: nowrap; }
  .inv-lines .show-sm { font-size: var(--text-xs); }
  .inv-lines .hide-sm:first-child + * { padding-left: 0; }  /* the first cell shown is at the card's edge */
  .invoice-doc { overflow-x: auto; }
  /* An invoice's time: each entry a block, its work on top (its date and person under it), then its hours, value and
     Remove on one line */
  .invoice-time-table, .invoice-time-table tbody, .invoice-time-table tfoot { display: block; }
  .invoice-time-table thead, .invoice-time-table tr > .hide-sm { display: none; }
  .invoice-time-table tr { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-4); padding: var(--space-2-5) 0; border-bottom: 1px solid var(--border); }
  .invoice-time-table tbody tr:last-child { border-bottom: 0; }
  .invoice-time-table tr > th, .invoice-time-table tr > td { display: block; padding: 0; border: 0; }
  .invoice-time-table tbody td:not(.num):not(.right) { flex: 1 1 100%; }
  .invoice-time-table .invoice-time-hours::after { content: " h"; }
  .invoice-time-table td.right { margin-left: auto; }
  .invoice-time-table tfoot tr { border-top: 2px solid var(--border); border-bottom: 0; }
  .invoice-time-table tfoot th { flex: 1; }
}

/* --- The client portal's overview: a box to send documents, then four blocks -------------------------------------- */
.portal-send { padding: var(--space-3); }
.dropzone-big { min-height: 148px; gap: var(--space-1-5); }
.dropzone-big .icon { width: 34px; height: 34px; }
.dropzone-big .dropzone-text { font-size: var(--text-lg); }
.dropzone-big .dropzone-text strong { font-weight: 650; }
.portal-send-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2-5) var(--space-3); margin-top: var(--space-3); }
.camera-button { position: relative; overflow: hidden; }
.camera-button input[type="file"] { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; }
.camera-button.has-files { border-color: var(--primary); color: var(--link); }
/* A camera is a phone's or a tablet's: a computer chooses files or drops them */
@media (hover: hover) and (pointer: fine) { .camera-button { display: none; } }
@media (hover: none), (pointer: coarse) { .drop-hint { display: none; } }
/* "Send" shows once something is chosen (always without JavaScript) */
.js .portal-send:not(:has(.has-files)) .send-button { display: none; }
.portal-blocks { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-5); align-items: start; }
.portal-block { margin: 0; min-width: 0; }
.portal-block h2 { display: flex; align-items: center; gap: var(--space-2); }
.portal-block h2 .icon { width: 18px; height: 18px; color: var(--muted); }
.portal-block.is-waiting { border-color: var(--warning-border); }
.portal-block.is-waiting h2 .icon { color: var(--warning-border); }
.portal-block.is-waiting .approve-box { border-color: transparent; }  /* the card's amber edge says it already: the box keeps its tint */
.portal-block.is-late h2 .icon { color: var(--danger); }
.portal-block .count.is-new { background: var(--info-bg); color: var(--info-text); }
.todo-overview + .portal-approvals { margin-top: var(--space-3); padding-top: var(--space-3); border-top: 1px solid var(--border); }
.portal-approvals h3 { display: flex; align-items: center; gap: var(--space-1-5); margin: 0 0 var(--space-1-5); font-size: var(--text-base); }
.portal-approvals h3 .icon { width: 16px; height: 16px; color: var(--warning-border); }
.portal-owing { margin: 0 0 var(--space-2); }
.portal-owing-value { font-size: var(--text-2xl); font-weight: 650; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }
.portal-invoice-list { list-style: none; margin: 0; padding: 0; }
.portal-invoice-list li { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-2-5); padding: var(--space-3) 0; border-top: 1px solid var(--border); }
.portal-invoice-list li .num { margin-left: auto; }
@media (max-width: 899px) { .portal-blocks { grid-template-columns: minmax(0, 1fr); gap: var(--space-4); } }
@media (max-width: 720px) {
  .dropzone-big { min-height: 120px; }
  .portal-send-actions .btn { flex: 1 1 140px; min-height: 48px; }
}

/* The portal settings: the accent colour, typed or picked */
.colour-row { display: flex; align-items: center; gap: var(--space-2-5); }
/* Named from the form down, and the swatch as an input: anything lighter loses to the form's full-width fields */
.form .field .colour-row input[type="text"] { width: 9rem; font-family: var(--font-mono); }
.form .field .colour-row input.colour-picker { width: 44px; flex: none; height: var(--control-height); padding: var(--space-0-5); cursor: pointer; }
.no-js .colour-picker { display: none; }

/* --- On paper: the deadline list, a client's summary ------------------------------------------------------------- */
.print-note { margin: 0 0 10pt; font-size: 9pt; color: #444; }
@media print {
  @page { margin: 14mm 12mm; }
  @page invoice-narrow { margin: 8mm; }  /* an invoice's page margin, Narrow or Wide (billing/_invoice_doc.html) */
  @page invoice-wide { margin: 22mm 20mm; }
  .list-region > form, .more-menu, .card-done, .tick, .timer-toggle, .search-dialog, .deletion-banner,
  .load-more, .empty .actions, .section-header .btn, .link-action, .attention-stats { display: none !important; }
  .page-header { margin-bottom: 8pt; }
  .page-header h1 { font-size: 16pt; }
  .page-subtitle, .muted { color: #444 !important; }
  .badge, .count { border: 0.5pt solid #888; background: none !important; color: #000 !important; }
  .overdue-text { color: #000 !important; font-weight: 700; text-decoration: underline; }
  table { font-size: 9.5pt; }
  th, td { padding: 4pt 6pt; border-bottom: 0.5pt solid #bbb; }
  thead th, .data-table thead th { background: none !important; box-shadow: none; border-bottom: 1pt solid #000; color: #000; }
  thead { display: table-header-group; }  /* the column names on every page */
  tr { break-inside: avoid; }
  .table-wrap, .table-scroll, .data-table-box { overflow: visible !important; }
  .hide-sm { display: table-cell !important; }
  .group-row th { background: none !important; border-bottom: 1pt solid #000; padding-top: 10pt; font-size: 10.5pt; color: #000 !important; }
  .client-handled, tr.future { opacity: 1; }
  .client-handled, .client-handled a:not(.btn), .client-handled .due-date { color: inherit; }

  /* The board becomes a list: a heading a column, a line a deadline */
  .board { display: block; overflow: visible; }
  .board-column { border: 0; margin: 0 0 10pt; background: none; break-inside: auto; }
  .column-header { position: static; padding: 0 0 2pt; border-bottom: 1pt solid #000; background: none; }
  .board-column.overdue .column-title, .board-column.overdue .column-sub { color: #000; }  /* as the list's headings */
  .column-items { display: block; padding: 0; }
  .column-empty { display: none; }
  .deadline-card { display: grid; grid-template-columns: 34mm 52mm 1fr; gap: 0 8pt; align-items: baseline; padding: 3pt 0;
    border: 0; border-bottom: 0.5pt solid #bbb; border-radius: 0; background: none; font-size: 9.5pt; break-inside: avoid; }
  .deadline-card .card-top { display: block; }
  .deadline-card .card-entity, .deadline-card .card-title { margin: 0; white-space: normal; }
  .deadline-card .card-badges, .deadline-card .task-progress, .deadline-card .card-moved, .deadline-card .card-for { grid-column: 3; margin: 0; }
  .next-task { display: none; }

  /* A client's summary: its facts, then each section under the other */
  .record-facts { border: 0.5pt solid #bbb; }
  .record-grid { display: block !important; }
  .record-mark { border: 0.5pt solid #888; background: none !important; color: #000 !important; }
  .rail-card, .record-body .card { margin-bottom: 10pt; padding: 0; }
  .rail-date { border: 0.5pt solid #888; background: none !important; }
  h2 { font-size: 11.5pt; margin: 8pt 0 4pt; }
  .who-chip, .avatar { border: 0.5pt solid #888; background: none !important; color: #000 !important; }
}

/* Bars of a chart: their height as a class (billing_tags.bar_height), since the security policy allows no style
   attributes. */
.h-0 { height: 0%; } .h-1 { height: 1%; } .h-2 { height: 2%; } .h-3 { height: 3%; } .h-4 { height: 4%; } .h-5 { height: 5%; } .h-6 { height: 6%; } .h-7 { height: 7%; } .h-8 { height: 8%; } .h-9 { height: 9%; }
.h-10 { height: 10%; } .h-11 { height: 11%; } .h-12 { height: 12%; } .h-13 { height: 13%; } .h-14 { height: 14%; } .h-15 { height: 15%; } .h-16 { height: 16%; } .h-17 { height: 17%; } .h-18 { height: 18%; } .h-19 { height: 19%; }
.h-20 { height: 20%; } .h-21 { height: 21%; } .h-22 { height: 22%; } .h-23 { height: 23%; } .h-24 { height: 24%; } .h-25 { height: 25%; } .h-26 { height: 26%; } .h-27 { height: 27%; } .h-28 { height: 28%; } .h-29 { height: 29%; }
.h-30 { height: 30%; } .h-31 { height: 31%; } .h-32 { height: 32%; } .h-33 { height: 33%; } .h-34 { height: 34%; } .h-35 { height: 35%; } .h-36 { height: 36%; } .h-37 { height: 37%; } .h-38 { height: 38%; } .h-39 { height: 39%; }
.h-40 { height: 40%; } .h-41 { height: 41%; } .h-42 { height: 42%; } .h-43 { height: 43%; } .h-44 { height: 44%; } .h-45 { height: 45%; } .h-46 { height: 46%; } .h-47 { height: 47%; } .h-48 { height: 48%; } .h-49 { height: 49%; }
.h-50 { height: 50%; } .h-51 { height: 51%; } .h-52 { height: 52%; } .h-53 { height: 53%; } .h-54 { height: 54%; } .h-55 { height: 55%; } .h-56 { height: 56%; } .h-57 { height: 57%; } .h-58 { height: 58%; } .h-59 { height: 59%; }
.h-60 { height: 60%; } .h-61 { height: 61%; } .h-62 { height: 62%; } .h-63 { height: 63%; } .h-64 { height: 64%; } .h-65 { height: 65%; } .h-66 { height: 66%; } .h-67 { height: 67%; } .h-68 { height: 68%; } .h-69 { height: 69%; }
.h-70 { height: 70%; } .h-71 { height: 71%; } .h-72 { height: 72%; } .h-73 { height: 73%; } .h-74 { height: 74%; } .h-75 { height: 75%; } .h-76 { height: 76%; } .h-77 { height: 77%; } .h-78 { height: 78%; } .h-79 { height: 79%; }
.h-80 { height: 80%; } .h-81 { height: 81%; } .h-82 { height: 82%; } .h-83 { height: 83%; } .h-84 { height: 84%; } .h-85 { height: 85%; } .h-86 { height: 86%; } .h-87 { height: 87%; } .h-88 { height: 88%; } .h-89 { height: 89%; }
.h-90 { height: 90%; } .h-91 { height: 91%; } .h-92 { height: 92%; } .h-93 { height: 93%; } .h-94 { height: 94%; } .h-95 { height: 95%; } .h-96 { height: 96%; } .h-97 { height: 97%; } .h-98 { height: 98%; } .h-99 { height: 99%; }
.h-100 { height: 100%; }

.code-resend { margin-top: var(--space-3); }
@media (max-width: 899px), (pointer: coarse) {
  details:not(.menu) > summary { min-height: var(--touch-target); box-sizing: border-box; padding-block: var(--space-3); }
}

/* Firmdesk staff's pages (/ops/): a form card among the list cards is as wide as they are, one right edge; what is
   in it keeps a form's width */
.card.ops-form { max-width: none; }
.ops-form > * { max-width: 640px; }

/* The onboarding funnel (/ops/, superusers only) */
.ops-stats { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); margin-bottom: var(--space-4); }
.ops-stats .stat-value { font-size: var(--text-2xl); }
.table-card-intro { margin: 0; padding: 0 var(--space-5) var(--space-2); }
.ops-table tr.is-quiet th, .ops-table tr.is-quiet td { color: var(--muted); }
.ops-done { display: inline-flex; align-items: center; gap: var(--space-1); color: var(--success-text); font-weight: 600; }
.ops-done .icon { width: 14px; height: 14px; }
.ops-table thead th { white-space: normal; vertical-align: bottom; min-width: 5.5rem; }
.ops-firms tbody th { white-space: normal; min-width: 12rem; overflow-wrap: break-word; }
.ops-how { margin-bottom: var(--space-4); }
.ops-how ol { margin: 0 0 var(--space-2); padding-left: var(--space-5); }
.ops-how p { margin: 0; }
.ops-files .ops-file { min-width: 18rem; }
.ops-files .ops-file strong { overflow-wrap: anywhere; }
.ops-note { margin: var(--space-1) 0 0; white-space: normal; overflow-wrap: anywhere; }
.ops-files .copy-field { margin-top: var(--space-1-5); }
.ops-actions { display: flex; justify-content: flex-end; gap: var(--space-1-5); flex-wrap: wrap; }
/* Service health (/ops/health/) */
.ops-flags ul, .ops-elsewhere { margin: 0; padding-left: 0; list-style: none; }
.ops-flags li, .ops-elsewhere li { margin: 0 0 var(--space-2); }
.ops-all-well { display: flex; align-items: center; gap: var(--space-2); margin: 0 0 var(--space-4); color: var(--success-text); font-weight: 600; }
.ops-health-table tbody th { width: 30%; min-width: 9rem; white-space: normal; text-transform: none; letter-spacing: 0; font-size: inherit; color: var(--text); }
.ops-health-table td { white-space: normal; overflow-wrap: anywhere; }
.ops-health-table td.right { width: 1%; white-space: nowrap; }
/* The notice (/ops/notice/) */
.ops-notice { margin: 0 0 var(--space-4); }
.ops-notice .service-notice { margin-bottom: var(--space-1-5); }
.ops-notice-meta { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-1-5) var(--space-3); }
.ops-notice-meta p { margin: 0; }
.ops-past-notices { margin: 0; padding-left: var(--space-5); }
.ops-past-notices li { margin: 0 0 var(--space-1-5); }
/* The what's new email (/ops/news/) */
.ops-month { display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-2); margin: 0 0 var(--space-4); }
.ops-month select { width: auto; }
.ops-failed { margin: 0 0 var(--space-3); padding-left: var(--space-5); overflow-wrap: anywhere; }
.ops-news-entry { max-width: 640px; }
.ops-news-entry h3 { margin: var(--space-4) 0 var(--space-1); font-size: var(--text-md); }
.ops-news-entry p { margin: 0 0 var(--space-2); }
.sent-files .primary-cell { overflow-wrap: anywhere; }

/* A page's first-visit tip (hello/tips.py), until it's closed */
.tip { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); margin: 0 0 var(--stack-gap); padding: var(--space-2-5) var(--space-4); border: 1px solid var(--info-border); border-radius: var(--radius); background: var(--info-bg); color: var(--text); }
.tip > .icon { flex: none; color: var(--info-text); }
.tip-text { flex: 1 1 320px; margin: 0; font-size: var(--text-sm); }
.tip form { margin: 0; }

/* Who can do what, beside a new team member's form */
.member-roles h3 { margin: var(--space-3) 0 var(--space-1); font-size: var(--text-base); }
.member-roles dl { margin: 0; }
.member-roles dt { margin-top: var(--space-2); font-weight: 600; font-size: var(--text-sm); }
.member-roles dd { margin: var(--space-0-5) 0 0; color: var(--muted); font-size: var(--text-sm); }
.member-roles p { margin: 0 0 var(--space-2); }
.member-roles p:last-child { margin: var(--space-3) 0 0; }

/* My work, for someone new */
.whats-next { margin: var(--space-2) auto 0; padding-left: var(--space-5); max-width: 460px; text-align: left; }
.whats-next li { margin: var(--space-1) 0; }

/* The portal's welcome, on a client's first visit */
.portal-tour { border-color: var(--primary); }
.portal-tour-head { display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: var(--space-2) var(--space-3); }
.portal-tour-head h2 { margin: 0; font-size: var(--text-md); }
.portal-tour-head form { margin: 0; flex: none; }
.portal-tour-steps { list-style: none; margin: var(--space-2-5) 0 0; padding: 0; display: grid; gap: var(--space-2); }
.portal-tour-steps li { display: flex; gap: var(--space-2-5); align-items: flex-start; }
.portal-tour-steps .icon { flex: none; margin-top: var(--space-0-5); color: var(--primary); }

/* The portal's header on a phone: a finger's width to tap the client switcher and the account menu */
@media (max-width: 899px), (pointer: coarse) {
  .client-button { min-height: var(--touch-target); box-sizing: border-box; }
  .account-button { display: grid; place-items: center; min-width: var(--touch-target); min-height: var(--touch-target); }
}

/* /ops/pilots/: its many columns' headings may wrap (ops/templates/ops/pilot.html). */
.pilot-weeks th { white-space: normal; }

/* ==========================================================================================================
   Areas of the app: rules for one part's pages go under its heading, so each part can grow on its own.
   ========================================================================================================== */

/* == Area: work and clients (Home, My work, deadlines, clients, contacts, services, tasks, import) == */
/* A client's record: the next deadline's name, then its date under it, each cut short with "…" when narrow. */
.record-facts .fact-sub { overflow: hidden; text-overflow: ellipsis; }

/* A checklist shown as a stack of fields (narrow): the remove box says what it does, as the table's heading did,
   and the first row's "Days before" has the heading's (?). */
.checklist-table .stack-head { display: none; }
@container checklist (max-width: 840px) {
  .checklist-table .sr-only-wide { position: static; width: auto; height: auto; overflow: visible; clip: auto; white-space: normal; }
  .checklist-table .stack-head { display: flex; align-items: center; margin-bottom: var(--space-0-5); font-size: var(--text-sm); font-weight: 600; color: var(--muted); }
}

/* == Area: money (time, timesheets, approvals, billing) == */
/* A title with its (?) beside it, the (?) kept out of the title's own name (Mark billed). */
.money-heading { display: flex; align-items: center; gap: var(--space-0-5); min-width: 0; }
.money-heading h1, .money-heading h2 { margin: 0; }
/* The Billing overview's chart legend, then its (?) about what billed and received count. */
.money-legend { display: flex; align-items: center; gap: var(--space-1); }
/* A timesheet cell that can't be typed into says why under its hours (several entries, or billed): no tooltip. */
.cell-note { display: block; font-size: var(--text-xs); font-weight: 400; line-height: 1.2; color: var(--muted); white-space: nowrap; }
/* A value that leaves out hours with no billing rate says how many, under it. */
.unbilled-actions { display: inline-flex; align-items: center; gap: var(--space-2); }  /* Invoice time, then Mark billed behind ⋯: one line, so a row is one line tall */
.unbilled-table th[scope="row"] { white-space: normal; }  /* a long name wraps, so the last column stays inside the card */
.unbilled-table thead th.num { white-space: normal; }  /* "31-60 days" on two lines when it must */
.unbilled-table .report-line > th, .unbilled-table .report-line > td { vertical-align: middle; }  /* a client's row holds buttons: its words on their centre line */
@media (max-width: 720px) {  /* a phone: Invoice time goes behind ⋯ too, and a name takes what room is left */
  .unbilled-actions .menu-item.show-sm { display: flex; }
  .unbilled-table th[scope="row"] { min-width: 0; }
  .unbilled-table th, .unbilled-table td { padding-left: var(--space-1-5); padding-right: var(--space-1-5); }  /* the card's edges keep theirs */
}
/* A deadline's budget (engagements/_budget.html): hours used against it, amber from 80%, red past it. */
.budget-bar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); margin-bottom: var(--space-3); }
.budget-bar progress { width: 220px; max-width: 100%; height: 10px; accent-color: var(--success-text); }
.budget-bar.is-near progress { accent-color: var(--warning-text); }
.budget-bar.is-over progress { accent-color: var(--danger); }
.warn-text { color: var(--warning-text); font-weight: 600; }
.budget-edit summary { cursor: pointer; font-weight: 600; margin-top: var(--space-2); }
.budget-edit form { margin-top: var(--space-3); }
.unrated-note { display: block; font-size: var(--text-xs); color: var(--warning-text); white-space: nowrap; }
/* Capacity (timesheets/_capacity.html): a person's work due against their hours, week by week; amber from 80%, red past
   them. The cell's tint says it as well as its colour, and its words say how much. */
.capacity-cell { white-space: nowrap; }
.capacity-cell.is-near { background: var(--warning-bg-soft); }
.capacity-cell.is-near strong { color: var(--warning-text); }
.capacity-cell.is-over { background: var(--danger-bg); }
.capacity-cell.is-over strong { color: var(--danger); }
.capacity-of { color: var(--muted); font-size: var(--text-sm); }
.capacity-table thead th.num { white-space: nowrap; }
.capacity-table tbody td:first-child { min-width: 0; }
.capacity-total { border-right: 1px solid var(--border); }  /* the weeks' total, beside the name, before the weeks */
#capacity-work { margin-top: var(--space-6); }
.capacity-away { display: block; font-size: var(--text-xs); color: var(--muted); }  /* "Away 3 days" under a week's hours */
/* A person's time off (team/teammember_detail.html): a line per span, its Take away button at the end. */
.time-off-list { list-style: none; margin: 0 0 var(--space-3); padding: 0; }
.time-off-list li { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); padding: var(--space-2) 0; border-bottom: 1px solid var(--border); }
.time-off-list li:last-child { border-bottom: 0; }
.time-off-list li.is-past { opacity: 0.7; }
.time-off-add summary { cursor: pointer; font-weight: 600; margin-top: var(--space-2); }
.time-off-add form { margin-top: var(--space-3); }
/* The overview's two tables sit side by side only where their four columns fit. */
.report-pair { grid-template-columns: repeat(auto-fit, minmax(min(440px, 100%), 1fr)); }


/* == Area: the firm (team, settings, plans, sign-in, public pages) == */
.settings-form .form { max-width: none; }  /* a form card as wide as the cards above it */


/* == Area: the client portal, client side == */
/* The account menu says whose it is: the first name beside the initials where there's room; on a phone, the
   initials alone (the name is still what a screen reader hears). */
.account-button { display: inline-flex; align-items: center; gap: var(--space-2); padding: 3px var(--space-2) 3px 3px; border: 1px solid transparent; border-radius: var(--radius-full); }
.account-button:hover, .account-menu[open] > .account-button { border-color: var(--border); }
.account-name { max-width: 12em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; color: var(--text); }
.account-button .chevron { width: 16px; height: 16px; color: var(--muted); transition: transform 0.15s; }
.account-menu[open] .account-button .chevron { transform: rotate(180deg); }
@media (max-width: 720px) {
  .account-button { padding: 0; border: 0; }
  .account-name { position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); }
  .account-button .chevron { display: none; }
}

/* A button that's off, with the reason beside it (a disabled button can't be focused, so it can't show a tooltip) */
.disabled-with-reason { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-2); }

/* Several photos in a row: each camera button holds one. Once it has its photo (app.js marks the box .has-files)
   it shrinks to "Photo 1" and the next button shows; after the last, a word to send these first. */
.camera-shots { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.camera-shots .camera-button + .camera-button, .camera-full, .camera-button .camera-taken { display: none; }
.camera-shots .camera-button.has-files + .camera-button { display: inline-flex; }
.camera-take, .camera-button.has-files .camera-taken { display: inline-flex; align-items: center; }
.camera-button.has-files .camera-take { display: none; }
.portal-send-actions .camera-button.has-files { flex: 0 0 auto; }
.camera-shots:not(:has(.camera-button:not(.has-files))) .camera-full { display: block; flex-basis: 100%; }
@media (hover: hover) and (pointer: fine) { .camera-shots { display: none; } }
@media (max-width: 720px) { .portal-send-actions .camera-shots { flex: 1 1 100%; } }

/* The calendar: an item's time before its title, and the legend's key for what's overdue */
.calendar-item-time { flex-shrink: 0; font-weight: 600; }
.calendar-key.is-past-due::before { border: 1px dashed var(--danger); }

/* Profile, on a phone: who's signed in, with the way to sign out */
.account-card h2 { margin-bottom: var(--space-0-5); overflow-wrap: anywhere; }
.account-card p { margin: 0 0 var(--space-3); overflow-wrap: anywhere; }
.account-card form { margin: 0; }


/* == Area: the client portal, firm side == */
/* A request the client did everything on waits for the firm: its stat and chip in the firm's colour, like new answers */
.chip.is-todo-review { border-color: var(--primary); color: var(--link); }
/* A switch with a (?) (portal/_toggle.html): only the label's words work the switch, so only they show the hand */
div.toggle-text { cursor: auto; }
div.toggle-text .toggle-label { cursor: pointer; }
@media (max-width: 899px), (pointer: coarse) {  /* its label is what a finger taps: as tall as a whole row's */
  div.toggle-text .toggle-label { display: inline-flex; align-items: center; min-height: var(--touch-target); }
}
/* A (?) beside a button or a badge in a row of them: on the buttons' middle line */
.review-actions > .hint, .email-pending-form .actions > .hint { align-self: center; }
/* A request's first open item: its (?) comes after the two buttons, so they stand where the rows' below do; with room
   it is shown before them */
.review-actions > .hint { margin-left: 0; }
@media (min-width: 721px) { .review-actions > .hint { order: -1; } }
.page-subtitle .field-head, .primary-cell .field-head, td .field-head { vertical-align: middle; }

/* --- Offers (plans/offers.py): the banner, the pop-up, and the code on the plans ------------------------------------ */
.offer-banner {
  display: flex; align-items: center; gap: var(--space-2-5); flex-wrap: wrap; margin: 0 0 var(--space-4); padding: var(--space-2-5) var(--space-4);
  border: 1px solid var(--info-border); border-radius: var(--radius); background: var(--info-bg); color: var(--text);
}
.offer-banner > .icon { flex: none; color: var(--info-text); }
.offer-banner-text { flex: 1 1 260px; }
.offer-banner-actions { display: flex; align-items: center; gap: var(--space-2); margin: 0; }
.offer-code {
  font-family: var(--font-mono); font-weight: 600; letter-spacing: 0.06em; padding: var(--space-0-5) var(--space-2);
  border: 1px dashed var(--info-text); border-radius: var(--radius-md); background: var(--surface);
}
.offer-dialog { width: min(460px, calc(100vw - 32px)); }
.offer-code-big { margin: var(--space-4) 0; text-align: center; }
.offer-code-big .offer-code { font-size: 1.35rem; padding: var(--space-1-5) var(--space-4); }
.offer-applied {
  display: flex; align-items: center; gap: var(--space-2-5); flex-wrap: wrap; margin: var(--space-3) 0; padding: var(--space-2) var(--space-3);
  border: 1px solid var(--success-border); border-radius: var(--radius); background: var(--success-bg);
}
.offer-applied > .icon { color: var(--success-text); }
.offer-applied form { margin: 0 0 0 auto; }
.offer-code-entry { margin: var(--space-2-5) 0 var(--space-1); }
.offer-code-entry summary { cursor: pointer; color: var(--link); font-size: var(--text-sm); }
.offer-code-entry .inline-form { margin-top: var(--space-2); }
.offer-code-entry input { max-width: 200px; text-transform: uppercase; }
.offer-fields { min-width: 0; margin: 0 0 var(--space-4); padding: var(--space-3) var(--space-4) var(--space-1); border: 1px solid var(--border); border-radius: var(--radius); }
.offer-fields > legend { padding: 0 var(--space-1-5); font-weight: 600; }

/* == Area: the Inbox == */
/* The address, beside the page's name */
.inbox-address { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-2-5); margin-top: var(--space-1); }
.inbox-address .copy-field { margin: 0; min-width: 0; width: min(420px, 100%); }

/* Two panes: the conversations, and the one open. Each scrolls on its own on a wide screen. */
/* Split view (portal/staff/todos.html): on a wide window, a request opens beside the list (static/js/app.js). The
   list keeps the request's title, client and status; the reader shows its page without the boxes inside a box. */
.split-only { display: none; }
.split.is-open { display: grid; grid-template-columns: minmax(340px, 5fr) minmax(0, 7fr); gap: var(--space-5); align-items: start; }
.split.is-open .split-hide { display: none; }
.split.is-open .split-only, :root[data-density="compact"] .split.is-open .data-table td .split-only { display: block; color: var(--muted); }
@media (max-width: 720px) {  /* a phone has the same short rows: the title with its client and date under it, then where it stands */
  .data-table.todo-table .split-hide { display: none; }
  .data-table.todo-table .split-only, :root[data-density="compact"] .data-table.todo-table td .split-only { display: block; color: var(--muted); }
}
/* Beside a request, the counts that need attention are one line of small links */
.split.is-open .attention-stats { display: flex; flex-wrap: wrap; gap: var(--space-1-5); margin-bottom: var(--space-3); }
.split.is-open .attention-stat { flex-direction: row; align-items: baseline; gap: var(--space-1-5); padding: var(--space-1) var(--space-2-5); border-radius: var(--radius-full); }
.split.is-open .attention-stat .stat-value { font-size: var(--text-base); }
.split.is-open .attention-stat .stat-label { font-size: var(--text-sm); }
.split-list { min-width: 0; }
.split .todo-table tr.is-current > td { background: var(--primary-soft); }
.split-reader {
  position: sticky; top: 16px; display: flex; flex-direction: column; min-width: 0; max-height: calc(100vh - 32px);
  border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); box-shadow: var(--shadow-xs);
}
.split-reader[hidden] { display: none; }
.split-bar { display: flex; align-items: center; gap: var(--space-1-5); padding: var(--space-2) var(--space-3); border-bottom: 1px solid var(--border); }
.split-bar [data-split-page] { margin-left: auto; }
.split-position { margin-left: var(--space-1); }
.split-body { flex: 1; min-height: 120px; overflow-y: auto; padding: var(--space-4) var(--space-6) var(--space-6); }
.split-body:focus { outline: none; }
.split-body .breadcrumb { display: none; }
.split-body .page-header { margin-bottom: var(--space-1); }
.split-body h1 { font-size: var(--text-xl); }
.split-body .card { margin: var(--space-4) 0 0; padding: var(--space-4) 0 0; border: 0; border-top: 1px solid var(--border); border-radius: 0; background: none; box-shadow: none; }
.split-body .card.email-pending { padding: var(--space-3) var(--space-4); border: 1px solid var(--info-border); border-radius: var(--radius); }
/* The split ends where the page does: the window less the page's top padding (28), the header with the address (72),
   the gap under it (20) and the page's bottom padding (48). Each pane uses the card's 20px inset. */
.inbox-split {
  display: grid; grid-template-columns: minmax(320px, 400px) minmax(0, 1fr);
  height: calc(100vh - 168px); height: calc(100dvh - 168px); min-height: 520px;
  border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); overflow: hidden;
}
.inbox-list-col { min-height: 0; overflow-y: auto; border-right: 1px solid var(--border); background: var(--surface); }
.inbox-viewer { min-width: 0; min-height: 0; overflow-y: auto; background: var(--bg); }
.inbox-list { display: flex; flex-direction: column; min-height: 100%; }
.inbox-list .toolbar { margin: 0; padding: var(--space-2) var(--space-5); border-bottom: 1px solid var(--border); flex-wrap: nowrap; }
.inbox-list .search-field { flex: 1; min-width: 0; }
.inbox-list .filter-chips { padding: var(--space-1-5) var(--space-5) 0; }
.inbox-list .load-more { margin-top: auto; }
/* The public pages' breadcrumb, over their title. */
.legal-main > .breadcrumb { margin-bottom: var(--space-2-5); }
/* The list's column is narrow: its empty message is stacked (icon, title, sentence), not side by side, where the
   title broke over three lines. */
.inbox-list .empty.is-quiet { flex-direction: column; align-items: center; gap: var(--space-1-5); padding: var(--space-8) var(--space-5); text-align: center; }
.inbox-list .empty.is-quiet > .icon { margin: 0 0 var(--space-0-5); }

/* The filters: a row of tabs that scrolls sideways when it must */
.inbox-filters {
  position: sticky; top: 0; z-index: 3; display: flex; gap: var(--space-0-5); padding: var(--space-1-5) var(--space-3) 0; overflow-x: auto;
  border-bottom: 1px solid var(--border); background: var(--surface); scrollbar-width: none;
}
.inbox-filters::-webkit-scrollbar { display: none; }
.inbox-filters a {
  display: inline-flex; align-items: center; gap: var(--space-1); padding: 7px var(--space-2); margin-bottom: -1px; white-space: nowrap;  /* the first one's words at the panes' 20px */
  border-bottom: 2px solid transparent; color: var(--muted); font-weight: 500; font-size: var(--text-sm);
}
.inbox-filters a:hover { color: var(--text); text-decoration: none; }
.inbox-filters a.active { color: var(--text); font-weight: 600; border-bottom-color: var(--primary); }
.inbox-filters .count { font-size: var(--text-xs); }

/* A conversation in the list: who, when, what, its first words, and where it stands */
.inbox-rows { list-style: none; margin: 0; padding: 0; }
.inbox-row + .inbox-row { border-top: 1px solid var(--border); }
.inbox-row-link { display: grid; gap: var(--space-0-5); padding: var(--space-2-5) var(--space-5); color: var(--text); position: relative; }
.inbox-row-link:hover { text-decoration: none; background: var(--surface-2); }
.inbox-row.is-current .inbox-row-link { background: var(--primary-soft); }
.inbox-row.is-unread .inbox-row-link::before {
  content: ""; position: absolute; left: var(--space-2); top: 17px; width: 6px; height: 6px; border-radius: 50%; background: var(--primary);
}
.inbox-row-top { display: flex; align-items: baseline; gap: var(--space-1-5); min-width: 0; }
.inbox-row-who { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.inbox-row-count { color: var(--muted); font-size: var(--text-xs); }
.inbox-row-when { flex-shrink: 0; color: var(--muted); font-size: var(--text-xs); }
.inbox-row-subject { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--text-sm); }
.inbox-row.is-unread .inbox-row-who, .inbox-row.is-unread .inbox-row-subject { font-weight: 650; }
.inbox-row-preview {
  display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden;
  color: var(--muted); font-size: var(--text-sm);
}
.inbox-row-tags { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-2); margin-top: 3px; }
.inbox-tag { display: inline-flex; align-items: center; gap: var(--space-1); color: var(--muted); font-size: var(--text-xs); max-width: 100%; }
.inbox-tag .icon { width: 13px; height: 13px; flex-shrink: 0; }

/* The open conversation */
.inbox-nothing-open { display: grid; place-items: center; min-height: 100%; padding: var(--space-6); }
.inbox-thread { padding: var(--space-5); }
.inbox-thread-head { display: flex; align-items: flex-start; gap: var(--space-3); margin-bottom: var(--space-3); }
.inbox-thread-title { flex: 1; min-width: 0; }
.inbox-thread-title h2 { margin: 0 0 var(--space-0-5); font-size: var(--text-lg); overflow-wrap: anywhere; }
.inbox-thread-title p { margin: 0; }
.inbox-back { display: none; align-items: center; gap: var(--space-1); font-size: var(--text-sm); }
.inbox-panels { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: var(--space-3); margin-bottom: var(--space-3); }
.inbox-panel { padding: var(--space-3) var(--space-4); border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); }
.inbox-panel h3 { margin: 0 0 var(--space-1); font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); }
.inbox-panel p { margin: 0 0 var(--space-1-5); }
.inbox-panel-main { font-weight: 600; overflow-wrap: anywhere; }
.inbox-panel form.inline { margin: var(--space-0-5) var(--space-1-5) 0 0; }
.inbox-suggestions { display: flex; flex-wrap: wrap; gap: var(--space-1-5); margin: var(--space-1) 0 var(--space-2); }
.inbox-suggestions form { margin: 0; }
.inbox-disclosure { margin-top: var(--space-1); }
.inbox-disclosure > summary { cursor: pointer; color: var(--link); font-size: var(--text-sm); }
.inbox-disclosure .form { margin-top: var(--space-2); max-width: none; }
.inbox-disclosure .field { margin-bottom: var(--space-2); }
.inbox-disclosure select, .inbox-disclosure input:not([type="checkbox"]) { width: 100%; }
.inbox-file-form .check-row { margin: var(--space-1) 0 var(--space-2-5); }

/* Its files, together */
.inbox-files-box { margin-bottom: var(--space-3); padding: var(--space-3) var(--space-4); border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); }
.inbox-files-box h3 { margin: 0 0 var(--space-1); font-size: var(--text-md); }
.inbox-files { list-style: none; margin: 0; padding: 0; }
.inbox-files li { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-3); padding: var(--space-2) 0; border-top: 1px solid var(--border); }
.inbox-files li:first-child { border-top: 0; }
.inbox-files .doc-title-line { flex: 1 1 220px; min-width: 0; }
.inbox-file-from { flex: 1 1 180px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.inbox-file-actions { display: inline-flex; align-items: center; gap: var(--space-2); margin-left: auto; }
.inbox-file-actions form { margin: 0; }
.inbox-files-box > p { margin: var(--space-1-5) 0 0; }

/* Every email in it: the latest open, the others one line each until opened */
.inbox-messages { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--space-2); }
.inbox-message { min-width: 0; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); }
.inbox-message-summary { display: flex; align-items: baseline; gap: var(--space-2-5); padding: var(--space-2-5) var(--space-4); cursor: pointer; list-style: none; }
.inbox-message-summary::-webkit-details-marker { display: none; }
.inbox-message-who { flex-shrink: 0; max-width: 40%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; }
.inbox-message-snippet { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--muted); font-size: var(--text-sm); }
.inbox-message[open] .inbox-message-snippet { visibility: hidden; }
.inbox-message-when { flex-shrink: 0; color: var(--muted); font-size: var(--text-xs); }
.inbox-message-body { padding: 0 var(--space-4) var(--space-3); }
.inbox-headers { display: grid; gap: 3px; margin: 0 0 var(--space-3); padding-bottom: var(--space-2-5); border-bottom: 1px solid var(--border); font-size: var(--text-sm); }
.inbox-headers > div { display: grid; grid-template-columns: 96px minmax(0, 1fr); gap: var(--space-2); }
.inbox-headers dt { color: var(--muted); }
.inbox-headers dd { margin: 0; overflow-wrap: anywhere; }
/* The email's own HTML, in its sandboxed frame: on white, as its sender drew it */
.inbox-body-frame { display: block; width: 100%; height: 60vh; min-height: 320px; border: 1px solid var(--border); border-radius: var(--radius); background: #fff; }
.inbox-body-frame.is-short { height: 240px; min-height: 0; }  /* a few lines: no screen of white under them */
.inbox-body-text { max-height: 60vh; overflow: auto; white-space: pre-wrap; overflow-wrap: anywhere; font-size: var(--text-sm); line-height: 1.55; }
.inbox-message-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-4); margin-top: var(--space-2-5); }
.inbox-message-actions a, .inbox-message-actions .link-button { display: inline-flex; align-items: center; gap: var(--space-1); }
.inbox-message-actions form { margin: 0; }
.inbox-message-actions .icon { width: 14px; height: 14px; }

/* A client's Emails tab */
.inbox-client-list { list-style: none; margin: 0; padding: 0; }
.inbox-client-list li { display: grid; grid-template-columns: 110px minmax(0, 1fr); gap: var(--space-3); padding: var(--space-2) 0; border-top: 1px solid var(--border); }
.inbox-client-list li:first-child { border-top: 0; }
.inbox-client-what { display: flex; flex-direction: column; min-width: 0; overflow-wrap: anywhere; }

/* A narrower screen: one pane at a time. The list until a conversation is open, then the conversation, with the
   way back to the list at its top; the page scrolls as a whole. */
@media (max-width: 899px) {
  .inbox-split { display: block; height: auto; min-height: 0; border: 0; border-radius: 0; background: none; overflow: visible; }
  .inbox-list-col { overflow: visible; border: 1px solid var(--border); border-radius: var(--radius); }
  .inbox-viewer { overflow: visible; background: none; }
  .inbox-split:has(.inbox-thread) .inbox-list-col, .inbox-split:not(:has(.inbox-thread)) .inbox-viewer { display: none; }
  .inbox-thread { padding: 0; }
  .inbox-thread-head { flex-wrap: wrap; }
  .inbox-back { display: inline-flex; flex-basis: 100%; }
  /* The conversation has the screen. The page's heading stays for a screen reader: the rest of the header goes. */
  .inbox-page:has(.inbox-thread) .inbox-header { margin: 0; padding: 0; min-height: 0; }
  .inbox-page:has(.inbox-thread) .inbox-header > :not(:first-child), .inbox-page:has(.inbox-thread) .inbox-header > div > :not(h1) { display: none; }
  .inbox-page:has(.inbox-thread) .inbox-header h1 { position: absolute; width: 1px; height: 1px; margin: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  .inbox-filters { top: 56px; border-radius: calc(var(--radius) - 1px) calc(var(--radius) - 1px) 0 0; }  /* under the sticky top bar; its corners follow the list card's, inside its border */
}
@media (max-width: 560px) {
  .inbox-headers > div, .inbox-client-list li { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .inbox-message-who { max-width: 55%; }
}

/* A draft letter's preview: what's left to fill in, in [square brackets] (letters/render.py) */
mark.letter-blank { padding: 0 var(--space-0-5); border-radius: 3px; background: var(--warning-bg); color: inherit; }


/* --- A task's page (tasks/task_page.html): the work and its thread beside its facts --------------------------------- */
/* One surface in two panes, as Home's: a hairline parts them. Wide, the notes, the files and the thread on the left;
   on the right the facts, then the time and who hears of it. Narrower, the facts, then the thread, then the rest. */
.content.is-read-page { max-width: calc(var(--width-read) + 2 * var(--page-gutter)); }
.task-frame {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(280px, 340px); grid-template-rows: auto 1fr;
  grid-template-areas: "main facts" "main side";
  border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface);
}
.task-body { grid-area: main; min-width: 0; padding: var(--space-5); }
.task-facts { grid-area: facts; min-width: 0; padding: var(--space-5) var(--space-5) var(--space-4); border-left: 1px solid var(--border); }
.task-side { grid-area: side; min-width: 0; padding: 0 var(--space-5) var(--space-2); border-left: 1px solid var(--border); }
.task-side .panel-section { padding: var(--space-4) 0; border-top: 1px solid var(--border); }
.task-side .section-header { margin-bottom: var(--space-2); }
.task-side .entry-list { margin: 0; }
.task-side .entry:first-child { border-top: 0; }
.task-section + .task-section { margin-top: var(--space-7); }
.task-section .section-header { margin-bottom: var(--space-2-5); }
.task-section h2 { font-size: var(--text-md); }
.task-notes { max-width: 72ch; line-height: 1.55; overflow-wrap: anywhere; }

/* The facts: what it is, each a link to change it where it can be changed */
.task-details { display: grid; grid-template-columns: 72px minmax(0, 1fr); gap: var(--space-3) var(--space-3); margin: 0; }
.task-details dt { padding-top: var(--space-0-5); color: var(--muted); font-size: var(--text-sm); }
.task-details dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }
.fact-edit {
  display: inline-flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-2); max-width: 100%;
  margin: calc(-1 * var(--space-0-5)) calc(-1 * var(--space-1-5)); padding: var(--space-0-5) var(--space-1-5);
  border-radius: var(--radius-sm); color: var(--text);
}
.fact-edit:hover { background: var(--surface-3); text-decoration: none; }
.fact-edit-icon { width: 14px; height: 14px; color: var(--muted); }
.fact-edit:hover .fact-edit-icon { color: var(--text); }
.person { display: inline-flex; align-items: center; gap: var(--space-1-5); }
.person .avatar-small, .follower-list .avatar-small, .menu-item .avatar-small, .notice-item .avatar-small { box-shadow: none; }
.fact-form { margin-top: var(--space-2); }

/* The files: added by themselves or with a comment, each opened by its name */
.file-list { list-style: none; margin: 0; padding: 0; }
.file-row { display: flex; align-items: center; gap: var(--space-2-5); padding: var(--space-2) 0; }
.file-row + .file-row { border-top: 1px solid var(--border); }
.file-row-main { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.file-row-main > a { font-weight: 500; color: var(--text); }
.file-row-main > a:hover { color: var(--link); }
.file-row .icon-button, .notice-head .icon-button { width: 32px; height: 32px; color: var(--muted); }
.file-row .icon-button:hover, .notice-head .icon-button:hover { color: var(--text); }
.file-row .icon-button .icon, .notice-head .icon-button .icon { width: 16px; height: 16px; }
.task-files-empty { margin: 0; }
.file-saved { display: inline-flex; align-items: center; gap: var(--space-1); color: var(--success-text); white-space: nowrap; }
.file-saved .icon { width: 14px; height: 14px; }
.task-files-form { border-radius: var(--radius); }
.task-files-form.is-dragging { outline: 2px dashed var(--primary); outline-offset: var(--space-1); background: var(--primary-soft); }
/* A client's task's requests (tasks/_requests.html): a line each, saying where it stands, that opens in place to show
   its items, past the chevron, as the subtasks and files around it are listed */
.request-menu .menu-panel { left: auto; right: 0; width: min(360px, calc(100vw - 2 * var(--page-gutter))); max-height: 320px; overflow-y: auto; z-index: 30; }
.request-menu .menu-item { flex-direction: column; align-items: flex-start; gap: 0; white-space: normal; }
.request-menu-title { font-weight: 500; overflow-wrap: anywhere; }
.request-list { list-style: none; margin: 0; padding: 0; }
.request-row + .request-row { border-top: 1px solid var(--border); }
.request-disclosure > summary {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-2-5); min-height: var(--control-height);
  padding: var(--space-2) 0; border-radius: var(--radius-sm); list-style: none; cursor: pointer;
}
.request-disclosure > summary::-webkit-details-marker { display: none; }
.request-chevron { width: 16px; height: 16px; flex-shrink: 0; color: var(--muted); transition: transform 0.15s; }
.request-disclosure[open] .request-chevron { transform: rotate(90deg); }
.request-title { flex: 1 1 12rem; min-width: 0; font-weight: 500; overflow-wrap: anywhere; }
.request-disclosure > summary:hover .request-title { color: var(--link); }
.request-meta { display: inline-flex; flex-wrap: wrap; align-items: center; gap: var(--space-1-5) var(--space-2-5); }
.request-meta .badge + .badge { margin-left: calc(-1 * var(--space-1)); }
.request-meta .todo-progress progress { width: 70px; }
.request-body { padding: 0 0 var(--space-3) calc(16px + var(--space-2-5)); }
.request-items { list-style: none; margin: 0 0 var(--space-2-5); padding: 0; }
.request-item { display: flex; align-items: flex-start; gap: var(--space-2-5); padding: var(--space-1-5) 0; }
.request-item + .request-item { border-top: 1px solid var(--border); }
.request-item > .todo-check { width: 20px; height: 20px; margin-top: 0; }
.request-item > .todo-check .icon { width: 11px; height: 11px; }
.request-item-main { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.request-item .review-label { font-weight: 500; }
.request-item-answer { color: var(--text-2); }
.request-item-state { display: inline-flex; flex-wrap: wrap; justify-content: flex-end; gap: var(--space-1); padding-top: 1px; white-space: nowrap; }
.request-accepted { color: var(--success-text); }
.request-item .review-response { margin-top: var(--space-1-5); }  /* an answer to review, in full (tasks/_requests.html) */
.request-review-actions { display: flex; flex-wrap: wrap; align-items: flex-start; gap: var(--space-1-5); margin-top: var(--space-2); }
.request-review-actions .send-back[open] { flex-basis: 100%; }  /* its note box under the buttons, within the item */
.request-review-actions .send-back-form { width: min(340px, 100%); }
.request-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.request-unlink { margin-left: auto; }
@media (max-width: 720px) {
  .request-body { padding-left: 0; }
}

/* A file input inside a button: the button is what's seen and clicked, the input under it takes the files */
label:has(> .file-input-hidden) { position: relative; overflow: hidden; cursor: pointer; }
.file-input-hidden { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; }
label:has(> .file-input-hidden:focus-visible) { outline: 2px solid var(--primary); outline-offset: 2px; }
.file-chip {
  display: inline-flex; align-items: center; gap: var(--space-2); max-width: 100%; min-height: var(--control-height);
  padding: var(--space-1) var(--space-2-5) var(--space-1) var(--space-1-5); border: 1px solid var(--border); border-radius: var(--radius-md);
  color: var(--text); font-size: var(--text-sm);
}
.file-chip:hover { border-color: var(--border-strong); background: var(--surface-2); text-decoration: none; }
.file-chip-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 500; }
.file-chip-size { color: var(--muted); white-space: nowrap; }

/* The thread: changes as quiet lines with an icon in the avatars' column, comments as cards */
.thread { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-3); }
.thread-event { display: flex; gap: var(--space-2-5); align-items: flex-start; color: var(--text-2); font-size: var(--text-sm); }
.thread-event p { min-width: 0; margin: 0; padding-top: var(--space-1); overflow-wrap: anywhere; }
.thread-event strong { color: var(--text); font-weight: 600; }
.thread-icon { display: inline-grid; place-items: center; width: 28px; height: 28px; flex-shrink: 0; border-radius: 50%; background: var(--surface-3); color: var(--muted); }
.thread-icon .icon { width: 14px; height: 14px; }
.thread-when { margin-left: var(--space-1); color: var(--muted); white-space: nowrap; }
.thread-earlier { padding-left: 38px; }
.thread-empty .empty { padding: var(--space-2) 0; }
.task-comments { display: inline-flex; align-items: center; gap: var(--space-1); margin-left: var(--space-1-5); color: var(--muted); font-size: var(--text-sm); white-space: nowrap; }
.task-comments:hover { color: var(--link); text-decoration: none; }
.task-comments .icon { width: 14px; height: 14px; }
.task-comments.is-done { color: var(--success-text); }
/* Where a task's requests stand (tasks/queries.py, request_chip): answers to review stand out as the firm's turn,
   late is red, complete is green; with the client, or not sent, it's quiet like the other counts */
.task-requests.is-review { padding: 0 var(--space-1-5); border-radius: var(--radius-full); background: var(--warning-bg); color: var(--warning-text); font-weight: 500; }
.task-requests.is-review:hover { color: var(--warning-text); text-decoration: underline; }
.task-requests.is-overdue { color: var(--danger); }

/* A task's subtasks: a line each, its tick in the avatars' column; who ticked it beside it; Change and Delete on
   hover or focus (always, on a touch screen) */
.count.is-done { background: var(--success-bg); color: var(--success-text); }
.subtask-list { list-style: none; margin: 0 0 var(--space-1); padding: 0; }
.subtask { display: flex; align-items: center; gap: var(--space-2-5); min-height: var(--control-height); padding: var(--space-0-5) 0; }
.subtask + .subtask { border-top: 1px solid var(--border); }
.subtask > form:first-child { display: flex; justify-content: center; width: 28px; flex-shrink: 0; }  /* in the avatars' column */
.subtask-title { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.subtask.is-done .subtask-title { color: var(--muted); text-decoration: line-through; }
.subtask-who { white-space: nowrap; }
.subtask-actions { display: inline-flex; gap: var(--space-0-5); }
.subtask-actions .icon-button { width: 28px; height: 28px; color: var(--muted); }
.subtask-actions .icon-button:hover { color: var(--text); }
.subtask-actions .icon-button .icon { width: 15px; height: 15px; }
@media (hover: hover) {
  .subtask-actions { opacity: 0; }
  .subtask:hover .subtask-actions, .subtask:focus-within .subtask-actions { opacity: 1; }
}
.subtask-edit { display: flex; flex: 1; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.subtask-edit input { flex: 1; min-width: 12rem; }
.subtask-add { display: flex; align-items: center; gap: var(--space-2-5); min-height: var(--control-height); border-top: 1px solid var(--border); }
.subtask-list:empty + .subtask-add, .section-header + .subtask-add { border-top: 0; }
.subtask-add-icon { width: 28px; height: 16px; flex-shrink: 0; color: var(--muted); }
.subtask-add input, .subtask-add input:hover, .subtask-add input:focus { flex: 1; min-width: 0; padding-inline: 0; border: 0; background: none; box-shadow: none; }
.subtask-add:focus-within { box-shadow: inset 0 -2px 0 var(--primary); }
.subtasks-done { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin: var(--space-1) 0 var(--space-2); color: var(--success-text); }
.subtasks-done .icon { width: 16px; height: 16px; }
.step-subtasks { margin-top: var(--space-1-5); }
.step-subtasks summary { cursor: pointer; color: var(--link); }
.step-subtasks textarea { width: 100%; margin-top: var(--space-1-5); }
.thread-new {
  display: flex; align-items: center; gap: var(--space-2); color: var(--link); font-size: var(--text-xs); font-weight: 600;
  letter-spacing: 0.05em; text-transform: uppercase;
}
.thread-new::before, .thread-new::after { content: ""; flex: 1; height: 1px; background: var(--info-border); }
.thread-comment { display: flex; gap: var(--space-2-5); align-items: flex-start; }
.comment-card { flex: 1; min-width: 0; padding: var(--space-2-5) var(--space-3) var(--space-3); border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); }
.thread-comment.is-new .comment-card { border-color: var(--info-border); }
.thread-comment:target .comment-card, .thread-event:target .thread-icon { box-shadow: 0 0 0 2px var(--primary); }
.comment-head { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-2); min-height: 22px; font-size: var(--text-sm); }
.comment-head strong { color: var(--text); font-weight: 600; }
.comment-when { color: var(--muted); }
a.comment-when:hover { color: var(--link); }
.comment-actions { display: inline-flex; align-items: center; gap: var(--space-2); margin-left: auto; }
.thread-comment.is-replied .comment-card { box-shadow: 0 0 0 2px var(--primary); }
.comment-menu > summary.icon-button { width: 28px; height: 28px; margin: calc(-1 * var(--space-1)) calc(-1 * var(--space-1-5)) calc(-1 * var(--space-1)) 0; color: var(--muted); }
.comment-menu > summary.icon-button:hover, .comment-menu[open] > summary.icon-button { color: var(--text); }
.comment-menu > summary .icon { width: 16px; height: 16px; }
.comment-body { margin-top: var(--space-1); line-height: 1.55; overflow-wrap: anywhere; }
.comment-files { list-style: none; margin: var(--space-2-5) 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: var(--space-2); }
.comment-files li { max-width: 100%; }
.comment-picture { display: block; }
.comment-picture img { display: block; max-width: min(260px, 100%); max-height: 200px; border: 1px solid var(--border); border-radius: var(--radius-md); object-fit: cover; }
.comment-edit { flex: 1; min-width: 0; }
.comment-edit textarea { display: block; width: 100%; min-height: 76px; field-sizing: content; resize: vertical; }
.comment-edit .actions { margin-top: var(--space-2); }
/* Someone named with @; the reader's own waits on them, so it's amber */
.mention { padding: 0 var(--space-0-5); border-radius: var(--radius-sm); background: var(--primary-soft); color: var(--link); font-weight: 600; }
.mention.is-you { background: var(--warning-bg); color: var(--warning-text); }

/* The comment box: the words, the files chosen as chips, then a bar with Add files, who sees it, and Comment */
.composer { display: flex; gap: var(--space-2-5); align-items: flex-start; margin-top: var(--space-4); }
.composer-box { flex: 1; min-width: 0; border: 1px solid var(--control-border); border-radius: var(--radius); background: var(--surface); }
.composer-box:hover { border-color: var(--muted); }
.composer-box:focus-within { border-color: var(--primary); box-shadow: 0 0 0 3px var(--focus-ring); }
.composer.is-dragging .composer-box { border-color: var(--primary); background: var(--primary-soft); }
.composer textarea, .composer textarea:hover, .composer textarea:focus {
  display: block; width: 100%; min-height: 64px; max-height: 50vh; padding: var(--space-2-5) var(--space-3); border: 0;
  border-radius: var(--radius) var(--radius) 0 0; background: none; box-shadow: none; outline: none; resize: none; field-sizing: content;
}
.composer-files { list-style: none; margin: 0; padding: 0 var(--space-3) var(--space-2); display: flex; flex-wrap: wrap; gap: var(--space-1-5); }
.composer-files[hidden] { display: none; }
.composer-file {
  display: inline-flex; align-items: center; gap: var(--space-1); max-width: 100%; min-height: var(--control-height-sm);
  padding: 0 var(--space-0-5) 0 var(--space-2); border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--surface-2); font-size: var(--text-sm);
}
.composer-file span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.composer-file .icon-button { width: 24px; height: 24px; color: var(--muted); }
.composer-file .icon-button .icon { width: 14px; height: 14px; }
.composer-bar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); padding: var(--space-1-5) var(--space-2); border-top: 1px solid var(--border); }
.composer-note { flex: 1; min-width: 0; }

/* @ suggestions under the box being written in (static/js/app.js, "Mentions") */
.mention-list {
  position: fixed; z-index: 60; min-width: 220px; max-width: 320px; max-height: 264px; overflow-y: auto; margin: 0; padding: var(--space-1);
  list-style: none; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); box-shadow: var(--shadow-md);
}
.mention-list[hidden] { display: none; }
.mention-option { display: flex; align-items: center; gap: var(--space-2); min-height: var(--control-height); padding: var(--space-1) var(--space-2); border-radius: var(--radius-md); color: var(--text); cursor: pointer; }
.mention-option:hover, .mention-option.is-active { background: var(--surface-3); }
.mention-option .avatar-small { box-shadow: none; }
.mention-empty { padding: var(--space-2); color: var(--muted); font-size: var(--text-sm); }

/* Who hears of it: its followers, and what it tells the person looking */
.follower-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-2); }
.follower-list li { display: flex; align-items: center; gap: var(--space-2); min-width: 0; }
.follower-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.follower-why { color: var(--muted); font-size: var(--text-xs); white-space: nowrap; }
.add-follower .menu-panel { left: auto; right: 0; min-width: 220px; max-height: 320px; overflow-y: auto; }
.notify-choices { display: grid; gap: var(--space-0-5); margin: var(--space-1) 0 0; padding: 0; border: 0; }
.notify-choice {
  display: flex; align-items: flex-start; gap: var(--space-2-5); margin: 0 calc(-1 * var(--space-2)); padding: var(--space-1-5) var(--space-2);
  border-radius: var(--radius-md); cursor: pointer;
}
.notify-choice:hover { background: var(--surface-2); }
.notify-choice input { margin-top: 3px; }
.notify-choice > span { display: flex; flex-direction: column; min-width: 0; }
.notify-choice strong { font-weight: 600; }
.notify-why { margin: var(--space-2) 0 0; }

/* Followers and requests on New task, tasks on a request (includes/picker_field.html): ticks in a menu that names what
   is ticked */
.form .field.picker-field { flex-direction: column; align-items: stretch; flex-wrap: nowrap; }
.field .label-like { font-weight: 600; font-size: var(--text-sm); color: var(--text-2); }
.picker-menu > summary.select-like {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); min-height: var(--control-height);
  padding: 0 var(--space-2-5) 0 var(--space-2-5); border: 1px solid var(--control-border); border-radius: var(--radius-md); background: var(--surface); cursor: pointer;
}
.picker-menu > summary.select-like:hover { border-color: var(--muted); }
.picker-menu > summary.select-like > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.picker-menu .menu-panel { max-height: 280px; overflow-y: auto; }
.picker-menu .menu-item { white-space: normal; }  /* a task or a request with its date and what it's for */
.field .check-item { font-weight: 400; font-size: var(--text-base); color: var(--text); }

@media (max-width: 1100px) {
  .task-frame { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto; grid-template-areas: "facts" "main" "side"; }
  .task-facts, .task-side { border-left: 0; }
  .task-body { border-top: 1px solid var(--border); }
}
@media (max-width: 720px) {
  .task-body { padding: var(--space-4); }
  .task-facts { padding: var(--space-4) var(--space-4) var(--space-3); }
  .task-side { padding: 0 var(--space-4) var(--space-2); }
  .composer > .avatar, .thread-comment > .avatar { display: none; }
  .composer-note { flex-basis: 100%; order: 1; }
  .composer-bar .btn-primary { margin-left: auto; }
  .thread-earlier { padding-left: 0; }
}

/* --- Notifications (tasks/notifications.html): each task with something new, then the ones read lately --------- */
.notifications-bar {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-2);
  margin-bottom: var(--stack-gap);
}
.count.is-new { background: var(--info-bg); color: var(--info-text); }
.count[hidden] { display: none; }
/* One card: New, its tasks, Earlier, its tasks; a hairline parts each from the next */
.notice-list { border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); }
.notice-list > * + * { border-top: 1px solid var(--border); }
.notice-heading {
  display: flex; align-items: center; gap: var(--space-2); margin: 0; padding: var(--space-2) var(--space-4);
  color: var(--muted); font-size: var(--text-xs); font-weight: 600; letter-spacing: 0.05em; text-transform: uppercase;
}
.notice-group { padding: var(--space-3) var(--space-4); }
.notifications .load-more { margin-top: var(--space-3); }
.notice-head { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-2); }
.notice-dot { width: 8px; height: 8px; flex-shrink: 0; border-radius: 50%; background: var(--primary); }
.notice-task { min-width: 0; color: var(--text); font-weight: 600; overflow-wrap: anywhere; }
.notice-task:hover { color: var(--link); }
.notice-head form { margin: calc(-1 * var(--space-1)) calc(-1 * var(--space-1-5)) calc(-1 * var(--space-1)) auto; }
.notice-items { list-style: none; margin: var(--space-1-5) 0 0; padding: 0; display: grid; gap: var(--space-0-5); }
.notice-item { display: flex; align-items: flex-start; gap: var(--space-2); margin: 0 calc(-1 * var(--space-2)); padding: var(--space-1-5) var(--space-2); border-radius: var(--radius-md); color: var(--text-2); }
.notice-item:hover { background: var(--surface-2); text-decoration: none; }
.notice-item.is-new { color: var(--text); }
.notice-text { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.notice-text strong { color: var(--text); font-weight: 600; }
.notice-quote { display: block; margin-top: var(--space-0-5); color: var(--muted); font-size: var(--text-sm); }
.notice-time { padding-top: var(--space-0-5); white-space: nowrap; }
.notice-more { padding-left: var(--space-8); }
@media (max-width: 560px) {
  .notice-group { padding: var(--space-3); }
  .notice-time { display: none; }
}
