/* public/desk-shape-b.css
 *
 * ⛔ PORTED VERBATIM FROM docs/ui/mockups_live/subleeva-desk-p2-shape-b-mockup.html
 *    (sha256 4cc8fff92be0780c…), lines 13–378, by EXTRACTION — not retyped and not
 *    reinterpreted. Master's instruction, 2026-09-17, via Desk Chat 8: "Every custom
 *    property, every class, every value, as written. Don't adapt the mockup to the
 *    existing system."
 *
 * ⚠ SCOPED UNDER .shape-b-root, AND THE SCOPE IS THE ONLY EDIT MADE TO THE RULES.
 *    The mockup styles bare element selectors and generic class names (.sheet, .bar,
 *    .drawer, .face, .grp, .rec, .nav-link) that ALREADY EXIST on eight other live
 *    Desk surfaces through DeskShell. Loading these rules globally would silently
 *    restyle every one of them — a blast radius nobody authorised and nobody would
 *    see until it shipped. Scoping keeps the port byte-faithful in VALUES while
 *    confining it to the surface Master asked for.
 *
 * ⚠ :root and body rules are re-pointed to .shape-b-root for the same reason. The
 *    custom properties themselves are unchanged, so every var() below resolves to
 *    the mockup's own value, not to subleeva-tokens.css's.
 */
.shape-b-root{--canvas:#EBE5D7;--surface:#FBF9F3;--field:#FFFFFF;--ivory-brand:#F7F4EC;
--border-strong:#857E6F;--border-soft:#DAD4C6;--text:#1C1B18;--text-secondary:#5C574C;
--text-placeholder:#6B655A;--state-mutation:#F59E0B;--state-mutation-ink:#92400E;
--state-success:#0E7A6C;--state-pending-tint:#FAEBCF;--field-error:#C2372B;
--provisional:#8A4B9E;--provisional-wash:#F1E7F5;
--radius-field:8px;--radius-card:12px;--row-height:36px;--target-min:24px;
--font-ui:"Inter",system-ui,sans-serif;--font-voice:"Source Serif 4",Georgia,serif;
--font-rec:"Source Code Pro",ui-monospace,Menlo,monospace;
--fs-meta:12px;--fs-small:13px;--fs-body:14px;--fs-section:16px;--fs-panel:20px;
--drawer-face:40px;--desk-base-reserve:calc(var(--drawer-face) + 14px);--doc-max:680px;
--sh-contact:0 1px 2px rgba(60,40,25,.10);--sh-ambient:0 8px 24px rgba(60,40,25,.10);
--sh-drawer:0 2px 6px rgba(60,40,25,.14),0 18px 44px rgba(60,40,25,.20);--brand:#A84B24}
.shape-b-root[data-theme=cobalt]{--accent:#2D5BFF;--accent-ink:#1E46E0;--accent-hover:#1E46E0;--accent-wash:#E4EAFF}

.shape-b-root *, .shape-b-root *::before, .shape-b-root *::after{box-sizing:border-box;margin:0;padding:0}
.shape-b-root, .shape-b-root{height:100%}
.shape-b-root{background:var(--canvas);color:var(--text);font:400 var(--fs-body)/1.5 var(--font-ui);
  font-feature-settings:"tnum" 1;-webkit-font-smoothing:antialiased;overflow:hidden}
@media (prefers-reduced-motion: reduce){ .shape-b-root *{animation:none!important;transition:none!important} }

.shape-b-root .shell{height:100vh;display:flex;flex-direction:column;background:var(--canvas)}

/* ---------------- §1 Masthead, verbatim from reference ---------------- */
/* DESK_SHARED_SHELL.md §3 — grid, not flex. A single flex row made
   the spine and icons compete for the same space, and the icons lost
   (pushed past the right edge, reading as never built) — a real,
   documented defect, not a style preference. Three independent zones:
   wordmark, centred spine, icon block. */
.shape-b-root .masthead{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;
  gap:12px;padding:16px;background:var(--canvas);flex-shrink:0}
.shape-b-root .spine-wrap{position:relative;min-width:0;display:flex;align-items:center;gap:2px}
/* Guaranteed fallback — after several gesture-based fixes that tested
   clean here but apparently didn't hold up in real use, a plain click
   on a real button is the one thing that can't be intercepted by a
   browser's own back-navigation gesture, an unfamiliar trackpad, or
   anything else in between. */
.shape-b-root .scroll-arrow{flex-shrink:0;width:26px;height:26px;border-radius:50%;border:1px solid var(--border-soft);
  background:var(--field);color:var(--text-secondary);font-size:15px;line-height:1;
  display:flex;align-items:center;justify-content:center;cursor:pointer}
.shape-b-root .scroll-arrow:hover{border-color:var(--accent-ink);color:var(--accent-ink)}
.shape-b-root .mh-icons{display:flex;align-items:center;gap:6px;justify-self:end}
.shape-b-root .icon-btn{display:flex;align-items:center;justify-content:center;width:32px;height:32px;
border-radius:50%;border:1px solid transparent;background:transparent;
color:var(--text-secondary);cursor:pointer;flex-shrink:0;padding:0}
/* §4 — the four-layer scroll-shadow, required not decorative. Two
   solid-fade layers (LOCAL, scroll with content) plus two shadow
   layers (SCROLL, pinned to the box) — cancels exactly at the true
   end so the affordance never lies about whether there's more to
   scroll. §4.1's real fade token for the phase spine specifically:
   var(--canvas) 30%, never copied from a different ground. */
.shape-b-root .spine{display:flex;gap:2px;padding:0 18px 8px;overflow-x:auto;min-width:0;cursor:grab;
  overscroll-behavior-x:contain;
  scrollbar-width:none;
  background-image:
    linear-gradient(to right, var(--canvas) 30%, transparent),
    linear-gradient(to left, var(--canvas) 30%, transparent),
    linear-gradient(to right, rgba(28,27,24,.18), transparent),
    linear-gradient(to left, rgba(28,27,24,.18), transparent);
  background-repeat:no-repeat;
  background-size:40px 100%, 40px 100%, 10px 100%, 10px 100%;
  background-position:left, right, left, right;
  background-attachment:local, local, scroll, scroll}
.shape-b-root .spine::-webkit-scrollbar{display:none}
.shape-b-root .sp{display:flex;align-items:center;gap:7px;padding:6px 12px;border-radius:6px;
font-size:var(--fs-small);white-space:nowrap;color:var(--text-secondary);font-weight:400}
.shape-b-root .sp .g{width:15px;height:15px;display:grid;place-items:center;font-size:10px}
.shape-b-root .sp.done .g{color:var(--state-success)}
/* Only the shared, pre-branch pillars are real nav links — see the
   design note where these are wired in. Cursor + underline, not
   colour alone. */
.shape-b-root .sp.nav-link{cursor:pointer;text-decoration:underline;text-underline-offset:2px}
.shape-b-root .sp.nav-link:hover{color:var(--accent-ink)}
.shape-b-root .sp.nav-link:hover .g{color:var(--accent-ink)}
.shape-b-root .sp.here{color:var(--text);font-weight:600;background:var(--state-mutation);
box-shadow:inset 0 -2px 0 var(--state-mutation-ink)}
.shape-b-root .sp.ahead{color:var(--text-secondary);border:1.5px dashed var(--border-strong);background:rgba(133,126,111,.06)}

/* ---------------- stage + sheet ---------------- */
.shape-b-root .stage{flex:1;position:relative;overflow:hidden}
.shape-b-root .stage-inner{position:absolute;inset:0;overflow:hidden;display:flex;justify-content:center;
  align-items:stretch;padding:22px 48px var(--desk-base-reserve)}
.shape-b-root .sheet{width:100%;max-width:var(--doc-max);background:var(--field);border-radius:10px;
  box-shadow:var(--sh-contact),var(--sh-ambient);overflow:hidden;display:flex;
  flex-direction:column;min-height:0}

/* ---------------- Advisor — TEXT DIRECTLY ON THE SHEET, no panel.
   Corrected per Al's direct instruction against the P4 artefact's
   layout: no border, no background box, no card-in-a-card treatment.
   Sits above the tally, differentiated by colour/typography alone —
   a muted uppercase eyebrow, serif voice text in full ink. Collapse
   duration slowed (was .28s, read as a snap) to match the feel of
   other Desk transitions (drawers use .55s). */
.shape-b-root .advisor{margin:16px 26px 0;flex-shrink:0;cursor:pointer}
.shape-b-root .adv-head{display:flex;align-items:center;justify-content:space-between}
.shape-b-root .adv-tag{color:var(--text-secondary);font-size:14px;font-weight:600;
letter-spacing:.05em;text-transform:uppercase}
.shape-b-root .adv-toggle{color:var(--text-secondary);font-size:var(--fs-meta);font-weight:600;background:none;
border:none;cursor:pointer;font-family:var(--font-ui);text-decoration:underline;text-underline-offset:2px}
/* Collapse animates a wrapper whose max-height is set from its own
   REAL measured scrollHeight in JS, not a guessed constant — the
   earlier snap was caused by animating through a large empty range
   (a guessed 220px against ~100px of real content) rather than the
   duration being too short. Starting from the true height means the
   whole 0.55s is spent on visible motion. */
.shape-b-root .adv-content{overflow:hidden;transition:max-height .55s cubic-bezier(.16,.84,.29,1)}
.shape-b-root .adv-body{color:var(--text-secondary);font-size:var(--fs-small);line-height:1.6;margin-top:6px}
.shape-b-root .adv-body b{font-weight:600}
/* The one serif moment per view — real, verified against the live
   bundle by CC (CommandDeckWorkspace.tsx:139), currently unwritten
   in any governing doc. Title only; body stays Inter above. */
.shape-b-root .adv-title{font:600 var(--fs-body) var(--font-voice);color:var(--text);margin-top:8px}

/* ---------------- provisional badge — real UI marker ---------------- */
.shape-b-root .pane-status{padding:14px 26px 0;font-size:var(--fs-meta);color:var(--text-secondary)}
.shape-b-root .pane-status b{color:var(--text);font-weight:600}

/* ---------------- Tally — subtly differentiated from the advisor
   above by a feint divider and a soft tint band, NOT a bordered
   panel/card. Full-bleed to the sheet's own edges rather than an
   inset box, so it reads as a distinct zone without looking like
   another nested container.

   Fully dynamic now, per Al's instruction — the earlier "77
   allocation" ceiling figure had no traceable source and is gone
   entirely, not replaced with a different static number. Organisation
   and cluster counts are computed live from the real groups/rows
   data; "removed by you" only appears once something's actually been
   removed. The note ties the organisation count to WHY it's that
   number — the subscription's lead-goal — rather than framing it as
   an arbitrary ceiling, and uses the same live count as the figure
   above it so the two can never disagree. */
.shape-b-root .tally{margin-top:16px;padding:12px 26px 14px;border-top:1px solid rgba(133,126,111,.22);
  border-bottom:1px solid var(--border-soft);position:relative;z-index:1;
  box-shadow:0 3px 8px rgba(58,46,34,.12), 0 10px 24px rgba(58,46,34,.09);
  background:var(--ivory-brand)}
.shape-b-root .tally-figs{display:flex;gap:20px;font-family:var(--font-rec)}
.shape-b-root .tally-fig b{display:block;font-size:var(--fs-panel);line-height:1.1;color:var(--text)}
.shape-b-root .tally-fig span{font-size:var(--fs-meta);color:var(--text-secondary)}
.shape-b-root .tally-note{margin-top:6px;font-family:var(--font-rec);font-size:var(--fs-meta);color:var(--text-secondary)}

/* ---------------- §4 Field workspace — THE THREE-ZONE RULE (D410) ----------------
   background is --canvas, deliberately distinct from the --field sheet
   around it and the --surface bar below it. This is the exact zone
   v1 got wrong by leaving it --field/--surface throughout. */
.shape-b-root .work{padding:0 0 var(--desk-base-reserve);flex:1;min-height:0;
overflow-y:scroll;scrollbar-gutter:stable;background:
linear-gradient(rgba(0,0,0,0),var(--canvas) 65%) center bottom / 100% 64px local no-repeat,
radial-gradient(farthest-side at 50% 100%,rgba(20,16,8,.4),rgba(20,16,8,0)) center bottom / 100% 32px scroll no-repeat var(--canvas)}
.shape-b-root .work::-webkit-scrollbar{width:4px}
.shape-b-root .work::-webkit-scrollbar-track{background:transparent}
.shape-b-root .work::-webkit-scrollbar-thumb{background:var(--border-strong);border-radius:2px}

/* ---------------- Shape B rows — compact density (§10), sitting as
   --field cards against the --canvas work zone so they read as the
   active working surface, matching the general Desk rule that a
   working surface must never look "greyed out" against its ground. */
/* No pill/card treatment — clusters are flush, full-width rows
   separated by a hairline, not bordered boxes with gaps between
   them. Screen real estate matters more than the card metaphor here. */
.shape-b-root .cluster{border-bottom:1px solid var(--border-soft);background:var(--field)}
.shape-b-root .cluster-head{display:flex;align-items:baseline;gap:8px;padding:12px 16px;cursor:pointer;
  user-select:none;min-height:var(--target-min)}
.shape-b-root .cluster-head:hover{background:var(--ivory-brand)}
.shape-b-root .cluster-glyph{width:16px;text-align:center;color:var(--text-secondary);font-size:15px;flex-shrink:0}
/* Single row: name, description inline beside it (not stacked), stat
   right-aligned. Description truncates rather than wrapping or
   pushing the row to a second line. */
.shape-b-root .cluster-name{font:600 var(--fs-body) var(--font-ui);flex:0 0 auto;white-space:nowrap}
.shape-b-root .cluster-desc{font:400 var(--fs-meta) var(--font-ui);color:var(--text-secondary);
  flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.shape-b-root .cluster-stat{font-family:var(--font-rec);font-size:var(--fs-meta);color:var(--text-secondary);
  white-space:nowrap;flex:0 0 auto}
/* §20.1 — a cluster that found nothing gets a stated reason, not a
   colour change alone. The reason text itself is the second channel. */
.shape-b-root .cluster-stat.empty{font-style:italic}
/* §20.1 absence text is also a teaching-voice body, not a title —
   Inter, same rule as .org-detail-prose below. The advisor's own
   title carries this view's one serif moment; this doesn't add one. */
.shape-b-root .cluster-absence{padding:10px 16px 12px 34px;font-size:var(--fs-body);
  line-height:1.5;color:var(--text-secondary);background:repeating-linear-gradient(135deg,var(--surface),var(--surface) 8px,rgba(133,126,111,.10) 8px,rgba(133,126,111,.10) 16px)}
.shape-b-root .cluster-body{border-top:1px solid var(--border-soft)}

.shape-b-root .org-row{display:flex;align-items:center;gap:8px;padding:12px 16px 12px 46px;
  border-top:1px solid var(--border-soft);cursor:pointer;min-height:var(--target-min)}
.shape-b-root .org-row:first-child{border-top:none}
.shape-b-root .org-row:hover{background:var(--ivory-brand)}
.shape-b-root .org-name{font:500 var(--fs-small) var(--font-ui);flex-shrink:0}
.shape-b-root .org-sub{font:400 var(--fs-meta) var(--font-ui);color:var(--text-secondary);overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0}

.shape-b-root .org-detail{padding:10px 16px 12px 34px;border-top:1px solid var(--border-soft);background:var(--ivory-brand)}
.shape-b-root .org-detail-row{display:flex;gap:8px;font-size:var(--fs-small);margin-bottom:5px}
.shape-b-root .org-detail-row .k{color:var(--text-secondary);width:90px;flex-shrink:0}
/* Per the ratified "one serif moment per view" rule (DESK_PATTERN.md
   §4) — this is a teaching-voice BODY, not a title, so it stays Inter
   like everything else in the workspace. The advisor's own title
   (.adv-title, above) carries this view's one serif moment; this
   text does not duplicate it. */
.shape-b-root .org-detail-prose{font-size:var(--fs-body);line-height:1.5;margin:8px 0}
.shape-b-root .org-remove{font:500 var(--fs-small) var(--font-ui);color:var(--field-error);background:none;
  border:1px solid var(--field-error);border-radius:6px;padding:5px 10px;cursor:pointer}

/* ---------------- §5 Approve bar, verbatim structure from reference,
   upward shadow added per DESK_PATTERN.md §6.3 + literal value from
   DESK_CHROME_AND_CONTROLS_STANDARD.md:328 ---------------- */
.shape-b-root .bar{flex-shrink:0;border-top:2px solid var(--border-strong);padding:14px 24px;
background:var(--surface);display:flex;align-items:center;gap:16px;
box-shadow:0 -3px 8px rgba(58,46,34,.12), 0 -10px 24px rgba(58,46,34,.09)}
.shape-b-root .bar-main{flex:1 1 auto;min-width:0}
.shape-b-root .btn-primary{background:var(--accent);color:#fff;border:none;border-radius:var(--radius-field);
min-height:var(--row-height);padding:0 16px;font:500 var(--fs-body) var(--font-ui);
display:inline-flex;align-items:center;cursor:pointer}
.shape-b-root .lede{font-size:var(--fs-small);color:var(--text-secondary);margin-top:6px}

/* ---------------- §6 Drawer geometry, verbatim from reference ---------------- */
.shape-b-root .scrim{position:absolute;inset:0;z-index:4;background:transparent;opacity:0;
pointer-events:none;transition:opacity .5s ease}
.shape-b-root .scrim.on{background:rgba(28,27,24,0.06);opacity:1;pointer-events:auto}
.shape-b-root .drawer{position:absolute;z-index:5;background:var(--surface);display:flex;overflow:hidden;
box-shadow:0 0 0 rgba(0,0,0,0);
transition:transform .55s cubic-bezier(.16,.84,.29,1),box-shadow .55s cubic-bezier(.16,.84,.29,1)}
.shape-b-root .drawer.left{left:0;top:0;bottom:0;width:min(340px,82vw);flex-direction:row;
transform:translateX(calc(-100% + var(--drawer-face)))}
.shape-b-root .drawer.right{right:0;top:0;bottom:0;width:min(320px,82vw);flex-direction:row;
transform:translateX(calc(100% - var(--drawer-face)))}
.shape-b-root .drawer.bottom{left:0;right:0;bottom:0;max-height:62vh;flex-direction:column;
transform:translateY(calc(100% - var(--drawer-face)))}
.shape-b-root .drawer.open.left, .shape-b-root .drawer.open.right{transform:translateX(0);box-shadow:var(--sh-drawer)}
.shape-b-root .drawer.open.bottom{transform:translateY(0);box-shadow:var(--sh-drawer)}
.shape-b-root .face{flex-shrink:0;background:var(--surface);cursor:pointer;position:relative;display:flex;
align-items:center;justify-content:center;color:var(--text-secondary);border:none;padding:0}
.shape-b-root .drawer.left .face{width:var(--drawer-face);order:2;border-left:1px solid var(--border-soft)}
.shape-b-root .drawer.right .face{width:var(--drawer-face);order:1;border-right:1px solid var(--border-soft)}
.shape-b-root .drawer.bottom .face{height:var(--drawer-face);order:1;border-bottom:1px solid var(--border-soft)}
/* THE REAL BUG, found via actual rendered inspection (Playwright),
   not guessed: .face had explicit order values but .d-body never
   did, defaulting to order:0. Flex items sort by order ascending
   regardless of DOM order. Left drawer worked by accident (0 sorts
   before face's 2, which happens to be the correct arrangement for
   that side). Right and bottom did NOT — d-body's default 0 sorted
   BEFORE face's 1, so d-body ended up in the visible closed-state
   sliver instead of face. This is why the bottom drawer's full
   content rendered visibly, and why the right drawer was almost
   certainly showing the same defect, just less obviously. */
.shape-b-root .drawer.left .d-body{order:1}
.shape-b-root .drawer.right .d-body{order:2}
.shape-b-root .drawer.bottom .d-body{order:2}
.shape-b-root .face-label{font-size:var(--fs-meta);letter-spacing:.08em;text-transform:uppercase;
font-weight:600;writing-mode:vertical-rl}
.shape-b-root .drawer.left .face-label{transform:rotate(180deg)}
.shape-b-root .drawer.bottom .face-label{writing-mode:horizontal-tb}
/* Real, live values — confirmed by CC against DeskShell.tsx:81-92 AND
   the served bundle (sha256 d280d8ea..., byte offset 960502), not
   derived from the written spec alone. My earlier version set
   vertical centring but never set an actual horizontal inset at all
   — no right:5px for left, no left:5px for right — so the handle had
   no real defined horizontal position. Also missing the real two-part
   shadow. Fixed to the exact confirmed values below. */
.shape-b-root .handle{position:absolute;background:var(--ivory-brand);border:1px solid var(--border-soft);
border-radius:100px;box-shadow:inset 0 1px 0 rgba(255,255,255,0.6), 0 1px 1px rgba(60,40,25,0.08)}
.shape-b-root .drawer.bottom .handle{cursor:ns-resize}
.shape-b-root .drawer.left .handle{width:5px;height:34px;right:5px;top:50%;transform:translateY(-50%)}
.shape-b-root .drawer.right .handle{width:5px;height:34px;left:5px;top:50%;transform:translateY(-50%)}
.shape-b-root .drawer.bottom .handle{width:34px;height:5px;top:5px;left:50%;transform:translateX(-50%)}
.shape-b-root .d-body{overflow-y:auto;flex:1;min-height:0;padding:16px 18px 22px}
.shape-b-root .grp{margin-bottom:18px}
.shape-b-root .grp h4{font-size:var(--fs-meta);letter-spacing:.06em;text-transform:uppercase;
color:var(--text-secondary);font-weight:600;margin-bottom:8px;padding-bottom:5px;
border-bottom:1px solid var(--border-soft)}
.shape-b-root .rec{display:flex;justify-content:space-between;gap:12px;padding:4px 0;
font-size:var(--fs-small);align-items:baseline}
.shape-b-root .rec .k{color:var(--text-secondary);flex-shrink:0}
.shape-b-root .rec .v{font-family:var(--font-rec);text-align:right;min-width:0;overflow-wrap:anywhere;color:var(--text)}
/* Per the ratified "one serif moment per view" rule — this drawer
   prose is a teaching-voice body, same class of fix as Lede and the
   other two instances already corrected. The advisor's title carries
   this view's one serif moment; this doesn't add a second. */
.shape-b-root .serif{font-size:var(--fs-small);line-height:1.58;color:var(--text-secondary)}
.shape-b-root .progrow{display:flex;gap:11px;padding:7px 0;align-items:center}
/* Drawer as nav tool — completed steps and key identifiers are real
   navigation, not just record. Two-channel affordance (underline +
   cursor), not colour alone: this is the same accessibility rule
   already applied to the advisor toggle. */
.shape-b-root .nav-link{cursor:pointer;text-decoration:underline;text-underline-offset:2px}
.shape-b-root .nav-link:hover{color:var(--accent-ink)}
.shape-b-root .progrow.nav-link:hover .l{color:var(--accent-ink)}
.shape-b-root .progrow.nav-link{cursor:pointer}
.shape-b-root .progrow .g{width:18px;height:18px;border-radius:50%;display:grid;place-items:center;
font-size:10px;flex-shrink:0}
.shape-b-root .progrow .l{font-size:var(--fs-small);font-weight:400;color:var(--text-secondary)}
.shape-b-root .progrow.done .g{background:var(--surface);color:var(--state-success);border:1px solid var(--state-success)}
.shape-b-root .progrow.progress .g{background:var(--accent-wash);color:var(--accent-ink);border:2px solid var(--accent)}
.shape-b-root .progrow.progress .l{font-weight:500;color:var(--text)}
.shape-b-root .progrow.pending .g{background:transparent;color:var(--text-secondary);border:1px dashed var(--border-strong)}

/* The Map — rooms only where the pipeline's genuinely produced
   something, one door for the immediate next step, nothing beyond it
   drawn at all. "Visited" is a separate, per-user layer on top of the
   shared room state — the room existing and the user having opened it
   are two different facts, not one. */
.shape-b-root .map-room{display:flex;gap:11px;padding:9px 0;align-items:flex-start}
.shape-b-root .map-room.nav-link{cursor:pointer}
.shape-b-root .map-room.nav-link:hover .map-name{color:var(--accent-ink)}
.shape-b-root .map-g{width:18px;height:18px;border-radius:50%;display:grid;place-items:center;
  font-size:10px;flex-shrink:0;margin-top:1px}
.shape-b-root .map-room.visited .map-g{background:var(--surface);color:var(--state-success);border:1px solid var(--state-success)}
.shape-b-root .map-room.here .map-g{background:var(--accent-wash);color:var(--accent-ink);border:2px solid var(--accent)}
.shape-b-root .map-body{display:flex;flex-direction:column}
.shape-b-root .map-name{font-size:var(--fs-small);font-weight:500;color:var(--text)}
.shape-b-root .map-room.here .map-name{font-weight:600}
.shape-b-root .map-sub{font-size:var(--fs-meta);color:var(--text-secondary);margin-top:1px}
/* The door — §20's honest-absence vocabulary: a real, stated
   invitation, not a locked-looking placeholder and not clickable.
   Hatched fill + dashed border + hollow glyph, never colour alone. */
.shape-b-root .map-door{display:flex;gap:11px;padding:9px 0;align-items:flex-start;
  background:repeating-linear-gradient(135deg,transparent,transparent 8px,rgba(133,126,111,.08) 8px,rgba(133,126,111,.08) 16px);
  border-radius:6px;padding-left:8px;margin-left:-8px}
.shape-b-root .map-door .map-g{background:transparent;color:var(--text-secondary);border:1.5px dashed var(--border-strong)}
.shape-b-root .map-door .map-name{color:var(--text-secondary);font-weight:500}
.shape-b-root .map-door .map-sub{font-style:italic}

/* ---------------- The Map — left-to-right branching tree ----------------
   Nodes are a real parent/child structure (an id + explicit parent_id
   per node), not "generation N connects to generation N+1" — that
   assumption breaks the moment two branches run to different depths,
   which is exactly what real campaign fan-out does (one campaign can
   be stages ahead of another). Connector lines are drawn as an SVG
   overlay, computed from each node's REAL rendered position after
   layout, from its actual parent — not inferred from column order. */
.shape-b-root .map-title{padding:14px 18px 4px;font-size:var(--fs-meta);font-weight:600;letter-spacing:.06em;
  text-transform:uppercase;color:var(--text-secondary)}
.shape-b-root .map-d-body{padding:0 0 16px;position:relative}

.shape-b-root .toast{position:fixed;left:50%;bottom:24px;transform:translate(-50%,10px);background:var(--text);
  color:#fff;font-size:var(--fs-small);font-weight:500;padding:9px 16px;border-radius:8px;
  opacity:0;pointer-events:none;transition:opacity .3s ease,transform .3s ease;z-index:20;
  max-width:80%;text-align:center;line-height:1.4}
.shape-b-root .toast.on{opacity:1;transform:translate(-50%,0)}

/* ═══ ADDITIONS — NOT PART OF THE PORTED REGION ABOVE ═══
 *
 * ⚠ KEPT BELOW THE PORT, AND SEPARATELY LABELLED, so the extracted region stays
 *   byte-comparable against the mockup. Nothing above this line was edited.
 *
 * The mockup's `.org-remove` is always live, because in the mockup removal works.
 * In the real app NO ENDPOINT REMOVES AN ORGANISATION FROM A CONFIRMED COHORT, so
 * the control ships disabled with adjacent text (ADR-131 §1). Rendered against the
 * real component it still LOOKED clickable — full-strength error red, normal
 * cursor — which is the state-blocked failure ADR-131 §1 exists to prevent.
 * Caught by photographing the rendered surface, not by reading the markup.
 */
.shape-b-root .org-remove[disabled]{opacity:.45;cursor:default}
.shape-b-root .org-remove[disabled]:hover{background:none}

/* ⚠ THE LABEL COLUMN IS WIDENED FOR A LABEL THE MOCKUP NEVER HAD. Its own
 * detail keys are "Legal name", "Website", "Based", "Generated" — all of which
 * fit 90px. "Entered cohort" does not, and wrapped onto two lines against the
 * ported width, which looked like a rendering fault rather than a longer label.
 *
 * ⛔ IN THE ADDITIONS BLOCK, NOT THE PORTED REGION, so the extracted CSS stays
 * byte-comparable against the artefact. The mockup's value is unchanged above;
 * this overrides it only where the ported region is not the whole story.
 * Caught by photographing the rendered surface, not by reading the markup. */
.shape-b-root .org-detail-row .k{width:106px}

/* ⛔ THE TREE HALF OF THIS SELECTOR MOVED to public/desk-map.css — [[D517]].
   `.spine` is a MASTHEAD element and stays scoped to this root. */
.shape-b-root .spine.dragging{cursor:grabbing;user-select:none}