/* ============================================================
   RMB Front-End System — Component Library
   Every component, built from ui/tokens.css. BEM naming; state on
   attributes; no theme branches. See ui/manifest.json + ui/RULES.md.
   Load AFTER ui/tokens.css.
   ============================================================ */

/* ===== base =====
   [hidden] means hidden until told otherwise. The UA rule is only
   display:none at zero specificity, so any component that sets its own display
   — .btn, .callout, .timer, a row using display:contents — outranks it and the
   attribute silently stops working. Pages have been patching this one selector
   at a time; this settles it once. */
[hidden]{ display:none !important; }

/* ===== .btn (canonical — reused verbatim from component-reference) ===== */
.btn{
  --btn-bg:var(--accent); --btn-fg:var(--on-accent); --btn-bd:transparent;
  display:inline-flex; align-items:center; justify-content:center; gap:var(--sp-8);
  font-family:var(--font-sans); font-size:var(--text-15); font-weight:600; line-height:1;
  height:38px; padding:0 var(--sp-16); border:1px solid var(--btn-bd); border-radius:var(--radius-md);
  background:var(--btn-bg); color:var(--btn-fg); cursor:pointer; white-space:nowrap; text-decoration:none;
  transition:filter var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.btn:hover{ filter:brightness(1.06); }
.btn:focus-visible{ outline:2px solid var(--accent); outline-offset:2px; }
.btn__icon{ width:16px; height:16px; display:inline-flex; }
/* split button: the main action, and an arrow that opens the rest of the family.
   Both halves are .btn; the join is drawn by dropping the inner radii. */
.btn-split{ display:inline-flex; align-items:stretch; }
.btn-split .btn-split__main{ border-top-right-radius:0; border-bottom-right-radius:0; }
.btn-split .btn-split__more{ border-top-left-radius:0; border-bottom-left-radius:0; border-left-color:color-mix(in srgb, var(--on-accent) 30%, transparent); padding:0 var(--sp-8); }
.btn-split .btn--secondary.btn-split__more{ border-left-color:var(--btn-bd); }
.btn-split .btn-split__more .icon{ width:16px; height:16px; }
.btn__icon svg:not(.icon){ width:100%; height:100%; fill:none; stroke:currentColor; stroke-width:1.6; }
.btn--secondary{ --btn-bg:var(--surface); --btn-fg:var(--ink); --btn-bd:var(--line-2); }
.btn--secondary:hover{ filter:none; background:var(--surface-2); }
.btn--secondary.is-active{ background:var(--surface-2); border-color:var(--accent); color:var(--accent-ink); }
.btn--ghost{ --btn-bg:transparent; --btn-fg:var(--muted); }
.btn--ghost:hover{ filter:none; background:var(--surface-2); color:var(--ink); }
.btn--danger{ --btn-bg:var(--danger); --btn-fg:var(--on-danger); }
.btn--sm{ height:30px; padding:0 var(--sp-12); font-size:var(--text-12); }
.btn--lg{ height:46px; padding:0 var(--sp-24); font-size:var(--text-18); }
.btn[disabled],.btn[aria-disabled="true"]{ opacity:.45; cursor:not-allowed; }
.btn[data-loading]{ color:transparent; pointer-events:none; position:relative; }
.btn[data-loading]::after{ content:""; position:absolute; width:15px; height:15px; border:2px solid var(--btn-fg); border-top-color:transparent; border-radius:50%; animation:btn-spin .6s linear infinite; }
@keyframes btn-spin{ to{ transform:rotate(360deg); } }

/* ===== icon (Lucide) =====
   Icons are Lucide only, from the self-hosted sprite. Reference a symbol:
   <svg class="icon"><use href="ui/icons.svg#NAME"/></svg>
   (or "#NAME" against an inlined copy of the sprite). */
.icon{
  width:16px;
  height:16px;
  flex:none;
  display:inline-block;
  vertical-align:-0.18em;
  fill:none;
  stroke:currentColor;
  stroke-width:2;
  stroke-linecap:round;
  stroke-linejoin:round;
}
.icon--sm{ width:14px; height:14px; }
.icon--lg{ width:20px; height:20px; }

/* ===== .icon-btn ===== */
.icon-btn{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  width:28px;
  height:28px;
  padding:0;
  border:none;
  border-radius:var(--radius-md);
  background:transparent;
  color:var(--muted);
  cursor:pointer;
  transition:background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.icon-btn svg:not(.icon){ width:16px; height:16px; fill:none; stroke:currentColor; stroke-width:1.6; }
.icon-btn:hover{ background:var(--surface-2); color:var(--ink); }
.icon-btn:focus-visible{ outline:2px solid var(--accent); outline-offset:2px; }
.icon-btn--sm{ width:24px; height:24px; }
.icon-btn--sm svg{ width:14px; height:14px; }
.icon-btn--danger:hover{ background:var(--danger-soft); color:var(--danger-ink); }
.icon-btn[disabled]{ opacity:.45; cursor:not-allowed; }

/* ===== .badge ===== */
.badge{
  --badge-bg:var(--neutral-soft);
  --badge-fg:var(--neutral-ink);
  display:inline-flex;
  align-items:center;
  gap:var(--sp-4);
  height:20px;
  padding:0 var(--sp-8);
  border-radius:var(--radius-pill);
  font-family:var(--font-sans);
  font-size:var(--text-12);
  font-weight:600;
  line-height:1;
  white-space:nowrap;
  background:var(--badge-bg);
  color:var(--badge-fg);
}
.badge__dot{ width:6px; height:6px; border-radius:50%; background:currentColor; flex:none; }
.badge--queue{ --badge-bg:var(--neutral-soft); --badge-fg:var(--neutral-ink); }
.badge--active{ --badge-bg:var(--info-soft); --badge-fg:var(--info-ink); }
.badge--info{ --badge-bg:var(--info-soft); --badge-fg:var(--info-ink); }
.badge--success{ --badge-bg:var(--success-soft); --badge-fg:var(--success-ink); }
.badge--warning{ --badge-bg:var(--warning-soft); --badge-fg:var(--warning-ink); }
.badge--danger{ --badge-bg:var(--danger-soft); --badge-fg:var(--danger-ink); }
.badge--review{ --badge-bg:var(--purple-soft); --badge-fg:var(--purple-ink); }
.badge--returned{ --badge-bg:var(--orange-soft); --badge-fg:var(--orange-ink); }
.badge--draft{ --badge-bg:var(--surface-2); --badge-fg:var(--muted); }
.badge--archived{ --badge-bg:var(--neutral-soft); --badge-fg:var(--neutral-ink); }

/* ===== .chip ===== */
.chip{
  display:inline-flex;
  align-items:center;
  gap:var(--sp-4);
  height:20px;
  padding:0 var(--sp-8);
  border:1px solid currentColor;
  border-radius:var(--radius-sm);
  font-family:var(--font-mono);
  font-size:var(--text-12);
  font-weight:500;
  line-height:1;
  white-space:nowrap;
  background:transparent;
  color:var(--muted);
}
.chip--input{ color:var(--orange-ink); }
.chip--proof{ color:var(--purple-ink); }
.chip--delivered{ color:var(--success-ink); }
.chip--service{ color:var(--info-ink); }
.chip--neutral{ color:var(--neutral-ink); }
.chip--count{ gap:0; padding:0 var(--sp-4); min-width:20px; justify-content:center; }
.chip--sm{ height:var(--sp-16); min-width:var(--sp-16); font-size:var(--text-9); } /* beside small text: a field label, a caption */

/* ===== .status-dot ===== */
.status-dot{
  display:inline-block;
  width:8px;
  height:8px;
  border-radius:50%;
  background:var(--neutral);
  flex:none;
}
.status-dot--success{ background:var(--success); }
.status-dot--warning{ background:var(--warning); }
.status-dot--danger{ background:var(--danger); }
.status-dot--info{ background:var(--info); }
.status-dot--neutral{ background:var(--neutral); }

/* ===== .priority ===== */
.priority{
  --prio:var(--muted);
  display:inline-flex;
  align-items:center;
  gap:var(--sp-4);
  font-family:var(--font-sans);
  font-size:var(--text-12);
  font-weight:500;
  color:var(--ink);
}
.priority__dot{ width:8px; height:8px; border-radius:50%; background:var(--prio); flex:none; }
.priority--lowest{ --prio:var(--faint); }
.priority--low{ --prio:var(--neutral); }
.priority--normal{ --prio:var(--info); }
.priority--high{ --prio:var(--warning); }
.priority--highest{ --prio:var(--danger); }

/* ===== .avatar ===== */
.avatar{
  --av-bg:var(--accent-soft);
  --av-fg:var(--accent-ink);
  display:inline-flex;
  align-items:center;
  justify-content:center;
  width:24px;
  height:24px;
  border-radius:50%;
  font-family:var(--font-sans);
  font-size:var(--text-9);
  font-weight:600;
  line-height:1;
  letter-spacing:0.02em;
  background:var(--av-bg);
  color:var(--av-fg);
  user-select:none;
}
/* a real photo fills the circle; the initials underneath are the fallback */
.avatar__img{ display:block; width:100%; height:100%; border-radius:50%; object-fit:cover; }
.avatar--sm{ width:20px; height:20px; }
.avatar--lg{ width:32px; height:32px; font-size:var(--text-12); }
.avatar--xl{ width:64px; height:64px; font-size:var(--text-24); }
.avatar--a{ --av-bg:var(--accent-soft); --av-fg:var(--accent-ink); }
.avatar--b{ --av-bg:var(--info-soft); --av-fg:var(--info-ink); }
.avatar--c{ --av-bg:var(--purple-soft); --av-fg:var(--purple-ink); }
.avatar--d{ --av-bg:var(--orange-soft); --av-fg:var(--orange-ink); }
.avatar--more{ --av-bg:var(--surface-2); --av-fg:var(--muted); border:1px solid var(--line-2); }
.avatar-stack{ display:inline-flex; align-items:center; }
.avatar-stack .avatar{ border:2px solid var(--surface); margin-left:calc(-1 * var(--sp-8)); }
.avatar-stack .avatar:first-child{ margin-left:0; }
/* ===== link ===== */
.link{ color:var(--accent-ink); text-decoration:none; }
.link:hover{ text-decoration:underline; }
.link:focus-visible{ outline:2px solid var(--accent); outline-offset:2px; border-radius:var(--radius-sm); }
.link--muted{ color:var(--muted); }

/* ===== eyebrow ===== */
.eyebrow{
  font-family:var(--font-mono);
  font-size:var(--text-12);
  font-weight:600;
  letter-spacing:0.14em;
  text-transform:uppercase;
  color:var(--faint);
}

/* ===== divider ===== */
.divider{
  height:1px;
  border:0;
  background:var(--line);
}
.divider--inset{ margin-left:var(--sp-16); margin-right:var(--sp-16); }

/* ===== cell-mono ===== */
.cell-mono{ font-family:var(--font-mono); font-size:var(--text-12); color:var(--muted); }

/* ===== cell-amount ===== */
.cell-amount{
  font-family:var(--font-mono);
  font-size:var(--text-15);
  color:var(--ink);
  text-align:right;
}
.cell-amount.is-zero{ color:var(--faint); }

/* ===== skeleton ===== */
.skeleton{
  height:var(--sp-12);
  border-radius:var(--radius-sm);
  background:linear-gradient(90deg, var(--surface-2) 25%, var(--line) 37%, var(--surface-2) 63%);
  background-size:400% 100%;
  animation:skeleton-shimmer 1.4s var(--ease) infinite;
}
@keyframes skeleton-shimmer{ from{ background-position:100% 0; } to{ background-position:0 0; } }

/* ===== meter ===== */
.meter{
  width:100%;
  height:var(--sp-8);
  background:var(--surface-2);
  border-radius:var(--radius-pill);
  overflow:hidden;
}
.meter__fill{
  height:100%;
  background:var(--accent);
  border-radius:var(--radius-pill);
  transition:width var(--dur-fast) var(--ease);
}
.meter__fill--warning{ background:var(--warning); }
.meter__fill--danger{ background:var(--danger); }
/* stacked: several series sharing one track, so a total can be read by
   composition — which part of an estimate went where. Segment widths are
   per-instance data and belong inline. Hue identifies the series, so an
   overrun is drawn as its own --over segment straight after the series it
   belongs to rather than by recolouring it. */
.meter--stacked{ display:flex; }
.meter__seg{ height:100%; background:var(--neutral); }
.meter__seg + .meter__seg{ border-left:1px solid var(--surface); }
.meter__seg--a{ background:var(--accent); }
.meter__seg--b{ background:var(--info); }
.meter__seg--c{ background:var(--purple); }
.meter__seg--over{ background:var(--danger); }
/* --rest is the unused remainder of that series' budget: same hue, soft
   tint. Without it an under-run looks identical to empty track. */
.meter__seg--rest{ background:color-mix(in srgb, var(--neutral) 26%, transparent); }
.meter__seg--a.meter__seg--rest{ background:color-mix(in srgb, var(--accent) 26%, transparent); }
.meter__seg--b.meter__seg--rest{ background:color-mix(in srgb, var(--info) 26%, transparent); }
.meter__seg--c.meter__seg--rest{ background:color-mix(in srgb, var(--purple) 26%, transparent); }
/* legend swatch, for a .detail-label or caption naming a series */
.meter__key{
  display:inline-block;
  width:var(--sp-8);
  height:var(--sp-8);
  margin-right:var(--sp-4);
  border-radius:var(--radius-sm);
  background:var(--neutral);
}
.meter__key--a{ background:var(--accent); }
.meter__key--b{ background:var(--info); }
.meter__key--c{ background:var(--purple); }

/* ===== field ===== */
.field{
  display:flex;
  flex-direction:column;
  gap:var(--sp-8);
}
.field__label{
  font-family:var(--font-sans);
  font-size:var(--text-12);
  font-weight:600;
  color:var(--ink);
}
/* a count beside the label sits the way it does on a tab: --sp-8 apart, centered */
.field__label:has(> .chip){ display:flex; align-items:center; gap:var(--sp-8); }
/* required, never optional: an unmarked field is optional; a required one ends its label with * */
.field__label > .field__req{ margin-left:var(--sp-4); color:var(--danger); }
.field__help{ font-family:var(--font-sans); font-size:var(--text-12); color:var(--faint); }
.field__error{ display:none; font-family:var(--font-sans); font-size:var(--text-12); color:var(--danger); }

/* ===== input ===== */
.input{
  width:100%;
  height:38px;
  padding:0 var(--sp-12);
  font-family:var(--font-sans);
  font-size:var(--text-15);
  color:var(--ink);
  background:var(--surface);
  border:1px solid var(--line-2);
  border-radius:var(--radius-md);
  transition:border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}
.input::placeholder{ color:var(--faint); }
.input:hover{ border-color:var(--faint); }
.input:focus{
  outline:none;
  border-color:var(--accent);
  box-shadow:0 0 0 3px var(--accent-soft);
}
.input[disabled]{
  background:var(--surface-2);
  color:var(--faint);
  cursor:not-allowed;
}
textarea.input{
  height:auto;
  min-height:88px;
  padding:var(--sp-8) var(--sp-12);
  line-height:1.55;
  resize:vertical;
}

/* ===== select ===== */
.select{ position:relative; display:block; }
.select > .input{
  padding-right:var(--sp-32);
  appearance:none;
  -webkit-appearance:none;
  cursor:pointer;
}
.select::after{
  content:"";
  position:absolute;
  top:50%;
  right:var(--sp-12);
  width:6px;
  height:6px;
  border-right:1.5px solid var(--muted);
  border-bottom:1.5px solid var(--muted);
  transform:translateY(-70%) rotate(45deg);
  pointer-events:none;
}

/* ===== field--invalid ===== */
.field--invalid .input{ border-color:var(--danger); }
.field--invalid .input:focus{ box-shadow:0 0 0 3px var(--danger-soft); }
.field--invalid .field__error{ display:block; }
.field--invalid .field__help{ display:none; }

/* ===== choice ===== */
.choice{
  display:inline-flex;
  align-items:center;
  gap:var(--sp-8);
  font-family:var(--font-sans);
  font-size:var(--text-15);
  color:var(--ink);
  cursor:pointer;
}
/* A label long enough to wrap — consent text, mostly. .choice is a flex row, so
   a bare sentence containing links breaks into one flex item per node and
   stacks; __label keeps it a single item that wraps as text. --top then sets
   the box against the first line instead of the middle of the block. */
.choice__label{ flex:1 1 auto; }
.choice--top{ align-items:flex-start; }
.choice--top .choice__box{ margin-top:var(--sp-4); }
.choice__box{
  width:16px;
  height:16px;
  flex:none;
  accent-color:var(--accent);
  cursor:pointer;
}
.choice[aria-disabled="true"]{ opacity:.5; cursor:not-allowed; }

/* ===== switch ===== */
.switch{
  display:inline-flex;
  align-items:center;
  gap:var(--sp-12);
  font-family:var(--font-sans);
  font-size:var(--text-15);
  color:var(--ink);
  cursor:pointer;
}
/* a switch that can't be turned off (a required question) reads as locked */
.switch:has(.switch__input:disabled){ opacity:.5; cursor:not-allowed; }
.switch__input{ position:absolute; opacity:0; width:0; height:0; }
.switch__track{
  position:relative;
  flex:none;
  width:40px;
  height:22px;
  background:var(--line-2);
  border-radius:var(--radius-pill);
  transition:background var(--dur-fast) var(--ease);
}
.switch__track::after{
  content:"";
  position:absolute;
  top:2px;
  left:2px;
  width:18px;
  height:18px;
  background:var(--surface);
  border-radius:50%;
  box-shadow:var(--shadow-sm);
  transition:transform var(--dur-fast) var(--ease);
}
.switch__input:checked + .switch__track{ background:var(--accent); }
.switch__input:checked + .switch__track::after{ transform:translateX(18px); }
.switch__input:focus-visible + .switch__track{
  outline:2px solid var(--accent);
  outline-offset:2px;
}
/* ===== card ===== */
.card{ background:var(--surface); border:1px solid var(--line); border-radius:var(--radius-lg); box-shadow:var(--shadow); overflow:hidden; display:flex; flex-direction:column; }
/* body grows so the footer locks to the bottom when cards share a row's height */
.card__header{
  padding:var(--sp-16);
  border-bottom:1px solid var(--line);
  font-family:var(--font-sans);
  font-weight:600;
  font-size:var(--text-15);
  color:var(--ink);
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:var(--sp-12);
}
/* header actions: icon buttons at the right of .card__header */
.card__actions{ display:inline-flex; align-items:center; gap:var(--sp-4); }
.card__body{
  padding:var(--sp-16);
  color:var(--muted);
  font-size:var(--text-15);
  line-height:1.55;
  flex:1 1 auto;
}
.card__footer{
  padding:var(--sp-12) var(--sp-16);
  border-top:1px solid var(--line);
  display:flex;
  gap:var(--sp-8);
  justify-content:flex-end;
}
.card--compact .card__header, .card--compact .card__body{ padding:var(--sp-12); }

/* ===== panel ===== */
.panel{ background:var(--surface); border:1px solid var(--line); border-radius:var(--radius-lg); box-shadow:var(--shadow); overflow:hidden; }
.panel__header{
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:var(--sp-12);
  padding:var(--sp-12) var(--sp-16);
  border-bottom:1px solid var(--line);
}
.panel__title{
  display:flex;
  align-items:center;
  gap:var(--sp-8);
  font-family:var(--font-sans);
  font-size:var(--text-15);
  font-weight:600;
  color:var(--ink);
  margin:0;
}
/* a section's own status beside its title: a marker, plus the reason when something is missing */
.panel__status{ display:inline-flex; align-items:center; gap:var(--sp-8); margin-left:var(--sp-8); font-size:var(--text-12); font-weight:500; color:var(--muted); vertical-align:middle; }
.panel__status .marker{ width:18px; height:18px; }
.panel__status[data-state="missing"]{ color:var(--warning-ink); }
.panel__action{ display:inline-flex; align-items:center; gap:var(--sp-8); }
/* header action links are secondary to the title — one rhythm point down (15 → 12) */
.panel__action .link{ font-size:var(--text-12); font-weight:500; }
.panel__body{ padding:var(--sp-16); color:var(--muted); font-size:var(--text-15); line-height:1.55; }
.panel__footer{
  display:flex;
  align-items:center;
  justify-content:flex-end;
  gap:var(--sp-8);
  padding:var(--sp-12) var(--sp-16);
  border-top:1px solid var(--line);
}
/* generalized states — hidden by default, revealed by the state modifier */
.panel__empty, .panel__skeleton, .panel__error{ display:none; }
.panel.is-empty .panel__body{ display:none; }
.panel.is-empty .panel__empty{ display:flex; }
/* an empty state a script shows on its own (a filter or search that leaves nothing), by removing [hidden] */
.panel__empty[data-empty-standalone]:not([hidden]){ display:flex; }
.panel.is-loading .panel__body{ display:none; }
.panel.is-loading .panel__skeleton{ display:flex; }
.panel.has-error .panel__body{ display:none; }
.panel.has-error .panel__error{ display:flex; }
.panel__empty{
  flex-direction:column;
  align-items:center;
  text-align:center;
  gap:var(--sp-8);
  padding:var(--sp-32) var(--sp-16);
}
.panel__empty-heading{ font-family:var(--font-sans); font-size:var(--text-15); font-weight:600; color:var(--ink); }
.panel__empty-sub{ font-family:var(--font-sans); font-size:var(--text-12); color:var(--faint); max-width:44ch; }
.panel__skeleton{ flex-direction:column; gap:var(--sp-12); padding:var(--sp-16); }
.panel__skeleton::before, .panel__skeleton::after{
  content:"";
  height:var(--sp-12);
  border-radius:var(--radius-sm);
  background:linear-gradient(90deg, var(--surface-2), var(--line), var(--surface-2));
  background-size:200% 100%;
  animation:panel-shimmer 1.2s linear infinite;
}
.panel__skeleton::after{ width:60%; }
@keyframes panel-shimmer{ to{ background-position:-200% 0; } }
.panel__error{
  flex-direction:column;
  align-items:center;
  text-align:center;
  gap:var(--sp-12);
  padding:var(--sp-32) var(--sp-16);
  color:var(--danger-ink);
}

/* ===== section-heading ===== */
.section-heading{
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:var(--sp-12);
  padding-bottom:var(--sp-8);
  border-bottom:1px solid var(--line);
}
.section-heading__title{
  font-family:var(--font-mono);
  font-size:var(--text-12);
  font-weight:600;
  letter-spacing:0.08em;
  text-transform:uppercase;
  color:var(--muted);
  margin:0;
}
.section-heading__action{ display:inline-flex; align-items:center; gap:var(--sp-8); }
/* a heading right above a bordered block (a list group, a panel, a table) drops its rule — one line, not two;
   above a form field it drops it too, so the field's label never sits on the line */
.section-heading:has(+ .list-group, + .panel, + .tbl, + .field, + .form-2){ border-bottom:0; padding-bottom:var(--sp-12); }
/* a heading that starts a new group of fields stands further off the field before it than fields do from each other */
.field + .section-heading, .form-2 + .section-heading{ margin-top:var(--sp-32); }

/* a callout right above a list stands off it (only while it shows) */
.callout:not([hidden]) + .list-group{ margin-top:var(--sp-16); }

/* ===== name-row — an icon picker beside the name it belongs to (settings, create forms) ===== */
.name-row{ display:grid; grid-template-columns:auto 1fr; gap:var(--sp-16); }
.name-row--3{ grid-template-columns:auto 1fr 1fr; }
@media (max-width:760px){ .name-row, .name-row--3{ grid-template-columns:1fr; } }

/* ===== form-2 — two short, related fields side by side (RULES: Forms) ===== */
.form-2{ display:grid; grid-template-columns:1fr 1fr; gap:var(--sp-16); }
@media (max-width:760px){ .form-2{ grid-template-columns:1fr; } }

/* ===== detail-list ===== */
.detail-list{ margin:0; display:flex; flex-direction:column; gap:var(--sp-12); }
.detail-row{ display:flex; flex-direction:column; gap:var(--sp-4); }
.detail-label{ font-family:var(--font-sans); font-size:var(--text-12); font-weight:500; color:var(--faint); }
.detail-value{
  margin:0; /* dd carries a 40px UA indent — the value sits flush under its label */
  display:flex;
  align-items:center;
  gap:var(--sp-8);
  font-family:var(--font-sans);
  font-size:var(--text-15);
  color:var(--ink);
}
.detail-value a{ color:var(--accent-ink); text-decoration:none; }
.detail-value a:hover{ text-decoration:underline; }
.detail-list--horizontal .detail-row{
  flex-direction:row;
  align-items:baseline;
  justify-content:space-between;
  gap:var(--sp-16);
}
.detail-list--horizontal .detail-label{ flex:none; }
.detail-list--horizontal .detail-value{ text-align:right; justify-content:flex-end; }

/* ===== list-row ===== */
.list-row{
  display:flex;
  align-items:flex-start; /* top-align: lead + trail sit on the title line, never centered */
  gap:var(--sp-12);
  padding:var(--sp-12);
  border-radius:var(--radius-md);
}
/* lead + trail get a one-line min-height and center their content, so an icon /
   badge lines up with the CENTER of the title (the first line), not its top. */
.list-row__lead{ flex:none; display:inline-flex; align-items:center; justify-content:center; min-height:var(--sp-24); color:var(--muted); }
/* a row that can't be chosen or changed right now (the current folder, a question asked once) */
.list-row[aria-disabled="true"]{ opacity:.5; }
.list-row__main{ flex:1 1 auto; min-width:0; display:flex; flex-direction:column; gap:var(--sp-4); }
.list-row__title{
  font-family:var(--font-sans);
  font-size:var(--text-15);
  font-weight:600;
  line-height:var(--sp-24);
  color:var(--ink);
  overflow:hidden;
  text-overflow:ellipsis;
  white-space:nowrap;
}
.list-row__sub{ font-family:var(--font-sans); font-size:var(--text-12); color:var(--faint); }
.list-row__trail{ flex:none; display:inline-flex; align-items:center; gap:var(--sp-8); min-height:var(--sp-24); margin-left:auto; }
.list-row--link{ color:inherit; cursor:pointer; transition:background var(--dur-fast) var(--ease); text-decoration:none; }
.list-row--link:hover{ background:var(--surface-2); }
/* A run of rows that stand as one thing — a nav guide, a settings menu. The
   border gives a lone row a shape at rest instead of floating in the panel;
   hairlines separate siblings and the hover fill stays inside the corners. */
.list-group{ border:1px solid var(--line); border-radius:var(--radius-md); overflow:hidden; background:var(--surface); }
.list-group > .list-row + .list-row{ border-top:1px solid var(--line); }
/* the same run, but as solid blocks with a gap instead of a bordered box with
   dividers — matches .accordion, so rows and questions can share a page */
.list-group--soft{ border:0; border-radius:0; overflow:visible; background:transparent; display:flex; flex-direction:column; gap:var(--sp-8); }
.list-group--soft > .list-row{ background:var(--ground); border-radius:var(--radius-md); }
.list-group--soft > .list-row + .list-row{ border-top:0; }
.list-group--soft > .list-row--link:hover{ background:color-mix(in srgb, var(--ink) 4%, var(--ground)); }

/* ===== tbl =====
   One shared grid: head + body + rows are display:contents so every cell is a
   grid item of .tbl and all columns line up (header always matches its cells).
   Spacing is cell padding (not grid gap) so row backgrounds stay continuous. */
.tbl{
  display:grid;
  grid-template-columns:var(--cols);
  font-family:var(--font-sans);
  font-size:var(--text-15);
}
.tbl__head, .tbl__body, .tbl__row{ display:contents; }
.tbl__col{
  display:flex;
  align-items:center;
  gap:var(--sp-8);
  min-width:0;
  padding:var(--sp-12);
  color:var(--ink);
  border-bottom:1px solid var(--line);
  white-space:nowrap;
  overflow:hidden;
}
.tbl__head .tbl__col{
  padding:var(--sp-8) var(--sp-12);
  font-size:var(--text-12);
  font-weight:600;
  color:var(--faint);
  border-bottom:1px solid var(--line-2);
}
.tbl__body .tbl__row:last-child .tbl__col{ border-bottom:0; }
/* alignment — left by default; right only for numbers/dates/actions */
.tbl__col--right{ justify-content:flex-end; text-align:right; }
.tbl__col--center{ justify-content:center; text-align:center; }
.tbl__col--sm{ font-size:var(--text-12); color:var(--muted); }
.tbl__col--primary{ font-weight:600; }
.tbl__col--amount{ justify-content:flex-end; font-family:var(--font-mono); }
.tbl__col--actions{ justify-content:flex-end; gap:var(--sp-4); }
/* row state — applied to the cells so the fill spans the whole row */
.tbl__row:hover .tbl__col{ background:var(--surface-2); }
.tbl__row.is-selected .tbl__col{ background:var(--accent-soft); }
.tbl__row.is-overdue .tbl__col--primary, .tbl__row.is-overdue .tbl__col--amount{ color:var(--danger-ink); }
/* sortable header */
.tbl__col[data-sort]{ cursor:pointer; user-select:none; }
.tbl__col[data-sort].tbl__col--right .sort-indicator{ order:-1; }
.tbl__col[data-sort]:hover{ color:var(--ink); }
.sort-indicator{ width:8px; height:8px; flex:none; opacity:0; border-right:2px solid currentColor; border-bottom:2px solid currentColor; }
.tbl__col.sort-asc .sort-indicator{ opacity:1; transform:rotate(-135deg); }
.tbl__col.sort-desc .sort-indicator{ opacity:1; transform:rotate(45deg); }

/* ===== dropdown ===== */
.dropdown{
  display:none;
  min-width:200px;
  padding:var(--sp-4);
  background:var(--surface);
  border:1px solid var(--line-2);
  border-radius:var(--radius-md);
  box-shadow:var(--shadow);
}
.dropdown.is-open{ display:block; }
.dropdown__item{
  display:flex;
  align-items:center;
  gap:var(--sp-8);
  width:100%;
  padding:var(--sp-8) var(--sp-12);
  border:0;
  border-radius:var(--radius-sm);
  background:transparent;
  font-family:var(--font-sans);
  font-size:var(--text-15);
  color:var(--ink);
  text-align:left;
  text-decoration:none;
  cursor:pointer;
}
.dropdown__item:hover{ background:var(--surface-2); }
.dropdown__item.is-active{ background:var(--accent-soft); color:var(--accent-ink); font-weight:600; }
.dropdown__count{
  margin-left:auto;
  font-family:var(--font-mono);
  font-size:var(--text-12);
  color:var(--faint);
}
/* --grid: a palette of icon-only items (an icon picker); the trigger is a .btn carrying the current icon */
.dropdown--grid{ min-width:0; grid-template-columns:repeat(4, auto); gap:var(--sp-4); }
.dropdown--grid.is-open{ display:grid; }
.dropdown--grid .dropdown__item{ justify-content:center; padding:var(--sp-8); }

/* ===== breadcrumb ===== */
.breadcrumb{ display:flex; align-items:center; flex-wrap:wrap; gap:var(--sp-8); font-family:var(--font-sans); font-size:var(--text-12); }
.breadcrumb__item{ color:var(--muted); text-decoration:none; }
.breadcrumb__item:hover{ color:var(--ink); text-decoration:underline; }
.breadcrumb__item.is-current{ color:var(--ink); font-weight:600; pointer-events:none; }
.breadcrumb__sep{ color:var(--faint); user-select:none; }

/* ===== pagination ===== */
.pagination{ display:flex; align-items:center; justify-content:space-between; gap:var(--sp-16); flex-wrap:wrap; }
.pagination__info{ font-family:var(--font-sans); font-size:var(--text-12); color:var(--faint); }
.pagination__controls{ display:inline-flex; align-items:center; gap:var(--sp-4); }
.pagination__btn{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  min-width:32px;
  height:32px;
  padding:0 var(--sp-8);
  border:1px solid var(--line-2);
  border-radius:var(--radius-md);
  background:var(--surface);
  font-family:var(--font-sans);
  font-size:var(--text-15);
  color:var(--ink);
  cursor:pointer;
  transition:background var(--dur-fast) var(--ease);
}
.pagination__btn:hover{ background:var(--surface-2); }
.pagination__btn.is-active{ background:var(--accent); border-color:var(--accent); color:var(--on-accent); font-weight:600; }
.pagination__btn[disabled]{ opacity:.45; cursor:not-allowed; }

/* ===== search ===== */
.search{ position:relative; display:block; }
.search__icon{
  position:absolute;
  top:50%;
  left:var(--sp-12);
  width:16px;
  height:16px;
  transform:translateY(-50%);
  /* center the glyph in the box: the icon's inline-block vertical-align would
     otherwise ride ~3px low inside this fixed square */
  display:flex;
  align-items:center;
  justify-content:center;
  color:var(--faint);
  pointer-events:none;
}
.search__icon .icon{ vertical-align:0; }
.search__icon svg:not(.icon){ width:100%; height:100%; fill:none; stroke:currentColor; stroke-width:1.6; }
.search__input{
  width:100%;
  height:38px;
  padding:0 var(--sp-12) 0 var(--sp-32);
  font-family:var(--font-sans);
  font-size:var(--text-15);
  color:var(--ink);
  background:var(--surface);
  border:1px solid var(--line-2);
  border-radius:var(--radius-md);
  transition:border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}
.search__input::placeholder{ color:var(--faint); }
.search__input:hover{ border-color:var(--faint); }
.search__input:focus{ outline:none; border-color:var(--accent); box-shadow:0 0 0 3px var(--accent-soft); }

/* ===== tabs ===== */
.tabs{ display:flex; align-items:center; gap:var(--sp-4); border-bottom:1px solid var(--line); }
.tab{
  position:relative;
  display:inline-flex;
  align-items:center;
  gap:var(--sp-8);
  padding:var(--sp-8) var(--sp-12);
  border:0;
  background:transparent;
  font-family:var(--font-sans);
  font-size:var(--text-15);
  font-weight:500;
  color:var(--muted);
  text-decoration:none; /* tabs may be <a>; never show the link underline */
  cursor:pointer;
  transition:color var(--dur-fast) var(--ease);
}
.tab:hover{ color:var(--ink); }
.tab.is-active{ color:var(--accent-ink); font-weight:600; }
.tab.is-active::after{
  content:"";
  position:absolute;
  left:var(--sp-12);
  right:var(--sp-12);
  bottom:-1px;
  height:2px;
  background:var(--accent);
  border-radius:var(--radius-pill);
}
/* the row sits on the content edge: the first tab's label (and its underline) starts flush left, the last ends flush right */
.tabs > .tab:first-child{ padding-left:0; }
.tabs > .tab:first-child.is-active::after{ left:0; }
.tabs > .tab:last-child{ padding-right:0; }
.tabs > .tab:last-child.is-active::after{ right:0; }

/* ===== segmented ===== */
.segmented{
  display:inline-flex;
  align-items:stretch;      /* buttons fill the track height */
  height:38px;              /* match the standard control height (.btn, .search__input) */
  padding:var(--sp-4);
  gap:var(--sp-4);
  background:var(--surface-2);
  border:1px solid var(--line);
  border-radius:var(--radius-md);
}
/* in a form field a segmented choice sizes to its options instead of stretching across the form */
.field > .segmented{ align-self:flex-start; }
.segmented__btn{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  padding:var(--sp-4) var(--sp-12);
  border:0;
  border-radius:var(--radius-sm);
  background:transparent;
  font-family:var(--font-sans);
  font-size:var(--text-12);
  font-weight:500;
  color:var(--muted);
  cursor:pointer;
  text-decoration:none; /* a segment may be an <a> when the view is its own page */
  white-space:nowrap;
  transition:background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.segmented__btn:hover{ color:var(--ink); }
/* keep weight constant across states — bumping to 600 on active re-widths the
   button and shifts the whole control on click. Active reads via surface+shadow+ink. */
.segmented__btn.is-active{ background:var(--surface); color:var(--ink); box-shadow:var(--shadow); }
.segmented__btn[aria-disabled]{ opacity:0.4; cursor:default; }
.segmented__btn[aria-disabled]:hover{ color:var(--muted); }
/* ===== modal ===== */
.modal-overlay{
  /* the real posture — a dialog covers the app. Ten pages used to repeat this
     override because the component shipped as the gallery shim instead. */
  position:fixed;
  inset:0;
  z-index:var(--z-modal);
  display:none;
  place-items:center;
  padding:var(--sp-24);
  overflow-y:auto;              /* a tall dialog scrolls rather than clipping */
  background:color-mix(in srgb, var(--ink) 45%, transparent);
}
/* the gallery stage: a contained gutter so the dialog can be shown in a row */
.modal-overlay--inline{
  position:relative;
  inset:auto;
  z-index:auto;
  min-height:300px;
  border-radius:var(--radius-lg);
}
.modal-overlay.is-open{ display:grid; }
.modal{
  width:100%;
  max-width:460px;
  display:flex;
  flex-direction:column;
  background:var(--surface);
  border:1px solid var(--line);
  border-radius:var(--radius-lg);
  box-shadow:var(--shadow);
  overflow:hidden;
}
.modal__header{
  position:relative;
  padding:var(--sp-24) var(--sp-24) var(--sp-16);
  border-bottom:1px solid var(--line);
}
.modal__title{
  margin:0;
  font-family:var(--font-sans);
  font-size:var(--text-18);
  font-weight:600;
  color:var(--ink);
}
.modal__subtitle{
  margin:var(--sp-4) 0 0;
  font-size:var(--text-12);
  color:var(--muted);
}
.modal__body{
  padding:var(--sp-24);
  display:flex;
  flex-direction:column;
  gap:var(--sp-16);
  font-size:var(--text-15);
  line-height:1.55;
  color:var(--muted);
}
.modal__footer{
  display:flex;
  justify-content:flex-end;
  gap:var(--sp-8);
  padding:var(--sp-16) var(--sp-24);
  border-top:1px solid var(--line);
  background:var(--surface-2);
}
/* close control shared by modal + sheet */
.modal__close,
.sheet__close{
  position:absolute;
  top:var(--sp-16);
  right:var(--sp-16);
  display:inline-flex;
  align-items:center;
  justify-content:center;
  width:30px;
  height:30px;
  padding:0;
  border:1px solid transparent;
  border-radius:var(--radius-md);
  background:transparent;
  color:var(--muted);
  font-size:var(--text-18);
  line-height:1;
  cursor:pointer;
  transition:background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.modal__close:hover,
.sheet__close:hover{ background:var(--surface-2); color:var(--ink); }
/* a document to read inside a modal — an agreement, a brief — before acting on it */
.modal__doc{ max-height:280px; overflow-y:auto; padding:var(--sp-16); border:1px solid var(--line); border-radius:var(--radius-md); background:var(--surface-2); }
.modal__doc h4{ margin:0 0 var(--sp-4); font-family:var(--font-sans); font-size:var(--text-12); font-weight:600; letter-spacing:.04em; text-transform:uppercase; color:var(--muted); }
.modal__doc h4 + p{ margin-top:0; }
.modal__doc p{ margin:0 0 var(--sp-12); font-size:var(--text-15); line-height:1.55; color:var(--ink); }
.modal__doc p:last-child{ margin-bottom:0; }
.modal__meta{ display:flex; flex-wrap:wrap; gap:var(--sp-8) var(--sp-16); margin:0 0 var(--sp-12); font-size:var(--text-12); color:var(--muted); }
.modal--confirm{ max-width:400px; }
.modal--wide{ max-width:680px; }
.modal--xl{ max-width:960px; } /* a comparison: four plans side by side */
.modal--confirm .modal__body{ color:var(--ink); }

/* ===== popover ===== */
/* A .card anchored beside the thing it edits — quick edit in place. Its header, body
   and footer are .card parts; .popover adds only the anchoring. The caller positions
   it (--x/--y inline, per-instance data like .tbl's --cols) inside a position:relative
   parent. Navigation (All Settings) sits in the header's .card__actions beside Close;
   the footer holds Cancel / Save. It opens beside its target, never over it, and the
   header is a drag handle. */
.popover{
  position:absolute;
  left:var(--x, 0);
  top:var(--y, 0);
  z-index:var(--z-dropdown);
  width:300px;
  display:none;
}
.popover.is-open{ display:flex; }
/* the header is the handle: a callout can be dragged anywhere in its parent */
.popover > .card__header{ cursor:grab; user-select:none; }
.popover.is-dragging > .card__header{ cursor:grabbing; }
/* the gallery stage: in flow, always shown */
.popover--inline{ position:static; display:flex; }

/* ===== color ===== */
/* A color picker field on the .search pattern: one .input-height box, the native picker
   sits inside it as the swatch, the hex is the text. Any color. */
.color{ position:relative; display:block; }
.color__swatch{
  position:absolute;
  top:50%;
  left:var(--sp-8);
  width:var(--sp-24);
  height:var(--sp-24);
  padding:0;
  transform:translateY(-50%);
  border:1px solid var(--line-2);
  border-radius:var(--radius-sm);
  background:transparent;
  cursor:pointer;
}
.color__swatch::-webkit-color-swatch-wrapper{ padding:0; }
.color__swatch::-webkit-color-swatch{ border:0; border-radius:var(--radius-sm); }
.color__hex{
  width:100%;
  height:38px;
  padding:0 var(--sp-12) 0 var(--sp-48);
  font-family:var(--font-mono);
  font-size:var(--text-15);
  text-transform:uppercase;
  color:var(--ink);
  background:var(--surface);
  border:1px solid var(--line-2);
  border-radius:var(--radius-md);
  transition:border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}
.color__hex::placeholder{ color:var(--faint); }
.color__hex:hover{ border-color:var(--faint); }
.color__hex:focus{ outline:none; border-color:var(--accent); box-shadow:0 0 0 3px var(--accent-soft); }

/* ===== unit ===== */
/* A unit affix inside a number field: "px", "%", "in" ghosted at the right, so the
   number is never left to interpretation. Wraps an .input. */
.unit{ position:relative; display:block; }
.unit .input{ padding-right:var(--sp-48); }
/* the browser's spinner would sit where the unit is and crowd the value out; typing is the control */
.unit .input[type="number"]{ -moz-appearance:textfield; appearance:textfield; }
.unit .input[type="number"]::-webkit-inner-spin-button,
.unit .input[type="number"]::-webkit-outer-spin-button{ -webkit-appearance:none; margin:0; }
.unit__label{
  position:absolute;
  top:50%;
  right:var(--sp-12);
  transform:translateY(-50%);
  font-family:var(--font-mono);
  font-size:var(--text-12);
  color:var(--faint);
  pointer-events:none;
}

/* ===== pricing ===== */
/* Plans side by side: each plan is one block — name, price, what it includes, a short list of
   what differs, and a button at the bottom that picks it. */
.pricing{ display:grid; grid-template-columns:repeat(auto-fit, minmax(180px, 1fr)); gap:var(--sp-12); }
.pricing__plan{
  display:flex;
  flex-direction:column;
  gap:var(--sp-12);
  padding:var(--sp-16);
  border:1px solid var(--line-2);
  border-radius:var(--radius-lg);
  background:var(--surface);
  cursor:pointer;
  transition:border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}
.pricing__plan:hover{ border-color:var(--faint); }
.pricing__plan.is-selected{ border-color:var(--accent); box-shadow:0 0 0 3px var(--accent-soft); }
.pricing__head{ display:flex; align-items:center; justify-content:space-between; gap:var(--sp-8); }
.pricing__name{ font-family:var(--font-sans); font-size:var(--text-15); font-weight:600; color:var(--ink); }
.pricing__price{ display:flex; align-items:baseline; gap:var(--sp-4); }
.pricing__amt{ font-family:var(--font-sans); font-size:var(--text-24); font-weight:700; letter-spacing:-0.01em; color:var(--ink); }
.pricing__per{ font-size:var(--text-12); color:var(--muted); }
.pricing__meta{ font-size:var(--text-12); color:var(--muted); line-height:1.5; }
.pricing__list{ margin:0; padding:0; list-style:none; display:flex; flex-direction:column; gap:var(--sp-8); flex:1 1 auto; }
.pricing__item{ display:flex; align-items:flex-start; gap:var(--sp-8); font-size:var(--text-12); line-height:1.5; color:var(--ink); }
.pricing__item .icon{ flex:none; width:16px; height:16px; margin-top:1px; color:var(--accent); }
.pricing__item--off{ color:var(--muted); }
.pricing__item--off .icon{ color:var(--faint); }
.pricing__choose{ padding-top:var(--sp-12); border-top:1px solid var(--line); }
.pricing__choose .btn{ width:100%; justify-content:center; }
/* --wide: a plan that spans the row (Custom) — its terms on the left, the fields that set it on the right */
.pricing__plan--wide{
  grid-column:1 / -1;
  display:grid;
  grid-template-columns:1fr 1fr;
  gap:var(--sp-12) var(--sp-24);
}
.pricing__detail{ display:flex; flex-direction:column; gap:var(--sp-12); }
.pricing__fields{ display:flex; flex-direction:column; gap:var(--sp-16); }
.pricing__plan--wide .pricing__choose{ grid-column:1 / -1; display:flex; justify-content:flex-end; }
.pricing__plan--wide .pricing__choose .btn{ width:auto; }
@media (max-width:760px){ .pricing__plan--wide{ grid-template-columns:1fr; } }

/* ===== sheet ===== */
.sheet__scrim{
  /* the real posture — a sheet slides over the app. Six pages used to repeat
     this override because the component shipped as the gallery shim. */
  position:fixed;
  inset:0;
  z-index:var(--z-modal);
  display:none;
  background:color-mix(in srgb, var(--ink) 45%, transparent);
}
.sheet__scrim.is-open{ display:block; }
/* the gallery stage: contained, always shown, so a sheet can sit in a spec row */
.sheet__scrim--inline{
  position:relative;
  inset:auto;
  z-index:auto;
  display:block;
  min-height:360px;
  overflow:hidden;
  border-radius:var(--radius-lg);
}
.sheet{
  position:absolute;
  top:0;
  right:0;
  bottom:0;
  width:min(400px, 82%);
  display:flex;
  flex-direction:column;
  background:var(--surface);
  border-left:1px solid var(--line);
  box-shadow:var(--shadow);
}
/* --bottom: the sheet rises from the bottom edge instead — for panels under a
   full-screen canvas. Same header, body and footer. */
/* --wide: room for a grid of thumbnails (a picker) */
.sheet--wide{ width:min(680px, 92%); }
.sheet--bottom{
  top:auto;
  left:0;
  right:0;
  width:auto;
  height:min(60vh, 520px);
  border-left:0;
  border-top:1px solid var(--line);
  border-radius:var(--radius-lg) var(--radius-lg) 0 0;
}
.sheet__scrim--inline .sheet--bottom{ height:80%; } /* fits the gallery stage */
.sheet__header{
  position:relative;
  padding:var(--sp-24) var(--sp-24) var(--sp-16);
  border-bottom:1px solid var(--line);
}
.sheet__title{
  margin:0;
  font-family:var(--font-sans);
  font-size:var(--text-18);
  font-weight:600;
  color:var(--ink);
}
.sheet__body{
  flex:1;
  overflow-y:auto;
  padding:var(--sp-24);
  display:flex;
  flex-direction:column;
  gap:var(--sp-16);
  font-size:var(--text-15);
  line-height:1.55;
  color:var(--muted);
}
.sheet__footer{
  display:flex;
  justify-content:flex-end;
  gap:var(--sp-8);
  padding:var(--sp-16) var(--sp-24);
  border-top:1px solid var(--line);
  background:var(--surface-2);
}

/* ===== chat ===== */
/* A two-sided conversation in a box: the other party's messages on the left, yours on the
   right, each with its avatar and name. The log scrolls; the composer is the box's footer.
   .thread is for comments on a record; this is for talking to someone (or something). */
.chat{ display:flex; flex-direction:column; border:1px solid var(--line); border-radius:var(--radius-lg); background:var(--surface); overflow:hidden; }
.chat__log{ display:flex; flex-direction:column; gap:var(--sp-16); padding:var(--sp-16); max-height:420px; overflow-y:auto; }
.chat__msg{ display:flex; align-items:flex-start; gap:var(--sp-12); max-width:72%; }
.chat__msg > .avatar{ flex:none; } /* the bubble must never squeeze the avatar out of round */
.chat__msg--mine{ align-self:flex-end; flex-direction:row-reverse; }
.chat__body{ display:flex; flex-direction:column; gap:var(--sp-4); min-width:0; }
.chat__msg--mine .chat__body{ align-items:flex-end; }
.chat__author{ font-family:var(--font-sans); font-size:var(--text-12); font-weight:600; color:var(--muted); }
.chat__bubble{
  margin:0;
  padding:var(--sp-8) var(--sp-12);
  border-radius:var(--radius-lg);
  background:var(--surface-2);
  color:var(--ink);
  font-size:var(--text-15);
  line-height:1.5;
}
.chat__msg--mine .chat__bubble{ background:var(--accent-soft); color:var(--accent-ink); }
.chat__composer{ padding:var(--sp-12) var(--sp-16); border-top:1px solid var(--line); background:var(--surface-2); }
/* one integrated box: a single line that grows as you type, the send control inside it at the right */
.chat__box{ display:flex; align-items:flex-end; gap:var(--sp-8); padding:var(--sp-4) var(--sp-4) var(--sp-4) var(--sp-12); border:1px solid var(--line-2); border-radius:var(--radius-md); background:var(--surface); transition:border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease); }
.chat__box:focus-within{ border-color:var(--accent); box-shadow:0 0 0 3px var(--accent-soft); }
.chat__input{ flex:1 1 auto; min-height:30px; max-height:160px; padding:var(--sp-4) 0; border:0; background:transparent; resize:none; font-family:var(--font-sans); font-size:var(--text-15); line-height:1.4; color:var(--ink); }
.chat__input:focus{ outline:none; }
.chat__input::placeholder{ color:var(--faint); }
.chat__hints{ display:flex; flex-wrap:wrap; gap:var(--sp-8); padding:var(--sp-12) var(--sp-16) 0; }

/* ===== toast ===== */
.toast{
  --toast-soft:var(--neutral-soft);
  --toast-ink:var(--neutral-ink);
  display:flex;
  align-items:flex-start;
  gap:var(--sp-12);
  width:100%;
  max-width:380px;
  padding:var(--sp-12) var(--sp-16);
  background:var(--surface);
  border:1px solid var(--line);
  border-radius:var(--radius-md);
  box-shadow:var(--shadow);
}
.toast__icon{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  flex:none;
  width:22px;
  height:22px;
  border-radius:var(--radius-pill);
  background:var(--toast-soft);
  color:var(--toast-ink);
  font-size:var(--text-12);
  font-weight:700;
}
.toast__body{
  flex:1;
  font-size:var(--text-15);
  line-height:1.45;
  color:var(--ink);
}
.toast__dismiss{
  flex:none;
  padding:0;
  border:none;
  background:transparent;
  color:var(--faint);
  font-size:var(--text-15);
  line-height:1;
  cursor:pointer;
}
.toast__dismiss:hover{ color:var(--ink); }
/* where toasts land — bottom-right, newest last; ui/actions.js creates it */
.toasts{ position:fixed; right:var(--sp-24); bottom:var(--sp-24); z-index:var(--z-toast); display:flex; flex-direction:column; gap:var(--sp-8); width:min(380px, calc(100vw - var(--sp-48))); }
.toast--success{ --toast-soft:var(--success-soft); --toast-ink:var(--success-ink); }
.toast--error{ --toast-soft:var(--danger-soft); --toast-ink:var(--danger-ink); }
.toast--info{ --toast-soft:var(--info-soft); --toast-ink:var(--info-ink); }

/* ===== alert ===== */
.alert{
  --alert-accent:var(--info);
  --alert-soft:var(--info-soft);
  --alert-ink:var(--info-ink);
  display:flex;
  align-items:flex-start;
  gap:var(--sp-8);
  padding:var(--sp-12) var(--sp-16);
  background:var(--alert-soft);
  border:1px solid var(--alert-accent);
  border-radius:var(--radius-md);
  color:var(--alert-ink);
}
/* icon + dismiss sit on the message's first line */
.alert__icon{
  flex:none;
  display:flex;
  align-items:center;
  height:calc(var(--text-15) * 1.5);
  color:var(--alert-accent);
}
.alert__message{
  flex:1;
  margin:0;
  font-size:var(--text-15);
  line-height:1.5;
}
.alert__message strong{ font-weight:600; }
.alert__dismiss{
  flex:none;
  display:flex;
  align-items:center;
  height:calc(var(--text-15) * 1.5);
  padding:0;
  border:none;
  background:transparent;
  color:inherit;
  cursor:pointer;
  opacity:.6;
}
.alert__dismiss:hover{ opacity:1; }
.alert--warning{ --alert-accent:var(--warning); --alert-soft:var(--warning-soft); --alert-ink:var(--warning-ink); }
.alert--danger{ --alert-accent:var(--danger); --alert-soft:var(--danger-soft); --alert-ink:var(--danger-ink); }
.alert--info{ --alert-accent:var(--info); --alert-soft:var(--info-soft); --alert-ink:var(--info-ink); }

/* ===== callout ===== */
.callout{
  --callout-accent:var(--info);
  --callout-soft:var(--info-soft);
  --callout-ink:var(--info-ink);
  padding:var(--sp-12) var(--sp-16);
  background:var(--callout-soft);
  border:1px solid var(--callout-accent);
  border-radius:var(--radius-md);
  font-size:var(--text-15);
  line-height:1.55;
  color:var(--callout-ink);
}
.callout strong{ font-weight:600; }
/* a link inside a callout takes the callout's own ink and an underline, so it reads on any tone */
.callout a, .callout .link{
  color:var(--callout-ink);
  font-weight:600;
  text-decoration:underline;
  text-underline-offset:2px;
}
.callout a:hover, .callout .link:hover{ text-decoration-thickness:2px; }
.callout--info{ --callout-accent:var(--info); --callout-soft:var(--info-soft); --callout-ink:var(--info-ink); }
.callout--warning{ --callout-accent:var(--warning); --callout-soft:var(--warning-soft); --callout-ink:var(--warning-ink); }

/* ===== stat ===== */
.stat{
  display:flex;
  flex-direction:column;
  gap:var(--sp-4);
  padding:var(--sp-16);
  background:var(--surface);
  border:1px solid var(--line);
  border-radius:var(--radius-lg);
  box-shadow:var(--shadow);
  min-width:160px;
}
.stat__value{
  font-family:var(--font-sans);
  font-size:var(--text-24);
  font-weight:700;
  letter-spacing:-0.01em;
  line-height:1.1;
  color:var(--ink);
}
.stat__label{
  font-size:var(--text-12);
  color:var(--muted);
}
.stat__delta{
  display:inline-flex;
  align-items:center;
  gap:var(--sp-4);
  align-self:flex-start;
  margin-top:var(--sp-4);
  padding:2px var(--sp-8);
  border-radius:var(--radius-pill);
  border:1px solid var(--line-2);
  font-size:var(--text-12);
  font-weight:600;
  background:var(--neutral-soft);
  color:var(--neutral-ink);
}
.stat__delta--up{ border-color:transparent; background:var(--success-soft); color:var(--success-ink); }
.stat__delta--down{ border-color:transparent; background:var(--danger-soft); color:var(--danger-ink); }
.stat__delta--neutral{ border-color:var(--line-2); background:var(--neutral-soft); color:var(--neutral-ink); }
.stat--lg{ padding:var(--sp-24); }
.stat--lg .stat__value{ font-size:var(--text-30); }

/* ===== stepper ===== */
.stepper{
  display:flex;
  align-items:flex-start;
  width:100%;
}
.stepper__step{
  position:relative;
  flex:1;
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:var(--sp-8);
  padding-top:var(--sp-32);
  text-align:center;
  font-size:var(--text-12);
  color:var(--muted);
}
/* the node */
.stepper__step::before{
  content:"";
  position:absolute;
  top:0;
  width:26px;
  height:26px;
  border-radius:var(--radius-pill);
  border:2px solid var(--line-2);
  background:var(--surface);
  z-index:1;
}
/* the connector line to the next node */
.stepper__step:not(:last-child)::after{
  content:"";
  position:absolute;
  top:12px;
  left:50%;
  width:100%;
  height:2px;
  background:var(--line-2);
}
.stepper__step.is-done{ color:var(--ink); }
.stepper__step.is-done::before{
  background:var(--accent);
  border-color:var(--accent);
}
.stepper__step.is-done:not(:last-child)::after{ background:var(--accent); }
.stepper__step.is-current{ color:var(--ink); font-weight:600; }
.stepper__step.is-current::before{
  border-color:var(--accent);
  box-shadow:0 0 0 3px var(--accent-soft);
}
/* explaining a flow rather than tracking one: every node shows its number, and
   the numbers match a list of the same steps beneath it */
.stepper--numbered{ counter-reset:step; }
.stepper--numbered .stepper__step{ counter-increment:step; color:var(--ink); }
.stepper--numbered .stepper__step::before{
  content:counter(step);
  display:flex; align-items:center; justify-content:center;
  font-size:var(--text-12); font-weight:600; line-height:1;
  color:var(--accent-ink); border-color:var(--accent); background:var(--accent-soft);
}
.stepper--numbered .stepper__step:not(:last-child)::after{ background:var(--accent-soft); }

/* ===== file-row ===== */
.file-row{
  display:flex;
  align-items:center;
  gap:var(--sp-12);
  padding:var(--sp-12) var(--sp-16);
  background:var(--surface);
  border:1px solid var(--line);
  border-radius:var(--radius-md);
}
.file-row__icon{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  flex:none;
  width:36px;
  height:36px;
  border-radius:var(--radius-sm);
  background:var(--surface-2);
  color:var(--muted);
}
.file-row__icon svg{
  width:18px;
  height:18px;
  fill:none;
  stroke:currentColor;
  stroke-width:1.6;
}
.file-row__name{
  display:block;
  font-size:var(--text-15);
  font-weight:500;
  color:var(--ink);
}
.file-row__sub{
  display:block;
  margin-top:2px;
  font-size:var(--text-12);
  color:var(--faint);
}
.file-row > .chip{ margin-left:auto; }
/* a file row that downloads is one click target — the whole row, not a button
   in it. The trailing glyph is the hint, pushed to the edge. */
/* a row can also be a link (an SOP step's web reference): it reads like a download row */
a.file-row{ color:inherit; text-decoration:none; }
.file-row[data-behavior="download"], a.file-row{ cursor:pointer; transition:background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease); }
.file-row[data-behavior="download"]:hover, a.file-row:hover{ background:var(--surface-2); border-color:var(--line-2); }
.file-row[data-behavior="download"]:focus-visible{ outline:2px solid var(--accent); outline-offset:2px; }
.file-row__trail{ display:inline-flex; align-items:center; margin-left:auto; color:var(--faint); flex:none; }
.file-row > .chip ~ .file-row__trail{ margin-left:0; }
.file-row[data-behavior="download"]:hover .file-row__trail{ color:var(--ink); }
.file-row--compact{ padding:var(--sp-8) var(--sp-12); }
.file-row--compact .file-row__icon{ width:28px; height:28px; }
.file-row--compact .file-row__icon svg{ width:15px; height:15px; }

/* ===== thread ===== */
.thread{
  display:flex;
  flex-direction:column;
  gap:var(--sp-24);
}
.comment{
  display:flex;
  align-items:flex-start;
  gap:var(--sp-12);
}
.comment__avatar{ flex:none; }
.comment__author{
  font-size:var(--text-15);
  font-weight:600;
  color:var(--ink);
}
.comment__role{
  margin-left:var(--sp-8);
  font-size:var(--text-12);
  font-weight:500;
  color:var(--accent-ink);
}
.comment__time{
  margin-left:var(--sp-8);
  font-size:var(--text-12);
  color:var(--faint);
}
.comment__body{
  margin-top:var(--sp-4);
  font-size:var(--text-15);
  line-height:1.55;
  color:var(--muted);
}
/* edit / delete, on the header line; shown when the comment is hovered or focused */
.comment > div{ flex:1; min-width:0; }
.comment__head{ display:flex; align-items:baseline; }
/* a comment that records an action — hold, resume, approve, return — opens with the action as an
   icon and a bold label; the person's note follows as ordinary text. Same row, same thread. */
.comment__event{ display:inline-flex; align-items:center; gap:var(--sp-4); margin-right:var(--sp-4); font-weight:600; color:var(--ink); }
.comment__event .icon{ color:var(--muted); }
.comment__actions{ margin-left:auto; display:inline-flex; gap:var(--sp-4); opacity:0; transition:opacity .12s; }
.comment:hover .comment__actions, .comment:focus-within .comment__actions{ opacity:1; }
.comment.is-editing{ display:none; }
.composer{
  display:flex;
  flex-direction:column;
  gap:var(--sp-8);
  padding:var(--sp-12);
  background:var(--surface);
  border:1px solid var(--line);
  border-radius:var(--radius-lg);
}
.composer__actions{
  display:flex;
  align-items:center;
  justify-content:flex-end;
  gap:var(--sp-8);
}

/* ===== version-list ===== */
/* each version is its own element — four corners, a gap — not one box sliced by rules */
.version-list{
  display:flex;
  flex-direction:column;
  gap:var(--sp-8);
}
.version{
  display:flex;
  align-items:center;
  gap:var(--sp-12);
  padding:var(--sp-12) var(--sp-16);
  background:var(--surface);
  border:1px solid var(--line);
  border-radius:var(--radius-md);
}
.version__num{
  flex:none;
  font-family:var(--font-mono);
  font-size:var(--text-12);
  font-weight:600;
  color:var(--ink);
}
.version__status{ flex:none; }
.version__meta{
  flex:1;
  font-size:var(--text-12);
  color:var(--faint);
}
.version__download{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  flex:none;
  width:32px;
  height:32px;
  border:1px solid var(--line-2);
  border-radius:var(--radius-md);
  background:var(--surface);
  color:var(--muted);
  cursor:pointer;
  transition:background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.version__download:hover{ background:var(--surface-2); color:var(--ink); }
.version__download svg{
  width:16px;
  height:16px;
  fill:none;
  stroke:currentColor;
  stroke-width:1.6;
}
.approval{
  display:flex;
  align-items:center;
  flex-wrap:wrap;
  gap:var(--sp-12);
}
.approval__text{ flex:1; min-width:200px; }
.approval__actions{
  display:flex;
  gap:var(--sp-8);
}

/* ===== logo ===== */
/* the brand lockup; paths are filled, so it opts out of the .icon stroke treatment */
.logo{
  display:block;
  flex:none;
  width:auto;
  height:20px;
  fill:currentColor;
  stroke:none;
  color:var(--ink);
}
.logo--mark{ height:22px; }
.logo--lg{ height:26px; }

/* Third-party brand marks (Google, etc.). Supplied artwork in fixed brand
   colors that we are not allowed to recolor, so the paths carry their own
   fills and sit outside both the token layer and .icon's stroke treatment. */
.brandmark{ width:16px; height:16px; flex:none; stroke:none; }

/* ============================================================
   team — the team grid: people down the side, working days across
   Past days show attainment (marker: on time / over / missed); today and ahead
   show hours left (day-avail) or a lock when there is no room; time off is a
   neutral marker. Rows can be grouped (team__group) for sub-groups or, on the
   all-teams view, for teams. Rendered by ui/team-grid.js from ui/team-data.js;
   .legend explains the marks above it. Every day header opens the day view.
   ============================================================ */
/* legend */
.legend{display:flex;flex-wrap:wrap;gap:var(--sp-16);margin:0 0 var(--sp-24);}
.legend__item{display:flex;align-items:center;gap:var(--sp-8);font-size:var(--text-12);color:var(--muted);}
/* day marker — colored dot holding a status icon (past) or availability (future).
/* past-day attainment uses the catalog .marker; the availability pill is page-local */
.day-avail{display:inline-flex;align-items:center;justify-content:center;min-width:24px;height:24px;padding:0 var(--sp-8);border:1px dashed var(--line-2);border-radius:var(--radius-pill);color:var(--muted);font-size:var(--text-12);font-weight:500;flex:none;}
.day-avail--full{border-style:solid;border-color:var(--line);color:var(--faint);}
/* scrolling attainment grid */
.team{overflow-x:auto;}
.team__inner{display:inline-block;min-width:100%;}
.team__row{display:flex;align-items:stretch;}
.team__row + .team__row{border-top:1px solid var(--line);}
/* top-align: avatar sits on the name's first line, not centered against name+capacity */
.team__name{position:sticky;left:0;z-index:1;width:208px;flex:none;display:flex;align-items:flex-start;gap:var(--sp-8);padding:var(--sp-12) var(--sp-16) var(--sp-12) 0;background:var(--surface);border-right:1px solid var(--line);}
.team__lead{display:flex;align-items:center;min-height:var(--sp-24);flex:none;}
.team__namemain{display:flex;flex-direction:column;min-width:0;}
.team__person{font-size:var(--text-15);font-weight:600;line-height:var(--sp-24);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.team__cap{font-size:var(--text-12);color:var(--muted);}
.team__days{display:flex;flex:none;}
/* header row */
.team__row--head{border-bottom:1px solid var(--line);}
.team__row--head .team__name{background:var(--surface);}
.team__label{font-size:var(--text-12);font-weight:600;letter-spacing:0.06em;text-transform:uppercase;color:var(--muted);}
.team__dayhead{width:38px;flex:none;display:flex;flex-direction:column;align-items:center;gap:var(--sp-4);padding:var(--sp-8) 0;color:inherit;text-decoration:none;cursor:pointer;border-radius:var(--radius-sm);}
a.team__dayhead:hover{background:var(--surface-2);}
a.team__dayhead:hover .team__dom{color:var(--accent-ink);}
.team__dow{font-size:var(--text-9);font-weight:600;letter-spacing:0.04em;text-transform:uppercase;color:var(--faint);}
.team__dom{font-size:var(--text-12);color:var(--muted);}
.team__dayhead--month .team__dow{color:var(--accent-ink);}
.team__dayhead--today .team__dom{color:var(--accent-ink);font-weight:700;}
/* body day cells */
/* markers top-align to the same first-line box as the member name */
.day-col{width:38px;flex:none;display:flex;align-items:flex-start;justify-content:center;padding:var(--sp-12) 0;}
.day-col--week, .team__dayhead--week{border-left:1px solid var(--line);}
.day-col--today, .team__dayhead--today{background:var(--surface-2);} /* neutral: the markers carry the color */
/* the today column is one shape: the head rounds its top, the last row rounds its bottom */
.team__dayhead--today{border-radius:var(--radius-sm) var(--radius-sm) 0 0;}
.team__row:last-child .day-col--today{border-radius:0 0 var(--radius-sm) var(--radius-sm);}
.team__caption{display:block;font-size:var(--text-12);color:var(--muted);}
@media (max-width:760px){
  .team__name{width:160px;}
}
.team__group{display:flex;background:var(--surface-2);}
.team__group-label{position:sticky;left:0;display:flex;align-items:center;gap:var(--sp-8);padding:var(--sp-8) var(--sp-12);font-size:var(--text-12);font-weight:600;color:var(--muted);white-space:nowrap;}
.team__group-label .link{font-weight:600;}
.team__group-meta{font-weight:400;color:var(--faint);}

/* ============================================================
   screen — the page frame under the topbar
   Three widths, picked by page kind (RULES.md › Layout): reading (default,
   centered 1024) · --wide (full-bleed: lists, tables, boards, dashboards) ·
   --narrow (confirmation cards). Head = eyebrow + title (+ intro / meta) on the
   left, actions on the right; below --bp-md the actions drop to a full-width row.
   ============================================================ */
.screen{max-width:1024px;margin:0 auto;}
.screen--wide{max-width:none;}
.screen--narrow{max-width:640px;}
.screen__head{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--sp-16);flex-wrap:wrap;margin:0 0 var(--sp-16);}
.screen__lead{display:flex;align-items:center;gap:var(--sp-16);min-width:0;}
.screen__title{display:flex;align-items:center;gap:var(--sp-8);font-size:var(--text-30);font-weight:750;letter-spacing:-0.02em;margin:var(--sp-8) 0 0;}
.screen__title .icon{width:26px;height:26px;color:var(--muted);}
.screen__intro{color:var(--muted);font-size:var(--text-15);line-height:1.55;margin:var(--sp-8) 0 0;max-width:66ch;}
.screen__meta{display:flex;align-items:center;gap:var(--sp-8);flex-wrap:wrap;margin-top:var(--sp-12);font-size:var(--text-12);color:var(--muted);}
.screen__meta-item{display:inline-flex;align-items:center;gap:var(--sp-8);}
.screen__meta-sep{color:var(--faint);}
.screen__price{font-size:var(--text-24);font-weight:750;color:var(--ink);flex:none;}
.screen__actions{display:flex;align-items:center;gap:var(--sp-8);flex-wrap:wrap;flex:none;}
.screen__search{width:240px;}
@media (max-width:760px){
  .screen__actions{width:100%;}
  .screen__search{flex:1 1 auto;width:auto;}
}
.screen__tabs{margin:0 0 var(--sp-24);}
.screen__callout{margin:0 0 var(--sp-24);}
.stack + .screen__callout, .panel + .screen__callout, .tbl + .screen__callout, .list-group + .screen__callout{margin-top:var(--sp-24);}
.screen__alert{margin:0 0 var(--sp-24);}
.screen__row{display:grid;grid-template-columns:1fr;gap:var(--sp-24);}

/* shot — a framed screenshot with a caption. The frame holds a live page,
   scaled to half, inert; the caption says what it is and links to it. */
.shot{margin:0;border:1px solid var(--line);border-radius:var(--radius-md);overflow:hidden;background:var(--surface);}
.shot__frame{position:relative;aspect-ratio:16 / 10;overflow:hidden;background:var(--ground);}
.shot__frame iframe{position:absolute;top:0;left:0;width:200%;height:200%;border:0;transform:scale(0.5);transform-origin:0 0;pointer-events:none;}
.shot__caption{padding:var(--sp-8) var(--sp-12);font-size:var(--text-12);color:var(--muted);border-top:1px solid var(--line);}

/* stack — panels and blocks one under another, the page-level rhythm */
.stack{display:flex;flex-direction:column;gap:var(--sp-24);}
.stack--sm{gap:var(--sp-16);}

/* ===== perspective =====
   Prototype scaffolding, not product UI. Some screens genuinely render
   differently for different audiences — the same stored status reads one way to
   QA and another to the client. Rather than put a role picker inside the page,
   where it reads as a feature and clutters the very layout it is meant to
   demonstrate, the switch floats clear of the page in the corner. The page
   itself then shows exactly what that audience would see, and nothing else.
   Only add it where more than one perspective actually exists. */
.perspective{
  position:fixed;
  right:var(--sp-24);
  bottom:var(--sp-24);
  z-index:var(--z-dropdown);
  display:flex;
  flex-direction:column;
  align-items:flex-end;
  gap:var(--sp-8);
}
.perspective__trigger{
  display:inline-flex;
  align-items:center;
  gap:var(--sp-8);
  height:36px;
  padding:0 var(--sp-12);
  border:1px solid var(--line-2);
  border-radius:var(--radius-pill);
  background:var(--surface);
  color:var(--muted);
  box-shadow:var(--shadow);
  font-family:var(--font-sans);
  font-size:var(--text-12);
  font-weight:600;
  cursor:pointer;
  transition:background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.perspective__trigger:hover{ background:var(--surface-2); color:var(--ink); }
.perspective__trigger:focus-visible{ outline:2px solid var(--accent); outline-offset:2px; }
.perspective__who{ color:var(--ink); }
.perspective__note{
  display:block;
  padding:var(--sp-8) var(--sp-12) var(--sp-12);
  margin:0 0 var(--sp-4);
  border-bottom:1px solid var(--line);
  font-size:var(--text-12);
  line-height:1.45;
  color:var(--faint);
}
/* The panel floats centered above the trigger (--shift nudges it back inside the
   viewport when it's wider than the trigger; see ui/perspective.js). The seat
   names set its width and never wrap; the note wraps to whatever width they set. */
.perspective .dropdown{
  position:absolute;
  bottom:calc(100% + var(--sp-8));
  left:50%;
  transform:translateX(calc(-50% + var(--shift, 0px)));
  min-width:240px;
}
.perspective .dropdown__item{ white-space:nowrap; }
.perspective .divider{ margin:var(--sp-4) 0; }
/* a note under a rule introduces the item below it, not the list above */
.perspective__note--foot{ border-bottom:0; padding-bottom:var(--sp-4); margin:0; }
.perspective .dropdown__item .icon{ margin-left:auto; color:var(--faint); }
@media (max-width:760px){
  .perspective{ right:var(--sp-12); bottom:var(--sp-12); }
}

/* ===== thumb =====
   An image frame that holds its shape before the image arrives. A catalog of
   visual work is unreadable as a grid of identical glyphs, so services, samples
   and galleries all show artwork — and all need the same box while that artwork
   is missing, loading, or absent for a given record. Put an <img> inside and it
   covers; put an .icon inside and it reads as an empty frame rather than a
   broken one. Pick the ratio at the call site; the frame never crops the layout. */
.thumb{
  display:flex;
  align-items:center;
  justify-content:center;
  overflow:hidden;
  border:1px solid var(--line);
  border-radius:var(--radius-md);
  background:var(--surface-2);
  color:var(--faint);
}
.thumb img{ display:block; width:100%; height:100%; object-fit:cover; }
.thumb svg{ width:24px; height:24px; flex:none; fill:none; stroke:currentColor; stroke-width:1.4; }
.thumb--wide{ aspect-ratio:16 / 10; }
.thumb--hero{ aspect-ratio:4 / 3; }
.thumb--square{ aspect-ratio:1; }
.thumb--sm svg{ width:16px; height:16px; }

/* ===== .svc-card =====
   A service in a catalog: artwork, what it costs, what it is, and one action.
   The cost sits on the thumbnail in a solid pill so it stays legible over any
   image. Its unit is the account's — hours against a plan, or a price — so the
   __cost slot takes whatever the page deals in. Composes .card. */
.svc-card__open{
  /* .card is a column flex and .card__body grows so footers line up across a
     row. Wrapping the body in a link puts a box between them, so the link has
     to carry the growth through or every card ends at its own text height. */
  display:flex;
  flex-direction:column;
  flex:1 1 auto;
  color:inherit;
  text-decoration:none;
}
.svc-card__open:hover .svc-card__name{ color:var(--accent-ink); }
.svc-card__open:focus-visible{ outline:2px solid var(--accent); outline-offset:-2px; }
.svc-card__media{ position:relative; }
.svc-card__media .thumb{ border-radius:0; border-width:0 0 1px; }
.svc-card__cost{
  position:absolute;
  top:var(--sp-8);
  right:var(--sp-8);
  display:inline-flex;
  align-items:baseline;
  gap:var(--sp-4);
  padding:var(--sp-4) var(--sp-8);
  border:1px solid var(--line-2);
  border-radius:var(--radius-pill);
  background:var(--surface);
  font-size:var(--text-15);
  font-weight:700;
  color:var(--ink);
}
.svc-card__cost small{ font-size:var(--text-9); font-weight:500; color:var(--muted); }
.svc-card__name{ font-size:var(--text-15); font-weight:600; color:var(--ink); margin:0 0 var(--sp-4); }
.svc-card__desc{ margin:0; font-size:var(--text-12); color:var(--muted); line-height:1.5; }
.svc-card .card__footer{ justify-content:center; }
.svc-card .card__footer .btn{ width:100%; }

/* ===== app shell ===== */
/* keep an inlined icon sprite out of layout even where the [hidden] UA rule is overridden */
svg[hidden]{ display:none; }
.app{ display:grid; grid-template-columns:var(--sidebar-w) 1fr; min-height:100vh; }
.sidebar{
  display:flex;
  flex-direction:column;
  padding:var(--sp-12);
  background:var(--surface);
  border-right:1px solid var(--line);
  position:sticky;
  top:0;
  height:100vh;
  overflow-y:auto;
}
.sidebar__brand{
  display:flex;
  align-items:center;
  gap:var(--sp-8);
  padding:var(--sp-8) var(--sp-8) var(--sp-16);
  font-size:var(--text-18);
  font-weight:700;
  color:var(--ink);
}
.sidebar__footer{ margin-top:auto; padding-top:var(--sp-8); border-top:1px solid var(--line); }
/* A running timer sits just above the footer divider. It claims the sidebar's
   free space so it rides down to the bottom — and the footer stops claiming it,
   or the two would split the gap and leave the timer floating mid-rail. While no
   timer is running the element is [hidden], the selector misses, and the footer
   keeps the space to itself. */
.sidebar > .timer{ margin-top:auto; margin-bottom:var(--sp-12); }
.timer:not([hidden]) ~ .sidebar__footer{ margin-top:0; }

.nav{ display:flex; flex-direction:column; gap:2px; }
.nav__label{
  font-family:var(--font-mono);
  font-size:var(--text-9);
  letter-spacing:0.1em;
  text-transform:uppercase;
  color:var(--faint);
  padding:var(--sp-16) var(--sp-8) var(--sp-4);
}
.nav__item{
  display:flex;
  align-items:center;
  gap:var(--sp-8);
  width:100%;
  padding:var(--sp-8);
  border:0;
  border-radius:var(--radius-md);
  background:transparent;
  color:var(--muted);
  font-family:var(--font-sans);
  font-size:var(--text-15);
  font-weight:500;
  text-align:left;
  text-decoration:none;
  cursor:pointer;
}
.nav__item:hover{ background:var(--surface-2); color:var(--ink); }
.nav__item.is-active{ background:var(--accent-soft); color:var(--accent-ink); font-weight:600; }
.nav__item .icon{ flex:none; }
.nav__item-badge{ margin-left:auto; }

.app__main{ display:flex; flex-direction:column; min-width:0; }
.topbar{
  display:flex;
  align-items:center;
  gap:var(--sp-12);
  flex:none;
  height:var(--topbar-h);
  padding:0 var(--sp-24);
  background:var(--surface);
  border-bottom:1px solid var(--line);
  position:sticky;
  top:0;
  z-index:var(--z-sticky);
}
.topbar__trigger{ display:none; }
.topbar__actions{ display:flex; align-items:center; gap:var(--sp-8); margin-left:auto; }
.app__content{ flex:1; min-width:0; padding:var(--sp-24) var(--sp-32) var(--sp-64); }

/* responsive: collapse the sidebar below --bp-md (JS drawer wires the trigger in production) */
@media (max-width:760px){
  .app{ grid-template-columns:1fr; }
  .sidebar{ display:none; }
  .topbar__trigger{ display:inline-flex; }
  .app__content{ padding:var(--sp-16) var(--sp-16) var(--sp-48); }
}

/* ===== summary =====
   Cost/order-summary lines: a label on the left, a value on the right.
   Base line is itemized (muted); --row is a subtotal/tax line; --total is the
   emphasized bottom line. The value goes in __val. */
.summary{ display:flex; flex-direction:column; }
.summary__line{
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:var(--sp-16);
  padding:var(--sp-4) 0;
  font-size:var(--text-12);
  color:var(--muted);
}
.summary__val{ color:var(--ink); }
.summary__line--row{ font-size:var(--text-15); }
.summary__line--row .summary__val{ font-weight:600; }
.summary__line--total{ font-size:var(--text-18); color:var(--ink); font-weight:700; }
.summary__line--total .summary__val{ font-size:var(--text-18); font-weight:700; }

/* ===== confirm-hero =====
   A centered success header for confirmation screens: a circular icon badge,
   a title, and a sub. Icon reads success by default. */
.confirm-hero{ text-align:center; padding:var(--sp-16) 0 var(--sp-32); }
.confirm-hero__icon{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  width:64px;
  height:64px;
  border-radius:var(--radius-pill);
  background:var(--success-soft);
  color:var(--success-ink);
  margin-bottom:var(--sp-16);
}
.confirm-hero__icon svg{ width:32px; height:32px; fill:none; stroke:currentColor; stroke-width:2; }
.confirm-hero__title{ font-size:var(--text-24); font-weight:750; letter-spacing:-0.01em; margin:0 0 var(--sp-8); }
.confirm-hero__sub{ margin:0; color:var(--muted); font-size:var(--text-15); line-height:1.55; }

/* ===== dropzone =====
   A dashed file-upload target: an icon, a primary line (__text), and a
   secondary hint (__sub). Drop a button inside for the click path. */
.dropzone{
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:var(--sp-8);
  padding:var(--sp-32);
  text-align:center;
  border:1px dashed var(--line-2);
  border-radius:var(--radius-lg);
  background:var(--surface);
}
/* beside a preview, the zone is a row and does not need to be tall */
.dropzone--inline{ flex-direction:row; align-items:center; text-align:left; padding:var(--sp-16); gap:var(--sp-12); }
.dropzone__main{ display:flex; flex-direction:column; gap:var(--sp-4); min-width:0; }
.dropzone--interactive{ cursor:pointer; }
.dropzone--interactive:hover,
.dropzone.is-dragover{ border-color:var(--accent); background:var(--surface-2); }
.dropzone__icon{ display:inline-flex; color:var(--faint); }
.dropzone__icon svg{ width:26px; height:26px; fill:none; stroke:currentColor; stroke-width:1.6; }
.dropzone__text{ font-size:var(--text-12); color:var(--muted); }
.dropzone__sub{ font-size:var(--text-12); color:var(--faint); }

/* ===== picture =====
   An image field: the current picture (an .avatar, initials as the fallback)
   with Remove under it, beside a .dropzone that takes a file by click or drag.
   One shape for a profile photo, an account logo, a folder image. Behaviour is
   ui/picture.js on [data-behavior="picture"]; it fires `change` on the file
   input after a drop or a remove so a form's own dirty-tracking sees it. */
.picture{ display:flex; align-items:stretch; gap:var(--sp-16); }
.picture__current{ display:flex; flex-direction:column; align-items:center; gap:var(--sp-8); flex:none; }
.picture .dropzone{ flex:1 1 auto; }

/* ===== auth (signed-out screens: login, sign up, reset, verify) ===== */
.auth{ min-height:100vh; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:var(--sp-24); padding:var(--sp-48) var(--sp-24); }
.auth__brand{ display:inline-flex; align-items:center; gap:var(--sp-8); font-size:var(--text-18); font-weight:700; color:var(--ink); text-decoration:none; }
.auth__card{ width:min(400px, 100%); background:var(--surface); border:1px solid var(--line); border-radius:var(--radius-lg); box-shadow:var(--shadow); padding:var(--sp-32); }
.auth__card--center{ text-align:center; }
.auth__icon{ display:inline-flex; align-items:center; justify-content:center; width:48px; height:48px; margin-bottom:var(--sp-16); border-radius:var(--radius-pill); background:var(--accent-soft); color:var(--accent-ink); }
.auth__icon svg{ width:24px; height:24px; }
.auth__title{ margin:0; font-size:var(--text-24); font-weight:750; letter-spacing:-0.01em; }
.auth__sub{ margin:var(--sp-8) 0 0; color:var(--muted); font-size:var(--text-15); line-height:1.55; }
.auth__body{ margin-top:var(--sp-24); display:flex; flex-direction:column; gap:var(--sp-16); }
.auth__body .btn{ width:100%; }
.auth__or{ display:flex; align-items:center; gap:var(--sp-12); color:var(--faint); font-size:var(--text-12); }
.auth__or::before,.auth__or::after{ content:""; flex:1; height:1px; background:var(--line); }
.auth__row{ display:flex; align-items:center; justify-content:space-between; gap:var(--sp-8); }
.auth__foot{ color:var(--muted); font-size:var(--text-12); text-align:center; }

/* ===== marker =====
   A filled status circle holding a Lucide icon — for pass/warn/fail-style states
   that need an icon, not just a dot (cf. .status-dot, which is icon-less). */
.marker{ display:inline-flex; align-items:center; justify-content:center; width:24px; height:24px; border-radius:50%; flex:none; }
.marker .icon{ width:14px; height:14px; }
.marker--success{ background:var(--success-soft); color:var(--success-ink); }
.marker--warning{ background:var(--warning-soft); color:var(--warning-ink); }
.marker--danger{  background:var(--danger-soft);  color:var(--danger-ink); }
.marker--info{    background:var(--info-soft);    color:var(--info-ink); }
.marker--neutral{ background:var(--neutral-soft); color:var(--neutral-ink); }
/* series tones — the same a/b/c/d palette .avatar and .meter__seg use, for
   when the disc identifies WHICH thing rather than how it is doing. */
.marker--a{ background:var(--accent-soft); color:var(--accent-ink); }
.marker--b{ background:var(--info-soft);   color:var(--info-ink); }
.marker--c{ background:var(--purple-soft); color:var(--purple-ink); }
.marker--d{ background:var(--orange-soft); color:var(--orange-ink); }

/* ===== bar-chart =====
   A horizontal bar list: label · bar · value per row. Composes .meter for the bar
   (so .meter__fill--warning/--danger threshold colors work). No vertical bars —
   they can't be built lint-clean without off-scale inline heights. */
.bar-chart{ display:flex; flex-direction:column; gap:var(--sp-16); }
.bar-chart__row{ display:grid; grid-template-columns:minmax(96px, 30%) 1fr auto; align-items:center; gap:var(--sp-12); }
/* the label never runs into the bar: it gets up to 30% of the row, then an ellipsis (put the full text in title=) */
.bar-chart__label{ font-size:var(--text-12); color:var(--muted); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; min-width:0; }
.bar-chart__value{ font-size:var(--text-12); font-weight:600; text-align:right; font-variant-numeric:tabular-nums; }
.bar-chart--strong .bar-chart__label{ font-size:var(--text-12); font-weight:600; color:var(--ink); }   /* labels-as-headers */

/* ===== accordion =====
   Native <details>/<summary> disclosure — no JS. .accordion wraps .accordion__item
   (<details>); the chevron rotates on [open]. */
/* each item is a solid block that expands — no hairlines between questions */
.accordion{ display:flex; flex-direction:column; gap:var(--sp-8); }
.accordion__item{ background:var(--ground); border-radius:var(--radius-md); }
.accordion__item[open]{ background:var(--ground); }
.accordion__q{ list-style:none; cursor:pointer; padding:var(--sp-16); font-size:var(--text-15); font-weight:600; display:flex; align-items:center; justify-content:space-between; gap:var(--sp-12); border-radius:var(--radius-md); }
.accordion__q:hover{ background:color-mix(in srgb, var(--ink) 4%, var(--surface-2)); }
.accordion__q::-webkit-details-marker{ display:none; }
.accordion__q .icon{ color:var(--muted); transition:transform var(--dur-fast) var(--ease); flex:none; }
.accordion__item[open] .accordion__q .icon{ transform:rotate(180deg); }
.accordion__a{ margin:0; padding:0 var(--sp-16) var(--sp-16); color:var(--muted); font-size:var(--text-15); line-height:1.6; max-width:70ch; }

/* ===== timer =====
   The running work timer. One per person, and it follows them between screens —
   in r2c2 the clock is a server-side TimeTracker record, so it outlives the page
   that started it. Mounted in .sidebar__footer because that is the one region on
   screen everywhere; the task name links back to the work being measured.
   State is [data-state="running"|"paused"], and no timer means no element at all
   (native [hidden]) rather than an empty box holding space. */
.timer{
  display:flex;
  flex-direction:column;
  gap:var(--sp-4);
  padding:var(--sp-8);
  border:1px solid var(--line);
  border-radius:var(--radius-md);
  background:var(--surface-2);   /* lifts off the sidebar, which is --surface in both themes */
}
.timer__task{
  display:flex;
  align-items:center;
  gap:var(--sp-8);
  min-width:0;
  color:var(--ink);
  font-size:var(--text-12);
  font-weight:600;
  text-decoration:none;
}
/* An author display:flex outranks the UA's [hidden]{display:none}, so no timer
   has to be spelled out — otherwise an empty box sits in the rail all day. */
.timer[hidden]{ display:none; }
/* the name is the only elastic part — everything else is fixed, so it truncates */
.timer__name{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.timer__task:hover .timer__name{ text-decoration:underline; }
.timer__row{ display:flex; align-items:center; gap:var(--sp-8); }
.timer__clock{
  font-family:var(--font-mono);
  font-size:var(--text-15);
  font-variant-numeric:tabular-nums;   /* digits must not jog the controls each second */
  letter-spacing:0.02em;
  color:var(--ink);
}
.timer__controls{ display:flex; align-items:center; gap:var(--sp-4); margin-left:auto; }
/* held time is still time, but it isn't accruing — the clock stops reading live */
.timer[data-state="paused"] .timer__clock,
.timer[data-state="confirming"] .timer__clock{ color:var(--muted); }

/* The confirm step. Stopping does not write straight to the ledger — the box
   grows to show the figure being logged and to ask what the time went on. The
   transport controls step aside while it is open: pause and stop mean nothing
   once the session is closed and the only question left is log or cancel. */
.timer__confirm{
  display:none;
  flex-direction:column;
  gap:var(--sp-8);
  padding-top:var(--sp-8);
  border-top:1px solid var(--line);
}
.timer[data-state="confirming"] .timer__confirm{ display:flex; }
.timer[data-state="confirming"] .timer__controls{ display:none; }
.timer__ask{ margin:0; font-size:var(--text-12); color:var(--muted); line-height:1.5; }
.timer__note{ font-size:var(--text-12); }
.timer__actions{ display:flex; gap:var(--sp-4); }
/* two equal halves — neither answer is the small print */
.timer__actions .btn{ flex:1; }
