/* ── W1C · the two-project comparison journey ──────────────────────────────────────────
   🔒 DESIGN: the owner-approved two-project D1/D2 foundation (10 Sep 2026) — frames
   `CJ-D1-*`, `CJ-D2O-*`, `CJ-D2U-*`. 🔒 RULINGS: the owner implementation ruling of
   12 Sep 2026 and the visual-fidelity correction ruling of 13 Sep 2026
   (DECISION_REGISTER § 42). ⛔ Declared BEFORE owner ruling FC-4, which must stay last.

   ⌛ 13 SEPTEMBER 2026 — THIS SHEET IS A **PORT**, ⛔ NOT A RECONSTRUCTION.
   🔴 WHY IT WAS REWRITTEN. Two correction passes restored the missing regions and still did
   not reach fidelity, because the sheet had been written by reading the frames and choosing
   values that looked right. A computed-style comparison of the implementation against the
   approved frames — the same properties in the same browser — returned **162 differences
   across 200 component measurements**: inverted label/value font weights, a different card
   purple, a different card ink, wrong type scale on the scope sentence and the brief, chips
   pilled in every state, capsules where the design has rounded rectangles, and six components
   the implementation had renamed so they could not be compared at all.

   ⛔ SO NOTHING BELOW IS CHOSEN HERE. Every declaration is the approved frames' own, read out
   of their `<style>` blocks, and every token block is copied verbatim from the frame that
   declares it. Where the product and a frame use the same name for different values, the
   FRAME's value wins inside this scope — that is exactly the trap the previous sheet fell into.

   🔴 THERE ARE **THREE** INHERITANCE CONTEXTS, AND FLATTENING THEM WAS A MEASURED DEFECT:
     · `body`   `color:var(--ink-2); font-size:15px; line-height:1.55` — the product shell,
                which the heading, the cards and the FACT TABLE sit in. ⛔ Not overridden here.
     · `.d08`   the CARD scope — its own token block, below.
     · `.sc-d*` `color:var(--ink); font-size:15px; line-height:1.6` — the ANALYTICAL screens
                only, applied on the answer containers below (and 1.85 in Arabic).
   The card's `--ink` is `#191622` and the screen's is `#17151d`; the card's `--purple` is
   `#6d4aff` and the screen's is `#6d47e1`. ⛔ Do not "tidy" these into one palette.

   ⚠ RECORDED, AND RE-MEASURED: the frames ask `font-weight:800` on titles, rail values, chips
   and subgroup heads. An earlier sheet drew 700, reasoning that DejaVu ships no heavier face
   under `font-synthesis:none`. That is sound about the RENDERED GLYPHS and wrong about the
   COMPUTED STYLE — declaring 800 renders identically and matches the frame, so 800 is
   declared. The frames' own RTL rules drop to 700 in Arabic; those are ported too.

   ⚠ RECORDED DIFFERENCE: the frames declare `--font:"Plus Jakarta Sans"` then override it to
   `"DejaVu Sans"` in their own harness block. Measured: BOTH surfaces load `DejaVu Sans 400`
   and `700` and nothing else, so the family string is a capture-environment artefact and
   ⛔ not a product difference. `font-family` is inherited from the product here.

   ⚠ THIS FILE WAS ONCE TRUNCATED TO ZERO BYTES by a scripted edit of mine whose output stream
   opened (and so emptied) the file before the call raised. It is untracked, so nothing but a
   rewrite could restore it. The parity harness caught it immediately — every component went
   red at once — which is the one good thing to say about it. */

/* ══ THE SCREEN TOKEN SCOPE ═══════════════════════════════════════════════════════════
   Verbatim from the frames' `.sc-d1` / `.sc-d2o` / `.sc-d2u` blocks, which a token-by-token
   comparison proved identical (38 tokens, 0 differences). */
.cmp-journey{
  --purple:#6d47e1; --purple-deep:#4a2bb0; --purple-hover:#5433c9;
  --orange:#ff6c16; --orange-deep:#d94f00;
  --ink:#17151d; --body:#443f4e; --muted:#706d78;
  --line:#e7e1f2; --hairline:#f0ecf7; --soft:#f5f1ff; --tint:#fcfbfe; --paper:#fff;
  --track:#eeebf5;
  --green:#28915f; --green-bg:#e4f8e9; --green-ink:#157343;
  --amber:#c88200; --warn-bg:#fff8f3; --warn-ink:#68310f; --grey-bg:#f2f1f5;
  --r-sm:10px; --r-md:12px; --r-lg:16px; --r-xl:18px; --r-2xl:24px; --r-pill:999px;
  --cap-h:20px; --cap-h2:32px; --cap-gap:9px; --trk-h:12px; --rail-gap:16px;
  /* 🔴 THE JOURNEY ROOT ADDS NO GAP OF ITS OWN, and a blanket one was a measured defect.
     ⌛ 13 Sep 2026: this carried `gap:28px`, which stacked on top of every region's own
     approved margin. Measured against `CJ-D1-EN-VP1` at VP1:
        heading → scope   approved 10px, implemented 38px
        scope   → cards   approved  0px, implemented 28px
        cards   → facts   approved 12px, implemented 40px
     Every COMPONENT matched the frame while the whole screen's rhythm did not — which is why
     component parity alone cannot carry a fidelity claim. The approved regions space
     themselves (`.w1c-scope{margin:10px 0 0}`, `.w1c-rows{margin-top:12px}`) and the
     analytical panel supplies its own separation through `padding-top`. ⛔ 28px is the
     ANALYTICAL PANEL's internal gap, ⛔ not the answer's. */
  display:flex; flex-direction:column; gap:0;
  /* 🔒 THE SHARED COLUMN GRID — one label column plus one per project (SCALE-01/02), so every
     card sits directly above its own value column. ⚠ Logical, so the label column lands
     leftmost in EN and rightmost in AR from `dir` alone — ⛔ no physical override, ⛔ no second
     DOM. ⚠ Parameterising the count is a TOKEN, ⛔ not an implementation of 3-/4-project
     layouts, which remain deferred. */
  --w1c-n:2; --w1c-cols:repeat(calc(var(--w1c-n) + 1), minmax(0, 1fr));
}
.cmp-journey[data-projects="3"]{--w1c-n:3}
.cmp-journey[data-projects="4"]{--w1c-n:4}

/* ══ THE CARD TOKEN SCOPE — verbatim from the frames' `.d08` block ════════════════════
   🔴 DIFFERENT VALUES UNDER THE SAME NAMES. This is the D-08 card's own palette and it is
   ⛔ not the screen's. Measured: using the screen's values here put every card string and the
   `View project` button at the wrong colour.
   ⌛ 18 Sep 2026 — `project-workspace-tabs.md` § 9.7 CASE 4 (OD-W5D-34): the W5 ranking rail (`.w5-rail`,
   `render/w5_ranking.js`) is the THIRD host of this ONE card. It joins every selector list below and nothing
   else: ⛔ no value changed, ⛔ specificity unchanged (`:is()` takes its most specific argument, and all three are one
   class), so the comparison and the Q9 rail render byte-for-byte as before. Its host layout (the horizontal scroller)
   lives in `w5_ranking.css`.
   ⌛ 24 Sep 2026 — DECISION_REGISTER § 79 (owner ruling: the DEP-W2-21 Buying Power rail reuses the site's canonical
   card EXACTLY, ⛔ no W2-only variant): `.dep21` is the FOURTH host, joining every list below the same way — ⛔ no value
   changed, specificity unchanged. Its host layout (the D-06 rev 2 row) lives in `w2_buying_power.css`. */
:is(.cmp-journey, .q9-rail, .w5-rail, .dep21) .d08{
  --ink:#191622; --body:#3c3547; --muted:#6f6880;
  --line:#e7e1f2; --soft:#f5f1ff; --tint:#fcfbfe;
  --purple:#6d4aff; --purple-deep:#4b2fd6;
  --r-md:12px; --r-lg:16px; --r-2xl:24px;
}
:is(.cmp-journey, .q9-rail, .w5-rail, .dep21) .d08,:is(.cmp-journey, .q9-rail, .w5-rail, .dep21) .d08 *{box-sizing:border-box}

/* ⛔ THE HEADING IS THE SHELL'S OWN `.railhead h2` AND IS NOT RESTYLED HERE. The approved
   frames draw it with the product's existing component (1.01rem / 700 / -.012em), so the
   journey adds nothing — a local override would be a second authority for a heading the shell
   already governs. ⚠ An earlier pass invented a `.cmp-title` component at 1.02rem / 800, which
   matched no approved frame and therefore could not be compared to one. */

/* ══ THE CANONICAL D-08 CARDS ═════════════════════════════════════════════════════════ */
.cmp-journey .cx-rail{display:grid; grid-template-columns:var(--w1c-cols); gap:12px;
  width:100%; max-width:1180px; margin-inline:auto}
/* 🔒 the label column of the fact table sits under this spacer, which is why the cards are
   offset — ⛔ the empty first column is the approved alignment, not a layout accident */
.cmp-journey .w1c-spacer{display:block}
.cmp-journey .cx-rail>.cx-card{display:flex; flex-direction:column; block-size:100%}
.cmp-journey .cx-rail>.cx-card>.cx-body{flex:1 1 auto}
.cmp-journey .cx-rail>.cx-card .cx-go{margin-top:auto; padding-top:2px}
:is(.cmp-journey, .q9-rail, .w5-rail, .dep21) .cx-card{border:1px solid var(--line); border-radius:var(--r-lg); overflow:hidden;
  background:#fff; box-shadow:0 8px 26px rgba(23,21,29,.06); min-width:0}
:is(.cmp-journey, .q9-rail, .w5-rail, .dep21) .cx-media{aspect-ratio:16/9; overflow:hidden;
  background:linear-gradient(135deg,#efeaf9,#f7f4fd);
  display:flex; align-items:center; justify-content:center}
:is(.cmp-journey, .q9-rail, .w5-rail, .dep21) .cx-media .asset-ic,:is(.cmp-journey, .q9-rail, .w5-rail, .dep21) .cx-media .ico{width:44px; height:44px;
  color:var(--purple-deep); opacity:.55}
/* ⛔ the media slot's own fallback icon is 44px; a photograph fills the slot. The guard is
   `:not(.ico)` because the small inline icons must never be stretched to the slot. */
:is(.cmp-journey, .q9-rail, .w5-rail, .dep21) .cx-media img:not(.ico){width:100%; height:100%; object-fit:cover}
/* ⌛ 19 Sep 2026 — a MIXED-asset card's media slot draws one 44px icon per evidenced asset (owner direction); the
   only addition is the space between them. ⛔ Single-asset cards are untouched (`data-media="fallback+icon"`). */
:is(.cmp-journey, .q9-rail, .w5-rail, .dep21) .cx-media[data-media="fallback+icons"]{gap:18px}
:is(.cmp-journey, .q9-rail, .w5-rail, .dep21) .cx-body{padding:11px 12px; display:flex; flex-direction:column; gap:6px}
:is(.cmp-journey, .q9-rail, .w5-rail, .dep21) .cx-pill{align-self:center; display:inline-flex; align-items:center; max-width:100%;
  padding:3px 9px; border-radius:999px;
  background:linear-gradient(135deg,#92400E 0%,#B45309 100%); color:#fff;
  font-size:.6rem; font-weight:700; letter-spacing:.06em; text-transform:uppercase;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
:is(.cmp-journey, .q9-rail, .w5-rail, .dep21) .cx-pill-c{background:linear-gradient(135deg,#3d3949 0%,#6b6478 100%)}
:is(.cmp-journey, .q9-rail, .w5-rail, .dep21) .cx-nm{font-size:.92rem; font-weight:700; color:var(--ink); text-align:center;
  line-height:1.3; margin:0}
:is(.cmp-journey, .q9-rail, .w5-rail, .dep21) .cx-meta{display:flex; align-items:center; gap:7px; font-size:.78rem;
  color:var(--body); flex-wrap:wrap}
:is(.cmp-journey, .q9-rail, .w5-rail, .dep21) .cx-asset{display:inline-flex; align-items:center; gap:5px; background:var(--soft);
  border-radius:6px; padding:2px 8px; font-weight:600; color:var(--purple-deep);
  font-size:.75rem}
:is(.cmp-journey, .q9-rail, .w5-rail, .dep21) .cx-asset .asset-ic,:is(.cmp-journey, .q9-rail, .w5-rail, .dep21) .cx-asset .ico{width:15px; height:15px;
  color:var(--purple-deep)}
:is(.cmp-journey, .q9-rail, .w5-rail, .dep21) .cx-loc{font-size:.78rem; color:var(--body)}
/* 🔒 D-08 region 5 — the configurations, and region 9 — the governed amenities. ⚠ The two
   share one treatment in the approved design; they are DIFFERENT REGIONS with different
   producers and are ⛔ never merged in the DOM. */
:is(.cmp-journey, .q9-rail, .w5-rail, .dep21) .cx-units,:is(.cmp-journey, .q9-rail, .w5-rail, .dep21) .cx-amen{display:flex; align-items:center; gap:7px;
  flex-wrap:wrap; margin:0; padding:0; list-style:none}
:is(.cmp-journey, .q9-rail, .w5-rail, .dep21) .cx-unit,:is(.cmp-journey, .q9-rail, .w5-rail, .dep21) .cx-am{display:inline-flex; align-items:center;
  background:var(--soft); border-radius:6px; padding:2px 8px; font-weight:600;
  color:var(--purple-deep); font-size:.75rem}
:is(.cmp-journey, .q9-rail, .w5-rail, .dep21) .cx-am{gap:5px}
/* 🔒 OWNER RULING, 10 Sep 2026 — the amenity icons carry the APPROVED PURPLE TOKEN, painted
   through a mask of THE SAME APPROVED FILE so the governed geometry is exact.
   🔴 ⌛ 13 Sep 2026: the card was drawing them as `<img>`, which is why they rendered BLACK
   (an `<img>`-referenced SVG is an isolated document whose `currentColor` cannot inherit the
   page's) and why they were intermittently ABSENT from captures (`loading="lazy"`).
   ⚠ This is the same treatment `styles.css` already applies to the workspace header
   (`.ws .wshell .amenities .ico`), mapped to the card's own 15px size. The file's URL arrives
   on the element as `--ico`, so this stylesheet stays free of `url()` (QA-44).
   ⛔ No filter, ⛔ no hue rotation, ⛔ no approximation, ⛔ no artwork modified. */
:is(.cmp-journey, .q9-rail, .w5-rail, .dep21) .cx-am .am-ic{flex:none; width:15px; height:15px;
  background-color:var(--purple-deep);
  -webkit-mask-image:var(--ico); mask-image:var(--ico);
  -webkit-mask-repeat:no-repeat; mask-repeat:no-repeat;
  -webkit-mask-position:center; mask-position:center;
  -webkit-mask-size:contain; mask-size:contain;
  margin-inline-end:0; vertical-align:baseline}
/* ⛔ THE ASSET-TYPE ICON IS NOT MASKED. Its approved treatment is two-tone — `--ink` strokes
   with a `#6D47E1` door — and a mask would flatten the door away. It keeps the `<img>`. */
:is(.cmp-journey, .q9-rail, .w5-rail, .dep21) .cx-am .amen-ic{width:15px; height:15px; color:var(--purple-deep)}
:is(.cmp-journey, .q9-rail, .w5-rail, .dep21) .cx-avail{font-size:.78rem; color:var(--body)}
:is(.cmp-journey, .q9-rail, .w5-rail, .dep21) .cx-pnote{font-size:.72rem; color:var(--muted)}
:is(.cmp-journey, .q9-rail, .w5-rail, .dep21) .cx-price{font-size:.82rem; font-weight:700; color:var(--ink)}
:is(.cmp-journey, .q9-rail, .w5-rail, .dep21) .cx-go{margin-top:2px}
/* 🔒 CMP-D08-10 — the ONE approved action per project. ⚠ `--purple` here is the CARD scope's
   `#6d4aff`, ⛔ not the screen's `#6d47e1`.
   ⌛ `line-height:normal` and `text-align:center` are the UA button defaults the frame keeps,
   and `text-decoration:none` because the control renders as an `<a>` on this route and the
   product's link styling underlined it — caught only once `textDecorationLine` was added to
   the measured property set. */
:is(.cmp-journey, .q9-rail, .w5-rail, .dep21) .cx-btn{display:inline-flex; align-items:center; justify-content:center;
  width:100%; min-height:44px; padding:0 14px; border:0; border-radius:10px;
  background:var(--purple); color:#fff; font-family:inherit; font-size:.86rem;
  font-weight:700; cursor:pointer; line-height:normal; text-align:center;
  text-decoration:none}
:is(.cmp-journey, .q9-rail, .w5-rail, .dep21) .cx-btn:focus-visible{outline:2px solid var(--purple-deep); outline-offset:2px}

/* ══ THE PROJECT GUIDE VARIANT of the ONE canonical card ═══════════════════════════════════
   🔒 AUTHORITY: owner direction of 19 Sep 2026 (DECISION_REGISTER § 66.14), selecting the full treatment of the
   approved IMPL-CLS-1 classification proofs `SC-PROJ-001-{EN,AR}-VP1.IMPL-CLS-1.project_guide.html`: the slate
   pill (`.cx-pill-c`, above), region 4 as the LABELLED neighbourhood row, region 5 as OUTLINED chips and region 9
   as plain icon + label items. ⌛ A NARROW supersession of § 51.7(1) for THIS variant only — the Dal Verified and
   unclassified cards keep § 51.7(1)'s unlabelled `.cx-loc` line and filled chips, and none of these rules can reach
   them (`[data-variant]` is emitted only for the `card_ribbon_guide` key). Values are the proof's own declarations.
   ⛔ Colour, type scale, pill, name, asset, price, availability, media and action are the shared rules above. */
:is(.cmp-journey, .q9-rail, .w5-rail, .dep21) .cx-card[data-variant="project_guide"] .cx-nbhd{display:flex; align-items:baseline;
  gap:6px; font-size:.78rem; flex-wrap:wrap}
:is(.cmp-journey, .q9-rail, .w5-rail, .dep21) .cx-card[data-variant="project_guide"] .cx-nbhd-lab{color:var(--muted); font-weight:400}
:is(.cmp-journey, .q9-rail, .w5-rail, .dep21) .cx-card[data-variant="project_guide"] .cx-nbhd-val{color:var(--ink); font-weight:700}
:is(.cmp-journey, .q9-rail, .w5-rail, .dep21) .cx-card[data-variant="project_guide"] .cx-units{gap:6px; align-items:normal}
:is(.cmp-journey, .q9-rail, .w5-rail, .dep21) .cx-card[data-variant="project_guide"] .cx-unit{background:none;
  border:1px solid var(--line); font-weight:400; color:var(--body)}
:is(.cmp-journey, .q9-rail, .w5-rail, .dep21) .cx-card[data-variant="project_guide"] .cx-amen{gap:5px 10px; align-items:normal}
:is(.cmp-journey, .q9-rail, .w5-rail, .dep21) .cx-card[data-variant="project_guide"] .cx-am{background:none; padding:0;
  border-radius:0; font-size:.72rem; font-weight:400; color:var(--body)}
/* the icon keeps the 10 Sep 2026 ruling's mask method and purple token; only its size is the proof's 14px */
:is(.cmp-journey, .q9-rail, .w5-rail, .dep21) .cx-card[data-variant="project_guide"] .cx-am .am-ic{width:14px; height:14px}

/* ══ W3A · THE Q9 NEIGHBOURHOOD PROJECT RAIL ══════════════════════════════════════════
   🔒 DESIGN: `W3A_PROJECT_RAIL_REPRESENTATIVES` (LOCKED 7 Sep 2026) — frames
   `SC-PROJ-001-{EN,AR}-VP{1..5}` of `review_html/step16a_w3a_representative_design_output_2026-09-07/`
   (manifest a8854dd4…; the complete delivery verified 425 / 425 against the REV6 zip).
   🔒 AUTHORITY: the owner authorisation of 14 Sep 2026, DECISION_REGISTER § 51.2.
   ⛔ A PORT, NOT A RECONSTRUCTION: every declaration below is the frames' own `.cx`, `.cx-dis`,
   `.cx-rail` (owner ruling O-14, option W-B) and `<style id="d08-multi-card-action-baseline">` rule.
   The CARD is the canonical D-08 component declared above and shared with the comparison through
   `:is(.cmp-journey, .q9-rail, .w5-rail, .dep21)` — ⛔ one authority for the card; two hosts then, three since 18 Sep 2026 (§ 9.7 case 4).
   ⛔ SCOPED TO `.q9-rail`: nothing here reaches `.cmp-journey`, its `--w1c-cols` grid, its label
   spacer or its scroll container, so the 2-, 3- and 4-project comparison is unaffected. */
.q9-rail .d08{background:#fff; padding:18px 16px; display:flex; flex-direction:column; gap:14px;
  color:var(--body); font-size:15px; line-height:1.6}
.q9-rail .cx-dis{font-size:.76rem; color:var(--muted); line-height:1.5;
  border-inline-start:2px solid var(--line); padding-inline-start:9px; margin:0}
/* 🔒 O-14 · OWNER RULING, 5 Sep 2026 — option W-B: the rail is capped at 1180px at desktop and card
   width RESULTS from the four-column grid. ⛔ No card-width cap is declared anywhere. */
.q9-rail .cx-rail{display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:12px;
  width:100%; max-width:1180px; margin-inline:auto}
/* ⌛ 14 Sep 2026 — OWNER DECISION, DECISION_REGISTER § 51.7(2): the breakpoints follow the RAIL'S OWN
   available width, ⛔ not the browser's. The approved 1107 / 719 thresholds are kept and the container is
   the Q9 rail host, so the full-width approved layouts are unchanged (four / two / one column at
   VP1 / VP2 / VP3–VP5), and inside the desktop 50/50 workspace journey — the 662 px conversation half —
   the rail is one column.
   ⌛ Superseded for the Q9 rail, preserved: `@media (max-width:1107px){ .q9-rail .cx-rail{grid-template-
   columns:repeat(2,minmax(0,1fr))} }` and `@media (max-width:719px){ .q9-rail .cx-rail{grid-template-
   columns:1fr} }` — the W3A frames' viewport rules.
   ⚠ `inline-size:100%` is REQUIRED: inline-size containment on an auto-width box can collapse it to
   0 px (measured on the W1C comparison scroller, 13 Sep 2026). */
.q9-rail{container:q9rail / inline-size; inline-size:100%}
@container q9rail (max-width:1107px){ .q9-rail .cx-rail{grid-template-columns:repeat(2,minmax(0,1fr))} }
@container q9rail (max-width:719px){ .q9-rail .cx-rail{grid-template-columns:1fr} }
/* 🔒 THE 7 Sep 2026 W3A OWNER RULING, clause 1 — the multi-card action baseline, a HOST rule: cards in
   one visible row share ONE bottom baseline for `View project`; the slack sits immediately above
   region 10; the tallest card is unchanged; a single-column card keeps its natural height. */
.q9-rail .cx-rail > .cx-card{display:flex; flex-direction:column}
.q9-rail .cx-rail > .cx-card > .cx-media{flex:0 0 auto}
.q9-rail .cx-rail > .cx-card > .cx-body{flex:1 1 auto}
.q9-rail .cx-rail > .cx-card > .cx-body > :nth-last-child(2){margin-block-end:auto}
/* ⌛ 14 Sep 2026 — OWNER DECISION, DECISION_REGISTER § 51.8 (Option A): in the DESKTOP 50/50 SPLIT ONLY the Q9
   rail card is capped at 286px — the approved W3A rail card width at VP1 (O-14, option W-B) — and sits at the
   rail's LOGICAL start: the left edge in English, the right edge in Arabic. The canonical 16:9 media ratio is
   unchanged, so the image placeholder is 286 × 159.75px (it filled the 592px column at 331.88px).
   ⛔ `.wsroot .origin` exists only in the ≥ 900px split, so full-width desktop and mobile Q9 are outside the
   selector; ⛔ the canonical card rules above and the comparison cards are unchanged. */
.wsroot .origin .q9-rail .cx-rail > .cx-card{max-inline-size:286px; justify-self:start}

/* ══ THE SEVEN-ROW FACT TABLE ═════════════════════════════════════════════════════════
   🔴 THE WEIGHTS WERE INVERTED, AND THAT WAS MEASURED: the approved LABEL is 400 and the
   approved VALUE is 700; the implementation had the label at 700 and the value at 400, so
   every row read as a list of labels with quiet values. */
.cmp-journey .w1c-rows{margin-top:12px; max-width:1180px; margin-inline:auto}
.cmp-journey .w1c-row{display:grid; grid-template-columns:var(--w1c-cols); gap:12px;
  align-items:baseline; padding:8px 0; border-top:1px solid var(--hairline)}
.cmp-journey .w1c-row:first-child{border-top:0; padding-top:0}
.cmp-journey .w1c-lab{margin:0; font-size:.81rem; color:var(--muted)}
.cmp-journey .w1c-cell{margin:0; font-size:.87rem; font-weight:700; color:var(--ink);
  font-variant-numeric:tabular-nums; text-align:start; min-width:0}
/* 🔒 D11-EN-APPROVED-05 — the governed unavailable sentence, and the F-01 qualification.
   ⛔ Never a filler dash, ⛔ never bold, ⛔ never the producer's English machine note. */
.cmp-journey .w1c-na,.cmp-journey .w1c-qual{font-size:.81rem; color:var(--muted);
  font-weight:400}
.cmp-journey .w1c-na{display:block}
/* 🔒 D11-QUAL-01 CLOSED, 13 Sep 2026 — the qualification sits BENEATH its own project's date.
   ⛔ No new treatment: it keeps the secondary size, weight and colour declared just above,
   shared with `.w1c-na`. `display:block` is what puts it on its own line; the cell is the
   grid item, so this wraps inside the project's own column at BOTH bands and ⛔ never
   widens the row or pushes a neighbour. */
.cmp-journey .w1c-qual{display:block; margin-top:2px; line-height:1.35;
  overflow-wrap:break-word}
.cmp-journey .w1c-note,.cmp-journey .w1c-scope{margin:10px 0 0; font-size:.74rem;
  line-height:1.45; color:var(--muted)}
/* ⛔ THE FACT TABLE IS NOT A PANEL. The approved frames run the rows directly under the cards,
   separated by hairlines only, so the table reads as a continuation of the card columns. The
   shared `.block` chrome would draw a bordered, tinted, padded card around them. */
.cmp-journey .block-compare{border:0; background:transparent; padding:0; border-radius:0}
/* 🔒 ONE DOM AT BOTH BANDS. The approved VP1 frame puts `.w1c-cell` directly in the row grid;
   the approved VP3 frame wraps each cell in `.w1c-nrow` with its project's name in
   `.w1c-nproj`. A runtime renderer emits ONE tree, so it always emits the wrapper and
   `display:contents` dissolves it at the wide band — the cell then participates in the row
   grid exactly as the VP1 frame's does. ⛔ NOT the inline "project · value" text an earlier
   pass substituted, which is in no approved frame. */
.cmp-journey .w1c-nrow{display:contents}
.cmp-journey .w1c-nproj{display:none}

/* ══ SHARED BLOCK CHROME — the eyebrow heads and the load-bearing briefs ══════════════ */
.cmp-journey .d1x-block-head,.cmp-journey .dox-block-head,.cmp-journey .dux-block-head{
  display:flex; align-items:baseline; justify-content:space-between; gap:16px; flex-wrap:wrap}
.cmp-journey .d1x-block-title,.cmp-journey .dox-block-title,.cmp-journey .dux-block-title{
  margin:0; font-size:.78rem; font-weight:800; letter-spacing:.11em; text-transform:uppercase;
  color:var(--purple)}
.cmp-journey .d1x-block-unit,.cmp-journey .dox-block-unit,.cmp-journey .dux-block-unit{
  font-size:.8rem; color:var(--muted); font-weight:600}
.cmp-journey .dox-brief,.cmp-journey .dux-brief{display:flex; align-items:flex-start; gap:13px}
.cmp-journey .dox-brief-body,.cmp-journey .dux-brief-body{flex:1 1 auto; min-width:0;
  display:flex; flex-direction:column; gap:7px}
/* 🔴 LOAD-BEARING, and measured at the WRONG SIZE before: the approved brief is 1.06rem /
   1.55, the implementation drew .82rem / 1.6 — a quiet caption where the design has a
   statement. */
.cmp-journey .dox-brief-text,.cmp-journey .dux-brief-text{margin:0; font-size:1.06rem;
  line-height:1.55; color:var(--body); max-width:74ch}
.cmp-journey .dox-brief-text b,.cmp-journey .dux-brief-text b{color:var(--ink); font-weight:800}

/* ══ THE ANALYTICAL SCREENS — the shared answer surface ═══════════════════════════════
   🔒 Verbatim from the frames' `.sc-d1` / `.sc-d2o` / `.sc-d2u` base rule. ⚠ Set HERE and not
   on the journey root, because the heading, the cards and the fact table above belong to the
   product shell and must keep its `--ink-2` / 1.55. */
/* 🔴 THE PANEL IS PADDED, ⛔ NOT MAX-WIDTH-CONSTRAINED — and getting that backwards moved
   every analytical region inward by 29 px.
   ⌛ 13 Sep 2026, MEASURED on both surfaces at VP1: in the approved frame the answer fills its
   surface and insets 34 px, so the block heads, briefs, matrix and drill span 1238 px, while
   the CARD RAIL and FACT ROWS constrain themselves to 1180 px with their own
   `max-width` + auto margins. The implementation had put `max-width:1180px` on the ANSWER, so
   the analytical regions were pulled in to the card width — approved 101 px vs implemented
   130 px from the column edge.
   ⚠ The card rail still lands at exactly the same place: inside a padded 1240 px content box
   a centred 1180 px rail resolves to the same left edge it had before. Verified, ⛔ not
   assumed — the alignment assertion re-runs below. */
.cmp-journey .d1x-answer,.cmp-journey .dox-answer,.cmp-journey .dux-answer{
  width:100%; padding:30px 34px 34px;
  color:var(--ink); font-size:15px; line-height:1.6;
  display:flex; flex-direction:column; gap:28px}

/* ── the shared rail grammar (D1 and D2 Unit Type draw the same rails) ── */
.cmp-journey .d1x-num,.cmp-journey .dux-num,.cmp-journey .dox-num{direction:ltr;
  unicode-bidi:isolate; font-variant-numeric:tabular-nums}
.cmp-journey .d1x-subgroups{display:flex; flex-direction:column; margin-top:14px}
.cmp-journey .d1x-sg,.cmp-journey .dux-sg{padding:18px 0; border-top:1px solid var(--hairline)}
.cmp-journey .d1x-sg:first-child,.cmp-journey .dux-sg:first-child{border-top:0; padding-top:2px}
.cmp-journey .d1x-sg:last-child,.cmp-journey .dux-sg:last-child{padding-bottom:0}
.cmp-journey .d1x-sg-head,.cmp-journey .dux-sg-head{margin-bottom:13px; font-size:1rem;
  font-weight:800; letter-spacing:-.01em; color:var(--ink)}
.cmp-journey .d1x-sz{font-weight:600; color:var(--muted)}
.cmp-journey .d1x-rails,.cmp-journey .dux-rails{position:relative}
/* 🔒 THE APPROVED RAIL GEOMETRY IS AN EXPLICIT GRID, ⛔ not stacked flow with an absolutely
   positioned guide. ⌛ The implementation had built it the second way, which is why the
   track's spacing did not match and why the guides had to be placed by arithmetic. The frames
   assign every child its own `grid-row` and let the GUIDE span the rows it must cross, so the
   dashed line is bounded by the layout rather than by a computed offset. */
.cmp-journey .d1x-rails.d1x-grid,.cmp-journey .dux-rails.dux-grid{display:grid;
  grid-template-columns:100%}
.cmp-journey .d1x-grid>.d1x-rail-cap,.cmp-journey .dux-grid>.dux-rail-cap{grid-column:1;
  margin-bottom:var(--cap-gap)}
.cmp-journey .d1x-grid>.d1x-track,.cmp-journey .dux-grid>.dux-track{grid-column:1}
.cmp-journey .d1x-grid>.d1x-track.d1x-first,
.cmp-journey .dux-grid>.dux-track.dux-first{margin-bottom:var(--rail-gap)}
.cmp-journey .d1x-grid>:nth-child(1),.cmp-journey .dux-grid>:nth-child(1){grid-row:1}
.cmp-journey .d1x-grid>:nth-child(2),.cmp-journey .dux-grid>:nth-child(2){grid-row:2}
.cmp-journey .d1x-grid>:nth-child(3),.cmp-journey .dux-grid>:nth-child(3){grid-row:3}
.cmp-journey .d1x-grid>:nth-child(4),.cmp-journey .dux-grid>:nth-child(4){grid-row:4}
/* D1 draws one rail per project plus the shared benchmark, so it runs to seven children */
.cmp-journey .d1x-grid.d1x-d1>:nth-child(5){grid-row:5}
.cmp-journey .d1x-grid.d1x-d1>:nth-child(6){grid-row:6}
.cmp-journey .d1x-grid.d1x-d1>:nth-child(7){grid-row:7}
/* 🔒 the guide is a GRID ITEM spanning the tracks it crosses — ⛔ never an absolute overlay */
.cmp-journey .d1x-grid>.d1x-guide,.cmp-journey .dux-grid>.dux-guide{grid-column:1;
  grid-row:2 / 5; position:relative; inset:auto; width:auto; height:auto; border:0; z-index:0}
.cmp-journey .d1x-grid.d1x-d1>.d1x-guide{grid-row:2 / 8}
.cmp-journey .d1x-grid>.d1x-guide::before,.cmp-journey .dux-grid>.dux-guide::before{
  content:""; position:absolute; top:0; bottom:0; left:var(--x);
  border-left:1px dashed rgba(109,71,225,.42)}
[dir="rtl"] .cmp-journey .d1x-grid>.d1x-guide::before,
[dir="rtl"] .cmp-journey .dux-grid>.dux-guide::before{left:auto; right:var(--x);
  border-left:0; border-right:1px dashed rgba(109,71,225,.42)}
.cmp-journey .d1x-grid>.d1x-rail-cap,.cmp-journey .d1x-grid>.d1x-track,
.cmp-journey .dux-grid>.dux-rail-cap,.cmp-journey .dux-grid>.dux-track{position:relative;
  z-index:1}
.cmp-journey .d1x-rail-cap,.cmp-journey .dux-rail-cap{height:var(--cap-h); display:flex;
  align-items:center; justify-content:space-between; gap:12px; margin-bottom:var(--cap-gap)}
.cmp-journey .d1x-rail-cap.d1x-two,.cmp-journey .dux-rail-cap.dux-two{height:auto;
  min-height:var(--cap-h2); align-items:flex-start}
.cmp-journey .d1x-rail-cap.d1x-two .d1x-rail-name,
.cmp-journey .dux-rail-cap.dux-two .dux-rail-name{align-items:flex-start}
.cmp-journey .d1x-rail-cap.d1x-two .d1x-dot,
.cmp-journey .dux-rail-cap.dux-two .dux-dot{margin-top:5px}
.cmp-journey .d1x-rail-cap.d1x-two .d1x-rail-val,
.cmp-journey .dux-rail-cap.dux-two .dux-rail-val{margin-top:-1px}
.cmp-journey .d1x-rail-name,.cmp-journey .dux-rail-name{display:flex; align-items:center;
  gap:7px; min-width:0; font-size:.79rem; font-weight:700; color:var(--body);
  background:var(--paper); padding-inline-end:8px}
.cmp-journey .d1x-rail-name>span,.cmp-journey .dux-rail-name>span{min-width:0; display:flex;
  flex-direction:column; line-height:1.28}
.cmp-journey .d1x-band,.cmp-journey .dux-band{font-size:.72rem; font-weight:600;
  color:var(--muted); font-style:normal}
/* 🔒 D1 names its project on the rail (RULING 4 — the caption IS the column heading);
   D2 Unit Type names the project once at its panel head and the rail reads the governed
   `asking_label`. ⛔ The two are different regions and this weight belongs only to D1. */
.cmp-journey .d1x-pname{font-size:.86rem; font-weight:800; color:var(--ink);
  letter-spacing:-.01em}
.cmp-journey .d1x-dot,.cmp-journey .dux-dot{flex:none; width:9px; height:9px; border-radius:50%}
.cmp-journey .d1x-dot-o,.cmp-journey .dux-dot-o{background:var(--orange)}
.cmp-journey .d1x-dot-p,.cmp-journey .dux-dot-p{background:var(--purple)}
.cmp-journey .d1x-rail-val,.cmp-journey .dux-rail-val{flex:none; font-size:.88rem;
  font-weight:800; letter-spacing:-.01em; font-variant-numeric:tabular-nums; direction:ltr;
  unicode-bidi:isolate; background:var(--paper); padding-inline-start:8px}
.cmp-journey .d1x-val-o,.cmp-journey .dux-val-o{color:var(--orange-deep)}
.cmp-journey .d1x-val-p,.cmp-journey .dux-val-p{color:var(--purple-deep)}
.cmp-journey .d1x-track,.cmp-journey .dux-track{position:relative; height:var(--trk-h);
  border-radius:var(--r-pill); background:var(--track)}
.cmp-journey .d1x-bar,.cmp-journey .dux-bar{position:absolute; top:0; bottom:0; left:var(--lo);
  width:var(--w); border-radius:var(--r-pill)}
/* 🔒 RULING 1 — every project rail is SOLID orange, the benchmark SOLID purple, and
   ⛔ freshness (RULING 3) changes neither solidity, colour nor geometry. */
.cmp-journey .d1x-bar-o,.cmp-journey .dux-bar-o{background:var(--orange);
  box-shadow:inset 0 0 0 1px rgba(217,79,0,.30)}
.cmp-journey .d1x-bar-p,.cmp-journey .dux-bar-p{background:var(--purple);
  box-shadow:inset 0 0 0 1px rgba(74,43,176,.30)}
.cmp-journey .d1x-bar::before,.cmp-journey .d1x-bar::after,
.cmp-journey .dux-bar::before,.cmp-journey .dux-bar::after{content:""; position:absolute;
  top:-4px; bottom:-4px; width:2.5px; border-radius:2px}
.cmp-journey .d1x-bar::before,.cmp-journey .dux-bar::before{left:0}
.cmp-journey .d1x-bar::after,.cmp-journey .dux-bar::after{right:0}
.cmp-journey .d1x-bar-o::before,.cmp-journey .d1x-bar-o::after,
.cmp-journey .dux-bar-o::before,.cmp-journey .dux-bar-o::after{background:var(--orange-deep)}
.cmp-journey .d1x-bar-p::before,.cmp-journey .d1x-bar-p::after,
.cmp-journey .dux-bar-p::before,.cmp-journey .dux-bar-p::after{background:var(--purple-deep)}
/* the governed no-scale treatment: the project stays represented and its own price is still
   printed, but ⛔ no rail is drawn without evidence */
.cmp-journey .d1x-rails.d1x-no-scale,.cmp-journey .dux-rails.dux-no-scale{
  border:1px dashed var(--line); border-radius:var(--r-md); padding:12px 14px}
.cmp-journey .d1x-no-scale .d1x-track,.cmp-journey .dux-no-scale .dux-track{display:none}
.cmp-journey .d1x-no-scale .d1x-rail-cap,.cmp-journey .dux-no-scale .dux-rail-cap{
  margin-bottom:0; height:auto; min-height:20px}
.cmp-journey .d1x-no-scale .d1x-rail-name,.cmp-journey .d1x-no-scale .d1x-rail-val,
.cmp-journey .dux-no-scale .dux-rail-name,.cmp-journey .dux-no-scale .dux-rail-val{
  background:transparent}

/* ── status chips ──────────────────────────────────────────────────────────────────────
   🔴 THE BASE CHIP CARRIES NO BACKGROUND AND NO BORDER, and that is the approved treatment:
   `pos_status_above` and `pos_status_below` render as PLAIN TEXT with no modifier class
   (verified across all four D1 frames), and only `within` / `partial` / `none` add a fill.
   An earlier sheet put the `none` styling on the base, so all six states drew a pill and
   `G-D1-CHIPS-MEANINGFUL`'s three distinct backgrounds collapsed toward one. ⛔ And ⛔ no
   seventh treatment is invented for `pos_status_unassessable` (OI-VIS-02, still open). */
.cmp-journey .d1x-chip,.cmp-journey .dux-chip{display:inline-flex; align-items:center;
  margin-top:13px; padding:5px 12px; border-radius:var(--r-pill); font-size:.76rem;
  font-weight:800}
.cmp-journey .d1x-chip.d1x-within,.cmp-journey .dux-chip.dux-within{background:var(--green-bg);
  color:var(--green-ink); border:1px solid rgba(40,145,95,.22)}
.cmp-journey .d1x-chip.d1x-partial,.cmp-journey .dux-chip.dux-partial{background:var(--warn-bg);
  color:var(--warn-ink); border:1px solid rgba(200,130,0,.30)}
.cmp-journey .d1x-chip.d1x-none,.cmp-journey .dux-chip.dux-none{background:var(--grey-bg);
  color:var(--muted); border:1px solid var(--line)}
/* 🔒 RULING 9's scope line — across neighbourhoods every chip takes ONE neutral treatment,
   because a coloured chip there reads as a ranking. ⛔ The MEANING is carried by the WORDING. */
.cmp-journey .dux-chip.dux-local{background:#f7f5fb; border:1px solid var(--line);
  color:var(--body); font-weight:700}
/* 🔒 D1's verdicts — one per project. ⚠ The project name is `<b>` at weight 800 and
   **opacity .72**: the emphasis is carried by OPACITY, ⛔ not by a lighter weight, which is
   what an earlier pass guessed. */
.cmp-journey .d1x-verdicts{display:flex; flex-wrap:wrap; gap:8px 10px; margin-top:15px}
.cmp-journey .d1x-verdicts .d1x-chip{margin-top:0; gap:8px; align-items:baseline}
.cmp-journey .d1x-verdicts .d1x-chip b{font-weight:800; opacity:.72; white-space:nowrap;
  flex:none}
.cmp-journey .d1x-note{margin:15px 0 0; font-size:.8rem; color:var(--muted)}

/* ══ D2 OVERALL — the configuration matrix ════════════════════════════════════════════
   🔒 The approved grid: a fixed row-head column plus one per project, `gap:1px` over a
   `--line` background so the 1-px gaps ARE the rules and each cell paints its own ground.
   ⌛ The implementation had rebuilt this with borders and its own class names
   (`dox-mrow`/`dox-mcol`/`dox-mcell`/`dox-msub`), which is why six components could not even
   be compared against the frame. The approved vocabulary is restored. */
.cmp-journey .dox-mtx{display:grid;
  grid-template-columns:132px repeat(var(--w1c-n),minmax(0,1fr));
  gap:1px; background:var(--line); border:1px solid var(--line); border-radius:var(--r-lg);
  overflow:hidden; margin-top:14px}
.cmp-journey .dox-mh{background:var(--soft); padding:11px 14px; display:flex;
  flex-direction:column; gap:1px}
.cmp-journey .dox-mh b{font-size:.85rem; font-weight:800; color:var(--ink); line-height:1.25}
.cmp-journey .dox-mh span{font-size:.75rem; color:var(--muted)}
.cmp-journey .dox-mrh{background:var(--soft); padding:14px; display:flex; flex-direction:column;
  gap:5px; font-size:.9rem; font-weight:800; color:var(--ink)}
.cmp-journey .dox-cell{background:var(--paper); padding:14px; display:flex;
  flex-direction:column; gap:3px; min-width:0}
.cmp-journey .dox-c-sz{font-size:.88rem; font-weight:800; color:var(--ink);
  letter-spacing:-.01em}
.cmp-journey .dox-c-sub{font-size:.76rem; color:var(--muted); line-height:1.4}
/* 🔒 §3's three unavailable states are never conflated, and the producer names which applies. */
.cmp-journey .dox-cell.dox-notoff,.cmp-journey .dox-cell.dox-unknown{background:#faf9fb}
.cmp-journey .dox-cell.dox-notoff .dox-c-state,
.cmp-journey .dox-cell.dox-unknown .dox-c-state{color:var(--muted)}
.cmp-journey .dox-cell.dox-nopos .dox-c-sub{color:var(--warn-ink)}
/* 🔒 the eligibility badge lives in the ROW HEAD, ⛔ not inside the drill button */
.cmp-journey .dox-cfg-tag{align-self:flex-start; font-size:.65rem; font-weight:800;
  letter-spacing:.05em; text-transform:uppercase; padding:2px 8px; border-radius:var(--r-pill);
  background:var(--green-bg); color:var(--green-ink)}
/* 🔒 THE DRILL SECTION and its COMPARE ACTIONS.
   🔴 `--r-md` IS A ROUNDED RECTANGLE, ⛔ NOT A CAPSULE. The owner named this exactly: an
   earlier pass drew `--r-pill` capsules with a CSS `::after` arrow. The approved control is a
   12-px-radius rectangle with a 1-px purple outline and a real arrow. */
.cmp-journey .dox-drill{border:1px solid #ddd2ff; background:var(--soft);
  border-radius:var(--r-lg); padding:18px 20px 20px}
.cmp-journey .dox-drill-head{font-size:.78rem; font-weight:800; letter-spacing:.11em;
  text-transform:uppercase; color:var(--purple)}
.cmp-journey .dox-drill-pills{display:flex; flex-wrap:wrap; gap:10px; margin-top:12px}
.cmp-journey .dox-cmp{display:inline-flex; align-items:center; gap:8px; min-height:44px;
  padding:0 20px; border:1px solid var(--purple); border-radius:var(--r-md);
  background:var(--paper); color:var(--purple-deep); font-family:inherit; font-size:.95rem;
  font-weight:800; cursor:pointer; line-height:normal;
  transition:background 180ms cubic-bezier(.2,.7,.3,1), transform 180ms cubic-bezier(.2,.7,.3,1)}
.cmp-journey .dox-cmp:hover{background:#ece5ff}
.cmp-journey .dox-cmp:active{transform:translateY(1px)}
.cmp-journey .dox-cmp:focus-visible{outline:2px solid var(--purple-deep); outline-offset:3px}
.cmp-journey .dox-drill-note{margin:13px 0 0; font-size:.84rem; color:var(--body); max-width:74ch}
/* 🔒 THE APPROVED NARROW MATRIX — ⛔ a table never scrolls sideways. One bordered block per
   configuration, its head carrying the label and the eligibility badge, then one row per
   project NAMING ITS OWN PROJECT. ⚠ `.dox-mcfg` is the block and `.dox-mrow` the project row;
   nesting one `.dox-mrow` inside another lays them out side by side and overflows the
   viewport — measured at 568 px inside 390 px before this was corrected. */
.cmp-journey .dox-mtx-m{display:none; flex-direction:column; gap:12px; margin-top:14px}
.cmp-journey .dox-mcfg{border:1px solid var(--line); border-radius:var(--r-lg);
  overflow:hidden}
.cmp-journey .dox-mcfg-head{display:flex; align-items:center; gap:9px; flex-wrap:wrap;
  background:var(--soft); padding:11px 14px; font-size:.92rem; font-weight:800;
  color:var(--ink)}
.cmp-journey .dox-mrow{display:flex; align-items:flex-start; gap:12px; padding:11px 14px;
  border-top:1px solid var(--hairline)}
.cmp-journey .dox-mrow-p{flex:0 0 108px; font-size:.8rem; font-weight:700; color:var(--body);
  line-height:1.35}
.cmp-journey .dox-mrow .dox-cell{flex:1 1 auto; padding:0; background:transparent}

/* ══ D2 UNIT TYPE ═════════════════════════════════════════════════════════════════════ */
.cmp-journey .dux-topbar{display:flex; align-items:center; justify-content:space-between;
  gap:14px; flex-wrap:wrap}
.cmp-journey .dux-back{display:inline-flex; align-items:center; gap:9px; min-height:44px;
  padding:0 16px 0 12px; border:1px solid var(--line); border-radius:var(--r-md);
  background:var(--paper); color:var(--purple-deep); font-family:inherit; font-size:.92rem;
  font-weight:800; cursor:pointer; line-height:normal;
  transition:background 180ms cubic-bezier(.2,.7,.3,1)}
.cmp-journey .dux-back:hover{background:var(--soft)}
.cmp-journey .dux-back:focus-visible{outline:2px solid var(--purple-deep); outline-offset:3px}
.cmp-journey .dux-footbar{display:flex}
/* 🔒 ONE JOINED SEGMENTED CONTROL — a single tinted track holding both segments, the selection
   a raised paper fill inside it. ⛔ Never two detached pills, and ⛔ never a solid primary
   purple, which would read as the page's main action. */
.cmp-journey .dux-cfgsw{display:inline-flex; background:var(--grey-bg);
  border-radius:var(--r-md); padding:3px; gap:3px}
.cmp-journey .dux-cfg{min-height:38px; padding:0 18px; border:0;
  border-radius:calc(var(--r-md) - 3px); background:transparent; color:var(--body);
  font-family:inherit; font-size:.9rem; font-weight:800; cursor:pointer; line-height:normal}
.cmp-journey .dux-cfg.dux-on{background:var(--paper); color:var(--purple-deep);
  box-shadow:0 1px 2px rgba(23,21,29,.10)}
.cmp-journey .dux-cfg:focus-visible{outline:2px solid var(--purple-deep); outline-offset:2px}
.cmp-journey .dux-lps{display:flex; flex-direction:column; gap:16px}
.cmp-journey .dux-lp{border:1px solid var(--line); border-radius:var(--r-lg);
  background:var(--tint); padding:18px 20px 20px}
.cmp-journey .dux-lp-head{display:flex; align-items:flex-start; justify-content:space-between;
  gap:16px; flex-wrap:wrap}
.cmp-journey .dux-lp-id{display:flex; align-items:center; gap:10px; flex-wrap:wrap; min-width:0}
.cmp-journey .dux-lp-name{font-size:1.06rem; font-weight:800; letter-spacing:-.015em;
  color:var(--ink)}
.cmp-journey .dux-lp-nb{font-size:.86rem; font-weight:700; color:var(--purple-deep)}
.cmp-journey .dux-lp-nb::before{content:"·"; margin-inline-end:8px; color:var(--muted);
  font-weight:600}
.cmp-journey .dux-lp-side{display:flex; align-items:center; gap:10px; flex-wrap:nowrap}
/* 🔒 the governed classification — the SAME key the D-08 card's ribbon carries */
.cmp-journey .dux-status{flex:none; display:inline-flex; align-items:center; gap:6px;
  padding-block:5px; padding-inline:8px 11px; border-radius:var(--r-pill);
  background:var(--soft); color:var(--purple-deep); border:1px solid #e0d6ff;
  font-size:.73rem; font-weight:800; letter-spacing:.03em; white-space:nowrap}
.cmp-journey .dux-lp .dux-status{font-size:.68rem}
.cmp-journey .dux-lp-split{margin:14px 0 0; font-size:.86rem; color:var(--body); max-width:70ch}
.cmp-journey .dux-lp-body{display:flex; flex-direction:column; gap:14px; margin-top:16px}
/* 🔒 each size group is its OWN container — the approved nesting, ⛔ not a flat run */
.cmp-journey .dux-lc{width:100%; border:1px solid var(--hairline); border-radius:var(--r-md);
  background:var(--paper); padding:13px 16px 15px}
.cmp-journey .dux-lc-lbl{font-size:.68rem; font-weight:800; letter-spacing:.09em;
  text-transform:uppercase; color:var(--muted); margin-bottom:8px}
.cmp-journey .dux-lc .dux-sg{padding:0; border-top:0}
.cmp-journey .dux-lc .dux-sg-head{margin:0 0 12px; font-size:.94rem}
.cmp-journey .dux-lc .dux-chip{margin-top:14px}
.cmp-journey .dux-unavail{margin:14px 0 0; font-size:.86rem; color:var(--muted)}

/* ══ THE APPROVED GLYPHS, AS CSS MASKS ════════════════════════════════════════════════
   🔴 THE CLIENT MAY NOT EMIT AN ICON. `noIcons()` in `test/step16a.test.mjs` asserts against
   every dispatched payload that the client adds no `<svg>`, no `<use>`, no icon `<i>` and no
   icon glyph of its own; the only permitted images are the approved logo and the governed
   asset-type / amenity library files served through the byte-pinned `render/icons.js`, which
   carries neither an arrow nor a verification mark.
   ⌛ The approved frames DO draw these as inline `<svg>`, and porting them that way tripped the
   guard on four payloads. Drawing them as masks keeps the approved shape, size and stroke
   weight while ⛔ nothing enters the DOM or the accessible name. ⛔ No new asset file is
   minted, which would need its own approval. */
.cmp-journey .cmp-ic{display:inline-block; flex:none; background-color:currentColor;
  -webkit-mask-repeat:no-repeat; mask-repeat:no-repeat;
  -webkit-mask-position:center; mask-position:center;
  -webkit-mask-size:contain; mask-size:contain}
.cmp-journey .cmp-ic-arrow{width:16px; height:16px;
  -webkit-mask-image:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/><path d="m12 5 7 7-7 7"/></svg>');
  mask-image:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/><path d="m12 5 7 7-7 7"/></svg>')}
.cmp-journey .dux-back .cmp-ic-back{width:17px; height:17px; transform:scaleX(-1)}
[dir="rtl"] .cmp-journey .dux-back .cmp-ic-back{transform:none}
[dir="rtl"] .cmp-journey .dox-cmp .cmp-ic-arrow{transform:scaleX(-1)}
.cmp-journey .cmp-ic-verified{width:13px; height:13px;
  -webkit-mask-image:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2 4 5v6c0 5 3.4 9.4 8 11 4.6-1.6 8-6 8-11V5z"/><path d="m9 12 2 2 4-4"/></svg>');
  mask-image:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2 4 5v6c0 5 3.4 9.4 8 11 4.6-1.6 8-6 8-11V5z"/><path d="m9 12 2 2 4-4"/></svg>')}

/* ══ RTL — the frames' own `.d1x-rtl` / `.dox-rtl` / `.dux-rtl` rules, PORTED VERBATIM ═══
   ⌛ A first attempt GENERALISED these and got eleven components wrong in Arabic: it extended
   the weight drop to the matrix heads, the cell sizes, the eligibility badge and the Compare
   action — all of which the approved design keeps at 800 in Arabic — and cleared
   `text-transform` on the badge, which stays uppercase. ⛔ The list below is exactly the
   frames'; ⛔ nothing is added to it. */
[dir="rtl"] .cmp-journey .d1x-answer,[dir="rtl"] .cmp-journey .dox-answer,
[dir="rtl"] .cmp-journey .dux-answer{line-height:1.85}
/* 🔒 a BLANKET reset — tight Latin tracking is wrong on every Arabic glyph */
[dir="rtl"] .cmp-journey .d1x-answer,[dir="rtl"] .cmp-journey .d1x-answer *,
[dir="rtl"] .cmp-journey .dox-answer,[dir="rtl"] .cmp-journey .dox-answer *,
[dir="rtl"] .cmp-journey .dux-answer,[dir="rtl"] .cmp-journey .dux-answer *,
[dir="rtl"] :is(.cmp-journey, .q9-rail, .w5-rail, .dep21) .cx-pill{letter-spacing:normal}
/* 🔒 the eyebrow heads lose their uppercase/tracked treatment, meaningless in Arabic */
[dir="rtl"] .cmp-journey .d1x-block-title,[dir="rtl"] .cmp-journey .dox-block-title,
[dir="rtl"] .cmp-journey .dux-block-title{letter-spacing:0; text-transform:none;
  font-weight:700}
/* 🔒 and exactly these drop to 700, because the Arabic face ships no 800 */
[dir="rtl"] .cmp-journey .dux-status,[dir="rtl"] .cmp-journey .d1x-chip,
[dir="rtl"] .cmp-journey .dux-chip,[dir="rtl"] .cmp-journey .d1x-rail-val,
[dir="rtl"] .cmp-journey .dux-rail-val,[dir="rtl"] .cmp-journey .d1x-sg-head,
[dir="rtl"] .cmp-journey .dux-sg-head{font-weight:700}
[dir="rtl"] .cmp-journey .dox-brief-text,[dir="rtl"] .cmp-journey .dux-brief-text{
  font-size:.97rem}
/* 🔒 the bar is offset from the RIGHT in RTL — ⛔ a left offset would mirror every rail */
[dir="rtl"] .cmp-journey .d1x-bar,[dir="rtl"] .cmp-journey .dux-bar{left:auto;
  right:var(--lo)}

/* ══ THE NARROW BAND ══════════════════════════════════════════════════════════════════ */
@media (max-width:719px){
  .cmp-journey{--w1c-cols:1fr}
  /* 🔒 the approved handset inset and rhythm — `.dox-handset .dox-answer{padding:22px 20px 26px;
     gap:24px}`. ⌛ 13 Sep 2026: the implementation carried the desktop 28px gap at both bands. */
  .cmp-journey .d1x-answer,.cmp-journey .dox-answer,.cmp-journey .dux-answer{
    padding:22px 20px 26px; gap:24px}
  .cmp-journey .cx-rail{grid-template-columns:1fr}
  .cmp-journey .w1c-spacer{display:none}
  .cmp-journey .w1c-row{align-items:stretch}
  .cmp-journey .w1c-lab{font-weight:700; color:var(--muted); margin-bottom:2px}
  /* 🔒 THE APPROVED STACKED STRUCTURE — a two-column grid pairing each project's NAME with
     its own value, aligned down the screen. ⛔ NOT inline "project · value" text. */
  .cmp-journey .w1c-nrow{display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1.25fr);
    gap:10px; align-items:baseline; padding:3px 0}
  .cmp-journey .w1c-nproj{display:block; font-size:.78rem; font-weight:800; color:var(--muted);
    min-width:0; overflow-wrap:anywhere}
  /* the approved narrow matrix replaces the wide grid entirely */
  .cmp-journey .dox-mtx{display:none}
  .cmp-journey .dox-mtx-m{display:flex}
  .cmp-journey .d1x-rail-name,.cmp-journey .dux-rail-name{font-size:.75rem}
  .cmp-journey .d1x-band,.cmp-journey .dux-band{font-size:.69rem}
  .cmp-journey .d1x-rail-val,.cmp-journey .dux-rail-val{font-size:.81rem}
  .cmp-journey .d1x-pname{font-size:.82rem}
  .cmp-journey .dox-brief-text,.cmp-journey .dux-brief-text{font-size:.98rem}
  .cmp-journey .d1x-verdicts{flex-direction:column; align-items:flex-start; gap:8px}
  .cmp-journey .dux-topbar{gap:10px}
  .cmp-journey .dux-lp{padding:15px 14px 16px}
  .cmp-journey .dux-lp-head{flex-direction:column; gap:10px}
  .cmp-journey .dux-lp-side{flex-wrap:wrap; width:100%}
  .cmp-journey .dux-lc{padding:12px 13px 14px}
  .cmp-journey .dux-cfg{padding:0 15px}
}

/* ── 🔴 THE ONE RULE IN THIS SHEET THAT REACHES OUTSIDE `.cmp-journey`, AND WHY ────────────
   The workspace's governed return control is the shared `.backbar` strip. `styles.css:627`
   hides it at ≥ 900px (`@media (min-width:900px){ .backbar{display:none} }`) — a rule that is
   **pre-existing at the byte-pin baseline `911ec47b`** and ⛔ was not introduced by this work.
   The approved comparison journey records the control as *"present on all twelve approved
   frames … at both governed bands"*, so at the desktop band the approved `Back to comparison`
   was simply not there.

   ⛔ THE PRE-EXISTING RULE IS NOT DELETED AND `styles.css` IS NOT EDITED. The correction is
   scoped by the `cmp-origin` marker `main.js` sets only when the workspace was opened from a
   comparison, so:
     · a comparison-origin workspace shows the control at BOTH bands — the approved behaviour;
     · every other workspace is BYTE-IDENTICAL to before, including its desktop band.
   🔒 The new-unprotected-module route is the § 30.6 precedent, taken instead of widening a
   byte-pinned stylesheet. ⚠ `.backbar.cmp-origin` (0,2,0) outranks `.backbar` (0,1,0), so it
   wins on specificity and ⛔ does not depend on sheet order.
   ⚠ Filed as `R-01`; whether the strip should be REMOVED entirely outside a comparison is an
   authority conflict, reported in the delivery and ⛔ not resolved here. */
@media (min-width:900px){
  .backbar.cmp-origin{display:flex}
}

/* ══ § 43 · OWNER DECISION 2 / M-4 — the single-confirmed-project explanation ══════════════
   🔒 Rev6 SCALE-04, verbatim and scoped: *"Place the existing governed explanation directly
   beneath its row, spanning the full matrix width — not inside a project-value cell."* Applied at
   2, 3 and 4 projects (M-4, 13 Sep 2026). ⛔ PLACEMENT ONLY: the container is the locked `.dox-cell`
   (wide) or `.dox-mrow` (narrow) and the text is the locked `.dox-drill-note`; the two declarations
   span the row and remove the note's leading margin. ⛔ No colour, size, radius or spacing chosen. */
.cmp-journey .dox-mtx .dox-mtx-note{grid-column:1/-1}
.cmp-journey .dox-mtx-note .dox-drill-note{margin-top:0}

/* ══ § 43 · OWNER DECISION 1 — the approved 3-/4-project desktop layout ══════════════════════
   🔒 Rev6 (12 Sep 2026), adopted from candidate S-1, verbatim and scoped to `.cmp-journey`.
   ⛔ `.w1c-scroll` wraps the card rail and the fact section and NOTHING else — ⛔ never the page,
   ⛔ never the D2 matrix, ⛔ never the drill actions or the stacked unit-type panels. It is emitted
   ONLY at three and four projects, so two projects are unchanged. ⛔ Engages at the approved desktop
   breakpoint only; below 1108 px the published reflows are untouched and mobile stays stacked.
   ⛔ Every value is Rev6's own derivation from the approved two-project rail arithmetic or an
   existing token. */
.cmp-journey .w1c-scroll{max-width:1180px; margin-inline:auto}
/* ⚠ the backdrop cell exists at every width, so it is hidden outside the desktop band */
.cmp-journey .w1c-labbg{display:none}
@media (min-width:1108px){
  .cmp-journey .w1c-scroll{
    --w1c-card-col:calc((1180px - 24px)/3);   /* 385.33px — the approved card */
    --w1c-lab-col:calc((1180px - 36px)/4);    /* the label at N=3, unchanged from the divided grid */
    /* `scroll`, ⛔ not `auto`: the bar is a permanent affordance (Rev6 INH-4) */
    overflow-x:scroll; overflow-y:hidden;
    scrollbar-width:auto; scrollbar-color:var(--purple) var(--soft);
    overscroll-behavior-x:contain;
    scroll-snap-type:inline mandatory;
    scroll-padding-inline-start:calc(var(--w1c-lab-col) + 12px);
    /* ⚠ lets a governed structural note inside the region keep to the visible width */
    container-type:inline-size;
    /* 🔴 MEASURED 13 Sep 2026 in the live host, ⛔ not in Rev6's static frame: `.cmp-journey` is a
       flex COLUMN, so an auto-margined item is not stretched and sizes to fit-content. With the
       containment above that collapsed the region to 0 px (1440 and 1108, EN and AR); without it the
       region took 1180 px inside a 974 px parent at 1108 and overflowed the page by 139 px.
       `inline-size:100%` restores the block-flow fill Rev6's frame had — the SAME
       `width:100% + max-width:1180px + margin-inline:auto` the published `.cx-rail` already uses —
       giving 1180 px at 1440 (scrollable 636 px, Rev6's own figure) and 974 px at 1108, 0 px overflow. */
    inline-size:100%;
  }
  .cmp-journey[data-projects="4"] .w1c-scroll{--w1c-lab-col:calc((1180px - 48px)/5)}
  .cmp-journey .w1c-scroll .cx-rail>.cx-card{scroll-snap-align:start}
  .cmp-journey .w1c-scroll:focus-visible{outline:2px solid var(--purple-deep); outline-offset:3px;
    border-radius:var(--r-lg)}
  .cmp-journey .w1c-scroll::-webkit-scrollbar{height:10px}
  .cmp-journey .w1c-scroll::-webkit-scrollbar-track{background:var(--soft); border-radius:999px}
  .cmp-journey .w1c-scroll::-webkit-scrollbar-thumb{background:var(--purple); border-radius:999px}
  /* ONE token drives the card rail AND the fact rows, so alignment is structural */
  .cmp-journey .w1c-scroll .w1c-scrollinner{min-width:max-content;
    --w1c-cols:var(--w1c-lab-col) repeat(var(--w1c-n),var(--w1c-card-col))}
  .cmp-journey .w1c-scroll .cx-rail,.cmp-journey .w1c-scroll .w1c-rows{max-width:none; margin-inline:0}
  /* the fixed leading edge — pinned logically, so Arabic mirrors with no second rule */
  .cmp-journey .w1c-scroll .w1c-spacer,.cmp-journey .w1c-scroll .w1c-labbg,
  .cmp-journey .w1c-scroll .w1c-lab{position:sticky; inset-inline-start:0}
  .cmp-journey .w1c-scroll .w1c-spacer,.cmp-journey .w1c-scroll .w1c-labbg{background:var(--surface); z-index:1}
  .cmp-journey .w1c-scroll .w1c-lab{z-index:2}
  .cmp-journey .w1c-scroll .w1c-labbg{display:block; grid-area:1/1; align-self:stretch;
    margin-block:-8px; margin-inline-end:-12px}
  .cmp-journey .w1c-scroll .w1c-row>.w1c-lab{grid-area:1/1}
  /* ══ § 43.5 · OWNER CORRECTION (13 Sep 2026) — THE RESERVED LABEL COLUMN ═══════════════════════
     🔒 *"Reserve a separate fixed label column — left in English, right in Arabic. Cards and their
     matching fact values scroll together only within the remaining space; nothing passes underneath the
     labels. Keep the approved label width and outer page margins. At settled scroll positions, align the
     leading visible card with the project-area boundary. Check the end position too: no partly hidden
     leading card or View project button. Partial cards during active scrolling may be clipped at the
     project-area boundary, never covered by labels."*
     ⛔ The approved label width (`--w1c-lab-col`), card width, 12 px gap, region width and page margins
     are UNCHANGED, and so is the markup. Two things are added:
     (1) CLIPPING. Each card and each fact cell is clipped at the project-area boundary — the label
         column's width plus the approved gap — so no part of it is painted or can be pressed beneath the
         labels. The boundary moves with the scroll offset, which only the browser knows; the comparison
         module (`render/compare.js`, ⛔ not the protected `main.js`) publishes it as `--w1c-sx`. Arabic clips from the right. The −24 px outer insets keep the card's
         own shadow on the three free sides.
     (2) SETTLED POSITIONS. The existing snap already lands a card on the boundary; the END was the one
         position it could not, because the scroll range was not a whole number of card steps. The
         trailing space below makes it one: `mod(region width − label column, card step)` — the exact
         remainder, so the last settled position starts on a whole card too. The space is inside the
         region, ⛔ never a page margin. */
  .cmp-journey .w1c-scroll{--w1c-sx:0px; --w1c-pitch:calc(var(--w1c-card-col) + 12px)}
  /* ⚠ ON THE CARD RAIL AND THE ROW GROUP, ⛔ not on `.w1c-scrollinner`: the space must lie INSIDE the box
     the two D11 warnings pin within (the fact section), or they cannot follow the region to its end —
     measured: with the space on the inner wrapper both warnings left the visible region at the end
     position. The rows themselves keep their width, so their hairlines still end at the last cell. */
  .cmp-journey .w1c-scroll .cx-rail,
  .cmp-journey .w1c-scroll .w1c-rows{
    padding-inline-end:mod(calc(100cqi - var(--w1c-lab-col)), var(--w1c-pitch))}
  .cmp-journey .w1c-scroll .cx-rail>.cx-card:nth-of-type(1),
  .cmp-journey .w1c-scroll .w1c-row>.w1c-cell:nth-of-type(1){--w1c-i:0}
  .cmp-journey .w1c-scroll .cx-rail>.cx-card:nth-of-type(2),
  .cmp-journey .w1c-scroll .w1c-row>.w1c-cell:nth-of-type(2){--w1c-i:1}
  .cmp-journey .w1c-scroll .cx-rail>.cx-card:nth-of-type(3),
  .cmp-journey .w1c-scroll .w1c-row>.w1c-cell:nth-of-type(3){--w1c-i:2}
  .cmp-journey .w1c-scroll .cx-rail>.cx-card:nth-of-type(4),
  .cmp-journey .w1c-scroll .w1c-row>.w1c-cell:nth-of-type(4){--w1c-i:3}
  .cmp-journey .w1c-scroll .cx-rail>.cx-card,
  .cmp-journey .w1c-scroll .w1c-row>.w1c-cell{
    /* ⚠ − 1px: scroll offsets are whole pixels but the approved card step is 397.33 px, so a settled card
       lands within a pixel of the boundary, on either side. Clipping starts 1 px inside the approved 12 px
       gap, so a settled card is never shaved and a scrolling one is still cut before the labels. */
    --w1c-clip:clamp(-24px, calc(var(--w1c-sx) - var(--w1c-i) * var(--w1c-pitch) - 1px), var(--w1c-card-col));
    clip-path:inset(-24px -24px -24px var(--w1c-clip))}
  [dir="rtl"] .cmp-journey .w1c-scroll .cx-rail>.cx-card,
  [dir="rtl"] .cmp-journey .w1c-scroll .w1c-row>.w1c-cell{
    clip-path:inset(-24px var(--w1c-clip) -24px -24px)}
  /* ⚠ § 43 review item — no Rev6 frame draws a D11 structural warning at 3–4 projects. Kept in its
     governed slot, pinned to the leading edge and held to the visible width so it neither scrolls
     away nor widens the region. ⛔ No typographic value is changed. */
  .cmp-journey .w1c-scroll .w1c-note{position:sticky; inset-inline-start:0; max-inline-size:100cqi;
    box-sizing:border-box}
}

/* ══ § 58 · OWNER DECISION (15 Sep 2026) — AMOUNT TOGETHER ═══════════════════════════════════════════════
   🔒 "Keep each comparison amount, magnitude and currency on one line. Ranges may break at the dash, never inside an amount.
   No value, wording, precision or layout-breakpoint changes. Keep project workspaces untouched."
   `render/amount_together.js` wraps each money unit of a comparison answer in `.cx-amt` (text unchanged) — ⛔ never inside `.wsroot`,
   so this rule never reaches the project workspace. ⛔ No breakpoint, size, spacing or colour is changed. */
.cmp-journey .cx-amt{white-space:nowrap}
