// Channel Builder — GROUND-UP replacement for the four-editor create chain
// (Channel -> Schedule -> Schedule Items -> Playout). One library-to-lineup screen.
// Left: searchable library browser. Center: the channel lineup (add by double-click
// or drag; drag to reorder). Right: friendly options + Channel Template + Advanced.
// Behind the scenes "Create" builds Channel + Collection + Schedule + Items + Playout.
(function () {
  const NS = window.ChicoryTVDesignSystem_eb3b61;
  const { Button, IconButton, Input, Select, Switch, Badge, ChannelLogo, Tooltip } = NS;
  const Ico = window.Ico;
  const mono = { fontFamily: "var(--font-mono)", fontVariantNumeric: "tabular-nums" };
  const eyebrow = { font: "var(--weight-semibold) var(--text-2xs)/1 var(--font-sans)", letterSpacing: "0.06em", textTransform: "uppercase", color: "var(--text-disabled)" };

  // ---- Mock library (shows / movies / music / docs across libraries) --------
  const LIB = [
    { id: "s1", title: "Looney Tunes", type: "Show",  library: "Cartoons",       sub: "247 shorts",     min: 96 },
    { id: "s2", title: "Tom & Jerry", type: "Show",   library: "Cartoons",       sub: "164 shorts",     min: 72 },
    { id: "s3", title: "Popeye",       type: "Show",  library: "Cartoons",       sub: "108 shorts",     min: 54 },
    { id: "s4", title: "The Flintstones", type: "Show", library: "Cartoons",     sub: "166 episodes",   min: 84 },
    { id: "s5", title: "Scooby-Doo",   type: "Show",  library: "Cartoons",       sub: "97 episodes",    min: 60 },
    { id: "s6", title: "Pink Panther", type: "Show",  library: "Cartoons",       sub: "124 shorts",     min: 48 },
    { id: "m1", title: "Blade Runner", type: "Movie", library: "Movies",         sub: "1982 · Sci-Fi",  min: 117 },
    { id: "m2", title: "Alien",        type: "Movie", library: "Movies",         sub: "1979 · Horror",  min: 117 },
    { id: "m3", title: "The Thing",    type: "Movie", library: "Movies",         sub: "1982 · Horror",  min: 109 },
    { id: "m4", title: "Metropolis",   type: "Movie", library: "Movies",         sub: "1927 · Sci-Fi",  min: 153 },
    { id: "m5", title: "Nosferatu",    type: "Movie", library: "Movies",         sub: "1922 · Horror",  min: 94 },
    { id: "t1", title: "The Twilight Zone", type: "Show", library: "TV Shows",   sub: "156 episodes",   min: 51 },
    { id: "t2", title: "Star Trek",    type: "Show",  library: "TV Shows",       sub: "79 episodes",    min: 50 },
    { id: "t3", title: "Columbo",      type: "Show",  library: "TV Shows",       sub: "69 episodes",    min: 94 },
    { id: "t4", title: "Cheers",       type: "Show",  library: "TV Shows",       sub: "275 episodes",   min: 24 },
    { id: "u1", title: "80s Synthpop", type: "Music", library: "Music Videos",   sub: "212 videos",     min: 45 },
    { id: "u2", title: "90s Alt Rock", type: "Music", library: "Music Videos",   sub: "188 videos",     min: 45 },
    { id: "u3", title: "Chart Countdown", type: "Music", library: "Music Videos", sub: "Top 40",        min: 60 },
    { id: "d1", title: "Blue Planet",  type: "Doc",   library: "Documentaries",  sub: "8 episodes",     min: 50 },
    { id: "d2", title: "Planet Earth", type: "Doc",   library: "Documentaries",  sub: "11 episodes",    min: 50 },
    { id: "d3", title: "Cosmos",       type: "Doc",   library: "Documentaries",  sub: "13 episodes",    min: 60 },
  ];
  const LIBRARIES = ["All", "Cartoons", "Movies", "TV Shows", "Music Videos", "Documentaries"];
  const TYPE_ICON = { Show: "Tv", Movie: "Film", Music: "Music", Doc: "Radio", Multi: "Layers", Smart: "Sparkles", Manual: "FolderTree", Rerun: "Repeat" };

  // Collections — curated groups (Manual / Smart / Multi / Rerun) addable as a
  // single lineup entry, so the builder isn't limited to raw library items.
  const COLLECTIONS = [
    { id: "c1", title: "Prime Time Cartoons", type: "Multi",  library: "Collection", sub: "Multi · 62 items",    min: 180, coll: true },
    { id: "c2", title: "Classic Sci-Fi",      type: "Smart",  library: "Collection", sub: "Smart · rating \u2265 8", min: 240, coll: true },
    { id: "c3", title: "Retro Station IDs",   type: "Manual", library: "Collection", sub: "Manual · 24 items",   min: 12,  coll: true },
    { id: "c4", title: "Saturday Morning",    type: "Rerun",  library: "Collection", sub: "Rerun block · weekly",min: 120, coll: true },
    { id: "c5", title: "Halloween Marathon",  type: "Manual", library: "Collection", sub: "Manual · 9 films",    min: 900, coll: true },
  ];

  // Channel Templates — bundle the clunky technical config; one is pre-selected.
  const TEMPLATES = [
    { id: "std",   name: "Standard",     builtin: true,  desc: "General-purpose 1080p H.264, retro bumpers.", shuffle: false, always: true,
      sets: ["1080p H.264", "HLS Segmenter", "Sequential", "Always on", "Pre + post filler"] },
    { id: "music", name: "Music videos", builtin: true,  desc: "Continuous rotation, no fillers, direct stream.", shuffle: true, always: true,
      sets: ["720p H.264", "HLS Direct", "Shuffle", "Always on", "No filler"] },
    { id: "film",  name: "Movie night",  builtin: true,  desc: "Film-grain HEVC, mid-roll ad breaks.", shuffle: false, always: false,
      sets: ["1080p HEVC", "MPEG-TS", "Sequential", "On-demand", "Mid-roll ads"] },
    { id: "retro", name: "Retro Saturday AM", builtin: false, desc: "Your saved cartoon-block template.", shuffle: true, always: true,
      sets: ["1080p H.264", "HLS Segmenter", "Shuffle", "Always on", "Bumpers + ads"] },
  ];

  // Advanced (~30-field) override set, grouped. Values shown as template-inherited.
  const ADV = [
    { group: "Streaming", fields: [
      ["Streaming mode", "HLS Segmenter"], ["FFmpeg profile", "1080p H.264"], ["Resolution", "1920×1080"],
      ["Video bitrate", "8000 kbps"], ["Audio bitrate", "192 kbps"], ["Buffer size", "16000 kb"],
    ]},
    { group: "Filler", fields: [
      ["Pre-roll", "Retro Bumpers"], ["Mid-roll", "Ad Break"], ["Post-roll", "Outro"],
      ["Tail filler", "None"], ["Fallback", "Test Pattern"], ["Filler kind", "Pad to :00"],
    ]},
    { group: "Playback", fields: [
      ["Interleave", "On"], ["Keep multi-part together", "On"], ["Watermark", "Channel logo"],
      ["Subtitle mode", "Any"], ["Preferred audio", "English"], ["Preferred subtitle", "None"],
    ]},
    { group: "Behavior", fields: [
      ["Guide mode default", "Normal"], ["Song video mode", "Off"], ["On-demand", "Off"],
      ["Idle behavior", "Offline image"], ["Transcode audio", "Normalize"], ["Number scheme", "Auto"],
    ]},
  ];

  // deterministic low-chroma poster hue from a title
  function hueOf(s) { let h = 0; for (let i = 0; i < s.length; i++) h = (h * 31 + s.charCodeAt(i)) % 360; return h; }

  function fmtDur(totalMin) {
    const h = Math.floor(totalMin / 60), m = totalMin % 60;
    if (h && m) return h + "h " + String(m).padStart(2, "0") + "m";
    if (h) return h + "h";
    return m + "m";
  }

  // ---- Overlay scroll region — hides native bar (no reflow when it appears),
  //      shows a subtle thumb only while scrolling, fading out when idle. ------
  function ScrollArea({ children, innerStyle, scrollerRef }) {
    const local = React.useRef(null);
    const timer = React.useRef(null);
    const [thumb, setThumb] = React.useState(null);
    const setRef = (n) => { local.current = n; if (scrollerRef) scrollerRef.current = n; };
    const update = () => {
      const el = local.current; if (!el) return;
      const { scrollTop, scrollHeight, clientHeight } = el;
      if (scrollHeight <= clientHeight + 2) { setThumb(null); return; }
      const track = clientHeight - 8;
      const h = Math.max(28, track * clientHeight / scrollHeight);
      const top = 4 + (track - h) * (scrollTop / (scrollHeight - clientHeight));
      setThumb({ top, h });
      clearTimeout(timer.current);
      timer.current = setTimeout(() => setThumb((t) => (t ? { ...t, hidden: true } : null)), 850);
    };
    React.useEffect(() => { const id = setTimeout(update, 60); return () => { clearTimeout(id); clearTimeout(timer.current); }; }, []);
    return (
      <div style={{ position: "relative", flex: 1, minHeight: 0, minWidth: 0 }}>
        <div ref={setRef} onScroll={update} className="ctv-hide-sb"
          style={{ height: "100%", overflowY: "auto", overflowX: "hidden", scrollbarWidth: "none", scrollBehavior: "smooth", ...innerStyle }}>
          {children}
        </div>
        {thumb && (
          <div style={{ position: "absolute", top: thumb.top, right: 2, width: 4, height: thumb.h, borderRadius: 3,
            background: "var(--text-secondary)", opacity: thumb.hidden ? 0 : 0.5,
            transition: "opacity 260ms var(--ease-standard, ease)", pointerEvents: "none" }} />
        )}
      </div>
    );
  }

  // ---- Segmented control — iOS-style sliding active highlight ---------------
  function Segmented({ value, options, onChange, style }) {
    const idx = Math.max(0, options.findIndex((o) => o.value === value));
    return (
      <div style={{ position: "relative", display: "grid", gridAutoFlow: "column", gridAutoColumns: "1fr", padding: 2, borderRadius: "var(--radius-sm)", background: "var(--ctv-bg-sunken)", border: "1px solid var(--border-hairline)", ...style }}>
        <div style={{ position: "absolute", top: 2, bottom: 2, left: 2, width: `calc((100% - 4px) / ${options.length})`, transform: `translateX(${idx * 100}%)`, background: "var(--ctv-surface-3)", borderRadius: "var(--radius-xs)", boxShadow: "var(--shadow-sm)", transition: "transform 300ms cubic-bezier(0.16,1,0.3,1)", pointerEvents: "none" }} />
        {options.map((o) => {
          const on = o.value === value;
          return (
            <button key={o.value} type="button" title={o.title || o.label} onClick={() => onChange(o.value)}
              style={{ position: "relative", zIndex: 1, display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 6, padding: "5px 10px", border: "none", background: "transparent", cursor: "pointer",
                color: on ? "var(--text-primary)" : "var(--text-secondary)", transition: "color 220ms cubic-bezier(0.16,1,0.3,1)", font: "var(--weight-medium) var(--text-2xs)/1 var(--font-sans)" }}>
              {o.icon && <Ico n={o.icon} s={13} />}{o.label}
            </button>
          );
        })}
      </div>
    );
  }

  // ---- Poster placeholder (striped, tinted, mono meta) ----------------------
  function Poster({ item, w, h, mini }) {
    const hue = hueOf(item.title);
    return (
      <div style={{
        position: "relative", width: w, height: h, flex: "0 0 auto", overflow: "hidden",
        borderRadius: "var(--radius-sm)", border: "1px solid var(--border-hairline)",
        background: `linear-gradient(160deg, hsl(${hue} 24% 17%), hsl(${hue} 26% 12%))`,
      }}>
        <div style={{ position: "absolute", inset: 0, backgroundImage: `repeating-linear-gradient(135deg, hsl(${hue} 22% 10% / .55) 0 1px, transparent 1px 9px)` }} />
        <div style={{ position: "absolute", top: mini ? 4 : 7, left: mini ? 4 : 7, display: "inline-flex", color: `hsl(${hue} 30% 68%)` }}>
          <Ico n={TYPE_ICON[item.type] || "Film"} s={mini ? 12 : 15} />
        </div>
        {!mini && (
          <div style={{ position: "absolute", left: 0, right: 0, bottom: 0, padding: "18px 8px 8px", background: "linear-gradient(to top, rgba(11,13,17,.92), transparent)" }}>
            <div style={{ font: "var(--weight-semibold) var(--text-xs)/1.15 var(--font-sans)", color: "var(--text-primary)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{item.title}</div>
            <div style={{ marginTop: 3, ...mono, font: "var(--text-2xs)/1 var(--font-mono)", color: "var(--text-secondary)" }}>{item.sub}</div>
          </div>
        )}
      </div>
    );
  }

  // ---- Library card ----------------------------------------------------------
  function LibCard({ item, added, compact, onAdd, onDragStart, onDragEnd }) {
    if (compact) {
      return (
        <div draggable onDragStart={onDragStart} onDragEnd={onDragEnd} onDoubleClick={onAdd} title="Double-click or drag to add" className="ctv-press"
          style={{ display: "flex", alignItems: "center", gap: 10, padding: "6px 8px", borderRadius: "var(--radius-sm)", cursor: "grab",
            background: added ? "color-mix(in srgb, var(--action-primary) 14%, transparent)" : "var(--surface-card)", border: `1px solid ${added ? "color-mix(in srgb, var(--action-primary) 35%, transparent)" : "var(--border-hairline)"}` }}>
          <Poster item={item} w={30} h={40} mini />
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ font: "var(--weight-medium) var(--text-xs)/1.15 var(--font-sans)", color: "var(--text-primary)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{item.title}</div>
            <div style={{ marginTop: 2, font: "var(--text-2xs)/1 var(--font-sans)", color: "var(--text-secondary)" }}>{item.type} · <span style={mono}>{item.sub}</span></div>
          </div>
          <IconButton size="sm" title={added ? "Added" : "Add to lineup"} onClick={onAdd}>
            <Ico n={added ? "Check" : "Plus"} s={15} color={added ? "var(--action-primary)" : undefined} />
          </IconButton>
        </div>
      );
    }
    return (
      <div draggable onDragStart={onDragStart} onDragEnd={onDragEnd} onDoubleClick={onAdd} title="Double-click or drag to add" className="ctv-lift"
        style={{ position: "relative", cursor: "grab" }}>
        <div style={{ position: "relative", borderRadius: "var(--radius-sm)", boxShadow: added ? "0 0 0 2px var(--action-primary)" : "none" }}>
          <Poster item={item} w="100%" h={150} />
          {added && (
            <div style={{ position: "absolute", top: 6, right: 6, width: 22, height: 22, borderRadius: "50%", background: "var(--action-primary)", color: "var(--text-on-accent)", display: "flex", alignItems: "center", justifyContent: "center", boxShadow: "var(--shadow-sm)", animation: "ctv-pop 260ms cubic-bezier(0.16,1,0.3,1)" }}>
              <Ico n="Check" s={14} />
            </div>
          )}
        </div>
      </div>
    );
  }

  // ---- Lineup row ------------------------------------------------------------
  function LineupRow({ item, index, shuffle, dragging, isOver, onRemove, dragProps }) {
    return (
      <div {...dragProps} className="ctv-lift"
        style={{ display: "flex", alignItems: "center", gap: 11, padding: "9px 10px", borderRadius: "var(--radius-md)",
          background: "var(--surface-card)", border: "1px solid var(--border-hairline)",
          boxShadow: isOver ? "0 -2px 0 var(--action-primary)" : "none", opacity: dragging ? 0.35 : 1,
          transition: "opacity var(--dur-fast)" }}>
        <span style={{ display: "inline-flex", cursor: "grab", color: "var(--text-faint)", flex: "0 0 auto" }} title="Drag to reorder"><Ico n="GripVertical" s={16} /></span>
        <span style={{ width: 22, flex: "0 0 auto", textAlign: "center" }}>
          {shuffle
            ? <Ico n="Shuffle" s={13} color="var(--text-disabled)" />
            : <span style={{ ...mono, font: "var(--weight-medium) var(--text-xs)/1 var(--font-mono)", color: "var(--text-secondary)" }}>{index + 1}</span>}
        </span>
        <Poster item={item} w={34} h={46} mini />
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ font: "var(--weight-semibold) var(--text-sm)/1.2 var(--font-sans)", color: "var(--text-primary)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{item.title}</div>
          <div style={{ marginTop: 2, font: "var(--text-2xs)/1 var(--font-sans)", color: "var(--text-secondary)" }}>{item.type} · {item.library}</div>
        </div>
        <span style={{ ...mono, font: "var(--text-2xs)/1 var(--font-mono)", color: "var(--text-disabled)", flex: "0 0 auto" }}>{fmtDur(item.min)}</span>
        <IconButton size="sm" title="Remove" onClick={onRemove}><Ico n="X" s={15} /></IconButton>
      </div>
    );
  }

  // ---- Channel image dropzone + live logo/bug preview -----------------------
  function ImagePanel({ logoSrc, setLogoSrc, name }) {
    const [sep, setSep] = React.useState(false);
    const [over, setOver] = React.useState(false);
    const fileRef = React.useRef(null);
    const read = (file) => { if (!file) return; const r = new FileReader(); r.onload = () => setLogoSrc(r.result); r.readAsDataURL(file); };
    return (
      <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
        <div
          onDragOver={(e) => { e.preventDefault(); setOver(true); }}
          onDragLeave={() => setOver(false)}
          onDrop={(e) => { e.preventDefault(); setOver(false); read(e.dataTransfer.files && e.dataTransfer.files[0]); }}
          onClick={() => fileRef.current && fileRef.current.click()}
          style={{ display: "flex", gap: 12, padding: 12, borderRadius: "var(--radius-sm)", cursor: "pointer",
            background: "var(--ctv-bg-sunken)", border: `1px dashed ${over ? "var(--ctv-accent)" : "var(--border-control)"}` }}>
          <ChannelLogo name={name || "New Channel"} src={logoSrc} size={52} radius="var(--radius-sm)" />
          <div style={{ flex: 1, minWidth: 0, display: "flex", flexDirection: "column", justifyContent: "center", gap: 3 }}>
            <div style={{ font: "var(--weight-medium) var(--text-xs)/1 var(--font-sans)", color: "var(--text-primary)" }}>{logoSrc ? "Channel image set" : "Drop channel image"}</div>
            <div style={{ font: "var(--text-2xs)/1.35 var(--font-sans)", color: "var(--text-secondary)" }}>Used as both the guide logo and the on-screen bug.</div>
          </div>
          <input ref={fileRef} type="file" accept="image/*" style={{ display: "none" }} onChange={(e) => read(e.target.files && e.target.files[0])} />
        </div>

        {/* live preview: listing logo + on-screen bug */}
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10 }}>
          <div style={{ padding: 10, borderRadius: "var(--radius-sm)", background: "var(--surface-card)", border: "1px solid var(--border-hairline)" }}>
            <div style={{ ...eyebrow, marginBottom: 8 }}>Guide logo</div>
            <div style={{ display: "flex", alignItems: "center", gap: 9 }}>
              <ChannelLogo name={name || "New Channel"} src={logoSrc} size={30} radius="var(--radius-xs)" />
              <div style={{ minWidth: 0 }}>
                <div style={{ font: "var(--weight-medium) var(--text-2xs)/1.1 var(--font-sans)", color: "var(--text-primary)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{name || "New Channel"}</div>
                <div style={{ ...mono, font: "9px/1 var(--font-mono)", color: "var(--text-disabled)" }}>listing</div>
              </div>
            </div>
          </div>
          <div style={{ padding: 10, borderRadius: "var(--radius-sm)", background: "var(--surface-card)", border: "1px solid var(--border-hairline)" }}>
            <div style={{ ...eyebrow, marginBottom: 8 }}>On-screen bug</div>
            <div style={{ position: "relative", height: 42, borderRadius: "var(--radius-xs)", overflow: "hidden", background: "linear-gradient(160deg,#1a1d24,#0e1014)", backgroundImage: "repeating-linear-gradient(135deg, rgba(255,255,255,.03) 0 1px, transparent 1px 7px)" }}>
              <div style={{ position: "absolute", bottom: 5, right: 5, opacity: 0.9 }}>
                <ChannelLogo name={name || "New Channel"} src={logoSrc} size={22} radius="3px" />
              </div>
            </div>
          </div>
        </div>

        <button type="button" onClick={() => setSep((s) => !s)}
          style={{ alignSelf: "flex-start", display: "inline-flex", alignItems: "center", gap: 5, background: "none", border: "none", cursor: "pointer", padding: "2px 0", font: "var(--text-2xs)/1 var(--font-sans)", color: "var(--text-secondary)" }}>
          <Ico n={sep ? "ChevronDown" : "ChevronRight"} s={13} />Set logo & bug separately
        </button>
        {sep && (
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10, padding: 10, borderRadius: "var(--radius-sm)", background: "var(--ctv-bg-sunken)", border: "1px solid var(--border-hairline)" }}>
            <Button size="sm" variant="secondary" startIcon={<Ico n="Image" s={14} />} onClick={() => fileRef.current && fileRef.current.click()}>Logo image</Button>
            <Button size="sm" variant="secondary" startIcon={<Ico n="Image" s={14} />} onClick={() => fileRef.current && fileRef.current.click()}>Bug image</Button>
          </div>
        )}
      </div>
    );
  }

  // ---- Advanced disclosure — one-click Override (edit) or View defaults ------
  function Advanced({ templateName, scrollerRef }) {
    const [mode, setMode] = React.useState("closed"); // closed | view | override
    const [vals, setVals] = React.useState(() => { const o = {}; ADV.forEach((g) => g.fields.forEach(([k, v]) => { o[k] = v; })); return o; });
    const override = mode === "override";
    const count = ADV.reduce((n, g) => n + g.fields.length, 0);
    const fieldsRef = React.useRef(null);
    const rootRef = React.useRef(null);
    const [maxH, setMaxH] = React.useState(0);
    React.useLayoutEffect(() => {
      if (mode === "closed") setMaxH(0);
      else if (fieldsRef.current) setMaxH(fieldsRef.current.scrollHeight);
    }, [mode]);
    const toggle = (m) => {
      const next = mode === m ? "closed" : m;
      setMode(next);
      if (next !== "closed" && scrollerRef && scrollerRef.current && rootRef.current) {
        const sc = scrollerRef.current;
        requestAnimationFrame(() => {
          const target = sc.scrollTop + rootRef.current.getBoundingClientRect().top - sc.getBoundingClientRect().top - 20;
          sc.scrollTo({ top: Math.max(0, target), behavior: "smooth" });
        });
      }
    };
    const tabBtn = (active) => ({
      display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 6, padding: "8px 10px",
      borderRadius: "var(--radius-sm)", cursor: "pointer", font: "var(--weight-medium) var(--text-xs)/1 var(--font-sans)",
      background: active ? "color-mix(in srgb, var(--action-primary) 14%, transparent)" : "var(--ctv-surface-2)",
      color: active ? "var(--action-primary)" : "var(--text-secondary)",
      border: `1px solid ${active ? "color-mix(in srgb, var(--action-primary) 38%, transparent)" : "var(--border-hairline)"}`,
      transition: "background 200ms cubic-bezier(0.16,1,0.3,1), color 200ms cubic-bezier(0.16,1,0.3,1), border-color 200ms cubic-bezier(0.16,1,0.3,1)",
    });
    return (
      <div ref={rootRef} style={{ borderTop: "1px solid var(--border-hairline)", paddingTop: 14 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 9, marginBottom: 10 }}>
          <Ico n="SlidersHorizontal" s={16} color="var(--text-secondary)" />
          <span style={{ font: "var(--weight-medium) var(--text-sm)/1 var(--font-sans)", color: "var(--text-primary)" }}>Advanced</span>
          <span style={{ flex: 1 }} />
          <span style={{ ...mono, font: "var(--text-2xs)/1 var(--font-mono)", color: "var(--text-disabled)" }}>{count} fields · {templateName}</span>
        </div>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8 }}>
          <button type="button" onClick={() => toggle("override")} style={tabBtn(override)}>
            <Ico n="SquarePen" s={14} />{override ? "Overriding" : "Override settings"}
          </button>
          <button type="button" onClick={() => toggle("view")} style={tabBtn(mode === "view")}>
            <Ico n="Eye" s={14} />View defaults
          </button>
        </div>
        <div style={{ overflow: "hidden", maxHeight: maxH, transition: "max-height 340ms cubic-bezier(0.16,1,0.3,1)" }}>
          <div ref={fieldsRef} style={{ marginTop: 12, display: "flex", flexDirection: "column", gap: 14 }}>
            <div style={{ display: "flex", alignItems: "center", gap: 8, font: "var(--text-2xs)/1.35 var(--font-sans)", color: "var(--text-secondary)" }}>
              <Ico n="Info" s={13} color={override ? "var(--action-primary)" : "var(--text-disabled)"} />
              {override ? "Editing these overrides the template for this channel only." : `Read-only — inherited from the ${templateName} template. Turn on Override to edit.`}
            </div>
            {ADV.map((g) => (
              <div key={g.group}>
                <div style={{ ...eyebrow, marginBottom: 8 }}>{g.group}</div>
                {override ? (
                  <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8 }}>
                    {g.fields.map(([k]) => (
                      <Input key={k} size="sm" label={k} value={vals[k]} onChange={(e) => setVals((s) => ({ ...s, [k]: e.target.value }))} />
                    ))}
                  </div>
                ) : (
                  <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8 }}>
                    {g.fields.map(([k, v]) => (
                      <div key={k} style={{ padding: "7px 9px", borderRadius: "var(--radius-xs)", background: "var(--ctv-bg-sunken)", border: "1px solid var(--border-hairline)", opacity: 0.72 }}>
                        <div style={{ font: "var(--text-2xs)/1 var(--font-sans)", color: "var(--text-disabled)" }}>{k}</div>
                        <div style={{ marginTop: 3, font: "var(--weight-medium) var(--text-xs)/1 var(--font-sans)", color: "var(--text-primary)", ...(/\d/.test(v) ? mono : {}) }}>{v}</div>
                      </div>
                    ))}
                  </div>
                )}
              </div>
            ))}
          </div>
        </div>
      </div>
    );
  }

  // ---- Main ------------------------------------------------------------------
  function ChannelBuilder() {
    const [q, setQ] = React.useState("");
    const [libFilter, setLibFilter] = React.useState("All");
    const [compact, setCompact] = React.useState(false);
    const [lineup, setLineup] = React.useState(() => ["s1", "s2", "s3", "s4"].map((id) => LIB.find((x) => x.id === id)));
    const [name, setName] = React.useState("Retro Cartoons");
    const [number, setNumber] = React.useState("13.1");
    const [shuffle, setShuffle] = React.useState(false);
    const [always, setAlways] = React.useState(true);
    const [logoSrc, setLogoSrc] = React.useState(null);
    const [tpl, setTpl] = React.useState("std");
    const [tplOpen, setTplOpen] = React.useState(false);
    const [source, setSource] = React.useState("library"); // library | collections

    // drag state
    const [dragLib, setDragLib] = React.useState(null);   // library item id being dragged
    const [dragRow, setDragRow] = React.useState(null);   // lineup index being dragged
    const [overRow, setOverRow] = React.useState(null);
    const railScrollerRef = React.useRef(null);

    const addedIds = new Set(lineup.map((i) => i.id));
    const pool = source === "collections" ? COLLECTIONS : LIB;
    const filtered = pool.filter((i) =>
      (source === "collections" || libFilter === "All" || i.library === libFilter) &&
      (!q || i.title.toLowerCase().includes(q.toLowerCase())));

    const add = (item) => setLineup((l) => (l.some((x) => x.id === item.id) ? l : [...l, item]));
    const removeAt = (idx) => setLineup((l) => l.filter((_, i) => i !== idx));
    const totalMin = lineup.reduce((n, i) => n + i.min, 0);
    const template = TEMPLATES.find((t) => t.id === tpl);
    const canCreate = name.trim() && lineup.length > 0;

    // reorder / insert on drop at target index
    const dropAt = (targetIdx) => {
      if (dragRow != null) {
        setLineup((l) => { const n = l.slice(); const [m] = n.splice(dragRow, 1); n.splice(targetIdx, 0, m); return n; });
      } else if (dragLib != null) {
        const item = [...LIB, ...COLLECTIONS].find((x) => x.id === dragLib);
        if (item && !addedIds.has(item.id)) setLineup((l) => { const n = l.slice(); n.splice(targetIdx, 0, item); return n; });
      }
      setDragLib(null); setDragRow(null); setOverRow(null);
    };
    const dropEnd = () => {
      if (dragLib != null) { const item = [...LIB, ...COLLECTIONS].find((x) => x.id === dragLib); if (item) add(item); }
      setDragLib(null); setDragRow(null); setOverRow(null);
    };

    return (
      <div style={{ display: "flex", flexDirection: "column", height: "100%" }}>
        {/* builder toolbar */}
        <div style={{ display: "flex", alignItems: "center", gap: 12, padding: "12px 20px", borderBottom: "1px solid var(--border-hairline)", flex: "0 0 auto" }}>
          <span style={{ display: "inline-flex", alignItems: "center", justifyContent: "center", width: 34, height: 34, borderRadius: "var(--radius-sm)", background: "var(--ctv-accent-soft)", color: "var(--ctv-accent)", flex: "0 0 auto" }}><Ico n="Plus" s={19} /></span>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ font: "var(--weight-semibold) var(--text-md)/1 var(--font-sans)", color: "var(--text-primary)" }}>New Channel</div>
            <div style={{ marginTop: 3, font: "var(--text-xs)/1 var(--font-sans)", color: "var(--text-secondary)" }}>Build from your library — <span style={mono}>{lineup.length}</span> in lineup · <span style={mono}>{fmtDur(totalMin)}</span></div>
          </div>
          <Button variant="ghost">Cancel</Button>
          <Tooltip placement="bottom" label={canCreate ? "Creates the channel, schedule & playout" : "Name the channel and add at least one item"}>
            <Button variant="primary" disabled={!canCreate} startIcon={<Ico n="Check" s={15} />}>Create Channel</Button>
          </Tooltip>
        </div>

        {/* body — library | lineup | settings */}
        <div style={{ flex: 1, minHeight: 0, display: "grid", gridTemplateColumns: "minmax(0,1.2fr) minmax(0,1fr) 304px", gap: 0 }}>
          {/* LEFT — library browser */}
          <section style={{ display: "flex", flexDirection: "column", minHeight: 0, minWidth: 0, overflow: "hidden", borderRight: "1px solid var(--border-hairline)" }}>
            <div style={{ padding: "14px 16px 10px", display: "flex", flexDirection: "column", gap: 10 }}>
              <div style={{ display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap", rowGap: 8 }}>
                <Segmented value={source} onChange={setSource} options={[{ value: "library", label: "Library", icon: "Library" }, { value: "collections", label: "Collections", icon: "FolderTree" }]} />
                <span style={{ flex: 1 }} />
                <Segmented value={compact ? "list" : "grid"} onChange={(v) => setCompact(v === "list")} options={[{ value: "grid", icon: "LayoutGrid", title: "Poster grid" }, { value: "list", icon: "Rows3", title: "Compact list" }]} />
              </div>
              <Input size="sm" value={q} onChange={(e) => setQ(e.target.value)} leadingIcon={<Ico n="Search" s={15} />} placeholder={source === "collections" ? "Search collections\u2026" : "Search shows & movies\u2026"} />
              {source === "library" && (
                <div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>
                  {LIBRARIES.map((l) => {
                    const on = libFilter === l;
                    return (
                      <button key={l} type="button" onClick={() => setLibFilter(l)} className="ctv-press"
                        style={{ padding: "4px 10px", borderRadius: "var(--radius-pill)", cursor: "pointer",
                          font: "var(--weight-medium) var(--text-2xs)/1.4 var(--font-sans)",
                          background: on ? "var(--ctv-accent-soft)" : "var(--ctv-surface-2)",
                          color: on ? "var(--ctv-accent)" : "var(--text-secondary)",
                          border: `1px solid ${on ? "rgba(224,138,60,.35)" : "var(--border-hairline)"}` }}>{l}</button>
                    );
                  })}
                </div>
              )}
            </div>
            <ScrollArea innerStyle={{ padding: "4px 16px 16px" }}>
              {filtered.length === 0 ? (
                <div style={{ padding: "40px 0", textAlign: "center", font: "var(--text-xs)/1.5 var(--font-sans)", color: "var(--text-disabled)" }}>No titles match.</div>
              ) : compact ? (
                <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
                  {filtered.map((item) => (
                    <LibCard key={item.id} item={item} compact added={addedIds.has(item.id)} onAdd={() => add(item)}
                      onDragStart={() => setDragLib(item.id)} onDragEnd={dropEnd} />
                  ))}
                </div>
              ) : (
                <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(104px,1fr))", gap: 10 }}>
                  {filtered.map((item) => (
                    <LibCard key={item.id} item={item} added={addedIds.has(item.id)} onAdd={() => add(item)}
                      onDragStart={() => setDragLib(item.id)} onDragEnd={dropEnd} />
                  ))}
                </div>
              )}
            </ScrollArea>
          </section>

          {/* CENTER — lineup */}
          <section style={{ display: "flex", flexDirection: "column", minHeight: 0, minWidth: 0, overflow: "hidden", borderRight: "1px solid var(--border-hairline)" }}
            onDragOver={(e) => { if (dragLib != null) e.preventDefault(); }}
            onDrop={() => { if (dragLib != null) dropEnd(); }}>
            <div style={{ padding: "14px 16px 10px", display: "flex", alignItems: "center", gap: 10 }}>
              <span style={eyebrow}>Lineup</span>
              <Badge tone={shuffle ? "accent" : "neutral"}><span style={{ display: "inline-flex", alignItems: "center", gap: 4 }}><Ico n={shuffle ? "Shuffle" : "ListOrdered"} s={11} />{shuffle ? "Shuffled" : "Sequential"}</span></Badge>
              <span style={{ flex: 1 }} />
              {lineup.length > 0 && <button type="button" onClick={() => setLineup([])} style={{ background: "none", border: "none", cursor: "pointer", font: "var(--text-2xs)/1 var(--font-sans)", color: "var(--text-secondary)" }}>Clear</button>}
            </div>
            <ScrollArea innerStyle={{ padding: "4px 16px 16px" }}>
              {lineup.length === 0 ? (
                <div style={{ height: "100%", minHeight: 220, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", gap: 12, textAlign: "center",
                  border: `1px dashed ${dragLib != null ? "var(--ctv-accent)" : "var(--border-control)"}`, borderRadius: "var(--radius-md)",
                  background: dragLib != null ? "var(--ctv-accent-soft)" : "transparent", color: "var(--text-disabled)", padding: 24 }}>
                  <Ico n="ListVideo" s={26} />
                  <div style={{ font: "var(--text-sm)/1.5 var(--font-sans)", maxWidth: 240 }}>This channel has no content yet. Double-click or drag titles from the library to build the lineup.</div>
                </div>
              ) : (
                <div style={{ display: "flex", flexDirection: "column", gap: 7 }}>
                  {lineup.map((item, idx) => (
                    <LineupRow key={item.id + "-" + idx} item={item} index={idx} shuffle={shuffle}
                      dragging={dragRow === idx} isOver={overRow === idx && (dragRow !== idx)}
                      onRemove={() => removeAt(idx)}
                      dragProps={{
                        draggable: true,
                        onDragStart: () => setDragRow(idx),
                        onDragEnd: () => { setDragRow(null); setOverRow(null); },
                        onDragOver: (e) => { e.preventDefault(); setOverRow(idx); },
                        onDrop: (e) => { e.stopPropagation(); dropAt(idx); },
                      }} />
                  ))}
                  <div style={{ marginTop: 4, padding: "10px 12px", borderRadius: "var(--radius-md)", border: "1px dashed var(--border-hairline)", display: "flex", alignItems: "center", gap: 8, color: "var(--text-disabled)", font: "var(--text-2xs)/1 var(--font-sans)" }}>
                    <Ico n="Plus" s={14} />Double-click or drag more titles to add
                  </div>
                </div>
              )}
            </ScrollArea>
          </section>

          {/* RIGHT — friendly options + template + advanced */}
          <aside style={{ position: "relative", minWidth: 0, overflow: "hidden", display: "flex", flexDirection: "column", background: "var(--surface-card)" }}>
            <ScrollArea scrollerRef={railScrollerRef} innerStyle={{ padding: "14px 16px 24px", display: "flex", flexDirection: "column", gap: 16 }}>
            <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
              <Input label="Channel name" value={name} onChange={(e) => setName(e.target.value)} placeholder="e.g. Retro Cartoons" />
              <Input label="Number" value={number} onChange={(e) => setNumber(e.target.value)}
                trailing={<span style={{ ...mono, font: "9px/1 var(--font-mono)", padding: "2px 5px", borderRadius: "3px", background: "var(--ctv-accent-soft)", color: "var(--ctv-accent)" }}>AUTO</span>} />
            </div>

            <ImagePanel logoSrc={logoSrc} setLogoSrc={setLogoSrc} name={name} />

            {/* friendly toggles */}
            <div style={{ display: "flex", flexDirection: "column", gap: 4 }}>
              <label onClick={() => setShuffle((s) => !s)} style={{ display: "flex", alignItems: "flex-start", gap: 11, padding: "10px 0", cursor: "pointer" }}>
                <div style={{ flex: 1 }}>
                  <div style={{ display: "flex", alignItems: "center", gap: 7 }}>
                    <span style={{ font: "var(--weight-medium) var(--text-sm)/1.2 var(--font-sans)", color: "var(--text-primary)" }}>Shuffle</span>
                    {shuffle !== template.shuffle && <span style={{ font: "var(--text-2xs)/1 var(--font-sans)", color: "var(--text-disabled)", padding: "2px 6px", borderRadius: "var(--radius-xs)", background: "var(--ctv-surface-2)", border: "1px solid var(--border-hairline)" }}>overrides template</span>}
                  </div>
                  <div style={{ marginTop: 2, font: "var(--text-2xs)/1.35 var(--font-sans)", color: "var(--text-secondary)" }}>{shuffle ? "Plays in a random order." : "Plays in sequence (chronological)."}</div>
                </div>
                <Switch checked={shuffle} onChange={setShuffle} />
              </label>
              <div style={{ height: 1, background: "var(--border-hairline)" }} />
              <label onClick={() => setAlways((s) => !s)} style={{ display: "flex", alignItems: "flex-start", gap: 10, padding: "10px 11px", borderRadius: "var(--radius-sm)", cursor: "pointer",
                background: always ? "var(--ctv-live-soft)" : "transparent", border: `1px solid ${always ? "var(--ctv-live)" : "transparent"}`, transition: "background 240ms cubic-bezier(0.16,1,0.3,1), border-color 240ms cubic-bezier(0.16,1,0.3,1)" }}>
                <span style={{ display: "inline-flex", marginTop: 1, color: "var(--ctv-live)", flex: "0 0 auto" }}><Ico n="Radio" s={16} /></span>
                <div style={{ flex: 1 }}>
                  <div style={{ display: "flex", alignItems: "center", gap: 7 }}>
                    <span style={{ font: "var(--weight-medium) var(--text-sm)/1.2 var(--font-sans)", color: "var(--text-primary)" }}>Always playing</span>
                    {always !== template.always && <span style={{ font: "var(--text-2xs)/1 var(--font-sans)", color: "var(--text-disabled)", padding: "2px 6px", borderRadius: "var(--radius-xs)", background: "var(--ctv-surface-2)", border: "1px solid var(--border-hairline)" }}>overrides template</span>}
                    {always && (
                      <span style={{ display: "inline-flex", alignItems: "center", gap: 4, padding: "2px 7px", borderRadius: "var(--radius-pill)", background: "var(--ctv-live-soft)", color: "var(--ctv-live)", font: "var(--weight-semibold) 9px/1.4 var(--font-sans)", letterSpacing: ".06em" }}>
                        <span style={{ width: 5, height: 5, borderRadius: "50%", background: "var(--ctv-live)" }} />LIVE
                      </span>
                    )}
                  </div>
                  <div style={{ marginTop: 3, font: "var(--text-2xs)/1.35 var(--font-sans)", color: "var(--text-secondary)" }}>Like live TV — advances on schedule even when nobody is watching.</div>
                </div>
                <Switch checked={always} onChange={setAlways} />
              </label>
            </div>

            {/* Channel Template */}
            <div>
              <div style={{ ...eyebrow, marginBottom: 8 }}>Channel Template</div>
              <button type="button" onClick={() => setTplOpen((o) => !o)} className="ctv-press"
                style={{ width: "100%", display: "flex", alignItems: "center", gap: 10, padding: "10px 11px", borderRadius: "var(--radius-sm)", cursor: "pointer", textAlign: "left",
                  background: "var(--ctv-bg-sunken)", border: "1px solid var(--border-control)" }}>
                <span style={{ display: "inline-flex", alignItems: "center", justifyContent: "center", width: 30, height: 30, borderRadius: "var(--radius-xs)", background: "var(--ctv-surface-3)", color: "var(--ctv-accent)", flex: "0 0 auto" }}><Ico n="SlidersHorizontal" s={15} /></span>
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ display: "flex", alignItems: "center", gap: 6 }}>
                    <span style={{ font: "var(--weight-medium) var(--text-sm)/1 var(--font-sans)", color: "var(--text-primary)" }}>{template.name}</span>
                    {!template.builtin && <Badge tone="neutral">Custom</Badge>}
                  </div>
                  <div style={{ marginTop: 3, font: "var(--text-2xs)/1.3 var(--font-sans)", color: "var(--text-secondary)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{template.desc}</div>
                </div>
                <Ico n={tplOpen ? "ChevronUp" : "ChevronDown"} s={15} color="var(--text-disabled)" />
              </button>

              {tplOpen && (
                <div style={{ marginTop: 6, display: "flex", flexDirection: "column", gap: 4, padding: 4, borderRadius: "var(--radius-sm)", background: "var(--ctv-bg-sunken)", border: "1px solid var(--border-hairline)" }}>
                  {TEMPLATES.map((t) => {
                    const on = t.id === tpl;
                    return (
                      <button key={t.id} type="button" className="ctv-press" onClick={() => { setTpl(t.id); setTplOpen(false); setShuffle(t.shuffle); setAlways(t.always); }}
                        style={{ display: "flex", alignItems: "center", gap: 9, padding: "8px 9px", borderRadius: "var(--radius-xs)", cursor: "pointer", textAlign: "left",
                          background: on ? "color-mix(in srgb, var(--action-primary) 14%, transparent)" : "transparent", border: "none" }}>
                        <Ico n={on ? "CircleCheck" : "Circle"} s={15} color={on ? "var(--action-primary)" : "var(--text-disabled)"} />
                        <div style={{ flex: 1, minWidth: 0 }}>
                          <div style={{ display: "flex", alignItems: "center", gap: 6 }}>
                            <span style={{ font: "var(--weight-medium) var(--text-xs)/1 var(--font-sans)", color: "var(--text-primary)" }}>{t.name}</span>
                            {!t.builtin && <Badge tone="neutral">Custom</Badge>}
                          </div>
                          <div style={{ marginTop: 2, font: "var(--text-2xs)/1.3 var(--font-sans)", color: "var(--text-secondary)" }}>{t.desc}</div>
                        </div>
                      </button>
                    );
                  })}
                  <button type="button" style={{ display: "flex", alignItems: "center", gap: 7, padding: "8px 9px", borderRadius: "var(--radius-xs)", cursor: "pointer", background: "none", border: "none", color: "var(--text-secondary)", font: "var(--weight-medium) var(--text-xs)/1 var(--font-sans)" }}>
                    <Ico n="Save" s={14} />Save current settings as template…
                  </button>
                </div>
              )}

              <div style={{ marginTop: 8, display: "flex", flexWrap: "wrap", gap: 5 }}>
                {template.sets.map((s) => (
                  <span key={s} style={{ padding: "3px 8px", borderRadius: "var(--radius-xs)", background: "var(--ctv-surface-2)", border: "1px solid var(--border-hairline)", font: "var(--text-2xs)/1.4 var(--font-sans)", color: "var(--text-secondary)", ...(/\d/.test(s) ? mono : {}) }}>{s}</span>
                ))}
              </div>
            </div>

            <Advanced templateName={template.name} scrollerRef={railScrollerRef} />
            </ScrollArea>
          </aside>
        </div>
      </div>
    );
  }

  window.CTVChannelBuilder = ChannelBuilder;
})();
