/* Walter Wealth Document Studio — interface chrome
   Brand: Ink #062A30 · Sage #BAC4B9 · Light Sage #D9DDD8 · Sand #F8F4F0 · Sky #DBE5E6 */

* { box-sizing: border-box; margin: 0; padding: 0; }

:root {
  --ink: #062A30;
  --ink-2: #0a3a40;
  --sage: #BAC4B9;
  --sage-light: #D9DDD8;
  --sand: #F8F4F0;
  --sky: #DBE5E6;
  --teal: #4e6a6a;
  --mist: #b6c0bc;

  /* Motion, shared with the guide page so the two surfaces move alike. */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease: cubic-bezier(0.32, 0.72, 0, 1);
  --t-fast: 160ms;
  --t-mid: 320ms;

  /* Every text control reads from this. iOS zooms the page whenever a focused
     field is under 16px, which on a phone throws the whole layout sideways
     mid-sentence — so the mobile block lifts it rather than each rule guessing. */
  --control-font: 13.5px;
}

html, body { height: 100%; }
/* dvh so the chrome of a mobile browser cannot clip the bottom bar. */
body { height: 100dvh; }

/* Keyboard users get a visible ring; pointer users never see it. */
:focus-visible {
  outline: 2px solid var(--teal);
  outline-offset: 2px;
  border-radius: 4px;
}
.topbar :focus-visible { outline-color: var(--sage); }

body {
  font-family: 'Inter', 'Helvetica Neue', Arial, sans-serif;
  background: var(--sand);
  color: var(--ink);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* ── Boot overlay ────────────────────────────────────── */

.boot {
  position: fixed;
  inset: 0;
  z-index: 200;
  /* A soft lift behind the card rather than a flat field — no extra request. */
  background: radial-gradient(1100px 620px at 50% 24%, var(--ink-2), var(--ink) 62%);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  opacity: 1;
  transition: opacity var(--t-mid) var(--ease-out);
  /* Fail-safe, in CSS so it holds even if app.js never loads: the overlay is
     the only thing between a user and the tool, and it must not be able to
     become a locked door. JS normally removes it in a few hundred ms. */
  animation: boot-failsafe 0s 8s forwards;
}
@keyframes boot-failsafe { to { opacity: 0; visibility: hidden; pointer-events: none; } }
/* Removed from the DOM once faded, so it can never intercept a click. */
.boot.is-done { opacity: 0; pointer-events: none; }

.boot-card {
  text-align: center;
  max-width: 430px;
  padding: 44px 44px 38px;
  border: 1px solid rgba(186, 196, 185, 0.13);
  border-radius: 20px;
  background: rgba(255, 255, 255, 0.015);
  animation: boot-in var(--t-mid) var(--ease-out) both;
}
@keyframes boot-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

.boot-logo { height: 26px; width: auto; display: block; margin: 0 auto; }
.boot-rule { display: block; width: 34px; height: 1px; background: var(--teal); margin: 22px auto; }
.boot-title { font-size: 25px; font-weight: 700; letter-spacing: -0.01em; color: #fff; }
.boot-tagline {
  font-family: 'Playfair Display', Georgia, serif;
  font-style: italic; font-weight: 500;
  font-size: 15px; color: var(--sage);
  margin-top: 7px;
}

.boot-ring { position: relative; width: 104px; height: 104px; margin: 30px auto 24px; }
.boot-ring svg { width: 100%; height: 100%; transform: rotate(-90deg); }
.boot-track, .boot-arc { fill: none; stroke-width: 3; }
.boot-track { stroke: rgba(186, 196, 185, 0.14); }
.boot-arc {
  stroke: var(--sage-light);
  stroke-linecap: round;
  /* 2πr for r=44. The offset is set from real milestones, not a clock. */
  stroke-dasharray: 276.5;
  stroke-dashoffset: 276.5;
  transition: stroke-dashoffset var(--t-mid) var(--ease-out);
}
.boot-mark {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: 34px; height: auto;
  opacity: 0.9;
}

.boot-status { font-size: 13.5px; color: var(--sage-light); }
.boot-note { font-size: 12px; color: var(--teal); margin-top: 26px; }

/* ── Top bar ─────────────────────────────────────────── */

.topbar {
  background: var(--ink);
  color: #fff;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 18px;
  row-gap: 8px;
  padding: 10px 24px;
  min-height: 64px;
  flex: 0 0 auto;
  /* The actions menu hangs off this bar rather than the page, so it stays put
     under its own button when the tab strip wraps to a second row. */
  position: relative;
}

/* 11px, not the 14 a wordmark needed: the gap was holding "Walter Wealth" off
   the title beside it, and the mark is a third of that width. */
.topbar-brand { display: flex; align-items: center; gap: 11px; min-width: 0; flex: 0 0 auto; }
.topbar-logo { height: 24px; width: auto; display: block; }
.topbar-title { display: flex; flex-direction: column; line-height: 1.25; white-space: nowrap; }
.topbar-app { font-size: 13px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--sage-light); }
.topbar-tagline { font-family: 'Playfair Display', Georgia, serif; font-style: italic; font-weight: 500; font-size: 12px; color: var(--sage); }

/* ── The step picker ─────────────────────────────────────
   One control in the bar instead of a strip of eight. The strip was the busiest
   thing on the screen and still only listed two thirds of the engagement: four
   of the twelve steps are documents somebody else produces, so it numbered what
   was left 2, 3, 5, 6, 8, 9, 10, 12 and the gaps read as a fault. The panel
   below holds all twelve; the bar holds where you are. */
.steps { position: relative; flex: 0 1 auto; min-width: 0; }

.step-pick {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  max-width: 100%;
  appearance: none;
  border: 1px solid rgba(255, 255, 255, 0.18);
  background: rgba(255, 255, 255, 0.06);
  color: #fff;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  padding: 8px 13px;
  border-radius: 999px;
  cursor: pointer;
  transition: background-color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.step-pick:hover { background: rgba(255, 255, 255, 0.12); border-color: var(--teal); }
.step-pick:focus-visible { outline: 2px solid var(--sage-light); outline-offset: 2px; }

/* Tabular figures so "10 of 12" and "4 of 6" do not shift the label between
   documents as you move through the engagement. */
.step-pick-no {
  flex: 0 0 auto;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
  color: var(--sage);
  white-space: nowrap;
}
.step-pick-no:empty { display: none; }
.step-pick-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.step-pick-chev {
  flex: 0 0 auto;
  width: 8px; height: 8px;
  border-right: 1.5px solid var(--sage);
  border-bottom: 1.5px solid var(--sage);
  transform: translateY(-2px) rotate(45deg);
  transition: transform var(--t-fast) var(--ease);
}
.step-pick[aria-expanded="true"] .step-pick-chev { transform: translateY(1px) rotate(-135deg); }

.step-menu {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  z-index: 60;
  /* Wide enough for the longest step name beside the name of whoever owns it:
     "Financial Services Guide given / Alliance Wealth" is the pair that sets it,
     and truncating either half loses the thing the row is there to say. */
  width: 384px;
  max-width: calc(100vw - 32px);
  max-height: min(70vh, 560px);
  overflow-y: auto;
  padding: 8px;
  background: #fff;
  border: 1px solid var(--sage);
  border-radius: 13px;
  box-shadow: 0 14px 40px rgba(6, 42, 48, 0.22);
}
.step-menu[hidden] { display: none; }

.step-phase {
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--mist);
  padding: 10px 8px 5px;
}
.step-phase:first-child { padding-top: 4px; }

.step-row {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 8px 9px;
  border: 1px solid transparent;
  border-radius: 8px;
  background: transparent;
  font: inherit;
  font-size: 13px;
  color: var(--ink);
  text-align: left;
  cursor: pointer;
  transition: background-color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.step-row:hover { background: var(--sand); border-color: var(--sage-light); }
.step-row:focus-visible { outline: 2px solid var(--teal); outline-offset: -2px; }
.step-row.is-current { background: var(--sky); border-color: var(--sage); font-weight: 600; }

.step-no {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px; height: 20px;
  padding: 0 4px;
  border-radius: 999px;
  background: var(--sand);
  color: var(--teal);
  font-size: 10.5px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.step-row.is-current .step-no { background: var(--ink); color: var(--sage-light); }
.step-label { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* A document the studio produces: the row now carries two actions, so it is a
   container with an open control that fills it and a Draft control beside it.
   The open control is unstyled — the row's own padding, border and hover are
   what you see — so tapping it looks and behaves exactly as the whole row did
   before it grew a second button. */
.step-row-ours { cursor: default; }
.step-open {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 0;
  margin: 0;
  border: 0;
  background: transparent;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
}
.step-open:focus-visible { outline: 2px solid var(--teal); outline-offset: 2px; border-radius: 6px; }

/* Draft with AI. A quiet pill so it does not compete with the step number or
   the badge, teal like the other AI touches in the studio. */
.step-draft {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 9px;
  border-radius: 999px;
  border: 1px solid var(--sage);
  background: #fff;
  font: inherit;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--teal);
  cursor: pointer;
  transition: background-color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.step-draft:hover { background: var(--sky); border-color: var(--teal); }
.step-draft .ico { width: 14px; height: 14px; }

/* A step somebody else produces. Quieter than ours, and it says whose it is
   rather than only that it is not a document you can open here. */
.step-row-theirs { cursor: default; color: var(--teal); }
.step-row-theirs .step-no { background: transparent; box-shadow: inset 0 0 0 1px var(--sage-light); }
.step-from {
  flex: 0 0 auto;
  font-size: 10px;
  color: var(--mist);
  white-space: nowrap;
}

/* Mark done, as a button rather than a tick box: an action you press, that then
   reads back "Done" with a check. Still only a record that a document produced
   elsewhere has happened — the studio does not author these. */
.step-tick-btn {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 10px;
  border-radius: 999px;
  border: 1px solid var(--sage-light);
  background: #fff;
  font: inherit;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--teal);
  cursor: pointer;
  transition: background-color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.step-tick-btn:hover { background: var(--sand); border-color: var(--sage); }
.step-tick-btn.is-done { background: var(--sky); border-color: var(--sage); color: var(--ink); }
.step-tick-btn .ico { width: 14px; height: 14px; }
.step-tick-btn:disabled { opacity: 0.5; cursor: default; }
.step-row-theirs.is-done .step-no { box-shadow: inset 0 0 0 1px var(--sage); color: var(--ink); }

/* One weight, one cap style, sized in the type — the set has to read as one
   hand, not as decoration bolted onto each control. */
.ico {
  width: 15px; height: 15px;
  flex: 0 0 auto;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Print / Save PDF holds the corner at every width. It is the only action that
   stayed on the bar: nine of them across the top left the tab strip fighting for
   room, and everything else here is pressed once a document rather than once a
   sentence, which is what a menu is for. Print and the menu button share one
   group so they wrap as a pair — apart, the bar running a few pixels short put
   Print on the first row and left Menu alone on the second. */
.topbar-right { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; margin-left: auto; }

/* Who is signed in. Quiet by design: it is a fact you check, not a control, and
   the bar already has two things competing to be pressed. The role rides with
   the name because what the studio offers differs by it, and someone who cannot
   find Finalise should be able to see why without asking. */
.topbar-who {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  padding: 5px 10px;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.16);
  background: rgba(255, 255, 255, 0.06);
  white-space: nowrap;
  cursor: default;
}
.topbar-who[hidden] { display: none; }
/* .btn sets display: inline-flex, which outranks the hidden attribute's own
   display:none — so the button would show even while hidden without this. Same
   reason topbar-who needs its own rule above. */
.topbar-signin[hidden] { display: none; }
.topbar-who-name { font-size: 12.5px; font-weight: 600; color: #fff; }
.topbar-who-role {
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--sage);
}
/* An assistant cannot issue advice, so the button that does it reads as
   unavailable rather than disappearing — the overlay behind it is where the
   reason lives, and a button that removes itself takes the reason with it. */
.btn-finalise[data-permitted="no"] { opacity: 0.55; }

/* The menu itself. A dropdown under the hamburger at desktop widths, and a
   bottom sheet below 900px — same markup, same handlers, two shapes. */
.topbar-more {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  flex: 0 0 auto;
  appearance: none;
  border: 1px solid var(--teal);
  background: transparent;
  color: var(--sage-light);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  border-radius: 999px;
  padding: 8px 13px;
  cursor: pointer;
  transition:
    background-color var(--t-fast) var(--ease),
    border-color var(--t-fast) var(--ease),
    color var(--t-fast) var(--ease);
}
.topbar-more:hover { color: #fff; border-color: var(--sage); }
body[data-actions="open"] .topbar-more { background: var(--teal); color: #fff; border-color: var(--sage); }

.topbar-actions {
  position: absolute;
  top: calc(100% - 8px);
  right: 24px;
  z-index: 60;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 3px;
  min-width: 236px;
  padding: 8px;
  background: var(--ink);
  border: 1px solid var(--teal);
  border-radius: 14px;
  box-shadow: 0 22px 48px rgba(6, 42, 48, 0.38);
  /* visibility, not display, so the panel can transition and still be skipped by
     the tab order while it is shut. */
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px);
  transition:
    opacity var(--t-fast) var(--ease-out),
    transform var(--t-fast) var(--ease-out),
    visibility var(--t-fast);
}
body[data-actions="open"] .topbar-actions { opacity: 1; visibility: visible; transform: none; }
.topbar-actions .btn { width: 100%; justify-content: flex-start; border-radius: 10px; padding: 9px 11px; }

/* Separates the two that change what is on screen from the five that do the
   work — Load sample and Reset overwrite a draft, and should not sit a pixel
   from Save. */
.topbar-menu-rule { height: 1px; background: var(--teal); margin: 5px 4px; }

.btn {
  appearance: none;
  border: 1px solid transparent;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  padding: 8px 11px;
  border-radius: 999px;
  cursor: pointer;
  white-space: nowrap;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  transition:
    background-color var(--t-fast) var(--ease),
    border-color var(--t-fast) var(--ease),
    color var(--t-fast) var(--ease),
    transform var(--t-fast) var(--ease),
    opacity var(--t-fast) var(--ease);
}
/* A small give on press — the one piece of feedback a pointer can feel. */
.btn:active { transform: scale(0.97); }
.btn:disabled:active { transform: none; }
.btn-primary { background: var(--sage-light); color: var(--ink); }
.btn-primary:hover { background: #fff; }
.btn-ghost { background: transparent; color: var(--sage-light); border-color: var(--teal); }
.btn-ghost:hover { color: #fff; border-color: var(--sage); background: rgba(255, 255, 255, 0.06); }

/* ── Workspace ───────────────────────────────────────── */

.workspace { display: flex; flex: 1 1 auto; min-height: 0; position: relative; }

.panel {
  flex: 0 0 400px;
  background: #fff;
  border-right: 1px solid var(--sage-light);
  min-height: 0;
  display: flex;
  flex-direction: column;
}
.panel-scroll { overflow-y: auto; width: 100%; flex: 1 1 auto; padding: 20px 22px 40px; }

/* The save status sits with the form it reports on, not in the topbar, where it
   was competing with the tabs for the same row. */
.panel-foot {
  flex: 0 0 auto;
  border-top: 1px solid var(--sage-light);
  padding: 9px 22px;
  background: #fcfbfa;
  min-height: 38px;
  display: flex;
  align-items: center;
  justify-content: flex-end;
}
.edit-status {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 11.5px;
  color: var(--teal);
  white-space: nowrap;
  transition: opacity var(--t-mid) var(--ease);
}
.edit-status:empty { opacity: 0; }
.edit-status::before {
  content: '';
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--sage);
  transition: background-color var(--t-fast) var(--ease), opacity var(--t-fast) var(--ease);
}
.edit-status[data-state="saving"] { color: var(--mist); }
.edit-status[data-state="saving"]::before { opacity: 0.45; }

/* Small caps label that heads a region of the panel. */
.panel-label {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--teal);
  margin-bottom: 9px;
}
.panel-label-divider {
  margin: 22px 0 10px;
  padding-top: 16px;
  border-top: 1px solid var(--sage-light);
  color: var(--mist);
}

/* The preview renders a real 210mm sheet, which is 794px wide and cannot
   reflow — narrowing it would stop it being a preview. So on anything narrower
   the whole frame is scaled down to fit instead: the iframe is laid out at its
   full size and shrunk, which keeps the page proportioned exactly as it prints.
   --pv-scale is set from the measured container width in app.js; at desktop
   widths it stays 1 and these calcs collapse to the plain 100%. */
.preview { flex: 1 1 auto; min-width: 0; background: #e7e3de; overflow: hidden; }
.preview iframe {
  width: calc(100% / var(--pv-scale, 1));
  height: calc(100% / var(--pv-scale, 1));
  border: 0;
  display: block;
  transform: scale(var(--pv-scale, 1));
  transform-origin: 0 0;
}

/* ── Form ────────────────────────────────────────────── */

.form-note {
  display: flex;
  gap: 10px;
  background: var(--sand);
  border: 1px solid var(--sage-light);
  border-radius: 12px;
  padding: 12px 14px;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--ink);
  margin-bottom: 4px;
}
.form-note .ico { color: var(--mist); margin-top: 2px; }

.form-group {
  border: 1px solid var(--sage-light);
  border-radius: 12px;
  margin-bottom: 8px;
  background: #fff;
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.form-group:hover { border-color: var(--sage); }
.form-group[open] {
  border-color: var(--sage);
  box-shadow: 0 1px 3px rgba(6, 42, 48, 0.05);
}
.form-group > summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 14px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--teal);
  user-select: none;
  border-radius: 12px;
}
.form-group > summary::-webkit-details-marker { display: none; }
.form-group > summary .ico { color: var(--mist); transition: color var(--t-fast) var(--ease); }
.form-group > summary:hover .ico,
.form-group[open] > summary .ico { color: var(--teal); }
.group-label { flex: 1 1 auto; min-width: 0; }
/* One chevron that turns, rather than a plus that becomes a minus. */
.group-chevron { transition: transform var(--t-mid) var(--ease); }
.form-group[open] > summary .group-chevron { transform: rotate(180deg); }
.form-group-body { padding: 2px 14px 14px; }

.field { margin-bottom: 14px; }
.field-label { display: block; font-size: 12.5px; font-weight: 500; color: var(--ink); margin-bottom: 5px; }
.field-hint { font-size: 11.5px; color: var(--teal); margin-top: 4px; line-height: 1.45; }

.field input[type="text"],
.field input[type="date"],
.field select,
.field textarea {
  width: 100%;
  font: inherit;
  font-size: var(--control-font);
  color: var(--ink);
  background: var(--sand);
  border: 1px solid var(--sage-light);
  border-radius: 8px;
  padding: 9px 11px;
  transition:
    background-color var(--t-fast) var(--ease),
    border-color var(--t-fast) var(--ease);
}
.field input:hover, .field select:hover, .field textarea:hover { border-color: var(--sage); }
.field textarea { min-height: 84px; resize: vertical; line-height: 1.5; }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: 2px solid var(--sage);
  outline-offset: 0;
  background: #fff;
}

/* Repeating rows (lists, tables, blocks) */
.rep-item { border: 1px solid var(--sage-light); border-radius: 10px; padding: 12px; margin-bottom: 10px; background: #fcfbfa; position: relative; }
.rep-item .field:last-of-type { margin-bottom: 0; }
.rep-row { display: flex; gap: 8px; margin-bottom: 8px; align-items: flex-start; }
.rep-row input, .rep-row textarea { flex: 1 1 auto; }

.rep-remove {
  appearance: none; border: 0; background: transparent;
  color: var(--teal); font-size: 16px; line-height: 1;
  cursor: pointer; padding: 6px;
}
.rep-remove:hover { color: #8a3b2e; }
.rep-item > .rep-remove { position: absolute; top: 8px; right: 8px; }

.rep-add {
  appearance: none;
  border: 1px dashed var(--sage);
  background: transparent;
  color: var(--teal);
  font: inherit; font-size: 12.5px; font-weight: 500;
  border-radius: 8px;
  padding: 8px 12px;
  cursor: pointer;
  width: 100%;
}
.rep-add:hover { background: var(--sand); }

.rep-sub-label { font-size: 11px; font-weight: 600; letter-spacing: 0.05em; text-transform: uppercase; color: var(--mist); display: block; margin: 8px 0 4px; }
.rep-item .rep-sub-label:first-child { margin-top: 0; }

/* Image picker: a thumbnail of the current choice above its dropdown, so the
   adviser sees the image they are placing rather than choosing a name blind. */
.field-image-preview {
  width: 100%;
  aspect-ratio: 16 / 9;
  border-radius: 8px;
  overflow: hidden;
  background: var(--sky);
  border: 1px solid var(--sage-light);
  margin-bottom: 8px;
}
.field-image-preview img { width: 100%; height: 100%; object-fit: cover; display: block; }
.field-image-preview.is-empty {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  color: var(--mist);
  aspect-ratio: 16 / 5;
}

/* The Save that folds a collapsible row (file notes). Full width under the
   fields, quiet — the data already saved as it was typed. */
.rep-save {
  appearance: none;
  border: 1px solid var(--sage);
  background: #fff;
  color: var(--ink);
  font: inherit; font-size: 12.5px; font-weight: 600;
  border-radius: 8px;
  padding: 7px 12px;
  margin-top: 10px;
  cursor: pointer;
  width: 100%;
  transition: background var(--t-fast) var(--ease-out), border-color var(--t-fast) var(--ease-out);
}
.rep-save:hover { background: var(--sand); border-color: var(--teal); }

/* A saved row, folded to a summary: the short fields as chips, the note under
   them, and Edit / Remove to the side. */
.rep-saved {
  border: 1px solid var(--sage-light);
  border-left: 3px solid var(--sage);
  border-radius: 10px;
  padding: 10px 12px;
  margin-bottom: 8px;
  background: #fff;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px 10px;
}
.rep-saved-main { display: flex; flex-wrap: wrap; gap: 6px; flex: 1 1 auto; min-width: 0; }
.rep-chip {
  font-size: 12px;
  font-weight: 600;
  color: var(--ink);
  background: var(--sky);
  border-radius: 6px;
  padding: 2px 7px;
  white-space: nowrap;
}
.rep-saved-note {
  flex: 1 1 100%;
  order: 3;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--ink-2);
  margin: 0;
  white-space: pre-wrap;
}
.rep-saved-actions { display: flex; align-items: center; gap: 2px; flex: 0 0 auto; }
.rep-edit {
  appearance: none; border: 0; background: transparent;
  color: var(--teal); font: inherit; font-size: 12px; font-weight: 600;
  cursor: pointer; padding: 4px 8px; border-radius: 6px;
}
.rep-edit:hover { background: var(--sand); color: var(--ink); }

/* ── AI draft panel ──────────────────────────────────────── */

/* No card around the notes: the panel's own white is the surface, and the
   "Document sections" rule below is what separates drafting from editing. */
.ai-panel { margin-bottom: 0; }
.ai-panel textarea {
  width: 100%;
  font: inherit;
  font-size: var(--control-font);
  color: var(--ink);
  background: var(--sand);
  border: 1px solid var(--sage-light);
  border-radius: 10px;
  padding: 10px 12px;
  min-height: 84px;
  line-height: 1.5;
  resize: vertical;
  transition:
    background-color var(--t-fast) var(--ease),
    border-color var(--t-fast) var(--ease);
}
.ai-panel textarea:hover { border-color: var(--sage); }
.ai-panel textarea:focus { outline: 2px solid var(--sage); outline-offset: 0; background: #fff; }

/* Attached reference documents */

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

.ai-files { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 9px; }
.ai-files.hidden { display: none; }
/* Needed because .btn sets display, which the UA stylesheet's [hidden] loses to. */
.ai-collect.hidden { display: none; }

.ai-file {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  max-width: 100%;
  background: #fff;
  border: 1px solid var(--sage);
  border-radius: 999px;
  padding: 4px 6px 4px 11px;
  font-size: 12px;
  line-height: 1.4;
  /* Each chip arrives on its own rather than snapping into the row. */
  animation: chip-in var(--t-mid) var(--ease-out) both;
}
@keyframes chip-in {
  from { opacity: 0; transform: translateY(-4px) scale(0.96); }
  to   { opacity: 1; transform: none; }
}
.ai-file-name {
  max-width: 190px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 500;
}
.ai-file-size { color: var(--teal); font-variant-numeric: tabular-nums; }
.ai-file-remove {
  appearance: none;
  border: 0;
  background: var(--sky);
  color: var(--ink);
  font: inherit;
  font-size: 14px;
  line-height: 1;
  width: 19px; height: 19px;
  border-radius: 50%;
  cursor: pointer;
  flex: 0 0 auto;
  transition: background-color var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
}
.ai-file-remove:hover { background: var(--sage); }
.ai-file-remove:active { transform: scale(0.9); }

/* Primary action on its own row; the two secondary actions share the next. */
.ai-panel-actions {
  margin-top: 10px;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
/* The sage-light fill of .btn-primary is near-invisible on a light panel, so
   the studio's main action carries the ink instead. */
.ai-panel-actions .btn-primary {
  flex: 1 1 100%;
  justify-content: center;
  background: var(--ink);
  color: var(--sage-light);
  padding: 11px 16px;
  border-radius: 10px;
}
.ai-panel-actions .btn-primary:hover { background: var(--ink-2); color: #fff; }
/* The two secondary actions share the row evenly, rather than one of them
   sitting short because its label is shorter. */
.ai-panel-actions .btn-import { flex: 1 1 0; justify-content: center; border-radius: 10px; }

/* Secondary action in the notes panel (light background, so it needs its own
   ghost colours rather than the topbar's .btn-ghost) */
.btn-import { background: transparent; color: var(--teal); border-color: var(--sage); }
.btn-import:hover { color: var(--ink); border-color: var(--teal); }

.btn.is-loading { opacity: 0.6; cursor: default; }

.ai-status { font-size: 12px; line-height: 1.5; color: var(--teal); margin-top: 8px; min-height: 1em; }
.ai-status.error { color: #8a3b2e; font-weight: 500; }

/* ── Ask AI to edit ─────────────────────────────────────────── */
/* A second act below the drafting controls, ruled off so it does not read as
   another draft button. It writes changes to a document that already exists, so
   it earns its own space and its own review. */
.ai-edit { margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--line, #e4e6e0); }
.ai-edit .panel-label { margin-bottom: 6px; }
.ai-edit-input {
  width: 100%;
  min-height: 56px;
  resize: vertical;
}

/* The proposed change, shown before it is applied. Tinted so a review on screen
   is unmistakably a pending thing, not part of the document yet. */
.ai-edit-review { margin-top: 12px; }
.ai-edit-review:empty { margin-top: 0; }
.ai-edit-review-head { font-size: 12px; font-weight: 600; color: var(--ink); margin: 0 0 10px; }
.ai-edit-change {
  background: var(--sage-light, #eef1ea);
  border: 1px solid var(--sage, #cdd5c4);
  border-radius: 10px;
  padding: 10px 12px;
  margin-bottom: 8px;
}
.ai-edit-change-label {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--teal);
  margin-bottom: 6px;
}
.ai-edit-change-from {
  font-size: 12px;
  line-height: 1.5;
  color: #8a7f76;
  text-decoration: line-through;
  text-decoration-color: rgba(138, 59, 46, 0.4);
  margin-bottom: 4px;
  white-space: pre-wrap;
}
.ai-edit-change-to {
  font-size: 13px;
  line-height: 1.55;
  color: var(--ink);
  white-space: pre-wrap;
}

/* ── Overlays (library, access key) ─────────────────────────── */

.overlay {
  position: fixed;
  inset: 0;
  background: rgba(6, 42, 48, 0.55);
  backdrop-filter: saturate(140%) blur(6px);
  -webkit-backdrop-filter: saturate(140%) blur(6px);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 50;
  padding: 24px;
  animation: overlay-in var(--t-mid) var(--ease-out) both;
}
.overlay.hidden { display: none; }

.overlay-card {
  background: #fff;
  width: 100%;
  max-width: 560px;
  max-height: 80vh;
  overflow-y: auto;
  border-radius: 14px;
  padding: 22px 24px 24px;
  box-shadow: 0 20px 60px rgba(6, 42, 48, 0.35);
  /* Rises and settles rather than appearing all at once. */
  animation: card-in var(--t-mid) var(--ease-out) both;
}

@keyframes overlay-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes card-in {
  from { opacity: 0; transform: translateY(12px) scale(0.985); }
  to   { opacity: 1; transform: none; }
}

.overlay-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 14px;
}
.overlay-head h2 { font-size: 16px; font-weight: 600; color: var(--ink); }

.btn-close {
  appearance: none;
  border: 0;
  background: transparent;
  color: var(--teal);
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
  padding: 4px 6px;
  border-radius: 50%;
  transition: color var(--t-fast) var(--ease), background-color var(--t-fast) var(--ease);
}
.btn-close:hover { color: var(--ink); background: var(--sand); }

.overlay-text { font-size: 13px; color: var(--teal); line-height: 1.5; margin-bottom: 14px; }

.key-input {
  width: 100%;
  font: inherit;
  font-size: var(--control-font);
  color: var(--ink);
  background: var(--sand);
  border: 1px solid var(--sage-light);
  border-radius: 8px;
  padding: 10px 12px;
  margin-bottom: 14px;
}
.key-input:focus { outline: 2px solid var(--sage); outline-offset: 0; background: #fff; }

/* ── Library list ────────────────────────────────────────── */

.lib-empty, .lib-error { font-size: 13px; color: var(--teal); padding: 10px 2px; }
.lib-error { color: #8a3b2e; }
.lib-empty a { color: var(--teal); }

/* Row buttons sit on white inside the overlay cards, so the topbar's ghost
   colours are too light to read there. */
.overlay-card .btn-ghost { color: var(--teal); }
.overlay-card .btn-ghost:hover { color: var(--ink); border-color: var(--ink); }

.library-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 2px;
  border-bottom: 1px solid var(--sage-light);
}
.library-row:last-child { border-bottom: 0; }

.library-row-info { min-width: 0; }
.library-row-title { font-size: 13.5px; font-weight: 600; color: var(--ink); }
.library-row-meta { font-size: 11.5px; color: var(--teal); margin-top: 3px; }

.library-row-actions { display: flex; gap: 6px; flex: 0 0 auto; }

.btn-small { padding: 6px 12px; font-size: 12px; }

/* ── Client bar ──────────────────────────────────────────
   Who the open document is for, on its own row under the chrome. The document
   tabs answer "which document"; this answers "for whom", and the two questions
   were previously tangled into one row of tabs. */

.clientbar {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  padding: 10px 24px;
  background: var(--sand);
  border-bottom: 1px solid var(--sage-light);
  min-height: 52px;
}

.clientbar-picker { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; min-width: 0; }

/* `hidden` is not a global utility in this stylesheet — it is scoped per
   component, so a bare .hidden would lose to .clientbar-picker on source order
   and the picker would stay on screen for the practice document. */
.clientbar-picker.hidden, .clientbar-note.hidden { display: none; }

.clientbar-label {
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--teal);
}

#client-select {
  font: inherit;
  font-size: max(14px, var(--control-font));
  font-weight: 600;
  color: var(--ink);
  background: #fff;
  border: 1px solid var(--sage);
  border-radius: 9px;
  padding: 8px 12px;
  min-width: 240px;
  max-width: 100%;
  transition: border-color var(--t-fast) var(--ease-out);
}
#client-select:hover { border-color: var(--teal); }
#client-select:focus-visible { outline: 2px solid var(--teal); outline-offset: 1px; }

.clientbar .btn-import { background: #fff; }

.clientbar-note { font-size: 12.5px; color: var(--teal); max-width: 70ch; }

/* ── Client details card ─────────────────────────────────
   Above the document form and outside it: the fields that belong to the client
   rather than to this document, typed once and stamped into both. */

.client-card {
  background: var(--sky);
  border: 1px solid var(--sage);
  border-radius: 12px;
  padding: 14px 16px 16px;
  margin-bottom: 18px;
}

.client-card .panel-label { margin-bottom: 2px; }
.client-card-hint { font-size: 12px; color: var(--teal); margin: 0 0 12px; }

.client-card-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px 12px; }

/* One height for every box in the grid. A date input is 2.5px taller than a text
   input of the same font and padding — Chromium's own picker glyph — which is
   enough to leave "First meeting" sitting a hair above "Postal address" beside
   it. The floor is derived from the control font so it holds when that lifts to
   16px on a phone, and it only ever raises a box, never crops one. */
.client-card-grid input { background: #fff; min-height: calc(var(--control-font) + 24px); }

/* Inputs line up across a row even when one label wraps and its neighbour does
   not. The cell is as tall as the tallest in its row, the label takes the slack,
   and the input sits at the bottom — so a narrow panel that wraps "Salutation
   (Dear …)" onto two lines cannot leave the box beside it floating half a line
   high. Shortening the labels fixed today's case; this fixes the next one. */
.client-card-grid .field {
  margin-bottom: 0;
  display: flex;
  flex-direction: column;
  align-items: stretch;
}
.client-card-grid .field-label { flex: 1 1 auto; }

/* Saved once, the card folds to this line. The whole row is the control that
   opens it again — a caret on the right says so. */
.client-card.is-collapsed { padding: 0; }
.client-card-summary {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 16px;
  background: transparent;
  border: 0;
  border-radius: 12px;
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: background var(--t-fast) var(--ease-out);
}
.client-card-summary:hover { background: rgba(255, 255, 255, 0.45); }
.client-card-summary:focus-visible { outline: 2px solid var(--teal); outline-offset: -2px; }
.client-card-sum-main { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.client-card-sum-eyebrow {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--teal);
}
.client-card-sum-name {
  font-size: 14.5px;
  font-weight: 650;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.client-card-sum-sub {
  font-size: 12px;
  color: var(--teal);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.client-card-sum-chev { flex: 0 0 auto; display: inline-flex; color: var(--teal); }
.client-card-sum-chev .ico { width: 18px; height: 18px; }

/* The Save that folds the card. Full width under the fields, quiet — it confirms
   what the auto-save already did. */
.client-card-save {
  margin-top: 14px;
  width: 100%;
  justify-content: center;
  background: #fff;
}

/* One column once two would each be too narrow to read a client's address in. */
@media (max-width: 1180px) {
  .client-card-grid { grid-template-columns: minmax(0, 1fr); }
}

/* ── Library search and grouping ─────────────────────────
   At 59 clients and up to three documents each, a flat list is unreadable. */

.lib-search {
  font: inherit;
  font-size: var(--control-font);
  color: var(--ink);
  width: 100%;
  background: #fff;
  border: 1px solid var(--sage);
  border-radius: 9px;
  padding: 9px 12px;
  margin-bottom: 6px;
  transition: border-color var(--t-fast) var(--ease-out);
}
.lib-search:hover { border-color: var(--teal); }
.lib-search:focus-visible { outline: 2px solid var(--teal); outline-offset: 1px; }

.lib-group {
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--teal);
  padding: 16px 2px 6px;
  border-bottom: 1px solid var(--sage);
}
.lib-group:first-child { padding-top: 8px; }

/* ── Client dashboard ────────────────────────────────────
   The studio's home. A dropdown is a fine way to change client while you are
   already editing, but it is a poor way to see a practice: it shows one name at
   a time and says nothing about what state anyone's documents are in. This
   shows all 59 at once, each with the standing of both their documents. */

/* ── The left rail ───────────────────────────────────────
   The studio's four places in one fixed corner. It sits below the topbar and
   above the content, which is shifted right to clear it. Shown on the three
   full-width views; the editor hides it and reclaims the room for the sheet. */
:root { --nav-w: 216px; }
.sidenav { display: none; }
body[data-view="dashboard"] .sidenav,
body[data-view="clients"] .sidenav,
body[data-view="assistant"] .sidenav {
  display: flex;
  flex-direction: column;
  gap: 3px;
  position: fixed;
  top: 64px;              /* the topbar's height */
  left: 0;
  bottom: 0;
  width: var(--nav-w);
  padding: 16px 12px;
  background: var(--ink);
  border-right: 1px solid var(--ink-2);
  z-index: 20;
}
.sidenav-item {
  display: flex;
  align-items: center;
  gap: 11px;
  width: 100%;
  text-align: left;
  font: inherit;
  font-size: 14px;
  font-weight: 550;
  color: rgba(217,221,216,0.72);
  background: transparent;
  border: 0;
  border-radius: 10px;
  padding: 11px 13px;
  cursor: pointer;
  transition: color var(--t-fast) var(--ease-out), background-color var(--t-fast) var(--ease-out);
}
.sidenav-item .ico { width: 18px; height: 18px; flex: 0 0 auto; opacity: 0.85; }
.sidenav-item:hover { color: #fff; background: var(--ink-2); }
.sidenav-item:focus-visible { outline: 2px solid var(--sage); outline-offset: 2px; }
/* The active place. The sage marker and the lifted weight say "you are here". */
.sidenav-item.is-active {
  color: #fff;
  background: var(--ink-2);
  font-weight: 650;
  box-shadow: inset 3px 0 0 var(--sage);
}
.sidenav-item.is-active .ico { opacity: 1; }

.dashboard { display: none; }
body[data-view="dashboard"] .dashboard,
body[data-view="clients"] .dashboard {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
  margin-left: var(--nav-w);
  background: var(--sand);
}

/* Dashboard is the overview: the brief and a quick ask, no roster. Clients is
   the roster: the search, the New client actions and the rows, no brief. The
   same section serves both — the view decides which of its parts are shown. */
body[data-view="dashboard"] .dash-head-actions,
body[data-view="dashboard"] .dash-grid,
body[data-view="dashboard"] #dash-practice { display: none; }
body[data-view="clients"] #today-panel,
body[data-view="clients"] .dash-ask { display: none; }

/* The editor chrome answers questions about one open document, so none of it
   belongs on the roster or the overview. */
body[data-view="dashboard"] .clientbar,
body[data-view="dashboard"] .workspace,
body[data-view="dashboard"] .panebar,
body[data-view="dashboard"] .steps,
body[data-view="dashboard"] #btn-save,
body[data-view="dashboard"] #btn-sample,
body[data-view="dashboard"] #btn-reset,
body[data-view="dashboard"] #btn-finalise,
body[data-view="dashboard"] .topbar-menu-rule,
body[data-view="dashboard"] #btn-print,
body[data-view="clients"] .clientbar,
body[data-view="clients"] .workspace,
body[data-view="clients"] .panebar,
body[data-view="clients"] .steps,
body[data-view="clients"] #btn-save,
body[data-view="clients"] #btn-sample,
body[data-view="clients"] #btn-reset,
body[data-view="clients"] #btn-finalise,
/* With Load sample and Reset gone from the menu here, the rule that separates
   them from the rest would be a line under the last item. */
body[data-view="clients"] .topbar-menu-rule,
body[data-view="clients"] #btn-print { display: none; }

/* ── Walter Wealth AI ────────────────────────────────────
   A view, not a widget. An answer about 59 clients is a page of prose and a
   list, and a corner panel would make every one of them a scroll. The rail
   holds the history because a chat you cannot get back to is a chat you stop
   trusting to be worth starting. */

.assistant { display: none; }
body[data-view="assistant"] .assistant {
  display: flex;
  flex: 1 1 auto;
  min-height: 0;
  margin-left: var(--nav-w);
  background: var(--sand);
}

/* Same rule as the roster: the editor's chrome answers questions about one open
   document and none of it belongs here. */
body[data-view="assistant"] .clientbar,
body[data-view="assistant"] .workspace,
body[data-view="assistant"] .panebar,
body[data-view="assistant"] .steps,
body[data-view="assistant"] .dashboard,
body[data-view="assistant"] #btn-save,
body[data-view="assistant"] #btn-sample,
body[data-view="assistant"] #btn-reset,
body[data-view="assistant"] #btn-finalise,
body[data-view="assistant"] .topbar-menu-rule,
body[data-view="assistant"] #btn-print { display: none; }

.asst-rail {
  flex: 0 0 232px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-height: 0;
  padding: 16px 12px;
  border-right: 1px solid var(--sage-light);
  background: #fff;
}

.asst-new { justify-content: center; }
.asst-new .ico { width: 15px; height: 15px; }

/* Both only exist below the tablet breakpoint, where the rail is a sheet. */
.asst-rail-close { display: none; align-self: flex-end; margin: -4px -4px 0 0; }
.asst-rail-scrim { display: none; }

.asst-history {
  flex: 1 1 auto;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-height: 0;
}
.asst-history-none { font-size: 12px; color: var(--mist); padding: 8px 9px; }

.asst-history-row {
  display: flex;
  align-items: center;
  gap: 2px;
  border-radius: 8px;
}
.asst-history-row:hover { background: var(--sand); }
.asst-history-row[data-current="yes"] { background: var(--sky); }

/* One line, ellipsed. A chat title is the opening question, which runs long far
   more often than it runs short, and two lines of it would put four chats on a
   rail that should hold twenty. */
.asst-history-go {
  flex: 1 1 auto;
  min-width: 0;
  border: 0;
  background: transparent;
  font: inherit;
  font-size: 12.5px;
  color: var(--teal);
  text-align: left;
  padding: 8px 4px 8px 9px;
  cursor: pointer;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.asst-history-row:hover .asst-history-go,
.asst-history-row[data-current="yes"] .asst-history-go { color: var(--ink); }
.asst-history-row[data-current="yes"] .asst-history-go { font-weight: 500; }

.asst-history-del {
  flex: 0 0 auto;
  border: 0;
  background: transparent;
  color: var(--mist);
  padding: 6px 8px;
  cursor: pointer;
  opacity: 0;
  transition: opacity var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.asst-history-del .ico { width: 14px; height: 14px; }
.asst-history-row:hover .asst-history-del,
.asst-history-del:focus-visible { opacity: 1; }
.asst-history-del:hover { color: #8a3b2e; }

.asst-main {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
}

.asst-head {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 14px 24px;
  border-bottom: 1px solid var(--sage-light);
  background: #fff;
}
.asst-head-title { flex: 1 1 auto; min-width: 0; }
.asst-title { font-size: 17px; font-weight: 600; color: var(--ink); margin: 0; }
.asst-sub { font-size: 11.5px; color: var(--mist); margin: 2px 0 0; }
.asst-rail-toggle, .asst-new-small { display: none; }

/* ── The thread ── */

.asst-thread {
  flex: 1 1 auto;
  overflow-y: auto;
  min-height: 0;
  padding: 22px 24px 8px;
  display: flex;
  flex-direction: column;
  gap: 20px;
}

/* One measure, centred, and the composer under it shares it. Prose set to the
   full width of a 27in monitor is prose nobody finishes a line of. */
.asst-msg { max-width: 760px; width: 100%; margin: 0 auto; }
.asst-who {
  display: block;
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--mist);
  margin-bottom: 5px;
}
.asst-msg[data-role="assistant"] .asst-who { color: var(--teal); }

.asst-body { font-size: 14px; line-height: 1.6; color: var(--ink); }
/* The person's own words are one block on a tint; the reply is prose on the
   page. They are different kinds of thing and reading back over a conversation
   is much faster when the shape says which is which. */
.asst-msg[data-role="user"] .asst-body {
  background: #fff;
  border: 1px solid var(--sage-light);
  border-left: 3px solid var(--sage);
  border-radius: 10px;
  padding: 11px 13px;
  white-space: pre-wrap;
}

.asst-body p { margin: 0 0 10px; }
.asst-body p:last-child { margin-bottom: 0; }
.asst-body h4 {
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
  margin: 16px 0 7px;
}
.asst-body h4:first-child { margin-top: 0; }
.asst-body ul, .asst-body ol { margin: 0 0 10px; padding-left: 20px; }
.asst-body li { margin-bottom: 5px; }
.asst-body li:last-child { margin-bottom: 0; }

/* The confirm card. A proposal, sitting under the reply that made it, that the
   person approves or declines. Once decided it collapses to a line of record. */
.asst-action {
  max-width: 760px;
  width: 100%;
  margin: 8px auto 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
  background: #fff;
  border: 1px solid var(--sage);
  border-left: 3px solid var(--ink);
  border-radius: 12px;
  padding: 12px 14px;
}
.asst-action-desc { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.asst-action-title { font-size: 12px; font-weight: 700; letter-spacing: 0.03em; text-transform: uppercase; color: var(--ink); }
.asst-action-detail { font-size: 14px; color: var(--ink-2); }
.asst-action-btns { display: flex; gap: 8px; flex: 0 0 auto; }
.asst-action-cancel { background: transparent; color: var(--teal); border: 1px solid var(--sage-light); }
.asst-action-cancel:hover { color: var(--ink); border-color: var(--sage); }
/* The settled card: a quiet line, ink for done, muted for cancelled. */
.asst-action[data-state] { border-left-color: var(--sage); background: var(--sand); padding: 9px 14px; }
.asst-action[data-state="done"] { border-left-color: var(--teal); }
.asst-action-said { font-size: 13px; color: var(--teal); }
.asst-action[data-state="cancelled"] .asst-action-said { color: var(--mist); }
.asst-body strong { font-weight: 600; }
.asst-body code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12.5px;
  background: var(--sky);
  border-radius: 4px;
  padding: 1px 4px;
}

.asst-thinking { font-size: 13px; color: var(--mist); }

.asst-cursor {
  display: inline-block;
  width: 7px;
  height: 15px;
  margin-left: 2px;
  vertical-align: text-bottom;
  background: var(--teal);
  animation: asst-blink 1s steps(2, start) infinite;
}
@keyframes asst-blink { to { visibility: hidden; } }

.asst-error {
  font-size: 12.5px;
  color: #8a3b2e;
  margin: 8px 0 0;
}
.asst-loading { font-size: 13px; color: var(--mist); }

/* ── The opening screen ── */

.asst-empty {
  margin: auto;
  max-width: 520px;
  text-align: center;
  padding: 20px 0 40px;
}
.asst-empty-mark {
  width: 46px;
  height: 46px;
  margin: 0 auto 14px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--sky);
  color: var(--teal);
}
.asst-empty-mark .ico { width: 22px; height: 22px; }
.asst-empty-title { font-size: 20px; font-weight: 600; color: var(--ink); margin: 0 0 8px; }
.asst-empty-note { font-size: 13.5px; line-height: 1.6; color: var(--teal); margin: 0 0 20px; }

.asst-chips { display: flex; flex-direction: column; gap: 8px; }
/* Full-width rows rather than a wrapping cloud: they are sentences, and a cloud
   of sentences breaks in the middle of one and reads as noise. */
.asst-chip {
  font: inherit;
  font-size: 13px;
  color: var(--teal);
  text-align: left;
  background: #fff;
  border: 1px solid var(--sage-light);
  border-radius: 10px;
  padding: 10px 13px;
  cursor: pointer;
  transition: border-color var(--t-fast) var(--ease-out), color var(--t-fast) var(--ease);
}
.asst-chip:hover { border-color: var(--teal); color: var(--ink); }

/* ── The composer ── */

.asst-compose {
  flex: 0 0 auto;
  display: flex;
  align-items: flex-end;
  gap: 8px;
  padding: 12px 24px 0;
  width: min(100%, 808px);   /* 760 measure + the 24px gutters either side */
  margin: 0 auto;
}

.asst-input {
  flex: 1 1 auto;
  font: inherit;
  font-size: var(--control-font);
  line-height: 1.5;
  color: var(--ink);
  background: #fff;
  border: 1px solid var(--sage);
  border-radius: 12px;
  padding: 11px 13px;
  resize: none;
  max-height: 200px;
  overflow-y: auto;
  transition: border-color var(--t-fast) var(--ease-out);
}
.asst-input:hover { border-color: var(--teal); }
.asst-input:focus-visible { outline: 2px solid var(--teal); outline-offset: 1px; }

.asst-send { flex: 0 0 auto; }
.asst-send .ico { width: 15px; height: 15px; }
.asst-stop { flex: 0 0 auto; background: #fff; }

/* Attach is a plain icon button — a paperclip, no label — sitting quietly to
   the left of the field. The word is kept in the DOM for the screen reader and
   hidden from view, so the control reads as "Attach a document" without the
   text crowding the compose row. */
.asst-attach {
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: #fff;
  border: 1px solid var(--sage);
  border-radius: 999px;
  color: var(--teal);
}
.asst-attach:hover { color: var(--ink); border-color: var(--teal); background: var(--sand); }
.asst-attach .ico { width: 17px; height: 17px; margin: 0; }
.asst-attach span {
  position: absolute; width: 1px; height: 1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
}

/* The pinned files, above the compose bar. They ride up with every question
   until removed, so a document can be attached once and asked about again. */
.asst-files {
  flex: 0 0 auto;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  width: min(100%, 808px);
  margin: 10px auto 0;
  padding: 0 24px;
}
.asst-file {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 12.5px;
  color: var(--ink);
  background: var(--sky);
  border: 1px solid var(--sage);
  border-radius: 999px;
  padding: 5px 6px 5px 12px;
  max-width: 100%;
}
.asst-file-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 220px; }
.asst-file-size { color: var(--teal); flex: 0 0 auto; }
.asst-file-rm {
  flex: 0 0 auto;
  width: 20px; height: 20px;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 15px; line-height: 1;
  color: var(--teal);
  background: #fff;
  border: 1px solid var(--sage-light);
  border-radius: 999px;
  cursor: pointer;
}
.asst-file-rm:hover { color: var(--ink); border-color: var(--sage); }
.asst-file-note { font-size: 12px; color: #8a3b2e; }

/* The record on a sent question of what it was asked against. */
.asst-msg-files { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.asst-msg-file {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 12px; color: var(--teal);
}
.asst-msg-file .ico { width: 13px; height: 13px; flex: 0 0 auto; }
/* Needed because .btn sets display, which the UA stylesheet's [hidden] loses to.
   Without it Stop stays on the row after the answer has finished. */
.asst-stop[hidden] { display: none; }

.asst-foot {
  flex: 0 0 auto;
  font-size: 11px;
  line-height: 1.5;
  color: var(--mist);
  padding: 8px 24px 14px;
  width: min(100%, 808px);
  margin: 0 auto;
}

/* ── The per-client assistant ─────────────────────────────
   A conversation that belongs to one client. It opens beside their open
   document — its own thread, its own memory, and it sees only this client.

   Pinned rather than laid out: a fixed-width panel absolutely placed against the
   right edge of the workspace, floating over the document rather than pushing it
   narrower. Squeezing it into the flex row left too little for the preview at
   narrower widths, which is what made the two look tangled together. The
   practice assistant above owns the same shapes; this is a quieter version of
   them sized for a docked panel. */

.clientai {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: clamp(320px, 32vw, 412px);
  max-width: 94vw;
  z-index: 30;
  display: flex;
  flex-direction: column;
  min-height: 0;
  background: #fff;
  border-left: 1px solid var(--sage-light);
  box-shadow: -10px 0 30px -20px rgba(6, 42, 48, 0.4);
  animation: clientai-in var(--t-mid) var(--ease);
}
/* A class sets display:flex, which outranks the UA [hidden] rule, so the closed
   state has to be spelled out here or the panel would never hide. */
.clientai[hidden] { display: none; }

/* With the panel open the launcher would sit on top of the composer's Send, so
   it stands down until the panel is closed. */
body[data-clientai="open"] .asst-fab { display: none; }

@keyframes clientai-in {
  from { transform: translateX(20px); opacity: 0; }
  to   { transform: translateX(0); opacity: 1; }
}

.clientai-head {
  flex: 0 0 auto;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  padding: 13px 14px 11px 16px;
  border-bottom: 1px solid var(--sage-light);
  background: #fcfbfa;
}
.clientai-head-titles { min-width: 0; }
.clientai-eyebrow {
  display: block;
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--teal);
  margin-bottom: 3px;
}
.clientai-title {
  font-size: 15px;
  font-weight: 600;
  line-height: 1.3;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.clientai-thread {
  flex: 1 1 auto;
  overflow-y: auto;
  min-height: 0;
  padding: 16px 16px 6px;
  display: flex;
  flex-direction: column;
  gap: 15px;
}
.clientai-msg { width: 100%; }
.clientai-body { font-size: 13.5px; line-height: 1.6; color: var(--ink); }
/* The person's words on a tint, the reply as prose — the same shape language as
   the practice assistant so a glance says which is which. */
.clientai-msg[data-role="user"] .clientai-body {
  background: var(--sand);
  border: 1px solid var(--sage-light);
  border-left: 3px solid var(--sage);
  border-radius: 10px;
  padding: 9px 11px;
  white-space: pre-wrap;
}
.clientai-body p { margin: 0 0 9px; }
.clientai-body p:last-child { margin-bottom: 0; }
.clientai-body h4 { font-size: 12.5px; font-weight: 600; color: var(--ink); margin: 14px 0 6px; }
.clientai-body h4:first-child { margin-top: 0; }
.clientai-body ul, .clientai-body ol { margin: 0 0 9px; padding-left: 18px; }
.clientai-body li { margin-bottom: 4px; }
.clientai-body li:last-child { margin-bottom: 0; }
.clientai-body strong { font-weight: 600; }
.clientai-body code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px;
  background: var(--sky);
  border-radius: 4px;
  padding: 1px 4px;
}

.clientai-empty {
  font-size: 13px;
  line-height: 1.6;
  color: var(--teal);
  background: var(--sky);
  border-radius: 10px;
  padding: 12px 13px;
  margin: 0;
}
.clientai-thinking { font-size: 12.5px; color: var(--mist); }
.clientai-error { font-size: 12px; color: #8a3b2e; margin: 6px 0 0; }

.clientai-compose {
  flex: 0 0 auto;
  display: flex;
  align-items: flex-end;
  gap: 7px;
  padding: 10px 14px 8px;
  border-top: 1px solid var(--sage-light);
}
.clientai-input {
  flex: 1 1 auto;
  font: inherit;
  font-size: var(--control-font);
  line-height: 1.5;
  color: var(--ink);
  background: #fff;
  border: 1px solid var(--sage);
  border-radius: 11px;
  padding: 9px 11px;
  resize: none;
  max-height: 160px;
  overflow-y: auto;
  transition: border-color var(--t-fast) var(--ease-out);
}
.clientai-input:hover { border-color: var(--teal); }
.clientai-input:focus-visible { outline: 2px solid var(--teal); outline-offset: 1px; }
.clientai-send { flex: 0 0 auto; }
.clientai-send .ico { width: 14px; height: 14px; }
.clientai-stop { flex: 0 0 auto; background: #fff; }
.clientai-stop[hidden] { display: none; }
.clientai-foot {
  flex: 0 0 auto;
  font-size: 10.5px;
  line-height: 1.5;
  color: var(--mist);
  text-align: center;
  padding: 0 16px 12px;
}

/* ── The launcher ─────────────────────────────────────────
   The way back in from anywhere else. It sits above the phone's pane switch and
   clears the home indicator, because a button under either is a button that
   cannot be pressed. */

.asst-fab {
  position: fixed;
  right: 20px;
  bottom: calc(20px + env(safe-area-inset-bottom));
  z-index: 40;
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 11px 16px 11px 13px;
  border: 0;
  border-radius: 999px;
  background: var(--ink);
  color: var(--sage-light);
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  box-shadow: 0 8px 24px rgba(6, 42, 48, 0.28);
  transition: background-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease),
              transform var(--t-fast) var(--ease-out);
}
.asst-fab:hover { background: var(--ink-2); color: #fff; transform: translateY(-1px); }
.asst-fab:active { transform: translateY(0); }
.asst-fab:focus-visible { outline: 2px solid var(--sage); outline-offset: 3px; }
/* Gone on the assistant itself: a button that takes you where you already are. */
body[data-view="assistant"] .asst-fab { display: none; }

/* The chevron from the logo, drawn in CSS rather than fetched: the launcher is
   on screen from the first paint and a request for a 400-byte mark is a request
   that can fail. */
.asst-fab-mark {
  width: 18px;
  height: 18px;
  flex: 0 0 auto;
  background: currentColor;
  -webkit-mask: url('../img/mark-white.svg') center / contain no-repeat;
  mask: url('../img/mark-white.svg') center / contain no-repeat;
}

.dash-head {
  flex: 0 0 auto;
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  /* The bar spans the pane, but its title and controls sit in the same 1060
     column the brief and roster below use — otherwise on a wide monitor the
     search and New-client buttons drift to the far edge, out of line with the
     content they act on. */
  padding: 20px max(24px, calc((100% - 1060px) / 2)) 16px;
  background: #fff;
  border-bottom: 1px solid var(--sage-light);
}
.dash-title { font-size: 23px; font-weight: 700; letter-spacing: -0.02em; color: var(--ink); }
.dash-sub { font-size: 13px; color: var(--teal); margin-top: 4px; letter-spacing: 0.005em; }

.dash-head-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.dash-search-wrap { display: block; }
.dash-search {
  font: inherit;
  font-size: var(--control-font);
  color: var(--ink);
  background: var(--sand);
  border: 1px solid var(--sage);
  border-radius: 9px;
  padding: 9px 12px;
  min-width: 230px;
  transition: border-color var(--t-fast) var(--ease-out), background-color var(--t-fast) var(--ease);
}
.dash-search:hover { border-color: var(--teal); }
.dash-search:focus-visible { outline: 2px solid var(--teal); outline-offset: 1px; background: #fff; }
/* .btn-primary is sage-light, which all but disappears on the white head. */
.dash-new { background: var(--ink); color: var(--sage-light); border-radius: 10px; padding: 10px 14px; }
.dash-new:hover { background: var(--ink-2); color: #fff; }

/* The content runs in a centred column rather than edge to edge. On a wide
   monitor a full-bleed list of short rows reads as an admin panel; a measured
   column reads as a considered page, and keeps the eye's travel short. */
.dash-body { flex: 1 1 auto; overflow-y: auto; padding: 22px 24px 48px; }
.dash-body > .today,
.dash-body > .dash-ask,
.dash-body > .dash-grid,
.dash-body > #dash-practice { max-width: 1060px; margin-inline: auto; width: 100%; }

/* ── Ask Walter Wealth AI, from the roster ───────────────
   A signature element, not a form field. The ink field and the brand mark make
   it read as the assistant reaching onto the dashboard rather than a search box
   that happens to say Ask. It hands off to the one assistant; it is a door. */
/* Sits below the roster now, so it opens with a heading rather than appearing
   out of nowhere, and its margin is on top — it follows the clients. */
.dash-ask { margin: 28px auto 4px; }
.dash-ask-head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin: 0 4px 10px;
}
.dash-ask-eyebrow {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink);
}
.dash-ask-note {
  font-family: 'Playfair Display', Georgia, serif;
  font-style: italic;
  font-size: 13px;
  color: var(--teal);
}
.dash-ask-form {
  display: flex;
  align-items: center;
  gap: 12px;
  background:
    linear-gradient(180deg, rgba(255,255,255,0.06), rgba(255,255,255,0) 60%),
    var(--ink);
  border: 1px solid var(--ink-2);
  border-radius: 14px;
  padding: 10px 10px 10px 16px;
  box-shadow: 0 1px 2px rgba(6,42,48,0.10), 0 12px 28px -18px rgba(6,42,48,0.45);
  transition: box-shadow var(--t-mid) var(--ease-out), border-color var(--t-fast) var(--ease-out);
}
.dash-ask-form:focus-within {
  border-color: var(--sage);
  box-shadow: 0 1px 2px rgba(6,42,48,0.12), 0 16px 34px -18px rgba(6,42,48,0.55);
}
.dash-ask-mark {
  flex: 0 0 auto;
  width: 26px;
  height: 26px;
  border-radius: 8px;
  background: var(--sage) url("../img/mark-white.svg") center / 15px 15px no-repeat;
  opacity: 0.95;
}
.dash-ask-input {
  flex: 1 1 auto;
  min-width: 0;
  font: inherit;
  font-size: 15px;
  color: #fff;
  background: transparent;
  border: 0;
  padding: 6px 0;
}
.dash-ask-input::placeholder { color: rgba(217,221,216,0.72); }
.dash-ask-input:focus { outline: none; }
.dash-ask-send {
  flex: 0 0 auto;
  background: var(--sage-light);
  color: var(--ink);
  border-radius: 10px;
  padding: 9px 16px;
  font-weight: 600;
}
.dash-ask-send:hover { background: #fff; }
.dash-ask-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 10px 2px 0;
}
.dash-ask-chip {
  font: inherit;
  font-size: 12.5px;
  color: var(--teal);
  background: #fff;
  border: 1px solid var(--sage-light);
  border-radius: 999px;
  padding: 6px 13px;
  cursor: pointer;
  transition: color var(--t-fast) var(--ease-out), border-color var(--t-fast) var(--ease-out), background-color var(--t-fast) var(--ease-out);
}
.dash-ask-chip:hover { color: var(--ink); border-color: var(--sage); background: var(--sky); }
.dash-ask-chip:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
/* ── The roster ──────────────────────────────────────────
   One row per client, not one card. Cards carried every stage as its own
   labelled row, which was right for one client and unreadable for 59: almost
   everybody is at the same early stage, so every card printed the same six
   labels and the only thing telling two of them apart was the name. Fifteen
   screens of scroll, and no way to see who was furthest behind.

   The row answers the four questions actually asked while scanning — who, where
   are they up to, how long have I got, what do I do — in fixed columns, so the
   eye can run down each one. */
.dash-grid { display: flex; flex-direction: column; gap: 6px; }

.dash-row {
  display: grid;
  /* Fixed tracks for the clock and the action rather than auto: a column only
     works if it is a column, and letting the deadline pill size to its own text
     ragged the action edge across every row, which is the edge the eye follows. */
  grid-template-columns: minmax(150px, 1.5fr) minmax(180px, 2fr) 172px minmax(0, 1.3fr) auto;
  align-items: center;
  gap: 14px;
  background: #fff;
  border: 1px solid var(--sage-light);
  border-radius: 11px;
  padding: 9px 12px;
  border-left: 3px solid transparent;
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.dash-row:hover { border-color: var(--sage); box-shadow: 0 2px 10px rgba(6, 42, 48, 0.05); }
/* Where the editor would land if you pressed Edit. At 59 rows the one you were
   last in is otherwise impossible to find. */
.dash-row.is-current { border-color: var(--teal); }

/* The one state that has to be findable while scrolling past 59 of them. */
.dash-row[data-urgency="overdue"] { border-left-color: #8a3b2e; }
.dash-row[data-urgency="urgent"] { border-left-color: #c08a3e; }

.dash-who {
  appearance: none;
  border: 0;
  background: transparent;
  font: inherit;
  text-align: left;
  cursor: pointer;
  min-width: 0;
  padding: 3px 4px;
  margin: -3px -4px;
  border-radius: 7px;
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.dash-who:hover .dash-name { color: var(--teal); text-decoration-color: var(--teal); }
.dash-who:focus-visible { outline: 2px solid var(--teal); outline-offset: 1px; }

.dash-name {
  font-size: 14px;
  font-weight: 600;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  text-decoration: underline;
  text-decoration-color: var(--sage);
  text-decoration-thickness: 1.5px;
  text-underline-offset: 3px;
  transition: color var(--t-fast) var(--ease), text-decoration-color var(--t-fast) var(--ease);
}
.dash-name.is-unnamed { color: var(--teal); font-weight: 500; font-style: italic; }
.dash-row-sub {
  font-size: 11px;
  color: var(--mist);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ── The step strip ──────────────────────────────────────
   A segment per stage of this client's own path, in delivery order. Filled where
   it is done, ringed at the one they are up to. It carries no text, so it stays
   the same width whatever a stage is called, which is what lets twenty of them
   be compared by eye down a column. The line beneath says which step in words:
   the strip is for comparing, the words are for reading. */
.dash-where { min-width: 0; display: flex; flex-direction: column; gap: 5px; }

.dash-strip { display: flex; gap: 3px; align-items: center; }
.dash-seg {
  flex: 1 1 0;
  min-width: 5px;
  height: 6px;
  border-radius: 3px;
  background: var(--sage-light);
  transition: background-color var(--t-fast) var(--ease);
}
.dash-seg[data-state="done"] { background: var(--teal); }
/* The one they are up to, said with colour alone. A ring round it was the first
   attempt and it swamped the strip: at six stages each segment is wide, so an
   outline turned the current step into the loudest object on the row when it is
   only meant to be the readable one. Ink against teal against pale is enough,
   because the current step is always the first that is not teal. */
.dash-seg[data-state="current"] { background: var(--ink); }
/* A stage the studio does not produce reads hollow while it is outstanding, so
   "waiting on the licensee" and "waiting on us" are not the same mark. */
.dash-seg[data-kind="external"][data-state="todo"] {
  background: transparent;
  box-shadow: inset 0 0 0 1.5px var(--sage-light);
}

.dash-at {
  font-size: 11px;
  color: var(--teal);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ── The next action ─────────────────────────────────────
   One verb per line. The full picker still lives in the client file; a roster of
   59 needs the single next thing, not a menu on every row. */
.dash-act {
  appearance: none;
  font: inherit;
  font-size: 12px;
  font-weight: 500;
  display: flex;
  align-items: center;
  gap: 7px;
  min-width: 0;
  padding: 7px 11px;
  border: 1px solid var(--sage-light);
  border-radius: 8px;
  background: var(--sand);
  color: var(--ink);
  cursor: pointer;
  text-align: left;
  transition: border-color var(--t-fast) var(--ease), background-color var(--t-fast) var(--ease),
              transform var(--t-fast) var(--ease);
}
/* Hugs its label rather than filling the track. Stretched, it read as an input
   box, and a row of full-width boxes says nothing about which one to press. */
.dash-act { justify-self: start; max-width: 100%; }
.dash-act > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dash-act .ico { width: 15px; height: 15px; flex: 0 0 auto; color: var(--teal); }
.dash-act:hover { border-color: var(--teal); background: #fff; }
.dash-act:active { transform: scale(0.99); }
/* Someone else to move. Named rather than hidden, so an assistant can see what
   the file is waiting on instead of meeting a row with nothing on it. */
.dash-act[data-waiting="yes"] { background: transparent; border-style: dashed; color: var(--teal); }
.dash-act[data-waiting="yes"] .ico { color: var(--mist); }
.dash-act.is-done { border-color: transparent; background: transparent; color: var(--mist); cursor: default; }
.dash-act.is-done .ico { color: var(--sage); }

.dash-del {
  appearance: none;
  border: 0;
  background: transparent;
  padding: 6px;
  border-radius: 7px;
  cursor: pointer;
  color: var(--mist);
  display: inline-flex;
  transition: color var(--t-fast) var(--ease), background-color var(--t-fast) var(--ease);
}
.dash-del .ico { width: 15px; height: 15px; }
.dash-del:hover { color: #8a3b2e; background: var(--sand); }

/* .dash-due is shared with the client file, where it is a standalone line and
   carries its own top margin. In a row it is a grid cell, so the margin becomes
   a shove downward and the fill becomes a stretched pill. */
.dash-row .dash-due { justify-self: start; margin-top: 0; font-size: 11.5px; padding: 6px 9px; }
/* A client with no first meeting has no deadline, and the empty cell is what
   holds the action column in line for the rest of them. */
.dash-row .dash-due:empty { border: 0; background: transparent; padding: 0; }

/* Where the picker would land if you pressed Edit — worth marking, because at
   59 cards the one you were last in is otherwise impossible to find. */

/* The card title opens the client's file, so it has to look like it does: the
   underline and the arrow are the whole point, since a heading that happens to be
   clickable is a heading nobody clicks. */

.dash-badge {
  flex: 0 0 auto;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 3px 8px;
  border-radius: 999px;
  white-space: nowrap;
}
/* Ordered by how durable each state is. Filed is the strongest — the document
   has left as a PDF in the client's Drive folder — so it is the one that reads
   loudest, and only it carries a tick. */
.dash-badge[data-state="filed"] { background: var(--ink); color: #fff; }
.dash-badge[data-state="filed"]::before { content: "✓ "; }
.dash-badge[data-state="library"] { background: var(--sage); color: var(--ink); }
.dash-badge[data-state="draft"] { background: var(--sky); color: var(--ink); }
.dash-badge[data-state="empty"] { color: var(--mist); border: 1px solid var(--sage-light); }

.dash-empty { font-size: 13px; color: var(--teal); padding: 22px 2px; }

/* The Financial Services Guide belongs to the practice, not to any one client,
   so it sits below the roster rather than inside a card on it. */
.dash-practice {
  margin-top: 20px;
  background: var(--sky);
  border: 1px solid var(--sage);
  border-radius: 14px;
  padding: 14px 16px;
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
}
.dash-practice-text { flex: 1 1 260px; min-width: 0; }
.dash-practice-title { font-size: 14px; font-weight: 600; }
.dash-practice-note { font-size: 12px; color: var(--teal); margin-top: 3px; }
.dash-practice .btn { background: #fff; }

/* ── The pipeline on a client card ───────────────────────
   The roster shows where each client is up to in Nick's actual process, which
   differs by client type and mostly consists of stages the studio does not
   produce. Three things have to be legible at a glance: which path they are on,
   how close the SOA deadline is, and which stages are done. */

.dash-path {
  flex: 0 0 auto;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 3px 8px;
  border-radius: 999px;
  white-space: nowrap;
  background: var(--sand);
  color: var(--teal);
  border: 1px solid var(--sage-light);
}
/* The 59 are the work in front of us, so they read as the default rather than
   as an exception. */
.dash-path[data-type="new"] { background: var(--sky); color: var(--ink); border-color: var(--sage); }

/* The deadline. Its own line, because it is what decides the order of the day. */
.dash-due {
  display: flex;
  align-items: center;
  gap: 7px;
  margin-top: 9px;
  padding: 7px 10px;
  border-radius: 9px;
  font-size: 12px;
  font-weight: 500;
  background: var(--sand);
  color: var(--teal);
  border: 1px solid var(--sage-light);
}
.dash-due .ico { width: 14px; height: 14px; flex: 0 0 auto; }
.dash-due[data-level="overdue"] { background: #fdf1ee; border-color: #e2bcb0; color: #8a3b2e; font-weight: 600; }
.dash-due[data-level="urgent"] { background: #fdf7ee; border-color: #e0cdaa; color: #7a5a22; font-weight: 600; }
.dash-due[data-level="soon"] { background: var(--sky); border-color: var(--sage); color: var(--ink); }
.dash-due[data-level="done"] { color: var(--mist); }
.dash-due[data-level="unknown"] { color: var(--mist); border-style: dashed; }

/* A left edge on the whole card for anything overdue — the one state that has to
   be findable while scrolling past 59 of them. */

/* Stages the studio does not generate are a tick, not a link: the studio cannot
   know whether the licensee's FSG was actually sent, only the adviser can. */

.dash-tick {
  flex: 0 0 auto;
  width: 16px; height: 16px;
  margin: 0;
  accent-color: var(--teal);
  cursor: pointer;
}

/* Done, but by hand and elsewhere — deliberately quieter than Filed, which the
   studio can actually vouch for. */
.dash-badge[data-state="external-done"] { background: var(--sage-light); color: var(--ink); }
.dash-badge[data-state="external-todo"] { color: var(--mist); border: 1px dashed var(--sage); }

/* ── Phase headings ──────────────────────────────────────
   A new client's eleven documents are a sequence, not a list. The headings say
   which part of the engagement each belongs to and carry that part's progress. */

.dash-phase-count {
  flex: 0 0 auto;
  font-size: 10px;
  font-weight: 600;
  color: var(--mist);
  font-variant-numeric: tabular-nums;
}
.dash-phase-count[data-complete="yes"] { color: var(--teal); }

/* ── The client file ─────────────────────────────────────
   Opened from a client's name. Every document they are owed, in the order they
   are delivered, with whose document each one is. */

.overlay-wide { max-width: 720px; }

.cf-top { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
.cf-meta { font-size: 12px; color: var(--teal); }
#cf-body .dash-due { margin-top: 12px; }

/* ── What do you want to do? ─────────────────────────────
   The file says where the client is up to; this says what to do about it. One
   recommended action, sized like a decision, and the alternatives beside it. */

/* ── The AI work list ────────────────────────────────────
   Sits under the action picker and is deliberately quieter than it. The picker
   is derived from state and can be trusted to be right, so it keeps the buttons;
   this reads the notes, is worth what the notes are worth, and is a list of
   sentences for a person to act on. The visual weight says which is which. */
.cf-ai {
  margin-top: 14px;
  padding: 13px 14px;
  border: 1px solid var(--sage-light);
  border-radius: 12px;
  background: var(--sand);
}
.cf-ai-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.cf-ai-title {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--teal);
}
.cf-ai-title .ico { width: 14px; height: 14px; }
.cf-ai-body { margin-top: 10px; }
.cf-ai-note { font-size: 12.5px; color: var(--teal); line-height: 1.5; }
.cf-ai-error { color: #8a3b2e; }
.cf-ai-go { margin-top: 10px; background: #fff; }
.cf-ai-again { margin-top: 10px; }

.cf-ai-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 9px; }
.cf-ai-step {
  padding: 10px 11px;
  background: #fff;
  border: 1px solid var(--sage-light);
  border-radius: 9px;
  border-left: 3px solid var(--sage);
}
.cf-ai-step[data-urgency="now"] { border-left-color: #8a3b2e; }
.cf-ai-step[data-urgency="this-week"] { border-left-color: #c08a3e; }

.cf-ai-step-top { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.cf-ai-step-top strong { flex: 1 1 auto; min-width: 0; font-size: 13px; font-weight: 600; }

.cf-ai-owner {
  flex: 0 0 auto;
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 2px 7px;
  border-radius: 999px;
  background: var(--sage-light);
  color: var(--ink);
}
/* Whose move it is, coloured so a file can be scanned for "waiting on someone
   else" without reading it. */
.cf-ai-owner[data-owner="client"] { background: var(--sky); }
.cf-ai-owner[data-owner="licensee"] { background: var(--sand); border: 1px solid var(--sage); }

.cf-ai-when { flex: 0 0 auto; font-size: 10.5px; color: var(--mist); }
.cf-ai-why { font-size: 12px; color: var(--teal); line-height: 1.5; margin-top: 4px; }

.cf-ai-watch {
  display: flex;
  gap: 8px;
  margin-top: 10px;
  padding: 9px 11px;
  border-radius: 9px;
  background: var(--sky);
  border: 1px solid var(--sage);
  font-size: 12px;
  line-height: 1.5;
}
.cf-ai-watch .ico { width: 14px; height: 14px; flex: 0 0 auto; color: var(--teal); }
.cf-ai-caveat { margin-top: 9px; font-size: 11px; color: var(--mist); line-height: 1.45; }

.cf-next {
  margin-top: 16px;
  padding: 14px;
  border: 1px solid var(--sage);
  border-radius: 12px;
  background: var(--sky);
}
.cf-next-head {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--teal);
  margin-bottom: 10px;
}

.cf-next-primary {
  appearance: none;
  font: inherit;
  text-align: left;
  width: 100%;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 13px 14px;
  border: 0;
  border-radius: 10px;
  background: var(--ink);
  color: var(--sage-light);
  transition: background-color var(--t-fast) var(--ease);
}
.cf-next-primary:hover { background: var(--ink-2); }
.cf-next-primary:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
.cf-next-primary > .ico { flex: 0 0 auto; width: 18px; height: 18px; color: var(--sage-light); }

.cf-next-text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.cf-next-text strong { font-size: 14px; font-weight: 600; color: #fff; }
.cf-next-text span { font-size: 11.5px; color: var(--sage); }

.cf-next-go { flex: 0 0 auto; display: inline-flex; }
.cf-next-go .ico {
  width: 15px; height: 15px; color: var(--sage);
  transition: transform var(--t-fast) var(--ease-out);
}
.cf-next-primary:hover .cf-next-go .ico { transform: translateX(2px); }

.cf-next-list { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 9px; }
.cf-next-alt {
  appearance: none;
  font: inherit;
  font-size: 12px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 11px;
  border: 1px solid var(--sage);
  border-radius: 8px;
  background: #fff;
  color: var(--teal);
  transition: color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.cf-next-alt:hover { color: var(--ink); border-color: var(--teal); }
.cf-next-alt .ico { width: 14px; height: 14px; }

.cf-next-more { font-size: 11px; color: var(--teal); margin-top: 9px; }

.cf-phase { margin-top: 20px; }
.cf-phase-head { display: flex; align-items: baseline; gap: 10px; }
.cf-phase-title { flex: 1 1 auto; font-size: 13px; font-weight: 600; color: var(--ink); }
.cf-phase-head .dash-phase-count { font-size: 11px; }
.cf-phase-note { font-size: 11.5px; color: var(--mist); margin: 2px 0 8px; }

.cf-row {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 11px 12px;
  border: 1px solid var(--sage-light);
  border-radius: 10px;
  background: var(--sand);
}
.cf-row + .cf-row { margin-top: 6px; }
.cf-row[data-state="filed"] { background: #fff; border-color: var(--sage); }
.cf-row-main { flex: 1 1 auto; min-width: 0; }

.cf-row-label { display: flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 600; color: var(--ink); }
.cf-row-label .ico { width: 15px; height: 15px; flex: 0 0 auto; color: var(--teal); }

/* Whose document it is and which way it travels — the two facts that decide who
   has to do something next. */
.cf-row-from { font-size: 11px; color: var(--teal); margin-top: 3px; }
.cf-row-note { font-size: 11.5px; color: var(--mist); margin-top: 4px; line-height: 1.45; }

.cf-row-side {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  justify-content: flex-end;
  max-width: 46%;
}
.cf-row-when { font-size: 11px; color: var(--teal); font-variant-numeric: tabular-nums; }

.cf-tick {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 12px;
  color: var(--mist);
  cursor: pointer;
  padding: 6px 10px 6px 8px;
  border: 1px solid var(--sage-light);
  border-radius: 8px;
  background: #fff;
  white-space: nowrap;
  transition: color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.cf-tick:hover { color: var(--ink); border-color: var(--teal); }
.cf-tick[data-done="yes"] { color: var(--ink); border-color: var(--sage); font-weight: 500; }

.cf-added {
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--teal);
  background: var(--sky);
  border: 1px solid var(--sage);
  border-radius: 999px;
  padding: 2px 6px;
}
/* Taken off deliberately, as against never having applied. Sand rather than sky
   so the two reasons for being on the off-path list read apart at a glance. */
.cf-removed { color: var(--mist); background: var(--sand); border-color: var(--sage-light); }

/* Documents in the process that this client's path leaves out. Present, quiet,
   and addable — Nick's "the 59 don't get a welcome pack" is a default. */
.cf-off { border-top: 1px solid var(--sage-light); padding-top: 16px; }
.cf-row-off { background: transparent; border-style: dashed; align-items: center; }
.cf-row-off .cf-row-label { font-weight: 500; color: var(--teal); }
.cf-row-off .cf-row-label .ico { color: var(--mist); }

.cf-add, .cf-drop {
  appearance: none;
  font: inherit;
  font-size: 11.5px;
  font-weight: 500;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 6px 10px;
  border-radius: 8px;
  border: 1px solid var(--sage);
  background: #fff;
  color: var(--teal);
  white-space: nowrap;
  transition: color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease), background-color var(--t-fast) var(--ease);
}
.cf-add:hover { color: var(--ink); border-color: var(--teal); }
.cf-drop { border-color: var(--sage-light); color: var(--mist); }
.cf-drop:hover { color: #8a3b2e; border-color: #e2bcb0; }

/* Attach the real document to a step the studio does not produce: the FSG that
   went out, the fact find that came back, the signed authority. A label rather
   than a button, because the file input it wraps is the control. */
.cf-attach {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 11px;
  border: 1px solid var(--sage-light);
  border-radius: 8px;
  background: #fff;
  font-size: 12px;
  font-weight: 500;
  color: var(--teal);
  cursor: pointer;
  white-space: nowrap;
  transition: border-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.cf-attach:hover { border-color: var(--teal); color: var(--ink); }
.cf-attach .ico { width: 14px; height: 14px; }
.cf-attach:focus-within { outline: 2px solid var(--teal); outline-offset: 1px; }
.cf-attach[data-state="busy"] { color: var(--mist); cursor: progress; }
.cf-attach[data-state="error"] { color: #8a3b2e; border-color: #e2bcb0; }

/* What is already attached, named on the row. A file nobody can see from the
   file is a file nobody knows is there. */
.cf-files {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  margin-top: 6px;
  font-size: 11.5px;
  color: var(--teal);
  line-height: 1.45;
}
.cf-files .ico { width: 13px; height: 13px; flex: 0 0 auto; margin-top: 1px; }

/* The way out of the step menu to what the menu cannot do. */
.step-foot {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 6px;
  padding: 10px 9px;
  border: 0;
  border-top: 1px solid var(--sage-light);
  border-radius: 0 0 8px 8px;
  background: transparent;
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  color: var(--teal);
  text-align: left;
  cursor: pointer;
  transition: background-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.step-foot:hover { background: var(--sand); color: var(--ink); }
.step-foot .ico { width: 14px; height: 14px; flex: 0 0 auto; }
.step-foot-hint { font-weight: 400; color: var(--mist); font-size: 11px; }
.step-foot-hint:empty { display: none; }

/* Everything this client's path leaves out, in one press. */
.step-add-all { margin-top: 6px; border-style: dashed; border-color: var(--sage); color: var(--teal); }
.step-add-all:hover { background: var(--sky); border-style: solid; }
.step-add-all .ico, .step-add-one .ico { width: 15px; height: 15px; flex: 0 0 auto; }

/* The heading over the "add to this client" list, set off from the path above
   it by a rule so the two are not read as one continuous sequence. */
.step-phase-off { margin-top: 6px; border-top: 1px solid var(--sage-light); padding-top: 9px; }

/* A single off-path step and its +. Reads as an add — teal, the + where a step
   number would be — rather than as another step already on the path. */
.step-add-one { color: var(--teal); }
.step-add-one:hover { background: var(--sky); border-color: var(--sage); }
.step-add-one .ico { color: var(--teal); }

.cf-add-all { margin: 4px 0 10px; background: #fff; }

/* ── The client's own documents ──────────────────────────
   What they gave us, as against what we made. Every client's set differs, so it
   is a list on their file rather than fields on a form. */
.cf-docs { margin-top: 18px; }
.cf-doc-row { background: #fff; }
.cf-docs-add { margin-top: 8px; }
.cf-docs-add input[disabled] + span { color: var(--mist); }
.cf-add .ico, .cf-drop .ico { width: 13px; height: 13px; }

/* The client file's head stays put while the body scrolls, so "Open in the
   editor" — which lives in the head beside the close — is always in reach. The
   card becomes a column: a fixed head, a scrolling body. Scoped to this overlay;
   the others keep the whole-card scroll. */
#cf-overlay .overlay-card {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  padding: 0;
}
#cf-overlay .overlay-head {
  flex: 0 0 auto;
  margin: 0;
  padding: 20px 24px 14px;
  border-bottom: 1px solid var(--sage-light);
}
#cf-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: 16px 24px 22px;
}
.cf-head-actions { display: flex; align-items: center; gap: 12px; }

/* ── A new client, read out of their documents ───────────
   The 59 all arrive the same way: a folder of paperwork somebody has already
   been sent. Typing the name, salutation and postal address off the screen 59
   times is the kind of work that produces one transposed street number nobody
   notices until it prints on an SOA — so the reading is done for you and the
   checking is done by you. Which is why every field here carries the file and
   the place it came from, and nothing is saved until Nick presses create. */

/* Second action on the roster head. Outlined against the filled New client, so
   the pair reads as one primary and one alternative rather than two decisions
   of equal weight. */
.dash-from-docs {
  border-radius: 10px;
  padding: 10px 14px;
  border: 1px solid var(--sage);
  background: #fff;
  color: var(--teal);
}
.dash-from-docs:hover { border-color: var(--teal); color: var(--ink); }
.dash-from-docs .ico { width: 15px; height: 15px; }

.nc-pick { padding: 11px 14px; font-size: 13px; }
.nc-pick .ico { width: 15px; height: 15px; }

.nc-files { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
/* Long enough to say which document it is, short enough that eight of them
   still wrap into a couple of lines. */
.nc-files .cf-added {
  text-transform: none;
  letter-spacing: 0;
  font-size: 11px;
  font-weight: 500;
  padding: 4px 9px;
  max-width: 220px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.nc-go { margin-top: 14px; }
.nc-go .ico { width: 15px; height: 15px; }
.nc-go[disabled] { cursor: progress; }

/* Label, value and source stacked, one field per row. Side by side would fit,
   but the source line is the whole point of the screen and it is the first
   thing a two-column layout squeezes. */
.nc-fields { display: flex; flex-direction: column; gap: 10px; margin: 12px 0 4px; }

.nc-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 10px 12px;
  border: 1px solid var(--sage-light);
  border-radius: 10px;
  background: var(--sand);
}

.nc-field-label {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--mist);
}

.nc-field-input {
  font: inherit;
  font-size: var(--control-font);
  color: var(--ink);
  background: #fff;
  border: 1px solid var(--sage);
  border-radius: 8px;
  padding: 8px 10px;
  width: 100%;
  transition: border-color var(--t-fast) var(--ease-out);
}
.nc-field-input:hover { border-color: var(--teal); }
.nc-field-input:focus-visible { outline: 2px solid var(--teal); outline-offset: 1px; }

/* Where it came from — or that it did not come from anywhere, which is the more
   important of the two and so is the one that is coloured. */
.nc-field-source { font-size: 11.5px; line-height: 1.45; color: var(--teal); }
.nc-field-source[data-found="no"] { color: #8a3b2e; }

.nc-seen-head { margin: 18px 0 8px; }
.nc-seen { display: flex; width: 100%; margin-bottom: 6px; }

@media (max-width: 720px) {
  /* The roster head has room for one full-width button per line at this width,
     and From documents is the one that reads as an explanation of itself. */
  .dash-from-docs { flex: 0 0 auto; }
}

/* Which path a client is on, on the client card in the editor. */
.client-card-path { margin-bottom: 12px; }
.client-card-path select {
  width: 100%;
  font: inherit;
  font-size: var(--control-font);
  color: var(--ink);
  background: #fff;
  border: 1px solid var(--sage);
  border-radius: 8px;
  padding: 9px 11px;
}
.client-card-path .field-hint { color: var(--teal); }

/* ── Finalise & file to Drive ────────────────────────────
   The overlay states its case before it does anything: which client, which
   document, and the exact folder and filename the PDF will land at. Filing
   writes to a client's permanent record, so nobody should have to guess where
   it went. */

.file-note { font-size: 13px; line-height: 1.55; color: var(--teal); margin-bottom: 12px; }
.file-note.file-warn {
  color: #7a3427;
  background: #fdf6f3;
  border: 1px solid #e8cfc6;
  border-radius: 10px;
  padding: 11px 13px;
}
.file-note.file-ok {
  color: var(--ink);
  background: var(--sky);
  border: 1px solid var(--sage);
  border-radius: 10px;
  padding: 11px 13px;
}

.file-steps {
  margin: 0 0 14px 18px;
  padding: 0;
  font-size: 13px;
  line-height: 1.6;
  color: var(--ink);
}
.file-steps li { margin-bottom: 3px; }

/* What is unfinished about the document, before it can be filed.
   A worklist rather than an error panel: each line is something to go and do,
   so it reads as a list of tasks and not as the form telling you off. */
.file-checks { margin-bottom: 14px; }
.file-checks .file-note { margin-bottom: 9px; }

.file-check-list {
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 13px;
  line-height: 1.55;
  color: var(--ink);
}
.file-check-list li {
  position: relative;
  padding: 8px 12px 8px 26px;
  border-bottom: 1px solid var(--sage-light);
}
.file-check-list li:last-child { border-bottom: 0; }
/* A marker rather than a bullet, so the two kinds are told apart at a glance
   without colour being the only thing carrying it. */
.file-check-list li::before {
  position: absolute;
  left: 8px;
  top: 8px;
  font-weight: 700;
}
[data-kind="block"] .file-check-list li::before { content: "×"; color: #b4472f; }
[data-kind="advise"] .file-check-list li::before { content: "!"; color: var(--teal); }

/* The section it is in, so it can be found without reading the whole form. */
.file-check-where {
  display: block;
  margin-top: 2px;
  font-size: 11.5px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--teal);
}

/* The destination, set as a path so it reads as a filesystem location rather
   than prose. Wraps rather than truncates: a filename you cannot read in full
   is not a confirmation of anything. */
.file-path {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--ink);
  background: var(--sand);
  border: 1px solid var(--sage-light);
  border-radius: 10px;
  padding: 11px 13px;
  margin-bottom: 14px;
  overflow-wrap: anywhere;
}
.file-path .ico { color: var(--teal); margin-top: 1px; }

.file-progress {
  font-size: 14px;
  font-weight: 600;
  color: var(--ink);
  margin-bottom: 10px;
  padding-left: 24px;
  position: relative;
}
/* A ring that turns, because the Worker gives no progress channel back and a
   percentage would be invented. */
.file-progress::before {
  content: "";
  position: absolute;
  left: 0; top: 50%;
  margin-top: -7px;
  width: 14px; height: 14px;
  border-radius: 50%;
  border: 2px solid var(--sage-light);
  border-top-color: var(--teal);
  animation: file-spin 700ms linear infinite;
}
@keyframes file-spin { to { transform: rotate(360deg); } }

.file-go {
  width: 100%;
  justify-content: center;
  background: var(--ink);
  color: var(--sage-light);
  border-radius: 10px;
  padding: 12px 16px;
  margin-top: 2px;
}
.file-go:hover { background: var(--ink-2); color: #fff; }
.overlay-card .btn-import.file-go { background: transparent; color: var(--teal); }
.overlay-card .btn-import.file-go:hover { background: var(--sand); color: var(--ink); }

/* Dimmed, not hidden, when /api/capabilities says the Worker cannot render or
   file. Still clickable, because the overlay behind it is what explains why. */
.btn-finalise[data-available="no"] { opacity: 0.55; }
.btn-finalise[data-available="no"]:hover { opacity: 1; }

/* Closes the menu on a click anywhere else, at every width. Only in the DOM
   while it is open, so it can never swallow a click on a shut menu. */
.sheet-scrim { display: none; }
body[data-actions="open"] .sheet-scrim {
  display: block;
  position: fixed;
  inset: 0;
  z-index: 55;
  animation: overlay-in var(--t-fast) var(--ease-out) both;
}

/* ── The morning brief ───────────────────────────────────

   Above the roster, in the roster's own language: the deadline colours are the
   dash-due palette so "overdue" looks like overdue everywhere. Each row is one
   button — name, action, reason — because the whole point is that the next
   press is obvious. */
.today {
  background: #fff;
  border: 1px solid var(--sage-light);
  border-radius: 14px;
  padding: 18px 20px 14px;
  margin-bottom: 18px;
}
.today-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 10px;
}
.today-title {
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.01em;
  color: var(--ink);
  margin: 0;
}
.today-date { font-size: 13px; color: var(--teal); }
.today-clear { margin: 2px 0 6px; font-size: 14px; color: var(--teal); }
.today-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
  counter-reset: today;
}
.today-item {
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-areas: "name act" "name why";
  column-gap: 14px;
  row-gap: 2px;
  align-items: baseline;
  width: 100%;
  text-align: left;
  padding: 10px 12px 10px 14px;
  background: var(--sand);
  border: 1px solid var(--sage-light);
  border-left-width: 4px;
  border-radius: 10px;
  cursor: pointer;
  font: inherit;
  transition: background var(--t-fast) var(--ease-out), border-color var(--t-fast) var(--ease-out);
}
.today-item:hover { background: var(--sky); }
.today-item:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
.today-name {
  grid-area: name;
  font-weight: 650;
  color: var(--ink);
  font-size: 14px;
  min-width: 130px;
}
.today-act { grid-area: act; font-size: 14px; color: var(--ink-2); }
.today-why { grid-area: why; font-size: 12.5px; color: var(--teal); }
/* The same words for the same states as the roster's own badges. */
.today-item[data-band="overdue"] { border-left-color: #8a3b2e; background: #fdf1ee; }
.today-item[data-band="overdue"] .today-why { color: #8a3b2e; font-weight: 600; }
.today-item[data-band="dueNow"] { border-left-color: #7a5a22; background: #fdf7ee; }
.today-item[data-band="dueNow"] .today-why { color: #7a5a22; }
.today-item[data-band="notes"] { border-left-color: var(--teal); }
.today-item[data-band="noDate"] { border-left-color: var(--mist); border-left-style: dashed; }
.today-foot {
  margin: 10px 2px 0;
  font-size: 12.5px;
  color: var(--teal);
}

/* ── Mobile ──────────────────────────────────────────────
   Below this width the form and an A4 sheet cannot share the screen. So the two
   panes become one at a time with a switch at the bottom, and the menu drops
   from the top bar to a bottom sheet, within thumb reach. Nothing moves in the
   DOM: every control keeps the handler it already had. */

.panebar { display: none; }

@media (max-width: 900px) {
  :root { --control-font: 16px; }

  /* No room for a fixed rail on a phone. It collapses, the content reclaims the
     full width, and the Dashboard and Clients views fold back into one scrolling
     page — the brief, the roster and the ask together — reached the way it was
     before the rail existed: the topbar menu and the floating launcher. */
  body[data-view="dashboard"] .sidenav,
  body[data-view="clients"] .sidenav,
  body[data-view="assistant"] .sidenav { display: none; }
  body[data-view="dashboard"] .dashboard,
  body[data-view="clients"] .dashboard,
  body[data-view="assistant"] .assistant { margin-left: 0; }
  body[data-view="dashboard"] .dash-head-actions,
  body[data-view="dashboard"] .dash-grid,
  body[data-view="dashboard"] #dash-practice,
  body[data-view="clients"] #today-panel,
  body[data-view="clients"] .dash-ask { display: revert; }

  /* The rail becomes a sheet over the thread. A column wide enough to read a
     chat title is 230px, which at 390px leaves 160 for the chat — so below this
     width the history is somewhere you go rather than something you see. */
  .asst-rail {
    position: absolute;
    inset: 0 auto 0 0;
    z-index: 12;
    width: min(280px, 82vw);
    transform: translateX(-102%);
    transition: transform var(--t-mid) var(--ease-out);
    box-shadow: 0 0 40px rgba(6, 42, 48, 0.18);
  }
  .asst-rail[data-open="yes"] { transform: none; }
  .assistant { position: relative; }
  .asst-rail-toggle, .asst-new-small { display: inline-flex; }
  .asst-rail-close { display: inline-flex; }

  /* The rail covers the head that opened it, so the way out cannot be the way
     in. Tapping anywhere off the sheet closes it, the same as every other sheet
     in the studio. */
  .asst-rail-scrim {
    display: block;
    position: absolute;
    inset: 0;
    z-index: 11;
    background: rgba(6, 42, 48, 0.4);
  }
  .asst-rail-scrim[hidden] { display: none; }
  /* The rail's own New chat is unreachable while the rail is shut, so the head
     carries one. Two of them on screen at once would be the confusing part. */
  .asst-head-title .asst-sub { display: none; }
  .asst-head { padding: 10px 14px; gap: 8px; }
  .asst-title { font-size: 15px; }
  .asst-thread { padding: 16px 14px 8px; gap: 16px; }
  .asst-compose { padding: 10px 14px 0; }
  .asst-foot { padding: 8px 14px 12px; }
  /* Icon only, so the head fits History, New chat and Minimise across 390px. */
  .asst-rail-toggle span, .asst-new-small span, .asst-min span { display: none; }

  /* Clear of the pane switch, which is the one bar that is fixed to the bottom
     at this width and would otherwise sit on top of the launcher. */
  .asst-fab { right: 14px; bottom: calc(76px + env(safe-area-inset-bottom)); }
  /* The roster and the assistant have no pane switch, so there it can sit low. */
  body[data-view="dashboard"] .asst-fab { bottom: calc(16px + env(safe-area-inset-bottom)); }

  .topbar { padding: 8px 14px; min-height: 56px; gap: 10px; row-gap: 8px; }
  .topbar-logo { height: 21px; }
  .topbar-tagline { display: none; }
  .topbar-app { font-size: 11.5px; }

  .topbar-more { padding: 9px 13px; min-height: 42px; }
  /* Icon only. The label is on the aria-label, and the corner has to hold the
     brand, Print / Save PDF and this across 390px. */
  .topbar-more span, .topbar-right .btn span { display: none; }
  .topbar-right .btn { padding: 10px 12px; }

  /* Its own row and the full width of it. The picker is the thing you reach for
     most on a phone, and sharing a row with the brand left it a thumb wide. */
  .steps { flex: 1 1 100%; order: 3; }
  .step-pick { width: 100%; justify-content: flex-start; min-height: 42px; }
  .step-pick-label { flex: 1 1 auto; }
  /* Anchored to the row rather than the button, so it spans the screen instead
     of hanging off the left edge at 390px. */
  .step-menu { width: 100%; max-height: 60vh; }
  .step-row { min-height: 42px; }
  .dash-tick { width: 20px; height: 20px; }

  .btn { min-height: 42px; padding: 10px 13px; }

  /* The dropdown becomes a bottom sheet in place — same element, same handlers,
     slid up from the edge nearest the thumb instead of hung under a button at
     the top of the screen. */
  .topbar-actions {
    position: fixed;
    top: auto;
    left: 0; right: 0; bottom: 0;
    z-index: 60;
    min-width: 0;
    gap: 6px;
    border: 0;
    border-top: 1px solid var(--teal);
    border-radius: 18px 18px 0 0;
    padding: 12px 14px calc(14px + env(safe-area-inset-bottom));
    max-height: 82dvh;
    overflow-y: auto;
    box-shadow: 0 -18px 50px rgba(6, 42, 48, 0.4);
    /* Shown at all times and moved off-screen instead, so the sheet slides
       rather than fading in place as the dropdown does. */
    opacity: 1;
    visibility: visible;
    transform: translateY(101%);
    transition: transform var(--t-mid) var(--ease-out);
  }
  body[data-actions="open"] .topbar-actions { transform: none; }
  .topbar-actions .btn {
    font-size: 15px;
    padding: 13px 15px;
    min-height: 48px;
    border-radius: 12px;
  }
  .topbar-menu-rule { margin: 3px 4px; }

  body[data-actions="open"] .sheet-scrim {
    background: rgba(6, 42, 48, 0.5);
  }

  .clientbar { padding: 9px 14px; gap: 8px; min-height: 0; }
  .clientbar-label { display: none; }   /* the select carries its own aria-label */
  .clientbar-back { flex: 0 0 auto; }
  .clientbar-picker { flex: 1 1 100%; gap: 8px; }
  #client-select { flex: 1 1 100%; min-width: 0; min-height: 44px; }
  .clientbar-picker .btn { flex: 1 1 0; justify-content: center; }

  /* One pane at a time, chosen by the bar at the bottom. */
  .workspace { flex-direction: column; }
  .panel { flex: 1 1 auto; width: 100%; border-right: 0; }
  /* Centred and capped, so a tablet gets a readable measure instead of fields
     stretched the full 800px. No effect on a phone, which is narrower anyway. */
  .panel-scroll { padding: 16px 14px 32px; max-width: 660px; margin-inline: auto; }
  .panel-foot { padding: 8px 14px; }
  body[data-pane="preview"] .panel { display: none; }
  body[data-pane="form"] .preview { display: none; }

  /* On a phone it stays a right-hand sheet rather than filling the screen: a
     strip of the document is left showing at the left edge, so it reads as a
     panel over the page and not a separate full-screen view. It sits inside the
     workspace, so the pane switch below it stays reachable. */
  .clientai {
    width: min(440px, 90vw);
    padding-bottom: env(safe-area-inset-bottom);
  }

  .panebar {
    display: flex;
    flex: 0 0 auto;
    justify-content: center;
    padding: 8px 14px calc(8px + env(safe-area-inset-bottom));
    background: var(--ink);
    z-index: 40;
  }
  .panebar-switch {
    display: flex;
    gap: 4px;
    width: 100%;
    max-width: 360px;
    padding: 3px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.08);
  }
  .panebar-btn {
    flex: 1 1 0;
    appearance: none;
    border: 0;
    background: transparent;
    color: var(--sage-light);
    font: inherit;
    font-size: 13.5px;
    font-weight: 600;
    min-height: 44px;
    border-radius: 999px;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    transition: background-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
  }
  body[data-pane="form"] #pane-form,
  body[data-pane="preview"] #pane-preview { background: var(--sage-light); color: var(--ink); }

  /* Overlays become sheets rather than centred cards — a centred card on a
     phone leaves dead margin on all four sides and less room for the list. */
  .overlay { padding: 0; align-items: flex-end; }
  .overlay-card {
    max-width: none;
    max-height: 92dvh;
    border-radius: 16px 16px 0 0;
    padding: 18px 16px calc(20px + env(safe-area-inset-bottom));
  }
  .btn-close { font-size: 26px; min-width: 44px; min-height: 44px; }
  /* Title and actions each get a full-width row; side by side they squeeze the
     document name down to two words. */
  .library-row { flex-direction: column; align-items: stretch; gap: 9px; }
  .library-row-actions .btn { flex: 1 1 0; justify-content: center; }

  /* Search and New client share a row rather than stacking — two full-width
     controls cost 60px of the roster before the first card. */
  .dash-head { padding: 15px 14px 14px; }
  .dash-head-actions { width: 100%; gap: 8px; flex-wrap: nowrap; }
  .dash-search-wrap { flex: 1 1 auto; min-width: 0; }
  .dash-search { width: 100%; min-width: 0; }
  .dash-new { flex: 0 0 auto; }
  .dash-body { padding: 14px 14px 30px; }
  .dash-grid { gap: 8px; }
  .dash-tick { width: 20px; height: 20px; }

  /* Five columns do not fit 390px, so the row becomes two lines: who and the
     clock on the first, the strip and the action beneath. The delete button
     keeps its own column on the first line rather than sitting a thumb-width
     from the action, which is the press that must not be a near miss. */
  .dash-row {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas:
      "who   del"
      "where where"
      "due   due"
      "act   act";
    gap: 9px 10px;
    padding: 12px;
  }
  .dash-who { grid-area: who; min-height: 36px; }
  .dash-name { font-size: 16px; white-space: normal; }
  .dash-where { grid-area: where; }
  .dash-due { grid-area: due; margin-top: 0; }
  /* Full width here, unlike desktop: a thumb wants the whole row, and with one
     row per screenful there is no column of buttons for a hugging edge to help. */
  .dash-act { grid-area: act; min-height: 44px; justify-content: center; justify-self: stretch; }
  .dash-del { grid-area: del; min-width: 40px; min-height: 40px; align-items: center; justify-content: center; }
  /* A little taller: at this width the strip is the whole progress display and a
     6px bar beside 16px type reads as a rule rather than a measure. */
  .dash-seg { height: 8px; }
  .dash-at { font-size: 12px; white-space: normal; }

  /* Status and action stack under the document rather than beside it: at 390px a
     badge, a date and a button in the same row leave the label two words wide. */
  .cf-row { flex-direction: column; gap: 9px; }
  .cf-row-side { max-width: none; width: 100%; justify-content: flex-start; }
  .cf-row-side .btn, .cf-add, .cf-drop { min-height: 40px; }
  .cf-row-off { flex-direction: column; align-items: stretch; }
  /* The fixed head keeps its own padding; the body takes the safe-area room at
     the foot so the last rows clear the home indicator as they scroll. */
  #cf-overlay .overlay-head { padding: 18px 16px 12px; }
  #cf-body { padding: 14px 16px calc(18px + env(safe-area-inset-bottom)); }
  /* On a phone the label would crowd the close, so the head action shows its
     pen alone; the full button still sits on every step row and at the roster. */
  #cf-open-editor span { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  #cf-open-editor { padding: 9px 11px; }
  /* The alternatives go full width rather than wrapping into ragged pairs. */
  .cf-next-alt { flex: 1 1 100%; min-height: 44px; }

  .ai-panel-actions .btn-import { flex: 1 1 100%; }

  .boot-card { padding: 32px 22px 28px; }
  .boot-title { font-size: 21px; }
  .boot-ring { width: 84px; height: 84px; margin: 22px auto 18px; }
  .boot-note { margin-top: 20px; }
}

/* Phone-only. A tablet has room for the full brand lockup and for managing
   clients from the bar; a 390px screen has neither, and every row of chrome
   here is a row of the document you cannot see. */
@media (max-width: 560px) {
  /* The mark alone carries the brand, and "Clients" or the document tab already
     says where you are. Reclaims a whole topbar row. */
  .topbar-title { display: none; }

  /* The mark alone. "Ask AI" beside it is two words explaining a button that is
     pressed far more often than it is read, and the width is worth more. */
  .asst-fab-label { display: none; }
  .asst-fab { padding: 13px; gap: 0; }

  /* The roster is where clients are added and removed now, so the bar keeps only
     the picker. It also stops Delete client sitting a thumb-width from the
     client you are working on. */
  #btn-client-new, #btn-client-delete { display: none; }

  /* With those gone the back arrow and the picker fit one row, so the arrow drops
     its label and the client's name gets the width instead — a truncated name is
     the one thing on this bar that must not happen. */
  .clientbar-back span { display: none; }
  .clientbar-back { padding: 10px 12px; }
  .clientbar-picker { flex: 1 1 auto; min-width: 0; }

  /* Client file shares that row rather than claiming a third one. The wider
     breakpoint gives the select a full-width basis, which is right when it sits
     alone and wrong the moment a button sits beside it. */
  #client-select { flex: 1 1 auto; }
  .clientbar-picker .btn { flex: 0 0 auto; }
}

/* Motion is feedback here, never information — with it suppressed the studio
   behaves identically, just without the easing. */
@media (prefers-reduced-motion: reduce) {
  /* .boot excluded: its animation is an 8s fail-safe, not decoration. */
  *:not(.boot) { animation-duration: 1ms !important; animation-delay: 0ms !important; }
  .btn:active, .step-row:active, .ai-file-remove:active, .dash-act:active { transform: none; }
  /* The overlay still covers the boot; it just goes without the fade. */
  .boot, .boot-arc { transition: none; }
  /* The actions sheet arrives in place instead of sliding up. */
  .topbar-actions { transition: none; }
}

/* Whether the browser's work has reached the server. Quiet when it has — this is
   reassurance, not an alert — and only raises its voice when it has not. */
.sync-state { font-size: 11.5px; color: var(--mist); }
.sync-state[data-state="ok"] { color: var(--teal); }
.sync-state[data-state="error"] { color: #8a3b2e; font-weight: 500; }
/* The roster's copy of it, under the client count. */
.dash-sync { margin-top: 4px; }

/* The brief on a phone: the name takes its own line, the reason wraps under
   the action, and the row grows to thumb size. */
@media (max-width: 900px) {
  .today { padding: 14px 14px 12px; }
  .today-item {
    grid-template-columns: 1fr;
    grid-template-areas: "name" "act" "why";
    row-gap: 3px;
    padding: 12px;
  }
  .today-name { min-width: 0; }

  /* The ask bar keeps its shape but the send button loses its label to a glyph,
     so the input keeps the width a real question needs on a phone. */
  .dash-ask { margin-bottom: 16px; }
  .dash-ask-form { padding: 8px 8px 8px 12px; gap: 8px; }
  .dash-ask-input { font-size: 16px; }  /* 16px or iOS zooms on focus */
  .dash-ask-send { padding: 9px 12px; }
  .dash-ask-chips { gap: 6px; }
  .dash-ask-chip { font-size: 12px; padding: 6px 11px; }
}
