/* Kundali Register — app styles.
   Cross-platform system fonts only. No webfont, no CDN, works offline. */

/* KriyaIQ palette — taken from the values in kriyaiq.com's own bundle, not
   eyeballed from a screenshot:

     #ffcb2b  brand yellow        #4a32c9  the top bar
     #e6b727  yellow, pressed     #121212  ground
     #1e1e1e  surface             #2c2c2c  raised surface
     #4caf50  good                #ff9800  warn        #f44336  critical

   Two of those cannot be used as TEXT on the dark ground and are corrected
   below where that matters; each is marked. Everything else is exact.
   Every foreground below is measured at 4.5:1 or better against ground, surface
   and sunken in BOTH themes; see tools/contrast.mjs — INCLUDING `faint`, which
   used to be excused as decorative and then turned up carrying table headers
   and the ayanamsa line, so it is now held to the same 4.5:1 as everything else.

   Colour is never the only carrier of meaning. The good/warn/critical trio is
   the usual trap — red and green are the pair a deuteranope or protanope cannot
   separate — so every place that uses it also states the thing in words (the
   guna band is labelled "Excellent" … "Not recommended", a confidence is
   labelled "high"/"medium"/"low"), and the three are additionally separated by
   LIGHTNESS, which survives every form of colour blindness. tools/contrast.mjs
   simulates protanopia, deuteranopia and tritanopia and fails the build if any
   pair of them becomes indistinguishable.

   Links carry an underline as well as a colour, for the same reason.

   The brand yellow (#FFC629) is the dark-theme accent, where it sits on black
   exactly as it does on kriyaiq.com. On a light ground it would land near 1.7:1
   and be unreadable, so light mode uses a dark amber from the same family. The
   PRIMARY BUTTON keeps the brand yellow with near-black text in both themes —
   that pairing is the most recognisable thing on the KriyaIQ site and it passes
   contrast comfortably either way. */
:root {
  --brand: #ffcb2b;           /* exact, from the KriyaIQ bundle */
  --brand-press: #e6b727;     /* exact — their pressed state */
  --brand-ink: #121212;       /* text on the yellow; their ground colour */
  --bar: #4a32c9;             /* exact — the KriyaIQ top bar */
  --bar-ink: #ffffff;

  --ground: #F4F4F5;
  --surface: #FFFFFF;
  --sunken: #E7E7EA;
  --ink: #18181B;
  --muted: #57575E;
  --faint: #66666F;
  --rule: #D7D7DC;
  --link: #14549e;            /* same blue as --sea; see the note below */
  --link-visited: #6b3fa0;
  /* On a light ground the brand colours are unreadable as text — #ffcb2b lands
     near 1.6:1 — so light mode uses the same hues darkened until they pass. */
  --accent: #7a5200;
  --brass: #6E4A08;
  --sea: #14549e;             /* #1976d2 darkened */
  /* Same three-lightness-level idea as the dark theme; see the note there. */
  --good: #2d7020;
  --warn: #6b3d0f;
  --crit: #59110d;

  --ui: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",
        "Noto Sans", "Noto Sans Kannada", sans-serif;
  --kn: "Noto Sans Kannada", "Kannada MN", "Nirmala UI", "Tunga", var(--ui);
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Consolas, "Liberation Mono", monospace;

  --tap: 44px;
  --pad: 16px;
  --radius: 8px;
  --safe-b: env(safe-area-inset-bottom, 0px);
  --safe-t: env(safe-area-inset-top, 0px);
}

@media (prefers-color-scheme: dark) {
  :root {
    --ground: #121212;       /* exact */
    --surface: #1e1e1e;      /* exact */
    --sunken: #0a0a0a;
    --ink: #ffffff;          /* exact */
    --muted: #a8a8ae;
    --faint: #8a8a93;
    --rule: #2c2c2c;         /* exact — their raised surface, used as our rule */
    --accent: #ffcb2b;       /* exact */
    --brass: #e6b727;        /* exact */
    /* #1976d2 is only 3.5:1 on #121212 and #4caf50 only 4.4:1, so both are
       lifted for text. Their unmodified values stay on the bar and on fills,
       where they are not carrying words. */
    --sea: #64a8ef;
    --link: #64a8ef;
    --link-visited: #c9a3ea;
    /* The trio is spread across three LIGHTNESS levels, not three hues, because
       hue is the thing colour blindness takes away. #4caf50 and #ff9800 sat at
       almost the same lightness, so to a deuteranope they were one colour.
       These are as far apart as the 4.5:1 floor permits — see tools/contrast.mjs
       for the measured separation, and the glyph rules below for the cue that
       does not depend on colour at all. */
    --good: #b9ecbb;
    --warn: #e8a72e;
    --crit: #ee6a61;
  }
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--ui);
  font-size: 16px;                 /* NFR-09 floor */
  line-height: 1.45;
  overscroll-behavior-y: contain;
  overflow-x: hidden;              /* the page itself never scrolls sideways */
}

[lang="kn"], .kn { font-family: var(--kn); }

/* ── Top bar ─────────────────────────────────────────────────────────── */
.topbar {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; gap: 4px;
  padding: calc(var(--safe-t) + 8px) 8px 8px;
  background: var(--surface);
  border-bottom: 1px solid var(--rule);
}
.topbar .title { flex: 1; font-size: 17px; font-weight: 600; padding-inline: 6px; }
.topbar button {
  min-width: var(--tap); min-height: var(--tap);
  border: 0; background: none; color: var(--ink);
  font-size: 22px; cursor: pointer; border-radius: var(--radius);
}
.topbar button:active { background: var(--sunken); }
.topbar .back { font-size: 30px; line-height: 1; padding-bottom: 4px; }

.screen { padding: var(--pad); padding-bottom: calc(96px + var(--safe-b)); max-width: 820px; margin: 0 auto; }

/* ── Controls ────────────────────────────────────────────────────────── */
input, select, textarea, button { font: inherit; font-family: var(--ui); }

/* Links.
   There was no rule here at all, so every link fell through to the browser's
   own #0000EE — roughly 2:1 on the dark ground, and unreadable. The underline
   stays: colour alone is not a reliable signal for a colour-blind reader, and
   removing it would leave nothing else marking the link. */
a { color: var(--link); text-underline-offset: 2px; }
a:visited { color: var(--link-visited); }
a:hover { text-decoration-thickness: 2px; }
a:focus-visible { outline: 2px solid var(--link); outline-offset: 2px; border-radius: 2px; }

input, select, textarea {
  width: 100%;
  min-height: var(--tap);
  padding: 10px 12px;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
  appearance: none;
}
input[type="file"] { padding: 8px; }
/* The rule above sets `appearance: none` for text fields. Left in place it also
   strips the tick out of a checkbox and the dot out of a radio — they kept the
   box and lost the only part that says whether they are on. Both are restored
   explicitly, along with the padding and border the text-field rule gave them. */
input[type="checkbox"], input[type="radio"] {
  appearance: auto;
  -webkit-appearance: auto;
  width: 22px; height: 22px; min-height: 0; flex: 0 0 auto;
  padding: 0; border: 0; border-radius: 0; background: none;
  accent-color: var(--accent);
}
input[type="radio"] { border-radius: 50%; }
select {
  background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%),
                    linear-gradient(135deg, var(--muted) 50%, transparent 50%);
  background-position: calc(100% - 18px) 50%, calc(100% - 13px) 50%;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  padding-right: 34px;
}
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

label { display: block; margin-bottom: 12px; font-size: 14px; color: var(--muted); }
label input, label select, label textarea { margin-top: 4px; color: var(--ink); font-size: 16px; }
.req { color: var(--accent); font-size: 11px; text-transform: uppercase; letter-spacing: .06em; margin-left: 4px; }

.row { display: flex; gap: 12px; }
.row > label { flex: 1; min-width: 0; }

fieldset { border: 1px solid var(--rule); border-radius: var(--radius); padding: 14px; margin: 0 0 16px; background: var(--surface); }
legend { font-size: 12px; text-transform: uppercase; letter-spacing: .09em; color: var(--faint); padding: 0 6px; }

.hint { font-size: 13px; color: var(--muted); margin: 0 0 12px; }
.check { display: flex; gap: 10px; align-items: flex-start; background: var(--surface); border: 1px solid var(--rule); border-radius: var(--radius); padding: 12px; }
.check span { font-size: 14px; color: var(--ink); }

.more { margin-bottom: 16px; }
.more > summary { cursor: pointer; padding: 12px; min-height: var(--tap); display: flex; align-items: center;
  background: var(--surface); border: 1px solid var(--rule); border-radius: var(--radius); font-size: 15px; }
.more[open] > summary { border-radius: var(--radius) var(--radius) 0 0; border-bottom: 0; }
.more fieldset { border-radius: 0 0 var(--radius) var(--radius); margin-bottom: 0; }

.btn {
  min-height: var(--tap); padding: 10px 16px;
  border: 1px solid var(--rule); border-radius: var(--radius);
  background: var(--surface); color: var(--ink);
  font-size: 15px; cursor: pointer;
}
.btn:active { background: var(--sunken); }
.btn.primary { background: var(--brand); color: var(--brand-ink);
  border-color: var(--brand); font-weight: 700; }
.btn.primary:active { background: var(--brand-press); }
.btn.danger { color: var(--crit); border-color: var(--crit); }
.btn:disabled { opacity: .5; cursor: not-allowed; }
.actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 12px; }

.fabs {
  position: fixed; right: 18px; bottom: calc(18px + var(--safe-b));
  display: flex; flex-direction: column; gap: 12px; align-items: center; z-index: 15;
}
.fab {
  width: 58px; height: 58px; border-radius: 50%;
  border: 0; background: var(--brand); color: var(--brand-ink);
  font-size: 30px; line-height: 1; cursor: pointer;
  display: grid; place-items: center;
  box-shadow: 0 4px 14px rgba(0,0,0,.24);
}
.fab.scan { width: 50px; height: 50px; background: var(--surface); color: var(--ink);
  border: 1px solid var(--rule); }

/* ── Scan review ─────────────────────────────────────────────────────── */
.warnbox { border-left: 3px solid var(--warn); padding-left: 10px; }

/* Impossible to mistake for a subtitle. */
.demo-banner {
  background: var(--crit); color: #fff;
  /* crit is light in dark mode, so force dark text there for legibility */
  border-radius: var(--radius); padding: 14px 16px; margin-bottom: 14px;
  font-size: 14.5px; line-height: 1.45;
}
.demo-banner b { display: block; font-size: 16px; margin-bottom: 4px; }

.scanshot { width: 100%; max-height: 260px; object-fit: contain; background: var(--sunken);
  border: 1px solid var(--rule); border-radius: var(--radius); display: block; cursor: zoom-in; }
.scanshot.zoom { max-height: none; cursor: zoom-out; }

.progress { height: 4px; background: var(--sunken); border-radius: 2px; overflow: hidden; margin: 12px 0; }
.progress i { display: block; height: 100%; width: 40%; background: var(--accent);
  animation: slide 1.1s ease-in-out infinite; }
@keyframes slide { 0% { transform: translateX(-100%); } 100% { transform: translateX(350%); } }

.rec-tabs { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 12px; }
.rec-tab { padding: 8px 14px; min-height: var(--tap); border: 1px solid var(--rule);
  border-radius: var(--radius); background: var(--surface); color: var(--ink);
  cursor: pointer; font-size: 14px; }
/* The selected tab is marked by weight and a border as well as by its fill, so
   it is still identifiable when the fill is hard to judge. */
.rec-tab[aria-current="true"] { background: var(--ink); color: var(--ground);
  border-color: var(--ink); font-weight: 700; }

.frow { display: grid; grid-template-columns: 1fr; gap: 4px; padding: 10px 0;
  border-bottom: 1px solid var(--rule); }
.frow:last-child { border-bottom: 0; }
.frow .lab { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--muted); }
.frow input, .frow select { margin: 0; }
.frow .src { font-size: 12px; color: var(--faint); font-family: var(--mono);
  overflow-wrap: anywhere; }

.conf { font-size: 10px; text-transform: uppercase; letter-spacing: .07em;
  padding: 2px 7px; border-radius: 10px; border: 1px solid currentColor; white-space: nowrap; }
.conf.high { color: var(--good); }
.conf.medium { color: var(--warn); }
.conf.low { color: var(--crit); }

.frow.medium input, .frow.medium select { border-color: var(--warn); }
.frow.low input, .frow.low select { border-color: var(--crit); }

.xcheck { border-radius: var(--radius); padding: 10px 12px; margin: 12px 0; font-size: 14px;
  border-left: 3px solid var(--rule); background: var(--sunken); }
.xcheck.ok { border-left-color: var(--good); }
.xcheck.warn { border-left-color: var(--warn); }
.xcheck.conflict { border-left-color: var(--crit); }

/* ── The cue that is not colour ────────────────────────────────────────────
   Three states cannot be told apart by hue alone by a reader with red-green
   colour blindness, and they cannot be spread far enough apart in lightness
   either without pushing one of them below 4.5:1. So every place the trio is
   used carries a glyph as well, and the glyph — not the colour — is what
   actually carries the meaning. The colour is the fast path for readers who
   have it; the glyph is the guarantee for everyone else.

   aria-hidden is not needed: generated content is not exposed as text by
   screen readers, and each of these already sits beside a word. */
.xcheck.ok::before, .xcheck.warn::before, .xcheck.conflict::before,
.conf::before, .score.good::before, .score.warn::before, .score.crit::before,
.tile-n.good::before, .tile-n.crit::before {
  font-weight: 700; margin-right: .45em; font-variant-emoji: text;
}
.xcheck.ok::before      { content: '\2713'; }   /* ✓ */
.xcheck.warn::before    { content: '\0021'; }   /* ! */
.xcheck.conflict::before{ content: '\2715'; }   /* ✕ */
.conf.high::before      { content: '\2713'; }
.conf.medium::before    { content: '\0021'; }
.conf.low::before       { content: '\2715'; }
.score.good::before     { content: '\2713'; font-size: .6em; vertical-align: .3em; }
.score.warn::before     { content: '\0021'; font-size: .6em; vertical-align: .3em; }
.score.crit::before     { content: '\2715'; font-size: .6em; vertical-align: .3em; }
.tile-n.good::before    { content: '\2713'; font-size: .55em; vertical-align: .35em; }
.tile-n.crit::before    { content: '\2715'; font-size: .55em; vertical-align: .35em; }
/* A koota that scored nothing is already saying so with a 0; the underline
   makes it findable when the red is not. */
table.koota tr.zero td.num { text-decoration: underline; text-underline-offset: 2px; }

.leftover { font-family: var(--mono); font-size: 12px; color: var(--muted);
  background: var(--sunken); border-radius: var(--radius); padding: 10px 12px;
  white-space: pre-wrap; overflow-wrap: anywhere; max-height: 180px; overflow-y: auto; }

/* ── Toolbar & list ──────────────────────────────────────────────────── */
.toolbar { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 10px; }
.toolbar #q { flex: 1 1 100%; }
.toolbar select { flex: 1; min-width: 130px; }

.counts { font-size: 13px; color: var(--muted); margin-bottom: 10px; font-variant-numeric: tabular-nums; }

/* minmax(0,1fr): grid items default to min-width:auto, which lets the nowrap
   text below push each row past the viewport. */
.list { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: minmax(0, 1fr); gap: 8px; }
.item {
  display: flex; gap: 12px; align-items: center; min-width: 0;
  background: var(--surface); border: 1px solid var(--rule);
  border-radius: var(--radius); padding: 10px 12px;
  cursor: pointer; min-height: 64px;
}
.item:active { background: var(--sunken); }
.item .av {
  width: 44px; height: 44px; flex: none; border-radius: var(--radius);
  background: var(--sunken); object-fit: cover;
  display: grid; place-items: center; font-size: 17px; color: var(--faint); font-weight: 600;
}
.item .who { flex: 1; min-width: 0; }
.item .nm { font-weight: 600; font-size: 16px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.item .meta { font-size: 13px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.item .score {
  flex: none; text-align: right; font-variant-numeric: tabular-nums;
  font-size: 20px; font-weight: 600; min-width: 62px;
}
.item .score small { display: block; font-size: 11px; font-weight: 400; color: var(--faint); }
.score.good { color: var(--good); } .score.warn { color: var(--warn); } .score.crit { color: var(--crit); }

.empty { text-align: center; padding: 40px 10px; color: var(--muted); }
.empty p { margin: 0 0 10px; }

/* ── Cards & chart preview ───────────────────────────────────────────── */
.card { background: var(--surface); border: 1px solid var(--rule); border-radius: var(--radius); padding: 14px; margin-bottom: 14px; }
.card h3 { margin: 0 0 10px; font-size: 15px; }
.card h2 { margin: 0 0 4px; font-size: 22px; }

.chart-preview { background: var(--sunken); border-radius: var(--radius); padding: 10px 12px; font-size: 14px; }
.chart-preview b { font-variant-numeric: tabular-nums; }

.kv { display: grid; grid-template-columns: minmax(110px, 38%) 1fr; gap: 6px 12px; font-size: 15px; }
.kv dt { color: var(--muted); font-size: 14px; }
.kv dd { margin: 0; }

.flagline { border-left: 3px solid var(--accent); padding: 8px 12px; background: var(--sunken); border-radius: 0 var(--radius) var(--radius) 0; font-size: 14px; margin: 12px 0; }

.big { font-size: 44px; font-weight: 600; line-height: 1; font-variant-numeric: tabular-nums;
  white-space: nowrap; flex: none; }
.big small { font-size: 15px; font-weight: 400; color: var(--muted); }

table.koota { width: 100%; border-collapse: collapse; font-size: 15px; }
table.koota th { text-align: left; font-size: 11px; text-transform: uppercase; letter-spacing: .08em;
  color: var(--faint); font-weight: 400; border-bottom: 1px solid var(--ink); padding: 4px 6px 4px 0; }
table.koota td { padding: 7px 6px 7px 0; border-bottom: 1px solid var(--rule); vertical-align: top; }
/* Heading and figures share an alignment, and a right-aligned column keeps a
   gutter so its figures do not run into the next column's words. */
table.koota td.num, table.koota th.num { text-align: right;
  font-variant-numeric: tabular-nums; white-space: nowrap; padding-right: 14px; }
table.koota td.num:last-child, table.koota th.num:last-child { padding-right: 0; }
table.koota td.note { color: var(--muted); font-size: 13px; }
table.koota tr.zero td.num { color: var(--crit); font-weight: 600; }
table.koota tr.tot td { border-top: 2px solid var(--ink); border-bottom: 0; font-weight: 600; font-size: 17px; }

/* ── Autocomplete ────────────────────────────────────────────────────── */
.place { position: relative; }
.ac {
  list-style: none; margin: 2px 0 0; padding: 0; position: absolute;
  left: 0; right: 0; z-index: 30;
  background: var(--surface); border: 1px solid var(--rule); border-radius: var(--radius);
  box-shadow: 0 8px 20px rgba(0,0,0,.16); max-height: 240px; overflow-y: auto;
}
.ac li { padding: 11px 12px; cursor: pointer; min-height: var(--tap); display: flex;
  justify-content: space-between; gap: 10px; align-items: center; font-size: 15px; }
.ac li:hover, .ac li[aria-selected="true"] { background: var(--sunken); }
.ac li span { color: var(--muted); font-size: 13px; }

/* ── Toast ───────────────────────────────────────────────────────────── */
.toast {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: calc(88px + var(--safe-b)); z-index: 60;
  background: var(--ink); color: var(--ground);
  padding: 11px 18px; border-radius: 22px; font-size: 14px;
  max-width: calc(100vw - 32px); text-align: center;
  box-shadow: 0 4px 16px rgba(0,0,0,.28);
}

.photo-row { display: flex; gap: 14px; align-items: flex-start; margin-bottom: 14px; }
.photo-slot { width: 92px; height: 116px; flex: none; border-radius: var(--radius);
  border: 1px dashed var(--rule); background: var(--sunken); overflow: hidden;
  display: grid; place-items: center; }
.photo-slot[data-empty="1"]::after { content: 'No photo'; font-size: 11px; color: var(--faint); }
.photo-slot img { width: 100%; height: 100%; object-fit: cover; }
.photo-buttons { display: flex; flex-wrap: wrap; gap: 8px; align-content: flex-start; flex: 1; min-width: 0; }
.photo-buttons .btn { padding: 8px 12px; min-height: 40px; font-size: 14px; }
.photo-buttons .hint { flex: 1 1 100%; }

/* ── Document preview ────────────────────────────────────────────────── */
.doc-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 14px; }
.doc-stage { background: #fff; border: 1px solid var(--rule); border-radius: var(--radius);
  overflow-x: auto; padding: 10px; }
.doc-stage .doc { margin: 0 auto; }
.doc-stage img { display: block; max-width: 100%; height: auto; margin: 0 auto; }
.doc-hint { font-size: 13px; color: var(--muted); margin: 10px 0 0; }

/* Print only the document. No popup, so no pop-up blocker to lose to. */
@media print {
  .topbar, .fabs, .toast, .no-print { display: none !important; }
  body { background: #fff; padding: 0; }
  .screen { display: none !important; }
  #scDocument { display: block !important; padding: 0; max-width: none; }
  .doc-stage { border: 0; padding: 0; background: #fff; overflow: visible; }
}

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .001ms !important; transition-duration: .001ms !important; }
}

@media (min-width: 640px) {
  .screen { padding: 24px; }
  .kv { grid-template-columns: 180px 1fr; }
}

/* ── Dashboard ───────────────────────────────────────────────────────── */
.tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 10px; margin-bottom: 14px; }
.tile { background: var(--surface); border: 1px solid var(--rule);
  border-radius: var(--radius); padding: 14px; }
.tile-n { font-size: 28px; font-weight: 600; line-height: 1.1;
  font-variant-numeric: tabular-nums; }
.tile-n.good { color: var(--good); }
.tile-n.crit { color: var(--crit); }
.tile-l { font-size: 12.5px; color: var(--muted); margin-top: 2px; }
.tbl-wrap { overflow-x: auto; }

/* --crit is a light salmon in dark mode; white on it fails contrast. */
@media (prefers-color-scheme: dark) {
  .demo-banner { color: #202124; }
  .demo-banner b { color: #202124; }
}
.doc-sep { font-family: var(--mono); font-size: 11px; letter-spacing: .12em;
  text-transform: uppercase; color: var(--muted); margin: 18px 0 6px; }
.doc-sep:first-child { margin-top: 0; }
@media print { .doc-sep { display: none; } }

/* ── Traditional chart ───────────────────────────────────────────────── */
/* Everything else about the chakra lives in CHAKRA_CSS, in
   src/engine/chart-render.js, and is injected at boot. It used to be copied
   here as well, so a change to one copy silently left the other behind — which
   is exactly what happened when full graha names were added. Only the rules
   that belong to the app's layout rather than the chart itself stay here. */
.chakra-row { display: flex; flex-wrap: wrap; gap: 16px; margin-top: 14px; }
.chakra-row > .chakra { flex: 1 1 300px; }

/* ── Sync conflicts ──────────────────────────────────────────────────── */
.conflict-pair { display: grid; gap: 10px; grid-template-columns: 1fr; }
@media (min-width: 520px) { .conflict-pair { grid-template-columns: 1fr 1fr; } }
.conflict-pair .btn { text-align: left; padding: 12px 14px; min-height: 62px;
  display: flex; flex-direction: column; gap: 4px; align-items: flex-start; }
.cf-tag { font-size: 11px; text-transform: uppercase; letter-spacing: .08em;
  color: var(--muted); }
.conflict-pair .btn.primary .cf-tag { color: var(--ground); opacity: .8; }

/* ── Waiting for something that happens in another app ─────────────────── */
.spinner { width: 16px; height: 16px; flex: 0 0 auto; border-radius: 50%;
  border: 2px solid var(--rule); border-top-color: var(--accent);
  animation: spin .8s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .spinner { animation-duration: 3s; } }

/* ── Branding ─────────────────────────────────────────────────────────────
   The KriyaIQ wordmark: "Kriya" in the text colour, "IQ" in the brand yellow,
   exactly as on kriyaiq.com. Kept as markup rather than an image so it stays
   sharp at any size, needs no network, and inherits the theme. */
.brand { display: inline-flex; align-items: baseline; gap: .12em;
  font-weight: 800; letter-spacing: -.02em; line-height: 1; }
.brand .k { color: var(--ink); }
.brand .iq { color: var(--brand); }
.brand .sub { font-weight: 500; letter-spacing: 0; color: var(--muted);
  font-size: .42em; margin-left: .5em; align-self: center; }

/* The bar that sits above every screen of the app. */
.brandbar { display: flex; align-items: center; justify-content: space-between;
  gap: 12px; padding: 10px 0 12px; border-bottom: 1px solid var(--rule);
  margin-bottom: 16px; }
.brandbar .brand { font-size: 22px; }
.brandbar .right { display: flex; align-items: center; gap: 10px;
  font-size: 13px; color: var(--muted); }

/* ── The KriyaIQ bar ───────────────────────────────────────────────────────
   The same bar the MES product carries: solid #4a32c9, the wordmark at the
   left with "IQ" in brand yellow, the product name beside it, then context —
   who is signed in and as what. It is deliberately NOT theme-aware: the bar is
   the brand, and it looks the same in light mode as in dark, exactly as it does
   across the rest of KriyaIQ. */
.kbar {
  background: var(--bar); color: var(--bar-ink);
  display: flex; align-items: center; gap: 14px;
  padding: calc(var(--safe-t) + 9px) 14px 9px;
  font-size: 14px; position: relative; z-index: 21;
}
.kbar .mark { color: var(--bar-ink); text-decoration: none; font-size: 19px;
  font-weight: 700; display: inline-flex; align-items: baseline; gap: .32em; }
.kbar .mark:visited { color: var(--bar-ink); }
.kbar .brand { font-size: 19px; }
.kbar .brand .k { color: #fff; }
.kbar .brand .iq { color: var(--brand); }
/* "by" is the quiet word in "Kundali by KriyaIQ" — smaller and lighter, so the
   two names either side of it read as the two names. */
.kbar .by { font-size: .68em; font-weight: 400; opacity: .8; }
.kbar .sep { width: 1px; align-self: stretch; background: rgba(255,255,255,.28); margin: 2px 0; }
.kbar .tenant { font-weight: 700; white-space: nowrap; overflow: hidden;
  text-overflow: ellipsis; max-width: 34vw; }
.kbar .spacer { flex: 1; }
.kbar .who { opacity: .82; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  max-width: 42vw; font-size: 13px; }
.kbar .who b { color: var(--brand); font-weight: 700; }
.kbar a.tab { color: var(--brand); background: rgba(0,0,0,.28); text-decoration: none;
  padding: 7px 13px; border-radius: 6px; font-weight: 600; white-space: nowrap; }

@media (max-width: 34rem) {
  .kbar { gap: 9px; padding-left: 11px; padding-right: 11px; }
  .kbar .mark { font-size: 17px; }
  .kbar .sep { display: none; }
  .kbar .who { font-size: 12px; max-width: 40vw; }
}

/* ── Ranking weights (UC-MM-07) ────────────────────────────────────────────
   One row per factor: what it is on the left, how much it counts on the right.
   The rows stack on a phone rather than squeezing four buttons beside a label. */
.wrow { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 10px 18px;
  align-items: center; padding: 12px 0; border-bottom: 1px solid var(--rule); }
.wrow:last-child { border-bottom: 0; }
.wrow .wname { font-size: 15px; font-weight: 600; }
.wrow .whint { font-size: 13px; color: var(--muted); margin-top: 2px; }
.wrow .rec-tabs { margin: 0; flex-wrap: nowrap; }
.wrow .rec-tab { padding: 7px 11px; font-size: 13px; min-height: 38px; }
@media (max-width: 32rem) {
  .wrow { grid-template-columns: 1fr; }
  .wrow .rec-tabs { justify-content: flex-start; }
}

/* Why a match placed where it did. Never colour alone — each carries its own
   glyph, as everywhere else the app signals good and bad. */
.item .why { display: flex; flex-wrap: wrap; gap: 4px 12px; margin-top: 4px; font-size: 12px; }
.item .why .y { color: var(--good); }
.item .why .n { color: var(--crit); }

/* ── Fees (UC-MM-15, UC-MM-19) ─────────────────────────────────────────────
   Figures line up in a column, so tabular numerals throughout — proportional
   digits make two amounts of the same magnitude look different lengths. */
.feegrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 12px; padding: 12px; background: var(--sunken); border-radius: var(--radius); }
.feegrid > div { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.feegrid span:first-child { font-size: 12px; color: var(--muted);
  text-transform: uppercase; letter-spacing: .06em; }
.feegrid .rs, .feegrid b { font-size: 18px; font-weight: 600;
  font-variant-numeric: tabular-nums; }
.feegrid b.due { color: var(--warn); }
.feegrid b.clear { color: var(--good); }

.feelist { margin: 0 0 12px; padding: 0; list-style: none; }
.feelist li { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  padding: 8px 0; border-bottom: 1px solid var(--rule); font-size: 14px; }
.feelist li:last-child { border-bottom: 0; }
.feelist .k { min-width: 92px; color: var(--muted); }
.feelist .a { font-weight: 600; font-variant-numeric: tabular-nums; min-width: 84px; }
.feelist .a.neg { color: var(--crit); }
.feelist .d { color: var(--faint); font-size: 13px; font-variant-numeric: tabular-nums; }
.feelist .n { color: var(--muted); font-size: 13px; flex: 1 1 100%; }

.linkbtn { background: none; border: 0; padding: 6px 0; margin-left: auto;
  color: var(--link); font-size: 13px; cursor: pointer; text-decoration: underline;
  text-underline-offset: 2px; min-height: 32px; }

/* ── Follow-ups (UC-MM-14) ─────────────────────────────────────────────────
   Overdue, today and this week are three different things to a matchmaker
   working through a morning, so they are three labelled groups rather than one
   list sorted by date. The label carries the meaning; the colour only reinforces
   it, so the grouping still reads with no colour at all. */
.followup { display: grid; gap: 10px; margin-top: 10px; }
.followup .actions { flex-wrap: wrap; }
.followgroup + .followgroup { margin-top: 14px; }
.fghead { display: flex; align-items: baseline; gap: 8px; font-size: 12px;
  text-transform: uppercase; letter-spacing: .07em; color: var(--muted);
  margin-bottom: 6px; }
.fghead span { font-variant-numeric: tabular-nums; color: var(--faint); }
.fghead.late { color: var(--crit); }
.fghead.late::before { content: '\2715'; font-weight: 700; }
.fghead.today { color: var(--warn); }
.fghead.today::before { content: '\0021'; font-weight: 700; }

/* The candidate reading their own biodata before approving it (UC-CN-04). */
.biopreview { background: #fff; border: 1px solid var(--rule); border-radius: var(--radius);
  padding: 14px; margin: 0 0 12px; overflow-x: auto; }
.biopreview .doc { max-width: none; }

/* A message quoted back to the person it was written about (UC-CN-08). */
.quoted { font-style: italic; color: var(--muted); }

/* ── What she has been shown (UC-CN-09) ────────────────────────────────────
   A card per pairing rather than a list row: this is a person being proposed,
   and it should not read like a search result. */
.matchcard { border: 1px solid var(--rule); border-radius: var(--radius);
  padding: 14px; margin-bottom: 10px; background: var(--surface); }
.matchcard.mutual { border-color: var(--good); }
.matchcard .mhead { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; }
.matchcard .mname { font-size: 17px; font-weight: 600; }
.matchcard .mmeta { color: var(--muted); font-size: 14px; margin-top: 2px; }
.matchcard .mguna { font-size: 22px; font-weight: 600; font-variant-numeric: tabular-nums;
  white-space: nowrap; }
.matchcard .mguna small { display: block; font-size: 11px; color: var(--muted); font-weight: 400; }
.matchcard .mstate { margin-top: 8px; font-size: 13px; color: var(--muted); }

/* Multi-choice preferences (UC-CN-06). */
.chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 6px; }
.chip { display: inline-flex; align-items: center; gap: 7px; padding: 8px 12px;
  border: 1px solid var(--rule); border-radius: 999px; cursor: pointer;
  font-size: 14px; min-height: 40px; }
.chip input { margin: 0; width: auto; }
.chip:has(input:checked) { border-color: var(--ink); background: var(--sunken); font-weight: 600; }

/* A community attestation, marked on a name (UC-SA-03). */
.tag-ok { font-size: 11px; font-weight: 600; color: var(--good);
  letter-spacing: .04em; white-space: nowrap; }

/* ── Importing a register (UC-SA-02) ───────────────────────────────────────
   The column mapping and the rows that need a human eye. Deliberately plain:
   this screen is read once, carefully, by someone deciding whether to trust it
   with thirty years of records. */
.maprows { display: grid; gap: 8px; }
.maprow { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 10px; align-items: center; margin: 0; }
.maprow > span { font-size: 14px; color: var(--muted); overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
.maprow select { margin: 0; }

.csvrows { margin: 0; padding: 0; list-style: none; max-height: 320px; overflow-y: auto; }
.csvrows li { display: grid; grid-template-columns: 34px 1fr; gap: 4px 10px;
  padding: 8px 0 8px 10px; border-bottom: 1px solid var(--rule); font-size: 14px;
  border-left: 3px solid transparent; }
.csvrows li b { font-variant-numeric: tabular-nums; color: var(--faint); font-weight: 400; }
.csvrows li span { grid-column: 2; font-size: 13px; color: var(--muted); }
.csvrows li.v-refused { border-left-color: var(--crit); }
.csvrows li.v-doubtful { border-left-color: var(--warn); }
.csvrows li.v-duplicate { border-left-color: var(--faint); }

/* The shared thread on a proposal (UC-FM-05). */
.notethread { margin: 0 0 12px; padding: 0; list-style: none; }
.notethread li { padding: 10px 12px; border-radius: var(--radius); margin-bottom: 8px;
  background: var(--sunken); border-left: 3px solid var(--rule); }
.notethread li.n-family { border-left-color: var(--sea); }
.notethread li.n-matchmaker { border-left-color: var(--accent); }
.notethread .nwho { font-size: 12px; color: var(--muted); display: flex;
  justify-content: space-between; gap: 10px; margin-bottom: 4px; }
.notethread .nbody { font-size: 14.5px; }

/* ── Paying (UC-AD-06) ─────────────────────────────────────────────────────
   The reference is the most important thing on this panel — it is what turns
   reconciliation from a judgement into a lookup — so it is the largest thing. */
.paybox { border: 1px solid var(--brand); border-radius: var(--radius);
  padding: 16px; margin-top: 12px; }
.payref { display: flex; flex-direction: column; gap: 2px; padding: 12px;
  background: var(--sunken); border-radius: var(--radius); margin-bottom: 12px; }
.payref span { font-size: 12px; color: var(--muted); text-transform: uppercase;
  letter-spacing: .07em; }
.payref b { font-size: 26px; font-family: var(--mono); letter-spacing: .04em; }
.paybox .actions { flex-wrap: wrap; }
