/* ============================================================
   enrich.css — the SHARED visual language for Halcyon's enrich phase.
   =================================================================
   This file is the single home for the reusable pieces every enriched
   surface composes from, so later enrich work never has to touch
   halcyon.css:

     (a) .halcyon-tip      — a contextual tooltip (role=tooltip, hidden by
                            default, edge-flips, .ti-dlt-* styled)
     (b) .empty-coach     — an empty-state that coaches the first action
                            (centered icon + copy + CTA)
     (c) motion utilities — keyframes + classes the flowcharts reuse:
                            stroke-draw (dasharray), staggered fades, the
                            node travel states (.is-traveled / .is-here /
                            .is-landed), and the play-the-path token.

   Every color is a Datum token, so light / dark flip with theme.js.

   MOTION CONTRACT: all motion is OFF by default and only turns on inside
   the @media (prefers-reduced-motion: no-preference) block near the
   bottom. With reduced motion (or by default before that block applies),
   each element shows its FINAL state instantly — fully drawn paths,
   visible nodes, readable copy. Nothing depends on animation to be usable.
   ============================================================ */

/* ============================================================
   (a) .halcyon-tip — contextual tooltip
   ------------------------------------------------------------
   A sibling node the enrich JS positions next to a control. Hidden by
   default (aria-hidden + display:none); shown by adding .is-open. The JS
   sets data-side to flip the arrow to whichever side actually fit. Styled
   on the same Datum surface family as the existing .ti-tip engine, with
   the .ti-dlt-* token names the enrich layer uses.
   ============================================================ */
.halcyon-tip {
  position: fixed;                  /* positioned by JS relative to the target */
  z-index: 2147483400;              /* above content, below the tour scrim */
  top: 0;
  left: 0;
  display: none;                    /* hidden by default — JS reveals it */
  max-width: min(280px, calc(100vw - 16px));
  box-sizing: border-box;
  padding: 8px 11px;
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--border-accent);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow);
  font-family: var(--sans);
  font-size: 12.5px;
  line-height: 1.45;
  pointer-events: none;             /* never steals hover from the target */
  opacity: 0;                       /* fade handled in the motion block */
}
/* shown state: JS sets display:block via .is-open, opacity rides up */
.halcyon-tip.is-open {
  display: block;
  opacity: 1;
}
.halcyon-tip[aria-hidden="true"] { display: none; }

/* the .ti-dlt-* parts the enrich JS builds inside the tip */
.ti-dlt-body { display: block; }
.ti-dlt-title {
  display: block;
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.8px;
  text-transform: uppercase;
  color: var(--accent-deep);
  margin-bottom: 3px;
}
.ti-dlt-text { display: block; color: var(--text); }

/* the little pointer arrow, flipped to the resolved side via data-side */
.ti-dlt-arrow {
  position: absolute;
  width: 8px; height: 8px;
  background: var(--surface-2);
  border: 1px solid var(--border-accent);
  transform: rotate(45deg);
}
.halcyon-tip[data-side="top"]    .ti-dlt-arrow { bottom: -5px; left: 50%; margin-left: -4px; border-top: none; border-left: none; }
.halcyon-tip[data-side="bottom"] .ti-dlt-arrow { top: -5px;    left: 50%; margin-left: -4px; border-bottom: none; border-right: none; }
.halcyon-tip[data-side="left"]   .ti-dlt-arrow { right: -5px;  top: 50%;  margin-top: -4px;  border-bottom: none; border-left: none; }
.halcyon-tip[data-side="right"]  .ti-dlt-arrow { left: -5px;   top: 50%;  margin-top: -4px;  border-top: none; border-right: none; }

/* a control that carries a tip gets a quiet help affordance */
[data-tip] { cursor: help; }
[data-tip]:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }

/* ============================================================
   (b) .empty-coach — empty-state that coaches the first action
   ------------------------------------------------------------
   Centered icon glyph + plain headline + one line of copy + one or two
   CTAs. Drops into any surface that has no data yet. Calm, never an error.
   ============================================================ */
.empty-coach {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 10px;
  max-width: 46ch;
  margin: 24px auto;
  padding: 28px 24px;
  background: var(--surface);
  border: 1px dashed var(--border);
  border-radius: var(--radius);
  min-width: 0;
}
/* the icon: a mono glyph in an accent-tinted disc (no image asset) */
.empty-coach .empty-coach-ico {
  width: 44px; height: 44px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%;
  background: var(--accent-pale);
  border: 1px solid var(--border-accent);
  color: var(--accent);
  font-family: var(--mono);
  font-size: 18px; font-weight: 700;
  flex-shrink: 0;
}
.empty-coach .empty-coach-title {
  font-size: 16px;
  font-weight: 600;
  color: var(--text);
  letter-spacing: -0.01em;
}
.empty-coach .empty-coach-copy {
  font-size: 13.5px;
  color: var(--text-dim);
  line-height: 1.5;
}
/* the CTA row — accent (navigation) + ghost (learn) buttons sit together */
.empty-coach .empty-coach-cta {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  justify-content: center;
  margin-top: 4px;
}

/* ============================================================
   (c) MOTION UTILITY LAYER — for the flowcharts
   ------------------------------------------------------------
   Classes the enrich diagrams add to SVG / DOM nodes. Defined here as
   STATIC final states first; the @media (no-preference) block at the
   bottom is the ONLY place that animates them. The play-the-path token
   (--km-path-play) lets a single JS toggle drive the marker travel.
   ============================================================ */

/* play-the-path orchestration token. JS flips it 0 -> 1 to "play". The
   default 0 keeps every path-driven element in its resting final state. */
:root { --km-path-play: 0; }

/* a path that draws on demand (SVG stroke). Default: fully drawn (offset 0)
   so reduced-motion / no-JS readers see the complete diagram. */
.km-draw {
  stroke-dasharray: var(--km-dash, 1);
  stroke-dashoffset: 0;              /* final, fully-drawn state by default */
}

/* a fade-up entrance element. Default: visible, in place (the final state). */
.km-fade-up {
  opacity: 1;
  transform: none;
}

/* a pop-in element (circles on the capability ripple). Default: full size. */
.km-pop {
  opacity: 1;
  transform: scale(1);
}

/* node travel states for "play the path": every node starts neutral, then
   the marker leaves a trail (.is-traveled), sits on one (.is-here), and the
   result lights gold (.is-landed). These are COLOR states, safe without
   any motion — the path reads even frozen. */
.km-node { transition: none; }
.km-node.is-traveled {
  color: var(--accent);
  opacity: 1;
}
.km-node.is-here {
  color: var(--accent-deep);
}
.km-node.is-landed {
  color: var(--gold);
}
/* SVG fill/stroke variants so the same states work on circles/rings */
.km-node-fill.is-traveled { fill: var(--accent); }
.km-node-fill.is-here     { fill: var(--accent-deep); }
.km-node-fill.is-landed   { fill: var(--gold); }
.km-node-stroke.is-traveled { stroke: var(--accent); }
.km-node-stroke.is-here     { stroke: var(--accent-deep); }
.km-node-stroke.is-landed   { stroke: var(--gold); }

/* the traveling marker dot itself (the thing that runs the path) */
.km-marker {
  fill: var(--accent);
  opacity: 0;                        /* hidden until a path actually plays */
}

/* stagger helpers: set --km-i (index) on each child; the motion block reads
   it to delay each one. No effect without the motion block. */
.km-stagger > * { --km-i: 0; }

/* keyframes — declared always (cheap), only REFERENCED in the motion block */
@keyframes km-stroke-draw {
  from { stroke-dashoffset: var(--km-dash, 1); }
  to   { stroke-dashoffset: 0; }
}
@keyframes km-fade-up-in {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes km-pop-in {
  0%   { opacity: 0; transform: scale(0.6); }
  70%  { opacity: 1; transform: scale(1.06); }
  100% { opacity: 1; transform: scale(1); }
}
@keyframes km-marker-travel {
  from { offset-distance: 0%; opacity: 1; }
  to   { offset-distance: 100%; opacity: 1; }
}
@keyframes km-gate-shimmer {
  0%, 100% { opacity: 0.35; }
  50%      { opacity: 0.65; }
}

/* ============================================================
   MOTION ON — the ONLY place animation turns on. Everything above is the
   static final state; with prefers-reduced-motion: reduce (or before this
   block matches) the diagrams are complete and readable without motion.
   ============================================================ */
@media (prefers-reduced-motion: no-preference) {
  .halcyon-tip {
    transform: translateY(2px);
    transition: opacity .14s ease, transform .14s ease;
  }
  .halcyon-tip.is-open { transform: translateY(0); }

  /* a path that should draw when its container gains .is-playing */
  .is-playing .km-draw {
    stroke-dashoffset: var(--km-dash, 1);
    animation: km-stroke-draw 2s ease forwards;
    animation-delay: calc(var(--km-i, 0) * 150ms);
  }

  /* fade-up entrance: arms when the container gains .in (Intersection Obs.) */
  .km-fade-up {
    opacity: 0;
    transform: translateY(10px);
    will-change: opacity, transform;
  }
  .in .km-fade-up,
  .km-fade-up.in {
    animation: km-fade-up-in .5s ease forwards;
    animation-delay: calc(var(--km-i, 0) * 120ms);
  }

  /* pop-in for ripple circles */
  .km-pop {
    opacity: 0;
    transform: scale(0.6);
    will-change: opacity, transform;
  }
  .in .km-pop,
  .km-pop.in {
    animation: km-pop-in .5s cubic-bezier(0.34, 1.4, 0.5, 1) forwards;
    animation-delay: calc(var(--km-i, 0) * 100ms);
  }

  /* the marker travels its motion-path when the path container is playing */
  .is-playing .km-marker {
    opacity: 1;
    animation: km-marker-travel 1.8s ease forwards;
  }

  /* a gate "waiting for a decision" shimmer (subtle, infinite) */
  .km-gate-shimmer { animation: km-gate-shimmer 3s ease-in-out infinite; }

  /* node state changes ease gently when motion is allowed */
  .km-node,
  .km-node-fill,
  .km-node-stroke { transition: color .25s ease, fill .25s ease, stroke .25s ease, opacity .25s ease; }
}

/* explicit reduced-motion guard: hard-stop everything to its final state.
   (Belt and suspenders — the default states above already match, but this
   makes the contract impossible to miss and overrides any future addition.) */
@media (prefers-reduced-motion: reduce) {
  .halcyon-tip { transition: none; transform: none; }
  .halcyon-tip.is-open { transform: none; }
  .km-draw { stroke-dashoffset: 0 !important; animation: none !important; }
  .km-fade-up { opacity: 1 !important; transform: none !important; animation: none !important; }
  .km-pop { opacity: 1 !important; transform: scale(1) !important; animation: none !important; }
  .km-marker { animation: none !important; }
  .km-gate-shimmer { animation: none !important; opacity: 0.5; }
  .km-node, .km-node-fill, .km-node-stroke { transition: none !important; }
}

/* ============================================================
   AGENT-TRACE — the "watch the agent work" affordance, generalized.
   A container of [data-trace-step] rows. When the container gains
   .is-playing, agent-trace.js reveals one step per 300ms by setting
   data-trace-state="on" on each in turn (it never touches innerHTML, only
   the attribute + the trust class the markup already carries). Each step
   reads as agent work (cyan), agent suggestion (cyan + suggested), or the
   final human gate (gold). A reader follows the work step by step, then sees
   that a person decides at the end. Spec 4.4.
   ============================================================ */
.km-trace { display: flex; flex-direction: column; gap: 8px; }
.km-trace-step {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
}
.km-trace-step .km-trace-marker {
  flex: none;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  font-weight: 700;
  color: var(--text-dim);
  background: var(--surface-2);
  border: 1px solid var(--border);
}
.km-trace-step .km-trace-text { flex: 1 1 auto; min-width: 0; }
.km-trace-step .km-trace-title { font-weight: 600; font-size: 13.5px; color: var(--text); }
.km-trace-step .km-trace-detail { font-size: 12.5px; color: var(--text-dim); line-height: 1.5; }

/* default (idle / pre-play): steps sit dim and waiting. Under reduce this is
   ALSO the resting state, but the reveal below forces every step visible. */
@media (prefers-reduced-motion: no-preference) {
  .km-trace-step {
    opacity: 0.34;
    transform: translateY(6px);
    transition: opacity 0.32s ease, transform 0.32s ease, border-color 0.32s ease;
  }
  /* a revealed step lights up: full opacity, settles up, trust color picks up */
  .km-trace-step[data-trace-state="on"] {
    opacity: 1;
    transform: translateY(0);
  }
  /* the marker fills with the step's trust color once revealed */
  .km-trace-step[data-trace-state="on"].km-agent-work .km-trace-marker,
  .km-trace-step[data-trace-state="on"] .km-agent-work + .km-trace-marker {
    color: var(--accent);
    background: var(--accent-soft);
    border-color: var(--border-accent);
  }
  .km-trace-step[data-trace-state="on"].km-human-gate {
    border-color: var(--gold);
    background: var(--gold-soft);
  }
  .km-trace-step[data-trace-state="on"].km-human-gate .km-trace-marker {
    color: var(--gold);
    background: var(--gold-soft);
    border-color: var(--gold);
  }
}

/* reduced motion: no reveal sequence. Every step is shown, still, at rest in
   its final state, fully readable. The agent-trace.js reduce path sets every
   step on immediately, and these rules guarantee the visual end state. */
@media (prefers-reduced-motion: reduce) {
  .km-trace-step {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
  .km-trace-step.km-human-gate {
    border-color: var(--gold);
    background: var(--gold-soft);
  }
}
