/* Ancestree — a warm, papery family-tree workspace. */

:root {
  --ink:        #2c2620;
  --ink-soft:   #6b6154;
  --ink-faint:  #9a9084;
  --paper:      #f6f1e7;
  --paper-2:    #fffdf8;
  --line:       #d8cbb4;
  --line-soft:  #e7ddca;
  --walnut:     #8a5637;
  --walnut-dk:  #6d422a;
  --sage:       #7c8a6c;
  --gold:       #b3903f;
  --rose:       #b4645f;
  --shadow:     0 1px 2px rgba(58,44,28,.10), 0 6px 18px rgba(58,44,28,.10);
  --shadow-lg:  0 24px 70px rgba(40,30,18,.34);
  --card-w:     180px;
  --card-h:     92px;
  --ui: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --serif: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, "Times New Roman", serif;
}

* { box-sizing: border-box; }

/* The browser's own `[hidden] { display: none }` lives in the UA stylesheet, and
   ANY author `display` beats it — origin wins over specificity. Several
   components below set display: flex/grid, which silently resurrects them when
   hidden: the overlays then cover the page at opacity 0 and eat every click.
   Keep this rule, and keep it !important. */
[hidden] { display: none !important; }

html, body {
  height: 100%;
  margin: 0;
}

body {
  font-family: var(--ui);
  color: var(--ink);
  background: var(--paper);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  -webkit-font-smoothing: antialiased;
}


/* --------------------------------------------------------------- top bar */

.topbar {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 10px 16px;
  background: linear-gradient(180deg, #fffdf8, #f4eee1);
  border-bottom: 1px solid var(--line);
  box-shadow: 0 1px 0 rgba(255,255,255,.7) inset;
  z-index: 30;
}

.brand {
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: var(--serif);
  font-size: 19px;
  letter-spacing: .01em;
  color: var(--walnut-dk);
  flex: 0 0 auto;
}

.tree-title {
  flex: 0 1 300px;
  min-width: 120px;
  font-family: var(--serif);
  font-size: 17px;
  color: var(--ink);
  background: transparent;
  border: 1px solid transparent;
  border-radius: 7px;
  padding: 6px 9px;
  text-overflow: ellipsis;
}
.tree-title:hover:not(:disabled) { border-color: var(--line-soft); background: rgba(255,255,255,.6); }
.tree-title:focus { outline: none; border-color: var(--gold); background: #fff; }
.tree-title:disabled { color: var(--ink-soft); }

.tools {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
}
.tool-group { display: flex; gap: 6px; }

/* --------------------------------------------------- tree picker + menus */

.tree-id { position: relative; display: flex; align-items: center; gap: 2px; flex: 0 1 auto; }

.tree-menu-btn {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 6px 9px;
  font-size: 12px;
  color: var(--ink-soft);
}
.tree-menu-btn svg { display: block; }

.tree-menu {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  width: 336px;
  max-height: 70vh;
  overflow-y: auto;
  background: var(--paper-2);
  border: 1px solid var(--line);
  border-radius: 10px;
  box-shadow: 0 16px 40px rgba(58,44,28,.22);
  z-index: 50;
  padding: 6px;
}
.tree-menu-head,
.tree-menu-foot {
  display: flex;
  gap: 6px;
  padding: 6px 8px;
  font-family: var(--serif);
  font-size: 11px;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.tree-menu-foot { border-top: 1px solid var(--line-soft); margin-top: 4px; padding-top: 8px; }

.tree-list { list-style: none; margin: 0; padding: 0; }
.tree-list li { display: flex; align-items: stretch; gap: 2px; }
.tree-empty { padding: 10px 8px; font-size: 13px; color: var(--ink-faint); font-style: italic; }

.tree-row {
  flex: 1 1 auto;
  min-width: 0;
  text-align: left;
  font: inherit;
  padding: 8px 9px;
  border: none;
  border-radius: 7px;
  background: transparent;
  cursor: pointer;
  color: var(--ink);
}
.tree-row:hover { background: rgba(180,150,90,.12); }
.tree-row.current { background: rgba(180,150,90,.18); }
.tree-row-name {
  display: block;
  font-family: var(--serif);
  font-size: 14px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.tree-row-meta { display: block; font-size: 11px; color: var(--ink-faint); margin-top: 2px; }

.tree-row-del {
  flex: 0 0 auto;
  width: 28px;
  border: none;
  border-radius: 7px;
  background: transparent;
  color: var(--ink-faint);
  font-size: 17px;
  line-height: 1;
  cursor: pointer;
}
.tree-row-del:hover { background: #f6e2e0; color: #8f3f3a; }

.menu-wrap { position: relative; }
#exportBtn { display: inline-flex; align-items: center; gap: 6px; }
#exportBtn svg { display: block; }

.dropdown {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  width: 250px;
  background: var(--paper-2);
  border: 1px solid var(--line);
  border-radius: 10px;
  box-shadow: 0 16px 40px rgba(58,44,28,.22);
  z-index: 50;
  padding: 6px;
}
.dropdown.menu-list button {
  display: block;
  width: 100%;
  text-align: left;
  font: inherit;
  padding: 8px 10px;
  border: none;
  border-radius: 7px;
  background: transparent;
  cursor: pointer;
  color: var(--ink);
}
.dropdown.menu-list button:hover { background: rgba(180,150,90,.12); }
.dropdown.menu-list strong { display: block; font-weight: 600; font-size: 13px; }
.dropdown.menu-list span {
  display: block;
  font-size: 11.5px;
  color: var(--ink-faint);
  margin-top: 1px;
}

/* ---------------------------------------------------------------- buttons */

.btn {
  font: inherit;
  font-size: 13px;
  padding: 7px 13px;
  border-radius: 8px;
  border: 1px solid var(--line);
  background: linear-gradient(180deg, #fffefb, #f5efe3);
  color: var(--ink);
  cursor: pointer;
  white-space: nowrap;
  transition: background .13s, border-color .13s, transform .06s, box-shadow .13s;
}
.btn:hover { border-color: var(--gold); box-shadow: 0 1px 3px rgba(58,44,28,.12); }
.btn:active { transform: translateY(1px); }
.btn:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
.btn.primary {
  background: linear-gradient(180deg, #9c6440, var(--walnut));
  border-color: var(--walnut-dk);
  color: #fdf8ef;
}
.btn.primary:hover { background: linear-gradient(180deg, #a86e47, #7c4d31); }
.btn.primary:disabled { opacity: .55; cursor: default; }
/* inline-grid so a glyph and an inline SVG centre identically */
.btn.icon {
  display: inline-grid;
  place-items: center;
  padding: 7px 10px;
  min-width: 34px;
  height: 32px;
  font-size: 14px;
  line-height: 1;
}
.btn.icon svg { display: block; }
.btn.small { font-size: 12px; padding: 5px 10px; }
.zoom-level {
  min-width: 52px;
  height: 32px;
  padding: 7px 6px;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  color: var(--ink-soft);
}
.btn.with-icon { display: inline-flex; align-items: center; gap: 6px; height: 32px; }
.btn.with-icon svg { display: block; }
.btn:disabled {
  opacity: .4;
  cursor: default;
  border-color: var(--line);
  box-shadow: none;
}
.btn:disabled:hover { border-color: var(--line); box-shadow: none; }
.btn.ghost { background: transparent; border-color: transparent; color: var(--ink-soft); }
.btn.ghost:hover { border-color: var(--line); color: var(--ink); box-shadow: none; }

/* ----------------------------------------------------------------- stage */

.stage {
  position: relative;
  flex: 1 1 auto;
  overflow: hidden;
  cursor: grab;
  touch-action: none;
  background-color: var(--paper);
  background-image: radial-gradient(circle at 1px 1px, rgba(120,100,70,.16) 1px, transparent 0);
  background-size: 20px 20px;
}
.stage.panning { cursor: grabbing; }
.stage.linking { cursor: crosshair; }
.stage.linking .card { cursor: crosshair; }

.viewport {
  position: absolute;
  left: 0; top: 0;
  width: 0; height: 0;
  transform-origin: 0 0;
}

.edges, .guides {
  position: absolute;
  left: 0; top: 0;
  width: 1px; height: 1px;
  overflow: visible;
  pointer-events: none;
}

.edge {
  fill: none;
  stroke: #b6a483;
  stroke-width: 2;
  stroke-linejoin: round;
  stroke-linecap: round;
  transition: stroke .12s, stroke-width .12s;
}
/* A couple who could not share a row — one is an ancestor of the other. */
.edge.cross-gen { stroke-dasharray: 7 5; stroke: #a8917a; }

.edge.selected {
  stroke: var(--walnut);
  stroke-width: 3.5;
}

/* Fat invisible twin of each line: a 2px stroke is far too thin to click. */
.edge-hit {
  fill: none;
  stroke: transparent;
  stroke-width: 16;
  stroke-linejoin: round;
  stroke-linecap: round;
  pointer-events: stroke;
  cursor: pointer;
}

.union-mark { fill: var(--gold); opacity: .85; }
.union-mark.cross-gen { fill: #a8917a; }
.guide {
  stroke: var(--rose);
  stroke-width: 1;
  stroke-dasharray: 5 5;
  vector-effect: non-scaling-stroke;
  opacity: .85;
}

.nodes { position: absolute; left: 0; top: 0; }
.nodes.settling .card { transition: transform .42s cubic-bezier(.22,1,.36,1); }

/* ----------------------------------------------------------------- cards */

.card {
  position: absolute;
  left: 0; top: 0;
  width: var(--card-w);
  height: var(--card-h);
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  background: linear-gradient(180deg, var(--paper-2), #f7f1e4);
  border: 1px solid var(--line);
  border-radius: 12px;
  box-shadow: var(--shadow);
  cursor: grab;
  user-select: none;
  transition: box-shadow .15s, border-color .15s;
}
.card::before {                    /* the tinted spine down the left edge */
  content: "";
  position: absolute;
  left: 0; top: 10px; bottom: 10px;
  width: 3px;
  border-radius: 3px;
  background: var(--ink-faint);
}
.card[data-gender="f"]::before { background: #b07f9a; }
.card[data-gender="m"]::before { background: #6f8aa8; }
.card[data-gender="x"]::before { background: var(--sage); }

.card:hover { border-color: var(--gold); box-shadow: 0 2px 4px rgba(58,44,28,.12), 0 10px 24px rgba(58,44,28,.14); }
.card:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; }
.card.selected {
  border-color: var(--walnut);
  box-shadow: 0 0 0 2px rgba(138,86,55,.28), var(--shadow);
}
.card.dragging {
  cursor: grabbing;
  box-shadow: 0 10px 30px rgba(58,44,28,.28);
  z-index: 5;
}

.avatar {
  flex: 0 0 auto;
  width: 42px; height: 42px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-family: var(--serif);
  font-size: 15px;
  letter-spacing: .02em;
  color: #fffdf7;
  background: linear-gradient(150deg, #a5744f, #7d4e32);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.28);
}
.card[data-gender="f"] .avatar { background: linear-gradient(150deg, #b5849e, #8d5c78); }
.card[data-gender="m"] .avatar { background: linear-gradient(150deg, #7590ad, #4f6c8a); }

/* Initials are uppercase, so they carry no descender — but the line box still
   reserves descender space, which parks the visible letters about a pixel low
   in the circle. Nudge by a font-relative amount so every size is centred. */
.initials {
  display: block;
  transform: translateY(-0.067em);
}

.avatar.has-photo { background: #e6dcc8; overflow: hidden; }
.avatar.has-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  border-radius: 50%;
}

/* a card lit up as the drop target for a dragged photo */
.card.drop-target {
  border-color: var(--walnut);
  border-style: dashed;
  box-shadow: 0 0 0 3px rgba(138,86,55,.20), var(--shadow);
}
.card.drop-target .avatar { opacity: .5; }

/* Clip as a backstop: a name, a birth surname and a lifespan is a lot for a
   92px card, and a substituted font must not push text out of it. */
.meta { min-width: 0; overflow: hidden; }
.name {
  font-family: var(--serif);
  font-size: 15px;
  line-height: 1.2;
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}
/* The surname someone carried before marrying. One line — the card has 72px of
   content height and a two-line name already claims most of it. */
.born {
  font-size: 10px;
  line-height: 1.2;
  color: var(--ink-faint);
  font-style: italic;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  margin-top: 1px;
}
.dates { font-size: 11.5px; color: var(--ink-soft); margin-top: 1px; letter-spacing: .02em; }

.book-btn {
  position: absolute;
  right: 7px; bottom: 7px;
  width: 26px; height: 26px;
  display: grid;
  place-items: center;
  border-radius: 7px;
  border: 1px solid transparent;
  background: transparent;
  color: var(--ink-faint);
  cursor: pointer;
  opacity: 0;
  transition: opacity .15s, color .15s, background .15s;
}
.card:hover .book-btn, .card.selected .book-btn { opacity: 1; }
.book-btn:hover { color: var(--walnut); background: #fff; border-color: var(--line); }


/* ------------------------------------------------------------------ pill */

.pill {
  position: fixed;
  transform: translate(-50%, -100%);
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 4px;
  background: #fffdf7;
  border: 1px solid var(--line);
  border-radius: 10px;
  box-shadow: 0 8px 22px rgba(58,44,28,.20);
  z-index: 40;
  animation: pop .14s ease-out;
}
@keyframes pop { from { opacity: 0; transform: translate(-50%, -92%); } }
.pill button {
  font: inherit;
  font-size: 12px;
  padding: 5px 9px;
  border: none;
  background: transparent;
  color: var(--ink);
  border-radius: 6px;
  cursor: pointer;
  white-space: nowrap;
}
.pill button:hover { background: #f1e8d6; }
.pill button.danger:hover { background: #f6e2e0; color: #8f3f3a; }
.pill-sep { width: 1px; height: 18px; background: var(--line-soft); margin: 0 3px; }

.edge-pill { transform: translate(-50%, -50%); }
.edge-label {
  padding: 0 6px;
  font-size: 12px;
  color: var(--ink-soft);
  max-width: 190px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ------------------------------------------------------------- statusbar */

.statusbar {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 7px 16px;
  font-size: 11.5px;
  color: var(--ink-soft);
  background: linear-gradient(180deg, #f4eee1, #efe7d6);
  border-top: 1px solid var(--line);
  z-index: 20;
}
.legend { display: flex; align-items: center; gap: 6px; }
.swatch {
  width: 9px; height: 9px;
  border-radius: 3px;
  display: inline-block;
  margin-left: 6px;
}
.swatch.f { background: #b07f9a; }
.swatch.m { background: #6f8aa8; }
.swatch.x { background: var(--sage); }
.tips { margin-left: auto; text-align: right; }
.statusbar .btn.small { flex: 0 0 auto; }

/* The claim that nothing leaves your browser is only worth making if you can
   go and check it, so the way to the source lives in the app, not just in a
   README nobody opens. */
.source-link {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 8px;
  border: 1px solid transparent;
  border-radius: 7px;
  color: var(--ink-soft);
  text-decoration: none;
  transition: color .13s, border-color .13s, background .13s;
}
.source-link svg { display: block; }
.source-link:hover {
  color: var(--walnut-dk);
  border-color: var(--line);
  background: #fffdf7;
}
.source-link:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }

/* ------------------------------------------------------------------ hint */

.hint {
  position: fixed;
  left: 50%;
  bottom: 58px;
  transform: translate(-50%, 12px);
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 9px 10px 9px 16px;
  background: #33291c;
  color: #f7efe0;
  font-size: 13px;
  border-radius: 20px;
  box-shadow: 0 10px 30px rgba(30,22,12,.34);
  opacity: 0;
  pointer-events: none;
  transition: opacity .2s, transform .2s;
  z-index: 60;
}
.hint.show { opacity: 1; transform: translate(-50%, 0); }
/* The toast itself ignores clicks; only the action inside it takes them. */
.hint.show .hint-undo { pointer-events: auto; }

.hint-undo {
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: .02em;
  padding: 4px 12px;
  border: 1px solid rgba(247,239,224,.35);
  border-radius: 14px;
  background: transparent;
  color: #f0c987;
  cursor: pointer;
  white-space: nowrap;
}
.hint-undo:hover { background: rgba(240,201,135,.16); border-color: #f0c987; }

/* ------------------------------------------------------------------ book */

.book-overlay {
  position: fixed;
  inset: 0;
  background: rgba(35,26,16,.55);
  backdrop-filter: blur(3px);
  display: grid;
  /* An implicit `auto` track grows to the book's max-content width, and the
     book's `100%` then resolves against that oversized track — which is how it
     came to stick out past a phone screen. minmax(0,1fr) pins it to the
     overlay instead. */
  grid-template-columns: minmax(0, 1fr);
  place-items: center;
  padding: 24px;
  z-index: 80;
  opacity: 0;
  transition: opacity .22s;
}
.book-overlay.open { opacity: 1; }

.book {
  position: relative;
  display: flex;
  width: min(1000px, 100%);
  /* A grid item's min-width is `auto`, i.e. min-content, which beats the width
     above. Without this the date pickers inside hold the book open wider than
     a phone screen. */
  min-width: 0;
  height: min(660px, 88vh);
  background: #efe6d2;
  border-radius: 8px;
  box-shadow: var(--shadow-lg);
  padding: 12px;
  gap: 0;
  transform: scale(.94) rotateX(6deg);
  transform-origin: center 65%;
  transition: transform .28s cubic-bezier(.2,1,.3,1);
}
.book-overlay.open .book { transform: none; }

.page {
  flex: 1 1 50%;
  min-width: 0;
  background:
    linear-gradient(180deg, #fffdf6, #fbf6ea);
  padding: 30px 34px;
  overflow-y: auto;
  overscroll-behavior: contain;
}
.page-left {
  border-radius: 5px 0 0 5px;
  box-shadow: inset -14px 0 22px -18px rgba(80,60,30,.5);
}
.page-right {
  border-radius: 0 5px 5px 0;
  box-shadow: inset 14px 0 22px -18px rgba(80,60,30,.5);
  transform-origin: left center;
}
.page-right.flip { animation: pageflip .42s ease-out; }
@keyframes pageflip {
  0%   { transform: perspective(1400px) rotateY(-38deg); opacity: .35; }
  100% { transform: perspective(1400px) rotateY(0); opacity: 1; }
}

.spine {
  flex: 0 0 14px;
  background: linear-gradient(90deg, #d9cdb2, #bda98a 45%, #d9cdb2);
  box-shadow: inset 0 0 8px rgba(70,50,25,.35);
}

.close-book {
  position: absolute;
  top: -14px; right: -14px;
  width: 34px; height: 34px;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: #fffdf7;
  color: var(--ink-soft);
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  box-shadow: var(--shadow);
  z-index: 2;
}
.close-book:hover { color: var(--ink); border-color: var(--gold); }

/* left page contents */

.portrait-wrap {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-bottom: 16px;
}

.portrait {
  position: relative;
  flex: 0 0 auto;
  width: 76px; height: 76px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  overflow: hidden;
  font-family: var(--serif);
  font-size: 25px;
  color: #fffdf7;
  background: linear-gradient(150deg, #a5744f, #7d4e32);
  box-shadow: 0 3px 10px rgba(80,55,30,.28), inset 0 1px 0 rgba(255,255,255,.3);
}
.portrait[data-gender="f"] { background: linear-gradient(150deg, #b5849e, #8d5c78); }
.portrait[data-gender="m"] { background: linear-gradient(150deg, #7590ad, #4f6c8a); }

.portrait-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.portrait.editable { cursor: pointer; }
.portrait-overlay {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-family: var(--ui);
  font-size: 11px;
  letter-spacing: .04em;
  color: #fff;
  background: rgba(45,32,18,.58);
  opacity: 0;
  transition: opacity .15s;
}
.portrait.editable:hover .portrait-overlay,
.portrait.editable:focus-within .portrait-overlay { opacity: 1; }

.portrait-remove {
  font: inherit;
  font-size: 12px;
  padding: 4px 9px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: #fffdf7;
  color: var(--ink-soft);
  cursor: pointer;
}
.portrait-remove:hover { border-color: #c98f8b; color: #93413c; background: #fdf4f3; }

.portrait-tip {
  font-size: 11.5px;
  line-height: 1.45;
  color: var(--ink-faint);
  max-width: 130px;
}

.person-name {
  font-family: var(--serif);
  font-size: 26px;
  line-height: 1.2;
  margin: 0 0 18px;
  width: 100%;
  border: none;
  border-bottom: 1px solid transparent;
  background: transparent;
  color: var(--ink);
  padding: 2px 0;
}
input.person-name:hover { border-bottom-color: var(--line); }
input.person-name:focus { outline: none; border-bottom-color: var(--gold); }

.person-fields { display: grid; gap: 3px; margin-bottom: 26px; }
.pf {
  display: grid;
  grid-template-columns: 82px 1fr;
  align-items: center;
  gap: 8px;
  font-size: 13.5px;
}
.pf-label {
  font-family: var(--serif);
  font-size: 12px;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.pf-input {
  font: inherit;
  font-size: 13.5px;
  padding: 5px 6px;
  border: 1px solid transparent;
  border-radius: 5px;
  background: transparent;
  color: var(--ink);
  width: 100%;
}
.pf-input:hover { background: rgba(180,150,90,.09); }
.pf-input:focus { outline: none; background: #fff; border-color: var(--gold); }
.pf-input::placeholder { color: #c3b8a5; }

/* Born / Died date pickers */
.pf-datewrap { display: flex; align-items: center; gap: 6px; min-width: 0; }
.pf-datepick { flex: 0 1 auto; min-width: 0; font-variant-numeric: tabular-nums; }
.pf-datetext { flex: 1 1 auto; min-width: 0; font-style: italic; }
.pf-legacy {
  flex: 0 1 auto;
  font-size: 11.5px;
  color: var(--ink-faint);
  font-style: italic;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  border-bottom: 1px dotted var(--line);
  cursor: help;
}

/* Switch a date field between the picker and free text. */
.date-mode {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  margin-left: auto;
  padding: 0;
  font: inherit;
  font-size: 13px;
  line-height: 1;
  border: 1px solid transparent;
  border-radius: 6px;
  background: transparent;
  color: var(--ink-faint);
  cursor: pointer;
  opacity: 0;
  transition: opacity .15s, color .15s, border-color .15s;
}
.pf:hover .date-mode,
.date-mode:focus-visible { opacity: 1; }
.date-mode:hover { color: var(--walnut); border-color: var(--line); background: #fffdf7; }

/* "Known for": two lines, then ellipsis, with the full text on hover. */
.pf.pf-tall { align-items: start; }
.pf.pf-tall .pf-label { padding-top: 6px; }

.pf-clampwrap {
  font-size: 13.5px;
  line-height: 1.45;
  min-height: calc(2 * 1.45em + 10px);
  padding: 4px 6px;
  border: 1px solid transparent;
  border-radius: 5px;
  color: var(--ink);
}
/* The clamp itself. Must stay a plain inline child — as a grid/flex item its
   display would be blockified and -webkit-box (which line-clamp needs) lost. */
.pf-clamp {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  max-height: calc(2 * 1.45em);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.pf-clampwrap.editable { cursor: text; }
.pf-clampwrap.editable:hover { background: rgba(180,150,90,.09); }
.pf-clampwrap.editable:focus-visible { outline: none; background: #fff; border-color: var(--gold); }
.pf-clampwrap.empty { color: #c3b8a5; }

textarea.pf-multiline {
  font-family: inherit;
  line-height: 1.45;
  height: calc(2 * 1.45em + 10px);
  resize: vertical;
  min-height: calc(2 * 1.45em + 10px);
}

.toc-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding-bottom: 7px;
  border-bottom: 1px solid var(--line-soft);
  font-family: var(--serif);
  font-size: 12px;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.mini-btn {
  font: inherit;
  font-family: var(--ui);
  font-size: 12px;
  letter-spacing: 0;
  text-transform: none;
  padding: 4px 9px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: #fffdf7;
  color: var(--walnut-dk);
  cursor: pointer;
}
.mini-btn:hover { border-color: var(--gold); background: #fff; }
.mini-btn.danger { color: #93413c; }
.mini-btn.danger:hover { border-color: #c98f8b; background: #fdf4f3; }

.toc { list-style: none; margin: 8px 0 0; padding: 0; }
.toc-empty { font-size: 13px; color: var(--ink-faint); font-style: italic; padding: 8px 0; }
.toc-item {
  display: flex;
  gap: 10px;
  align-items: baseline;
  width: 100%;
  text-align: left;
  font: inherit;
  padding: 7px 8px;
  border: none;
  border-left: 2px solid transparent;
  border-radius: 0 5px 5px 0;
  background: transparent;
  cursor: pointer;
  color: var(--ink);
}
.toc-item:hover { background: rgba(180,150,90,.11); }
.toc-item.current { border-left-color: var(--walnut); background: rgba(180,150,90,.15); }
.toc-date { flex: 0 0 auto; font-size: 11.5px; color: var(--ink-faint); font-variant-numeric: tabular-nums; }
.toc-title {
  font-family: var(--serif);
  font-size: 14px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* right page contents */

.entry-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 14px;
}
.entry-dates {
  display: flex;
  align-items: center;
  gap: 5px;
  flex-wrap: wrap;
  min-width: 0;
}
.entry-date, .entry-end {
  font-family: var(--serif);
  font-size: 13px;
  color: var(--ink-soft);
  letter-spacing: .04em;
  border: 1px solid transparent;
  background: transparent;
  border-radius: 5px;
  padding: 4px 6px;
}
.entry-date:hover, .entry-end:hover { background: rgba(180,150,90,.1); }
.entry-date:focus, .entry-end:focus { outline: none; background: #fff; border-color: var(--gold); }

.date-dash { color: var(--ink-faint); font-family: var(--serif); }

.date-add, .date-clear {
  font: inherit;
  font-family: var(--ui);
  font-size: 11.5px;
  padding: 3px 7px;
  border: 1px solid transparent;
  border-radius: 5px;
  background: transparent;
  color: var(--ink-faint);
  cursor: pointer;
}
.date-add:hover { color: var(--walnut-dk); border-color: var(--line); background: #fffdf7; }
.date-clear { font-size: 14px; line-height: 1; padding: 2px 6px; }
.date-clear:hover { color: #93413c; border-color: #c98f8b; background: #fdf4f3; }

.entry-warn {
  margin: -6px 0 10px;
  font-size: 12px;
  color: #93413c;
  background: #fdf4f3;
  border: 1px solid #e4c4c1;
  border-radius: 6px;
  padding: 5px 9px;
}

.toc-span { margin-left: 3px; color: var(--gold); font-size: 10px; }

.entry-title {
  font-family: var(--serif);
  font-size: 23px;
  line-height: 1.25;
  margin: 0 0 4px;
  width: 100%;
  border: none;
  border-bottom: 1px solid transparent;
  background: transparent;
  color: var(--ink);
  padding: 2px 0;
}
input.entry-title:hover { border-bottom-color: var(--line); }
input.entry-title:focus { outline: none; border-bottom-color: var(--gold); }
.entry-title::placeholder { color: #cfc4b0; }

.entry-body {
  width: 100%;
  margin-top: 14px;
  font-family: var(--serif);
  font-size: 15.5px;
  line-height: 30px;   /* matches the ruled-line spacing below */
  color: #3b332a;
  background: repeating-linear-gradient(
    transparent, transparent 29px, rgba(150,125,80,.16) 29px, rgba(150,125,80,.16) 30px);
  border: none;
  resize: none;
  overflow: hidden;
  padding: 0;
}
.entry-body:focus { outline: none; }
.entry-body::placeholder { color: #cfc4b0; font-style: italic; }
.page-empty {
  height: 100%;
  display: grid;
  place-content: center;
  justify-items: center;
  gap: 10px;
  text-align: center;
  color: var(--ink-soft);
  font-family: var(--serif);
}
.page-empty .flourish { font-size: 30px; color: var(--gold); opacity: .6; }
.page-empty p { margin: 0; font-size: 16px; }
/* ---------------------------------------------------------------- dialog */

.dialog-overlay {
  position: fixed;
  inset: 0;
  background: rgba(35,26,16,.5);
  backdrop-filter: blur(2px);
  display: grid;
  place-items: center;
  padding: 24px;
  z-index: 90;
  opacity: 0;
  transition: opacity .18s;
}
.dialog-overlay.open { opacity: 1; }

.dialog {
  width: min(560px, 100%);
  background: var(--paper-2);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 26px 26px 20px;
  box-shadow: var(--shadow-lg);
}
.dialog-narrow { width: min(420px, 100%); }
.dialog-foot-right { justify-content: flex-end; }
.btn.danger-btn {
  background: linear-gradient(180deg, #b0574f, #91423b);
  border-color: #7d3831;
  color: #fdf5f4;
}
.btn.danger-btn:hover { background: linear-gradient(180deg, #bd6159, #823933); }

.dialog h2 { font-family: var(--serif); font-size: 22px; margin: 0 0 6px; font-weight: 500; }
.dialog-sub { margin: 0 0 18px; font-size: 13.5px; color: var(--ink-soft); line-height: 1.5; }

.dialog-foot {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px solid var(--line-soft);
}

/* --------------------------------------------------------------- narrow */

@media (max-width: 820px) {
  .tree-title { flex-basis: 150px; }
  .tips { display: none; }
  /* The mark alone still reads, and the anchor keeps its aria-label. */
  .source-link span { display: none; }
  .source-link { padding: 4px 6px; }
  /* .tips was doing the pushing; without it, keep the group on the right. */
  .statusbar .btn.small { margin-left: auto; }
  .book { flex-direction: column; height: 90vh; }
  .spine { display: none; }
  .page-left { border-radius: 5px 5px 0 0; box-shadow: none; border-bottom: 1px solid var(--line); }
  .page-right { border-radius: 0 0 5px 5px; box-shadow: none; }
}

/* Without a mouse there is no hover, so anything revealed by it is invisible.
   Show those controls outright on touch devices. */
@media (hover: none) {
  .book-btn { opacity: 1; }
  .date-mode { opacity: 1; }
  .portrait-overlay {
    opacity: 1;
    inset: auto 0 0 0;
    height: 20px;
    font-size: 9.5px;
    background: rgba(45,32,18,.62);
  }
  .tips { display: none; }
  /* A finger is not a cursor. The toolbar's 31px controls are hard to hit
     without being sure; 38px is comfortable and still leaves the canvas the
     bulk of a phone screen. */
  .btn { min-height: 38px; }
  .btn.icon { height: 38px; min-width: 38px; }
  .btn.with-icon { height: 38px; }
  .zoom-level { height: 38px; }
  .tree-menu-btn { min-height: 38px; }
  .tree-title { padding: 8px 9px; }
}

/* Phone width: the toolbar cannot sit on one line beside the tree name. Left
   alone it runs off the right edge, and a page wider than the screen makes the
   browser shrink the whole layout to fit — which was pushing the life book off
   screen too. Give the tools a row of their own and let them wrap: everything
   stays reachable, and nothing hides behind a swipe. */
@media (max-width: 700px) {
  .topbar {
    flex-wrap: wrap;
    gap: 8px 10px;
    padding: 8px 10px;
  }
  .brand { font-size: 17px; }
  /* Brand and tree name are 26px too wide together for a 412px screen, and
     wrapping cost a whole row. Let the name give up that much instead. */
  .tree-id { flex: 1 1 120px; min-width: 0; }
  .tree-title { flex: 1 1 auto; min-width: 0; }
  .tools {
    margin-left: 0;
    width: 100%;
    gap: 8px;
  }

  /* The menus hang off their own button, which on a phone puts them half off
     the screen. Hand the containing block to the topbar instead so they span
     the width and drop below the whole bar. The two-class selectors beat
     .zoom-menu's own left/transform further down the file. */
  .tree-id,
  .menu-wrap { position: static; }
  .topbar { position: relative; }
  .topbar .tree-menu,
  .topbar .dropdown {
    top: calc(100% + 6px);
    left: 8px;
    right: 8px;
    width: auto;
    transform: none;
    max-height: 66vh;
    overflow-y: auto;
  }
}

/* Very narrow phones (an iPhone SE is 320px). At the sizes above, the tools
   need three rows and eat 42% of the screen. Trimming the padding is enough to
   pack them into two without dropping a single control. */
@media (max-width: 380px) {
  .topbar { gap: 6px 8px; padding: 7px 8px; }
  .tools { gap: 6px; }
  .tool-group { gap: 5px; }
  .btn { padding: 7px 9px; font-size: 12.5px; }
  .btn.icon { padding: 7px 6px; min-width: 30px; }
  .zoom-level { min-width: 46px; }
  .brand { font-size: 15px; }
}

/* Phone width: the colour key is the first thing that can go — the card tints
   are legible without it, and the book spells the field out anyway. */
@media (max-width: 600px) {
  .legend { display: none; }
}

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

.storage-foot { align-items: center; justify-content: space-between; flex-wrap: nowrap; }
.storage-foot .mini-btn { white-space: nowrap; }
.storage-use {
  font-size: 10.5px;
  letter-spacing: 0;
  text-transform: none;
  text-align: right;
  line-height: 1.3;
}

/* ------------------------------------------------------------ zoom menu */

.zoom-menu { width: 224px; right: auto; left: 50%; transform: translateX(-50%); }

.zoom-form {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 8px 8px;
}
.zoom-form label {
  flex: 0 0 auto;
  white-space: nowrap;
  font-family: var(--serif);
  font-size: 11px;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.zoom-form .mini-btn { flex: 0 0 auto; }
.zoom-input-wrap {
  position: relative;
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
}
.zoom-input-wrap input {
  width: 100%;
  font: inherit;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  padding: 5px 20px 5px 7px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: #fffdf7;
  color: var(--ink);
}
.zoom-input-wrap input:focus { outline: none; border-color: var(--gold); background: #fff; }
.zoom-pct {
  position: absolute;
  right: 7px;
  font-size: 11.5px;
  color: var(--ink-faint);
  pointer-events: none;
}

.zoom-presets {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 4px;
  padding: 6px 8px 8px;
  border-top: 1px solid var(--line-soft);
}
.zoom-presets button {
  font: inherit;
  font-size: 12px;
  padding: 5px 4px;
  border: 1px solid transparent;
  border-radius: 6px;
  background: transparent;
  color: var(--ink);
  cursor: pointer;
}
.zoom-presets button:hover { background: rgba(180,150,90,.14); border-color: var(--line); }

/* ------------------------------------------------------- union states */

/* An unmarried partnership: the usual genealogical dashed line. */
.edge.unwed { stroke-dasharray: 6 4; }

.union-break {
  fill: none;
  stroke: #a8917a;
  stroke-width: 1.8;
  stroke-linecap: round;
}

.union-label {
  font-family: var(--ui);
  font-size: 10px;
  letter-spacing: .03em;
  fill: var(--ink-faint);
  pointer-events: none;
  paint-order: stroke;
  stroke: var(--paper);
  stroke-width: 3px;
  stroke-linejoin: round;
}

.edge-union { display: flex; align-items: center; gap: 4px; }
.edge-union select,
.edge-union .union-date {
  font: inherit;
  font-size: 12px;
  padding: 4px 6px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: #fffdf7;
  color: var(--ink);
}
.edge-union .union-date { width: 62px; }
.edge-union select:focus,
.edge-union .union-date:focus { outline: none; border-color: var(--gold); background: #fff; }

/* Naming a card in place, straight after it is created. */
.name-edit {
  display: block;
  width: 100%;
  font-family: var(--serif);
  font-size: 15px;
  line-height: 1.2;
  color: var(--ink);
  padding: 1px 4px;
  margin: -1px -4px;
  border: 1px solid var(--gold);
  border-radius: 5px;
  background: #fff;
}
.name-edit:focus { outline: none; box-shadow: 0 0 0 2px rgba(179,144,63,.25); }

/* Relationships, listed in the book so they are findable without knowing to
   click a connector on the canvas. */
.rel-list { list-style: none; margin: 8px 0 22px; padding: 0; }
.rel {
  padding: 8px 10px;
  margin-bottom: 6px;
  /* Set apart from the page so each relationship reads as its own block. */
  background: rgba(180,150,90,.09);
  border-left: 2px solid var(--line);
  border-radius: 0 7px 7px 0;
}
.rel-who {
  display: flex;
  align-items: baseline;
  gap: 8px;
  font-family: var(--serif);
  font-size: 14px;
  color: var(--ink);
}
.rel-none { color: var(--ink-faint); font-style: italic; }
.rel-kids { font-family: var(--ui); font-size: 11px; color: var(--ink-faint); }
.rel-fields { display: flex; gap: 5px; margin-top: 5px; }
.rel-fields select,
.rel-fields input {
  font: inherit;
  font-size: 12px;
  padding: 4px 6px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: #fffdf7;
  color: var(--ink);
  min-width: 0;
}
.rel-fields input { width: 68px; }
.rel-fields select:focus,
.rel-fields input:focus { outline: none; border-color: var(--gold); background: #fff; }

.toc-export {
  margin: 10px 0 4px;
  padding-top: 9px;
  border-top: 1px solid var(--line-soft);
  font-size: 11.5px;
  color: var(--ink-faint);
}
.link-btn {
  font: inherit;
  font-size: 11.5px;
  padding: 0;
  border: none;
  background: none;
  color: var(--walnut);
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}
.link-btn:hover { color: var(--walnut-dk); }
.toc-export .dot { margin: 0 5px; }

/* ------------------------------------------------------ printing a life */

.print-root { display: none; }

@media print {
  /* Only the chapters go on paper. */
  body.printing > *:not(.print-root) { display: none !important; }
  body.printing {
    display: block;
    overflow: visible;
    background: #fff;
  }
  body.printing .print-root {
    display: block;
    font-family: var(--serif);
    color: #1c1a17;
    max-width: 100%;
  }
  .pr-head { margin-bottom: 28px; }
  .pr-head h1 { font-size: 26pt; font-weight: 500; margin: 0 0 6px; }
  .pr-sub { margin: 0 0 8px; font-size: 10pt; color: #555; letter-spacing: .03em; }
  .pr-known { margin: 0; font-size: 11pt; font-style: italic; color: #333; }

  .pr-chapter {
    /* Never split a chapter heading from the paragraph it belongs to. */
    break-inside: avoid-page;
    margin-bottom: 22px;
  }
  .pr-chapter h2 {
    font-size: 15pt;
    font-weight: 500;
    margin: 0 0 3px;
    break-after: avoid-page;
  }
  .pr-when {
    margin: 0 0 10px;
    font-family: var(--ui);
    font-size: 9pt;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: #777;
    break-after: avoid-page;
  }
  .pr-body { font-size: 11.5pt; line-height: 1.65; }
  .pr-body p { margin: 0 0 10px; }
  .pr-foot {
    margin-top: 30px;
    padding-top: 10px;
    border-top: 1px solid #ccc;
    font-size: 9pt;
    color: #777;
  }
  @page { margin: 20mm 18mm; }
}

/* ----------------------------------------------------- the empty board */

/* Hidden by default; FT.render adds .board-empty to <body> when the open tree
   has nobody in it. Deliberately not tied to what is on screen — someone who
   has panned away from their tree still has a tree. */
.empty-state {
  position: absolute;
  inset: 0;
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  padding: 24px;
  text-align: center;
  /* The board underneath stays draggable; only the two actions take clicks. */
  pointer-events: none;
}
body.board-empty .empty-state { display: flex; }

.empty-mark { color: var(--line); margin-bottom: 14px; }

.empty-lead {
  margin: 0;
  font-family: var(--serif);
  font-size: 19px;
  line-height: 1.45;
  color: var(--ink);
  max-width: 30ch;
}
.empty-sub {
  margin: 0 0 22px;
  font-size: 13.5px;
  /* The strongest thing this app has to say — not a footnote. */
  color: var(--ink-soft);
}

/* Two deliberate lines rather than one wrapping sentence: an inline button
   makes line breaking unpredictable, and at some widths it stranded two words
   on a line of their own. */
.empty-actions {
  display: flex;
  align-items: center;
  gap: 9px;
  margin: 0 0 10px;
  font-size: 13.5px;
  color: var(--ink-soft);
}
.empty-alt {
  margin: 0;
  font-size: 13px;
  color: var(--ink-faint);
  max-width: 40ch;
  line-height: 1.7;
}

/* The words you read are the things you click, so nothing has to describe
   where a button lives — a claim that would go stale as the bar reflows. */
.empty-btn,
.empty-link {
  font: inherit;
  cursor: pointer;
  pointer-events: auto;
  white-space: nowrap;
}
.empty-btn {
  padding: 6px 13px;
  border-radius: 8px;
  border: 1px solid var(--walnut-dk);
  background: linear-gradient(180deg, #9c6440, var(--walnut));
  color: #fdf8ef;
  box-shadow: 0 1px 3px rgba(58,44,28,.16);
}
.empty-btn:hover { background: linear-gradient(180deg, #a86e47, #7c4d31); }
.empty-btn:active { transform: translateY(1px); }

.empty-link {
  padding: 0;
  border: none;
  background: none;
  color: var(--walnut);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.empty-link:hover { color: var(--walnut-dk); }

.empty-btn:focus-visible,
.empty-link:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; }

@media (max-width: 600px) {
  .empty-lead { font-size: 17px; }
}
