/* ============================================================================
   Execution map — the run diagram, drawn as the graph it actually is.
   ----------------------------------------------------------------------------
   `.diagram` was a flat 4-column grid of seven cards. The dependency graph in
   lib/marketing-nodes.js (`inputs_from`) and lib/node-state.js (`DEPENDENCIES`)
   was invisible in it — the gap docs/roadmap-22-7-node-current-execution-map.md
   records as "This field is invisible to the UI and to the exporters".

   This file lays the same cards out as the documented graph:

        1 Research → 2 Strategy → 3 Creative
                          ↓
              ┌───────────┼───────────┐
           4 Digital   5 CRM   6 Partnership
              └───────────┼───────────┘
                          ↓
                    7 Executive

   The fan-out opens after node 3, not node 2 — nodes 4-6 require the Creative
   package as well as the Strategic one. That correction is the whole reason
   the graph is worth drawing.

   ADDITIVE ONLY. No existing class, attribute or status contract is changed;
   `setStatus()` and its tests are untouched. Everything here keys off the
   `data-status` / `data-node` attributes the dashboard already writes.

   Colour comes from the palette derivation — `--role-*` per node, `--ok`
   `--warn` `--err` `--idle` for status. Nothing is hardcoded, so a palette
   change carries through (CLAUDE.md: "Do not hand-edit colours").
   ========================================================================== */

/* ── the stack ─────────────────────────────────────────────────────────── */
/*
   Folders in a drawer, not tiles on a wall: one column, each step indented
   further than the one before it.

   The indent is the node's DEPTH in the graph, not its position in the list —
   which is what lets a vertical stack still tell the truth about parallelism.
   Nodes 4, 5 and 6 share one indent, so three folders sitting at the same
   offset read as siblings rather than as three more steps of a staircase, and
   a bracket down their leading edge says so outright. Node 7 steps out again
   because it waits for all of them.

       01 Research
         02 Strategy
           03 Creative
             ├ 04 Digital
             ├ 05 CRM
             └ 06 Partnership
               07 Executive
*/

.workflow { container-type: inline-size; }

.diagram.nm-map {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0;
  /* the indent should answer to the COLUMN, not the window: the same 3.4vw is
     generous beside a wide brief and crushing beside a narrow one. `cqi` is the
     container's inline size; the vw line stays first as the fallback. */
  --nm-indent: clamp(18px, 3.4vw, 54px);
  --nm-indent: clamp(16px, 5.5cqi, 54px);
  /* Clear air between one folder and the next. The tab lives inside this gap,
     13px of it, so `--nm-air` is what you actually see between two folders.
     Seven cards six pixels apart stopped being a stack and became a slab. */
  --nm-air: clamp(15px, 2cqi, 26px);
  --nm-card-w: clamp(260px, 100%, 520px);
}

.diagram.nm-map > .node-card {
  --nm-depth: 0;
  /* A folder is sized to look like one, not to fill whatever column it is in.
     Left to stretch, seven full-width bars stop reading as objects and start
     reading as rows in a table. The cap holds; the indent is taken out of the
     width only when the column is too narrow to grant both. */
  width: min(var(--nm-card-w), calc(100% - var(--nm-depth) * var(--nm-indent)));
  margin-inline-start: calc(var(--nm-depth) * var(--nm-indent));
  /* 13px of headroom for the tab, then the air above it */
  margin-top: calc(13px + var(--nm-air));
  /* their 150px floor was sized for a four-across grid; in a stack it leaves
     a third of each folder empty */
  min-height: 0;
  padding: 14px 16px 13px;
  gap: 5px;
}
.diagram.nm-map > .node-card:first-child { margin-top: 0; }

.diagram.nm-map > .node-card[data-node="researcher"] { --nm-depth: 0; z-index: 7; }
.diagram.nm-map > .node-card[data-node="strategist"] { --nm-depth: 1; z-index: 6; }
.diagram.nm-map > .node-card[data-node="creative"]   { --nm-depth: 2; z-index: 5; }
.diagram.nm-map > .node-card[data-node="digital"]    { --nm-depth: 3; z-index: 4; }
.diagram.nm-map > .node-card[data-node="crm"]        { --nm-depth: 3; z-index: 3; }
.diagram.nm-map > .node-card[data-node="affiliate"]  { --nm-depth: 3; z-index: 2; }
.diagram.nm-map > .node-card[data-node="efficiency"] { --nm-depth: 4; z-index: 1; }

/* ── the branch bracket ────────────────────────────────────────────────── */
/* A line down the leading edge of the three parallel nodes, with a tick into
   each one. It is the only thing on screen that says 4, 5 and 6 do not wait
   for each other. */

.diagram.nm-map > .node-card[data-node="digital"]::before,
.diagram.nm-map > .node-card[data-node="crm"]::before,
.diagram.nm-map > .node-card[data-node="affiliate"]::before {
  content: "";
  position: absolute;
  inset-inline-start: calc(var(--nm-indent) * -0.55);
  top: calc(var(--nm-air) * -1);
  bottom: 0;
  width: 1.5px;
  background: var(--line);
}
/* the first of the three opens the bracket, the last closes it */
.diagram.nm-map > .node-card[data-node="digital"]::before { top: 50%; }
.diagram.nm-map > .node-card[data-node="affiliate"]::before { bottom: 50%; }

.diagram.nm-map > .node-card[data-node="digital"]::after,
.diagram.nm-map > .node-card[data-node="crm"]::after,
.diagram.nm-map > .node-card[data-node="affiliate"]::after,
.diagram.nm-map > .node-card[data-node="efficiency"]::after {
  content: "";
  position: absolute;
  inset-inline-start: calc(var(--nm-indent) * -0.55);
  top: 50%;
  width: calc(var(--nm-indent) * 0.55);
  height: 1.5px;
  background: var(--line);
}
/* node 7 is fed by the bracket it steps out of */
.diagram.nm-map > .node-card[data-node="efficiency"]::before {
  content: "";
  position: absolute;
  inset-inline-start: calc(var(--nm-indent) * -0.55);
  bottom: 50%;
  height: calc(100% + var(--nm-air) + 13px);
  width: 1.5px;
  background: var(--line);
}

/* a branch that will not run stops being drawn as live */
.diagram.nm-map > .node-card.is-skipped::before,
.diagram.nm-map > .node-card.is-skipped::after { opacity: .4; }

/* the rails belonged to the grid; the bracket replaces them */
.diagram.nm-map .nm-rail { display: none; }

@media (max-width: 720px) {
  .diagram.nm-map { --nm-indent: 12px; }
  .diagram.nm-map > .node-card { width: 100%; }
}

/* ── folder tab: the node's identity colour, above the card ────────────── */

.node-card .nm-tab {
  position: absolute;
  top: -11px;
  inset-inline-start: 16px;
  width: 46px;
  height: 11px;
  background: var(--role);
  border-radius: 6px 6px 0 0;
  clip-path: polygon(0 0, calc(100% - 9px) 0, 100% 100%, 0 100%);
  transition: transform .18s, filter .18s;
}
[dir="rtl"] .node-card .nm-tab {
  clip-path: polygon(9px 0, 100% 0, 100% 100%, 0 100%);
}
.node-card:hover .nm-tab { transform: translateY(-2px); }
.node-card.is-skipped .nm-tab { filter: grayscale(1); opacity: .5; }


/* ── the progress line ─────────────────────────────────────────────────── */

.nm-progress {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 8px;
}

.nm-meter {
  position: relative;
  flex: 1 1 auto;
  height: 5px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--ink-3) 22%, transparent);
  overflow: hidden;
}
.nm-meter i {
  position: absolute;
  inset-inline-start: 0;
  top: 0;
  bottom: 0;
  width: 100%;
  /* `inline-start` is not a transform-origin keyword — it silently falls back
     to 50%, and the bar then grows out of its own middle. Physical values,
     mirrored for Persian (lang.js writes dir on <body>). */
  transform-origin: left center;
  transform: scaleX(var(--nm-progress, 0));
  background: var(--role);
  border-radius: inherit;
  transition: transform .45s cubic-bezier(.22,.75,.2,1), background .3s;
}

[dir='rtl'] .nm-meter i { transform-origin: right center; }

.nm-pct {
  font-size: var(--fs-micro);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--ink-3);
  min-width: 34px;
  text-align: end;
}

/* status re-colours the fill — the hue rule from CLAUDE.md holds:
   green means ok, red means blocked, amber means attention */
.node-card[data-status="done"]  .nm-meter i { background: var(--ok); }
.node-card[data-status="error"] .nm-meter i { background: var(--err); }
.node-card[data-status="review"] .nm-meter i { background: var(--warn); }
.node-card[data-status="idle"]  .nm-meter i { background: var(--idle); }

/* a run that stopped short of 100% is the case worth investigating, so it is
   marked in text as well as colour */
.node-card[data-nm-short="1"] .nm-pct { color: var(--warn); }
.node-card[data-nm-short="1"] .nm-meter { box-shadow: 0 0 0 1px var(--warn) inset; }

/* skipped: no percentage to report */
.node-card.is-skipped .nm-progress { visibility: hidden; }

/* ── waiting on dependencies ───────────────────────────────────────────── */
/* Today an idle node and a node blocked behind an unfinished dependency read
   identically — the same class of defect R-UI-1 found for skipped nodes.
   `data-nm-wait` separates them, and .nm-wait-note carries it in text. */

.node-card[data-nm-wait="1"] { opacity: .82; }
.nm-wait-note {
  display: none;
  font-size: var(--fs-micro);
  font-weight: 600;
  color: var(--ink-3);
  margin-top: 4px;
}
.node-card[data-nm-wait="1"] .nm-wait-note { display: block; }

/* the stack already is a vertical spine; narrow screens only need the indent
   to stop eating the card, which the --nm-indent clamp above handles */

@media (prefers-reduced-motion: reduce) {
  .node-card .nm-tab,
  .nm-meter i { transition: none; }
}

/* ============================================================================
   THE FOLDER TREATMENT
   ----------------------------------------------------------------------------
   The cards read as plain boxes with a coloured hairline on top. Each node
   already owns an identity colour (`--role-*`, derived per palette, per theme),
   and the map now says how the nodes relate — so the cards can carry that
   identity instead of hinting at it, and behave like the physical objects the
   diagram implies: folders in a drawer.

   Everything below is drawn from `--role` and the app's own surface tokens, so
   it follows a palette change and both themes without a hand-written colour.
   Text keeps sitting on `--bg-elev`, never on a saturated fill — a wash strong
   enough to read as "this node is amber" is not one you can put type on, and
   seven hues would need seven different answers.
   ========================================================================== */

/* the tab has to be allowed out of the card */
.diagram.nm-map > .node-card { overflow: visible; }

/* ── the folder itself ─────────────────────────────────────────────────── */

.diagram.nm-map > .node-card {
  /* the colour wash fades into the surface, so the card reads as a coloured
     folder holding a white sheet rather than a white box with a stripe */
  background:
    linear-gradient(
      180deg,
      color-mix(in srgb, var(--role) 26%, var(--bg-elev)) 0%,
      color-mix(in srgb, var(--role) 9%,  var(--bg-elev)) 34%,
      var(--bg-elev) 68%
    ) !important;
  border-color: color-mix(in srgb, var(--role) 28%, var(--line));
  box-shadow:
    0 1px 2px color-mix(in srgb, var(--role) 14%, transparent),
    0 10px 20px -14px color-mix(in srgb, var(--role) 42%, transparent);
  transition:
    transform .42s cubic-bezier(.22,.75,.2,1),
    box-shadow .42s cubic-bezier(.22,.75,.2,1),
    border-color .42s cubic-bezier(.22,.75,.2,1),
    opacity .3s ease,
    filter .3s ease;
}

/* a hairline of the node's own colour along the top edge, so the wash starts
   from something definite */
.diagram.nm-map > .node-card {
  border-top-width: 3px;
  border-top-color: var(--role);
}

/* ── the tab ───────────────────────────────────────────────────────────── */

.diagram.nm-map > .node-card .nm-tab {
  top: -13px;
  width: 62px;
  height: 14px;
  background: linear-gradient(180deg,
      color-mix(in srgb, #fff 20%, var(--role)) 0%,
      var(--role) 100%);
  border-radius: 7px 7px 0 0;
  clip-path: polygon(0 0, calc(100% - 11px) 0, 100% 100%, 0 100%);
  box-shadow: 0 -1px 0 color-mix(in srgb, #fff 26%, transparent) inset;
  transition: transform .42s cubic-bezier(.22,.75,.2,1), filter .42s;
}
[dir='rtl'] .diagram.nm-map > .node-card .nm-tab {
  clip-path: polygon(11px 0, 100% 0, 100% 100%, 0 100%);
}
/* headroom for the tab is set by the stack layout, above */

/* ── the icon reads as part of the folder, not a sticker on it ─────────── */

.diagram.nm-map > .node-card .node-icon {
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--role) 34%, transparent),
    0 2px 6px -2px color-mix(in srgb, var(--role) 45%, transparent);
  transition: transform .42s cubic-bezier(.22,.75,.2,1), box-shadow .42s;
}
.diagram.nm-map > .node-card .node-order {
  background: color-mix(in srgb, var(--role) 16%, var(--st-paper));
  color: var(--ink-2);
}

/* ── hover / focus: the folder comes forward ───────────────────────────── */
/* The original stack slid a folder sideways out of the pile. These do not
   overlap, so the same intent is expressed as a lift: the card rises, its tab
   rises further, the shadow deepens, and the rest of the map recedes. */

.diagram.nm-map > .node-card:hover,
.diagram.nm-map > .node-card:focus-visible {
  transform: translateY(-6px) scale(1.015);
  border-color: var(--role);
  box-shadow:
    0 2px 4px color-mix(in srgb, var(--role) 18%, transparent),
    0 18px 30px -16px color-mix(in srgb, var(--role) 55%, transparent),
    0 34px 60px -34px color-mix(in srgb, var(--role) 40%, transparent);
  z-index: 3;
}
.diagram.nm-map > .node-card:hover .nm-tab,
.diagram.nm-map > .node-card:focus-visible .nm-tab {
  transform: translateY(-5px);
  filter: brightness(1.06);
}
/* the connector lights up in the node's own colour — the relationship is part
   of what you are pointing at, not scenery behind it */
.diagram.nm-map > .node-card:hover::before,
.diagram.nm-map > .node-card:hover::after {
  background: var(--role);
  opacity: .85;
}

.diagram.nm-map > .node-card:hover .node-icon,
.diagram.nm-map > .node-card:focus-visible .node-icon {
  transform: scale(1.07);
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--role) 52%, transparent),
    0 6px 14px -4px color-mix(in srgb, var(--role) 55%, transparent);
}

@media (hover: hover) {
  .diagram.nm-map:has(> .node-card:hover) > .node-card:not(:hover) {
    opacity: .74;
    filter: saturate(.85);
  }
}

/* ── the running node is the one you want to find ──────────────────────── */

.diagram.nm-map > .node-card[data-status="running"] {
  border-color: var(--role);
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--role) 45%, transparent),
    0 14px 26px -16px color-mix(in srgb, var(--role) 60%, transparent);
  animation: nmBreathe 2.4s ease-in-out infinite;
}
@keyframes nmBreathe {
  0%, 100% { box-shadow:
      0 0 0 1px color-mix(in srgb, var(--role) 45%, transparent),
      0 14px 26px -16px color-mix(in srgb, var(--role) 60%, transparent); }
  50%      { box-shadow:
      0 0 0 3px color-mix(in srgb, var(--role) 26%, transparent),
      0 18px 34px -16px color-mix(in srgb, var(--role) 70%, transparent); }
}

/* ── settled states keep the folder language, quietly ──────────────────── */

.diagram.nm-map > .node-card[data-status="done"] {
  border-top-color: var(--ok);
}
.diagram.nm-map > .node-card[data-status="done"] .nm-tab { background: var(--ok); }

.diagram.nm-map > .node-card[data-status="error"] {
  border-top-color: var(--err);
}
.diagram.nm-map > .node-card[data-status="error"] .nm-tab { background: var(--err); }

/* a skipped folder is closed: greyed, flatter, and it does not lift */
.diagram.nm-map > .node-card.is-skipped {
  box-shadow: none;
  border-color: var(--line);
}
.diagram.nm-map > .node-card.is-skipped:hover {
  transform: none;
  box-shadow: none;
  border-color: var(--line);
}
.diagram.nm-map > .node-card.is-skipped .nm-tab { filter: grayscale(1); opacity: .45; }

@media (prefers-reduced-motion: reduce) {
  .diagram.nm-map > .node-card,
  .diagram.nm-map > .node-card .nm-tab,
  .diagram.nm-map > .node-card .node-icon { transition: none; }
  .diagram.nm-map > .node-card[data-status="running"] { animation: none; }
  .diagram.nm-map > .node-card:hover,
  .diagram.nm-map > .node-card:focus-visible { transform: none; }
}

/* ============================================================================
   REFLOW — the folders move below the brief when the column gets too narrow
   ----------------------------------------------------------------------------
   `#colResizer` already lets the brief column be dragged between 280 and 720px.
   Past a point the workflow column is too narrow for a folder to be a folder,
   and squeezing it further is worse than moving it: below the brief it gets the
   full width back.

   The switch is decided from the WIDTH THAT WOULD RESULT, computed in
   node-map.js from `--brief-col` and main's own box — never from the workflow
   column as measured. Measuring it would feed back: stacking makes the column
   wide, a wide column un-stacks, and the layout oscillates on every frame.
   ========================================================================== */

body.nm-stacked main {
  grid-template-columns: 1fr !important;
  gap: 20px !important;
}

/* the vertical grip becomes a horizontal seam between the two stacked halves */
body.nm-stacked .col-resizer {
  display: flex !important;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: auto;
  height: 30px;
  cursor: ew-resize;
  border-radius: 999px;
  background: color-mix(in srgb, var(--ink-3) 6%, transparent);
}
body.nm-stacked .col-resizer::before {
  position: static;
  width: 34px;
  height: 3px;
  border-radius: 999px;
  background: var(--line);
  transform: none;
}
body.nm-stacked .col-resizer::after { display: none; }
body.nm-stacked .col-resizer:hover { background: color-mix(in srgb, var(--brand-red) 8%, transparent); }
body.nm-stacked .col-resizer:hover::before { background: var(--brand-red); width: 44px; height: 3px; }

.nm-resizer-hint {
  display: none;
  font-size: var(--fs-micro);
  font-weight: 600;
  color: var(--ink-3);
  white-space: nowrap;
}
body.nm-stacked .nm-resizer-hint { display: inline; }

/* with the full width back, the folders keep their own proportions — the cap
   is the point, otherwise stacking just trades a narrow column for a wide bar */
body.nm-stacked .diagram.nm-map { --nm-card-w: clamp(300px, 100%, 560px); }

/* ── the stack arrives ─────────────────────────────────────────────────── */
/*
   Folders rise into place in depth order, so the chain reads itself out once:
   research, strategy, creative, then the three branches TOGETHER — they share
   a depth, so they share a delay, and the one moment the eye is given the
   parallelism is the moment it appears.
*/

@keyframes nmRise {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: none; }
}

.diagram.nm-map > .node-card {
  animation: nmRise .52s cubic-bezier(.22, .75, .2, 1) backwards;
  animation-delay: calc(var(--nm-depth) * 90ms);
}

/* the bracket follows the folders it belongs to */
@keyframes nmFade { from { opacity: 0; } to { opacity: 1; } }
.diagram.nm-map > .node-card::before,
.diagram.nm-map > .node-card::after {
  animation: nmFade .5s ease .34s backwards;
}

@media (prefers-reduced-motion: reduce) {
  .diagram.nm-map > .node-card,
  .diagram.nm-map > .node-card::before,
  .diagram.nm-map > .node-card::after { animation: none; }
}

/* ── the folder holds its own output ───────────────────────────────────────
   The node's markdown used to live in a second list of seven collapsibles
   below the map. It now sits inside the folder it belongs to — the same
   element, moved — so a node is one object on screen instead of two halves.
   ========================================================================= */

.nm-disclose {
  display: none;
  align-items: center;
  gap: 6px;
  margin-top: 10px;
  align-self: flex-start;
  padding: 5px 11px;
  border: 1px solid color-mix(in srgb, var(--role) 34%, var(--line));
  border-radius: 999px;
  background: color-mix(in srgb, var(--role) 10%, transparent);
  color: var(--ink-2);
  font: inherit;
  font-size: 12px;
  font-weight: 700;
  cursor: pointer;
  transition: background .2s, border-color .2s, color .2s;
}
.node-card[data-nm-has-output="1"] .nm-disclose { display: inline-flex; }
.nm-disclose:hover {
  background: color-mix(in srgb, var(--role) 20%, transparent);
  border-color: var(--role);
  color: var(--ink);
}
.nm-disclose:focus-visible {
  outline: 2px solid var(--role);
  outline-offset: 2px;
}
.nm-disclose i {
  width: 0; height: 0;
  border-inline: 4px solid transparent;
  border-top: 5px solid currentColor;
  transition: transform .2s;
}
.nm-disclose[aria-expanded="true"] i { transform: rotate(180deg); }

/* the adopted output */
.node-card .out-item.nm-adopted {
  margin-top: 12px;
  border: 0;
  border-top: 1px solid color-mix(in srgb, var(--role) 26%, var(--line));
  border-radius: 0;
  background: none;
  box-shadow: none;
}
/* the folder's own header already names the node, shows its icon and carries
   the status — the row's header would say all of it a second time */
.node-card .out-item.nm-adopted > .out-head { display: none; }

/* an open folder takes the column: markdown in a 520px card is a keyhole */
.diagram.nm-map > .node-card.nm-open { width: 100%; }

/* the shell left behind once all seven have moved out */
.output-list.nm-emptied { display: none; }

@media (prefers-reduced-motion: reduce) {
  .nm-disclose, .nm-disclose i { transition: none; }
}

/* ── reading the output ────────────────────────────────────────────────────
   A finished node returns 10,000–24,000 characters. Seven of those opened in
   one column is a document kilometres long, and inside a card it arrives as an
   undifferentiated wall. This is the reading surface for it.
   ========================================================================= */

.node-card .out-item.nm-adopted .out-body {
  /* Capped, with its own scroll. Without this, opening two folders pushes the
     rest of the map off the end of the page and the stack stops being a map. */
  max-height: min(62vh, 640px);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding-inline-end: 6px;
}

/* a measure. 120 characters of prose per line is not a reading width */
.node-card .out-item.nm-adopted .out-body > * { max-width: 74ch; }

/* rhythm: headings need air above them and none below */
.node-card .out-item.nm-adopted .out-body :is(h1, h2, h3, h4) {
  margin-block: 1.4em .35em;
  line-height: 1.3;
}
.node-card .out-item.nm-adopted .out-body :is(h1, h2, h3, h4):first-child {
  margin-block-start: .2em;
}
.node-card .out-item.nm-adopted .out-body p { line-height: 1.72; }
.node-card .out-item.nm-adopted .out-body :is(ul, ol) { line-height: 1.68; }

/* The nodes emit structured contracts alongside prose, and a JSON blob has no
   spaces to break at — left alone it forces the card wider than the column and
   the whole stack starts scrolling sideways. */
.node-card .out-item.nm-adopted .out-body {
  overflow-wrap: anywhere;
  word-break: normal;
}
.node-card .out-item.nm-adopted .out-body :is(pre, code) {
  overflow-wrap: normal;
  white-space: pre;
}
.node-card .out-item.nm-adopted .out-body pre {
  max-width: 100%;
  overflow-x: auto;
  padding: 12px 14px;
  border-radius: 8px;
  background: color-mix(in srgb, var(--ink-3) 10%, transparent);
  font-size: 12px;
  line-height: 1.55;
}

/* a table has to scroll on its own rather than widen the folder */
.node-card .out-item.nm-adopted .out-body table {
  display: block;
  max-width: 100%;
  overflow-x: auto;
  border-collapse: collapse;
  font-size: 13px;
}
.node-card .out-item.nm-adopted .out-body :is(th, td) {
  padding: 7px 10px;
  border: 1px solid var(--line);
  vertical-align: top;
}
.node-card .out-item.nm-adopted .out-body th {
  background: color-mix(in srgb, var(--role) 12%, transparent);
  text-align: start;
  font-weight: 700;
}

/* scrolled content needs an edge, or it looks like it simply ended */
.node-card.nm-open .out-item.nm-adopted {
  position: relative;
}
.node-card.nm-open .out-item.nm-adopted::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  bottom: 0;
  height: 26px;
  background: linear-gradient(180deg, transparent, var(--bg-elev));
  pointer-events: none;
  border-radius: 0 0 var(--radius) var(--radius);
}

/* the node's colour marks its output as its own */
.node-card .out-item.nm-adopted .out-body :is(h1, h2, h3) {
  color: var(--ink);
}
.node-card .out-item.nm-adopted .out-body blockquote {
  margin-inline: 0;
  padding-inline-start: 14px;
  border-inline-start: 3px solid color-mix(in srgb, var(--role) 45%, transparent);
  color: var(--ink-2);
}

@media (prefers-reduced-motion: reduce) {
  .node-card .out-item.nm-adopted .out-body { scroll-behavior: auto; }
}

/* ══════════════════════════════════════════════════════════════════════
   An OPEN folder is not a folder any more
   ══════════════════════════════════════════════════════════════════════
   The 520px cap above is right for the stack: seven full-width bars stop
   reading as objects and start reading as rows in a table. But the same cap
   follows a folder when you open it, and then it is capping a DOCUMENT.
   Measured on a real run at 1269px: the card held 520px, the plan text read
   at 442px, and 749px — 59% of the page — sat empty beside it.

   So the cap belongs to the closed state. Open one and it takes the column;
   close it and the stack looks exactly as it did. */
.diagram.nm-map > .node-card:has(.out-item.open) {
  --nm-card-w: 100%;
}

/* Prose keeps its measure — 120 characters a line is still not a reading
   width, and that was never the problem. What was crushed at 74ch is
   everything that is NOT prose: a strategy plan is mostly wide markdown
   tables, budget grids and fenced blocks, and those are unreadable folded
   into a narrow column rather than merely tight. */
.node-card .out-item.nm-adopted .out-body > :is(table, pre, blockquote),
.node-card .out-item.nm-adopted .out-body > :is(div, section):has(table),
.node-card .out-item.nm-adopted .out-body > .table-wrap {
  max-width: none;
}

/* A wide table still must not push the page sideways. */
.node-card .out-item.nm-adopted .out-body > :is(table, pre) {
  overflow-x: auto;
  display: block;
}

/* The height cap exists so two open folders cannot push the map off the end
   of the page — a real concern, kept. But 640px is a letterbox for the one
   folder you are actually reading, so the folder in focus gets the taller
   allowance and the others keep the modest one. */
.diagram.nm-map > .node-card:has(.out-item.open) .out-item.nm-adopted .out-body {
  max-height: min(78vh, 1100px);
}
