/* instrument.css — THE INSTRUMENT register kit (canvas + first-party shells). #p4fable I1.
   The chrome language (warm-black + JetBrains Mono + hairlines + chartreuse) PROMOTED to a
   feedback language: ZERO new token values, a thin alias seam so the accent can parameterize
   (§1c: any shell that re-points --accent gets its face) and a future organ re-base is a
   re-point, not a rewrite. --ai violet is BANNED as an instrument cue (violet stays AI-only).
   Motion law: brightness / border / background / transform only; EXACTLY three keyframes, none
   looping, ALL under prefers-reduced-motion:no-preference (the canvas's first motion, pre-guarded). */
:root {
  --inst-accent: var(--accent);          /* register accent = chrome accent; organs re-point --accent */
  --inst-ink-mid: var(--ink-mid);
  --inst-cool1: 0.82;                     /* Signal opacity steps (compositor-only) */
  --inst-cool2: 0.70;
  --inst-standby: 0.60;                   /* floor — quiet is never illegible */
  --inst-dim: 0.32;                       /* lens-dim (I2), HOROS parity */
  --inst-bracket: 12px;                   /* corner-arm length */
}

/* --- Signal: recency as brightness. One rule for every kind, pages included. Priority in the JS
   map guarantees held/selected/lens/ghost outrank cooling, so these only paint a quiet cell. --- */
.cell-node.inst-cool1   { opacity: var(--inst-cool1); }
.cell-node.inst-cool2   { opacity: var(--inst-cool2); }
.cell-node.inst-standby { opacity: var(--inst-standby); }

/* --- The Lens (I2): dim-all-but. Opacity ONLY on the canvas (never a filter on iframe-bearing
   tiles). Static states; the fade between them is guarded below. --- */
.cell-node.inst-lens-self { opacity: 1; }
.cell-node.inst-lens-dim  { opacity: var(--inst-dim); }

/* --- Response: held brackets. ONE pseudo-element, eight tiny corner gradients (four corners,
   two 1.5px arms each), zero extra DOM. Selection (K1) consumes the SAME geometry, dimmer. --- */
.cell-node.inst-held    { opacity: 1; }
.cell-node.inst-held::after,
.cell-node.inst-selected::after {
  content: ""; position: absolute; inset: -4px; pointer-events: none; z-index: 12;
  background-image:
    linear-gradient(var(--inst-accent), var(--inst-accent)), linear-gradient(var(--inst-accent), var(--inst-accent)),
    linear-gradient(var(--inst-accent), var(--inst-accent)), linear-gradient(var(--inst-accent), var(--inst-accent)),
    linear-gradient(var(--inst-accent), var(--inst-accent)), linear-gradient(var(--inst-accent), var(--inst-accent)),
    linear-gradient(var(--inst-accent), var(--inst-accent)), linear-gradient(var(--inst-accent), var(--inst-accent));
  background-repeat: no-repeat;
  background-size:
    var(--inst-bracket) 1.5px, 1.5px var(--inst-bracket),   /* top-left: h-arm, v-arm */
    var(--inst-bracket) 1.5px, 1.5px var(--inst-bracket),   /* top-right */
    var(--inst-bracket) 1.5px, 1.5px var(--inst-bracket),   /* bottom-left */
    var(--inst-bracket) 1.5px, 1.5px var(--inst-bracket);   /* bottom-right */
  background-position:
    left top, left top,
    right top, right top,
    left bottom, left bottom,
    right bottom, right bottom;
}
.cell-node.inst-selected::after { z-index: 11; opacity: 0.7; }

/* --- Loose end (I5/K2, §3.6): a content citizen with zero connections. A small open-bracket
   terminus on the connect (right) edge — the most honest to-do mark on the surface; nobody wrote
   it, the thread is simply hanging. Quiet INK, never accent (it is a fact, not a call to action —
   the accent belongs to the port that hover reveals to tie it off). Additive: the JS map returns it
   alongside cooling, and it is suppressed under held/selected/lens (those own ::after). --- */
.cell-node.inst-loose::before {
  content: ""; position: absolute; right: -9px; top: 50%; width: 5px; height: 13px;
  transform: translateY(-50%); pointer-events: none; z-index: 6; opacity: 0.65;
  border: 1.5px solid var(--ink-faint); border-left: 0;   /* ⌐ opening rightward = an untied thread */
  border-radius: 0 2px 2px 0;
}
.cell-node.inst-loose:hover::before { opacity: 0; }        /* hover reveals the port here — the mark yields to the affordance */

/* --- Flag (I7 · FLAGS, §3.8): a DESTINATION pinned on the board — a north-star. A small accent pennant
   planted at the tile's top-left, drawn by ONE pseudo-element (a single clip-path polygon = a staff + a
   right-pointing flag), zero extra DOM. Additive + altitude-independent: the JS map appends inst-flag to
   whatever brightness wins, so a flag reads whether the cell is held, selected, dimmed, a ghost, or quiet.
   It SUPPRESSES the loose terminus (both are ::before; a flagged cell is intentional, never a hanging
   thread). Solid accent on the re-pointable --inst-accent (§1c), NO glow — register-legal (the same
   solid-accent vocabulary as the port dot, the provenance dots, the publish sweep). The ROUTE it lights
   lives on the threads (canvas.css .conn-route), not here. Above the held/selected brackets (z 12). --- */
.cell-node.inst-flag::before {
  content: ""; position: absolute; left: 8px; top: -15px; width: 15px; height: 17px;
  background: var(--inst-accent, var(--accent)); pointer-events: none; z-index: 13;
  clip-path: polygon(0 0, 13px 3.5px, 2.5px 7px, 2.5px 17px, 0 17px);   /* staff (left, full height) + a right-pointing pennant at the top */
}

/* --- Ghost (K3, §8.3.1): a DRAFT cell — authored, not yet public. The EXCLUSIVE brightness state
   between lens and cooling (a draft reads ghost regardless of age; the JS map returns it in place of
   the signal bucket). A dashed hairline on the NODE ITSELF (outline, not a pseudo-element) so it
   composes over held/selected's ::after brackets AND loose's ::before terminus with no collision,
   plus a gentle dim. Quiet INK, never accent — a draft is a state, not a call to action; the PUBLISH
   verb is the call. Register-legal: outline + opacity only, no glow/blur (:focus-visible still wins
   its own outline for the keyboard grid). Shared skin: K6 ✦-generated subtrees land wearing it too. --- */
.cell-node.inst-ghost {
  opacity: 0.72;
  outline: 1.5px dashed var(--inst-ink-mid);
  outline-offset: 3px;
}

/* --- The readout: one voice, self-provisioned at the mount's bottom edge (.canvas-mount is
   position:relative;overflow:hidden). Mono, uppercase, one line, aria-live. --- */
#inst-readout {
  position: absolute; left: 0; bottom: 0; z-index: 40;
  display: flex; align-items: center; gap: 12px;
  max-width: 100%; padding: 6px 12px;
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--inst-ink-mid); white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  pointer-events: none; opacity: 0; transition: opacity 220ms ease;
}
#inst-readout.inst-readout-show { opacity: 1; }
#inst-readout .inst-readout-act {
  pointer-events: auto; cursor: pointer;
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--inst-accent); background: none; border: 0; border-bottom: 1px solid var(--inst-accent);
  padding: 0 0 1px;
}
#inst-readout .inst-readout-act:focus-visible { outline: 1px solid var(--inst-accent); outline-offset: 2px; }

/* --- Base (static) styles for the motion elements; the animations themselves are guarded below. --- */
/* The Hand's launcher (I4) is a tick target too: it flashes when a card enters (jot) or leaves (play) your
   hand. It REUSES the inst-tick keyframe below (no fourth keyframe — the motion law holds at exactly three). */
.cell-node.inst-tick, .shelf-launch.inst-tick { outline: 1.5px solid transparent; outline-offset: 1px; }
.inst-sweep-bar {
  position: absolute; top: 0; bottom: 0; left: 0; width: 1px; z-index: 41; pointer-events: none;
  background: var(--inst-accent); box-shadow: 0 0 8px var(--accent-glow);
}

/* --- Motion law: EXACTLY three keyframes, none loop, ALL guarded by construction. --- */
@media (prefers-reduced-motion: no-preference) {
  @keyframes inst-tick   { from { outline-color: var(--inst-accent); } to { outline-color: transparent; } }
  @keyframes inst-breath { 0% { box-shadow: 0 0 0 2px var(--inst-accent), 0 8px 28px rgba(0,0,0,0.35); } 100% { box-shadow: 0 0 0 0 rgba(0,0,0,0), 0 8px 28px rgba(0,0,0,0.35); } }
  @keyframes inst-sweep  { from { transform: translateX(-2px); opacity: 0; } 12% { opacity: 0.85; } to { transform: translateX(100vw); opacity: 0; } }
  .cell-node.inst-tick, .shelf-launch.inst-tick { animation: inst-tick 120ms steps(2, end); }
  .cell-node.inst-breath { animation: inst-breath 2s cubic-bezier(0.2, 0.7, 0.2, 1); }
  .inst-sweep-bar        { animation: inst-sweep 600ms cubic-bezier(0.2, 0.7, 0.2, 1); }
  .inst-lens .cell-node  { transition: opacity 180ms ease; }       /* the Lens fade (I2), guarded */
}
