/*
  Shared styles for the Domain-Driven Design site.
  Approved visual style: dark navy neon, glass panels with a little glare, no stars.
  Fonts: Sora (headings), IBM Plex Sans (body), IBM Plex Mono (code).
  Notation: violet = bounded context wall, teal = aggregate wall,
            coral = door (encapsulation point), blue = building block and wires,
            dashed line = reference by id.
  First ported from the approved design sample, which was retired once every
  page-content bead had landed (bead d43); the site itself is now the reference.
*/

:root {
  color-scheme: dark;
  --bg: #060A14;
  --ink: #EEF3FF;
  --ink-2: #B3BFD9;
  --ink-3: #7483A5;
  --line: rgba(140, 170, 255, .14);
  --line-strong: rgba(140, 170, 255, .30);
  --panel: rgba(11, 17, 33, .74);
  --panel-top: rgba(255, 255, 255, .045);

  --strat: #B69CFF;
  --strat-soft: #D8CBFF;
  --strat-glow: rgba(160, 130, 255, .55);
  --strat-wash: rgba(160, 130, 255, .07);
  --tact: #2FE6C8;
  --tact-soft: #A0F6E6;
  --tact-glow: rgba(47, 230, 200, .5);
  --tact-wash: rgba(47, 230, 200, .07);
  --door: #FF7B54;
  --door-soft: #FFC6B3;
  --door-glow: rgba(255, 110, 70, .6);
  --door-wash: rgba(255, 123, 84, .10);
  --door-fill: #1B0F12;
  --block: #5C9DFF;
  --block-soft: #A9CBFF;
  --block-glow: rgba(80, 150, 255, .5);
  /* Reference rules (bead dcg.7.4): the blocked marker for a forbidden path.
     Deliberately not coral or teal, so it is never mistaken for a door or an
     aggregate wall even before its crossed-circle shape and label are read. */
  --blocked: #FF4D6D;
  --blocked-soft: #FFB3C1;
  --blocked-glow: rgba(255, 77, 109, .55);
  --blocked-wash: rgba(255, 77, 109, .09);
  --wire: #4F7FD6;
  --wire-lit: #B5D3FF;
  --node-fill: #0C1326;
  --dep: #E4EBFF;
  --dep-glow: rgba(190, 210, 255, .45);
  /* Subdomains (bead dcg.6.2): a quiet warm grey tile, and gold / steel grey
     type markers, kept apart from the wall, door and block colours. */
  --sub-fill: rgba(12, 19, 38, .85);
  --sub-stroke: rgba(214, 204, 176, .40);
  --sub-stroke-strong: rgba(226, 218, 196, .70);
  --sub-gold: #FFC94D;
  --sub-gold-soft: #FFE3A1;
  --sub-gold-glow: rgba(255, 195, 70, .5);
  --sub-gold-wash: rgba(255, 201, 77, .08);
  --sub-grey: #A9B4CB;
  /* Context map (bead dcg.6.5): systems outside the shop's control. */
  --ext: #8391B0;
  --ext-soft: #C3CCDF;
  --code-inline: rgba(140, 170, 255, .12);
  --syn-k: #C3A6FF;
  --syn-t: #72E4F7;
  --syn-s: #FFD27A;
  --syn-c: #6A7899;

  --display: "Sora", "Segoe UI", system-ui, sans-serif;
  --sans: "IBM Plex Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --mono: "IBM Plex Mono", ui-monospace, Consolas, "Courier New", monospace;
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  color: var(--ink);
  background-color: var(--bg);
  background-image:
    radial-gradient(1100px 620px at 28% -8%, rgba(56, 120, 255, .20), transparent 62%),
    radial-gradient(760px 520px at 92% 16%, rgba(150, 110, 255, .14), transparent 62%),
    radial-gradient(900px 700px at 50% 60%, rgba(40, 200, 220, .06), transparent 65%);
  background-attachment: fixed;
  font: 400 17px/1.65 var(--sans);
  -webkit-font-smoothing: antialiased;
}
a:focus-visible, button:focus-visible, [tabindex]:focus-visible { outline: 2px solid var(--block-soft); outline-offset: 2px; }
.wrap { max-width: 1140px; margin-inline: auto; padding-inline: 24px; }
code { font-family: var(--mono); font-size: .9em; color: var(--ink); background: var(--code-inline); padding: 1px 6px; border-radius: 5px; }
.eyebrow {
  font: 600 12px/1.2 var(--sans);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin: 0 0 14px;
}
.eyebrow.tact, .eyebrow[data-tone="tact"] { color: var(--tact); text-shadow: 0 0 14px var(--tact-glow); }
.eyebrow.door, .eyebrow[data-tone="door"] { color: var(--door); text-shadow: 0 0 14px var(--door-glow); }
.eyebrow[data-tone="strat"] { color: var(--strat); text-shadow: 0 0 14px var(--strat-glow); }
.eyebrow[data-tone="block"] { color: var(--block); text-shadow: 0 0 14px var(--block-glow); }
.eyebrow.door { display: flex; align-items: center; gap: 8px; }
.icon { width: 18px; height: 18px; flex: none; }

.glass {
  position: relative;
  background: linear-gradient(180deg, var(--panel-top), transparent 45%), var(--panel);
  border: 1px solid var(--line);
  border-radius: 18px;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .05), 0 30px 80px -40px rgba(0, 0, 0, .9);
  backdrop-filter: blur(12px);
}
.glass::before {
  content: "";
  position: absolute;
  top: -1px;
  left: 12%;
  right: 12%;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(170, 205, 255, .6), transparent);
  pointer-events: none;
}

/* Header */
.site-header {
  position: sticky;
  top: 0;
  z-index: 10;
  background: rgba(6, 10, 20, .68);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--line);
}
.header-inner { display: flex; align-items: center; gap: 24px; min-height: 64px; }
.brand {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  color: var(--ink);
  text-decoration: none;
  font: 500 18px/1.2 var(--display);
  letter-spacing: -.01em;
}
.brand small { font: 400 13px var(--sans); color: var(--ink-3); letter-spacing: 0; }
/* Where the folded landing illustration sits, in place of a brand mark (bead dcg.3.3).
   40px is the size the illustration's mini layer is drawn for. */
.fold-slot { width: 40px; height: 40px; overflow: visible; flex: none; }
/* It is also the "Back to the start" button (bead dcg.3.7). The click area
   stretches over the whole brand, so the site name still leads back to the
   start, while keyboard and screen reader users meet one control. */
button.fold-slot {
  display: block;
  padding: 0;
  border: 0;
  border-radius: 10px;
  background: none;
  color: inherit;
  font: inherit;
  cursor: pointer;
}
button.fold-slot::after { content: ""; position: absolute; inset: 0; }
/* The page heading receives focus after a fold, so screen readers read where
   they are; it is not a control, so it gets no focus ring. */
.view h1[tabindex="-1"]:focus,
.view h2[tabindex="-1"]:focus,
.view h3[tabindex="-1"]:focus,
.view [data-section][tabindex="-1"]:focus { outline: none; }
.main-nav { display: flex; gap: 6px; margin-left: auto; }
.main-nav a {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 7px 15px;
  border-radius: 10px;
  color: var(--ink-2);
  text-decoration: none;
  font-size: 15px;
  font-weight: 500;
}
.main-nav a:hover { color: var(--ink); background: rgba(255, 255, 255, .05); }
.main-nav a::before { content: ""; width: 9px; height: 9px; border-radius: 2px; border: 1.6px solid var(--strat); box-shadow: 0 0 8px var(--strat-glow); }
.main-nav a.nav-tact::before { border-color: var(--tact); box-shadow: 0 0 8px var(--tact-glow); }
.main-nav a[aria-current="page"],
html[data-boot="tactical"] .main-nav a.nav-tact {
  color: var(--tact-soft);
  background: var(--tact-wash);
  box-shadow: inset 0 0 0 1px rgba(47, 230, 200, .45), 0 0 22px -6px var(--tact-glow);
}
.main-nav a.nav-strat[aria-current="page"],
html[data-boot="strategic"] .main-nav a.nav-strat {
  color: var(--strat-soft);
  background: var(--strat-wash);
  box-shadow: inset 0 0 0 1px rgba(182, 156, 255, .45), 0 0 22px -6px var(--strat-glow);
}

/* Views: hash-routed, one visible at a time */
.view[hidden] { display: none; }
/* First paint (bead dcg.3.4). Until app.js has run, the markup alone would show
   the landing with the header. An inline script in index.html's <head> marks the
   view the URL asks for on <html data-boot>, so the first paint already matches
   the state app.js sets: a deep link shows its page (and its tab as active, above),
   the landing shows without header and footer. app.js removes data-boot once that
   state is set, and from then on these rules no longer apply. */
html[data-boot="landing"] .site-header,
html[data-boot="landing"] .site-footer,
html[data-boot="strategic"] #view-landing,
html[data-boot="tactical"] #view-landing { display: none; }
html[data-boot="strategic"] #view-strategic,
html[data-boot="tactical"] #view-tactical { display: block; }

/* Illustration: shared by the landing-illustration concepts in
   site/illustration-concepts.html. One <svg class="ill"> holds both sizes,
   in <g data-layer="..."> layers. Add .is-mini to show the 40px version: every [data-detail]
   layer is hidden and the "mini" layer (drawn on a 40 x 40 grid, scaled by 16
   onto the same 640 x 640 viewBox) is shown instead. Concept C (Calm core) is
   the one in use on the landing view (bead dcg.3.6); illustration-concepts.html
   keeps its own copy of this block with the original hard-coded colours so it
   still renders unchanged if the user switches concepts later. */
.ill { display: block; width: 100%; height: auto; overflow: visible; }

.ill-halo-a { stop-color: var(--block); stop-opacity: .30; }
.ill-halo-b { stop-color: var(--strat); stop-opacity: .13; }
.ill-halo-c { stop-color: var(--strat); stop-opacity: 0; }
.ill-room-a { stop-color: var(--tact); stop-opacity: .10; }
.ill-room-b { stop-color: var(--strat); stop-opacity: .05; }

.ill-tangle-wires, .ill-tangle-parts { filter: drop-shadow(0 0 5px var(--block-glow)); }
.ill-loop, .ill-xwire { fill: none; stroke: var(--wire); stroke-linecap: round; }
.ill-tangle-over .ill-xwire { stroke: var(--block); }
.ill-tdot { fill: var(--block-soft); }
.ill-comp { fill: var(--node-fill); stroke: var(--block); stroke-width: 1.5; }
.ill-comp-line { fill: none; stroke: var(--block-soft); stroke-width: 1.4; stroke-linecap: round; opacity: .55; }

.ill-wall { fill: rgba(8, 12, 26, .55); stroke: var(--strat); stroke-width: 2.2; filter: drop-shadow(0 0 10px var(--strat-glow)); }
.ill-agg { fill: var(--tact-wash); stroke: var(--tact); stroke-width: 2; filter: drop-shadow(0 0 8px var(--tact-glow)); }
.ill-block { fill: var(--node-fill); stroke: var(--block); stroke-width: 1.6; filter: drop-shadow(0 0 6px var(--block-glow)); }
.ill-block-line { fill: none; stroke: var(--block-soft); stroke-width: 1.6; stroke-linecap: round; opacity: .7; }
.ill-wire { fill: none; stroke: var(--block-soft); stroke-width: 1.6; stroke-dasharray: 4 6; opacity: .85; animation: ill-flow 1.4s linear infinite; }
.ill-dot { fill: var(--block-soft); filter: drop-shadow(0 0 5px var(--block-glow)); }
.ill-entry { fill: none; stroke: var(--wire-lit); stroke-width: 1.8; opacity: .6; filter: drop-shadow(0 0 4px var(--block-glow)); }
.ill-entry-flow { fill: none; stroke: var(--ink); stroke-width: 2; stroke-linecap: round; stroke-dasharray: 2 18; opacity: .85; animation: ill-flow-far 2.2s linear infinite; }
.ill-door { fill: var(--door-fill); stroke: var(--door); stroke-width: 2.2; filter: drop-shadow(0 0 8px var(--door-glow)); animation: ill-door 3.6s ease-in-out infinite; }

.ill-draft-plan { fill: none; stroke: var(--strat); stroke-width: 1.2; opacity: .22; }
.ill-draft-line { fill: none; stroke: var(--strat); stroke-width: 2; stroke-linecap: round; opacity: .8; filter: drop-shadow(0 0 8px var(--strat-glow)); }
.ill-pen { fill: var(--strat-soft); }
.ill-pen-glow { fill: var(--strat-glow); transform-box: fill-box; transform-origin: center; animation: ill-pen 2.4s ease-in-out infinite; }

@keyframes ill-flow { to { stroke-dashoffset: -20; } }
@keyframes ill-flow-far { to { stroke-dashoffset: -40; } }
@keyframes ill-door { 50% { filter: drop-shadow(0 0 18px var(--door-glow)); } }
@keyframes ill-pen { 50% { transform: scale(1.7); opacity: .2; } }

/* Illustration: 40px version */
.ill-mini { display: none; }
.ill.is-mini [data-detail] { display: none; }
.ill.is-mini .ill-mini { display: inline; }
.ill-m-knot { fill: none; stroke: var(--block); stroke-width: 1.3; stroke-linejoin: round; filter: drop-shadow(0 0 .6px var(--block-glow)); }
.ill-m-knot-2 { stroke: var(--block-soft); stroke-width: .7; opacity: .55; }
.ill-m-wall { fill: var(--node-fill); stroke: var(--strat); stroke-width: 1.5; filter: drop-shadow(0 0 .8px var(--strat-glow)); }
.ill-m-agg { fill: none; stroke: var(--tact); stroke-width: 1; }
.ill-m-door { fill: var(--door); filter: drop-shadow(0 0 .8px var(--door-glow)); animation: ill-m-door 3.6s ease-in-out infinite; }
@keyframes ill-m-door { 50% { filter: drop-shadow(0 0 2px var(--door-glow)); } }

@media (prefers-reduced-motion: reduce) {
  .ill, .ill * { animation: none !important; }
}

/* Landing view: full-screen hero before a page is chosen (bead dcg.3.6).
   The header and footer are hidden here. Opening a page folds the
   illustration into the header's #fold-slot (see "Fold and unfold" below). */
body[data-view="landing"] .site-header,
body[data-view="landing"] .site-footer { display: none; }

.landing {
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: clamp(14px, 2.6vh, 28px);
  padding: clamp(20px, 5vh, 56px) 24px;
  text-align: center;
}
.landing-title { margin: 0; font-size: clamp(28px, 6.2vmin, 52px); max-width: 18ch; }
.landing-tagline { max-width: 46ch; font-size: clamp(14.5px, 2.1vmin, 18px); }
.landing-hero {
  display: block;
  /* A <button> (bead dcg.3.7): drop the native button look. */
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  /* As large as the space left under the title, tagline and hint allows. */
  width: max(180px, min(640px, 86vw, calc(100dvh - 320px)));
  /* Keeps its square size while the illustration is away in the header. */
  aspect-ratio: 1 / 1;
  cursor: pointer;
  border-radius: 40px;
  outline-offset: 6px;
  transition: filter .25s ease, transform .25s ease;
}
.landing-hero:hover, .landing-hero:focus-visible {
  filter: drop-shadow(0 0 32px var(--block-glow));
  transform: scale(1.02);
}
.landing-hint { margin: 0; font-size: 13px; color: var(--ink-3); }
@media (prefers-reduced-motion: reduce) {
  .landing-hero { transition: none; }
  .landing-hero:hover, .landing-hero:focus-visible { transform: none; }
}

/* Fold and unfold (bead dcg.3.3, driven by site/assets/app.js).
   At rest the one illustration <svg> sits in the landing hero (body[data-fold="unfolded"])
   or, with .is-mini, in the header's #fold-slot (body[data-fold="folded"]). While it
   moves (body[data-fold="moving"]) it rides in .fold-flyer, a fixed box laid out at
   the landing size whose transform carries it between the two rects. Both layouts
   exist during the move: the page and header in flow, as they will be when folded,
   and the landing as a fixed overlay, as it will be when unfolded. */
.fold-flyer {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 30;
  transform-origin: 0 0;
  cursor: pointer;
}
.fold-flyer[hidden] { display: none; }
.fold-flyer .ill { transform-origin: 50% 50%; }
/* A copy of the mini layer on top of the detailed drawing, for the cross-fade. */
.fold-flyer-mini { position: absolute; top: 0; left: 0; }
/* The ambient loops hold still during the move, so the drawing is not repainted. */
.fold-flyer .ill, .fold-flyer .ill * { animation-play-state: paused; }

body[data-fold="moving"] #view-landing {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 20;
  /* 100vw, not 100%: the landing is laid out as it will be once the page (and
     any scrollbar it brings) is gone again. */
  width: 100vw;
}
body[data-fold="moving"] .landing-hero { transform: none; filter: none; transition: none; }
body[data-fold="moving"] .site-header,
body[data-fold="moving"] main,
body[data-fold="moving"] .site-footer { pointer-events: none; }

/* Hero */
.hero { padding-block: 56px 28px; }
.hero-grid { display: grid; grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr); gap: 40px; align-items: center; }
/* Zoom breadcrumb (bead dcg.5, built by components.js from sections.js). The same
   five levels on both pages; the levels a page is about are lit in their notation
   colour (violet for the strategic walls, teal inside an aggregate). */
.zoom { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; margin-bottom: 40px; }
.zoom-label { font-size: 13px; color: var(--ink-3); }
.zoom ol { list-style: none; display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin: 0; padding: 0; font-size: 13px; }
.zoom li.lvl a {
  display: flex;
  align-items: center;
  gap: 7px;
  min-height: 28px;
  padding: 3px 11px 3px 9px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: rgba(255, 255, 255, .02);
  color: var(--ink-3);
  text-decoration: none;
  transition: color .15s, border-color .15s, background-color .15s;
}
.zoom li.lvl a::before { content: ""; width: 9px; height: 9px; border-radius: 2px; border: 1.6px solid var(--strat); opacity: .6; }
.zoom li.lvl[data-tone="tact"] a::before { border-color: var(--tact); }
.zoom li.lvl a:hover { color: var(--ink); border-color: var(--line-strong); background: rgba(255, 255, 255, .05); }
.zoom li.lvl a:focus-visible { outline-offset: 2px; }
.zoom li.on[data-tone="strat"] a { color: var(--strat-soft); background: var(--strat-wash); border-color: rgba(182, 156, 255, .5); box-shadow: 0 0 18px -6px var(--strat-glow); }
.zoom li.on[data-tone="tact"] a { color: var(--tact-soft); background: var(--tact-wash); border-color: rgba(47, 230, 200, .45); box-shadow: 0 0 18px -6px var(--tact-glow); }
.zoom li.on[data-tone="strat"] a::before { opacity: 1; box-shadow: 0 0 6px var(--strat-glow); }
.zoom li.on[data-tone="tact"] a::before { opacity: 1; box-shadow: 0 0 6px var(--tact-glow); }
.zoom li.sep { color: var(--ink-3); opacity: .6; }
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
@media (prefers-reduced-motion: reduce) { .zoom li.lvl a { transition: none; } }
h1 {
  font: 600 clamp(38px, 5.4vw, 64px)/1.06 var(--display);
  letter-spacing: -.025em;
  margin: 0 0 22px;
  max-width: 15ch;
  background: linear-gradient(180deg, #FFFFFF 20%, #BCD2FF);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  filter: drop-shadow(0 0 26px rgba(90, 150, 255, .35));
}
.lead { font-size: clamp(18px, 2vw, 20px); color: var(--ink-2); max-width: 56ch; margin: 0; }

.hero-art { width: 100%; max-width: 460px; justify-self: end; overflow: visible; }
.ha-bc { fill: var(--strat-wash); stroke: var(--strat); stroke-width: 2; filter: drop-shadow(0 0 10px var(--strat-glow)); }
.ha-agg { fill: var(--tact-wash); stroke: var(--tact); stroke-width: 2; filter: drop-shadow(0 0 10px var(--tact-glow)); }
.ha-node { fill: var(--node-fill); stroke: var(--block); stroke-width: 1.6; filter: drop-shadow(0 0 6px var(--block-glow)); }
.ha-door { fill: var(--door-fill); stroke: var(--door); stroke-width: 2; filter: drop-shadow(0 0 8px var(--door-glow)); animation: door-pulse 3.2s ease-in-out infinite; }
.ha-wire { fill: none; stroke: var(--block-soft); stroke-width: 1.6; stroke-dasharray: 4 6; opacity: .85; animation: wire-flow 1.4s linear infinite; }
.ha-dot { fill: var(--block-soft); filter: drop-shadow(0 0 5px var(--block-glow)); }
@keyframes door-pulse { 50% { filter: drop-shadow(0 0 18px var(--door-glow)); } }
@keyframes wire-flow { to { stroke-dashoffset: -20; } }
@media (prefers-reduced-motion: reduce) { .ha-door, .ha-wire { animation: none; } }

/* Strategic hero (bead dcg.6.1): problem space and solution space. The rows are
   built by site/assets/spaces.js from webshop.js. Three grid columns: subdomain
   tiles inside the domain, the wires, bounded context walls. Grid rows: the
   column heads, a thin row for the domain label, then one row per subdomain, so
   each tile, wire and wall line up at every width. */
.spaces { margin: 44px 0 0; padding: 28px clamp(14px, 3vw, 36px) 22px; }
.spaces-map {
  display: grid;
  grid-template-columns: minmax(0, 1fr) clamp(40px, 11vw, 150px) minmax(0, 1fr);
  grid-template-rows: auto 10px;
  grid-auto-rows: minmax(62px, auto);
  row-gap: 12px;
  max-width: 880px;
  margin-inline: auto;
  padding-inline: 14px;
}
.spaces-head { margin: 0 0 12px; display: flex; flex-direction: column; gap: 2px; grid-row: 1; }
.spaces-head.is-problem { grid-column: 1; margin-left: -14px; }
.spaces-head.is-solution { grid-column: 3; }
.spaces-head-name { font: 600 12px/1.4 var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--ink-2); }
.spaces-head.is-solution .spaces-head-name { color: var(--strat); text-shadow: 0 0 14px var(--strat-glow); }
.spaces-head-sub { font-size: 14px; line-height: 1.4; color: var(--ink-3); }

.spaces-outline { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none; }
.spaces-domain { position: relative; grid-column: 1; margin: -14px; }
.spaces-domain-shape { fill: rgba(92, 157, 255, .045); stroke: var(--line-strong); stroke-width: 1.2; }
.spaces-domain-name {
  position: absolute;
  top: 5px;
  left: 14px;
  font: 600 11px/16px var(--sans);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.spaces-sub, .spaces-ctx { position: relative; display: flex; align-items: center; padding: 10px 18px; }
.spaces-sub { grid-column: 1; }
.spaces-ctx { grid-column: 3; }
.spaces-name { position: relative; font: 600 17px/1.3 var(--display); letter-spacing: -.01em; overflow-wrap: anywhere; }
.spaces-sub .spaces-name { color: var(--ink); }
.spaces-ctx .spaces-name { color: var(--strat-soft); }
.spaces-caption { max-width: 880px; margin: 22px auto 0; padding: 16px 14px 0; border-top: 1px solid var(--line); font-size: 14px; color: var(--ink-3); }

/* The mapping draws once .is-drawn is set: each wire runs from its subdomain to
   its context, its arrowhead lands, and the context wall lights up. */
.spaces-link { position: relative; grid-column: 2; }
.spaces-wire { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.spaces-wire .n-line { stroke-dasharray: 1 1; stroke-dashoffset: 1; filter: drop-shadow(0 0 3px var(--block-glow)); }
.spaces-wire .n-dot, .spaces-wire .n-arrow { opacity: 0; }
.spaces-ctx { opacity: .45; }
.spaces.is-drawn .spaces-wire .n-line { stroke-dashoffset: 0; transition: stroke-dashoffset .55s cubic-bezier(.4, 0, .2, 1) var(--d); }
.spaces.is-drawn .spaces-wire .n-dot { opacity: 1; transition: opacity .2s ease var(--d); }
.spaces.is-drawn .spaces-wire .n-arrow { opacity: 1; transition: opacity .2s ease calc(var(--d) + .45s); }
.spaces.is-drawn .spaces-ctx { opacity: 1; transition: opacity .35s ease calc(var(--d) + .45s); }
@media (prefers-reduced-motion: reduce) {
  /* A fade only: the wires are whole from the start and appear with their walls. */
  .spaces-wire .n-line { stroke-dasharray: none; stroke-dashoffset: 0; }
  .spaces-link { opacity: 0; }
  .spaces-wire .n-dot, .spaces-wire .n-arrow { opacity: 1; }
  .spaces.is-drawn .spaces-link, .spaces.is-drawn .spaces-ctx { opacity: 1; transition: opacity .4s ease; }
  .spaces.is-drawn .spaces-wire .n-line, .spaces.is-drawn .spaces-wire .n-dot, .spaces.is-drawn .spaces-wire .n-arrow { transition: none; }
}
@media (max-width: 640px) {
  .spaces { margin-top: 32px; }
  .spaces-map { row-gap: 10px; grid-auto-rows: minmax(52px, auto); padding-inline: 10px; }
  .spaces-head.is-problem { margin-left: -10px; }
  .spaces-domain { margin: -12px -10px; }
  .spaces-domain-name { left: 10px; }
  .spaces-sub, .spaces-ctx { padding: 8px 10px; }
  .spaces-name { font-size: 14px; }
  .spaces-head-sub { font-size: 13px; }
}

/* Sections */
.block { padding-block: 44px; }
.section-head { max-width: 68ch; margin-bottom: 30px; }
h2 { font: 600 clamp(28px, 3.4vw, 38px)/1.15 var(--display); letter-spacing: -.02em; margin: 0 0 12px; color: var(--ink); text-shadow: 0 0 30px rgba(90, 150, 255, .25); }
.section-head p:last-child { color: var(--ink-2); margin: 0; }

/* Composition explorer (bead dcg.7.3): who may touch what inside the Sales
   context, built by site/assets/explorer.js from webshop.js. The .explorer grid
   (a drawing and a panel beside it) is also reused by the subdomain map, the
   room and the context map.

   The drawing is one set of markup with two layouts, and .is-wide is set by
   explorer.js from the width the drawing has:
     wide    the walls nested inside each other, their name plates at the foot
             like the labels on the older drawings, coral doors straddling the
             top edge of the wall they open, and the lines between the boxes in
             an SVG overlay (.expl-wires) above the wall backgrounds and below
             the boxes.
     narrow  zoom levels (bead h72): one wall at a time in .expl-level, its
             boxes placed absolutely by explorer.js from the hand-made layouts
             in webshop.js, walls inside it as tiles (.expl-tile), lines in
             their own overlay (.expl-level-wires) and exits under the wall,
             with a breadcrumb and a mini-map above (.expl-zoombar). */
.explorer { display: grid; grid-template-columns: minmax(0, 1fr) 330px; gap: 20px; align-items: start; }
.diagram-card { margin: 0; padding: 20px; }
.expl-card { padding: 20px clamp(12px, 1.8vw, 20px) 16px; }
.expl-rule { display: flex; align-items: center; gap: 10px; margin: 0 0 16px; font: 600 14px/1.4 var(--sans); color: var(--ink); }
.expl-rule .n-glyph { width: 34px; height: 20px; flex: none; }
.expl-caption { margin: 14px 0 0; font-size: 14px; line-height: 1.5; color: var(--ink-3); }
.expl-diagram { position: relative; }
.expl-wires { position: absolute; inset: 0; z-index: 1; display: none; width: 100%; height: 100%; overflow: visible; pointer-events: none; }
.expl-diagram.is-wide .expl-wires { display: block; }

/* The walls: violet for the bounded context, a violet dashed folder for the
   module (a grouping, never a wall that keeps anything out) and teal for an
   aggregate. */
.expl-wall { position: relative; display: flex; flex-direction: column; transition: box-shadow .2s; }
.expl-wall.is-wall {
  padding: 12px 14px 14px;
  border: 2.2px solid var(--strat);
  border-radius: 22px;
  background: radial-gradient(90% 70% at 50% 40%, rgba(92, 157, 255, .06), transparent 70%), rgba(160, 130, 255, .05);
  box-shadow: 0 0 0 4px rgba(160, 130, 255, .06), 0 0 30px -8px var(--strat-glow), inset 0 0 44px -18px var(--strat-glow);
}
.expl-wall.is-module { padding: 10px 12px 12px; border: 1.6px dashed var(--strat); border-radius: 14px; background: var(--strat-wash); }
.expl-wall.is-aggregate {
  padding: 10px 12px 12px;
  border: 1.8px solid var(--tact);
  border-radius: 16px;
  background: linear-gradient(var(--tact-wash), var(--tact-wash)), rgba(12, 19, 38, .5);
  box-shadow: 0 0 24px -12px var(--tact-glow), inset 0 0 34px -20px var(--tact-glow);
}
.expl-wall.is-shown { box-shadow: 0 0 0 3px rgba(181, 211, 255, .14), 0 0 28px -6px var(--block-glow); }

/* A wall name plate. */
.expl-head { position: relative; z-index: 2; display: flex; align-items: center; gap: 4px; margin: 0 0 10px; }
.expl-name {
  display: inline-flex;
  align-items: baseline;
  gap: 8px;
  min-width: 0;
  padding: 3px 8px;
  border: 1px solid transparent;
  border-radius: 9px;
  background: transparent;
  color: var(--ink);
  font: inherit;
  text-align: left;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: border-color .15s, background-color .15s;
}
.expl-name-text { font: 600 17px/1.2 var(--display); letter-spacing: -.01em; }
.expl-name-text.is-code { font: 500 15px/1.25 var(--mono); }
.expl-name-kind { font: 600 10.5px/1.4 var(--sans); letter-spacing: .12em; text-transform: uppercase; }
.expl-name.is-wall .expl-name-text { color: var(--strat-soft); text-shadow: 0 0 18px var(--strat-glow); }
.expl-name.is-module .expl-name-text { color: var(--strat-soft); font-size: 14px; }
.expl-name.is-wall .expl-name-kind, .expl-name.is-module .expl-name-kind { color: var(--strat); }
.expl-name.is-aggregate .expl-name-text { color: var(--tact-soft); text-shadow: 0 0 18px var(--tact-glow); font-size: 15px; }
.expl-name.is-aggregate .expl-name-kind { color: var(--tact); }
.expl-diagram:not(.is-static) .expl-name:hover { border-color: var(--line-strong); background: rgba(255, 255, 255, .04); }
.expl-name[aria-checked="true"] { border-color: var(--ink); background: rgba(255, 255, 255, .06); }

/* The base stacking, which the wide layout arranges. */
.expl-kids { display: flex; flex-direction: column; gap: 10px; }
.expl-slot { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.expl-branch { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.expl-slot.is-outside { margin-top: 10px; }

/* The boxes: blue building blocks, coral doors, violet walls outside. */
.expl-box {
  position: relative;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: 7px;
  min-width: 0;
  padding: 7px 10px;
  border: 1.4px solid var(--block);
  border-radius: 10px;
  background: var(--node-fill);
  color: var(--ink);
  font: inherit;
  text-align: left;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  box-shadow: 0 0 10px -4px var(--block-glow);
  transition: border-color .15s, box-shadow .15s;
}
.expl-box-text { display: flex; flex-direction: column; min-width: 0; }
.expl-box-name { font: 500 14px/1.3 var(--mono); }
.expl-box-name:not(.is-code) { font: 600 14px/1.3 var(--sans); }
.expl-box-kind { font: 600 10px/1.5 var(--sans); letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3); }
.expl-box.is-value { border-color: rgba(92, 157, 255, .5); }
.expl-box.is-value .expl-box-name { font-size: 13px; }
.expl-door-icon { width: 15px; height: 15px; flex: none; color: var(--door); }
.expl-box.is-door { border-color: var(--door); background: var(--door-fill); color: var(--door-soft); box-shadow: 0 0 16px -2px var(--door-glow); }
.expl-box.is-door .expl-box-kind { color: var(--door); }
.expl-box.is-context { border-color: var(--strat); background: linear-gradient(var(--strat-wash), var(--strat-wash)), var(--node-fill); }
.expl-box.is-context .expl-box-kind { color: var(--strat); }
/* Hover only where pointing does something: the drawing the transactions
   stepper renders (.is-static, bead dcg.7.5) is a picture its steps light. */
.expl-diagram:not(.is-static) .expl-box:hover, .expl-box.is-lit { border-color: var(--block-soft); box-shadow: 0 0 20px -2px var(--block-glow); }
.expl-diagram:not(.is-static) .expl-box.is-door:hover, .expl-box.is-door.is-lit { border-color: var(--door-soft); color: #fff; box-shadow: 0 0 24px 1px var(--door-glow); }
.expl-diagram:not(.is-static) .expl-box.is-context:hover, .expl-box.is-context.is-lit { border-color: var(--strat-soft); box-shadow: 0 0 22px -2px var(--strat-glow); }
.expl-box[aria-checked="true"] { border-color: #fff; box-shadow: inset 0 0 0 1px #fff, 0 0 24px -2px var(--block-glow); }
.expl-box.is-door[aria-checked="true"] { box-shadow: inset 0 0 0 1px #fff, 0 0 26px 2px var(--door-glow); }
.expl-name:focus-visible, .expl-box:focus-visible { outline-offset: 3px; }

/* The lines: all shown at rest; a selection lights its own and dims the rest. */
.expl-wire { transition: opacity .15s; }
.expl-wire .n-line, .expl-wire .n-arrow { stroke: var(--wire); stroke-width: 1.5; transition: stroke .15s; }
.expl-wire .n-arrow { fill: none; stroke-linecap: round; stroke-linejoin: round; }
.expl-wire .n-dot { fill: var(--wire); transition: fill .15s; }
.expl-wire.is-lit .n-line, .expl-wire.is-lit .n-arrow { stroke: var(--wire-lit); filter: drop-shadow(0 0 4px var(--block-glow)); }
.expl-wire.is-lit .n-dot { fill: var(--wire-lit); }
.expl-diagram.has-lit .expl-wire:not(.is-lit) { opacity: .22; }

/* Drawing in: the doors open, then the lines run out from the end they start at. */
.expl-card:not(.is-drawn) .expl-wire, .expl-card:not(.is-drawn) .expl-box.is-door { opacity: 0; }
.expl-card.is-drawn:not(.is-settled) .expl-box.is-door { animation: expl-fade .4s ease both; }
.expl-card.is-drawn:not(.is-settled) .expl-wire.is-wire .n-line { stroke-dasharray: 1 1; animation: expl-draw .55s cubic-bezier(.4, 0, .2, 1) both var(--d); }
.expl-card.is-drawn:not(.is-settled) .expl-wire.is-reference .n-line { animation: expl-fade .4s ease both var(--d); }
.expl-card.is-drawn:not(.is-settled) .expl-wire .n-dot { animation: expl-fade .2s ease both var(--d); }
.expl-card.is-drawn:not(.is-settled) .expl-wire .n-arrow { animation: expl-fade .2s ease both calc(var(--d) + .45s); }
@keyframes expl-draw { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
@keyframes expl-fade { from { opacity: 0; } to { opacity: 1; } }

/* The panel beside the drawing. */
.expl-panel { scroll-margin-top: 96px; }
.expl-kind { display: flex; align-items: center; gap: 8px; color: var(--block-soft); text-shadow: 0 0 14px var(--block-glow); }
.expl-kind .n-glyph { width: 30px; height: 18px; flex: none; }
.expl-panel[data-type="door"] .expl-kind { color: var(--door); text-shadow: 0 0 14px var(--door-glow); }
.expl-panel[data-type="aggregate"] .expl-kind { color: var(--tact); text-shadow: 0 0 14px var(--tact-glow); }
.expl-panel[data-type="wall"] .expl-kind,
.expl-panel[data-type="module"] .expl-kind,
.expl-panel[data-type="context"] .expl-kind { color: var(--strat); text-shadow: 0 0 14px var(--strat-glow); }
.insp-name.expl-title { font-family: var(--display); font-weight: 600; letter-spacing: -.01em; text-shadow: none; }
.insp-name.expl-title.is-code { font-family: var(--mono); font-weight: 500; }
.expl-note {
  display: flex;
  gap: 10px;
  margin: 0 0 16px;
  padding: 10px 12px;
  border: 1px solid var(--line-strong);
  border-radius: 12px;
  background: rgba(255, 255, 255, .03);
  color: var(--ink-2);
  font-size: 14px;
  line-height: 1.45;
}
.expl-note.is-door { border-color: rgba(255, 123, 84, .4); background: var(--door-wash); color: var(--door-soft); }
.expl-note.is-rule { border-color: rgba(47, 230, 200, .4); background: var(--tact-wash); color: var(--tact-soft); }
.expl-note .expl-door-icon { margin-top: 2px; }
.expl-panel [hidden] { display: none; }
.expl-panel .insp-rel li { display: flex; align-items: baseline; flex-wrap: wrap; gap: 0 2px; line-height: 1.45; }
.expl-panel .insp-rel .rel { margin: 0; }
.expl-line { width: 26px; height: 14px; flex: none; align-self: center; }
.expl-ref { color: var(--ink); font-weight: 600; }
code.expl-ref { font-weight: 500; padding: 0 4px; }

/* Wide: the walls nested, with room for the lines between the boxes. The
   drawing keeps a band at the top for the doors that straddle the wall. */
.expl-diagram.is-wide { padding-top: 22px; }
.expl-diagram.is-wide .expl-wall.is-wall { padding: 30px 20px 14px; }
.expl-diagram.is-wide .expl-wall.is-module { padding: 14px 18px 16px; }
.expl-diagram.is-wide .expl-wall.is-aggregate { padding: 28px 16px 14px; }
/* The name plate moves to the foot of its wall, like the labels on the older drawings. */
.expl-diagram.is-wide .expl-head { order: 2; margin: 12px 0 0; }
.expl-diagram.is-wide .expl-kids { display: block; }
.expl-diagram.is-wide .expl-slot.is-doors {
  position: absolute;
  top: 0;
  left: 34px;
  z-index: 3;
  flex-direction: row;
  gap: 16px;
  transform: translateY(-50%);
}
.expl-diagram.is-wide .expl-wall.is-aggregate > .expl-kids > .is-doors { left: auto; right: 34px; }
.expl-diagram.is-wide .expl-slot.is-top { flex-direction: row; justify-content: flex-end; align-items: flex-start; gap: 18px; margin-bottom: 18px; }
.expl-diagram.is-wide .expl-wall.is-module > .expl-kids > .is-top { justify-content: flex-start; margin-bottom: 26px; }
.expl-diagram.is-wide .expl-slot.is-bottom { flex-direction: row; gap: 18px; margin-top: 22px; }
.expl-diagram.is-wide .expl-slot.is-outside { flex-direction: row; justify-content: center; gap: clamp(60px, 16vw, 200px); margin-top: 28px; }
.expl-diagram.is-wide .expl-branch { display: grid; grid-template-columns: minmax(140px, 190px) minmax(0, 1fr); gap: 14px 34px; align-items: start; }
.expl-diagram.is-wide .expl-branch > .expl-box { grid-column: 1; }
.expl-diagram.is-wide .expl-branch > .is-values { grid-column: 2; grid-row: 1; flex-direction: row; gap: 12px; margin: 0; }
.expl-diagram.is-wide .expl-branch > .is-below { grid-column: 1 / -1; margin: 0; }

/* Narrow: zoom levels (bead h72). The wide drawing is hidden and its buttons
   are moved into the level shown, placed by explorer.js. */
.expl-diagram:not(.is-wide) > .expl-wall, .expl-diagram:not(.is-wide) > .expl-slot { display: none; }
.expl-level { position: relative; transform-origin: 50% 0; }
.expl-level[hidden] { display: none; }
.expl-level.is-entering { animation: expl-level-in .28s cubic-bezier(.2, .8, .2, 1); }
@keyframes expl-level-in { from { opacity: 0; transform: scale(.94); } to { opacity: 1; transform: none; } }
.expl-level .expl-wall, .expl-level .expl-box, .expl-level > .expl-name, .expl-exit, .expl-enter { position: absolute; margin: 0; }
.expl-level .expl-wall { z-index: 0; }
.expl-level-wires { position: absolute; inset: 0; z-index: 1; width: 100%; height: 100%; overflow: visible; pointer-events: none; }
.expl-level .expl-box { z-index: 2; }
.expl-level .expl-box-name { white-space: nowrap; }
.expl-level > .expl-name { z-index: 3; background: #0B1122; }
.expl-tile { display: flex; flex-direction: column; align-items: flex-start; justify-content: space-between; padding: 8px 6px; cursor: pointer; -webkit-tap-highlight-color: transparent; }
.expl-tile .expl-name { flex-wrap: wrap; row-gap: 0; }
.expl-tile-open { padding: 0 8px; font: 500 12px/1.4 var(--sans); color: var(--ink-2); }
.expl-tile:hover .expl-tile-open { color: var(--ink); }
.expl-exit { z-index: 2; padding: 3px 10px; border: 1px solid var(--line-strong); border-radius: 999px; background: rgba(6, 10, 20, .9); font: 500 12px/1.5 var(--sans); color: var(--ink-2); white-space: nowrap; }
.expl-enter { font-size: 13px; line-height: 1.4; color: var(--ink-3); }
.expl-zoombar { display: flex; align-items: flex-end; justify-content: space-between; gap: 10px; margin: 0 0 12px; }
.expl-zoombar[hidden] { display: none; }
.expl-crumbs { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 6px; }
.expl-crumbs button { min-height: 32px; padding: 4px 9px; border: 1px solid var(--line); border-radius: 8px; background: none; color: var(--ink-2); font: 500 13px var(--sans); cursor: pointer; }
.expl-crumbs button:hover { color: var(--ink); border-color: var(--line-strong); }
.expl-crumbs button[aria-current="true"] { color: var(--ink); border-color: var(--line-strong); background: rgba(140, 170, 255, .1); }
.expl-crumb-sep { color: var(--ink-3); }
.expl-mini { flex: none; width: 84px; height: auto; padding: 3px; border: 1px solid var(--line-strong); border-radius: 8px; background: rgba(3, 5, 11, .85); }
.expl-mini rect { fill: rgba(160, 130, 255, .06); stroke: var(--strat); stroke-width: 1.5; cursor: pointer; }
.expl-mini rect.is-module { stroke-dasharray: 3 2; }
.expl-mini rect.is-aggregate { fill: var(--tact-wash); stroke: var(--tact); }
.expl-mini rect.is-here { fill: rgba(255, 255, 255, .16); stroke: #fff; stroke-width: 2.5; }

@media (prefers-reduced-motion: reduce) {
  /* A fade only: the lines do not run. */
  .expl-name, .expl-box, .expl-wall, .expl-wire { transition: none; }
  .expl-level.is-entering { animation: expl-fade .2s ease; }
  .expl-card.is-drawn:not(.is-settled) .expl-wire.is-wire .n-line { stroke-dasharray: none; animation: expl-fade .4s ease both; }
  .expl-card.is-drawn:not(.is-settled) .expl-wire .n-arrow { animation: expl-fade .4s ease both; }
}
@media (max-width: 640px) {
  .expl-card { padding: 16px 12px 14px; }
  .expl-rule { font-size: 13px; }
  .expl-wall.is-wall { padding: 10px 10px 12px; border-radius: 18px; }
  .expl-wall.is-module, .expl-wall.is-aggregate { padding: 8px 9px 10px; }
  .expl-name { padding: 2px 6px; }
  .expl-name-text { font-size: 15px; }
  .expl-box { padding: 6px 8px; }
  .expl-box-name, .expl-box-name:not(.is-code) { font-size: 13px; }
  .expl-panel { padding: 20px; scroll-margin-top: 112px; }
}

.legend {
  list-style: none;
  margin: 18px 0 0;
  padding: 16px 0 0;
  border-top: 1px solid var(--line);
  display: flex;
  flex-wrap: wrap;
  gap: 10px 22px;
  font-size: 13px;
  color: var(--ink-2);
}
.legend li { display: flex; align-items: center; gap: 8px; }
.legend svg { width: 34px; height: 20px; flex: none; overflow: visible; }

/* Notation glyphs (bead dcg.5). The single source of the notation colours: the
   legend panel, the small diagram legends (both drawn from notation.js) and any
   diagram that wants the same look use these classes. */
.n-glyph { overflow: visible; }
/* .lg-* are the older names, still used by the legend in site/illustration-concepts.html. */
.n-bc, .lg-bc { fill: var(--strat-wash); stroke: var(--strat); stroke-width: 1.6; filter: drop-shadow(0 0 4px var(--strat-glow)); }
.n-agg, .lg-agg { fill: var(--tact-wash); stroke: var(--tact); stroke-width: 1.6; filter: drop-shadow(0 0 4px var(--tact-glow)); }
/* The transaction boundary (bead dcg.7.5): the same teal as the aggregate wall
   it closes around, but drawn as a ring outside it, dashed while the
   transaction is open and solid once it has committed. */
.n-tx { fill: none; stroke: var(--tact); stroke-width: 1.6; stroke-dasharray: 5 4; stroke-linecap: round; opacity: .9; }
.n-door, .lg-door { fill: var(--door-fill); stroke: var(--door); stroke-width: 1.6; filter: drop-shadow(0 0 4px var(--door-glow)); }
.n-block, .lg-block { fill: var(--node-fill); stroke: var(--block); stroke-width: 1.6; filter: drop-shadow(0 0 4px var(--block-glow)); }
.n-blocked-ring { fill: none; stroke: var(--blocked); stroke-width: 2; filter: drop-shadow(0 0 4px var(--blocked-glow)); }
.n-blocked-slash { fill: none; stroke: var(--blocked); stroke-width: 2; stroke-linecap: round; filter: drop-shadow(0 0 4px var(--blocked-glow)); }
.n-line, .lg-line { fill: none; stroke: var(--wire-lit); stroke-width: 1.6; }
.n-line.ref, .lg-line.ref { stroke-dasharray: 4 3; }
.n-line.faint { opacity: .45; }
.n-arrow { fill: none; stroke: var(--wire-lit); stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.n-dot, .lg-dot { fill: var(--wire-lit); }
/* Depends on, in the code (bead dcg.7.1): thick, solid head, no start dot. */
.n-dep { fill: none; stroke: var(--dep); stroke-width: 2.6; stroke-linecap: round; filter: drop-shadow(0 0 3px var(--dep-glow)); }
.n-dep-head { fill: var(--dep); stroke: var(--dep); stroke-width: 1; stroke-linejoin: round; filter: drop-shadow(0 0 3px var(--dep-glow)); }
/* Building-block glyphs (bead dcg.7.2): the marks inside an n-block (lines,
   a small id label, the back box of a repository's stack), and the module
   wall, a folder tab in the same violet as a context wall but with a dashed
   stroke, so it always reads as a grouping, never as a bounded context. */
.n-block-line { fill: none; stroke: var(--block-soft); stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.n-block-text { font-family: var(--mono); font-size: 8px; font-weight: 600; fill: var(--block-soft); }
.n-block-back { fill: var(--node-fill); stroke: var(--block-soft); stroke-width: 1.2; opacity: .55; }
.n-module { fill: var(--strat-wash); stroke: var(--strat); stroke-width: 1.6; stroke-dasharray: 3 2; filter: drop-shadow(0 0 4px var(--strat-glow)); }
/* Subdomain tile and type markers (bead dcg.6.2). */
.n-sub { fill: var(--sub-fill); stroke: var(--sub-stroke); stroke-width: 1.3; }
.n-core { fill: var(--sub-gold); stroke: var(--sub-gold-soft); stroke-width: 1; stroke-linejoin: round; filter: drop-shadow(0 0 4px var(--sub-gold-glow)); }
.n-supporting { fill: var(--node-fill); stroke: var(--sub-gold); stroke-width: 1.6; }
.n-supporting-fill { fill: var(--sub-gold); }
.n-generic { fill: var(--node-fill); stroke: var(--sub-grey); stroke-width: 1.6; stroke-linejoin: round; }
/* Context map (bead dcg.6.5): external systems, relationship lines, the U and D
   badges (solid versus hollow, so the letter is never the only cue) and the
   pattern badges (coral for a door, blue for a team pattern). */
.n-ext { fill: var(--node-fill); stroke: var(--ext); stroke-width: 1.6; }
.n-rel { fill: none; stroke: var(--block); stroke-width: 1.8; stroke-linecap: round; }
.n-up { fill: var(--wire-lit); stroke: var(--wire-lit); stroke-width: 1.2; }
.n-down { fill: var(--node-fill); stroke: var(--wire-lit); stroke-width: 1.6; }
.n-badge-door { fill: var(--door-fill); stroke: var(--door); stroke-width: 1.4; }
.n-badge-team { fill: var(--node-fill); stroke: var(--block); stroke-width: 1.4; }
.n-badge-text { font: 600 10px/1 var(--mono); text-anchor: middle; dominant-baseline: central; }
.n-up-text { fill: var(--bg); }
.n-down-text { fill: var(--wire-lit); }
.n-badge-door-text { fill: var(--door-soft); }
.n-badge-team-text { fill: var(--block-soft); }

.inspector { position: sticky; top: 88px; padding: 24px; }
.insp-name { font: 500 24px/1.2 var(--mono); margin: 0 0 10px; overflow-wrap: anywhere; text-shadow: 0 0 18px rgba(120, 170, 255, .35); }
.insp-text { color: var(--ink-2); font-size: 15px; margin: 0 0 18px; }
.insp-door {
  display: flex;
  gap: 10px;
  background: var(--door-wash);
  border: 1px solid rgba(255, 123, 84, .4);
  color: var(--door-soft);
  border-radius: 12px;
  padding: 10px 12px;
  font-size: 14px;
  line-height: 1.45;
  margin-bottom: 20px;
  box-shadow: 0 0 26px -12px var(--door-glow);
}
.insp-door .icon { margin-top: 1px; color: var(--door); filter: drop-shadow(0 0 4px var(--door-glow)); }
.insp-rel h4 { font: 600 12px var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--ink-3); margin: 0 0 6px; }
.insp-rel ul { list-style: none; margin: 0 0 16px; padding: 0; font-size: 14px; }
.insp-rel li { padding: 7px 0; border-top: 1px solid var(--line); color: var(--ink-2); }
.insp-rel .rel { color: var(--ink-3); margin-right: 5px; }
.insp-rel li.none { color: var(--ink-3); }
.insp-hint { font-size: 13px; color: var(--ink-3); margin: 0; }

/* Subdomains (bead dcg.6.2): a territory map of the webshop domain, built by
   site/assets/subdomains.js from webshop.js. It reuses the composition explorer's
   layout (.explorer, .diagram-card, .inspector and the .insp-* parts). Tile size
   follows the type: core tiles are the largest. */
.subd-map-label { margin: 0 0 8px 4px; font: 600 11px/16px var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--ink-3); }
.subd-map {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 10px;
  padding: 12px;
  border: 1.2px solid var(--line-strong);
  border-radius: 16px;
  background: rgba(92, 157, 255, .045);
}
.subd-tile {
  grid-column: span 2;
  min-height: 132px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: flex-start;
  gap: 16px;
  padding: 14px 16px 16px;
  border: 1.3px solid var(--sub-stroke);
  border-radius: 10px;
  background: var(--sub-fill);
  color: var(--ink);
  font: inherit;
  text-align: left;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: border-color .15s, box-shadow .15s, background-color .15s;
}
.subd-tile[data-type="core"] { grid-column: span 3; min-height: 184px; }
.subd-tile:hover { border-color: var(--sub-stroke-strong); background-color: rgba(20, 29, 54, .92); }
.subd-tile[aria-checked="true"] {
  border-color: var(--ink);
  background-color: rgba(22, 31, 58, .95);
  box-shadow: inset 0 0 0 1px var(--ink), 0 0 30px -8px rgba(255, 226, 160, .45);
}
.subd-tile:focus-visible { outline-offset: 3px; }
.subd-type { display: flex; align-items: center; gap: 4px; font: 600 11px/1.4 var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--ink-3); }
.subd-tile[data-type="core"] .subd-type, .subd-tile[data-type="supporting"] .subd-type { color: var(--sub-gold-soft); }
.subd-marker { width: 36px; height: 22px; flex: none; margin-left: -8px; overflow: visible; }
.subd-tile-name { font: 600 19px/1.2 var(--display); letter-spacing: -.01em; overflow-wrap: anywhere; }
.subd-tile[data-type="core"] .subd-tile-name { font-size: 24px; }
.subd-tile-body { display: flex; flex-direction: column; gap: 4px; }
.subd-tile-effort { font-size: 13px; line-height: 1.35; color: var(--ink-3); }

.subd-kind { display: flex; align-items: center; gap: 4px; color: var(--ink-2); }
.subd-kind[data-type="core"], .subd-kind[data-type="supporting"] { color: var(--sub-gold-soft); }
.subd-kind .subd-marker { width: 32px; height: 19px; margin-left: -7px; }
.insp-name.subd-name { font-family: var(--display); font-weight: 600; letter-spacing: -.01em; text-shadow: none; }
.subd-effort {
  margin-bottom: 20px;
  padding: 10px 12px;
  border-radius: 12px;
  border: 1px solid rgba(255, 201, 77, .35);
  background: var(--sub-gold-wash);
}
.subd-effort[data-type="generic"] { border-color: rgba(169, 180, 203, .35); background: rgba(169, 180, 203, .07); }
.subd-effort-head { margin: 0 0 3px; font: 600 16px/1.3 var(--display); color: var(--sub-gold-soft); }
.subd-effort[data-type="generic"] .subd-effort-head { color: var(--ink); }
.subd-effort-text { margin: 0; font-size: 14px; line-height: 1.45; color: var(--ink-2); }
.subd-meaning { margin: 0 0 16px; padding-top: 7px; border-top: 1px solid var(--line); font-size: 14px; line-height: 1.5; color: var(--ink-2); }
.subd-ctx { color: var(--strat-soft); font-weight: 600; }
@media (prefers-reduced-motion: reduce) { .subd-tile { transition: none; } }
@media (max-width: 640px) {
  .subd-map { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; padding: 8px; }
  .subd-tile { grid-column: span 1; min-height: 112px; padding: 12px; gap: 12px; }
  .subd-tile[data-type="core"] { grid-column: span 2; min-height: 104px; }
  .subd-tile[data-type="generic"] { grid-column: span 2; min-height: 0; }
  .subd-tile-name { font-size: 16px; }
  .subd-tile-effort { font-size: 12.5px; }
  .subd-tile[data-type="core"] .subd-tile-name { font-size: 20px; }
  .subd-panel { padding: 20px; }
}

/* Ubiquitous language (bead dcg.6.3): one word, a meaning inside each context
   wall. Built by site/assets/language.js from webshop.js. The panels for the
   words share one stage; switching cross-fades them while the stage animates
   its height (set by language.js), so nothing below jumps. */
.lang { padding: 20px clamp(14px, 2.4vw, 24px) 18px; }
.lang-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 14px; margin-bottom: 20px; }
.lang-label { margin: 0; font: 600 11px/16px var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--ink-3); }
.lang-words { display: flex; flex-wrap: wrap; gap: 8px; }
.lang-word-radio {
  min-height: 40px;
  padding: 6px 18px;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  background: rgba(255, 255, 255, .03);
  color: var(--ink-2);
  font: 600 16px/1.2 var(--display);
  letter-spacing: -.01em;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: color .15s, border-color .15s, background-color .15s, box-shadow .15s;
}
.lang-word-radio:hover { color: var(--ink); border-color: rgba(169, 203, 255, .55); background: rgba(255, 255, 255, .06); }
.lang-word-radio[aria-checked="true"] {
  color: var(--ink);
  border-color: var(--ink);
  background: rgba(92, 157, 255, .14);
  box-shadow: inset 0 0 0 1px var(--ink), 0 0 26px -8px var(--block-glow);
}
.lang-word-radio:focus-visible { outline-offset: 3px; }
.lang-hint { margin: 0 0 0 auto; font-size: 13px; color: var(--ink-3); }

.lang-stage { position: relative; }
.lang-stage.is-switching { transition: height .36s cubic-bezier(.4, 0, .2, 1); }
.lang-panel { transition: opacity .26s ease; }
.lang-panel.is-leaving { position: absolute; top: 0; left: 0; right: 0; opacity: 0; pointer-events: none; transition-duration: .16s; }
.lang-panel.is-entering { opacity: 0; transition: none; }
.lang-panel.is-entering .lang-wall { opacity: 0; transform: translateY(10px); transition: none; }

.lang-walls {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 16px;
}
.lang-wall {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 16px 16px 18px;
  border: 1.6px solid var(--strat);
  border-radius: 16px;
  background: var(--strat-wash);
  box-shadow: 0 0 14px -2px var(--strat-glow), inset 0 0 18px -10px var(--strat-glow);
  transition: opacity .3s ease calc(var(--i, 0) * 45ms), transform .36s cubic-bezier(.2, .8, .2, 1) calc(var(--i, 0) * 45ms);
}
.lang-ctx { margin: 0; font: 600 11px/16px var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--strat-soft); }
.lang-word { margin: 0; font: 600 24px/1.15 var(--display); letter-spacing: -.015em; color: var(--ink); }
.lang-meaning { margin: 0; font-size: 15px; line-height: 1.5; color: var(--ink-2); }
.lang-meaning-short { display: none; }
.lang-attrs { list-style: none; margin: auto 0 0; padding: 12px 0 0; border-top: 1px solid rgba(182, 156, 255, .22); display: grid; gap: 7px; }
.lang-attr { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 8px; }
.lang-attr-name, .lang .lang-attr-name {
  display: inline-block;
  padding: 2px 8px;
  border: 1.3px solid var(--block);
  border-radius: 6px;
  background: var(--node-fill);
  color: var(--ink);
  font: 500 13px/1.45 var(--mono);
  box-shadow: 0 0 8px -3px var(--block-glow);
  overflow-wrap: anywhere;
}
.lang-attr-note { font-size: 13px; line-height: 1.4; color: var(--ink-3); }
.lang .legend { margin-top: 20px; }

/* Without walls: one shared model, no violet wall around it. */
.lang-contrast { margin-top: 24px; align-items: start; }
.lang-merged { margin: 0; padding: 22px 22px 20px; }
.lang-merged-head { display: flex; flex-direction: column; gap: 4px; margin-bottom: 14px; }
.lang-merged-kicker { font: 600 12px/1.4 var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--ink-3); }
.lang-merged-title { font: 600 20px/1.3 var(--display); letter-spacing: -.01em; color: var(--ink); }
.lang-merged-title code { font-size: .9em; }
.lang-merged-list { list-style: none; margin: 0; padding: 4px 14px; border: 1.2px solid var(--line-strong); border-radius: 12px; background: rgba(12, 19, 38, .5); }
.lang-field { padding: 9px 0; border-top: 1px solid var(--line); }
.lang-field:first-child { border-top: 0; }
.lang-field-row { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 4px 12px; }
.lang-field-used { font-size: 13px; color: var(--ink-3); text-align: right; }
.lang-field-ctx { color: var(--strat-soft); }
.lang-field-note { margin: 6px 0 0; font-size: 14px; line-height: 1.45; color: var(--ink-2); }
.lang-field.is-clash .lang-field-note { padding: 8px 10px; border-radius: 8px; background: rgba(255, 255, 255, .05); border: 1px solid var(--line-strong); }
.lang-field-tag { font-weight: 600; color: var(--ink); }
.lang-merged-costs h4 { margin: 16px 0 6px; font: 600 12px var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--ink-3); }
.lang-merged-costs ul { margin: 0; padding-left: 18px; font-size: 14px; line-height: 1.5; color: var(--ink-2); }
.lang-merged-costs li + li { margin-top: 4px; }

@media (prefers-reduced-motion: reduce) {
  /* A fade only: no sliding walls and no height animation. */
  .lang-word-radio { transition: none; }
  .lang-stage.is-switching { transition: none; }
  .lang-wall { transition: none; }
  .lang-panel.is-entering .lang-wall { opacity: 1; transform: none; }
}
@media (max-width: 640px) {
  .lang { padding: 16px 14px 14px; }
  .lang-hint { margin-left: 0; flex-basis: 100%; }
  .lang-word-radio { padding: 6px 14px; font-size: 15px; }
  /* Side by side in two compact columns, so one word's walls fit on about
     one screen instead of stacking; the "without walls" contrast below
     keeps its own single-column layout. */
  .lang-walls { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
  .lang-wall { padding: 12px 12px 14px; gap: 7px; }
  .lang-ctx { font-size: 10.5px; }
  .lang-word { font-size: 17px; }
  .lang-meaning { font-size: 13px; line-height: 1.45; }
  .lang-meaning-full { display: none; }
  .lang-meaning-short { display: inline; }
  .lang-attrs { gap: 5px; padding-top: 10px; }
  .lang-attr-name, .lang .lang-attr-name { font-size: 11.5px; overflow-wrap: anywhere; white-space: normal; }
  /* Attribute notes stay for screen readers but are dropped visually to
     save space; see .sr-only above for the same clipping technique. */
  .lang-attr-note {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }
  .lang-merged { padding: 18px 16px; }
  .lang-field-used { text-align: left; }
}

/* Bounded contexts (bead dcg.6.4): the Sales context drawn as a room, built by
   site/assets/room.js from webshop.js. It reuses the explorer layout (.explorer,
   .diagram-card, .inspector, .insp-*). Top to bottom: the contexts outside, a gap
   for the wires, the room with doors straddling its wall, a gap, the contexts
   outside. The strong violet wall and the bright room against the dim outside
   carry "inside versus outside"; the coral doors are the only openings in it. */
.room-card { padding: 22px clamp(14px, 2.4vw, 24px) 18px; }
.room-diagram { position: relative; }
.room-wires { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none; }
.room-zone { margin: 0 0 8px; font: 600 11px/16px var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--ink-3); }
.room-zone.is-bottom { margin: 8px 0 0; }
.room-caption { margin: 16px 0 0; font-size: 14px; line-height: 1.5; color: var(--ink-3); }
.room-outside { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; }
.room-gap { height: 52px; }

/* Outside: other contexts, their own thinner walls, dimmed. */
.room-ctx {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-height: 64px;
  padding: 10px 14px;
  border: 1.3px solid rgba(182, 156, 255, .55);
  border-radius: 12px;
  background: rgba(6, 10, 20, .7);
  color: var(--ink-2);
  font: inherit;
  text-align: left;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: border-color .15s, box-shadow .15s, opacity .15s;
}
.room-ctx-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 6px; }
.room-ctx-name { font: 600 16px/1.3 var(--display); letter-spacing: -.01em; color: var(--strat-soft); }
.room-ctx-kind { font-size: 12px; color: var(--ink-3); }
.room-ctx-owns { font-size: 13px; line-height: 1.4; color: var(--ink-3); }
.room-ctx:hover, .room-ctx.is-lit { border-color: var(--strat); box-shadow: 0 0 16px -4px var(--strat-glow); }
.room-ctx[aria-checked="true"] { border-color: var(--ink); box-shadow: inset 0 0 0 1px var(--ink), 0 0 24px -6px var(--strat-glow); }

/* The room: the Sales wall. */
.room-wall {
  position: relative;
  padding: 30px clamp(12px, 2vw, 20px);
  border: 2.6px solid var(--strat);
  border-radius: 26px;
  background:
    radial-gradient(120% 90% at 50% 0%, rgba(160, 130, 255, .16), transparent 70%),
    rgba(160, 130, 255, .07);
  box-shadow: 0 0 0 5px rgba(160, 130, 255, .08), 0 0 34px -4px var(--strat-glow), inset 0 0 44px -12px var(--strat-glow);
  transition: box-shadow .2s;
}
.room-wall.is-shown { box-shadow: 0 0 0 6px rgba(160, 130, 255, .16), 0 0 46px 0 var(--strat-glow), inset 0 0 54px -10px var(--strat-glow); }
.room-inside { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }

.room-part {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
  min-width: 0;
  padding: 12px 14px 14px;
  border: 1px solid rgba(182, 156, 255, .26);
  border-radius: 12px;
  background: rgba(12, 19, 38, .78);
  color: var(--ink);
  font: inherit;
  text-align: left;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: border-color .15s, box-shadow .15s, background-color .15s;
}
.room-part[data-part="model"] { grid-column: 1 / -1; }
.room-part:hover { border-color: rgba(216, 203, 255, .6); background-color: rgba(20, 29, 54, .9); }
.room-part[aria-checked="true"] { border-color: var(--ink); background-color: rgba(22, 31, 58, .95); box-shadow: inset 0 0 0 1px var(--ink), 0 0 26px -8px var(--strat-glow); }
.room-part-kind { display: flex; align-items: center; gap: 7px; font: 600 11px/1.4 var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--strat-soft); }
.room-pic { width: 20px; height: 20px; flex: none; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.room-part-name { font: 600 17px/1.25 var(--display); letter-spacing: -.01em; overflow-wrap: anywhere; }
.room-chips { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 2px; }
.room-chip {
  display: inline-block;
  padding: 1px 7px;
  border: 1.2px solid var(--line-strong);
  border-radius: 6px;
  background: var(--node-fill);
  color: var(--ink-2);
  font: 500 12px/1.5 var(--sans);
  overflow-wrap: anywhere;
}
.room-chip.is-block, .room-chip.is-table { border-color: var(--block); color: var(--ink); font-family: var(--mono); box-shadow: 0 0 8px -3px var(--block-glow); }
.room-chip.is-agg { border-color: var(--tact); background: var(--tact-wash); color: var(--tact-soft); font: 500 13px/1.5 var(--mono); box-shadow: 0 0 8px -3px var(--tact-glow); }

/* The wall's own button: the room's name plate. */
.room-part.is-wall {
  grid-column: 1 / -1;
  flex-direction: row;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 4px 12px;
  padding: 8px 12px;
  border-color: transparent;
  background: transparent;
}
.room-part.is-wall:hover { border-color: rgba(216, 203, 255, .45); background: rgba(160, 130, 255, .06); }
.room-part.is-wall[aria-checked="true"] { border-color: var(--strat-soft); background: rgba(160, 130, 255, .08); box-shadow: inset 0 0 0 1px var(--strat-soft); }
.room-wall-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 8px; }
.room-wall-name { font: 600 26px/1.15 var(--display); letter-spacing: -.02em; color: var(--strat-soft); text-shadow: 0 0 18px var(--strat-glow); }
.room-wall-kind { font: 600 12px/1.4 var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--strat); }
.room-wall-tag { font: 600 11px/1.4 var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--strat-soft); opacity: .8; }

/* Doors: coral, straddling the wall line, which they cut open. */
.room-doors { position: absolute; left: 0; right: 0; z-index: 1; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); pointer-events: none; }
.room-doors.is-top { top: 0; transform: translateY(-50%); margin-top: -1.3px; }
.room-doors.is-bottom { bottom: 0; transform: translateY(50%); margin-bottom: -1.3px; }
/* --cut: two dark bands, beside the door, that cut the wall line open. */
.room-door {
  --cut: 17px 0 0 -12px var(--node-fill), -17px 0 0 -12px var(--node-fill);
  position: relative;
  justify-self: center;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  max-width: calc(100% - 12px);
  padding: 5px 11px 5px 8px;
  border: 1.6px solid var(--door);
  border-radius: 9px;
  background: var(--door-fill);
  color: var(--door-soft);
  font: 600 13px/1.25 var(--sans);
  text-align: left;
  cursor: pointer;
  pointer-events: auto;
  -webkit-tap-highlight-color: transparent;
  box-shadow: var(--cut), 0 0 18px 1px var(--door-glow);
  transition: border-color .15s, box-shadow .15s, color .15s;
}
.room-door.is-event .room-door-name { font: 500 13px/1.25 var(--mono); }
.room-door-name { overflow-wrap: anywhere; }
.room-door-icon { width: 16px; height: 16px; color: var(--door); }
.room-door:hover, .room-door.is-lit { border-color: var(--door-soft); color: #fff; box-shadow: var(--cut), 0 0 26px 3px var(--door-glow); }
.room-door[aria-checked="true"] { border-color: #fff; color: #fff; box-shadow: var(--cut), inset 0 0 0 1px #fff, 0 0 30px 4px var(--door-glow); }
.room-door:focus-visible, .room-part:focus-visible, .room-ctx:focus-visible { outline-offset: 3px; }

/* Wires, lit with what they belong to. */
.room-wire { transition: opacity .15s; }
.room-wire .n-line { stroke: var(--wire-lit); }
.room-wire.is-lit .n-line { filter: drop-shadow(0 0 4px var(--block-glow)); stroke-width: 2.2; }
.room-diagram.has-lit-wires .room-wire:not(.is-lit) { opacity: .3; }

/* Drawing in: the doors open, the wires run out to the contexts, and the
   contexts outside light up. Before that, only the room is there. */
.room-card:not(.is-drawn) .room-door { opacity: 0; }
.room-card:not(.is-drawn) .room-wire { opacity: 0; }
.room-card:not(.is-drawn) .room-ctx { opacity: .35; }
.room-card.is-drawn .room-door { animation: room-door-open .45s cubic-bezier(.2, .8, .2, 1) both; }
.room-card.is-drawn .room-doors.is-bottom .room-door { animation-delay: .12s; }
.room-card.is-drawn .room-wire .n-line { stroke-dasharray: 1 1; animation: room-wire-draw .5s cubic-bezier(.4, 0, .2, 1) both var(--d); }
.room-card.is-drawn .room-wire.is-ref .n-line { stroke-dasharray: 4 3; animation: room-fade .4s ease both var(--d); }
.room-card.is-drawn .room-wire .n-dot { animation: room-fade .2s ease both var(--d); }
.room-card.is-drawn .room-wire .n-arrow { animation: room-fade .2s ease both calc(var(--d) + .4s); }
.room-card.is-drawn .room-ctx { animation: room-ctx-light .4s ease both .95s; }
@keyframes room-door-open { from { opacity: 0; transform: scale(.6); } to { opacity: 1; transform: none; } }
@keyframes room-wire-draw { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
@keyframes room-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes room-ctx-light { from { opacity: .35; } to { opacity: 1; } }

/* The panel. */
.room-kind { display: flex; align-items: center; gap: 7px; color: var(--strat); text-shadow: 0 0 14px var(--strat-glow); }
.room-panel[data-type="door"] .room-kind { color: var(--door); text-shadow: 0 0 14px var(--door-glow); }
.room-panel[data-type="outside"] .room-kind { color: var(--ink-3); text-shadow: none; }
.room-kind .room-door-icon { width: 18px; height: 18px; }
.insp-name.room-name { font-family: var(--display); font-weight: 600; letter-spacing: -.01em; text-shadow: none; }
.insp-name.room-name.is-mono { font-family: var(--mono); font-weight: 500; }
.room-rule {
  display: flex;
  gap: 10px;
  margin: 0 0 20px;
  padding: 10px 12px;
  border: 1px solid rgba(255, 123, 84, .4);
  border-radius: 12px;
  background: var(--door-wash);
  color: var(--door-soft);
  font-size: 14px;
  line-height: 1.45;
  box-shadow: 0 0 26px -12px var(--door-glow);
}
.room-rule .room-door-icon { margin-top: 1px; }
.room-rule[hidden], .room-panel [hidden] { display: none; }
.room-term { color: var(--ink); font-weight: 600; }
.room-door-ref { color: var(--door-soft); font-weight: 600; }
.room-panel .room-chip.is-agg { margin-right: 2px; }

/* Forward links. */
.room-next { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; margin-top: 24px; }
.room-next-link { display: flex; flex-direction: column; gap: 4px; padding: 16px 20px; border-radius: 16px; color: var(--ink); text-decoration: none; transition: border-color .2s, box-shadow .2s; }
.room-next-link small { font: 600 11px/1.6 var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--strat); }
.room-next-link.is-tact small { color: var(--tact); }
.room-next-title { font: 600 18px/1.3 var(--display); letter-spacing: -.01em; }
.room-next-text { font-size: 14px; line-height: 1.5; color: var(--ink-2); }
.room-next-link:hover { border-color: rgba(182, 156, 255, .6); box-shadow: 0 0 34px -14px var(--strat-glow); }
.room-next-link.is-tact:hover { border-color: rgba(47, 230, 200, .55); box-shadow: 0 0 34px -14px var(--tact-glow); }
.room + .room-next { margin-top: 24px; }

@media (prefers-reduced-motion: reduce) {
  /* A fade only: the doors do not grow and the wires do not run. */
  .room-ctx, .room-part, .room-door, .room-wall, .room-wire, .room-next-link { transition: none; }
  .room-card.is-drawn .room-door { animation: room-fade .4s ease both; }
  .room-card.is-drawn .room-wire .n-line, .room-card.is-drawn .room-wire .n-dot, .room-card.is-drawn .room-wire .n-arrow { stroke-dasharray: none; animation: room-fade .4s ease both; }
  .room-card.is-drawn .room-wire.is-ref .n-line { stroke-dasharray: 4 3; }
  .room-card.is-drawn .room-ctx { animation: room-ctx-light .4s ease both; }
}
@media (max-width: 640px) {
  .room-card { padding: 16px 12px 14px; }
  .room-outside { gap: 10px; }
  .room-gap { height: 44px; }
  .room-ctx { min-height: 0; padding: 8px 10px; }
  .room-ctx-owns { display: none; }
  .room-ctx-name { font-size: 15px; }
  .room-wall { padding: 26px 8px; border-radius: 20px; }
  .room-inside { gap: 8px; }
  .room-part { padding: 10px; }
  .room-part-name { font-size: 15px; }
  .room-part:not([data-part="model"]) .room-chips { display: none; }
  .room-wall-name { font-size: 22px; }
  .room-wall-tag { display: none; }
  .room-door { --cut: 14px 0 0 -10px var(--node-fill), -14px 0 0 -10px var(--node-fill); gap: 4px; padding: 4px 7px 4px 5px; font-size: 12px; }
  .room-door.is-event .room-door-name { font-size: 11.5px; }
  .room-door-icon { width: 14px; height: 14px; }
  .room-next { grid-template-columns: minmax(0, 1fr); }
  .room-panel { padding: 20px; }
}

/* Context map (bead dcg.6.5): every context and the relationships between them,
   built by site/assets/contextmap.js from webshop.js. A pattern filter on top,
   then the explorer layout (.explorer, .diagram-card, .inspector, .insp-*): the
   map with its relationship list under it, and the side panel. Upstream and
   downstream are shown by a solid U and a hollow D badge (never colour alone)
   and by position: the upstream side is always drawn higher. */
.cmap-filter { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 14px; margin-bottom: 18px; }
.cmap-filter-label { margin: 0; font: 600 11px/16px var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--ink-3); }
.cmap-patterns { display: flex; flex-wrap: wrap; gap: 8px; }
.cmap-chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 36px;
  padding: 4px 13px 4px 6px;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  background: rgba(255, 255, 255, .03);
  color: var(--ink-2);
  font: 500 14px/1.2 var(--sans);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: color .15s, border-color .15s, background-color .15s, box-shadow .15s;
}
.cmap-chip.is-all { padding-left: 14px; }
.cmap-chip:hover { color: var(--ink); border-color: rgba(169, 203, 255, .55); background: rgba(255, 255, 255, .06); }
.cmap-chip[aria-checked="true"] { color: var(--ink); border-color: var(--ink); background: rgba(92, 157, 255, .14); box-shadow: inset 0 0 0 1px var(--ink), 0 0 26px -8px var(--block-glow); }
.cmap-chip:focus-visible { outline-offset: 3px; }

/* Badges in the page text: the same shapes as on the map. */
.cmap-abbr {
  display: inline-grid;
  place-items: center;
  flex: none;
  min-width: 26px;
  height: 20px;
  padding: 0 5px;
  border: 1.4px solid var(--block);
  border-radius: 5px;
  background: var(--node-fill);
  color: var(--block-soft);
  font: 600 11px/1 var(--mono);
}
.cmap-abbr.is-door { border-color: var(--door); background: var(--door-fill); color: var(--door-soft); }
.cmap-ud {
  display: inline-grid;
  place-items: center;
  flex: none;
  width: 20px;
  height: 20px;
  border: 1.6px solid var(--wire-lit);
  border-radius: 50%;
  font: 600 11px/1 var(--mono);
}
.cmap-ud.is-up { background: var(--wire-lit); color: var(--bg); }
.cmap-ud.is-down { background: var(--node-fill); color: var(--wire-lit); }

.cmap-card { padding: 18px clamp(12px, 2.4vw, 22px); }
.cmap-key { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 16px; margin: 0 0 10px; font-size: 13px; color: var(--ink-2); }
.cmap-key-item { display: inline-flex; align-items: center; gap: 7px; }
.cmap-key-note { color: var(--ink-3); }
.cmap-canvas { position: relative; }
.cmap-svg { display: block; width: 100%; height: auto; aspect-ratio: var(--cmap-ratio, 1.34); overflow: visible; -webkit-tap-highlight-color: transparent; }
/* A narrow box (under 640px, contextmap.js adds .is-zoomable): the same drawing
   in a window of fixed height, zoomed by its viewBox (bead qwt). At the whole
   picture vertical drags still scroll the page; once zoomed in, one finger pans. */
.cmap-canvas.is-zoomable .cmap-viewport {
  position: relative;
  height: clamp(260px, min(60vh, 92vw), 560px);
  height: clamp(260px, min(60svh, 92vw), 560px);
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: rgba(6, 10, 22, .45);
  touch-action: pan-y;
  user-select: none;
  -webkit-user-select: none;
}
.cmap-canvas.is-zoomable .cmap-viewport.is-zoomed { touch-action: none; cursor: grab; }
.cmap-canvas.is-zoomable .cmap-viewport.is-zoomed:active { cursor: grabbing; }
.cmap-canvas.is-zoomable .cmap-svg { width: 100%; height: 100%; aspect-ratio: auto; overflow: hidden; }
.cmap-canvas.is-zoomable .cmap-node { cursor: pointer; }
.cmap-canvas.is-zoomable .cmap-hit { stroke-width: var(--cmap-hit, 26px); }
.cmap-zoombar { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 12px; margin-top: 10px; }
.cmap-zoombar[hidden] { display: none; }
.cmap-zoom-where { flex: 1 1 12em; margin: 0; font-size: 13px; line-height: 1.4; color: var(--ink-3); }
.cmap-zoom-btns { display: flex; flex-wrap: wrap; gap: 8px; }
.cmap-zoom-btn {
  min-height: 36px;
  padding: 6px 14px;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  background: rgba(255, 255, 255, .03);
  color: var(--ink);
  font: 500 14px/1.2 var(--sans);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: color .15s, border-color .15s, background-color .15s;
}
.cmap-zoom-btn:hover { border-color: rgba(169, 203, 255, .55); background: rgba(255, 255, 255, .06); }
.cmap-zoomout { border-color: var(--ink); background: rgba(92, 157, 255, .14); }
.cmap-zoomout[aria-disabled="true"] { color: var(--ink-3); border-color: var(--line); background: none; cursor: default; }
.cmap-zoom-btn:focus-visible { outline-offset: 3px; }

/* Far out on a zoomable map: the walls' names large, the small text hidden,
   the lines and walls a little heavier so they still show at a third of their size. */
.cmap-node-far { display: none; font-family: var(--display); font-weight: 600; letter-spacing: -.01em; fill: var(--strat-soft); text-anchor: middle; dominant-baseline: central; paint-order: stroke; stroke: var(--bg); stroke-width: .22em; stroke-linejoin: round; }
.cmap-node.is-external .cmap-node-far { fill: var(--ext-soft); }
.cmap-node.is-lit .cmap-node-far { fill: #fff; }
.cmap-svg.is-far .cmap-node-far { display: inline; }
.cmap-svg.is-far .cmap-node-name,
.cmap-svg.is-far .cmap-node-kind,
.cmap-svg.is-far .n-badge-text { display: none; }
.cmap-svg.is-far .cmap-line, .cmap-svg.is-far .cmap-tick { stroke-width: 3.6; }
.cmap-svg.is-far .cmap-rel.is-selected .cmap-line, .cmap-svg.is-far .cmap-rel.is-selected .cmap-tick { stroke-width: 5.5; }
.cmap-svg.is-far .cmap-wall { stroke-width: 3.4; }
.cmap-svg.is-far .cmap-node.is-lit .cmap-wall { stroke-width: 4.4; }
.cmap-caption { margin: 12px 0 0; font-size: 14px; line-height: 1.5; color: var(--ink-3); }

/* The walls on the map. */
.cmap-node { transition: opacity .2s; }
.cmap-wall.n-bc { fill: #100F2C; stroke-width: 2; filter: drop-shadow(0 0 6px var(--strat-glow)); }
.cmap-wall.n-ext { fill: var(--node-fill); }
.cmap-node-name { font: 600 15px/1 var(--display); letter-spacing: -.01em; fill: var(--strat-soft); text-anchor: middle; dominant-baseline: central; }
.cmap-node.is-external .cmap-node-name { fill: var(--ext-soft); }
.cmap-node-kind { font: 600 9.5px/1 var(--sans); letter-spacing: .1em; text-transform: uppercase; fill: var(--ink-3); text-anchor: middle; dominant-baseline: central; }
.cmap-node.is-lit .cmap-wall.n-bc { stroke: var(--strat-soft); stroke-width: 2.6; filter: drop-shadow(0 0 4px var(--strat-glow)) drop-shadow(0 0 14px var(--strat-glow)); }
.cmap-node.is-lit .cmap-wall.n-ext { stroke: var(--ext-soft); stroke-width: 2.2; }
.cmap-node.is-lit .cmap-node-name { fill: #fff; }
.cmap-node.is-dim { opacity: .35; }

/* The lines: a wide invisible band takes the pointer, the focus and the tap. */
.cmap-rel { cursor: pointer; outline: none; transition: opacity .2s; }
.cmap-rel:focus-visible { outline: none; }
.cmap-hit { fill: none; stroke: transparent; stroke-width: 26; stroke-linecap: round; stroke-linejoin: round; pointer-events: stroke; transition: stroke .15s; }
.cmap-line, .cmap-tick { stroke: var(--wire); transition: stroke .15s, stroke-width .15s; }
.cmap-rel:hover .cmap-line, .cmap-rel:hover .cmap-tick { stroke: var(--block-soft); }
.cmap-rel.is-selected .cmap-hit { stroke: rgba(92, 157, 255, .10); }
.cmap-rel.is-selected .cmap-line, .cmap-rel.is-selected .cmap-tick { stroke: var(--wire-lit); stroke-width: 3; filter: drop-shadow(0 0 5px var(--block-glow)); }
.cmap-rel:focus-visible .cmap-hit { stroke: rgba(169, 203, 255, .28); }
.cmap-rel.is-dim { opacity: .2; }
.cmap-rel.is-dim.is-selected, .cmap-node.is-dim.is-lit { opacity: 1; }
.cmap-badge.is-hot rect { stroke-width: 2.2; filter: drop-shadow(0 0 6px var(--block-glow)); }
.cmap-badge.is-door.is-hot rect { filter: drop-shadow(0 0 6px var(--door-glow)); }
.cmap-svg .n-badge-text { font-size: 11px; }

/* Drawing in: the walls light up, the lines run, the badges land. */
/* The animations run on the parts, so a dimmed group (.is-dim) stays dimmed. */
.cmap-card:not(.is-drawn) .cmap-node > * { opacity: .3; }
.cmap-card:not(.is-drawn) .cmap-line,
.cmap-card:not(.is-drawn) .cmap-tick,
.cmap-card:not(.is-drawn) .cmap-cap,
.cmap-card:not(.is-drawn) .cmap-mid { opacity: 0; }
.cmap-card.is-drawn .cmap-node > * { animation: cmap-light .45s ease both; }
.cmap-card.is-drawn .cmap-line { stroke-dasharray: 1 1; animation: cmap-draw .55s cubic-bezier(.4, 0, .2, 1) both var(--d); }
.cmap-card.is-drawn .cmap-tick,
.cmap-card.is-drawn .cmap-cap,
.cmap-card.is-drawn .cmap-mid { animation: room-fade .3s ease both calc(var(--d) + .4s); }
@keyframes cmap-draw { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
@keyframes cmap-light { from { opacity: .3; } to { opacity: 1; } }

/* The relationship list under the map. */
.cmap-list-box { margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--line); }
.cmap-list-head { margin: 0 0 10px; font: 600 12px/1.4 var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--ink-3); }
.cmap-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 8px; }
.cmap-item {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
  min-width: 0;
  padding: 10px 12px;
  border: 1px solid var(--line-strong);
  border-radius: 12px;
  background: rgba(12, 19, 38, .6);
  color: var(--ink);
  font: inherit;
  text-align: left;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: border-color .15s, background-color .15s, box-shadow .15s, opacity .2s;
}
.cmap-item:hover { border-color: rgba(169, 203, 255, .55); background-color: rgba(20, 29, 54, .9); }
.cmap-item[aria-checked="true"] { border-color: var(--ink); background-color: rgba(22, 31, 58, .95); box-shadow: inset 0 0 0 1px var(--ink), 0 0 26px -8px var(--block-glow); }
.cmap-item:focus-visible { outline-offset: 3px; }
.cmap-item.is-dim:not([aria-checked="true"]) { opacity: .45; }
.cmap-item-sides { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; font: 600 15px/1.3 var(--display); letter-spacing: -.01em; }
.cmap-item-side { display: inline-flex; align-items: center; gap: 6px; }
.cmap-item-name { color: var(--strat-soft); overflow-wrap: anywhere; }
.cmap-item-name.is-external { color: var(--ext-soft); }
.cmap-item-and { margin-inline: -6px; font: 400 13px/1.3 var(--sans); color: var(--ink-3); }
.cmap-item-patterns { display: flex; flex-wrap: wrap; gap: 4px 10px; font-size: 13px; line-height: 1.3; color: var(--ink-2); }
.cmap-item-pattern { display: inline-flex; align-items: center; gap: 6px; }
.cmap-item-pattern.is-hot { color: var(--ink); }
.cmap-item-pattern.is-hot .cmap-abbr { box-shadow: 0 0 12px -2px var(--block-glow); }
.cmap-item-pattern.is-hot .cmap-abbr.is-door { box-shadow: 0 0 12px -2px var(--door-glow); }

/* The panel. */
.cmap-kind { color: var(--strat); text-shadow: 0 0 14px var(--strat-glow); }
.insp-name.cmap-name { font-family: var(--display); font-weight: 600; letter-spacing: -.01em; text-shadow: none; }
.cmap-sides { display: grid; gap: 8px; margin: 0 0 18px; }
.cmap-side { display: flex; align-items: flex-start; gap: 10px; padding: 9px 12px; border: 1px solid var(--line-strong); border-radius: 12px; background: rgba(12, 19, 38, .5); }
.cmap-side .cmap-ud { margin-top: 2px; }
.cmap-side-text { display: flex; flex-direction: column; gap: 1px; margin: 0; font-size: 14px; line-height: 1.45; }
.cmap-side-role { font: 600 11px/1.5 var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--ink-3); }
.cmap-side-name { font: 600 17px/1.3 var(--display); letter-spacing: -.01em; color: var(--strat-soft); }
.cmap-side-name.is-external { color: var(--ext-soft); }
.cmap-side-note { color: var(--ink-2); }
.cmap-why h4 { margin: 0 0 4px; font: 600 12px var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--ink-3); }
.cmap-pats { display: grid; gap: 10px; margin: 0 0 18px; }
.cmap-pat { padding: 12px 14px; border: 1px solid rgba(92, 157, 255, .35); border-radius: 12px; background: rgba(92, 157, 255, .06); }
.cmap-pat.is-door { border-color: rgba(255, 123, 84, .4); background: var(--door-wash); box-shadow: 0 0 26px -14px var(--door-glow); }
.cmap-pat.is-hot { border-color: var(--block-soft); }
.cmap-pat.is-door.is-hot { border-color: var(--door-soft); }
.cmap-pat-head { display: flex; align-items: center; gap: 8px; margin: 0 0 4px; font: 600 17px/1.3 var(--display); letter-spacing: -.01em; color: var(--ink); }
.cmap-pat.is-door .cmap-pat-name { color: var(--door-soft); }
.cmap-pat-where { margin: 0 0 8px; font-size: 13px; line-height: 1.4; color: var(--ink-3); }
.cmap-pat-idea { margin: 0 0 8px; font-size: 14px; line-height: 1.5; color: var(--ink); }
.cmap-pat-when { margin: 0; font-size: 14px; line-height: 1.5; color: var(--ink-2); }
.cmap-pat-when strong { color: var(--ink); font-weight: 600; }
.cmap-panel [hidden] { display: none; }
/* Where a tap on a stacked layout scrolls the panel to: just under the sticky header. */
.cmap-panel { scroll-margin-top: 84px; }
@media (max-width: 640px) { .cmap-panel { scroll-margin-top: 112px; } }
.cmap-panel .insp-rel li { line-height: 1.45; }

@media (prefers-reduced-motion: reduce) {
  /* A fade only: the lines do not run. */
  .cmap-chip, .cmap-item, .cmap-node, .cmap-rel, .cmap-hit, .cmap-line, .cmap-tick { transition: none; }
  .cmap-card.is-drawn .cmap-line { stroke-dasharray: none; animation: room-fade .4s ease both; }
  .cmap-card.is-drawn .cmap-node > *,
  .cmap-card.is-drawn .cmap-tick,
  .cmap-card.is-drawn .cmap-cap,
  .cmap-card.is-drawn .cmap-mid { animation: room-fade .4s ease both; }
}
@media (max-width: 640px) {
  .cmap-filter { gap: 8px; }
  .cmap-patterns { gap: 6px; }
  .cmap-chip { min-height: 34px; padding-right: 11px; font-size: 13px; }
  .cmap-card { padding: 14px 12px; }
  .cmap-list { grid-template-columns: minmax(0, 1fr); }
  .cmap-panel { padding: 20px; }
}

/* A small reusable Before/After style segmented switch (bead ca1.3, site/assets/
   switcher.js): a two- (or more-) option ARIA radiogroup rendered as a pill.
   --switcher-accent and --switcher-accent-fill pick the highlight colour for the
   selected option; a feature sets them on its own host if the default (coral,
   the door colour) is not the right one. */
.switcher {
  --switcher-accent: var(--door);
  --switcher-accent-fill: var(--door-fill);
  display: inline-flex;
  flex-wrap: wrap;
  gap: 4px;
  padding: 4px;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  background: rgba(255, 255, 255, .03);
}
.switcher-opt {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 40px;
  padding: 8px 16px;
  border: none;
  border-radius: 999px;
  background: none;
  color: var(--ink-2);
  font: 600 13px/1.2 var(--sans);
  text-align: center;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: color .15s, background-color .15s, box-shadow .15s;
}
.switcher-opt:hover { color: var(--ink); }
.switcher-opt[aria-checked="true"] {
  background: var(--switcher-accent);
  color: var(--switcher-accent-fill);
  box-shadow: 0 0 16px -4px var(--switcher-accent);
}
.switcher-opt:focus-visible { outline-offset: 3px; }
.switcher-icon { width: 16px; height: 16px; }
@media (prefers-reduced-motion: reduce) {
  .switcher-opt { transition: none; }
}

/* Doors in the wall (bead dcg.6.6): a stepper that follows one message across a
   wall per door pattern, built by site/assets/doors.js from webshop.js. Tabs on
   top, one panel per step, Previous and Next under it. A step's stage is the
   message before the door, the violet wall with its coral door, and the message
   after it; the side of the stage inside the wall has a violet wash. On narrow
   screens the three stack and the wall turns horizontal. On phones (640px and
   below) the switcher (data-mobile-show on .doors-stage) shows one message at a
   time instead. */
.doors { padding: 20px clamp(14px, 2.4vw, 24px) 18px; }
.doors-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 14px; margin-bottom: 22px; }
.doors-label { margin: 0; font: 600 11px/16px var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--ink-3); }
.doors-tabs { display: flex; flex-wrap: wrap; gap: 8px; }
.doors-tab {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 40px;
  padding: 5px 16px 5px 6px;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  background: rgba(255, 255, 255, .03);
  color: var(--ink-2);
  font: 600 15px/1.2 var(--display);
  letter-spacing: -.01em;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: color .15s, border-color .15s, background-color .15s, box-shadow .15s;
}
.doors-tab-n { display: inline-grid; place-items: center; width: 26px; height: 26px; border-radius: 50%; background: rgba(255, 255, 255, .06); font: 600 13px/1 var(--sans); color: var(--ink-2); }
.doors-tab:hover { color: var(--ink); border-color: rgba(255, 198, 179, .5); background: rgba(255, 255, 255, .06); }
.doors-tab[aria-selected="true"] {
  color: var(--ink);
  border-color: var(--door-soft);
  background: var(--door-wash);
  box-shadow: inset 0 0 0 1px var(--door-soft), 0 0 26px -8px var(--door-glow);
}
.doors-tab[aria-selected="true"] .doors-tab-n { background: var(--door); color: var(--door-fill); }
.doors-tab:focus-visible { outline-offset: 3px; }
.doors-hint { margin: 0 0 0 auto; font-size: 13px; color: var(--ink-3); }
.doors-panel[hidden] { display: none; }

/* The step's head. */
.doors-head { margin-bottom: 14px; }
.doors-title { display: flex; align-items: center; gap: 10px; margin: 0 0 6px; font: 600 26px/1.2 var(--display); letter-spacing: -.015em; color: var(--door-soft); }
.doors-title .cmap-abbr { height: 24px; min-width: 38px; font-size: 12.5px; box-shadow: 0 0 14px -2px var(--door-glow); }
.doors-idea { margin: 0 0 10px; font-size: 16px; line-height: 1.5; color: var(--ink); max-width: 68ch; }
.doors-where { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 18px; margin: 0; font-size: 14px; line-height: 1.4; color: var(--ink-2); }
.doors-where-part { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 0 6px; }
.doors-where-part .cmap-ud { margin-right: 1px; }
.doors-where-part.is-door { flex-wrap: nowrap; align-items: flex-start; color: var(--door-soft); }
.doors-where-icon { width: 17px; height: 17px; color: var(--door); }
.doors-ctx { color: var(--strat-soft); font-weight: 600; }
.doors-ctx.is-external { color: var(--ext-soft); }
.doors-says { margin: 0 0 18px; max-width: 78ch; font-size: 15px; line-height: 1.6; color: var(--ink-2); }

/* The stage. */
.doors-stage {
  --wash: linear-gradient(90deg, transparent calc(50% - 1px), rgba(160, 130, 255, .08) calc(50% - 1px));
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 124px minmax(0, 1fr);
  align-items: stretch;
  padding: 14px;
  border: 1px solid var(--line);
  border-radius: 16px;
  background: var(--wash), rgba(6, 10, 20, .35);
}
.doors-stage[data-inside="before"] { --wash: linear-gradient(270deg, transparent calc(50% - 1px), rgba(160, 130, 255, .08) calc(50% - 1px)); }

/* The mobile switch (site/assets/switcher.js): built for every step, but only
   shown at 640px and below (see that media query). */
.doors-switcher-wrap { display: none; }

.doors-msg { position: relative; z-index: 1; min-width: 0; margin: 0; border: 1px solid var(--line-strong); border-radius: 12px; background: rgba(9, 14, 28, .88); overflow: hidden; }
.doors-msg.is-inside { border-color: rgba(182, 156, 255, .5); box-shadow: 0 0 22px -10px var(--strat-glow); }
.doors-msg-cap { display: flex; flex-direction: column; gap: 3px; padding: 9px 14px; border-bottom: 1px solid var(--line); }
.doors-zone { font: 600 11px/1.5 var(--sans); letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3); }
.doors-msg.is-inside .doors-zone-side { color: var(--strat-soft); }
.doors-zone-where { color: var(--ink-2); }
.doors-zone-where.is-external { color: var(--ext-soft); }
.doors-msg-title { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 2px 12px; }
.doors-msg-title b { font: 500 14px/1.4 var(--mono); color: var(--ink); overflow-wrap: anywhere; }
.doors-msg-format { font-size: 12.5px; color: var(--ink-3); }

/* The code: a block per line, a gutter for the change numbers, and a hanging
   indent (--indent is the line's leading spaces) so long lines wrap under
   themselves instead of scrolling. */
.doors-code { margin: 0; padding: 10px 12px 12px 0; font: 400 13px/1.6 var(--mono); color: #DCE6FA; white-space: pre-wrap; overflow-wrap: anywhere; }
.doors-code code { display: block; background: none; padding: 0; font-size: inherit; color: inherit; border-radius: 0; }
.doors-line {
  position: relative;
  display: block;
  padding-left: calc(30px + (var(--indent, 0) + 2) * 1ch);
  text-indent: -2ch;
  border-left: 2px solid transparent;
}
.doors-line.is-marked { border-left-color: var(--door); background: linear-gradient(90deg, rgba(255, 123, 84, .10), transparent 70%); }
.doors-line.is-dropped { border-left-color: var(--ink-3); background: linear-gradient(90deg, rgba(116, 131, 165, .12), transparent 70%); color: var(--ink-3); }
.doors-line.is-dropped span:not(.doors-mark) { color: inherit; }
.doors-mark {
  position: absolute;
  left: 6px;
  top: .2em;
  display: inline-grid;
  place-items: center;
  width: 17px;
  height: 17px;
  border-radius: 50%;
  background: var(--door);
  color: var(--door-fill);
  font: 600 10.5px/1 var(--sans);
  text-indent: 0;
}
.doors-line.is-dropped .doors-mark, .doors-change.is-dropped .doors-mark { background: var(--ink-3); color: var(--bg); }

/* The wall and its door. */
.doors-wall { position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 140px; }
.doors-wall::before {
  content: "";
  position: absolute;
  top: -14px;
  bottom: -14px;
  left: 50%;
  width: 3px;
  margin-left: -1.5px;
  background: var(--strat);
  box-shadow: 0 0 14px 1px var(--strat-glow);
}
.doors-wall-name {
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  padding: 2px 6px;
  border-radius: 6px;
  background: #0B0C22;
  font: 600 10.5px/1.4 var(--sans);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--strat-soft);
  white-space: nowrap;
}
.doors-door {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  width: 112px;
  margin: 0;
  padding: 10px 8px;
  border: 1.8px solid var(--door);
  border-radius: 12px;
  background: var(--door-fill);
  color: var(--door-soft);
  font: 600 13px/1.25 var(--sans);
  text-align: center;
  box-shadow: 0 0 20px 1px var(--door-glow);
}
.doors-door-icon { width: 20px; height: 20px; color: var(--door); }
.doors-door-name { overflow-wrap: anywhere; }

/* The message token that crosses the wall. */
.doors-token {
  --from: translate(-50%, -50%) translateX(-120px);
  --to: translate(-50%, -50%) translateX(120px);
  position: absolute;
  z-index: 3;
  top: 50%;
  left: 50%;
  padding: 3px 10px;
  border: 1.4px solid var(--block);
  border-radius: 999px;
  background: var(--node-fill);
  color: var(--ink);
  font: 500 12px/1.4 var(--mono);
  white-space: nowrap;
  box-shadow: 0 0 16px -2px var(--block-glow);
  opacity: 0;
  pointer-events: none;
}

/* Playing a step: the message before appears, the token crosses through the
   door (which lights up as it passes), and the message after appears. */
.doors:not(.is-drawn) .doors-msg,
.doors:not(.is-drawn) .doors-door { opacity: 0; }
.doors-panel.is-playing .doors-msg.is-before { animation: doors-in-left .4s cubic-bezier(.2, .8, .2, 1) both; }
.doors-panel.is-playing .doors-door { animation: doors-door 1.4s ease both; }
.doors-panel.is-playing .doors-token { animation: doors-cross 1.1s cubic-bezier(.45, 0, .35, 1) .3s both; }
.doors-panel.is-playing .doors-msg.is-after { animation: doors-in-right .45s cubic-bezier(.2, .8, .2, 1) 1.05s both; }
@keyframes doors-in-left { from { opacity: 0; transform: translateX(-10px); } to { opacity: 1; transform: none; } }
@keyframes doors-in-right { from { opacity: 0; transform: translateX(10px); } to { opacity: 1; transform: none; } }
@keyframes doors-cross {
  0% { opacity: 0; transform: var(--from); border-color: var(--block); }
  18% { opacity: 1; }
  48% { border-color: var(--block); }
  52% { border-color: var(--door); box-shadow: 0 0 18px 0 var(--door-glow); }
  82% { opacity: 1; }
  100% { opacity: 0; transform: var(--to); border-color: var(--door); }
}
@keyframes doors-door {
  0% { opacity: 1; }
  45% { box-shadow: 0 0 20px 1px var(--door-glow); }
  62% { box-shadow: 0 0 34px 8px var(--door-glow); border-color: var(--door-soft); }
  100% { opacity: 1; box-shadow: 0 0 20px 1px var(--door-glow); }
}

/* What the door does, who reads it, and the link to the map. */
.doors-details { display: grid; grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr); gap: 20px 28px; margin-top: 22px; }
.doors-details h4 { margin: 0 0 8px; font: 600 12px var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--ink-3); }
.doors-change-list { list-style: none; margin: 0; padding: 0; }
.doors-change { position: relative; padding: 8px 0 8px 28px; border-top: 1px solid var(--line); }
.doors-change .doors-mark { left: 0; top: 10px; }
.doors-change-fields { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 6px; font-size: 13px; color: var(--ink-3); }
.doors-change-fields code { font-size: 12.5px; overflow-wrap: anywhere; }
.doors-change-arrow { color: var(--door); }
.doors-change-none { font-style: italic; }
.doors-change-says { margin: 3px 0 0; font-size: 14px; line-height: 1.5; color: var(--ink-2); }
.doors-side { display: flex; flex-direction: column; gap: 16px; }
.doors-reader-list { list-style: none; margin: 0; padding: 0; font-size: 14px; line-height: 1.55; color: var(--ink-2); }
.doors-reader { padding: 8px 0; border-top: 1px solid var(--line); }
.doors-reader code { font-size: 12.5px; }
.doors-map-link { display: flex; flex-direction: column; gap: 4px; padding: 14px 18px; border-radius: 14px; color: var(--ink); text-decoration: none; transition: border-color .2s, box-shadow .2s; }
.doors-map-link small { font: 600 11px/1.6 var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--strat); }
.doors-map-link-title { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; font: 600 17px/1.3 var(--display); letter-spacing: -.01em; }
.doors-map-link-text { font-size: 14px; line-height: 1.5; color: var(--ink-2); }
.doors-map-link:hover { border-color: rgba(182, 156, 255, .6); box-shadow: 0 0 34px -14px var(--strat-glow); }

/* Previous, the step count and Next. */
.doors-nav { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-top: 22px; padding-top: 16px; border-top: 1px solid var(--line); }
.doors-count { margin: 0; font: 600 13px/1.4 var(--sans); letter-spacing: .08em; text-transform: uppercase; color: var(--ink-2); }
.doors-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 40px;
  padding: 6px 16px;
  border: 1px solid var(--line-strong);
  border-radius: 10px;
  background: rgba(255, 255, 255, .03);
  color: var(--ink);
  font: 500 15px/1.2 var(--sans);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: color .15s, border-color .15s, background-color .15s;
}
.doors-btn:hover { border-color: rgba(255, 198, 179, .55); background: rgba(255, 255, 255, .06); }
.doors-btn[aria-disabled="true"] { color: var(--ink-3); border-color: var(--line); background: none; cursor: default; }
.doors-btn:focus-visible { outline-offset: 3px; }
.doors .legend { margin-top: 18px; }

@media (prefers-reduced-motion: reduce) {
  /* A fade only: the messages do not slide, the token does not cross and the door does not pulse. */
  .doors-tab, .doors-btn, .doors-map-link { transition: none; }
  .doors-token { display: none; }
  .doors-panel.is-playing .doors-door { animation: room-fade .3s ease both; }
  .doors-panel.is-playing .doors-msg.is-before { animation: room-fade .3s ease both; }
  .doors-panel.is-playing .doors-msg.is-after { animation: room-fade .35s ease .15s both; }
}
@media (max-width: 860px) {
  .doors-details { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 720px) {
  /* Stacked: before, the wall lying across with its door, after. */
  .doors-stage {
    --wash: linear-gradient(180deg, transparent calc(50% - 1px), rgba(160, 130, 255, .08) calc(50% - 1px));
    grid-template-columns: minmax(0, 1fr);
    padding: 10px;
  }
  .doors-stage[data-inside="before"] { --wash: linear-gradient(0deg, transparent calc(50% - 1px), rgba(160, 130, 255, .08) calc(50% - 1px)); }
  .doors-wall { min-height: 0; }
  .doors-wall::before { top: 50%; bottom: auto; left: -10px; right: -10px; width: auto; height: 3px; margin: -1.5px 0 0; }
  .doors-wall { padding: 22px 0 18px; }
  .doors-wall-name { top: 0; left: 0; transform: none; }
  .doors-door { flex-direction: row; flex-wrap: wrap; justify-content: center; width: auto; max-width: calc(100% - 40px); padding: 7px 12px; }
  .doors-token { --from: translate(-50%, -50%) translateY(-54px); --to: translate(-50%, -50%) translateY(54px); }
  .doors-panel.is-playing .doors-msg.is-before { animation-name: doors-in-top; }
  .doors-panel.is-playing .doors-msg.is-after { animation-name: doors-in-bottom; }
  @keyframes doors-in-top { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: none; } }
  @keyframes doors-in-bottom { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
}
@media (max-width: 720px) and (prefers-reduced-motion: reduce) {
  .doors-panel.is-playing .doors-msg.is-before, .doors-panel.is-playing .doors-msg.is-after { animation-name: room-fade; }
}
@media (max-width: 640px) {
  .doors { padding: 16px 12px 14px; }
  .doors-hint { margin-left: 0; flex-basis: 100%; }
  .doors-tab { padding-right: 12px; font-size: 14px; }
  .doors-title { font-size: 22px; }
  .doors-idea { font-size: 15px; }
  .doors-code { font-size: 12px; }
  .doors-line { padding-left: calc(26px + (var(--indent, 0) + 2) * 1ch); }
  .doors-mark { left: 4px; }
  .doors-wall-name { font-size: 10px; letter-spacing: .06em; }
  .doors-btn { padding: 6px 12px; }

  /* One message at a time: the door, the switch, then the chosen message
     card, with its own scrollbar if the code runs long. Swiping the card
     switches (site/assets/switcher.js, swipeArea = .doors-stage). */
  .doors-stage { display: flex; flex-direction: column; gap: 12px; padding: 12px; }
  .doors-wall { order: 1; width: 100%; }
  .doors-switcher-wrap { display: flex; order: 2; justify-content: center; }
  .doors-msg { order: 3; max-height: 62vh; overflow-y: auto; }
  .doors-stage[data-mobile-show="before"] .doors-msg.is-after,
  .doors-stage[data-mobile-show="after"] .doors-msg.is-before { display: none; }
  .doors-msg.is-switch-fade { animation: room-fade .25s ease both; }
}

/* Zoom in (bead dcg.6.7): the card that hands over to the Tactical page. The whole
   card is one link. Its figure is drawn by site/assets/zoomin.js: the Sales wall
   (.zw-card, a copy of the Tactical hero's outer wall) on a piece of the context
   map. Following the link zooms that wall into the Tactical hero (app.js). */
.zoomin {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
  align-items: center;
  gap: 16px 40px;
  padding: 22px 36px 22px 22px;
  border-radius: 20px;
  color: var(--ink);
  text-decoration: none;
  transition: border-color .2s, box-shadow .2s;
}
.zoomin:hover {
  border-color: rgba(47, 230, 200, .55);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .05), 0 0 60px -22px var(--tact-glow);
}
.zoomin:focus-visible { outline-offset: 4px; }
.zoomin-art { display: block; min-width: 0; }
.zoomin-svg { display: block; width: 100%; height: auto; overflow: visible; }
.zoomin-body { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; min-width: 0; }
.zoomin-kicker { font: 600 12px/1.6 var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--tact); text-shadow: 0 0 14px var(--tact-glow); }
.zoomin-title { font: 600 clamp(26px, 3.2vw, 36px)/1.12 var(--display); letter-spacing: -.02em; }
.zoomin-text { max-width: 38ch; font-size: 16px; line-height: 1.55; color: var(--ink-2); }
.zoomin-cta {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-top: 12px;
  padding: 9px 18px;
  border: 1px solid rgba(47, 230, 200, .45);
  border-radius: 999px;
  background: var(--tact-wash);
  color: var(--tact-soft);
  font: 600 15px/1.2 var(--sans);
  box-shadow: 0 0 24px -10px var(--tact-glow);
  transition: background-color .2s, border-color .2s;
}
.zoomin:hover .zoomin-cta { border-color: var(--tact); background: rgba(47, 230, 200, .14); }

/* The map around Sales: quiet, like the dimmed walls on the context map. */
.zoomin-rel { fill: none; stroke: var(--block); stroke-width: 1.6; stroke-linecap: round; opacity: .45; }
.zoomin-ctx-wall { fill: #100F2C; stroke: var(--strat); stroke-width: 1.5; opacity: .6; }
.zoomin-ctx-name { font: 600 15px/1 var(--display); letter-spacing: -.01em; fill: var(--strat-soft); text-anchor: middle; dominant-baseline: central; opacity: .7; }
/* The Sales wall. Its parts keep the hero's classes (.ha-*) and are drawn in hero
   units, scaled down onto the map, so their lines are thickened here to read at
   that size. The moving copy in app.js carries .zw-card too, so it starts out
   looking exactly like this. */
.zw-card .ha-bc { stroke-width: 3.4; filter: drop-shadow(0 0 12px var(--strat-glow)); }
.zw-card .ha-door { stroke-width: 3; }
.zw-card .ha-wire { stroke-width: 2.6; }
.zw-card .ha-dot { r: 5; }
.zw-name { font: 600 38px/1 var(--display); letter-spacing: -.01em; fill: var(--strat-soft); text-anchor: middle; dominant-baseline: central; }
.zw-kind { font: 600 19px/1 var(--sans); letter-spacing: .1em; text-transform: uppercase; fill: var(--ink-3); text-anchor: middle; dominant-baseline: central; }
.zoomin:hover .zw-card .ha-bc { stroke: var(--strat-soft); filter: drop-shadow(0 0 6px var(--strat-glow)) drop-shadow(0 0 20px var(--strat-glow)); }
.zoomin-svg[data-layout="narrow"] .zoomin-ctx-name { font-size: 14px; }

@media (prefers-reduced-motion: reduce) {
  .zoomin, .zoomin-cta { transition: none; }
}
@media (max-width: 920px) {
  .zoomin { grid-template-columns: minmax(0, 1fr); padding: 22px; }
  .zoomin-art { width: 100%; max-width: 600px; justify-self: center; }
}
@media (max-width: 640px) {
  .zoomin { padding: 16px 16px 20px; gap: 14px; }
  .zoomin-art { max-width: 280px; }
  .zoomin-cta { margin-top: 6px; }
}

/* Zoom between the pages (bead dcg.6.7, driven by site/assets/app.js). While the
   Sales wall grows from the card into the Tactical hero (body[data-zoom-move]),
   both pages are fixed at the offsets they rest at, app.js sets their `top`, and
   the footer rides along with the page it shows under (or waits out of sight).
   .zoom-flyer is the moving copy of the wall, laid out at the size of the hero
   drawing and carried by its transform, like the fold's flyer. */
body[data-zoom-move] #view-strategic,
body[data-zoom-move] #view-tactical,
body[data-zoom-move] .site-footer { position: fixed; left: 0; right: 0; z-index: 1; }
body[data-zoom-move] .site-footer.is-zoom-away { visibility: hidden; }
body[data-zoom-move] .site-header,
body[data-zoom-move] main,
body[data-zoom-move] .site-footer { pointer-events: none; }
/* The two drawings the copy stands in for, while it moves. */
.is-zoom-hidden { visibility: hidden; }
.zoom-flyer { position: fixed; top: 0; left: 0; z-index: 5; transform-origin: 0 0; cursor: pointer; }
.zoom-flyer[hidden] { display: none; }
.zoom-flyer > svg { position: absolute; top: 0; left: 0; width: 100%; height: 100%; max-width: none; overflow: visible; }
/* On its way the wall hides the fading page behind it; the hero's drawing
   fades in on top of it, and the backdrop leaves with the card's drawing. */
.zoom-flyer > .zw-card .ha-bc { fill: rgba(13, 16, 38, .94); }
/* The ambient loops hold still in the copy, so it is not repainted every frame. */
.zoom-flyer svg, .zoom-flyer svg * { animation-play-state: paused; }

/* Layers inside a context (bead dcg.7.1): ports and adapters in the Sales context,
   built by site/assets/layers.js from webshop.js. The violet Sales wall holds
   three columns (wide) or three rows (narrow, the default): the driving side, the
   application ring with the domain model ring inside it, and the driven side.
   Application services are coral doors in the application ring; ports are coral
   doors of the domain model. The dependency arrows (.n-dep) sit in an SVG overlay
   above the ring backgrounds and below the parts; .is-wide is set by layers.js
   from the diagram's own width. */
.layers-card { padding: 22px clamp(12px, 2.4vw, 24px) 18px; }
.layers-rule { display: flex; align-items: center; gap: 10px; margin: 0 0 16px; font: 600 14px/1.4 var(--sans); color: var(--ink); }
.layers-rule .n-glyph { width: 34px; height: 20px; flex: none; }
.layers-caption { margin: 16px 0 0; font-size: 14px; line-height: 1.5; color: var(--ink-3); }
.layers-diagram { position: relative; }
.layers-arrows { position: absolute; inset: 0; z-index: 1; width: 100%; height: 100%; overflow: visible; pointer-events: none; }

.layers-wall {
  position: relative;
  padding: 12px clamp(8px, 1.8vw, 18px) 20px;
  border: 2.4px solid var(--strat);
  border-radius: 26px;
  background: radial-gradient(90% 70% at 50% 45%, rgba(92, 157, 255, .07), transparent 70%), rgba(160, 130, 255, .05);
  box-shadow: 0 0 0 5px rgba(160, 130, 255, .07), 0 0 34px -6px var(--strat-glow), inset 0 0 44px -16px var(--strat-glow);
}
.layers-wall-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 8px; margin: 0 0 12px 4px; }
.layers-wall-name { font: 600 22px/1.2 var(--display); letter-spacing: -.02em; color: var(--strat-soft); text-shadow: 0 0 18px var(--strat-glow); }
.layers-wall-kind { font: 600 11px/1.4 var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--strat); }

/* The layer names: small buttons of their own. */
.layers-label {
  position: relative;
  z-index: 2;
  display: inline-flex;
  margin: 0 0 8px;
  padding: 3px 8px;
  border: 1px solid transparent;
  border-radius: 8px;
  background: transparent;
  color: var(--ink-2);
  font: 600 11px/1.4 var(--sans);
  letter-spacing: .12em;
  text-transform: uppercase;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: border-color .15s, background-color .15s, color .15s;
}
.layers-label.is-domain { color: #D5E2FF; }
.layers-label:hover { border-color: var(--line-strong); background: rgba(255, 255, 255, .04); color: var(--ink); }
.layers-label[aria-checked="true"] { border-color: var(--ink); color: var(--ink); background: rgba(255, 255, 255, .06); }

.layers-grid { display: flex; flex-direction: column; }
.layers-list { display: grid; gap: 8px; }
.layers-side.is-driving .layers-list { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.layers-side.is-driven .layers-list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.layers-side.is-driving { margin-bottom: 62px; }
.layers-side.is-driven { margin-top: 58px; }

/* The rings: no colour of their own, so violet stays the context wall and teal
   the aggregate wall. The domain model is the brighter one. */
.layers-ring { position: relative; border-radius: 20px; transition: box-shadow .2s, border-color .2s; }
.layers-ring.is-application { padding: 30px 10px 14px; border: 1.6px solid rgba(140, 170, 255, .4); background: rgba(92, 157, 255, .03); }
/* Narrow: the application ring's name sits at its foot, clear of the arrows from its doors. */
.layers-ring.is-application { display: flex; flex-direction: column; align-items: flex-start; }
.layers-ring.is-application > .layers-label { order: 1; margin: 10px 0 0; }
.layers-ring.is-application > .layers-ring.is-domain { align-self: stretch; }
.layers-ring.is-domain {
  margin-top: 46px;
  padding: 10px 10px 12px;
  border: 1.8px solid rgba(205, 220, 255, .65);
  background: radial-gradient(80% 70% at 50% 40%, rgba(92, 157, 255, .12), transparent 75%), rgba(12, 19, 38, .6);
  box-shadow: 0 0 30px -10px var(--block-glow), inset 0 0 36px -18px var(--block-glow);
}
.layers-ring.is-shown, .layers-side.is-shown .layers-list { box-shadow: 0 0 0 4px rgba(181, 211, 255, .12), 0 0 30px -8px var(--block-glow); }
.layers-side.is-shown .layers-list { border-radius: 12px; }

/* Doors: application services and ports. */
.layers-doors { position: relative; z-index: 2; }
.layers-doors.is-app { position: absolute; top: 0; left: 50%; display: flex; gap: 10px; width: max-content; max-width: calc(100% - 16px); transform: translate(-50%, -50%); }
.layers-doors.is-port { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 12px; }
.layers-door {
  position: relative;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  padding: 6px 10px 6px 7px;
  border: 1.6px solid var(--door);
  border-radius: 9px;
  background: var(--door-fill);
  color: var(--door-soft);
  font: 500 13px/1.25 var(--mono);
  text-align: left;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  box-shadow: 0 0 16px 0 var(--door-glow);
  transition: border-color .15s, box-shadow .15s, color .15s;
}
.layers-door-name { min-width: 0; }
.layers-door-icon { width: 15px; height: 15px; color: var(--door); }
.layers-door:hover, .layers-door.is-lit { border-color: var(--door-soft); color: #fff; box-shadow: 0 0 24px 3px var(--door-glow); }
.layers-door[aria-checked="true"] { border-color: #fff; color: #fff; box-shadow: inset 0 0 0 1px #fff, 0 0 28px 4px var(--door-glow); }

/* Aggregates: teal walls. */
.layers-aggs { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
.layers-agg {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
  min-width: 0;
  padding: 8px 10px 10px;
  border: 1.6px solid var(--tact);
  border-radius: 12px;
  background: linear-gradient(var(--tact-wash), var(--tact-wash)), var(--node-fill);
  color: var(--ink);
  font: inherit;
  text-align: left;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  box-shadow: 0 0 12px -4px var(--tact-glow);
  transition: border-color .15s, box-shadow .15s;
}
.layers-agg-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 8px; }
.layers-agg-name { font: 500 15px/1.3 var(--mono); color: var(--ink); }
.layers-agg-kind { font: 600 10.5px/1.4 var(--sans); letter-spacing: .1em; text-transform: uppercase; color: var(--tact); }
.layers-chips { display: flex; flex-wrap: wrap; gap: 5px; }
.layers-chip { padding: 0 6px; border: 1.2px solid var(--block); border-radius: 6px; background: var(--node-fill); color: var(--ink-2); font: 500 12px/1.5 var(--mono); }
.layers-agg:hover, .layers-agg.is-lit { border-color: var(--tact-soft); box-shadow: 0 0 20px -2px var(--tact-glow); }
.layers-agg[aria-checked="true"] { border-color: #fff; box-shadow: inset 0 0 0 1px #fff, 0 0 24px -2px var(--tact-glow); }

/* Adapters: ordinary building blocks, blue. */
.layers-block {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  min-width: 0;
  padding: 7px 10px 8px;
  border: 1.4px solid var(--block);
  border-radius: 10px;
  background: var(--node-fill);
  color: var(--ink);
  font: inherit;
  text-align: left;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  box-shadow: 0 0 10px -4px var(--block-glow);
  transition: border-color .15s, box-shadow .15s;
}
.layers-block-name { font: 600 14px/1.3 var(--sans); max-width: 100%; }
.layers-block-name.is-code { font: 500 13px/1.3 var(--mono); }
.layers-block-detail { font-size: 12px; line-height: 1.35; color: var(--ink-3); }
.layers-block:hover, .layers-block.is-lit { border-color: var(--block-soft); box-shadow: 0 0 18px -2px var(--block-glow); }
.layers-block[aria-checked="true"] { border-color: #fff; box-shadow: inset 0 0 0 1px #fff, 0 0 22px -2px var(--block-glow); }
.layers-label:focus-visible, .layers-door:focus-visible, .layers-agg:focus-visible, .layers-block:focus-visible { outline-offset: 3px; }

/* The arrows: all shown at rest; a selection lights its own and dims the rest. */
.layers-arrow { transition: opacity .15s; }
.layers-arrow .n-dep { opacity: .85; }
.layers-arrow.is-lit .n-dep { opacity: 1; stroke: #fff; stroke-width: 3; filter: drop-shadow(0 0 5px var(--dep-glow)); }
.layers-arrow.is-lit .n-dep-head { fill: #fff; stroke: #fff; }
.layers-diagram.has-lit .layers-arrow:not(.is-lit) { opacity: .22; }

/* Drawing in: the doors open, then the arrows run from the outside in. */
.layers-card:not(.is-drawn) .layers-arrow, .layers-card:not(.is-drawn) .layers-door { opacity: 0; }
.layers-card.is-drawn:not(.is-settled) .layers-door { animation: layers-fade .4s ease both; }
.layers-card.is-drawn:not(.is-settled) .layers-doors.is-port .layers-door { animation-delay: .15s; }
.layers-card.is-drawn:not(.is-settled) .layers-arrow .n-dep { stroke-dasharray: 1 1; animation: layers-draw .5s cubic-bezier(.4, 0, .2, 1) both var(--d); }
.layers-card.is-drawn:not(.is-settled) .layers-arrow .n-dep-head { animation: layers-fade .2s ease both calc(var(--d) + .4s); }
@keyframes layers-draw { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
@keyframes layers-fade { from { opacity: 0; } to { opacity: 1; } }

/* The panel, under the diagram: the explanation, then who depends on whom. */
.layers-panel { position: static; display: grid; grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr); gap: 8px 36px; margin-top: 20px; scroll-margin-top: 96px; }
.layers-kind { display: flex; align-items: center; gap: 7px; color: var(--block-soft); text-shadow: 0 0 14px var(--block-glow); }
.layers-panel[data-type="door"] .layers-kind { color: var(--door); text-shadow: 0 0 14px var(--door-glow); }
.layers-panel[data-type="aggregate"] .layers-kind { color: var(--tact); text-shadow: 0 0 14px var(--tact-glow); }
.layers-panel[data-type="layer"] .layers-kind { color: var(--ink-2); text-shadow: none; }
.layers-kind .layers-door-icon { width: 18px; height: 18px; }
.insp-name.layers-name { font-family: var(--display); font-weight: 600; letter-spacing: -.01em; text-shadow: none; }
.insp-name.layers-name.is-code { font-family: var(--mono); font-weight: 500; }
.layers-note {
  display: flex;
  gap: 10px;
  margin: 0 0 12px;
  padding: 10px 12px;
  border: 1px solid rgba(255, 123, 84, .4);
  border-radius: 12px;
  background: var(--door-wash);
  color: var(--door-soft);
  font-size: 14px;
  line-height: 1.45;
}
.layers-note.is-rule { border-color: rgba(47, 230, 200, .4); background: var(--tact-wash); color: var(--tact-soft); }
.layers-note .layers-door-icon { margin-top: 2px; }
.layers-panel [hidden] { display: none; }
.layers-panel .insp-rel .rel { margin-right: 6px; }
.layers-ref { color: var(--ink); font-weight: 600; }
code.layers-ref { font-weight: 500; }

.layers-diagram.is-wide .layers-wall { padding: 14px 18px 22px; }
.layers-diagram.is-wide .layers-grid { display: grid; grid-template-columns: 250px minmax(0, 1fr) 222px; align-items: center; }
.layers-diagram.is-wide .layers-side.is-driving { margin: 0 100px 0 0; }
.layers-diagram.is-wide .layers-side.is-driven { margin: 0 0 0 34px; }
.layers-diagram.is-wide .layers-list { grid-template-columns: minmax(0, 1fr); gap: 12px; padding: 0; }
.layers-diagram.is-wide .layers-ring > .layers-label { position: absolute; top: 10px; left: 12px; }
.layers-diagram.is-wide .layers-ring.is-application { display: block; padding: 44px calc(var(--ports-half, 86px) + 20px) 24px calc(var(--app-half, 54px) + 50px); }
.layers-diagram.is-wide .layers-ring.is-application > .layers-label { margin: 0; }
.layers-diagram.is-wide .layers-doors.is-app { top: 50%; left: 0; flex-direction: column; gap: 18px; }
.layers-diagram.is-wide .layers-ring.is-domain { margin-top: 0; padding: 44px calc(var(--ports-half, 86px) + 16px) 22px 16px; min-height: 270px; display: flex; flex-direction: column; justify-content: center; }
.layers-diagram.is-wide .layers-aggs { grid-template-columns: minmax(0, 1fr); gap: 12px; }
.layers-diagram.is-wide .layers-doors.is-port { position: absolute; top: 50%; right: 0; flex-direction: column; flex-wrap: nowrap; align-items: flex-start; gap: 8px; margin: 0; transform: translate(50%, -50%); }

@media (prefers-reduced-motion: reduce) {
  /* A fade only: the arrows do not run. */
  .layers-label, .layers-door, .layers-agg, .layers-block, .layers-ring, .layers-arrow { transition: none; }
  .layers-card.is-drawn:not(.is-settled) .layers-arrow .n-dep { stroke-dasharray: none; animation: layers-fade .4s ease both; }
  .layers-card.is-drawn:not(.is-settled) .layers-arrow .n-dep-head { animation: layers-fade .4s ease both; }
}
@media (max-width: 720px) {
  .layers-panel { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 640px) {
  .layers-card { padding: 16px 12px 14px; }
  .layers-rule { font-size: 13px; }
  .layers-wall { border-radius: 20px; }
  .layers-wall-name { font-size: 19px; }
  .layers-block { padding: 6px 7px 7px; }
  .layers-block-name { font-size: 13px; }
  .layers-block-name.is-code { font-size: 12px; }
  .layers-block-detail { display: none; }
  .layers-door { gap: 4px; padding: 5px 8px 5px 6px; font-size: 12px; }
  .layers-door-icon { width: 13px; height: 13px; }
  .layers-agg-name { font-size: 14px; }
  .layers-panel { padding: 20px; scroll-margin-top: 112px; }
}

/* Phones (bead ca1.1, layers.js adds .is-map): the wide drawing at 940px, shown
   whole in a window like the context map's and zoomed by a transform
   (site/assets/zoomview.js). The ring names keep room for their large far-out
   size at every zoom, so the drawing keeps its size when they grow. */
.layers-viewport.is-map {
  position: relative;
  height: clamp(260px, min(60vh, 92vw), 560px);
  height: clamp(260px, min(60svh, 92vw), 560px);
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: rgba(6, 10, 22, .45);
  touch-action: pan-y;
  user-select: none;
  -webkit-user-select: none;
}
.layers-viewport.is-map.is-zoomed { touch-action: none; cursor: grab; }
.layers-viewport.is-map.is-zoomed:active { cursor: grabbing; }
.layers-viewport.is-map .layers-diagram { position: absolute; top: 0; left: 0; width: 940px; transform-origin: 0 0; }
.layers-viewport.is-map .layers-ring.is-application,
.layers-viewport.is-map .layers-ring.is-domain { padding-top: calc(var(--layers-far, 32px) * 1.25 + 20px); }
.layers-viewport.is-map .layers-side { display: flex; flex-direction: column; align-items: flex-start; }
.layers-viewport.is-map .layers-side > .layers-list { align-self: stretch; }
.layers-viewport.is-map .layers-side > .layers-label { align-items: flex-end; min-height: calc(var(--layers-far, 32px) * 1.25 + 6px); }
/* The driven side's name grows to the left, into the gap, not out of the wall. */
.layers-viewport.is-map .layers-side.is-driven > .layers-label { align-self: flex-end; }
.layers-diagram.is-far .layers-label { padding: 0 4px; border-color: transparent; background: none; font: 600 var(--layers-far, 32px)/1.2 var(--display); letter-spacing: -.01em; text-transform: none; white-space: nowrap; color: var(--ink); text-shadow: 0 0 10px var(--bg), 0 0 4px var(--bg); }
.layers-diagram.is-far .layers-label[aria-checked="true"] { color: #fff; text-decoration: underline; text-underline-offset: .18em; text-decoration-thickness: 2px; }
.layers-diagram.is-far .layers-block-detail,
.layers-diagram.is-far .layers-agg-kind,
.layers-diagram.is-far .layers-chips,
.layers-diagram.is-far .layers-wall-kind { visibility: hidden; }
.layers-zoombar { margin-top: 10px; }

/* Building block cards (site/assets/blocks.js builds these eight from
   window.Webshop.buildingBlocks; bead dcg.7.2). */
.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 18px; }
.card { padding: 24px; display: flex; flex-direction: column; gap: 10px; transition: border-color .2s, box-shadow .2s; }
.card:hover { border-color: var(--line-strong); box-shadow: inset 0 1px 0 rgba(255, 255, 255, .05), 0 0 40px -18px var(--block-glow); }
.card-glyph { display: inline-block; width: 56px; height: 34px; overflow: visible; }
.card-glyph .n-glyph { width: 100%; height: 100%; }
.card h3 { font: 600 22px/1.2 var(--display); letter-spacing: -.01em; margin: 4px 0 0; }
.card > p { margin: 0; color: var(--ink-2); font-size: 15.5px; }
.card dl {
  margin: auto 0 0;
  padding-top: 14px;
  border-top: 1px solid var(--line);
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 8px 14px;
  font-size: 14px;
  color: var(--ink-2);
}
.card dt { font: 600 11px/1.9 var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--ink-3); }
.card dt.door { color: var(--door); text-shadow: 0 0 10px var(--door-glow); }
.card dd { margin: 0; }

/* The "Show code" toggle on a card and the snippet it reveals, styled like
   the Order.cs code-card (.k/.ty/.st/.cm/.dr below are shared with it). */
.card-code-toggle {
  align-self: flex-start;
  margin-top: 2px;
  padding: 7px 14px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--ink-2);
  font: 600 12px/1.4 var(--sans);
  letter-spacing: .03em;
  cursor: pointer;
  transition: border-color .2s, color .2s, box-shadow .2s;
}
.card-code-toggle:hover { border-color: var(--block); color: var(--ink); box-shadow: 0 0 20px -10px var(--block-glow); }
.card-code-toggle[aria-expanded="true"] { border-color: var(--block); color: var(--block-soft); }
.card-code { margin-top: -2px; border-radius: 12px; overflow: hidden; background: rgba(6, 10, 20, .55); border: 1px solid var(--line); }
.card-code-head { padding: 7px 14px; border-bottom: 1px solid var(--line); font: 500 11px/1.5 var(--mono); letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3); }
.card-code pre { margin: 0; max-width: 100%; overflow-x: auto; padding: 14px 16px; font: 400 13px/1.6 var(--mono); color: #DCE6FA; }
.card-code pre code { background: none; padding: 0; font-size: inherit; color: inherit; white-space: pre; }
.card-code:not([hidden]) { animation: card-code-in .18s ease both; }
@keyframes card-code-in { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
  .card-code-toggle { transition: none; }
  .card-code:not([hidden]) { animation: none; }
}

/* Callout + code */
.split { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: 20px; align-items: stretch; }
.callout {
  position: relative;
  border-radius: 18px;
  padding: 28px;
  background: radial-gradient(420px 220px at 0% 0%, rgba(255, 123, 84, .20), transparent 70%), var(--panel);
  border: 1px solid rgba(255, 123, 84, .38);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .05), 0 0 50px -22px var(--door-glow);
}
.callout h3 { font: 600 26px/1.2 var(--display); letter-spacing: -.015em; margin: 0 0 12px; }
.callout p { margin: 0 0 12px; color: var(--ink-2); }
.callout p:last-child { margin-bottom: 0; }
.code-card { margin: 0; overflow: hidden; }
.code-card figcaption {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding: 11px 18px;
  border-bottom: 1px solid var(--line);
  font-size: 13px;
  color: var(--ink-3);
}
.code-card figcaption b { font: 500 13px var(--mono); color: var(--ink-2); }
.code-card pre { margin: 0; padding: 18px 20px; overflow-x: auto; font: 400 14px/1.7 var(--mono); color: #DCE6FA; }
.code-card pre code { background: none; padding: 0; font-size: inherit; color: inherit; }
.k { color: var(--syn-k); }
.ty { color: var(--syn-t); }
.st { color: var(--syn-s); }
.cm { color: var(--syn-c); font-style: italic; }
.dr { color: var(--door); background: var(--door-wash); border-radius: 3px; box-shadow: 0 0 0 2px var(--door-wash); text-shadow: 0 0 10px var(--door-glow); }

/* Reference rules: allowed and forbidden (bead dcg.7.4). Four pairs built by
   site/assets/references.js from window.Webshop.referenceRules. Each pair is
   two glass panels: the forbidden (or, for the fourth pair, discouraged) path
   and the allowed one. A panel is told apart from its opposite three ways at
   once — never colour alone: its icon (the crossed n-blocked glyph or a coral
   door), its label text, and its border tone. Diagrams are small, fixed <svg>
   drawings using the shared n-* notation classes from the legend below; the
   ref-* classes here are their extra parts (labels, the attempted stub, the
   transaction boundary), plus the panel chrome around them. */
/* minmax(0, …) everywhere a grid item holds a code block: without it the track
   grows to the code's min-content width and the page scrolls sideways. */
.ref-pairs { display: grid; grid-template-columns: minmax(0, 1fr); gap: 24px; margin-top: 8px; }
.ref-pair-title { margin: 0 0 12px; font: 600 19px/1.25 var(--display); letter-spacing: -.01em; }
.ref-pair-body { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 16px; align-items: stretch; }
.ref-panel { padding: 18px; display: flex; flex-direction: column; gap: 10px; }
.ref-panel.is-forbidden { border-color: rgba(255, 77, 109, .32); box-shadow: inset 0 1px 0 rgba(255, 255, 255, .05), 0 0 40px -24px var(--blocked-glow); }
.ref-panel.is-allowed { border-color: rgba(255, 123, 84, .32); box-shadow: inset 0 1px 0 rgba(255, 255, 255, .05), 0 0 40px -24px var(--door-glow); }
.ref-panel-head { display: flex; align-items: center; gap: 9px; }
.ref-panel-icon { display: inline-flex; width: 32px; height: 20px; flex: none; }
.ref-panel-icon .n-glyph { width: 100%; height: 100%; }
.ref-panel-label { font: 700 12px/1.3 var(--sans); letter-spacing: .1em; text-transform: uppercase; }
.is-forbidden .ref-panel-label { color: var(--blocked-soft); text-shadow: 0 0 10px var(--blocked-glow); }
.is-allowed .ref-panel-label { color: var(--door-soft); text-shadow: 0 0 10px var(--door-glow); }
.ref-diagram { line-height: 0; }
.ref-svg { display: block; width: 100%; height: auto; overflow: visible; }
.ref-box-label { font: 600 11.5px/1 var(--sans); fill: var(--ink); }
.ref-box-label.is-on-door { fill: var(--door-soft); }
.ref-box-label.is-on-block { fill: var(--block-soft); }
.ref-box-label.is-tiny { font-size: 9.5px; }
.ref-box-label.is-ghost { fill: var(--tact-soft); }
.ref-wall-label { font: 600 10.5px/1 var(--sans); letter-spacing: .06em; text-transform: uppercase; fill: var(--tact-soft); }
.ref-line-label { font: 500 10px/1 var(--sans); fill: var(--ink-3); }
.ref-internal .n-line { opacity: .55; }
/* The faint stub past the blocked marker: what the forbidden line was trying
   to reach. Its own dashed, uncoloured treatment — never the coral or teal of
   a real line — is one more way to read "not allowed" without colour. */
.ref-attempt { fill: none; stroke: var(--ink-3); stroke-width: 1.4; stroke-dasharray: 3 3; opacity: .6; }
.ref-tx-boundary { fill: none; stroke-width: 1.8; }
.ref-tx-boundary.is-discouraged { fill: var(--blocked-wash); stroke: var(--blocked); stroke-dasharray: 7 5; }
.ref-tx-boundary.is-allowed { fill: var(--tact-wash); stroke: var(--tact); }
.ref-tx-label { font: 600 10.5px/1 var(--sans); letter-spacing: .06em; text-transform: uppercase; fill: var(--ink-2); }
.n-agg.is-ghost { opacity: .55; stroke-dasharray: 4 3; }
.ref-hint { margin: 0; border-radius: 10px; overflow-x: auto; background: rgba(6, 10, 20, .55); border: 1px solid var(--line); padding: 10px 14px; }
.ref-hint code { display: block; width: max-content; min-width: 100%; background: none; padding: 0; font: 400 13px/1.5 var(--mono); color: #DCE6FA; white-space: pre; }
.ref-says { margin: 0; color: var(--ink-2); font-size: 14.5px; }
.ref-forward {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 2px;
  color: var(--door-soft);
  text-decoration: none;
  font: 600 13.5px/1.4 var(--sans);
}
.ref-forward:hover { text-decoration: underline; text-underline-offset: 3px; }
#tactical-references .legend { margin-top: 30px; }

/* The mobile Forbidden/Allowed switch (bead ca1.5, window.Switcher from
   site/assets/switcher.js): hidden above 640px, where both panels show side by
   side. On phones it picks which panel of .ref-pair-body is shown. */
.ref-switcher-wrap { display: none; }

/* Fades the four pairs in, staggered by --d, once the section is in view (see
   "Drawing on view" in references.js). Reduced motion keeps the fade, drops
   the rise. */
.ref-pairs .ref-pair { opacity: 0; transform: translateY(14px); transition: opacity .5s ease var(--d, 0s), transform .5s cubic-bezier(.4, 0, .2, 1) var(--d, 0s); }
.ref-pairs.is-drawn .ref-pair { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .ref-pairs .ref-pair { transform: none; transition: opacity .4s ease var(--d, 0s); }
}

@media (max-width: 640px) {
  .ref-pair-body { grid-template-columns: minmax(0, 1fr); }
  .ref-switcher-wrap { display: flex; justify-content: center; margin-bottom: 4px; }
  .ref-pair-body[data-mobile-show="forbidden"] .ref-panel.is-allowed,
  .ref-pair-body[data-mobile-show="allowed"] .ref-panel.is-forbidden { display: none; }
  .ref-panel.is-switch-fade { animation: room-fade .25s ease both; }
}

/* One transaction, one aggregate (bead dcg.7.5): a stepper over a second copy of
   the composition explorer's drawing, built by site/assets/transactions.js from
   window.Webshop.transaction.

   Top to bottom: the step tabs, then the explorer layout (.explorer,
   .diagram-card, .inspector) with the drawing beside the step's own panel, then
   the PlaceOrder method with the step's line marked, then the timeline, then
   Previous and Next (which reuse the .doors-nav, .doors-count and .doors-btn of
   the doors stepper, bead dcg.6.6).

   The drawing is the .expl-* markup of the composition explorer with
   .expl-diagram.is-static: nothing there is a control, so the step lights what it
   uses (.is-lit) and fades the rest (.is-dim, set by explorer.js's setLit). On
   top of it lies .tx-ring, the transaction boundary, measured around the Order
   aggregate's wall: dashed while the transaction is open, solid once it has
   committed, exactly as the shared legend shows it. Nothing moves anywhere in
   the section: the steps only fade between states, so reduced motion changes
   little beyond the ring's slow breath. */
.tx { margin-top: 8px; }
.tx-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 14px; margin-bottom: 20px; }
.tx-label { margin: 0; font: 600 11px/16px var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--ink-3); }
.tx-hint { margin: 0 0 0 auto; font-size: 13px; color: var(--ink-3); }
.tx-tabs { display: flex; flex-wrap: wrap; gap: 8px; }
.tx-tab {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 40px;
  padding: 5px 16px 5px 6px;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  background: rgba(255, 255, 255, .03);
  color: var(--ink-2);
  font: 600 15px/1.2 var(--display);
  letter-spacing: -.01em;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: color .15s, border-color .15s, background-color .15s, box-shadow .15s;
}
.tx-tab-n { display: inline-grid; place-items: center; width: 26px; height: 26px; border-radius: 50%; background: rgba(255, 255, 255, .06); font: 600 13px/1 var(--sans); color: var(--ink-2); }
.tx-tab:hover { color: var(--ink); border-color: rgba(160, 246, 230, .5); background: rgba(255, 255, 255, .06); }
.tx-tab[aria-selected="true"] {
  color: var(--ink);
  border-color: var(--tact);
  background: var(--tact-wash);
  box-shadow: inset 0 0 0 1px var(--tact), 0 0 26px -8px var(--tact-glow);
}
.tx-tab[aria-selected="true"] .tx-tab-n { background: var(--tact); color: #04211C; }
.tx-tab:focus-visible { outline-offset: 3px; }

/* The step's panel, beside the drawing. */
.tx-panel { scroll-margin-top: 96px; }
.tx-num { margin: 0 0 10px; }
.insp-name.tx-title { font: 600 21px/1.25 var(--display); letter-spacing: -.01em; text-shadow: none; }
.tx-says { margin-bottom: 16px; }
.tx-state {
  display: flex;
  align-items: center;
  gap: 9px;
  margin: 0 0 12px;
  padding: 9px 12px;
  border: 1px solid var(--line-strong);
  border-radius: 10px;
  font: 600 13px/1.4 var(--sans);
  color: var(--ink-2);
}
.tx-state::before { content: ""; flex: none; width: 11px; height: 11px; border: 1.8px dashed var(--ink-3); border-radius: 50%; }
.tx-state[data-state="open"] { border-color: rgba(47, 230, 200, .4); color: var(--tact-soft); }
.tx-state[data-state="open"]::before { border-color: var(--tact); }
.tx-state[data-state="closed"] { border-color: rgba(47, 230, 200, .55); background: var(--tact-wash); color: var(--tact-soft); }
.tx-state[data-state="closed"]::before { border-style: solid; border-color: var(--tact); background: var(--tact); box-shadow: 0 0 10px var(--tact-glow); }
.tx-state[data-state="done"]::before { border-style: solid; border-color: var(--tact); }
.tx-note { margin: 0 0 10px; padding: 9px 12px; border: 1px solid var(--line); border-radius: 10px; background: rgba(255, 255, 255, .03); font-size: 14px; line-height: 1.5; color: var(--ink-2); }
.tx-note[hidden] { display: none; }
.tx-note.is-holds { border-color: rgba(47, 230, 200, .3); }
.tx-note-label { color: var(--ink-3); font: 600 11px/1.4 var(--sans); letter-spacing: .1em; text-transform: uppercase; margin-right: 6px; }

/* The drawing: a picture, so nothing in it looks clickable, and whatever the
   step does not use fades back. */
.expl-diagram.is-static .expl-box, .expl-diagram.is-static .expl-name { cursor: default; }
.expl-diagram.is-static .expl-box,
.expl-diagram.is-static .expl-name,
.expl-diagram.is-static .expl-wall { transition: opacity .3s ease, border-color .2s, box-shadow .25s; }
.expl-diagram.is-static .is-dim { opacity: .26; }
.expl-diagram.is-static .expl-name.is-lit { border-color: var(--line-strong); background: rgba(255, 255, 255, .05); }

/* The transaction boundary, measured around the aggregate's wall. */
.tx-ring {
  position: absolute;
  z-index: 1;
  border: 1.8px dashed var(--tact);
  border-radius: 22px;
  background: var(--tact-wash);
  box-shadow: 0 0 22px -8px var(--tact-glow), inset 0 0 40px -26px var(--tact-glow);
  pointer-events: none;
  transition: opacity .35s ease, border-color .3s, box-shadow .3s;
}
.tx:not(.is-drawn) .tx-ring, .tx-ring[data-state="none"] { opacity: 0; }
.tx-ring[data-state="open"] { animation: tx-breathe 3.6s ease-in-out infinite; }
.tx-ring[data-state="closed"] { border-style: solid; box-shadow: 0 0 34px -6px var(--tact-glow), inset 0 0 40px -22px var(--tact-glow); }
.tx-ring[data-state="done"] { border-style: solid; opacity: .5; }
.tx-ring-label {
  position: absolute;
  top: -11px;
  left: 16px;
  padding: 1px 9px;
  border: 1px solid var(--tact);
  border-radius: 999px;
  background: #0A1220;
  font: 600 10.5px/1.7 var(--sans);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--tact-soft);
  white-space: nowrap;
}
.tx-ring[data-state="none"] .tx-ring-label { display: none; }
@keyframes tx-breathe {
  0%, 100% { box-shadow: 0 0 18px -10px var(--tact-glow), inset 0 0 40px -28px var(--tact-glow); }
  50% { box-shadow: 0 0 30px -4px var(--tact-glow), inset 0 0 40px -20px var(--tact-glow); }
}

/* The method, with the step's line marked. It scrolls inside its own box. */
.tx-code-card { margin-top: 20px; }
.tx-code-card pre { padding: 16px 0; }
.tx-code-line { display: block; width: max-content; min-width: 100%; padding: 1px 20px; border-left: 2px solid transparent; opacity: .5; transition: opacity .25s ease, background-color .25s; }
.tx-code-line.is-now { opacity: 1; border-left-color: var(--tact); background: linear-gradient(90deg, rgba(47, 230, 200, .13), transparent 65%); }

/* The timeline: the one transaction the steps walk through, a gap, then the
   ones the event starts afterwards. */
.tx-when-card { margin-top: 20px; padding: 20px clamp(14px, 2vw, 24px); }
.tx-when-head { margin: 0 0 14px; font: 600 12px var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--ink-3); }
.tx-when-list { display: grid; grid-template-columns: minmax(0, 1fr) auto repeat(3, minmax(0, 1fr)); gap: 12px; margin: 0; padding: 0; list-style: none; }
.tx-when { padding: 13px 14px; border: 1px solid var(--line); border-radius: 14px; background: rgba(255, 255, 255, .02); transition: border-color .25s, box-shadow .25s, background-color .25s, opacity .25s; }
.tx-when.is-later { border-style: dashed; }
.tx-when.is-lit { border-color: var(--tact); background: var(--tact-wash); box-shadow: 0 0 30px -12px var(--tact-glow); }
.tx-when-top { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; margin: 0 0 7px; }
.tx-when-n { display: inline-grid; place-items: center; width: 20px; height: 20px; border-radius: 50%; border: 1px solid var(--tact); color: var(--tact-soft); font: 600 11px/1 var(--sans); }
.tx-when-when { font: 600 10.5px/1.4 var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--ink-3); }
.tx-when.is-now .tx-when-when { color: var(--tact); }
.tx-when-ctx { font: 600 12px/1.4 var(--sans); color: var(--strat-soft); }
.tx-when-title { margin: 0 0 5px; font: 600 15px/1.3 var(--display); letter-spacing: -.01em; color: var(--ink); }
.tx-when-says { margin: 0; font-size: 13.5px; line-height: 1.5; color: var(--ink-2); }
.tx-gap { display: flex; flex-direction: column; align-items: center; gap: 8px; min-width: 46px; }
.tx-gap::before, .tx-gap::after { content: ""; flex: 1; border-left: 2px dotted var(--line-strong); }
.tx-gap-text { font: 600 10px/1.4 var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--ink-3); }
.tx-nav { margin-top: 22px; }
.tx .legend { margin-top: 20px; }

@media (prefers-reduced-motion: reduce) {
  /* A fade and nothing else: the boundary holds still once it is drawn. */
  .tx-tab { transition: none; }
  .tx-ring[data-state="open"] { animation: none; }
}
@media (max-width: 900px) {
  .tx-when-list { grid-template-columns: minmax(0, 1fr); }
  .tx-gap { flex-direction: row; min-width: 0; padding: 2px 0; }
  .tx-gap::before, .tx-gap::after { border-left: 0; border-top: 2px dotted var(--line-strong); }
}
@media (max-width: 640px) {
  .tx-hint { margin-left: 0; flex-basis: 100%; }
  .tx-tab { padding-right: 12px; font-size: 14px; }
  .insp-name.tx-title { font-size: 19px; }
  .tx-code-card pre { font-size: 12.5px; }
  .tx-code-line { padding-inline: 14px; }
  .tx-ring { border-radius: 18px; }
}

/* Back out through the wall (bead dcg.7.6): OrderPlaced leaving Sales, built by
   site/assets/backout.js from webshop.js. The path runs from left to right — the
   Sales wall with the Order aggregate in it, the coral door in that wall, the
   Shipping wall on the other side — and the payload travels across it, blue
   inside the wall and coral once it has been through the door. Under the path
   the same three payloads in words, and what crosses against what stays inside.
   At 720px the path stands up: the two walls above each other with the door
   lying across between them, as the doors stepper does on the Strategic page. */
.bo { padding: 20px clamp(14px, 2.4vw, 24px) 18px; }
.bo-lead { margin: 0 0 22px; max-width: 78ch; font-size: 16px; line-height: 1.6; color: var(--ink-2); }

/* The path. */
.bo-track {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1.25fr) 150px minmax(0, 1fr);
  align-items: stretch;
  margin-bottom: 26px;
}
.bo-zone {
  position: relative;
  display: flex;
  align-items: center;
  min-height: 168px;
  /* The same padding above and below, so the wire inside the wall lines up with
     the one outside it; none on the side the wire leaves by, so it reaches the
     wall itself. */
  padding: 24px 18px;
  border: 1.6px solid var(--strat);

  border-radius: 16px;
  background: var(--strat-wash);
  box-shadow: inset 0 0 44px -20px var(--strat-glow), 0 0 26px -16px var(--strat-glow);
}
.bo-zone.is-from { padding-right: 0; }
.bo-zone.is-to { padding-left: 0; }
.bo-zone-name {
  position: absolute;
  top: -9px;
  left: 16px;
  padding: 1px 8px;
  border-radius: 6px;
  background: #0B0C22;
  font: 600 10.5px/1.6 var(--sans);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--strat-soft);
  white-space: nowrap;
}
/* The aggregate in the wall, and the wire from it to the door. The wire is as
   long as the payload's journey inside the wall, so the two always line up. */
.bo-zone-body { display: flex; flex-direction: column; align-items: center; gap: 12px; min-width: 0; }
.bo-zone.is-from .bo-zone-body { margin-left: auto; }
.bo-zone.is-to .bo-zone-body { margin-right: auto; }
.bo-inwire { position: relative; flex: 0 0 200px; height: 2px; background: var(--wire); }
.bo-zone.is-from .bo-inwire { background: linear-gradient(90deg, var(--wire), var(--wire-lit)); }
.bo-zone.is-to .bo-inwire { background: linear-gradient(90deg, var(--wire-lit), var(--wire)); }
/* The notation's own marks: a dot where the line starts, an arrow where it
   points to. */
.bo-zone.is-from .bo-inwire::before {
  content: "";
  position: absolute;
  left: -3px;
  top: 50%;
  width: 7px;
  height: 7px;
  margin-top: -3.5px;
  border-radius: 50%;
  background: var(--wire);
}
.bo-zone.is-to .bo-inwire::after {
  content: "";
  position: absolute;
  right: -1px;
  top: 50%;
  margin-top: -5px;
  border: 5px solid transparent;
  border-left: 7px solid var(--wire);
  border-right: 0;
}
.bo-box {
  padding: 9px 18px;
  border: 1.6px solid var(--tact);
  border-radius: 10px;
  background: var(--tact-wash);
  color: var(--ink);
  font: 500 16px/1.3 var(--mono);
  box-shadow: 0 0 24px -10px var(--tact-glow);
}
/* The note sits at the foot of the wall, out of the flow, so the wire runs at
   the height of the aggregate it starts from. */
.bo-zone-note { position: absolute; left: 16px; right: 16px; bottom: 14px; font-size: 13px; line-height: 1.5; color: var(--ink-3); text-align: center; }

/* Between the two walls: the door straddles the Sales wall's edge, the wire
   crosses to Shipping, and the payload travels along it. */
.bo-cross { position: relative; }
.bo-wire {
  position: absolute;
  top: 50%;
  left: 0;
  right: 0;
  height: 2px;
  margin-top: -1px;
  background: linear-gradient(90deg, var(--wire), var(--wire-lit));
  opacity: .8;
}
.bo-door {
  position: absolute;
  top: 50%;
  left: 0;
  z-index: 2;
  display: grid;
  place-items: center;
  width: 46px;
  height: 56px;
  border: 1.8px solid var(--door);
  border-radius: 12px;
  background: var(--door-fill);
  transform: translate(-50%, -50%);
  box-shadow: 0 0 20px 1px var(--door-glow);
}
.bo-door-icon { width: 22px; height: 22px; color: var(--door); }
.bo-door-name {
  position: absolute;
  top: calc(50% - 52px);
  left: 0;
  transform: translateX(-50%);
  white-space: nowrap;
  font: 500 13px/1.4 var(--mono);
  color: var(--door-soft);
}
.bo-token {
  position: absolute;
  top: 50%;
  left: 0;
  z-index: 3;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 4px 13px 5px;
  border: 1.4px solid var(--block);
  border-radius: 999px;
  background: var(--node-fill);
  white-space: nowrap;
  transform: translate(-50%, -50%);
  box-shadow: 0 0 16px -2px var(--block-glow);
  opacity: 0;
  pointer-events: none;
}
.bo-token b { font: 500 12.5px/1.35 var(--mono); color: var(--ink); }
.bo-token small { font: 600 9.5px/1.2 var(--sans); letter-spacing: .08em; text-transform: uppercase; color: var(--ink-3); }
.bo-token.is-wall { border-color: var(--door); box-shadow: 0 0 18px -2px var(--door-glow); }
.bo-token.is-wall b { color: var(--door-soft); }
/* Where each payload starts and ends: inside the wall to the door, then the
   door to Shipping. */
.bo-token.is-inside { --from: translate(-50%, -50%) translateX(-200px); --to: translate(-50%, -50%) translateX(0); }
.bo-token.is-wall { --from: translate(-50%, -50%) translateX(0); --to: translate(-50%, -50%) translateX(350px); }

/* The three payloads. */
.bo-stages { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; margin: 0; padding: 0; list-style: none; }
.bo-stage {
  display: flex;
  flex-direction: column;
  min-width: 0;
  padding: 14px 16px 16px;
  border: 1px solid var(--line-strong);
  border-radius: 14px;
  background: rgba(9, 14, 28, .55);
}
.bo-stage[data-tone="strat"] { border-color: rgba(182, 156, 255, .38); }
.bo-stage[data-tone="door"] { border-color: rgba(255, 198, 179, .42); background: linear-gradient(180deg, var(--door-wash), transparent 55%), rgba(9, 14, 28, .55); }
.bo-stage-kicker { display: flex; align-items: center; gap: 8px; margin: 0 0 8px; font: 600 11px/1.5 var(--sans); letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3); }
.bo-stage-n { display: inline-grid; place-items: center; width: 21px; height: 21px; flex: none; border-radius: 50%; background: rgba(255, 255, 255, .06); font: 600 11px/1 var(--sans); color: var(--ink-2); }
.bo-stage[data-tone="strat"] .bo-stage-where { color: var(--strat-soft); }
.bo-stage[data-tone="door"] .bo-stage-where { color: var(--door-soft); }
.bo-stage[data-tone="door"] .bo-stage-n { background: var(--door); color: var(--door-fill); }
.bo-stage-title { margin: 0 0 6px; font: 600 19px/1.25 var(--display); letter-spacing: -.01em; }
.bo-stage-says { margin: 0 0 14px; font-size: 14.5px; line-height: 1.55; color: var(--ink-2); }
.bo-msg { margin: auto 0 0; border: 1px solid var(--line); border-radius: 12px; background: rgba(6, 10, 20, .75); overflow: hidden; }
.bo-msg-cap { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 2px 10px; padding: 8px 12px; border-bottom: 1px solid var(--line); }
.bo-msg-cap b { font: 500 13.5px/1.4 var(--mono); color: var(--ink); overflow-wrap: anywhere; }
.bo-msg-format { font-size: 12px; color: var(--ink-3); }
/* A block per line, with the leading spaces as a hanging indent, so a long
   line wraps under itself instead of pushing the page wide. */
.bo-code { margin: 0; padding: 10px 12px 12px; font: 400 12.5px/1.6 var(--mono); color: #DCE6FA; white-space: pre-wrap; overflow-wrap: anywhere; overflow-x: auto; }
.bo-code code { display: block; padding: 0; background: none; font-size: inherit; color: inherit; border-radius: 0; }
.bo-line { display: block; padding-left: calc((var(--indent, 0) + 2) * 1ch); text-indent: -2ch; }

/* What crosses the wall, and what never does. */
.bo-rule { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px 28px; margin-top: 24px; padding-top: 18px; border-top: 1px solid var(--line); }
/* The mobile stage switch (site/assets/backout.js); shown only at 640px and
   below (see that media query), where it replaces the three-column layout. */
.bo-switcher-wrap { display: none; }
.bo-half h4 { margin: 0 0 6px; font: 600 12px var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--ink-3); }
.bo-half.is-crosses h4 { color: var(--door-soft); }
.bo-half.is-stays h4 { color: var(--strat-soft); }
.bo-half-says { margin: 0 0 6px; font-size: 14px; line-height: 1.5; color: var(--ink-2); }
.bo-half-list { list-style: none; margin: 0; padding: 0; font-size: 14px; line-height: 1.55; color: var(--ink-2); }
.bo-half-list li { padding: 7px 0; border-top: 1px solid var(--line); }
.bo-half-list code { font-size: 12.5px; overflow-wrap: anywhere; }
.bo-half.is-stays .bo-half-list code { color: var(--ink-2); background: rgba(140, 170, 255, .08); }

.bo-foot { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 14px 20px; margin-top: 22px; padding-top: 16px; border-top: 1px solid var(--line); }
.bo-foot .legend { margin: 0; }
.bo-replay { flex: none; }

/* Playing the handover: the path fades in, the payload leaves the aggregate as
   Sales' own Order, changes at the door into OrderPlaced version 1 and arrives
   in Shipping, and each payload appears as it is reached. */
.bo:not(.is-drawn) .bo-track, .bo:not(.is-drawn) .bo-stage { opacity: 0; }
.bo.is-drawn .bo-track { animation: bo-fade .45s ease both; }
.bo.is-playing .bo-token.is-inside { animation: bo-travel 1.05s cubic-bezier(.45, 0, .35, 1) .25s both; }
.bo.is-playing .bo-token.is-wall { animation: bo-travel 1.05s cubic-bezier(.45, 0, .35, 1) 1.35s both; }
.bo.is-playing .bo-door { animation: bo-door-open 1s ease 1.05s both; }
.bo.is-playing .is-from .bo-box { animation: bo-lit .7s ease .15s both; }
.bo.is-playing .is-to .bo-box { animation: bo-lit .7s ease 2.4s both; }
.bo.is-playing .bo-stage { animation: bo-rise .5s ease both; }
.bo.is-playing .bo-stage.is-inside { animation-delay: .15s; }
.bo.is-playing .bo-stage.is-wall { animation-delay: 1.3s; }
.bo.is-playing .bo-stage.is-outside { animation-delay: 2.4s; }
@keyframes bo-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes bo-rise { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
@keyframes bo-travel {
  0% { opacity: 0; transform: var(--from); }
  16% { opacity: 1; }
  84% { opacity: 1; }
  100% { opacity: 0; transform: var(--to); }
}
@keyframes bo-door-open {
  0%, 100% { border-color: var(--door); box-shadow: 0 0 20px 1px var(--door-glow); }
  50% { border-color: var(--door-soft); box-shadow: 0 0 34px 8px var(--door-glow); }
}
@keyframes bo-lit {
  0%, 100% { box-shadow: 0 0 24px -10px var(--tact-glow); }
  45% { box-shadow: 0 0 30px 0 var(--tact-glow); }
}

/* The card that hands back to the Strategic page. The whole card is one link,
   and its drawing is the Tactical end of the "sales-out" zoom: following it
   shrinks this Sales wall onto the Sales wall of the context map (app.js). */
.zoomout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: center;
  gap: 16px 40px;
  margin-top: 28px;
  padding: 22px 36px 22px 22px;
  border-radius: 20px;
  color: var(--ink);
  text-decoration: none;
  transition: border-color .2s, box-shadow .2s;
}
.zoomout:hover { border-color: rgba(182, 156, 255, .55); box-shadow: inset 0 1px 0 rgba(255, 255, 255, .05), 0 0 60px -22px var(--strat-glow); }
.zoomout:focus-visible { outline-offset: 4px; }
.zoomout-art { display: block; min-width: 0; }
.bo-card-svg { display: block; width: 100%; height: auto; overflow: visible; }
.zoomout-body { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; min-width: 0; }
.zoomout-kicker { font: 600 12px/1.6 var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--strat); text-shadow: 0 0 14px var(--strat-glow); }
.zoomout-title { font: 600 clamp(26px, 3.2vw, 36px)/1.12 var(--display); letter-spacing: -.02em; }
.zoomout-text { max-width: 38ch; font-size: 16px; line-height: 1.55; color: var(--ink-2); }
.zoomout-cta {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-top: 12px;
  padding: 9px 18px;
  border: 1px solid rgba(182, 156, 255, .45);
  border-radius: 999px;
  background: var(--strat-wash);
  color: var(--strat-soft);
  font: 600 15px/1.2 var(--sans);
  box-shadow: 0 0 24px -10px var(--strat-glow);
  transition: background-color .2s, border-color .2s;
}
.zoomout:hover .zoomout-cta { border-color: var(--strat); background: rgba(160, 130, 255, .14); }

/* The card's drawing: the Sales wall in the shape it has on the context map,
   the Order aggregate behind it, the door the event leaves by and the Shipping
   wall outside. The wall is also copied onto the context map as the Strategic
   end of the zoom (.bo-map-end, hidden there by an inline style so the moving
   copy app.js builds from it still shows). */
.bo-cw { fill: #100F2C; stroke-width: 3.6; filter: drop-shadow(0 0 10px var(--strat-glow)); }
.bo-c-agg { stroke-width: 2.6; filter: drop-shadow(0 0 6px var(--tact-glow)); }
.bo-c-door { stroke-width: 2.8; filter: drop-shadow(0 0 8px var(--door-glow)); }
.bo-c-out { fill: #100F2C; stroke-width: 2.4; opacity: .55; filter: none; }
.bo-c-wire { stroke-width: 2.4; }
.bo-c-arrow { stroke-width: 2.4; }
.bo-c-name { font-family: var(--display); font-weight: 600; text-anchor: middle; dominant-baseline: central; }
.bo-c-name.is-agg { font: 500 19px var(--mono); fill: var(--tact-soft); }
.bo-c-name.is-wall { font-size: 17px; fill: var(--strat-soft); text-anchor: start; letter-spacing: .04em; }
.bo-c-name.is-out { font-size: 17px; fill: var(--strat-soft); opacity: .85; }
.bo-c-name.is-door { font: 500 14px var(--mono); fill: var(--door-soft); }
.zoomout:hover .bo-cw { stroke: var(--strat-soft); filter: drop-shadow(0 0 6px var(--strat-glow)) drop-shadow(0 0 20px var(--strat-glow)); }
/* On its way the wall hides the page fading behind it, as the zoom-in card does. */
.zoom-flyer > .bo-map-end .bo-cw { fill: rgba(13, 16, 38, .94); }

@media (prefers-reduced-motion: reduce) {
  /* A fade only: nothing travels, the door does not pulse and the payloads
     appear together. */
  .zoomout, .zoomout-cta, .bo-replay { transition: none; }
  .bo-token { display: none; }
  .bo.is-playing .bo-door,
  .bo.is-playing .is-from .bo-box,
  .bo.is-playing .is-to .bo-box { animation: none; }
  .bo.is-playing .bo-stage, .bo.is-playing .bo-stage.is-inside,
  .bo.is-playing .bo-stage.is-wall, .bo.is-playing .bo-stage.is-outside { animation: room-fade .35s ease both; }
}
@media (max-width: 980px) {
  /* One payload per row: its words beside its code. */
  .bo-stages { grid-template-columns: minmax(0, 1fr); }
  .bo-stage { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr); column-gap: 22px; align-items: start; }
  .bo-stage-kicker, .bo-stage-title, .bo-stage-says { grid-column: 1; }
  .bo-stage-says { margin-bottom: 0; }
  .bo-msg { grid-column: 2; grid-row: 1 / span 3; margin: 0; }
}
@media (max-width: 920px) {
  .zoomout { grid-template-columns: minmax(0, 1fr); padding: 22px; }
  .zoomout-art { width: 100%; max-width: 620px; justify-self: center; }
}
@media (max-width: 720px) {
  /* Stacked: the Sales wall, the door lying across it, the Shipping wall. */
  .bo-track { grid-template-columns: minmax(0, 1fr); }
  .bo-zone { flex-direction: column; min-height: 0; padding: 24px 16px 18px; }
  .bo-zone.is-from { padding-right: 16px; padding-bottom: 0; }
  .bo-zone.is-to { padding-left: 16px; padding-top: 0; }
  .bo-zone-body { margin: 0 auto; }
  .bo-zone-note { position: static; max-width: 30ch; }
  .bo-inwire { flex-basis: 88px; width: 2px; height: auto; align-self: center; }
  .bo-zone.is-from .bo-inwire { background: linear-gradient(180deg, var(--wire), var(--wire-lit)); }
  .bo-zone.is-to .bo-inwire { background: linear-gradient(180deg, var(--wire-lit), var(--wire)); }
  .bo-zone.is-from .bo-inwire::before { left: 50%; top: -3px; margin: 0 0 0 -3.5px; }
  .bo-zone.is-to .bo-inwire::after {
    right: auto;
    left: 50%;
    top: auto;
    bottom: -1px;
    margin: 0 0 0 -5px;
    border: 5px solid transparent;
    border-top: 7px solid var(--wire);
    border-bottom: 0;
  }
  .bo-cross { min-height: 104px; }
  .bo-wire { top: 0; bottom: 0; left: 50%; right: auto; width: 2px; height: auto; margin: 0 0 0 -1px; background: linear-gradient(180deg, var(--wire), var(--wire-lit)); }
  .bo-door { top: 0; left: 50%; }
  .bo-door-name { top: 4px; left: calc(50% + 36px); transform: none; }
  .bo-token { top: 0; left: 50%; }
  .bo-token.is-inside { --from: translate(-50%, -50%) translateY(-88px); --to: translate(-50%, -50%) translateY(0); }
  .bo-token.is-wall { --from: translate(-50%, -50%) translateY(0); --to: translate(-50%, -50%) translateY(192px); }
  .bo-rule { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 640px) {
  .bo { padding: 16px 12px 14px; }
  .bo-stage { grid-template-columns: minmax(0, 1fr); }
  .bo-stage-says { margin-bottom: 14px; }
  .bo-msg { grid-column: 1; grid-row: auto; }
  .bo-stage-title { font-size: 18px; }
  .bo-code { font-size: 12px; }
  .bo-foot { justify-content: flex-start; }
  .zoomout { padding: 16px 16px 20px; gap: 14px; }
  .zoomout-art { max-width: 320px; }
  .zoomout-cta { margin-top: 6px; }

  /* One stage at a time under the path (site/assets/backout.js,
     window.Switcher). data-mobile-show on .bo-stages picks the visible stage;
     data-mobile-current on .bo-track highlights the matching point of the
     path instead of playing the travelling animation. Swiping .bo-stages
     switches (swipeArea = stagesEl). */
  .bo-switcher-wrap { display: flex; justify-content: center; margin: 14px 0; }
  .bo-stages[data-mobile-show] > .bo-stage { display: none; }
  .bo-stages[data-mobile-show="inside"] > .bo-stage.is-inside,
  .bo-stages[data-mobile-show="wall"] > .bo-stage.is-wall,
  .bo-stages[data-mobile-show="outside"] > .bo-stage.is-outside { display: flex; }
  .bo-stage.is-switch-fade { animation: room-fade .25s ease both; }

  .bo-token { display: none; }
  .bo.is-playing .bo-door,
  .bo.is-playing .is-from .bo-box,
  .bo.is-playing .is-to .bo-box { animation: none; }
  .bo-track[data-mobile-current="inside"] .bo-zone.is-from .bo-box {
    border-color: var(--strat-soft); box-shadow: 0 0 22px -6px var(--strat-glow);
  }
  .bo-track[data-mobile-current="wall"] .bo-door {
    border-color: var(--door-soft); box-shadow: 0 0 30px 4px var(--door-glow);
  }
  .bo-track[data-mobile-current="outside"] .bo-zone.is-to .bo-box {
    border-color: var(--strat-soft); box-shadow: 0 0 22px -6px var(--strat-glow);
  }
}

/* Pager (bead dcg.5): one at the end of every section, built by components.js
   from sections.js. It runs through all Strategic sections, then all Tactical
   ones. Inside a page it is compact; the last section of a page gets the full
   size, as in the design sample. */
.pager { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-top: 36px; }
.pager a { display: block; padding: 11px 16px; text-decoration: none; color: var(--ink); border-radius: 14px; transition: border-color .2s, box-shadow .2s; }
.pager a:hover { border-color: rgba(92, 157, 255, .5); box-shadow: 0 0 34px -14px var(--block-glow); }
.pager small { display: block; font: 600 11px/1.6 var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--ink-3); }
.pager .pager-title { display: block; font: 500 16px/1.3 var(--display); letter-spacing: -.01em; }
.pager .next { text-align: right; }
.pager.is-page-end { gap: 16px; margin-top: 56px; padding-bottom: 20px; }
.pager.is-page-end a { padding: 16px 20px; border-radius: 16px; }
.pager.is-page-end small { font-size: 12px; }
.pager.is-page-end .pager-title { font-size: 19px; }
@media (prefers-reduced-motion: reduce) { .pager a { transition: none; } }

/* Footer (bead dcg.5): credits and a site map from sections.js. */
.site-footer { border-top: 1px solid var(--line); padding-block: 36px 40px; font-size: 14px; color: var(--ink-3); }
.footer-grid { display: grid; grid-template-columns: minmax(0, 1.3fr) minmax(0, 2fr); gap: 28px 48px; }
.footer-about p { margin: 0 0 10px; max-width: 48ch; }
.footer-title { font: 500 16px/1.3 var(--display); color: var(--ink); }
.footer-title small { font: 400 13px var(--sans); color: var(--ink-3); }
.footer-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 18px; }
.footer-map { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 24px 32px; }
.footer-heading { margin: 0 0 8px; font: 600 12px/1.6 var(--sans); letter-spacing: .12em; text-transform: uppercase; }
.footer-map ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 4px; }
.site-footer a, .link-button { color: var(--ink-2); text-decoration: none; }
.footer-heading a { color: var(--ink-3); }
.site-footer a:hover, .link-button:hover { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }
.link-button { padding: 0; border: 0; background: none; font: inherit; cursor: pointer; }
.site-footer li a { display: inline-block; padding-block: 2px; }
.site-version { margin: 0; font: 400 12px var(--mono); color: var(--ink-3); }
.site-footer .site-version { margin-top: 20px; }
.landing .site-version { margin-top: 6px; }

/* Legend button in the header (bead dcg.5) */
.legend-toggle {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: none;
  padding: 6px 13px 6px 10px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: rgba(255, 255, 255, .03);
  color: var(--ink-2);
  font: 500 15px/1.4 var(--sans);
  cursor: pointer;
}
.legend-toggle:hover, .legend-toggle[aria-expanded="true"] { color: var(--ink); border-color: var(--line-strong); background: rgba(255, 255, 255, .06); }
.legend-toggle-icon { width: 18px; height: 18px; overflow: visible; }

/* Legend panel (bead dcg.5): a modal <dialog> sliding in from the right. */
.legend-panel {
  position: fixed;
  inset: 0 0 0 auto;
  margin: 0;
  width: min(400px, 100vw);
  max-width: 100vw;
  height: 100dvh;
  max-height: 100dvh;
  padding: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  color: var(--ink);
  background: linear-gradient(180deg, rgba(255, 255, 255, .05), transparent 30%), rgba(9, 14, 28, .94);
  border: 0;
  border-left: 1px solid var(--line-strong);
  box-shadow: -30px 0 80px -30px rgba(0, 0, 0, .9), inset 1px 0 0 rgba(170, 205, 255, .08);
  backdrop-filter: blur(16px);
}
.legend-panel:not([open]) { display: none; }
.legend-panel:focus-visible { outline: 2px solid var(--block-soft); outline-offset: -3px; }
.legend-panel::backdrop { background: rgba(3, 6, 14, .6); }
.legend-panel::before {
  content: "";
  position: absolute;
  top: 12%;
  bottom: 12%;
  left: -1px;
  width: 1px;
  background: linear-gradient(180deg, transparent, rgba(170, 205, 255, .6), transparent);
  pointer-events: none;
}
.legend-panel-head {
  position: sticky;
  top: 0;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 18px 20px 14px 24px;
  background: rgba(9, 14, 28, .92);
  border-bottom: 1px solid var(--line);
}
.legend-panel-head h2 { margin: 0; font-size: 22px; }
.legend-close {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: rgba(255, 255, 255, .03);
  color: var(--ink-2);
  cursor: pointer;
}
.legend-close:hover { color: var(--ink); border-color: var(--line-strong); }
.legend-close svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; }
.legend-panel-intro { margin: 16px 24px 4px; color: var(--ink-2); font-size: 15px; }
.legend-panel-body { padding: 0 24px 28px; }
.notation-group { margin: 22px 0 6px; font: 600 12px/1.6 var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--ink-3); }
.notation-list { list-style: none; margin: 0; padding: 0; }
.notation-list li { display: grid; grid-template-columns: 56px minmax(0, 1fr); gap: 14px; align-items: start; padding: 12px 0; border-top: 1px solid var(--line); }
.notation-list .n-glyph { width: 56px; height: 34px; }
.notation-name { margin: 0; font-weight: 600; font-size: 15px; color: var(--ink); }
.notation-meaning { margin: 2px 0 0; font-size: 14px; line-height: 1.5; color: var(--ink-2); }

/* Placeholder view content, until the real page-content beads land */
.placeholder .section-head { margin-bottom: 0; }
.hero p.lead + .pager { margin-top: 40px; }

@media (max-width: 920px) {
  .brand small { display: none; }
  .explorer { grid-template-columns: minmax(0, 1fr); }
  .inspector { position: static; }
}
@media (max-width: 860px) {
  .split, .hero-grid { grid-template-columns: minmax(0, 1fr); }
  .hero-art { justify-self: center; max-width: 380px; }
  .footer-grid { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 640px) {
  .wrap { padding-inline: 16px; }
  /* Two rows: the brand, then the tabs with the legend button at the end. The
     brand keeps its own width, so its stretched click area stays on it. */
  .header-inner { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 8px 10px; padding-block: 8px; }
  .brand { grid-column: 1 / -1; justify-self: start; }
  .main-nav { margin-left: 0; }
  .legend-toggle { align-self: center; }
  .diagram-card { padding: 14px; }
  .pager { grid-template-columns: 1fr; }
  .pager .next { text-align: left; }
  .pager-empty { display: none; }
  .footer-map { grid-template-columns: minmax(0, 1fr); }
}
