/* ---------------------------------------------------------------
   Theme tokens. Every color in the UI resolves to one of these, so a
   theme change happens here rather than across the whole file.
   The 3D scene's colors mirror these in theme.js — Three.js needs
   numeric hex, so the two can't literally share a declaration.
   --------------------------------------------------------------- */
:root {
  --bg-deep: #0d0f14;      /* page + input backgrounds */
  --bg-panel: #11141b;     /* panels, buttons, toolbars */
  --bg-hover: #1e293b;     /* hovered controls */
  --border: #334155;       /* control + panel borders */
  --border-subtle: #1e293b;/* quieter panel dividers */
  --text: #e2e8f0;         /* primary text */
  --text-muted: #94a3b8;   /* labels, secondary text */
  --accent: #ffb347;       /* selection highlight */
  --accent-blue: #5a8dee;  /* drop targets, default node color */
  --danger: #f87171;       /* error text */

  --panel-width: 280px;
}

/* Reset the default page margin so our 3D canvas can fill the
   entire browser window, edge to edge. */
html, body {
  margin: 0;
  padding: 0;
  overflow: hidden; /* the 3D scene handles its own "scrolling" (orbiting) */
  height: 100%;
  background: var(--bg-deep);
}

#scene-container {
  position: relative; /* anchors the CSS2D label layer to this element */
  z-index: 0; /* explicit and low, so panels with a higher z-index reliably paint over node labels */
  width: 100vw;
  height: 100vh;
}

/* Three.js inserts a <canvas> element into #scene-container at runtime;
   this makes sure it behaves as a block-level element with no gaps. */
#scene-container canvas {
  display: block;
}

/* Node actions, now docked to the bottom-center of the screen. */
/* Shown only while free-flight mode is active (see freeFlight.js). */
#flight-mode-indicator {
  position: fixed;
  bottom: 64px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 10;
  padding: 8px 16px;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: 4px;
  color: var(--text-muted);
  font: 13px system-ui, sans-serif;
  white-space: nowrap;
}

#toolbar {
  position: fixed;
  bottom: 16px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 10;
  display: flex;
  gap: 8px;
}

#toolbar button {
  padding: 8px 14px;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: 4px;
  color: var(--text);
  font: 13px system-ui, sans-serif;
  cursor: pointer;
}

#toolbar button:hover:not(:disabled) {
  background: var(--bg-hover);
}

/* While Pull/Push Children is actually held down — pointer or
   keyboard — rather than merely hoverable. Same accent used for the
   free-flight status line's active state, so "something is actively
   engaged" reads consistently across the UI. */
#toolbar button.active {
  color: var(--accent);
  border-color: var(--accent);
}

#toolbar button:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

/* Sign-in / sign-up gate. Covers everything — there is nothing useful
   behind it until a session exists, and app.js hasn't even built the
   3D world yet at that point. */
#auth-overlay {
  position: fixed;
  inset: 0;
  z-index: 100; /* above every panel, toolbar and the canvas itself */
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-deep);
}

/* Required, not redundant: the `display: flex` above is an author rule
   on an ID, and any author `display` beats the browser's own
   `[hidden] { display: none }` — so without this, setting .hidden in
   auth.js would do nothing and the gate would never come down.
   #flight-mode-indicator, the other element toggled this way, sets no
   display of its own and so needs no equivalent. */
#auth-overlay[hidden] {
  display: none;
}

#auth-form {
  display: flex;
  flex-direction: column;
  gap: 14px;
  width: min(340px, calc(100vw - 32px));
  padding: 28px;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: 8px;
}

#auth-form h1 {
  margin: 0;
  color: var(--text);
  font: 600 22px system-ui, sans-serif;
}

#auth-intro {
  margin: -6px 0 2px;
  color: var(--text-muted);
  font: 13px system-ui, sans-serif;
}

#auth-form label {
  display: flex;
  flex-direction: column;
  gap: 6px;
  color: var(--text-muted);
  font: 13px system-ui, sans-serif;
}

#auth-form input {
  padding: 9px 10px;
  background: var(--bg-deep);
  border: 1px solid var(--border);
  border-radius: 4px;
  color: var(--text);
  font: 14px system-ui, sans-serif;
}

#auth-form input:focus-visible {
  outline: 2px solid var(--accent-blue);
  outline-offset: 1px;
}

#auth-submit {
  padding: 10px 12px;
  background: var(--accent-blue);
  border: 1px solid var(--accent-blue);
  border-radius: 4px;
  color: var(--bg-deep);
  font: 600 14px system-ui, sans-serif;
  cursor: pointer;
}

#auth-submit:hover:not(:disabled) {
  filter: brightness(1.1);
}

#auth-submit:disabled {
  opacity: 0.6;
  cursor: progress; /* submitting: hashing a password takes a moment on a Pi */
}

/* A button that reads as a link — it switches the form between signing
   in and signing up rather than submitting anything, so it shouldn't
   carry the same visual weight as the action it sits under. */
.linklike {
  align-self: center;
  padding: 2px;
  background: none;
  border: none;
  color: var(--text-muted);
  font: 13px system-ui, sans-serif;
  text-decoration: underline;
  cursor: pointer;
}

.linklike:hover {
  color: var(--text);
}

/* Who's signed in, at the bottom of the save/load menu. */
#account-row {
  display: flex;
  flex-basis: 100%;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding-top: 10px;
  border-top: 1px solid var(--border-subtle);
}

#account-name {
  color: var(--text-muted);
  font: 12px system-ui, sans-serif;
}

/* Hamburger button that reveals the save/load menu below it. */
#menu-toggle-btn {
  position: fixed;
  top: 16px;
  left: 16px;
  z-index: 11; /* above #mindspace-bar, so it stays clickable to close the menu too */
  width: 36px;
  height: 36px;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: 4px;
  color: var(--text);
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
}

#menu-toggle-btn:hover {
  background: var(--bg-hover);
}

/* Current mindspace name, shown next to the hamburger button — kept in
   sync with the name field on an interval rather than wired to every
   place that field can change (typing, load, rename, import); see the
   comment in app.js for why. Its sibling span mirrors the save/load
   status line that otherwise only lives inside the collapsed menu (see
   #mindspace-status) — that menu is closed most of the time, so a
   message like "Couldn't save: ..." landing only there would go
   unseen; mirroring it here keeps it visible regardless. */
#current-filename {
  position: fixed;
  top: 16px;
  left: 60px;
  z-index: 10;
  height: 36px;
  display: flex;
  align-items: center;
  gap: 8px;
  max-width: calc(100vw - 76px);
  color: var(--text-muted);
  font: 13px system-ui, sans-serif;
  pointer-events: none;
}

#current-filename-name {
  flex-shrink: 0;
}

#current-filename-status {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

#current-filename-status:empty {
  display: none; /* no stray divider/gap when there's nothing to show */
}

#current-filename-status.status--error {
  color: var(--danger);
}

/* Free-flight mode status/controls hint, bottom-left. Content is set
   by app.js from FreeFlight's own control bindings (see freeFlight.js's
   getControlsHint), so a rebinding there is reflected here too. */
#flight-status {
  position: fixed;
  bottom: 16px;
  left: 16px;
  z-index: 10;
  padding: 8px 12px;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: 4px;
  color: var(--text-muted);
  font: 12px system-ui, sans-serif;
}

#flight-status.active {
  color: var(--accent);
  border-color: var(--accent);
}

/* Save/load/rename/delete controls for whole mindspaces — hidden until
   the hamburger button is clicked. */
#mindspace-bar {
  display: none;
  position: fixed;
  top: 60px;
  left: 16px;
  z-index: 10;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  max-width: 380px;
  padding: 12px;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: 6px;
}

#mindspace-bar.open {
  display: flex;
}

#mindspace-bar select,
#mindspace-bar input {
  padding: 7px 10px;
  background: var(--bg-deep);
  border: 1px solid var(--border);
  border-radius: 4px;
  color: var(--text);
  font: 13px system-ui, sans-serif;
}

#mindspace-bar button {
  padding: 7px 12px;
  background: var(--bg-deep);
  border: 1px solid var(--border);
  border-radius: 4px;
  color: var(--text);
  font: 13px system-ui, sans-serif;
  cursor: pointer;
}

#mindspace-bar button:hover {
  background: var(--bg-hover);
}

#mindspace-status {
  flex-basis: 100%;
  font-size: 12px;
  color: var(--text-muted);
  min-height: 1.2em;
}

.autosave-control {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: var(--text-muted);
}

.autosave-control select {
  padding: 5px 8px;
  background: var(--bg-deep);
  border: 1px solid var(--border);
  border-radius: 4px;
  color: var(--text);
  font: 13px system-ui, sans-serif;
}

.autosave-control select:disabled {
  opacity: 0.5;
}

#mindspace-status.status--error {
  color: var(--danger);
}

/* Node name search, docked to the top-center. */
#search-bar {
  position: fixed;
  top: 16px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 10;
  width: var(--panel-width);
}

#search-bar input {
  width: 100%;
  box-sizing: border-box;
  padding: 8px 12px;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: 4px;
  color: var(--text);
  font: 13px system-ui, sans-serif;
}

/* Floating name label above each node, rendered by CSS2DRenderer.
   `.node-label` is the outer element CSS2DRenderer positions directly
   every frame — left bare here so nothing we do ever conflicts with
   that. All visual styling, plus the distance-based scale applied by
   distanceFade.js, lives on `.node-label-text` instead, which
   CSS2DRenderer never touches.
   Text color is set per-node in JS (node.js's setBaseColor), matching
   the node's own hierarchy color — this stylesheet only handles the
   parts that don't vary per node. */
.node-label {
  pointer-events: auto; /* opts back into clicks (see interactions.js) — the container around it stays pass-through */
  cursor: pointer;
}

.node-label-text {
  display: inline-block;
  /* CSS2DRenderer already centers `.node-label` itself on the node's
     anchor point (its default `center` is (0.5, 0.5), i.e. it applies
     its own `translate(-50%, -50%)` — see three.js's CSS2DRenderer.js).
     This element sits flush inside that already-centered box, so it
     only needs the other half of a vertical shift to go from
     "vertically centered on the anchor" to "bottom edge at the
     anchor" — no horizontal shift at all, since the outer element
     already centered that axis. Re-applying a full -50% horizontally
     (as an earlier version of this rule did) double-counts the outer
     element's own centering and drags the label left by roughly half
     its own width — a fixed, scale-independent error that distanceFade.js's
     later per-node label width (via distance-based text scale) simply
     made obvious. */
  transform: translateY(-50%);
  transform-origin: center bottom;
  padding: 2px 8px;
  font: 13px system-ui, sans-serif;
  background: rgba(13, 15, 20, 0.65);
  border-radius: 4px;
  white-space: nowrap;
  /* Scale is only recomputed every couple of frames (see
     distanceFade.js), not continuously — this transition smooths that
     into a continuous-looking change instead of visible small steps. */
  transition: transform 0.15s ease-out;
}

/* Selection is shown via the label's own font weight, not a color
   override — the label's color is reserved for showing which branch
   the node belongs to, at all times, selected or not. The class lives
   on the outer element (see node.js's setSelected), so this reaches
   the actual text via a descendant selector. */
.node-label--selected .node-label-text {
  font-weight: 700;
}

/* Persistent tree view of all nodes, docked to the upper-right. */
#hierarchy-panel {
  position: fixed;
  top: 0;
  right: 0;
  width: var(--panel-width);
  /* Capped so a long node list scrolls internally rather than growing
     down into #info-panel; collapsed, the panel shrinks to its header. */
  max-height: 45vh;
  box-sizing: border-box;
  padding: 20px;
  background: var(--bg-panel);
  border-left: 1px solid var(--bg-hover);
  border-bottom: 1px solid var(--bg-hover);
  color: var(--text);
  font-family: system-ui, sans-serif;
  overflow-y: auto;
  z-index: 5;
}

#hierarchy-panel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 12px;
}

#hierarchy-panel h2 {
  margin: 0;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-muted);
}

#hierarchy-collapse-btn {
  background: none;
  border: none;
  color: var(--text-muted);
  font-size: 13px;
  line-height: 1;
  padding: 2px 4px;
  cursor: pointer;
  transition: transform 0.15s ease-out;
}

#hierarchy-collapse-btn:hover {
  color: var(--text);
}

/* Collapsed: the list is hidden, and since the panel uses max-height
   rather than a fixed height, it naturally shrinks down to just the
   header row — no separate "collapsed height" rule needed. */
#hierarchy-panel.collapsed #hierarchy-list {
  display: none;
}

#hierarchy-panel.collapsed #hierarchy-collapse-btn {
  transform: rotate(-90deg);
}

.hierarchy-item {
  padding: 4px 0;
  font-size: 13px;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  cursor: pointer;
}

.hierarchy-item:hover {
  color: var(--accent);
}

.hierarchy-item--selected {
  color: var(--accent);
  background: rgba(255, 179, 71, 0.1);
  border-radius: 3px;
}

.hierarchy-item {
  cursor: grab;
}

.hierarchy-item--dragging {
  opacity: 0.4;
}

.hierarchy-item--drop-target {
  background: rgba(90, 141, 238, 0.25);
  outline: 1px dashed var(--accent-blue);
  border-radius: 3px;
}

/* Type-to-search dropdown used for choosing a node's parent. */
.parent-search {
  position: relative;
}

.suggestions {
  display: none;
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  margin-top: 4px;
  max-height: 160px;
  overflow-y: auto;
  background: var(--bg-deep);
  border: 1px solid var(--border);
  border-radius: 4px;
  z-index: 20;
}

.suggestions.visible {
  display: block;
}

.suggestion-item {
  padding: 6px 8px;
  font-size: 13px;
  color: var(--text);
  cursor: pointer;
}

.suggestion-item:hover {
  background: var(--bg-hover);
}

.image-attachment-list {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 8px;
}

.image-attachment {
  position: relative;
  width: 64px;
  height: 64px;
}

.image-attachment img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 4px;
  border: 1px solid var(--border);
}

.image-attachment-remove {
  position: absolute;
  top: -6px;
  right: -6px;
  width: 18px;
  height: 18px;
  line-height: 16px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--bg-panel);
  color: var(--text);
  font-size: 13px;
  cursor: pointer;
}

.image-attachment-remove:hover {
  background: var(--danger);
  color: var(--bg-panel);
}

.status-text {
  font-size: 12px;
  color: var(--text-muted);
  min-height: 1.2em;
  margin-top: 6px;
}

.status-text.status--error {
  color: var(--danger);
}

/* Selected-node detail panel — occupies the lower portion of the same
   right-hand column, below the hierarchy tree above it. */
/* Selected-node detail panel — now anchored independently to the
   bottom-right, decoupled from the hierarchy panel above it. Since
   the hierarchy panel now sizes itself to its content (see
   max-height above), the two would otherwise fight over vertical
   space; anchoring each from the opposite edge of the screen avoids
   that entirely. */
#info-panel {
  position: fixed;
  bottom: 0;
  right: 0;
  width: var(--panel-width);
  height: 55vh;
  overflow-y: auto; /* long notes / many attachments scroll instead of overflowing */
  box-sizing: border-box;
  padding: 24px 20px;
  background: var(--bg-panel);
  border-left: 1px solid var(--bg-hover);
  border-top: 1px solid var(--bg-hover);
  color: var(--text);
  font-family: system-ui, sans-serif;
  transform: translateX(100%);
  transition: transform 0.15s ease-out;
  z-index: 5;
}

#info-panel.visible {
  transform: translateX(0);
}

#info-panel label {
  display: block;
  margin-bottom: 18px;
  font-size: 13px;
  color: var(--text-muted);
}

#info-panel input,
#info-panel textarea {
  display: block;
  width: 100%;
  margin-top: 6px;
  box-sizing: border-box;
  padding: 8px;
  background: var(--bg-deep);
  border: 1px solid var(--border);
  border-radius: 4px;
  color: var(--text);
  font: inherit;
  resize: vertical;
}
