{"id":1330,"date":"2026-04-16T02:04:53","date_gmt":"2026-04-16T01:04:53","guid":{"rendered":"https:\/\/southsunindustries.com\/?page_id=1330"},"modified":"2026-04-16T02:15:09","modified_gmt":"2026-04-16T01:15:09","slug":"reprocessing-matrix","status":"publish","type":"page","link":"https:\/\/southsunindustries.com\/index.php\/reprocessing-matrix\/","title":{"rendered":"Reprocessing Matrix"},"content":{"rendered":"\n<div id=\"jrm-root\" class=\"jhc\">\n  <div class=\"jhc__header\">\n    <h2 class=\"jhc__title\">Reprocessing Matrix<\/h2>\n    <div class=\"jhc__sub\">\n      View who can reprocess each ore category, and add or update your own entry below.\n    <\/div>\n  <\/div>\n\n  <div class=\"jhc__grid\">\n    <section class=\"jhc__card\">\n      <div class=\"jrm__accordion\">\n        <button class=\"jhc__btn jhc__btn--primary jrm__accordionToggle\" id=\"jrm-toggle\" type=\"button\" aria-expanded=\"false\">\n          Show Guide &#038; Add \/ Update Entry\n        <\/button>\n\n        <div class=\"jrm__accordionPanel\" id=\"jrm-panel\" hidden>\n          <div class=\"jrm__guide\">\n            <div>1. Enter your <b>Discord name<\/b>.<\/div>\n            <div>2. Tick every ore category you can reprocess.<\/div>\n            <div>3. Click <b>Save Entry<\/b>.<\/div>\n            <div>4. If your name already exists, your row will be updated instead of duplicated.<\/div>\n            <div>5. The table below will refresh automatically.<\/div>\n          <\/div>\n\n          <div class=\"jhc__row\">\n            <div class=\"jhc__field\">\n              <label class=\"jhc__label\" for=\"jrm-name\">Discord Name<\/label>\n              <input class=\"jhc__input\" id=\"jrm-name\" type=\"text\" placeholder=\"Enter Discord name\">\n            <\/div>\n          <\/div>\n\n          <div class=\"jhc__row\">\n            <div class=\"jhc__field\">\n              <label class=\"jhc__label\">Ore Types<\/label>\n              <div class=\"jrm__checks\" id=\"jrm-checks\"><\/div>\n            <\/div>\n          <\/div>\n\n          <div class=\"jhc__actions\">\n            <button class=\"jhc__btn jhc__btn--primary\" id=\"jrm-save\" type=\"button\">Save Entry<\/button>\n            <button class=\"jhc__btn\" id=\"jrm-clear\" type=\"button\">Clear Form<\/button>\n\n            <div class=\"jhc__contractBox\" aria-live=\"polite\">\n              <div class=\"jhc__contractTop\">\n                <div>\n                  <div class=\"jhc__contractLabel\">Directory Size<\/div>\n                  <div class=\"jhc__contractToon\" id=\"jrm-count\">\u2014<\/div>\n                <\/div>\n                <button class=\"jhc__contractCopy\" id=\"jrm-refresh\" type=\"button\" title=\"Refresh table\">\n                  Refresh\n                <\/button>\n              <\/div>\n            <\/div>\n          <\/div>\n\n          <div class=\"jhc__status\" id=\"jrm-status\"><\/div>\n        <\/div>\n      <\/div>\n    <\/section>\n  <\/div>\n\n  <section class=\"jhc__card\">\n    <h3 class=\"jhc__h3\">Current Reprocessors<\/h3>\n\n    <div class=\"jrm__tableWrap\">\n      <table class=\"jrm__table\" id=\"jrm-table\">\n        <thead>\n          <tr id=\"jrm-head-row\"><\/tr>\n        <\/thead>\n        <tbody id=\"jrm-body\">\n          <tr>\n            <td colspan=\"12\" class=\"jrm__empty\">Loading data&#8230;<\/td>\n          <\/tr>\n        <\/tbody>\n      <\/table>\n    <\/div>\n\n    <div class=\"jhc__summary\" id=\"jrm-summary\">Loading directory&#8230;<\/div>\n  <\/section>\n<\/div>\n\n<style>\n  .jhc{\n    font-family:system-ui,-apple-system,Segoe UI,Roboto,Arial,sans-serif;\n    color:#e9eef7;\n  }\n\n  .jhc__header{margin-bottom:12px}\n  .jhc__title{\n    margin:0 0 6px;\n    font-size:22px;\n    line-height:1.2;\n    color:#f6f8ff;\n    letter-spacing:.2px;\n    text-shadow:0 1px 0 rgba(0,0,0,.4);\n  }\n  .jhc__sub{color:rgba(233,238,247,.70);font-size:13px}\n\n  .jhc__grid{display:flex;gap:12px;flex-wrap:wrap;margin:12px 0}\n\n  .jhc__card{\n    border:1px solid rgba(255,255,255,.10);\n    border-radius:12px;\n    padding:14px;\n    background:linear-gradient(180deg, rgba(30,40,54,.92), rgba(18,25,35,.92));\n    box-shadow:\n      0 10px 26px rgba(0,0,0,.25),\n      inset 0 1px 0 rgba(255,255,255,.05);\n    flex:1;\n    min-width:280px;\n  }\n\n  .jhc__h3{\n    margin:0 0 8px;\n    font-size:16px;\n    color:#f6f8ff;\n  }\n\n  .jhc__row{display:flex;gap:12px;flex-wrap:wrap}\n  .jhc__field{flex:1;min-width:220px}\n\n  .jhc__label{\n    display:block;\n    color:rgba(233,238,247,.70);\n    font-size:12px;\n    margin-bottom:6px;\n  }\n\n  .jhc__help,\n  .jhc__status,\n  .jhc__summary{\n    color:rgba(233,238,247,.58);\n    font-size:12px;\n  }\n\n  .jhc__status{margin-top:10px;min-height:16px}\n  .jhc__summary{margin-top:10px}\n\n  .jhc__input{\n    width:100%;\n    padding:10px;\n    border:1px solid rgba(255,255,255,.12);\n    border-radius:10px;\n    font:inherit;\n    box-sizing:border-box;\n    background:rgba(8,12,18,.45);\n    color:#e9eef7;\n    outline:none;\n    box-shadow:inset 0 1px 0 rgba(255,255,255,.03);\n    appearance:none;\n  }\n\n  .jhc__input::placeholder{color:rgba(233,238,247,.42)}\n\n  .jhc__input:focus{\n    border-color:rgba(120,170,255,.55);\n    box-shadow:\n      inset 0 1px 0 rgba(255,255,255,.03),\n      0 0 0 4px rgba(120,170,255,.14);\n  }\n\n  .jhc__actions{\n    display:flex;\n    gap:10px;\n    flex-wrap:wrap;\n    align-items:stretch;\n    margin-top:12px;\n  }\n\n  .jhc__btn{\n    padding:10px 14px;\n    border:1px solid rgba(255,255,255,.14);\n    border-radius:10px;\n    background:rgba(8,12,18,.35);\n    color:#e9eef7;\n    cursor:pointer;\n    transition:transform .06s ease, border-color .15s ease, box-shadow .15s ease, background .15s ease;\n  }\n\n  .jhc__btn:hover{\n    background:rgba(8,12,18,.48);\n    border-color:rgba(255,255,255,.22);\n  }\n\n  .jhc__btn:active{transform:translateY(1px)}\n  .jhc__btn:disabled{opacity:.6;cursor:not-allowed}\n\n  .jhc__btn--primary{\n    background:linear-gradient(180deg, rgba(118,168,255,.92), rgba(84,132,225,.92));\n    border-color:rgba(118,168,255,.55);\n    color:#06111f;\n    font-weight:700;\n    box-shadow:0 10px 22px rgba(118,168,255,.18);\n  }\n\n  .jhc__btn--primary:hover{\n    border-color:rgba(118,168,255,.75);\n    box-shadow:0 12px 26px rgba(118,168,255,.24);\n  }\n\n  .jhc__contractBox{\n    display:flex;\n    flex-direction:column;\n    justify-content:center;\n    min-width:260px;\n    padding:10px 14px;\n    border:1px solid rgba(118,168,255,.55);\n    border-radius:10px;\n    background:linear-gradient(180deg, rgba(118,168,255,.18), rgba(84,132,225,.12));\n    box-shadow:\n      0 0 0 1px rgba(118,168,255,.15) inset,\n      0 8px 22px rgba(118,168,255,.16);\n  }\n\n  .jhc__contractTop{\n    display:flex;\n    align-items:center;\n    justify-content:space-between;\n    gap:12px;\n    flex-wrap:wrap;\n  }\n\n  .jhc__contractLabel{\n    font-size:11px;\n    text-transform:uppercase;\n    letter-spacing:.6px;\n    color:rgba(233,238,247,.72);\n    margin-bottom:4px;\n  }\n\n  .jhc__contractToon{\n    font-size:18px;\n    font-weight:800;\n    color:#f6f8ff;\n    line-height:1.2;\n    text-shadow:0 1px 0 rgba(0,0,0,.35);\n  }\n\n  .jhc__contractCopy{\n    padding:8px 12px;\n    border:1px solid rgba(255,255,255,.18);\n    border-radius:10px;\n    background:rgba(8,12,18,.35);\n    color:#e9eef7;\n    cursor:pointer;\n    font-weight:700;\n    transition:transform .06s ease, border-color .15s ease, box-shadow .15s ease, background .15s ease;\n  }\n\n  .jhc__contractCopy:hover{\n    background:rgba(8,12,18,.48);\n    border-color:rgba(118,168,255,.40);\n    box-shadow:0 0 0 4px rgba(120,170,255,.10);\n  }\n\n  .jhc__contractCopy:active{transform:translateY(1px)}\n\n  .jrm__accordionToggle{\n    width:100%;\n    justify-content:center;\n  }\n\n  .jrm__accordionPanel{\n    margin-top:12px;\n  }\n\n  .jrm__guide{\n    color:rgba(233,238,247,.70);\n    font-size:13px;\n    margin-bottom:14px;\n    display:grid;\n    gap:4px;\n  }\n\n  .jrm__checks{\n    display:grid;\n    grid-template-columns:repeat(auto-fit, minmax(220px, 1fr));\n    gap:10px;\n  }\n\n  .jrm__check{\n    display:flex;\n    align-items:flex-start;\n    gap:8px;\n    padding:10px 12px;\n    border:1px solid rgba(255,255,255,.10);\n    border-radius:10px;\n    background:rgba(8,12,18,.25);\n    color:#e9eef7;\n    font-size:13px;\n    line-height:1.35;\n    box-shadow:inset 0 1px 0 rgba(255,255,255,.03);\n  }\n\n  .jrm__check input{\n    margin-top:2px;\n    accent-color:#76a8ff;\n  }\n\n  .jrm__tableWrap{\n    width:100%;\n    overflow-x:auto;\n    border:1px solid rgba(255,255,255,.10);\n    border-radius:12px;\n    background:rgba(8,12,18,.25);\n    box-shadow:inset 0 1px 0 rgba(255,255,255,.04);\n  }\n\n  .jrm__table{\n    width:100%;\n    border-collapse:collapse;\n    min-width:1200px;\n    font-size:13px;\n    color:#e9eef7;\n  }\n\n  .jrm__table thead th{\n    background:linear-gradient(180deg, rgba(98,121,220,.95), rgba(72,93,187,.95));\n    color:#f6f8ff;\n    text-align:center;\n    font-weight:700;\n    padding:10px 8px;\n    border-right:1px solid rgba(255,255,255,.16);\n    border-bottom:1px solid rgba(255,255,255,.14);\n    white-space:nowrap;\n  }\n\n  .jrm__table thead th:first-child{\n    text-align:left;\n    min-width:160px;\n  }\n\n  .jrm__table tbody td{\n    padding:8px 8px;\n    border-right:1px solid rgba(255,255,255,.08);\n    border-bottom:1px solid rgba(255,255,255,.08);\n    background:rgba(255,255,255,.03);\n    text-align:center;\n  }\n\n  .jrm__table tbody td:first-child{\n    text-align:left;\n    font-weight:650;\n    color:#f6f8ff;\n    background:rgba(255,255,255,.05);\n  }\n\n  .jrm__table tbody tr:hover td{\n    background:rgba(118,168,255,.08);\n  }\n\n  .jrm__yes{\n    font-weight:800;\n    color:#f6f8ff;\n  }\n\n  .jrm__empty{\n    text-align:center !important;\n    color:rgba(233,238,247,.58);\n    padding:16px !important;\n  }\n<\/style>\n\n<script>\n(() => {\n  const root = document.getElementById(\"jrm-root\");\n  if (!root) return;\n\n  const JRM_WEB_APP_URL = \"PASTE_YOUR_GOOGLE_APPS_SCRIPT_WEB_APP_URL_HERE\";\n\n  const ORE_HEADERS = [\n    \"Abyssal Ore V\",\n    \"Coherent Ore V\",\n    \"Common Moon Ore V\",\n    \"Complex Ore V\",\n    \"Exceptional Moon Ore V\",\n    \"Mercoxit Ore V\",\n    \"Rare Moon Ore V\",\n    \"Simple Ore V\",\n    \"Ubiquitous Moon Ore V\",\n    \"Uncommon Moon Ore V\",\n    \"Unrefined Minerals V\"\n  ];\n\n  const ALL_HEADERS = [\"Discord Name\", ...ORE_HEADERS];\n\n  const $ = (sel) => root.querySelector(sel);\n\n  const toggleBtn = $(\"#jrm-toggle\");\n  const panelEl = $(\"#jrm-panel\");\n  const nameEl = $(\"#jrm-name\");\n  const checksEl = $(\"#jrm-checks\");\n  const saveBtn = $(\"#jrm-save\");\n  const clearBtn = $(\"#jrm-clear\");\n  const refreshBtn = $(\"#jrm-refresh\");\n  const statusEl = $(\"#jrm-status\");\n  const countEl = $(\"#jrm-count\");\n  const summaryEl = $(\"#jrm-summary\");\n  const headRowEl = $(\"#jrm-head-row\");\n  const bodyEl = $(\"#jrm-body\");\n\n  let currentRows = [];\n\n  function escapeHtml(str) {\n    return String(str ?? \"\").replace(\/[&<>\"']\/g, c => ({\n      \"&\": \"&amp;\",\n      \"<\": \"&lt;\",\n      \">\": \"&gt;\",\n      '\"': \"&quot;\",\n      \"'\": \"&#39;\"\n    }[c]));\n  }\n\n  function setStatus(msg, isError = false) {\n    statusEl.textContent = msg || \"\";\n    statusEl.style.color = isError\n      ? \"rgba(255,220,220,.92)\"\n      : \"rgba(233,238,247,.58)\";\n  }\n\n  function buildHeader() {\n    headRowEl.innerHTML = ALL_HEADERS.map(h => `<th>${escapeHtml(h)}<\/th>`).join(\"\");\n  }\n\n  function buildCheckboxes() {\n    checksEl.innerHTML = ORE_HEADERS.map((ore, index) => `\n      <label class=\"jrm__check\" for=\"jrm-ore-${index}\">\n        <input type=\"checkbox\" id=\"jrm-ore-${index}\" value=\"${escapeHtml(ore)}\">\n        <span>${escapeHtml(ore)}<\/span>\n      <\/label>\n    `).join(\"\");\n  }\n\n  function clearForm() {\n    nameEl.value = \"\";\n    checksEl.querySelectorAll('input[type=\"checkbox\"]').forEach(cb => {\n      cb.checked = false;\n    });\n    setStatus(\"\");\n  }\n\n  function setFormFromRow(row) {\n    clearForm();\n    nameEl.value = row[\"Discord Name\"] || \"\";\n    checksEl.querySelectorAll('input[type=\"checkbox\"]').forEach(cb => {\n      cb.checked = String(row[cb.value] || \"\").trim().toLowerCase() === \"x\";\n    });\n  }\n\n  function getFormData() {\n    const discordName = nameEl.value.trim();\n\n    const data = {\n      \"Discord Name\": discordName\n    };\n\n    ORE_HEADERS.forEach(header => {\n      const checkbox = checksEl.querySelector(`input[value=\"${CSS.escape(header)}\"]`);\n      data[header] = checkbox && checkbox.checked ? \"x\" : \"\";\n    });\n\n    return data;\n  }\n\n  function renderTable(rows) {\n    currentRows = rows.slice();\n\n    countEl.textContent = `${rows.length} ${rows.length === 1 ? \"Member\" : \"Members\"}`;\n    summaryEl.textContent = rows.length\n      ? `Showing ${rows.length} reprocessor${rows.length === 1 ? \"\" : \"s\"}.`\n      : \"No reprocessors found.\";\n\n    if (!rows.length) {\n      bodyEl.innerHTML = `<tr><td colspan=\"${ALL_HEADERS.length}\" class=\"jrm__empty\">No entries found.<\/td><\/tr>`;\n      return;\n    }\n\n    bodyEl.innerHTML = rows.map(row => `\n      <tr data-name=\"${escapeHtml(row[\"Discord Name\"] || \"\")}\">\n        <td>${escapeHtml(row[\"Discord Name\"] || \"\")}<\/td>\n        ${ORE_HEADERS.map(header => {\n          const hasValue = String(row[header] || \"\").trim().toLowerCase() === \"x\";\n          return `<td>${hasValue ? `<span class=\"jrm__yes\">x<\/span>` : \"\"}<\/td>`;\n        }).join(\"\")}\n      <\/tr>\n    `).join(\"\");\n  }\n\n  async function loadRows() {\n    setStatus(\"Loading directory...\");\n\n    try {\n      const response = await fetch(JRM_WEB_APP_URL, {\n        method: \"GET\"\n      });\n\n      if (!response.ok) {\n        throw new Error(`HTTP ${response.status}`);\n      }\n\n      const data = await response.json();\n\n      if (!Array.isArray(data)) {\n        throw new Error(\"Unexpected response format.\");\n      }\n\n      renderTable(data);\n      setStatus(\"Directory loaded.\");\n    } catch (error) {\n      renderTable([]);\n      setStatus(`Failed to load directory. ${error.message}`, true);\n    }\n  }\n\n  async function saveRow() {\n    const payload = getFormData();\n\n    if (!payload[\"Discord Name\"]) {\n      setStatus(\"Enter a Discord name.\", true);\n      return;\n    }\n\n    const hasAtLeastOne = ORE_HEADERS.some(header => payload[header] === \"x\");\n    if (!hasAtLeastOne) {\n      setStatus(\"Select at least one ore type.\", true);\n      return;\n    }\n\n    setStatus(\"Saving entry...\");\n\n    try {\n      const response = await fetch(JRM_WEB_APP_URL, {\n        method: \"POST\",\n        headers: {\n          \"Content-Type\": \"text\/plain;charset=utf-8\"\n        },\n        body: JSON.stringify(payload)\n      });\n\n      if (!response.ok) {\n        throw new Error(`HTTP ${response.status}`);\n      }\n\n      const result = await response.json();\n\n      if (!result.success) {\n        throw new Error(result.message || \"Save failed.\");\n      }\n\n      setStatus(\"Entry saved successfully.\");\n      clearForm();\n      await loadRows();\n    } catch (error) {\n      setStatus(`Failed to save entry. ${error.message}`, true);\n    }\n  }\n\n  toggleBtn.addEventListener(\"click\", () => {\n    const isOpen = !panelEl.hidden;\n    panelEl.hidden = isOpen;\n    toggleBtn.setAttribute(\"aria-expanded\", String(!isOpen));\n    toggleBtn.textContent = isOpen\n      ? \"Show Guide & Add \/ Update Entry\"\n      : \"Hide Guide & Add \/ Update Entry\";\n  });\n\n  saveBtn.addEventListener(\"click\", saveRow);\n  clearBtn.addEventListener(\"click\", clearForm);\n  refreshBtn.addEventListener(\"click\", loadRows);\n\n  buildHeader();\n  buildCheckboxes();\n  loadRows();\n})();\n<\/script>\n","protected":false},"excerpt":{"rendered":"<p> [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_price":"","_stock":"","_tribe_ticket_header":"","_tribe_default_ticket_provider":"","_ticket_start_date":"","_ticket_end_date":"","_tribe_ticket_show_description":"","_tribe_ticket_show_not_going":false,"_tribe_ticket_use_global_stock":"","_tribe_ticket_global_stock_level":"","_global_stock_mode":"","_global_stock_cap":"","_tribe_rsvp_for_event":"","_tribe_ticket_going_count":"","_tribe_ticket_not_going_count":"","_tribe_tickets_list":"[]","_tribe_ticket_has_attendee_info_fields":false,"footnotes":"","_tec_slr_enabled":"","_tec_slr_layout":""},"class_list":["post-1330","page","type-page","status-publish","hentry"],"ticketed":false,"_links":{"self":[{"href":"https:\/\/southsunindustries.com\/index.php\/wp-json\/wp\/v2\/pages\/1330","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/southsunindustries.com\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/southsunindustries.com\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/southsunindustries.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/southsunindustries.com\/index.php\/wp-json\/wp\/v2\/comments?post=1330"}],"version-history":[{"count":3,"href":"https:\/\/southsunindustries.com\/index.php\/wp-json\/wp\/v2\/pages\/1330\/revisions"}],"predecessor-version":[{"id":1333,"href":"https:\/\/southsunindustries.com\/index.php\/wp-json\/wp\/v2\/pages\/1330\/revisions\/1333"}],"wp:attachment":[{"href":"https:\/\/southsunindustries.com\/index.php\/wp-json\/wp\/v2\/media?parent=1330"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}