/* =========================================================
   SEMANTIC BRAIN — INTERACTION FOUNDATION ENGINE (visual layer)
   ---------------------------------------------------------
   This file is the SINGLE source of truth for how any interactive
   canvas object (Concept, Question, Note, Argument, Reference,
   Synthesis, and any future object type) looks and animates across
   its six states: idle, hover, selected, editing, connecting,
   disabled. Pairs with `interaction-engine.js`, which builds/wires the
   DOM these rules style and drives `data-sb-state` on `.sb-interactive`
   roots.

   Do NOT add a second, competing definition of `.sb-interactive-*` /
   `.sb-confirm-*` / `.sb-floating-input` anywhere else in the project.
   Every current object renderer in knowledge-views.js consumes these
   classes through the engine; any future object type must do the same
   instead of inventing its own hover/toolbar/ring/delete-confirm CSS.
   ========================================================= */

/* ---------------------------------------------------------
   1. OBJECT WRAPPER + STATES
   `.sb-interactive` is added to an object's own already-positioned
   root element (e.g. `.kv-node`, `.kv-question-card`) — it never
   introduces an extra positioning wrapper, so every existing
   drag/geometry calculation keyed to that root element keeps working
   unchanged. `data-sb-state` is the explicit JS-driven state; native
   `:hover` is kept as a parallel, zero-latency signal for the ring and
   toolbar specifically, so a hover never "waits" on a JS event to
   appear — the two mechanisms agree by construction (see engine JS).
   --------------------------------------------------------- */
.sb-interactive {
  position:relative;
  --node-color:var(--sb-primary);
}

.sb-interactive[data-sb-state="disabled"] {
  pointer-events:none;
  opacity:var(--sb-opacity-disabled);
  filter:saturate(.7);
}

.sb-interactive[data-sb-state="selected"] {
  box-shadow:0 0 0 8px color-mix(in srgb,var(--node-color) 22%,transparent),0 0 30px color-mix(in srgb,var(--node-color) 65%,transparent);
}

.sb-interactive[data-sb-state="connecting"] {
  cursor:crosshair;
}

/* ---------------------------------------------------------
   2. INTERACTION REGION — object + ring + toolbar as ONE hover zone
   `.sb-interactive-head` (toolbar, optionally stacked above an
   external label) and `.sb-interactive-ring` are both direct
   descendants of `.sb-interactive`, positioned with zero gap between
   their boxes and the object's own box — a native `:hover` on the
   root is therefore continuously true for the entire time the pointer
   travels object → ring → toolbar, because at every point along that
   path the cursor sits over *some* descendant box. This is the fix
   for the previous flicker: that bug existed because the toolbar was
   floated at a fixed pixel offset with a real gap to the object's own
   box, so the cursor crossed dead space belonging to neither element.
   --------------------------------------------------------- */
/* The ring's hit-region is its own real box minus a hole the exact size of
   the object's own box underneath it — a true annulus, not a filled
   rectangle. `inset:-56px` means the ring's box already fully covers the
   object too, not just the space around it; without the `clip-path`
   below, whichever state below turns `pointer-events` to `auto` on this
   element (hover/connecting/locked) would then silently swallow every
   click meant for the object itself (title dblclick-to-rename, the
   question's answer textarea, drag-start, ...) — which is whenever the
   object is hovered, i.e. almost always. The polygon traces the outer box
   clockwise, a seam into the hole, the inner box counter-clockwise (so
   the two boundaries cancel out under the default nonzero fill rule), and
   back — the standard "picture frame" clip-path technique. The hole is
   inset by exactly `--sb-ring-margin` on every edge (the same value the
   ring itself is expanded by), so it always lines up with the object's
   own box regardless of that object's actual size or shape.
   IMPORTANT: this has to live on the ring element itself, not on a
   `::before`/`::after` pseudo-element — `clip-path` on a pseudo-element
   only affects its own paint in every engine tested here, not the host
   element's hit-testing, so a pseudo-only hole looks right but silently
   keeps swallowing clicks. Putting it on the real element is what
   actually excludes the hole from hit-testing. */
.sb-interactive-ring {
  --sb-ring-margin:56px;
  position:absolute;
  inset:calc(-1 * var(--sb-ring-margin));
  z-index:1;
  border-radius:50%;
  opacity:0;
  pointer-events:none;
  cursor:crosshair;
  clip-path:polygon(
    0% 0%, 100% 0%, 100% 100%, 0% 100%, 0% 0%,
    var(--sb-ring-margin) var(--sb-ring-margin),
    var(--sb-ring-margin) calc(100% - var(--sb-ring-margin)),
    calc(100% - var(--sb-ring-margin)) calc(100% - var(--sb-ring-margin)),
    calc(100% - var(--sb-ring-margin)) var(--sb-ring-margin),
    var(--sb-ring-margin) var(--sb-ring-margin)
  );
  transition:opacity var(--sb-duration-base) var(--sb-ease-standard);
}
.sb-interactive--card > .sb-interactive-ring {
  border-radius:calc(var(--sb-radius-lg) + 46px);
}
.sb-interactive--no-connect .sb-interactive-ring { cursor:default; }

/* The painted ring is a thin inset stroke + soft outer glow — deliberately
   restrained (DS5 "never excess glow"), never a solid disc. Purely
   decorative (`pointer-events:none`) — the parent's own clip-path above
   is what owns the real hit-region now. */
.sb-interactive-ring::before {
  content:"";
  position:absolute;
  inset:20px;
  border-radius:inherit;
  border:1px solid color-mix(in srgb, var(--node-color) 50%, transparent);
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--node-color) 14%, transparent) inset,
    0 0 24px color-mix(in srgb, var(--node-color) 30%, transparent);
  pointer-events:none;
}

.sb-interactive:hover > .sb-interactive-ring,
.sb-interactive[data-sb-state="hover"] > .sb-interactive-ring,
.sb-interactive[data-sb-state="connecting"] > .sb-interactive-ring,
.sb-interactive-ring.locked {
  opacity:1;
  pointer-events:auto;
}
/* Editing/disabled always win over a stray native :hover — e.g. the
   instant an object enters "editing", the ring must fade out even if
   the pointer never technically left the region. "Idle" deliberately
   has NO such override: idle is simply "nothing special is happening
   yet", and a genuine native :hover must still be free to reveal the
   ring the normal way while state is idle (it flips to "hover" on the
   very next pointerenter — see interaction-engine.js). */
.sb-interactive[data-sb-state="editing"] > .sb-interactive-ring,
.sb-interactive[data-sb-state="disabled"] > .sb-interactive-ring {
  opacity:0 !important;
  pointer-events:none !important;
}

/* ---------------------------------------------------------
   2b. INLINE EDITING (title/content rename)
   Single shared visual treatment for "this text is currently
   contentEditable", toggled by `SBInteractionEngine.editInline()` on
   whichever element it's editing (a Concept's external label, a
   Question's title, an Observation's text, ...) — previously three
   near-identical selectors duplicated in knowledge-views.css
   (`.kv-node-label.editing`, `.kv-question-title.editing`,
   `.kv-observation-text.editing`), now the one place this rule lives.
   --------------------------------------------------------- */
.sb-inline-editing {
  padding:6px 8px;
  border-radius:var(--sb-radius-sm);
  background:var(--sb-surface-1);
  box-shadow:0 0 0 1px var(--sb-primary);
}

/* ---------------------------------------------------------
   3. TOOLBAR
   Always floats fully above the object's own box (`bottom:100%`),
   never overlapping it or an external label — see `.sb-interactive-head`
   below for how a label that lives OUTSIDE the object (e.g. a Concept's
   title) is guaranteed to sit between the object and the toolbar,
   never under it.
   --------------------------------------------------------- */
.sb-interactive-head {
  position:absolute;
  z-index:14;
  left:50%;
  bottom:100%;
  transform:translateX(-50%);
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:8px;
  padding-bottom:12px; /* closes the gap to the object's own top edge */
}

.sb-interactive-toolbar {
  display:flex;
  align-items:center;
  gap:4px;
  padding:5px;
  border:1px solid var(--sb-border-strong);
  border-radius:var(--sb-radius-md);
  background:var(--sb-surface-1);
  box-shadow:var(--sb-shadow-2);
  backdrop-filter:blur(16px);
  opacity:0;
  pointer-events:none;
  transform:translateY(4px);
  transition:
    opacity var(--sb-duration-base) var(--sb-ease-standard) .1s,
    transform var(--sb-duration-base) var(--sb-ease-standard) .1s;
}
.sb-interactive:hover .sb-interactive-toolbar,
.sb-interactive[data-sb-state="hover"] .sb-interactive-toolbar,
.sb-interactive-head:focus-within .sb-interactive-toolbar {
  opacity:1;
  pointer-events:auto;
  transform:translateY(0);
  transition-delay:0s;
}
.sb-interactive[data-sb-state="editing"] .sb-interactive-toolbar,
.sb-interactive[data-sb-state="disabled"] .sb-interactive-toolbar {
  opacity:0 !important;
  pointer-events:none !important;
}

.sb-interactive-toolbar button {
  width:27px;
  height:27px;
  display:grid;
  place-items:center;
  padding:0;
  border:0;
  border-radius:var(--sb-radius-sm);
  background:transparent;
  transition:background var(--sb-duration-fast) var(--sb-ease-standard),transform var(--sb-duration-fast) var(--sb-ease-standard);
}
.sb-interactive-toolbar button:hover { background:rgba(255,255,255,.09); transform:translateY(-1px); }
.sb-interactive-toolbar button:active { transform:translateY(0); }
.sb-interactive-toolbar svg {
  width:16px;
  height:16px;
  fill:none;
  stroke:currentColor;
  stroke-width:1.8;
  stroke-linecap:round;
  stroke-linejoin:round;
}
.sb-interactive-toolbar [data-sb-color] { color:var(--sb-primary-strong); }
.sb-interactive-toolbar [data-sb-image] { color:var(--sb-secondary); }
.sb-interactive-toolbar [data-sb-delete] { color:var(--sb-error); }
.sb-interactive-toolbar [data-sb-color-input] {
  position:absolute;
  width:1px;
  height:1px;
  opacity:0;
  pointer-events:none;
}

/* ---------------------------------------------------------
   4. FLOATING CREATE / EDIT INPUT
   Double-click-to-create must never show a rectangle before the user
   has typed anything — only a bare caret. Chrome (border/background/
   shadow) fades in the moment the field gains real content, via the
   `.has-content` class the engine toggles on input.
   --------------------------------------------------------- */
.sb-floating-input {
  position:absolute;
  z-index:35;
  min-width:64px;
  max-width:220px;
  transform:translate(-50%,-50%);
  padding:9px 11px;
  border:1px solid transparent;
  border-radius:var(--sb-radius-lg);
  background:transparent;
  box-shadow:none;
  transition:
    background var(--sb-duration-base) var(--sb-ease-standard),
    border-color var(--sb-duration-base) var(--sb-ease-standard),
    box-shadow var(--sb-duration-base) var(--sb-ease-standard);
}
.sb-floating-input.has-content {
  border-color:var(--sb-border-strong);
  background:var(--sb-surface-1);
  box-shadow:var(--sb-shadow-2);
  backdrop-filter:blur(14px);
}
.sb-floating-input.question { border-left:3px solid color-mix(in srgb, var(--sb-primary) 55%, transparent); }
.sb-floating-input.observation { border-left:3px solid var(--sb-warning); }
.sb-floating-input-field {
  display:block;
  width:100%;
  min-height:24px;
  resize:none;
  overflow:hidden;
  border:0;
  outline:none;
  background:transparent;
  color:var(--sb-text);
  text-align:center;
  font:inherit;
  font-weight:700;
  line-height:1.3;
}
.sb-floating-input-field::placeholder { color:var(--sb-text-muted); }
/* The one deliberate "flashy" cue this engine allows: a soft blinking
   caret-colored underline while the field is still empty, so an empty
   floating input still reads as "waiting for you to type" rather than
   as nothing at all. */
.sb-floating-input:not(.has-content) .sb-floating-input-field {
  box-shadow:0 1px 0 0 color-mix(in srgb, var(--sb-primary) 55%, transparent);
  animation:sbCaretPulse 1.6s var(--sb-ease-standard) infinite;
}
@keyframes sbCaretPulse {
  0%,100% { box-shadow:0 1px 0 0 color-mix(in srgb, var(--sb-primary) 55%, transparent); }
  50% { box-shadow:0 1px 0 0 color-mix(in srgb, var(--sb-primary) 15%, transparent); }
}
/* style.css defines a global, !important `textarea:focus-visible` /
   `input:focus-visible` ring (a real accessibility feature, kept as-is
   everywhere else in the app). The engine auto-focuses this field the
   instant it's created so typing can start immediately with no extra
   click — but Chromium's :focus-visible heuristic treats that
   programmatic focus as keyboard-style, so without this override the
   global ring+halo would paint a full rectangle around the field before
   a single character is typed, defeating requirement 5 ("no rectangle
   before typing starts"). This field isn't reachable by Tab (it only
   ever exists for the few seconds of an active create/edit gesture), so
   there's no real keyboard-navigation cost to replacing the generic ring
   with this component's own affordance: the caret-pulse above while
   empty, and the `.has-content` chrome (border/background/shadow, this
   file, §4 above) the moment real text exists. */
.sb-floating-input-field:focus-visible {
  outline:none !important;
  box-shadow:none !important;
}
.sb-floating-input:not(.has-content) .sb-floating-input-field:focus-visible {
  box-shadow:0 1px 0 0 color-mix(in srgb, var(--sb-primary) 55%, transparent) !important;
  animation:sbCaretPulse 1.6s var(--sb-ease-standard) infinite;
}

/* ---------------------------------------------------------
   5. DELETE CONFIRMATION — never window.confirm()
   One shared dialog for both the "leaf" and "root of a hierarchy"
   copy variants (toggled via the engine's confirmDelete() options),
   consistent with the rest of the app's --sb-* token system rather
   than the untokenized one-off values still used by the legacy
   `.dialog`/`.context-menu` components elsewhere in the project.
   --------------------------------------------------------- */
.sb-confirm-overlay {
  position:fixed;
  inset:0;
  z-index:2000;
  display:flex;
  align-items:center;
  justify-content:center;
  background:rgba(4,6,14,.55);
  backdrop-filter:blur(3px);
  opacity:0;
  transition:opacity var(--sb-duration-base) var(--sb-ease-standard);
}
.sb-confirm-overlay.visible { opacity:1; }
.sb-confirm-dialog {
  width:min(380px, calc(100vw - 48px));
  padding:22px;
  border:1px solid var(--sb-border-strong);
  border-radius:var(--sb-radius-lg);
  background:var(--sb-surface-1);
  box-shadow:var(--sb-shadow-3);
  transform:translateY(10px) scale(.98);
  transition:transform var(--sb-duration-base) var(--sb-ease-emphasis);
}
.sb-confirm-overlay.visible .sb-confirm-dialog { transform:translateY(0) scale(1); }
.sb-confirm-dialog h3 {
  margin:0 0 9px;
  color:var(--sb-text);
  font-size:var(--sb-text-lg);
  font-weight:var(--sb-weight-bold);
}
.sb-confirm-dialog p {
  margin:0 0 20px;
  color:var(--sb-text-secondary);
  font-size:var(--sb-text-sm);
  line-height:1.55;
}
.sb-confirm-actions {
  display:flex;
  justify-content:flex-end;
  gap:9px;
}
.sb-confirm-btn {
  padding:9px 16px;
  border:1px solid var(--sb-border-strong);
  border-radius:var(--sb-radius-sm);
  background:var(--sb-surface-2);
  color:var(--sb-text);
  font-weight:var(--sb-weight-semibold);
  transition:background var(--sb-duration-fast) var(--sb-ease-standard),transform var(--sb-duration-fast) var(--sb-ease-standard);
}
.sb-confirm-btn:hover { transform:translateY(-1px); }
.sb-confirm-btn.secondary:hover { background:color-mix(in srgb, var(--sb-surface-2) 100%, white 8%); }
.sb-confirm-btn.danger {
  border-color:color-mix(in srgb, var(--sb-error) 55%, transparent);
  background:color-mix(in srgb, var(--sb-error) 22%, var(--sb-surface-2));
}
.sb-confirm-btn.danger:hover { background:color-mix(in srgb, var(--sb-error) 34%, var(--sb-surface-2)); }
.sb-confirm-btn:focus-visible { outline:2px solid var(--sb-primary-strong); outline-offset:2px; }

@media (prefers-reduced-motion: reduce) {
  .sb-interactive-ring,
  .sb-interactive-toolbar,
  .sb-floating-input,
  .sb-floating-input-field,
  .sb-confirm-overlay,
  .sb-confirm-dialog,
  .sb-confirm-btn {
    animation:none !important;
    transition:none !important;
  }
}
