/* Deep Field page chrome. The components themselves live in vendor/scifi-ui
   and are not restyled here beyond sizing; everything below is layout. */

:root {
  --bg: #07080B;
  --mono: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: rgb(var(--holo-ink));
  font: 400 16px/1.65 ui-sans-serif, -apple-system, "Segoe UI", Roboto, sans-serif;
  -webkit-text-size-adjust: 100%;
}

a { color: rgb(var(--holo-cyan)); }

.wrap {
  max-width: 1080px;
  margin: 0 auto;
  padding: 0 16px 80px;
}
@media (min-width: 760px) { .wrap { padding: 0 32px 96px; } }

/* shared small caps label, the page's HUD voice. Units never go in here. */
.k, .eyebrow {
  margin: 0 0 6px;
  font: 500 10px/1.3 var(--mono);
  letter-spacing: .19em;
  text-transform: uppercase;
  color: #6BA4E6;
}

/* ---- masthead ---- */
/* the banner now holds the open space the top padding used to, so the mast
   starts closer to the viewport edge. The bottom padding is the gap down to
   the button bar, kept tight so the bar reads as part of the masthead. */
.mast { padding: clamp(20px, 3vw, 40px) 0 clamp(10px, 1.6vw, 16px); }

/* the header image. A projected plate in the same language as the panels: a
   hairline edge, bloom underneath, faint scanlines, and a dissolve into the
   page along the lower edge so the image ends in the background rather than
   on a cut. Shown whole rather than cropped to a band, because the wordmark
   sits in the top corner and a crop would clip it. */
.mast-banner {
  position: relative;
  isolation: isolate;
  /* the masthead's own bottom padding spaces the plate from the button bar */
  margin: 0;
  border-radius: 10px;
  overflow: hidden;
  border: 1px solid rgb(var(--holo-line) / .14);
  background: rgb(var(--holo-panel) / .8);
  box-shadow: 0 0 30px rgb(0 0 0 / .55), 0 0 24px rgb(var(--holo-glow) / .12);
}
/* the <picture> around the banner image is inline by default; block keeps
   it from adding a line box under the image */
.mast-banner picture { display: block; }
.mast-banner img {
  display: block;
  width: 100%;
  /* the width and height attributes give the aspect ratio, so the box is
     reserved before the bytes land */
  height: auto;
}
.mast-banner::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background:
    repeating-linear-gradient(0deg,
      rgb(150 205 255 / .045) 0 1px, transparent 1px 3px),
    linear-gradient(to bottom,
      transparent 0%, transparent 60%, rgb(7 8 11 / .70) 100%);
}
/* the lit lower edge the heropanel uses, so the plate reads as projected */
.mast-banner::before {
  content: "";
  position: absolute;
  inset: auto 0 0;
  z-index: 2;
  height: 1px;
  pointer-events: none;
  background: linear-gradient(to right,
    transparent, rgb(var(--holo-beam) / .35), transparent);
}
.mast h1 {
  margin: 0 0 12px;
  font: 600 clamp(40px, 9vw, 84px)/1 var(--mono);
  letter-spacing: .08em;
  color: rgb(var(--holo-ink));
  text-shadow: 0 0 28px rgb(var(--holo-glow) / .45);
}
.lede { max-width: 60ch; margin: 0; color: #A9BDD6; }

/* ---- button bar ----
   A slim .holopanel under the masthead: a row of .chip buttons, so they look
   and behave like every other button on the page. The buttons sit in a grid
   so they stay equal widths, as many equal columns as fit and never narrower
   than the longest label. The padding at the bar's sides equals the gap
   between buttons; the top and bottom get more, so the buttons have room
   above and below them inside the panel. */
.btnbar {
  --btnbar-space: 10px;
  --btnbar-pad-y: 20px;
  display: flex;
  align-items: center;
  gap: var(--btnbar-space);
  padding: var(--btnbar-pad-y) var(--btnbar-space);
  border-radius: 12px;
}
.btnbar-btns {
  flex: 1 1 auto;
  min-width: 0;
  display: grid;
  /* 116px fits the longest label, "Transmissions", with its padding */
  grid-template-columns: repeat(auto-fit, minmax(116px, 1fr));
  gap: var(--btnbar-space);
}
/* some bar entries are links to other pages, so drop the link underline
   and let them look exactly like the <button> chips */
.btnbar-btn {
  padding: 11px 8px;
  text-align: center;
  white-space: nowrap;
  text-decoration: none;
}
/* the current view, warm like a pressed chip */
.btnbar-btn[aria-current] {
  color: rgb(var(--holo-warm));
  border-color: rgb(var(--holo-warm) / .55);
  background: rgb(var(--holo-warm) / .08);
}

section { margin-top: clamp(28px, 5vw, 48px); }
/* the first section sits closer to the button bar than sections sit to each
   other, so the bar stays with the masthead above rather than floating */
.btnbar + section { margin-top: clamp(18px, 3vw, 28px); }

h2 {
  margin: 0 0 14px;
  font: 500 12px/1.3 var(--mono);
  letter-spacing: .28em;
  text-transform: uppercase;
  color: rgb(var(--holo-line) / .75);
}

/* ---- archive panel ---- */
.archive { padding: clamp(18px, 3vw, 28px); }

/* the readout's own strip is 26px, sized for a banner. Here it is the main
   figure on the page, so it gets room; the bars are percentages of the
   tallest, so nothing else changes. */
.archive .holoreadout-hist { height: clamp(90px, 16vw, 150px); gap: 4px; margin-top: 18px; }
.archive .holoreadout-bar { cursor: pointer; }
.archive .holoreadout-stats { font-size: 12px; }
.archive .holoreadout-stats b { font-size: 22px; }
.archive .holoreadout-cap { font-size: 10px; }

.decades-axis {
  display: flex;
  gap: 4px;
  margin-top: 4px;
  font: 400 9px/1 var(--mono);
  color: rgb(var(--holo-dim) / .8);
  font-variant-numeric: tabular-nums;
}
.decades-axis span { flex: 1 1 0; text-align: center; min-width: 0; overflow: hidden; }
@media (max-width: 560px) {
  .decades-axis span:nth-child(even) { visibility: hidden; }
}

.decade {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 14px 22px;
  margin-top: 24px;
  padding-top: 18px;
  border-top: 1px solid rgb(var(--holo-line) / .08);
}
@media (max-width: 640px) {
  .decade { grid-template-columns: 1fr auto; }
  .decade-ctl { grid-column: 1 / -1; grid-row: 2; }
}
.decade-read .v {
  margin: 0;
  min-width: 5ch;
  font: 500 28px/1 var(--mono);
  font-variant-numeric: tabular-nums;
  color: rgb(var(--holo-ink));
}
.decade-ctl { min-width: 0; }
.decade-ends {
  display: flex;
  justify-content: space-between;
  margin-top: 4px;
  font: 400 9px/1 var(--mono);
  color: rgb(var(--holo-dim) / .8);
}
/* with every decade shown the rail is not the thing filtering, so it steps
   back until someone reaches for it */
.decade.is-all .holobar { opacity: .5; transition: opacity .3s ease; }
.decade.is-all .holobar:hover,
.decade.is-all .holobar:focus-within,
.decade.is-all .holobar.holo-on { opacity: 1; }

/* ---- chips, the page's one plain button ---- */
.chip {
  font: 500 10px/1 var(--mono);
  letter-spacing: .16em;
  text-transform: uppercase;
  padding: 9px 12px;
  border-radius: 8px;
  cursor: pointer;
  color: rgb(var(--holo-line) / .85);
  background: rgb(var(--holo-line) / .05);
  border: 1px solid rgb(var(--holo-line) / .18);
  transition: background .15s ease, border-color .15s ease;
}
.chip:hover { background: rgb(var(--holo-line) / .1); border-color: rgb(var(--holo-line) / .35); }
.chip[aria-pressed="true"] {
  color: rgb(var(--holo-warm));
  border-color: rgb(var(--holo-warm) / .55);
  background: rgb(var(--holo-warm) / .08);
}
.chip:focus-visible, input:focus-visible, select:focus-visible {
  outline: 2px solid rgb(var(--holo-beam) / .9);
  outline-offset: 2px;
}
.chip[hidden] { display: none !important; }

/* ---- filters ---- */
.filters {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: end;
  gap: 16px 22px;
}
@media (max-width: 900px) {
  .filters { grid-template-columns: minmax(0, 1fr) auto; }
  .themes { grid-column: 1 / -1; grid-row: 2; }
}
.search, .sort { display: block; min-width: 0; }
.search span, .sort span { display: block; }
input[type="search"], select {
  width: 100%;
  font-family: inherit;
  font-size: 15px;
  line-height: 1.2;
  padding: 10px 12px;
  border-radius: 8px;
  color: rgb(var(--holo-ink));
  background: rgb(var(--holo-panel) / .8);
  border: 1px solid rgb(var(--holo-line) / .16);
}
select { width: auto; }
input[type="search"]::placeholder { color: rgb(var(--holo-dim) / .6); }

.themes { min-width: 0; }
/* "Themes" and the selected names on one line above the rail. The row keeps
   the label's bottom margin, so the rail sits where it did; a long list of
   names wraps under itself rather than under the label.
   width: 0 with min-width: 100% keeps this row out of the column's sizing, so
   the rail alone sets the width and the names wrap at the rail's edge instead
   of stretching the column. */
.themes-head {
  display: flex;
  align-items: baseline;
  gap: 14px;
  width: 0;
  min-width: 100%;
  margin: 0 0 6px;
}
.themes-head .k { flex: 0 0 auto; margin: 0; }
.themes-on {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  font: 400 10px/1.3 var(--mono);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: rgb(var(--holo-dim));
}

.count {
  margin: 26px 0 12px;
  font: 400 11px/1.3 var(--mono);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: rgb(var(--holo-dim));
}
.count b { color: rgb(var(--holo-ink)); font-weight: 500; }

/* ---- results ---- */
.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: 14px;
}
.grid .holotint { padding: 1.05rem 1.1rem 1.1rem; border-radius: 14px; }
.film-sub {
  margin: 0 0 8px;
  display: flex;
  align-items: center;
  gap: 7px;
  font: 500 9.5px/1 var(--mono);
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--holotint-solid);
}
.film-sub::before {
  content: "";
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--holotint-solid);
  box-shadow: 0 0 8px var(--holotint-solid);
}
.film-title { margin: 0 0 8px; font-size: 17px; line-height: 1.25; font-weight: 600; }
.film-title a { color: rgb(var(--holo-ink)); text-decoration: none; }
.film-title a:hover { text-decoration: underline; text-underline-offset: 3px; }
.film-meta {
  margin: auto 0 0;
  font: 400 11.5px/1.5 var(--mono);
  color: rgb(var(--holo-dim));
  font-variant-numeric: tabular-nums;
}
.film-meta .yr { color: rgb(var(--holo-line)); }

/* ---- transmissions: post cards ----
   The cards from the old transmissions page, rebuilt in this site's voice:
   the same .holotint card, sizes and type as the Browse grid's film cards,
   with .film-sub for the date line and .film-title for the headline.
   js/transmissions.js builds them from data/transmissions.json. The headline link
   stretches over the whole card; the "more" toggle sits above that link so
   it opens the extra text instead of the post. */
.posts {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(260px, 100%), 1fr));
  gap: 14px;
}
.posts > * { min-width: 0; }
.posts .holotint { padding: 1.05rem 1.1rem 1.1rem; border-radius: 14px; }
.posts .film-sub { flex-wrap: wrap; line-height: 1.3; font-variant-numeric: tabular-nums; }
.posts .film-sub .sep { opacity: .5; }
/* static, so the link's ::before measures the card, not the heading; and
   z-index auto, because a flex item with a z-index traps the ::before under
   the card parts after it, such as the "Read post" line */
.posts .post-title { position: static; z-index: auto; text-wrap: balance; }
.post-title a::before { content: ""; position: absolute; inset: 0; z-index: 2; border-radius: inherit; }
.post-title a:focus-visible { outline: none; }
.post-title a:focus-visible::before {
  outline: 2px solid rgb(var(--holo-beam) / .9);
  outline-offset: -4px;
}
.post-summary, .post-more-text p {
  margin: 0;
  font-size: 14px;
  line-height: 1.55;
  color: #A9BDD6;
}
.post-more-text p { margin-top: 8px; }
.posts .post-more {
  position: relative; z-index: 3;
  align-self: flex-start;
  min-height: 24px;
  margin: 6px 0 0; padding: 4px 0;
  border: 0; background: none; cursor: pointer;
  font: 500 10px/1.3 var(--mono);
  letter-spacing: .16em;
  text-transform: uppercase;
  color: rgb(var(--holo-cyan) / .8);
}
.posts .post-more:hover { color: rgb(var(--holo-cyan)); text-decoration: underline; text-underline-offset: 3px; }
.posts .post-more:focus-visible {
  outline: 2px solid rgb(var(--holo-beam) / .9);
  outline-offset: 2px;
  border-radius: 2px;
}
.post-keys {
  display: flex; flex-wrap: wrap; gap: 6px;
  margin: 12px 0 0; padding: 0; list-style: none;
}
.post-keys li {
  padding: 4px 7px;
  border-radius: 4px;
  border: 1px solid rgb(var(--holo-line) / .14);
  background: rgb(var(--holo-line) / .04);
  font: 400 9.5px/1.2 var(--mono);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: rgb(var(--holo-dim));
}
/* margin-top: auto pins "Read post" to the bottom, so a row of cards lines up */
.posts .holotint-go { margin-top: auto; padding-top: 14px; font-size: 13px; }
.count.is-error { color: rgb(var(--holo-warm)); }

.empty {
  grid-column: 1 / -1;
  padding: 30px;
  text-align: center;
  color: rgb(var(--holo-dim));
  border: 1px dashed rgb(var(--holo-line) / .15);
  border-radius: 14px;
}

.more-wrap { display: flex; justify-content: center; margin-top: 22px; }

.foot {
  margin-top: 64px;
  font-size: 13px;
  color: rgb(var(--holo-dim) / .85);
  max-width: 60ch;
}
/* a footer wearing .holopanel, like index.html's: full width with the same
   padding as the section panels, the text still held to 60ch inside, and no
   extra gap above the first line or below the last */
.foot.holopanel { max-width: none; padding: clamp(16px, 3vw, 26px); }
.foot.holopanel > * { max-width: 60ch; }
.foot.holopanel > :first-child { margin-top: 0; }
.foot.holopanel > :last-child { margin-bottom: 0; }
/* a centred footer (index.html). The lines keep their 60ch measure, so the
   block is centred by its margins and the text within it */
.foot-center { text-align: center; }
.foot-center > * { margin-left: auto; margin-right: auto; }

@media (prefers-reduced-motion: reduce) {
  .chip, .decade.is-all .holobar { transition: none; }
}




/* ---- film detail -------------------------------------------------------
   A native modal <dialog> wearing the library's .holopanel surface, so focus
   trapping and Escape are the browser's job. The surface, rim and entrance
   are .holopanel's; everything below is placement. */
dialog.detail {
  /* a modal dialog sits in the top layer anchored to the viewport; .holopanel
     sets position: relative, which would drop it back into document flow */
  position: fixed;
  inset: 0;
  margin: auto;
  width: min(980px, calc(100% - 24px));
  max-width: none;
  max-height: calc(100% - 24px);
  overflow-x: hidden;
  overflow-y: auto;
  padding: clamp(20px, 4vw, 40px);
  scrollbar-width: thin;
}
dialog.detail::backdrop {
  background: radial-gradient(ellipse at center, rgba(0, 15, 40, .82) 0%, rgba(0, 0, 0, .94) 100%);
  backdrop-filter: blur(10px) saturate(1.2);
  -webkit-backdrop-filter: blur(10px) saturate(1.2);
}
body:has(dialog.detail[open]) { overflow: hidden; }

.detail-close { position: absolute; top: 16px; right: 16px; z-index: 6; }

.detail-head { padding-right: 90px; }
.detail-title {
  margin: 0 0 6px;
  font: 600 clamp(26px, 4.4vw, 40px)/1.1 var(--mono);
  letter-spacing: .02em;
  color: rgb(var(--holo-ink));
}
.detail-desc { margin: 0; color: #A9BDD6; font-size: 15px; }

.detail-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 8px 36px;
  margin-top: 8px;
}
@media (min-width: 760px) {
  .detail-body { grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); }
}

/* the trace overhangs the frame by 22px, so the frame keeps its library
   margin; only the caption is pulled up under it */
.detail-fig { margin: 0; }
.detail-fig[hidden], .detail-noimg[hidden], .holoload[hidden] { display: none !important; }
.detail-fig .holoframe img { max-height: 420px; object-fit: contain; background: rgb(0 0 0 / .35); }
.detail-fig figcaption {
  margin-top: -22px;
  font-size: 11.5px;
  line-height: 1.5;
  color: rgb(var(--holo-dim) / .9);
}
.detail-noimg {
  margin: 26px 0 0;
  padding: 26px 18px;
  text-align: center;
  font: 400 11px/1.5 var(--mono);
  letter-spacing: .08em;
  color: rgb(var(--holo-dim));
  border: 1px dashed rgb(var(--holo-line) / .15);
  border-radius: 10px;
}
.detail-media .holoload { margin: 30px 0 10px; align-items: flex-start; gap: 10px; }
#d-readout { margin-top: 26px; }
#d-readout .holoreadout-hist { height: 48px; gap: 3px; }

.facts {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  gap: 8px 16px;
  margin: 26px 0 0;
  font-size: 14px;
}
.facts dt {
  font: 500 9.5px/1.9 var(--mono);
  letter-spacing: .16em;
  text-transform: uppercase;
  color: #6BA4E6;
}
.facts dd { margin: 0; color: rgb(var(--holo-ink) / .9); }
.facts .pending { color: rgb(var(--holo-dim) / .6); }
.facts a, .rel a, .detail-links a { color: rgb(var(--holo-cyan)); }

.extract { margin-top: 20px; font-size: 14.5px; line-height: 1.65; color: rgb(var(--holo-ink) / .82); }
.extract p { margin: 0 0 6px; }
.extract .attr { font-size: 11.5px; color: rgb(var(--holo-dim) / .85); }

.detail-links {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 18px;
  margin: 16px 0 0;
  font: 500 10.5px/1.4 var(--mono);
  letter-spacing: .14em;
  text-transform: uppercase;
}

.detail-related {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 18px 36px;
  margin-top: 28px;
  padding-top: 20px;
  border-top: 1px solid rgb(var(--holo-line) / .08);
}
@media (min-width: 760px) { .detail-related { grid-template-columns: 1fr 1fr; } }
.rel { display: flex; flex-wrap: wrap; gap: 8px; }
.rel a {
  display: inline-block;
  padding: 6px 10px;
  border-radius: 8px;
  font-size: 13px;
  text-decoration: none;
  color: rgb(var(--holo-ink) / .88);
  background: rgb(var(--holo-line) / .04);
  border: 1px solid rgb(var(--holo-line) / .12);
  transition: border-color .15s ease, background .15s ease;
}
.rel a:hover, .rel a:focus-visible { border-color: rgb(var(--holo-line) / .35); background: rgb(var(--holo-line) / .08); }
.rel a small { margin-left: 6px; font: 400 10.5px/1 var(--mono); color: rgb(var(--holo-dim)); }
.rel .none { font-size: 13px; color: rgb(var(--holo-dim) / .7); }

@media (prefers-reduced-motion: reduce) {
  .rel a { transition: none; }
}




/* ---- lineage -----------------------------------------------------------
   An SVG of edges under a list of positioned links, both inside one stage
   that scrolls sideways on its own when the graph is wider than the panel,
   so a long lineage never widens the page. */
:root {
  --rel-adapt: var(--holo-warm);
  --rel-sequel: var(--holo-cyan);
  --rel-influence: 183 139 255;
}
.section-lede { max-width: 64ch; margin: -4px 0 16px; color: #A9BDD6; font-size: 15px; }
.lineage { padding: clamp(16px, 3vw, 26px); }

.ln-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 12px 24px;
}
.ln-focus { margin: 0; font-size: 18px; font-weight: 600; color: rgb(var(--holo-ink)); }
.ln-focus small { margin-left: 8px; font: 400 11px/1 var(--mono); letter-spacing: .08em; color: rgb(var(--holo-dim)); }
.ln-focus a { margin-left: 10px; font: 500 10.5px/1 var(--mono); letter-spacing: .14em; text-transform: uppercase; color: rgb(var(--holo-cyan)); }
.ln-rels { display: flex; flex-wrap: wrap; gap: 8px; }
.ln-rel::before {
  content: "";
  display: inline-block;
  width: 14px; height: 0;
  margin-right: 8px;
  vertical-align: middle;
  border-top: 2px solid rgb(var(--c));
}
.ln-rel.rel-adapt { --c: var(--rel-adapt); }
.ln-rel.rel-sequel { --c: var(--rel-sequel); }
.ln-rel.rel-influence { --c: var(--rel-influence); }
.ln-rel.rel-influence::before { border-top-style: dashed; }
/* a link kind switched off is the evidence taken away; the chip says so
   by going quiet rather than warm */
.ln-rel[aria-pressed="true"] { color: rgb(var(--c)); border-color: rgb(var(--c) / .5); background: rgb(var(--c) / .08); }
.ln-rel[aria-pressed="false"]::before { opacity: .35; }

.ln-stage {
  position: relative;
  margin-top: 18px;
  overflow-x: auto;
  overflow-y: hidden;
  border-radius: 10px;
  background:
    linear-gradient(rgb(var(--holo-line) / .03), rgb(var(--holo-line) / .01)),
    repeating-linear-gradient(90deg, transparent 0 195px, rgb(var(--holo-line) / .04) 195px 196px);
  border: 1px solid rgb(var(--holo-line) / .07);
  scrollbar-width: thin;
  scrollbar-color: rgb(var(--holo-line) / .25) transparent;
}
.ln-stage::-webkit-scrollbar { height: 8px; }
.ln-stage::-webkit-scrollbar-thumb { background: rgb(var(--holo-line) / .25); border-radius: 4px; }
.ln-stage::-webkit-scrollbar-track { background: transparent; }
.ln-stage:focus-visible { outline: 2px solid rgb(var(--holo-beam) / .9); outline-offset: 2px; }
.ln-edges { position: absolute; left: 0; top: 0; overflow: visible; pointer-events: none; }
.ln-edges path { fill: none; stroke-width: 1.6; }
.ln-edges .rel-adapt { stroke: rgb(var(--rel-adapt) / .8); }
.ln-edges .rel-sequel { stroke: rgb(var(--rel-sequel) / .8); }
.ln-edges .rel-influence { stroke: rgb(var(--rel-influence) / .85); }
.ln-edges .is-dashed { stroke-dasharray: 5 4; }
.ln-edges marker path { stroke: none; }

.ln-nodes { position: relative; list-style: none; margin: 0; padding: 0; }
.ln-nodes li { position: absolute; left: 0; top: 0; will-change: transform, opacity; }
.ln-node {
  display: flex;
  flex-direction: column;
  justify-content: center;
  box-sizing: border-box;
  width: 150px;
  height: 56px;
  padding: 6px 10px 6px 12px;
  border-radius: 9px;
  text-decoration: none;
  color: rgb(var(--holo-ink));
  background: rgb(var(--holo-panel) / .92);
  border: 1px solid rgb(var(--holo-line) / .14);
  border-left: 3px solid var(--tint, rgb(var(--holo-dim)));
  transition: border-color .2s ease, box-shadow .2s ease, background .2s ease;
}
.ln-node:hover, .ln-node:focus-visible {
  background: rgb(22 30 44 / .96);
  border-color: rgb(var(--holo-line) / .4);
  border-left-color: var(--tint, rgb(var(--holo-dim)));
  box-shadow: 0 0 18px rgb(var(--holo-glow) / .22);
}
.ln-node:focus-visible { outline: 2px solid rgb(var(--holo-beam) / .9); outline-offset: 2px; }
.ln-node .t {
  display: block;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-size: 13px;
  font-weight: 600;
  line-height: 1.3;
}
.ln-node .m {
  display: block;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font: 400 10px/1.4 var(--mono);
  letter-spacing: .04em;
  color: rgb(var(--holo-dim));
}
.ln-node .m b { font-weight: 500; color: rgb(var(--holo-line)); }
/* works outside the archive: a book, a story, a film that is not sci-fi */
.ln-node.is-outside { background: rgb(var(--holo-panel) / .7); border-style: dashed; border-left-style: solid; }
.ln-node.is-focus {
  border-color: rgb(var(--holo-warm) / .75);
  border-left-color: var(--tint, rgb(var(--holo-warm)));
  box-shadow: 0 0 0 1px rgb(var(--holo-warm) / .25), 0 0 26px rgb(var(--holo-warm) / .22);
}
.ln-details {
  position: absolute;
  left: 0;
  top: 60px;
  font: 500 9.5px/1 var(--mono);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: rgb(var(--holo-cyan));
  white-space: nowrap;
}

.ln-note {
  margin: 12px 0 0;
  font: 400 10px/1.6 var(--mono);
  letter-spacing: .08em;
  color: rgb(var(--holo-dim) / .9);
}
.ln-empty {
  padding: 40px 20px;
  text-align: center;
  color: rgb(var(--holo-dim));
}
.ln-suggest { margin-top: 18px; padding-top: 14px; border-top: 1px solid rgb(var(--holo-line) / .08); }

@media (prefers-reduced-motion: reduce) {
  .ln-node { transition: none; }
}




/* ---- constellation -----------------------------------------------------
   The canvas is pinned to its box here. constellation.js sizes the drawing
   buffer from this box and never the reverse, so the stage cannot grow. */
:root { --rel-director: var(--holo-line); }
.constellation { padding: clamp(16px, 3vw, 26px); }
.constellation .holoreadout-hist { height: 40px; gap: 4px; }
.ln-rel.rel-director { --c: var(--rel-director); }

.cn-controls {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: 10px 18px;
  margin-top: 18px;
}
.cn-zoom { display: flex; gap: 6px; }
.cn-zoom .chip { min-width: 36px; }

.cn-stage {
  position: relative;
  margin-top: 14px;
  overflow: hidden;
  border-radius: 10px;
  border: 1px solid rgb(var(--holo-line) / .07);
  background:
    radial-gradient(ellipse at 50% 45%, rgb(var(--holo-glow) / .07), transparent 70%),
    rgb(4 6 10 / .6);
}
.cn-canvas {
  display: block;
  width: 100%;
  height: clamp(420px, 68vh, 700px);
  cursor: grab;
}
.cn-canvas:active { cursor: grabbing; }

.cn-card {
  position: absolute;
  z-index: 2;
  width: 240px;
  max-width: calc(100% - 16px);
  padding: 12px 14px 12px;
  border-radius: 10px;
  background: rgb(var(--holo-panel) / .94);
  border: 1px solid rgb(var(--holo-warm) / .45);
  box-shadow: 0 10px 30px rgb(0 0 0 / .5), 0 0 22px rgb(var(--holo-warm) / .12);
}
.cn-card[hidden] { display: none !important; }
.cn-card .film-sub { margin-bottom: 6px; }
.cn-card-t { margin: 0 22px 4px 0; font-size: 15px; font-weight: 600; line-height: 1.3; color: rgb(var(--holo-ink)); }
.cn-card-m { margin: 0 0 3px; font: 400 11px/1.45 var(--mono); color: rgb(var(--holo-dim)); }
.cn-card-a {
  display: flex;
  gap: 16px;
  margin: 8px 0 0;
  font: 500 10.5px/1 var(--mono);
  letter-spacing: .14em;
  text-transform: uppercase;
}
.cn-card-a a { color: rgb(var(--holo-cyan)); }
.cn-card-x {
  position: absolute;
  top: 6px;
  right: 8px;
  width: 26px;
  height: 26px;
  padding: 0;
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  color: rgb(var(--holo-dim));
  background: none;
  border: 0;
  border-radius: 6px;
}
.cn-card-x:hover { color: rgb(var(--holo-ink)); background: rgb(var(--holo-line) / .08); }
.cn-card-x:focus-visible { outline: 2px solid rgb(var(--holo-beam) / .9); outline-offset: 1px; }
