/* ---- Design tokens ---------------------------------------------------- */
:root {
  --paper: #f7f4ec;
  --paper-panel: #f1ecdf;
  --paper-line: #ddd5c0;
  --ink: #262220;
  --ink-soft: #7a7266;
  --seal-wine: #7a2e33;
  --seal-slate: #35586b;
  --accent: #7a2e33;

  --card-bg: #ffffff;
  --male-color: #7fa3b8;
  --male-border: #c3d5de;
  --female-color: #cf90a3;
  --female-border: #e6c6d0;
  --card-radius: 14px;
  --link-color: #8a8272;

  --font-display: 'Spectral', Georgia, serif;
  --font-body: 'IBM Plex Sans', -apple-system, Segoe UI, sans-serif;
  --font-mono: 'IBM Plex Mono', 'Courier New', monospace;

  --radius: 6px;
  --sidebar-width: 280px;
}

* { box-sizing: border-box; }

html, body {
  height: 100%;
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
}

.app {
  height: 100vh;
  display: flex;
  flex-direction: column;
}

/* ---- Top bar ------------------------------------------------------------ */
.topbar {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 16px;
  border-bottom: 1px solid var(--paper-line);
  background: var(--paper-panel);
}

.topbar h1 {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 19px;
  margin: 0;
  letter-spacing: 0.01em;
}

.status-line {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--ink-soft);
}

.icon-btn {
  border: 1px solid var(--paper-line);
  background: var(--paper);
  color: var(--ink);
  border-radius: var(--radius);
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.icon-btn:hover { background: var(--paper-panel); }

.account-menu {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 6px 4px 10px;
  border: 1px solid var(--paper-line);
  border-radius: var(--radius);
  background: var(--paper);
}
.account-email {
  font-size: 12.5px;
  color: var(--ink);
  max-width: 160px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.account-role-badge {
  font-family: var(--font-mono);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--ink-soft);
  background: var(--paper-panel);
  border: 1px solid var(--paper-line);
  border-radius: 4px;
  padding: 2px 6px;
  flex-shrink: 0;
}
.account-menu .icon-btn {
  width: 26px;
  height: 26px;
  border: none;
  background: none;
  flex-shrink: 0;
}
.account-menu .icon-btn:hover { background: var(--paper-panel); }

/* ---- Body / layout -------------------------------------------------- */
.body {
  flex: 1;
  display: flex;
  min-height: 0;
}

.sidebar {
  width: var(--sidebar-width);
  flex-shrink: 0;
  overflow-y: auto;
  border-right: 1px solid var(--paper-line);
  background: var(--paper-panel);
  padding: 16px;
  transition: margin-left 0.2s ease;
}

.app.collapsed .sidebar {
  margin-left: calc(-1 * var(--sidebar-width));
}

.canvas-wrap {
  position: relative;
  flex: 1;
  min-width: 0;
  min-height: 0;
}

/* ---- Panels / controls ------------------------------------------------ */
.panel {
  padding-bottom: 16px;
  margin-bottom: 16px;
  border-bottom: 1px solid var(--paper-line);
}
.panel:last-child { border-bottom: none; }

.panel-label {
  display: block;
  font-family: var(--font-mono);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink-soft);
  margin-bottom: 8px;
}

#searchInput {
  width: 100%;
  padding: 7px 9px;
  border: 1px solid var(--paper-line);
  border-radius: var(--radius);
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 13px;
}
#searchInput:focus {
  outline: 2px solid var(--seal-slate);
  outline-offset: 1px;
}

.search-results {
  list-style: none;
  margin: 6px 0 0;
  padding: 0;
  border: 1px solid var(--paper-line);
  border-radius: var(--radius);
  background: var(--paper);
  max-height: 220px;
  overflow-y: auto;
}
.search-results li {
  padding: 7px 9px;
  font-size: 13px;
  cursor: pointer;
  border-bottom: 1px solid var(--paper-line);
}
.search-results li:last-child { border-bottom: none; }
.search-results li:hover { background: var(--paper-panel); }
.search-results li .meta {
  display: block;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--ink-soft);
}

.selected-person {
  margin-top: 10px;
  font-size: 13px;
}
.focus-indicator {
  margin-top: 10px;
  padding: 6px 8px;
  border: 1px solid var(--paper-line);
  border-radius: var(--radius);
  background: var(--paper);
  font-size: 12px;
}
.link-btn {
  border: none;
  background: none;
  color: var(--seal-wine);
  text-decoration: underline;
  cursor: pointer;
  font-size: 12px;
  padding: 0 0 0 6px;
}

.radio-row {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  padding: 5px 0;
  cursor: pointer;
}
.radio-row:has(input:disabled) {
  opacity: 0.45;
  cursor: default;
}
.picture-mode-btn:disabled {
  opacity: 0.45;
  cursor: default;
}
.scope-sub-controls {
  margin-top: 4px;
  padding-top: 8px;
  border-top: 0.5px solid var(--paper-line);
}
.scope-sub-controls[hidden] { display: none; }

/* Sits first in the section, before the scope radio group - orientation
   applies to the "no focus" overview too, not just a focused tree, so it
   needs to stay visible regardless of scope, and is placed first as the
   more fundamental "how does the whole tree lay out" choice. Separator
   goes below rather than above (unlike .scope-sub-controls) since nothing
   precedes it except the section header. */
#orientationRow {
  padding-bottom: 10px;
  margin-bottom: 12px;
  border-bottom: 0.5px solid var(--paper-line);
}

.hint {
  font-size: 12px;
  color: var(--seal-wine);
  margin: 6px 0 0;
}

.switch-row {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
}
.switch {
  position: relative;
  display: inline-flex;
}
.switch input {
  position: absolute;
  opacity: 0;
  width: 34px;
  height: 18px;
  margin: 0;
  cursor: pointer;
}
.switch-track {
  width: 34px;
  height: 18px;
  border-radius: 20px;
  background: var(--paper-line);
  display: inline-block;
  position: relative;
  transition: background 0.15s ease;
}
.switch-thumb {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--paper);
  transition: left 0.15s ease;
}
.switch input:checked + .switch-track { background: var(--seal-slate); }
.switch input:checked + .switch-track .switch-thumb { left: 18px; }

.secondary-btn {
  width: 100%;
  padding: 8px 10px;
  border: 1px solid var(--paper-line);
  border-radius: var(--radius);
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 13px;
  cursor: pointer;
}
.secondary-btn:hover { background: var(--paper-panel); }
.secondary-btn:disabled {
  color: var(--ink-soft);
  cursor: not-allowed;
}

/* ---- Canvas / loading -------------------------------------------------- */
#FamilyChart {
  width: 100%;
  height: 100%;
}
#FamilyChart[hidden] { display: none; }

/* Overview (no focus): every connected group rendered at native, matching
   scale on one shared pannable/zoomable canvas - #FamilyChartOverview is
   the fixed viewport (this is where our own single d3.zoom listener
   attaches, mirroring how family-chart wires its own per-tree zoom), and
   .overview-canvas is the one element the resulting transform is applied
   to, so everything scales and pans together. Each cluster's own
   family-chart instance has its built-in zoom stripped and is sized to
   its exact computed content - see renderOverview() in app.js. */
#FamilyChartOverview {
  width: 100%;
  height: 100%;
  overflow: hidden;
  position: relative;
  cursor: grab;
}
#FamilyChartOverview[hidden] { display: none; }
#FamilyChartOverview.grabbing { cursor: grabbing; }

.overview-canvas {
  position: absolute;
  top: 0;
  left: 0;
  transform-origin: 0 0;
}

/* Large (multi-generation) clusters. Vertical orientation: stacked as full-
   width rows (column flow) - the default. Horizontal orientation: placed
   side by side instead (row flow), matching each cluster's own tree now
   running left-to-right rather than top-to-bottom - see renderOverview() in
   app.js, which also sets .orientation-horizontal to match the current
   toggle. `gap` (rather than a margin on the children) means the same
   value works for both directions without swapping which margin side is
   used. */
.overview-large-clusters {
  display: flex;
  flex-direction: column;
  gap: 28px;
}
.overview-large-clusters.orientation-horizontal {
  flex-direction: row;
  align-items: flex-start;
}

/* Individuals, couples, and other small groups don't each deserve a full
   row - they flow together so several sit side by side. */
.overview-small-clusters {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 40px;
}

.loading-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--paper);
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--ink-soft);
}
.loading-overlay[hidden] { display: none; }

/* ---- Pan / zoom controls ------------------------------------------------ */
.view-controls {
  position: absolute;
  right: 16px;
  bottom: 16px;
  display: flex;
  align-items: flex-end;
  gap: 10px;
  z-index: 5;
}
.view-controls[hidden] { display: none; }

.pan-pad {
  display: grid;
  grid-template-columns: repeat(3, 30px);
  grid-template-rows: repeat(3, 30px);
  gap: 2px;
  background: var(--paper-panel);
  border: 1px solid var(--paper-line);
  border-radius: var(--radius);
  padding: 4px;
}

.pan-btn {
  border: 1px solid transparent;
  background: var(--paper);
  color: var(--ink);
  border-radius: 4px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  padding: 0;
}
.pan-btn:hover { background: var(--paper-line); }
.pan-btn:active { background: var(--seal-slate); color: var(--paper); }

.pan-up { grid-column: 2; grid-row: 1; }
.pan-left { grid-column: 1; grid-row: 2; }
.pan-center { grid-column: 2; grid-row: 2; }
.pan-right { grid-column: 3; grid-row: 2; }
.pan-down { grid-column: 2; grid-row: 3; }

.zoom-stack {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--paper-line);
  border-radius: var(--radius);
  overflow: hidden;
}

.overview-btn {
  width: 32px;
  height: 32px;
  background: var(--paper-panel);
  border: 1px solid var(--paper-line);
  border-radius: var(--radius);
}
#overviewBtn[hidden] { display: none; }

.zoom-btn {
  width: 32px;
  height: 32px;
  border: none;
  border-bottom: 1px solid var(--paper-line);
  background: var(--paper-panel);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
}
.zoom-btn:last-child { border-bottom: none; }
.zoom-btn:hover { background: var(--paper-line); }
.zoom-btn:active { background: var(--seal-slate); color: var(--paper); }

/* ---- family-chart theme overrides -------------------------------------
   family-chart exposes these as CSS custom properties on .f3; we retheme
   them to match the registry-ledger palette instead of its dark default. */
.f3 {
  --genderless-color: var(--ink-soft);
  --background-color: var(--paper);
  --text-color: var(--ink);
  font-family: var(--font-body);
}

.f3 div.card {
  font-family: var(--font-body);
}

/* Scope display: the focused person always gets a highlight ring,
   regardless of scope. "Grey out others" dims everyone outside the
   current scope's relevant set rather than removing them - transition is
   the card's own existing one, so this settles in smoothly alongside a
   tree redraw rather than popping. */
.f3 div.card.is-focus-person .card-inner {
  outline: 2px solid var(--seal-slate);
  outline-offset: 1px;
}
.f3 div.card.is-dimmed {
  --male-color: var(--paper-line);
  --female-color: var(--paper-line);
  --male-border: var(--paper-line);
  --female-border: var(--paper-line);
}
.f3 div.card.is-dimmed .card-label,
.f3 div.card.is-dimmed .card-label * {
  color: var(--ink-soft);
}

/* Card fill: family-chart's default puts a solid gender-colored background
   on .card-inner. We override that with a white card, a thin light outline,
   and a wider colored band on the left only. */
.f3 div.card-male .card-inner,
.f3 div.card-female .card-inner,
.f3 div.card-genderless .card-inner {
  background-color: var(--card-bg);
  border-radius: var(--card-radius);
  border: 1px solid var(--paper-line);
  border-left-width: 6px;
  padding: 2px 4px;
  position: relative;
}
.f3 div.card-male .card-inner {
  border-color: var(--male-border);
  border-left-color: var(--male-color);
}
.f3 div.card-female .card-inner {
  border-color: var(--female-border);
  border-left-color: var(--female-color);
}

/* Redundant, higher-specificity restatement of family-chart's own
   .person-icon svg background rule. That rule already ties the avatar
   square to --male-color/--female-color the same way the border above
   does, and should update live the same way - but in practice it was
   observed staying frozen regardless of color changes. This explicit
   override (one class more specific, and loaded after family-chart's own
   stylesheet) guarantees it wins the cascade regardless of what was
   suppressing the original rule. */
.f3 div.card.card-male .person-icon svg { background-color: var(--male-color); }
.f3 div.card.card-female .person-icon svg { background-color: var(--female-color); }
.f3 div.card.card-genderless .person-icon svg { background-color: var(--genderless-color); }

/* Must come after the three rules above - same specificity, so source
   order decides, and this needs to win for dimmed cards. */
.f3 div.card.is-dimmed .person-icon svg {
  background-color: var(--card-bg);
  color: var(--paper-line);
}

/* Sex mark: back to inline, right before the surname - baked directly
   into the display_name string in app.js (toChartNodes), so it flows
   naturally with the text and stays correctly placed even when the name
   wraps, rather than needing a fixed corner position. */
.f3 .card-label > div:first-child {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 13px;
}
.f3 .inline-sex-mark {
  font-weight: 700;
}
/* Sex-icon toggle is pure CSS visibility - see app.js toChartNodes for why
   (avoids a chart data rebuild, which would reset pan/zoom). The trailing
   space is embedded inside the span itself so hiding it removes the gap
   before the name too, rather than leaving a stray leading space. */
body.hide-sex-icon .f3 .inline-sex-mark {
  display: none;
}
.f3 div.card-male .inline-sex-mark { color: var(--male-color); }
.f3 div.card-female .inline-sex-mark { color: var(--female-color); }

.f3 .card-label > div:not(:first-child) {
  font-family: var(--font-mono);
  font-size: 10.5px;
  opacity: 0.9;
}

/* Marriage date now renders on the spouse connector line itself (see
   setLinkSpouseText in app.js) rather than inside either person's card.
   Matches the darker link color below, rather than family-chart's
   hardcoded white (meant for its own dark default background). */
.f3 .link-text text {
  fill: var(--link-color) !important;
  font-family: var(--font-mono) !important;
  font-size: 10.5px !important;
  font-weight: 500;
}

/* family-chart hardcodes a 4px light-gray outline plus a heavy dark glow
   on whichever card is currently centered ("main"), designed to read as a
   glow against its own dark default background. On our light paper it
   showed up as a mismatched gray halo around the card's own colored
   border, so we replace both with a subtle paper-toned lift instead. */
.f3 div.card-main .card-inner {
  outline: none;
}
.f3 div.card-main .card-inner,
.f3 div.card:hover .card-inner {
  box-shadow: 0 2px 6px rgba(38, 34, 32, 0.14);
}
.f3 .link {
  stroke: var(--link-color) !important;
}
.f3 div.card-inner.f3-path-to-main {
  outline: none;
}

/* ---- Edit mode ------------------------------------------------------- */
.edit-mode-badge {
  font-family: var(--font-mono);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--seal-wine);
  border: 1px solid var(--female-color);
  border-radius: 20px;
  padding: 2px 9px;
}

.app.editing .canvas-wrap {
  outline: 2px solid var(--female-color);
  outline-offset: -2px;
}

/* ---- Editor form ------------------------------------------------------ */
.editor-field-row {
  display: flex;
  gap: 10px;
}
.editor-field-row > div { flex: 1; }

.photo-field-row {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 8px;
}
.photo-preview {
  width: 60px;
  height: 60px;
  object-fit: cover;
  border-radius: 6px;
  border: 1px solid var(--paper-line);
  flex-shrink: 0;
}
.photo-preview[hidden] { display: none; }

#editModalBody input[type="text"],
#editModalBody select,
#editModalBody textarea {
  width: 100%;
  padding: 7px 9px;
  border: 1px solid var(--paper-line);
  border-radius: var(--radius);
  background: var(--card-bg);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 13px;
}
#editModalBody textarea { resize: vertical; min-height: 50px; }

.relation-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  border: 1px solid var(--paper-line);
  border-radius: var(--radius);
  padding: 7px 9px;
  font-size: 13px;
  background: var(--card-bg);
  margin-bottom: 6px;
}
.relation-row .muted { color: var(--ink-soft); }

.relation-action {
  border: none;
  background: none;
  font-size: 11px;
  text-decoration: underline;
  cursor: pointer;
  padding: 0;
}
.relation-action.change { color: var(--seal-slate); }
.relation-action.remove { color: var(--seal-wine); }

.add-relation-btn {
  width: 100%;
  padding: 7px;
  border: 1px dashed var(--male-border);
  border-radius: var(--radius);
  background: var(--card-bg);
  color: var(--seal-slate);
  font-family: var(--font-body);
  font-size: 12.5px;
  cursor: pointer;
  margin-bottom: 4px;
}

.editor-search-results {
  list-style: none;
  margin: 6px 0 0;
  padding: 0;
  border: 1px solid var(--paper-line);
  border-radius: var(--radius);
  background: var(--card-bg);
  max-height: 180px;
  overflow-y: auto;
}
.editor-search-results li {
  padding: 7px 9px;
  font-size: 13px;
  cursor: pointer;
  border-bottom: 1px solid var(--paper-line);
}
.editor-search-results li:last-child { border-bottom: none; }
.editor-search-results li:hover { background: var(--paper-panel); }

.editor-btn-row {
  display: flex;
  gap: 10px;
  margin-top: 16px;
}
.editor-btn-row .primary-btn,
.editor-btn-row .secondary-btn,
.editor-btn-row .danger-btn {
  flex: 1;
  margin-top: 0;
}

.editor-section-divider {
  border-top: 1px solid var(--paper-line);
  margin: 18px 0 12px;
}

.danger-btn {
  padding: 9px 10px;
  border: 1px solid var(--female-color);
  border-radius: var(--radius);
  background: var(--card-bg);
  color: var(--seal-wine);
  font-family: var(--font-body);
  font-size: 13px;
  cursor: pointer;
}
.danger-btn:hover { background: var(--paper-panel); }
.danger-btn.solid {
  background: var(--seal-wine);
  color: #fff;
  border-color: var(--seal-wine);
}

.editor-back-link {
  border: none;
  background: none;
  font-size: 12px;
  color: var(--ink-soft);
  text-decoration: underline;
  cursor: pointer;
  padding: 0;
  margin-bottom: 10px;
}

.delete-warning {
  font-size: 13px;
  line-height: 1.5;
  background: var(--paper-panel);
  border: 1px solid var(--female-color);
  border-radius: var(--radius);
  padding: 10px 12px;
  margin: 6px 0 4px;
}

/* ---- Settings modal ----------------------------------------------------- */
.modal-overlay {
  position: absolute;
  inset: 0;
  background: rgba(38, 34, 32, 0.35);
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 5vh 16px;
  z-index: 20;
  overflow-y: auto;
}
.modal-overlay[hidden] { display: none; }

.modal {
  background: var(--paper);
  border-radius: 10px;
  border: 1px solid var(--paper-line);
  width: 100%;
  max-width: 460px;
  max-height: 90vh;
  display: flex;
  flex-direction: column;
}
.modal-wide { max-width: 720px; }

.legal-links {
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--paper-line);
  text-align: center;
  font-size: 12px;
  color: var(--ink-soft);
}
.legal-links .link-btn { padding: 0; }

.doc-viewer-body h2 {
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 600;
  margin: 20px 0 8px;
}
.doc-viewer-body h2:first-child { margin-top: 0; }
.doc-viewer-body p { line-height: 1.6; margin: 0 0 10px; }
.doc-viewer-body ul { margin: 0 0 10px; padding-left: 20px; line-height: 1.6; }
.doc-viewer-body li { margin-bottom: 4px; }
.doc-viewer-body code {
  font-family: var(--font-mono);
  font-size: 12px;
  background: var(--paper-panel);
  border: 1px solid var(--paper-line);
  border-radius: 3px;
  padding: 1px 5px;
}
.doc-viewer-body table {
  width: 100%;
  border-collapse: collapse;
  margin: 0 0 14px;
  font-size: 13px;
}
.doc-viewer-body th, .doc-viewer-body td {
  border: 1px solid var(--paper-line);
  padding: 6px 8px;
  text-align: left;
  vertical-align: top;
}
.doc-viewer-body th { background: var(--paper-panel); }

.modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 18px;
  border-bottom: 1px solid var(--paper-line);
}
.modal-header h2 {
  font-family: var(--font-display);
  font-size: 17px;
  font-weight: 600;
  margin: 0;
}

.modal-body {
  padding: 4px 18px 18px;
  overflow-y: auto;
}

.settings-section {
  padding: 16px 0;
  border-bottom: 1px solid var(--paper-line);
}
.settings-section:last-child { border-bottom: none; }
.settings-section h3 {
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 600;
  margin: 0;
}
.settings-section-header {
  display: grid;
  grid-template-columns: auto 1fr auto auto 20px;
  align-items: center;
  gap: 7px;
  margin-bottom: 8px;
}
.admin-tag {
  font-family: var(--font-mono);
  font-size: 9px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--seal-wine);
  background: #fbeff1;
  border: 1px solid var(--female-color);
  border-radius: 4px;
  padding: 2px 6px;
  justify-self: end;
}
.settings-section-header .sidebar-accordion-toggle {
  margin-left: 0;
  justify-self: end;
}
.settings-hint {
  font-size: 12px;
  color: var(--ink-soft);
  margin: 0 0 10px;
}

.field-label {
  display: block;
  font-family: var(--font-mono);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink-soft);
  margin: 10px 0 5px;
}

.modal-body input[type="text"],
.modal-body input[type="file"],
.modal select {
  width: 100%;
  padding: 7px 9px;
  border: 1px solid var(--paper-line);
  border-radius: var(--radius);
  background: var(--card-bg);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 13px;
}

.checkbox-row {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 12.5px;
  margin: 12px 0 0;
  cursor: pointer;
}

.primary-btn {
  width: 100%;
  padding: 9px 10px;
  margin-top: 14px;
  border: none;
  border-radius: var(--radius);
  background: var(--seal-slate);
  color: #fff;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 13px;
  cursor: pointer;
}
.primary-btn:hover { opacity: 0.92; }
.primary-btn:disabled { opacity: 0.6; cursor: not-allowed; }

.secondary-btn.as-link {
  display: block;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  color: var(--ink);
}

.settings-result {
  margin-top: 12px;
  padding: 10px 12px;
  border-radius: var(--radius);
  font-size: 12.5px;
  background: var(--paper-panel);
  border: 1px solid var(--paper-line);
}
.settings-result.error {
  border-color: var(--female-color);
  background: #fbeff1;
  color: var(--seal-wine);
  font-weight: 500;
}
.settings-result.saved {
  border-color: var(--male-color);
  color: var(--seal-slate);
}
.settings-result ul {
  margin: 6px 0 0;
  padding-left: 18px;
}

/* ---- Pending-request badge on tree cards -------------------------------- */
.f3 div.has-pending .card-inner::before {
  content: "";
  position: absolute;
  top: 6px;
  right: 6px;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: #c9982e;
  border: 1px solid #fff;
  z-index: 2;
}

/* ---- Admin tables (Manage users / Pending requests) --------------------- */
.admin-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 12.5px;
  margin-top: 6px;
}
.admin-table th {
  text-align: left;
  font-family: var(--font-mono);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--ink-soft);
  border-bottom: 1px solid var(--paper-line);
  padding: 4px 6px;
}
.admin-table td {
  padding: 6px;
  border-bottom: 1px solid var(--paper-line);
  vertical-align: middle;
}
.admin-table input[type="text"],
.admin-table input[type="email"],
.admin-table select {
  width: 100%;
  padding: 4px 6px;
  border: 1px solid var(--paper-line);
  border-radius: 4px;
  background: var(--card-bg);
  font-family: var(--font-body);
  font-size: 12px;
}
.admin-table .row-actions {
  display: flex;
  gap: 6px;
  white-space: nowrap;
}
.admin-table .row-actions button {
  border: none;
  background: none;
  font-size: 11px;
  text-decoration: underline;
  cursor: pointer;
  padding: 0;
}
.admin-table .row-actions .save-row { color: var(--seal-slate); }
.admin-table .row-actions .delete-row { color: var(--seal-wine); }

.request-card {
  border: 1px solid var(--paper-line);
  border-radius: var(--radius);
  padding: 9px 11px;
  margin-bottom: 8px;
  background: var(--card-bg);
  font-size: 12.5px;
}
.request-card .request-meta {
  font-family: var(--font-mono);
  font-size: 10.5px;
  color: var(--ink-soft);
  margin-bottom: 4px;
}
.request-card .request-detail {
  margin-bottom: 8px;
  line-height: 1.5;
}
.request-card .request-detail code {
  background: var(--paper-panel);
  padding: 1px 4px;
  border-radius: 3px;
  font-family: var(--font-mono);
  font-size: 11px;
}
.request-actions {
  display: flex;
  gap: 8px;
}
.request-actions button {
  flex: 1;
  padding: 6px;
  border-radius: 4px;
  font-size: 12px;
  cursor: pointer;
}
.request-actions .approve-btn {
  border: 1px solid var(--male-color);
  background: var(--card-bg);
  color: var(--seal-slate);
}
.request-actions .reject-btn {
  border: 1px solid var(--female-color);
  background: var(--card-bg);
  color: var(--seal-wine);
}

/* ---- Link visual finishing touches (junction dots, date label box) ------ */
.f3 circle.link-joint {
  fill: var(--link-color);
}
.f3 rect.link-text-bg {
  rx: 3px;
}

/* ---- Card expand icon + full-detail popup ------------------------------- */
.card-expand-btn {
  position: absolute;
  bottom: 6px;
  right: 8px;
  width: 16px;
  height: 16px;
  padding: 0;
  border: none;
  background: none;
  color: var(--ink-soft);
  font-size: 13px;
  line-height: 1;
  cursor: pointer;
  opacity: 0.55;
}
.card-expand-btn:hover { opacity: 1; color: var(--seal-slate); }

.detail-popup {
  position: absolute;
  z-index: 15;
  width: 250px;
  max-height: 260px;
  overflow-y: auto;
  background: var(--card-bg);
  border: 1px solid var(--paper-line);
  border-radius: 10px;
  box-shadow: 0 6px 18px rgba(38, 34, 32, 0.18);
  padding: 12px 14px;
  font-size: 12.5px;
}
.detail-popup[hidden] { display: none; }

.detail-popup-photo {
  width: 100%;
  max-height: 140px;
  object-fit: cover;
  border-radius: 6px;
  margin-bottom: 8px;
  display: block;
}

.detail-popup-name {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 14px;
  margin-bottom: 3px;
  padding-right: 16px;
}
.detail-popup-sex { font-weight: 700; }
.detail-popup-dates {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--ink-soft);
  margin-bottom: 8px;
}
.detail-popup-row {
  margin-bottom: 5px;
  line-height: 1.4;
}
.detail-popup-row .label {
  font-family: var(--font-mono);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--ink-soft);
  display: block;
}
.detail-popup-close {
  position: absolute;
  top: 6px;
  right: 8px;
  border: none;
  background: none;
  font-size: 15px;
  line-height: 1;
  color: var(--ink-soft);
  cursor: pointer;
}
.detail-popup-close:hover { color: var(--seal-wine); }

/* ---- Contextual help icons + popover ----------------------------------- */
.help-icon {
  width: 19px;
  height: 19px;
  flex: none;
  border-radius: 50%;
  border: 1px solid var(--paper-line);
  background: var(--paper);
  color: var(--ink-soft);
  font-size: 11px;
  line-height: 1;
  padding: 0;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.help-icon:hover { background: var(--paper-panel); color: var(--ink); }

.help-popup {
  position: fixed;
  z-index: 60;
  width: 280px;
  max-height: 320px;
  overflow-y: auto;
  background: var(--card-bg);
  border: 1px solid var(--paper-line);
  border-radius: 10px;
  box-shadow: 0 6px 18px rgba(38, 34, 32, 0.18);
  padding: 12px 14px;
  font-size: 12.5px;
}
.help-popup[hidden] { display: none; }
.help-popup-title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 14px;
  margin-bottom: 6px;
  padding-right: 16px;
}
.help-popup-body { line-height: 1.5; }
.help-popup-admin {
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px solid var(--paper-line);
  line-height: 1.5;
}
.help-popup-contact {
  margin-top: 10px;
  padding-top: 8px;
  border-top: 1px solid var(--paper-line);
  font-size: 11px;
  color: var(--ink-soft);
  font-style: italic;
  line-height: 1.4;
}
.help-popup-contact a { color: var(--ink-soft); }
.help-popup-close {
  position: absolute;
  top: 6px;
  right: 8px;
  border: none;
  background: none;
  font-size: 15px;
  line-height: 1;
  color: var(--ink-soft);
  cursor: pointer;
}
.help-popup-close:hover { color: var(--seal-wine); }

/* ---- Sidebar section separation --------------------------------------- */
.sidebar-section + .sidebar-section {
  border-top: 2px solid var(--paper-line);
  padding-top: 14px;
  margin-top: 14px;
}
.sidebar-section-header {
  display: flex;
  align-items: center;
  gap: 7px;
  margin-bottom: 8px;
}
.sidebar-section-header .panel-label { margin-bottom: 0; }
/* The header is a flex row, so only elements with their own margin-left:auto
   get pushed right. .sidebar-accordion-toggle already has that; give the
   help icon the same so it moves with it, and cancel the toggle's own auto
   margin when it directly follows the icon so the two sit together at the
   right edge instead of splitting apart. */
.sidebar-section-header .help-icon { margin-left: auto; }
.sidebar-section-header .help-icon + .sidebar-accordion-toggle { margin-left: 0; }
.sidebar-section-num {
  width: 16px;
  height: 16px;
  border-radius: 4px;
  background: var(--seal-slate);
  color: #fff;
  font-size: 9px;
  font-weight: 600;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.sidebar-accordion-toggle {
  margin-left: auto;
  border: none;
  background: none;
  color: var(--ink-soft);
  font-size: 11px;
  cursor: pointer;
  padding: 0 2px;
  transition: transform 0.15s ease;
}
.sidebar-accordion-toggle[aria-expanded="true"] { transform: rotate(180deg); }
.sidebar-accordion-body {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--paper-line);
}

.card-content-area {
  margin-bottom: 12px;
}
.content-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  row-gap: 6px;
  gap: 10px;
  font-size: 13px;
  margin-bottom: 12px;
}
.content-row:last-child {
  margin-bottom: 0;
}
.content-row-toggle {
  cursor: pointer;
}
.content-row .picture-mode-picker {
  margin-bottom: 0;
  flex-shrink: 0;
}

.card-style-area {
  background: var(--paper-panel);
  border: 1px solid var(--paper-line);
  border-radius: 8px;
  padding: 10px;
}
.card-style-area .sidebar-section-header {
  margin-bottom: 8px;
}

#pdfExportBody input[type="text"],
#pdfExportBody select {
  width: 100%;
  padding: 7px 9px;
  border: 1px solid var(--paper-line);
  border-radius: var(--radius);
  background: var(--card-bg);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 13px;
}



/* ---- Style picker (5 structural card layouts) --------------------------- */
.picture-mode-picker {
  display: flex;
  gap: 4px;
  margin-bottom: 4px;
}
.picture-mode-btn {
  flex: 1;
  min-width: 72px;
  padding: 6px 10px;
  font-size: 10.5px;
  border: 1px solid var(--paper-line);
  border-radius: 5px;
  background: #fff;
  cursor: pointer;
  color: var(--ink-soft);
}
.picture-mode-btn.active {
  border-color: var(--seal-slate);
  color: var(--ink);
  font-weight: 600;
}

/* "Photo only" - when a person has no photo, the whole avatar column
   disappears (same as "None"), rather than leaving an empty tinted box.
   :has() lets us target only the icon-fallback case, since family-chart
   renders either <img> or the silhouette <svg> inside the same
   .person-icon wrapper - an actual photo is untouched by this rule. */
body.picture-mode-photo_only .f3 .person-icon:not(:has(img)) {
  display: none;
}

/* "None" - remove the whole avatar column so the text takes its width. */
body.picture-mode-none .f3 .person-icon {
  display: none;
}

/* Whenever the avatar column is actually hidden, the text area needs to
   explicitly grow into the freed space - family-chart's own card-label
   has no flex-grow by default, so without this it stays at its natural
   width and the card looks unbalanced (most visible on the stripe/bar
   accent, which then wraps a mismatched content area). */
body.picture-mode-none .f3 .card-label,
body.picture-mode-photo_only .f3 .person-icon:not(:has(img)) + .card-label {
  flex: 1;
}

.style-picker {
  display: flex;
  gap: 6px;
  margin-bottom: 4px;
  flex-wrap: wrap;
}
.style-picker-btn {
  width: 40px;
  height: 28px;
  border-radius: 5px;
  border: 1px solid var(--paper-line);
  background: #fff;
  cursor: pointer;
  padding: 0;
  position: relative;
}
.style-picker-btn.active { outline: 2px solid var(--seal-slate); outline-offset: 1px; }

.saved-look-card {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 6px;
  margin-bottom: 6px;
  border: 1px solid var(--paper-line);
  border-radius: 6px;
  background: var(--card-bg);
  cursor: pointer;
  text-align: left;
}
.saved-look-card:hover { border-color: var(--seal-slate); }
.saved-look-preview {
  position: relative;
  width: 40px;
  height: 28px;
  flex-shrink: 0;
}
.saved-look-name {
  font-size: 12px;
  color: var(--ink);
}

/* ---- Card style: top bar (accent across the top edge, not the left) ----- */
body.card-style-top_bar .f3 div.card-male .card-inner,
body.card-style-top_bar .f3 div.card-female .card-inner,
body.card-style-top_bar .f3 div.card-genderless .card-inner {
  border-left-width: 1px;
  border-top-width: 5px;
  background-color: var(--card-bg);
}
body.card-style-top_bar .f3 div.card-male .card-inner {
  border-color: var(--male-border);
  border-top-color: var(--male-color);
}
body.card-style-top_bar .f3 div.card-female .card-inner {
  border-color: var(--female-border);
  border-top-color: var(--female-color);
}

/* ---- Card style: header band (name row filled, body stays white) -------
   card-inner's own padding is zeroed here rather than negatively offset,
   so the name row's background can touch the card's real top/right edges
   without guessing at exact padding values. The avatar keeps its own
   spacing regardless, since family-chart gives .person-icon its own
   padding/margin independent of card-inner's. */
body.card-style-header_band .f3 div.card-male .card-inner,
body.card-style-header_band .f3 div.card-female .card-inner,
body.card-style-header_band .f3 div.card-genderless .card-inner {
  border-left-width: 1px;
  background-color: var(--card-bg);
  overflow: hidden;
  padding: 0;
}
body.card-style-header_band .f3 div.card-male .card-inner { border-color: var(--male-border); }
body.card-style-header_band .f3 div.card-female .card-inner { border-color: var(--female-border); }
body.card-style-header_band .f3 .card-label > div:first-child {
  margin: 0;
  padding: 4px 8px;
  color: #fdfcf9;
  display: block;
  width: 100%;
  box-sizing: border-box;
}
body.card-style-header_band .f3 .inline-sex-mark {
  color: #fdfcf9 !important;
}
body.card-style-header_band .f3 div.card-male .card-label > div:first-child { background-color: var(--male-color); }
body.card-style-header_band .f3 div.card-female .card-label > div:first-child { background-color: var(--female-color); }
body.card-style-header_band .f3 .card-label > div:not(:first-child) {
  padding: 2px 8px 4px;
}
/* card-label is never actually stretched to the card's full height - its
   height:100% can't resolve without the parent using align-items:stretch,
   and family-chart's own card-image-rect container uses align-items:center
   instead. So card-label stays shrink-wrapped to its own content, and THAT
   whole (short) block is what gets vertically centered inside the taller
   card - pushing the colored name row away from the card's top edge.
   Overriding align-self here (not justify-content inside card-label, which
   has no effect since card-label is never actually tall enough to need
   internal centering) pins the block to the top instead. */
body.card-style-header_band .f3 .card-label {
  align-self: flex-start;
  justify-content: flex-start;
  flex: 1;
  min-width: 0;
}

/* ---- Card style: gradient (colour fades in from the left edge) ---------
   Previously an injected folded-corner triangle - that required
   re-injecting a real DOM element into every card after every redraw
   (family-chart recreates card markup on its own updates), which proved
   unreliable as more redraw paths were added (scope changes, focus
   changes, the overview). A pure CSS gradient is keyed off the same
   .card-male/.card-female classes family-chart itself always sets
   correctly, so there's nothing to fall out of sync. */
body.card-style-corner_tab .f3 div.card-male .card-inner,
body.card-style-corner_tab .f3 div.card-female .card-inner,
body.card-style-corner_tab .f3 div.card-genderless .card-inner {
  border: 1px solid var(--paper-line);
  background-color: var(--card-bg);
  overflow: hidden;
}
body.card-style-corner_tab .f3 div.card-male .card-inner {
  background-image: linear-gradient(to right, var(--male-border), transparent 85%);
}
body.card-style-corner_tab .f3 div.card-female .card-inner {
  background-image: linear-gradient(to right, var(--female-border), transparent 85%);
}

/* ---- Card style: plain outline (thin border only, no accent shape) ------ */
body.card-style-outline .f3 div.card-male .card-inner,
body.card-style-outline .f3 div.card-female .card-inner,
body.card-style-outline .f3 div.card-genderless .card-inner {
  border-left-width: 1px;
  background-color: var(--card-bg);
}
body.card-style-outline .f3 div.card-male .card-inner { border-color: var(--male-color); }
body.card-style-outline .f3 div.card-female .card-inner { border-color: var(--female-color); }

/* "Handwritten" font pairing: upright, clear handwriting style - not a slanted cursive script */
body.font-handwritten .f3 .card-label > div:first-child {
  font-family: 'Patrick Hand', cursive;
  font-weight: 400;
  font-size: 15px;
}

/* "Arial" font pairing: plain system font, no web-font loading needed */
body.font-arial .f3 .card-label > div:first-child {
  font-family: Arial, Helvetica, sans-serif;
  font-weight: 600;
}
