/* Coverage Ledger components. Shared controls and primitives have one owner:
   this file. Feature sheets may lay them out or retone a complete dark-room
   composition, but do not redefine their internals. */

/* ---- LAYOUT — the ONLY consumers of the --space scale ---- */
.cl-stack, .cl-cluster, .cl-split, .cl-grid { --cl-gap: var(--space-3); }
[data-gap="0"] { --cl-gap: var(--space-0); }
[data-gap="1"] { --cl-gap: var(--space-1); }
[data-gap="2"] { --cl-gap: var(--space-2); }
[data-gap="3"] { --cl-gap: var(--space-3); }
[data-gap="4"] { --cl-gap: var(--space-4); }
[data-gap="5"] { --cl-gap: var(--space-5); }
[data-gap="6"] { --cl-gap: var(--space-6); }
[data-gap="7"] { --cl-gap: var(--space-7); }
.cl-stack { display: flex; flex-direction: column; gap: var(--cl-gap); }
.cl-cluster { display: flex; flex-wrap: wrap; align-items: center; gap: var(--cl-gap); }
.cl-split { display: flex; align-items: center; justify-content: space-between; gap: var(--cl-gap); }
.cl-split[data-align="start"] { align-items: flex-start; }
.cl-grid { display: grid; gap: var(--cl-gap); grid-template-columns: repeat(2, minmax(0, 1fr)); }
.cl-grid[data-cols="1"] { grid-template-columns: 1fr; }
.cl-grid[data-cols="3"] { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.cl-grid[data-cols="4"] { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.cl-center { width: 100%; max-width: var(--page-max); margin-inline: auto; padding-inline: var(--space-3); }
.cl-center[data-measure] { max-width: var(--measure); }

/* ---- TYPE — the ONLY emitters of font-size/family/weight ---- */
.cl-text { font-family: var(--serif); font-size: var(--fs-body); line-height: 1.6; color: var(--body); margin: 0; }
.cl-text[data-tone="muted"] { color: var(--muted); }
.cl-text[data-tone="faint"] { color: var(--faint); }
.cl-text[data-size="lead"] { font-size: var(--fs-lead); }
.cl-text[data-size="meta"] { font-size: var(--fs-micro); }
.cl-heading { font-family: var(--serif); color: var(--ink); font-weight: var(--fw-bold); line-height: 1.12; text-wrap: balance; margin: 0; }
.cl-heading[data-level="display"] { font-size: var(--fs-display); }
.cl-heading[data-level="h2"] { font-size: var(--fs-h2); }
.cl-heading[data-level="h3"] { font-size: var(--fs-h3); }
.cl-label, .cl-eyebrow { font-family: var(--brand); text-transform: uppercase; letter-spacing: 0.08em; font-size: var(--fs-slug); font-weight: 400; color: var(--muted); margin: 0; }
.cl-eyebrow[data-rule] { align-items: center; display: flex; gap: 14px; }
.cl-eyebrow[data-rule]::before { background: var(--gold-display); content: ""; flex: 0 0 44px; height: 2px; }

/* ---- SURFACE — every bounded region (sheet/tile/bare/room + disposition wash) ---- */
.cl-surface { background: var(--surface); color: var(--body); border-radius: var(--radius); padding: var(--space-4); }
.cl-surface[data-pad="0"] { padding: 0; }
.cl-surface[data-pad="2"] { padding: var(--space-2); }
.cl-surface[data-pad="3"] { padding: var(--space-3); }
.cl-surface[data-pad="5"] { padding: var(--space-5); }
.cl-surface[data-edge="hairline"] { border: 1px solid var(--border); }
.cl-surface[data-edge="rule"] { border: 1px solid var(--border-strong); }
.cl-surface[data-tone="bare"] { background: transparent; padding: 0; }
.cl-surface[data-tone="tile"] { border: 1px solid var(--border); }
.cl-surface[data-room="screen"] { background: var(--screen); color: var(--on-screen); }
.cl-surface[data-tone="ink"] { background: var(--ink); color: var(--bg); }
.cl-surface[data-tone="ink"] .cl-eyebrow { color: var(--gold-soft); }
.cl-surface[data-edge="heavy"] { border: 3px solid var(--border-strong); } /* master-sheet frame */
.cl-surface[data-accent] { border-left: 5px solid var(--cl-accent, var(--border-strong)); } /* treatment rule */
/* data-grain — the shared fractalNoise overlay (replaces hand-copied dark-room ::before). */
.cl-surface[data-grain] { position: relative; }
.cl-surface[data-grain]::before { content: ""; position: absolute; inset: 0; border-radius: inherit; background-image: var(--grain); opacity: 0.055; pointer-events: none; }
.cl-surface[data-wash="advance"] { background: var(--disp-advance-soft); }
.cl-surface[data-wash="conditions"] { background: var(--disp-conditions-soft); }
.cl-surface[data-wash="hold"] { background: var(--disp-hold-soft); }
.cl-surface[data-lift] { transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease); }
.cl-surface[data-lift]:hover { transform: translate(-2px, -2px); box-shadow: var(--offset-sm); } /* ink offset, no blur */

/* ---- SECTION — a FLAT region of the one document (never a card) ----
   The masthead/verdict/memo/plan/support blocks are all the SAME thing: a flat
   region of one continuous sheet, set off by its heading rule, NOT a floating
   framed box. So this atom carries NO background, NO border, NO radius, NO
   shadow — depth on paper is the heading's ink rule, never a frame. Its only job
   is the anchored-jump scroll offset (clears the stacked sticky bars) + a
   heading slot that rules off below itself.
     - .cl-section      : the flat region (the box-format families merge here)
     - .cl-section-head : the heading row, ruled off by a heavy ink bottom border */
.cl-section { background: transparent; border: 0; border-radius: 0; box-shadow: none; margin: 0; padding: 0; scroll-margin-top: var(--section-anchor, 132px); }
.cl-section-head { display: flex; flex-wrap: wrap; align-items: end; justify-content: space-between; gap: var(--space-1) var(--space-3); border-bottom: 2px solid var(--border-strong); margin: 0 0 var(--space-4); padding-bottom: var(--space-2); }
.cl-section-head[data-rule="hairline"] { border-bottom-color: var(--border); border-bottom-width: 1px; }
.cl-section-head[data-rule="heavy"] { border-bottom-width: 4px; }

/* ---- BUTTON — every committed action, one build system, own busy state ---- */
.cl-btn { display: inline-flex; align-items: center; justify-content: center; gap: var(--space-1); font-family: var(--brand); text-transform: uppercase; letter-spacing: 0.06em; font-weight: 700; font-size: var(--fs-slug); min-height: var(--tap-min); padding: var(--space-2) var(--space-4); border: 1px solid var(--border-strong); border-radius: var(--radius); background: var(--surface); color: var(--ink); cursor: pointer; text-decoration: none; transition: transform var(--dur) var(--ease); }
.cl-btn[data-variant="primary"] { background: var(--ink); color: var(--surface); }
.cl-btn[data-variant="secondary"] { background: var(--surface); color: var(--ink); }
.cl-btn[data-variant="ghost"] { border-color: transparent; background: transparent; }
.cl-btn[data-variant="danger"] { color: var(--red); border-color: var(--red); background: transparent; }
.cl-btn[data-size="sm"] { min-height: 36px; padding: var(--space-1) var(--space-3); }
.cl-btn[data-full] { width: 100%; }
.cl-btn:active { transform: translateY(1px); }
.cl-btn:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
.cl-btn[disabled], .cl-btn[aria-disabled="true"] { opacity: 0.5; cursor: not-allowed; }
.cl-btn[data-busy] { cursor: progress; color: transparent; position: relative; }
.cl-btn[data-busy]::after { content: ""; position: absolute; width: 1em; height: 1em; border: 2px solid currentcolor; border-top-color: transparent; border-radius: 50%; color: var(--ink); animation: cl-spin 0.7s linear infinite; }
.cl-btn[data-variant="primary"][data-busy]::after { color: var(--surface); }

@media (max-width: 560px) {
  .cl-grid,
  .cl-grid[data-cols] { grid-template-columns: 1fr; }
  .cl-btn[data-size="sm"] { min-height: var(--tap-min); }
  .cl-dialog { padding: var(--space-2); }
  .cl-dialog-panel { padding: var(--space-3); }
}

/* ---- STATUS — every non-verdict readiness/progress signal (one source) ---- */
.cl-status { display: inline-flex; align-items: center; gap: var(--space-0); font-family: var(--brand); text-transform: uppercase; letter-spacing: 0.06em; font-size: var(--fs-micro); color: var(--muted); }
.cl-status::before { content: ""; width: 0.5em; height: 0.5em; border-radius: 50%; background: currentcolor; }
.cl-status[data-state="advance"] { color: var(--disp-advance); }
.cl-status[data-state="conditions"] { color: var(--disp-conditions); }
.cl-status[data-state="hold"] { color: var(--disp-hold); }
.cl-status[data-state="locked"] { color: var(--locked); }
.cl-status[data-state="running"] { color: var(--read-running); }
.cl-status[data-state="skipped"] { color: var(--faint); text-decoration: line-through; }
.cl-status[data-state="failed"] { color: var(--red); }
/* room screen — glowing dark-room readout */
.cl-status[data-room="screen"][data-state="advance"], .cl-status[data-room="screen"][data-state="conditions"], .cl-status[data-room="screen"][data-state="hold"] { text-shadow: 0 0 18px currentcolor; }
/* shape square — a small square tick instead of the dot */
.cl-status[data-shape="square"]::before { border-radius: 0; }
/* fill — a soft pill keyed to the disposition */
.cl-status[data-fill] { padding: 2px 9px; border-radius: var(--radius-stamp); }
.cl-status[data-fill][data-state="advance"] { background: var(--disp-advance-soft); }
.cl-status[data-fill][data-state="conditions"] { background: var(--disp-conditions-soft); }
.cl-status[data-fill][data-state="hold"] { background: var(--disp-hold-soft); }

/* ---- METER — a determinate progress bar (track + fill keyed to --cl-value) ---- */
.cl-meter { display: block; width: 100%; height: var(--space-1); background: var(--border); border-radius: var(--radius); overflow: hidden; }
.cl-meter > .cl-meter-fill { display: block; height: 100%; width: var(--cl-value, 0%); background: var(--ink); transition: width var(--dur) var(--ease); }
.cl-meter[data-room="screen"] { background: var(--screen-hairline); }
.cl-meter[data-room="screen"] > .cl-meter-fill { background: var(--gold-soft); }

/* ---- STAMP — the signature: the verdict landing on the page ----
   Real stamp weight: a DOUBLE ink rule (3px border + a second ring laid via
   box-shadow at 1px gap), bolder Courier letterforms, a stronger warm skew, and
   a hair of letterpress (double-stroke text-shadow). Warm ink, hard-cornered. */
/* The verdict stamp: ONE border line (no double-ring box-shadow), larger text,
   NOT bolded (regular weight, no fake-bold text-shadow) — a clean rubber stamp. */
.cl-stamp { display: inline-flex; align-self: flex-start; width: fit-content; max-width: 100%; align-items: center; padding: var(--space-1) var(--space-3); border: 3px solid currentcolor; border-radius: var(--radius-stamp); font-family: var(--brand); font-size: 1.5rem; font-weight: 400; text-transform: uppercase; letter-spacing: 0.12em; white-space: pre-line; transform: rotate(-3.5deg); color: var(--ink); }
.cl-stamp[data-disposition="advance"] { color: var(--disp-advance); }
.cl-stamp[data-disposition="conditions"] { color: var(--disp-conditions); }
.cl-stamp[data-disposition="hold"] { color: var(--disp-hold); }
.cl-stamp[data-settle] { animation: cl-stamp-settle var(--dur-stamp) var(--ease) both; }
/* On narrow screens the double rule + skew clips the longest label
   ("ADVANCE WITH CONDITIONS") against the card edge. Stand the stamp upright,
   let it span the row as a padded block, and guarantee breathing margin. */
@media (max-width: 32rem) {
  .cl-stamp { display: flex; width: 100%; justify-content: center; text-align: center; transform: none; margin: var(--space-2) 0; padding: var(--space-2) var(--space-3); letter-spacing: 0.1em; }
  /* the settle still lands, but upright — so the gavel-drop doesn't reintroduce
     the skew that would clip the longest label against the card edge */
  .cl-stamp[data-settle] { animation-name: cl-stamp-settle-flat; }
}

/* ---- FIELD — one form-control primitive (text/textarea/file) ---- */
.cl-field { display: flex; flex-direction: column; gap: var(--space-1); }
.cl-field > .cl-label { color: var(--muted); }
.cl-field-control { font-family: var(--serif); font-size: var(--fs-body); color: var(--ink); background: var(--surface); border: 1px solid var(--border-strong); border-radius: var(--radius); padding: var(--space-2) var(--space-3); min-height: var(--tap-min); width: 100%; }
.cl-field-control:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
.cl-field-control::placeholder { color: var(--faint); opacity: 1; }
.cl-field-control { text-overflow: ellipsis; }
textarea.cl-field-control { line-height: 1.55; min-height: 128px; resize: vertical; }
.cl-field[data-invalid] .cl-field-control { border-color: var(--red); }
.cl-field-help { font-family: var(--brand); font-size: var(--fs-micro); color: var(--faint); }
.cl-field[data-invalid] .cl-field-help { color: var(--red); }

/* ---- DIALOG — the single overlay engine (scrim + panel; room paper|dark) ---- */
.cl-dialog { position: fixed; inset: 0; z-index: var(--z-dialog); display: grid; place-items: center; padding: var(--space-4); background: var(--scrim); }
.cl-dialog[hidden] { display: none; }
/* Optional full-bleed backdrop layer: lets a modal carry a dedicated dismiss
   target (data-*-dismiss) behind the panel instead of relying on the scrim
   element itself. Sits under the panel; the panel stacks above via position. */
.cl-dialog-scrim { position: absolute; inset: 0; z-index: 0; }
.cl-dialog-panel { position: relative; z-index: 1; background: var(--surface); color: var(--body); border: 1px solid var(--border-strong); border-radius: var(--radius); padding: var(--space-5); max-width: 32rem; width: 100%; max-height: calc(100vh - 2 * var(--space-4)); overflow-y: auto; }
.cl-dialog[data-room="dark"] .cl-dialog-panel { background: var(--screen); color: var(--on-screen); border-color: var(--screen-hairline); }
/* In-panel dismiss affordance (the × close button), pinned top-right. */
.cl-dialog-dismiss { position: absolute; top: var(--space-2); right: var(--space-2); z-index: 2; display: grid; place-items: center; width: var(--tap-min); height: var(--tap-min); border: 0; background: transparent; color: var(--muted); font-size: 1.5rem; line-height: 1; cursor: pointer; border-radius: var(--radius); }
.cl-dialog-dismiss:hover { color: var(--ink); }
.cl-dialog[data-room="dark"] .cl-dialog-dismiss { color: var(--on-screen); }

/* ---- DISCLOSURE — the one accordion (eyebrow+title+detail) ---- */
.cl-disclosure { border-top: 1px solid var(--border); }
.cl-disclosure > summary { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); padding: var(--space-2) 0; cursor: pointer; list-style: none; min-height: var(--tap-min); }
.cl-disclosure > summary::-webkit-details-marker { display: none; }
.cl-disclosure > summary::after { content: "+"; font-family: var(--brand); color: var(--muted); }
.cl-disclosure[open] > summary::after { content: "\2013"; } /* en dash */
.cl-disclosure > summary:focus-visible { outline: 2px solid var(--gold-soft); outline-offset: 2px; }
.cl-disclosure-body { padding-bottom: var(--space-3); }
/* FLAT (non-collapsible) disclosure: the head keeps the summary's row layout but has
   NO caret, NO pointer, and the body is always shown. Used for every read section
   except the gate accordions — nothing in the read collapses except the gates. */
.cl-disclosure-flat > .cl-disclosure-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); padding: var(--space-2) 0; }

/* ---- TABS — one strip/switcher/nav that ALWAYS shows an active marker ---- */
.cl-tabs { display: flex; gap: var(--space-3); border-bottom: 1px solid var(--border); }
.cl-tabs[data-kind="nav"] { flex-direction: column; gap: var(--space-1); border-bottom: 0; }
.cl-tabs[data-kind="ledger"] { gap: 0; }
.cl-tabs[data-kind="ledger"] > .cl-tab { flex: 1; text-align: center; padding: var(--space-2) var(--space-3); }
.cl-tab { font-family: var(--brand); text-transform: uppercase; letter-spacing: 0.06em; font-size: var(--fs-micro); color: var(--muted); background: none; border: 0; padding: var(--space-2) 0; cursor: pointer; min-height: var(--tap-min); border-bottom: 2px solid transparent; }
.cl-tab[aria-current="true"], .cl-tab[aria-selected="true"] { color: var(--ink); border-bottom-color: var(--gold); }
.cl-tab:focus-visible { outline: 2px solid var(--gold-soft); outline-offset: 2px; }

/* ---- LIST — every ledger/bulleted/data row (label-left / value-right) ---- */
.cl-list { display: flex; flex-direction: column; margin: 0; padding: 0; list-style: none; }
.cl-row { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-3); padding: var(--space-2) 0; border-top: 1px solid var(--border); }
.cl-row:first-child { border-top: 0; }
.cl-row > .cl-label { color: var(--muted); }
.cl-row-value { font-family: var(--serif); color: var(--ink); text-align: right; }
.cl-row[data-state="advance"] { background: var(--disp-advance-soft); }
.cl-row[data-state="conditions"] { background: var(--disp-conditions-soft); }
.cl-row[data-state="hold"] { background: var(--disp-hold-soft); }

/* ---- TABLE — markdown receipts, pacing, scene notes ---- */
.cl-table { width: 100%; border-collapse: collapse; display: block; overflow-x: auto; margin: var(--space-3) 0; color: var(--body); }
.cl-table thead { border-bottom: 2px solid var(--border-strong); }
.cl-table th {
  color: var(--ink);
  font-family: var(--brand);
  font-size: var(--fs-slug);
  font-weight: 700;
  letter-spacing: 0.06em;
  padding: var(--space-2) var(--space-3) var(--space-2) 0;
  text-align: left;
  text-transform: uppercase;
}
.cl-table td {
  border-bottom: 1px solid var(--border);
  font-family: var(--serif);
  font-size: var(--fs-body);
  line-height: 1.5;
  min-width: 10rem;
  padding: var(--space-2) var(--space-3) var(--space-2) 0;
  vertical-align: top;
}
.cl-table tbody tr:last-child td { border-bottom: 0; }

/* ---- NOTE-ROW — the ONE labelled coverage entry (head + fields + meta) ----
   The single primitive every craft/coverage note collapses onto: a flat region
   of the one sheet divided by a hairline rule (NOT a card — no fill, no frame,
   no round). It carries the three text roles and nothing else:
     - .cl-note-head : the serif lead (the note itself)   — reading role
     - .cl-note-field: a hung field, Courier label + serif body (Onscreen / Fix /
                       If ignored / Perspective / On the page) — caption + body
     - .cl-note-meta : the closing Courier registration line — label role
   It is the body inside a Disclosure (severity/priority in the summary) OR a
   standalone <li> in a List. Replaces the role/scene/structure/evidence/note
   box families AND the note-detail / note-field / note-meta trio. */
.cl-note { display: grid; gap: var(--space-1); }
.cl-note[data-divide] { border-top: 1px solid var(--border); padding-top: var(--space-2); }
.cl-note[data-divide]:first-child { border-top: 0; padding-top: 0; }
.cl-note-head { font-family: var(--serif); color: var(--ink); line-height: 1.5; margin: 0; }
.cl-note-fields { display: grid; gap: var(--space-0); margin-left: var(--space-3); }
.cl-note-field { font-family: var(--serif); font-size: var(--fs-body); color: var(--body); line-height: 1.5; margin: 0; }
.cl-note-field > .cl-label, .cl-note-field > strong {
  font-family: var(--brand); text-transform: uppercase; letter-spacing: 0.04em;
  font-size: var(--fs-slug); font-weight: 700; color: var(--ink); margin-right: var(--space-0);
}
.cl-note-meta { font-family: var(--brand); font-size: var(--fs-micro); font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--faint); margin: 0; }

/* ---- CARD — the ONE shared project/read card (the card IS the button) ----
   One atom for BOTH the slate (project cards) and the project page (read cards).
   The card body is the click target — opening the project / the read — so it
   carries the surface tile + the hover ink-offset lift (the depth already reads
   right) and lays the info out in THREE roles and no more:
     - .cl-card-title  : the serif title                      — reading role
     - .cl-card-status : ONE mono standing/status line        — label role (status)
     - .cl-card-meta   : ONE quiet mono meta line             — label role (meta)
   No competing weights, no stacked prose, no foot full of buttons. The single
   per-card affordance besides the body click is the top-right MENU (below).
   It rides cl-surface so tone="tile"/data-accent/data-lift all still apply; this
   block adds only the clickable-body framing + the 3-role layout slot + the
   menu's top-right anchoring. */
.cl-card { position: relative; display: flex; flex-direction: column; gap: var(--space-1); cursor: pointer; }
.cl-card[data-accent] { border-left-width: 4px; }
/* The body is the hit target; the menu trigger sits above it (z + stop-prop in
   JS) so clicking ... never opens the card. */
.cl-card-body { display: flex; flex-direction: column; gap: var(--space-1); }
/* Leave room for the top-right menu trigger so a long title never slides under it. */
.cl-card[data-menu] .cl-card-body { padding-right: var(--space-5); }
.cl-card-title { font-family: var(--serif); color: var(--ink); font-weight: var(--fw-bold); font-size: var(--fs-h3); line-height: 1.15; margin: 0; }
.cl-card-status { font-family: var(--brand); text-transform: uppercase; letter-spacing: 0.06em; font-size: var(--fs-micro); color: var(--muted); margin: 0; }
.cl-card-meta { font-family: var(--brand); font-size: var(--fs-micro); letter-spacing: 0.04em; color: var(--faint); margin: 0; }

/* EMPTY / ADD card — the entitlement & add affordance. A granted-but-unactivated
   read/project (data-empty) OR the "+ start your next" tile when entitlements run
   out (same look). A quiet DASHED frame (not a filled tile), a centered + glyph
   and a label — it reads as "a slot waiting to be filled", in the grid where the
   real cards are. Still the card-as-button (the whole frame is the target). */
.cl-card[data-empty] {
  background: transparent;
  border: 1px dashed var(--border-strong);
  border-left-width: 1px; /* the dashed frame is uniform — no disposition accent */
  padding: var(--space-4); /* tone="bare" zeros surface padding; restore the slot's breathing room */
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: var(--space-1);
  min-height: 132px;
  color: var(--muted);
}
.cl-card[data-empty] .cl-card-plus { font-family: var(--brand); font-size: 1.6rem; line-height: 1; color: var(--faint); }
.cl-card[data-empty] .cl-card-title { font-size: var(--fs-body); font-weight: 400; color: var(--muted); }
.cl-card[data-empty]:hover { border-color: var(--ink); color: var(--ink); }
.cl-card[data-empty]:hover .cl-card-plus { color: var(--ink); }
/* The add card (entitlements exhausted) is the same dashed slot with a hair more
   presence — a heavier dashed rule — so it reads as the deliberate "add one". */
.cl-card[data-empty][data-add] { border-color: var(--muted); }
.cl-card[data-empty]:focus-visible { outline: 2px solid var(--gold-soft); outline-offset: 2px; }

/* PURCHASE card — a paid action that opens the purchase modal. A padlock instead
   of the +; the GOLD variant (the headline buy: "Start a new project" / "Get more
   reads") fills with the gold wash + a solid gold edge so it reads as the premium,
   gated affordance, distinct from the quiet dashed ADD tile. */
.cl-card[data-empty] .cl-card-plus svg { width: 1.5rem; height: 1.5rem; display: block; }
.cl-card[data-empty][data-locked][data-gold] {
  border: 1px solid var(--gold-display);
  background: var(--gold-wash);
}
.cl-card[data-empty][data-gold] .cl-card-plus { color: var(--gold); }
.cl-card[data-empty][data-gold] .cl-card-title { color: var(--ink); font-weight: var(--fw-bold); }
.cl-card[data-empty][data-gold]:hover { border-color: var(--ink); color: var(--ink); box-shadow: var(--offset-sm); }
.cl-card[data-empty][data-gold]:hover .cl-card-plus { color: var(--ink); }

/* STACK — the "N ready" head shows page-paper SHEETS squared off behind it, so it
   reads plainly as "more than one waiting" (granted entitlements; minted projects)
   without fighting the front face. Drawn with a layered box-shadow rather than an
   offset ::before, for two reasons: (1) it costs ZERO layout — no margin hack — so
   the head stays the exact height of its grid row-mates (the old margin shrank it
   under align-items:stretch, the misalignment that read as "overlapping"); and
   (2) the shadow sits TRULY behind the border box, so it never tints the card's own
   surface or draws an inset frame line (the z-index:-1 ::before painted OVER the
   card's background). Each sheet is a --bg fill + a 1px ink edge (the spread trick);
   hard ink offset, no blur (depth on paper is the offset, never a soft drop). The
   4px/8px offsets stay well inside the 16px grid gap, so the sheets never reach a
   neighbor. The "N ready" sub-label carries the actual count. */
.cl-card[data-stack] {
  box-shadow:
    4px 4px 0 0 var(--bg), 4px 4px 0 1px var(--border-strong),
    8px 8px 0 0 var(--bg), 8px 8px 0 1px var(--border-strong);
}
/* Hold the sheets while the head lifts on hover — the lift rule alone would replace
   box-shadow with its single offset and the sheets would vanish; the translate from
   the lift rule still provides the motion. */
.cl-card[data-stack]:hover {
  box-shadow:
    4px 4px 0 0 var(--bg), 4px 4px 0 1px var(--border-strong),
    8px 8px 0 0 var(--bg), 8px 8px 0 1px var(--border-strong);
}
.cl-card-count { font-family: var(--brand); font-size: var(--fs-micro); letter-spacing: 0.06em; text-transform: uppercase; color: var(--faint); margin-top: var(--space-0); }

/* Flutter — the most-recent project/read card gives a gentle, brief lift on render
   and every 30s (JS toggles [data-flutter] across a reflow to restart it). */
.cl-card[data-flutter] { animation: cl-flutter 1.05s var(--ease) 1; }

/* ---- MENU — the top-right per-card actions popover (... -> action items) ----
   One small trigger opens a popover anchored to the card's top-right corner with
   exactly the card's actions (Purchase more reads / Export / Delete). CSS-only
   open via :focus-within (the popover shows while the trigger or an item holds
   focus); the tiny toggle in kit.js adds click-outside / Escape dismissal and
   keeps aria-expanded honest. Accessible: real <button>s, aria-haspopup, the
   popover is aria-hidden until open, Delete reads as the lone destructive item. */
.cl-menu { position: absolute; top: var(--space-1); right: var(--space-1); z-index: 1; }
.cl-menu-trigger {
  display: grid; place-items: center; width: var(--tap-min); height: var(--tap-min);
  border: 0; background: transparent; color: var(--muted); cursor: pointer;
  font-family: var(--brand); font-size: 1.25rem; line-height: 1; letter-spacing: 0.1em;
  border-radius: var(--radius);
}
.cl-menu-trigger:hover { color: var(--ink); }
.cl-menu-trigger:focus-visible { outline: 2px solid var(--gold-soft); outline-offset: 2px; }
.cl-menu-popover {
  position: absolute; top: calc(100% - var(--space-1)); right: 0; z-index: var(--z-sticky);
  min-width: 180px; display: none; flex-direction: column;
  background: var(--surface); border: 1px solid var(--border-strong); border-radius: var(--radius);
  box-shadow: var(--offset-sm); padding: var(--space-0) 0;
}
/* Open ONLY via the JS toggle's data-open (wireMenus, always called on render).
   :focus-within was ALSO an opener, but it fought the toggle — clicking the trigger
   again removed data-open yet the trigger kept focus, so :focus-within held the
   popover open and a second click never closed it. data-open alone makes the click
   authoritative (open → click closes; Escape / click-outside also close). */
.cl-menu[data-open] .cl-menu-popover { display: flex; }
.cl-menu-item {
  display: block; width: 100%; text-align: left; background: transparent; border: 0;
  font-family: var(--brand); text-transform: uppercase; letter-spacing: 0.06em;
  font-size: var(--fs-slug); color: var(--ink); cursor: pointer;
  padding: var(--space-2) var(--space-3); min-height: var(--tap-min);
}
.cl-menu-item:hover, .cl-menu-item:focus-visible { background: var(--gold-wash); outline: none; }
.cl-menu-item[data-variant="danger"] { color: var(--red); }
.cl-menu-item[data-variant="danger"]:hover, .cl-menu-item[data-variant="danger"]:focus-visible { background: var(--disp-hold-soft); }

/* ---- NOTICE — one non-modal messaging primitive (banner/inline/toast) ---- */
.cl-notice { display: flex; gap: var(--space-2); align-items: flex-start; font-family: var(--serif); font-size: var(--fs-body); color: var(--ink); border: 1px solid var(--border-strong); border-left-width: 3px; border-radius: var(--radius); padding: var(--space-2) var(--space-3); background: var(--surface); }
.cl-notice[data-tone="info"] { border-left-color: var(--muted); }
.cl-notice[data-tone="advance"] { border-left-color: var(--disp-advance); background: var(--disp-advance-soft); }
.cl-notice[data-tone="conditions"] { border-left-color: var(--disp-conditions); background: var(--disp-conditions-soft); }
.cl-notice[data-tone="hold"] { border-left-color: var(--disp-hold); background: var(--disp-hold-soft); }
.cl-notice[data-placement="toast"] { position: fixed; right: var(--space-3); bottom: var(--space-3); z-index: var(--z-toast); box-shadow: var(--offset); max-width: 24rem; }
.cl-notice:empty { display: none; }

/* ---- keyframes; all guarded below ---- */
@keyframes cl-spin { to { transform: rotate(360deg); } }
@keyframes cl-stamp-settle { from { transform: rotate(-7deg) scale(1.14); opacity: 0; } to { transform: rotate(-3.5deg) scale(1); opacity: 1; } }
@keyframes cl-stamp-settle-flat { from { transform: rotate(-3.5deg) scale(1.14); opacity: 0; } to { transform: rotate(0) scale(1); opacity: 1; } }
@keyframes cl-flutter {
  0%, 100% { transform: translateY(0) rotate(0); }
  22% { transform: translateY(-4px) rotate(-0.5deg); }
  46% { transform: translateY(0) rotate(0.45deg); }
  68% { transform: translateY(-2px) rotate(-0.25deg); }
}

@media (prefers-reduced-motion: reduce) {
  .cl-surface[data-lift], .cl-btn, .cl-stamp[data-settle], .cl-btn[data-busy]::after, .cl-meter > .cl-meter-fill, .cl-card[data-flutter] { transition: none; animation: none; }
}

/* ---- PURCHASE modal — the option-row list (one clean choice per row) ---------
   Each row is a wide button: name (+ optional "Best value" tag) and a one-line
   detail on the left, the price on the right. The whole row is the target. */
.cl-purchase-options { display: flex; flex-direction: column; gap: var(--space-2); }
.cl-purchase-option {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-3);
  width: 100%; text-align: left; cursor: pointer;
  background: var(--surface); border: 1px solid var(--border-strong); border-radius: var(--radius);
  padding: var(--space-3) var(--space-3);
  transition: box-shadow var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.cl-purchase-option:hover { border-color: var(--ink); box-shadow: var(--offset-sm); }
.cl-purchase-option:focus-visible { outline: 2px solid var(--gold-soft); outline-offset: 2px; }
.cl-purchase-option-main { display: flex; flex-direction: column; gap: var(--space-0); }
.cl-purchase-option-name { font-family: var(--serif); font-weight: var(--fw-bold); font-size: var(--fs-h3); color: var(--ink); line-height: 1.1; }
.cl-purchase-option-detail { font-family: var(--brand); font-size: var(--fs-micro); letter-spacing: 0.04em; color: var(--muted); }
.cl-purchase-option-price { font-family: var(--serif); font-size: var(--fs-h3); color: var(--ink); white-space: nowrap; }
.cl-purchase-best {
  font-family: var(--brand); text-transform: uppercase; letter-spacing: 0.08em;
  font-size: var(--fs-micro); color: var(--gold); border: 1px solid var(--gold-display);
  border-radius: var(--radius); padding: 1px 6px; margin-left: var(--space-1); vertical-align: middle;
}
