/* Kinship Globe — chrome deliberately kept to the same weight as the radial
   tree: a full-bleed canvas, a floating HUD, one control bar, everything else
   behind a panel or modal. */

* { margin: 0; padding: 0; box-sizing: border-box; }

/* A class-level display value outranks the hidden attribute, so state it once. */
[hidden] { display: none !important; }

/* Light mode is a separate palette, not an inversion: the globe's own material
   changes with it (see THEMES in globe.js), and the chrome follows. */
html[data-theme="light"] body {
  --bg: #eaeef6;
  --surface: rgba(250, 252, 255, 0.95);
  --text: #3d4a5c;
  --textBright: #16202e;
  --textMuted: #7b8798;
  --border: rgba(40, 60, 90, 0.16);
  --btnBg: rgba(255, 255, 255, 0.86);
  --btnBorder: rgba(40, 60, 90, 0.14);
  --accent: #1668b8;
  --scrim: rgba(238, 242, 248, 0.9);
  --halo: rgba(120, 150, 200, 0.20);
  --haloMid: rgba(150, 172, 210, 0.09);
  --grainAlpha: 0.30;
  --grainBlend: overlay;
}
html[data-theme="light"] dialog::backdrop { background: rgba(20, 30, 45, 0.42); }

body {
  --bg: #050a1a;
  --surface: rgba(6, 6, 18, 0.94);
  --text: #b0b0c0;
  --textBright: #dcdce8;
  --textMuted: #505068;
  --border: rgba(90, 90, 120, 0.18);
  --btnBg: rgba(14, 14, 28, 0.85);
  --btnBorder: rgba(80, 80, 110, 0.15);
  --accent: #4a9eff;
  --scrim: rgba(10, 10, 22, 0.9);
  --halo: rgba(46, 74, 158, 0.40);
  --haloMid: rgba(28, 34, 92, 0.22);
  --grainAlpha: 0.22;
  --grainBlend: screen;
  /* Flat near-black made the globe look pasted onto nothing. A wide halo behind
     it and a little grain give the field some air without becoming scenery:
     the canvas clears to transparent, so this costs nothing per frame. */
  background-color: var(--bg);
  /* Deep field rather than near-black: a cool nebula centred behind the globe
     and a second, warmer one thrown off to one side, so the sky has a colour
     and a direction instead of just being dark. */
  background-image:
    radial-gradient(78% 58% at 76% 22%,
      rgba(96, 46, 128, 0.20) 0%, rgba(58, 30, 86, 0.08) 48%, rgba(0, 0, 0, 0) 74%),
    radial-gradient(115% 88% at 50% 44%,
      var(--halo) 0%, var(--haloMid) 46%, rgba(0, 0, 0, 0) 76%);
  background-repeat: no-repeat, no-repeat;
  background-attachment: fixed;
  color: var(--text);
  overflow: hidden;
  touch-action: none;
  overscroll-behavior: none;
  -webkit-text-size-adjust: 100%;
  -webkit-user-select: none;
  user-select: none;
  font-family: system-ui, -apple-system, sans-serif;
}

/* The canvas owns every gesture over it: no browser pan, no pinch-zoom, no
   double-tap zoom. The globe has its own zoom and its own drag. */
#globe { display: block; cursor: grab; outline: none; touch-action: none; }
#globe.dragging { cursor: grabbing; }
#globe:focus-visible { box-shadow: inset 0 0 0 2px var(--accent); }

body::after {
  content: ''; position: fixed; inset: 0; z-index: 0; pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.95' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='gamma' exponent='4'/%3E%3CfeFuncG type='gamma' exponent='4'/%3E%3CfeFuncB type='gamma' exponent='4'/%3E%3C/feComponentTransfer%3E%3CfeColorMatrix type='matrix' values='0.52 0 0 0 0 0 0.60 0 0 0 0 0 1 0 0 0 0 0 1 0'/%3E%3C/filter%3E%3Crect width='240' height='240' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 240px 240px;
  opacity: var(--grainAlpha);
  mix-blend-mode: var(--grainBlend);
}
#globe { position: relative; z-index: 1; }

/* Zoomed into a language the globe fills the frame, and the title and the site
   links end up over lit ocean instead of empty space. A soft scrim gives them
   their contrast back without drawing a bar across the top of the picture. */
body::before {
  content: ''; position: fixed; inset: 0 0 auto 0; height: 96px; z-index: 90;
  pointer-events: none;
  background: linear-gradient(to bottom, var(--scrim), transparent);
}

.hud {
  position: fixed; top: 20px; left: 50%; transform: translateX(-50%);
  text-align: center; z-index: 100; pointer-events: none; max-width: 92vw;
}
.hud h1 {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-weight: 300; font-size: 36px; letter-spacing: 7px;
  text-transform: uppercase; color: var(--textBright);
}

/* Attribution under the title, deliberately quiet: the page has its own name
   now, and this says where it comes from without competing with it. */
.hud-sub {
  margin-top: 4px; font-size: 10px; letter-spacing: 2.4px;
  text-transform: uppercase; color: var(--textMuted);
}
.hud-sub a { color: inherit; text-decoration: none; pointer-events: auto; }
.hud-sub a:hover { color: var(--text); text-decoration: underline; }

.sites {
  position: fixed; top: 20px; right: 62px; z-index: 100;
  font-size: 10px; letter-spacing: 0.5px; text-align: right;
}
.sites { display: flex; gap: 10px; }

/* Sits opposite the title, out of the way of everything you actually operate. */
.corner-btn {
  position: fixed; top: 16px; right: 16px; z-index: 110;
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; border-radius: 50%;
  background: var(--btnBg); border: 1px solid var(--btnBorder);
  color: var(--textMuted); cursor: pointer; backdrop-filter: blur(6px);
  transition: color 0.15s, border-color 0.15s;
}
.corner-btn:hover { color: var(--textBright); border-color: var(--border); }
.corner-btn:focus-visible { outline: 1px solid var(--accent); outline-offset: 2px; }
.sites a { color: var(--textMuted); text-decoration: none; transition: color 0.15s; }
.dialog-links {
  display: flex; flex-wrap: wrap; gap: 14px;
  border-top: 1px solid var(--border); margin-top: 4px; padding-top: 12px;
}
.dialog-links a {
  color: var(--accent); text-decoration: none; font-size: 12px;
  letter-spacing: 0.3px;
}
.dialog-links a:hover { text-decoration: underline; }
.sites a:hover { color: var(--textBright); }

.tip {
  position: fixed; background: var(--surface); border: 1px solid var(--border);
  border-radius: 5px; padding: 9px 13px; max-width: 300px;
  pointer-events: none; opacity: 0; transition: opacity 0.1s;
  z-index: 1000; backdrop-filter: blur(10px); color: var(--text); font-size: 12px;
}
.tip.show { opacity: 1; }
.tip strong { display: block; color: var(--textBright); font-size: 15px; font-weight: 600; }

.legend {
  position: fixed; left: 18px; bottom: 16px; z-index: 100;
  display: flex; flex-direction: column; gap: 5px;
  font-size: 10px; color: var(--textMuted); pointer-events: none;
}
.legend-title { letter-spacing: 0.6px; text-transform: uppercase; }
.legend-row { display: flex; align-items: center; gap: 12px; }
.legend-item { display: inline-flex; align-items: center; gap: 5px; }
.legend-item i { display: inline-block; border-radius: 50%; flex: 0 0 auto; }

.hint {
  position: fixed; bottom: 58px; left: 50%; transform: translateX(-50%);
  font-size: 11px; letter-spacing: 0.4px; color: var(--textMuted);
  z-index: 100; pointer-events: none; text-align: center;
  white-space: nowrap; transition: opacity 0.8s;
}
.hint.hide { opacity: 0; }

/* Sits where the hint sits, and replaces it while a selection is live. Quiet by
   default: no border, no panel, just two lines of type over the scene. */
.readout {
  position: fixed; bottom: 84px; left: 50%; transform: translateX(-50%);
  z-index: 101; max-width: min(560px, calc(100vw - 24px));
  display: flex; flex-direction: column; gap: 3px; align-items: center;
  /* It used to sit on bare canvas, which was fine over empty space and illegible
     the moment the globe was zoomed in behind it. Same surface as the bar. */
  background: var(--btnBg); border: 1px solid var(--btnBorder);
  padding: 7px 14px; border-radius: 12px; backdrop-filter: blur(10px);
  color: var(--textMuted); font: inherit; text-align: center; cursor: pointer;
  transition: background 0.15s, color 0.15s;
}
.readout[hidden] { display: none; }
.readout:hover, .readout:focus-visible {
  border-color: var(--border); color: var(--text);
}
.readout .r-main {
  font-size: 13px; letter-spacing: 0.3px; color: var(--textBright);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  max-width: 100%;
}
.readout .r-main i {
  display: inline-block; width: 7px; height: 7px; border-radius: 50%;
  margin-right: 7px; vertical-align: middle;
}
.readout .r-more { opacity: 0.62; }
.readout .r-sub {
  font-size: 11px; letter-spacing: 0.3px; color: var(--textMuted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  max-width: 100%;
}

/* The bar is down to one decision. It is centred under a centred globe, icon
   only, and the lit half is the only colour on screen outside the data. Search
   sits beside it as a ghost glyph — reachable, but not competing with the one
   control that changes what you are looking at. Everything else moved into the
   surfaces it belongs to: the family filter into search, the reference material
   into About. */
.ctrl {
  position: fixed; bottom: calc(18px + env(safe-area-inset-bottom, 0px));
  left: 0; right: 0;
  display: flex; align-items: center; justify-content: center; gap: 10px;
  z-index: 100; padding: 0 12px; pointer-events: none;
}
.ctrl > * { pointer-events: auto; }

/* Three exclusive views in one control: shared shell, one lit segment. */
.seg {
  display: inline-flex; align-items: stretch; overflow: hidden;
  background: var(--btnBg); border: 1px solid var(--btnBorder);
  border-radius: 999px; backdrop-filter: blur(10px);
}
.seg-opt {
  display: inline-flex; align-items: center; justify-content: center;
  width: 46px; min-height: 40px; padding: 0;
  border: none; background: none; cursor: pointer;
  color: var(--textMuted); transition: color 0.15s, background 0.15s;
}
.seg-opt + .seg-opt { border-left: 1px solid var(--btnBorder); }
.seg-opt svg { display: block; }
.seg-opt:hover { color: var(--text); }
.seg-opt.is-on {
  background: color-mix(in srgb, var(--accent) 18%, transparent);
  color: var(--accent);
}
.seg-opt:focus-visible { outline: 1px solid var(--accent); outline-offset: -2px; }

/* One tap, one state. The icon shows the state you are in now, and the accent
   fill says it is on — so the control never has to be read to be understood. */
.pill-toggle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 46px; min-height: 40px; padding: 0;
  background: var(--btnBg); border: 1px solid var(--btnBorder);
  border-radius: 999px; backdrop-filter: blur(10px);
  color: var(--textMuted); cursor: pointer;
  transition: color 0.15s, background 0.15s, border-color 0.15s;
}
.pill-toggle:hover { color: var(--text); }
.pill-toggle.is-on {
  background: color-mix(in srgb, var(--accent) 18%, var(--btnBg));
  border-color: color-mix(in srgb, var(--accent) 42%, var(--btnBorder));
  color: var(--accent);
}
.pill-toggle:focus-visible { outline: 1px solid var(--accent); outline-offset: 2px; }
.pill-toggle svg { display: block; }
.pill-toggle .i-on { display: none; }
.pill-toggle .i-off { display: block; }
.pill-toggle.is-on .i-on { display: block; }
.pill-toggle.is-on .i-off { display: none; }

.switch {
  display: inline-flex; align-items: stretch; overflow: hidden;
  background: var(--btnBg); border: 1px solid var(--btnBorder);
  border-radius: 999px; backdrop-filter: blur(10px);
}
.switch-opt {
  display: inline-flex; align-items: center; justify-content: center;
  width: 54px; min-height: 40px; padding: 0;
  border: none; background: none; cursor: pointer;
  color: var(--textMuted); transition: color 0.15s, background 0.15s;
}
.switch-opt + .switch-opt { border-left: 1px solid var(--btnBorder); }
.switch-opt svg { display: block; }
.switch-opt:hover { color: var(--text); }
.switch-opt.is-on {
  background: color-mix(in srgb, var(--accent) 16%, transparent);
  color: var(--accent);
}
.switch-opt:focus-visible { outline: 1px solid var(--accent); outline-offset: -2px; }

.ghost-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; border-radius: 50%;
  background: none; border: 1px solid transparent;
  color: var(--textMuted); cursor: pointer;
  transition: color 0.15s, border-color 0.15s, background 0.15s;
}
.ghost-btn:hover, .ghost-btn.is-on {
  color: var(--textBright); background: var(--btnBg); border-color: var(--btnBorder);
}
.ghost-btn:focus-visible { outline: 1px solid var(--accent); outline-offset: 2px; }

/* The family filter is a scope control, so it lives with search and reads as a
   labelled field rather than another button in the chrome. */
.panel-field { display: flex; align-items: center; gap: 10px; }
.panel-field > span {
  color: var(--textMuted); font-size: 10px; letter-spacing: 0.8px;
  text-transform: uppercase; flex: 0 0 auto;
}
.panel-field select {
  flex: 1 1 auto; min-width: 0; min-height: 34px; padding: 0 8px;
  background: var(--btnBg); border: 1px solid var(--btnBorder);
  border-radius: 4px; color: var(--text); font-family: inherit; font-size: 13px;
}
.panel-field select:focus { outline: none; border-color: var(--accent); }

/* The two dismiss buttons left in the markup — panel close and modal close.
   These lost their rule when the control bar was rebuilt and were rendering as
   raw browser buttons, grey and bevelled, inside dark surfaces. */
.icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; padding: 0; flex: 0 0 auto;
  background: none; border: none; border-radius: 6px;
  color: var(--textMuted); cursor: pointer; appearance: none;
  transition: color 0.15s, background 0.15s;
}
.icon-btn:hover {
  color: var(--textBright);
  background: color-mix(in srgb, var(--text) 10%, transparent);
}
.icon-btn:focus-visible { outline: 1px solid var(--accent); outline-offset: 1px; }
.icon-btn svg { display: block; }

/* Opens a modal and goes away again: no chrome at all. */
.quiet-btn {
  background: none; border: none; cursor: pointer; padding: 6px 2px;
  color: var(--textMuted); font-family: inherit; font-size: 12px;
  letter-spacing: 0.4px; text-decoration: underline;
  text-underline-offset: 3px; text-decoration-color: var(--btnBorder);
}
.quiet-btn:hover { color: var(--textBright); text-decoration-color: currentColor; }

.sep { width: 1px; background: var(--btnBorder); margin: 0 3px; align-self: stretch; }

/* Search + data panel */
/* The search panel expands upward out of its own control rather than arriving
   as a separate overlay: same width as the bar, anchored just above it, so it
   reads as the field opening rather than a second surface appearing. The
   reference material that used to live down here (coverage, provenance) moved
   into the About modal, which is where explaining belongs. */
.panel {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: calc(72px + env(safe-area-inset-bottom, 0px));
  width: min(420px, calc(100vw - 20px)); max-height: 54dvh;
  z-index: 900; padding: 12px 14px 14px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 12px; backdrop-filter: blur(18px); overflow-y: auto;
  display: flex; flex-direction: column; gap: 9px;
  user-select: text;
}
.panel-head {
  display: flex; align-items: center; justify-content: space-between;
  color: var(--textMuted); font-size: 10px; letter-spacing: 0.8px; text-transform: uppercase;
}
.panel input[type="search"] {
  width: 100%; min-height: 38px; padding: 0 11px;
  background: var(--btnBg); border: 1px solid var(--btnBorder); border-radius: 4px;
  color: var(--textBright); font-size: 16px; font-family: inherit;
}
.panel input[type="search"]:focus { outline: none; border-color: var(--accent); }
.result-count { font-size: 10px; color: var(--textMuted); }
.search-results { display: grid; gap: 3px; max-height: 34vh; overflow-y: auto; }
.result-button {
  display: grid; grid-template-columns: 1fr auto; gap: 2px 8px;
  min-height: 38px; padding: 6px 9px; text-align: left; cursor: pointer;
  background: transparent; border: 1px solid transparent; border-radius: 4px;
  color: var(--text); font-family: inherit;
}
.result-button:hover { background: var(--btnBg); border-color: var(--btnBorder); }
.result-button strong { font-size: 13px; color: var(--textBright); font-weight: 500; }
.result-button span, .result-button small { color: var(--textMuted); font-size: 10px; }
.result-button small { grid-column: 1 / -1; }

.selection { border-top: 1px solid var(--border); padding-top: 10px; }
.selection h3 {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-weight: 500; font-size: 22px; color: var(--textBright);
}
.selection dl { display: grid; grid-template-columns: 84px 1fr; gap: 6px 10px; margin: 10px 0; font-size: 12px; }
.selection dt { color: var(--textMuted); }
.selection dd { margin: 0; overflow-wrap: anywhere; }
.text-btn {
  background: none; border: none; color: var(--accent);
  font-size: 12px; cursor: pointer; padding: 4px 0; font-family: inherit;
}

.fold { border-top: 1px solid var(--border); padding-top: 8px; }
.fold summary { cursor: pointer; font-size: 12px; color: var(--text); padding: 4px 0; }
.fold summary:hover { color: var(--textBright); }
.fold p { margin: 6px 0; font-size: 11px; line-height: 1.55; color: var(--textMuted); }
.fold code { font-family: ui-monospace, monospace; font-size: 10px; color: var(--text); }
.swatch {
  display: inline-block; width: 8px; height: 8px; border-radius: 50%;
  margin-right: 6px; vertical-align: baseline; flex: 0 0 auto;
}
.table-scroll { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; font-size: 11px; margin-top: 6px; }
caption { padding: 0 0 8px; color: var(--textMuted); text-align: left; font-size: 10px; }
th, td { padding: 6px 4px; border-bottom: 1px solid var(--border); text-align: right; white-space: nowrap; }
th { color: var(--textMuted); font-weight: 400; }
th:first-child, td:first-child { text-align: left; white-space: normal; }

#loading {
  position: fixed; inset: 0; display: flex; align-items: center;
  justify-content: center; flex-direction: column;
  background: var(--bg); z-index: 2000; transition: opacity 0.4s;
}
#loading.hide { opacity: 0; pointer-events: none; visibility: hidden; }
.spinner {
  width: 28px; height: 28px; border: 2px solid var(--btnBorder);
  border-top-color: var(--accent); border-radius: 50%;
  animation: spin 0.7s linear infinite; margin-bottom: 14px;
}
@keyframes spin { to { transform: rotate(360deg); } }
#loading h2 {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-weight: 300; font-size: 28px; letter-spacing: 4px; color: var(--textBright);
}
#loading p { font-size: 13px; color: var(--textMuted); margin-top: 5px; }

dialog {
  max-width: 460px; width: calc(100vw - 32px); padding: 20px 22px;
  /* Centre it and let long copy scroll inside rather than pinning to the top
     edge. dvh so an iOS URL bar appearing does not clip the last line. */
  margin: auto; max-height: calc(100dvh - 40px); overflow-y: auto;
  background: var(--surface); color: var(--text);
  border: 1px solid var(--border); border-radius: 8px;
  backdrop-filter: blur(18px); user-select: text;
}
/* showModal() otherwise focuses the close button, which Safari rings in bright
   blue over dark chrome. The dialog takes focus itself instead, so the keyboard
   still lands inside it without the button being outlined. */
dialog:focus { outline: none; }
dialog .icon-btn:focus-visible {
  outline: 1px solid var(--border); outline-offset: 2px; border-radius: 4px;
}
.dialog-head h2 { line-height: 1.15; }
dialog::backdrop { background: rgba(0, 0, 0, 0.6); }
.dialog-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.dialog-head h2 {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-weight: 500; font-size: 24px; color: var(--textBright);
}
dialog p { margin: 10px 0; font-size: 12px; line-height: 1.6; }
/* The lead states what the page is showing, so it is the brightest prose here,
   not the dimmest. It was set to --textMuted, which measured 2.6:1 against the
   dialog surface and failed WCAG AA outright. */
dialog .key { color: var(--textBright); font-size: 13px; }
dialog .fine { color: var(--text); font-size: 11.5px; }
/* Inline links in the prose had no rule at all and fell back to the browser
   default #0000EE, which is close to invisible on a near-black surface. */
dialog p a, dialog li a, dialog dd a { color: var(--accent); }
dialog p a:hover, dialog li a:hover, dialog dd a:hover { color: var(--textBright); }
dialog ul { margin: 8px 0 8px 18px; font-size: 12px; line-height: 1.6; }
dialog strong { color: var(--textBright); }

@media (max-width: 700px) {
  .hud h1 { font-size: 22px; letter-spacing: 4px; }
  .sites { display: none; }
  .hint { display: none; }

  .panel { max-height: 46dvh; }
  .search-results { max-height: 26vh; }
}

@media (prefers-reduced-motion: reduce) {
  .spinner { animation: none; }
  .hint, #loading { transition: none; }
}

/* Social-card capture: ?bare=1 leaves only the drawing. */
body.bare .hud, body.bare .sites, body.bare .corner-btn, body.bare .ctrl,
body.bare .hint, body.bare .readout, body.bare .panel, body.bare .tip,
body.bare::before { display: none !important; }
