/* Components (PLAN 3.8, 3.10): buttons, badges, cards, banners, the page
   head, the stat strip, key-value, tabs, timeline, modal, drawer, menu,
   popover, toasts, empty state and skeleton - the pieces screens are built
   from. Every value is a token; there is no colour here.

   All of it is in the `components` layer (declared in tokens.css), below
   the utilities: `.note.mt` or `.card.mt` get the utility's margin, not the
   component's. */

@layer components {

/* ── page head ────────────────────────────────────────────────────────────
   Two spellings. The one screens build by hand today is a flex row: a title
   block, a spacer, then buttons and filters. The component (pagehead.js)
   adds `.ph` and lays out three rows: crumbs; title + status | actions;
   subtitle and meta. */
.page-head { display: flex; align-items: center; gap: var(--s-3); margin-bottom: var(--s-4); min-width: 0; }
.page-head .spacer { flex: 1; }
.page-head h1 { overflow-wrap: anywhere; }

.page-head.ph { display: block; }
.ph-main { display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap; min-width: 0; }
.ph-title { display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap; min-width: 0; flex: 1 1 320px; }
.ph-actions { display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap; justify-content: flex-end; }
.ph-sub { margin-top: var(--s-1); color: var(--text-muted); font-size: var(--fs-md); max-width: var(--measure); }
.ph-meta {
  margin-top: var(--s-1); display: flex; flex-wrap: wrap; gap: var(--s-1) var(--s-2);
  color: var(--text-muted); font-size: var(--fs-sm); line-height: var(--lh-sm);
}
/* The ⋯ button repeats the secondary actions on a phone only (pagehead.js
   decides what goes in it at click time). */
.ph-actions .ph-more-phone { display: none; }

.crumbs { margin-bottom: var(--s-1); font-size: var(--fs-sm); line-height: var(--lh-sm); color: var(--text-muted); min-width: 0; }
.crumbs ol { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-1); }
.crumbs li { display: inline-flex; align-items: center; gap: var(--s-1); min-width: 0; }
.crumbs li + li::before { content: "›"; color: var(--text-subtle); }
.crumbs a { color: var(--text-muted); }
.crumbs a:hover { color: var(--accent); }
.crumbs [aria-current="page"] { color: var(--text); }

/* ── buttons ──────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s-1h);
  height: var(--control-h); padding: 0 var(--s-3); min-width: 0;
  border: 1px solid var(--border-strong); border-radius: var(--r-md);
  background: var(--surface); color: var(--text);
  font: inherit; font-size: var(--fs-md); font-weight: 500; line-height: 1;
  cursor: pointer; white-space: nowrap; text-decoration: none; user-select: none;
  transition: background-color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease),
              color var(--dur-fast) var(--ease);
}
a.btn:hover { text-decoration: none; }
.btn:hover { background: var(--surface-2); border-color: var(--border-input); }
.btn:active { background: var(--surface-3); }
.btn:focus-visible { box-shadow: var(--focus); }
.btn[disabled], .btn[aria-disabled="true"] {
  background: var(--surface-2); border-color: var(--border); color: var(--text-disabled);
  cursor: not-allowed;
}
.btn-primary { background: var(--accent-solid); border-color: var(--accent-solid); color: var(--accent-fg); }
.btn-primary:hover { background: var(--accent-solid-hover); border-color: var(--accent-solid-hover); }
.btn-primary:active { background: var(--accent-solid-hover); }
.btn-primary[disabled] { background: var(--surface-3); border-color: var(--surface-3); color: var(--text-disabled); }
.btn-danger { color: var(--danger); border-color: var(--danger-border); }
.btn-danger:hover { background: var(--danger-subtle); border-color: var(--danger); }
.btn-ghost { border-color: transparent; background: transparent; color: var(--text-muted); }
.btn-ghost:hover { background: var(--surface-3); border-color: transparent; color: var(--text); }
.btn-ghost[disabled] { background: transparent; border-color: transparent; }
.btn-sm { height: calc(var(--control-h) - 6px); padding: 0 var(--s-2); font-size: var(--fs-sm); gap: var(--s-1); }
.btn-icon { width: var(--control-h); padding: 0; }
.btn-sm.btn-icon { width: calc(var(--control-h) - 6px); }
/* A toggle button that is on (segmented control, a pressed filter). */
.btn[aria-pressed="true"]:not(.btn-primary) {
  background: var(--accent-subtle); border-color: var(--accent-border); color: var(--accent);
}
.btn-group { display: inline-flex; }
.btn-group > .btn { border-radius: 0; margin-inline-start: -1px; }
.btn-group > .btn:first-child { border-start-start-radius: var(--r-md); border-end-start-radius: var(--r-md); margin-inline-start: 0; }
.btn-group > .btn:last-child { border-start-end-radius: var(--r-md); border-end-end-radius: var(--r-md); }
.btn-group > .btn:focus-visible { position: relative; z-index: 1; }

/* A touch screen gets a finger-sized target (WCAG 2.5.5 / PLAN 3.15). */
@media (pointer: coarse) {
  .btn { min-height: 40px; }
  .btn-sm, .btn-icon { min-width: 40px; }
}

/* The (i) beside a label or a figure: opens the rationale popover. */
.info-btn {
  display: inline-grid; place-items: center; width: 18px; height: 18px; padding: 0;
  border: none; border-radius: var(--r-pill); background: transparent; color: var(--text-subtle);
  cursor: pointer; vertical-align: middle;
}
.info-btn:hover { color: var(--accent); background: var(--accent-subtle); }
.info-btn .ico { width: 13px; height: 13px; }

/* ── card ──────────────────────────────────────────────────────────── */
.card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); box-shadow: var(--shadow-1); min-width: 0;
}
.card-head {
  display: flex; align-items: center; gap: var(--s-3); min-height: 44px;
  padding: var(--s-2) var(--s-4); border-bottom: 1px solid var(--border);
}
.card-head .spacer { flex: 1; }
.card-head h3 { font-size: var(--fs-md); line-height: var(--lh-md); font-weight: 600; }
/* The title keeps its line; a note or a button beside it gives way. */
.card-head > h2, .card-head > h3 { flex-shrink: 0; max-width: 100%; }
.card-body { padding: var(--s-4); }
/* ── empty state and skeleton ─────────────────────────────────────────── */
.empty { padding: var(--s-10) var(--s-5); text-align: center; color: var(--text-muted); }
.empty > .ico, .empty-icon { width: 28px; height: 28px; color: var(--text-subtle); margin-bottom: var(--s-2); }
.empty h3 { margin-bottom: var(--s-1); color: var(--text); }
.empty > div:not([class]) { max-width: 60ch; margin-inline: auto; }
.skeleton {
  background: linear-gradient(90deg, var(--surface-2) 25%, var(--surface-3) 37%, var(--surface-2) 63%);
  background-size: 400% 100%; animation: shimmer 1.3s ease infinite; border-radius: var(--r-sm); height: 11px;
}
@keyframes shimmer { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }
@media (prefers-reduced-motion: reduce) { .skeleton { animation: none; } }

/* A link to one record (dom.docLink). A document number broken over two
   lines reads as two numbers, so it never wraps. */
.doclink { white-space: nowrap; }

/* ── badges ───────────────────────────────────────────────────────────────
   One badge, five tones (PLAN 3.7). `badge tone-*` is what statusBadge
   draws; the `badge-*` names are what 50 screens say through statusClass(),
   and two of them (leases, assets) use the tone class alone, so every tone
   name carries the whole badge. Colour is never the only signal: a badge
   always has its text. */
.badge, .badge-ok, .badge-warn, .badge-danger, .badge-info, .badge-accent, .badge-neutral {
  display: inline-flex; align-items: center; gap: var(--s-1); height: 20px; padding: 0 var(--s-2);
  border-radius: var(--r-pill); border: 1px solid var(--neutral-border);
  background: var(--neutral-subtle); color: var(--neutral);
  font-size: var(--fs-sm); line-height: 18px; font-weight: 600; white-space: nowrap; vertical-align: middle;
}
.badge .ico { width: 12px; height: 12px; }
.badge.tone-ok, .badge-ok         { background: var(--ok-subtle);     color: var(--ok);     border-color: var(--ok-border); }
.badge.tone-warn, .badge-warn     { background: var(--warn-subtle);   color: var(--warn);   border-color: var(--warn-border); }
.badge.tone-danger, .badge-danger { background: var(--danger-subtle); color: var(--danger); border-color: var(--danger-border); }
.badge.tone-info, .badge-info, .badge-accent  { background: var(--info-subtle);   color: var(--info);   border-color: var(--info-border); }
.badge.tone-neutral, .badge-neutral { background: var(--neutral-subtle); color: var(--neutral); border-color: var(--neutral-border); }
/* A count beside a tab or a heading: quieter than a status. */
.badge.count { height: 18px; padding: 0 var(--s-1h); font-size: var(--fs-xs); line-height: 16px; background: var(--surface-3); border-color: transparent; color: var(--text-muted); }

/* ── banners ──────────────────────────────────────────────────────────────
   A message about the page: a problem to fix, a warning, or a confirmation
   that stays. The text stays in the body colour so a long message reads
   easily; the tint, the edge and the icon carry the tone. A banner's
   DEFAULT is the warning tone (what `banner` alone has always meant), and
   every tone is named so none depends on the default. */
.banner {
  display: flex; align-items: flex-start; gap: var(--s-2);
  padding: var(--s-2) var(--s-3); margin-bottom: var(--s-3);
  border: 1px solid var(--warn-border); border-inline-start-width: 3px; border-radius: var(--r-md);
  background: var(--warn-subtle); color: var(--text); font-size: var(--fs-md); line-height: var(--lh-md);
  min-width: 0; overflow-wrap: anywhere;
}
.banner > .ico { color: var(--warn); margin-top: 2px; }
.banner b { font-weight: 600; }
.banner-body { flex: 1; min-width: 0; }
.banner-body ul { margin: var(--s-1) 0 0; padding-inline-start: var(--s-5); }
.banner-actions { display: flex; gap: var(--s-2); flex: none; align-items: center; }
.banner.warn, .banner.tone-warn { background: var(--warn-subtle); border-color: var(--warn-border); }
.banner.err, .banner.tone-danger { background: var(--danger-subtle); border-color: var(--danger-border); }
.banner.err > .ico, .banner.tone-danger > .ico, .banner.err b, .banner.tone-danger b { color: var(--danger); }
.banner.ok, .banner.tone-ok { background: var(--ok-subtle); border-color: var(--ok-border); }
.banner.ok > .ico, .banner.tone-ok > .ico { color: var(--ok); }
.banner.info, .banner.tone-info { background: var(--info-subtle); border-color: var(--info-border); }
.banner.info > .ico, .banner.tone-info > .ico { color: var(--info); }
.banner.tone-neutral { background: var(--surface-2); border-color: var(--border-strong); }
.banner.tone-neutral > .ico { color: var(--text-muted); }
/* The tone's own colour on the edge, so the tone reads before the text. */
.banner.warn, .banner.tone-warn, .banner:not([class*="tone-"]):not(.err):not(.ok):not(.info) { border-inline-start-color: var(--warn); }
.banner.err, .banner.tone-danger { border-inline-start-color: var(--danger); }
.banner.ok, .banner.tone-ok { border-inline-start-color: var(--ok); }
.banner.info, .banner.tone-info { border-inline-start-color: var(--info); }
.banner.tone-neutral { border-inline-start-color: var(--text-subtle); }

/* ── stat: a headline figure ──────────────────────────────────────────────
   `.card.stat` with .label / .value / .note inside is how 149 blocks are
   built by hand; the stat strip (stats.js) draws `.stat-tile`s with the
   same anatomy. The label says what the figure is and carries the
   currency; the value is tabular so figures in a row line up. */
.stat { padding: var(--s-3) var(--s-4); min-width: 0; }
.stat .label, .stat-label {
  font-size: var(--fs-xs); line-height: var(--lh-xs); font-weight: 600; letter-spacing: .04em;
  text-transform: uppercase; color: var(--text-muted);
}
.stat .value, .stat-value {
  margin-top: var(--s-1); font-size: var(--fs-2xl); line-height: var(--lh-2xl); font-weight: 600;
  font-variant-numeric: tabular-nums lining-nums; overflow-wrap: anywhere; color: var(--text);
}
.stat .note, .stat-note { margin-top: var(--s-half); font-size: var(--fs-sm); line-height: var(--lh-sm); color: var(--text-subtle); }
.stat-label, .stat-value, .stat-note { display: block; }
.stat.clickable { cursor: pointer; }
.stat.clickable:hover { border-color: var(--border-strong); }

/* The stat strip: a row of tiles whose column count keeps rows even (no
   4 + 2 holes). stats.js sets --n (tile count) and --cols (columns at full
   width); the strip is a size container, so it re-flows by its own width,
   not the window's - the same strip works in a page and in a drawer. */
.stats { container-type: inline-size; min-width: 0; }
.stats-grid {
  display: grid; gap: var(--s-3);
  grid-template-columns: repeat(var(--cols, 4), minmax(0, 1fr));
}
@container (max-width: 1080px) { .stats-grid { grid-template-columns: repeat(var(--cols-md, var(--cols, 4)), minmax(0, 1fr)); } }
@container (max-width: 720px)  { .stats-grid { grid-template-columns: repeat(var(--cols-sm, 2), minmax(0, 1fr)); } }
@container (max-width: 380px)  { .stats-grid { grid-template-columns: repeat(var(--cols-xs, 2), minmax(0, 1fr)); gap: var(--s-2); } }

.stat-tile {
  display: block; text-align: start; min-width: 0; padding: var(--s-3) var(--s-4);
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-lg);
  box-shadow: var(--shadow-1); color: var(--text); font: inherit;
  container-type: inline-size;
}
a.stat-tile { text-decoration: none; }
a.stat-tile:hover, button.stat-tile:hover { border-color: var(--border-strong); background: var(--surface-2); }
button.stat-tile { cursor: pointer; width: 100%; }
button.stat-tile[aria-pressed="true"] {
  border-color: var(--accent); background: var(--accent-subtle);
  box-shadow: inset 0 0 0 1px var(--accent);
}
button.stat-tile[aria-pressed="true"] .stat-label { color: var(--accent); }
/* The base layer's focus ring is a box-shadow, and a component that sets its
   own box-shadow (the tile's elevation above) wins over it whatever the
   specificity, because this layer comes later. So every focusable thing with
   a shadow of its own repeats the ring here; the pressed tile keeps its inset
   accent line under the ring. */
a.stat-tile:focus-visible, button.stat-tile:focus-visible,
a.card:focus-visible, .card[tabindex]:focus-visible { box-shadow: var(--focus); }
button.stat-tile[aria-pressed="true"]:focus-visible { box-shadow: inset 0 0 0 1px var(--accent), var(--focus); }
/* A figure shrinks to fit its tile rather than clip: stats.js sets --len
   (characters in the figure), and a tabular digit is about .6em wide. A
   developer's cash balance runs to thirteen digits, and "1,161,186,67…"
   reads as a different amount. */
.stat-tile .stat-value {
  font-size: min(var(--fs-2xl), calc(100cqi / (var(--len, 8) * .6)));
  line-height: var(--lh-2xl); white-space: nowrap; overflow-wrap: normal;
}
.stat-value .unit { font-size: var(--fs-sm); font-weight: 500; color: var(--text-muted); margin-inline-start: var(--s-1); }
.stat-tile.tone-danger .stat-value, .stat.tone-danger .value { color: var(--danger); }
.stat-tile.tone-warn .stat-value, .stat.tone-warn .value { color: var(--warn); }
.stat-tile.tone-ok .stat-value, .stat.tone-ok .value { color: var(--ok); }

/* ── key-value ────────────────────────────────────────────────────────────
   `dl.kv` with dt/dd straight inside is the hand-built spelling (28
   screens): one label column, one value column. kv.js draws `.kv-grid`:
   pairs in N columns, labels a fixed width, capped at the detail width,
   one column on a phone. */
.kv { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--s-1h) var(--s-4); align-items: baseline; }
.kv dt { color: var(--text-muted); font-size: var(--fs-sm); line-height: var(--lh-sm); }
.kv dd { margin: 0; font-weight: 500; min-width: 0; overflow-wrap: anywhere; }

.kv-grid {
  display: grid; gap: var(--s-2) var(--s-6); max-width: var(--detail-max); margin: 0;
  grid-template-columns: repeat(var(--kv-cols, 2), minmax(0, 1fr));
}
.kv-item {
  display: grid; grid-template-columns: var(--kv-label, var(--kv-label-w)) minmax(0, 1fr);
  gap: var(--s-3); align-items: baseline; min-width: 0;
  padding-block: var(--s-1); border-bottom: 1px solid var(--border);
}
.kv-item dt { color: var(--text-muted); font-size: var(--fs-sm); line-height: var(--lh-sm); }
.kv-item dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }
.kv-item dd.empty-val { color: var(--text-subtle); }
.kv-item.span-all { grid-column: 1 / -1; }
.kv-item.span-2 { grid-column: span 2; }
@media (max-width: 860px) { .kv-grid { grid-template-columns: minmax(0, 1fr); } .kv-item.span-2 { grid-column: auto; } }
@media (max-width: 600px) {
  .kv-item { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .kv { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .kv dd { margin-bottom: var(--s-2); }
}

/* ── tabs (APG tabs pattern) ──────────────────────────────────────────── */
.tabs { min-width: 0; }
.tabs-list {
  display: flex; gap: var(--s-1); border-bottom: 1px solid var(--border);
  overflow-x: auto; scrollbar-width: none; min-width: 0;
}
.tabs-list::-webkit-scrollbar { display: none; }
.tab {
  display: inline-flex; align-items: center; gap: var(--s-1h); flex: none;
  height: 36px; padding: 0 var(--s-3); margin-bottom: -1px;
  border: none; border-bottom: 2px solid transparent; background: none;
  color: var(--text-muted); font: inherit; font-size: var(--fs-md); font-weight: 500; cursor: pointer;
  border-radius: var(--r-md) var(--r-md) 0 0;
  transition: color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.tab:hover { color: var(--text); background: var(--surface-2); }
.tab[aria-selected="true"] { color: var(--accent); border-bottom-color: var(--accent); font-weight: 600; }
.tab-panel { padding-top: var(--s-4); min-width: 0; }
.tab-panel:focus-visible { box-shadow: var(--focus); }

/* ── timeline ─────────────────────────────────────────────────────────── */
.timeline { list-style: none; margin: 0; padding: 0; position: relative; }
.tl-item { position: relative; display: grid; grid-template-columns: 16px minmax(0, 1fr); gap: var(--s-3); padding-bottom: var(--s-4); }
.tl-item:last-child { padding-bottom: 0; }
/* The rail joins one dot to the next; the last event has no line below it. */
.tl-item:not(:last-child)::before {
  content: ""; position: absolute; top: 14px; bottom: 0; inset-inline-start: 7px;
  width: 2px; background: var(--border);
}
.tl-dot {
  width: 12px; height: 12px; margin: 4px 2px 0; border-radius: var(--r-pill);
  background: var(--surface); border: 2px solid var(--neutral);
}
.tl-dot.tone-ok { border-color: var(--ok); background: var(--ok-subtle); }
.tl-dot.tone-warn { border-color: var(--warn); background: var(--warn-subtle); }
.tl-dot.tone-danger { border-color: var(--danger); background: var(--danger-subtle); }
.tl-dot.tone-info { border-color: var(--info); background: var(--info-subtle); }
.tl-what { font-weight: 600; }
.tl-meta { font-size: var(--fs-sm); line-height: var(--lh-sm); color: var(--text-muted); }
.tl-note { margin-top: var(--s-1); font-size: var(--fs-sm); line-height: var(--lh-sm); color: var(--text-muted); max-width: var(--measure); }

/* ── modal and drawer ─────────────────────────────────────────────────── */
.scrim {
  position: fixed; inset: 0; z-index: var(--z-modal); background: var(--scrim);
  display: flex; justify-content: center; align-items: flex-start;
  padding: 10vh var(--s-4) var(--s-4); overflow-y: auto;
  animation: fade var(--dur-slow) var(--ease);
}
.modal {
  --modal-w: 560px;
  width: min(var(--modal-w), 100%); max-height: calc(100vh - 12vh - var(--s-4));
  display: flex; flex-direction: column;
  background: var(--surface); color: var(--text); border-radius: var(--r-xl);
  border: 1px solid var(--border-strong); box-shadow: var(--shadow-3); overflow: hidden;
  animation: rise var(--dur-slow) var(--ease);
}
.modal.size-sm { --modal-w: 400px; }
.modal.size-md { --modal-w: 560px; }
.modal.size-lg { --modal-w: 760px; }
.modal.size-xl { --modal-w: 980px; }
.modal-head {
  display: flex; align-items: center; gap: var(--s-2); flex: none;
  padding: var(--s-3) var(--s-3) var(--s-3) var(--s-5); border-bottom: 1px solid var(--border);
}
.modal-title { flex: 1; min-width: 0; font-size: var(--fs-lg); line-height: var(--lh-lg); font-weight: 600; overflow-wrap: anywhere; }
.modal-body { padding: var(--s-4) var(--s-5); overflow-y: auto; flex: 1 1 auto; min-height: 0; }
.modal-errors:empty { display: none; }
.modal-errors { padding: 0 var(--s-5); }
.modal-errors .banner { margin: 0 0 var(--s-3); }
.modal-foot {
  display: flex; align-items: center; gap: var(--s-2); justify-content: flex-end; flex-wrap: wrap; flex: none;
  padding: var(--s-3) var(--s-5); border-top: 1px solid var(--border); background: var(--surface-2);
}
.modal-foot .hint { margin-inline-end: auto; font-size: var(--fs-xs); color: var(--text-subtle); }
.modal-foot .hint kbd { font-size: 10px; }
@media (max-width: 600px) {
  /* A phone gets a sheet from the bottom edge, full width. */
  .scrim { padding: var(--s-4) 0 0; align-items: flex-end; }
  .modal { max-height: calc(100vh - var(--s-4)); border-radius: var(--r-xl) var(--r-xl) 0 0; }
  .modal-foot .hint { display: none; }
}

.scrim.drawer-scrim { padding: 0; justify-content: flex-end; align-items: stretch; z-index: var(--z-drawer); }
.drawer {
  --drawer-w: 480px;
  width: min(var(--drawer-w), 100%); height: 100%; display: flex; flex-direction: column;
  background: var(--surface); border-inline-start: 1px solid var(--border-strong); box-shadow: var(--shadow-3);
  animation: slide-in var(--dur-slow) var(--ease);
}
.drawer .modal-body { flex: 1; }

@keyframes fade { from { opacity: 0; } }
@keyframes rise { from { opacity: 0; transform: translateY(6px); } }
@keyframes slide-in { from { transform: translateX(24px); opacity: 0; } }

/* ── menu and popover ─────────────────────────────────────────────────── */
.menu, .popover {
  position: fixed; z-index: var(--z-dropdown); min-width: 180px; max-width: min(360px, calc(100vw - 16px));
  background: var(--surface); color: var(--text); border: 1px solid var(--border-strong);
  border-radius: var(--r-lg); box-shadow: var(--shadow-2);
  animation: fade var(--dur-fast) var(--ease);
}
.menu { padding: var(--s-1); max-height: 60vh; overflow-y: auto; }
.menu-item {
  display: flex; align-items: center; gap: var(--s-2); width: 100%; min-height: 30px;
  padding: var(--s-1) var(--s-2); border: none; border-radius: var(--r-sm); background: none;
  color: var(--text); font: inherit; font-size: var(--fs-md); text-align: start; cursor: pointer; text-decoration: none;
}
.menu-item:hover, .menu-item:focus-visible { background: var(--row-hover); text-decoration: none; box-shadow: none; }
.menu-item:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.menu-item .ico { color: var(--text-muted); }
.menu-item .menu-hint { margin-inline-start: auto; padding-inline-start: var(--s-4); font-size: var(--fs-xs); color: var(--text-subtle); }
.menu-item.danger, .menu-item.danger .ico { color: var(--danger); }
.menu-item[aria-disabled="true"] { color: var(--text-disabled); cursor: not-allowed; }
.menu-item[aria-disabled="true"] .ico { color: var(--text-disabled); }
.menu-sep { height: 1px; margin: var(--s-1) calc(-1 * var(--s-1)); background: var(--border); }

.popover { z-index: var(--z-popover); padding: var(--s-3) var(--s-4); font-size: var(--fs-sm); line-height: var(--lh-sm); max-width: min(340px, calc(100vw - 16px)); }
/* A menu or popover opened from inside a modal or drawer (ui.js floating()
   marks it): above the scrim, or it is painted under it and cannot be seen. */
.menu.over-dialog, .popover.over-dialog { z-index: calc(var(--z-modal) + 1); }

/* ── toasts ───────────────────────────────────────────────────────────── */
.toasts {
  position: fixed; inset-inline-end: var(--s-4); bottom: var(--s-4); z-index: var(--z-toast);
  display: flex; flex-direction: column; gap: var(--s-2); max-width: calc(100vw - 2 * var(--s-4));
}
.toast {
  display: flex; align-items: flex-start; gap: var(--s-2);
  width: 360px; max-width: 100%; padding: var(--s-2) var(--s-2) var(--s-2) var(--s-3);
  background: var(--surface); color: var(--text);
  border: 1px solid var(--border-strong); border-inline-start: 3px solid var(--accent);
  border-radius: var(--r-lg); box-shadow: var(--shadow-2);
  animation: rise var(--dur-slow) var(--ease);
  transition: opacity var(--dur-slow) var(--ease);
}
.toast-body { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.toast b { display: block; font-weight: 600; }
.toast span { color: var(--text-muted); font-size: var(--fs-sm); line-height: var(--lh-sm); }
.toast .btn { flex: none; }
.toast.err { border-inline-start-color: var(--danger); }
.toast.ok  { border-inline-start-color: var(--ok); }
.toast.leaving { opacity: 0; }

/* ── meter: certified against revised contract value ─────────────────── */
.meter { height: 7px; border-radius: var(--r-sm); background: var(--surface-3); overflow: hidden; }
.meter-fill { height: 100%; background: var(--accent); transition: width var(--dur-slow) var(--ease); }

/* ── attachments: the evidence behind a document ────────────────────────── */
.dropzone {
  display: flex; align-items: center; justify-content: center; gap: var(--s-2);
  margin-top: var(--s-3); padding: var(--s-4); border: 1px dashed var(--border-input);
  border-radius: var(--r-md); color: var(--text-muted); font-size: var(--fs-sm); cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.dropzone:hover, .dropzone.over { border-color: var(--accent); background: var(--accent-subtle); }

/* ── posting preview (components/posting.js) ──────────────────────────── */
.post-facts { display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-6); margin-bottom: var(--s-4); }
.post-fact { display: flex; flex-direction: column; gap: var(--s-half); min-width: 0; }
.post-fact > span:first-child { font-size: var(--fs-xs); line-height: var(--lh-xs); font-weight: 600; letter-spacing: .04em; text-transform: uppercase; color: var(--text-muted); }
.post-lines { border: 1px solid var(--border); border-radius: var(--r-md); overflow: auto; }
.post-lines table.tbl { margin: 0; }
.post-lines .acct-name { color: var(--text-muted); }
.post-lines .acct-dims { display: block; font-size: var(--fs-xs); color: var(--text-subtle); }
.post-check { display: flex; align-items: center; gap: var(--s-2); margin-top: var(--s-3); font-size: var(--fs-sm); color: var(--text-muted); }

/* ── a customer-facing document (components/print.js) ──────────────────
   The same page on screen (a preview with a Print button) and on paper:
   letterhead, parties, lines, amount in words, pay-to account, signatures. */
.print-doc {
  max-width: 820px; margin: 0 auto; padding: var(--s-8);
  background: var(--surface); color: var(--text); border: 1px solid var(--border);
  border-radius: var(--r-lg); box-shadow: var(--shadow-1);
}
.pd-letterhead { display: flex; justify-content: space-between; gap: var(--s-8); flex-wrap: wrap; padding-bottom: var(--s-4); border-bottom: 2px solid var(--text); }
.pd-letterhead .pd-entity b { display: block; font-size: var(--fs-lg); }
.pd-letterhead .pd-docmeta { text-align: end; }
.pd-small { font-size: var(--fs-sm); line-height: var(--lh-sm); color: var(--text-muted); }
.pd-title { margin: var(--s-6) 0 var(--s-4); font-size: var(--fs-xl); font-weight: 700; letter-spacing: .04em; text-transform: uppercase; }
.pd-parties { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--s-4); margin-bottom: var(--s-5); }
.pd-box { border: 1px solid var(--border-strong); border-radius: var(--r-sm); padding: var(--s-3); break-inside: avoid; }
.pd-box h3 { font-size: var(--fs-xs); line-height: var(--lh-xs); text-transform: uppercase; letter-spacing: .04em; color: var(--text-muted); margin-bottom: var(--s-1); }
.pd-totals { --kv-cols: 1; margin-top: var(--s-3); margin-inline-start: auto; width: min(360px, 100%); gap: 0; }
.pd-totals .kv-item { grid-template-columns: minmax(0, 1fr) auto; }
.pd-totals .kv-item dd { text-align: end; }
.pd-totals .kv-item.grand { border-bottom: 2px solid var(--text); font-weight: 700; }
.pd-words { margin-top: var(--s-3); font-style: italic; }
.pd-payto { margin-top: var(--s-5); border: 1px solid var(--text); border-radius: var(--r-sm); padding: var(--s-3); break-inside: avoid; }
.pd-sign { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-10); margin-top: var(--s-10); break-inside: avoid; }
.pd-sign div { border-top: 1px solid var(--text); padding-top: var(--s-1); font-size: var(--fs-sm); color: var(--text-muted); }
.pd-foot { margin-top: var(--s-6); font-size: var(--fs-xs); color: var(--text-muted); }

} /* @layer components */

@media (max-width: 860px) {
  /* On a desktop the page head keeps one line (the title block takes the
     room it needs and the actions sit to its right); wrapping it there
     pushed filters and the primary button onto rows of their own. On a
     phone that line is wider than the screen, so the head wraps. */
  @layer components {
    .page-head { flex-wrap: wrap; }
  }
}
@media (max-width: 600px) {
  @layer components {
    /* Beyond the primary, a phone's actions live in the ⋯ menu. */
    .ph-actions > .ph-secondary { display: none; }
    .ph-actions .ph-more-phone { display: inline-flex; }
    /* Title, then subtitle and meta, then the actions: the reading order. */
    .page-head.ph { display: flex; flex-direction: column; align-items: stretch; }
    .ph-main { display: contents; }
    /* flex: none - in a column the 320px basis of the desktop row would be a height. */
    .ph-title { order: 1; flex: none; }
    .ph-sub, .ph-meta { order: 2; }
    .ph-actions { order: 3; width: 100%; justify-content: flex-start; margin-top: var(--s-3); }
    /* A card head's title and its buttons wrap onto two lines rather than
       squeezing the buttons until their labels run into each other. */
    .card-head, .card-head > .row { flex-wrap: wrap; }
    .card-head .btn { flex-shrink: 0; }
    .toasts { inset-inline: var(--s-2); bottom: var(--s-2); }
    .toast { width: auto; }
  }
}
