/* ==========================================================================
   Sitemap page (page-sitemap.php) — list view + 3D graph view.
   Scoped under .smp to stay clear of theme globals.
   ========================================================================== */

/*
 * Colours come from the design system's runtime token layer
 * (assets_v2/dist/tokens.generated.css, enqueued site-wide as `neo-tokens`),
 * so this page reads as the same brand as the rest of neo4j.com.
 *
 * Each var() carries the token's own value as a fallback. An unresolvable
 * var() in a `color` is invalid at computed-value time and makes the property
 * inherit, which on the dark hero means text the same colour as its
 * background — so the page must not depend on the token sheet having loaded.
 */
.smp {
  --smp-ink: var(--neo-color-neutral-legacy-75, #151e29);
  --smp-ink-soft: var(--neo-color-neutral-legacy-55, #535b66);
  --smp-rule: var(--neo-color-neutral-legacy-25, #e6e9ee);
  --smp-paper: var(--neo-color-neutral-legacy-10, #ffffff);
  --smp-paper-soft: var(--neo-color-neutral-legacy-15, #f5f7fa);
  /* Almost black but keeping the site's navy character, not flat/hueless —
     kept in sync with STAGE_BG etc. in the graph's palette.js. No token goes
     this dark: the nearest, neutral-80, is #09090A and has no hue at all. */
  --smp-space: #000208;
  --smp-space-2: #060a16;
  /* Text on the dark surface. The same value as --smp-paper, named for the job
     it does so a reader is not left wondering why 'paper' is a text colour. */
  --smp-on-space: var(--neo-color-neutral-legacy-10, #ffffff);
  /* The accent on dark surfaces, and the page's most-used colour after white.
     Baltic, because it is the family the rest of the theme reaches for by a
     wide margin. The light end of it specifically: baltic's common shades are
     50 and 60, but those are meant for light backgrounds and only reach
     2.5:1 on this near-black one. The deeper of the pair carries small type,
     hovers and focus rings, so it is held to AA body contrast (8.2:1). */
  --smp-cyan: var(--neo-color-baltic-20, #8fe3e8);
  --smp-cyan-deep: var(--neo-color-baltic-25, #5cc3c9);
  --smp-max: 1240px;
  font-size: 16px;
}

.smp a {
  transition: color 0.15s ease;
}

/* --------------------------------------------------------------------------
   Hero
   -------------------------------------------------------------------------- */

.smp-hero {
  position: relative;
  overflow: hidden;
  background: radial-gradient(120% 140% at 78% 10%, var(--neo-color-baltic-70, #081e2b) 0%, var(--smp-space-2) 45%, var(--smp-space) 100%);
  color: var(--smp-on-space);
  padding: 5.5rem 1.5rem 3.5rem;
}

.smp-hero__bg {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image:
    radial-gradient(2px 2px at 12% 30%, rgba(143, 227, 232, 0.9) 0%, transparent 100%),
    radial-gradient(2px 2px at 25% 68%, rgba(255, 207, 114, 0.8) 0%, transparent 100%),
    radial-gradient(1.5px 1.5px at 38% 22%, rgba(255, 255, 255, 0.7) 0%, transparent 100%),
    radial-gradient(2.5px 2.5px at 55% 80%, rgba(92, 195, 201, 0.7) 0%, transparent 100%),
    radial-gradient(2px 2px at 67% 35%, rgba(143, 227, 232, 0.8) 0%, transparent 100%),
    radial-gradient(1.5px 1.5px at 78% 60%, rgba(255, 207, 114, 0.7) 0%, transparent 100%),
    radial-gradient(2px 2px at 88% 25%, rgba(255, 255, 255, 0.6) 0%, transparent 100%),
    radial-gradient(2.5px 2.5px at 93% 75%, rgba(92, 195, 201, 0.6) 0%, transparent 100%);
  opacity: 0.85;
}

.smp-hero__inner {
  position: relative;
  max-width: var(--smp-max);
  margin: 0 auto;
}

.smp-hero__kicker {
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--smp-cyan-deep);
  margin: 0 0 1rem;
}

.smp-hero__title {
  color: var(--smp-on-space);
  font-size: clamp(2.2rem, 5vw, 3.6rem);
  line-height: 1.08;
  margin: 0 0 1rem;
  max-width: 18em;
}

.smp-hero__accent {
  color: var(--smp-cyan);
}

.smp-hero__sub {
  font-size: 1.1rem;
  line-height: 1.55;
  color: rgba(255, 255, 255, 0.78);
  max-width: 44em;
  margin: 0 0 2rem;
}

.smp-toggle {
  display: inline-flex;
  gap: 4px;
  padding: 4px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.07);
  border: 1px solid rgba(143, 227, 232, 0.25);
  backdrop-filter: blur(6px);
}

.smp-toggle__btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  border: 0;
  cursor: pointer;
  font: inherit;
  font-size: 0.95rem;
  font-weight: 600;
  color: rgba(255, 255, 255, 0.75);
  background: transparent;
  border-radius: 999px;
  padding: 0.6em 1.4em;
  transition: background 0.2s ease, color 0.2s ease;
}

.smp-toggle__btn svg {
  width: 1em;
  height: 1em;
}

.smp-toggle__btn:hover {
  color: var(--smp-on-space);
}

.smp-toggle__btn.is-active {
  background: var(--smp-cyan);
  color: var(--smp-space);
}

.smp-hero__stats {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem 2.2rem;
  margin: 2.2rem 0 0;
  padding: 0;
  font-size: 0.92rem;
  color: rgba(255, 255, 255, 0.6);
}

.smp-hero__stats strong {
  color: var(--smp-cyan);
  font-weight: 700;
  margin-right: 0.35em;
}

/* --------------------------------------------------------------------------
   List view
   -------------------------------------------------------------------------- */

.smp-list {
  background: var(--smp-paper);
  padding: 2.5rem 1.5rem 5rem;
}

.smp-list__inner {
  max-width: var(--smp-max);
  margin: 0 auto;
}

.smp-filterbar {
  position: sticky;
  top: 0;
  z-index: 20;
  background: rgba(255, 255, 255, 0.92);
  backdrop-filter: blur(8px);
  padding: 1rem 0;
  border-bottom: 1px solid var(--smp-rule);
  margin-bottom: 2rem;
}

.smp-filterbar__label {
  display: block;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--smp-ink-soft);
  margin-bottom: 0.4rem;
}

.smp-filterbar__row {
  display: flex;
  align-items: center;
  gap: 1rem;
}

.smp-filterbar__input {
  flex: 1;
  max-width: 34rem;
  font: inherit;
  font-size: 1rem;
  padding: 0.65em 1em;
  border: 1.5px solid var(--smp-rule);
  border-radius: 8px;
  color: var(--smp-ink);
  background: var(--smp-paper);
}

.smp-filterbar__input:focus {
  outline: none;
  border-color: var(--smp-cyan-deep);
  box-shadow: 0 0 0 3px rgba(92, 195, 201, 0.25);
}

.smp-filterbar__count {
  font-size: 0.88rem;
  color: var(--smp-ink-soft);
  white-space: nowrap;
}

/* Compact view toggle — lives in the graph HUD, where the hero's main
   toggle has scrolled out of view. */

.smp-minitoggle {
  display: inline-flex;
  gap: 2px;
  padding: 3px;
  border-radius: 999px;
  flex: none;
}

.smp-minitoggle__btn {
  font: inherit;
  font-size: 0.78rem;
  font-weight: 600;
  border: 0;
  cursor: pointer;
  border-radius: 999px;
  padding: 0.35em 1em;
  background: transparent;
  transition: background 0.15s ease, color 0.15s ease;
}

.smp-minitoggle--dark {
  background: rgba(4, 24, 35, 0.75);
  border: 1px solid rgba(143, 227, 232, 0.3);
  backdrop-filter: blur(8px);
}

.smp-minitoggle--dark .smp-minitoggle__btn {
  color: rgba(255, 255, 255, 0.7);
}

.smp-minitoggle--dark .smp-minitoggle__btn.is-active {
  background: var(--smp-cyan);
  color: var(--smp-space);
}

.smp-list__heading {
  scroll-margin-top: 6.5rem;
  display: flex;
  align-items: baseline;
  gap: 0.8rem;
  font-size: 1.6rem;
  color: var(--smp-ink);
  margin: 3rem 0 1.2rem;
  padding-bottom: 0.6rem;
  border-bottom: 2px solid var(--smp-ink);
}

.smp-list__heading:first-of-type {
  margin-top: 0;
}

.smp-count {
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--smp-ink-soft);
  background: var(--smp-paper-soft);
  border: 1px solid var(--smp-rule);
  border-radius: 999px;
  padding: 0.15em 0.7em;
  white-space: nowrap;
}

.smp-cards {
  column-count: 3;
  column-gap: 1.5rem;
}

@media (max-width: 1024px) {
  .smp-cards { column-count: 2; }
}

@media (max-width: 640px) {
  .smp-cards { column-count: 1; }
}

.smp-card {
  break-inside: avoid;
  background: var(--smp-paper-soft);
  border: 1px solid var(--smp-rule);
  border-radius: 12px;
  padding: 1.2rem 1.4rem 1.4rem;
  margin: 0 0 1.5rem;
}

.smp-card__title {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.6rem;
  font-size: 1.05rem;
  margin: 0 0 0.6rem;
  color: var(--smp-ink);
}

.smp-card__title .smp-link {
  color: var(--smp-ink);
}

.smp-link {
  color: var(--neo-color-baltic-50, #0a6190);
  text-decoration: none;
}

.smp-link:hover {
  color: var(--neo-color-baltic-55, #02507b);
  text-decoration: underline;
}

.smp-link--heading {
  color: inherit;
}

.smp-tree {
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: 0.93rem;
  line-height: 1.5;
}

.smp-tree .smp-tree {
  padding-left: 1rem;
  border-left: 1px solid var(--smp-rule);
  margin-left: 0.2rem;
}

.smp-tree__item {
  margin: 0.28rem 0;
}

.smp-tree__item.smp-hidden {
  display: none;
}

.smp-card.smp-hidden,
.smp-list__heading.smp-hidden,
.smp-more.smp-hidden {
  display: none;
}

mark.smp-mark {
  background: rgba(143, 227, 232, 0.45);
  color: inherit;
  border-radius: 3px;
  padding: 0 0.1em;
}

.smp-more {
  display: inline-block;
  margin-top: 0.8rem;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--neo-color-baltic-50, #0a6190);
  text-decoration: none;
}

.smp-more:hover {
  text-decoration: underline;
}

/* --------------------------------------------------------------------------
   Graph view
   -------------------------------------------------------------------------- */

.smp-graph {
  background: var(--smp-space);
}

.smp-graph__stage {
  position: relative;
  height: calc(100vh - 72px);
  min-height: 560px;
  overflow: hidden;
}

.smp-graph__stage:fullscreen {
  /* Beats the JS-measured inline height while fullscreen. */
  height: 100vh !important;
}

/*
 * Fallback for browsers with no Element.requestFullscreen — iOS Safari grants
 * it to video elements only, and an iframe without allow="fullscreen" is
 * refused. JS adds this class instead; see setFauxFullscreen() in
 * sitemap-graph/index.js.
 *
 * dvh rather than vh: on a phone, vh is the tallest the viewport ever gets, so
 * the bottom of the stage sits behind the browser's own chrome until the
 * address bar happens to be collapsed.
 */
.smp-graph__stage.is-faux-fullscreen {
  position: fixed;
  inset: 0;
  z-index: 2147483647;
  width: 100vw;
  height: 100vh !important;
  height: 100dvh !important;
  min-height: 0;
}

/* Hold the page still underneath, the way real fullscreen does. */
.smp-fullscreen-lock,
.smp-fullscreen-lock body {
  overflow: hidden;
}

.smp-graph__canvas {
  position: absolute;
  inset: 0;
  cursor: grab;
}

.smp-graph__canvas:active {
  cursor: grabbing;
}

.smp-graph__vignette {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(115% 115% at 50% 45%, transparent 55%, rgba(1, 10, 18, 0.55) 100%);
}

/* Loading state */

.smp-graph__loading {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1.4rem;
  color: rgba(255, 255, 255, 0.7);
  font-size: 0.95rem;
  background: var(--smp-space);
  z-index: 5;
  transition: opacity 0.6s ease;
}

.smp-graph__loading.is-done {
  opacity: 0;
  pointer-events: none;
}

.smp-graph__loading-orb {
  width: 52px;
  height: 52px;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 35%, var(--smp-cyan), var(--smp-cyan-deep) 55%, transparent 75%);
  box-shadow: 0 0 30px rgba(143, 227, 232, 0.8), 0 0 80px rgba(143, 227, 232, 0.35);
  animation: smp-pulse 1.6s ease-in-out infinite;
}

@keyframes smp-pulse {
  0%, 100% { transform: scale(1); opacity: 0.85; }
  50% { transform: scale(1.18); opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .smp-graph__loading-orb { animation: none; }
}

/* HUD overlays */

.smp-graph__hud {
  position: absolute;
  z-index: 10;
}

.smp-graph__hud--top-left {
  top: 1.2rem;
  left: 1.2rem;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  align-items: flex-start;
}
.smp-graph__hud--top-right { top: 1.2rem; right: 1.2rem; }
.smp-graph__hud--bottom-left { bottom: 1.2rem; left: 1.2rem; }
.smp-graph__hud--bottom-right { bottom: 1.2rem; right: 1.2rem; display: flex; gap: 0.5rem; }

.smp-graph__hint {
  margin: 0;
  font-size: 0.78rem;
  letter-spacing: 0.04em;
  color: rgba(255, 255, 255, 0.45);
}

.smp-graph__hudbtn {
  font: inherit;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: rgba(255, 255, 255, 0.75);
  background: rgba(4, 24, 35, 0.7);
  border: 1px solid rgba(143, 227, 232, 0.3);
  border-radius: 6px;
  padding: 0.45em 0.9em;
  cursor: pointer;
  backdrop-filter: blur(6px);
  transition: color 0.15s ease, border-color 0.15s ease;
}

.smp-graph__hudbtn:hover {
  color: var(--smp-cyan);
  border-color: var(--smp-cyan);
}

.smp-graph__hudbtn.is-on {
  color: var(--smp-space);
  background: var(--smp-cyan);
  border-color: var(--smp-cyan);
}

/*
 * Finger-sized targets where there is a finger. The padding above lands these
 * at 32px tall, which is comfortable for a cursor and awkward for a thumb;
 * 44px is the usual floor for touch.
 *
 * Keyed on the input device rather than the viewport width on purpose: a touch
 * laptop needs the bigger target at any width, and a narrow desktop window does
 * not need it at all. Pointer-precise browsers keep the HUD exactly as it was.
 */
@media (pointer: coarse) {
  .smp-graph__hudbtn {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 0.45em 1em;
  }
}

/* Graph search */

.smp-graph-search {
  position: relative;
  width: min(21rem, calc(100vw - 3rem));
}

/* !important: the theme's global input rules repaint search fields white
   on focus, which turned typed text white-on-white. */

.smp-graph .smp-graph-search__input,
.smp-graph .smp-graph-search__input:focus {
  width: 100%;
  font: inherit;
  font-size: 0.92rem;
  color: var(--smp-on-space) !important;
  -webkit-text-fill-color: var(--smp-on-space);
  caret-color: var(--smp-cyan);
  background: rgba(4, 24, 35, 0.85) !important;
  border: 1px solid rgba(143, 227, 232, 0.3) !important;
  border-radius: 8px;
  padding: 0.6em 1em;
  backdrop-filter: blur(8px);
}

.smp-graph .smp-graph-search__input::placeholder {
  color: rgba(255, 255, 255, 0.4);
}

.smp-graph .smp-graph-search__input:focus {
  outline: none;
  border-color: var(--smp-cyan) !important;
  box-shadow: 0 0 0 3px rgba(143, 227, 232, 0.18) !important;
}

.smp-graph-search__results {
  list-style: none;
  margin: 0.4rem 0 0;
  padding: 0.3rem;
  max-height: 21rem;
  overflow-y: auto;
  background: rgba(4, 24, 35, 0.92);
  border: 1px solid rgba(143, 227, 232, 0.25);
  border-radius: 8px;
  backdrop-filter: blur(10px);
}

.smp-graph-search__results li {
  margin: 0;
}

.smp-graph-search__results button {
  display: block;
  width: 100%;
  text-align: left;
  font: inherit;
  font-size: 0.86rem;
  color: rgba(255, 255, 255, 0.85);
  background: transparent;
  border: 0;
  border-radius: 6px;
  padding: 0.45em 0.7em;
  cursor: pointer;
}

.smp-graph-search__results button:hover,
.smp-graph-search__results button.is-active {
  background: rgba(143, 227, 232, 0.14);
  color: var(--smp-on-space);
}

.smp-graph-search__results .smp-result-type {
  display: inline-block;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin-right: 0.6em;
  opacity: 0.75;
}

/* Legend */

.smp-legend {
  display: flex;
  flex-direction: column;
  gap: 2px;
  max-height: calc(100vh - 220px);
  overflow-y: auto;
  background: rgba(4, 24, 35, 0.7);
  border: 1px solid rgba(143, 227, 232, 0.2);
  border-radius: 10px;
  padding: 0.6rem;
  backdrop-filter: blur(8px);
}

.smp-legend__item {
  display: flex;
  align-items: center;
  gap: 0.55em;
  font: inherit;
  font-size: 0.78rem;
  color: rgba(255, 255, 255, 0.8);
  background: transparent;
  border: 0;
  border-radius: 6px;
  padding: 0.3em 0.6em;
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.15s ease, opacity 0.15s ease;
}

.smp-legend__item:hover {
  background: rgba(143, 227, 232, 0.12);
}

.smp-legend__item.is-muted {
  opacity: 0.32;
}

.smp-legend__swatch {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  box-shadow: 0 0 8px currentColor;
  flex: none;
}

/* --------------------------------------------------------------------------
   Page preview panel

   Selecting a node splits the stage: this panel takes the right half and the
   graph's camera centre shifts left to re-centre in what's left (see
   setViewSplit in graph.js). The canvas is never resized — the panel simply
   slides over it — so opening stays a compositor-only transform instead of
   forcing the bloom pass to reallocate its render targets mid-transition.
   -------------------------------------------------------------------------- */

.smp-preview {
  position: absolute;
  z-index: 14;
  top: 0;
  right: 0;
  bottom: 0;
  width: 50%;
  max-width: 56rem;
  flex-direction: column;
  background: rgba(1, 18, 28, 0.94);
  border-left: 1px solid rgba(143, 227, 232, 0.32);
  box-shadow: -20px 0 60px rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(14px);
  color: var(--smp-on-space);
  /* Parked off-stage until .is-open; the stage's overflow:hidden clips it. */
  transform: translateX(100%);
  /* easeInOutQuad, to match animateCamera()/setViewSplit() — the panel slide
     and the camera shift have to read as one movement, not two. */
  transition: transform 0.42s cubic-bezier(0.45, 0, 0.55, 1);
  will-change: transform;
}

/* :not([hidden]) matters — a bare `display: flex` here would be an author
   rule beating the UA's [hidden] { display: none }, so the panel would never
   actually hide. */
.smp-preview:not([hidden]) {
  display: flex;
}

.smp-preview.is-open {
  transform: none;
}

/* The panel covers both right-hand HUDs, so slide them into the strip the
   graph still owns rather than let them vanish underneath it.
   --smp-preview-w is written from JS as the panel's measured width, so this
   tracks the max-width cap and stays in step with the camera. */
.smp-graph__hud--top-right,
.smp-graph__hud--bottom-right {
  transition: transform 0.42s cubic-bezier(0.45, 0, 0.55, 1);
}

.smp-graph__stage.has-preview .smp-graph__hud--top-right,
.smp-graph__stage.has-preview .smp-graph__hud--bottom-right {
  transform: translateX(calc(-1 * var(--smp-preview-w, 50%)));
}

/* Header — what used to be the free-floating node card, so a selection has
   one surface describing it instead of two competing ones. */

.smp-preview__head {
  flex: none;
  display: flex;
  align-items: flex-start;
  gap: 0.8rem;
  padding: 1rem 1rem 0.95rem 1.3rem;
  border-bottom: 1px solid rgba(143, 227, 232, 0.18);
}

.smp-preview__ident {
  min-width: 0;
}

.smp-preview__type {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  margin: 0 0 0.4rem;
}

/* Carries the node's own colour, so the panel is visibly tied to the dot you
   clicked out in the graph. */
.smp-preview__dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: currentColor;
  box-shadow: 0 0 9px currentColor;
  flex: none;
}

.smp-preview__title {
  font-size: 1.2rem;
  line-height: 1.28;
  color: var(--smp-on-space);
  margin: 0 0 0.35rem;
  /* Long node names shouldn't push the close button or grow the header. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.smp-preview__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5rem;
  font-size: 0.78rem;
  color: rgba(255, 255, 255, 0.5);
  margin: 0;
  min-width: 0;
}

.smp-preview__path {
  font-family: "Fira Code", ui-monospace, SFMono-Regular, Menlo, monospace;
  color: rgba(255, 255, 255, 0.62);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 100%;
}

.smp-preview__degree::before {
  content: "·";
  margin-right: 0.5rem;
  color: rgba(255, 255, 255, 0.3);
}

.smp-preview__degree:empty {
  display: none;
}

.smp-preview__close {
  flex: none;
  margin-left: auto;
  font-size: 1.5rem;
  line-height: 1;
  color: rgba(255, 255, 255, 0.5);
  background: transparent;
  border: 0;
  padding: 0 0.2rem;
  cursor: pointer;
}

.smp-preview__close:hover {
  color: var(--smp-on-space);
}

/* The framed page.

   The iframe is laid out at a FIXED desktop width (--smp-frame-w, set from JS)
   and scaled down to fit the panel. A half-width panel is around tablet width,
   and the site isn't designed for that breakpoint — rendering at desktop and
   scaling gives a true picture of the page instead of a layout nobody ships.
   Height is divided back out by the scale so the result still fills the box. */

.smp-preview__frame {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
  background: var(--smp-paper);
}

.smp-preview__viewport {
  position: absolute;
  inset: 0;
  overflow: hidden;
}

/* Actual-size mode: the frame keeps its full desktop width and the viewport
   scrolls instead of shrinking it. */
.smp-preview__viewport.is-scrollable {
  overflow: auto;
  overscroll-behavior: contain;
}

.smp-preview__iframe {
  display: block;
  width: var(--smp-frame-w, 100%);
  height: var(--smp-frame-h, 100%);
  border: 0;
  background: var(--smp-paper);
  transform: scale(var(--smp-frame-scale, 1));
  transform-origin: 0 0;
  opacity: 0;
  transition: opacity 0.3s ease;
}

.smp-preview__frame[data-state="ready"] .smp-preview__iframe {
  opacity: 1;
}

/* Skeleton — shaped like a page (nav bar, hero, copy) rather than three
   anonymous bars, and in the framed page's light palette: handing over from a
   dark placeholder to a white page flashes. */

.smp-preview__skeleton {
  position: absolute;
  inset: 0;
  display: none;
  flex-direction: column;
  gap: 1.2rem;
  padding: 1.6rem 2rem 2.4rem;
  background: var(--smp-paper);
}

.smp-preview__frame[data-state="loading"] .smp-preview__skeleton {
  display: flex;
}

.smp-preview__sk {
  border-radius: 6px;
  background: linear-gradient(90deg, var(--neo-color-neutral-legacy-20, #eef1f6) 0%, var(--neo-color-neutral-legacy-25, #e6e9ee) 45%, var(--neo-color-neutral-legacy-20, #eef1f6) 90%);
  background-size: 300% 100%;
  animation: smp-shimmer 1.3s linear infinite;
}

.smp-preview__sk--bar { height: 2.2rem; border-radius: 8px; margin-bottom: 0.6rem; }
.smp-preview__sk--hero { height: 34%; border-radius: 10px; }
.smp-preview__sk--line { height: 0.85rem; }
.smp-preview__sk--short { width: 62%; }

@keyframes smp-shimmer {
  from { background-position: 100% 0; }
  to { background-position: -100% 0; }
}

/* Explained dead ends: a hub with no archive page, a 404, or a URL that
   redirects off neo4j.com and so can't be framed at all. */

.smp-preview__state {
  position: absolute;
  inset: 0;
  display: none;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: 0.6rem;
  padding: 2rem 2.2rem;
  background: rgba(1, 18, 28, 0.97);
  color: rgba(255, 255, 255, 0.66);
  font-size: 0.9rem;
  line-height: 1.55;
}

.smp-preview__frame[data-state="nopage"] .smp-preview__state,
.smp-preview__frame[data-state="missing"] .smp-preview__state,
.smp-preview__frame[data-state="offsite"] .smp-preview__state,
.smp-preview__frame[data-state="error"] .smp-preview__state {
  display: flex;
}

.smp-preview__state p {
  margin: 0;
  max-width: 34rem;
}

.smp-preview__state-title {
  font-size: 1.05rem;
  font-weight: 700;
  color: var(--smp-on-space);
}

.smp-preview__state-cta {
  margin-top: 0.5rem;
  font-size: 0.85rem;
  font-weight: 700;
  color: var(--smp-cyan);
  border: 1px solid rgba(143, 227, 232, 0.45);
  border-radius: 6px;
  padding: 0.5em 1.05em;
  text-decoration: none;
  transition: border-color 0.15s ease, color 0.15s ease;
}

.smp-preview__state-cta:hover {
  color: var(--smp-on-space);
  border-color: var(--smp-cyan);
}

.smp-preview__state-cta[hidden] {
  display: none;
}

/* Footer */

.smp-preview__foot {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.8rem 1.3rem;
  border-top: 1px solid rgba(143, 227, 232, 0.18);
}

.smp-preview__zoomgroup {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  min-width: 0;
}

.smp-preview__zoomgroup[hidden] {
  display: none;
}

.smp-preview__scale {
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  color: rgba(255, 255, 255, 0.38);
  font-variant-numeric: tabular-nums;
}

.smp-preview__zoom {
  font: inherit;
  font-size: 0.75rem;
  font-weight: 600;
  color: rgba(255, 255, 255, 0.7);
  background: transparent;
  border: 1px solid rgba(143, 227, 232, 0.28);
  border-radius: 6px;
  padding: 0.35em 0.75em;
  cursor: pointer;
  white-space: nowrap;
  transition: color 0.15s ease, border-color 0.15s ease;
}

.smp-preview__zoom:hover {
  color: var(--smp-cyan);
  border-color: var(--smp-cyan);
}

.smp-preview__cta {
  display: inline-block;
  /* Stays right even when the zoom controls are hidden in the bottom sheet,
     which would otherwise leave space-between with nothing to push against. */
  margin-left: auto;
  font-size: 0.9rem;
  font-weight: 700;
  color: var(--smp-space);
  background: var(--smp-cyan);
  border-radius: 6px;
  padding: 0.5em 1.1em;
  text-decoration: none;
  white-space: nowrap;
  transition: background 0.15s ease;
}

.smp-preview__cta:hover {
  background: var(--neo-color-baltic-15, #c3f8fb);
  color: var(--smp-space);
}

.smp-preview__cta[hidden] {
  display: none;
}

@media (prefers-reduced-motion: reduce) {
  .smp-preview,
  .smp-preview__iframe,
  .smp-graph__hud--top-right,
  .smp-graph__hud--bottom-right {
    transition: none;
  }
  .smp-preview__sk {
    animation: none;
  }
}

/* Narrow viewports: there's no half worth splitting, so the same panel
   becomes a bottom sheet over the graph and the camera is left alone
   (index.js decides that off the same 900px breakpoint). */

@media (max-width: 899px) {
  .smp-preview {
    top: auto;
    left: 0;
    right: 0;
    bottom: 0;
    width: auto;
    max-width: none;
    height: 72%;
    border-left: 0;
    border-top: 1px solid rgba(143, 227, 232, 0.32);
    border-radius: 14px 14px 0 0;
    box-shadow: 0 -20px 60px rgba(0, 0, 0, 0.55);
    transform: translateY(100%);
  }

  .smp-preview.is-open {
    transform: none;
  }

  /* A sheet this tall leaves nowhere to relocate these to. */
  .smp-graph__stage.has-preview .smp-graph__hud--top-right,
  .smp-graph__stage.has-preview .smp-graph__hud--bottom-right {
    display: none;
  }
}

@media (max-width: 640px) {
  .smp-graph__hud--top-right { display: none; }
  .smp-graph__hint { display: none; }
  .smp-graph__stage { height: calc(100vh - 56px); min-height: 480px; }
}

/* Node labels — HTML overlay via CSS2DRenderer, so they stay pixel-crisp
   and out of the bloom pass. */

.smp-labels-layer {
  position: absolute;
  top: 0;
  left: 0;
  pointer-events: none;
  z-index: 2;
}

.smp-node-label {
  pointer-events: none;
  white-space: nowrap;
  color: var(--smp-on-space);
  font-family: "syne-neo", "Public Sans", "Helvetica Neue", sans-serif;
  font-weight: 700;
  letter-spacing: 0.015em;
  transition: opacity 0.25s ease;
}

.smp-node-label__text {
  display: inline-block;
  text-shadow:
    0 1px 2px rgba(1, 18, 28, 0.95),
    0 0 10px rgba(1, 18, 28, 0.85),
    0 0 22px rgba(1, 18, 28, 0.6);
}

.smp-node-label--root {
  font-size: 17px;
  letter-spacing: 0.03em;
}

.smp-node-label--hub {
  font-size: 14px;
}

.smp-node-label--minor {
  font-size: 12px;
  color: rgba(255, 255, 255, 0.9);
}

/* Caption inside the disc (Bloom-style) — font-size is driven per frame
   from the disc's projected on-screen size. */

.smp-node-label.is-inside .smp-node-label__text {
  text-shadow: 0 1px 3px rgba(1, 18, 28, 0.45);
  letter-spacing: 0.03em;
}

.smp-node-label.is-dark-text.is-inside .smp-node-label__text {
  color: var(--neo-color-baltic-75, #041823);
  text-shadow: none;
}

/* Hover tooltip injected by 3d-force-graph */

.smp-graph .scene-tooltip {
  font-family: inherit !important;
  pointer-events: none;
}

.smp-tip {
  display: flex;
  flex-direction: column;
  gap: 2px;
  background: rgba(4, 24, 35, 0.9);
  border: 1px solid rgba(143, 227, 232, 0.35);
  border-radius: 8px;
  padding: 0.5em 0.8em;
  max-width: 22rem;
  backdrop-filter: blur(6px);
}

.smp-tip__name {
  font-size: 0.88rem;
  font-weight: 600;
  color: var(--smp-on-space);
}

.smp-tip__path {
  font-size: 0.72rem;
  color: rgba(255, 255, 255, 0.55);
  word-break: break-all;
}

/* Relationship-type chip shown when hovering a link */

.smp-tip--rel {
  display: inline-block;
  font-family: "Fira Code", "SF Mono", Menlo, monospace;
  font-size: 0.74rem;
  font-weight: 600;
  color: var(--smp-cyan);
  border-color: rgba(143, 227, 232, 0.5);
}
