/* ═══════════════════════════════════════════════════════════════════
   Nexus Dashboard — icon set

   Replaces the 1,636 emoji that were the dashboard's entire icon system.
   Emoji are banned by the design directive, and lucide (the obvious
   replacement) is banned too, so these are hand-drawn: one 24x24 grid,
   1.5px strokes, square caps, `currentColor` throughout. They inherit text
   colour, so a status hue set on the parent flows into the mark and no icon
   ever needs its own colour rule.

   56 icons for 145 distinct emoji, on purpose. Three different "send" glyphs
   and four different "chart" glyphs were never three and four ideas; the
   consolidation is the point. ~7 KB of path data, smaller than one woff2.

   FILE NAME IS LOAD-BEARING. `dashboard-` puts this inside both
   check-dashboard-refs.js (/^dashboard/) and check-css-classes.js
   (/^dashboard.*\.js$/). A file called icons.js would be scanned by neither,
   which is a coverage hole rather than a convenience.

   THREE top-level declarations, deliberately: ICON_PATHS, icon, iconHtml.
   check-dashboard-refs.js reports new top-level names for review, and
   ICON_PATHS references nothing, so it cannot create a load-order hazard.
   Per-icon lookup tables (TOAST_ICON, ST_ICON) live inside their consuming
   functions to hold the count at three.

   Classic script, no import/export — it loads via <script src> in both
   dashboard.html and app.html, first in the dashboard*.js block.
   ═══════════════════════════════════════════════════════════════════ */

const ICON_PATHS = {
  // ── status + feedback (replaces ✓ ✅ ❌ ⚠ ✕ ✗ 🟢 🔴 🟡 🛑) ──
  check: "M4 12.5l5 5L20 6.5",
  x: "M6 6l12 12M18 6L6 18",
  alert: "M12 3.5l9 16.5H3zM12 10v4.5M12 17.5v.01",
  info: "M12 21a9 9 0 100-18 9 9 0 000 18M12 11.5v5.5M12 7.5v.01",
  clock: "M12 21a9 9 0 100-18 9 9 0 000 18M12 7v5.2l3.5 2",
  stop: "M6.5 6.5h11v11h-11z",
  pause: "M9.5 5v14M14.5 5v14",
  play: "M8 5l11 7-11 7z",

  // ── navigation ──
  home: "M4 11l8-7 8 7M6.5 9.3V20h11V9.3",
  search: "M11 19a8 8 0 100-16 8 8 0 000 16M21 21l-4.6-4.6",
  filter: "M4 5h16l-6.2 7.2V20l-3.6-2v-5.8z",
  inbox: "M3 13.5h5l1.5 3h5l1.5-3h5M4.5 13.5l2.8-8h9.4l2.8 8V20H4.5z",
  folder: "M3 6h6l2 2.5h10V19.5H3z",
  book: "M4 5.5A2.5 2.5 0 016.5 3H20v15H6.5A2.5 2.5 0 004 20.5zM4 20.5A2.5 2.5 0 016.5 18H20v3H6.5",
  external: "M14 4h6v6M20 4l-8.5 8.5M18 14v5.5H4.5V6H10",

  // ── people + orgs (replaces 👥 👤 🏢) ──
  users:
    "M8.5 11a3.4 3.4 0 100-6.8 3.4 3.4 0 000 6.8M2.5 20c0-3.3 2.7-5.5 6-5.5s6 2.2 6 5.5M16.5 11.2a3 3 0 100-6M17.5 15.2c2.5.5 4 2.3 4 4.8",
  user: "M12 11.5a4 4 0 100-8 4 4 0 000 8M4.5 20.5c0-3.7 3.4-6.2 7.5-6.2s7.5 2.5 7.5 6.2",
  building: "M4 20.5V5l8-2.2V20.5M12 20.5V9.5l8 2.2v8.8M7 8.5v.01M7 12.5v.01M7 16.5v.01",

  // ── channels (replaces 🐦 ✉ 📧 ✈ 💼 💬) ──
  mail: "M3 6h18v12H3zM3.5 6.5l8.5 6.6 8.5-6.6",
  send: "M21 3L10.5 13.5M21 3l-6.8 18-3.7-7.5L3 9.8z",
  message: "M4 5h16v11H9.5L4 20z",
  briefcase: "M3.5 8h17v11.5h-17zM8.5 8V5.5h7V8M3.5 13h17",
  bird: "M20 5.5c-.8.5-1.6.8-2.5 1a4 4 0 00-6.8 3.6C7.4 9.9 4.6 8.3 2.8 5.8a4 4 0 001.2 5.3c-.6 0-1.2-.2-1.8-.5a4 4 0 003.2 3.9c-.6.2-1.2.2-1.8.1a4 4 0 003.7 2.8A8 8 0 013 19.2a11.3 11.3 0 006.1 1.8c7.4 0 11.4-6.1 11.4-11.4v-.5c.8-.6 1.5-1.3 2-2.1-.7.3-1.5.5-2.3.6z",

  // ── work objects ──
  target: "M12 21a9 9 0 100-18 9 9 0 000 18M12 16.5a4.5 4.5 0 100-9 4.5 4.5 0 000 9M12 12v.01",
  chart: "M4 4v16h16M8 17v-4.5M12.5 17V8.5M17 17V11",
  trend: "M4 16l5-5 3.5 3.5L20 7M15.5 7H20v4.5",
  clipboard:
    "M9 4.5h6V7H9zM9.5 5.5H7A1.5 1.5 0 005.5 7v12.5A1.5 1.5 0 007 21h10a1.5 1.5 0 001.5-1.5V7A1.5 1.5 0 0017 5.5h-2.5",
  note: "M5 3.5h9l5 5V20.5H5zM14 3.5v5h5M8.5 13h7M8.5 16.5h4.5",
  save: "M5 4h11l3 3v13H5zM8.5 4v5h7V4M8.5 20v-6h7v6",
  layers: "M12 3l9 5-9 5-9-5zM3 13l9 5 9-5",
  package: "M12 3l8 4.5v9L12 21l-8-4.5v-9zM4.2 7.6L12 12l7.8-4.4M12 12v9",
  money:
    "M12 21a9 9 0 100-18 9 9 0 000 18M12 6.5v11M9.5 9.5c0-1.1 1.1-1.9 2.5-1.9s2.5.8 2.5 1.9-1.1 1.9-2.5 1.9-2.5.9-2.5 2 1.1 1.9 2.5 1.9 2.5-.8 2.5-1.9",

  // ── system ──
  settings:
    "M4 7h9M17.5 7H20M4 12h3.5M12 12h8M4 17h11M19 17h1M15 7a2 2 0 104 0 2 2 0 10-4 0M7.5 12a2 2 0 104 0 2 2 0 10-4 0M13 17a2 2 0 104 0 2 2 0 10-4 0",
  refresh: "M20 12a8 8 0 11-2.4-5.7M20 3.5V8h-4.5",
  shuffle:
    "M4 7h3.5l9 10H20M4 17h3.5l2.2-2.4M16.5 7H20M17.5 4.5L20 7l-2.5 2.5M17.5 14.5L20 17l-2.5 2.5",
  bolt: "M13.5 3L5.5 14H11l-.5 7 8-11H13z",
  bell: "M18 15.5V10.5a6 6 0 10-12 0v5l-2 3h16zM10 21.5h4",
  lock: "M7.5 11V8a4.5 4.5 0 019 0v3M5.5 11h13v9.5h-13zM12 14.5V17",
  eye: "M2.5 12S6 6.5 12 6.5 21.5 12 21.5 12 18 17.5 12 17.5 2.5 12 2.5 12zM12 15a3 3 0 100-6 3 3 0 000 6",
  pin: "M12 21v-6M8.5 3.5h7l-1 6.2 2.5 2.5V15H7v-2.8l2.5-2.5z",
  plus: "M12 5v14M5 12h14",
  trash: "M4 7h16M9.5 7V4.5h5V7M6.5 7l1 13.5h9L17.5 7M10 11v5.5M14 11v5.5",
  edit: "M4 20h4.2L19.3 8.9a2.2 2.2 0 00-3.2-3.2L5 16.8z",
  download: "M12 4v11M7.5 10.5L12 15l4.5-4.5M4 20h16",
  calendar: "M4 6h16v14.5H4zM4 10.5h16M8.5 3.5V7M15.5 3.5V7",

  // ── domain (replaces 🚀 🤖 🔥 🎯 📣 🌐 🧪 📸 🔗 📡 ⭐) ──
  launch:
    "M12 3c3.4 2.2 5.3 5.6 5.3 9.4L12 18l-5.3-5.6C6.7 8.6 8.6 5.2 12 3zM12 11.5a1.6 1.6 0 100-3.2 1.6 1.6 0 000 3.2M9 18.5L7 21.5M15 18.5l2 3",
  bot: "M12 2.5v3.5M6.5 6h11A2.5 2.5 0 0120 8.5v8.5a2.5 2.5 0 01-2.5 2.5h-11A2.5 2.5 0 014 17V8.5A2.5 2.5 0 016.5 6zM9 11v2.5M15 11v2.5",
  flame:
    "M12.5 3c.6 3.6-3.2 4.9-3.2 8.6 0 1 .4 1.9 1 2.5-1.4-.2-2.4-1.4-2.6-2.9C6.6 12.4 6 14 6 15.6 6 18.6 8.7 21 12 21s6-2.4 6-5.4c0-4.6-4.4-6.7-5.5-12.6z",
  megaphone: "M4 10v4.5h3.2L14 18.5v-13L7.2 10zM17 9.8a4 4 0 010 5",
  globe:
    "M12 21a9 9 0 100-18 9 9 0 000 18M3.2 12h17.6M12 3c2.4 2.5 3.7 5.6 3.7 9S14.4 18.5 12 21M12 3c-2.4 2.5-3.7 5.6-3.7 9S9.6 18.5 12 21",
  flask:
    "M9.5 3h5M11 3v6.2L5.6 19a1.5 1.5 0 001.3 2.2h10.2A1.5 1.5 0 0018.4 19L13 9.2V3M8.5 14.5h7",
  camera: "M4 8h3l1.6-2.2h6.8L17 8h3v11.5H4zM12 16.8a3.6 3.6 0 100-7.2 3.6 3.6 0 000 7.2",
  link: "M10.5 13.5a4.4 4.4 0 006.2 0l2.3-2.3a4.4 4.4 0 00-6.2-6.2L11.6 6M13.5 10.5a4.4 4.4 0 00-6.2 0L5 12.8a4.4 4.4 0 006.2 6.2L12.4 18",
  signal: "M5 17.5a10 10 0 0114 0M8.2 14.5a6 6 0 017.6 0M12 18.5v.01",
  star: "M12 4l2.5 5.2 5.6.8-4 4 1 5.6-5.1-2.7-5.1 2.7 1-5.6-4-4 5.6-.8z",
  help: "M12 21a9 9 0 100-18 9 9 0 000 18M9.6 9.4a2.5 2.5 0 114 2.1c-.9.7-1.6 1.3-1.6 2.5M12 17.5v.01",
};

/**
 * Build an icon element.
 * @param {string} name   key of ICON_PATHS
 * @param {{size?:number,label?:string,cls?:string}} [opts]
 *   label omitted → aria-hidden (decorative, the adjacent text carries meaning)
 *   label given    → role="img" + <title>, for icon-only controls
 * @returns {SVGElement}
 */
function icon(name, opts) {
  const o = opts || {};
  const NS = "http://www.w3.org/2000/svg";
  const svg = document.createElementNS(NS, "svg");
  const size = o.size || 16;
  svg.setAttribute("viewBox", "0 0 24 24");
  svg.setAttribute("width", String(size));
  svg.setAttribute("height", String(size));
  svg.setAttribute("fill", "none");
  svg.setAttribute("stroke", "currentColor");
  svg.setAttribute("stroke-width", "1.5");
  svg.setAttribute("stroke-linecap", "square");
  svg.setAttribute("stroke-linejoin", "miter");
  svg.setAttribute("class", "i" + (o.cls ? " " + o.cls : ""));
  const d = ICON_PATHS[name];
  if (!d) {
    // Visible-to-tooling rather than silently blank: the design gate carries an
    // icon-name-unknown rule so a typo fails the build instead of shipping a
    // 16px hole nobody notices.
    svg.setAttribute("data-icon-missing", String(name));
    return svg;
  }
  const path = document.createElementNS(NS, "path");
  path.setAttribute("d", d);
  svg.appendChild(path);
  if (o.label) {
    svg.setAttribute("role", "img");
    const t = document.createElementNS(NS, "title");
    t.textContent = o.label;
    svg.insertBefore(t, svg.firstChild);
  } else {
    svg.setAttribute("aria-hidden", "true");
  }
  return svg;
}

/**
 * Same mark as a string, for the innerHTML template sites where a Node cannot
 * be inserted (the sidebar builder writes whole rows as HTML).
 * @param {string} name
 * @param {{size?:number}} [opts]
 * @returns {string}
 */
/* ── icon.for(): the bridge from the old emoji icon system ───────────────────
 *
 * 145 distinct emoji were in use against 56 marks, so this map is deliberately
 * many-to-one, and the collapse is the point: nine glyphs meaning "money" was
 * never a design, it was nine people reaching for whatever the picker offered.
 * Recording the decision ONCE here is what stops forty files each guessing again.
 *
 * TWO THINGS ABOUT THE SHAPE OF THIS, both load-bearing:
 *
 * 1. Keyed by CODEPOINT, not by glyph and not by \u escape. The design gate
 *    decodes \uXXXX before matching (that is why the 240 escaped emoji in these
 *    files are not invisible to it), so a table written either of those ways
 *    would itself register as ~70 new emoji findings and fail the ratchet. A
 *    codepoint is also the honest key for a codepoint-to-name map.
 *
 * 2. Hung off icon() rather than declared at top level. This file keeps EXACTLY
 *    three top-level declarations on purpose (see the header), and
 *    check-dashboard-refs.js watches that surface. The map lives in a closure.
 *
 * Returns null when there is no mapping, so a caller falls back to whatever it
 * was rendering before rather than punching a 16px hole in the layout.
 */
icon.for = (function () {
  var BY_CODEPOINT = {
    // people and orgs
    0x1f465: "users",
    0x1f464: "user",
    0x1f91d: "users",
    0x1f3e2: "building",
    0x1f454: "briefcase",
    0x1f4bc: "briefcase",
    // money and value
    0x1f4b0: "money",
    0x1f4b8: "money",
    0x1f4b5: "money",
    0x1f48e: "money",
    0x1f3af: "target",
    // comms
    0x1f4e3: "megaphone",
    0x1f4e2: "megaphone",
    0x1f4ac: "message",
    0x2709: "mail",
    0x1f4e7: "mail",
    0x1f4e5: "inbox",
    0x1f4e4: "send",
    0x1f514: "bell",
    0x1f515: "bell",
    // platforms and reach
    0x1f426: "bird",
    0x1f310: "globe",
    0x1f517: "link",
    0x1f4e1: "signal",
    0x1f6a6: "signal",
    // data and analysis
    0x1f4ca: "chart",
    0x1f4c8: "trend",
    0x1f4c9: "trend",
    0x1f9ec: "flask",
    0x1f9ea: "flask",
    0x1f52c: "flask",
    0x1f50d: "search",
    0x1f50e: "search",
    0x1f4cb: "clipboard",
    0x1f4dd: "note",
    0x1f4c4: "note",
    0x1f4c1: "folder",
    0x1f5c2: "folder",
    0x1f4e6: "package",
    0x1f4da: "book",
    0x1f393: "book",
    0x1f4c5: "calendar",
    0x1f5d3: "calendar",
    0x1f39f: "calendar",
    // state and action
    0x26a1: "bolt",
    0x1f525: "flame",
    0x1f680: "launch",
    0x1f916: "bot",
    0x2699: "settings",
    0x1f527: "settings",
    0x1f504: "refresh",
    0x1f501: "refresh",
    0x1f500: "shuffle",
    0x1f512: "lock",
    0x1f510: "lock",
    0x1f441: "eye",
    0x1f4cc: "pin",
    0x1f4cd: "pin",
    0x2795: "plus",
    0x1f5d1: "trash",
    0x270f: "edit",
    0x1f4be: "save",
    0x2b07: "download",
    0x1f4f8: "camera",
    0x1f4f7: "camera",
    0x1f6aa: "external",
    0x2b50: "star",
    0x2753: "help",
    0x2139: "info",
    0x26a0: "alert",
    0x274c: "x",
    0x2705: "check",
    0x2714: "check",
    0x23f0: "clock",
    0x1f550: "clock",
    0x23f3: "clock",
    0x1f6ab: "stop",
    0x23f8: "pause",
    0x25b6: "play",
    0x1f3e0: "home",
    0x1f9f1: "layers",
    // second pass, from the glyphs the first conversion round surfaced
    0x1f6e1: "lock",
    0x1f39b: "settings",
    0x1f6e0: "settings",
    0x1f575: "search",
    0x1f9e9: "layers",
    0x267e: "refresh",
    0x2764: "star",
    0x1f331: "trend",
    // Deliberately NOT mapped, because no mark in the set means them and a wrong
    // icon is worse than a glyph: U+2708 aeroplane, U+2694 crossed swords,
    // U+21A9 reply arrow. U+1D54F, U+2022 and U+00B7 are letterforms and
    // punctuation rather than emoji, and the gate agrees.
  };
  return function iconFor(value) {
    if (!value) return null;
    if (ICON_PATHS[value]) return value;
    var str = String(value);
    // strip the variation selector some glyphs carry (U+FE0F)
    var cp = str.codePointAt(0);
    return (cp && BY_CODEPOINT[cp]) || null;
  };
})();

function iconHtml(name, opts) {
  const size = (opts && opts.size) || 16;
  const d = ICON_PATHS[name];
  if (!d)
    return (
      '<svg class="i" width="' +
      size +
      '" height="' +
      size +
      '" data-icon-missing="' +
      name +
      '"></svg>'
    );
  return (
    '<svg class="i" viewBox="0 0 24 24" width="' +
    size +
    '" height="' +
    size +
    '" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="square" ' +
    'stroke-linejoin="miter" aria-hidden="true"><path d="' +
    d +
    '"/></svg>'
  );
}
