// Top controls — rethought IA.
// Row 1: brand · prominent prompt field · help button
// Row 2: transport (reset · play · step) · stage path · speed · temp
const STAGE_LABELS = ['TOKENIZE', 'EMBED', 'ATTEND', 'MLP', 'SAMPLE'];

const IconPlay = ({ size = 14, color = 'currentColor' }) => (
  <svg width={size} height={size} viewBox="0 0 12 12" fill="none" aria-hidden="true">
    <path d="M3 2 L10 6 L3 10 Z" fill={color} />
  </svg>
);
const IconPause = ({ size = 14, color = 'currentColor' }) => (
  <svg width={size} height={size} viewBox="0 0 12 12" fill="none" aria-hidden="true">
    <rect x="3" y="2.5" width="2" height="7" fill={color} />
    <rect x="7" y="2.5" width="2" height="7" fill={color} />
  </svg>
);
const IconStep = ({ size = 12, color = 'currentColor' }) => (
  <svg width={size} height={size} viewBox="0 0 12 12" fill="none" aria-hidden="true">
    <path d="M2 2 L8 6 L2 10 Z" fill={color} />
    <rect x="9" y="2.5" width="1.6" height="7" fill={color} />
  </svg>
);
const IconReset = ({ size = 12, color = 'currentColor' }) => (
  <svg width={size} height={size} viewBox="0 0 12 12" fill="none" aria-hidden="true">
    <path d="M2.5 6 a3.5 3.5 0 1 1 1 2.5" stroke={color} strokeWidth="1.4" fill="none" strokeLinecap="round" />
    <path d="M1 3 L2.5 6 L5 5" stroke={color} strokeWidth="1.4" fill="none" strokeLinecap="round" strokeLinejoin="round" />
  </svg>
);
const IconHelp = ({ size = 13, color = 'currentColor' }) => (
  <svg width={size} height={size} viewBox="0 0 12 12" fill="none" aria-hidden="true">
    <circle cx="6" cy="6" r="5" stroke={color} strokeWidth="1.2" fill="none" />
    <path d="M4.4 4.6 a1.6 1.6 0 1 1 2.2 1.8 c-.4.2-.6.5-.6 1 v.1" stroke={color} strokeWidth="1.2" fill="none" strokeLinecap="round" />
    <circle cx="6" cy="9" r="0.6" fill={color} />
  </svg>
);
const IconEdit = ({ size = 11, color = 'currentColor' }) => (
  <svg width={size} height={size} viewBox="0 0 12 12" fill="none" aria-hidden="true">
    <path d="M2 9 L2 10 L3 10 L9.5 3.5 L8.5 2.5 Z" stroke={color} strokeWidth="1" fill="none" strokeLinejoin="round" />
    <path d="M8.5 2.5 L9.5 3.5" stroke={color} strokeWidth="1" />
  </svg>
);

// --- Shared tooltip -----------------------------------------------------
// Rich tooltip matching the SPEED/TEMP hint style. Use via <TooltipHost>.
//
// Usage:
//   <TooltipHost title="PAUSE" body="spacebar" shortcut="SPACE">
//     <button>...</button>
//   </TooltipHost>
//
// Opens above the hosted element, clamped into the viewport.

function TooltipHost({ children, title, body, shortcut, width = 240, disabled = false }) {
  const [hover, setHover] = React.useState(false);
  const [focused, setFocused] = React.useState(false);
  const [pos, setPos] = React.useState(null);
  const ref = React.useRef(null);
  const show = !disabled && (hover || focused) && (title || body);

  React.useLayoutEffect(() => {
    if (!show || !ref.current) { setPos(null); return; }
    const update = () => {
      const el = ref.current; if (!el) return;
      const r = el.getBoundingClientRect();
      const margin = 12;
      // Center tooltip on the element, clamp into viewport
      let left = r.left + r.width / 2 - width / 2;
      if (left < margin) left = margin;
      if (left + width > window.innerWidth - margin) left = window.innerWidth - width - margin;
      const estHeight = 80;
      const openAbove = r.top > estHeight + margin;
      const top = openAbove ? r.top - 8 : r.bottom + 8;
      const transform = openAbove ? 'translateY(-100%)' : 'translateY(0)';
      setPos({ left, top, width, transform });
    };
    update();
    window.addEventListener('scroll', update, true);
    window.addEventListener('resize', update);
    return () => {
      window.removeEventListener('scroll', update, true);
      window.removeEventListener('resize', update);
    };
  }, [show, width]);

  // Clone single child to attach ref + handlers without adding a wrapper <div>
  const child = React.Children.only(children);
  const clonedChild = React.cloneElement(child, {
    ref: (node) => {
      ref.current = node;
      const { ref: origRef } = child;
      if (typeof origRef === 'function') origRef(node);
      else if (origRef && typeof origRef === 'object') origRef.current = node;
    },
    onMouseEnter: (e) => { setHover(true); child.props.onMouseEnter?.(e); },
    onMouseLeave: (e) => { setHover(false); child.props.onMouseLeave?.(e); },
    onFocus: (e) => { setFocused(true); child.props.onFocus?.(e); },
    onBlur: (e) => { setFocused(false); child.props.onBlur?.(e); },
  });

  return (
    <>
      {clonedChild}
      {show && pos && ReactDOM.createPortal(
        <div style={{
          position: 'fixed',
          left: pos.left, top: pos.top,
          width: pos.width, zIndex: 10000,
          transform: pos.transform,
          background: 'linear-gradient(180deg, rgba(18,24,18,0.98), rgba(12,16,12,0.98))',
          border: '1px solid var(--line-strong)',
          borderRadius: 6, padding: '10px 12px',
          boxShadow: '0 6px 24px rgba(0,0,0,0.5), 0 0 20px color-mix(in oklch, var(--ink) 15%, transparent)',
          pointerEvents: 'none',
        }}>
          {(title || shortcut) && (
            <div style={{
              display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 8,
              marginBottom: body ? 4 : 0,
            }}>
              {title && (
                <div style={{
                  fontFamily: 'var(--mono)', fontSize: 9, color: 'var(--ink)',
                  letterSpacing: '0.14em', textShadow: '0 0 6px var(--ink)',
                }}>{title}</div>
              )}
              {shortcut && (
                <div style={{
                  fontFamily: 'var(--mono)', fontSize: 8.5, fontWeight: 500, letterSpacing: '0.1em',
                  color: 'var(--text-faint)',
                  border: '1px solid var(--line-strong)', borderRadius: 2,
                  padding: '1px 5px',
                }}>{shortcut}</div>
              )}
            </div>
          )}
          {body && (
            <div style={{ fontFamily: 'var(--sans)', fontSize: 12, lineHeight: 1.55, color: 'var(--text-dim)', textWrap: 'pretty' }}>
              {body}
            </div>
          )}
        </div>,
        document.body
      )}
    </>
  );
}

// Structured rows inside a tooltip body: [value, meaning] pairs.
function TipRows({ rows }) {
  return (
    <div style={{ marginTop: 8, display: 'grid', gridTemplateColumns: 'auto 1fr', columnGap: 10, rowGap: 4 }}>
      {rows.map(([k, v], i) => (
        <React.Fragment key={i}>
          <div style={{
            fontFamily: 'var(--mono)',
            fontSize: 10.5,
            letterSpacing: '0.04em',
            color: 'var(--green)',
            textAlign: 'right',
            whiteSpace: 'nowrap',
            alignSelf: 'baseline',
            paddingTop: 1,
          }}>{k}</div>
          <div style={{ color: 'var(--text-dim)', fontSize: 12, lineHeight: 1.4 }}>{v}</div>
        </React.Fragment>
      ))}
    </div>
  );
}

// Subtle footnote row at the bottom of a tooltip — italic-feeling secondary line.
function TipFootnote({ children }) {
  return (
    <div style={{
      marginTop: 8,
      paddingTop: 8,
      borderTop: '1px solid rgba(255,255,255,0.06)',
      fontSize: 11,
      lineHeight: 1.45,
      color: 'rgba(229,229,229,0.55)',
    }}>{children}</div>
  );
}

function Controls({
  prompt, onPromptChange, playing, onPlayToggle, onStep, onReset,
  speed, onSpeedChange, temperature, onTempChange, tokenCount, stepIdx,
  progress, onJumpStage, onHelp, autoScroll, onAutoScrollToggle,
}) {
  return (
    <div style={{
      display: 'flex', flexDirection: 'column', gap: 10,
      padding: '14px 18px 16px',
      borderBottom: '1px solid color-mix(in oklch, var(--ink) 35%, transparent)',
      background: `
        linear-gradient(180deg, rgba(140,255,160,0.055) 0%, rgba(140,255,160,0.02) 60%, rgba(140,255,160,0.008) 100%),
        repeating-linear-gradient(90deg, transparent 0, transparent 3px, rgba(140,255,160,0.008) 3px, rgba(140,255,160,0.008) 4px)
      `,
      boxShadow: 'inset 0 -1px 0 rgba(140,255,160,0.08), 0 1px 0 rgba(0,0,0,0.4), 0 6px 14px -8px rgba(0,0,0,0.6)',
      position: 'relative',
      zIndex: 10,
    }}>
      {/* Row 1: brand · prompt · help */}
      <div style={{ display: 'flex', alignItems: 'center', gap: 14 }}>
        <TooltipHost
          title="TRANSFORMER · LIVE"
          body={<>
            <div>A working diagram of how a language model picks its next word. No real weights harmed in the making of this demo.</div>
            <TipFootnote>The green dot means it's running. Or bored. Hard to tell.</TipFootnote>
          </>}
          width={280}
        >
          <div style={{
            display: 'inline-flex', alignItems: 'center', gap: 7,
            fontFamily: 'var(--mono)', fontSize: 10, color: 'var(--ink)',
            letterSpacing: '0.14em', textShadow: '0 0 8px var(--ink)',
            padding: '6px 10px',
            border: '1px solid color-mix(in oklch, var(--ink) 50%, transparent)',
            borderRadius: 3,
            background: 'color-mix(in oklch, var(--ink) 6%, transparent)',
            whiteSpace: 'nowrap',
            boxShadow: 'inset 0 0 8px color-mix(in oklch, var(--ink) 12%, transparent)',
            cursor: 'default',
          }}>
            <span style={{
              display: 'inline-block', width: 6, height: 6, borderRadius: '50%',
              background: 'var(--ink)', boxShadow: '0 0 6px var(--ink)',
              animation: 'brand-pulse 2s ease-in-out infinite',
            }} />
            TRANSFORMER·LIVE
          </div>
        </TooltipHost>

        <PromptField value={prompt} onChange={onPromptChange} />

        <HelpBtn onClick={onHelp} />
      </div>

      {/* Row 2: transport · stage path · sliders */}
      <div style={{ display: 'flex', alignItems: 'center', gap: 16 }}>
        <Transport
          playing={playing}
          onPlayToggle={onPlayToggle}
          onStep={onStep}
          onReset={onReset}
        />
        <StagePath stepIdx={stepIdx} progress={progress} onJumpStage={onJumpStage} />
        <AutoScrollToggle on={autoScroll} onToggle={onAutoScrollToggle} />
        <div style={{ display: 'flex', gap: 14, alignItems: 'center' }}>
          <SliderControl label="SPEED" value={speed} min={0.2} max={3} step={0.1} onChange={onSpeedChange} format={(v) => `${v.toFixed(1)}×`}
            hintTitle="ANIMATION SPEED"
            hint={<>
              <div>How fast the visualization plays.</div>
              <TipRows rows={[
                ['0.2×', 'slow crawl — watch every frame'],
                ['1.0×', 'default pace'],
                ['3.0×', 'speedrun'],
              ]} />
              <TipFootnote>Only affects the animation. Real models don't have this knob (unfortunately).</TipFootnote>
            </>} />
          <SliderControl label="TEMP" value={temperature} min={0.1} max={2} step={0.05} onChange={onTempChange} format={(v) => v.toFixed(2)}
            hintTitle="TEMPERATURE"
            hint={<>
              <div>Controls how random the next-word pick is.</div>
              <TipRows rows={[
                ['~0.2', 'safe, repetitive — top candidate dominates'],
                ['~0.9', 'default — lively but coherent'],
                ['~1.5', 'flatter, weirder, more creative'],
              ]} />
              <TipFootnote>Pause on Stage 05 and drag the slider — watch the probability bars argue it out.</TipFootnote>
            </>} />
        </div>
      </div>
      <style>{`@keyframes brand-pulse { 0%, 100% { opacity: 0.4; } 50% { opacity: 1; } }`}</style>
    </div>
  );
}

function PromptField({ value, onChange }) {
  const [focused, setFocused] = React.useState(false);
  const inputRef = React.useRef(null);
  return (
    <button
      type="button"
      onClick={() => inputRef.current && inputRef.current.focus()}
      style={{
        flex: 1, minWidth: 0, display: 'flex', alignItems: 'center', gap: 10,
        padding: '8px 14px',
        background: focused ? 'rgba(140,255,160,0.04)' : 'rgba(140,255,160,0.015)',
        border: `1px solid ${focused ? 'var(--ink)' : 'var(--line-strong)'}`,
        borderRadius: 6, cursor: 'text', textAlign: 'left',
        boxShadow: focused ? '0 0 14px color-mix(in oklch, var(--ink) 22%, transparent)' : 'none',
        transition: 'border-color 150ms, background 150ms, box-shadow 150ms',
      }}
    >
      <div style={{
        display: 'flex', alignItems: 'center', gap: 5,
        fontFamily: 'var(--mono)', fontSize: 9, fontWeight: 500, letterSpacing: '0.16em',
        color: focused ? 'var(--ink)' : 'var(--text-dim)',
        textShadow: focused ? '0 0 6px var(--ink)' : 'none',
        flexShrink: 0, whiteSpace: 'nowrap',
      }}>
        <IconEdit /> YOUR PROMPT
      </div>
      <div style={{ width: 1, height: 16, background: 'var(--line-strong)', flexShrink: 0 }} />
      <input
        ref={inputRef}
        value={value}
        onChange={(e) => onChange(e.target.value)}
        onFocus={() => setFocused(true)}
        onBlur={() => setFocused(false)}
        placeholder="type anything — watch it flow through the model…"
        style={{
          flex: 1, minWidth: 0,
          background: 'transparent', border: 'none', outline: 'none',
          fontFamily: 'var(--mono)', fontSize: 14, color: 'var(--text)',
          caretColor: 'var(--ink)', padding: 0,
        }}
      />
      {/* blinking prompt glyph on the right when unfocused to hint it's editable */}
      {!focused && !value && (
        <span style={{
          fontFamily: 'var(--mono)', fontSize: 14, color: 'var(--ink)',
          textShadow: '0 0 6px var(--ink)', flexShrink: 0,
          animation: 'prompt-blink 1.1s steps(2) infinite',
        }}>▮</span>
      )}
      <style>{`@keyframes prompt-blink { to { opacity: 0; } }`}</style>
    </button>
  );
}

function Transport({ playing, onPlayToggle, onStep, onReset }) {
  return (
    <div style={{
      display: 'inline-flex', alignItems: 'center', gap: 2,
      padding: 2,
      border: '1px solid var(--line-strong)', borderRadius: 6,
      background: 'rgba(0,0,0,0.25)',
      flexShrink: 0,
    }}>
      <TooltipHost
        title="RESET"
        body={<>
          <div>Clear all generated tokens and start over from your prompt.</div>
          <TipFootnote>Useful after tweaking TEMP or when the model says something cursed.</TipFootnote>
        </>}
        shortcut="R"
      >
        <TransportBtn onClick={onReset}><IconReset /></TransportBtn>
      </TooltipHost>
      <TooltipHost
        title={playing ? 'PAUSE' : 'PLAY'}
        body={<>
          <div>{playing ? 'Freeze the animation where it is.' : 'Start the pipeline animating.'}</div>
          <TipFootnote>{playing ? 'Good moment to drag TEMP and watch the probabilities panic.' : 'Or tap → to creep forward one stage at a time.'}</TipFootnote>
        </>}
        shortcut="SPACE"
      >
        <TransportBtn onClick={onPlayToggle} primary playing={playing}>
          {playing ? <IconPause /> : <IconPlay />}
          <span style={{ fontFamily: 'var(--mono)', fontSize: 11, fontWeight: 600, letterSpacing: '0.12em', marginLeft: 7 }}>
            {playing ? 'PAUSE' : 'PLAY'}
          </span>
        </TransportBtn>
      </TooltipHost>
      <TooltipHost
        title="STEP"
        body={<>
          <div>Pause and advance exactly one stage forward.</div>
          <TipFootnote>The patient way to actually see what's happening.</TipFootnote>
        </>}
        shortcut="→"
      >
        <TransportBtn onClick={onStep}><IconStep /></TransportBtn>
      </TooltipHost>
    </div>
  );
}

const TransportBtn = React.forwardRef(function TransportBtn({ children, onClick, primary, playing, onMouseEnter, onMouseLeave, onFocus, onBlur }, ref) {
  const [hover, setHover] = React.useState(false);
  // Primary (play/pause): outlined-with-glow when playing, filled when paused (invites click).
  // The pulse on the whole bar + the stage progress already signal "playing" — keep this quiet during motion.
  let bg, color, shadow;
  if (primary) {
    if (playing) {
      bg = hover ? 'color-mix(in oklch, var(--ink) 18%, transparent)' : 'color-mix(in oklch, var(--ink) 10%, transparent)';
      color = 'var(--ink)';
      shadow = hover ? '0 0 14px color-mix(in oklch, var(--ink) 40%, transparent), inset 0 0 8px color-mix(in oklch, var(--ink) 18%, transparent)' : 'inset 0 0 6px color-mix(in oklch, var(--ink) 14%, transparent)';
    } else {
      bg = hover ? 'var(--ink)' : 'color-mix(in oklch, var(--ink) 88%, transparent)';
      color = 'var(--bg)';
      shadow = '0 0 12px color-mix(in oklch, var(--ink) 45%, transparent)';
    }
  } else {
    bg = hover ? 'rgba(140,255,160,0.12)' : 'transparent';
    color = 'var(--ink)';
    shadow = 'none';
  }
  return (
    <button
      ref={ref}
      onClick={onClick}
      onMouseEnter={(e) => { setHover(true); onMouseEnter?.(e); }}
      onMouseLeave={(e) => { setHover(false); onMouseLeave?.(e); }}
      onFocus={onFocus}
      onBlur={onBlur}
      style={{
        display: 'inline-flex', alignItems: 'center',
        padding: primary ? '6px 12px' : '6px 8px',
        background: bg,
        color,
        border: primary && playing ? '1px solid color-mix(in oklch, var(--ink) 50%, transparent)' : 'none',
        borderRadius: 4,
        cursor: 'pointer',
        boxShadow: shadow,
        transition: 'background 120ms, box-shadow 120ms, color 120ms',
      }}
    >{children}</button>
  );
});

function AutoScrollToggle({ on, onToggle }) {
  const [hover, setHover] = React.useState(false);
  const active = !!on;
  // Follows the same "outlined monospace chip, filled when active" vocabulary as the brand chip / HELP.
  return (
    <TooltipHost
      title="FOLLOW ACTIVE STAGE"
      body={<>
        <div>Auto-scroll the panel view to the stage that's currently running.</div>
        <TipRows rows={[
          ['ON', 'view follows the pipeline as it runs'],
          ['OFF', 'view stays wherever you left it'],
        ]} />
        <TipFootnote>Currently <span style={{ color: active ? 'var(--green)' : 'var(--text-dim)' }}>{active ? 'ON' : 'OFF'}</span> — leash is {active ? 'attached' : 'off'}.</TipFootnote>
      </>}
      shortcut="F"
    >
      <button
        onClick={onToggle}
        onMouseEnter={() => setHover(true)}
        onMouseLeave={() => setHover(false)}
        aria-pressed={active}
        style={{
          display: 'inline-flex', alignItems: 'center', gap: 6,
          fontFamily: 'var(--mono)', fontSize: 10, fontWeight: 500, letterSpacing: '0.14em',
          padding: '6px 10px', cursor: 'pointer', whiteSpace: 'nowrap',
          color: active ? 'var(--bg)' : (hover ? 'var(--ink)' : 'var(--text-dim)'),
          background: active
            ? (hover ? 'var(--ink)' : 'color-mix(in oklch, var(--ink) 88%, transparent)')
            : (hover ? 'color-mix(in oklch, var(--ink) 10%, transparent)' : 'transparent'),
          border: `1px solid ${active ? 'var(--ink)' : 'var(--line-strong)'}`,
          borderRadius: 4,
          textShadow: 'none',
          boxShadow: active
            ? '0 0 12px color-mix(in oklch, var(--ink) 40%, transparent)'
            : 'none',
          transition: 'all 140ms',
          flexShrink: 0,
        }}
      >
        <svg width="11" height="11" viewBox="0 0 12 12" fill="none" aria-hidden="true">
          <path d="M6 1.5 L6 10" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round" />
          <path d="M3 7 L6 10 L9 7" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round" strokeLinejoin="round" fill="none" />
          <path d="M2 11.2 L10 11.2" stroke="currentColor" strokeWidth="1" strokeLinecap="round" opacity={active ? 1 : 0.5} />
        </svg>
        <span>FOLLOW</span>
      </button>
    </TooltipHost>
  );
}

function StagePath({ stepIdx, progress, onJumpStage }) {
  const descriptions = [
    'Chop the prompt into token IDs the model can read. Spaces are tokens too. Sorry.',
    'Turn each token ID into a high-dimensional vector — coordinates in a meaning-space where similar words sit near each other.',
    'Every token looks at every other token. This is where the magic happens, and also most of the compute.',
    'Feed-forward layers process each position independently. Nobody really knows what they learn.',
    'Turn the final vector into probabilities, roll the dice, pick the next token.',
  ];
  return (
    <div style={{
      flex: 1, display: 'flex', alignItems: 'center', gap: 0, minWidth: 0,
      border: '1px solid var(--line)', borderRadius: 6,
      padding: '3px 6px',
      background: 'rgba(140,255,160,0.015)',
    }}>
      {STAGE_LABELS.map((label, i) => {
        const isActive = i === stepIdx;
        const isPast = i < stepIdx;
        const fill = isActive ? progress : (isPast ? 1 : 0);
        return (
          <React.Fragment key={i}>
            <TooltipHost
              title={`STAGE 0${i + 1} · ${label}`}
              body={<div>{descriptions[i]}</div>}
              shortcut={String(i + 1)}
            >
              <button
                onClick={() => onJumpStage && onJumpStage(i)}
                style={{
                  flex: 1, minWidth: 0,
                  display: 'flex', flexDirection: 'column', alignItems: 'stretch',
                  gap: 3, padding: '4px 8px',
                  background: isActive ? 'color-mix(in oklch, var(--ink) 6%, transparent)' : 'transparent',
                  border: 'none', borderRadius: 3, cursor: 'pointer',
                  textAlign: 'left',
                }}
              >
              <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', gap: 6 }}>
                <div style={{
                  fontFamily: 'var(--mono)', fontSize: 9,
                  color: isActive ? 'var(--ink)' : 'var(--text-faint)',
                  letterSpacing: '0.1em',
                }}>0{i + 1}</div>
                <div style={{
                  fontFamily: 'var(--mono)', fontSize: 10, fontWeight: 500,
                  letterSpacing: '0.1em',
                  color: isActive ? 'var(--ink)' : (isPast ? 'var(--text-dim)' : 'var(--text-faint)'),
                  textShadow: isActive ? '0 0 8px var(--ink)' : 'none',
                  whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
                }}>{label}</div>
              </div>
              <div style={{
                height: 3, borderRadius: 2, overflow: 'hidden',
                background: 'rgba(140,255,160,0.08)',
                position: 'relative',
              }}>
                <div style={{
                  position: 'absolute', inset: 0, width: `${fill * 100}%`,
                  background: isActive
                    ? 'linear-gradient(90deg, color-mix(in oklch, var(--ink) 60%, transparent), var(--ink))'
                    : 'color-mix(in oklch, var(--ink) 55%, transparent)',
                  boxShadow: isActive ? '0 0 8px var(--ink)' : 'none',
                  transition: isActive ? 'width 120ms linear' : 'width 300ms',
                }} />
              </div>
              </button>
            </TooltipHost>
            {i < STAGE_LABELS.length - 1 && (
              <div style={{
                width: 10, height: 1, flexShrink: 0,
                background: i < stepIdx ? 'var(--ink)' : 'var(--line-strong)',
                opacity: i < stepIdx ? 0.7 : 1,
                marginTop: 20,
              }} />
            )}
          </React.Fragment>
        );
      })}
    </div>
  );
}

function HelpBtn({ onClick }) {
  const [hover, setHover] = React.useState(false);
  return (
    <TooltipHost
      title="GUIDED TOUR"
      body={<>
        <div>A stage-by-stage walkthrough of the whole pipeline.</div>
        <TipRows rows={[
          ['EXPLAINS', 'what each stage does in plain English'],
          ['CALLS OUT', "what's real math vs. what's stylized"],
        ]} />
      </>}
      shortcut="?"
    >
      <button
        onClick={onClick}
        onMouseEnter={() => setHover(true)}
        onMouseLeave={() => setHover(false)}
        style={{
          display: 'inline-flex', alignItems: 'center', gap: 7,
          fontFamily: 'var(--mono)', fontSize: 11, fontWeight: 500, letterSpacing: '0.1em',
          padding: '8px 14px', cursor: 'pointer',
          color: hover ? 'var(--bg)' : 'var(--ink)',
          background: hover ? 'var(--ink)' : 'color-mix(in oklch, var(--ink) 14%, transparent)',
          border: '1px solid var(--ink)',
          borderRadius: 6,
          boxShadow: hover
            ? '0 0 18px color-mix(in oklch, var(--ink) 55%, transparent)'
            : '0 0 10px color-mix(in oklch, var(--ink) 25%, transparent)',
          transition: 'background 150ms, color 150ms, box-shadow 150ms',
          whiteSpace: 'nowrap',
          flexShrink: 0,
        }}
      >
        <IconHelp size={13} />
        HELP
      </button>
    </TooltipHost>
  );
}

function SliderControl({ label, value, min, max, step, onChange, format, hint, hintTitle, shortcut }) {
  const ref = React.useRef(null);
  return (
    <TooltipHost title={hintTitle} body={hint} shortcut={shortcut} width={280} disabled={!hint}>
      <label
        ref={ref}
        style={{ display: 'flex', flexDirection: 'column', gap: 2, minWidth: 86, position: 'relative' }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', fontFamily: 'var(--mono)', fontSize: 9, color: 'var(--text-faint)', letterSpacing: '0.1em' }}>
          <span style={{
            display: 'inline-flex', alignItems: 'center', gap: 4,
            borderBottom: hint ? '1px dotted var(--line-strong)' : 'none',
            cursor: hint ? 'help' : 'default',
          }}>
            {label}{hint && <span style={{
              display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
              width: 10, height: 10, borderRadius: '50%',
              border: '1px solid var(--line-strong)', fontSize: 8, color: 'var(--text-dim)',
            }}>?</span>}
          </span>
          <span style={{ color: 'var(--ink)' }}>{format(value)}</span>
        </div>
        <input type="range" min={min} max={max} step={step} value={value}
          onChange={(e) => onChange(parseFloat(e.target.value))}
          style={{ width: '100%', accentColor: 'oklch(0.85 0.18 145)' }} />
      </label>
    </TooltipHost>
  );
}

window.Controls = Controls;
