/* The tree column (src/ui/tree.js). */
/* ---- the tree (collapsed: each row shifted to its lineage node; open: the whole tree; all motion sideways) ---- */
.tree {
  position: relative;
  width: var(--tree-w);
  flex: none;
  z-index: 2;
} /* --tree-w, --tree-m: set from tree.js */
.tree-panel {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  z-index: 21;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--sidebar);
  border-right: 1px solid var(--edge);
  transition:
    width var(--t-move) var(--ease),
    box-shadow var(--t-move);
}
.tree-panel.open {
  box-shadow:
    0 0 0 1px var(--black-40),
    10px 0 28px var(--black-42);
}
.tree-scroll {
  flex: 1;
  min-height: 0;
  overflow-x: hidden;
  overflow-y: auto;
  scrollbar-width: thin;
}
.tree-scroll.sideways {
  overflow-x: auto;
} /* open, wider than the window less a margin, and done widening (tree.js) */
.tree-canvas {
  position: relative;
}
/* the fixed add button: a node's size with a node's margin (30 px, FOOT_M in tree.js); open, it spans the tree */
.tree-foot {
  flex: none;
  position: relative;
  height: calc(var(--thumb) + 2 * var(--tree-m));
}
.tree-add {
  position: absolute;
  left: var(--tree-m);
  top: var(--tree-m);
  width: calc(100% - 2 * var(--tree-m) + 1px);
  height: var(--thumb); /* right: the margin less the 1 px border */
  display: grid;
  place-items: center;
  padding: 0;
  border: 1.5px dashed var(--dash);
  border-radius: 10px;
  background: none;
  color: var(--label);
  cursor: pointer;
  transition:
    border-color var(--t-state),
    background-color var(--t-state),
    color var(--t-state);
}
.tree-add:is(:hover, .is-hover):not(:disabled),
.tree-add.active {
  border-style: solid;
  border-color: var(--accent);
  background: var(--accent);
  color: var(--white);
}
.tree-add:disabled {
  opacity: 0.35;
  cursor: default;
}
/* the next step in a project that is only its input: the selected node's two rings (solid inside, soft outside),
   breathing around the gray button. One beat: the inner ring rises first, the outer follows a little later and
   lingers, like a ripple leaving the button; both settle to nothing before the next beat */
.tree-add.nudge::before,
.tree-add.nudge::after {
  content: "";
  position: absolute;
  inset: -1.5px;
  border-radius: 11px;
  pointer-events: none;
}
.tree-add.nudge::before {
  animation: nudge-out 2.6s ease-in-out infinite;
}
.tree-add.nudge::after {
  animation: nudge-in 2.6s ease-in-out infinite;
}
.tree-add.nudge:is(:is(:hover, .is-hover), .active)::before,
.tree-add.nudge:is(:is(:hover, .is-hover), .active)::after {
  animation: none;
}
@keyframes nudge-in {
  0%,
  70%,
  100% {
    box-shadow: 0 0 0 0 var(--accent-00);
  }
  30% {
    box-shadow: 0 0 0 3px var(--accent-90);
  }
}
@keyframes nudge-out {
  0%,
  12%,
  100% {
    box-shadow: 0 0 0 0 var(--accent-00);
  }
  45% {
    box-shadow: 0 0 0 7px var(--accent-32);
  }
  82% {
    box-shadow: 0 0 0 9px var(--accent-00);
  }
}
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    transition-duration: 0s !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
  }
}
.add-menu.foot {
  top: auto;
  bottom: var(--tree-m);
}
.add-menu.foot .add-arrow {
  top: auto;
  bottom: 22px;
}
.link > span {
  position: absolute;
  transition:
    left var(--t-move) var(--ease),
    width var(--t-move) var(--ease),
    opacity var(--t-fade),
    border-color var(--t-move);
}
.link.fresh > span {
  transition: none;
}
.link-v {
  width: 0;
  border-left: 2px solid var(--link-line);
}
.link-h {
  height: 0;
  border-top: 2px solid var(--link-line);
}
.link.draft .link-v {
  border-left-style: dashed;
}
.link.draft .link-h {
  border-top-style: dashed;
}
.link.hidden > span {
  opacity: 0;
}
/* the active path (the selected node's lineage), while the tree is open: brighter links, white labels (it fades in
   as the tree opens; collapsed, the column shows only the path) */
.tree-panel.open .link.path .link-v {
  border-left-color: var(--link-path);
}
.tree-panel.open .link.path .link-h {
  border-top-color: var(--link-path);
}
.node-label {
  transition: color var(--t-move);
}
.tree-panel.open .node.path .node-label {
  color: var(--text);
}
.node {
  position: absolute;
  width: var(--thumb);
  height: var(--thumb);
  cursor: pointer;
  transition:
    left var(--t-move) var(--ease),
    opacity var(--t-fade);
}
/* the node's hover area reaches down over its label and its add button, so the pointer can travel from the thumbnail
   to the button without the button disappearing on the way */
/* the node's hover area is its whole cell in the grid (a column wide, a row high), so the pointer glides from one
   node to the next, sideways or up and down, without passing through a gap */
.node::before {
  content: "";
  position: absolute;
  left: calc(-1 * var(--cell-x));
  right: calc(-1 * var(--cell-x));
  top: 0;
  height: var(--row);
}
.node.fresh {
  transition: none;
}
.node.hidden {
  opacity: 0;
  pointer-events: none;
}
/* a version beside the line, closed: only the edge of its outline shows at the column's edge */
.node::after {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  width: var(--thumb);
  height: var(--thumb);
  box-sizing: border-box;
  border: 1.5px solid var(--peek-line);
  border-radius: 8px;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--t-fade);
}
.node.peek {
  pointer-events: none;
}
.node.peek::after {
  opacity: 1;
}
.node.peek > :not(.node-ring) {
  opacity: 0;
}
.node > .node-img,
.node > .node-label,
.node > .node-corner {
  transition:
    opacity var(--t-fade),
    box-shadow var(--t-state),
    color var(--t-move);
}
.node-img {
  display: block;
  width: var(--thumb);
  height: var(--thumb);
  object-fit: cover;
  border-radius: 8px;
  background: var(--black);
  box-shadow: 0 0 0 1px var(--white-14);
  transition: box-shadow var(--t-state);
}
.node.on .node-img {
  box-shadow:
    0 0 0 3px var(--accent),
    0 0 0 7px var(--accent-35);
}
.node:is(:hover, .is-hover):not(.on) .node-img {
  box-shadow: 0 0 0 2px var(--node-hover);
}
.node-draft {
  display: grid;
  place-items: center;
  box-shadow: none !important;
  outline: 2px dashed var(--draft-line);
  outline-offset: -2px;
  background: var(--white-03);
  color: var(--label);
}
.node.on .node-draft {
  outline-color: var(--accent);
  outline-width: 3px;
  color: var(--text);
  background: var(--accent-12);
}
.node.error .node-img {
  box-shadow: 0 0 0 2px var(--error);
}
/* running: a short dash that travels around the thumbnail's outline */
.node-ring {
  position: absolute;
  left: -4px;
  top: -4px;
  width: calc(var(--thumb) + 8px);
  height: calc(var(--thumb) + 8px);
  pointer-events: none;
  overflow: visible;
}
.node-ring path {
  fill: none;
  stroke: var(--white);
  stroke-width: 2.5;
  stroke-dasharray: 59 200; /* the rect's perimeter (69 px square, 10 px corners: 259) */
  stroke-linecap: round;
  animation: trace 1.3s linear infinite;
}
@keyframes trace {
  to {
    stroke-dashoffset: -259;
  }
}
/* a running draft's own outline goes solid and quiet, so the traveling dash is what moves; selected, it stays blue
   (the dash travels over its edge) */
.node.running .node-draft {
  outline-style: solid;
}
.node.running:not(.on) .node-draft {
  outline-color: var(--corner);
}
.node.running.on .node-ring path {
  stroke-width: 3;
}
/* measured (or estimated) progress: the outline fills clockwise from the top left, the value of the run queue's line */
.node-ring.measured path {
  animation: none;
  stroke-dashoffset: 0;
  transition: stroke-dasharray 0.25s linear;
}
.node-label {
  position: absolute;
  z-index: 1;
  left: 50%;
  top: calc(var(--thumb) + 5px);
  transform: translateX(-50%);
  max-width: 88px;
  padding: 0 4px;
  border-radius: 3px;
  background: var(--sidebar);
  color: var(--label);
  font-size: var(--fs-tiny);
  font-weight: var(--fw-text);
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.node.on .node-label {
  color: var(--text);
}
/* the corner: the step's type; hovering the node turns it into delete, hovering it turns it and the box red */
.node-corner {
  position: absolute;
  z-index: 2;
  left: 4px;
  top: 4px;
  display: grid;
  place-items: center;
  width: 20px;
  height: 20px;
  padding: 0;
  border: 0;
  border-radius: 5px;
  background: var(--black-74);
  color: var(--white);
  cursor: pointer;
  transition:
    background-color var(--t-state),
    opacity var(--t-fade);
}
.node-corner > span {
  display: block;
}
.node-corner .nc-del {
  display: none;
}
.node-corner.bare {
  opacity: 0;
}
.node:is(:hover, .is-hover) .node-corner {
  opacity: 1;
  background: var(--corner);
}
.node:is(:is(:hover, .is-hover), :has(.node-corner.asking)) .node-corner .nc-type {
  display: none;
}
.node:is(:is(:hover, .is-hover), :has(.node-corner.asking)) .node-corner .nc-del {
  display: block;
}
.node .node-corner:is(:is(:hover, .is-hover), .asking) {
  opacity: 1;
  background: var(--danger);
}
.node:has(.node-corner:is(:is(:hover, .is-hover), .asking)) .node-img {
  box-shadow: 0 0 0 2px var(--danger) !important;
}
.node:has(.node-corner:is(:is(:hover, .is-hover), .asking)) .node-draft {
  outline-color: var(--danger) !important;
  color: var(--danger-light);
}
.op-icon {
  display: grid;
  place-items: center;
  width: 16px;
  height: 16px;
  flex: none;
}
/* the add button: one look everywhere, in the space under a node's label (always under the selected node; under
   any other finished node while hovered) */
.node-add {
  position: absolute;
  z-index: 2;
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  padding: 0;
  border: 1.5px dashed var(--dash);
  border-radius: 7px;
  background: var(--sidebar);
  color: var(--label);
  font-size: var(--fs-big);
  font-weight: var(--fw-text);
  line-height: 1;
  cursor: pointer;
  transition:
    left var(--t-move) var(--ease),
    color var(--t-state),
    border-color var(--t-state),
    background-color var(--t-state);
}
.node-add:is(:hover, .is-hover):not(:disabled),
.node-add.active {
  border-style: solid;
  border-color: var(--accent);
  background: var(--accent);
  color: var(--white);
}
.node-add:disabled {
  opacity: 0.35;
  cursor: default;
}
.node .node-add.hover {
  left: calc((var(--thumb) - 24px) / 2);
  top: calc(var(--thumb) + var(--plus-y));
  display: none;
  transition: none;
}
.node .node-add.hover.active {
  display: grid;
}
/* dragging a node: the one it would be copied onto lights its add button up; the dragged one dims */
.node.drop-target .node-img {
  box-shadow: 0 0 0 2px var(--accent);
}
.node.drag-src {
  opacity: 0.45;
}
/* the copy a drop would make, where it will land (tree.js: withGhosts): the nodes it copies, faded */
.node.ghost {
  opacity: 0.45;
  pointer-events: none;
}
.link.ghost > span {
  opacity: 0.5;
}
.node:is(:hover, .is-hover) .node-add.hover {
  display: grid;
}
/* the add menu: a popover beside the + it came from, its arrow pointing at it */
.add-menu {
  position: absolute;
  z-index: 30;
  display: flex;
  flex-direction: column;
  gap: 2px;
  width: max-content;
  padding: 6px;
  background: var(--pop);
  border: 1px solid var(--pop-border);
  border-radius: 10px;
  box-shadow: var(--shadow-float);
  animation: pop var(--t-state) ease-out;
  transform-origin: 0 26px;
}
.add-arrow {
  position: absolute;
  left: -7px;
  top: 19px;
  width: 12px;
  height: 12px;
  background: var(--pop);
  border-left: 1px solid var(--pop-border);
  border-bottom: 1px solid var(--pop-border);
  transform: rotate(45deg);
}
.add-title {
  padding: 5px 8px 6px;
  color: var(--dim);
  font-size: var(--fs-text);
  font-weight: var(--fw-text);
}
.add-item {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  width: 100%;
  padding: 8px;
  border: 0;
  border-radius: var(--r);
  background: none;
  color: var(--text);
  text-align: left;
  cursor: pointer;
}
.add-item .op-icon {
  margin-top: 1px;
  color: var(--label);
}
.add-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  white-space: nowrap;
}
.add-item:is(:hover, .is-hover) {
  background: var(--accent);
}
.add-item:is(:hover, .is-hover) :is(.label, .op-icon) {
  color: var(--white);
}
