:root {
  --bg: #ffffff;
  --fg: #1f2328;
  --muted: #6b7280;
  --line: #e5e7eb;
  --head: #f6f7f9;
  --zebra: #fafbfc;
  --accent: #2563eb;
  --chip: #eef2ff;
  --chip-fg: #3730a3;
  --new: #fef3c7;
  --new-fg: #92400e;
  --readonly: #f9fafb;
  --error: #b91c1c;
  --shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
}
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #0f1115;
    --fg: #e6e8eb;
    --muted: #9aa3ad;
    --line: #262b33;
    --head: #161a20;
    --zebra: #12151a;
    --accent: #60a5fa;
    --chip: #1f2a44;
    --chip-fg: #c7d2fe;
    --new: #3b2f0b;
    --new-fg: #fcd34d;
    --readonly: #13161b;
    --error: #f87171;
    --shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
  }
}
* {
  box-sizing: border-box;
}
html,
body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font: 14px/1.4 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}
.app {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}
.topbar {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 14px 20px;
  border-bottom: 1px solid var(--line);
  position: sticky;
  top: 0;
  background: var(--bg);
  z-index: 3;
}
.topbar h1 {
  font-size: 18px;
  margin: 0;
  flex: 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.search {
  font: inherit;
  padding: 6px 10px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--bg);
  color: var(--fg);
  min-width: 180px;
}
.grid-wrap {
  overflow: auto;
  flex: 1;
}
.grid {
  border-collapse: separate;
  border-spacing: 0;
  min-width: 100%;
}
.grid th,
.grid td {
  border-bottom: 1px solid var(--line);
  border-right: 1px solid var(--line);
  padding: 8px 12px;
  text-align: left;
  vertical-align: top;
  max-width: 420px;
}
.grid th {
  /* Sticky is also the positioning context the resize handle anchors to. */
  position: sticky;
  top: 0;
  background: var(--head);
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  user-select: none;
  z-index: 2;
  padding-right: 16px;
}
.grid th .lock {
  margin-left: 6px;
  opacity: 0.65;
  vertical-align: -2px;
  display: inline-block;
  line-height: 0;
}
.col-resize {
  position: absolute;
  top: 0;
  /* Straddles the boundary rather than sitting behind it: aiming exactly at a 1px
     line is the difference between resizing a column and re-sorting the table. */
  right: -6px;
  width: 13px;
  height: 100%;
  cursor: col-resize;
  touch-action: none;
  z-index: 1;
}
.col-resize::after {
  content: "";
  position: absolute;
  top: 20%;
  bottom: 20%;
  right: 6px;
  width: 2px;
  border-radius: 1px;
  background: transparent;
}
.grid th:hover .col-resize::after {
  background: var(--accent);
}
body.resizing {
  cursor: col-resize;
  user-select: none;
}
/* A pinned column must clip rather than push its neighbours around. */
.grid[style*="fixed"] td,
.grid[style*="fixed"] th {
  overflow: hidden;
  text-overflow: ellipsis;
}
.grid[style*="fixed"] td .cell-text {
  display: block;
  overflow-wrap: anywhere;
}
.grid th .sort-arrow {
  margin-left: 6px;
  font-size: 10px;
  color: var(--muted);
}
.grid tbody tr:nth-child(even) td {
  background: var(--zebra);
}
.grid td.readonly {
  background: var(--readonly);
  color: var(--muted);
}
.grid td:first-child.readonly {
  color: var(--fg);
  font-weight: 600;
}
.grid td.editable {
  cursor: text;
}
.grid td.editable:hover {
  box-shadow: inset 0 0 0 1px var(--accent);
}
.grid td.editing {
  box-shadow: inset 0 0 0 2px var(--accent);
  background: var(--bg) !important;
  padding: 4px 6px;
}
.grid td.empty {
  text-align: center;
  color: var(--muted);
  padding: 40px;
}
.foot {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 20px;
  border-top: 1px solid var(--line);
  color: var(--muted);
  font-size: 12.5px;
  position: sticky;
  bottom: 0;
  background: var(--bg);
}
.screen {
  margin: auto;
  max-width: 480px;
  padding: 48px 24px;
  text-align: center;
}
.screen h1 {
  font-size: 20px;
  margin: 0 0 8px;
}
.toast {
  position: fixed;
  left: 50%;
  bottom: 56px;
  transform: translate(-50%, 16px);
  opacity: 0;
  transition: all 0.25s ease;
  background: var(--fg);
  color: var(--bg);
  padding: 10px 14px;
  border-radius: 10px;
  box-shadow: var(--shadow);
  max-width: 90vw;
  z-index: 10;
}
.toast-error {
  background: var(--error);
  color: #fff;
}
.toast.show {
  opacity: 1;
  transform: translate(-50%, 0);
}
@media (max-width: 640px) {
  .topbar {
    padding: 10px 12px;
    gap: 8px;
  }
  .grid th,
  .grid td {
    padding: 6px 8px;
    max-width: 260px;
  }
  .foot {
    flex-direction: column;
    gap: 2px;
  }
}
.grid td.editing {
  overflow: visible;
  position: relative;
}

/* Password gate */
.password-form {
  display: flex;
  gap: 8px;
  margin-top: 14px;
  justify-content: center;
}
.password-field {
  position: relative;
  display: flex;
  align-items: center;
}
.password-form input {
  padding: 8px 36px 8px 10px;
  border-radius: 8px;
  min-width: 220px;
  border: 1px solid var(--line);
  background: var(--bg);
  color: var(--fg);
  font: inherit;
}
.password-form input:focus {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
.password-eye {
  position: absolute;
  right: 4px;
  border: none;
  background: transparent;
  /* A button does not inherit color -- the user agent forces `buttontext`, which is
     near-black in both themes. The icon strokes with currentColor, so without this it
     is invisible on the dark gate. */
  color: var(--fg);
  cursor: pointer;
  display: flex;
  align-items: center;
  line-height: 1;
  padding: 4px 6px;
  opacity: 0.7;
}
.password-eye:hover {
  opacity: 1;
}
.password-form button[type="submit"] {
  padding: 8px 16px;
  border-radius: 8px;
  border: 1px solid var(--accent);
  background: var(--accent);
  color: #fff;
  font: inherit;
  cursor: pointer;
}
.password-form button:disabled {
  opacity: 0.6;
  cursor: default;
}
.error-text {
  color: var(--error);
}

/* Keyboard use: the grid is reachable and shows where it is. */
.grid td:focus {
  outline: none;
}
.grid td:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 2px var(--accent);
}
/* The invitation at the foot of the table. */
.add-row td {
  background: var(--bg);
  padding: 6px 12px;
}
.grid tbody tr.add-row:nth-child(even) td {
  background: var(--bg);
}
.add-row form {
  display: flex;
  gap: 8px;
  align-items: center;
}
.add-button {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: none;
  background: transparent;
  color: var(--muted);
  font: inherit;
  cursor: pointer;
  padding: 4px 2px;
  border-radius: 6px;
}
.add-button:hover {
  color: var(--accent);
}
.add-input {
  font: inherit;
  padding: 5px 8px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--bg);
  color: var(--fg);
  min-width: 220px;
}
.add-input:focus {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
.add-confirm {
  font: inherit;
  padding: 5px 12px;
  border-radius: 6px;
  border: 1px solid var(--accent);
  background: var(--accent);
  color: #fff;
  cursor: pointer;
}
.add-confirm:disabled {
  opacity: 0.6;
  cursor: default;
}
.toast-info {
  background: var(--fg);
  color: var(--bg);
}

/* ---------- Table / Canvas ---------- */
.view-host {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
/* The canvas fills the screen below the bar rather than growing with its content:
   everything in it is absolutely positioned, so it has no height of its own. */
.app.mode-canvas {
  height: 100vh;
  height: 100dvh;
}
.mode-switch {
  display: inline-flex;
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 2px;
  gap: 2px;
  flex: none;
}
.mode-switch button {
  font: inherit;
  font-size: 13px;
  border: none;
  background: transparent;
  color: var(--muted);
  padding: 4px 12px;
  border-radius: 6px;
  cursor: pointer;
}
.mode-switch button[aria-selected="true"] {
  background: var(--chip);
  color: var(--chip-fg);
}


/* Chips, cell text and the editor popovers.
   Shared by the table, the canvas panel and the plugin's Bases canvas view,
   which injects this file and canvas.css with the theme's colours mapped in. */
.cell-text {
  white-space: pre-wrap;
  word-break: break-word;
}
.cell-input {
  font: inherit;
  width: 100%;
  border: none;
  outline: none;
  background: transparent;
  color: var(--fg);
  padding: 4px 6px;
}
.select-wrap {
  width: 100%;
}
.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}
.chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: var(--chip);
  color: var(--chip-fg);
  border-radius: 999px;
  padding: 2px 8px;
  font-size: 12.5px;
  line-height: 1.5;
  white-space: nowrap;
}
.chip-new {
  background: var(--new);
  color: var(--new-fg);
  border: 1px dashed currentColor;
}
.chip-x {
  border: none;
  background: transparent;
  color: inherit;
  cursor: pointer;
  font-size: 14px;
  line-height: 1;
  padding: 0 0 0 2px;
  opacity: 0.7;
}
.chip-x:hover {
  opacity: 1;
}
.chips-editor {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  align-items: center;
  min-height: 28px;
  cursor: text;
}
.chips-input {
  font: inherit;
  border: none;
  outline: none;
  background: transparent;
  color: var(--fg);
  min-width: 120px;
  flex: 1;
  padding: 2px 4px;
}
.muted {
  color: var(--muted);
}
.select-wrap,
.chips-editor {
  position: relative;
}
.suggest {
  position: absolute;
  left: 0;
  top: 100%;
  margin-top: 4px;
  min-width: 220px;
  max-width: 360px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow: var(--shadow);
  z-index: 20;
  overflow: hidden;
}
.suggest-item {
  padding: 6px 10px;
  cursor: pointer;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.suggest-item.active,
.suggest-item:hover {
  background: var(--chip);
  color: var(--chip-fg);
}
.link-button {
  border: none;
  background: transparent;
  color: var(--accent);
  font: inherit;
  cursor: pointer;
  padding: 0;
  text-decoration: underline;
}
/* The hidden attribute must win over any class that sets display -- the view hosts,
   the mode switch and the canvas panel are all shown and hidden by attribute. */
[hidden] {
  display: none !important;
}

/* ---------- The canvas ---------- */
.canvas-host {
  position: relative;
  overflow: hidden;
}
.canvas-wrap {
  position: absolute;
  inset: 0;
  overflow: hidden;
  cursor: grab;
  touch-action: none;
  background-color: var(--zebra);
  background-image: radial-gradient(var(--line) 1px, transparent 1px);
  background-size: 22px 22px;
}
.canvas-wrap.panning {
  cursor: grabbing;
}
.canvas-world {
  position: absolute;
  left: 0;
  top: 0;
  transform-origin: 0 0;
}
/* Sizes below are canvas units, not screen pixels: they scale with the zoom, the way
   text on an Obsidian canvas card does. */
/* Anything divided by --k is a fixed size on screen rather than on the canvas: the
   track bands and their labels have to read at the zoom that fits a whole roadmap on
   a screen, which is a tenth of full size or less. */
.cv-group {
  position: absolute;
  --c: var(--muted);
  border: calc(2px / var(--k, 1)) solid color-mix(in srgb, var(--c) 75%, transparent);
  border-radius: calc(12px / var(--k, 1));
  background: color-mix(in srgb, var(--c) 11%, transparent);
}
.cv-group-anchor {
  position: absolute;
  height: 0;
  pointer-events: none;
}
.cv-group-label {
  position: absolute;
  left: 0;
  bottom: 100%;
  transform-origin: 0 100%;
  transform: scale(calc(1 / var(--k, 1))) translateY(-6px);
  font-size: 14px;
  font-weight: 600;
  line-height: 1.3;
  padding: 3px 11px;
  border-radius: 7px;
  background: var(--c);
  color: var(--on-c, #fff);
  white-space: nowrap;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
}
.cv-edges {
  position: absolute;
  left: 0;
  top: 0;
  overflow: visible;
  pointer-events: none;
}
.cv-edges path {
  fill: none;
  stroke-width: 1.6;
}
.cv-card {
  position: absolute;
  --c: var(--line);
  box-sizing: border-box;
  background: var(--bg);
  border: calc(1.5px / var(--k, 1)) solid var(--line);
  border-radius: 14px;
  padding: 20px 22px;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.08);
  cursor: pointer;
  overflow: hidden;
  transition: box-shadow 0.15s ease, opacity 0.15s ease;
}
.cv-card:hover {
  box-shadow: 0 6px 22px rgba(0, 0, 0, 0.16);
}
.cv-card:focus {
  outline: none;
}
/* A coloured card is tinted through, as Obsidian draws it, rather than given an edge
   that disappears once the canvas is zoomed out. */
.cv-card.tinted {
  background: color-mix(in srgb, var(--c) 16%, var(--bg));
  border-color: color-mix(in srgb, var(--c) 60%, var(--line));
}
.cv-card:focus-visible,
.cv-card.selected {
  box-shadow: 0 0 0 calc(3px / var(--k, 1)) var(--accent);
}
.cv-card.dim {
  opacity: 0.25;
}
.cv-card-title {
  font-size: 26px;
  font-weight: 600;
  line-height: 1.25;
  margin-bottom: 14px;
  overflow-wrap: anywhere;
}
.cv-card-chips {
  gap: 8px;
}
.cv-card-chips .chip {
  font-size: 18px;
  padding: 4px 14px;
}
.chip-flag {
  background: var(--new);
  color: var(--new-fg);
}
.cv-controls {
  position: absolute;
  right: 16px;
  bottom: 16px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  z-index: 2;
}
.cv-control {
  width: 34px;
  height: 34px;
  border-radius: 8px;
  border: 1px solid var(--line);
  background: var(--bg);
  color: var(--fg);
  font: inherit;
  font-size: 17px;
  line-height: 1;
  cursor: pointer;
  box-shadow: var(--shadow);
}
.cv-control:hover {
  border-color: var(--accent);
}

/* ---------- The side panel ---------- */
.canvas-panel {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: min(380px, 100%);
  background: var(--bg);
  border-left: 1px solid var(--line);
  box-shadow: var(--shadow);
  overflow-y: auto;
  z-index: 3;
  display: flex;
  flex-direction: column;
}
.cv-panel-head {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 18px 18px 10px;
  border-bottom: 1px solid var(--line);
}
.cv-panel-title {
  flex: 1;
  font-size: 17px;
  margin: 0;
  overflow-wrap: anywhere;
}
.cv-panel-open {
  font: inherit;
  color: inherit;
  border: none;
  background: transparent;
  padding: 0;
  cursor: pointer;
  text-align: left;
}
.cv-panel-open:hover {
  text-decoration: underline;
}
.cv-panel-close {
  border: none;
  background: transparent;
  color: var(--muted);
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
  padding: 0 4px;
}
.cv-panel-close:hover {
  color: var(--fg);
}
.cv-fields {
  padding: 8px 12px;
  flex: 1;
}
.cv-field {
  padding: 8px 6px;
}
.cv-field-label {
  font-size: 12px;
  color: var(--muted);
  margin-bottom: 4px;
  display: flex;
  align-items: center;
  gap: 4px;
}
.cv-field-value {
  min-height: 28px;
  padding: 4px 6px;
  border-radius: 6px;
}
.cv-field.editable .cv-field-value {
  cursor: text;
}
.cv-field.editable .cv-field-value:hover {
  background: var(--head);
}
.cv-field-value:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 2px var(--accent);
}
.cv-field-value.editing {
  box-shadow: inset 0 0 0 2px var(--accent);
  position: relative;
}
.cv-empty {
  font-size: 13px;
}
.cv-panel-foot {
  padding: 12px 18px 18px;
  border-top: 1px solid var(--line);
}
/* The panel slides over the canvas's right edge; move the zoom controls out from
   under it rather than let them vanish while a card is open. */
.canvas-host.panel-open .cv-controls {
  right: calc(min(380px, 100%) + 16px);
}
@media (max-width: 640px) {
  /* On a phone the panel is the whole width, so the controls simply wait. */
  .canvas-host.panel-open .cv-controls {
    display: none;
  }
}
