/* ============================================================================
   Sataviya — "Field & Ink"  |  Anjana Chaudhary roll explorer (read-only)
   sage-khaki paper · peacock-teal brand · marigold focal · Gujarati first-class
   ============================================================================ */
:root {
  --bg:        #eceee7;   /* soft sage-khaki paper */
  --surface:   #ffffff;
  --surface-2: #f5f7f1;
  --ink:       #182a2c;   /* deep teal-charcoal */
  --muted:     #5f6d6c;
  --faint:     #8a9694;
  --line:      #d9ded4;
  --line-soft: #e7eae2;
  --brand:     #0e6b6b;   /* peacock teal */
  --brand-700: #0a5252;
  --brand-050: #e2efec;
  --accent:    #d9862a;   /* marigold */
  --accent-050:#f7ead6;
  --male:      #3a6ea5;
  --female:    #c26a86;
  --danger:    #b4453a;
  --radius:    16px;
  --radius-sm: 11px;
  --shadow:    0 1px 2px rgba(24,42,44,.05), 0 8px 24px -14px rgba(24,42,44,.22);
  --shadow-sm: 0 1px 2px rgba(24,42,44,.06);
  --maxw:      680px;
  --sans: "Inter", system-ui, sans-serif;
  --serif: "Fraunces", Georgia, serif;
  --guj: "Noto Sans Gujarati", "Inter", sans-serif;
}

/* Dark mode — "Field & Ink at night": deep teal-charcoal paper, brighter peacock/marigold. */
:root[data-theme="dark"] {
  --bg:        #141d1c;
  --surface:   #1c2928;
  --surface-2: #172221;
  --ink:       #e9efeb;
  --muted:     #a2b2af;
  --faint:     #6d7f7c;
  --line:      #2c3c3a;
  --line-soft: #243432;
  --brand:     #38b2ad;
  --brand-700: #7fd6d0;
  --brand-050: rgba(56,178,173,.16);
  --accent:    #e6982f;
  --accent-050:rgba(230,152,47,.16);
  --male:      #6f9fd6;
  --female:    #d98aa4;
  --shadow:    0 1px 2px rgba(0,0,0,.4), 0 10px 28px -14px rgba(0,0,0,.6);
  --shadow-sm: 0 1px 2px rgba(0,0,0,.35);
}
html { color-scheme: light dark; }

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
:lang(gu), .guj { font-family: var(--guj); }
a { color: var(--brand); text-decoration: none; }
button { font-family: inherit; }

/* subtle paper texture: faint horizontal "record" lines, very low contrast */
body::before {
  content: ""; position: fixed; inset: 0; pointer-events: none; z-index: 0;
  background-image: linear-gradient(rgba(24,42,44,.018) 1px, transparent 1px);
  background-size: 100% 34px;
}
#app { position: relative; z-index: 1; }

.wrap { max-width: var(--maxw); margin: 0 auto; padding: 0 16px; }

/* ---------- header ---------- */
.appbar {
  position: sticky; top: 0; z-index: 20;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: saturate(1.1) blur(8px);
  border-bottom: 1px solid var(--line);
}
.appbar-inner { display: flex; align-items: center; gap: 11px; height: 58px; padding: 0 12px; }
.mark {
  width: 34px; height: 34px; flex: 0 0 auto; border-radius: 9px;
  background: var(--brand); color: #fff;
  display: grid; place-items: center;
  font-family: var(--guj); font-size: 19px; font-weight: 600;
  box-shadow: inset 0 -2px 0 rgba(0,0,0,.15);
}
/* the mark and the name travel together and sit in the same place on every page */
.brand-mark { display: flex; align-items: center; gap: 10px; flex: 0 0 auto; cursor: pointer; }
.brand-mark b { font-family: var(--serif); font-weight: 600; font-size: 1.16rem;
  letter-spacing: -.01em; color: var(--ink); white-space: nowrap; }
.brand-mark:hover b { color: var(--brand); }
/* on a narrow canvas the search needs the room; the mark alone still says where you are */
@media (max-width: 640px) { .canvas-topbar .brand-mark b { display: none; } }
.brand { display: flex; flex-direction: column; line-height: 1.05; }
.brand b { font-family: var(--serif); font-weight: 600; font-size: 1.24rem; letter-spacing: -.01em; color: var(--ink); }
.brand span { font-size: .74rem; color: var(--brand-700); letter-spacing: .02em; font-weight: 600; }
.appbar-actions { margin-left: auto; display: flex; align-items: center; gap: 12px; }
.appbar .home-link { font-size: .85rem; color: var(--muted); }

/* theme toggle — quiet, round, present in both top bars */
.theme-toggle {
  flex: 0 0 auto; width: 38px; height: 38px; border-radius: 10px;
  display: grid; place-items: center; cursor: pointer;
  background: var(--surface); color: var(--muted);
  border: 1px solid var(--line); box-shadow: var(--shadow-sm);
  transition: color .15s, border-color .15s, background .15s;
  -webkit-tap-highlight-color: transparent;
}
.theme-toggle:hover { color: var(--brand); border-color: var(--brand); }
.theme-toggle:active { transform: scale(.95); }

/* ---------- search screen ---------- */
.hero { padding: 26px 0 8px; }
/* On the landing page the search IS the page, so it is centred rather than run up against
   the left edge with the text. Everywhere else the hero is a heading above a list and stays
   ranged left, which is what a list wants to be read against. */
.home .hero { text-align: center; padding: 64px 0 8px; }
.home .hero h1 { font-size: 2.1rem; }
.home .searchbox { max-width: 560px; margin-left: auto; margin-right: auto; }
.hero h1 {
  font-family: var(--serif); font-weight: 500; font-size: 1.7rem;
  letter-spacing: -.02em; margin: 0 0 4px; color: var(--ink);
}
.hero p { margin: 0 0 18px; color: var(--muted); font-size: .95rem; }

.searchbox { position: relative; margin-bottom: 8px; }
.searchbox svg { position: absolute; left: 15px; top: 50%; transform: translateY(-50%); color: var(--faint); }
.searchbox input {
  width: 100%; height: 54px; padding: 0 16px 0 44px;
  font-family: var(--sans); font-size: 1.05rem; color: var(--ink);
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 14px; box-shadow: var(--shadow-sm);
  outline: none; transition: border-color .15s, box-shadow .15s;
}
.searchbox input::placeholder { color: var(--faint); }
.searchbox input:focus { border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-050); }

.hint { color: var(--muted); font-size: .9rem; padding: 6px 2px; }

/* ---------- person cards (bilingual name; lineage accent) ---------- */
.results { display: flex; flex-direction: column; gap: 10px; padding: 10px 0 32px; }
.pcard {
  display: flex; align-items: center; gap: 12px;
  background: var(--surface); border: 1px solid var(--line);
  border-left: 3px solid var(--accent);       /* lineage accent */
  border-radius: var(--radius-sm); padding: 13px 14px;
  box-shadow: var(--shadow-sm); cursor: pointer;
  transition: transform .12s ease, box-shadow .12s ease, border-color .12s;
  -webkit-tap-highlight-color: transparent;
}
.pcard:active { transform: scale(.99); }
.pcard:hover { box-shadow: var(--shadow); border-left-color: var(--brand); }
.pcard.stub { border-left-color: var(--faint); background: var(--surface-2); }
.pcard-body { min-width: 0; flex: 1; }
.pcard .gu { font-family: var(--guj); font-size: 1.22rem; font-weight: 600; color: var(--ink); line-height: 1.25; }
.pcard .en { font-family: var(--serif); font-size: .95rem; color: var(--muted); margin-top: 1px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pcard .meta { font-size: .78rem; color: var(--faint); margin-top: 3px; text-transform: capitalize; }
.pcard .chev { color: var(--faint); flex: 0 0 auto; }

/* ---------- states ---------- */
.state { text-align: center; color: var(--muted); padding: 48px 20px; }
.state .big { font-family: var(--serif); font-size: 1.15rem; color: var(--ink); margin-bottom: 4px; }
.spinner {
  width: 26px; height: 26px; margin: 40px auto; border-radius: 50%;
  border: 2.5px solid var(--line); border-top-color: var(--brand);
  animation: spin .8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* section heading (eyebrow) */
.eyebrow { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; margin: 4px 0 10px; }
.eyebrow h2 {
  font-family: var(--sans); font-weight: 600; font-size: .82rem;
  letter-spacing: .09em; text-transform: uppercase; color: var(--brand-700); margin: 0;
}

/* ---------- family tree (BALKAN host) ---------- */
.tree-overlay {
  position: absolute; inset: 0; display: grid; place-items: center;
  background: color-mix(in srgb, var(--surface-2) 78%, transparent);
  color: var(--muted); font-size: .92rem; text-align: center; padding: 20px;
  pointer-events: none;
}
/* Card fill by gender, with an ancestor nobody recorded a name for left neutral. Here
   rather than on the drawn element so the whole palette lives in one file and the dark
   theme's lighter blue and pink reach the cards like everything else. */
.canvas-host .node > rect.card { fill: var(--male); }
.canvas-host .node.female > rect.card { fill: var(--female); }
.canvas-host .node.stub > rect.card { fill: var(--faint); }

/* focal person + ancestor stub emphasis. Selectors target .canvas-host (the full-screen
   canvas host). */
/* the searched person gets a steady marigold border PLUS a radiating WAVE: ring rects
   (injected by JS as .focal-wave, behind the card) scale outward and fade, staggered so
   the ripple is continuous. transform-box:fill-box makes scale() grow from each ring's
   own centre. */
.canvas-host .node.center > rect.card {
  stroke: var(--accent); stroke-width: 3px;
}
/* A single slow-cadence wave: it pulses out only a little and dissipates quickly (fades
   out near the node, well before spreading wide), then a calm pause before repeating. */
@keyframes focal-wave {
  0%   { transform: scale(1);    opacity: .6; }
  35%  { transform: scale(1.22); opacity: 0; }
  100% { transform: scale(1.22); opacity: 0; }
}
.canvas-host .node.center > rect.focal-wave {
  fill: none;
  stroke: var(--accent); stroke-width: 3px;
  transform-box: fill-box; transform-origin: center;
  animation: focal-wave 4.5s ease-out infinite;
  pointer-events: none;
}
/* Plays even under prefers-reduced-motion (an intentional wayfinding cue the user asked
   for), just a gentler, smaller expansion. */
@media (prefers-reduced-motion: reduce) {
  @keyframes focal-wave {
    0%   { transform: scale(1);    opacity: .5; }
    35%  { transform: scale(1.16); opacity: 0; }
    100% { transform: scale(1.16); opacity: 0; }
  }
}
/* the other end of a traced connection: the same marigold ring as the focal person, minus
   the pulse — two people are being pointed at, and two things pulsing is just noise */
.canvas-host .node.faredge > rect.card { stroke: var(--accent); stroke-width: 3px; }
.canvas-host .node.stub > rect.card { stroke: var(--faint) !important; stroke-dasharray: 5 3 !important; }
/* edge colors by relationship. BALKAN link groups carry the child's gender
   (link male/female) and 'right-partner'/'partner' for marriage. Scope to
   g.link ... path so node cards/text are never touched. */
.canvas-host g.link path { stroke-width: 3.5px !important; }
/* BALKAN names a marriage link 'partner', 'right-partner' or 'left-partner' depending on
   which side of the hierarchy the spouse landed on, and which one you get changes when the
   view swings to the other family. Match the substring so a marriage looks like a marriage
   whichever side it is drawn from. */
.canvas-host g.link.male:not([class*="partner"]) path { stroke: var(--male) !important; }    /* parent → son */
.canvas-host g.link.female:not([class*="partner"]) path { stroke: var(--female) !important; }/* parent → daughter */
/* marriage = DOUBLE line: a wide marigold stroke with a thin background-coloured one down
   the middle, leaving two parallel rails. treejs draws both; nothing is cloned in. */
.canvas-host g.link[class*="partner"] path { stroke: var(--accent) !important; stroke-width: 6px !important; }
.canvas-host g.link[class*="partner"] path.tj-rail-inner { stroke: var(--surface-2) !important; stroke-width: 2px !important; }
/* a marriage that had to reach across a row, or over a neighbour: same colour, dashed, so
   it never passes for the ordinary side-by-side rail */
.canvas-host g.link.bridged path { stroke-dasharray: 9 6 !important; }
.canvas-host g.link.bridged path.tj-rail-inner { stroke-dasharray: none !important; }


/* A line you can point at, when you are signed in. The hit stroke treejs lays underneath
   is invisible and generous, so the cursor and the highlight are the only cue that the
   line is live at all. */
.canvas-host g.link.removable { cursor: pointer; }
.canvas-host g.link.removable:hover path.tj-line {
  stroke: var(--danger) !important;
  stroke-width: 6px !important;
}
.canvas-host g.link.removable:hover path.tj-rail-inner {
  stroke: var(--surface-2) !important;
  stroke-width: 2px !important;
}

/* Confirming a removal, anchored on the line that was tapped. */
.rmv-scrim { position: fixed; inset: 0; z-index: 60; }
.rmv {
  position: fixed; transform: translate(-50%, -108%); width: 280px;
  padding: 13px 15px; border-radius: 14px;
  background: var(--surface); border: 1px solid var(--line); box-shadow: var(--shadow);
}
.rmv-title { font-family: var(--serif); font-weight: 600; font-size: 1rem; color: var(--ink); }
.rmv-what {
  margin: 6px 0 0; font-family: var(--guj); font-size: .96rem; color: var(--ink);
}
.rmv-note { margin: 6px 0 0; font-size: .78rem; color: var(--muted); }
.rmv-err { margin-top: 8px; font-size: .8rem; color: var(--danger); }
.rmv-acts { display: flex; justify-content: flex-end; gap: 8px; margin-top: 12px; }
.rmv-done { font-size: .92rem; color: var(--brand-700); font-weight: 600; }

/* a portrait on the card, when someone has added one */
.canvas-host image.card-photo { pointer-events: none; }

/* ---------- choosing a photo, inside the details form ---------- */
.pf-photo { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.pf-photo-shot {
  width: 64px; height: 64px; object-fit: cover; border-radius: 12px;
  border: 1px solid var(--line); background: var(--surface-2);
}
.pf-photo-empty {
  width: 64px; height: 64px; border-radius: 12px; display: grid; place-items: center;
  color: var(--faint); border: 1px dashed var(--line); background: var(--surface-2);
}
.pf-photo-empty svg { width: 20px; height: 20px; }
.pf-photo-acts { display: flex; gap: 8px; flex-wrap: wrap; }
.pf-photo-input { display: none; }
.pf-photo-err { flex-basis: 100%; font-size: .8rem; color: var(--danger); }
/* the photo row is the one field that wants the full width of the form */
.pf-field.photo { grid-column: 1 / -1; }

/* legend swatches (positioned by .canvas-legend) */
.lg-male { background: var(--male); } .lg-female { background: var(--female); }
.lg-center { background: #fff; border: 3px solid var(--accent); }
.lg-stub { background: var(--surface-2); border: 1.5px dashed var(--faint); }
.lg-marriage { border-top-color: var(--accent) !important; }

/* avatar dot by gender */
.dot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; }
.dot.m { background: var(--male); } .dot.f { background: var(--female); }

/* ---------- full-screen canvas profile ---------- */
/* The family tree owns the whole viewport; only a search bar sits on top. The
   canvas pans/zooms freely (BALKAN handles drag + wheel/pinch). */
.canvas-page {
  position: fixed; inset: 0; z-index: 5;
  display: flex; flex-direction: column;
  background: var(--surface-2);
}
.canvas-topbar {
  /* the same height as the list pages' header, so the mark does not shift when you open
     a person */
  flex: 0 0 auto; display: flex; align-items: center; gap: 10px;
  height: 58px; padding: 0 12px;
  background: color-mix(in srgb, var(--bg) 90%, transparent);
  backdrop-filter: saturate(1.1) blur(8px);
  border-bottom: 1px solid var(--line); z-index: 30;
}

.canvas-search { position: relative; flex: 1 1 auto; max-width: 640px; margin: 0 auto; }
.canvas-search svg { position: absolute; left: 13px; top: 50%; transform: translateY(-50%); color: var(--faint); pointer-events: none; }
.canvas-search input {
  width: 100%; height: 44px; padding: 0 40px 0 40px;
  font-family: var(--sans); font-size: 1rem; color: var(--ink);
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 12px; box-shadow: var(--shadow-sm); outline: none;
  transition: border-color .15s, box-shadow .15s;
}
.canvas-search input::placeholder { color: var(--faint); }
.canvas-search input:focus { border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-050); }
.cs-clear {
  position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
  border: none; background: transparent; color: var(--faint);
  font-size: 22px; line-height: 1; cursor: pointer; padding: 4px 9px;
}
.cs-clear:hover { color: var(--ink); }

.canvas-results {
  position: absolute; top: calc(100% + 6px); left: 0; right: 0;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 12px; box-shadow: var(--shadow);
  max-height: min(64vh, 460px); overflow-y: auto; z-index: 40; padding: 5px;
}
.cs-row { display: flex; align-items: center; gap: 10px; padding: 9px 10px; border-radius: 9px; cursor: pointer; -webkit-tap-highlight-color: transparent; }
.cs-row:hover { background: var(--surface-2); }
.cs-row-body { min-width: 0; flex: 1; }
.cs-row .gu { font-family: var(--guj); font-weight: 600; font-size: 1.04rem; color: var(--ink); line-height: 1.25; }
.cs-row .en { font-size: .78rem; color: var(--faint); text-transform: capitalize; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cs-empty { padding: 16px; text-align: center; color: var(--muted); }

.canvas-canvas {
  flex: 1 1 auto; position: relative; overflow: hidden; touch-action: none;
  background-color: var(--surface-2);
  background-image: radial-gradient(circle at 1px 1px, rgba(127,127,127,.14) 1px, transparent 0);
  background-size: 22px 22px;
}
/* BALKAN paints the host div white; force it transparent so the themed (light/dark)
   canvas + dot-grid show through. */
.canvas-host { width: 100%; height: 100%; cursor: grab; background: transparent !important; }
.canvas-host:active { cursor: grabbing; }
.canvas-host svg { width: 100%; height: 100%; }

/* subtle floating context, kept off the top so the search bar stands alone */
.canvas-focal {
  position: absolute; left: 12px; bottom: 12px; z-index: 15; max-width: 72vw;
  display: flex; align-items: center; gap: 11px;
  background: color-mix(in srgb, var(--surface) 92%, transparent); backdrop-filter: blur(6px);
  border: 1px solid var(--line); border-left: 3px solid var(--accent);
  border-radius: 12px; padding: 8px 13px; box-shadow: var(--shadow-sm);
}
.canvas-focal .cf-body { min-width: 0; }
.canvas-focal .gu { font-family: var(--guj); font-weight: 700; font-size: 1.08rem; color: var(--ink); line-height: 1.2; }
@media (min-width: 900px) {
  .canvas-focal { gap: 14px; padding: 13px 20px; border-radius: 15px; border-left-width: 4px; }
  .canvas-focal .gu { font-size: 1.5rem; }
  .canvas-focal .en { font-size: .95rem; margin-top: 3px; }
  .canvas-focal .vtag { font-size: .82rem; padding: 4px 12px; }
}
.canvas-focal .en { font-size: .76rem; color: var(--muted); text-transform: capitalize; margin-top: 1px; }

/* village tag — a chip on the right, an attribute of the person (not part of the name) */
.vtag {
  flex: 0 0 auto; align-self: center;
  font-family: var(--guj); font-size: .84rem; font-weight: 600; line-height: 1.3;
  color: var(--brand-700); background: var(--brand-050);
  border: 1px solid color-mix(in srgb, var(--brand) 30%, transparent);
  border-radius: 999px; padding: 4px 11px; white-space: nowrap;
}

.canvas-legend {
  position: absolute; right: 12px; bottom: 12px; z-index: 15; max-width: 62vw;
  display: flex; flex-wrap: wrap; gap: 5px 12px;
  background: color-mix(in srgb, var(--surface) 90%, transparent); backdrop-filter: blur(6px);
  border: 1px solid var(--line); border-radius: 10px; padding: 7px 11px;
  font-size: .72rem; color: var(--muted); box-shadow: var(--shadow-sm);
}
.canvas-legend span { display: inline-flex; align-items: center; gap: 5px; }
.canvas-legend i { width: 12px; height: 12px; border-radius: 4px; flex: 0 0 auto; }
.canvas-legend i.lg-line { width: 15px; height: 0; border-radius: 0; border-top: 2.6px solid; }

@media (max-width: 480px) {
  .canvas-focal { max-width: 52vw; }
  .canvas-legend { display: none; }   /* keep the small screen uncluttered */
}

@media (min-width: 560px) {
  .hero h1 { font-size: 2rem; }
}

/* ============================================================================
   Editing — proposed relationship overrides (sign in · link · delete · review · audit)
   Extends "Field & Ink": brand actions, marigold link accent, danger for removal.
   Everything is token-driven, so light/dark + reduced-motion carry over untouched.
   ============================================================================ */

/* buttons + icon buttons (shared by modal, linker, drawer) */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  font-family: var(--sans); font-size: .92rem; font-weight: 600; line-height: 1;
  padding: 11px 16px; border-radius: 11px; cursor: pointer;
  background: var(--brand); color: #fff; border: 1px solid var(--brand);
  box-shadow: var(--shadow-sm); -webkit-tap-highlight-color: transparent;
  transition: filter .15s, transform .1s, background .15s, border-color .15s;
}
.btn:hover { filter: brightness(1.06); }
.btn:active { transform: scale(.98); }
.btn:disabled { opacity: .55; cursor: default; filter: none; }
.btn.ghost { background: var(--surface); color: var(--muted); border-color: var(--line); }
.btn.ghost:hover { color: var(--brand); border-color: var(--brand); filter: none; }
.btn.danger { background: var(--danger); border-color: var(--danger); color: #fff; }
.btn.sm { padding: 7px 12px; font-size: .82rem; border-radius: 9px; }

.btn.login {
  height: 38px; padding: 0 16px; border-radius: 10px; font-size: .92rem; font-weight: 600;
}
.icon-btn {
  flex: 0 0 auto; width: 38px; height: 38px; border-radius: 10px;
  display: grid; place-items: center; cursor: pointer;
  background: var(--surface); color: var(--muted);
  border: 1px solid var(--line); box-shadow: var(--shadow-sm);
  font-size: 20px; line-height: 1; -webkit-tap-highlight-color: transparent;
  transition: color .15s, border-color .15s, background .15s;
}
.icon-btn:hover { color: var(--brand); border-color: var(--brand); }
.icon-btn:active { transform: scale(.95); }
.icon-btn.editing { color: #fff; background: var(--brand); border-color: var(--brand); }
.icon-btn.editing:hover { filter: brightness(1.06); color: #fff; }

/* editor tools popover */
.edit-wrap { position: relative; display: inline-flex; }
.edit-menu {
  position: absolute; right: 0; top: calc(100% + 8px); z-index: 60; min-width: 194px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 12px; box-shadow: var(--shadow); padding: 6px;
}
.edit-menu a, .edit-menu button {
  display: flex; align-items: center; gap: 9px; width: 100%;
  padding: 9px 10px; border-radius: 8px; font-family: var(--sans); font-size: .9rem;
  color: var(--ink); background: transparent; border: none; cursor: pointer; text-align: left;
}
.edit-menu a:hover, .edit-menu button:hover { background: var(--surface-2); color: var(--brand); }
.edit-menu svg { color: var(--faint); flex: 0 0 auto; }
.edit-menu a:hover svg, .edit-menu button:hover svg { color: var(--brand); }

/* sign-in modal */
.modal-scrim {
  position: fixed; inset: 0; z-index: 100; padding: 18px;
  background: rgba(10,18,18,.42); backdrop-filter: blur(3px);
  display: grid; place-items: center;
}
.modal {
  width: 100%; max-width: 384px; background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: 20px;
}
.modal-title { display: flex; align-items: center; gap: 9px;
  font-family: var(--serif); font-weight: 600; font-size: 1.2rem; color: var(--ink); }
.modal-title svg { color: var(--brand); }
.modal-sub { margin: 8px 0 16px; font-size: .86rem; color: var(--muted); line-height: 1.45; }
.modal-err { color: var(--danger); font-size: .85rem; margin: -4px 0 12px; }
.modal-actions { display: flex; justify-content: flex-end; gap: 9px; margin-top: 4px; }

/* form fields (modal + linker note) */
.fld { display: block; margin-bottom: 12px; }
.fld > span { display: block; font-size: .72rem; font-weight: 700; letter-spacing: .05em;
  text-transform: uppercase; color: var(--faint); margin-bottom: 5px; }
.fld input { width: 100%; height: 44px; padding: 0 13px; font-family: var(--sans);
  font-size: 1rem; color: var(--ink); background: var(--surface-2);
  border: 1px solid var(--line); border-radius: 10px; outline: none;
  transition: border-color .15s, box-shadow .15s, background .15s; }
.fld input:focus { border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-050); background: var(--surface); }

/* ---------- linker (split screen) ----------
   Two live family trees with a connector arcing between them. The panels reuse the
   full-screen canvas chrome (.canvas-canvas / .canvas-host), so every tree style —
   node colours, marriage rails, the focal wave — applies inside them unchanged. */
.link-page { overflow: hidden; }
.link-head { flex: 1 1 auto; min-width: 0; }
.link-head-title { font-family: var(--serif); font-weight: 600; font-size: 1.05rem; color: var(--ink); line-height: 1.2; }
.link-head-sub { font-size: .75rem; color: var(--faint); }
.link-gate { flex: 1 1 auto; display: grid; place-items: center; }

.link-split { flex: 1 1 auto; position: relative; display: flex; min-height: 0; }
.link-panel {
  flex: 1 1 0; min-width: 0; min-height: 0; position: relative;
  display: flex; flex-direction: column;
}
.link-panel.b { border-left: 1px solid var(--line); }
.link-panel-bar {
  flex: 0 0 auto; position: relative; z-index: 25;
  display: flex; align-items: center; gap: 9px; padding: 9px 11px;
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  backdrop-filter: saturate(1.1) blur(6px);
  border-bottom: 1px solid var(--line-soft);
}
.link-panel-bar .canvas-search { max-width: none; }
.link-panel-bar .canvas-search input { height: 38px; font-size: .92rem; }
.link-tag {
  flex: 0 0 auto; width: 24px; height: 24px; border-radius: 7px;
  display: grid; place-items: center;
  font-size: .72rem; font-weight: 800; letter-spacing: .02em;
}
.link-tag.a { color: var(--male);   background: color-mix(in srgb, var(--male) 17%, transparent); }
.link-tag.b { color: var(--female); background: color-mix(in srgb, var(--female) 19%, transparent); }
.link-panel-body { flex: 1 1 auto; min-height: 0; }

.link-empty {
  position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 9px; padding: 24px;
  text-align: center; color: var(--muted);
}
.link-empty-mark {
  width: 48px; height: 48px; border-radius: 50%; display: grid; place-items: center;
  color: var(--faint); border: 1px dashed var(--line); background: var(--surface);
}
.link-empty-mark svg { width: 20px; height: 20px; }
.link-empty-title { font-family: var(--serif); font-size: 1.05rem; font-weight: 600; color: var(--ink); }
.link-empty p { max-width: 30ch; font-size: .86rem; color: var(--faint); margin: 0; }

/* The connector — spans both panels, never intercepts pointer events.
   width/height are explicit: an <svg> is a replaced element, so inset:0 alone leaves it at
   its 300x150 intrinsic size and the path gets clipped out of view. */
.link-wire {
  position: absolute; inset: 0; width: 100%; height: 100%; z-index: 18;
  pointer-events: none; overflow: hidden; color: var(--accent);
}
.link-wire-path {
  fill: none; stroke: currentColor; stroke-width: 3.5px; stroke-linecap: round;
  filter: drop-shadow(0 1px 3px rgba(0,0,0,.28));
}
.link-wire.pending { color: var(--brand); }
.link-wire.pending .link-wire-path { stroke-dasharray: 9 7; }

/* The picked node. Inside the linker a marigold ring means exactly one thing — "I chose
   this person" — so the panel's focal ring and its pulsing wave are suppressed there;
   otherwise two identical rings in one panel would mean two different things. */
.canvas-host g.node.picked > rect.card {
  stroke: var(--accent) !important; stroke-width: 7px !important;
  filter: drop-shadow(0 0 7px var(--accent));
}
.canvas-host.linking .node.center > rect.card {
  stroke: rgba(15,28,28,.42) !important; stroke-width: 3px !important;
}
.canvas-host.linking .node.center > rect.focal-wave { display: none; }
.canvas-host.linking g.node { cursor: pointer; }

/* ---------- linker action bar ---------- */
.link-actionbar {
  flex: 0 0 auto; z-index: 30;
  padding: 11px 14px calc(11px + env(safe-area-inset-bottom));
  background: color-mix(in srgb, var(--bg) 94%, transparent);
  backdrop-filter: saturate(1.1) blur(8px);
  border-top: 1px solid var(--line);
  display: flex; flex-direction: column; gap: 9px;
}
.link-pair { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.link-slot {
  display: grid; place-items: center; min-width: 92px; height: 34px; padding: 0 12px;
  border-radius: 10px; border: 1px dashed var(--line); color: var(--faint);
  font-size: .72rem; font-weight: 800; letter-spacing: .06em;
}
.link-chip {
  display: inline-flex; align-items: center; gap: 8px; height: 34px; padding: 0 6px 0 11px;
  border-radius: 10px; background: var(--surface); border: 1px solid var(--line);
  box-shadow: var(--shadow-sm);
}
.link-chip.a { border-left: 3px solid var(--male); }
.link-chip.b { border-left: 3px solid var(--female); }
.link-chip-name { font-family: var(--guj); font-weight: 600; font-size: 1rem; color: var(--ink); }
.link-chip-x {
  border: none; background: transparent; color: var(--faint); cursor: pointer;
  font-size: 19px; line-height: 1; padding: 2px 6px; border-radius: 7px;
}
.link-chip-x:hover { color: var(--danger); background: color-mix(in srgb, var(--danger) 10%, transparent); }
.link-join { color: var(--accent); display: inline-flex; }
.link-join svg { width: 18px; height: 18px; }

.link-msg { font-size: .88rem; color: var(--muted); }
.link-msg.warn { color: var(--danger); }
.link-is { color: var(--muted); font-size: .9rem; }

/* which way round the link runs, inferred from the tree rather than asked */
.link-reads { display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px; margin-bottom: 7px; }
.link-reads-txt { font-family: var(--guj); font-size: 1.02rem; font-weight: 600; color: var(--ink); }
.link-which { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 8px; }
.link-which-q { font-size: .8rem; color: var(--muted); }
.link-which-opt {
  font-family: var(--guj); font-size: .95rem; padding: 6px 12px; cursor: pointer;
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--line); border-radius: 999px;
}
.link-which-opt.on { border-color: var(--brand); background: var(--brand-050); color: var(--brand-700); font-weight: 600; }

/* the relationship word — a select, because the roll has 25 of them, not 3 */
.link-word {
  height: 34px; min-width: 190px; padding: 0 10px;
  font-family: var(--sans); font-size: .92rem; color: var(--ink);
  background: var(--surface); border: 1px solid var(--line); border-radius: 10px;
  box-shadow: var(--shadow-sm); cursor: pointer;
}
.link-word:focus { outline: none; border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-050); }
.link-word:disabled { opacity: .5; cursor: default; }

/* what the claim will actually record — the whole point for composite words, whose edge
   lands on a third person rather than on either of the two picked */
.link-plan {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px;
  padding: 9px 12px; border-radius: 10px;
  background: var(--surface-2); border: 1px solid var(--line-soft);
}
.link-plan.indirect { border-color: color-mix(in srgb, var(--accent) 45%, transparent); background: var(--accent-050); }
.link-plan-tag {
  flex: 0 0 auto; font-size: .64rem; font-weight: 800; letter-spacing: .07em;
  text-transform: uppercase; color: var(--brand-700);
}
.link-plan.indirect .link-plan-tag { color: var(--accent); }
.link-plan-txt { font-family: var(--guj); font-size: 1rem; color: var(--ink); }
.link-plan-arrow {
  font-family: var(--sans); font-size: .68rem; font-weight: 700; letter-spacing: .03em;
  text-transform: uppercase; color: var(--muted); margin: 0 6px;
}
.link-plan-note { font-size: .78rem; color: var(--muted); }

.link-go { display: flex; align-items: center; gap: 9px; margin-top: 9px; }
.link-go .link-note { flex: 1 1 auto; margin-top: 0; }
.link-go .btn { flex: 0 0 auto; }

.link-note {
  width: 100%; height: 40px; margin-top: 9px; padding: 0 13px;
  font-family: var(--sans); font-size: .92rem; color: var(--ink);
  background: var(--surface-2); border: 1px solid var(--line); border-radius: 10px; outline: none;
}
.link-note:focus { border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-050); background: var(--surface); }

/* ---------- the pencil on each node card ---------- */
/* Pointing at somebody lifts their family out of the chart: father, grandfathers, siblings
   and first cousins come forward and everyone else falls back. A chart of a joint family is
   a wall of cards, and the question a reader is nearly always asking — which of these belong
   together — is answered by moving the pointer rather than by tracing lines with a finger. */
.canvas-host g.node.kin { filter: drop-shadow(0 6px 10px rgba(15,28,28,.35)); }
.canvas-host g.node.kin > rect.card { stroke: rgba(15,28,28,.75); }
.canvas-host g.node.dim, .canvas-host g.link.dim { opacity: .22; }
.canvas-host g.node.dim, .canvas-host g.link.dim,
.canvas-host g.node.kin { transition: opacity .12s ease, filter .12s ease; }
:root[data-theme="dark"] .canvas-host g.node.kin { filter: drop-shadow(0 6px 12px rgba(0,0,0,.65)); }
:root[data-theme="dark"] .canvas-host g.node.kin > rect.card { stroke: rgba(233,239,235,.6); }
@media (prefers-reduced-motion: reduce) {
  .canvas-host g.node, .canvas-host g.link { transition: none; }
}

/* ---------- a field correction, shown as a diff ---------- */

/* ---------- person details form ---------- */
/* Wider than the other modals — this one is a fourteen-field form. It has to raise .modal's
   max-width, not its width: max-width wins over width, so setting width alone left the form
   clamped to 384px with its second column cut off. */
.pf-modal { max-width: min(620px, 94vw); max-height: 88vh; overflow-y: auto; }
.pf-sub-en { font-family: var(--serif); color: var(--faint); font-size: .86rem; margin-left: 8px; }
/* Two columns when there is room for two, one when there isn't — measured against the space
   the form actually has rather than the width of the window, which is what the modal cares
   about. min-width:0 lets a field narrow past an input's intrinsic width instead of pushing
   the grid wider than its container. */
.pf-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 232px), 1fr));
  gap: 10px 12px; margin: 14px 0 4px;
}
.pf-field { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.pf-label {
  display: flex; align-items: baseline; gap: 7px;
  font-size: .7rem; font-weight: 700; letter-spacing: .05em;
  text-transform: uppercase; color: var(--muted);
}
.pf-private {
  font-size: .58rem; letter-spacing: .06em; padding: 1px 6px; border-radius: 999px;
  color: var(--brand-700); background: var(--brand-050); text-transform: uppercase;
}
.pf-field input, .pf-field select {
  height: 38px; padding: 0 11px; font-family: var(--sans); font-size: .94rem; color: var(--ink);
  background: var(--surface-2); border: 1px solid var(--line); border-radius: 9px; outline: none;
}
.pf-field input:focus, .pf-field select:focus {
  border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-050); background: var(--surface);
}
/* a field you've actually altered, so it's obvious what will be proposed */
.pf-field.dirty input, .pf-field.dirty select {
  border-color: var(--accent); background: var(--accent-050);
}
.pf-field.dirty .pf-label { color: var(--accent); }
.pf-count { margin-right: auto; font-size: .8rem; color: var(--muted); }

/* ---------- trace: the chain of people connecting two nodes ---------- */
.link-wire.tracing { color: var(--brand); }
.link-wire.tracing .link-wire-path { stroke-dasharray: 2 8; stroke-linecap: round; }

/* Two people with nothing joining them: a small cross where the panels meet, rather than
   a line that would suggest a connection the roll doesn't record. */
.link-wire-x circle { fill: var(--surface); stroke: var(--line); stroke-width: 1.5px; }
.link-wire-x path {
  stroke: var(--faint); stroke-width: 2.4px; stroke-linecap: round; fill: none;
}
.link-actionbar.trace { max-height: 42vh; overflow-y: auto; }

.trace-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 9px; }
.trace-label { font-family: var(--guj); font-size: 1.05rem; color: var(--muted); }
.trace-label b { font-weight: 600; color: var(--ink); }
.trace-steps { font-size: .78rem; color: var(--faint); }

/* The chain is drawn, not described: the people along it and the edges the roll stores
   between them, rendered by the same tree code as everything else, in its own band under
   the two panels you pick from. */
/* With the picking panels tucked away, the answer gets the whole canvas.
   min-height:0 is load-bearing: a flex item will not shrink below its content without it,
   so the canvas would grow past the bottom of the page and take the drawing with it. */
.link-split.tucked { display: none; }
.trace-graph {
  flex: 1 1 auto; position: relative; display: flex; flex-direction: column;
  min-height: 0;
}
.trace-graph-back {
  position: absolute; top: 9px; right: 12px; z-index: 6;
  padding: 4px 12px; border-radius: 999px; cursor: pointer;
  font: inherit; font-size: .78rem; color: var(--brand-700);
  background: color-mix(in srgb, var(--surface) 90%, transparent);
  border: 1px solid var(--line);
}
.trace-graph-back:hover { border-color: var(--brand); }
.trace-graph-body { flex: 1 1 auto; min-height: 0; }
.trace-graph-tag {
  position: absolute; top: 9px; left: 12px; z-index: 5; pointer-events: none;
  padding: 3px 10px; border-radius: 999px;
  font-size: .68rem; font-weight: 800; letter-spacing: .07em; text-transform: uppercase;
  color: var(--brand-700); background: color-mix(in srgb, var(--surface) 86%, transparent);
  border: 1px solid var(--line-soft);
}

@media (max-width: 900px) {
  .link-actionbar.trace { max-height: 38vh; }
}

.link-actionbar.done { background: var(--brand-050); border-top-color: color-mix(in srgb, var(--brand) 34%, transparent); }
.link-done { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px; }
.link-done-txt { color: var(--brand-700); font-size: .95rem; }
.link-done-acts { display: flex; align-items: center; gap: 12px; }
.link-done-acts a { font-weight: 600; color: var(--brand-700); }

/* two trees don't fit side by side on a phone — stack them, connector runs vertically */
@media (max-width: 900px) {
  .link-split { flex-direction: column; }
  .link-panel.b { border-left: none; border-top: 1px solid var(--line); }
  .link-head-sub { display: none; }
  /* the claim wraps onto its own lines rather than squeezing the names */
  .link-pair { row-gap: 6px; }
  .link-word { min-width: 0; flex: 1 1 140px; }
  .link-go { flex-wrap: wrap; }
  .link-go .link-note { flex-basis: 100%; }
}

.toast { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: 10px; margin-top: 16px; padding: 13px 15px; border-radius: 12px; font-size: .92rem; }
.toast.ok { background: var(--brand-050); border: 1px solid color-mix(in srgb, var(--brand) 34%, transparent); color: var(--brand-700); }
.toast-acts { display: flex; align-items: center; gap: 12px; }
.toast-acts a { font-weight: 600; color: var(--brand-700); }

/* ---------- profile relationship drawer (delete) ---------- */
/* the editing tools that float over a profile's tree */
.canvas-tools { position: absolute; right: 12px; top: 12px; z-index: 16; display: flex; gap: 8px; }
.canvas-tools .canvas-editbtn { position: static; }

.canvas-editbtn {
  position: absolute; right: 12px; top: 12px; z-index: 16;
  display: inline-flex; align-items: center; gap: 7px; padding: 8px 13px; border-radius: 11px;
  font-family: var(--sans); font-size: .85rem; font-weight: 600; cursor: pointer;
  color: #fff; background: var(--brand); border: 1px solid var(--brand); box-shadow: var(--shadow-sm);
  -webkit-tap-highlight-color: transparent; transition: filter .15s, transform .1s;
}
.canvas-editbtn:hover { filter: brightness(1.06); }
.canvas-editbtn:active { transform: scale(.97); }
.canvas-editbtn svg { width: 16px; height: 16px; }

.drawer-scrim { position: fixed; inset: 0; z-index: 80; background: rgba(10,18,18,.4);
  backdrop-filter: blur(2px); display: flex; justify-content: flex-end; }
.drawer { width: min(400px, 92vw); height: 100%; display: flex; flex-direction: column;
  background: var(--surface); border-left: 1px solid var(--line); box-shadow: var(--shadow);
  padding: 16px; overflow-y: auto; }
.drawer-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; margin-bottom: 12px; }
.drawer-head-txt { min-width: 0; }
.drawer-title { font-family: var(--serif); font-weight: 600; font-size: 1.2rem; color: var(--ink); }
.drawer-sub { font-family: var(--guj); font-size: 1rem; color: var(--muted); margin-top: 2px; }
.drawer-err { color: var(--danger); font-size: .85rem; margin-bottom: 10px; }
.drawer-empty { color: var(--muted); font-size: .9rem; padding: 22px 4px; text-align: center; }
.drawer-list { display: flex; flex-direction: column; gap: 8px; }
.drow { display: flex; align-items: center; gap: 10px; padding: 10px 11px;
  background: var(--surface-2); border: 1px solid var(--line-soft); border-radius: 11px; }
.drow-kind { flex: 0 0 auto; min-width: 66px; font-size: .68rem; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--brand-700); }
.drow-body { min-width: 0; flex: 1; cursor: pointer; }
.drow-body .gu { font-family: var(--guj); font-weight: 600; color: var(--ink); font-size: 1rem; line-height: 1.2; }
.drow-body .en { font-family: var(--serif); font-size: .78rem; color: var(--faint); }
.drow-del { flex: 0 0 auto; width: 34px; height: 34px; border-radius: 9px; display: grid; place-items: center;
  background: transparent; color: var(--faint); border: 1px solid transparent; cursor: pointer;
  transition: color .15s, background .15s, border-color .15s; }
.drow-del:hover { color: var(--danger); background: color-mix(in srgb, var(--danger) 10%, transparent);
  border-color: color-mix(in srgb, var(--danger) 30%, transparent); }
.drow-confirm { display: flex; align-items: center; gap: 6px; flex: 0 0 auto; }
.drawer-link { display: flex; align-items: center; gap: 8px; margin-top: 14px; padding: 12px 13px;
  border-radius: 11px; border: 1px dashed var(--line); color: var(--brand); font-weight: 600; font-size: .9rem; }
.drawer-link:hover { border-color: var(--brand); background: var(--brand-050); }

/* ---------- edit history (audit ledger) ---------- */
.audit { display: flex; flex-direction: column; gap: 9px; padding: 8px 0 40px; }
.audit-row { display: flex; align-items: flex-start; gap: 12px; padding: 12px 14px;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-sm); box-shadow: var(--shadow-sm); }
.audit-act { flex: 0 0 auto; margin-top: 1px; font-size: .66rem; font-weight: 700; letter-spacing: .05em;
  text-transform: uppercase; padding: 4px 9px; border-radius: 999px; }
.audit-body { min-width: 0; flex: 1; }
.audit-pair { display: flex; flex-wrap: wrap; align-items: baseline; gap: 7px;
  font-family: var(--guj); font-size: 1.02rem; color: var(--ink); }
.audit-pair a { font-weight: 600; color: var(--ink); }
.audit-pair a:hover { color: var(--brand); }
.audit-type { font-family: var(--sans); font-size: .7rem; font-weight: 700; letter-spacing: .03em;
  text-transform: uppercase; color: var(--accent); background: var(--accent-050); padding: 2px 8px; border-radius: 999px; }
.audit-ids { margin-top: 3px; font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: .72rem; letter-spacing: .01em; color: var(--faint); }
.audit-meta { margin-top: 4px; font-size: .76rem; color: var(--faint); line-height: 1.5; }
.audit-sub { font-size: .74rem; font-weight: 600; color: var(--muted); margin-top: 2px; }
.audit-type.del { color: var(--danger); background: color-mix(in srgb, var(--danger) 12%, transparent); }

/* status badges (shared by history + review) */
.audit-act.pending  { color: var(--accent);    background: var(--accent-050); }
.audit-act.approved { color: var(--brand-700);  background: var(--brand-050); }
.audit-act.rejected { color: var(--danger);     background: color-mix(in srgb, var(--danger) 12%, transparent); }

/* ---------- roles: menu extras + pending badge ---------- */
.btn.login {
  height: 38px; padding: 0 16px; border-radius: 10px; font-size: .92rem; font-weight: 600;
}
.icon-btn { position: relative; }
.edit-badge {
  position: absolute; top: -5px; right: -5px; min-width: 17px; height: 17px; padding: 0 4px;
  border-radius: 9px; background: var(--accent); color: #fff; font-size: .66rem; font-weight: 700;
  display: grid; place-items: center; box-shadow: 0 0 0 2px var(--surface);
}
/* signed-in account block at the top of the editor menu */
.edit-account { padding: 8px 10px 10px; border-bottom: 1px solid var(--line-soft); margin-bottom: 5px; }
.edit-account-name { font-weight: 600; font-size: .92rem; color: var(--ink); line-height: 1.25;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.edit-account-mail { font-size: .76rem; color: var(--faint); margin-top: 1px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.edit-account-role { display: inline-block; margin-top: 6px; font-size: .66rem; font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase; padding: 3px 8px; border-radius: 999px;
  color: var(--muted); background: var(--surface-2); border: 1px solid var(--line-soft); }
.edit-account-role.admin { color: var(--brand-700); background: var(--brand-050);
  border-color: color-mix(in srgb, var(--brand) 30%, transparent); }

/* "Continue with Google" — white button per Google's branding guidance, in both themes */
.btn.google {
  width: 100%; gap: 10px; padding: 13px 16px; margin-bottom: 14px;
  background: #ffffff; color: #1f1f1f; border: 1px solid #dadce0;
  font-size: .95rem; font-weight: 600;
}
.btn.google:hover { background: #f7f8f8; filter: none; }
:root[data-theme="dark"] .btn.google { background: #ffffff; color: #1f1f1f; border-color: #5f6368; }
.btn.google svg { flex: 0 0 auto; }
.menu-count {
  margin-left: auto; min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px;
  background: var(--accent); color: #fff; font-size: .68rem; font-weight: 700; display: grid; place-items: center;
}

/* ---------- global toast ---------- */
.gtoast {
  position: fixed; left: 50%; bottom: 22px; transform: translateX(-50%); z-index: 200;
  max-width: min(520px, 92vw); padding: 12px 18px; border-radius: 12px; cursor: pointer;
  font-size: .92rem; font-weight: 500; box-shadow: var(--shadow);
  background: var(--ink); color: var(--bg); border: 1px solid transparent;
  animation: gtoast-in .22s ease-out;
}
.gtoast.ok  { background: var(--brand); color: #fff; }
.gtoast.err { background: var(--danger); color: #fff; }
@keyframes gtoast-in { from { opacity: 0; transform: translate(-50%, 8px); } to { opacity: 1; transform: translate(-50%, 0); } }
@media (prefers-reduced-motion: reduce) { .gtoast { animation: none; } }

/* ---------- drawer additions (pending removal) ---------- */
.drawer-note { font-size: .8rem; color: var(--muted); background: var(--surface-2);
  border: 1px solid var(--line-soft); border-radius: 10px; padding: 9px 11px; margin: 0 0 12px; line-height: 1.45; }
.drow-pending { flex: 0 0 auto; font-size: .72rem; font-weight: 700; letter-spacing: .02em;
  color: var(--accent); background: var(--accent-050); border-radius: 999px; padding: 4px 10px; }

/* ---------- adding someone the roll never held ----------
   A + on each edge of a card, tangent to it, so the direction you point is the direction
   the family is missing someone: a parent above, a child below, a spouse or sibling beside.
   They belong to the card's own group, so they pan and zoom with it. */
.canvas-host g.node-add { opacity: 0; pointer-events: none; transition: opacity .13s ease; }
.canvas-host g.node-add circle { fill: var(--surface); stroke: var(--brand); stroke-width: 1.5px; }
.canvas-host g.node-add path.node-add-plus { stroke: var(--brand); stroke-width: 2.2px; stroke-linecap: round; }
/* Revealed by the card, and kept alive by the + itself — the two are tangent, so the
   pointer never crosses a gap where the hover would drop and the target vanish. */
.canvas-host g.node:hover g.node-add,
.canvas-host g.node-add:hover { opacity: 1; pointer-events: auto; cursor: pointer; }
.canvas-host g.node-add:hover circle { fill: var(--brand); }
.canvas-host g.node-add:hover path.node-add-plus { stroke: var(--surface); }
/* Nothing hovers on a touchscreen, so there the focal card carries its own always — one
   card's worth of controls rather than every card's. */
@media (any-pointer: coarse) {
  .canvas-host g.node.center g.node-add { opacity: 1; pointer-events: auto; }
}
@media (prefers-reduced-motion: reduce) { .canvas-host g.node-add { transition: none; } }

/* The door out of the family: how many relatives are standing just outside, on the person
   they hang off. Sits above the card's corner so it never covers a face. Teal, not marigold
   — marigold on this chart means "this is who you are looking at" and must go on saying
   only that, with the focal person's ring right beside these. */
.canvas-host g.node-more { cursor: pointer; }
.canvas-host g.node-more rect {
  fill: var(--brand); stroke: var(--surface); stroke-width: 2px;
}
.canvas-host g.node-more text {
  fill: #fff; font-family: var(--sans); font-size: 12px; font-weight: 800;
  pointer-events: none;
}
.canvas-host g.node-more:hover rect { fill: var(--brand); }

/* which relationship the new person is — the words this edge of the card can offer */
.ap-words { display: flex; flex-wrap: wrap; gap: 8px; margin: 2px 0 10px; }
.ap-word {
  padding: 7px 15px; border-radius: 999px; cursor: pointer;
  font-size: .85rem; font-weight: 600; text-transform: capitalize;
  color: var(--muted); background: var(--surface); border: 1px solid var(--line);
  transition: color .15s, border-color .15s, background .15s;
}
.ap-word:hover:not(:disabled) { color: var(--brand-700); border-color: var(--brand); }
.ap-word.on { color: #fff; background: var(--brand); border-color: var(--brand); }
/* A word the roll has no room for is shown and disabled rather than hidden: "no brother"
   is a fact about this family worth seeing, and its title says why. */
.ap-word:disabled { opacity: .4; cursor: not-allowed; text-decoration: line-through; }
.ap-reading { margin: 0 0 12px; font-size: .84rem; color: var(--muted); }
.ap-why { margin: 4px 0 8px; padding-left: 18px; color: var(--muted); font-size: .88rem; }
.ap-why b { color: var(--ink); text-transform: capitalize; }
/* A value that came from the family rather than from the person filling the form. Marked
   rather than silently placed: it is a suggestion, and a wrong one has to be correctable
   without first being noticed. */
.pf-field.filled input, .pf-field.filled select {
  border-color: color-mix(in srgb, var(--brand) 45%, var(--line));
  background: color-mix(in srgb, var(--brand-050) 55%, var(--surface));
}
.pf-filled { margin-left: 6px; font-size: .6rem; font-weight: 700; letter-spacing: .05em;
  text-transform: uppercase; color: var(--brand-700); }
.pf-req { margin-left: 6px; font-size: .62rem; font-weight: 800; letter-spacing: .06em;
  text-transform: uppercase; color: var(--accent); }

/* ---------- review queue ----------
   A deck of decisions. Each card is one proposed change, and the two things that can happen
   to it are the same two whichever way they are reached: a tick and a cross to click, or the
   card itself pushed right or left. The washes under the card are what make the gesture
   legible — the colour and the word appear as it moves, so the outcome is named before the
   finger lets go rather than after. */
.rv-bar { display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  padding: 2px 2px 10px; }
.rv-count { font-size: .74rem; font-weight: 800; letter-spacing: .07em; text-transform: uppercase;
  color: var(--brand-700); }
/* The swipe is worth mentioning only where there is a finger to do it with. `any-pointer`
   rather than `pointer` so a laptop with a touchscreen — which reports a fine pointer
   because of its trackpad, and can still swipe — is told about it too. */
.rv-hint { display: none; font-size: .78rem; color: var(--faint); }
@media (any-pointer: coarse) { .rv-hint { display: inline; } }

.rv { display: flex; flex-direction: column; gap: 12px; padding: 0 0 48px; }
.rv-card { position: relative; border-radius: var(--radius); }

.rv-track { position: absolute; inset: 0; display: flex; align-items: center;
  justify-content: space-between; padding: 0 20px; border-radius: var(--radius);
  overflow: hidden; background: var(--surface-2); }
.rv-track.toward-yes { background: var(--brand-050); }
.rv-track.toward-no { background: color-mix(in srgb, var(--danger) 13%, transparent); }
/* far enough that letting go decides: the wash goes solid, so "release now" is visible */
.rv-track.armed.toward-yes { background: color-mix(in srgb, var(--brand) 26%, var(--surface)); }
.rv-track.armed.toward-no { background: color-mix(in srgb, var(--danger) 26%, var(--surface)); }
.rv-wash { display: inline-flex; align-items: center; gap: 8px;
  font-size: .8rem; font-weight: 800; letter-spacing: .07em; text-transform: uppercase; }
.rv-wash.yes { color: var(--brand-700); }
.rv-wash.no { color: var(--danger); }

.rv-face { position: relative; padding: 14px 16px 12px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow-sm);
  /* the browser keeps the vertical scroll; this only ever claims the horizontal */
  touch-action: pan-y; -webkit-user-select: none; user-select: none;
  transition: transform .26s cubic-bezier(.2,.8,.3,1), box-shadow .2s ease; }
.rv-card.leaving .rv-face { box-shadow: none; }
.rv-face:active { cursor: grabbing; }
/* while a finger is on it, follow the finger exactly — a transition here reads as lag */
.rv-card:not(.leaving) .rv-face:active { transition: none; }
@media (prefers-reduced-motion: reduce) { .rv-face { transition: none; } }

.rv-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.rv-kind { font-size: .67rem; font-weight: 800; letter-spacing: .06em; text-transform: uppercase;
  padding: 3px 9px; border-radius: 999px; }
.rv-kind.add { color: var(--brand-700); background: var(--brand-050); }
.rv-kind.delete { color: var(--danger); background: color-mix(in srgb, var(--danger) 12%, transparent); }
.rv-kind.update { color: var(--accent); background: var(--accent-050); }
.rv-kind.create { color: #fff; background: var(--brand); }
.rv-when { font-size: .74rem; color: var(--faint); white-space: nowrap; }

.rv-what { margin-top: 11px; }
/* Two full names, stacked, with the word between them where it belongs. Not a wrapping row:
   these names are long, and in a row the relationship ends up trailing the first name where
   it reads as part of it. Nothing is ever truncated — a name shortened to fit is a name that
   cannot be checked, which is the one thing this screen exists for. */
.rv-claim { display: flex; flex-direction: column; align-items: flex-start; gap: 5px;
  line-height: 1.35; }
.rv-claim .rv-word { margin-left: 2px; }
.rv-word { font-family: var(--sans); font-size: .7rem; font-weight: 800; letter-spacing: .04em;
  text-transform: uppercase; color: var(--brand-700); background: var(--brand-050);
  border-radius: 999px; padding: 3px 10px; }
.rv-word.del { color: var(--danger); background: color-mix(in srgb, var(--danger) 12%, transparent);
  text-decoration: line-through; }

/* The connection that would exist if this were approved — the same picture the trace view
   draws, because a relationship means nothing except against the people it runs through. */
.rv-graph { position: relative; margin-top: 12px; height: 230px;
  border: 1px solid var(--line-soft); border-radius: var(--radius-sm); overflow: hidden;
  background: var(--surface-2); }
.rv-graph.waiting { display: grid; place-items: center; }
.rv-graph.waiting .spinner { margin: 0; }
.rv-graph .canvas-host { position: absolute; inset: 0; }
/* a picture to read, not a chart to click through: panning and zooming, nothing else */
.rv-graph .tj-node { cursor: default; }
/* Where the card is decided by pushing it, the picture inside must not eat the push. It is
   framed to fit the whole connection already, so panning it earns nothing here — and losing
   the swipe across most of the card's height would cost a great deal.

   Descendants too, and not only the container: the hit strokes under each line set
   pointer-events themselves, and a child that states its own value is not covered by an
   ancestor's `none`. */
@media (any-pointer: coarse) { .rv-graph, .rv-graph * { pointer-events: none; } }
.rv-graph-note { margin-top: 10px; padding: 9px 12px; border-radius: var(--radius-sm);
  font-size: .84rem; color: var(--danger);
  background: color-mix(in srgb, var(--danger) 8%, transparent);
  border: 1px solid color-mix(in srgb, var(--danger) 24%, transparent); }

/* A person, named the way the village names them: given name, then father and grandfather,
   then where they live. Never the first name alone — it identifies nobody. */
.who { display: inline-flex; flex-wrap: wrap; align-items: baseline; gap: 3px 8px; }
a.who:hover .who-gu { color: var(--brand); }
.who-gu { font-family: var(--guj); font-size: 1.06rem; font-weight: 600; color: var(--ink); }
.who-en { font-family: var(--serif); font-size: .9rem; color: var(--muted); }
.who-village { font-family: var(--guj); font-size: .68rem; font-weight: 600;
  padding: 2px 9px; border-radius: 999px; color: var(--brand-700);
  background: var(--brand-050); white-space: nowrap; }
.who-unknown { color: var(--faint); font-style: italic; }

/* A correction, as a diff. The colours are the ones every code review uses rather than the
   page palette: a reviewer already knows what a red line and a green line mean. */
.diff { margin-top: 10px; display: flex; flex-direction: column; gap: 10px; }
.diff-field { border: 1px solid var(--line); border-radius: var(--radius-sm); overflow: hidden; }
.diff-name { padding: 5px 12px; font-size: .7rem; font-weight: 700; letter-spacing: .05em;
  text-transform: uppercase; color: var(--muted);
  background: var(--surface-2); border-bottom: 1px solid var(--line); }
.diff-line { display: flex; align-items: center; gap: 10px; padding: 6px 12px;
  font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: .85rem;
  white-space: pre-wrap; overflow-wrap: anywhere; }
.diff-sign { flex: 0 0 auto; font-weight: 700; opacity: .75; }
.diff-line.del { background: #ffebe9; color: #82071e; }
.diff-line.ins { background: #e6ffec; color: #0a5a26; }
:root[data-theme="dark"] .diff-line.del { background: rgba(248,81,73,.15); color: #ff9492; }
:root[data-theme="dark"] .diff-line.ins { background: rgba(63,185,80,.15); color: #56d364; }
.diff-none { opacity: .7; font-style: italic; }
.diff-shot { width: 54px; height: 54px; object-fit: cover; border-radius: 7px;
  background: var(--surface); border: 1px solid var(--line); }

.rv-foot { margin-top: 11px; display: flex; flex-wrap: wrap; gap: 4px 10px;
  font-size: .76rem; color: var(--faint); }
.rv-note { color: var(--muted); font-style: italic; }

.rv-acts { position: absolute; right: 14px; bottom: 12px; display: flex; gap: 10px; }
.rv-btn { display: grid; place-items: center; width: 42px; height: 42px; padding: 0;
  border-radius: 50%; cursor: pointer; background: var(--surface);
  border: 1.5px solid var(--line); color: var(--muted);
  transition: transform .12s ease, background .15s ease, border-color .15s ease, color .15s ease; }
.rv-btn:hover { transform: translateY(-1px); }
.rv-btn.yes:hover { color: var(--brand-700); border-color: var(--brand); background: var(--brand-050); }
.rv-btn.no:hover { color: var(--danger); border-color: var(--danger);
  background: color-mix(in srgb, var(--danger) 10%, transparent); }
.rv-btn:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.rv-btn:disabled { opacity: .45; cursor: default; transform: none; }
@media (prefers-reduced-motion: reduce) { .rv-btn:hover { transform: none; } }

/* The actions sit under the card's own content rather than beside it once there is no room
   to put them beside it. */
@media (max-width: 560px) {
  .rv-face { padding-bottom: 62px; }
  .rv-acts { left: 14px; right: 14px; justify-content: flex-end; }
  .rv-claim { font-size: 1.05rem; }
}
@media (min-width: 561px) { .rv-face { padding-right: 122px; } }
