/* =============================================================================
   Family Tree — layout, cards, connectors
   Nested <ul>/<li> tree with CSS-drawn connectors. Sizing flows from CSS
   variables so zoom, print and dark mode stay consistent.
   ========================================================================== */

:root {
  /* Mobile-first: these are the small-screen values. Larger breakpoints below
     step them up. Never set a max-width query. */
  --card-w: 148px;
  --card-photo: 60px;
  --gap-x: 10px;   /* horizontal gap between sibling subtrees */
  --gap-y: 22px;   /* vertical gap between generations */
  --line: #c9c2b7;
  --line-soft: #ded8ce;
  --card-bg: #ffffff;
  --card-border: #e7e2d9;
  --zoom: 1;
  --tap: 44px;     /* minimum comfortable touch target */
}

/* The shell fills the viewport so #treeCanvas becomes a real two-axis pan
   surface: drag, pinch and wheel zoom move the tree inside it, and the page
   itself does not scroll. */
.app-shell {
  display: flex;
  flex-direction: column;
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
}
.app-shell > header { position: relative; z-index: 40; }
.app-shell > main {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
.app-col {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

/* The canvas is the pan surface: drag, pinch and wheel zoom are handled in JS,
   so the browser must not claim those gestures. It fills the space left by the
   header and toolbar and scrolls the tree in both axes. */
.tree-canvas {
  cursor: grab;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  min-height: 0;
  touch-action: none;
}
.tree-canvas.is-panning { cursor: grabbing; }

.tree-stage {
  zoom: var(--zoom);
}

/* --------------------------------------------------------------- structure */

.ft-tree,
.ft-tree ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

.ft-tree {
  display: flex;
  flex-direction: column;
  align-items: center;
}

/* A node wraps its couple-row and its children list */
.ft-node {
  display: flex;
  flex-direction: column;
  align-items: center;
  position: relative;
}

.ft-node > .ft-children {
  display: flex;
  align-items: flex-start;
  justify-content: center;
  gap: var(--gap-x);
  margin-top: var(--gap-y);
  padding-top: 18px;
  position: relative;
}

/* children list: vertical spine coming down from the parent */
.ft-node > .ft-children::before {
  content: "";
  position: absolute;
  top: 0;
  left: 50%;
  width: 2px;
  height: 18px;
  background: var(--line);
  transform: translateX(-1px);
}

/* the horizontal bar linking siblings */
.ft-node > .ft-children::after {
  content: "";
  position: absolute;
  top: 18px;
  left: 0;
  right: 0;
  height: 2px;
  background: var(--line);
}

/* single child: no horizontal bar needed, just the spine */
.ft-node > .ft-children:has(> li:only-child)::after {
  left: 50%;
  right: auto;
  width: 0;
}

/* placeholders (empty branch / error) must not draw connectors */
.ft-node > .ft-children > li:has(> .ft-empty-branch)::after,
.ft-node > .ft-children > li:has(> .ft-error)::after { display: none; }

.ft-children > li {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
}

/* Each child draws its own stub up to the bar */
.ft-children > li::before {
  content: "";
  position: absolute;
  top: -18px;
  left: 50%;
  width: 2px;
  height: 18px;
  background: var(--line);
  transform: translateX(-1px);
}
.ft-children > li:has(> .ft-empty-branch)::before,
.ft-children > li:has(> .ft-skeleton)::before,
.ft-children > li:has(> .ft-error)::before { display: none; }

/* ------------------------------------------------------------ couple rows */

.ft-couples {
  display: flex;
  flex-direction: column;
  gap: 10px;
  align-items: center;
}

.ft-couple {
  display: flex;
  align-items: stretch;
  justify-content: center;
  gap: 0;
  position: relative;
}

.ft-partner {
  display: flex;
  align-items: center;
  gap: 0;
  position: relative;
}

/* heart / marriage marker between partners */
.ft-marriage-mark {
  align-self: center;
  margin: 0 3px;
  color: #e11d48;
  display: flex;
  align-items: center;
  justify-content: center;
}
.ft-marriage-mark svg { width: 18px; height: 18px; }
.ft-marriage-mark[data-status="divorced"] { color: #c08497; }
.ft-marriage-mark[data-status="separated"] { color: #d8b26a; }
.ft-marriage-mark[data-status="widowed"] { color: #78716c; }
.ft-marriage-mark[data-status="unknown"] { color: var(--line); }
html.dark-tree .ft-marriage-mark[data-status="married"],
html.dark-tree .ft-marriage-mark[data-status="partner"],
html.dark-tree .ft-marriage-mark[data-status="engaged"] { color: #fb7185; }

/* A couple that has been split needs the descing connector routed around */
.ft-couple + .ft-couple { margin-top: 4px; }

/* ------------------------------------------------------------------ cards
   The whole card is the tap target: it opens the profile. It carries
   role="button"/tabindex so keyboard and screen-reader users get the same
   action, and tree.js ignores clicks that land on the expand toggle. */

.ft-card {
  width: var(--card-w);
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: 14px;
  padding: 9px 8px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  text-align: center;
  box-shadow: 0 1px 2px rgba(28, 25, 23, .04);
  transition: box-shadow .15s ease, border-color .15s ease, transform .12s ease;
  position: relative;
  min-height: 130px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.ft-card:hover {
  box-shadow: 0 6px 18px -6px rgba(28, 25, 23, .18);
  border-color: #c9c2b7;
}
.ft-card:active { transform: scale(.985); }
.ft-card:focus-visible,
.ft-card:focus-within {
  outline: 2px solid #0d9488;
  outline-offset: 2px;
}

.ft-card.is-root-flag {
  border-color: #99f6e4;
  box-shadow: 0 0 0 2px rgba(20, 184, 166, .12);
}

.ft-card.is-target {
  animation: ft-flash 1.9s ease-out;
}
@keyframes ft-flash {
  0%, 40% { box-shadow: 0 0 0 4px rgba(20, 184, 166, .55); }
  100%    { box-shadow: 0 1px 2px rgba(28, 25, 23, .04); }
}

/* photo is the click target that expands details */
.ft-photo-btn {
  position: relative;
  width: var(--card-photo);
  height: var(--card-photo);
  min-width: 48px;
  min-height: 48px;
  border-radius: 999px;
  overflow: hidden;
  border: 2px solid #fff;
  box-shadow: 0 0 0 1px var(--card-border), 0 2px 6px rgba(28,25,23,.12);
  background: #efeae2;
  cursor: pointer;
  display: block;
  padding: 0;
  -webkit-tap-highlight-color: transparent;
  transition: transform .12s ease, box-shadow .12s ease;
}
.ft-photo-btn:hover {
  transform: scale(1.05);
  box-shadow: 0 0 0 2px #5eead4, 0 4px 12px rgba(28,25,23,.2);
}
.ft-photo-btn:focus-visible {
  outline: 2px solid #0d9488;
  outline-offset: 2px;
}
/* contain, not cover: a portrait photo must not be cropped to a square */
.ft-photo-btn img,
.ft-avatar img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}
/* the avatar sits on a soft backdrop so letterboxed portraits still read well */
.ft-avatar { background: #efeae2; }
html.dark-tree .ft-avatar { background: #292524; }

.ft-initials {
  width: 100%;
  height: 100%;
  display: grid;
  place-items: center;
  font-family: Georgia, Cambria, serif;
  font-size: 1.6rem;
  color: #57534e;
  letter-spacing: .02em;
}
.ft-initials[data-g="female"] { background: #fce7f3; color: #9d174d; }
.ft-initials[data-g="male"]   { background: #dbeafe; color: #1e40af; }
.ft-initials[data-g="other"]  { background: #ede9fe; color: #5b21b6; }

.ft-expand-hint {
  position: absolute;
  bottom: -3px;
  right: -3px;
  width: 20px;
  height: 20px;
  border-radius: 999px;
  background: #0f766e;
  color: #fff;
  display: grid;
  place-items: center;
  border: 2px solid #fff;
  font-size: 10px;
  line-height: 1;
}
.ft-expand-hint svg { width: 10px; height: 10px; }

.ft-name {
  font-family: Georgia, Cambria, serif;
  font-size: .95rem;
  font-weight: 600;
  color: #1c1917;
  line-height: 1.25;
  word-break: break-word;
}
.ft-meta {
  font-size: .7rem;
  color: #78716c;
  line-height: 1.3;
}
.ft-addr {
  font-size: .68rem;
  color: #57534e;
  line-height: 1.3;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
html.dark-tree .ft-addr { color: #a8a29e; }

/* Public custom fields flagged "show on card" */
.ft-fields {
  display: flex;
  flex-direction: column;
  gap: 2px;
  width: 100%;
  margin: 2px 0 0;
  text-align: left;
}
.ft-field {
  display: flex;
  align-items: baseline;
  gap: 4px;
  min-width: 0;
  font-size: .63rem;
  line-height: 1.25;
}
.ft-field dt {
  flex: 0 0 auto;
  color: #a8a29e;
  font-weight: 500;
  max-width: 45%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ft-field dt::after { content: ':'; }
.ft-field dd {
  margin: 0;
  min-width: 0;
  color: #44403c;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ft-badges { display: flex; gap: 4px; flex-wrap: wrap; justify-content: center; }
.ft-badge {
  font-size: .62rem;
  padding: 1px 6px;
  border-radius: 999px;
  border: 1px solid var(--card-border);
  color: #78716c;
  background: #fafaf9;
}
.ft-badge[data-c="living"]   { background:#ecfdf5; border-color:#a7f3d0; color:#065f46; }
.ft-badge[data-c="root"]     { background:#f0fdfa; border-color:#99f6e4; color:#0f766e; }
.ft-badge[data-c="adoptive"] { background:#fff7ed; border-color:#fed7aa; color:#9a3412; }
.ft-badge[data-c="step"]     { background:#f5f3ff; border-color:#ddd6fe; color:#5b21b6; }
.ft-badge[data-c="foster"],
.ft-badge[data-c="guardian"] { background:#fefce8; border-color:#fef08a; color:#854d0e; }

/* expand / collapse control pinned to the card's bottom-right corner */
.ft-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  align-self: flex-end;
  min-height: 30px;
  padding: 4px 10px;
  font-size: .72rem;
  font-weight: 600;
  color: #0f766e;
  background: #f0fdfa;
  border: 1px solid #99f6e4;
  border-radius: 999px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.ft-toggle:hover { background: #ccfbf1; }
.ft-toggle:active { background: #99f6e4; }
.ft-toggle svg { width: 10px; height: 10px; transition: transform .15s ease; }
.ft-toggle[aria-expanded="true"] svg { transform: rotate(180deg); }
.ft-toggle[data-state="loading"] { opacity: .55; pointer-events: none; }
.ft-toggle.is-leaf { display: none; }

/* children container hidden when collapsed */
.ft-node.is-collapsed > .ft-children { display: none; }
.ft-node.is-empty > .ft-children { display: none !important; }

/* skeleton loading row */
.ft-skeleton {
  width: var(--card-w);
  height: 130px;
  border-radius: 14px;
  background: linear-gradient(90deg, #f5f5f4 25%, #ededea 37%, #f5f5f4 63%);
  background-size: 400% 100%;
  animation: ft-shimmer 1.3s ease infinite;
}
@keyframes ft-shimmer {
  0%   { background-position: 100% 50%; }
  100% { background-position: 0 50%; }
}

.ft-error {
  width: min(260px, 78vw);
  border: 1px dashed #fda4af;
  background: #fff1f2;
  color: #9f1239;
  border-radius: 12px;
  padding: 12px;
  font-size: .78rem;
  text-align: center;
}

.ft-empty-branch {
  font-size: .75rem;
  color: #a8a29e;
  font-style: italic;
  padding: 4px 10px;
  white-space: nowrap;
}

/* --------------------------------------------------------------- overlays */

.ft-hint-pill {
  position: sticky;
  bottom: 0;
  margin: 0 auto calc(10px + env(safe-area-inset-bottom, 0px));
  width: fit-content;
  max-width: 92%;
  display: flex;
  align-items: center;
  gap: .4rem;
  font-size: .72rem;
  color: #57534e;
  background: rgba(255,255,255,.94);
  backdrop-filter: blur(4px);
  border: 1px solid var(--card-border);
  border-radius: 999px;
  padding: 6px 14px;
  box-shadow: 0 2px 8px rgba(0,0,0,.05);
  z-index: 5;
}

/* Floating "Add person" action for admins (clear entry point on the tree). */
.ft-fab {
  position: fixed;
  right: calc(16px + env(safe-area-inset-right, 0px));
  bottom: calc(68px + env(safe-area-inset-bottom, 0px));
  z-index: 30;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 12px 16px;
  border-radius: 999px;
  background: #0d9488;
  color: #fff;
  font-size: .85rem;
  font-weight: 600;
  box-shadow: 0 8px 24px -6px rgba(13, 148, 136, .65);
  transition: transform .12s ease, background .12s ease;
}
.ft-fab:hover { background: #0f766e; transform: translateY(-1px); }
.ft-fab:active { transform: scale(.97); }
@media (min-width: 1024px) {
  .ft-fab { bottom: calc(20px + env(safe-area-inset-bottom, 0px)); }
}

/* Per-card quick-add control (admins only). */
.ft-add {
  position: absolute;
  top: -8px;
  right: -8px;
  width: 26px;
  height: 26px;
  display: grid;
  place-items: center;
  padding: 0;
  border-radius: 999px;
  background: #0d9488;
  color: #fff;
  border: 2px solid #fff;
  box-shadow: 0 2px 6px rgba(28, 25, 23, .25);
  cursor: pointer;
  z-index: 3;
  transition: background .12s ease, transform .12s ease;
}
.ft-add svg { width: 13px; height: 13px; }
.ft-add:hover { background: #0f766e; transform: scale(1.08); }

/* Small popover opened by .ft-add. */
.ft-add-menu {
  position: fixed;
  z-index: 60;
  min-width: 152px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 6px;
  background: #fff;
  border: 1px solid var(--card-border);
  border-radius: 12px;
  box-shadow: 0 14px 34px -10px rgba(0, 0, 0, .35);
}
.ft-add-menu a {
  display: block;
  padding: 8px 10px;
  border-radius: 8px;
  font-size: .82rem;
  font-weight: 600;
  color: #0f766e;
}
.ft-add-menu a:hover { background: #f0fdfa; }
html.dark-tree .ft-add-menu { background: #292524; border-color: #44403c; }
html.dark-tree .ft-add-menu a { color: #5eead4; }
html.dark-tree .ft-add-menu a:hover { background: #3a3330; }

/* Horizontal chip strip (letter jump bar) - one row, swipeable. */
.chip-scroll {
  display: flex;
  gap: 6px;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  -ms-overflow-style: none;
  padding-bottom: 2px;
}
.chip-scroll::-webkit-scrollbar { display: none; }
.chip-scroll > * { flex: 0 0 auto; }

/* ------------------------------------------------------------- modal sheet
   Mobile-first: the profile is a bottom sheet with a drag handle. From 640px
   up it becomes a centred dialog.                                        */

/* The overlay is a flex column that pins the panel to the bottom edge. Only
   the panel scrolls: two scroll containers stacked on top of each other makes
   touch scrolling fight itself, and margin-top:auto needs a flex parent. */
.ft-sheet {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: none;
  flex-direction: column;
  justify-content: flex-end;
  overflow: hidden;
  background: rgba(28, 25, 23, .55);
  backdrop-filter: blur(2px);
}
.ft-sheet.is-open { display: flex; }

.ft-sheet__panel {
  position: relative;
  width: 100%;
  max-height: 92dvh;
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  touch-action: pan-y;
  background: #fff;
  border-radius: 20px 20px 0 0;
  box-shadow: 0 -8px 40px rgba(0, 0, 0, .28);
  padding-bottom: env(safe-area-inset-bottom, 0px);
  animation: ft-sheet-up .22s cubic-bezier(.22, 1, .36, 1);
}
@keyframes ft-sheet-up {
  from { transform: translateY(18px); opacity: .4; }
  to   { transform: translateY(0);    opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .ft-sheet__panel { animation: none; }
  .tree-stage { transition: none; }
}

/* Sticky so it stays reachable while the profile scrolls under it. */
.ft-sheet__grip {
  position: sticky;
  top: 0;
  z-index: 2;
  display: block;
  width: 100%;
  padding: 10px 0 6px;
  background: #fff;
  cursor: grab;
  touch-action: none;
}
html.dark-tree .ft-sheet__panel,
html.dark-tree .ft-sheet__grip { background: #1c1917; }
html.dark-tree .ft-sheet__grip::after { background: #57534e; }
.ft-sheet__grip::after {
  content: "";
  display: block;
  width: 42px;
  height: 4px;
  margin: 0 auto;
  border-radius: 999px;
  background: #d6d3d1;
}

/* ------------------------------------------------------------ touch tuning */

@media (hover: none) {
  .ft-card:hover { box-shadow: 0 1px 2px rgba(28, 25, 23, .04); border-color: var(--card-border); }
  .ft-photo-btn:hover { transform: none; box-shadow: 0 0 0 1px var(--card-border), 0 2px 6px rgba(28,25,23,.12); }
  .ft-photo-btn:active { transform: scale(.97); }
  .list-card:active { transform: scale(.985); }
}

/* ------------------------------------------------------- mobile → larger
   Mobile-first: base styles target phones, then step up.                     */

@media (min-width: 400px) {
  :root { --card-w: 158px; --card-photo: 64px; --gap-x: 12px; }
}

@media (min-width: 640px) {
  :root { --card-w: 176px; --card-photo: 72px; --gap-x: 15px; --gap-y: 27px; }
  .ft-card { padding: 10px; gap: 7px; min-height: 0; }
  .ft-name { font-size: .92rem; }
  .ft-meta { font-size: .69rem; }
  .ft-toggle { min-height: 0; padding: 1px 8px; font-size: .68rem; }
  .ft-hint-pill { padding: 4px 12px; }

  /* Centred dialog: the panel scrolls, so it needs a height budget of its own
     instead of letting the overlay grow past the viewport. */
  .ft-sheet {
    display: none;
    align-items: center;
    justify-content: center;
    padding: 24px;
  }
  .ft-sheet.is-open { display: flex; }
  .ft-sheet__panel {
    width: 100%;
    max-width: 48rem;
    max-height: calc(100dvh - 48px);
    border-radius: 16px;
    animation: none;
  }
  .ft-sheet__grip { display: none; }
}

@media (min-width: 1024px) {
  :root { --card-w: 200px; --card-photo: 84px; --gap-x: 18px; --gap-y: 30px; }
}

/* --------------------------------------------------------------- dark mode
   Opt-in (not media-query based) so it never fights Tailwind's own palette.
   Enable with <html class="dark-tree"> via the site theme setting.          */

html.dark-tree body { background-color: #1c1917 !important; color: #e7e5e4 !important; }
html.dark-tree { --line:#57534e; --line-soft:#44403c; --card-bg:#292524; --card-border:#44403c; }
html.dark-tree .ft-card { box-shadow: 0 1px 2px rgba(0,0,0,.4); }
html.dark-tree .ft-name { color: #fafaf9; }
html.dark-tree .ft-meta { color: #a8a29e; }
html.dark-tree .ft-field dt { color: #78716c; }
html.dark-tree .ft-field dd { color: #d6d3d1; }
html.dark-tree .ft-badge { background:#292524; color:#a8a29e; border-color:#44403c; }
html.dark-tree .ft-photo-btn { border-color:#44403c; }
html.dark-tree .ft-skeleton {
  background: linear-gradient(90deg,#292524 25%,#3a3330 37%,#292524 63%);
  background-size: 400% 100%;
}
html.dark-tree .ft-skeleton::after { content:""; }