    body { overflow: hidden; }
    v-screen { display: flex; flex-direction: column; height: 100dvh; }

    /* ── trees view — reached from the menu, not a startup gate: a bento
       grid, one tile per tree, its cover the most recently uploaded photo
       — ─────────────────────────────────────────────────────────────── */
    #projectGrid { margin-top: var(--l-sp-md); }
    #projectGrid ltile[data-empty] { background: var(--l-surface); border: 1px solid var(--l-border); aspect-ratio: 4/3; }
    #newProjectBtn { margin-top: var(--l-sp-lg); background: #111; color: #fff; border: none; border-radius: 12px; padding: var(--l-sp-sm) var(--l-sp-md); font-family: var(--l-font-label); font-weight: 400; font-size: var(--l-fs-sm); cursor: pointer; }

    /* ── gallery screen ───────────────────────────────────────────── */

    /* ── tree screen — kin's workflow: one pannable canvas, freeform node
       positions, a bottom dock (add-photo + unassigned-people tray), and a
       full-screen studio for cropping faces out of a photo. Ported from
       sites/p/kin (a Gemini Gem app the user pointed at as "much cleaner"),
       adapted to vamsa's ns/ls fact-line graph instead of kin's own plain
       nodes/links arrays, and to persisted photos+tags (so the person
       gallery and re-visiting a photo for more faces both still work —
       kin itself discards the source photo after each snap). ──────────── */
    /* Fixed light theme for the tree screen — matching sites/p/kin's own
       actual look exactly (it has no dark mode), rather than following
       laya's --l-bg/--l-fg system-theme tokens like the rest of the app.
       That mismatch was a real bug, not just a preference: the topbar's
       white icons/text were designed for a dark photo backdrop that no
       longer exists once the canvas itself is plain white — invisible
       white-on-white until a photo/node gave enough contrast to notice. */
    #screenTree { overscroll-behavior: none; position: relative; overflow: hidden; touch-action: none; background: #fdfdfd; -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; -webkit-tap-highlight-color: transparent; }
    /* One persistent bar for both views (canvas AND studio) — Back is the
       single, always-reachable way out of studio, so this needs to float
       above the studio overlay (z-index 200), not sit behind it. A frosted
       background (not transparent) keeps it legible over both the white
       canvas and the dark studio. */
    #treeBar { position: fixed; top: 0; left: 0; right: 0; z-index: 240; display: flex; align-items: center; gap: var(--l-gap-xs); padding: max(var(--l-sp-sm), env(safe-area-inset-top)) var(--l-sp-md) var(--l-sp-sm); background: rgba(255,255,255,.85); backdrop-filter: blur(20px); border-bottom: 1px solid rgba(0,0,0,.06); }
    #treeBar button { width: 46px; height: 46px; border-radius: 50%; border: none; background: none; color: #111; display: flex; align-items: center; justify-content: center; cursor: pointer; flex-shrink: 0; transition: transform .15s var(--l-spring); }
    #treeBar button:active { transform: scale(.9); }
    #treeBar button svg { width: 24px; height: 24px; stroke: currentColor; fill: none; stroke-width: 2; }
    #viewBannerText { font: 600 14px var(--l-font-label); color: #111; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    #treePeopleBtn svg { width: 16px; height: 16px; }

    ltreecanvas { position: absolute; top: 0; left: 0; width: 0; height: 0; overflow: visible; transform-origin: 0 0; }
    .treelines { position: absolute; top: 0; left: 0; width: 1px; height: 1px; overflow: visible; pointer-events: none; }
    .tree-connector { fill: none; stroke: var(--tree-line); stroke-width: 1.75px; stroke-linecap: round; stroke-linejoin: round; }
    .tree-junction { fill: var(--tree-line); stroke: none; }
    .tree-connector.spouse { stroke-dasharray: 4 3; }
    #nodesLayer { position: absolute; top: 0; left: 0; }

    /* Empty tree: a looping picture of the whole product — a group photo whose faces lift out
       and arrange themselves into a tree. No words. (Origin = where the first person lands.) */
    lemptyprompt { position: absolute; left: 0; top: 0; width: 0; height: 0; pointer-events: none; }
    .ep-svg { position: absolute; left: -100px; top: -140px; overflow: visible; }
    .ep-card { fill: #fafafa; stroke: #d9d9df; stroke-width: 2; }
    .ep-src { fill: #d9d9df; }
    .ep-fly { fill: #a1a1aa; opacity: 0; transform-box: fill-box; transform-origin: center; animation: epFly 5s cubic-bezier(.3,.7,.2,1) infinite; }
    .ep-fly.f1 { animation-delay: .18s; } .ep-fly.f3 { animation-delay: .36s; }
    .ep-line { fill: none; stroke: #c2c3cb; stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; stroke-dasharray: 1; stroke-dashoffset: 1; animation: epLine 5s ease-in-out infinite; }
    @keyframes epFly {
      0%, 6% { transform: translate(var(--dx), var(--dy)) scale(.85); opacity: 0; }
      12% { transform: translate(var(--dx), var(--dy)) scale(1.15); opacity: 1; }
      52% { transform: translate(0, 0) scale(1.12); opacity: 1; }
      58% { transform: translate(0, 0) scale(.96); }
      64%, 88% { transform: translate(0, 0) scale(1); opacity: 1; }
      96%, 100% { transform: translate(0, 0) scale(1); opacity: 0; }
    }
    @keyframes epLine { 0%, 60% { stroke-dashoffset: 1; opacity: 1; } 76%, 90% { stroke-dashoffset: 0; opacity: 1; } 98%, 100% { stroke-dashoffset: 0; opacity: 0; } }
    /* Faces waiting in the tray, nobody placed yet: show the landing spot instead. */
    ldropcircle { display: none; position: absolute; left: -50px; top: -50px; width: 100px; height: 100px; border-radius: 50%; border: 2px dashed #111; }
    lemptyprompt[data-tray] .ep-svg { display: none; }
    lemptyprompt[data-tray] ldropcircle { display: block; animation: epPulse 1.6s ease-in-out infinite; }
    @keyframes epPulse { 0%, 100% { transform: scale(1); opacity: .35; } 50% { transform: scale(1.09); opacity: .95; } }
    @media (prefers-reduced-motion: reduce) { .ep-fly { animation: none; opacity: 1; transform: none; } .ep-line { animation: none; stroke-dashoffset: 0; } lemptyprompt[data-tray] ldropcircle { animation: none; opacity: .8; } }

    /* Only the photo circle is draggable: the node box itself is click-through
       (its label sits wider than the photo), and lface opts back in. */
    lnode { position: absolute; display: flex; flex-direction: column; align-items: center; transform: translate(-50%, -50%); pointer-events: none; z-index: 10; transition: opacity .15s, transform .45s var(--l-spring); }
    lnode lface { pointer-events: auto; cursor: grab; touch-action: none; }
    lnode lface:active { cursor: grabbing; }
    lnode lnamelabel { pointer-events: auto; }
    lnode[data-dragging] { opacity: .25; }
    lface { display: block; width: 68px; height: 68px; border-radius: 50%; overflow: hidden; box-shadow: 0 4px 14px rgba(0,0,0,.12); transition: transform .18s var(--l-spring), box-shadow .18s; background: #eee; }
    lface img { width: 100%; height: 100%; object-fit: cover; display: block; pointer-events: none; }
    lface[data-g="m"] { box-shadow: 0 0 0 2.5px #bfdbfe, 0 4px 14px rgba(0,0,0,.12); }
    lface[data-g="f"] { box-shadow: 0 0 0 2.5px #fbcfe8, 0 4px 14px rgba(0,0,0,.12); }
    lface .mono { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; font-family: var(--l-font-display); font-weight: var(--l-fw-bold); font-size: var(--l-fs-md); color: #999; background: #f5f5f5; }
    /* Handwritten-feel name label, matching kin exactly. */
    lnamelabel { display: block; margin-top: 4px; font-family: 'Caveat', 'Patrick Hand', cursive, sans-serif; font-size: 20px; font-weight: 600; line-height: 1.1; color: #111; text-align: center; padding: 1px 4px; border-bottom: 1.5px solid transparent; outline: none; cursor: pointer; background: transparent; white-space: nowrap; max-width: 100px; overflow: hidden; text-overflow: ellipsis; transition: border-color .15s; }
    /* Each lnode is its own stacking context, so a hint inside an earlier
       node used to paint BEHIND later nodes' photos. Lifting the hovered
       node above all siblings puts its tag on top of everything. */
    lnode[data-hover-node] { z-index: 60; }
    lnode[data-enter] lface { animation: nodePop .5s var(--l-spring, cubic-bezier(.34,1.56,.64,1)) .05s backwards; }
    lnode[data-enter] lnamelabel { animation: nodeFade .4s ease-out .2s backwards; }
    lnode[data-fly] lnamelabel { animation: nodeFade .4s ease-out .25s backwards; }
    [data-enter].tree-connector.spouse { animation: nodeFade .5s ease-out .2s backwards; }
    path[data-enter].tree-connector:not(.spouse) { stroke-dasharray: 1; animation: lineDraw .6s cubic-bezier(.4,0,.2,1) .2s backwards; }
    [data-enter].tree-junction { transform-box: fill-box; transform-origin: center; animation: dotPop .5s var(--l-spring, cubic-bezier(.34,1.56,.64,1)) .45s backwards; }
    @keyframes lineDraw { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
    @keyframes dotPop { from { transform: scale(0); } to { transform: scale(1); } }
    @keyframes nodePop { from { transform: scale(.6); opacity: 0; } to { transform: scale(1); opacity: 1; } }
    @keyframes nodeFade { from { opacity: 0; } to { opacity: 1; } }
    @media (prefers-reduced-motion: reduce) { lnode[data-enter] lface, lnode[data-enter] lnamelabel, lnode[data-fly] lnamelabel, [data-enter].tree-connector, [data-enter].tree-junction { animation: none; } path[data-enter].tree-connector:not(.spouse) { stroke-dasharray: none; } #relBud { display: none; } }

    ldock { position: fixed; left: 0; right: 0; bottom: 0; height: 112px; background: rgba(255,255,255,.94); backdrop-filter: blur(24px); border-top: 1px solid #eee; display: flex; align-items: center; z-index: 300; padding: 0 var(--l-sp-sm) env(safe-area-inset-bottom); transition: background .2s, border-color .2s; }
    ldock[data-hover-trash] { background: rgba(254,226,226,.95); border-top-color: #ef4444; }
    ltrayslider { display: flex; align-items: center; gap: var(--l-gap-sm); overflow-x: auto; overflow-y: hidden; height: 100%; width: 100%; padding: 0 var(--l-sp-sm); touch-action: pan-x; scrollbar-width: none; }
    ltrayslider::-webkit-scrollbar { display: none; }
    laddbtn { flex: 0 0 auto; width: 62px; height: 62px; border-radius: 50%; border: 2px dashed #bbb; background: #fff; display: flex; align-items: center; justify-content: center; cursor: pointer; transition: border-color .15s, transform .15s var(--l-spring); }
    laddbtn:active { transform: scale(.92); border-color: #111; }
    laddbtn svg { width: 24px; height: 24px; stroke: #111; }
    ltrayitem { position: relative; flex: 0 0 auto; cursor: grab; touch-action: pan-x; }
    .tray-x { position: absolute; top: -2px; right: -2px; width: 22px; height: 22px; border-radius: 50%; border: 2px solid #fff; padding: 0; background: #111; color: #fff; font-size: 9px; line-height: 1; display: flex; align-items: center; justify-content: center; cursor: pointer; z-index: 2; box-shadow: 0 2px 6px rgba(0,0,0,.25); }
    .tray-x:active { background: #dc2626; }
    ltrayitem:active { cursor: grabbing; }
    ltrayitem lface { width: 58px; height: 58px; box-shadow: 0 4px 12px rgba(0,0,0,.1); }
    ltrayitem:active lface { transform: scale(1.08); }
    ltrayitem[data-newperson] lface { border: 2px dashed #b8b8c0; box-shadow: none; background: #fff; }
    ltrayitem[data-newperson] lface img { opacity: .75; }
    ltrayitem[data-new] lface { animation: trayPop .55s var(--l-spring, cubic-bezier(.34,1.56,.64,1)), trayWiggle .7s ease-in-out .6s; }
    @keyframes trayPop { from { transform: scale(.2) translateY(-34px); opacity: 0; } to { transform: none; opacity: 1; } }
    @keyframes trayWiggle { 0%, 100% { transform: rotate(0); } 25% { transform: rotate(-9deg); } 50% { transform: rotate(7deg); } 75% { transform: rotate(-4deg); } }
    @media (prefers-reduced-motion: reduce) { ltrayitem[data-new] lface { animation: none; } }

    #dragGhost { position: fixed; top: 0; left: 0; width: 68px; height: 68px; border-radius: 50%; overflow: hidden; pointer-events: none; z-index: 1000; transform: translate(-50%, -50%) scale(1.16); display: none; box-shadow: 0 16px 34px rgba(0,0,0,.3); animation: ghostLift .24s var(--l-spring, cubic-bezier(.34,1.56,.64,1)); }
    @keyframes ghostLift { from { transform: translate(-50%, -50%) scale(1); box-shadow: 0 4px 14px rgba(0,0,0,.12); } to { transform: translate(-50%, -50%) scale(1.16); box-shadow: 0 16px 34px rgba(0,0,0,.3); } }
    @media (prefers-reduced-motion: reduce) { #dragGhost { animation: none; } }
    #dragGhost img { width: 100%; height: 100%; object-fit: cover; }

    /* Liquid layer: a filtered SVG (blur + alpha threshold = the classic goo
       trick) ABOVE the canvas but below the bars/dock/dragged photo. The
       target photo is masked out of it, so what shows is a halo, the neck
       stretching to the dragged photo, and the relationship "bud" growing
       out of the photo. All of it is spring-driven from JS (gooFrame). */
    #gooLayer { position: fixed; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: 310; }
    #gooGroup { fill: #111; transition: fill .22s ease; }
    #relBud { position: fixed; left: 0; top: 0; z-index: 311; display: flex; align-items: center; height: 26px; padding: 0 14px; font-family: var(--l-font-label); font-size: 12px; font-weight: 400; letter-spacing: .08em; text-transform: uppercase; color: #fff; white-space: nowrap; pointer-events: none; opacity: 0; will-change: transform, opacity; }
    .goo-pop { position: fixed; z-index: 312; border-radius: 50%; border: 2px solid var(--pop, #111); pointer-events: none; animation: gooRing .62s cubic-bezier(.2,.7,.3,1) forwards; }
    @keyframes gooRing { from { transform: scale(.85); opacity: .75; } to { transform: scale(2.3); opacity: 0; } }

    /* ── studio — pan/zoom a photo under a fixed circular viewfinder, tap
       to snap a face straight into the tray. ─────────────────────────── */
    lstudio { display: flex; flex-direction: column; position: fixed; top: 0; left: 0; right: 0; bottom: 112px; background: #0a0a0a; z-index: 200; touch-action: none; }
    lstudio[hidden] { display: none !important; }
    lstudiostage { position: absolute; inset: 0; overflow: hidden; touch-action: none; }
    #studioImgWrap { position: absolute; top: 0; left: 0; transform-origin: 0 0; will-change: transform; pointer-events: none; }
    #studioImg { display: block; user-select: none; pointer-events: none; }
    lviewfinder { position: absolute; top: 50%; left: 50%; width: 180px; height: 180px; transform: translate(-50%, -50%); border-radius: 50%; border: 3.5px solid #fff; box-shadow: 0 0 0 9999px rgba(0,0,0,.6), 0 0 30px rgba(0,0,0,.75); pointer-events: auto; cursor: pointer; z-index: 210; display: flex; align-items: center; justify-content: center; }
    lstudio:not([data-snapped]) lviewfinder { outline: 2px solid transparent; animation: vfBreathe 2.6s ease-in-out infinite, vfRipple 2.6s ease-out infinite; }
    @keyframes vfBreathe { 0%, 100% { scale: 1; } 50% { scale: 1.035; } }
    @keyframes vfRipple { 0% { outline-color: rgba(255,255,255,.75); outline-offset: 2px; } 70%, 100% { outline-color: rgba(255,255,255,0); outline-offset: 30px; } }
    lstudio[data-snapped] ltaptip { display: none; }
    @media (prefers-reduced-motion: reduce) { lstudio:not([data-snapped]) lviewfinder { animation: none; } }
    lviewfinder:active { transform: translate(-50%, -50%) scale(.93); border-color: #60a5fa; }
    lviewfinder::before { content: ''; position: absolute; inset: -12px; border-radius: 50%; border: 1.5px dashed rgba(255,255,255,.6); animation: rotateGuide 20s linear infinite; }
    /* Light resize hint — a plain tick on the circle's edge, same color/
       weight as the dashed ring, pinch-to-resize here. */
    lviewfinder::after { content: ''; position: absolute; top: 50%; right: -14px; width: 2px; height: 22px; background: rgba(255,255,255,.6); border-radius: 2px; transform: translateY(-50%); }
    @keyframes rotateGuide { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
    /* Sibling of lviewfinder now, not a child — sits just below the circle
       so the hint text never covers the framed photo content. */
    ltaptip { position: absolute; top: calc(50% + 112px); left: 50%; transform: translateX(-50%); display: flex; align-items: center; gap: 6px; background: rgba(0,0,0,.65); backdrop-filter: blur(8px); border: 1px solid rgba(255,255,255,.35); color: #fff; font-family: var(--l-font-label); font-size: 11px; font-weight: 400; letter-spacing: .08em; text-transform: uppercase; padding: 5px 12px; border-radius: 99px; pointer-events: none; box-shadow: 0 4px 12px rgba(0,0,0,.5); z-index: 210; }
    ltaptip svg { width: 14px; height: 14px; fill: none; stroke: #fff; stroke-width: 2.2; }
    #snapFlash { position: absolute; inset: 0; background: #fff; opacity: 0; pointer-events: none; z-index: 300; }
    #snapFlash[data-flash] { opacity: .9; transition: opacity .15s ease-out; }


    /* undo / redo / toast */
    #treeBar button:disabled { opacity: .28; pointer-events: none; }
    #toast { position: fixed; left: 50%; bottom: calc(112px + 14px + env(safe-area-inset-bottom, 0px)); transform: translateX(-50%); z-index: 360; display: flex; align-items: center; gap: 14px; max-width: calc(100vw - 32px); padding: 10px 10px 10px 18px; border-radius: 99px; background: rgba(17,17,17,.94); color: #fff; font: 400 14px var(--l-font-label); box-shadow: 0 10px 30px rgba(0,0,0,.25); }
    #toast[hidden] { display: none; }
    #toast.in { animation: toastIn .28s var(--l-spring, cubic-bezier(.34,1.56,.64,1)); }
    @keyframes toastIn { from { transform: translateX(-50%) translateY(14px); opacity: 0; } to { transform: translateX(-50%); opacity: 1; } }
    #toast .ttext { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
    #toast button { border: none; border-radius: 99px; padding: 7px 14px; background: #fff; color: #111; font: 400 13px var(--l-font-label); cursor: pointer; }
    .ghostRow { display: flex; gap: 8px; flex-wrap: wrap; }
    .ghostRow button { border: none; background: none; color: #111; opacity: .6; font: 400 var(--l-fs-sm, 13px) var(--l-font-label); padding: 8px 4px; cursor: pointer; text-decoration: underline; text-underline-offset: 3px; }

    /* teach-in-context: one small card at a time, plus faint drop-zone guides */
    #coach { position: fixed; left: 50%; bottom: calc(112px + 10px + env(safe-area-inset-bottom, 0px)); transform: translateX(-50%); z-index: 320; width: max-content; max-width: min(360px, calc(100vw - 24px)); display: flex; align-items: center; gap: 8px; padding: 8px 8px 8px 14px; border-radius: 99px; background: rgba(255,255,255,.96); backdrop-filter: blur(20px); border: 1px solid rgba(0,0,0,.08); box-shadow: 0 8px 26px rgba(0,0,0,.14); animation: coachIn .3s var(--l-spring, cubic-bezier(.34,1.56,.64,1)); }
    #coach[hidden] { display: none; }
    #coach { pointer-events: none; }
    #coach .cbtns { pointer-events: auto; }
    @keyframes coachIn { from { transform: translateX(-50%) translateY(10px); opacity: 0; } to { transform: translateX(-50%); opacity: 1; } }
    #coach .cmain { flex: 1; min-width: 0; font: 400 13px/1.3 var(--l-font-label); color: #555; }
    #coach .ctitle { display: inline; margin-right: 5px; font-weight: 400; color: #111; }
    #coach .ctext { display: inline; }
    #coach .cbtns { display: flex; align-items: center; gap: 6px; }
    #coach .cbtns button { border: none; border-radius: 99px; cursor: pointer; white-space: nowrap; font: 400 12px var(--l-font-label); }
    #coachOk { width: 26px; height: 26px; padding: 0; background: #f1f1f3; color: #777; font-size: 11px !important; }
    #coachAction { padding: 7px 12px; background: #111; color: #fff; }
    #coach .cdemo:empty { display: none; }
    .coach-pulse { animation: coachPulse 1.5s ease-out infinite; }
    @keyframes coachPulse { 0% { box-shadow: 0 0 0 0 rgba(17,17,17,.35); } 100% { box-shadow: 0 0 0 16px rgba(17,17,17,0); } }
    #coachHand { position: fixed; left: 0; top: 0; z-index: 321; width: 58px; height: 58px; border-radius: 50%; background: #fff; border: 3px solid #111; box-shadow: 0 12px 28px rgba(0,0,0,.25); pointer-events: none; animation: coachDrag 2.6s ease-in-out infinite; }
    #coachHand[hidden] { display: none; }
    @keyframes coachDrag {
      0% { transform: translate(calc(var(--x0) * 1px), calc(var(--y0) * 1px)) translate(-50%, -50%) scale(1); opacity: 0; }
      10% { opacity: 1; }
      22% { transform: translate(calc(var(--x0) * 1px), calc(var(--y0) * 1px)) translate(-50%, -50%) scale(1.16); }
      72% { transform: translate(calc(var(--x1) * 1px), calc(var(--y1) * 1px)) translate(-50%, -50%) scale(1.16); opacity: 1; }
      90%, 100% { transform: translate(calc(var(--x1) * 1px), calc(var(--y1) * 1px)) translate(-50%, -50%) scale(1); opacity: 0; }
    }
    .zone-ghost { position: fixed; left: 0; top: 0; z-index: 309; padding: 3px 11px; border-radius: 99px; border: 1.5px dashed var(--zc, #999); color: var(--zc, #999); background: rgba(255,255,255,.92); font: 400 11px var(--l-font-label); letter-spacing: .07em; text-transform: uppercase; white-space: nowrap; pointer-events: none; opacity: 0; transition: opacity .18s; }
    #helpSheet { position: fixed; inset: 0; z-index: 500; display: flex; align-items: center; justify-content: center; padding: 20px; background: rgba(0,0,0,.4); backdrop-filter: blur(4px); }
    #helpSheet[hidden] { display: none; }
    #helpSheet .hcard { width: min(420px, 100%); max-height: 86dvh; overflow-y: auto; padding: 22px; border-radius: 22px; background: #fff; box-shadow: 0 24px 60px rgba(0,0,0,.3); animation: coachIn .3s var(--l-spring, cubic-bezier(.34,1.56,.64,1)); transform: none; }
    #helpSheet h3 { font: 800 20px var(--l-font-display); color: #111; margin-bottom: 10px; }
    #helpSheet ul { list-style: none; display: flex; flex-direction: column; gap: 10px; }
    #helpSheet li { font: 400 14px/1.4 var(--l-font-label); color: #444; }
    #helpSheet li b { color: #111; }
    #helpSheet .hbtns { display: flex; justify-content: space-between; margin-top: 18px; }
    #helpSheet .hbtns button { border: none; border-radius: 99px; padding: 10px 18px; font: 400 14px var(--l-font-label); cursor: pointer; }
    #helpReplay { background: #f1f1f3; color: #111; }
    #helpClose { background: #111; color: #fff; }
    @media (prefers-reduced-motion: reduce) { #coach, #toast.in, #helpSheet .hcard { animation: none; } .coach-pulse, #coachHand { animation: none; } #coachHand { display: none; } }

    /* person sheet: tap anyone, edit right there */
    #personSheet, .sheet { position: fixed; inset: 0; z-index: 340; display: flex; align-items: flex-end; justify-content: center; background: rgba(0,0,0,.28); animation: sheetFade .2s ease-out; }
    #personSheet[hidden], .sheet[hidden] { display: none; }
    @keyframes sheetFade { from { opacity: 0; } to { opacity: 1; } }
    .sheet .ps-card, #personSheet .ps-card { width: min(520px, 100%); max-height: 86dvh; overflow-y: auto; touch-action: pan-y; display: flex; flex-direction: column; gap: 12px; padding: 18px 18px calc(16px + env(safe-area-inset-bottom, 0px)); background: #fff; color: #111; border-radius: 24px 24px 0 0; box-shadow: 0 -12px 40px rgba(0,0,0,.18); animation: sheetUp .32s var(--l-spring, cubic-bezier(.34,1.56,.64,1)); }
    @keyframes sheetUp { from { transform: translateY(44px); opacity: 0; } to { transform: none; opacity: 1; } }
    .ps-head { display: flex; align-items: center; gap: 12px; }
    .ps-avatar-wrap { position: relative; flex: 0 0 auto; }
    #psAvatar { width: 64px; height: 64px; border-radius: 50%; overflow: hidden; background: #f1f1f3; display: flex; align-items: center; justify-content: center; font: 800 24px var(--l-font-display); color: #999; }
    #psAvatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
    /* Removing THIS (not a source photo — those delete freely) is the one deliberate way a
       profile picture is lost; see assignPersonAvatar()/#psAvatarDel's click handler. */
    #psAvatarDel { position: absolute; top: -2px; right: -2px; width: 22px; height: 22px; border-radius: 50%; border: 2px solid #fff; padding: 0; background: #111; color: #fff; font-size: 9px; line-height: 1; display: flex; align-items: center; justify-content: center; cursor: pointer; box-shadow: 0 2px 6px rgba(0,0,0,.25); }
    #psAvatarDel:active { background: #dc2626; }
    .ps-id { flex: 1; min-width: 0; display: flex; flex-direction: column; }
    #psName { -webkit-user-select: text; user-select: text; width: 100%; border: none; border-bottom: 1.5px solid transparent; background: transparent; font: 800 20px var(--l-font-display); color: #111; outline: none; padding: 2px 0; border-radius: 0; transition: border-color .15s; }
    #psName:focus { border-bottom-color: #111; }
    #psRel { font: 400 12.5px/1.3 var(--l-font-label); color: #8a8a8a; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .ps-x { flex: 0 0 auto; width: 30px; height: 30px; border: none; border-radius: 50%; background: #f1f1f3; color: #777; font-size: 12px; cursor: pointer; }
    .ps-note { position: relative; }
    #psNote { -webkit-user-select: text; user-select: text; width: 100%; min-height: 84px; padding: 12px 14px; border-radius: 14px; border: 1px solid #e4e4e7; background: #fafafa; font: 500 15px/1.4 var(--l-font-body, system-ui, sans-serif); color: #111; resize: none; outline: none; transition: border-color .15s, background .15s; }
    #psNote:focus { border-color: #111; background: #fff; }
    #psMem { display: flex; gap: 8px; overflow-x: auto; padding: 2px 0 4px; touch-action: pan-x; }
    #psMem[hidden] { display: none; }
    #psMem .mem-add { background: #f1f1f3; color: #555; font-size: 26px; font-weight: 300; line-height: 1; display: flex; align-items: center; justify-content: center; border: 2px dashed #c9c9d0; }
    #psMem .mem-add.open { background: #111; color: #fff; border-color: #111; }
    #psPool { display: flex; gap: 8px; overflow-x: auto; padding: 10px; border-radius: 14px; background: #f6f6f8; touch-action: pan-x; }
    #psPool .pool-tile { flex: 0 0 auto; width: 54px; height: 54px; padding: 0; border: none; border-radius: 50%; overflow: hidden; background: #eee; cursor: pointer; transition: transform .15s var(--l-spring); }
    #psPool .pool-tile:active { transform: scale(.92); }
    #psPool img { width: 100%; height: 100%; object-fit: cover; display: block; }
    .pool-empty { display: flex; align-items: center; justify-content: space-between; gap: 10px; width: 100%; font: 400 13px var(--l-font-label); color: #8a8a8a; }
    .pool-empty button { border: none; border-radius: 99px; padding: 8px 14px; background: #111; color: #fff; font: 400 12px var(--l-font-label); cursor: pointer; }
    #psMemHint { font: 400 12px var(--l-font-label); color: #8a8a8a; margin-top: -6px; }
    #psMemHint[hidden], #psPool[hidden] { display: none; }
    #psMem button { flex: 0 0 auto; position: relative; width: 54px; height: 54px; border: none; padding: 0; border-radius: 12px; overflow: hidden; background: #eee; cursor: pointer; transition: transform .15s var(--l-spring); }
    #psMem button:active { transform: scale(.94); }
    #psMem img { width: 100%; height: 100%; object-fit: cover; display: block; }
    #psMem button[data-current]::after { content: '✓'; position: absolute; right: 3px; top: 3px; width: 18px; height: 18px; border-radius: 50%; background: #111; color: #fff; font: 400 10px/18px system-ui, sans-serif; text-align: center; }
    .ps-gender { display: flex; gap: 8px; }
    .ps-gender button { border: none; border-radius: 99px; padding: 8px 16px; background: #f1f1f3; color: #555; font: 400 13px var(--l-font-label); cursor: pointer; transition: background .15s, color .15s, transform .15s var(--l-spring); }
    .ps-gender button:active { transform: scale(.95); }
    .ps-gender button[data-g="m"].on { background: #dbeafe; color: #1d4ed8; }
    .ps-gender button[data-g="f"].on { background: #fce7f3; color: #be185d; }
    #psRels { display: flex; flex-direction: column; gap: 8px; }
    .rel { position: relative; display: flex; align-items: center; gap: 10px; height: 58px; padding: 0 10px 0 14px; border-radius: 23px; background: #f1f1f3; overflow: hidden; -webkit-user-select: none; user-select: none; transition: height .24s ease, margin .24s ease, opacity .2s ease, background .2s; }
    .rel .rel-text { position: relative; z-index: 1; flex: 1; min-width: 0; font: 400 14px var(--l-font-label); color: #333; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
    .rel[data-static] { background: transparent; height: auto; padding: 2px 4px; }
    .rel[data-static] .rel-text { font-weight: 400; color: #8a8a8a; font-size: 13px; }
    .rel-child { padding-left: 38px; }
    .rel-grip { position: absolute; left: 6px; top: 0; bottom: 0; width: 30px; display: flex; align-items: center; justify-content: center; color: #b0b0b6; font-size: 20px; cursor: grab; touch-action: none; z-index: 3; }
    .rel-grip:active { cursor: grabbing; }
    /* Delete: a plain ✕ pinned to the row's right edge (replaces the old swipe-to-remove
       gesture — one tap is more discoverable and doesn't fight the sheet's own scroll). */
    .rel-del { flex: 0 0 auto; width: 32px; height: 32px; border: none; border-radius: 50%; background: #fff; color: #8a8a8a; font-size: 13px; display: flex; align-items: center; justify-content: center; cursor: pointer; transition: background .15s, color .15s, transform .15s var(--l-spring); }
    .rel-del:active { background: #fee2e2; color: #dc2626; transform: scale(.9); }
    .rel.sorting { z-index: 6; background: #fff; box-shadow: 0 10px 26px rgba(0,0,0,.2); transition: none; }
    .rel-avs { position: relative; z-index: 1; display: flex; flex: 0 0 auto; margin-right: 9px; }
    .rel-av { width: 42px; height: 42px; border-radius: 50%; overflow: hidden; background: #dcdce2; border: 2px solid #f1f1f3; color: #8a8a8a; display: flex; align-items: center; justify-content: center; font: 800 17px var(--l-font-display); }
    .rel-av + .rel-av { margin-left: -14px; }
    .rel-av img { width: 100%; height: 100%; object-fit: cover; display: block; }
    .rel-empty { font: 400 13px var(--l-font-label); color: #8a8a8a; padding: 2px 4px; }
    .ps-foot { display: flex; align-items: center; gap: 16px; }
    #psAdd, #psHow { border: none; background: none; color: #111; font: 400 13px var(--l-font-label); cursor: pointer; padding: 6px 2px; }
    #psDelete { border: none; background: none; color: #dc2626; font: 400 13px var(--l-font-label); cursor: pointer; padding: 6px 2px; }
    @media (prefers-reduced-motion: reduce) { #personSheet, .sheet, .sheet .ps-card, #personSheet .ps-card { animation: none; } }

    /* outline, type-to-add, how-related */
    .ol-node { margin: 2px 0 2px 14px; padding-left: 12px; border-left: 1.5px solid #e4e4e7; }
    #outlineList > .ol-node { margin-left: 0; border-left: none; padding-left: 0; }
    .ol-row { display: flex; align-items: center; flex-wrap: wrap; gap: 2px 8px; min-height: 40px; }
    .ol-tog { width: 24px; height: 24px; border: none; background: none; color: #999; font-size: 12px; cursor: pointer; padding: 0; }
    .ol-tog[disabled] { visibility: hidden; }
    .ol-av { flex: 0 0 auto; width: 30px; height: 30px; border-radius: 50%; overflow: hidden; background: #e4e4e7; color: #8a8a8a; display: inline-flex; align-items: center; justify-content: center; font: 800 12px var(--l-font-display); }
    .ol-av img { width: 100%; height: 100%; object-fit: cover; display: block; }
    .ol-name, .ol-sp { display: inline-flex; align-items: center; gap: 8px; }
    .ol-name { border: none; background: none; font: 400 16px var(--l-font-label); color: #111; padding: 7px 8px; border-radius: 9px; cursor: pointer; text-align: left; }
    .ol-name:active, .ol-sp:active { background: #f1f1f3; }
    .ol-sp { border: none; background: none; font: 400 14px var(--l-font-label); color: #8a8a8a; padding: 6px 6px; border-radius: 9px; cursor: pointer; }
    .ol-sp::before { content: '+ '; }
    .ol-node.collapsed > .ol-kids { display: none; }
    .sh-title { font: 800 18px var(--l-font-display); color: #111; }
    .q-row { display: flex; align-items: center; gap: 10px; font: 400 13px var(--l-font-label); color: #8a8a8a; }
    .sheet select { -webkit-user-select: text; user-select: text; flex: 1; min-width: 0; height: 44px; padding: 0 12px; border-radius: 12px; border: 1px solid #e4e4e7; background: #fafafa; font: 400 15px var(--l-font-label); color: #111; outline: none; }
    #qInput { -webkit-user-select: text; user-select: text; width: 100%; padding: 13px 14px; border-radius: 14px; border: 1px solid #e4e4e7; background: #fafafa; font: 400 16px var(--l-font-label); color: #111; outline: none; }
    #qInput:focus { border-color: #111; background: #fff; }
    .q-chips { display: flex; gap: 6px; flex-wrap: wrap; }
    .q-chips button { border: none; border-radius: 99px; padding: 8px 13px; background: #f1f1f3; color: #111; font: 400 13px var(--l-font-label); cursor: pointer; }
    .q-chips button:active { background: #e4e4e7; }
    .sh-primary { border: none; border-radius: 99px; height: 46px; background: #111; color: #fff; font: 400 15px var(--l-font-label); cursor: pointer; transition: transform .15s var(--l-spring); }
    .sh-primary:active { transform: scale(.97); }
    .h-pick { display: flex; align-items: center; gap: 8px; }
    .h-slot { flex: 1; min-width: 0; display: flex; }
    .h-find { flex: 1; min-width: 0; display: flex; align-items: center; gap: 8px; height: 50px; padding: 0 14px 0 12px; border: 2px solid #111; border-radius: 99px; background: #fff; }
    .h-mag { flex: 0 0 auto; display: flex; color: #8a8a8a; }
    .h-mag svg { width: 18px; height: 18px; }
    #hSearch { -webkit-user-select: text; user-select: text; flex: 1; min-width: 0; width: 100%; border: none; outline: none; background: transparent; font: 400 16px var(--l-font-label); color: #111; padding: 0; -webkit-appearance: none; appearance: none; }
    #hSearch::placeholder { color: #9a9aa2; font-weight: 400; }
    .h-chip { flex: 1; min-width: 0; display: flex; align-items: center; gap: 9px; padding: 8px 12px 8px 8px; border: 2px solid transparent; border-radius: 99px; background: #f1f1f3; color: #111; font: 400 14px var(--l-font-label); cursor: pointer; text-align: left; transition: border-color .15s, background .15s; }
    .h-chip.active { border-color: #111; background: #fff; }
    .h-av { flex: 0 0 auto; width: 34px; height: 34px; border-radius: 50%; overflow: hidden; background: #e4e4e7; color: #8a8a8a; display: flex; align-items: center; justify-content: center; font: 800 14px var(--l-font-display); }
    .h-av img { width: 100%; height: 100%; object-fit: cover; display: block; }
    .h-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    #hList { max-height: 34dvh; overflow-y: auto; touch-action: pan-y; display: flex; flex-direction: column; }
    .h-row { display: flex; align-items: center; gap: 12px; padding: 8px 4px; border: none; border-bottom: 1px solid #f0f0f2; background: none; font: 400 16px var(--l-font-label); color: #111; cursor: pointer; text-align: left; }
    .h-row .h-av { width: 42px; height: 42px; }
    .h-row:active { background: #f6f6f8; }
    .h-row[data-picked] { background: #f6f6f8; }
    .h-row[data-picked]::after { content: '✓'; margin-left: auto; font-weight: 400; }

    /* export options sheet — one row per family ("side"), plus "All families" */
    .ex-list { max-height: 42dvh; overflow-y: auto; touch-action: pan-y; display: flex; flex-direction: column; }
    .ex-row { display: flex; align-items: center; gap: 10px; padding: 13px 4px; border: none; border-bottom: 1px solid #f0f0f2; background: none; font: 400 15px var(--l-font-label); color: #111; cursor: pointer; text-align: left; }
    .ex-row:last-child { border-bottom: none; }
    .ex-row small { margin-left: auto; color: #8a8a8a; font-weight: 400; font-size: 12px; }
    .ex-row[data-on]::after { content: '✓'; font-weight: 400; color: #111; margin-left: 8px; }
    .ex-note { font: 400 12.5px var(--l-font-label); color: #8a8a8a; line-height: 1.5; }
    #exGo:disabled { opacity: .4; pointer-events: none; }

    /* PDF page picker — a grid of tap-to-select thumbnails (laya.pdf()'s cheap thumb(i),
       never the full-quality render() until a page is actually picked). */
    .pdf-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(84px, 1fr)); gap: 8px; max-height: 50dvh; overflow-y: auto; touch-action: pan-y; padding: 2px; }
    .pdf-page { position: relative; display: block; aspect-ratio: 3/4; border: none; border-radius: 10px; overflow: hidden; padding: 0; background: #f1f1f3; cursor: pointer; }
    .pdf-page img { width: 100%; height: 100%; object-fit: cover; display: block; opacity: 0; transition: opacity .2s; }
    .pdf-page img[data-loaded] { opacity: 1; }
    .pdf-page .pdf-num { position: absolute; left: 4px; bottom: 4px; padding: 2px 6px; border-radius: 99px; background: rgba(0,0,0,.55); color: #fff; font: 700 10px var(--l-font-label); }
    .pdf-page::after { content: ''; position: absolute; inset: 0; border: 3px solid transparent; border-radius: 10px; transition: border-color .15s; }
    .pdf-page[data-on]::after { border-color: #111; }
    .pdf-page[data-on] .pdf-check { display: flex; }
    .pdf-check { display: none; position: absolute; top: 5px; right: 5px; width: 20px; height: 20px; border-radius: 50%; background: #111; color: #fff; align-items: center; justify-content: center; font: 800 11px var(--l-font-label); }
    #pdfAdd:disabled { opacity: .4; pointer-events: none; }
    #hList .empty { color: #8a8a8a; font: 400 14px var(--l-font-label); padding: 18px 0; text-align: center; }
    .h-arrow { color: #8a8a8a; font-weight: 400; }
    .h-result:empty { display: none; }
    .h-result { min-height: 0; display: flex; flex-direction: column; gap: 10px; padding: 4px 2px 2px; }
    .h-card { display: flex; flex-direction: column; gap: 2px; padding: 12px 14px; border-radius: 16px; background: #f6f6f8; }
    .h-card small { font: 400 12px var(--l-font-label); color: #8a8a8a; }
    .h-card .h-gloss { font-weight: 400; color: #a0a0a8; text-transform: none; }
    .h-result b { font: 800 22px var(--l-font-display); color: #111; }
    .h-result span { font: 400 15px var(--l-font-label); color: #555; }
    .h-result small { font: 400 12px var(--l-font-label); color: #b0b0b6; }

    /* sides */
    #sidePill { position: fixed; top: calc(env(safe-area-inset-top, 0px) + 84px); left: 50%; transform: translateX(-50%); z-index: 235; display: flex; align-items: center; gap: 6px; max-width: calc(100vw - 32px); padding: 8px 14px; border: none; border-radius: 99px; background: rgba(255,255,255,.94); backdrop-filter: blur(12px); box-shadow: 0 2px 12px rgba(0,0,0,.12); color: #111; font: 400 13px var(--l-font-label); pointer-events: none; }
    #sidePill span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    #sidePill[hidden] { display: none; }
    #screenTree[data-view="photos"] #sidePill, #screenTree[data-view="people"] #sidePill, #screenTree[data-view="outline"] #sidePill, #screenTree[data-view="studio"] #sidePill, #screenTree[data-view="trees"] #sidePill { display: none; }
    lnode .side-chip { position: absolute; left: calc(50% + 14px); top: -9px; width: 26px; height: 26px; padding: 0; border: 2px solid #fff; border-radius: 50%; background: #111; color: #fff; font: 400 13px/1 system-ui, sans-serif; display: flex; align-items: center; justify-content: center; cursor: pointer; pointer-events: auto; z-index: 3; box-shadow: 0 2px 8px rgba(0,0,0,.25); transition: transform .15s var(--l-spring); }
    lnode .side-chip svg { width: 14px; height: 14px; }
    lnode .side-chip:active { transform: scale(.88); }
    #psSide { border: none; background: none; color: #111; font: 400 13px var(--l-font-label); cursor: pointer; padding: 6px 2px; }
    #psSide[hidden] { display: none; }

    /* menu — full screen, not a popup: nothing to miss-tap around, no backdrop math */
    #treeMenu { position: fixed; inset: 0; z-index: 305; display: flex; flex-direction: column; background: #fdfdfd; overflow-y: auto; overscroll-behavior: contain; padding: calc(env(safe-area-inset-top, 0px) + 16px) var(--l-sp-md) calc(env(safe-area-inset-bottom, 0px) + 24px); animation: menuIn .18s var(--l-spring, cubic-bezier(.34,1.56,.64,1)); }
    #treeMenu[hidden] { display: none; }
    @keyframes menuIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
    .menu-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 18px; }
    .menu-head > span { font-family: var(--l-font-display); font-size: 21px; font-weight: var(--l-fw-heavy, 800); letter-spacing: -.02em; color: #111; }
    /* header icon cluster: the handful of one-off actions (help/sound/delete) that don't need
       a whole row of their own, plus close — same small round-button treatment throughout */
    .menu-head-icons { display: flex; align-items: center; gap: 6px; }
    .menu-head-icons button { width: 38px; height: 38px; border-radius: 50%; border: none; background: rgba(0,0,0,.06); display: flex; align-items: center; justify-content: center; cursor: pointer; color: #111; }
    .menu-head-icons button:active { background: rgba(0,0,0,.12); }
    .menu-head-icons svg { width: 18px; height: 18px; stroke: currentColor; fill: none; }
    .menu-head-icons [data-act="delete-tree"] { color: #dc2626; }
    .menu-head-icons [data-act="sound"] .off { display: none; }
    .menu-head-icons [data-act="sound"][data-off] .on { display: none; }
    .menu-head-icons [data-act="sound"][data-off] .off { display: inline; }
    /* big-icon grid: the handful of things people tap constantly */
    .menu-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin-bottom: 22px; }
    .menu-grid button { position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 9px; padding: 20px 6px 16px; border: none; border-radius: 18px; background: #f2f2f3; cursor: pointer; transition: background .12s; }
    .menu-grid button:active, .menu-grid button[data-active] { background: rgba(0,0,0,.1); }
    .menu-grid svg { width: 30px; height: 30px; stroke: #111; fill: none; flex-shrink: 0; }
    .menu-grid span { font-family: var(--l-font-label); font-size: 13px; font-weight: 400; color: #111; text-align: center; }
    .menu-grid small { position: absolute; top: 8px; right: 10px; min-width: 16px; padding: 1px 4px; border-radius: 99px; background: rgba(0,0,0,.08); color: #666; font-weight: 400; font-size: 11px; text-align: center; }
    /* public-link block: the id itself is the button — big, bold, unmissable, tap to copy */
    .menu-public { display: flex; flex-direction: column; align-items: center; gap: 8px; padding: 18px 12px; margin-bottom: 14px; border-radius: 16px; background: #f2f2f3; }
    .menu-public > span { font-family: var(--l-font-label); font-size: 12px; font-weight: 400; color: #8a8a8a; text-transform: uppercase; letter-spacing: .06em; }
    #menuPublicIdBtn { border: none; background: none; padding: 0; margin: 0; font-family: var(--l-font-display); font-size: 30px; font-weight: var(--l-fw-heavy, 800); letter-spacing: .04em; color: #111; cursor: pointer; }
    #menuPublicIdBtn:active { opacity: .5; }
    #menuMakePrivate { border: none; background: none; padding: 4px; font-family: var(--l-font-label); font-size: 13px; font-weight: 400; color: #8a8a8a; text-decoration: underline; text-underline-offset: 3px; cursor: pointer; }
    /* compact list: everything else, still reachable, just not shouting */
    .menu-list { display: flex; flex-direction: column; gap: 1px; }
    .menu-list button { display: flex; align-items: center; gap: 12px; width: 100%; padding: 12px 10px; border: none; background: none; border-radius: 11px; font-family: var(--l-font-label); font-size: 15px; font-weight: 400; color: #111; cursor: pointer; text-align: left; transition: background .12s; }
    .menu-list button:active { background: rgba(0,0,0,.06); }
    .menu-list svg { width: 19px; height: 19px; stroke: currentColor; flex-shrink: 0; }

    /* photos + people + trees views: full-screen sheets under the top bar, dock hidden */
    #photosView, #peopleView, #outlineView, #treesView { position: fixed; inset: 0; z-index: 230; background: #fdfdfd; overflow-y: auto; touch-action: pan-y; overscroll-behavior: contain; padding: calc(env(safe-area-inset-top, 0px) + 80px) var(--l-sp-md) calc(env(safe-area-inset-bottom, 0px) + 28px); }
    #photosView[hidden], #peopleView[hidden], #outlineView[hidden], #treesView[hidden] { display: none; }
    #screenTree[data-view="photos"] #dock, #screenTree[data-view="people"] #dock, #screenTree[data-view="outline"] #dock, #screenTree[data-view="trees"] #dock { display: none; }
    .vhead { display: flex; align-items: center; gap: 8px; margin-bottom: 14px; }
    .vhead h2 { font-family: var(--l-font-display); font-size: var(--l-fs-lg, 22px); font-weight: var(--l-fw-heavy, 800); letter-spacing: -.02em; color: #111; }
    .vhead small { color: #8a8a8a; font-weight: 400; font-size: 13px; }
    .pv-actions { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-bottom: 14px; }
    .pv-actions button { display: flex; flex-direction: column; align-items: center; gap: 7px; padding: 14px 6px 12px; border: none; border-radius: 16px; background: #f1f1f3; color: #111; font: 400 13px var(--l-font-label); cursor: pointer; transition: transform .15s var(--l-spring), background .15s; }
    .pv-actions button:active { transform: scale(.95); background: #e4e4e7; }
    .pv-actions svg { width: 24px; height: 24px; stroke: currentColor; }
    .vhead .pill { display: inline-flex; align-items: center; gap: 6px; padding: 8px 14px; border: none; border-radius: 99px; background: #111; color: #fff; font-family: var(--l-font-label); font-size: 13px; font-weight: 400; cursor: pointer; transition: transform .15s var(--l-spring); }
    .vhead .pill:active { transform: scale(.94); }
    .vhead .pill svg { width: 15px; height: 15px; stroke: currentColor; }
    #photosGrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); gap: 8px; }
    #photosGrid .ph { position: relative; aspect-ratio: 1; border: none; padding: 0; border-radius: 14px; overflow: hidden; background: #eee; cursor: pointer; transition: transform .18s var(--l-spring); }
    #photosGrid .ph:active { transform: scale(.96); }
    #photosGrid .ph[data-current] { outline: 2.5px solid #111; outline-offset: 2px; }
    #photosGrid .ph img { width: 100%; height: 100%; object-fit: cover; display: block; pointer-events: none; }
    #photosGrid .phdel { position: absolute; top: 6px; right: 6px; width: 28px; height: 28px; border-radius: 50%; border: none; padding: 0; background: rgba(0,0,0,.6); color: #fff; display: flex; align-items: center; justify-content: center; cursor: pointer; backdrop-filter: blur(6px); transition: transform .15s var(--l-spring), background .15s; }
    #photosGrid .phdel:active { transform: scale(.88); background: #dc2626; }
    #photosGrid .phdel svg { width: 14px; height: 14px; }
    #photosGrid .ph span { position: absolute; left: 6px; bottom: 6px; padding: 2px 8px; border-radius: 99px; background: rgba(0,0,0,.62); color: #fff; font-size: 11px; font-weight: 400; font-family: var(--l-font-label); }
    #photosView .empty, #peopleView .empty { color: #8a8a8a; font-size: 14px; padding: 40px 0; text-align: center; }
    #peopleFilter { -webkit-user-select: text; user-select: text; width: 100%; padding: 11px 14px; border: 1px solid #e4e4e7; border-radius: 12px; background: #fff; font: 400 15px var(--l-font-label); color: #111; outline: none; margin-bottom: 8px; -webkit-appearance: none; appearance: none; }
    #peopleFilter:focus { border-color: #111; }
    .prow { display: flex; align-items: center; gap: 12px; padding: 8px 2px; border-bottom: 1px solid #f0f0f2; }
    .prow[hidden] { display: none; }
    .prow .pav { flex: 0 0 auto; width: 48px; height: 48px; border-radius: 50%; overflow: hidden; border: none; padding: 0; background: #eee; cursor: pointer; }
    .prow .pav img { width: 100%; height: 100%; object-fit: cover; display: block; }
    .prow .pav .mono { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; font-weight: 400; color: #999; background: #f5f5f5; }
    .prow .pbody { flex: 1; min-width: 0; display: flex; flex-direction: column; }
    .prow .pname { -webkit-user-select: text; user-select: text; width: 100%; border: none; border-bottom: 1.5px solid transparent; background: transparent; font: 400 17px var(--l-font-label); color: #111; padding: 2px 0; outline: none; transition: border-color .15s; border-radius: 0; }
    .prow .pname:focus { border-bottom-color: #111; }
    .prow .pmeta { font-size: 12px; color: #8a8a8a; font-weight: 400; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
    .pchips { display: flex; gap: 6px; overflow-x: auto; padding: 2px 0 10px; scrollbar-width: none; touch-action: pan-x; }
    .pchips::-webkit-scrollbar { display: none; }
    .pchips[hidden] { display: none; }
    .pchips button { flex: 0 0 auto; border: none; border-radius: 99px; padding: 8px 13px; background: #f1f1f3; color: #333; font: 400 12.5px var(--l-font-label); cursor: pointer; white-space: nowrap; transition: background .15s, color .15s, transform .15s var(--l-spring); }
    .pchips button:active { transform: scale(.95); }
    .pchips button.on { background: #111; color: #fff; }
    .pchips button small { margin-left: 5px; opacity: .6; font-weight: 400; }
    .prow .pgen { display: flex; gap: 5px; flex: 0 0 auto; }
    .prow .pgen button { width: 32px; height: 32px; border: none; border-radius: 50%; padding: 0; background: #f1f1f3; color: #8a8a8a; font: 400 12px var(--l-font-label); cursor: pointer; transition: background .15s, color .15s, transform .15s var(--l-spring); }
    .prow .pgen button:active { transform: scale(.9); }
    .prow .pgen button[data-g="m"].on { background: #dbeafe; color: #1d4ed8; }
    .prow .pgen button[data-g="f"].on { background: #fce7f3; color: #be185d; }
    .prow .pmem { color: #b0b0b6; }

    @media (prefers-reduced-motion: reduce) { #treeMenu { animation: none; } }
  
    :root {
      --tree-line: #c2c3cb; /* opaque: shared rails are drawn once per child, translucent lines stacked darker */
    }
  
