/* PlanExpert. One stylesheet, no build step, no framework.
 *
 * The design language follows CapExpert, so moving between the two does not
 * feel like changing tools: Montserrat, a near-black ink on a light grey page
 * with white panels, one soft blue accent, 12px card corners, and pills drawn
 * as a pale tint of their own colour rather than a solid block of it.
 *
 * Colours are HSL triples in variables, the same shape CapExpert uses, so the
 * dark scheme is a swap of the token block rather than a second set of rules.
 */

:root {
  /* CapExpert's palette, converted from its Tailwind tokens. */
  --bg:            hsl(210 7% 94%);
  --panel:         hsl(0 0% 100%);
  --panel-2:       hsl(210 7% 97.5%);
  --panel-3:       hsl(210 7% 94%);
  --ink:           hsl(180 7% 13%);
  --ink-2:         hsl(214 15% 42%);
  --ink-3:         hsl(214 12% 60%);
  --line:          hsl(210 8% 88%);
  --line-2:        hsl(210 8% 92.5%);

  --accent:        hsl(215 51% 65%);
  --accent-deep:   hsl(228 24% 34%);
  --accent-soft:   hsl(215 51% 65% / .13);
  --accent-line:   hsl(215 51% 65% / .45);

  /* Red means a problem: something needs whoever is looking at it, right
     now. Nothing else may be red -- see "Colour and status vocabulary" in
     CLAUDE.md. --progress and --neutral reuse --accent's and --ink-3's hues
     rather than inventing new ones. */
  --problem:       hsl(1 76% 40%);
  --attention:     hsl(38 92% 50%);
  --progress:      hsl(215 51% 65%);
  --done:          hsl(145 63% 42%);
  --neutral:       hsl(214 12% 60%);

  --shadow:        0 1px 8px rgba(0, 0, 0, .06);
  --shadow-lg:     0 4px 24px rgba(0, 0, 0, .10), 0 1px 3px rgba(0, 0, 0, .06);

  --r-card:        12px;
  --r-control:     8px;
  --r-pill:        999px;

  --row-h:         32px;

  /* Montserrat if it is installed, then the nearest geometric sans the OS
     ships, so the app never waits on a webfont it cannot reach offline. */
  --font: "Montserrat", "Avenir Next", "Century Gothic", "URW Gothic",
          -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

/* `data-theme` is resolved to light or dark before the first paint by the
   inline script in index.html, and `data-theme-mode` remembers whether that
   was the user's explicit choice or the system following along. Keying off an
   attribute rather than the media query is what lets the in-app toggle
   override the OS setting. */
:root[data-theme="dark"] {
  /* Taken from CapExpert's own dark tokens. Two things carry the look: the
     near-black has a slight cyan cast rather than being neutral, and the
     borders are indigo, not grey. */
    --bg:          hsl(195 8% 8%);
    --panel:       hsl(195 8% 11%);
    --panel-2:     hsl(195 8% 14%);
    --panel-3:     hsl(243 14% 17%);
    --ink:         hsl(210 7% 94%);
    --ink-2:       hsl(229 9% 70%);
    --ink-3:       hsl(229 9% 56%);
    --line:        hsl(243 25% 20%);
    --line-2:      hsl(243 20% 16%);

    --accent:      hsl(211 48% 66%);
    --accent-deep: hsl(211 55% 74%);
    --accent-soft: hsl(211 48% 66% / .17);
    --accent-line: hsl(211 48% 66% / .42);

    --problem:     hsl(0 72% 58%);
    --attention:   hsl(45 100% 55%);
    --progress:    hsl(211 48% 66%);
    --done:        hsl(145 55% 50%);
    --neutral:     hsl(229 9% 56%);

    --shadow:      0 1px 8px rgba(0, 0, 0, .45);
    --shadow-lg:   0 6px 28px rgba(0, 0, 0, .55), 0 1px 3px rgba(0, 0, 0, .4);
}

* { box-sizing: border-box; }

/* The `hidden` attribute is only a UA rule of `display: none`, so any class
   rule below that sets `display` beats it on specificity. That is how a hidden
   full-screen overlay ends up covering the page and eating every click while
   looking almost invisible. Three elements here toggle `hidden` and also carry
   a display from their class: the modal backdrop, the bulk edit bar and the
   view tabs. Make the attribute win. */
[hidden] { display: none !important; }

html, body { height: 100%; margin: 0; }

body {
  background: var(--bg);
  color: var(--ink);
  font: 13px/1.5 var(--font);
  -webkit-font-smoothing: antialiased;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

button, input, select, textarea { font: inherit; color: inherit; }

/* ---------------------------------------------------------------- topbar */

.topbar {
  display: flex;
  align-items: center;
  gap: 18px;
  padding: 0 18px;
  height: 58px;
  background: var(--panel);
  border-bottom: 1px solid var(--line);
  flex: none;
}

/* Two lines, mirroring the page title over its breadcrumb alongside it, so the
   lockup reads as part of the header rather than pinned to the corner. */
.brand { flex: none; line-height: 1.25; }

.brand-name {
  font-weight: 700;
  font-size: 17px;
  letter-spacing: -.2px;
  color: var(--ink);
}

.brand-name span { color: var(--accent); }

.brand-sub {
  font-size: 11px;
  letter-spacing: .1px;
  color: var(--ink-3);
}

/* The long form only where there is room for it. Below this the page title and
   the action buttons need every pixel, and "by CapExpert" is the first thing
   that can go -- the wordmark alone still says whose tool this is. */
@media (max-width: 1180px) {
  .brand-sub { display: none; }
}

/* Page title over a breadcrumb, the way CapExpert heads each screen. */
.page-head { flex: 1; min-width: 0; }

.page-title {
  font-size: 16px;
  font-weight: 700;
  letter-spacing: -.1px;
  line-height: 1.25;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.page-crumb {
  font-size: 11.5px;
  color: var(--ink-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.topbar-actions { display: flex; gap: 7px; flex: none; }

.btn {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r-control);
  padding: 6px 13px;
  cursor: pointer;
  color: var(--ink-2);
  font-weight: 500;
  font-size: 12.5px;
  white-space: nowrap;
  transition: background .12s, border-color .12s, color .12s;
}

.btn:hover { background: var(--panel-2); color: var(--ink); border-color: var(--ink-3); }
.btn.on { background: var(--accent-soft); border-color: var(--accent-line); color: var(--accent-deep); }
.btn.primary { background: var(--accent-deep); border-color: var(--accent-deep); color: #fff; }
.btn.primary:hover { filter: brightness(1.15); color: #fff; }
.btn.danger { color: var(--problem); }
.btn.danger:hover { background: var(--problem); border-color: var(--problem); color: #fff; }
.btn:disabled { opacity: .45; cursor: default; }

/* ------------------------------------------------------------- sections */

/* Navigate owns the tree, the grid and the inspector; every other section owns
   one panel. Written as "hide unless this is your section" so a new section
   adds one show-rule and nothing has to be taught to hide. */

body:not([data-view="navigate"]) .sidebar,
body:not([data-view="navigate"]) .resizer,
body:not([data-view="navigate"]) .main,
body:not([data-view="navigate"]) .inspector { display: none; }

.dash, .people { display: none; }
body[data-view="dashboard"] .dash { display: block; }
body[data-view="contacts"] .people { display: block; }

/* These act on the sheet you are looking at, and outside Navigate there is no
   sheet. Leaving them would silently act on whatever was open last. */
body:not([data-view="navigate"]) #btn-import,
body:not([data-view="navigate"]) #btn-export,
body:not([data-view="navigate"]) #btn-new-grid,
body:not([data-view="navigate"]) #btn-new-report { display: none; }

/* ---------------------------------------------------------------- layout */

.layout { flex: 1; display: flex; min-height: 0; }

/* ------------------------------------------------------------------ rail */

/* Sections, with settings pinned to the bottom. Narrow enough that it costs
   the grid almost nothing, wide enough to carry a word under each icon --
   an unlabelled icon rail is a guessing game until you have learned it. */
.rail {
  width: 64px;
  flex: none;
  display: flex;
  flex-direction: column;
  padding: 6px 0 8px;
  background: var(--panel);
  border-right: 1px solid var(--line);
}

.rail-spacer { flex: 1; }

.rail-btn {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  padding: 9px 2px 7px;
  background: none;
  border: 0;
  /* The active marker is a border rather than a pseudo-element so it cannot
     drift out of step with the padding. */
  border-left: 2px solid transparent;
  color: var(--ink-3);
  cursor: pointer;
  transition: background .12s, color .12s;
}

.rail-ico { font-size: 16px; line-height: 1; }
.rail-label { font-size: 9.5px; font-weight: 600; letter-spacing: .2px; }

.rail-btn:hover { background: var(--panel-2); color: var(--ink); }

.rail-btn.on {
  background: var(--accent-soft);
  border-left-color: var(--accent-deep);
  color: var(--accent-deep);
}

.rail-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

.sidebar {
  width: var(--sidebar-w, 226px);
  flex: none;
  background: var(--panel);
  border-right: 1px solid var(--line);
  overflow: auto;
  padding: 10px 8px 24px;
}

/* The handle overhangs the grid rather than the tree, so it never sits on top
   of the tree's scrollbar. It is transparent until you are on it, and the 5px
   it covers of the grid is inside that panel's 12px padding. */
.resizer {
  flex: none;
  width: 5px;
  margin-right: -5px;
  z-index: 2;
  cursor: col-resize;
  background: transparent;
  transition: background .12s ease;
}

.resizer:hover,
.resizer:focus-visible,
.resizer.dragging { background: var(--accent); }

.resizer:focus-visible { outline: none; }

/* Text selection follows the pointer during a drag and makes the whole grid
   flash blue, so the drag turns it off for the duration. */
body.resizing { user-select: none; cursor: col-resize; }

.main { flex: 1; min-width: 0; display: flex; flex-direction: column; }

.inspector {
  width: 264px;
  flex: none;
  background: var(--panel);
  border-left: 1px solid var(--line);
  overflow: auto;
  padding: 16px 16px 30px;
}

/* Collapsed: a narrow rail of icons, one per section, the same idea as the
   tree's own fold (setTreeHidden) but with something to click back open --
   the tree disappears into the Navigate rail button instead. */
.inspector.insp-collapsed {
  width: 44px;
  padding: 10px 7px;
  overflow: visible;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.insp-toggle {
  width: 28px;
  height: 28px;
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: var(--r-control);
  color: var(--ink-3);
  cursor: pointer;
  font-size: 12px;
  margin-bottom: 10px;
}

.insp-toggle:hover { color: var(--ink); border-color: var(--ink-3); }
.insp-collapsed .insp-toggle { margin-bottom: 8px; }

.insp-tab-btn {
  width: 30px;
  height: 30px;
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: 1px solid transparent;
  border-radius: var(--r-control);
  color: var(--ink-3);
  font-size: 14px;
  cursor: pointer;
  margin-bottom: 4px;
}

.insp-tab-btn:hover { background: var(--panel-2); color: var(--ink); border-color: var(--line); }

.insp-section { margin-top: 18px; }
.insp-section:first-of-type { margin-top: 0; }

/* --------------------------------------------------------------- sidebar */

.tree-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 5px 9px;
  margin-bottom: 1px;
  border-radius: var(--r-control);
  cursor: pointer;
  color: var(--ink-2);
  font-size: 12.5px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.tree-item:hover { background: var(--panel-2); color: var(--ink); }

.tree-item.active {
  background: var(--accent-soft);
  color: var(--accent-deep);
  font-weight: 600;
}

.tree-item .ico { flex: none; width: 15px; text-align: center; opacity: .6; }

.tree-folder {
  font-weight: 650;
  color: var(--ink);
  cursor: default;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: .55px;
  margin-top: 10px;
}

.tree-folder:hover { background: none; color: var(--ink); }

/* A folder with something in it is a button, so it has to look like one --
   which means undoing the inert styling above. */
.tree-folder.tree-toggle { cursor: pointer; }
.tree-folder.tree-toggle:hover { background: var(--panel-2); }
.tree-folder.tree-toggle:hover .ico { opacity: 1; }

.tree-folder.tree-toggle:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
  background: var(--panel-2);
}

/* The twisty carries the affordance, so it does not inherit the folder row's
   letter-spacing, and it sits a little brighter than a leaf's icon. */
.tree-folder .ico { font-size: 10px; letter-spacing: 0; opacity: .75; }

/* -------------------------------------------------------- view + toolbar */

.viewbar {
  display: flex;
  align-items: stretch;
  gap: 2px;
  padding: 0 16px;
  background: var(--panel);
  border-bottom: 1px solid var(--line);
  min-height: 36px;
  overflow-x: auto;
}

/* Uppercase, letter-spaced, underlined on the active one. */
.tab {
  padding: 10px 12px 8px;
  border-bottom: 2px solid transparent;
  cursor: pointer;
  color: var(--ink-3);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .55px;
  text-transform: uppercase;
  white-space: nowrap;
  display: flex;
  align-items: center;
  gap: 5px;
}

.tab:hover { color: var(--ink-2); }
.tab.active { color: var(--accent); border-bottom-color: var(--accent); }
.tab .x { opacity: .4; font-size: 10px; }
.tab .x:hover { opacity: 1; color: var(--problem); }

.toolbar {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 9px 16px;
  border-bottom: 1px solid var(--line);
  background: var(--bg);
  flex-wrap: wrap;
  min-height: 46px;
}

.toolbar select, .toolbar input[type=search] {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r-control);
  padding: 5px 9px;
  font-size: 12.5px;
  color: var(--ink-2);
  max-width: 200px;
}

.toolbar select:hover, .toolbar input[type=search]:hover { border-color: var(--ink-3); }
.toolbar .sep { width: 1px; height: 20px; background: var(--line); margin: 0 4px; }
.toolbar .spacer { flex: 1; }

.toolbar label {
  color: var(--ink-3);
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .5px;
}

.count { color: var(--ink-3); font-size: 12px; white-space: nowrap; }

/* --------------------------------------------------------------- surface */

.surface { flex: 1; overflow: auto; outline: none; position: relative; padding: 12px; }

/* ------------------------------------------------------------------ grid
 *
 * A card that happens to contain a table. Dense enough to still be a
 * spreadsheet -- CapExpert's airy row cards would cost too many visible rows.
 */

table.grid {
  border-collapse: separate;
  border-spacing: 0;
  min-width: 100%;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  overflow: hidden;
  box-shadow: var(--shadow);
}

table.grid th, table.grid td {
  border-bottom: 1px solid var(--line-2);
  padding: 0 10px;
  height: var(--row-h);
  text-align: left;
  font-weight: 400;
  vertical-align: middle;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 420px;
  background: var(--panel);
}

table.grid thead th {
  position: sticky;
  top: 0;
  z-index: 3;
  background: var(--panel-2);
  color: var(--ink-3);
  font-weight: 600;
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: .55px;
  border-bottom: 1px solid var(--line);
  cursor: pointer;
  user-select: none;
}

table.grid thead th:hover { color: var(--ink-2); }
table.grid thead th .fx { color: var(--accent); margin-left: 4px; font-size: 10px; }
table.grid thead th .arrow { color: var(--accent); margin-left: 4px; }

td.gutter, th.gutter {
  width: 36px;
  min-width: 36px;
  max-width: 36px;
  text-align: center;
  padding: 0;
  color: var(--ink-3);
  background: var(--panel-2);
  position: sticky;
  left: 0;
  z-index: 2;
  font-size: 11px;
  cursor: pointer;
}

thead th.gutter { z-index: 4; }
td.gutter.ticked { background: var(--accent-soft); color: var(--accent-deep); }

tr.row:hover td { background: var(--panel-2); }
tr.row.ticked td { background: var(--accent-soft); }

/* Every cell inside the selected rectangle. Deliberately above the focus
   outline below, so the one cell wearing both still shows the outline. */
td.cell.rng {
  background: var(--accent-soft) !important;
}

/* Only while a range is being dragged out. Left on permanently it would take
   away selecting the text inside a cell, which is still worth having. */
body.dragging-range { user-select: none; -webkit-user-select: none; }
body.dragging-range td.cell { cursor: cell; }

td.cell.sel {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
  border-radius: 3px;
  background: var(--panel) !important;
  z-index: 1;
  position: relative;
}

/* The cell whose value is on the clipboard. Dashed rather than solid so it
   reads as "taken from here" next to the solid selection, and it survives the
   selection moving away. Escape gives it up. */
td.cell.copied {
  outline: 2px dashed var(--accent-line);
  outline-offset: -2px;
  border-radius: 3px;
  position: relative;
}

/* A picklist, multi-picklist, contact or multi-contact cell: a chevron that
   opens its chooser, shown on hover so the affordance is not a secret kept
   for whichever cell happens to be selected. */
td.cell.choosable { position: relative; }

.cell-chevron {
  position: absolute;
  right: 3px;
  top: 50%;
  transform: translateY(-50%);
  width: 16px;
  height: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 4px;
  font-size: 9px;
  line-height: 1;
  color: var(--ink-3);
  background: var(--panel-2);
  opacity: 0;
  /* Not gated on :hover -- the first click at a fresh pointer position can
     land before the hover state has caught up, and that first click is the
     one this exists for. */
}

td.cell.choosable:hover .cell-chevron,
td.cell.choosable.sel .cell-chevron {
  opacity: 1;
}

.cell-chevron:hover { color: var(--ink); background: var(--line-2); }

td.calc { color: var(--ink-2); }
td.num { text-align: right; font-variant-numeric: tabular-nums; }
td.err { color: var(--problem); font-family: var(--mono); font-size: 11px; }
td.overdue { color: var(--problem); font-weight: 600; }

.indent { display: inline-block; }
.twisty { color: var(--ink-3); margin-right: 5px; font-size: 9px; }
.parent-row td { font-weight: 600; }

/* Kept visible only so the tree still reads around a filter match -- never a
 * match itself. Same de-emphasis as a disabled control elsewhere in the app. */
tr.row.filter-ghost td, .gantt-name.filter-ghost,
.gantt-bar.filter-ghost, .gantt-summary.filter-ghost, .gantt-milestone.filter-ghost {
  opacity: .45;
}

/* cell contents */

/* Soft tint of the value's own colour, the way CapExpert draws its category
   chips -- a pale background with the colour carried by the text. Reads far
   better than a solid block when a row is full of them. Each pill sets --c. */
.pill {
  display: inline-block;
  padding: 2px 9px;
  border-radius: var(--r-pill);
  font-size: 11px;
  font-weight: 600;
  line-height: 16px;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  vertical-align: middle;
  background: color-mix(in srgb, var(--c, var(--ink-3)) 15%, transparent);
  color: color-mix(in srgb, var(--c, var(--ink-3)) 78%, var(--ink));
}

:root[data-theme="dark"] .pill {
  background: color-mix(in srgb, var(--c, var(--ink-3)) 22%, transparent);
  color: color-mix(in srgb, var(--c, var(--ink-3)) 72%, white);
}

.filter-chip { cursor: pointer; display: inline-flex; align-items: center; gap: 5px; }
.filter-chip .x { opacity: .55; font-size: 10px; }
.filter-chip .x:hover { opacity: 1; color: var(--problem); }

.dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  margin-right: 6px;
  vertical-align: -1px;
  background: var(--c, var(--ink-3));
}

.avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  font-size: 9.5px;
  font-weight: 700;
  margin-right: 6px;
  vertical-align: -5px;
  flex: none;
  background: color-mix(in srgb, var(--c, var(--ink-3)) 18%, transparent);
  color: color-mix(in srgb, var(--c, var(--ink-3)) 80%, var(--ink));
}

:root[data-theme="dark"] .avatar {
  color: color-mix(in srgb, var(--c, var(--ink-3)) 75%, white);
}

.mark { font-size: 13px; }
.mark.off { opacity: .2; }

/* editor */

.editor {
  position: absolute;
  z-index: 20;
  border: 2px solid var(--accent);
  border-radius: var(--r-control);
  background: var(--panel);
  padding: 3px 7px;
  box-shadow: var(--shadow-lg);
  min-height: var(--row-h);
}

.editor select, .editor input, .editor textarea {
  border: none;
  outline: none;
  background: transparent;
  width: 100%;
  min-width: 130px;
  resize: none;
}

/* The picklist and multipicklist editor: a positioned list standing in for a
   native <select>, so it can filter, show each choice's colour, and open on
   the first click instead of needing one click to focus and a second to pop
   the list open. */
.picklist-list {
  position: absolute;
  left: -2px;
  top: calc(100% + 5px);
  z-index: 25;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r-control);
  box-shadow: var(--shadow-lg);
  padding: 4px;
  min-width: calc(100% + 4px);
  width: max-content;
  max-width: 280px;
  max-height: 240px;
  overflow-y: auto;
}

/* A cell near the bottom of the grid would otherwise hang the list off the
   edge of the scroll area, where the rows below the fold can't be clicked. */
.picklist-list.upward {
  top: auto;
  bottom: calc(100% + 5px);
}

.picklist-option {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 6px 8px;
  border-radius: calc(var(--r-control) - 2px);
  font-size: 12.5px;
  color: var(--ink-2);
  cursor: pointer;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.picklist-option:hover,
.picklist-option.hi { background: var(--panel-2); color: var(--ink); }

.picklist-option .dot { margin-right: 0; }

.picklist-option.picklist-special {
  color: var(--ink-3);
  border-top: 1px solid var(--line);
  border-radius: 0;
  margin-top: 3px;
  padding-top: 8px;
}

.picklist-check {
  flex: none;
  width: 14px;
  height: 14px;
  border: 1.5px solid var(--line);
  border-radius: 4px;
  position: relative;
}

.picklist-check.on {
  background: var(--accent-deep);
  border-color: var(--accent-deep);
}

.picklist-check.on::after {
  content: '';
  position: absolute;
  left: 4px;
  top: 1px;
  width: 3px;
  height: 7px;
  border: solid #fff;
  border-width: 0 1.5px 1.5px 0;
  transform: rotate(40deg);
}

/* ---------------------------------------------------------- group bands */

tr.band td {
  background: var(--panel-3);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  font-weight: 600;
  padding: 5px 10px;
  height: 32px;
  /* Cells clip by default; a clipped cell is its own scroll container, which
     stops the sticky label below from ever sticking. */
  overflow: visible;
  max-width: none;
}

.band-inner {
  display: flex;
  align-items: center;
  gap: 11px;
  position: sticky;
  left: 10px;
  width: max-content;
  max-width: 100%;
  /* The coloured rule CapExpert puts down the left of a grouped row. */
  border-left: 3px solid var(--c, var(--accent));
  padding-left: 9px;
}

.band-count { color: var(--ink-3); font-weight: 500; font-size: 11.5px; }
.band-total { color: var(--ink-2); font-weight: 600; font-size: 11.5px; }

.battery {
  display: inline-flex;
  height: 8px;
  width: 140px;
  border-radius: var(--r-pill);
  overflow: hidden;
  background: var(--line-2);
  flex: none;
}

.battery i { display: block; height: 100%; }

/* ----------------------------------------------------------------- board */

.board { display: flex; gap: 12px; align-items: flex-start; min-height: 100%; }

.lane {
  width: 262px;
  flex: none;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  box-shadow: var(--shadow);
  display: flex;
  flex-direction: column;
  max-height: 100%;
}

.lane.over { border-color: var(--accent); background: var(--accent-soft); }

.lane-head {
  padding: 10px 12px;
  border-bottom: 1px solid var(--line-2);
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 600;
  font-size: 12px;
  position: sticky;
  top: 0;
}

.lane-head .band-count { margin-left: auto; }
.lane-body { padding: 9px; display: flex; flex-direction: column; gap: 8px; overflow: auto; }

.card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-left: 3px solid var(--c, var(--ink-3));
  border-radius: var(--r-control);
  padding: 9px 11px;
  cursor: grab;
  font-size: 12.5px;
  box-shadow: var(--shadow);
  transition: box-shadow .12s, transform .12s;
}

.card:hover { box-shadow: var(--shadow-lg); transform: translateY(-1px); }
.card.dragging { opacity: .4; }

.card .card-id {
  color: var(--ink-3);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: .4px;
  font-variant-numeric: tabular-nums;
  margin-bottom: 2px;
}

.card .card-title { font-weight: 600; white-space: normal; line-height: 1.4; }

.card .card-meta {
  margin-top: 7px;
  display: flex;
  gap: 6px;
  align-items: center;
  color: var(--ink-3);
  font-size: 11.5px;
  flex-wrap: wrap;
}

/* ----------------------------------------------------------------- gantt */

/* Flex, not grid: a sticky grid item is pinned inside its own grid area and
   cannot ride the horizontal scroll, while a sticky flex item roams the whole
   container. The name rail depends on that. */
.gantt {
  display: flex;
  align-items: stretch;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  box-shadow: var(--shadow);
  width: max-content;
  min-width: 100%;
  /* No overflow: hidden here, however tempting for the rounded corners: it
     would make this box the sticky containing block and the name rail would
     scroll away with the chart. The canvas clips itself instead. */
}

/* The name rail rides over the chart while the surface scrolls sideways,
   the same trick the grid's gutter uses. */
.gantt-names {
  flex: none;
  width: 264px;
  position: sticky;
  left: 0;
  z-index: 5;
  background: var(--panel-2);
  border-right: 1px solid var(--line);
}

.gantt-name {
  position: absolute;
  left: 0;
  right: 0;
  height: 30px;
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 0 10px 0 8px;
  font-size: 12.5px;
  border-bottom: 1px solid var(--line-2);
  white-space: nowrap;
  overflow: hidden;
  cursor: pointer;
}

.gantt-name:hover { background: var(--panel-3); }
.gantt-name.parent { font-weight: 600; }
.gantt-name .indent { display: inline-block; flex: none; }
.gantt-name .gantt-title { overflow: hidden; text-overflow: ellipsis; }

.gantt-number {
  flex: none;
  min-width: 20px;
  text-align: right;
  color: var(--ink-3);
  font-size: 10.5px;
  font-variant-numeric: tabular-nums;
}

.gantt-chart { position: relative; }

.gantt-header {
  position: relative;
  height: 42px;
  border-bottom: 1px solid var(--line);
  background: var(--panel-2);
  font-size: 10.5px;
  color: var(--ink-3);
  user-select: none;
}

.gantt-month {
  position: absolute;
  top: 0;
  height: 21px;
  line-height: 21px;
  padding-left: 6px;
  border-left: 1px solid var(--line-2);
  font-weight: 600;
  letter-spacing: .4px;
  text-transform: uppercase;
  overflow: hidden;
  white-space: nowrap;
}

.gantt-day {
  position: absolute;
  top: 21px;
  height: 21px;
  line-height: 21px;
  text-align: center;
  font-variant-numeric: tabular-nums;
  overflow: hidden;
}

.gantt-day.week-start { border-left: 1px solid var(--line-2); text-align: left; padding-left: 4px; }

.gantt-canvas { position: relative; overflow: hidden; }

/* Non-working days at the fine zooms; alternating months at quarter zoom. */
.gantt-weekend, .gantt-band { position: absolute; top: 0; bottom: 0; background: var(--panel-2); }
.gantt-rule { position: absolute; top: 0; bottom: 0; width: 1px; background: var(--line-2); }

.gantt-today { position: absolute; top: 0; bottom: 0; width: 2px; background: var(--attention); opacity: .75; }
.gantt-today-dot {
  position: absolute;
  bottom: -3px;
  width: 7px;
  height: 7px;
  margin-left: -2px;
  border-radius: 50%;
  background: var(--attention);
}

.gantt-bar {
  position: absolute;
  height: 18px;
  border-radius: 5px;
  background: color-mix(in srgb, var(--bar, var(--accent)) 30%, transparent);
  border: 1px solid var(--bar, var(--accent));
  overflow: hidden;
  cursor: pointer;
}

.gantt-bar:hover { box-shadow: var(--shadow); }

.gantt-done { position: absolute; top: 0; bottom: 0; left: 0; background: var(--bar, var(--accent)); opacity: .8; }

.gantt-summary {
  position: absolute;
  height: 8px;
  border-radius: 2px;
  background: var(--ink-2);
  cursor: pointer;
}

/* Down-pointing end caps, so a phase reads as a bracket over its children. */
.gantt-summary::before, .gantt-summary::after {
  content: '';
  position: absolute;
  top: 0;
  border: 4px solid transparent;
  border-top: 8px solid var(--ink-2);
}
.gantt-summary::before { left: 0; }
.gantt-summary::after { right: 0; }

.gantt-milestone {
  position: absolute;
  width: 12px;
  height: 12px;
  margin: -6px 0 0 -6px;
  transform: rotate(45deg);
  border-radius: 2px;
  background: var(--accent-deep);
  cursor: pointer;
}

.gantt-links { position: absolute; top: 0; left: 0; pointer-events: none; }
.gantt-links path { fill: none; stroke: var(--ink-3); stroke-width: 1.2; opacity: .8; }
.gantt-links marker path { fill: var(--ink-3); stroke: none; }

/* Inserted by prepareGanttPrint() just before the print dialog opens, and
   removed again on afterprint -- display: none here is a belt-and-suspenders
   fallback in case those handlers ever leave it in the document. */
.print-header { display: none; }
.print-title { font-size: 15px; font-weight: 700; color: var(--ink); }
.print-meta {
  margin-top: 2px;
  font-size: 10px;
  color: var(--ink-2);
  text-transform: uppercase;
  letter-spacing: .4px;
}

/* Printing the gantt: everything but the chart itself is chrome for editing
   the sheet, not for reading a schedule, so it goes away. The scale that
   makes this a one-pager is computed in prepareGanttPrint() -- CSS alone
   cannot know how wide the chart happens to be. */
@media print {
  @page { size: landscape; margin: 0.4in; }

  /* Force the light palette regardless of the on-screen theme: a dark
     background is wasted ink and reads as a screenshot, not a handout. */
  :root[data-theme="dark"] {
    --bg:      hsl(210 7% 94%);
    --panel:   hsl(0 0% 100%);
    --panel-2: hsl(210 7% 97.5%);
    --panel-3: hsl(210 7% 94%);
    --ink:     hsl(180 7% 13%);
    --ink-2:   hsl(214 15% 42%);
    --ink-3:   hsl(214 12% 60%);
    --line:    hsl(210 8% 88%);
    --line-2:  hsl(210 8% 92.5%);
  }

  html, body { height: auto; overflow: visible; background: #fff; }
  body { display: block; }
  .layout, .main { display: block; height: auto; min-height: 0; overflow: visible; }
  .surface { overflow: visible; flex: none; padding: 0; }

  .topbar, .rail, .sidebar, .resizer, .viewbar, .toolbar,
  .inspector, .bulkbar, .toasts, .modal-backdrop { display: none !important; }

  .print-header {
    display: block;
    margin: 0 0 10px;
    padding-bottom: 8px;
    border-bottom: 1px solid var(--line);
  }

  .gantt {
    box-shadow: none;
    /* print-color-adjust is inherited, so setting it once here covers the
       status colours, weekend shading and progress fill below it -- without
       it browsers drop background colours by default to save ink, and a
       gantt with no bar fills is not a schedule. */
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }

  /* No scrolling in print, so the sticky name rail has nothing to stick
     against -- pin it to its normal flow position instead of leaving the
     stickiness to whatever each browser's print engine guesses. */
  .gantt-names { position: static; }
}

/* A date the scheduler owns: the value on screen came from predecessors or a
   rollup, not from what was typed in the cell. */
td.driven { color: var(--accent-deep); }
td.driven::after { content: ' ⚑'; font-size: 9px; color: var(--ink-3); }

/* ------------------------------------------------------------- inspector */

.insp-h {
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: .6px;
  color: var(--ink-3);
  margin: 18px 0 7px;
  font-weight: 700;
}

.insp-h:first-child { margin-top: 0; }
.insp-v { font-size: 13px; word-break: break-word; }
.insp-sub { color: var(--ink-2); font-size: 12px; }

.insp-formula {
  font-family: var(--mono);
  font-size: 11px;
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: var(--r-control);
  padding: 8px 9px;
  white-space: pre-wrap;
  word-break: break-word;
  color: var(--ink-2);
}

.pipeline { display: flex; gap: 3px; margin: 3px 0 5px; }

.pipeline i {
  flex: 1;
  height: 6px;
  border-radius: var(--r-pill);
  background: var(--line);
}

.pipeline i.on { background: var(--accent); }
/* Off-pipeline covers four different statuses (Overdue, Due soon,
   Unassigned, Stale) that are not all problems -- only Overdue is. The
   inspector sets --c per segment from the cell's own colour; this is the
   fallback for the rare case it doesn't. */
.pipeline i.off { background: var(--c, var(--problem)); }

.history { display: flex; flex-direction: column; gap: 9px; }

.hist { border-left: 2px solid var(--line); padding-left: 10px; font-size: 12px; }
.hist .when {
  display: flex;
  align-items: center;
  gap: 6px;
  color: var(--ink-3);
  font-size: 11px;
}

/* Who made the edit, pushed to the right of the timestamp. Same initials and
   hashed colour as an Owner cell, so the same person looks the same wherever
   they appear. */
.hist .by { display: flex; align-items: center; gap: 4px; margin-left: auto; }

.hist .by .avatar {
  width: 16px;
  height: 16px;
  font-size: 8px;
  flex: none;
  margin: 0;
}
/* An undo, a redo, or a deleted row or column moved this value rather than
   somebody typing it. Quiet, so it annotates the entry without competing
   with the values themselves. */
.hist .via {
  padding: 0 6px;
  border-radius: var(--r-pill);
  background: var(--line-2);
  color: var(--ink-2);
  font-size: 10px;
  font-weight: 600;
  white-space: nowrap;
}

.hist .from { color: var(--ink-3); text-decoration: line-through; }
.hist .to { color: var(--ink); }

.summary-field { display: flex; align-items: center; gap: 7px; margin-bottom: 6px; }

.summary-field input {
  flex: 1;
  min-width: 0;
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: var(--r-control);
  padding: 5px 8px;
}

/* --------------------------------------------------------------- bulkbar */

.bulkbar {
  flex: none;
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 10px 16px;
  background: var(--panel);
  border-top: 1px solid var(--line);
  box-shadow: 0 -2px 14px rgba(0, 0, 0, .06);
  flex-wrap: wrap;
}

.bulkbar .n { font-weight: 700; }

.bulkbar select, .bulkbar input {
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: var(--r-control);
  padding: 5px 9px;
  max-width: 200px;
}

/* ---------------------------------------------------------------- modals */

.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(16, 20, 28, .45);
  backdrop-filter: blur(2px);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 100;
  padding: 24px;
}

.modal {
  background: var(--panel);
  border-radius: var(--r-card);
  box-shadow: var(--shadow-lg);
  width: min(780px, 100%);
  max-height: 100%;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.modal h2 {
  margin: 0;
  padding: 17px 22px;
  font-size: 15px;
  font-weight: 700;
  border-bottom: 1px solid var(--line);
}

.modal-body { padding: 20px 22px; overflow: auto; }

.modal-foot {
  padding: 14px 22px;
  border-top: 1px solid var(--line);
  background: var(--panel-2);
  display: flex;
  gap: 9px;
  justify-content: flex-end;
  align-items: center;
}

.modal-foot .spacer { flex: 1; }

/* ------------------------------------------------------------- row menu */

.row-menu {
  position: fixed;
  z-index: 150;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r-control);
  box-shadow: var(--shadow-lg);
  padding: 4px;
  min-width: 150px;
  display: flex;
  flex-direction: column;
}

.row-menu-item {
  background: none;
  border: none;
  border-radius: calc(var(--r-control) - 2px);
  padding: 7px 10px;
  text-align: left;
  font: inherit;
  font-size: 12.5px;
  color: var(--ink-2);
  cursor: pointer;
}

.row-menu-item:hover { background: var(--panel-2); color: var(--ink); }
.row-menu-item.danger { color: var(--problem); }
.row-menu-item.danger:hover { background: var(--problem); color: #fff; }

.row-menu-sep { height: 1px; background: var(--line); margin: 4px 2px; }

.field { margin-bottom: 17px; }

.field > label {
  display: block;
  color: var(--ink-3);
  font-size: 10.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .55px;
  margin-bottom: 6px;
}

.field input[type=text], .field select, .field textarea {
  width: 100%;
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: var(--r-control);
  padding: 7px 10px;
}

.field textarea { min-height: 70px; font-family: var(--mono); font-size: 12px; }

.checks {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 16px;
  max-height: 200px;
  overflow: auto;
  border: 1px solid var(--line);
  border-radius: var(--r-control);
  padding: 10px 12px;
  background: var(--panel-2);
}

.checks label { display: flex; align-items: center; gap: 6px; font-size: 12.5px; }

.rowset { display: flex; flex-direction: column; gap: 7px; }
.rowline { display: flex; gap: 7px; align-items: center; }

.rowline select, .rowline input {
  flex: 1;
  min-width: 0;
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: var(--r-control);
  padding: 6px 9px;
}

.hint-lead { margin-top: 0; margin-bottom: 9px; }

/* One row of mutually exclusive choices, all of them visible. A settings panel
   is where you go to see what the options are, so the cycling button that used
   to live in the top bar would be the wrong control here. */
.segmented { display: flex; gap: 6px; }

.segmented button {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  padding: 11px 6px 9px;
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: var(--r-control);
  color: var(--ink-2);
  cursor: pointer;
  transition: background .12s, border-color .12s, color .12s;
}

.segmented button:hover { border-color: var(--ink-3); color: var(--ink); }

.segmented button.on {
  background: var(--accent-soft);
  border-color: var(--accent-line);
  color: var(--accent-deep);
}

.segmented button:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

.seg-ico { font-size: 17px; line-height: 1; }
.seg-label { font-size: 12px; font-weight: 600; }

/* A settings section, so more of them stack sensibly as they arrive. */
.set-group + .set-group {
  margin-top: 18px;
  padding-top: 18px;
  border-top: 1px solid var(--line-2);
}

.set-title {
  font-size: 10.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .55px;
  color: var(--ink-3);
  margin-bottom: 8px;
}

.templates { display: flex; flex-direction: column; gap: 8px; }

.template-card {
  display: block;
  width: 100%;
  text-align: left;
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: var(--r-control);
  padding: 10px 12px;
  cursor: pointer;
  color: inherit;
  font: inherit;
}

.template-card:hover { border-color: var(--accent); }

.template-card.on {
  border-color: var(--accent-deep);
  box-shadow: inset 0 0 0 1px var(--accent-deep);
}

.template-name { font-weight: 650; font-size: 13px; }
.template-blurb { color: var(--ink-2); font-size: 12px; margin-top: 3px; line-height: 1.45; }

.template-cols {
  color: var(--ink-3);
  font-family: var(--mono);
  font-size: 11px;
  margin-top: 6px;
  line-height: 1.4;
}

/* Which list a card came from — a template and the project it was copied
   from often share a name. */
.template-group {
  color: var(--ink-3);
  font-size: 10.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  margin-bottom: 2px;
}

/* One template is a statement, not a choice: it reads as a line rather than
   as a card you have to click to select something already selected. */
.template-single { font-weight: 650; font-size: 13px; }

/* A button that behaves like a link: it opens another modal rather than
   submitting the one it sits in. */
.linkish {
  display: inline-block;
  margin-top: 9px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--accent-deep);
  font: inherit;
  font-size: 12.5px;
  cursor: pointer;
}

.linkish:hover { text-decoration: underline; }
.linkish:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.hint { color: var(--ink-3); font-size: 12px; margin-top: 7px; line-height: 1.5; }
.errline { color: var(--problem); font-size: 12.5px; }

.choices-preview {
  display: flex;
  flex-direction: column;
  gap: 6px;
  max-height: 210px;
  overflow: auto;
  border: 1px solid var(--line);
  border-radius: var(--r-control);
  padding: 10px 12px;
  background: var(--panel-2);
}

.choice-row { display: flex; align-items: center; gap: 9px; }
.choice-row .pill { flex: 1; min-width: 0; text-align: center; }

.choice-row input[type=color] {
  width: 34px;
  height: 24px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: none;
  cursor: pointer;
  flex: none;
}

.colrow {
  display: grid;
  grid-template-columns: 1.4fr 1fr auto auto;
  gap: 7px;
  align-items: center;
  padding: 6px 0;
  border-bottom: 1px solid var(--line-2);
}

.colrow input, .colrow select {
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: var(--r-control);
  padding: 5px 8px;
  min-width: 0;
}

/* ---------------------------------------------------------------- toasts */

.toasts {
  position: fixed;
  right: 20px;
  bottom: 20px;
  display: flex;
  flex-direction: column;
  gap: 9px;
  z-index: 200;
  max-width: 400px;
}

.toast {
  background: var(--panel);
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  border-radius: var(--r-control);
  padding: 11px 15px;
  box-shadow: var(--shadow-lg);
  font-size: 12.5px;
}

.toast.bad { border-left-color: var(--problem); }
.toast.good { border-left-color: var(--done); }

/* ------------------------------------------------------------------ misc */

.empty {
  padding: 56px 24px;
  text-align: center;
  color: var(--ink-3);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  box-shadow: var(--shadow);
}

.empty h3 { color: var(--ink-2); font-weight: 600; margin: 0 0 10px; font-size: 14px; }

.totals-row td {
  background: var(--panel-2);
  border-top: 2px solid var(--line);
  font-weight: 700;
  position: sticky;
  bottom: 0;
}

/* ------------------------------------------------------------- dashboard */

.dash {
  flex: 1;
  min-width: 0;
  overflow: auto;
  padding: 20px 24px 40px;
}

.dash-head { margin-bottom: 18px; }
.dash-h { font-size: 19px; font-weight: 700; letter-spacing: -.2px; }
.dash-sub { font-size: 12.5px; color: var(--ink-3); margin-top: 3px; }

/* auto-fit rather than a fixed count: the tiles reflow on a narrow window
   instead of squeezing to the point where the numbers stop being readable. */
.tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(148px, 1fr));
  gap: 10px;
  margin-bottom: 20px;
}

.tile {
  background: var(--panel);
  border: 1px solid var(--line);
  border-left: 3px solid var(--c, var(--ink-3));
  border-radius: var(--r-card);
  padding: 13px 15px;
  box-shadow: var(--shadow);
}

.tile-n { font-size: 25px; font-weight: 700; line-height: 1.1; letter-spacing: -.5px; }
.tile-k { font-size: 11.5px; color: var(--ink-2); margin-top: 3px; font-weight: 500; }
/* Zero is good news here, so it should not shout like a count does. */
.tile.zero .tile-n { color: var(--ink-3); }

.dash-cols {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 14px;
  align-items: start;
}

.dash-card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  box-shadow: var(--shadow);
  overflow: hidden;
}

.dash-card-h {
  padding: 12px 15px;
  border-bottom: 1px solid var(--line-2);
  font-size: 10.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .55px;
  color: var(--ink-3);
}

/* The wrapper, not .dash-row itself, owns the divider now: a project or owner
   row can carry an expando under it, and the divider has to sit under that
   too, not reappear between the row and its own items. */
.dash-item-wrap { border-bottom: 1px solid var(--line-2); }
.dash-item-wrap:last-child { border-bottom: 0; }

.dash-row-line { display: flex; align-items: stretch; }

.dash-row {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: 1;
  min-width: 0;
  padding: 9px 15px;
  border: 0;
  background: none;
  color: inherit;
  text-align: left;
  font: inherit;
  cursor: pointer;
}

.dash-row:hover { background: var(--panel-2); }
.dash-row:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

.dash-chev { flex: none; width: 8px; color: var(--ink-3); font-size: 10px; }
.dash-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dash-n { font-variant-numeric: tabular-nums; font-size: 12.5px; color: var(--ink-2); flex: none; }

/* Proportion of this row's open items that need attention. Width only -- the
   number beside it carries the value, this just makes the row scannable. */
.dash-bar {
  flex: none;
  width: 74px;
  height: 5px;
  border-radius: 999px;
  background: var(--panel-3);
  overflow: hidden;
}

.dash-bar i { display: block; height: 100%; background: var(--c, var(--accent)); }

/* A project can still be opened whole -- expanding only shows its open items,
   not the closed ones a full log still has. Outside the row button itself
   since a button cannot nest inside another button. */
.dash-open {
  flex: none;
  width: 36px;
  border: 0;
  border-left: 1px solid var(--line-2);
  background: none;
  color: var(--ink-3);
  font-size: 13px;
  cursor: pointer;
}

.dash-open:hover { background: var(--panel-2); color: var(--ink); }
.dash-open:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

.dash-expando {
  max-height: 320px;
  overflow-y: auto;
  background: var(--panel-2);
  border-top: 1px solid var(--line-2);
}

.dash-item {
  display: block;
  width: 100%;
  padding: 8px 15px 8px 31px;
  border: 0;
  border-bottom: 1px solid var(--line-2);
  background: none;
  color: inherit;
  text-align: left;
  font: inherit;
  cursor: pointer;
}

.dash-item:last-child { border-bottom: 0; }
.dash-item:hover { background: var(--panel-3); }
.dash-item:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

.dash-item-top { display: flex; align-items: center; gap: 7px; }

.dash-dot { flex: none; width: 7px; height: 7px; border-radius: 50%; background: var(--c, var(--ink-3)); }

.dash-ref { flex: none; font-variant-numeric: tabular-nums; font-size: 11px; color: var(--ink-3); }

.dash-item-desc {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 12.5px;
}

.dash-item-due { flex: none; font-size: 11px; color: var(--ink-3); font-variant-numeric: tabular-nums; }

.dash-item-meta {
  margin-top: 2px;
  padding-left: 14px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 11px;
  color: var(--ink-3);
}

.dash-empty { padding: 15px; color: var(--ink-3); font-size: 12.5px; }

/* -------------------------------------------------------------- contacts */

.people {
  flex: 1;
  min-width: 0;
  overflow: auto;
  padding: 20px 24px 40px;
}

.people-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 16px;
}

.people-bar .grow { flex: 1; min-width: 0; }

.people-search {
  width: 260px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r-control);
  padding: 7px 11px;
}

.people-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(268px, 1fr));
  gap: 12px;
}

.card-person {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  text-align: left;
  width: 100%;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  box-shadow: var(--shadow);
  padding: 14px;
  cursor: pointer;
  color: inherit;
  font: inherit;
  transition: border-color .12s, box-shadow .12s;
}

.card-person:hover { border-color: var(--accent-line); box-shadow: var(--shadow-lg); }
.card-person:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

/* The existing grid avatar, one size up. Same initials, same hashed colour, so
   a face in the directory matches the same face in an Owner cell. */
.card-person .avatar {
  width: 38px;
  height: 38px;
  font-size: 13px;
  flex: none;
  margin: 0;
}

.person-body { flex: 1; min-width: 0; }
.person-name { font-weight: 650; font-size: 13.5px; }
.person-role { color: var(--ink-2); font-size: 12px; margin-top: 1px; }

.person-line {
  display: block;
  color: var(--ink-3);
  font-size: 11.5px;
  margin-top: 5px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.person-missing { color: var(--attention); }

/* Two across, because first/last and email/phone belong side by side. */
.field-pair { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }

/* Title block and the Mine/Everyone toggle on one line, the toggle right. */
.dash-head-row { display: flex; align-items: flex-start; gap: 12px; }
.dash-head-row .grow { flex: 1; min-width: 0; }
.dash-scope { display: flex; gap: 6px; flex: none; }

/* Folding the tree away. The resizer goes with it, or it would sit against the
   rail as a handle for something that is not there. */
body.tree-hidden .sidebar,
body.tree-hidden .resizer { display: none; }

/* ------------------------------------------------------- deleting things */

/* The row was ellipsising its own text; now the name does, so the ✕ keeps its
   place at the right edge instead of being pushed out of the row. */
.tree-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }

.tree-del,
.tree-add {
  flex: none;
  width: 18px;
  height: 18px;
  padding: 0;
  border: 0;
  border-radius: 4px;
  background: none;
  color: var(--ink-3);
  font-size: 11px;
  line-height: 1;
  cursor: pointer;
  /* Hidden until the row is under the pointer: twenty rows each showing a
     delete button reads as a page asking to be tidied. */
  visibility: hidden;
}

.tree-item:hover .tree-del,
.tree-item:hover .tree-add,
.tree-del:focus-visible,
.tree-add:focus-visible { visibility: visible; }

.tree-del:hover { background: var(--problem); color: #fff; }
/* Adding is not destructive, so it takes the accent rather than the red. */
.tree-add:hover { background: var(--accent); color: #fff; }
.tree-del:focus-visible,
.tree-add:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

.del-what {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 4px;
}

.del-line {
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: var(--r-control);
  padding: 6px 11px;
  font-weight: 600;
  font-size: 12.5px;
}

.del-list {
  max-height: 150px;
  overflow: auto;
  border: 1px solid var(--line);
  border-radius: var(--r-control);
  background: var(--panel-2);
  padding: 8px 11px;
  font-size: 12px;
  color: var(--ink-2);
  margin-bottom: 14px;
}

/* The value set for "is one of", on its own line under the filter row. */
.filter-checks { margin: -3px 0 4px; max-height: 132px; }

/* One OR/AND group nested one level inside the sheet Filter panel's tree. */
.filter-group {
  display: flex;
  flex-direction: column;
  gap: 7px;
  border-left: 2px solid var(--line);
  padding: 9px 0 2px 12px;
  margin-left: 4px;
}


/* --------------------------------------------------------------- accounts */

/* The Settings panel grew a people list when sign-in arrived. It reuses the
   pill and hint the rest of the panel already uses; these are the shapes it
   needed that did not exist yet. */

.btn-quiet {
  font: inherit; font-size: 13px; padding: 6px 11px;
  color: var(--ink-2); background: var(--panel);
  border: 1px solid var(--line); border-radius: var(--r-control);
  cursor: pointer;
}
.btn-quiet:hover { background: var(--panel-2); color: var(--ink); }
.btn-quiet:disabled { opacity: .5; cursor: default; }

.field-row { display: flex; gap: 8px; align-items: center; margin: 10px 0 4px; }
.field-row input {
  flex: 1 1 auto; min-width: 0; font: inherit; font-size: 13px;
  padding: 7px 10px; color: var(--ink); background: var(--panel);
  border: 1px solid var(--line); border-radius: var(--r-control);
}
.field-row input:focus { outline: none; border-color: var(--accent-line); }

.set-subtitle {
  margin-top: 18px; font-size: 12px; font-weight: 600;
  letter-spacing: .06em; text-transform: uppercase; color: var(--ink-2);
}

.account-card {
  padding: 12px 14px; border: 1px solid var(--line);
  border-radius: var(--r-control); background: var(--panel-2);
}

.user-list { display: flex; flex-direction: column; gap: 6px; }
.user-row {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 9px 11px; border: 1px solid var(--line);
  border-radius: var(--r-control); background: var(--panel);
}
.user-who { flex: 1 1 180px; min-width: 0; }
.user-name { font-size: 13px; font-weight: 600; color: var(--ink); }
.user-mail { font-size: 12px; color: var(--ink-3); }
.user-tags { display: flex; gap: 5px; flex-wrap: wrap; }
.user-actions { display: flex; gap: 6px; flex-wrap: wrap; }

/* ------------------------------------------------------------- permissions */

/* Locks and sharing arrived together. The padlock and the person are drawn
   as SVG in app.js and take the text colour of wherever they sit, so they
   follow the theme without colours of their own. */

.lock-ico, .person-ico { width: 9px; height: 11px; flex: none; }
.person-ico { width: 11px; height: 11px; }

table.grid thead th .lock-ico { color: var(--ink-3); margin-left: 5px; vertical-align: -1px; }
/* Beside a schedule's row number rather than instead of it: Predecessors
   refer to rows by that number. */
td.gutter .lock-ico { color: var(--ink-3); vertical-align: -1px; margin-right: 2px; }

/* A cell a lock keeps from the person looking at it: dimmer, and not a place
   to type. Only drawn for somebody the lock stops. */
td.cell.locked { color: var(--ink-3); cursor: not-allowed; }
td.cell.locked .pill { opacity: .7; }
.card.locked-card { border-style: dashed; }

.insp-lock {
  display: flex;
  gap: 6px;
  align-items: flex-start;
  margin-top: 8px;
  font-size: 12px;
  color: var(--ink-2);
  line-height: 1.45;
}
.insp-lock .lock-ico { margin-top: 2px; color: var(--ink-3); }

/* A menu line that says something rather than does something. */
.row-menu-note {
  padding: 7px 10px;
  max-width: 240px;
  font-size: 12px;
  line-height: 1.45;
  color: var(--ink-3);
}

.pill.view-only { --c: var(--ink-3); }

/* A report that left rows out says so above them. */
.report-note {
  margin: 0 0 10px;
  padding: 8px 12px;
  font-size: 12.5px;
  color: var(--ink-2);
  background: var(--accent-soft);
  border: 1px solid var(--accent-line);
  border-radius: var(--r-control);
}

/* Where the tree would be, for somebody nothing is shared with yet. */
.tree-note {
  margin: 14px 6px;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--ink-2);
}

.tree-share {
  flex: none;
  width: 18px;
  height: 18px;
  padding: 0;
  border: 0;
  border-radius: 4px;
  background: none;
  color: var(--ink-3);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  visibility: hidden;
}
.tree-item:hover .tree-share,
.tree-share:focus-visible { visibility: visible; }
.tree-share:hover { background: var(--accent); color: #fff; }
.tree-share:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

/* The Share dialog. */
.share-path { font-size: 12px; color: var(--ink-3); margin-bottom: 8px; }

.share-add select {
  flex: 1 1 auto;
  min-width: 0;
  font: inherit;
  font-size: 13px;
  padding: 7px 10px;
  color: var(--ink);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r-control);
}
.share-add select + select { flex: 0 0 auto; }

.share-list { display: flex; flex-direction: column; gap: 6px; margin-top: 8px; }

.share-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: var(--r-control);
  background: var(--panel);
}
.share-row .avatar { margin-right: 0; vertical-align: 0; }
.share-who { flex: 1 1 auto; min-width: 0; }
.share-who .user-mail { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.share-row select {
  font: inherit;
  font-size: 12.5px;
  padding: 5px 8px;
  color: var(--ink);
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: var(--r-control);
}

.pill.role-pill { --c: var(--accent-deep); }

.share-roles {
  margin-top: 16px;
  padding-top: 12px;
  border-top: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 12px;
  color: var(--ink-3);
  line-height: 1.45;
}
.share-roles b { color: var(--ink-2); font-weight: 600; }

/* Settings: what each person can reach. */
.user-reach { font-size: 12px; color: var(--ink-2); margin-top: 2px; }

.access-panel {
  flex: 1 1 100%;
  padding: 4px 2px 2px;
  border-top: 1px solid var(--line-2);
}
.access-list { max-height: 220px; overflow: auto; }
.access-line {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 3px 0;
  font-size: 12.5px;
}
.access-line .pill { flex: none; }
.access-name { color: var(--ink); min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.access-by { color: var(--ink-3); font-size: 11.5px; white-space: nowrap; }
.access-change { font-size: 12px; color: var(--ink-2); padding: 2px 0; }

.check-row {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--ink);
  margin: 8px 0 2px;
  cursor: pointer;
}

.btn-quiet.on { background: var(--accent-soft); border-color: var(--accent-line); color: var(--accent-deep); }
