/* Dal — Alpha Guest website, Step 16A. The Dal-native white-and-purple system exactly as the
   approved DN_* screens render it (STEP_16A_FINAL_GAPS_CLOSED_DAL_NATIVE_2026-09-03.html), with
   the FINAL OWNER RULING W-1 … W-6 and FC-1 … FC-5 applied.
   ⛔ No icon library, no inline SVG, no emoji, no Unicode icon glyph, no CSS-drawn icon: every state
      is carried by governed TEXT + colour + boundary. ⛔ No warm cast, no warm-tinted shadow.
   ⛔ The only typeface is the locked, self-hosted DejaVu Sans, 400 and 700 — nothing else is
      named, no other weight is requested, nothing is synthesised. */

/* ── the locked family (OWNER RULING FC-2: font-display swap on both faces, both preloaded) ── */
@font-face{font-family:"DejaVu Sans";font-style:normal;font-weight:400;font-display:swap;
  src:url("/assets/fonts/dejavu-sans/DejaVuSans.woff2") format("woff2")}
@font-face{font-family:"DejaVu Sans";font-style:normal;font-weight:700;font-display:swap;
  src:url("/assets/fonts/dejavu-sans/DejaVuSans-Bold.woff2") format("woff2")}

/* ══ DAL-NATIVE TOKENS (FABLE_STEP16A_TOKEN_CONTRACT.tsv — every value screen-verified) ══ */
:root{
  --canvas:#FFFFFF; --surface:#FFFFFF;
  --tint:#f5f1ff; --tint-2:#fcfbfe;
  --line:#e7e1f2; --hair:#f0ecf7; --line-accent:#d9cff0;
  --ink:#17151d; --ink-2:#443f4e; --ink-3:#706d78;
  --purple:#6d47e1; --purple-hover:#5433c9; --purple-deep:#4a2bb0; --focus:#b7a4f4;
  --ok:#0d6b45; --ok-bg:#eefaf4; --ok-line:#cbe9db;
  --warn:#8a5300; --warn-bg:#fff8ee; --warn-line:#f0e0c6;
  --err:#a3231f; --err-bg:#fdeeed; --err-line:#f3d2d0;
  --info:#4a2bb0; --info-bg:#f5f1ff; --info-line:#ddd3f7;
  --r-s:10px; --r-m:14px; --r-l:18px; --r-pill:999px;
  --lift-1:0 1px 2px rgba(23,21,29,.04);
  --lift-2:0 4px 20px -2px rgba(109,71,225,.06);
  --lift-3:0 12px 32px -4px rgba(109,71,225,.10);
  --font:"DejaVu Sans",sans-serif;
  --font-ar:"DejaVu Sans",sans-serif;
}
/* ⛔ NO synthetic bold, NO synthetic oblique — anywhere, in either direction (FC-5). */
html,body,body[dir=rtl]{font-synthesis:none;font-synthesis-weight:none;font-synthesis-style:none}

*{box-sizing:border-box}
html,body{margin:0;padding:0;min-height:100%}
body{background:var(--canvas);color:var(--ink-2);font-family:var(--font);font-size:15px;
  line-height:1.55;-webkit-font-smoothing:antialiased;overflow-x:hidden}
body[dir=rtl]{font-family:var(--font-ar)}
button,input{font:inherit}
.app{min-height:100vh}
.shell{position:relative;min-height:100vh;display:flex;flex-direction:column}
.main{flex:1;display:flex;flex-direction:column;min-width:0}
.shell>*:not(.bg){position:relative;z-index:1}
.bg{position:absolute;inset:0;pointer-events:none;z-index:0}
.bg .wash{position:absolute;left:0;right:0;top:0;height:420px;
  background:radial-gradient(120% 100% at 50% -20%, rgba(109,71,225,.05), rgba(109,71,225,0) 70%)}
.vh{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}

/* ── header (global-header: brand · map toggle · language) ────────────────── */
.hdr{padding:8px 16px 0;flex:0 0 auto}
.bar{display:flex;align-items:center;gap:8px;min-height:52px}
/* 🔒 the wordmark is the APPROVED dal_logo.png (1366×300) at the locked 22px cap height */
.brandimg{display:block;height:22px;width:auto;max-width:100px}
.brand{display:inline-flex;align-items:center;min-height:44px;min-width:44px;font-size:1.16rem;
  font-weight:700;letter-spacing:-.02em;color:var(--ink);text-decoration:none}
.sp{flex:1}
.ctl{display:inline-flex;align-items:center;justify-content:center;gap:6px;min-height:44px;
  min-width:44px;padding:0 13px;border-radius:var(--r-pill);border:1px solid var(--line);
  background:var(--surface);color:var(--ink-2);font:inherit;font-size:.79rem;font-weight:700;
  cursor:pointer;text-decoration:none;white-space:nowrap}
.ctl:hover{border-color:var(--line-accent);color:var(--ink)}
.ctl.on{background:var(--purple);border-color:var(--purple);color:#fff}

/* ── landing ─────────────────────────────────────────────────────────────── */
.entry{flex:1;display:flex;flex-direction:column;padding:0 16px 24px}
h1{margin:6px 0 0;font-size:28px;line-height:1.18;letter-spacing:-.022em;font-weight:700;
  color:var(--ink);text-wrap:balance}
body[dir=rtl] h1{font-weight:700;line-height:1.34;letter-spacing:normal}
.sup{margin:10px 0 0;font-size:.9rem;line-height:1.5;color:var(--ink-3);max-width:42ch}
.composer-wrap{margin-top:18px}
.composer{display:flex;align-items:center;gap:9px;background:var(--surface);margin:0;
  border:1.5px solid var(--line);border-radius:15px;padding:7px 7px 7px 15px;box-shadow:var(--lift-3);
  transition:border-color 200ms ease, box-shadow 200ms ease}
body[dir=rtl] .composer{padding:7px 15px 7px 7px}
.composer:focus-within{border-color:var(--purple);box-shadow:0 0 0 3px var(--tint),var(--lift-3)}
/* the real input, drawn exactly like the locked placeholder line */
.ph{flex:1;min-width:0;width:100%;height:44px;margin:0;padding:0;border:0;outline:0;background:transparent;
  font:inherit;font-size:.94rem;line-height:1.55;color:var(--ink);white-space:nowrap;text-overflow:clip;text-align:start}
.ph::placeholder{color:var(--ink-3);opacity:1}
/* 🔒 The frozen mobile string must not truncate. Width is reclaimed from SPACING only —
   ⛔ the input type is never stepped down. */
@media (max-width:420px){
  .entry{padding-inline:14px}
  .hdr{padding-inline:14px}
  .askbar{padding-inline:14px}
  .composer{padding:7px 4px 7px 12px;gap:8px}
  body[dir=rtl] .composer{padding:7px 12px 7px 4px}
}
.go{flex:0 0 44px;width:44px;height:44px;display:grid;place-items:center;border:0;padding:0;
  border-radius:11px;background:var(--purple);color:#fff;cursor:pointer;font:inherit;font-size:13.333px;
  font-weight:400;box-shadow:0 6px 14px rgba(109,71,225,.28);overflow:hidden}   /* the UA control size the frame painted, in the locked face */
.go:hover{background:var(--purple-deep)}
.hint{display:none}
.wide{margin-top:20px}
.railhead{display:flex;align-items:center;justify-content:space-between;gap:12px}
.railhead h2{margin:0;font-size:1.01rem;font-weight:700;letter-spacing:-.012em;color:var(--ink)}
.railnav{display:none;gap:8px}
/* 🔒 W-5 — text-only carousel controls sized to their label, 44px minimum target. */
.navb{min-width:44px;height:44px;display:grid;place-items:center;padding:0 14px;
  white-space:nowrap;font:inherit;font-size:.8rem;cursor:pointer;
  border:1px solid var(--line);border-radius:var(--r-pill);background:var(--surface);color:var(--ink-2)}
.navb[aria-disabled=true]{opacity:.45}

/* ── the journey rail — manual snap, visible next-card peek, no autoplay ───── */
.rail{display:flex;gap:10px;margin-top:12px;overflow-x:auto;scroll-snap-type:x mandatory;
  scroll-behavior:smooth;-webkit-overflow-scrolling:touch;padding-bottom:8px;scrollbar-width:none}
.rail::-webkit-scrollbar{height:0}
.jcard{flex:0 0 84%;min-width:0;scroll-snap-align:start;display:flex;background:var(--surface);
  border:1px solid var(--line);border-radius:var(--r-l);overflow:hidden;box-shadow:var(--lift-2);
  transition:transform 200ms ease, box-shadow 200ms ease}
/* 🔒 W-6 — no spine band: the card body occupies the whole card boundary. */
.jbody{flex:1;min-width:0;display:flex;flex-direction:column;padding:15px 14px}
.jt{margin:0 0 6px;font-size:.98rem;line-height:1.3;font-weight:700;letter-spacing:-.012em;color:var(--ink)}
.jd{flex:1;margin:0 0 10px;font-size:.83rem;line-height:1.5;color:var(--ink-3)}
.prow{list-style:none;margin:0;padding:0;border-top:1px solid var(--hair)}
/* ⌛ 14 Sep 2026 — DECISION_REGISTER § 53.7: TWO PROMPTS ON EVERY CARD, in English and Arabic, desktop and mobile (the
   owner's amendment to the locked landing layout). The second prompt `.p2` is no longer hidden below the desktop band or
   in Arabic, so the rule that hid it is removed. ⛔ The card, pill and rail treatments are unchanged. */
.pfill{display:flex;align-items:center;gap:0;width:100%;min-height:44px;padding:8px;
  margin-inline:-8px;border:0;border-radius:var(--r-s);background:transparent;font:inherit;
  font-size:.81rem;color:var(--ink-2);text-align:start;cursor:text}
.pfill:hover{background:var(--tint-2)}
.railprog{display:flex;gap:5px;margin-top:10px}
.railprog i{display:block;height:3px;width:14px;border-radius:99px;background:var(--line)}
.railprog i.on{background:var(--purple);width:22px}
.trust{display:flex;align-items:flex-start;gap:0;margin:18px 0 0;font-size:.75rem;line-height:1.45;
  color:var(--ink-3);max-width:52ch}

/* ── conversation ────────────────────────────────────────────────────────── */
.conv{flex:1;display:flex;flex-direction:column;gap:14px;padding:14px 16px 20px}
.turn{display:flex;flex-direction:column;gap:6px;outline:0}
.turn:focus-visible{outline:3px solid var(--focus);outline-offset:2px;border-radius:12px}
.who{font-size:.66rem;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3)}
body[dir=rtl] .who{letter-spacing:normal;text-transform:none;font-size:.74rem}
.umsg{align-self:flex-end;max-width:min(86%,600px);background:var(--tint);border:1px solid var(--line);
  border-radius:16px 16px 4px 16px;padding:11px 14px;color:var(--ink);font-size:.9rem;overflow-wrap:anywhere}
body[dir=rtl] .umsg{align-self:flex-start;border-radius:16px 16px 16px 4px}
/* W4 DJ-W4-S1 · the mixed-value isolates (arabic-mixed-value-rendering.md clauses 2-7), applied
   at render time by render/isolation.js — ⛔ nothing stored. `.num` is ONE LTR isolate for a
   complete numeric expression; `.mv` is the clause-4 wrapper, and it takes the direction of the
   BLOCK it sits in (`:dir()`), ⛔ not the page's, so an Arabic part inside an English frame keeps
   Arabic reading order. */
.num{direction:ltr;unicode-bidi:isolate;font-variant-numeric:tabular-nums;white-space:nowrap}
.mv{unicode-bidi:isolate;white-space:nowrap}
.mv:dir(rtl){direction:rtl}
.mv:dir(ltr){direction:ltr}
.dmsg{align-self:stretch;background:var(--surface);border:1px solid var(--line);border-radius:16px;
  padding:14px;box-shadow:var(--lift-1);min-width:0}
.dmsg>*:first-child{margin-top:0}
.dmsg>*:last-child{margin-bottom:0}
.dmsg+.dmsg{margin-top:10px}
.status{color:var(--ink-3);font-size:.9rem}
.note{color:var(--ink-3);font-size:.74rem;line-height:1.45;margin:10px 0 0}
.muted{color:var(--ink-3);font-size:.8rem}
/* the follow-up composer on /ask (the locked frames are presentation-only; the manifest's own
   entry actions submit from /ask, so the composer is pinned to the bottom of the conversation) */
.askbar{position:fixed;bottom:0;left:0;right:0;z-index:2;padding:8px 16px 14px;background:var(--canvas)}
.shell[data-route=ask] .conv,.shell[data-route=compare] .conv{padding-bottom:84px}
.askbar .composer{max-width:600px}

/* ── structured families (render/structured.js UNCHANGED; the frame adds the semantic chip) ── */
.sf{position:relative;display:grid;grid-template-columns:minmax(0,1fr) auto;column-gap:9px;
  background:var(--surface);border:1px solid var(--line);border-radius:var(--r-m);padding:14px;
  box-shadow:var(--lift-1)}
.sf+.sf{margin-top:10px}
/* 🔒 W4 Multipart (§ 72.6, DJ-W4-M1, H-M1 · render/multipart.js) · each part is the shell's `.sf`
   card as the approved frame draws it — a plain block (⛔ not the chip grid: a part has no chip),
   headed by the shared `.sfh h3` (ruling 7). ⛔ No Multipart style of its own beyond that. */
.mp>.sf.part{display:block}
.mp .sfh{display:flex;align-items:center;gap:9px;margin-bottom:10px}
.sf>.state{grid-column:2;grid-row:1;align-self:center;margin-bottom:10px}
.sf>.block-structured{display:contents}
.sf>.block-structured>*{grid-column:1/-1;min-width:0}
.sf>.block-structured>h2{grid-column:1;grid-row:1;margin:0 0 10px;font-size:.92rem;font-weight:700;
  color:var(--ink);align-self:center}
.sf h2{letter-spacing:-.01em}   /* low specificity, so the final RTL rule wins */
.state{font-size:.66rem;font-weight:700;letter-spacing:.05em;
  padding:3px 8px;border-radius:var(--r-pill);text-transform:uppercase}
body[dir=rtl] .state{letter-spacing:normal;text-transform:none}
.state.sup{background:var(--ok-bg);color:var(--ok);border:1px solid var(--ok-line)}
.state.una{background:var(--warn-bg);color:var(--warn);border:1px solid var(--warn-line)}
.state.ref{background:var(--err-bg);color:var(--err);border:1px solid var(--err-line)}
.facts{margin:0;display:flex;flex-direction:column}
.fact{display:flex;align-items:baseline;justify-content:space-between;gap:14px;padding:8px 0;
  border-top:1px solid var(--hair)}
.fact:first-child{border-top:0;padding-top:0}
.fact dt{margin:0;font-size:.81rem;color:var(--ink-3)}
.fact dd{margin:0;font-size:.87rem;font-weight:700;color:var(--ink);text-align:end;font-variant-numeric:tabular-nums}
.sub{margin-top:10px;padding-top:10px;border-top:1px solid var(--hair)}
.sub h3{margin:0 0 6px;font-size:.76rem;font-weight:700;color:var(--ink-3);letter-spacing:.04em;
  text-transform:uppercase}
body[dir=rtl] .sub h3{letter-spacing:normal;text-transform:none}
/* the Step 16 structured multipart's `article.part` (render/structured.js). 🔒 W4 remaining 140 (23 Sep 2026) —
   ⛔ never the W4 Multipart part card (`section.sf.part`, render/multipart.js): these two rules used to reach it and
   overrode the approved `.sf` card — a --hair top rule, 10 px margin/padding, and NO top border or padding at all on
   a first part, which is exactly UI-REF-005 (all parts refused, no completeness line). Measured against the approved
   W4-MP-{EN,AR}-{D,M} frames in one Chromium: the card is now the frame's `.sf`. */
.part:not(.sf){margin-top:10px;padding-top:10px;border-top:1px solid var(--hair)}
.part:not(.sf):first-child{margin-top:0;padding-top:0;border-top:0}
.part>h3{margin:0 0 8px;font-size:.84rem;font-weight:700;color:var(--ink)}
/* an unavailable family: the governed sentence inside the amber boundary */
.sf[data-state=unavailable] .block-structured>.note{margin-top:0;border-radius:var(--r-m);padding:12px 13px;
  font-size:.83rem;line-height:1.5;background:var(--warn-bg);border:1px solid var(--warn-line);color:var(--ink-2)}
.sf[data-state=refused] .block-refusal{margin-top:0}
.chip{display:inline-block;font-size:.71rem;font-weight:700;padding:2px 8px;border-radius:var(--r-pill);
  background:var(--ok-bg);color:var(--ok);border:1px solid var(--ok-line)}
.chip.q{background:var(--warn-bg);color:var(--warn);border-color:var(--warn-line)}

/* ── semantic notices — governed TEXT + colour + boundary; ⛔ no status icon ── */
.notice{display:flex;gap:0;align-items:flex-start;border-radius:var(--r-m);padding:12px 13px;
  font-size:.83rem;line-height:1.5}
.notice b{display:block;font-size:.8rem;margin-bottom:2px}
.notice.i{background:var(--info-bg);border:1px solid var(--info-line);color:var(--info)}
.notice.w{background:var(--warn-bg);border:1px solid var(--warn-line);color:var(--warn)}
.notice.e{background:var(--err-bg);border:1px solid var(--err-line);color:var(--err)}
.notice p{margin:0;color:var(--ink-2)}
.notice ul{margin:6px 0 0;padding-inline-start:18px;color:var(--ink-2)}
.notice>div{min-width:0}
/* the governed refusal is the red treatment (refusal-banner): the locked DN_D-REF notice — a bold
   registry heading where one exists, the service's sentence — with the offered replies below it */
.block-refusal{padding:0;border:0;background:none}
.block-refusal .notice.e .refusal{margin:0;color:var(--ink-2);white-space:pre-line}
.block-refusal+.sf,.block-refusal+.block{margin-top:10px}
/* 🔒 W4 remaining 140 (23 Sep 2026) — UI-PCMP-009 (§ 72.9, the corrected 20): the served clarification block sits
   directly beneath the refusal notice, spaced only by its question's own `.4em` paragraph margin, exactly as the
   approved W4-PCMP009 frames draw it. ⛔ No earlier composition places `.block-clarify` after a refusal. */
.block-refusal+.block-clarify{margin-top:0}
/* 🔒 W4 remaining 140 — the named W5 refusal's `.alt` control (UI-NRANK-024, § 72.9 / § 72.10) keeps the UA `normal`
   line box the approved frames draw; the global `button{font:inherit}` reset would otherwise hand it the prose
   line-height. ⛔ Declared HERE: `w5_refusal.css` is byte-pinned by the approved packages. Button box and text
   position are unchanged (measured: text centre 178.31 vs 178.32 px). */
.block-refusal .alt{line-height:normal}
.identity-names{margin:8px 0 0}
/* one Dal message holds every consecutive reply (DN_D-REF: refusal + two unavailable families).
   🔒 W4 DJ-W4-C1 (§ 72.6): each turn-scoped .dpart is separated from its neighbour by the shell's
   own hairline. */
.dpart+.dpart{margin-top:14px;padding-top:14px;border-top:1px solid var(--hair)}
.dpart>.answer>*:first-child{margin-top:0}
/* 🔒 W4 DJ-W4-S2 (§ 72.6, rev-2 owner ruling 5) · the follow-up row IS the LOCKED FOLLOW_UP_PILL_ROW
   control, values copied onto shell tokens: at most THREE pills (render/pill_row.js), the 1 px
   divider above the row, .84rem · 600 · purple-deep · 8/15 padding · line-height normal → 33 px at
   desktop, ≥ 44 px under 900 px. Bound to the BASE `.followups` selector so both hosts
   (refusal.js, buying_power.js) receive it. ⛔ No disabled state. */
.followups{display:flex;gap:10px;flex-wrap:wrap;margin-top:14px;padding-top:14px;border-top:1px solid var(--line)}
.followups .pill-btn{display:inline-flex;align-items:center;gap:7px;border:1px solid var(--line);
  background:var(--surface);color:var(--purple-deep);border-radius:var(--r-pill);padding:8px 15px;
  font-family:inherit;font-size:.84rem;font-weight:700;line-height:normal;text-align:start;cursor:pointer}
/* ⚠ the locked control declares 600; the locked family ships 400/700 only and synthesis is off, so 600
   PAINTS the 700 face — declared 700 here (01 DJ-W4-S2 "600 → 700"; the font lock admits no 600). */
@media (max-width:899px){.followups .pill-btn{min-height:44px}}
/* H-S1 — the label is ONE inline run: isolates inside a flex control would become flex items */
.followups .pill-btn>.pl{display:inline;min-width:0}
.followups .pill-btn:hover{background:var(--tint);border-color:var(--line-accent)}
.followups .pill-btn:focus-visible{outline:2px solid var(--purple);outline-offset:2px}
.followups .pill-btn[aria-pressed=true]{background:var(--purple);border-color:var(--purple);color:#fff}
/* H-S7 — the locked role-word slot, DORMANT: ⛔ no .role element is emitted until canonical EN/AR
   role copy exists AND the service supplies the role explicitly */
.followups .pill-btn .role{font-size:.6rem;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3)}
.followups .pill-btn[aria-pressed=true] .role{color:#e5dbff}

/* ── hero / project card (project-result-card + the deliberate entry) ──────── */
.hero-card{background:var(--surface);border:1px solid var(--line);border-radius:var(--r-l);
  overflow:hidden;box-shadow:var(--lift-2)}
.hero-card[data-entry]{cursor:pointer}
.hc-media{background:var(--surface);display:flex;align-items:flex-end;gap:10px;padding:15px 15px 12px;
  border-bottom:1px solid var(--line)}
.hc-media h2{margin:0;font-size:1.06rem;font-weight:700;color:var(--ink);letter-spacing:-.015em;flex:1;min-width:0}
.hc-body{padding:13px 14px}
.hc-sub{margin:0 0 10px;font-size:.8rem;color:var(--ink-3)}
.hc-body .note{margin-top:8px}
.amenities{list-style:none;margin:10px 0 0;padding:0;display:flex;flex-wrap:wrap;gap:6px}
.amenities li{font-size:.74rem;padding:3px 9px;border:1px solid var(--line);border-radius:var(--r-pill);color:var(--ink-2)}
.badge{display:inline-block;font-size:.71rem;font-weight:700;padding:2px 8px;border-radius:var(--r-pill);
  background:var(--tint);color:var(--purple-deep);border:1px solid var(--info-line);white-space:nowrap}
.actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px}
.btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;min-height:44px;
  padding:0 18px;border-radius:var(--r-m);font:inherit;font-size:.84rem;font-weight:700;cursor:pointer;
  border:1px solid var(--line);background:var(--surface);color:var(--ink);white-space:nowrap;text-decoration:none}
.btn.primary{background:var(--purple);border-color:var(--purple);color:#fff;
  box-shadow:0 6px 14px rgba(109,71,225,.24)}
.btn.primary:hover{background:var(--purple-deep)}
.btn:focus-visible,.ctl:focus-visible,.go:focus-visible,.navb:focus-visible,.pfill:focus-visible,
.brand:focus-visible,.tab:focus-visible,.pill-btn:focus-visible,.cardlink:focus-visible,.cfgopt:focus-visible,
.ph:focus-visible,summary:focus-visible{outline:3px solid var(--focus);outline-offset:2px}
.overview-section p{margin:10px 0 0;font-size:.86rem}
.rail-intro{margin:0 0 10px;font-size:.86rem;color:var(--ink-3)}

/* ── the Hero Project Card V2 (the component of record for a directly named project, CS-1):
   the placeholder banner carrying the full name, then the metadata line, availability, price,
   AD-023, the AD-028 handover line — and the deliberate entry */
.hero-card.v2{border-radius:24px}
.hc-ph{height:150px;display:flex;align-items:center;justify-content:center;padding:10px 12px;
  background:linear-gradient(135deg,#efeaf9,#f7f4fd)}
.hc-ph h2{margin:0;font-size:1.15rem;font-weight:700;color:var(--ink);text-align:center;line-height:1.3;letter-spacing:-.015em}
.hc-body.v2{display:flex;flex-direction:column;gap:6px;padding:11px 12px}
.hc-body.v2>p{margin:0}
.hc-meta{display:flex;align-items:center;gap:7px;font-size:.78rem;color:var(--ink-2);flex-wrap:wrap}
.hc-asset{display:inline-flex;align-items:center;gap:5px;background:var(--tint);border-radius:6px;padding:2px 8px;
  font-weight:700;color:var(--purple-deep);font-size:.75rem}
.hc-asset .ico{margin-inline-end:0;width:14px;height:14px;vertical-align:-2px}
.hc-avail{font-size:.78rem;color:var(--ink-2)}
.hc-price{font-size:.82rem;font-weight:700;color:var(--ink)}
.hc-pnote{font-size:.72rem;color:var(--ink-3)}
.hc-dis{font-size:.76rem;color:var(--ink-3);line-height:1.5;border-inline-start:2px solid var(--line);padding-inline-start:9px}
.hc-body.v2 .note{margin-top:2px}
.hc-body.v2 .actions{margin-top:6px}

/* ── Q9 discovery answer (render/rail.js) — the locked DN_D-PROJ composition: the lead line, one
   project card per project, its developer-stated price block under it ── */
.block-rail h2{margin:0 0 4px;font-size:.92rem;color:var(--ink)}
.railitem+.railitem{margin-top:10px}
.railitem .hero-card+.sf{margin-top:10px}
.hero-card.dn .hc-media h2{font-size:1.06rem}
.empty{margin:8px 0 0;font-size:.86rem}

/* ── tables and buying-power blocks (existing renderers, restyled) ─────────── */
.block h2{font-size:.95rem;color:var(--ink);margin:.2em 0 .4em}
.block h3{font-size:.86rem;color:var(--ink);margin:1em 0 .3em}
.flag{font-size:.86rem}
.scroll-x{overflow-x:auto;max-width:100%}
table{border-collapse:collapse;width:100%;font-size:.86rem}
th,td{padding:6px 8px;border-bottom:1px solid var(--hair);text-align:start;vertical-align:top}
th{color:var(--ink)}
.al-end{text-align:end}
td.rank,th.rank{width:2.2em;color:var(--ink-3)}
.kv{display:flex;justify-content:space-between;gap:12px;padding:7px 0;border-top:1px solid var(--hair);font-size:.82rem}
.kv:first-child{border-top:0}
.kv .value{font-weight:700;color:var(--ink);text-align:end;font-variant-numeric:tabular-nums}
.pill{display:inline-block;padding:3px 10px;border-radius:var(--r-pill);background:var(--ok-bg);color:var(--ok);
  border:1px solid var(--ok-line);font-size:.8rem;font-weight:700}
.units{list-style:none;padding:0;margin:6px 0}
.units li{padding:2px 0}
/* ── Buying Power — the approved composition (review_html/buying_power_preview.html, case 1):
   ⛔ THE VALUE NEVER WRAPS; THE LABEL ABSORBS IT (Sanjay, 7 Aug 2026) ── */
.block-bp{max-width:380px}
.bp-title,.bp-sec{font-size:.8rem;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:var(--ink-3)}
.bp-title{margin-bottom:10px}
.bp-sec{font-size:.73rem;margin:20px 0 8px}
body[dir=rtl] .bp-title,body[dir=rtl] .bp-sec{text-transform:none}
.bp-hero,.bp-kv,.bp-range{display:flex;justify-content:space-between;align-items:baseline;gap:10px;padding:3px 0}
.bp-hero .bp-lab,.bp-kv .bp-lab,.bp-range .bp-lab{min-width:0;flex:1 1 auto}
.bp-hero .bp-val,.bp-kv .bp-val,.bp-range .bp-val{flex:0 0 auto;white-space:nowrap;text-align:end}
.bp-hero-1 .bp-val{font-size:1.65rem;font-weight:700;letter-spacing:-.02em;color:var(--ink)}
body[dir=rtl] .bp-hero-1 .bp-val{letter-spacing:normal}
.bp-hero-1 .bp-lab{font-weight:700;color:var(--ink)}
.bp-lab{color:var(--ink-3);font-size:.9rem;line-height:1.3}
.bp-val{font-variant-numeric:tabular-nums;font-weight:700;font-size:1.13rem;color:var(--ink)}
.bp-assume{margin:12px 0 4px;padding-top:11px;border-top:1px solid var(--line);color:var(--ink-3);font-size:.83rem;line-height:1.5}
.bp-asset{display:flex;gap:11px;padding:11px 0;border-bottom:1px solid var(--line)}
.bp-asset+.bp-range{border-top:0;margin-top:2px}
.bp-asset .ico{flex:none;width:20px;height:20px;margin:1px 0 0;vertical-align:0}
.bp-abody{min-width:0}
.bp-alab{font-weight:700;font-size:1rem;color:var(--ink)}
.bp-mut{color:var(--ink-3);font-size:.87rem}
.bp-count{font-size:.87rem;font-weight:700;font-variant-numeric:tabular-nums;color:var(--ink)}
.bp-names{font-size:.87rem;color:var(--ink-2)}
.bp-range{margin-top:12px;padding-top:10px;border-top:1px solid var(--line)}
.bp-proj{font-size:1.13rem;font-weight:700;margin-top:4px;color:var(--ink)}
.bp-units{margin:12px 0;font-size:.93rem;line-height:1.9}
.bp-fresh{margin:8px 0 2px;font-size:.87rem;font-weight:700;font-variant-numeric:tabular-nums}
.bp-stale{font-weight:400;color:var(--ink-3)}
.bp-pill,.bp-badge{margin-bottom:10px}
.handoff{margin-top:12px}
.ask{margin:0;font-size:.9rem;color:var(--ink)}
.narrative p{margin:.4em 0}
/* 🔒 W4 DJ-W4-Q1 (§ 72.6, rev-2 ruling 7) · a clarification question is RESPONSE PROSE: inside
   `.narrative` it takes the shared base prose (15 px · 1.55 · ink-2), ⛔ not the legacy `.ask` tier,
   and ⛔ no toned band (DJ-W4-Q2). The W4 question block is not the Buying Power card, so the card's
   380 px cap does not apply to it. ⛔ The legacy `.ask` (UI-AFF-001, not READY) is untouched. */
.narrative>p.ask{margin:.4em 0;font-size:inherit;color:inherit}
.block-bp:has(>.narrative>p.ask){max-width:none}
.narrative pre.code{white-space:pre-wrap;font:inherit;margin:.4em 0;padding:8px 10px;border:1px solid var(--hair);border-radius:var(--r-s);background:var(--tint-2)}
.plain{white-space:pre-wrap;font:inherit;margin:0}
.block-ptco h2{font-size:.95rem;color:var(--ink);margin:.2em 0 .6em}
.block-ptco .panel+.panel,.block-ptco .panel+.notice{margin-top:10px}

/* ── workspace (workspace-shell · tabs · panels) ─────────────────────────────── */
.ws{flex:1;display:flex;flex-direction:column;background:var(--canvas)}
.wshead{padding:12px 16px;border-bottom:1px solid var(--line);background:var(--surface)}

/* ══ THE ONE COMMON PROJECT HEADER — the consolidated workspace shell ═══════════════════
   🔒 Owner-visually-approved 9 Sep 2026 and admitted for implementation the same day.
   Every declaration below is carried VERBATIM from the locked DAL_INSIGHTS_COMPLETE_10C
   header (evidence: the approved package's HEADER_CSS_PROVENANCE.tsv, 28 rows, all
   "byte-identical; only the selector gained the .ws scope"). ⛔ Nothing here is a new
   design value; the artefact's own token names are mapped to this client's equivalents:
     --paper -> --surface (#FFFFFF) · --body -> --ink-2 (#443f4e) · --muted -> --ink-3
     (#706d78) · --soft -> --tint (#f5f1ff) · --r-lg -> 16px (the artefact's own radius;
     this client's --r-l is 18px, so the literal is used rather than drifting the shell).
   ⚠ MOBILE-FIRST. The artefact ships two static bands and marks the narrow one `.handset`;
   here the handset values are the BASE and the desktop values are restored at the client's
   existing 900px breakpoint. VP3 (390) takes the base; VP2 (1000) and VP1 (1440) take the
   desktop block — which is exactly what gate G-11d asserts. */
.ws .wshell{border:1px solid var(--line);border-radius:16px;background:var(--surface);overflow:hidden}
.ws .wshell .wtop{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;padding:13px 14px;
  /* 🔴 B-5 — ONE OF THE TWO BEHAVIOURS THE NEW SHELL ENTRY SUPERSEDES. The locked header
     shipped `flex-wrap:wrap`, which let the classification badge wrap to a second line on a
     handset whenever the project name happened to be long. The badge now stays on the
     identity row at the LOGICAL INLINE END — right in EN, left in AR — at EVERY band, and
     the identity group shrinks and wraps its OWN name and neighbourhood instead.
     ⛔ No breakpoint guess, no width guess, no string-length dependence. */
  flex-wrap:nowrap}
.ws .wshell .wid{display:flex;align-items:center;gap:10px;flex-wrap:wrap;min-width:0;flex:1 1 auto}
/* ⚠ INTENTIONAL DIFFERENCE FROM THE ARTEFACT, and the only one in this block. The artefact
   declares a heavier weight than 700 on `.wname`, `.status` and `.brief-text b`, and a
   semi-bold on the two separators. This client ships exactly TWO faces — DejaVu Sans 400
   and 700 — and forbids synthesis (FC-5 `font-synthesis:none`); the approved frames loaded
   those same two faces, so every one of those declarations already RENDERED at 700 there.
   They are declared as 700 here so the stylesheet states what the loaded faces can actually
   draw. ⛔ The RENDERED weight is unchanged; QA-32/33/34 pins this constraint. */
.ws .wshell .wname{font-size:1.06rem;font-weight:700;letter-spacing:-.015em;color:var(--ink)}
.ws .wshell .wnb{font-size:.86rem;font-weight:700;color:var(--purple-deep)}
/* the separator is the header's OWN rule — ⛔ never a literal character in the payload string */
.ws .wshell .wnb::before{content:"\00B7";margin-inline-end:8px;color:var(--ink-3);font-weight:700}
/* render-time numeric isolation for RTL (IR-06 / IR-07) — ⛔ no stored bidi control character */
.ws .wshell .wnum{direction:ltr;unicode-bidi:isolate;font-variant-numeric:tabular-nums}
/* the governed classification badge — `flex:none` is what keeps it at the inline end */
.ws .wshell .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(--tint);color:var(--purple-deep);
  border:1px solid #e0d6ff;font-size:.73rem;font-weight:700;letter-spacing:.03em;white-space:nowrap}
.ws .wshell .status svg{flex:none;width:14px;height:14px}
body[dir=rtl] .ws .wshell .status{font-weight:700}
.ws .wshell > .brief{display:flex;align-items:flex-start;gap:13px;padding:2px 13px 14px}
.ws .wshell .brief-body{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:7px}
.ws .wshell .brief-text{margin:0;font-size:.98rem;line-height:1.55;color:var(--ink-2);max-width:74ch}
body[dir=rtl] .ws .wshell .brief-text{font-size:.97rem}
.ws .wshell .brief-text b{color:var(--ink);font-weight:700}
/* the governed middot between meta groups — ⛔ EXCEPT after a group that ends a sentence
   (the developer clause), which takes a plain 8px space and no middot (H-2) */
.ws .wshell .brief-text .hgrp{display:inline}
.ws .wshell .brief-text .hgrp+.hgrp::before{content:"\00B7";margin-inline:8px;color:var(--ink-3);font-weight:700}
.ws .wshell .brief-text .hgrp.sent+.hgrp::before{content:none;margin:0}
.ws .wshell .brief-text .hgrp.sent+.hgrp{margin-inline-start:8px}
.ws .wshell .amenities{margin:0;padding:0;list-style:none;display:flex;flex-wrap:wrap;align-items:center;
  gap:8px 16px;font-size:.8rem;color:var(--ink-3)}
.ws .wshell .amenities li{display:flex;align-items:center;gap:7px;white-space:nowrap}
/* 🔒 OWNER RULING, 10 Sep 2026 — the amenity icons carry the APPROVED PURPLE TOKEN.
   The approved library is authored with `stroke="currentColor"` and the approved frames
   colour it from the page (`.am-ic{color:var(--purple)}`). An <img>-referenced SVG is an
   isolated document whose `currentColor` resolves to BLACK and cannot inherit the page's —
   which is why these rendered black. The mask uses THE SAME APPROVED FILE for its geometry
   and paints it with the governed token: ⛔ no filter, ⛔ no hue rotation, ⛔ no
   approximation, and ⛔ no artwork modified. The file's URL arrives on the element as
   `--ico`, so this stylesheet stays free of `url()` (QA-44). */
.ws .wshell .amenities .ico{flex:none;width:16px;height:16px;background-color:var(--purple);
  -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}
.ws .wshell .wid .ico{flex:none;width:20px;height:20px;margin-top:1px}
/* equal-width tabs that WRAP and never scroll horizontally */
.tabs{display:flex;gap:6px;margin-top:11px}
.tab{flex:1 1 0;min-width:0;min-height:44px;display:flex;align-items:center;justify-content:center;
  text-align:center;padding:6px 8px;border-radius:var(--r-s);border:1px solid var(--line);
  background:var(--surface);color:var(--ink-2);font:inherit;font-size:.78rem;font-weight:700;
  cursor:pointer;line-height:1.25;overflow-wrap:anywhere}
.tab:hover{border-color:var(--line-accent);color:var(--ink)}
.tab[aria-selected=true]{background:var(--purple);border-color:var(--purple);color:#fff;
  box-shadow:0 4px 12px rgba(109,71,225,.22)}
.wsbody{flex:1;padding:14px 16px 18px;display:flex;flex-direction:column;gap:12px}
.panel{background:var(--surface);border:1px solid var(--line);border-radius:var(--r-m);padding:13px}
.panel h3{margin:0 0 9px;font-size:.85rem;font-weight:700;color:var(--ink);letter-spacing:.01em}
.panel h4{margin:10px 0 4px;font-size:.78rem;font-weight:700;color:var(--ink-3);letter-spacing:.04em;text-transform:uppercase}
body[dir=rtl] .panel h4{letter-spacing:normal;text-transform:none}
.panel p{margin:6px 0 0;font-size:.82rem}
/* OWNER RULING FC-3 — the state chip is pinned to the LOCKED geometry: flex-start with the
   10.00px offset declared, ⛔ never baseline alignment (a baseline drifts with the face). */
.metric{display:flex;align-items:flex-start;gap:9px}
.metric .band{margin-top:10px}
.metric .big{font-size:1.6rem;font-weight:700;color:var(--ink);font-variant-numeric:tabular-nums}
.big{letter-spacing:-.02em}   /* low specificity, so the final RTL rule wins */
.metric .of{color:var(--ink-3);font-size:.8rem;margin-top:10px}
.metric .band{font-size:.74rem;font-weight:700;padding:3px 9px;border-radius:var(--r-pill);
  background:var(--ok-bg);color:var(--ok);border:1px solid var(--ok-line)}
.rows{list-style:none;margin:0;padding:0}
.rows li{display:flex;justify-content:space-between;gap:12px;padding:7px 0;
  border-top:1px solid var(--hair);font-size:.82rem}
.rows li:first-child{border-top:0}
.rows b{color:var(--ink);font-variant-numeric:tabular-nums;text-align:end}
.rows.mt{margin-top:10px}
.rows li.one{justify-content:flex-start}
/* a costed scenario's label row inside the TCO cost rows (label · price), then its figures */
.rows li.scen{padding-top:12px}
.rows li.scen span{font-weight:700;color:var(--ink)}
.rows li:first-child.scen{padding-top:0}
/* the configuration control (tco-price-presentation.md §0.2) IS the metric-row chip: each governed
   option is the frame's `.band` chip inside a transparent 44px target. The target's padding is
   cancelled by its negative margin, so the chip keeps the locked FC-3 geometry (top edge 10.00px
   below the row) and the row keeps the frame's height; the costed option is the green band, the
   others neutral. ⛔ No second row, no new component. */
.cfgopt{display:inline-flex;align-items:center;border:0;background:none;padding:10px 0;margin:0 0 -20px;
  font:inherit;cursor:pointer;color:inherit}
.metric .cfgopt .band{margin-top:0}
.cfgopt[aria-pressed=false] .band{background:var(--surface);color:var(--ink-2);border-color:var(--line)}
.cfgopt[aria-pressed=false]:hover .band{border-color:var(--line-accent);color:var(--ink)}
.backbar{display:flex;align-items:center;gap:8px;padding:8px 16px;background:var(--surface);
  border-bottom:1px solid var(--line)}
/* below 900px the workspace REPLACES the conversation; the originating answer returns via Back */
.split .origin,.wsplit .origin{display:none}
/* 🔒 OWNER RULING, 10 Sep 2026 — the project-workspace consistency rule. The shared shell
   (`.wshead` = the common header + the three-tab strip) has the SAME BOX for every tab at a
   given viewport, language and project. ⛔ Host placement only — no panel interior is touched.
   ⌛ 12 Sep 2026 — DECISION_REGISTER § 30 supersedes this rule's PLACEMENT SENTENCE ONLY. The
   sentence recorded here was "sits OUTSIDE `.wsplit`, so … Any Dal Insights split begins
   BELOW it". The shell now travels INSIDE the project column `.wsc`, so the project header
   stops running across the conversation.
   🔴 THE REQUIREMENT ITSELF IS NOT SUPERSEDED and is still measured. It holds for a different
   reason now: § 25 (11 Sep 2026) put ALL THREE TABS in the split, so the project column is the
   same width whichever tab is selected — and therefore so is the shell. */
.wsplit{flex:1;display:flex;flex-direction:column;min-width:0}
/* the approved asset-type / amenity icons: decorative, beside the governed text they belong to */
.ico{display:inline-block;width:16px;height:16px;vertical-align:-3px;margin-inline-end:5px}
.amenities li .ico{width:14px;height:14px;vertical-align:-2px;margin-inline-end:4px}
.hc-media .badge{flex:0 0 auto;margin-bottom:3px}
details{margin-top:10px}
details>summary{cursor:pointer;font-weight:700;color:var(--ink);font-size:.82rem;min-height:44px;display:flex;align-items:center}
details ul{margin:6px 0 0;padding-inline-start:18px;font-size:.82rem}
/* ── Screen A · project price positioning — the locked 10C rail grammar on the Dal-native tokens.
   The rail colours are the locked artefact's own (orange project rail, purple benchmark rail);
   the chip states map onto the semantic tokens. Endpoint markers are real (empty) elements —
   ⛔ no pseudo-element content, no icon. */
.priced{--orange:#ff6c16;--orange-deep:#d94f00;--track:#eeebf5;--cap-gap:9px;--trk-h:12px;--rail-gap:16px}
.priced .block-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px;flex-wrap:wrap}
.priced .block-head h3{margin:0}
/* the 10C section label: small caps in the brand purple, the unit note beside it */
.priced .block-head h3.block-title{font-size:.78rem;font-weight:700;letter-spacing:.11em;text-transform:uppercase;color:var(--purple)}
body[dir=rtl] .priced .block-head h3.block-title{text-transform:none;letter-spacing:normal}
.priced .block-unit{font-size:.78rem;font-weight:700;color:var(--ink-3)}
.sg{padding:18px 0;border-top:1px solid var(--hair)}
.sg:first-child{border-top:0;padding-top:8px}
.sg:last-child{padding-bottom:0}
.sg-head{margin-bottom:13px;font-size:1rem;font-weight:700;color:var(--ink)}
.sg-head .sz{font-weight:400;color:var(--ink-3)}
.rails{position:relative}
.rails.grid{display:grid;grid-template-columns:100%}
.rails.grid>.rail-cap{grid-column:1;margin-bottom:var(--cap-gap);position:relative;z-index:1}
.rails.grid>.track{grid-column:1;position:relative;z-index:1}
.rails.grid>.track.first{margin-bottom:var(--rail-gap)}
.rails.grid>:nth-child(1){grid-row:1}.rails.grid>:nth-child(2){grid-row:2}.rails.grid>:nth-child(3){grid-row:3}.rails.grid>:nth-child(4){grid-row:4}
.rail-cap{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;min-height:32px}
.rail-name{display:flex;align-items:flex-start;gap:7px;min-width:0;font-size:.79rem;font-weight:700;color:var(--ink-2);
  background:var(--surface);padding-inline-end:8px}
.rail-name .band{display:block;font-size:.72rem;font-weight:400;color:var(--ink-3);font-style:normal}
.dot{flex:none;width:9px;height:9px;border-radius:50%;margin-top:5px}
.dot-o{background:var(--orange)}.dot-p{background:var(--purple)}
.rail-val{flex:none;font-size:.88rem;font-weight:700;font-variant-numeric:tabular-nums;direction:ltr;unicode-bidi:isolate;
  background:var(--surface);padding-inline-start:8px;margin-top:-1px}
.val-o{color:var(--orange-deep)}.val-p{color:var(--purple-deep)}
.rail-val.absent{font-size:.79rem;color:var(--ink-3);font-variant-numeric:normal}
.track{position:relative;height:var(--trk-h);border-radius:var(--r-pill);background:var(--track)}
.track .rbar{position:absolute;top:0;bottom:0;left:var(--lo);width:var(--w);border-radius:var(--r-pill)}
.track .rbar-o{background:var(--orange);box-shadow:inset 0 0 0 1px rgba(217,79,0,.30)}
/* 10C: evidence that is not live inventory (a brochure price) — same bar, hatched fill */
.track .rbar-o.hatched{background:repeating-linear-gradient(135deg,rgba(255,255,255,.62) 0 3px,rgba(255,255,255,0) 3px 7.5px),var(--orange)}
.track .rbar-p{background:var(--purple);box-shadow:inset 0 0 0 1px rgba(74,43,176,.30)}
.track .rbar .mark{position:absolute;top:-4px;bottom:-4px;left:0;width:2.5px;border-radius:2px}
.track .rbar .mark.end{left:auto;right:0}
.track .rbar-o .mark{background:var(--orange-deep)}.track .rbar-p .mark{background:var(--purple-deep)}
.rails.grid>.guide{grid-column:1;grid-row:2/5;position:relative;z-index:0;width:0;justify-self:start;
  margin-inline-start:var(--x);border-inline-start:1px dashed rgba(109,71,225,.42)}
.rails.no-scale{border:1px dashed var(--line);border-radius:var(--r-m);padding:12px 14px}
.rails.no-scale .rail-cap{min-height:20px}
.rails.no-scale .rail-cap+.rail-cap{margin-top:9px}
.rails.no-scale .rail-name,.rails.no-scale .rail-val{background:transparent}
.priced .chip{display:inline-flex;align-items:center;margin-top:13px;padding:5px 12px;border-radius:var(--r-pill);font-size:.76rem;font-weight:700}
.priced .chip.within{background:var(--ok-bg);color:var(--ok);border:1px solid var(--ok-line)}
.priced .chip.partial{background:var(--warn-bg);color:var(--warn);border:1px solid var(--warn-line)}
.priced .chip.none{background:var(--tint-2);color:var(--ink-3);border:1px solid var(--line)}
body[dir=rtl] .track .rbar{left:auto;right:var(--lo)}
body[dir=rtl] .track .rbar .mark{left:auto;right:0}
body[dir=rtl] .track .rbar .mark.end{right:auto;left:0}
/* 🔒 OWNER RULING F-1, 11 September 2026 — THE GUIDE RTL OVERRIDE IS REMOVED.
   ⛔ The rule that stood here was `body[dir=rtl] .rails.grid>.guide{justify-self:end;
   margin-inline-start:0;margin-inline-end:var(--x)}`, and it UNDID the mirroring the generic
   rule above already performs: that rule positions the guide with LOGICAL properties
   (`justify-self:start` + `margin-inline-start:var(--x)`), which flip on their own in RTL.
   The override pinned the guide back to the LTR position, so in Arabic the two benchmark
   guides no longer sat on the benchmark bar's ends.
   ⌛ MEASURED, ⛔ not assumed (`_work_orders/step16a_screen_a_rtl_guide_alignment_correction_
   2026-09-11/evidence/MECHANISM_PROOF.json`): disabling exactly these three declarations live
   moved the worst guide-to-bar error from 955.31 px to 1.01 px at VP1 and from 229.75 px to
   1.00 px at VP3, and the computed style flipped from `justify-self:end`/`margin-inline-end`
   to `justify-self:start`/`margin-inline-start`. ⚠ The ~1 px residual is the guide's own 1 px
   dashed border, which sits on the box's RIGHT edge in RTL — the drawn line is at the box's
   `right`, not its `x`. Measured at the border edge the error is 0.
   ⛔ THE THREE `.rbar` / `.mark` OVERRIDES ABOVE ARE CORRECT AND STAY. The bar is positioned
   with the PHYSICAL `left:var(--lo)`, so it genuinely needs an RTL counterpart; the guide is
   not. ⛔ EN is untouched — this selector never matched it (max error 0.03 px, unchanged). */
.segments .segment{padding:7px 0;border-top:1px solid var(--hair);font-size:.82rem}
.segments .segment:first-child{border-top:0}
.seg-subject{font-weight:700;color:var(--ink)}
.take-list{margin:0;padding-inline-start:18px;font-size:.82rem}
.callout{margin:0;font-size:.82rem}

/* ── map (map-placeholder: governed states, no tile provider) ───────────────── */
.mapwrap{position:relative;border:1px solid var(--line);border-radius:var(--r-m);overflow:hidden;
  background:linear-gradient(160deg,var(--tint),var(--tint-2));height:190px}
.mapgrid{position:absolute;inset:0;opacity:.5;
  background-image:linear-gradient(rgba(109,71,225,.14) 1px,transparent 1px),
    linear-gradient(90deg,rgba(109,71,225,.14) 1px,transparent 1px);background-size:38px 38px}
.maplabel{position:absolute;inset-inline-start:10px;top:10px;background:var(--surface);
  border:1px solid var(--line);border-radius:var(--r-s);padding:5px 9px;font-size:.72rem;
  font-weight:700;color:var(--ink);max-width:calc(100% - 20px)}
.map-notice{margin:8px 0 0;font-size:.76rem;color:var(--ink-3)}
.mapside{padding:14px 16px 20px}
/* the map panel INSIDE a neighbourhood answer (DN_D-NEIGH) */
.mapwrap.inanswer{margin-top:10px;display:block}
.cmp-title{margin:0 0 10px;font-size:.95rem;color:var(--ink)}
.block-compare .sf+.note{margin-top:10px}
.block-compare .actions{margin:12px 0 0;display:flex;gap:8px;flex-wrap:wrap}

/* ── legal routes: mounted, content pending (nothing invented) · not-found ─── */
.legal{flex:1;padding:24px 16px}
/* 🔒 W4 DJ-W4-N1 (§ 72.6, rev-2 ruling 1) · one sentence at the head of the content column, centred,
   in the shared section-heading tier (the `.sfh h3` values; Arabic tracking normal via FC-4) —
   ⛔ no return button, ⛔ no illustration, ⛔ no icon. Only the layout is the family's own. */
.notfound{flex:1;display:flex;justify-content:center;padding:72px 16px 24px}
.notfound p{margin:0;max-width:36ch;text-align:center;font-size:.92rem;font-weight:700;color:var(--ink);letter-spacing:-.01em}
@media (max-width:420px){.notfound{padding-top:48px}}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{transition:none!important;animation:none!important;scroll-behavior:auto!important}
  .rail{scroll-behavior:auto!important}}

/* ══ DESKTOP (≥900px) ══ */
@media (min-width:900px){
  .hdr{padding:16px 48px 0}
  .entry{padding:34px 48px 40px}
  .col{max-width:56ch}
  h1{font-size:clamp(2rem,3.2vw,2.9rem);line-height:1.14;margin-top:0}
  body[dir=rtl] h1{line-height:1.3}
  .sup{font-size:1.05rem;line-height:1.62;max-width:48ch;margin-top:13px}
  .composer-wrap{margin-top:26px;max-width:600px}
  .composer{border-radius:16px;padding:9px 9px 9px 18px}
  body[dir=rtl] .composer{padding:9px 18px 9px 9px}
  .ph{font-size:1rem}
  .hint{display:block;margin:12px 0 0;font-size:.89rem;color:var(--ink-3);max-width:54ch}
  .wide{margin-top:44px}
  .railnav{display:flex}
  .rail{gap:18px;margin-top:16px;overflow:visible;scroll-snap-type:none}
  .jcard{flex:1 1 0}
  .jcard:hover{transform:translateY(-2px);box-shadow:var(--lift-3)}
  .jbody{padding:20px 18px}
  .jt{font-size:1.05rem}
  .jd{font-size:.88rem;margin-bottom:14px}
  /* ⌛ 14 Sep 2026 — § 53.7: the rule that showed `.p2` on the English desktop only is retired; nothing hides it now. */
  .railprog{display:none}
  .trust{margin-top:24px;font-size:.77rem}
  .conv{padding:20px 48px 26px;gap:16px}
  .askbar{padding:8px 48px 18px}
  .umsg{max-width:min(62%,600px)}
  .dmsg{padding:18px}
  /* 🔒 the desktop composition per the approved screen of the view (main.js sets data-layout):
     split = DN_D-WS (the English Dal Insights entry, 50/50 beside the originating answer);
     full  = DN_D-TCO · DN_D-LOC · DN_A-WSD (the workspace directly under the header, full width) */
  /* 🔒 OWNER RULING, 10 Sep 2026 — THE SHARED SHELL HAS ONE GEOMETRY, WHATEVER THE TAB.
     `.wsroot` is identical for `split` and `full`, so `.wshead` — the common header and the
     three-tab strip — cannot move or resize when the reader switches tab. ⌛ Superseded: the
     host used to wrap the WHOLE workspace, shell included, in the 50/50 column for English
     Dal Insights, which moved the shell 620 -> 1400 px at VP1 and 400 -> 960 px at VP2.
     ⛔ HOST PLACEMENT ONLY — ⛔ no panel interior is modified. */
  .wsroot{flex:1;display:flex;flex-direction:column;min-width:0;padding:0}
  /* ⌛ 12 Sep 2026 — DECISION_REGISTER § 30: THE SPLIT NOW CARRIES THE WHOLE WORKSPACE.
     The shell travels with the panel inside `.wsc`, as every registered design draws it, so
     the project header no longer runs across the conversation.
     ⚠ § 16.8's REQUIREMENT survives and is still measured: one shell geometry across all
     three tabs. It holds because § 25 put all three tabs in the split — the column is the
     same width whichever tab is selected, so the shell is too. ⛔ Only the PLACEMENT
     sentences of § 16.8 and § 25.2 are superseded. */
  .wsroot[data-layout=split]>.wsplit{flex:1;flex-direction:row;gap:20px;padding:18px 48px 24px}
  .wsroot[data-layout=split]>.wsplit>*{flex:0 0 calc((100% - 20px)/2);min-width:0;display:flex;flex-direction:column}
  .wsroot[data-layout=split] .origin{display:flex}
  .wsroot[data-layout=split] .conv{padding:0}
  /* the panel column keeps the approved card treatment of the DN_D-WS split */
  .wsroot[data-layout=split]>.wsplit>.wsc{border:1px solid var(--line);border-radius:14px;overflow:hidden}
  /* ⛔ ONE CARD, NOT TWO NESTED ONES. `.wsc` carries the border and radius above, and the
     shell brings its own — which would draw a second frame inside the first. The registered
     frames put the border on the OUTER container only. */
  .wsroot[data-layout=split]>.wsplit>.wsc>.wshead .wshell{border:0;border-radius:0}
  .wsroot[data-layout=split]>.wsplit>.wsc>.wshead{padding:0;border-bottom:1px solid var(--line)}
  .wsroot[data-layout=full]>.wsplit>.wsc{flex:1;display:flex;flex-direction:column;min-width:0}
  .backbar{display:none}
  .wshead{padding:14px 20px}
  .wsbody{padding:16px 20px 20px}
  /* ── the DESKTOP band of the approved header: the locked (non-`.handset`) values ──
     🔴 G-11d asserts the two narrow-band declarations are PRESENT at VP3 and ABSENT at
     VP1. Restoring `flex-wrap:wrap` and the default `flex` here is exactly that boundary,
     and it must ⛔ never leak down to the handset band. */
  .ws .wshell .wtop{align-items:center;padding:15px 18px;flex-wrap:wrap}
  .ws .wshell .wid{flex:0 1 auto}
  .ws .wshell > .brief{padding:2px 18px 16px}
  .ws .wshell .brief-text{font-size:1.06rem}
  .ws .wshell .amenities{font-size:.84rem;gap:9px 22px}
  .ws .wshell .amenities .ico{width:18px;height:18px}   /* the artefact's own `.am-ic` size */
  .sf{padding:16px}
  .mapwrap{height:260px}
  .mapside{padding:0}
}

/* ── W1 · the restored Location Analysis regions ───────────────────────────────
   🔒 DESIGN: the registered frames LAF-MIX-* / LAF-BLT-* — their own classes and values.
   🔒 ORDER: `.claude/rules/location-audit-presentation.md`, the 2 Sep 2026 placement ruling.
   🔒 RELEASE: DECISION_REGISTER § 30 (12 Sep 2026). ⛔ Declared BEFORE owner ruling FC-4.

   ⚠ Frame → product tokens, ⛔ minting none: --paper→--surface · --hairline→--hair ·
   --body→--ink-2 · --muted→--ink-3 · --r-lg→--r-l.
   ⚠ RECORDED DIFFERENCE, the same one already recorded three times in this stylesheet:
   the frame asks weight 800 on `.pb-title`, `.marate` and `.ev`; QA-32/33/34 admits 400 and
   700 only, and DejaVu Sans ships no heavier face. All three are drawn at 700.

   ⚠ THE EVIDENCE CARDS FOLLOW THE PANEL, ⛔ NOT THE VIEWPORT — the same rule as the
   assumptions form and the factor rows. The frame uses three columns at VP1 and one at VP3;
   in the live split the panel is ~660 px whatever the window, so a container query is what
   asks the right question. */
.wsbody .ma{margin-top:12px}
.wsbody .marate{margin:2px 0 0;font-size:1.02rem;font-weight:700;color:var(--ink)}
.wsbody .matot{margin:4px 0 0;font-size:.86rem;color:var(--ink-2)}
.wsbody .ecards{display:grid;grid-template-columns:1fr;gap:10px;margin-top:12px;
  container-type:inline-size}
@container (min-width:560px){
  .wsbody .ecards{grid-template-columns:repeat(3,1fr)}
}
.wsbody .ecard{border:1px solid var(--hair);border-radius:12px;background:var(--tint);
  padding:12px 13px}
.wsbody .ek{display:block;font-size:.76rem;font-weight:700;color:var(--ink-3)}
.wsbody .ev{display:block;margin-top:4px;font-size:1.22rem;font-weight:700;color:var(--ink)}
.wsbody .ec{display:block;margin-top:6px;font-size:.76rem;color:var(--ink-2);line-height:1.45}
/* ⌛ W5-J — nearby-area yield evidence (C-9): one control holding the complete list. The approved
   "Hide the areas" label shows only while the list is open. */
.wsbody .ev-areas{margin-top:6px;font-size:.76rem;color:var(--ink-2)}
.wsbody .ev-areas summary{cursor:pointer;font-weight:700;color:var(--ink)}
.wsbody .ev-areas[open] .ev-show,.wsbody .ev-areas:not([open]) .ev-hide{display:none}
.wsbody .ev-names{margin:6px 0 0;padding-inline-start:18px;line-height:1.5}
.wsbody .ecounts{margin-top:12px;border-top:1px solid var(--hair);padding-top:8px}
.wsbody .ecrow{display:flex;justify-content:space-between;gap:12px;margin:0;padding:4px 0;
  font-size:.78rem;color:var(--ink-3)}
.wsbody .ecrow .num{font-weight:700;color:var(--ink-2)}
.wsbody .bd.shapes{margin-top:14px}
.wsbody .bd.shapes > summary{font-size:.9rem;font-weight:700;color:var(--ink);min-height:44px}
.wsbody .bd.shapes > .bdbody{padding:6px 0 0}
.wsbody .strengths{margin-top:12px;border-top:1px solid var(--hair);padding-top:10px}
.wsbody .strengths b{font-size:.8rem;color:var(--ink)}
.wsbody .strengths p{margin:4px 0 0;font-size:.84rem;color:var(--ink-2)}

/* ── W1 · the Location Analysis five-factor rows ───────────────────────────────
   🔒 DESIGN: DESIGN_STATUS.yaml → PROJECT_WORKSPACE_LOCATION_ANALYSIS_SCORE_SEMANTICS_
   2026_09_11 (LOCKED_DESIGN, 11 Sep 2026), frames LAF-MIX-* and LAF-BLT-*, EN/AR × VP1/VP3.
   🔒 PRODUCT: `.claude/rules/location-audit-presentation.md` § 3 — the five-factor
   presentation using the approved threshold methodology.
   🔒 RELEASE: the owner's ruling of 12 Sep 2026 reconciling GOV-08 § 17.5.
   ⛔ Declared BEFORE owner ruling FC-4, which must stay last.

   🔴 THE BELOW-THRESHOLD ORANGE IS THE APPROVED D1 COMPARISON PRICE-RAIL ORANGE, VERIFIED —
   ⛔ not chosen here. Measured 12 Sep 2026 across three independent sources, all identical:
     · the four APPROVED D1 frames, `CJ-D1-{EN,AR}-VP{1,3}.html` — `.sc-d1 .d1x-bar-o
       {background:var(--orange)}` with `--orange:#ff6c16`;
     · the eight registered Location Analysis frames — the same `--orange:#ff6c16`;
     · this stylesheet's own `.priced` rail — `--orange:#ff6c16`.
   ⚠ The D1 package also contains `diagnostic/rejected_iteration_01/`. ⛔ A rejected iteration
   is not an approved source and was read only to set it aside.

   ⚠ WHY AN ALIAS AND NOT A REUSE. The product's `--orange` is declared ON `.priced` — the
   Screen A price-positioning scope — so it does ⛔ NOT resolve inside `.panel.location`.
   There is no shared/global orange token. Per the ruling, a SCOPED alias carrying the exact
   verified value is introduced here, on the factor rows alone. ⛔ No global token is minted,
   ⛔ `.priced` is not touched, and ⛔ the D1 rail is unchanged.
   Evidence: the implementation package's `D1_RAIL_ORANGE.json`. */
/* 🔴 THE ROW LAYOUT FOLLOWS THE PANEL, ⛔ NOT THE VIEWPORT — the same ruling that governs the
   assumptions form's column count (11 Sep 2026). The Location Analysis panel is ~592 px in the
   approved split at VP1 and full width in the full-page host, so a VIEWPORT query would stack
   the wrong one; a CONTAINER query asks how much room this panel actually gives the rows. */
.wsbody .factors{--la-below:#ff6c16;container-type:inline-size}  /* = the verified D1 orange */
.wsbody .frow{display:grid;grid-template-columns:minmax(104px,150px) 1fr auto;
  align-items:center;gap:12px;padding:7px 0}
.wsbody .frow .fname{font-size:.86rem;font-weight:700;color:var(--ink)}
/* ⚠ the TRACK maps to --hair, ⛔ not --tint-2. Measured against the frame: --grey-bg there is
   #f2f1f5, and --hair (#f0ecf7) is its near neighbour, while --tint-2 (#fcfbfe) is all but
   white and left the unfilled part of the bar barely readable. --track→--hair is also the
   mapping the methodology dialog already records. */
.wsbody .frow .fbar{position:relative;height:9px;border-radius:var(--r-pill);
  background:var(--hair);overflow:hidden}
.wsbody .frow .ffill{position:absolute;inset-block:0;inset-inline-start:0;width:var(--w);
  background:var(--purple);border-radius:var(--r-pill)}
/* 🔴 the governed below-threshold treatment — the ONLY place the alias is used */
.wsbody .frow .ffill.low{background:var(--la-below)}
.wsbody .frow .fsc{font-size:.85rem;font-weight:700;color:var(--ink);
  font-variant-numeric:tabular-nums}
/* LA-FACT-03 · the governed narrative, bound beneath its own row */
.wsbody .factors .bdnote{margin:0 0 10px;font-size:.84rem;line-height:1.55;color:var(--ink-2)}
@container (max-width:420px){
  /* ⚠ In a narrow PANEL the label column would squeeze the bar to nothing, so the row stacks:
     the name and score share a line and the bar spans beneath them. ⛔ The row ORDER and the
     three elements are unchanged — only the wrapping is. */
  .wsbody .frow{grid-template-columns:1fr auto;gap:4px 10px}
  .wsbody .frow .fbar{grid-column:1 / -1;order:3}
}

/* ── W1 · the detailed-methodology dialog and its two triggers ─────────────────
   🔒 DESIGN: DECISION_REGISTER § 24 (the registered REV 2 frames W1R2-M1 … W1R2-M6 and
   W1R2-ORIGIN-DI-TRIGGERS, 11 Sep 2026). 🔒 PRESENTATION: § 23.3(10) — `presentation:
   "modal"`. ⛔ Declared BEFORE owner ruling FC-4, which must stay last.

   ⚠ THE APPROVED FRAMES CARRY THEIR OWN TOKEN SET; these rules map onto the PRODUCT
   palette and ⛔ mint no token. Frame → product: --paper→--surface · --hairline→--hair ·
   --body→--ink-2 · --muted→--ink-3 · --track→--hair · --r-lg→--r-l ·
   --shadow-card→--lift-3.

   ⚠ THREE RECORDED DIFFERENCES FROM THE FRAMES, each forced rather than chosen. All three
   are MEASURED in the implementation package's `REV2_PARITY_MEASURED.json`, which reports
   32/32 on every other geometry, type-scale and structure property:
     1. `.mdl-b` SCROLLS (`overflow:auto`) where the frame sets `overflow:hidden`. A
        scriptless frame cannot scroll, so `hidden` is how the artefact froze the state —
        ⛔ not a ruled behaviour. The frames themselves depict the SCROLLED state
        (`W1R2-M3-DI-MARKET-SCROLLED`), which an unscrollable body could never reach.
     2. `.mdl-t` is weight 700, where the frame asks for 800. QA-32/33/34 admits 400 and
        700 only — DejaVu Sans ships no heavier face and `font-synthesis:none` forbids
        faking one. The same difference is already recorded for `.aerr` and `.asum-t`.
     3. 🔴 THE DIALOG'S CORNER IS 18 px, where the frame draws 16 px — ⏸ FOR THE OWNER'S EYE.
        The frame's `--r-lg` is 16 px and this palette has `--r-s:10 --r-m:14 --r-l:18` with
        NO 16 px token. ⛔ A `--r-lg:16px` token was NOT minted: § 24's REV 2 entry records
        that no token was minted for these states, and minting one to close 2 px would
        contradict it. ⚠ VP1 only — the VP3 sheet is square-cornered in both.

   ⚠ EVERY OFFSET IS LOGICAL (`inset`, `margin-inline-start`), so an RTL document mirrors
   the dialog without a physical override — the class of bug owner ruling F-1 removed. */
.wsbody .mwrap{position:fixed;inset:0;z-index:40;display:flex;
  align-items:center;justify-content:center;padding:32px;
  background:rgba(23,21,29,.46)}
/* 🔴 REQUIRED, AND FOUND BY A REAL BROWSER. The `hidden` attribute is only `display:none`
   from the UA stylesheet, so the author `display:flex` above BEAT IT: the closed dialog
   stayed a full-viewport layer and swallowed every click on the panel behind it. Measured
   12 Sep 2026 — Playwright refused to click the trigger because `div.mwrap[hidden]`
   "intercepts pointer events". ⛔ Neither the render suite nor a structural check could see
   this; both asserted the attribute was present, and it was. */
.wsbody .mwrap[hidden]{display:none}
/* VP3: a full-height sheet rather than a centred dialog (the approved responsive split) */
.wsbody .mwrap.sheet{padding:0;align-items:flex-end}
.wsbody .mwrap.sheet .mdl{width:100%;height:100%;max-height:100%;border-radius:0}
.wsbody .mdl{width:min(640px,100%);max-height:100%;display:flex;flex-direction:column;
  background:var(--surface);border-radius:var(--r-l);box-shadow:var(--lift-3);
  overflow:hidden}
.wsbody .mdl-h{flex:none;display:flex;align-items:flex-start;gap:12px;
  padding:18px 20px 12px;border-bottom:1px solid var(--hair)}
.wsbody .mdl-t{margin:0;font-size:1rem;font-weight:700;letter-spacing:-.01em;color:var(--ink)}
.wsbody .mdl-s{display:block;margin-top:3px;font-size:.74rem;font-weight:700;color:var(--purple)}
.wsbody .mdl-x{margin-inline-start:auto;flex:none;width:36px;height:36px;border-radius:50%;
  border:1.5px solid var(--line);background:var(--surface);color:var(--ink-2);cursor:pointer;
  font-family:inherit;font-size:1rem;font-weight:700;line-height:1}
.wsbody .mdl-x:focus-visible{outline:2px solid var(--purple-deep);outline-offset:2px}
/* 🔒 W4 D5 (DECISION_REGISTER § 72.6, H-MD1) · FC-4 inside the Modal family only: `.wsbody .mdl-t` (0,2,0)
   out-specifies the final `body[dir=rtl] *` rule, so the Arabic title kept Latin tracking. */
body[dir=rtl] .mdl .mdl-t,body[dir=rtl] .mdl .mdl-s{letter-spacing:normal}
/* 🔒 W4 D6 (owner ruling 10, CF-W4-M1 closed) · the × target is ≥ 44×44 px on mobile; the labelled
   Close stays. */
@media (max-width:899px){.wsbody .mdl-x{width:44px;height:44px}}
/* ⛔ THE BODY SCROLLS — recorded difference 1. A long body is reachable, ⛔ never clipped. */
.wsbody .mdl-b{flex:1 1 auto;min-height:0;overflow:auto;padding:14px 20px 18px;
  font-size:.84rem;line-height:1.7;color:var(--ink-2)}
.wsbody .mdl-in{white-space:pre-line}
.wsbody .mdl-b.is-scrolled{box-shadow:inset 0 8px 8px -8px rgba(23,21,29,.22)}
.wsbody .mdl-f{flex:none;padding:12px 20px 16px;border-top:1px solid var(--hair);
  display:flex;justify-content:flex-end}
/* ⌛ `methodology_unavailable` is a QUIET EMPTY-CONTENT state.
   ⛔ Not amber, ⛔ not a failure treatment — `tco_recalculation_failed` is that, on a
   different surface with a different claim — and ⛔ never drawn over approved content. */
.wsbody .mdl-none{display:block;padding:18px 0 6px;color:var(--ink-3);
  font-size:.86rem;font-weight:700;text-align:center}
.wsbody .mdl-scrollcue{flex:none;height:4px;background:var(--hair)}
.wsbody .mdl-scrollcue i{display:block;height:4px;width:42%;background:var(--purple);
  border-radius:3px}
/* The two trigger shapes: `.meth` sits on a Dal Insights component, `.methact` in the
   TCO / Location Analysis `<details>` body and again as the dialog's footer Close button
   (§ 24.2 clause 4). ≥44 px at every band — ⛔ no second sizing system. */
.wsbody .meth,.wsbody .methact{min-height:44px;padding:0 14px;border-radius:var(--r-pill);
  border:1.5px solid var(--line);background:var(--surface);color:var(--purple-deep);
  font-family:inherit;font-size:.82rem;font-weight:700;cursor:pointer}
.wsbody .meth{margin-top:10px}
.wsbody .meth:hover,.wsbody .methact:hover{background:var(--tint);border-color:var(--purple)}
.wsbody .meth:focus-visible,.wsbody .methact:focus-visible{
  outline:2px solid var(--purple-deep);outline-offset:2px}

/* ── W1 · the registered TCO RESULTS composition ───────────────────────────────
   🔒 DESIGN: `PROJECT_WORKSPACE_TCO_HIERARCHY` (LOCKED_DESIGN, 27 Aug 2026) and the registered
   frames `WS-TCO-{EN,AR}-VP1` / `WS-TCO-EN-VP3`, which draw it identically.
   🔒 RULING: `DECISION_REGISTER.md` § 32 (12 Sep 2026). ⛔ Declared BEFORE owner ruling FC-4.

   🔴 EVERY RULE IS SCOPED TO `.wresults`, AND THAT IS DELIBERATE. `.pb`, `.pb-head` and
   `.pb-title` are already worn by Market Activity in the Location Analysis panel and by the
   assumptions form, and NEITHER carries a card frame today. An unscoped `.pb{border…}` would
   silently put a frame around both — a change § 32 does not authorise. ⛔ Nothing outside the
   TCO results region is touched.
   ✅ OWNER RULING FC-3's `.metric` rules are NOT edited: they still govern the Location
   Analysis score row. TCO simply stops using `.metric`.

   ⚠ Frame → product tokens, mapped BY VALUE and ⛔ minting none: --paper #fff→--surface ·
   --soft #f5f1ff→--tint · --hairline #f0ecf7→--hair · --body #443f4e→--ink-2 ·
   --muted #706d78→--ink-3 · --line, --ink, --purple-deep, --r-pill same name AND value.
   ⚠ RECORDED DIFFERENCE: the frame's `--r-lg` is 16px and this palette has no 16px token
   (--r-m 14, --r-l 18); `--r-l` is used, the same +2px already recorded for `section.setup`.
   ⚠ RECORDED DIFFERENCE: the frame asks weight 800 on `.pb-title`, `.pb-num`, `.fv`, `.scenp`
   and `.cfgtag`; QA-32/33/34 admits 400 and 700 only, so all are drawn at 700. */
/* ⌛ 12 Sep 2026 (§ 33 · R6) — 16px, THE REFERENCE'S OWN VALUE. The recorded 16↔18 difference is
   resolved to the reference. ⚠ This palette has no 16px token and ⛔ NO GLOBAL TOKEN IS ADDED OR
   CHANGED: the literal is written once, here, inside the `.wresults` scope. */
.wsbody .wresults .pb{border:1px solid var(--line);border-radius:16px;
  background:var(--surface);padding:16px 18px 18px}
.wsbody .wresults .pb + .pb{margin-top:12px}
.wsbody .wresults .pb-head{display:flex;align-items:center;justify-content:space-between;
  gap:12px;flex-wrap:wrap}
.wsbody .wresults .pb-title{margin:0;font-size:1.02rem;font-weight:700;letter-spacing:-.02em;
  color:var(--ink)}
/* the PURCHASE PRICE — ⛔ never labelled or styled as an ownership total */
.wsbody .wresults .pb-fig{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;margin-top:2px}
.wsbody .wresults .pb-num{font-size:1.4rem;font-weight:700;letter-spacing:-.03em;
  color:var(--purple-deep)}
/* 🔵 § 32 item 4 — the purple, NON-INTERACTIVE configuration chip */
.wsbody .wresults .cfgtag{font-size:.78rem;font-weight:700;color:var(--purple-deep);
  background:var(--tint);border-radius:var(--r-pill);padding:3px 10px}
.wsbody .wresults .pb-basis{margin:8px 0 0;font-size:.84rem;color:var(--ink-2);line-height:1.55}
.wsbody .wresults .pb-basis.dated{font-weight:700;color:var(--ink)}
.wsbody .wresults .scenp{font-size:.86rem;font-weight:700;color:var(--purple-deep)}
/* 🔴 THE CARDS FOLLOW THE PANEL, ⛔ NOT THE VIEWPORT — the same ruling that governs the
   assumptions form's columns.
   ⚠ `container-type` GOES ON THE SCENARIO SECTION, ⛔ NOT ON THE GRID. An element cannot query
   ITSELF: measured in Chromium, a grid that declares `container-type:inline-size` and then asks
   `@container (min-width:440px)` about its own width stays at ONE column at 600px, while the
   same query against its PARENT gives two. ⛔ Not reasoned — measured
   (`probes/container_query_self_reference.py`).
   ⚠ TWO COLUMNS IS THE CAP, ⛔ never "as many as fit": the frame's own `auto-fit` track list is
   what gave the assumptions form SEVEN columns in a full-width panel (§ 24's recorded finding),
   and the same hazard applies here. */
.wsbody .wresults .pb.scen{container-type:inline-size}
.wsbody .wresults .fgrid{display:grid;grid-template-columns:1fr;gap:10px;margin-top:12px}
@container (min-width:440px){
  .wsbody .wresults .fgrid{grid-template-columns:repeat(2,minmax(0,1fr))}
}
.wsbody .wresults .fcard{border:1px solid var(--hair);border-radius:12px;background:var(--tint);
  padding:11px 13px;min-width:0}
.wsbody .wresults .fk{display:block;font-size:.76rem;font-weight:700;color:var(--ink-3)}
/* ⛔ the figure must WRAP, never clip: a governed range like "SAR 1.71M – SAR 1.98M" is long */
.wsbody .wresults .fv{display:block;margin-top:5px;font-size:.98rem;font-weight:700;
  color:var(--ink);overflow-wrap:anywhere}
.wsbody .wresults .fc{display:block;margin-top:6px;font-size:.76rem;color:var(--ink-2);
  line-height:1.45}
/* ── § 33 · R4 — the callout, in the reference's own position and treatment ─────
   🔴 EVERY VALUE BELOW IS COMPUTED FROM THE REGISTERED FRAME, ⛔ not chosen: measured in a
   browser against `WS-TCO-{EN,AR}-VP1` (`probes/trace_frame_styles.py`) —
     background  rgb(255,248,243) = #fff8f3      text  rgb(104,49,15) = #68310f
     border-inline-start  4px solid rgb(255,108,22) = #ff6c16
     radius 12px · padding 12px 14px · the <b> at rgb(74,32,7) = #4a2007, .98rem
   ✅ #ff6c16 IS ALREADY VERIFIED IN THIS REPOSITORY — it is the approved D1 comparison
   price-rail orange § 29 traced and uses as `--la-below`. ⛔ No new orange is selected.
   ⚠ The three warm-ink values have no existing token; they are SCOPED ALIASES carrying the
   frame's exact measured values, ⛔ not a global token change and ⛔ not an invented colour. */
.wsbody .wresults .qual.callout,
.wsbody .panel.location ~ .qual.callout{--qc-orange:#ff6c16;--qc-bg:#fff8f3;--qc-ink:#68310f;
  --qc-strong:#4a2007;
  display:flex;flex-direction:column;gap:4px;
  border-inline-start:4px solid var(--qc-orange);background:var(--qc-bg);color:var(--qc-ink);
  padding:12px 14px;border-radius:0 12px 12px 0;margin-top:12px}
body[dir=rtl] .wsbody .wresults .qual.callout,
body[dir=rtl] .wsbody .panel.location ~ .qual.callout{border-radius:12px 0 0 12px}
.wsbody .wresults .qual.callout b,
.wsbody .panel.location ~ .qual.callout b{font-size:.98rem;font-weight:700;color:var(--qc-strong);
  letter-spacing:-.01em;line-height:1.5}

/* ── § 34 · R5 — the amenity note ──────────────────────────────────────────────
   🔴 EVERY VALUE IS COMPUTED FROM THE REGISTERED FRAME, ⛔ not chosen: measured in a browser
   against `WS-TCO-{EN,AR}-VP1` (`probes/trace_frame_styles.py`) —
     background rgb(252,251,254) = #fcfbfe → --tint-2      text rgb(112,109,120) = #706d78 → --ink-3
     border 1px rgb(240,236,247) = #f0ecf7 → --hair        radius 12px · padding 11px 14px
     size .82rem · weight 400  ⚠ WEIGHT 400 IS THE FRAME'S OWN — this note is deliberately
     lighter than the cost cards, because it is a disclosure beside the figures, not a figure.
   ⛔ Every token maps BY VALUE onto one this palette already has; no token is minted. */
.wsbody .wresults .amenbox{display:block;margin-top:10px;border:1px solid var(--hair);
  border-radius:12px;background:var(--tint-2);padding:11px 14px;
  font-size:.82rem;font-weight:400;color:var(--ink-3);line-height:1.6}

/* ── § 33 · R1 / R3 — the reference's detail stack ─────────────────────────────
   the full breakdown, the evidence-and-limitations disclosure, then the methodology. */
.wsbody .wresults .detailstack,
.wsbody .panel.location ~ .detailstack{display:flex;flex-direction:column;gap:8px;margin-top:12px}
.wsbody .wresults .detailstack > .bd,
.wsbody .panel.location ~ .detailstack > .bd{margin:0;border:1px solid var(--line);border-radius:16px;
  background:var(--surface)}
.wsbody .wresults .detailstack > .bd > summary,
.wsbody .panel.location ~ .detailstack > .bd > summary{list-style:none;cursor:pointer;min-height:44px;
  display:flex;flex-direction:column;justify-content:center;padding:10px 18px;
  font-size:.9rem;font-weight:700;color:var(--purple-deep)}
.wsbody .wresults .detailstack > .bd > summary::-webkit-details-marker,
.wsbody .panel.location ~ .detailstack > .bd > summary::-webkit-details-marker{display:none}
.wsbody .wresults .detailstack > .bd > summary:focus-visible,
.wsbody .panel.location ~ .detailstack > .bd > summary:focus-visible{outline:2px solid var(--purple-deep);
  outline-offset:-2px;border-radius:16px}
.wsbody .wresults .bdscen{margin:12px 0 6px;font-size:.82rem;font-weight:700;
  color:var(--purple-deep)}
.wsbody .wresults .bdgrp{margin:10px 0 4px;font-size:.76rem;font-weight:700;letter-spacing:.05em;
  text-transform:uppercase;color:var(--ink-3)}
.wsbody .wresults .bdrow{display:flex;justify-content:space-between;gap:14px;margin:0;
  padding:7px 0;border-bottom:1px solid var(--hair);font-size:.86rem;color:var(--ink-2)}
.wsbody .wresults .bdrow .num{font-weight:700;color:var(--ink)}
.wsbody .wresults .bdnote,
.wsbody .panel.location ~ .detailstack .bdnote{margin:8px 0 0;font-size:.84rem;color:var(--ink-2);line-height:1.55}
/* ⌛ 13 Sep 2026 — § 45.3: the single growth result names its governed band, drawn with the approved
   frame's `.tr-band` treatment (the band word, then its range, muted). --muted is --ink-3. */
.wsbody .panel.growth .tr-band{display:flex;align-items:baseline;gap:9px;flex-wrap:wrap;margin:0 0 6px;
  font-size:.95rem;font-weight:700;color:var(--ink)}
.wsbody .panel.growth .tr-band span{font-size:.8rem;font-weight:400;color:var(--ink-3)}

@media (max-width:720px){
  .wsbody .wresults .pb{padding:13px 14px 15px}
  .wsbody .wresults .detailstack > .bd > summary,
  .wsbody .panel.location ~ .detailstack > .bd > summary{padding:10px 14px}
}

/* ── W1 · the TCO unit-type selector, in its approved SETUP placement ──────────
   🔒 DESIGN: `PROJECT_WORKSPACE_TCO_HIERARCHY` (LOCKED_DESIGN, 27 Aug 2026), and the three
   registered frames `WS-TCO-{EN,AR}-VP1` / `WS-TCO-EN-VP3`, which draw it identically.
   🔒 RULING: `DECISION_REGISTER.md` § 31 (12 Sep 2026). ⛔ Declared BEFORE owner ruling FC-4.

   ⚠ TOKEN MAPPING — THE TRAP HERE IS THAT BOTH SHEETS DEFINE `--tint`, WITH DIFFERENT VALUES.
   The frame's `--tint` is #fcfbfe (this sheet's `--tint-2`) and its `--soft` is #f5f1ff (this
   sheet's `--tint`). Mapped by VALUE, ⛔ never by name:
     --paper #fff    → --surface  · --soft #f5f1ff → --tint   · --tint #fcfbfe → --tint-2
     --hairline #f0ecf7 → --hair  · --body #443f4e → --ink-2  · --muted #706d78 → --ink-3
     --line #e7e1f2, --ink, --purple, --purple-deep, --r-pill are the SAME name AND value.
   ⚠ RECORDED DIFFERENCE: the frame's `--r-lg` is 16px and this palette has no 16px token —
   `--r-m` is 14 and `--r-l` is 18. `--r-l` is used (+2px), the same 18px corner the owner
   accepted on 12 Sep for the methodology dialog. ⛔ No token is minted.
   ⚠ RECORDED DIFFERENCE: the frame asks for weight 800; QA-32/33/34 admits 400 and 700 only
   (DejaVu ships no heavier face, `font-synthesis:none`), so 700 is drawn — the same recorded
   difference the assumptions form below already carries. */
.wsbody .setup{display:flex;flex-direction:column;gap:12px;border:1.5px solid var(--purple);
  border-radius:var(--r-l);background:var(--tint-2);padding:14px 16px 16px}
.wsbody .cfgwrap{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.wsbody .cfglbl{font-size:.78rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;
  color:var(--ink-3)}
/* ⛔ THE OPTIONS WRAP, they never scroll sideways: a project may publish five configurations
   and the panel is ~592px in the approved split. */
.wsbody .cfgrow{display:flex;gap:8px;flex-wrap:wrap}
.wsbody .cfg{min-height:44px;padding:0 16px;border-radius:var(--r-pill);cursor:pointer;
  border:1.5px solid var(--line);background:var(--surface);color:var(--ink-2);
  font-family:inherit;font-size:.88rem;font-weight:700}
/* 🔴 the SELECTED treatment — filled purple, ⛔ not colour-only: `aria-checked` travels with it */
.wsbody .cfg.on{border-color:var(--purple);background:var(--purple);color:#fff}
.wsbody .cfg:focus-visible{outline:2px solid var(--purple-deep);outline-offset:2px}
.wsbody .selrange{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;
  border-top:1px solid var(--hair);padding-top:11px}
.wsbody .selcfg{font-size:.8rem;font-weight:700;color:var(--purple-deep);background:var(--tint);
  border-radius:var(--r-pill);padding:4px 11px}
.wsbody .selspan{font-size:1.06rem;font-weight:700;letter-spacing:-.02em;color:var(--ink)}
/* the assumptions card sits INSIDE the setup box, exactly as the frames nest it; ⛔ the box
   supplies no second border of its own around the card */
.wsbody .setup > .assum{margin:0}
@media (max-width:720px){
  .wsbody .cfg{min-height:44px}          /* ≥44px at the mobile band, as everywhere else */
  .wsbody .setup{padding:12px 13px 14px} /* the registered `.handset .setup` padding */
}

/* ── W1 · the eight-field TCO assumptions form ─────────────────────────────────
   🔒 DESIGN: DECISION_REGISTER § 24 (the REV 2 states, 11 Sep 2026).
   🔒 BEHAVIOUR: § 23. ⛔ Declared BEFORE owner ruling FC-4, which must stay last.

   ⚠ THE APPROVED FRAMES CARRY THEIR OWN TOKEN SET; these rules map onto the PRODUCT
   palette and ⛔ mint no token. The product's amber/warn family is --warn / --warn-bg /
   --warn-line — the same family `.notice.w` already uses — which is what the REV 2
   entry means by "the locked palette has no error token; no token was minted".
   Frame → product: --paper→--surface · --soft→--tint · --grey-bg→--tint-2 ·
   --hairline→--hair · --body→--ink-2 · --muted→--ink-3 · --amber→--warn-line ·
   --warn-ink→--warn · --r-md→--r-m · --track→--hair.

   🔴 NO SLIDER, CAPPED TRACK OR GAUGE ANYWHERE BELOW. § 23.1 gives the profit rate, the
   financing term and the community fee NO product maximum, and any affordance with an end
   asserts a ceiling the ruling forbids. A stepper plus free entry fits all four fields;
   only the financing ratio has a real bound. */
/* 🔴 THE COLUMN COUNT FOLLOWS THE PANEL, ⛔ NOT THE VIEWPORT.
   Measured 11 Sep 2026 against the registered frames: the approved composition draws this
   form inside a 592 px TCO panel — a 558 px section, a 524 px grid, TWO 257 px columns at
   VP1 and ONE column at VP3. The live client gives the TCO panel the full 1400 px, and an
   `auto-fit` track list obligingly produced SEVEN columns.
   ⚠ A VIEWPORT media query cannot fix that, because the viewport is 1440 px in BOTH hosts —
   the split journey and the full-page entry. A CONTAINER query asks the only question that
   matters: how much room does this panel actually give the form. The same rule is then
   correct in the approved split panel, in the wider full-page panel and at VP3.
   ⛔ TWO columns is the approved maximum, never "as many as fit". */
.wsbody .assum{padding:14px 16px 16px;container-type:inline-size}
.wsbody .assum .pb-title{font-size:.94rem}
.wsbody .ahelp{margin:6px 0 0;font-size:.82rem;color:var(--ink-2)}
.wsbody .agrid{display:grid;grid-template-columns:1fr;gap:10px;margin-top:12px}
@container (min-width:420px){
  .wsbody .agrid{grid-template-columns:repeat(2,minmax(0,1fr))}
}
.wsbody .afield{display:flex;flex-direction:column;gap:5px;min-width:0}
.wsbody .alab{font-size:.74rem;font-weight:700;color:var(--ink-3)}
.wsbody .aopts{display:flex;gap:6px;flex-wrap:wrap}
.wsbody .aopt{min-height:40px;padding:0 12px;border-radius:var(--r-pill);cursor:pointer;
  border:1.5px solid var(--line);background:var(--surface);color:var(--ink-2);
  font-family:inherit;font-size:.82rem;font-weight:700}
.wsbody .aopt.on{border-color:var(--purple);background:var(--tint);color:var(--purple-deep)}
.wsbody .aopt:focus-visible{outline:2px solid var(--purple-deep);outline-offset:2px}
.wsbody .aopts.is-invalid{border-radius:var(--r-s);outline:1.5px solid var(--warn-line);outline-offset:3px}
.wsbody .atog{width:46px;height:26px;border-radius:var(--r-pill);background:var(--tint-2);
  border:1.5px solid var(--line);position:relative;display:inline-block;cursor:pointer}
.wsbody .atog > i{position:absolute;top:2px;inset-inline-start:2px;width:18px;height:18px;
  border-radius:50%;background:var(--surface);box-shadow:0 1px 3px rgba(0,0,0,.18);
  transition:inset-inline-start .12s ease}
.wsbody .atog.on{background:var(--tint);border-color:var(--purple)}
.wsbody .atog.on > i{inset-inline-start:22px;background:var(--purple)}
.wsbody .atog:focus-visible{outline:2px solid var(--purple-deep);outline-offset:2px}
/* the numeric control — a stepper plus free entry */
.wsbody .anum{display:flex;align-items:stretch;min-height:40px;border-radius:var(--r-s);
  border:1.5px solid var(--line);background:var(--surface);overflow:hidden}
.wsbody .anum .aval{flex:1 1 auto;min-width:0;border:0;background:transparent;min-height:38px;
  padding:0 10px;color:var(--ink);font-family:inherit;font-size:.86rem;font-weight:700;
  direction:ltr;unicode-bidi:isolate;font-variant-numeric:tabular-nums;text-align:start}
.wsbody .anum .aval:focus{outline:none}
.wsbody .anum:focus-within{border-color:var(--purple-deep);outline:2px solid var(--purple-deep);outline-offset:2px}
.wsbody .anum .astep{flex:none;width:38px;min-height:38px;border:0;cursor:pointer;
  background:var(--tint);color:var(--purple-deep);font-family:inherit;font-size:1rem;
  font-weight:700;line-height:1;display:flex;align-items:center;justify-content:center}
.wsbody .anum .astep + .aval{border-inline-start:1.5px solid var(--hair)}
.wsbody .anum .aval + .astep{border-inline-start:1.5px solid var(--hair)}
.wsbody .anum .astep:hover{background:var(--tint)}
/* ⌛ 13 Sep 2026 — § 44 (B5): a step control at its bound is inactive, as REV 2
   `W1R2-C1-STEP-BOUNDS` draws it (grey-bg is --tint-2, muted is --ink-3). Only the minimum of
   every field and the 90% financing ratio are bounds; § 23.1 gives the rest no maximum. */
.wsbody .anum .astep[aria-disabled=true]{color:var(--ink-3);background:var(--tint-2);cursor:default}
.wsbody .anum.is-invalid{border-color:var(--warn-line);background:var(--warn-bg)}
.wsbody .anum.is-busy{border-color:var(--purple)}
/* § 23.3(4) · under `cash` the three financing inputs are VISIBLE but disabled, values RETAINED */
.wsbody .afield.is-off .anum{background:var(--tint-2);border-color:var(--hair)}
.wsbody .afield.is-off .anum .aval{color:var(--ink-3)}
.wsbody .afield.is-off .anum .astep{background:var(--tint-2);color:var(--ink-3);cursor:default}
/* § 23.3(2) · the rejection row — ⛔ colour alone is insufficient (§ 24.2 clause 5), so the
   message, its `aria-describedby` association and `aria-invalid` all travel with it */
.wsbody .aerr{margin:0;display:flex;gap:6px;align-items:flex-start;font-size:.74rem;
  font-weight:700;line-height:1.45;color:var(--warn)}
/* ⚠ RECORDED DIFFERENCE FROM THE APPROVED FRAME: the frame asks for weight 800 here and on
   `.asum-t`. QA-32/33/34 admits 400 and 700 only — DejaVu Sans ships no heavier face and
   `font-synthesis:none` forbids faking one — so both are drawn at 700. */
.wsbody .aerr .aerr-i{flex:none;width:14px;height:14px;border-radius:50%;background:var(--warn);
  color:#fff;font-size:.62rem;font-weight:700;line-height:14px;text-align:center;margin-top:2px}
/* ⌛ 14 Sep 2026 — § 47.1: an Arabic step number and its approved percentage-point unit wrap as ONE
   unit, so a line never ends between «1» and «نقطة مئوية». ⛔ No word changes; ⛔ no U+00A0 (G20). */
.wsbody .aerr .akeep{white-space:nowrap}
/* § 23.3(6) · Restore defaults — inert while nothing is overridden, because it CLEARS them */
.wsbody .arow{display:flex;justify-content:flex-end;margin-top:12px}
.wsbody .arestore{min-height:40px;padding:0 14px;border-radius:var(--r-pill);
  border:1.5px solid var(--line);background:var(--surface);color:var(--purple-deep);
  font-family:inherit;font-size:.82rem;font-weight:700;cursor:pointer}
.wsbody .arestore:hover{background:var(--tint);border-color:var(--purple)}
.wsbody .arestore:focus-visible{outline:2px solid var(--purple-deep);outline-offset:2px}
.wsbody .arestore[aria-disabled=true]{color:var(--ink-3);border-color:var(--hair);
  background:var(--tint-2);cursor:default}
/* the VP3 collapsed entry */
.wsbody .bd.assum > summary{min-height:44px}
.wsbody .asum-t{font-weight:700}
.wsbody .asum-v{display:flex;gap:6px;flex-wrap:wrap;margin-top:6px}
.wsbody .achip{font-size:.74rem;font-weight:700;color:var(--purple-deep);background:var(--tint);
  border-radius:var(--r-pill);padding:3px 9px}
.wsbody .bdbody{padding:2px 18px 16px}
/* the results region every control points at, and its two governed states */
.wsbody .wresults{display:block;position:relative}
/* ⚠ RECORDED DIFFERENCE FROM THE APPROVED FRAME: the frame draws the recalculating bar as a
   generated pseudo-element. QA-44 admits no generated content but the governed middot, so the
   bar is a REAL element the renderer emits only while busy. ⛔ Not a workaround of the guard —
   the guard's subject is CSS-drawn ornament, and this is markup the renderer owns. */
.wsbody .abar{position:absolute;inset-inline:0;top:0;height:3px;border-radius:3px;
  background:linear-gradient(90deg,var(--hair) 0 28%,var(--purple) 28% 56%,var(--hair) 56% 100%);
  z-index:3}
/* ⛔ THE FIGURES ARE DIMMED, NEVER REMOVED. A blank panel is the governed "not available"
   state and would be a different claim (§ 23.6). */
/* ⌛ 13 Sep 2026 — DECISION_REGISTER § 44 (B3): the REV 2 frame selectors (`W1R2-L1-RECALCULATING`).
   The rule that stood here targeted the compact results card rows and its metric row, which
   § 32 removed from the TCO panel, so nothing dimmed while a recalculation was running. */
.wsbody .wresults[data-state=busy] .fv,
.wsbody .wresults[data-state=busy] .scenp,
.wsbody .wresults[data-state=busy] .pb-num{opacity:.45}
/* § 23.6 · the failure notice sits ABOVE the retained figures and governs them.
   ⛔ Not beside the control. ⛔ Not an out-of-range error. ⛔ It asserts no maximum. */
.wsbody .afail{display:flex;gap:9px;align-items:flex-start;margin:0 0 14px;padding:12px 14px;
  border-radius:var(--r-m);background:var(--warn-bg);border:1.5px solid var(--warn-line);
  color:var(--warn);font-size:.82rem;font-weight:700;line-height:1.5}
.wsbody .afail .aerr-i{margin-top:3px}
/* ⌛ 13 Sep 2026 — § 44 (B4): the REV 2 failure treatment (`W1R2-F1-FAILURE`). The retained
   sections are marked and their figures muted, so a previous figure never reads as current
   (§ 23.6). It replaces a single border on the whole panel. Frame to product by value:
   amber is --warn-line, muted is --ink-3. */
.wsbody .wresults[data-state=failed] .pb.scen,
.wsbody .wresults[data-state=failed] .pb.basis{border-inline-start:3px solid var(--warn-line)}
.wsbody .wresults[data-state=failed] .fv,
.wsbody .wresults[data-state=failed] .scenp,
.wsbody .wresults[data-state=failed] .pb-num{color:var(--ink-3)}
@media (max-width:720px){
  /* ≥44 px on every control at the mobile band.
     ⚠ The single-column stack is NOT set here any more — it is the container query's
     default above, so the form stacks whenever the PANEL is narrow, including a narrow
     panel inside a wide window. */
  .wsbody .aopt,.wsbody .anum,.wsbody .anum .aval,.wsbody .anum .astep,
  .wsbody .arestore{min-height:44px}
}

/* ── W3B · CT-IDENTITY-CONTRAST — the approved answer block ───────────────────
   🔒 Owner-approved 7 Sep 2026 (W3B_OWNER_VISUAL_APPROVAL_RECORD_2026-09-07.md);
   implementation authorised 20 Sep 2026. Built ONLY from the shell's own tokens, type
   scale and hairline — ⛔ no new colour, ⛔ no new font, ⛔ no icon, glyph, emoji,
   illustration, chevron or divider artwork, ⛔ no card or card-like D-08 region.
   ⛔ This is NOT a project card and carries no card behaviour or navigation. */

/* the block's own box: the frozen shell's plain `.sf` card, WITHOUT the R16-6 chip grid —
   W3B is a scoped exception to R16-6 (owner decision 2, 20 Sep 2026) and draws no chip. */
.icb{background:var(--surface);border:1px solid var(--line);border-radius:var(--r-m);padding:14px;
  box-shadow:var(--lift-1)}
.icb+.icb{margin-top:10px}
.icb .sfh{display:flex;align-items:center;gap:9px;margin-bottom:10px}
/* ⚠ `.sfh h3`, NOT `.icb .sfh h3` — deliberately low specificity, exactly as the frozen
   shell declares it and for the same reason the neighbouring `.sf h2` rule says: the final
   `body[dir=rtl] *{letter-spacing:normal}` (FC-4 / RR-20) must win the tie. At `.icb .sfh h3`
   the heading kept -0.1472px of tracking under RTL on all ten Arabic cells — measured, then
   fixed. Specificity beats source order, so a "declared last" rule is only last if nothing
   outranks it. */
.sfh h3{margin:0;font-size:.92rem;font-weight:700;color:var(--ink);letter-spacing:-.01em}

/* DJ-03 · one stacked label-over-value row form, for BOTH rows and BOTH states. The
   shell's side-by-side `.fact` cannot carry a sentence, and a stacked row has no inline
   pair whose Arabic order could be in question. */
.ic-rows{margin:0;display:flex;flex-direction:column}
.ic-row{padding:12px 0;border-top:1px solid var(--hair)}   /* the shell's own .fact hairline */
.ic-row:first-child{border-top:0;padding-top:2px}
.ic-label{margin:0 0 5px;font-size:.81rem;line-height:1.4;color:var(--ink-3)}
.ic-value{margin:0;font-size:.95rem;line-height:1.5;font-weight:700;color:var(--ink)}
body[dir=rtl] .ic-value{line-height:1.65}

/* DJ-04 · the ruling sentence is the answer, so it outranks the project names AND the
   section heading. Size and terminal position carry the hierarchy, never a second weight. */
.ic-value.ic-ruling{font-size:1.02rem;line-height:1.5}
body[dir=rtl] .ic-value.ic-ruling{line-height:1.7}

/* DJ-05 · provenance is subordinate. When `identity.ruling` is null this line is ABSENT —
   the renderer omits it; there is no empty-state rule here on purpose. */
.ic-prov{margin:7px 0 0;font-size:.74rem;line-height:1.45;font-weight:400;
  color:var(--ink-3);font-variant-numeric:tabular-nums}

/* Each project name is its own independent isolate (fallback clauses 7/8, gate G-C12); the
   separator sits OUTSIDE both and is never swallowed. ⛔ ZERO bidi control characters are
   stored anywhere — the isolation is produced HERE, at render time, by CSS. */
.pname{unicode-bidi:isolate}
.pname.ltr{direction:ltr}
.ic-sep{font-weight:400;color:var(--ink-3)}

@media (min-width:900px){
  .icb{padding:16px}
  .ic-row{padding:14px 0}
  .ic-value{font-size:1rem}
  .ic-value.ic-ruling{font-size:1.08rem}
}

/* DJ-06 / ESC-W3B-04 (closed by the owner, approval clause 5) · at VP1 the answer block
   takes the governed 50/50 column — calc((100% - 20px)/2) = 662px of a 1344px container —
   and the companion analysis column is NOT drawn, because this conversation state carries
   no workspace payload. ⛔ Scoped to the CONVERSATION routes: inside the project
   workspace the origin column is ALREADY one half, and narrowing it again would halve it
   twice. ⛔ The project-workspace split root is untouched — and its selector is
   deliberately NOT spelled out here, because the § 30 guard scans the stylesheet for that
   literal and a mention in a comment reads to it as an escaped rule. */
@media (min-width:1108px){
  .shell[data-route=ask] .conv>.turn>.dmsg:has(>.dpart>.answer>.icb),
  .shell[data-route=compare] .conv>.turn>.dmsg:has(>.dpart>.answer>.icb){
    align-self:flex-start;width:calc((100% - 20px)/2)}
}
/* W4 DJ-W4-C3 / MD-W4-04 · the same W3B DJ-06 precedent for the W4 one-column families: the
   whole turn — the user bubble and the Dal reply — takes the 50/50 column at the inline start.
   ⛔ ONLY turns main.js marks `data-col=answer` (every part a one-column W4 answer, or a user
   turn whose reply is one). 🔒 Owner ruling 8 (XF-04): card-led answers keep the full grid, and
   their user bubble stays at the grid edge. */
@media (min-width:1108px){
  .shell[data-route=ask] .conv>.turn[data-col=answer],
  .shell[data-route=compare] .conv>.turn[data-col=answer]{
    width:calc((100% - 20px)/2);align-self:flex-start}
}

/* ── OWNER RULING FC-4 — declared LAST so it wins every specificity tie ────────
   ⛔ NO negative letter-spacing on ANY element under RTL, the Latin wordmark included. */
body[dir=rtl],body[dir=rtl] *{letter-spacing:normal}
