/**
 * 100x Life Planning System - People Module Styles
 * Relationship categories, person cards, ecosystem mapping
 */

/* ===== Container ===== */
.people-container,
.people-edit-container,
.people-chat-container {
  max-width: 900px;
  margin: 0 auto;
  padding: 1.5rem 1rem;
}

.people-header {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin-bottom: 2rem;
}

.people-title h1,
.people-title h2 {
  font-family: var(--font-heading);
  font-size: calc(2rem + var(--text-bump));
  color: var(--navy-primary);
  margin: 0;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.people-title h2 {
  font-size: calc(1.5rem + var(--text-bump));
}

.people-title p {
  color: var(--text-secondary);
  margin: 0;
}

/* ===== Scripture Quote ===== */
.people-scripture {
  background: linear-gradient(135deg, var(--teal-light), #f0fdf4);
  border-radius: 12px;
  padding: 1.5rem;
  margin-bottom: 2rem;
  text-align: center;
  border-left: 4px solid var(--teal-accent);
}

.people-scripture i {
  font-size: calc(2rem + var(--text-bump));
  color: var(--teal-ink);
  opacity: 0.5;
}

.people-scripture p {
  font-size: calc(1.1rem + var(--text-bump));
  font-style: italic;
  color: var(--navy-primary);
  margin: 0.5rem 0;
  line-height: 1.5;
}

.people-scripture cite {
  color: var(--text-muted);
  font-size: calc(0.9rem + var(--text-bump));
}

/* ===== Section ===== */
.people-section {
  background: var(--bg-primary);
  border-radius: 12px;
  padding: 1.5rem;
  margin-bottom: 1.5rem;
  border: 1px solid var(--border-light);
}

.people-section-header {
  margin-bottom: 0.75rem;
}

.people-section-header h2 {
  font-family: var(--font-heading);
  font-size: calc(1.25rem + var(--text-bump));
  color: var(--navy-primary);
  margin: 0;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.people-section-header h2 i {
  color: var(--teal-ink);
}

.people-section-description {
  color: var(--text-secondary);
  margin: 0 0 1rem 0;
  font-size: calc(0.9rem + var(--text-bump));
}

/* ===== Cross References ===== */
.people-cross-ref {
  background: var(--bg-secondary);
}

.people-cross-ref-list {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.people-cross-ref-item {
  background: var(--bg-primary);
  border-radius: 8px;
  padding: 1rem;
}

.people-cross-ref-section {
  font-size: calc(0.75rem + var(--text-bump));
  font-weight: 600;
  color: var(--teal-ink);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

/* "Add to…" — the quiet way a planning note becomes a mapped person. */
.people-cross-ref-add {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin-top: 0.6rem;
  background: none;
  border: 1px solid var(--border-light);
  color: var(--teal-ink);
  font-family: var(--font-ui);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: calc(0.8rem + var(--text-bump));
  padding: 0.35rem 0.8rem;
  min-height: var(--tap, 44px);
  cursor: pointer;
  transition: background var(--transition-fast), border-color var(--transition-fast);
}

.people-cross-ref-add:hover {
  background: var(--teal-light);
  border-color: var(--teal-accent);
}

.people-cross-ref-add.is-added {
  color: var(--text-muted);
  border-style: dashed;
  cursor: default;
}

.people-cross-ref-item p {
  margin: 0.5rem 0 0 0;
  color: var(--text-secondary);
  font-size: calc(0.9rem + var(--text-bump));
}

/* ===== Conversation mentions =====
   The sibling panel below the action-areas cross reference: names the member
   said out loud, offered back with the sentence they came from. Shares the
   cross-ref's card and its "Add to…" button so the two read as one idea in two
   places; the quote block and the second (declining) action are its own. */
.people-mentions {
  background: var(--bg-secondary);
}

.people-mentions-list {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  list-style: none;
  margin: 0;
  padding: 0;
}

.people-mentions-item {
  background: var(--bg-primary);
  border-radius: 8px;
  padding: 1rem;
}

.people-mentions-who {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.people-mentions-name {
  font-weight: 600;
  color: var(--teal-ink);
  font-size: calc(1rem + var(--text-bump));
}

.people-mentions-relationship {
  color: var(--text-secondary);
  font-size: calc(0.85rem + var(--text-bump));
}

/* The provenance. Set off from the row so it reads as a quotation of the
   member rather than as the app's own description of them. */
.people-mentions-quote {
  margin: 0.5rem 0 0 0;
  padding-left: 0.75rem;
  border-left: 2px solid var(--border-light);
  color: var(--text-secondary);
  font-size: calc(0.9rem + var(--text-bump));
}

.people-mentions-quote-label {
  display: block;
  font-size: calc(0.7rem + var(--text-bump));
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
  margin-bottom: 0.15rem;
}

.people-mentions-quote-text {
  font-style: italic;
}

.people-mentions-actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.5rem;
}

/* button_to wraps its button in a form; keep that form out of the layout so
   the two actions sit side by side. */
.people-mentions-dismiss-form {
  display: inline;
  margin: 0;
}

/* Declining is not a destructive action and should not look like one. Quieter
   than "Add to…", same size, same tap target. */
.people-mentions-dismiss {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin-top: 0.6rem;
  background: none;
  border: 1px solid transparent;
  color: var(--text-muted);
  font-family: var(--font-ui);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: calc(0.8rem + var(--text-bump));
  padding: 0.35rem 0.8rem;
  min-height: var(--tap, 44px);
  cursor: pointer;
  transition: color var(--transition-fast), border-color var(--transition-fast);
}

.people-mentions-dismiss:hover {
  color: var(--teal-ink);
  border-color: var(--border-light);
}

/* Constitution §5: what the member declined is still something we hold, so it
   is visible. Folded away by default because it is a record, not an offer. */
.people-mentions-passed {
  margin-top: 1rem;
  font-size: calc(0.85rem + var(--text-bump));
  color: var(--text-secondary);
}

.people-mentions-passed summary {
  cursor: pointer;
  color: var(--text-muted);
  min-height: var(--tap, 44px);
  display: flex;
  align-items: center;
}

.people-mentions-passed-copy,
.people-mentions-passed-names {
  margin: 0.25rem 0 0 0;
}

.people-mentions-passed-names {
  color: var(--teal-ink);
}

/* ===== Entry List ===== */
.people-entries-list {
  margin-bottom: 1rem;
}

.people-empty {
  text-align: center;
  padding: 3rem;
  color: var(--text-muted);
  background: var(--bg-secondary);
  border-radius: 12px;
}

.people-empty i {
  font-size: calc(3rem + var(--text-bump));
  margin-bottom: 1rem;
  display: block;
  opacity: 0.5;
}

/* ===== Entry Card ===== */
.people-entry-card {
  background: var(--bg-primary);
  border: 1px solid var(--border-light);
  border-radius: 12px;
  padding: 1.25rem;
  margin-bottom: 1rem;
}

.people-entry-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 1rem;
}

/* ── The person's face ──────────────────────────────────────────────────────
   Same affordance as the member's own photo in Settings: click the medallion,
   pick a file, it uploads. This row is where the map's faces come from. */
.people-entry-photo-form { margin: 0; }

/* A <button> since it opens the scoped phone-photo panel, so it needs the
   padding and font reset a bare label never did. */
.people-entry-photo {
  position: relative;
  display: block;
  width: 48px;
  height: 48px;
  padding: 0;
  border-radius: 50%;
  overflow: hidden;
  cursor: pointer;
  background: var(--bg-secondary);
  border: 1px solid var(--border-light);
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}

.people-entry-photo:hover,
.people-entry-photo:focus-within {
  border-color: var(--teal-accent);
  box-shadow: 0 0 0 3px rgba(72, 156, 184, 0.15);
}

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

.people-entry-photo-empty {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  color: var(--text-muted);
  font-size: calc(1.15rem + var(--text-bump));
}

.people-entry-photo-overlay {
  position: absolute;
  inset: auto 0 0 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0.1rem 0;
  background: rgba(19, 19, 19, 0.55);
  color: #ffffff;
  font-size: calc(0.6rem + var(--text-bump));
  opacity: 0;
  transition: opacity 0.15s ease;
}

.people-entry-photo:hover .people-entry-photo-overlay,
.people-entry-photo:focus-within .people-entry-photo-overlay { opacity: 1; }

.people-entry-photo.is-uploading { opacity: 0.6; }

.people-entry-identity {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

.people-entry-actions {
  display: flex;
  align-items: center;
  gap: 0.15rem;
}

.people-entry-photo-remove { color: var(--text-muted); }
.people-entry-photo-remove:hover { color: var(--teal-ink); }

.people-entry-photo-error {
  margin: -0.5rem 0 0.75rem;
  font-size: calc(0.8rem + var(--text-bump));
  color: #dc2626;
}

.people-entry-number {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--teal-fill);
  color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 600;
  font-size: calc(0.85rem + var(--text-bump));
}

.people-entry-delete {
  color: var(--text-muted);
}

.people-entry-delete:hover {
  color: #dc2626;
}

.people-entry-fields {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.people-field label {
  display: block;
  font-size: calc(0.8rem + var(--text-bump));
  font-weight: 600;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-bottom: 0.25rem;
}

.people-input {
  width: 100%;
  padding: 0.625rem 0.75rem;
  border: 1px solid var(--border-light);
  border-radius: 8px;
  font-family: inherit;
  font-size: calc(0.9rem + var(--text-bump));
  background: var(--bg-primary);
  color: var(--text-dark);
  transition: border-color 0.2s ease;
}

.people-input:focus {
  border-color: var(--teal-accent);
  box-shadow: 0 0 0 3px rgba(74, 155, 181, 0.1);
}

textarea.people-input {
  resize: vertical;
  min-height: 60px;
}

.people-checkbox {
  margin-right: 0.5rem;
}

.people-field label:has(.people-checkbox) {
  display: flex;
  align-items: center;
  text-transform: none;
  font-weight: normal;
  font-size: calc(0.9rem + var(--text-bump));
  color: var(--text-secondary);
}

/* ===== Add Person Button ===== */
.add-person-btn {
  width: 100%;
  padding: 1rem;
  border-style: dashed;
}

/* ===== Responsive ===== */
@media (max-width: 768px) {
  .people-container,
  .people-edit-container,
  .people-chat-container {
    padding: 0.75rem;
  }
}

/* ===== Dark Theme ===== */
[data-theme="dark"] .people-title h1,
[data-theme="dark"] .people-title h2 {
  color: var(--text-dark);
}

[data-theme="dark"] .people-scripture {
  background: linear-gradient(135deg, var(--teal-light), var(--bg-tertiary));
}

[data-theme="dark"] .people-section {
  background: var(--bg-secondary);
  border-color: var(--border-medium);
}

[data-theme="dark"] .people-entry-card {
  background: var(--bg-secondary);
  border-color: var(--border-medium);
}

[data-theme="dark"] .people-cross-ref-item {
  background: var(--bg-tertiary);
}

/* ===== Category Reflection (Rails parity) =====
   The original people.js renders these classes but relies on shared interview
   styling for the wrapper/textarea. These rules style the Rails-side helper
   markup (label, help text, status line) so the reflection block matches. */
.people-category-reflection {
  background: var(--bg-primary);
  border: 1px solid var(--border-light);
  border-radius: 12px;
  padding: 1.5rem;
  margin-top: 1.5rem;
}

.people-category-reflection > label {
  display: block;
  font-family: var(--font-heading);
  font-size: calc(1.1rem + var(--text-bump));
  color: var(--navy-primary);
  margin-bottom: 0.25rem;
}

.people-help-text {
  color: var(--text-secondary);
  margin: 0 0 1rem 0;
  font-size: calc(0.9rem + var(--text-bump));
}

/* The reflection textarea is styled by `.interview-textarea-wrapper textarea`
   in interview.css; these add the compact sizing the original trix-compact
   variant implied so the field doesn't tower over the block. */
.people-reflection-textarea {
  min-height: 80px;
}

.people-reflection-status {
  font-size: calc(0.8rem + var(--text-bump));
  color: var(--text-muted);
  margin-top: 0.5rem;
  min-height: 1rem;
}

/* ===== Module Chat (Rails parity) =====
   The Rails chat surface wraps the shared streaming interview-chat component.
   The seeded opener renders as the first `.message.ai` bubble inside the chat
   (via messages/_opener), identical to a streamed reply; this just supplies the
   flow. */
.people-chat-body {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  margin-bottom: 1.5rem;
}

.people-synth-error {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 1rem;
  padding: 0.75rem 1rem;
  background: #fef2f2;
  border: 1px solid #fecaca;
  border-radius: 8px;
  color: #b91c1c;
  font-size: calc(0.9rem + var(--text-bump));
}

.people-synth-error i {
  color: #dc2626;
}

[data-theme="dark"] .people-category-reflection {
  background: var(--bg-secondary);
  border-color: var(--border-medium);
}

[data-theme="dark"] .people-category-reflection > label {
  color: var(--text-dark);
}

/* ===== Relationship Map =====
   The hero of /people: the member at the centre, their people on three
   concentric rings by closeness. Geometry (left/top percentages, SVG paths,
   entrance delays) is computed server-side in People::Map and arrives inline;
   everything here is presentation. The square field is percentage-driven so it
   scales from 720px down to a phone without recomputing anything. */

.people-map {
  position: relative;
  margin: 0 0 2rem;
  padding: 1.75rem 1rem 1.25rem;
  background:
    radial-gradient(circle at 50% 44%, #ffffff 0%, var(--bg-primary) 42%, var(--bg-secondary) 100%);
  border: 1px solid var(--border-light);
  border-radius: var(--radius-panel-lg);
  overflow: hidden;
}

/* The brand topography, pooled behind the map and fading out before the edge. */
.people-map::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image: var(--texture-topography);
  background-size: 560px;
  background-position: center;
  opacity: 0.34;
  pointer-events: none;
  mask-image: radial-gradient(circle at 50% 46%, rgb(0, 0, 0) 22%, transparent 74%);
  -webkit-mask-image: radial-gradient(circle at 50% 46%, rgb(0, 0, 0) 22%, transparent 74%);
}

/* The square and its legend, side by side. The map takes the room that's left
   after the list, and the list is the first thing to move under it when there
   isn't any (see the narrow-viewport block). */
.people-map-body {
  position: relative;
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

/* Side padding is the sector labels' room to breathe when the field itself is
   the full width of the panel. */
.people-map-frame {
  position: relative;
  flex: 1 1 auto;
  min-width: 0;
  padding: 0 2.5rem;
}

.people-map-field {
  position: relative;
  width: min(100%, 700px);
  aspect-ratio: 1 / 1;
  margin: 0 auto;
}

/* ── Rings and spokes ───────────────────────────────────────────────────── */
.people-map-lines {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
}

/* Stacked to a stepped wash: three flat 2% fills, so the innermost band reads
   about 6% and each ring outward gets lighter. */
.people-map-zone {
  fill: rgba(72, 156, 184, 0.038);
  stroke: none;
  animation: people-map-fade 1s ease-out backwards;
}

.people-map-ring {
  fill: none;
  stroke: var(--teal-accent);
  stroke-width: 1;
  stroke-dasharray: 3 9;
  opacity: 0.3;
  animation: people-map-fade 0.9s ease-out backwards;
}

.people-map-field.is-empty .people-map-ring {
  stroke-dasharray: 4 10;
  opacity: 0.3;
}

.people-map-spoke {
  fill: none;
  stroke: var(--teal-accent);
  stroke-width: 1.2;
  stroke-linecap: round;
  opacity: 0.3;
  stroke-dasharray: 1;
  stroke-dashoffset: 0;
  animation: people-map-draw 0.8s cubic-bezier(0.22, 0.61, 0.36, 1) backwards;
}

/* A crowded sector would otherwise draw its own thicket of lines into the
   centre. The smaller the medallion, the fainter its tie — so the arcs, not the
   web, carry the composition. */
.people-map-spoke.scale-small { opacity: 0.2; }
.people-map-spoke.scale-dot { opacity: 0.13; }
.people-map-spoke.scale-micro { opacity: 0.1; }

/* The personal board is the methodology's inner circle; its lines carry more
   weight so the eye reads them as the strong ties. */
.people-map-spoke.is-board {
  stroke-width: 2;
  opacity: 0.6;
}

.people-map-spoke.is-dashed {
  stroke-dasharray: 0.02 0.02;
  opacity: 0.22;
  animation: people-map-fade 0.9s ease-out backwards;
}

/* ── Sector labels ──────────────────────────────────────────────────────── */
.people-map-label {
  position: absolute;
  max-width: 5.75rem;
  font-family: var(--font-ui);
  font-size: calc(0.66rem + var(--text-bump));
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  line-height: 1.25;
  color: var(--text-secondary);
  pointer-events: none;
  animation: people-map-fade 0.7s ease-out backwards;
}

/* A label with people behind it is the way into that category. */
a.people-map-label {
  pointer-events: auto;
  text-decoration: none;
  transition: color 0.15s ease;
}

a.people-map-label:hover,
a.people-map-label:focus-visible { color: var(--teal-ink); }

a.people-map-label.is-focused { color: var(--teal-ink); font-weight: 600; }

.people-map-label.anchor-middle { transform: translate(-50%, -50%); }
.people-map-label.anchor-start { transform: translate(0.45rem, -50%); }
.people-map-label.anchor-end { transform: translate(calc(-100% - 0.45rem), -50%); }

/* ── Centre ─────────────────────────────────────────────────────────────── */
.people-map-center {
  position: absolute;
  left: 50%;
  top: 50%;
  width: max(56px, 11%);
  aspect-ratio: 1 / 1;
  transform: translate(-50%, -50%);
}

.people-map-center-medallion {
  display: block;
  box-sizing: border-box;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  padding: 4px;
  background: var(--bg-primary);
  box-shadow:
    0 0 0 2px var(--teal-accent),
    0 0 0 9px rgba(72, 156, 184, 0.12),
    0 6px 20px rgba(19, 19, 19, 0.14);
  animation: people-map-center-in 0.7s cubic-bezier(0.22, 1.1, 0.36, 1) backwards;
}

.people-map-center-medallion .people-map-avatar {
  width: 100%;
  height: 100%;
  border-radius: 50%;
  object-fit: cover;
  font-size: calc(1.6rem + var(--text-bump));
}

.people-map-center-name {
  position: absolute;
  left: 50%;
  top: calc(100% + 0.5rem);
  transform: translateX(-50%);
  white-space: nowrap;
  font-family: var(--font-ui);
  font-size: calc(0.68rem + var(--text-bump));
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  color: var(--text-secondary);
  animation: people-map-fade 0.7s ease-out 0.35s backwards;
}

/* ── Medallions ─────────────────────────────────────────────────────────── */
/* Sized on the anchor, not the medallion: the anchor's containing block is the
   square field, so a percentage width has something real to resolve against. */
/* --node-scale is the density step People::Map picked for this category (see
   SCALE_FACTOR there — the numbers must agree, since the server uses them to
   answer "how many fit?"). */
.people-map-node {
  position: absolute;
  width: calc(max(23px, 5.6%) * var(--node-scale, 1));
  aspect-ratio: 1 / 1;
  transform: translate(-50%, -50%);
  text-decoration: none;
  line-height: 0;
  /* The medallions are round, and an outline follows its element's radius, so
     the shared focus ring reads as a ring rather than a box. These are the
     map's only controls: it used to strip the ring on both :focus AND
     :focus-visible, which is the audit's worst instance of C3. */
  border-radius: 50%;
  /* base.css keeps anchored elements clear of the sticky header with
     `[id] { scroll-margin-top: 72px }`, but a medallion is a button with no
     id — so anything that scrolls one into view (Tab moving focus around the
     map, a driver clicking one) parked it UNDER the header and journey bar,
     where it cannot be seen or clicked. Same allowance, plus the bar. */
  scroll-margin: 120px 0;
}

.people-map-node.scale-small { --node-scale: 0.74; }
.people-map-node.scale-dot { --node-scale: 0.56; }
.people-map-node.scale-micro { --node-scale: 0.42; }

.people-map-medallion {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  background: var(--bg-primary);
  border: 1px solid rgba(72, 156, 184, 0.3);
  color: var(--text-secondary);
  font-family: var(--font-ui);
  font-weight: 600;
  letter-spacing: 0.02em;
  transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease,
    opacity 0.18s ease;
  animation: people-map-bloom 0.66s cubic-bezier(0.22, 1.08, 0.36, 1) backwards;
  /* The medallion is decoration inside a button, and it MOVES: the bloom
     translates it into place over 0.66s, staggered per node, and hover scales
     it. While it moved, it was also the hit target — so a click during the
     map's entrance landed mousedown on the medallion and mouseup on the field
     behind it, and the browser dispatched `click` on their common ancestor.
     The seat did nothing. Handing pointer events to the button, whose box
     never moves, makes every medallion clickable the moment it is on screen
     (owner, 2026-08-17). Hover still works: mouseenter is bound to the
     button. */
  pointer-events: none;
}

.people-map-node.tier-2 { width: calc(max(26px, 6.4%) * var(--node-scale, 1)); }
.people-map-node.tier-1 { width: calc(max(30px, 7.4%) * var(--node-scale, 1)); }

.people-map-node.tier-3 .people-map-medallion { font-size: calc(0.54rem + var(--text-bump)); }
.people-map-node.tier-2 .people-map-medallion {
  font-size: calc(0.6rem + var(--text-bump));
  border-color: rgba(72, 156, 184, 0.42);
  color: var(--navy-medium);
}
.people-map-node.tier-1 .people-map-medallion {
  font-size: calc(0.66rem + var(--text-bump));
  background: linear-gradient(155deg, #ffffff 0%, var(--teal-light) 100%);
  border-color: rgba(72, 156, 184, 0.55);
  color: var(--navy-primary);
  box-shadow: 0 2px 8px rgba(19, 19, 19, 0.07);
}

.people-map-node.is-board .people-map-medallion {
  border-width: 2px;
  border-color: rgba(72, 156, 184, 0.9);
  box-shadow: 0 0 0 4px rgba(72, 156, 184, 0.1), 0 2px 8px rgba(19, 19, 19, 0.08);
}

.people-map-node.is-dashed .people-map-medallion {
  background: transparent;
  border-style: dashed;
  border-width: 1.5px;
  border-color: rgba(72, 156, 184, 0.5);
  color: rgba(72, 156, 184, 0.85);
  box-shadow: none;
}

.people-map-node.is-seat .people-map-medallion i {
  font-size: calc(0.95rem + var(--text-bump));
  line-height: 1;
}

.people-map-node.is-overflow .people-map-medallion {
  background: var(--teal-light);
  border-color: transparent;
  color: var(--teal-ink);
}

.people-map-node:hover .people-map-medallion,
.people-map-node:focus-visible .people-map-medallion {
  transform: scale(1.12);
  border-color: var(--teal-accent);
  box-shadow: 0 0 0 5px rgba(72, 156, 184, 0.16), 0 4px 14px rgba(19, 19, 19, 0.14);
}


.people-map-initials { display: block; line-height: 1; }

/* ── Faces ──────────────────────────────────────────────────────────────────
   A photo fills its medallion; the ring stays, so a face reads as the same
   token as a pair of initials. */
.people-map-photo {
  width: 100%;
  height: 100%;
  border-radius: 50%;
  object-fit: cover;
  display: block;
}

.people-map-node.has-photo .people-map-medallion {
  padding: 0;
  overflow: hidden;
  background: var(--teal-light);
}

/* ── Crowding ───────────────────────────────────────────────────────────────
   Past a certain count a sector's medallions overlap on purpose, the way a row
   of avatars does. The white ring separates them; hover lifts one clear. */
.people-map-node { z-index: 1; }

.people-map-node.scale-small .people-map-medallion,
.people-map-node.scale-dot .people-map-medallion,
.people-map-node.scale-micro .people-map-medallion {
  box-shadow: 0 0 0 2px var(--bg-primary), 0 1px 4px rgba(19, 19, 19, 0.1);
}

.people-map-node.scale-small .people-map-medallion { font-size: calc(0.5rem + var(--text-bump)) !important; }

/* Below "small" the initials stop being legible, so the medallion becomes a
   token: a face if there is one, otherwise a filled dot. The name is a hover
   away. */
.people-map-node.scale-dot .people-map-initials,
.people-map-node.scale-micro .people-map-initials,
.people-map-node.scale-dot .people-map-medallion > i,
.people-map-node.scale-micro .people-map-medallion > i { display: none; }

.people-map-node.scale-dot .people-map-medallion,
.people-map-node.scale-micro .people-map-medallion {
  background: linear-gradient(155deg, var(--teal-light) 0%, rgba(72, 156, 184, 0.55) 100%);
}

.people-map-node.scale-dot.has-photo .people-map-medallion,
.people-map-node.scale-micro.has-photo .people-map-medallion { background: var(--teal-light); }

/* Small tokens need a bigger lift to be readable under the pointer. */
.people-map-node.scale-dot:hover,
.people-map-node.scale-dot:focus-visible,
.people-map-node.scale-micro:hover,
.people-map-node.scale-micro:focus-visible { z-index: 6; }

.people-map-node.scale-dot:hover .people-map-medallion,
.people-map-node.scale-dot:focus-visible .people-map-medallion,
.people-map-node.scale-micro:hover .people-map-medallion,
.people-map-node.scale-micro:focus-visible .people-map-medallion { transform: scale(1.9); }

.people-map-node:hover, .people-map-node:focus-visible { z-index: 5; }

/* ── Folded categories (focus mode) ─────────────────────────────────────────
   Every category but the open one becomes one medallion with its icon and a
   count; clicking it opens that category instead. They sit back a step so the
   open category is plainly the subject. */
.people-map-node.is-cluster { --node-scale: 0.86; opacity: 0.8; }

.people-map-node.is-cluster:hover,
.people-map-node.is-cluster:focus-visible { opacity: 1; }

.people-map-node.is-cluster .people-map-medallion {
  flex-direction: column;
  gap: 0.05rem;
  background: var(--bg-primary);
  border-color: rgba(72, 156, 184, 0.5);
  color: var(--teal-ink);
}

/* The ring the open category sits on is drawn solid — the map says where you
   are without a word. */
.people-map-ring.is-focused {
  stroke-dasharray: none;
  opacity: 0.5;
}

.people-map-cluster-count {
  font-family: var(--font-ui);
  font-size: calc(0.58rem + var(--text-bump));
  line-height: 1;
  color: var(--navy-medium);
}

/* Point at one person and the rest of the map quiets down. Scoped with :has()
   so it only fires for a medallion, not for the pointer merely crossing the
   square; browsers without :has() simply don't dim. */
.people-map-field:has(.people-map-node:hover) .people-map-node:not(:hover) .people-map-medallion,
.people-map-field:has(.people-map-node:focus-visible) .people-map-node:not(:focus-visible) .people-map-medallion {
  opacity: 0.45;
}

/* ── Legend ─────────────────────────────────────────────────────────────────
   A slim column of the nine categories beside the map, each with its live
   count. The dot carries the same idea as the zone wash — the further out the
   ring, the lighter the mark — so the list reads in the same order as the
   rings do. */
.people-map-legend {
  position: relative;
  flex: 0 0 auto;
  width: 10.75rem;
}

.people-map-legend-title {
  margin: 0 0 0.4rem 0.45rem;
  font-family: var(--font-ui);
  font-size: calc(0.6rem + var(--text-bump));
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  color: var(--text-muted);
}

.people-map-legend-list {
  display: flex;
  flex-direction: column;
  gap: 0.05rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Empty-seat nodes are <button>s now (they open the add dialog) — shed the
   UA button chrome so they draw exactly like the anchor nodes. */
button.people-map-node {
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  font: inherit;
}

/* A legend row: the category control fills the row, the quiet + rides its
   trailing edge (every category is addable from the map). */
.people-map-legend-row {
  display: flex;
  align-items: center;
  gap: 0.15rem;
}

.people-map-legend-add {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 1.9rem;
  min-height: var(--tap, 44px);
  background: none;
  border: none;
  padding: 0;
  color: var(--text-muted);
  font-size: calc(0.95rem + var(--text-bump));
  cursor: pointer;
  opacity: 0.55;
  transition: opacity var(--transition-fast), color var(--transition-fast);
}

.people-map-legend-add:focus-visible { opacity: 1; }

@media (hover: hover) {
  .people-map-legend-row:hover .people-map-legend-add { opacity: 1; }
  .people-map-legend-add:hover { color: var(--teal-ink); }
}

.people-map-legend-item {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  width: 100%;
  padding: 0.28rem 0.45rem;
  border: 1px solid transparent;
  border-radius: var(--radius-panel);
  background: none;
  font-family: var(--font-ui);
  font-size: calc(0.66rem + var(--text-bump));
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  line-height: 1.2;
  text-align: left;
  text-decoration: none;
  color: var(--text-secondary);
  cursor: pointer;
  transition: color 0.15s ease, background-color 0.15s ease, border-color 0.15s ease;
}

.people-map-legend-name { flex: 1 1 auto; }

.people-map-legend-count {
  flex: 0 0 auto;
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
}

.people-map-legend-dot {
  flex: 0 0 auto;
  width: 0.45rem;
  height: 0.45rem;
  border-radius: 50%;
  background: var(--teal-accent);
}

.people-map-legend-item[data-tier="2"] .people-map-legend-dot { opacity: 0.6; }
.people-map-legend-item[data-tier="3"] .people-map-legend-dot { opacity: 0.36; }

/* "Everyone" is the way back, not a tenth category — it sits apart. */
.people-map-legend-item.is-all {
  margin-bottom: 0.2rem;
  padding-bottom: 0.34rem;
  border-bottom: 1px solid var(--border-light);
  border-radius: var(--radius-panel) var(--radius-panel) 0 0;
  color: var(--text-muted);
}

button.people-map-legend-item:hover,
a.people-map-legend-item:hover,
.people-map-legend-item:focus-visible {
  color: var(--teal-ink);
  background: var(--teal-light);
}

/* Lit — by a spotlight (aria-pressed) or by focus mode (aria-current). One
   look, because to the eye they mean the same thing: this is the category the
   map is about right now. */
.people-map-legend-item[aria-pressed="true"],
.people-map-legend-item[aria-current] {
  color: var(--teal-ink);
  background: var(--teal-light);
  border-color: rgba(72, 156, 184, 0.35);
  font-weight: 600;
}

.people-map-legend-item[aria-pressed="true"] .people-map-legend-count,
.people-map-legend-item[aria-current] .people-map-legend-count { color: var(--teal-ink); }

/* An orbit nobody is in yet. Named, so the map still tells you it exists, but
   there is nothing to light up. */
.people-map-legend-item.is-empty {
  color: var(--text-muted);
  opacity: 0.6;
}

/* A row with nothing on the map behind it isn't a control. (An empty personal
   board still is: the map drew its open seat.) */
span.people-map-legend-item { cursor: default; }

.people-map-legend-item.is-empty .people-map-legend-dot { background: var(--border-medium); }

/* ── Spotlight ──────────────────────────────────────────────────────────────
   The legend writes data-spotlight="<categoryId>" on the map section; from
   there it is one rule per category, because CSS can't compare an ancestor's
   attribute with a descendant's. The centre medallion carries no category, so
   the member never dims — which is what makes the spotlight legible.

   Order matters below: the peek rule that follows must outrank these. */
.people-map-node,
.people-map-spoke,
.people-map-label { transition: opacity 0.2s ease; }

.people-map[data-spotlight="familyAndFriends"] :is(.people-map-node, .people-map-spoke, .people-map-label):not([data-category="familyAndFriends"]),
.people-map[data-spotlight="personalBoard"] :is(.people-map-node, .people-map-spoke, .people-map-label):not([data-category="personalBoard"]),
.people-map[data-spotlight="stakeholders"] :is(.people-map-node, .people-map-spoke, .people-map-label):not([data-category="stakeholders"]),
.people-map[data-spotlight="missionTeam"] :is(.people-map-node, .people-map-spoke, .people-map-label):not([data-category="missionTeam"]),
.people-map[data-spotlight="advisors"] :is(.people-map-node, .people-map-spoke, .people-map-label):not([data-category="advisors"]),
.people-map[data-spotlight="keyLeadersNeeded"] :is(.people-map-node, .people-map-spoke, .people-map-label):not([data-category="keyLeadersNeeded"]),
.people-map[data-spotlight="expertsInfluencers"] :is(.people-map-node, .people-map-spoke, .people-map-label):not([data-category="expertsInfluencers"]),
.people-map[data-spotlight="otherRelationships"] :is(.people-map-node, .people-map-spoke, .people-map-label):not([data-category="otherRelationships"]),
.people-map[data-spotlight="investingIn"] :is(.people-map-node, .people-map-spoke, .people-map-label):not([data-category="investingIn"]) {
  opacity: 0.18;
}

/* A dimmed medallion still answers the pointer: a peek at who that is, without
   losing the category you're holding. Outranks the dim by one element. */
.people-map[data-spotlight] .people-map-field .people-map-node:hover,
.people-map[data-spotlight] .people-map-field .people-map-node:focus-visible { opacity: 1; }

/* ── Hover card ─────────────────────────────────────────────────────────── */
.people-map-card {
  position: absolute;
  z-index: 3;
  min-width: 8rem;
  max-width: 13rem;
  padding: 0.55rem 0.75rem 0.6rem;
  background: var(--bg-primary);
  border: 1px solid var(--border-light);
  border-top: 2px solid var(--teal-accent);
  border-radius: var(--radius-panel);
  box-shadow: var(--shadow-panel);
  pointer-events: none;
  animation: people-map-card-in 0.16s ease-out;
}

.people-map-card.is-below {
  border-top: 1px solid var(--border-light);
  border-bottom: 2px solid var(--teal-accent);
}

.people-map-card p { margin: 0; }

/* A face, larger than its medallion — the card is where you actually see who
   this is. */
.people-map-card-photo {
  display: block;
  width: 3.5rem;
  height: 3.5rem;
  margin: 0 auto 0.45rem;
  border-radius: 50%;
  object-fit: cover;
  box-shadow: 0 0 0 2px var(--teal-light);
}

.people-map-card-photo[hidden] { display: none; }

.people-map-card-name {
  font-family: var(--font-heading);
  font-size: calc(0.95rem + var(--text-bump));
  line-height: 1.25;
  color: var(--navy-primary);
}

.people-map-card-meta {
  margin-top: 0.15rem !important;
  font-size: calc(0.78rem + var(--text-bump));
  color: var(--text-secondary);
  line-height: 1.35;
}

.people-map-card-category {
  margin-top: 0.35rem !important;
  font-family: var(--font-ui);
  font-size: calc(0.62rem + var(--text-bump));
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  color: var(--teal-ink);
}

/* The hover hint is meaningless on a touch screen. */
@media (hover: none) {
  .people-map-hint { display: none; }
}

/* ── Caption ────────────────────────────────────────────────────────────── */
.people-map-caption {
  position: relative;
  margin: 1.1rem 0 0;
  text-align: center;
  font-size: calc(0.85rem + var(--text-bump));
  color: var(--text-secondary);
  animation: people-map-fade 0.8s ease-out 0.5s backwards;
}

.people-map-reset {
  margin-left: 0.35rem;
  color: var(--teal-ink);
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* ── Controls ───────────────────────────────────────────────────────────────
   One quiet button in the corner: expand to the wall display, or close it. */
.people-map-controls {
  position: absolute;
  top: 0.85rem;
  right: 0.95rem;
  z-index: 4;
}

.people-map-control {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  border: 1px solid var(--border-light);
  border-radius: var(--radius-full, 50rem);
  background: var(--bg-primary);
  color: var(--text-secondary);
  font-size: calc(0.8rem + var(--text-bump));
  cursor: pointer;
  opacity: 0.65;
  transition: opacity 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

.people-map-control:hover,
.people-map-control:focus-visible {
  opacity: 1;
  color: var(--teal-ink);
  border-color: var(--teal-accent);
}

/* ── Full screen ────────────────────────────────────────────────────────────
   A fixed, dimmed surface in the presentation deck's register (dark ground,
   teal light), holding the same map at expanded density. The overlay is a
   sibling of the inline map, so nothing is moved or cloned — the wall display
   is its own render. */
/* A <dialog> in the top layer: it owns the screen while it's open, whatever the
   page's stacking contexts say. */
.people-map-overlay {
  width: 100vw;
  max-width: 100vw;
  height: 100dvh;
  max-height: 100dvh;
  margin: 0;
  padding: 1rem;
  border: none;
  background: #0d0d0d;
  color: #f5f5f5;
  overflow: hidden;
}

.people-map-overlay:not([open]) { display: none; }

.people-map-overlay::backdrop { background: #0d0d0d; }

body.people-map-locked { overflow: hidden; }

.people-map-overlay turbo-frame {
  display: block;
  width: 100%;
  height: 100%;
}

.people-map.is-fullscreen .people-map-frame { width: 100%; }

.people-map.is-fullscreen {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  height: 100%;
  margin: 0;
  padding: 0.5rem;
  background: transparent;
  border: none;
  border-radius: 0;
  color: var(--text-light, #f5f5f5);
}

.people-map.is-fullscreen::before { opacity: 0.12; }

.people-map.is-fullscreen .people-map-frame { padding: 0 3.5rem; }

/* The square takes whatever the viewport can give it, minus the caption and the
   labels' breathing room on either side. */
.people-map.is-fullscreen .people-map-field {
  width: min(100%, calc(100dvh - 7rem));
  max-width: min(1150px, 88vw);
}

.people-map.is-fullscreen .people-map-label { color: rgba(255, 255, 255, 0.72); }
.people-map.is-fullscreen a.people-map-label:hover,
.people-map.is-fullscreen a.people-map-label:focus-visible,
.people-map.is-fullscreen a.people-map-label.is-focused { color: var(--teal-ink); }

.people-map.is-fullscreen .people-map-caption,
.people-map.is-fullscreen .people-map-center-name { color: rgba(255, 255, 255, 0.66); }

/* The legend goes with the map onto the dark ground — same list, same
   spotlight, lit for a wall. */
.people-map.is-fullscreen .people-map-body {
  width: 100%;
  justify-content: center;
}

.people-map.is-fullscreen .people-map-legend-title { color: rgba(255, 255, 255, 0.5); }

.people-map.is-fullscreen .people-map-legend-item { color: rgba(255, 255, 255, 0.72); }
.people-map.is-fullscreen .people-map-legend-count { color: rgba(255, 255, 255, 0.45); }
.people-map.is-fullscreen .people-map-legend-item.is-all { border-bottom-color: rgba(255, 255, 255, 0.16); }

.people-map.is-fullscreen button.people-map-legend-item:hover,
.people-map.is-fullscreen a.people-map-legend-item:hover,
.people-map.is-fullscreen .people-map-legend-item:focus-visible,
.people-map.is-fullscreen .people-map-legend-item[aria-pressed="true"],
.people-map.is-fullscreen .people-map-legend-item[aria-current] {
  color: var(--teal-ink);
  background: rgba(72, 156, 184, 0.16);
  border-color: rgba(72, 156, 184, 0.4);
}

.people-map.is-fullscreen .people-map-legend-item[aria-pressed="true"] .people-map-legend-count,
.people-map.is-fullscreen .people-map-legend-item[aria-current] .people-map-legend-count { color: var(--teal-ink); }

.people-map.is-fullscreen .people-map-legend-item.is-empty { color: rgba(255, 255, 255, 0.34); }

.people-map.is-fullscreen .people-map-reset { color: var(--teal-ink); }

.people-map.is-fullscreen .people-map-ring { opacity: 0.4; }
.people-map.is-fullscreen .people-map-zone { fill: rgba(72, 156, 184, 0.06); }
.people-map.is-fullscreen .people-map-spoke { opacity: 0.4; }

.people-map.is-fullscreen .people-map-control {
  background: rgba(255, 255, 255, 0.08);
  border-color: rgba(255, 255, 255, 0.25);
  color: #ffffff;
  opacity: 0.8;
}

.people-map.is-fullscreen .people-map-controls { top: 0.25rem; right: 0.5rem; }

/* Medallions keep their light faces against the dark ground — the point of the
   wall display is the people, not the chrome. */
.people-map.is-fullscreen .people-map-node.scale-small .people-map-medallion,
.people-map.is-fullscreen .people-map-node.scale-dot .people-map-medallion,
.people-map.is-fullscreen .people-map-node.scale-micro .people-map-medallion {
  box-shadow: 0 0 0 2px rgba(12, 12, 12, 0.9), 0 1px 5px rgba(0, 0, 0, 0.5);
}

/* Where a medallion just landed: the gallery section it anchors to lights its
   header for a beat, so the eye finds the shelf it jumped to. */
.people-gallery-section.is-map-flash .people-gallery-section-head {
  background: var(--teal-light);
  box-shadow: 0 0 0 3px rgba(72, 156, 184, 0.18);
}

/* ── Entrance ───────────────────────────────────────────────────────────── */
@keyframes people-map-bloom {
  from { opacity: 0; transform: translate(var(--bloom-x, 0), var(--bloom-y, 0)) scale(0.32); }
  to { opacity: 1; transform: translate(0, 0) scale(1); }
}

@keyframes people-map-center-in {
  from { opacity: 0; transform: scale(0.72); }
  to { opacity: 1; transform: scale(1); }
}

@keyframes people-map-draw {
  from { stroke-dashoffset: 1; opacity: 0; }
  to { stroke-dashoffset: 0; }
}

@keyframes people-map-fade {
  from { opacity: 0; }
}

@keyframes people-map-card-in {
  from { opacity: 0; transform: translateY(3px); }
}

@media (prefers-reduced-motion: reduce) {
  .people-map-zone,
  .people-map-ring,
  .people-map-spoke,
  .people-map-label,
  .people-map-medallion,
  .people-map-center-medallion,
  .people-map-center-name,
  .people-map-caption,
  .people-map-card {
    animation: none !important;
  }
  .people-map-node:hover .people-map-medallion,
  .people-map-node:focus-visible .people-map-medallion { transform: none; }

  /* The spotlight still dims — that's the information. It just arrives at
     once instead of fading in. */
  .people-map-node,
  .people-map-spoke,
  .people-map-label { transition: none; }
}

/* ── Narrow viewports ───────────────────────────────────────────────────
   The map keeps every person; what it sheds as the square shrinks is chrome —
   the outer sector labels first, then the rest of them, then the member's own
   name under the centre. Medallions have a floor so two initials still fit. */
/* Under this the column would squeeze the square more than it helps, so the
   legend folds into a wrapping row beneath the map — same rows, same clicks,
   laid out the way a caption would be. */
@media (max-width: 900px) {
  /* Stretch, not centre: a centred column item shrinks to its content, and the
     square would collapse with it. */
  .people-map-body {
    flex-direction: column;
    align-items: stretch;
  }

  .people-map-legend { width: 100%; }
  .people-map-legend-title { margin-left: 0; text-align: center; }

  .people-map-legend-list {
    flex-direction: row;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.25rem;
  }

  .people-map-legend-item { width: auto; }

  .people-map-legend-item.is-all {
    margin-bottom: 0;
    padding-bottom: 0.28rem;
    border: 1px solid transparent;
    border-radius: var(--radius-panel);
  }

  .people-map-legend-item[aria-pressed="true"],
  .people-map-legend-item[aria-current] { border-color: rgba(72, 156, 184, 0.35); }
}

@media (max-width: 720px) {
  .people-map { padding: 1.25rem 0.5rem 1rem; }
  .people-map-frame { padding: 0 2rem; }
  .people-map-label { max-width: 4.75rem; font-size: calc(0.55rem + var(--text-bump)); }
  .people-map-label[data-tier="3"] { display: none; }
}

@media (max-width: 560px) {
  .people-map::before { background-size: 380px; }
  .people-map-frame { padding: 0 0.5rem; }

  /* Below this the band between two rings is thinner than a line of type, so
     the sector labels go entirely rather than sit on top of the medallions.
     The category names are right below the map, in the list. */
  .people-map-label { display: none; }

  .people-map-center { width: max(44px, 12%); }
  .people-map-center-name { display: none; }

  .people-map-node { width: max(19px, 5.6%); }
  .people-map-node.tier-2 { width: max(22px, 6.4%); }
  .people-map-node.tier-1 { width: max(26px, 7.4%); }

  .people-map-node.tier-1 .people-map-medallion { font-size: calc(0.5rem + var(--text-bump)); }
  .people-map-node.tier-2 .people-map-medallion { font-size: calc(0.46rem + var(--text-bump)); }
  .people-map-node.tier-3 .people-map-medallion { font-size: calc(0.42rem + var(--text-bump)); }
  .people-map-node.is-seat .people-map-medallion i { font-size: calc(0.7rem + var(--text-bump)); }

  .people-map-card { max-width: 11rem; }
}

/* ── Dark theme ─────────────────────────────────────────────────────────── */
[data-theme="dark"] .people-map {
  background: radial-gradient(circle at 50% 44%, #2b2b2b 0%, var(--bg-primary) 42%, var(--bg-secondary) 100%);
}

[data-theme="dark"] .people-map-node.tier-1 .people-map-medallion {
  background: linear-gradient(155deg, #2e2e2e 0%, var(--teal-light) 100%);
}

[data-theme="dark"] .people-map-center-medallion {
  box-shadow:
    0 0 0 2px var(--teal-accent),
    0 0 0 9px rgba(91, 184, 212, 0.16),
    0 6px 20px rgba(0, 0, 0, 0.5);
}

/* ══════════════════════════════════════════════════════════════════════════
   "Add a photo" — one panel, two scopes. The gallery head opens it for the
   whole page; a card's chip or a row's medallion opens it for one person. Same
   markup either way (people/_phone_photo_panel), so there is one thing to
   style. Transcribed from
   docs/design-reference/extracted/people-gallery-phone-qr.html.
   The phone page it opens has its own stylesheet (modules/photo-upload.css),
   because that surface loads none of this.
   ══════════════════════════════════════════════════════════════════════════ */
.phone-photo-launcher {
  display: flex;
  justify-content: flex-end;
  margin: 0 0 1rem;
}

.phone-photo-launcher form { margin: 0; }

/* In the gallery the launcher is a quiet closing line, centered under the
   shelves: hint + action reading as one sentence. (The category page renders
   the same partial without the hint and keeps the plain button.) */
.phone-photo-launcher.has-hint {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.65rem;
  flex-wrap: wrap;
  margin-top: 0.5rem;
  padding-top: 1rem;
  border-top: 1px solid var(--border-light);
}

.phone-photo-launcher-hint {
  margin: 0;
  color: var(--text-muted);
  font-size: calc(0.95rem + var(--text-bump));
}

.phone-photo-launch {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  min-height: var(--tap, 44px);
  padding: 0.55rem 1rem;
  background: none;
  border: 1px solid var(--teal-accent);
  color: var(--teal-ink);
  font-family: var(--font-ui);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: calc(0.9rem + var(--text-bump));
  cursor: pointer;
  transition: background var(--transition-fast);
}

.phone-photo-launch:hover { background: var(--teal-light); }

/* The dialog. Native <dialog>, so focus trapping, Escape and the inert
   background are the platform's. */
.phone-photo-dialog {
  border: none;
  padding: 0;
  background: none;
  max-width: 540px;
  width: calc(100% - 2rem);
}

.phone-photo-dialog::backdrop { background: rgba(0, 0, 0, 0.5); }

.phone-photo-card {
  background: var(--bg-primary);
  box-shadow: var(--shadow-modal);
}

.phone-photo-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.5rem 1.5rem 0;
}

.phone-photo-head form { margin: 0; }

.phone-photo-eyebrow {
  font-family: var(--font-ui);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  font-size: calc(0.8rem + var(--text-bump));
  color: var(--teal-ink);
  margin: 0 0 0.3rem;
}

.phone-photo-title {
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: calc(1.6rem + var(--text-bump));
  color: var(--text-heading);
  margin: 0;
}

.phone-photo-sub {
  color: var(--text-muted);
  font-size: calc(1rem + var(--text-bump));
  margin: 0.35rem 0 0;
}

.phone-photo-close {
  background: none;
  border: none;
  color: var(--text-muted);
  font-size: calc(1.3rem + var(--text-bump));
  line-height: 1;
  cursor: pointer;
  padding: 0.2rem;
  min-width: var(--tap, 44px);
  min-height: var(--tap, 44px);
}

.phone-photo-close:hover { color: var(--text-primary); }

.phone-photo-body {
  padding: 1.25rem 1.5rem 1.5rem;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.25rem;
}

.phone-photo-option {
  border: 1px solid var(--border-light);
  padding: 1.1rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  margin: 0;
}

.phone-photo-qr {
  width: 150px;
  height: 150px;
  background: #ffffff;
}

.phone-photo-qr svg { display: block; width: 100%; height: 100%; }

.phone-photo-qr.is-unavailable {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: calc(0.85rem + var(--text-bump));
  color: var(--text-muted);
  border: 1px dashed var(--border-light);
}

.phone-photo-option-label {
  font-family: var(--font-ui);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  font-size: calc(0.85rem + var(--text-bump));
  color: var(--text-primary);
  margin: 0.9rem 0 0.3rem;
}

.phone-photo-option-note {
  color: var(--text-muted);
  font-size: calc(0.95rem + var(--text-bump));
  margin: 0;
  line-height: 1.5;
}

/* The other half: a file already on this computer. */
.phone-photo-drop {
  border: 1px dashed var(--border-medium);
  background: #fcfcfc;
  justify-content: center;
  transition: background var(--transition-fast), border-color var(--transition-fast);
}

.phone-photo-drop.is-over {
  border-color: var(--teal-accent);
  background: var(--teal-light);
}

.phone-photo-drop-icon {
  font-size: calc(2rem + var(--text-bump));
  color: var(--teal-accent);
}

.phone-photo-person {
  width: 100%;
  margin: 0.85rem 0 0.6rem;
  min-height: var(--tap, 44px);
  padding: 0.4rem 0.5rem;
  border: 1px solid var(--border-light);
  background: var(--bg-primary);
  color: var(--text-primary);
  font-family: var(--font-body);
  font-size: calc(0.9rem + var(--text-bump));
}

.phone-photo-file {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
}

.phone-photo-browse {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--tap, 44px);
  background: none;
  border: 1px solid var(--teal-accent);
  color: var(--teal-ink);
  font-family: var(--font-ui);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: calc(0.9rem + var(--text-bump));
  padding: 0.55rem 1.75rem;
  margin: 0.85rem 0 0.35rem;
  cursor: pointer;
}

.phone-photo-browse:hover { background: var(--teal-light); }

/* The real input is offscreen, so its ring has to show on the label that
   stands in for it. Same tokens as every other ring in the app. */
.phone-photo-file:focus-visible ~ .phone-photo-browse {
  outline: var(--focus-ring-width) solid var(--focus-ring-color);
  outline-offset: var(--focus-ring-offset);
}

/* Footer: the live status and the way out. */
.phone-photo-foot {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.9rem 1.5rem;
  background: var(--bg-secondary);
  border-top: 1px solid var(--border-light);
}

.phone-photo-foot form { margin: 0 0 0 auto; }

.phone-photo-status {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  color: var(--text-muted);
  font-size: calc(1rem + var(--text-bump));
}

.phone-photo-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--gold-dark, #DF9A32);
  flex-shrink: 0;
}

.phone-photo-status.is-done .phone-photo-dot { background: var(--teal-accent); }
.phone-photo-status.is-done .phone-photo-status-text { color: var(--teal-ink); }
.phone-photo-status.is-error .phone-photo-dot { background: #c0392b; }
.phone-photo-status.is-error .phone-photo-status-text { color: #a3241b; }

.phone-photo-done {
  background: none;
  border: 1px solid var(--border-light);
  color: var(--text-primary);
  font-family: var(--font-ui);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: calc(0.9rem + var(--text-bump));
  padding: 0.55rem 1rem;
  min-height: var(--tap, 44px);
  cursor: pointer;
}

.phone-photo-done:hover { background: var(--bg-primary); }

@media (max-width: 560px) {
  .phone-photo-body { grid-template-columns: 1fr; }
}

/* ══════════════════════════════════════════════════════════════════════════
   The People gallery — the photo-forward board under the relationship map.
   Transcribed from docs/design-reference/extracted/people-gallery-portrait
   .html; the prototype's literals are mapped onto the app's tokens (fonts,
   teal/gold, borders, the three elevations). The prototype's Frame/Circle
   card styles were prototype artifacts — the owner settled on Portrait
   (2026-08-11) and the variants were removed.
   ══════════════════════════════════════════════════════════════════════════ */
.people-gallery {
  margin: 0 0 2.5rem;
  /* The slate card tint has no app token (teal and gold do); local vars keep
     the rotation in one place and give dark theme one knob. */
  --people-tint-slate: #eef2f3;
  --people-slate-accent: #83A9B2;
}

[data-theme="dark"] .people-gallery {
  --people-tint-slate: #2e3538;
}

/* ── Head: the two counts, and the ways to add ──────────────────────────── */
.people-gallery-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1rem 2rem;
  flex-wrap: wrap;
  margin-bottom: 1.25rem;
}

.people-gallery-count {
  font-family: var(--font-ui);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  font-size: calc(0.95rem + var(--text-bump));
  color: var(--text-muted);
  margin: 0;
}

.people-gallery-actions {
  display: flex;
  align-items: stretch;
  gap: 0.6rem;
  flex-shrink: 0;
}

/* The phone launcher keeps its own markup (the QR panel is its passenger); in
   the gallery head it sits in the actions row instead of floating right. */
.people-gallery-actions .phone-photo-launcher {
  margin: 0;
}

/* ── "Add person" menu: nine categories behind one button ───────────────── */
.people-add-menu {
  position: relative;
}

.people-add-menu-summary {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-height: var(--tap, 44px);
  padding: 0.55rem 1rem;
  background: var(--teal-accent);
  border: 1px solid var(--teal-accent);
  color: #ffffff;
  font-family: var(--font-ui);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: calc(0.9rem + var(--text-bump));
  cursor: pointer;
  list-style: none;
  transition: background var(--transition-fast);
}

.people-add-menu-summary::-webkit-details-marker { display: none; }

@media (hover: hover) {
  .people-add-menu-summary:hover { background: var(--teal-fill); border-color: var(--teal-fill); }
}

.people-add-menu-list {
  position: absolute;
  right: 0;
  top: calc(100% + 0.4rem);
  z-index: 30;
  min-width: 17rem;
  margin: 0;
  padding: 0.35rem;
  list-style: none;
  background: var(--bg-primary);
  border: 1px solid var(--border-light);
  box-shadow: var(--shadow-md);
}

.people-add-menu-item {
  display: block;
  width: 100%;
  min-height: var(--tap, 44px);
  padding: 0.55rem 0.8rem;
  background: none;
  border: none;
  text-align: left;
  font-family: var(--font-body);
  font-size: calc(0.95rem + var(--text-bump));
  color: var(--text-primary);
  cursor: pointer;
}

@media (hover: hover) {
  .people-add-menu-item:hover { background: var(--teal-light); color: var(--teal-ink); }
}

/* ── Toolbar: filter chips and the card-style switch ────────────────────── */
.people-gallery-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem 1.5rem;
  flex-wrap: wrap;
  padding-bottom: 1.25rem;
  border-bottom: 1px solid var(--border-light);
  margin-bottom: 2.25rem;
}

.people-gallery-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 0;
}

.people-chip {
  min-height: var(--tap, 44px);
  padding: 0.5rem 0.85rem;
  border: 1px solid var(--border-light);
  background: var(--bg-primary);
  color: var(--text-muted);
  font-family: var(--font-ui);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: calc(0.9rem + var(--text-bump));
  cursor: pointer;
  transition: color var(--motion-quick, 150ms) var(--ease-out, ease),
              border-color var(--motion-quick, 150ms) var(--ease-out, ease),
              background var(--motion-quick, 150ms) var(--ease-out, ease);
}

@media (hover: hover) {
  .people-chip:hover {
    border-color: var(--teal-accent);
    color: var(--teal-ink);
  }
}

.people-chip[aria-pressed="true"] {
  border-color: var(--teal-accent);
  background: var(--teal-accent);
  color: #ffffff;
}

.people-chip-count {
  opacity: 0.55;
  margin-left: 0.45rem;
}

/* ── Category sections ──────────────────────────────────────────────────── */
.people-gallery-section {
  margin-bottom: 3rem;
}

.people-gallery-section-head {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin-bottom: 1.25rem;
  border-radius: var(--radius-panel);
  transition: background var(--motion-quick, 150ms) var(--ease-out, ease),
              box-shadow var(--motion-quick, 150ms) var(--ease-out, ease);
}

.people-gallery-section-icon {
  width: 44px;
  height: 44px;
  flex-shrink: 0;
  background: var(--teal-light);
  border-radius: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--teal-accent);
  font-size: calc(1.4rem + var(--text-bump));
}

.people-gallery-section-titles { min-width: 0; }

.people-gallery-section-title {
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: calc(1.5rem + var(--text-bump));
  color: var(--text-heading);
  margin: 0;
  line-height: 1.2;
}

.people-gallery-section-link {
  color: inherit;
  text-decoration: none;
}

@media (hover: hover) {
  .people-gallery-section-link:hover { color: var(--teal-ink); }
}

.people-gallery-section-desc {
  color: var(--text-muted);
  font-size: calc(1rem + var(--text-bump));
  margin: 0.1rem 0 0;
}

.people-gallery-section-rule {
  flex: 1 1 0;
  height: 1px;
  background: var(--border-light);
}

.people-gallery-section-count {
  font-family: var(--font-ui);
  letter-spacing: 0.1em;
  font-size: calc(1.05rem + var(--text-bump));
  color: var(--teal-ink);
  background: var(--teal-light);
  padding: 0.2rem 0.7rem;
}

/* ── The card grid (semantically a list) ────────────────────────────────── */
.people-card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: 1.25rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* ── Cards — base rules are the Portrait style ──────────────────────────── */
.people-card.tint-0 { --card-tint: var(--teal-light); --card-accent: var(--teal-accent); }
.people-card.tint-1 { --card-tint: var(--people-tint-slate); --card-accent: var(--people-slate-accent); }
.people-card.tint-2 { --card-tint: var(--gold-light); --card-accent: var(--gold); }

/* The card is a flippable pair of faces, so the visual box (background,
   border, overflow, shadow) lives on the FACES; the li itself is only the
   grid cell, the tint variables, and the 3D stage. */
.people-card {
  position: relative;
  border-radius: var(--radius-panel-lg);
  perspective: 1000px;
  transition: transform var(--motion-quick, 150ms) var(--ease-out, ease);
}

@media (hover: hover) {
  .people-card:hover {
    transform: translateY(-2px);
  }

  .people-card:hover .people-card-front,
  .people-card:hover .people-card-back {
    box-shadow: var(--shadow-md);
  }
}

/* ── The flip ────────────────────────────────────────────────────────────────
   Motion tier: --motion-enter with --ease-in-out. A face turning over is
   content entering/leaving the card — more than a hover flourish (quick),
   nowhere near a progress moment (ceremony) — and the movement stays within
   the screen, which is what the in-out curve is for. */
.people-card-flip {
  position: relative;
  height: 100%;
  transform-style: preserve-3d;
  transition: transform var(--motion-enter, 250ms) var(--ease-in-out, ease-in-out);
}

.people-card.is-flipped .people-card-flip { transform: rotateY(180deg); }

.people-card-front,
.people-card-back {
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  border-radius: inherit;
  overflow: hidden;
  box-shadow: var(--shadow-sm);
  transition: box-shadow var(--motion-quick, 150ms) var(--ease-out, ease);
}

.people-card-front {
  position: relative;
  height: 100%;
  background: var(--card-tint);
}

/* The notes face: name up top, the notes with room to scroll (never clamped),
   the category/role line and EDIT at the foot. Same footprint as the front —
   it sits rotated behind it. */
.people-card-back {
  position: absolute;
  inset: 0;
  transform: rotateY(180deg);
  display: flex;
  flex-direction: column;
  text-align: left;
  background: var(--surface-card);
  border: 1px solid var(--border-light);
  padding: 0.85rem 0.95rem 0.9rem;
}

/* The head never grows past its share: a long name used to push the whole
   column down and take EDIT out of the card's hidden overflow, so the one
   control on the face became unreachable (owner, 2026-08-18). */
.people-card-back-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.4rem;
  border-bottom: 2px solid var(--card-accent);
  padding-bottom: 0.45rem;
  flex: none;
}

.people-card-back-name {
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: calc(1.05rem + var(--text-bump));
  line-height: 1.25;
  color: var(--text-heading);
  margin: 0;
  min-width: 0;
  /* Three lines and then an ellipsis. The full name is on the front of the
     card and in the dialog this face opens. */
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
  overflow-wrap: anywhere;
}

.people-card-back-close {
  background: none;
  border: none;
  color: var(--text-muted);
  font-size: calc(0.95rem + var(--text-bump));
  line-height: 1;
  cursor: pointer;
  padding: 0.35rem;
  margin: -0.2rem -0.3rem 0 0;
  flex: 0 0 auto;
}

.people-card-back-close:hover { color: var(--text-heading); }

/* The back's fact list: every present field (relationship, role, ...). */
.people-card-back-facts {
  flex: none;
  margin: 0.5rem 0 0;
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}
.people-card-back-facts div { display: flex; gap: 0.4rem; align-items: baseline; min-width: 0; }
.people-card-back-facts dt {
  font-family: var(--font-ui);
  text-transform: uppercase;
  letter-spacing: 0.07em;
  font-size: calc(0.68rem + var(--text-bump));
  color: var(--text-muted);
  flex: none;
}
.people-card-back-facts dd {
  margin: 0;
  font-size: calc(0.88rem + var(--text-bump));
  color: var(--text-body);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.people-card-back-notes {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  margin: 0.6rem 0;
  font-size: calc(0.92rem + var(--text-bump));
  line-height: 1.55;
  color: var(--text-body);
}

.people-card-back-notes p { margin: 0 0 0.55em; }
.people-card-back-notes p:last-child { margin-bottom: 0; }

.people-card-back-empty { color: var(--text-muted); }

/* Two rows: the meta line, then one compact action row — photo icons on the
   left, EDIT pushed right. Kept tight so the notes above own the card. */
/* The foot holds its ground: EDIT is the only control on this face, so it is
   the last thing that may be squeezed out of the card. */
.people-card-back-foot {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.45rem;
  border-top: 1px solid var(--border-light);
  padding-top: 0.55rem;
  flex: none;
  margin-top: auto;
}

.people-card-back-foot .people-card-back-meta {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden; flex-basis: 100%; }

.people-card-back-foot .people-card-back-edit { margin-left: auto; }

.people-card-back-meta {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  font-family: var(--font-ui);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: calc(0.7rem + var(--text-bump));
  color: var(--text-muted);
  margin: 0;
  min-width: 0;
}

.people-card-back-edit {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  flex: 0 0 auto;
  background: none;
  border: 1px solid var(--teal-accent);
  color: var(--teal-ink);
  font-family: var(--font-ui);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: calc(0.78rem + var(--text-bump));
  padding: 0.3rem 0.65rem;
  min-height: var(--tap, 44px);
  cursor: pointer;
  transition: background var(--transition-fast);
}

.people-card-back-edit:hover { background: var(--teal-light); }

/* Photo management on the back: two bordered icon buttons in the foot's
   single action row, so the notes above keep the card's height. The forms
   stay in flow (the front chip's form is absolutely positioned; these must
   not be). */
.people-card-back-photo-form { display: inline-flex; margin: 0; }

.people-card-back-photo-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--tap, 44px);
  min-height: var(--tap, 44px);
  background: none;
  border: 1px solid var(--border-medium);
  padding: 0;
  color: var(--text-muted);
  font-size: calc(0.95rem + var(--text-bump));
  cursor: pointer;
  transition: color var(--transition-fast), border-color var(--transition-fast);
}

@media (hover: hover) {
  .people-card-back-photo-btn:hover { color: var(--teal-ink); border-color: var(--teal-accent); }
  .people-card-back-photo-remove:hover { color: var(--status-danger, #b02020); border-color: var(--status-danger, #b02020); }
}

/* Under prefers-reduced-motion the global block pins durations to 1ms, but a
   3D rotation still visually JUMPS through a mirrored mid-state — so the flip
   degrades explicitly to a plain crossfade: no rotation at all, the faces
   swap by opacity (instantly, per the pinned durations). The inert attribute
   keeps the hidden face out of reach either way. */
@media (prefers-reduced-motion: reduce) {
  .people-card-flip,
  .people-card.is-flipped .people-card-flip { transform: none; }

  .people-card-front,
  .people-card-back {
    backface-visibility: visible;
    -webkit-backface-visibility: visible;
    transition: opacity 1ms linear;
  }

  .people-card-back { transform: none; opacity: 0; }
  .people-card.is-flipped .people-card-back { opacity: 1; }
  .people-card.is-flipped .people-card-front { opacity: 0; }
}

.people-card-media {
  position: relative;
  width: 100%;
  aspect-ratio: 3 / 4;
}

.people-card-photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.people-card-scrim {
  position: absolute;
  inset: auto 0 0;
  height: 55%;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.75), rgba(0, 0, 0, 0.15) 60%, rgba(0, 0, 0, 0));
  pointer-events: none;
}

.people-card-initials {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-heading);
  font-size: calc(3.4rem + var(--text-bump));
  letter-spacing: 0.03em;
  color: var(--card-accent);
  opacity: 0.5;
}

.people-card-body {
  position: absolute;
  inset: auto 0 0;
  padding: 0 1rem 1rem;
}

.people-card-name {
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: calc(1.2rem + var(--text-bump));
  line-height: 1.2;
  text-wrap: pretty;
  color: var(--text-heading);
  margin: 0;
}

.people-card.has-photo .people-card-name { color: #ffffff; }

/* The name is the flip; a stretched pseudo-element makes the whole front face
   its target while the photo chip stays its own control above it. A real
   <button> now (Enter/Space flip natively, aria-expanded is honest), so it
   sheds the UA button chrome and keeps the name's type. */
.people-card-open {
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  font: inherit;
  text-align: left;
  color: inherit;
  text-decoration: none;
  cursor: pointer;
}

.people-card-open::after {
  content: '';
  position: absolute;
  inset: 0;
}

.people-card-meta {
  font-family: var(--font-ui);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  font-size: calc(0.8rem + var(--text-bump));
  color: var(--text-muted);
  margin: 0.2rem 0 0;
}

.people-card.has-photo .people-card-meta { color: rgba(255, 255, 255, 0.85); }

/* ── The "Add photo" chip (only on a card without a face) ───────────────── */
.people-card-photo-form {
  position: absolute;
  top: 0.6rem;
  right: 0.6rem;
  z-index: 2;
  margin: 0;
}

.people-card-photo-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  min-height: var(--tap, 44px);
  padding: 0.32rem 0.6rem;
  background: rgba(255, 255, 255, 0.92);
  border: 1px solid rgba(255, 255, 255, 0.92);
  color: var(--teal-ink);
  font-family: var(--font-ui);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: calc(0.75rem + var(--text-bump));
  cursor: pointer;
  transition: background var(--transition-fast), border-color var(--transition-fast);
}

@media (hover: hover) {
  .people-card-photo-chip:hover {
    background: #ffffff;
    border-color: var(--teal-accent);
  }
}

.people-card.is-uploading .people-card-photo-chip,
.people-card-photo-chip.is-uploading { opacity: 0.6; }

.people-card-photo-error {
  position: relative;
  z-index: 2;
  margin: 0;
  padding: 0.4rem 0.75rem;
  background: #fef2f2;
  color: #b91c1c;
  font-size: calc(0.8rem + var(--text-bump));
}

/* ── Tail card: "Add person into …" ─────────────────────────────────────── */
.people-card-tail {
  display: flex;
  box-shadow: none;
}

.people-card-add-form {
  display: flex;
  flex: 1 1 auto;
  margin: 0;
}

.people-card-add {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  min-height: 220px;
  border: 1px dashed var(--border-medium);
  border-radius: var(--radius-panel-lg);
  background: rgba(255, 255, 255, 0.5);
  color: var(--text-muted);
  cursor: pointer;
  padding: 1.25rem;
  transition: border-color var(--motion-quick, 150ms) var(--ease-out, ease),
              color var(--motion-quick, 150ms) var(--ease-out, ease),
              background var(--motion-quick, 150ms) var(--ease-out, ease);
}

[data-theme="dark"] .people-card-add { background: rgba(255, 255, 255, 0.04); }

@media (hover: hover) {
  .people-card-add:hover {
    border-color: var(--teal-accent);
    color: var(--teal-ink);
    background: var(--teal-light);
  }
}

.people-card-add i { font-size: calc(1.6rem + var(--text-bump)); }

.people-card-add-label {
  font-family: var(--font-ui);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  font-size: calc(0.9rem + var(--text-bump));
}

.people-card-add-into {
  font-family: var(--font-body);
  font-size: calc(0.9rem + var(--text-bump));
  line-height: 1.4;
  text-align: center;
  opacity: 0.85;
}

/* A tail card is chrome, not a person — it doesn't lift or tint. */
.people-card-tail { background: none; overflow: visible; }



/* ── Narrow viewports: the grid tightens, the wall stays a wall ─────────── */
@media (max-width: 560px) {
  .people-card-grid {
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: 0.75rem;
  }

  .people-card-add { min-height: 160px; }

  .people-gallery-toolbar { align-items: flex-start; }
}

/* ══════════════════════════════════════════════════════════════════════════
   The add/edit person dialog — same house family as the phone-photo panel:
   native <dialog>, eyebrow, serif title, X, scrim. Field chrome reuses the
   module's own .people-input; the primary action is teal ink-on-fill (the
   token pair for white words on teal, see variables.css).
   ══════════════════════════════════════════════════════════════════════════ */
.person-dialog {
  border: none;
  padding: 0;
  background: none;
  max-width: 520px;
  width: calc(100% - 2rem);
}

.person-dialog::backdrop { background: var(--overlay-scrim, rgba(0, 0, 0, 0.5)); }

.person-dialog-card {
  background: var(--bg-primary);
  box-shadow: var(--shadow-lg);
}

.person-dialog-form { margin: 0; }

.person-dialog-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.5rem 1.5rem 0;
}

.person-dialog-eyebrow {
  font-family: var(--font-ui);
  text-transform: uppercase;
  letter-spacing: var(--tracking-eyebrow, 0.12em);
  font-size: calc(0.8rem + var(--text-bump));
  color: var(--teal-ink);
  margin: 0 0 0.3rem;
}

.person-dialog-title {
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: calc(1.6rem + var(--text-bump));
  color: var(--text-heading);
  margin: 0;
}

.person-dialog-close {
  background: none;
  border: none;
  color: var(--text-muted);
  font-size: calc(1.3rem + var(--text-bump));
  line-height: 1;
  cursor: pointer;
  padding: 0.2rem;
  min-width: var(--tap, 44px);
  min-height: var(--tap, 44px);
}

.person-dialog-close:hover { color: var(--text-heading); }

/* The fields stack; a long dialog scrolls its body, not the page. */
.person-dialog-body {
  display: flex;
  flex-direction: column;
  gap: 0.95rem;
  padding: 1.25rem 1.5rem 0.25rem;
  max-height: min(58vh, 30rem);
  overflow-y: auto;
}

.person-dialog-field[hidden] { display: none; }

.person-dialog-field label {
  display: block;
  font-family: var(--font-ui);
  font-size: calc(0.8rem + var(--text-bump));
  font-weight: 600;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-bottom: 0.3rem;
}

.person-dialog-check label {
  display: flex;
  align-items: center;
  text-transform: none;
  font-family: var(--font-body);
  font-weight: normal;
  font-size: calc(0.9rem + var(--text-bump));
  color: var(--text-secondary);
  margin: 0;
}

.person-dialog-notes { min-height: 96px; }

/* VIEW mode: the whole person, read-only. */
/* The head sits outside the form now, so the view has to open its own space
   under it rather than inheriting the form body's. */
.person-dialog-view { padding: 1.25rem 1.5rem 1.25rem; }
.person-dialog-view-rows { margin: 0 0 1rem; display: flex; flex-direction: column; gap: 0.5rem; }
.person-dialog-view-rows div { display: grid; grid-template-columns: 140px 1fr; gap: 0.75rem; align-items: baseline; }
.person-dialog-view-rows dt,
.person-dialog-view-label {
  font-family: var(--font-ui);
  text-transform: uppercase;
  letter-spacing: 0.07em;
  font-size: calc(0.72rem + var(--text-bump));
  color: var(--text-muted);
  margin: 0;
}
.person-dialog-view-rows dd { margin: 0; font-size: calc(1rem + var(--text-bump)); color: var(--text-body); overflow-wrap: break-word; }
.person-dialog-view-label { margin-bottom: 0.35rem; }
.person-dialog-view-notes-body { font-size: calc(0.95rem + var(--text-bump)); line-height: 1.6; color: var(--text-body); white-space: pre-line; }
.person-dialog-view .person-dialog-foot { padding: 1rem 0 0; }

.person-dialog-foot {
  display: flex;
  justify-content: flex-end;
  padding: 1rem 1.5rem 1.5rem;
}

.person-dialog-submit {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--teal-fill);
  border: none;
  color: var(--text-on-accent, #ffffff);
  font-family: var(--font-ui);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: calc(0.9rem + var(--text-bump));
  padding: 0.65rem 1.4rem;
  min-height: var(--tap, 44px);
  cursor: pointer;
  transition: background var(--transition-fast);
}

.person-dialog-submit:hover { background: var(--teal-fill-hover); }

/* "Split into separate people": a quiet offer above the delete zone, shown
   only when an edit dialog opens on a name that reads as a list ("Alice, Bob
   & Carol"). Activating it swaps the offer for a preview — one editable input
   per proposed person — so segmentation can be fixed before committing. */
.person-dialog-split {
  border-top: 1px solid var(--border-light);
  padding: 0.6rem 1.5rem 1.1rem;
}

.person-dialog-split-offer {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  min-height: var(--tap, 44px);
  background: none;
  border: none;
  padding: 0;
  color: var(--text-muted);
  font-family: var(--font-ui);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: calc(0.78rem + var(--text-bump));
  cursor: pointer;
  transition: color var(--transition-fast);
}

@media (hover: hover) {
  .person-dialog-split-offer:hover { color: var(--teal-accent, #4a9bb5); }
}

.person-dialog-split-copy {
  font-family: var(--font-body);
  font-size: calc(0.9rem + var(--text-bump));
  color: var(--text-secondary);
  margin: 0.4rem 0 0.8rem;
}

.person-dialog-split-form { margin: 0; }

.person-dialog-split-rows {
  list-style: none;
  counter-reset: split-row;
  margin: 0 0 0.9rem;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.person-dialog-split-rows li {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  counter-increment: split-row;
}

.person-dialog-split-rows li::before {
  content: counter(split-row);
  font-family: var(--font-ui);
  font-size: calc(0.8rem + var(--text-bump));
  color: var(--text-muted);
  min-width: 1.1rem;
  text-align: right;
}

.person-dialog-split-rows li input { flex: 1; }

.person-dialog-split-actions {
  display: flex;
  align-items: center;
  gap: 0.9rem;
}

.person-dialog-split-submit[disabled] {
  opacity: 0.5;
  cursor: not-allowed;
}

.person-dialog-split-cancel {
  background: none;
  border: none;
  padding: 0;
  min-height: var(--tap, 44px);
  color: var(--text-muted);
  font-family: var(--font-ui);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: calc(0.78rem + var(--text-bump));
  cursor: pointer;
  transition: color var(--transition-fast);
}

@media (hover: hover) {
  .person-dialog-split-cancel:hover { color: var(--text-secondary); }
}

/* The danger zone: delete sits under the save form, quiet until hovered,
   and only ever rendered in edit mode. */
.person-dialog-danger {
  border-top: 1px solid var(--border-light);
  padding: 0.6rem 1.5rem 1.1rem;
}

/* Two acts, not one, when the person exists somewhere else: remove reads as
   the ordinary one and delete keeps the danger. */
.person-dialog-delete-form {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem 1.5rem;
}

.person-dialog-remove {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  min-height: var(--tap, 44px);
  background: none;
  border: none;
  padding: 0;
  color: var(--text-secondary);
  font-family: var(--font-ui);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: calc(0.78rem + var(--text-bump));
  cursor: pointer;
  transition: color var(--transition-fast);
}

@media (hover: hover) {
  .person-dialog-remove:hover { color: var(--teal-ink); }
}

.person-dialog-delete {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  min-height: var(--tap, 44px);
  background: none;
  border: none;
  padding: 0;
  color: var(--text-muted);
  font-family: var(--font-ui);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: calc(0.78rem + var(--text-bump));
  cursor: pointer;
  transition: color var(--transition-fast);
}

@media (hover: hover) {
  .person-dialog-delete:hover { color: var(--status-danger, #b02020); }
}

/* ── From your action areas ───────────────────────────────────────────────
   One row per person named in a "Who can help me?" cell, with where they were
   named and whether they are already on the map (People::RoadmapMentions).
   The panel used to print each cell whole with a single button under it. */
.people-cross-ref-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.15rem;
}

.people-cross-ref-item {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.7rem 0;
  border-bottom: 1px solid var(--border-light);
}

.people-cross-ref-item:last-child { border-bottom: 0; }

.people-cross-ref-who {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  min-width: 0;
}

.people-cross-ref-name {
  font-family: var(--font-heading);
  font-size: calc(16px * var(--text-scale));
  color: var(--text-dark);
}

.people-cross-ref-where {
  font-family: var(--font-ui);
  font-size: calc(12px * var(--text-scale));
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.people-cross-ref-status {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-family: var(--font-body);
  font-size: calc(13.5px * var(--text-scale));
  color: var(--teal-ink);
  white-space: nowrap;
}

/* Unmapped rows push their button to the right where the status would be. */
.people-cross-ref-item:not(.is-mapped) .people-cross-ref-add { margin-left: auto; }

.people-cross-ref-add { white-space: nowrap; }

/* "This updates them everywhere" — said inline while the member is typing a
   field that belongs to the human rather than the seat. Information, not a
   warning: editing one record in two places is the point of the feature. */
.person-dialog-everywhere {
  display: flex;
  align-items: flex-start;
  gap: 0.4rem;
  margin: 0.45rem 0 0;
  padding: 0.45rem 0.6rem;
  background: var(--teal-light);
  color: var(--teal-ink);
  font-size: calc(13px * var(--text-scale, 1));
  line-height: 1.45;
}

.person-dialog-everywhere i { margin-top: 0.15rem; }

/* Existing vs still needed, said as two words rather than a negated
   checkbox (owner, 2026-08-18). */
.person-dialog-label {
  display: block;
  margin-bottom: 0.35rem;
  font-family: var(--font-ui);
  text-transform: uppercase;
  letter-spacing: 0.07em;
  font-size: calc(0.72rem + var(--text-bump));
  color: var(--text-secondary);
}

/* One frame, two halves, no gutter. The labels were inline, so the frame
   carried a baseline gap under them and the checked fill stopped short of its
   own border (owner, 2026-08-18). Flex all the way down, and the frame clips
   the fill rather than the fill trying to meet it. */
.person-dialog-seg {
  display: inline-flex;
  align-items: stretch;
  border: 1px solid var(--border-medium);
  overflow: hidden;
}

/* Scoped through the frame on purpose: `.person-dialog-field label` sets
   display:block and a bottom margin, which beat a bare class and left the
   label taller than its own fill. */
.person-dialog-seg label.person-dialog-seg-opt {
  display: flex;
  position: relative;
  margin: 0;
}

.person-dialog-seg label.person-dialog-seg-opt input {
  position: absolute;
  inset: 0;
  opacity: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  cursor: pointer;
}

.person-dialog-seg label.person-dialog-seg-opt span {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0.5rem 1.1rem;
  font-family: var(--font-ui);
  font-size: calc(13px * var(--text-scale, 1));
  letter-spacing: 0.05em;
  line-height: 1;
  white-space: nowrap;
  color: var(--text-secondary);
  cursor: pointer;
  transition: background var(--transition-fast), color var(--transition-fast);
}

.person-dialog-seg-opt + .person-dialog-seg label.person-dialog-seg-opt span {
  border-left: 1px solid var(--border-medium);
}

.person-dialog-seg label.person-dialog-seg-opt input:checked + span {
  background: var(--teal-fill);
  color: var(--text-on-accent);
}

.person-dialog-seg label.person-dialog-seg-opt input:focus-visible + span {
  outline: var(--focus-ring-width) solid var(--focus-ring-color);
  outline-offset: -2px;
}

/* A card for somebody the member wants but does not yet have. */
.people-card-needed {
  display: flex;
  align-items: center;
  gap: 0.3rem;
  margin: 0.15rem 0 0;
  font-family: var(--font-ui);
  font-size: calc(11.5px * var(--text-scale, 1));
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--gold-dark);
}
