@font-face {
  font-family: "Hanken Grotesk";
  src: url("fonts/HankenGrotesk-Variable.woff2") format("woff2-variations");
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
}

@font-face {
  font-family: "Playpen Sans";
  src: url("fonts/PlaypenSans-Variable.woff2") format("woff2-variations");
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
}

@font-face {
  font-family: "Hanken Grotesk Fallback";
  src: local("Segoe UI"), local("Arial");
  size-adjust: 100.06%;
  ascent-override: 90%;
  descent-override: 22%;
  line-gap-override: 0%;
}

/* Colours live in themes.css, one block per theme. Only the tokens that no theme varies
   belong here. */
:root {
  --ui-font: "Hanken Grotesk", "Hanken Grotesk Fallback", system-ui, -apple-system,
    "Segoe UI", sans-serif;
  --text-caption: 0.6875rem;
  --text-body: 0.8125rem;
  --text-title: 0.9375rem;
  --text-heading: 1.125rem;
  --text-brand: 1.375rem;
  --weight-normal: 400;
  --weight-medium: 500;
  --weight-semibold: 600;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
  /* The canvas pans on horizontal wheel deltas, which would otherwise reach the browser as
     back-navigation, and on touch, which would otherwise pull to refresh. */
  overscroll-behavior: none;
  color-scheme: var(--color-scheme);
  background: var(--bg);
  color: var(--ink);
  font-family: var(--ui-font);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  font-kerning: normal;
  font-optical-sizing: auto;
  overflow: hidden;
}

/* Mobile browsers resolve 100vh against the viewport with the address bar and tab strip
   retracted, so on a tablet the app is laid out taller than the area actually on screen and
   its bottom edge — which `overflow: hidden` on body makes unscrollable — is cut off. The
   dynamic unit tracks the visible area as that chrome shows and hides. */
#app {
  display: flex;
  height: 100vh;
  height: 100dvh;
}

#sidebar {
  width: 220px;
  flex: 0 0 220px;
  background: var(--panel);
  border-right: 1px solid var(--panel-border);
  display: flex;
  flex-direction: column;
}

#sidebar-header {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  padding: 14px 16px 10px;
  border-bottom: 1px solid var(--panel-border);
}

#sidebar-identity {
  flex: 1;
  min-width: 0;
}

/* Collapsing hides the sidebar outright rather than narrowing it to a rail: the file rows,
   workspace bar and footer have no icon-only form, and reclaiming the full width is the point.
   #sidebar-reveal in the topbar is what brings it back. The state is stamped on the root
   element so the pre-paint script in index.html can apply it before the sidebar is parsed. */
:root[data-sidebar="collapsed"] #sidebar { display: none; }

#sidebar-reveal { display: none; }

:root[data-sidebar="collapsed"] #sidebar-reveal { display: block; }

#sidebar-toggle,
#sidebar-reveal {
  flex-shrink: 0;
  padding: 2px 7px;
  background: none;
  border: none;
  border-radius: 8px;
  color: var(--muted);
  font-family: inherit;
  font-size: var(--text-body);
  line-height: 1.4;
  cursor: pointer;
}

/* An inset shadow rather than a border, so revealing the edge on hover cannot shift the
   surrounding layout by the border's width. */
#sidebar-toggle:hover,
#sidebar-reveal:hover {
  background: var(--row-hover);
  box-shadow: inset 0 0 0 1px var(--panel-border);
  color: var(--ink);
}

.logo {
  font-size: var(--text-brand);
  font-weight: var(--weight-semibold);
  display: block;
}

.tagline {
  color: var(--muted);
  font-size: var(--text-caption);
}

#file-list {
  list-style: none;
  margin: 0;
  padding: 8px;
  overflow-y: auto;
  flex: 1;
}

#file-list li {
  padding: 6px 10px;
  border-radius: 8px;
  cursor: pointer;
  font-size: var(--text-body);
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

#file-list li:hover { background: var(--row-hover); color: var(--ink); }
#file-list li.active {
  background: var(--row-active);
  color: var(--ink);
  font-weight: var(--weight-medium);
}

#file-list .folder-row,
#file-list .file-row {
  display: flex;
  align-items: center;
  gap: 6px;
}

#file-list .folder-row { user-select: none; }
#file-list .file-row.editing { flex-wrap: wrap; }

.folder-caret {
  width: 10px;
  flex-shrink: 0;
  font-size: var(--text-caption);
}

.file-name {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
}

.file-rename-input {
  flex: 1;
  min-width: 0;
  padding: 2px 6px;
  background: var(--field-bg);
  border: 1px solid var(--accent);
  border-radius: 6px;
  color: var(--ink);
  font-family: inherit;
  font-size: var(--text-body);
  outline: none;
}

.file-rename-input.invalid { border-color: var(--danger); }

.file-rename-error {
  flex-basis: 100%;
  color: var(--danger);
  font-size: var(--text-caption);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.file-delete {
  visibility: hidden;
  flex-shrink: 0;
  padding: 0 4px;
  background: none;
  border: none;
  border-radius: 6px;
  color: var(--muted);
  font-family: inherit;
  font-size: var(--text-caption);
  cursor: pointer;
}

#file-list li:hover .file-delete { visibility: visible; }
.file-delete:hover, .file-delete.armed { color: var(--danger); }

#new-file-button {
  margin: 8px;
  padding: 8px;
  background: transparent;
  border: 1px dashed var(--panel-border);
  border-radius: 8px;
  color: var(--muted);
  font-family: inherit;
  font-size: var(--text-body);
  cursor: pointer;
}

#new-file-button:hover { color: var(--ink); border-color: var(--muted); }

#new-file-input {
  margin: 8px;
  padding: 8px;
  background: var(--field-bg);
  border: 1px solid var(--accent);
  border-radius: 8px;
  color: var(--ink);
  font-family: inherit;
  font-size: var(--text-body);
  outline: none;
}

#new-file-input.invalid { border-color: var(--danger); }

#new-file-error {
  margin: 0 8px 8px;
  color: var(--danger);
  font-size: var(--text-caption);
}

#workspace-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  border-top: 1px solid var(--panel-border);
}

#workspace-name {
  flex: 1;
  color: var(--muted);
  font-size: var(--text-body);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

#workspace-bar button {
  flex-shrink: 0;
  padding: 4px 8px;
  background: none;
  border: none;
  border-radius: 8px;
  color: var(--muted);
  font-family: inherit;
  font-size: var(--text-body);
  cursor: pointer;
}

/* The button's edge is an inset shadow rather than a border so revealing it on hover cannot
   shift the bar's layout by the border's width. */
#workspace-bar button:hover {
  background: var(--row-hover);
  box-shadow: inset 0 0 0 1px var(--panel-border);
  color: var(--ink);
}

#sidebar-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 12px;
  border-top: 1px solid var(--panel-border);
}

#help-toggle {
  background: none;
  border: none;
  color: var(--muted);
  font-family: inherit;
  font-size: var(--text-body);
  cursor: pointer;
}

#help-toggle:hover { color: var(--ink); }

#connection-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--danger);
  display: inline-block;
}

#connection-dot.connected { background: var(--success); }

#workspace {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
}

#topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 8px 14px;
  border-bottom: 1px solid var(--panel-border);
  background: var(--panel);
}

/* Flexes rather than relying on the topbar's space-between: #sidebar-reveal appears as a third
   child, which would otherwise push the breadcrumb to the middle whenever it is shown. */
#breadcrumb {
  flex: 1;
  min-width: 0;
  margin-right: 12px;
  font-size: var(--text-body);
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

#breadcrumb .crumb {
  cursor: pointer;
  color: var(--muted);
}

#breadcrumb .crumb:hover { color: var(--ink); text-decoration: underline; }
#breadcrumb .crumb.current { color: var(--ink); cursor: default; text-decoration: none; }
#breadcrumb .separator { margin: 0 6px; opacity: 0.5; }

#topbar-actions { display: flex; gap: 12px; align-items: center; }

#toolbar,
#view-controls { display: flex; gap: 4px; }

#toolbar button,
#view-controls button {
  background: transparent;
  border: 1px solid var(--panel-border);
  border-radius: 6px;
  color: var(--muted);
  font-family: inherit;
  font-size: var(--text-body);
  min-width: 28px;
  padding: 3px 7px;
  cursor: pointer;
}

#toolbar button:hover,
#view-controls button:hover { color: var(--ink); border-color: var(--muted); }

#toolbar button.active {
  color: var(--accent);
  border-color: var(--accent);
  font-weight: var(--weight-medium);
}

#zoom-level-button { font-variant-numeric: tabular-nums; }

#canvas-container {
  position: relative;
  flex: 1;
  min-height: 0;
}

#canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  touch-action: none;
}

#empty-state {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  color: var(--muted);
  pointer-events: none;
}

#empty-state h1 {
  font-size: var(--text-brand);
  font-weight: var(--weight-semibold);
  margin: 0 0 6px;
}

#empty-state p { margin: 0; font-size: var(--text-body); }

.hidden { display: none !important; }

.floating {
  position: absolute;
  background: var(--panel);
  border: 1px solid var(--panel-border);
  border-radius: 10px;
  box-shadow: var(--shadow-floating);
  padding: 10px;
  z-index: 10;
}

/* Sits on the canvas in place of the node's drawn title, so it carries no panel chrome and
   takes its font, size, colour and alignment from the canvas at the current zoom. */
#title-editor {
  position: absolute;
  z-index: 11;
  background: transparent;
  border: none;
  padding: 0 4px;
  outline: none;
  line-height: 1;
}

/* Names a region in place, over the label the canvas draws at its top-left corner. The reason
   line only appears when a name is refused. */
#region-name-editor {
  position: absolute;
  z-index: 11;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

#region-name-input {
  background: transparent;
  border: none;
  padding: 0 4px;
  outline: none;
  line-height: 1;
}

#region-name-error {
  display: none;
  max-width: 240px;
  background: var(--panel-bg);
  border: 1px solid var(--danger);
  border-radius: 4px;
  color: var(--danger);
  padding: 2px 6px;
  font-size: 12px;
}

#region-name-editor.rejected #region-name-error { display: block; }

#node-editor { width: 264px; display: flex; flex-direction: column; gap: 8px; }

#node-editor input[type="text"],
#node-editor input:not([type]),
#node-editor textarea,
#edge-editor input,
#edge-editor select,
#graph-panel input:not([type]),
#graph-panel textarea,
#preferences-options select {
  width: 100%;
  background: var(--field-bg);
  border: 1px solid var(--panel-border);
  border-radius: 7px;
  color: var(--ink);
  font-family: var(--ui-font);
  font-size: var(--text-body);
  padding: 6px 8px;
  outline: none;
  resize: vertical;
}

#node-editor input:focus,
#node-editor textarea:focus,
#edge-editor input:focus,
#edge-editor select:focus,
#graph-panel input:focus,
#graph-panel textarea:focus,
#preferences-options select:focus {
  border-color: var(--accent);
}

/* The native control's arrow is drawn by the platform and ignores the theme, so it is
   replaced: two gradient wedges make a chevron out of the theme's own tokens, which is why
   the background colour has to be set separately from the background images. */
#edge-editor select,
#preferences-options select {
  appearance: none;
  padding-right: 26px;
  background-color: var(--field-bg);
  background-image:
    linear-gradient(45deg, transparent 50%, var(--muted) 50%),
    linear-gradient(135deg, var(--muted) 50%, transparent 50%);
  background-position: right 13px center, right 9px center;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  cursor: pointer;
}

#edge-editor select:hover,
#preferences-options select:hover { border-color: var(--muted); }

#ne-title { font-size: var(--text-title); }

#ne-advanced summary {
  cursor: pointer;
  color: var(--muted);
  font-size: var(--text-body);
  user-select: none;
}

#ne-advanced[open] summary { margin-bottom: 6px; }

#ne-advanced label,
#graph-panel label {
  display: block;
  font-size: var(--text-caption);
  color: var(--muted);
  margin-bottom: 6px;
}

.check-row { display: flex; align-items: center; gap: 6px; }
.check-row input { accent-color: var(--accent); }

.editor-actions { display: flex; align-items: center; gap: 6px; }
.editor-actions .spacer { flex: 1; }

.quiet-button,
.danger-button {
  background: transparent;
  border: 1px solid var(--panel-border);
  border-radius: 7px;
  color: var(--muted);
  font-family: inherit;
  font-size: var(--text-body);
  padding: 4px 10px;
  cursor: pointer;
}

.quiet-button:hover { color: var(--accent); border-color: var(--accent); }
.danger-button:hover { color: var(--danger); border-color: var(--danger); }

#edge-editor { width: 248px; display: flex; flex-direction: column; gap: 8px; }

#ee-data { display: flex; flex-direction: column; gap: 6px; align-items: flex-start; }
#ee-data-rows { display: flex; flex-direction: column; gap: 4px; width: 100%; }

.field-caption { font-size: var(--text-caption); color: var(--muted); }

/* Read-only lines in an editor: what the file already says, and why an edit was refused. */
.field-note { font-size: var(--text-caption); color: var(--muted); margin: 0; }
.field-error { font-size: var(--text-caption); color: var(--danger); margin: 0; }

#region-editor { width: 264px; display: flex; flex-direction: column; gap: 8px; }
#region-editor textarea {
  width: 100%;
  background: var(--field-bg);
  border: 1px solid var(--panel-border);
  border-radius: 6px;
  color: var(--text);
  font-family: inherit;
  font-size: var(--text-body);
  padding: 6px 8px;
  resize: vertical;
}

#re-name { color: var(--canvas-region-stroke); font-size: var(--text-body); margin: 0; }
#re-members { display: flex; flex-direction: column; gap: 4px; }

#re-member-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
#re-member-list li { display: flex; }
/* Members are listed, not edited: the entry is a way back to the node, never a way to add one. */
#re-member-list button {
  background: transparent;
  border: none;
  color: var(--text);
  cursor: pointer;
  font-family: inherit;
  font-size: var(--text-body);
  padding: 1px 0;
  text-align: left;
}
#re-member-list button:hover { color: var(--canvas-region-stroke); }
#re-member-list .missing { color: var(--danger); cursor: default; }

.data-row { display: flex; align-items: center; gap: 4px; }
.data-row input { flex: 1 1 0; min-width: 0; }

.row-remove,
.row-edit {
  background: transparent;
  border: none;
  color: var(--muted);
  cursor: pointer;
  font-family: inherit;
  font-size: var(--text-body);
  line-height: 1;
  padding: 2px 4px;
}
.row-remove:hover { color: var(--danger); }
.row-edit:hover { color: var(--accent); }

#ne-references,
#re-references,
#gp-references { display: flex; flex-direction: column; gap: 6px; align-items: flex-start; }
#ne-reference-rows,
#re-reference-rows,
#gp-reference-rows { display: flex; flex-direction: column; gap: 6px; width: 100%; }

.reference-row { display: flex; align-items: center; gap: 4px; width: 100%; }
.reference-row.is-editing .reference-display,
.reference-row.is-editing .row-edit { display: none; }
.reference-row:not(.is-editing) .reference-editor { display: none; }

.reference-display,
.reference-row .reference-editor {
  flex: 1 1 0;
  min-width: 0;
  background: var(--field-bg);
  border: 1px solid var(--panel-border);
  border-radius: 7px;
  color: var(--ink);
  font-family: var(--ui-font);
  font-size: var(--text-body);
  padding: 6px 8px;
  outline: none;
}
.reference-display { cursor: default; line-height: 1.3; }
.reference-display a,
.reference-display span {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--ink);
  text-decoration: none;
}
.reference-display a {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}
.reference-display a:hover { color: var(--ink); }

#node-editor .reference-row .reference-editor,
#region-editor .reference-row .reference-editor,
#graph-panel .reference-row .reference-editor {
  width: auto;
}
.reference-row .reference-editor:focus { border-color: var(--accent); }

#ne-reference-rows.is-disabled,
#re-reference-rows.is-disabled,
#gp-reference-rows.is-disabled { pointer-events: none; }

#graph-panel {
  left: 14px;
  bottom: 14px;
  width: 250px;
}

#graph-panel.collapsed #gp-body { display: none; }
#graph-panel.collapsed { width: auto; padding: 4px 6px; }

#gp-toggle {
  background: none;
  border: none;
  color: var(--muted);
  font-family: inherit;
  font-size: var(--text-body);
  cursor: pointer;
  padding: 4px 6px;
  width: 100%;
  text-align: left;
}

#gp-toggle:hover { color: var(--ink); }

#help-overlay {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  background: var(--panel);
  border: 1px solid var(--panel-border);
  border-radius: 12px;
  padding: 18px 24px;
  box-shadow: var(--shadow-modal);
  z-index: 20;
}

#help-overlay h2 {
  margin: 0 0 10px;
  font-size: var(--text-heading);
  font-weight: var(--weight-semibold);
}

#help-overlay table { border-collapse: collapse; font-size: var(--text-body); }
#help-overlay td { padding: 3px 8px; }
#help-overlay td:first-child { color: var(--accent); white-space: nowrap; }
#help-overlay td:last-child { color: var(--muted); }

.modal {
  position: fixed;
  inset: 0;
  background: var(--scrim);
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: center;
}

.modal-panel {
  background: var(--panel);
  border: 1px solid var(--panel-border);
  border-radius: 12px;
  box-shadow: var(--shadow-modal);
  padding: 18px 20px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.modal-panel h2 {
  margin: 0;
  font-size: var(--text-heading);
  font-weight: var(--weight-semibold);
}

#preferences-panel { min-width: 280px; }

#preferences-options {
  display: flex;
  flex-direction: column;
  gap: 10px;
  font-size: var(--text-body);
  color: var(--muted);
}

/* Caption left, control right, every control the same width, so the options read as a column
   of settings rather than a stack of sentences. The checkbox row keeps its own layout: its
   caption follows the box. */
#preferences-options label:not(.check-row) {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

#preferences-options select { width: 190px; }

/* Marks where the user-level options end and the ones stored in this workspace's manifest
   begin — the two are saved to different places and travel differently. */
.settings-group-title {
  margin: 6px 0 0;
  font-size: var(--text-caption);
  font-weight: var(--weight-semibold);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
  border-top: 1px solid var(--panel-border);
  padding-top: 10px;
}

.settings-hint { margin: -4px 0 0; font-size: var(--text-caption); }

/* Slider and readout stay together on the right, rather than being spread apart by the
   space-between the other option rows use. */
.slider-row { justify-content: flex-start; }
.slider-row input[type="range"] { width: 150px; margin-left: auto; accent-color: var(--accent); }
.slider-row output { width: 26px; text-align: right; font-variant-numeric: tabular-nums; }

#screenshot-preview-frame {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 560px;
  height: 340px;
  background: var(--bg);
  border: 1px solid var(--panel-border);
  border-radius: 8px;
}

#screenshot-resolution,
#screenshot-options {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: var(--text-body);
  color: var(--muted);
}

#screenshot-scale-presets { display: flex; gap: 4px; }
#screenshot-scale-presets .quiet-button.active { color: var(--accent); border-color: var(--accent); }
#screenshot-scale-presets .quiet-button:disabled { color: var(--disabled); border-color: var(--disabled); cursor: default; }

#screenshot-resolution label { display: flex; align-items: center; gap: 6px; }

#screenshot-width {
  width: 84px;
  background: var(--field-bg);
  border: 1px solid var(--panel-border);
  border-radius: 7px;
  color: var(--ink);
  font-family: var(--ui-font);
  font-size: var(--text-body);
  padding: 4px 6px;
  outline: none;
}

#screenshot-width:focus { border-color: var(--accent); }
#screenshot-dimensions { margin-left: auto; }
#screenshot-error { margin: 0; font-size: var(--text-body); color: var(--danger); }
#screenshot-download:disabled { color: var(--disabled); border-color: var(--disabled); cursor: default; }

.context-menu {
  position: fixed;
  min-width: 168px;
  background: var(--panel);
  border: 1px solid var(--panel-border);
  border-radius: 10px;
  box-shadow: var(--shadow-modal);
  padding: 4px;
  z-index: 30;
  display: flex;
  flex-direction: column;
}

.context-menu-item {
  background: transparent;
  border: none;
  border-radius: 7px;
  color: var(--muted);
  font-family: inherit;
  font-size: var(--text-body);
  text-align: left;
  padding: 6px 10px;
  cursor: pointer;
}

.context-menu-item:hover { background: var(--row-hover); color: var(--ink); }
.context-menu-item.danger:hover { background: var(--row-hover); color: var(--danger); }
.context-menu-item.disabled { color: var(--disabled); cursor: default; pointer-events: none; }

.context-menu-separator {
  height: 1px;
  background: var(--panel-border);
  margin: 4px 6px;
}
