/* Black and white only — the client's brand carries no accent colour. Everything that would
   normally be signalled with hue is signalled here with weight, size and space instead. */
/* Dark theme. The client's logo is white artwork on transparency, so the product is built dark and
   the mark sits on it untouched. --ink is the FOREGROUND and --bg the ground; everything below is
   expressed through these two so the palette stays one decision. */
:root {
  --ink: #f7f7f7;        /* primary text and the "solid" fill (buttons, active rows) */
  --ink-2: #c4c4c4;
  --muted: #8b8b8b;
  /* #6a6a6a computed 3.41:1 on --surface — below AA for the small text it carries (.unit, .opt and
     the routes' unit labels). Raised to the AA floor; it stays one step under --muted, which is as
     many legible text tones as a monochrome dark palette actually has. */
  --faint: #7f7f7f;
  --line: #2a2a2a;
  --line-soft: #1e1e1e;
  --surface: #141414;    /* cards, panels */
  --bg: #0a0a0a;         /* the page behind them */
  --on-ink: #0a0a0a;     /* text that sits ON an --ink fill — never plain white */
  /* Chart.js is handed colour values, not tokens, so the trend area's tint needs a token of its
     own to survive the print re-theme. It is --ink at 7%; there is no opacity token to derive it. */
  --chart-fill: rgba(247,247,247,.07);
  /* The single hue in the product, and it lives in the charts alone. It marks the one series in
     each chart that carries the answer — the deed median line, the yield bars, net income. Every
     other series, and every gridline, axis and tick, stays in the greys above; a chart where
     everything is cyan reads as a different product. Light rather than dark by the owner's call:
     12.04:1 on --bg and 11.20:1 on --surface, so it holds at a hairline.
     Nothing else in the interface may take this token. */
  --accent: #6FD9E8;
  --accent-fill: rgba(111,217,232,.12);
  --raise: 0 1px 2px rgba(0,0,0,.5), 0 8px 24px -16px rgba(0,0,0,.9);
  --r: 10px;
  --font: 'IBM Plex Sans Arabic', system-ui, -apple-system, 'Segoe UI', sans-serif;
}
/* The browser paints form controls, scrollbars and the date picker from this. */
:root { color-scheme: dark; }

* { box-sizing: border-box; }
/* A class-level `display` beats the browser's own `[hidden] { display: none }`, so .login and .app
   both stayed on screen at once. Every hidden toggle in app.js depends on this one line. */
[hidden] { display: none !important; }
/* Carries the heading level a screen reader needs without adding a second visible title next to the
   tab that already names the pane. */
.sr-only { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }
html, body { height: 100%; }
body {
  margin: 0; background: var(--bg); color: var(--ink);
  font-family: var(--font); font-size: 14px; line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}
/* Western digits everywhere, even inside Arabic text. */
body, input, select, textarea, button, table { font-variant-numeric: tabular-nums; }
button, input, select { font: inherit; color: inherit; }
h1, h2, h3, legend { font-weight: 600; letter-spacing: -.01em; }

/* The stylesheet carried no :focus-visible rule at all, and the form rule below used to remove the
   UA ring outright, so nothing in the app showed keyboard focus. One ring for every control: --ink
   on --bg is 18:1, and the 2px offset clears the control's own border and any --ink fill it sits on. */
input:focus-visible, select:focus-visible, textarea:focus-visible,
button:focus-visible, a:focus-visible, summary:focus-visible, [tabindex]:focus-visible {
  outline: 2px solid var(--ink); outline-offset: 2px;
}

/* ── login ─────────────────────────────────────────────────────────── */
.login { min-height: 100%; display: grid; place-items: center; padding: 24px; background: var(--bg); }
.login-card { width: min(380px, 100%); display: grid; gap: 14px; }
.login-mark { width: 116px; height: auto; margin-bottom: 4px; }
.login-card h1 { margin: 0; font-size: 26px; }
.login-card .sub { margin: -10px 0 8px; color: var(--muted); }

/* ── shell: three panels, RTL so the sidebar sits at the start edge ── */
.app { height: 100%; display: grid; grid-template-columns: 280px minmax(0, 1fr) 340px; }
.panel { min-height: 0; overflow: auto; background: var(--surface); }
.side { border-inline-start: 1px solid var(--line); display: flex; flex-direction: column; }
.center { background: var(--bg); position: relative; display: flex; flex-direction: column;
  /* The PANE scrolls, not the panel, so the tabs and the تحليل/طباعة buttons stay put while a long
     form or a long results page moves under them. (It was introduced to pin the watermark; the
     watermark has since moved to the sidebar, but keeping the header fixed is worth it on its own.) */
  overflow: hidden; }
.chat { border-inline-end: 1px solid var(--line); display: flex; flex-direction: column; }
.app.chat-collapsed { grid-template-columns: 280px minmax(0, 1fr) 44px; }
.app.chat-collapsed .chat-log,
.app.chat-collapsed .chat-form,
.app.chat-collapsed .chat-head span,
.app.chat-collapsed #chatClear { display: none; }
.app.chat-collapsed #chatToggle { transform: rotate(180deg); }

/* ── profile ───────────────────────────────────────────────────────── */
.profile { display: grid; grid-template-columns: auto 1fr auto; gap: 10px; align-items: center;
  padding: 16px; border-bottom: 1px solid var(--line); }
.avatar { position: relative; width: 46px; height: 46px; border-radius: 50%; overflow: hidden;
  background: var(--ink); color: var(--on-ink); display: grid; place-items: center; cursor: pointer; flex: none; }
.avatar img { width: 100%; height: 100%; object-fit: cover; display: none; }
.avatar img[src] { display: block; }
.avatar img[src] + span { display: none; }
.avatar span { font-weight: 600; font-size: 17px; }
.profile-text { min-width: 0; display: grid; gap: 2px; }
.field-inline input { width: 100%; border: 0; background: transparent; padding: 1px 4px;
  border-radius: 5px; outline: none; }
.field-inline input:hover { background: var(--line-soft); }
/* --line on --line-soft is 1.3:1 — the ring was there and invisible. --ink-2 reads at 5.2:1. */
.field-inline input:focus { background: var(--line-soft); box-shadow: inset 0 0 0 1px var(--ink-2); }
.profile-text .field-inline:first-child input { font-weight: 600; }
.profile-text .field-inline:last-child input { font-size: 12.5px; color: var(--muted); }

/* ── project list ──────────────────────────────────────────────────── */
.side-head { display: flex; align-items: center; justify-content: space-between;
  padding: 14px 16px 6px; font-size: 12px; color: var(--muted); letter-spacing: .04em; }
.search { margin: 0 16px 8px; padding: 7px 10px; border: 1px solid var(--line);
  border-radius: 8px; background: var(--surface); }
.search:focus { border-color: var(--ink); }
.project-list { flex: 1; overflow: auto; padding: 0 8px 8px; }
.project-item { width: 100%; text-align: start; background: none; border: 0; cursor: pointer;
  padding: 9px 10px; border-radius: 8px; display: grid; gap: 1px; }
.project-item:hover { background: var(--line-soft); }
.project-item.is-active { background: var(--ink); color: var(--on-ink); }
.project-item strong { font-weight: 500; font-size: 13.5px; }
.project-item small { font-size: 11.5px; color: var(--muted); }
.project-item.is-active small { color: rgba(10,10,10,.65); }
.side-foot { padding: 12px 16px; border-top: 1px solid var(--line); display: flex; gap: 14px; }

/* ── center ────────────────────────────────────────────────────────── */
/* The mark anchors the sidebar rather than sitting behind the workspace. Aziz's UI spec §2.2 asks
   for a centre-panel watermark; Mohammed's call was the CRM's shape instead, where a small mark in
   the chrome carries the brand and the working area stays clean. Noted in the README. */
/* This is the app's <h1>: the lockup names the product, so nothing visible has to be added to give
   the page a level-one heading. margin:0 keeps the browser's h1 margin out of the panel. */
.side-brand { margin: 0; padding: 18px 16px 14px; border-bottom: 1px solid var(--line); }
.side-brand img { width: 104px; height: auto; display: block; }
.center-head { position: sticky; top: 0; z-index: 2; background: var(--bg);
  border-bottom: 1px solid var(--line); padding: 0 22px;
  display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.tabs { display: flex; }
.tab { background: none; border: 0; padding: 15px 2px; margin-inline-end: 22px; cursor: pointer;
  color: var(--muted); border-bottom: 2px solid transparent; margin-bottom: -1px; }
.tab.is-active { color: var(--ink); border-bottom-color: var(--ink); font-weight: 600; }
.head-actions { display: flex; align-items: center; gap: 8px; }
.saved { font-size: 12px; color: var(--muted); }
.tabpane { display: none; padding: 22px; position: relative; z-index: 1; }
.tabpane.is-active { display: block; flex: 1; min-height: 0; overflow-y: auto; }

/* ── cards + forms ─────────────────────────────────────────────────── */
.card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r);
  padding: 18px; margin: 0 0 16px; box-shadow: var(--raise); }
legend, summary { font-size: 13px; padding: 0 4px; }
summary { cursor: pointer; font-weight: 600; }
.assumptions[open] summary { margin-bottom: 12px; }
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 12px; }
.grid.three { grid-template-columns: repeat(3, 1fr); margin-top: 12px; }
.col-2 { grid-column: span 2; }
label { display: grid; gap: 5px; font-size: 12.5px; color: var(--ink-2); }
label.checkbox { grid-auto-flow: column; justify-content: start; align-items: center; gap: 8px; }
input:not([type=checkbox]):not([type=file]), select {
  border: 1px solid var(--line); border-radius: 8px; padding: 8px 10px;
  background: var(--surface); width: 100%; }
/* The :not() chain scores (0,2,1); a bare `input:focus` scores (0,1,1) and never applied, so no
   field in the app — login included — changed on focus. The focus rule has to carry the same chain. */
input:not([type=checkbox]):not([type=file]):focus, select:focus { border-color: var(--ink); }
/* Same specificity trap: .search sets 16px side margins but inherits width:100% from the rule
   above, so the sidebar scrolled sideways (311px of content in a 279px panel) on every screen. */
input.search:not([type=file]) { width: auto; }
.unit { color: var(--faint); font-weight: 400; }
.opt { color: var(--faint); font-weight: 400; font-size: 11px; }
.note { font-size: 12px; color: var(--muted); margin: 10px 0 0; }
.form-foot { display: flex; gap: 10px; padding-bottom: 20px; }

/* ── units table ───────────────────────────────────────────────────── */
.table-scroll { overflow-x: auto; margin: 0 -4px; }
table { width: 100%; border-collapse: collapse; font-size: 13px; }
th { text-align: start; font-weight: 500; font-size: 11.5px; color: var(--muted);
  padding: 0 6px 8px; white-space: nowrap; }
td { padding: 3px 4px; }
.units input { padding: 6px 8px; min-width: 72px; }
.units td:first-child input { min-width: 120px; }
.row-del { border: 0; background: none; color: var(--faint); cursor: pointer; font-size: 17px; padding: 0 6px; }
.row-del:hover { color: var(--ink); }

/* ── buttons ───────────────────────────────────────────────────────── */
.btn { border: 1px solid var(--ink); background: var(--surface); color: var(--ink);
  padding: 8px 16px; border-radius: 8px; cursor: pointer; transition: .15s ease; }
.btn:hover { background: var(--line-soft); }
.btn.primary { background: var(--ink); color: var(--on-ink); }
.btn.primary:hover { background: var(--ink-2); }
.btn.ghost { border-color: var(--line); color: var(--ink-2); }
.btn.ghost:hover { border-color: var(--ink-2); }
/* There is no hue to spend on danger. A dashed edge marks «حذف المشروع» as a different kind of
   action from the solid-edged «حفظ» beside it, and the muted label keeps it from competing. */
.btn.danger { border-style: dashed; border-color: var(--muted); color: var(--muted); }
.btn.danger:hover { border-color: var(--ink); color: var(--ink); background: var(--line-soft); }
.btn.block { width: 100%; padding: 10px; }
.btn:disabled { opacity: .45; cursor: default; }
.icon-btn { border: 1px solid var(--line); background: var(--surface); border-radius: 7px;
  width: 26px; height: 26px; display: grid; place-items: center; cursor: pointer; padding: 0; line-height: 1; }
.icon-btn:hover { border-color: var(--ink); }
.link { background: none; border: 0; padding: 0; color: var(--muted); cursor: pointer;
  text-decoration: underline; text-underline-offset: 3px; font-size: 12.5px; }
.link:hover { color: var(--ink); }

/* ── results ───────────────────────────────────────────────────────── */

/* The two answers, side by side. Stacks on a narrow screen. Print keeps both columns: a sheet of
   paper is wider than the 900px mobile breakpoint, and the card is the first thing a client sees. */
.routes .route-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.routes .route { background: var(--bg); border: 1px solid var(--line); border-radius: var(--r); padding: 14px 16px; }
.routes .route h4 { margin: 0 0 10px; font-size: 13px; font-weight: 600; }
.routes .big { font-size: 34px; font-weight: 600; letter-spacing: -.02em; line-height: 1.1; }
.routes .mid { font-size: 22px; font-weight: 600; letter-spacing: -.02em; }
.routes .big span, .routes .mid span { font-size: 11.5px; color: var(--faint); font-weight: 400; margin-inline-start: 6px; }
/* Monochrome cannot lean on the sign alone: at 34px the minus is a 14px mark on the edge of the
   figure, and it is the only thing separating a gain from a loss. A negative headline says so in
   words, ahead of the number, in the foreground ink so it reads as part of the figure. */
.routes .big .loss, .routes .mid .loss { color: var(--ink); font-weight: 600;
  margin-inline-start: 0; margin-inline-end: 8px; }
.routes .rl { display: flex; justify-content: space-between; gap: 10px; padding: 4px 0; font-size: 12px; border-bottom: 1px solid var(--line-soft); }
.routes .rl:last-child { border-bottom: 0; }
.routes .rl span { color: var(--muted); }
.routes .rl b { font-weight: 500; font-variant-numeric: tabular-nums; }
.routes .route-sub { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--line); }
.routes .route-sub h5 { margin: 0 0 6px; font-size: 11.5px; font-weight: 500; color: var(--muted); }
.routes .headline-note { margin: 14px 0 0; font-size: 15px; }
@media (max-width: 900px) { .routes .route-cols { grid-template-columns: 1fr; } }
@media print { .routes .route-cols { grid-template-columns: 1fr 1fr; } }
/* With no rent estimate there is no second route to show, and a 1fr 1fr grid would stretch the one
   remaining column's sibling to its height. Outranks both rules above, print included. */
.routes .route-cols.one { grid-template-columns: 1fr; }

.result-card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r);
  padding: 18px; margin-bottom: 16px; box-shadow: var(--raise); }
.result-card > h3 { margin: 0 0 4px; font-size: 15px; }
.result-card > .cap { margin: 0 0 14px; font-size: 12px; color: var(--muted); }
/* A second section inside a card — the deed evidence under the trend it proves. The child
   combinator keeps it off the routes card's own h4, which is a column heading, not a section. */
.result-card > h4 { margin: 20px 0 8px; font-size: 12.5px; font-weight: 600; }
/* On a phone the auto table layout crushed six columns into the card width and wrapped «شقة غرفتين»
   onto three lines rather than letting the wrapper do the one job it exists for. A floor, so the
   columns keep their shape and the scroll container scrolls. */
.table-scroll .data-table { min-width: 560px; }
.data-table th { border-bottom: 1px solid var(--line); }
.data-table td { padding: 9px 6px; border-bottom: 1px solid var(--line-soft); }
.data-table tr:last-child td { border-bottom: 0; }
.data-table .num { font-variant-numeric: tabular-nums; white-space: nowrap; }
.data-table tbody tr.is-base { background: var(--line-soft); font-weight: 500; }
/* A second value that belongs to the cell above it rather than to a column of its own — the unit's
   area under its name, the price per m² under its price. Two columns became one, twice. */
.data-table .sub { display: block; font-size: 11px; color: var(--faint); font-weight: 400; }
.chart-box { position: relative; height: 240px; }
/* A chart's own caption sits under it, tighter than a paragraph between two blocks. */
.chart-note { margin-top: 8px; }
.tag { display: inline-block; font-size: 10.5px; padding: 1px 7px; border: 1px solid var(--line);
  border-radius: 999px; color: var(--muted); vertical-align: middle; }
.tag.fact { border-color: var(--ink); color: var(--ink); }
.sources { font-size: 12px; color: var(--muted); }
.sources ul { margin: 6px 0 14px; padding-inline-start: 18px; }
.sources li { margin-bottom: 3px; }
.sources a { color: var(--ink-2); }
.sources h4 { margin: 0 0 8px; font-size: 12.5px; color: var(--ink); }
/* Reference sites, as a wrapped row of links rather than a bullet each — they are a list of names,
   not a list of statements. */
.src-hosts { display: flex; flex-wrap: wrap; gap: 6px 14px; margin: 6px 0 14px; padding: 0; list-style: none; }
.src-hosts li { margin: 0; }
/* Registered deed numbers are the most persuasive artefact a Saudi buyer can be shown; they get a
   table with named columns, not five em-dash-separated values on one bullet. */
.deeds-table { margin-bottom: 14px; }
.deeds-table td { color: var(--ink-2); }
.deeds-table .ref { color: var(--ink); font-weight: 500; }
/* «قراءة السوق» was six paragraphs of AI prose at one weight and nobody read it. A label/value grid
   makes it scannable: the label is the muted column, the reading is the foreground one. */
.read { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 9px 16px; margin: 0 0 14px; }
.read dt { color: var(--muted); white-space: nowrap; font-size: 12px; }
.read dd { margin: 0; color: var(--ink-2); font-size: 13px; line-height: 1.55; }
@media (max-width: 560px) {
  .read { grid-template-columns: 1fr; gap: 2px; }
  .read dd { margin-bottom: 10px; }
}
/* Material the operator needs and the client must not be handed. Excluded from print. */
.internal-only { margin-top: 14px; padding-top: 12px; border-top: 1px dashed var(--line); }
/* Now a <details>, so its own summary says «للاستخدام الداخلي» and the standalone note that used to
   say it above the block is gone; the :first-child rule that styled that note went with it. */
.internal-only > summary { color: var(--muted); font-weight: 500; }
.disclaimer { border: 1px solid var(--line); border-radius: var(--r); padding: 12px 16px;
  font-size: 12.5px; color: var(--ink-2); background: var(--line-soft); }

/* ── map ───────────────────────────────────────────────────────────── */
.map-wrap { position: relative; height: 240px; border: 1px solid var(--line);
  border-radius: 8px; overflow: hidden; margin-bottom: 12px; }
.map { position: absolute; inset: 0; }
.map-fallback { position: absolute; inset: 0; display: grid; place-items: center;
  background: var(--line-soft); color: var(--muted); font-size: 12.5px; text-align: center; padding: 20px; }

/* ── chat ──────────────────────────────────────────────────────────── */
.chat-head { display: flex; align-items: center; gap: 10px; padding: 12px 14px;
  border-bottom: 1px solid var(--line); font-size: 12px; color: var(--muted); }
.chat-head span { flex: 1; }
.chat-log { flex: 1; overflow: auto; padding: 14px; display: flex; flex-direction: column; gap: 10px; }
.bubble { max-width: 92%; padding: 9px 12px; border-radius: 12px; font-size: 13px; white-space: pre-wrap;
  overflow-wrap: anywhere; }
.bubble.user { align-self: flex-start; background: var(--ink); color: var(--on-ink); border-end-start-radius: 4px; }
.bubble.model { align-self: flex-end; background: var(--line-soft); border-end-end-radius: 4px; }
.bubble.chart { width: 100%; max-width: 100%; background: var(--surface); border: 1px solid var(--line); }
.bubble .chart-box { height: 190px; }
.chat-form { display: flex; gap: 8px; padding: 12px; border-top: 1px solid var(--line); }
.chat-form input { flex: 1; }
.typing { color: var(--muted); font-size: 12px; align-self: flex-end; }

/* ── misc ──────────────────────────────────────────────────────────── */
.empty { text-align: center; padding: 70px 20px; color: var(--muted); }
.empty h2 { color: var(--ink); margin: 0 0 6px; font-size: 18px; }
.err { border: 1px solid var(--ink); border-radius: 8px; padding: 9px 12px; font-size: 12.5px; }
.deed-hint { margin-top: 12px; padding: 10px 12px; background: var(--line-soft);
  border-radius: 8px; font-size: 12.5px; color: var(--ink-2); }
.toast { position: fixed; inset-block-end: 22px; inset-inline-start: 50%; transform: translateX(50%);
  background: var(--ink); color: var(--on-ink); padding: 10px 18px; border-radius: 999px; font-size: 13px; z-index: 50; }
.dlg { border: 1px solid var(--line); border-radius: var(--r); padding: 22px; max-width: 520px; width: 92%;
  background: var(--surface); color: var(--ink);
  box-shadow: 0 20px 60px -20px rgba(0,0,0,.4); }
.dlg::backdrop { background: rgba(0,0,0,.7); }
.dlg h3 { margin: 0 0 14px; }
.users-list { margin-bottom: 16px; font-size: 13px; }
.users-list .row { display: flex; justify-content: space-between; align-items: center;
  padding: 7px 0; border-bottom: 1px solid var(--line-soft); }
.progress { font-size: 12.5px; color: var(--muted); display: grid; gap: 3px; margin-top: 10px; }

/* ── responsive: the three panels become one column on a tablet ──────
   Each panel docks to the edge it already occupies in the desktop grid and slides off THAT edge.
   The two are opposite: in this RTL shell the sidebar's edge is inline-start (right) and the chat's
   is inline-end (left). Logical insets flip with the document direction; translateX does not — it
   is physical, so the two panels take opposite signs and neither one flips with the inset. */
.drawer-btn { display: none; }
@media (max-width: 1100px) {
  .app { grid-template-columns: 240px minmax(0, 1fr); }
  .chat { position: fixed; inset-block: 0; inset-inline-end: 0; width: min(360px, 90vw);
    z-index: 30; box-shadow: 0 0 60px rgba(0,0,0,.2); transform: translateX(-100%); transition: transform .2s ease; }
  .app.chat-open .chat { transform: none; }
  .app.chat-collapsed { grid-template-columns: 240px minmax(0, 1fr); }
  #chatDrawer { display: grid; }
  /* A drawer covering the workspace has to be dismissable by pressing the workspace. */
  .app.chat-open::after { content: ''; position: fixed; inset: 0; background: rgba(0,0,0,.55); z-index: 29; }
}
@media (max-width: 760px) {
  .app { grid-template-columns: 1fr; }
  .side { position: fixed; inset-block: 0; inset-inline-start: 0; width: min(300px, 88vw); z-index: 30;
    transform: translateX(100%); transition: transform .2s ease; box-shadow: 0 0 60px rgba(0,0,0,.2); }
  .app.side-open .side { transform: none; }
  #sideDrawer { display: grid; }
  .col-2 { grid-column: auto; }
  .grid.three { grid-template-columns: 1fr; }
  /* The header runs out of room before the panels do. */
  .center-head { padding: 0 12px; gap: 6px; }
  .tab { margin-inline-end: 14px; }
  .head-actions { gap: 6px; }
  .app.side-open::after { content: ''; position: fixed; inset: 0; background: rgba(0,0,0,.55); z-index: 29; }
}
@media (prefers-reduced-motion: reduce) { .side, .chat { transition: none; } }

/* ── print: the results become the client-facing document ──────────────
   Paper is white, so the palette flips back for print rather than burning a
   page of toner — and a dark-theme colour would otherwise print white-on-white.
   Redefining the tokens re-themes every component at once. */
@media print {
  :root {
    /* --faint was #8a8a8a: 3.45:1 on paper, the same AA failure as the dark theme's. */
    --ink: #0a0a0a; --ink-2: #3d3d3d; --muted: #5a5a5a; --faint: #6f6f6f;
    --line: #d8d8d8; --line-soft: #f2f2f2; --surface: #ffffff; --bg: #ffffff;
    --on-ink: #ffffff; --chart-fill: rgba(10,10,10,.06); --raise: none;
    /* The light cyan is all but invisible on paper, so print swaps the hue rather than dimming it:
       #0E6D7D is 6.00:1 on white and the same colour family, so the printed sheet reads as the
       same document. app.js re-resolves both from the stylesheet on beforeprint/afterprint. */
    --accent: #0E6D7D; --accent-fill: rgba(14,109,125,.10);
    color-scheme: light;
  }
  .side, .chat, .center-head, .form-foot, .drawer-btn { display: none !important; }
  /* The client's copy is a document about a named project, not an anonymous sheet of numbers. */
  .internal-only { display: none !important; }
  .print-head { display: grid !important; grid-template-columns: auto 1fr auto; align-items: end;
    gap: 8px 18px; border-bottom: 2px solid var(--ink); padding-bottom: 12px; margin-bottom: 20px; }
  .print-title { margin: 0; font-size: 21px; font-weight: 600; letter-spacing: -.01em; }
  .print-where { margin: 3px 0 0; font-size: 12.5px; color: var(--muted); }
  .print-meta { margin: 0; font-size: 11px; text-align: end; }
  .print-meta div + div { margin-top: 2px; }
  .print-meta dt, .print-meta dd { display: inline; margin: 0; }
  .print-meta dt { color: var(--muted); }
  .print-meta dt::after { content: ' '; }
  .print-meta dd { font-weight: 500; }
  body, .center { background: #fff; color: var(--ink); }
  .app { display: block; height: auto; }
  .panel { overflow: visible; }
  .tabpane { display: none !important; padding: 0; }
  .tabpane#pane-results { display: block !important; overflow: visible; }
  .result-card { break-inside: avoid; box-shadow: none; }
  .chart-box { height: 200px; }
  /* The mark is white artwork; on paper it needs inverting to stay visible. */
  .print-mark { display: block !important; filter: invert(1); width: 112px; margin: 0; }
}
.print-mark, .print-head { display: none; }

/* Strategy assumptions live inside the assumptions drawer; the first column is a label, not a field. */
.sub-legend { font-size: 12.5px; font-weight: 600; margin: 20px 0 8px; color: var(--ink); }
.strategy-assumptions td:first-child { color: var(--ink-2); white-space: nowrap; padding-inline-end: 12px; }
.strategy-assumptions input { min-width: 84px; }

/* ── loading screen ───────────────────────────────────────────────────
   Shown from first paint on every load, before the login screen, and removed
   once the app has finished loading. It is deliberately not dismissable, so
   app.js also enforces a hard ceiling — a stalled network must never leave
   someone stuck behind a splash they cannot click away. */
.splash {
  position: fixed; inset: 0; z-index: 100;
  background: var(--bg);
  display: grid; place-items: center;
  opacity: 1; transition: opacity .5s ease;
}
.splash.is-gone { opacity: 0; pointer-events: none; }

/* The portrait sits top-centre at a natural scale rather than being blown up
   to cover the viewport, which would crop his face at desktop widths. */
/* Centred with a grid, not with inset+translate: `inset-inline-start: 50%` flips to `right` in
   RTL, so a negative translateX pushed him off to one side. A grid centres in both directions. */
.splash-portrait { position: absolute; inset: 0; overflow: hidden; display: grid; justify-items: center; align-content: start; }
.splash-portrait img {
  height: min(60vh, 540px); width: auto; max-width: none;
  object-fit: contain;
  /* Its own black backdrop does most of the blending; this finishes the edges
     so there is no visible rectangle against the page. */
  -webkit-mask-image:
    radial-gradient(ellipse 72% 68% at 50% 36%, #000 50%, transparent 84%),
    linear-gradient(to bottom, #000 0%, #000 54%, transparent 92%);
  -webkit-mask-composite: source-in;
          mask-image:
    radial-gradient(ellipse 72% 68% at 50% 36%, #000 50%, transparent 84%),
    linear-gradient(to bottom, #000 0%, #000 54%, transparent 92%);
          mask-composite: intersect;
  opacity: .82;
  animation: splash-rise 1.6s cubic-bezier(.22,1,.36,1) both;
}
/* A scrim under the lockup so the white mark always has contrast to sit on,
   whatever falls behind it. */
.splash-portrait::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(to bottom, rgba(10,10,10,.10) 0%, rgba(10,10,10,.45) 52%, var(--bg) 80%);
}

.splash-center {
  position: relative; z-index: 1;
  display: grid; justify-items: center; gap: 22px;
  transform: translateY(19vh);
  animation: splash-in .9s .25s cubic-bezier(.22,1,.36,1) both;
}
.splash-logo { width: min(200px, 46vw); height: auto; }

/* The screen is left by pressing this, not by waiting — so it has to read as the
   one thing to do here, and be reachable by keyboard like any other control. */
.splash-enter { padding: 11px 26px; border-radius: 999px; font-size: 13.5px; }
.splash-enter:disabled { opacity: .6; }

.splash-who {
  position: absolute; z-index: 1;
  inset-block-end: 7vh; inset-inline-start: 8vw;
  animation: splash-who-in .9s .55s cubic-bezier(.22,1,.36,1) both;
}
.splash-name { font-size: 15px; font-weight: 600; letter-spacing: -.01em; }
.splash-title { font-size: 12.5px; color: var(--muted); margin-top: 1px; }

@keyframes splash-rise { from { opacity: 0; transform: translateY(16px) scale(1.02); } }
@keyframes splash-in   { from { opacity: 0; transform: translateY(calc(19vh + 10px)); } }
/* Its own: .splash-who carries no base transform, so reusing splash-in would fly it in from 19vh. */
@keyframes splash-who-in { from { opacity: 0; transform: translateY(10px); } }
.splash-center { animation-name: splash-in; }

@media (prefers-reduced-motion: reduce) {
  .splash-portrait img, .splash-center, .splash-who { animation: none; }
}
@media (max-width: 760px) {
  .splash-portrait img { height: min(46vh, 400px); }
  .splash-center { transform: translateY(15vh); }
  .splash-who { inset-inline-start: 7vw; inset-block-end: 6vh; }
}
/* Never on paper. */
@media print { .splash { display: none !important; } }
