/* class — opo1's canvas, inside opo8.

   Kept as bare as opo1 was. One typeface at one size, the site's own: the same
   face and weight as everything else, lowercase like everything else. No rules,
   no numbering, no panels, no tinted backgrounds. A word is quiet until it is
   pointed at or chosen, which is how the rows at the top already behave.

   The only lines left are the ones that are the work: a node's edge and the
   wires between nodes. */

#class-workspace {
  position: absolute; inset: 170px 26px 26px;
  display: flex; gap: 32px; min-height: 0;
  font: var(--weight) 14px/1.5 var(--type);
  color: var(--ink);
  text-transform: lowercase;
}
#class-workspace [hidden] { display: none !important; }

#class-workspace button {
  display: block; margin: 0; padding: 0;
  background: none; border: 0;
  font: inherit; color: inherit; text-transform: inherit; text-align: left;
  cursor: pointer;
  opacity: .6;
  transition: opacity .25s ease-out;
}
#class-workspace button:hover,
#class-workspace button[aria-current="true"],
#class-workspace button[aria-pressed="true"] { opacity: 1; }
#class-workspace :focus-visible { outline: 1px solid var(--ink); outline-offset: 3px; }

/* ---------- the list ---------- */

.project-index {
  flex: 0 0 auto; max-width: 200px;
  overflow-y: auto; scrollbar-width: none;
}
.project-index::-webkit-scrollbar { display: none; }
#reel .row { margin: 0 0 4px; }
#class-edit { margin-top: 24px; }

/* ---------- the canvas ---------- */

.project-stage-wrap { position: relative; flex: 1; min-width: 0; }

#stage { position: absolute; inset: 0; overflow: hidden; touch-action: none; }
#stage.grabbing { cursor: grabbing; }

#empty { position: absolute; left: 0; top: 0; pointer-events: none; }

#world  { position: absolute; top: 0; left: 0; transform-origin: 0 0; }
#wires  { position: absolute; inset: 0; width: 100%; height: 100%;
          overflow: visible; pointer-events: none; }
#wires-world { transform-origin: 0 0; }

/* weight is the only distinction: thin control, thick signal, dashed reference */
.wire           { fill: none; stroke: var(--hair); stroke-width: 1; vector-effect: non-scaling-stroke; }
.wire.signal    { stroke-width: 3.5; }
.wire.reference { stroke-dasharray: 3 3; }
.wire.live      { stroke-dasharray: 2 3; }
/* away: faded right out while one node is open, and not clickable */
.wire          { transition: opacity .2s ease-out; }
.wire.away     { opacity: 0; }
/* the lines that show what a dragged node lines up with. editing only */
.guide          { stroke: var(--ink); stroke-width: 1; vector-effect: non-scaling-stroke; }

/* the arrows either side of an open node. the id rule is only there to win
   back the margin and display every button in here is otherwise given */
#class-workspace .node-prev, #class-workspace .node-next {
  display: block; margin-top: -24px; z-index: 3;
}
#class-workspace .node-prev { left: 0; }
#class-workspace .node-next { right: 0; transform: scaleX(-1); }

/* the status line exists only while editing, for what editing needs to say */
#status {
  position: absolute; left: 0; bottom: 0;
  display: none; gap: 16px;
  pointer-events: none; white-space: nowrap;
}
#class-workspace.editing #status { display: flex; }
#status-mid { display: none; }

/* ---------- nodes ---------- */

.node {
  position: absolute; top: 0; left: 0;
  cursor: pointer;
  border: 1px solid var(--hair);
  background: var(--paper);
  /* No will-change here. It kept every node as its own graphics layer at full
     size, before the canvas zoom: a node stretched to 5000px wide is a
     60MB layer however small it looks. With a few of those the browser ran out
     of graphics memory, and the next hover fade on the page (the project list,
     the words at the top) came back blank for everything drawn after it. */
}
.node { transition: opacity .2s ease-out, visibility 0s; }
.node.away { opacity: 0; visibility: hidden; pointer-events: none;
             transition: opacity .2s ease-out, visibility 0s linear .2s; }
/* selected while editing: a thin outline just outside its edge, the same
   thickness on screen however far the canvas is zoomed */
.node.sel {
  border-color: var(--ink);
  outline: calc(2px * var(--inv, 1)) solid var(--ink);
  outline-offset: calc(2px * var(--inv, 1));
}
/* an open node is in front of everything it has grown over. without this the
   neighbours after it in the page were drawn on top, dimmed, and read as the
   open picture being see-through */
.node.expanded { z-index: 2; }

/* 18px tall: HEAD_H in js/class/config.js depends on it */
.node .node-head {
  height: 18px; padding: 0 4px;
  line-height: 18px;
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
  cursor: pointer; user-select: none;
}
/* while editing, a node is picked up anywhere, so nothing inside it takes the
   press first: no text selection, and a closed video or embed is a picture */
#class-workspace.editing .node { user-select: none; -webkit-user-select: none; }
#class-workspace.editing .node:not(.expanded) .body :is(video, audio, iframe) { pointer-events: none; }
/* a node with its name turned off: no name on the page, and a quieter one
   while editing so there is still something to hold it by */
#class-workspace:not(.editing) .node.nameless .node-head { display: none; }
#class-workspace.editing .node.nameless .node-head .name { opacity: .4; }

.node .body { position: relative; min-height: 24px; }
/* A picture shows the magnifier whenever it is looked at, not only once open: a
   click on a closed one enlarges it, a click on an open one looks closer
   (js/zoom.js, style.css). Tied to being open, the cursor had to change under a
   still pointer at the moment of opening, which the browser does not redraw
   until the pointer moves or clicks again. Editing keeps the hand. */
#class-workspace:not(.editing) .node .body > img { cursor: zoom-in; }
/* a link opens a page, so it keeps the hand */
#class-workspace:not(.editing) .node.link .body > img { cursor: pointer; }
/* a link with no card: the page's title over its address */
.node .link-text { padding: 10px 8px; white-space: pre-line; overflow-wrap: anywhere; }
.node .link-text::first-line { opacity: 1; }
#class-workspace:not(.editing) .node.expanded .body.zoomed > img { cursor: zoom-out; }
.node .body img, .node .body video, .node .body canvas { width: 100%; display: block; }
.node .body iframe { display: block; width: 100%; aspect-ratio: 16 / 9; border: 0; }
/* stretched from the corner: the height is set by graph.js and the picture
   fills it, pulled out of its proportions rather than cropped */
.node.free .body :is(img, video) { object-fit: fill; }
.node.free .body .stub { aspect-ratio: auto; }
/* closed, a video is a picture of itself: a click opens the node. open, it plays */
.node:not(.expanded) .body iframe { pointer-events: none; }

/* a node with no file yet: an empty frame, with what it is waiting for */
.node .stub { aspect-ratio: 4 / 3; display: grid; place-items: center; opacity: .6; }
.node .note { padding: 4px; white-space: pre-wrap; word-break: break-word; }
.node .cap  { padding: 4px; }

.node .transport { display: flex; gap: 12px; align-items: center; padding: 2px 4px; }
#class-workspace .node .transport button { display: inline; }

/* ports and the corner are for editing, and only exist then */
.port {
  position: absolute; width: 9px; height: 4px;
  background: var(--ink); cursor: crosshair;
}
.port.in  { left: -1px; }
.port.out { right: -1px; }
/* The sides and corners a node is stretched by. Drawn nowhere: they are only
   where the pointer turns into a resize arrow, straddling the node's edge. The
   same thickness on screen however far the canvas is zoomed, since --inv is one
   over the zoom. A port sits above them so a wire can still be pulled. */
.edge { position: absolute; z-index: 1; --band: calc(10px * var(--inv, 1)); }
.edge.n, .edge.s { left: 0; right: 0; height: var(--band); cursor: ns-resize; }
.edge.e, .edge.w { top: 0; bottom: 0; width: var(--band); cursor: ew-resize; }
.edge.n { top:    calc(var(--band) / -2); }
.edge.s { bottom: calc(var(--band) / -2); }
.edge.e { right:  calc(var(--band) / -2); }
.edge.w { left:   calc(var(--band) / -2); }
.edge.ne, .edge.nw, .edge.se, .edge.sw {
  width: calc(var(--band) * 1.6); height: calc(var(--band) * 1.6); z-index: 2;
}
.edge.ne { top: calc(var(--band) * -0.8);    right: calc(var(--band) * -0.8); cursor: nesw-resize; }
.edge.sw { bottom: calc(var(--band) * -0.8); left: calc(var(--band) * -0.8);  cursor: nesw-resize; }
.edge.nw { top: calc(var(--band) * -0.8);    left: calc(var(--band) * -0.8);  cursor: nwse-resize; }
.edge.se { bottom: calc(var(--band) * -0.8); right: calc(var(--band) * -0.8); cursor: nwse-resize; }
.port { z-index: 3; }
#class-workspace:not(.editing) .port,
#class-workspace:not(.editing) .edge { display: none; }

/* ---------- the text beside the work ---------- */
/* its own column, off the canvas, so it is read at its real size. written
   straight onto the ground, the way the bio is, and scrolled on its own */

.reading {
  flex: 0 0 clamp(220px, 24vw, 340px);
  min-height: 0;
  overflow-y: auto; scrollbar-width: none;
  overscroll-behavior: contain;
}
.reading::-webkit-scrollbar { display: none; }
.reading:empty { display: none; }
.panel h2, .panel p { margin: 0; font: inherit; }
/* an empty line between the blocks: the title, the lines under it, and each
   paragraph of the statement. `> * + p` has to be named: `.panel p` above
   outranks `> * + *`, and was taking the space back from the statement */
.panel > * + *, .panel > * + p { margin-top: 1.5em; }
.panel .value { opacity: .6; }

/* ---------- editing ---------- */

#inspector {
  flex: 0 0 240px;
  overflow-y: auto; scrollbar-width: none;
}
#inspector::-webkit-scrollbar { display: none; }
#inspector h3 { margin: 24px 0 8px; font: inherit; }
#inspector label { display: block; margin: 0 0 8px; }
#inspector label.check { display: flex; align-items: center; gap: 8px; }
#inspector .reset { margin: 0 0 6px; }
#inspector .size-tools { display: flex; gap: 16px; margin: 0 0 12px; }
#class-workspace #inspector .size-tools button { display: inline; }
#class-workspace #inspector button:disabled { opacity: .25; cursor: default; }
/* the list of nodes: a file name each, unfolding into its settings */
#inspector .node-name { width: 100%; padding: 3px 0; overflow-wrap: anywhere; }
#class-workspace #inspector .node-name[aria-expanded="true"] { opacity: 1; }
/* the selected node's name, boxed */
#class-workspace #inspector .node-name.selected {
  opacity: 1; padding: 3px 6px; border: 1px solid var(--ink); border-radius: 0;
}
#inspector .node-fields { padding: 6px 0 14px 12px; }
/* a node whose file is no longer in its folder */
#class-workspace #inspector .node-name.missing { opacity: 1; font-style: italic; }
#inspector .node-fields .delete { margin-top: 4px; }
#inspector input[type="checkbox"] {
  flex: none; width: auto; margin: 0; padding: 0;
  accent-color: rgb(var(--ink-rgb));
}
#inspector input, #inspector textarea, #inspector select {
  display: block; width: 100%; margin-top: 2px; padding: 2px 4px;
  font: inherit; text-transform: none;
  color: var(--ink); background: none;
  border: 1px solid var(--hair); border-radius: 0;
}
#inspector select option { background: var(--paper); }
#inspector textarea { min-height: 60px; resize: vertical; }
#inspector .bar { display: flex; flex-wrap: wrap; gap: 4px 16px; }
#inspector .bar + h3 { margin-top: 20px; }
#class-workspace #inspector .bar button { display: inline; }

/* ---------- narrow ---------- */

/* while editing on a smaller screen the fields take the text column's place;
   they are the same words, and the canvas needs the room */
@media (max-width: 1300px) {
  #class-workspace.editing .reading { display: none; }
}

@media (max-width: 700px) {
  #class-workspace { inset: 160px 16px 16px; flex-direction: column; gap: 20px; }
  .project-index {
    max-width: none; flex: 0 0 auto; max-height: 30vh;
    display: flex; flex-wrap: wrap; gap: 4px 16px;
  }
  #reel { display: contents; }
  #reel .row, #class-edit { margin: 0; }
  #class-edit { order: 1; }
  .reading { flex: 0 1 auto; max-height: 26vh; }
  .project-stage-wrap { flex: 1; min-height: 0; }
  #inspector {
    position: absolute; right: 0; top: 0; bottom: 0; z-index: 5;
    width: min(260px, 80vw); padding: 0 0 0 12px;
    background: var(--paper);
  }
}

@media (prefers-reduced-motion: reduce) {
  #class-workspace button { transition: none; }
}
