:root {
  --bg: #f5f2ec;
  --bg-glow: #fbf7f0;
  --panel: #ffffff;
  --ink: #211d18;
  --muted: #6f695d;
  --line: #e7e0d4;
  --line-strong: #d9cfbe;
  --accent: #8a4a1d;
  --accent-2: #b0632a;
  --accent-ink: #6d3914;
  --accent-soft: #f4ebe0;
  --ring: rgba(138, 74, 29, .26);

  --radius: 12px;
  --radius-sm: 7px;
  --shadow-sm: 0 1px 2px rgba(48, 34, 20, .05);
  --shadow: 0 3px 10px rgba(60, 44, 26, .06), 0 1px 3px rgba(60, 44, 26, .05);
  --shadow-lg: 0 14px 40px rgba(60, 44, 26, .12);

  /* Provenance colours. These are semantic, not decorative — they are how a
     reader tells computed fact from tradition at a glance. */
  --computed: #1d6b4f;
  --computed-bg: #e7f3ee;
  --rule: #6b4d9e;
  --rule-bg: #efe9f7;
  --supplied: #a8641a;
  --supplied-bg: #fbf0e2;
  --inferred: #8a8378;
  --inferred-bg: #f0eeea;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font: 15px/1.62 "Segoe UI", system-ui, sans-serif;
  color: var(--ink);
  background:
    radial-gradient(1200px 480px at 82% -10%, var(--bg-glow), transparent 60%),
    var(--bg);
  overflow-x: hidden;   /* nothing here should ever scroll the page sideways */
  -webkit-font-smoothing: antialiased;
}

/* ---- application shell: vertical sidebar + content column ----
   The sidebar is a warm-dark surface, distinct from the parchment content so
   the eye separates chrome from work. It is entirely decorative navigation:
   the print rules below strip it, so a report PDF carries none of it. */
.app-shell { display: flex; min-height: 100vh; align-items: stretch; }

.sidebar {
  --side-ink: #efe6d8;
  --side-muted: #b7a892;
  flex: 0 0 236px;
  align-self: stretch;
  position: sticky;
  top: 0;
  height: 100vh;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  background: linear-gradient(180deg, #3a2c1e, #2c2015);
  color: var(--side-ink);
  border-right: 1px solid #241a10;
}

.brandmark {
  display: flex; gap: 11px; align-items: center;
  padding: 20px 18px 16px; text-decoration: none; color: var(--side-ink);
  border-bottom: 1px solid rgba(255, 255, 255, .07);
}
.brandmark .emblem { flex: 0 0 auto; }
.wordmark { font-size: 16px; font-weight: 650; letter-spacing: .2px; }
.tagline { font-size: 10.5px; color: var(--side-muted); margin-top: 1px; }
.triad { font-size: 10px; color: #d9a441; margin-top: 4px; letter-spacing: .04em; }
.triad span { margin: 0 3px; }
.triad span:first-child { margin-left: 0; }

.nav { flex: 1 1 auto; padding: 12px 12px 8px; }
.nav-group { margin-bottom: 14px; }
.nav-head {
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .08em;
  color: var(--side-muted); padding: 4px 10px; margin-top: 4px;
}
.nav a[data-nav] {
  display: flex; align-items: center; gap: 11px;
  padding: 9px 10px; border-radius: 8px; margin: 1px 0;
  color: var(--side-ink); text-decoration: none; font-size: 13.5px;
  transition: background .15s, color .15s;
}
.nav a[data-nav] .ico { flex: 0 0 auto; opacity: .8; }
.nav a[data-nav]:hover { background: rgba(255, 255, 255, .07); }
.nav a[data-nav].active {
  background: #d9a441; color: #2c2015; font-weight: 600;
}
.nav a[data-nav].active .ico { opacity: 1; }

.sidebar-foot {
  padding: 12px 16px 18px; border-top: 1px solid rgba(255, 255, 255, .07);
  position: relative;
}
.sidebar-cta { width: 100%; justify-content: center; display: block; text-align: center; }
.logout-form { margin: 8px 0 0; }
.sidebar-logout {
  width: 100%; background: none; border: 1px solid rgba(255, 255, 255, .16);
  color: var(--side-muted); font: inherit; font-size: 13px; cursor: pointer;
  padding: 7px 0; border-radius: 8px; transition: color .15s, border-color .15s;
}
.sidebar-logout:hover { color: var(--side-ink); border-color: rgba(255, 255, 255, .32); }
.sidebar-om {
  position: absolute; right: 16px; bottom: 12px;
  font-size: 30px; color: rgba(217, 164, 65, .18); pointer-events: none;
}

/* ---- login ---- */
.login-main { max-width: 430px; margin: 12vh auto; padding: 0 16px; }
.login-panel { box-shadow: var(--shadow-lg); border-color: var(--line-strong); }
.login-panel h1 {
  display: inline-flex; align-items: center; gap: 10px; font-size: 20px;
}
.login-panel h1::before {
  content: ""; width: 20px; height: 20px; border-radius: 5px;
  background: linear-gradient(135deg, var(--accent-2), var(--accent));
  transform: rotate(45deg); box-shadow: 0 3px 9px var(--ring);
}
.login-panel h2 { margin-top: 4px; }

/* The content column, right of the sidebar. flex-grow:0 with an auto basis plus
   auto side margins so it CENTRES in the space beside the sidebar rather than
   hugging it — the auto-margin trick is the one place it works on a flex item,
   because with no grow there is free space for the margins to absorb. */
main {
  flex: 0 1 auto; width: 100%; min-width: 0;
  max-width: 1060px; margin-inline: auto; padding: 30px 30px 90px;
}
/* Data-entry pages (client and property forms, client detail) run wider so the
   repeating family/event rows fit on a single line. Reports keep the narrower
   1060px measure, which reads better and matches the A4 export. */
main.wide { max-width: 1340px; }

h2 {
  font-size: 21px; margin: 34px 0 15px; font-weight: 650; letter-spacing: -.01em;
  padding-left: 13px; position: relative;
}
h2::before {
  content: ""; position: absolute; left: 0; top: .18em; bottom: .18em;
  width: 4px; border-radius: 3px;
  background: linear-gradient(180deg, var(--accent-2), var(--accent));
}
h3 { font-size: 12.5px; margin: 22px 0 11px; font-weight: 700; color: var(--muted);
     text-transform: uppercase; letter-spacing: .09em; }

a { color: var(--accent); text-decoration-color: var(--ring); text-underline-offset: 2px; }
a:hover { color: var(--accent-ink); }

.panel {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 22px 24px;
  margin-bottom: 18px;
  box-shadow: var(--shadow);
}
/* The h3 that opens a panel gets a hairline under it for structure. */
.panel > h3:first-child {
  margin-top: 0; padding-bottom: 11px; margin-bottom: 15px;
  border-bottom: 1px solid var(--line);
}

/* ---- forms ---- */
.grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 15px 18px; }
.grid.three { grid-template-columns: repeat(3, 1fr); }
.grid.four { grid-template-columns: repeat(4, 1fr); }
.field { display: flex; flex-direction: column; gap: 5px; }
.field.wide { grid-column: 1 / -1; }
label { font-size: 12px; color: var(--muted); font-weight: 600; letter-spacing: .01em; }
label .req { color: #b3401f; }
input, select, textarea {
  font: inherit;
  padding: 9px 11px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: #fefdfb;
  color: var(--ink);
  transition: border-color .15s, box-shadow .15s, background .15s;
}
input:hover, select:hover, textarea:hover { border-color: #c9bda9; }
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3.5px var(--ring);
  background: #fff;
}
textarea { min-height: 74px; resize: vertical; }
.hint { font-size: 12px; color: var(--muted); margin-top: 3px; line-height: 1.5; }
.hint code {
  background: var(--accent-soft); color: var(--accent-ink);
  padding: 1px 5px; border-radius: 4px; font-size: .92em;
}

button, .btn {
  font: inherit; font-weight: 600; font-size: 14px;
  padding: 9px 18px;
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  background: linear-gradient(180deg, var(--accent-2), var(--accent));
  color: #fff;
  cursor: pointer;
  text-decoration: none;
  display: inline-block;
  box-shadow: var(--shadow-sm);
  transition: transform .12s, box-shadow .15s, filter .15s;
}
button:hover, .btn:hover { filter: brightness(1.05); box-shadow: var(--shadow); transform: translateY(-1px); }
button:active, .btn:active { transform: translateY(0); box-shadow: var(--shadow-sm); }
button:focus-visible, .btn:focus-visible { outline: none; box-shadow: 0 0 0 3.5px var(--ring); }
.btn.ghost, button.ghost {
  background: #fff; color: var(--accent);
  border-color: var(--line-strong); box-shadow: none;
}
.btn.ghost:hover, button.ghost:hover {
  background: var(--accent-soft); border-color: var(--accent); filter: none;
}
.btn.danger, button.danger {
  background: linear-gradient(180deg, #b8492f, #9c2f1c);
  border-color: transparent; color: #fff;
}
.btn.danger:hover, button.danger:hover { color: #fff; }
.actions { display: flex; gap: 10px; align-items: center; margin-top: 20px; flex-wrap: wrap; }

/* A <button> that reads as an inline text link, for row-action cells where a
   POST form needs a real button but a full button would overwhelm the row. */
button.linklike {
  background: none; border: none; padding: 0; margin: 0; font: inherit;
  color: var(--accent); cursor: pointer; box-shadow: none; text-decoration: underline;
}
button.linklike:hover { filter: none; background: none; }
button.linklike.danger { color: #b8492f; background: none; }
.row-actions { white-space: nowrap; }
.row-actions form { margin: 0; }

/* Paid order page (/get-report) — product chooser with live total. */
.order-products { display: grid; gap: 10px; }
.order-product {
  display: grid; grid-template-columns: auto 1fr auto; align-items: center;
  gap: 10px 12px; padding: 12px 14px; border: 1px solid var(--line);
  border-radius: 8px; cursor: pointer;
}
.order-product:hover { border-color: var(--accent); }
.order-product .op-name { font-weight: 600; }
.order-product .op-price { font-weight: 700; color: var(--accent-ink); white-space: nowrap; }
.order-product .op-note {
  grid-column: 2 / -1; font-size: .85rem; color: var(--muted); margin-top: 2px;
}
.order-product.is-muted { opacity: .45; }
.order-total {
  margin-top: 14px; font-size: 1.1rem; text-align: right;
}
.order-total b { color: var(--accent-ink); font-size: 1.35rem; }

/* Horoscope reading — the confident life-area narrative. Lead sits above each
   section's prose; the timing windows read as a clean date list. */
.horo-lead {
  font-size: 1.05rem; font-weight: 600; color: var(--accent-ink);
  margin: 0 0 10px;
}
.horo-windows {
  margin: 6px 0 0; padding-left: 0; list-style: none;
  border-top: 1px solid var(--line);
}
.horo-windows li {
  padding: 6px 0 6px 18px; border-bottom: 1px solid var(--line);
  position: relative; font-size: .95rem;
}
.horo-windows li::before {
  content: "▸"; position: absolute; left: 0; color: var(--accent);
}

/* On-screen report branding. The print cover (_report_cover) is PDF-only, so
   without this the logo and devotional image the practitioner uploads in
   Settings never appear on screen. */
.report-brand {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  padding: 14px 0 18px; border-bottom: 1px solid var(--line);
  margin-bottom: 18px;
}
.report-brand-logo { height: 56px; width: auto; }
.report-brand-cover { height: 72px; width: auto; border-radius: 6px; margin-left: auto; }
.report-brand-name { font-size: 1.15rem; font-weight: 600; }
.report-brand-tagline { color: var(--muted); font-size: .9rem; }

/* Sticky save bar — the settings page is long and its lower panels (test
   delivery, partner sites) sit below the practice form's Save, so keep Save in
   view while the operator scrolls the form it belongs to. */
.save-bar {
  position: sticky; bottom: 0; z-index: 4;
  background: var(--bg); border-top: 1px solid var(--line);
  padding: 12px 0; margin-top: 20px;
}

/* ---- repeating rows ----
   Flex-wrap rather than fixed grid columns. Grid items default to
   min-width:auto, so inputs refuse to shrink below their intrinsic size and
   push the whole page into horizontal scroll. Wrapping degrades cleanly at any
   width; min-width:0 is what actually lets the fields narrow. */
.rowset { display: flex; flex-direction: column; gap: 8px; }
.row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 10px;
  align-items: flex-end;
  padding: 10px 12px;
  background: #fcfbf9;
  border: 1px solid var(--line);
  border-radius: 4px;
}
.row .field { flex: 1 1 125px; min-width: 0; }
.row .field.grow { flex: 2.2 1 200px; }
.row .field.narrow { flex: 0 1 95px; }
.row .field.dt { flex: 1.4 1 175px; }
.row input,
.row select { width: 100%; min-width: 0; }

.row .rm {
  flex: 0 0 auto;
  margin-left: auto;
  align-self: flex-end;
  background: transparent;
  border: 1px solid var(--line);
  color: var(--muted);
  padding: 7px 10px;
  border-radius: 4px;
  line-height: 1;
}
.row .rm:hover { color: #a03020; border-color: #a03020; }

.checkcell {
  flex: 0 0 auto;
  display: flex; align-items: center; gap: 5px;
  padding-bottom: 9px; white-space: nowrap;
}
.checkcell input { width: auto; min-width: 0; }

/* ---- tables ---- */
table { width: 100%; border-collapse: collapse; font-size: 14px; }
th, td { text-align: left; padding: 9px 11px; border-bottom: 1px solid var(--line); }
th { font-size: 11px; text-transform: uppercase; letter-spacing: .07em; color: var(--muted); font-weight: 700; }
tbody tr { transition: background .12s; }
tbody tr:hover { background: var(--accent-soft); }
tbody tr:last-child td { border-bottom: none; }
/* Numeric columns right-align, and the HEADER must follow the cells — a
   left-aligned header sitting over right-aligned figures reads as a bug. */
th.num, td.num { text-align: right; }
td.num { font-variant-numeric: tabular-nums; }

/* ---- provenance tags ---- */
.tag {
  display: inline-block;
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: .7px;
  padding: 2px 7px;
  border-radius: 3px;
  font-weight: 600;
  vertical-align: middle;
}
.tag.computed      { color: var(--computed); background: var(--computed-bg); }
.tag.rule_derived  { color: var(--rule);     background: var(--rule-bg); }
.tag.user_supplied { color: var(--supplied); background: var(--supplied-bg); }
.tag.inferred      { color: var(--inferred); background: var(--inferred-bg); }
.tag.traditional   { color: var(--supplied); background: var(--supplied-bg); }
.tag.building_science { color: var(--computed); background: var(--computed-bg); }
.tag.behavioral    { color: var(--rule); background: var(--rule-bg); }

.note {
  font-size: 13px;
  color: var(--muted);
  border-left: 3px solid var(--line-strong);
  padding: 7px 0 7px 13px;
  margin: 11px 0;
}
.note.warn {
  border-left-color: #cf962f;
  background: linear-gradient(180deg, #fdf7ea, #fcf3e0);
  padding: 11px 14px; border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  color: #7a5a1c;
}
.source { font-size: 12px; color: var(--muted); font-style: italic; }

/* "In plain words" — a plain-English explainer under a section heading. Calm,
   clearly set apart from the reading itself, and kept in print. */
.plainwords {
  display: flex; gap: 12px; align-items: flex-start;
  font-size: 13.5px; line-height: 1.6; color: var(--ink);
  background: var(--accent-soft, #f3ede1);
  border: 1px solid var(--line); border-left: 3px solid var(--accent, #b4763b);
  border-radius: var(--radius-sm); padding: 11px 15px; margin: 10px 0 16px;
}
.plainwords .pw-label {
  flex: 0 0 auto; font-size: 11px; letter-spacing: .06em; text-transform: uppercase;
  font-weight: 700; color: var(--accent, #b4763b); padding-top: 2px; white-space: nowrap;
}

.empty {
  color: var(--muted); padding: 34px; text-align: center;
  background: #fbf9f5; border: 1px dashed var(--line-strong);
  border-radius: var(--radius-sm); font-size: 13.5px;
}

/* ---- place picker (search a place / drag a pin to fill lat & lon) ---- */
.placepicker { margin-top: 4px; }
.pp-controls { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.pp-controls .pp-search { flex: 1 1 260px; min-width: 0; }
.pp-controls button { padding: 8px 14px; font-size: 13.5px; }
.pp-results {
  margin-top: 7px; border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
  overflow: hidden; background: #fff; box-shadow: var(--shadow-sm);
}
.pp-result {
  display: block; width: 100%; text-align: left; background: #fff;
  border: none; border-bottom: 1px solid var(--line); border-radius: 0;
  padding: 9px 12px; font-size: 13px; color: var(--ink); font-weight: 400;
  box-shadow: none; transform: none;
}
.pp-result:last-child { border-bottom: none; }
.pp-result:hover { background: var(--accent-soft); color: var(--accent-ink); transform: none; box-shadow: none; filter: none; }
.pp-map {
  height: 320px; margin-top: 9px;
  border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
  overflow: hidden; z-index: 0;   /* keep tiles under the sticky header */
}
/* In a repeating row the picker is collapsed behind one button and, when
   opened, breaks onto its own full-width line beneath the row's fields — so a
   row still reads as a row. */
.pp-cell { flex: 0 0 auto; }
.pp-cell button { width: 100%; padding: 9px 12px; font-size: 13px; white-space: nowrap; }
.placepicker.pp-inrow {
  flex: 1 1 100%; margin-top: 10px; padding-top: 11px;
  border-top: 1px dashed var(--line-strong);
  /* Rendered last whatever its DOM position, so the full-width strip cannot
     push the row's ✕ button onto a line of its own. */
  order: 99;
}
.placepicker.pp-inrow[hidden] { display: none; }
.placepicker.pp-inrow .pp-map { height: 260px; }

.pp-status { font-size: 12px; color: var(--muted); margin-top: 6px; min-height: 1em; }
.pp-status.is-error { color: #a03020; }
/* Marker drawn in CSS so no icon images need vendoring beside leaflet.js. */
.pp-pin {
  background: var(--accent); border: 2.5px solid #fff; border-radius: 50%;
  box-shadow: 0 2px 8px rgba(60, 44, 26, .45); cursor: grab;
}

/* ---- tabs (long forms and detail pages) ---- */
.tabbar {
  display: flex; flex-wrap: wrap; gap: 4px;
  background: #efe9df; padding: 5px; border-radius: var(--radius);
  margin-bottom: 20px; box-shadow: inset 0 1px 2px rgba(60, 44, 26, .05);
}
.tab-btn {
  flex: 1 1 auto; min-width: 120px;
  background: transparent; color: var(--muted); border: none;
  padding: 9px 14px; border-radius: 8px; box-shadow: none;
  font-weight: 600; font-size: 13.5px; letter-spacing: .01em;
  transition: color .15s, background .15s, box-shadow .15s; transform: none;
}
.tab-btn:hover { color: var(--accent-ink); background: rgba(255,255,255,.55); transform: none; box-shadow: none; filter: none; }
.tab-btn.is-active {
  background: #fff; color: var(--accent-ink);
  box-shadow: var(--shadow-sm); transform: none;
}
.tab-btn .tab-count {
  display: inline-block; min-width: 18px; margin-left: 6px; padding: 0 5px;
  font-size: 11px; line-height: 17px; border-radius: 9px;
  background: var(--accent-soft); color: var(--accent);
}
.tab-panel[hidden] { display: none; }
.tab-panel { animation: tabfade .22s ease; }
@keyframes tabfade { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }

/* On the report the panels are long, so the tab strip sticks to the top of the
   viewport as you scroll one — you can switch section without scrolling back
   up. The strip is opaque, so content scrolling beneath it stays legible. */
.report-tabs > .tabbar {
  position: sticky; top: 0; z-index: 5;
  box-shadow: 0 2px 8px rgba(60, 44, 26, .07);
}

/* ---- direction checkbox grid ---- */
.dirgrid { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 8px; }
.dirbox {
  display: flex; align-items: center; gap: 6px;
  padding: 7px 13px; border: 1px solid var(--line); border-radius: 4px;
  background: #fff; cursor: pointer; font-size: 13.5px; font-weight: 600;
  color: var(--ink);
}
.dirbox input { width: auto; margin: 0; }
.dirbox:hover { border-color: var(--accent); }
.dirbox:has(input:checked) { background: var(--accent-soft); border-color: var(--accent); }

/* ---- uploaded document previews ---- */
.doc-gallery {
  display: flex; flex-wrap: wrap; gap: 18px; margin: 12px 0 6px;
}
.doc-card {
  /* 0 0 260px, not width:260px — a flex item with the default shrink factor
     collapses to a sliver when the container is narrow, taking the caption
     with it and turning one line of text into a column of single characters.
     Wrapping is the wanted behaviour; shrinking is not. */
  margin: 0; flex: 0 0 260px; max-width: 100%;
  border: 1px solid var(--line); border-radius: 5px;
  background: #fff; overflow: hidden;
}
.doc-card img {
  display: block; width: 100%; height: 190px;
  object-fit: contain; background: #f4f2ee;
}
.doc-card a { display: block; }
.doc-card a:hover img { background: var(--accent-soft); }
.doc-noimage {
  height: 190px; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 4px;
  background: #f4f2ee; color: var(--muted); font-size: 12.5px; text-align: center;
  padding: 0 14px;
}
.doc-card figcaption {
  padding: 9px 11px; font-size: 13px;
  border-top: 1px solid var(--line);
}
.doc-card figcaption .source { margin-top: 3px; }

@media print {
  /* Keep a plan whole on one page rather than splitting it across a break. */
  .doc-card { break-inside: avoid; page-break-inside: avoid; }
  .doc-card img { height: 210px; }
}

/* ---- grid centre picker ---- */
.grid-pick .pick-surface {
  position: relative; cursor: crosshair; background: #f4f2ee;
}
.grid-pick .pick-surface img {
  display: block; width: 100%; height: 190px; object-fit: contain;
}
.pick-marker {
  position: absolute; width: 16px; height: 16px; margin: -8px 0 0 -8px;
  border: 2px solid #b03a2e; border-radius: 50%;
  background: rgba(176, 58, 46, .28); pointer-events: none;
}
.pick-marker::before, .pick-marker::after {
  content: ""; position: absolute; background: #b03a2e;
}
.pick-marker::before { left: 5px; top: -9px; width: 2px; height: 30px; }
.pick-marker::after { top: 5px; left: -9px; height: 2px; width: 30px; }
.pick-form { display: flex; gap: 6px; align-items: center; margin-top: 7px; }
.pick-form button { padding: 4px 10px; font-size: 12.5px; }

/* ---- grid overlay in the report ---- */
.grid-figure { margin: 0 0 14px; }
.grid-figure svg { display: block; max-width: 100%; height: auto;
  border: 1px solid var(--line); border-radius: 5px; }
.grid-figure figcaption { font-size: 12.5px; color: var(--muted); margin-top: 7px; }

/* What each corner zone traditionally carries. Captioned rather than drawn
   over the plan, which the drawing has no room for. */
.zone-key { display: flex; flex-wrap: wrap; gap: 4px 14px; margin-top: 6px; }
.zone-key-item { font-size: 11.5px; }
.zone-key-item b { color: #7c1d12; margin-right: 4px; }

@media print {
  .grid-figure { break-inside: avoid; page-break-inside: avoid; }
}

/* ---- client objectives ---- */
.objective-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 6px 16px;
}
.objectives-lead { border-left: 3px solid var(--computed); }
.objectives-lead .concern { margin-top: 12px; }
.objectives-lead .concern h3 { margin-bottom: 4px; }
.concern-findings .cand { margin: 3px 0; font-size: 13px; }
/* A karaka the classical rule did NOT select for this native — kept visible,
   because it is still read, but set back so it cannot be mistaken for the
   significator the chart is read through. */
.cand.unselected { opacity: .62; }

/* ---- dashboard ---- */
.dash-head {
  display: flex; justify-content: space-between; align-items: flex-end;
  gap: 18px; flex-wrap: wrap; margin-bottom: 20px;
}

.kpi-row {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 14px; margin-bottom: 18px;
}
.kpi {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 16px 18px; box-shadow: var(--shadow);
}
.kpi-value { font-size: 30px; font-weight: 650; line-height: 1.1; }
.kpi-label { font-size: 13px; color: var(--muted); margin-top: 2px; }
.kpi-delta { font-size: 12px; color: var(--computed); margin-top: 6px; }
.kpi-delta.muted { color: var(--muted); }
.kpi-link { display: inline-block; margin-top: 8px; font-size: 12.5px; }

/* Two columns on a wide screen, stacking to one when there is not room. The
   side column carries today's panchanga, which is the thing most often read
   without scrolling. */
.dash-grid { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); gap: 18px; }
.dash-main, .dash-side { min-width: 0; }
@media (max-width: 1000px) { .dash-grid { grid-template-columns: 1fr; } }

.trio { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 14px; }
.trio-card { margin-bottom: 0; }
.trio-card h3 { margin-top: 0; }

table.mini { font-size: 13px; }
table.mini th { font-weight: 500; color: var(--muted); text-align: left; padding: 4px 8px 4px 0; }
table.mini td { padding: 4px 0; }

/* Ordered by what the omission costs, so the colour has to track severity
   rather than count — a single wrong lagna outranks ten missing plans. */
.attn { display: flex; align-items: center; gap: 12px; padding: 10px 0;
        border-top: 1px solid var(--line); }
.attn:first-of-type { border-top: none; }
.attn-body { flex: 1 1 auto; min-width: 0; }
.attn-count {
  flex: 0 0 auto; width: 30px; height: 30px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-weight: 650; font-size: 13px; color: #fff; background: var(--muted);
}
.attn-high .attn-count { background: #a03020; }
.attn-medium .attn-count { background: #c78a2a; }
.attn-low .attn-count { background: var(--inferred); }

ul.activity { list-style: none; margin: 0; padding: 0; }
ul.activity li { padding: 8px 0; border-top: 1px solid var(--line); font-size: 13px; }
ul.activity li:first-child { border-top: none; }

/* Set back deliberately: it is a statement about what is absent, and must not
   compete with the figures that are real. */
.notconnected { background: transparent; box-shadow: none; }
.notconnected ul { margin: 6px 0 0; padding-left: 20px; font-size: 13px; }
.notconnected li { margin: 3px 0; }

/* ---- building type ---- */
.buildingtype { margin: 0 0 16px; padding-bottom: 4px; border-bottom: 1px solid var(--line); }
.buildingtype .note { margin: 8px 0; }

/* ---- follow-up comparison ----
   Left-ruled like the objectives lead, because it plays the same role: the
   thing the reader is here for, ahead of the full reading. */
.followup { border-left: 3px solid var(--rule); }
.followup h3 { margin: 18px 0 6px; font-size: 14px; }
.followup table { margin-top: 4px; }
.followup ul { margin: 4px 0; padding-left: 20px; }
.followup li { margin: 2px 0; }
.followup-action { margin-top: 12px; font-size: 13px; }
.followup-action select { width: auto; margin-left: 6px; }
.followup-action label { display: flex; align-items: center; color: var(--muted); }

/* ---- practitioner's per-section notes ---- */
.practitioner-note {
  border-left: 3px solid var(--supplied); background: var(--supplied-bg);
  padding: 10px 14px; margin: 12px 0; border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}
.practitioner-note .pn-label {
  font-size: 11px; text-transform: uppercase; letter-spacing: .05em;
  color: var(--supplied); font-weight: 600; margin-bottom: 3px;
}
.practitioner-note p { margin: 0; white-space: pre-wrap; }

.notes-field { margin-bottom: 12px; }
.notes-field label { display: block; margin-bottom: 3px; font-size: 13.5px; }
.notes-field textarea { width: 100%; }

/* ---- integrated synthesis ---- */
.synthesis-cols { display: flex; gap: 18px; flex-wrap: wrap; }
.synthesis-col { flex: 1 1 260px; min-width: 0; }
.synthesis-col .col-head {
  font-size: 11.5px; text-transform: uppercase; letter-spacing: .04em;
  color: var(--muted); margin-bottom: 6px; border-bottom: 1px solid var(--line);
  padding-bottom: 3px;
}
.cand { margin-bottom: 7px; font-size: 13px; }
.synthesis-write { display: block; margin-top: 12px; }
.synthesis-write span {
  display: block; font-size: 12.5px; color: var(--muted); margin-bottom: 4px;
}
.synthesis-write textarea {
  width: 100%; box-sizing: border-box; font: inherit; font-size: 13.5px;
  padding: 8px; border: 1px solid var(--line); border-radius: 4px; resize: vertical;
}
.synthesis-body { font-size: 14px; line-height: 1.5; white-space: pre-wrap; margin: 4px 0 0; }
@media print { .synthesis-area .synthesis-write { display: none; } }

/* ---- entrance pada (operator view only) ---- */
.kv { width: auto; margin-bottom: 10px; }
.kv td { padding: 5px 16px 5px 0; vertical-align: top; border-bottom: 1px solid var(--line); }
.kv td:first-child { color: var(--muted); white-space: nowrap; font-size: 12.5px; }

/* ---- remedy priority (operator view only) ---- */
.priority { width: 100%; border-collapse: collapse; margin-bottom: 14px; }
.priority th, .priority td {
  text-align: left; vertical-align: top; padding: 7px 9px;
  border-bottom: 1px solid var(--line); font-size: 13px;
}
.priority th { font-size: 11.5px; text-transform: uppercase; letter-spacing: .04em;
  color: var(--muted); }
.priority .factors { margin: 0; padding-left: 15px; }
.priority .factors li { margin: 1px 0; }
.priority .factors .dasha { margin-top: 4px; }

.band {
  display: inline-block; padding: 1px 7px; border-radius: 9px;
  font-size: 11px; font-weight: 600; text-transform: uppercase;
  letter-spacing: .03em;
}
.band.high     { background: #f9eeec; color: #a03020; }
.band.moderate { background: #fdf6e8; color: #8a5f14; }
.band.low      { background: #f1f0ec; color: #6b6559; }

@media print {
  .priority tr { break-inside: avoid; page-break-inside: avoid; }
}

/* ---- vastu findings ---- */
.finding {
  padding: 11px 13px; margin-bottom: 8px;
  border-left: 3px solid var(--line); border-radius: 0 4px 4px 0; background: #fcfbf9;
}
.finding.compliant     { border-left-color: var(--computed); background: var(--computed-bg); }
.finding.tolerated     { border-left-color: #c78a2a; background: #fdf6e8; }
.finding.non_compliant { border-left-color: #a03020; background: #f9eeec; }
.finding.not_assessable { border-left-color: var(--inferred); opacity: .72; }
.finding-head { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
.finding .detail { font-size: 13.5px; margin-top: 4px; }
.finding .mechanism {
  font-size: 12.5px; margin-top: 7px; padding: 7px 10px;
  background: var(--computed-bg); color: var(--computed); border-radius: 3px;
}

/* Contested findings borrow the inferred palette rather than the failure one:
   the sources disagreeing is not the property's fault, and colouring it like a
   defect would be a verdict by stylesheet. */
.finding.contested { border-left-color: var(--inferred); background: var(--inferred-bg); }

.contested {
  margin-top: 10px; padding: 10px 12px;
  background: var(--panel); border: 1px solid var(--line); border-radius: 4px;
}
.contested-head { font-size: 13px; margin-bottom: 8px; }
.contested table { font-size: 13px; }
.contested th, .contested td { padding: 5px 8px; }
.contested .note { margin-bottom: 0; }
.contested .contested-head div { margin-top: 5px; font-weight: normal; }
/* The practice's own row, marked so it does not read as one text among many. */
.contested tr.is-practice { background: var(--supplied-bg); }

.school-split {
  margin-top: 10px; padding: 10px 12px;
  background: var(--rule-bg); border-radius: 4px;
}
.school-split-head { font-size: 13px; margin-bottom: 8px; color: var(--rule); }
.school-split table { font-size: 13px; }
.school-split th, .school-split td { padding: 5px 8px; }

.scoreline { display: flex; gap: 20px; flex-wrap: wrap; margin: 8px 0 16px; font-size: 14px; }
.scoreline b { font-size: 20px; display: block; }

.linkbtn {
  background: none; border: none; padding: 0; margin-left: 4px;
  color: var(--accent); text-decoration: underline; cursor: pointer;
  font: inherit; font-size: 12px;
}

.searchbar { display: flex; gap: 8px; margin-bottom: 16px; }
.searchbar input { flex: 1 1 auto; min-width: 0; max-width: 340px; }

/* ---- report ---- */
.report-head { border-bottom: 2px solid var(--ink); padding-bottom: 14px; margin-bottom: 6px; }
.report-head h2 { margin: 0 0 4px; font-size: 24px; }
.meta-line { font-size: 13px; color: var(--muted); }
.config-strip {
  display: flex; flex-wrap: wrap; gap: 18px;
  font-size: 12.5px; color: var(--muted);
  background: var(--accent-soft); padding: 10px 14px; border-radius: 4px;
  margin: 14px 0 22px;
}
.config-strip b { color: var(--ink); font-weight: 600; }

.house-card {
  border: 1px solid var(--line); border-radius: 5px;
  padding: 12px 14px; margin-bottom: 10px; background: #fff;
}
.house-card h4 { margin: 0 0 4px; font-size: 14px; }
.house-card .sig { font-size: 12.5px; color: var(--muted); margin-bottom: 8px; }
.occupant { font-size: 13.5px; padding: 3px 0; }
.occupant .g { font-weight: 600; text-transform: capitalize; }

/* ---- kundali ---- */
/* Two charts a row, each filling its half so they scale up to the page width
   instead of sitting at their ~320px intrinsic size with a gap on the right.
   Centred within the cell; capped so they never grow absurd on a wide screen. */
.chart-row {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 26px; justify-items: center;
}
.chart-fig { margin: 0; width: 100%; max-width: 460px; }
.chart-svg svg { display: block; width: 100%; max-width: 100%; height: auto; margin: 0 auto; }
.chart-fig figcaption {
  font-size: 12.5px; color: var(--muted);
  margin-top: 8px; text-align: center; max-width: 100%;
}
@media (max-width: 640px) {
  .chart-row { grid-template-columns: 1fr; }   /* one per row on a phone */
}

/* ---- dosha verdicts ----
   The banner colour encodes school agreement, not severity. "split" is the
   most informative outcome, not a failure state, so it reads as a highlight
   rather than a warning. */
.verdict-banner {
  padding: 9px 13px; border-radius: 4px; margin: 10px 0 14px;
  font-size: 14px; border-left: 4px solid;
}
.verdict-banner.all   { background: var(--supplied-bg); border-color: var(--supplied); }
.verdict-banner.split { background: var(--rule-bg);     border-color: var(--rule); }
.verdict-banner.none  { background: var(--computed-bg); border-color: var(--computed); }

b.yes { color: var(--supplied); }
b.no  { color: var(--computed); }

/* ---- remedies ---- */
.remedy { padding: 12px 0; border-bottom: 1px solid var(--line); }
.remedy:last-child { border-bottom: none; }
.remedy-head { display: flex; align-items: center; gap: 9px; margin-bottom: 4px; }
.flagline {
  font-size: 12.5px; margin-top: 6px; padding: 5px 10px; border-radius: 3px;
}
.flagline.cost   { background: #fdf6e8; color: #8a6412; }
.flagline.commit { background: #fbf0e2; color: var(--supplied); }
.flagline.refer  { background: #f5eaea; color: #8a3020; }

/* ---- elaborated bhava cards ---- */
.chip {
  display: inline-block; font-size: 10.5px; letter-spacing: .4px;
  padding: 1px 7px; margin: 0 3px 2px 0; border-radius: 10px;
  background: var(--accent-soft); color: var(--accent); font-weight: 600;
}
.house-card .lordline { font-size: 13.5px; margin: 6px 0 8px; }
.house-card .aspectline {
  font-size: 12.5px; color: var(--muted);
  margin-top: 8px; padding-top: 7px; border-top: 1px dotted var(--line);
}
.occupant .sig { margin: 2px 0 0 0; font-size: 12.5px; }
.muted { color: var(--muted); }

b.dig { font-weight: 600; }
b.dig.exalted      { color: var(--computed); }
b.dig.debilitated  { color: #a03020; }
b.dig.moolatrikona { color: var(--computed); }
b.dig.own-sign     { color: var(--rule); }
b.dig.combust      { color: var(--supplied); }

/* ---- yogas ---- */
.yoga { padding: 10px 0; border-bottom: 1px solid var(--line); }
.yoga:last-child { border-bottom: none; }
.yoga.off { opacity: .58; }
.yoga-head { display: flex; align-items: center; gap: 9px; }
.yoga .evidence { font-size: 13px; margin-top: 4px; }

/* ---- phala: what the tradition holds a configuration signifies ----
   Visually distinct from computed findings, because it is a different KIND of
   statement — sourced tradition, not arithmetic. */
.phala {
  margin: 8px 0 0;
  padding: 9px 12px;
  background: var(--supplied-bg);
  border-left: 3px solid var(--supplied);
  border-radius: 0 4px 4px 0;
  font-size: 13.5px;
}
.phala .source { margin-top: 5px; }

/* ---- dasha analysis ---- */
.dasha-block {
  padding: 11px 13px; margin-bottom: 9px;
  border-left: 3px solid var(--line); border-radius: 0 4px 4px 0;
  background: #fcfbf9;
}
.dasha-block.current { border-left-color: var(--computed); background: var(--computed-bg); }
.dasha-block.past    { opacity: .62; }
.dasha-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; font-size: 15px; }
.dasha-detail { font-size: 13px; margin: 6px 0; }
.activated { font-size: 12.5px; margin-top: 6px; }

.legend { display: flex; gap: 14px; flex-wrap: wrap; font-size: 12px; margin: 10px 0 20px; }
.legend span { display: flex; align-items: center; gap: 5px; }

/* Below this width the sidebar stops being a column and becomes a top strip:
   the whole shell stacks, and the nav lays out horizontally and wraps. This is
   the small-screen fallback, so a phone gets a compact top bar rather than a
   fixed column eating half the width. */
@media (max-width: 900px) {
  .app-shell { flex-direction: column; }
  .sidebar {
    flex: 0 0 auto; width: 100%; height: auto; position: static;
    border-right: none; border-bottom: 1px solid #241a10;
  }
  .nav { display: flex; flex-wrap: wrap; gap: 2px; }
  .nav-group { margin-bottom: 0; display: flex; flex-wrap: wrap; }
  .nav-head { display: none; }
  .sidebar-foot { display: flex; gap: 10px; align-items: center; }
  .sidebar-cta { width: auto; }
  .logout-form { margin: 0; }
  .sidebar-om { display: none; }
}

/* Collapse the fixed form grids before they can force the page wider than the
   viewport. body{overflow-x:hidden} hides the scrollbar but would still clip
   content, so the layout has to actually reflow. */
@media (max-width: 760px) {
  .grid,
  .grid.three,
  .grid.four { grid-template-columns: 1fr; }
  main { padding: 20px 14px 60px; }
  .config-strip { gap: 8px 14px; }
  .row .field,
  .row .field.grow,
  .row .field.narrow,
  .row .field.dt { flex: 1 1 100%; }
  .row .rm { margin-left: 0; }
}

@media print {
  /* The sidebar is chrome — strip it entirely, and flatten the shell so the
     content column becomes the whole page. Without this the PDF would carry the
     navigation down its left edge. */
  .sidebar, .actions, .no-print, .tabbar { display: none !important; }
  .app-shell { display: block; }
  body { background: #fff; }
  main { max-width: none; margin: 0; padding: 0; }
  .panel { border: none; padding: 0; box-shadow: none; }
  .house-card { break-inside: avoid; }
  /* A report is one document in print: every tab panel shows, not just the
     active one, so nothing is hidden in an exported PDF. */
  .tab-panel[hidden] { display: block !important; }
  /* The fade-in starts at opacity:0. Chrome's print snapshot is taken before it
     finishes, so without this every panel renders INVISIBLE in the PDF — the
     file has the right structure and no readable content. Disable it in print. */
  .tab-panel { animation: none !important; opacity: 1 !important; }
  .report-tabs > .tabbar { position: static; box-shadow: none; }
  h2::before { display: none; }

  /* Cover and closing pages appear only in print. The on-screen report head is
     redundant once there is a cover carrying the same name and date. */
  .print-only { display: block !important; }
  /* The cover and closing are flex columns; restore that here (after the
     generic print-only reveal, so it wins) now that the base rule leaves
     display unset to stay hidden on screen. */
  .print-cover, .print-closing { display: flex !important; }
  .report-head, .config-strip, .legend { display: none; }

  /* Each body section opens on a fresh page. EVERY report section heading breaks
     before itself — whether or not it sits inside the tab shell — so the printed
     PDF gives one section per page. The front-matter heading (the client name)
     lives in .report-head, which is display:none in print, so it neither renders
     nor triggers a stray leading break. */
  main h2 { break-before: page; page-break-before: always; }

  /* Never strand a sub-heading at the foot of a page. break-after:avoid keeps an
     h3/h4 with the content that follows it, so a heading that would otherwise sit
     alone above a page break (e.g. "Which stones this lagna supports at all", the
     Marriage/Children/Career windows, "Longevity", "Pancha Rina", "A spelling both
     systems agree on") moves to the next page together with its table or list. */
  h3, h4 { break-after: avoid; page-break-after: avoid; break-inside: avoid; }

  /* Keep populated tables whole. A table that will not fit in the space left on
     the page moves to the next page rather than straddling the break. When a
     table is genuinely longer than a page (a full dasha timeline, ashtakavarga)
     it cannot be kept whole, so as a fallback no single ROW is split and the
     header repeats on each continued page — never a row cut in half. */
  table { break-inside: avoid; page-break-inside: avoid; }
  /* Opt-out for tables we WANT to flow from where they start rather than jump to
     the next page whole — the long Vastu guidance list, which otherwise leaves
     its section's first page nearly empty below the intro. Rows stay unsplit. */
  table.allow-break { break-inside: auto; page-break-inside: auto; }
  tr { break-inside: avoid; page-break-inside: avoid; }
  thead { display: table-header-group; }
  /* The same whole-block treatment for the card-like units, so a finding, a
     remedy, a house card or a chart figure is never split across a page. */
  figure, .grid-figure, .doc-card, .remedy, .finding,
  .dasha-block, .concern, .contested, .school-split { break-inside: avoid; page-break-inside: avoid; }
}

/* Off-screen by default: the cover and closing exist only for the printed
   deliverable, where the @media print block above reveals them. */
.print-only { display: none; }

/* Current brand image beside its upload field, with a remove toggle. */
.brand-preview { display: flex; align-items: center; gap: 12px; margin-bottom: 8px; }
.brand-preview img {
  max-height: 60px; max-width: 160px; border: 1px solid var(--line);
  border-radius: 6px; padding: 4px; background: #fff;
}
.brand-remove { font-size: 13px; color: var(--muted); display: flex; align-items: center; gap: 5px; }

.print-cover {
  /* No `display` here: .print-only (display:none) must win on screen. The print
     block below restores the flex layout. Setting display:flex here would come
     after .print-only and defeat it, leaking the cover onto the web page. */
  min-height: 96vh;
  flex-direction: column; align-items: center; text-align: center;
  padding: 8vh 12mm 6vh;
  break-after: page; page-break-after: always;
}
.cover-top { margin-bottom: auto; }
.cover-logo { max-height: 90px; max-width: 60%; margin: 0 auto 14px; display: block; }
.cover-practice { font-size: 30px; font-weight: 650; letter-spacing: .3px; color: var(--accent-ink); }
.cover-tagline { font-size: 14px; color: var(--muted); margin-top: 4px; font-style: italic; }
.cover-image {
  max-height: 300px; max-width: 82%; margin: 24px auto; display: block;
  border-radius: 6px;
}
.cover-mid { margin: 8px 0 auto; }
.cover-title {
  font-size: 13px; text-transform: uppercase; letter-spacing: .14em;
  color: var(--accent); margin-bottom: 14px;
}
.cover-client { font-size: 26px; font-weight: 650; }
.cover-born { font-size: 14px; color: var(--muted); margin-top: 6px; }
.cover-foot { font-size: 12.5px; color: var(--muted); line-height: 1.8; }

.print-closing {
  /* display gated to print — see .print-cover for why. */
  break-before: page; page-break-before: always;
  min-height: 90vh; flex-direction: column;
  align-items: center; text-align: center; justify-content: center;
  padding: 8vh 14mm;
}
.closing-logo { max-height: 64px; max-width: 45%; margin-bottom: 16px; }
.closing-practice { font-size: 22px; font-weight: 650; color: var(--accent-ink); }
.closing-tagline { font-size: 13px; color: var(--muted); font-style: italic; margin-top: 3px; }
.closing-note { font-size: 15px; max-width: 30em; margin: 22px auto; line-height: 1.6; }
.closing-contact { font-size: 13.5px; line-height: 1.9; color: var(--ink); margin-top: 8px; }
.closing-fineprint {
  font-size: 11px; color: var(--muted); max-width: 34em; margin: 40px auto 0;
  line-height: 1.6;
}
