<!DOCTYPE html>
<html lang="{{HTML_LANG}}">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  {{BOOTSTRAP_CSS}}
  <style>{{DIALOG_CSS}}</style>
  <style>
    .marking-profile-preview-row {
      display: flex;
      align-items: center;
      justify-content: center;
      gap: 8px;
    }
    .marking-profile-preview-box {
      width: 50%;
      height: 168px;
      background: #f8fafc;
      flex-shrink: 0;
    }
    .marking-profile-preview-box svg {
      display: block;
      width: 100%;
      height: 160px;
    }
    .marking-rotate-btn {
      width: 36px;
      height: 36px;
      padding: 0;
      flex-shrink: 0;
      font-size: 18px;
      line-height: 1;
    }
    .marking-profile-preview-box polygon {
      fill: rgba(37, 99, 235, 0.12);
      stroke: #2563eb;
      stroke-width: 1.5;
      vector-effect: non-scaling-stroke;
    }
    .marking-profile-preview-box line {
      stroke: #2563eb;
      stroke-width: 1.5;
      vector-effect: non-scaling-stroke;
    }
    .marking-preset-thumb {
      width: 44px;
      height: 44px;
      flex-shrink: 0;
      background: #f8fafc;
      border-radius: 4px;
    }
    /* Admin illustration (PNG/SVG data URL) — thumb in the row, click to enlarge. */
    .marking-illu-thumb {
      width: 44px;
      height: 44px;
      flex-shrink: 0;
      background: #f8fafc;
      border: 1px solid #e3e8ef;
      border-radius: 4px;
      object-fit: contain;
      cursor: zoom-in;
    }
    #marking-illu-overlay {
      position: fixed;
      inset: 0;
      display: none;
      align-items: center;
      justify-content: center;
      background: rgba(15, 23, 42, 0.72);
      z-index: 1050;
      cursor: zoom-out;
    }
    #marking-illu-overlay.is-open { display: flex; }
    #marking-illu-overlay img {
      max-width: 92%;
      max-height: 92%;
      object-fit: contain;
      background: #fff;
      border-radius: 6px;
      padding: 8px;
    }
    .marking-preset-thumb svg {
      display: block;
      width: 44px;
      height: 44px;
    }
    .marking-preset-thumb polygon {
      fill: rgba(37, 99, 235, 0.15);
      stroke: #2563eb;
      stroke-width: 1.2;
      vector-effect: non-scaling-stroke;
    }
    /* Eye visibility toggle — same look as the Layer Manager. */
    .eye-btn { width: 32px; height: 28px; padding: 0; border: none; background: transparent; cursor: pointer; color: #555; display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; }
    .eye-btn.off { color: #bbb; }
    .eye-btn img { width: 18px; height: 18px; }
  </style>
</head>
<body class="p-3">
  <div class="container-fluid">
    <div class="mb-2 d-flex justify-content-between align-items-start">
      <div>
        <h2 class="h6 mb-0">{{MARKING_SETTINGS_TITLE}}</h2>
        <p class="text-muted small mb-0">{{MARKING_SETTINGS_SUBTITLE}}</p>
      </div>
      <span id="marking-save-status" class="small text-success" style="min-width:60px;text-align:right;"></span>
    </div>

    <div class="card border mb-2">
      <div class="card-body py-2 px-3">
        <div class="unfold-section-title">{{MARKING_SETTINGS_PRESETS_SECTION}}</div>
        <div class="row g-2 mb-2 d-none" id="marking-preset-name-row">
          <div class="col-12">
            <label class="form-label small mb-1">{{MARKING_PRESET_NAME}}</label>
            <input type="text" id="marking-preset-name" class="form-control form-control-sm" value="{{ACTIVE_PRESET_NAME}}" placeholder="Groove_LED">
          </div>
        </div>
        <div class="d-flex flex-wrap gap-2 align-items-center">
          <button type="button" class="btn btn-sm btn-outline-secondary" id="marking-new-preset-btn">{{MARKING_NEW_PRESET}}</button>
          <button type="button" class="btn btn-sm btn-primary d-none" id="marking-save-preset-btn">{{MARKING_SAVE_PRESET}}</button>
          <button type="button" class="btn btn-sm btn-outline-danger ms-auto" id="marking-reset-presets-btn">{{MARKING_RESET_PRESETS}}</button>
        </div>
      </div>
    </div>

    <div id="marking-profile-preview-wrap" class="card border mb-2 d-none">
      <div class="card-body py-2 px-3">
        <div class="unfold-section-title">{{MARKING_SETTINGS_PROFILE_PREVIEW}}</div>
        <div class="marking-profile-preview-row">
          <button type="button" id="marking-rotate-ccw-btn" class="btn btn-sm btn-outline-secondary marking-rotate-btn"
                  title="{{MARKING_ROTATE_CCW}}" aria-label="{{MARKING_ROTATE_CCW}}">&#8592;</button>
          <div id="marking-profile-preview-box" class="marking-profile-preview-box border rounded d-flex align-items-center justify-content-center">
            <svg id="marking-profile-preview-svg" preserveAspectRatio="xMidYMid meet" aria-hidden="true"></svg>
          </div>
          <button type="button" id="marking-rotate-cw-btn" class="btn btn-sm btn-outline-secondary marking-rotate-btn"
                  title="{{MARKING_ROTATE_CW}}" aria-label="{{MARKING_ROTATE_CW}}">&#8594;</button>
        </div>
        <p id="marking-profile-preview-hint" class="text-muted small mb-0 mt-2 d-none">{{MARKING_SETTINGS_PROFILE_PREVIEW_HINT}}</p>
      </div>
    </div>

    <div id="marking-params-section" class="card border mb-2 d-none">
      <div class="card-body py-2 px-3">
        <div class="unfold-section-title">{{MARKING_SETTINGS_PARAMS_SECTION}}</div>
        <div class="row g-2">
          <div class="col-12 js-marking-offset-line" id="marking-offsets-section">
            <label class="form-label small mb-1">{{MARKING_OFFSET_FROM_LINE}}</label>
            <div class="d-flex gap-1 small text-muted mb-1">
              <span style="flex:0 0 72px">{{MARKING_HUD_LINE}}/{{MARKING_HUD_AREA}}</span>
              <span style="flex:0 0 72px">mm</span>
              <span style="flex:0 0 72px">{{MARKING_HUD_WIDTH}}</span>
              <span style="flex:0 0 72px">{{MARKING_HUD_OFFSET}}</span>
              <span class="flex-grow-1">{{MARKING_HUD_LAYER}}</span>
            </div>
            <div id="marking-offsets-list"></div>
            <button type="button" class="btn btn-sm btn-outline-secondary mt-1" id="marking-offset-add">+ {{MARKING_ADD_OFFSET}}</button>
          </div>
          <div class="col-6 col-md-4 js-marking-profile-locked-offset">
            <label class="form-label small mb-1">{{MARKING_PROFILE_OFFSET_LOCKED_LINE}}</label>
            <input type="number" step="0.1" class="form-control form-control-sm js-marking-num" data-marking-key="profile_offset_from_locked_line_mm" value="{{PROFILE_OFFSET_LOCKED_LINE_MM}}">
          </div>
          <div class="col-12 js-marking-hide-custom">
            <label class="form-check mb-0">
              <input type="checkbox" class="form-check-input" id="marking-preset-ring" {{MARKING_PRESET_RING_CHECKED}}>
              <span class="form-check-label small">{{MARKING_PRESET_RING}}</span>
            </label>
          </div>
          <div class="col-12">
            <label class="form-check mb-0">
              <input type="checkbox" class="form-check-input" id="marking-mark-back-face" {{MARKING_MARK_BACK_FACE_CHECKED}}>
              <span class="form-check-label small">{{MARKING_MARK_BACK_FACE}}</span>
            </label>
          </div>
        </div>
      </div>
    </div>

    <div class="card border mb-2">
      <div class="card-body py-2 px-3">
        <p class="text-muted small mb-2">{{MARKING_SETTINGS_PRESETS_HINT}}</p>
        <div id="marking-preset-list"></div>
      </div>
    </div>
  </div>
  <script>
  (function () {
    var GG_MARKING_STRINGS = {
      saved: {{MARKING_SAVED_JSON}},
      save_failed: {{MARKING_SAVE_FAILED_JSON}},
      preset_saved: {{MARKING_PRESET_SAVED_JSON}},
      delete: {{MARKING_DELETE_JSON}},
      reset_confirm: {{MARKING_RESET_CONFIRM_JSON}},
      illu_title: {{MARKING_ILLU_TITLE_JSON}}
    };
    var ICON_BASE = '{{ICON_BASE_URL}}';
    var PRESETS = {{MARKING_PRESETS_JSON}};
    var ACTIVE_PRESET_ID = {{ACTIVE_PRESET_ID_JSON}};
    var EDITING_PRESET_ID = null;
    var IS_EDITING = false;
    var DEFAULT_PRESET_ID = {{MARKING_DEFAULT_PRESET_ID_JSON}};
    var BUILTIN_PRESET_IDS = {{MARKING_BUILTIN_PRESET_IDS_JSON}};
    function isBuiltinPreset(id) { return BUILTIN_PRESET_IDS.indexOf(id) !== -1; }
    var PROFILE_PREVIEW_PAD = 0.12;
    var OFFSETS_FROM_LINE_MM = {{OFFSETS_FROM_LINE_MM_JSON}};
    var OFFSET_LAYER_NAMES = {{OFFSET_LAYER_NAMES_JSON}};
    var OFFSET_MODES = {{OFFSET_MODES_JSON}};
    var OFFSET_AREA_WIDTHS_MM = {{OFFSET_AREA_WIDTHS_MM_JSON}};
    var EDGE_END_OFFSETS_MM = {{EDGE_END_OFFSETS_MM_JSON}};
    var DEFAULT_AREA_WIDTH_MM = {{DEFAULT_AREA_WIDTH_MM_JSON}};
    var DEFAULT_LAYER = {{LAYER_NAME_JSON}};

    // Single layer for a preset — line vs area mode no longer picks a layer.
    function defaultLayerForMode(_mode) {
      return DEFAULT_LAYER;
    }

    function syncOffsetRowWidthUi(widthInp, mode, i) {
      // Profile presets (custom shape or group) stamp their own geometry, so
      // the area width has no effect — lock it without touching stored values.
      var profilePreset = isProfilePreset(editingPreset());
      var line = mode === 'line' || profilePreset;
      widthInp.disabled = line;
      widthInp.classList.toggle('bg-light', line);
      if (profilePreset) {
        return;
      }
      if (mode === 'line') {
        OFFSET_AREA_WIDTHS_MM[i] = 0;
        widthInp.value = 0;
      } else if (!OFFSET_AREA_WIDTHS_MM[i] || OFFSET_AREA_WIDTHS_MM[i] <= 0) {
        OFFSET_AREA_WIDTHS_MM[i] = DEFAULT_AREA_WIDTH_MM;
        widthInp.value = DEFAULT_AREA_WIDTH_MM;
      }
    }

    // End trim is disabled for RING presets (a closed loop has no ends) and for
    // profile presets (stamped shapes, not trimmed lines).
    function endTrimDisabled() {
      return readRing() || isProfilePreset(editingPreset());
    }

    function renderOffsetRows(offsets, layers, modes, widths, trims) {
      var list = document.getElementById('marking-offsets-list');
      if (!list) return;
      list.innerHTML = '';
      var customArea = isCustomProfile(editingPreset());
      var trimOff = endTrimDisabled();
      offsets.forEach(function (val, i) {
        var rowMode = customArea ? 'area' : (modes[i] || modes[modes.length - 1] || 'area');
        if (customArea) OFFSET_MODES[i] = 'area';
        var row = document.createElement('div');
        row.className = 'd-flex align-items-center gap-1 mb-1';
        var modeSel = document.createElement('select');
        modeSel.className = 'form-select form-select-sm';
        ['line', 'area'].forEach(function (m) {
          var opt = document.createElement('option');
          opt.value = m;
          opt.textContent = m === 'line' ? '{{MARKING_HUD_LINE}}' : '{{MARKING_HUD_AREA}}';
          if (m === rowMode) opt.selected = true;
          modeSel.appendChild(opt);
        });
        if (customArea) {
          modeSel.disabled = true;
          modeSel.classList.add('bg-light');
        }
        modeSel.addEventListener('change', function () {
          if (customArea) return;
          OFFSET_MODES[i] = modeSel.value;
          sketchup.on_marking_setting_changed('offset_modes[' + i + ']', modeSel.value);
          syncOffsetRowWidthUi(widthInp, modeSel.value, i);
          if (!widthInp.disabled) {
            sketchup.on_marking_setting_changed('offset_area_widths_mm[' + i + ']', widthInp.value);
          }
          showStatus(true, 'saved');
        });
        var inp = document.createElement('input');
        inp.type = 'number';
        inp.step = '0.1';
        inp.className = 'form-control form-control-sm';
        inp.dataset.offsetIndex = i;
        inp.value = val;
        inp.addEventListener('change', function () {
          OFFSETS_FROM_LINE_MM[i] = parseFloat(inp.value) || 0;
          sketchup.on_marking_setting_changed('offsets_from_line_mm[' + i + ']', inp.value);
          showStatus(true, 'saved');
        });
        var widthInp = document.createElement('input');
        widthInp.type = 'number';
        widthInp.step = '0.1';
        widthInp.min = '0';
        widthInp.className = 'form-control form-control-sm';
        widthInp.value = widths[i] != null ? widths[i] : (rowMode === 'line' ? 0 : DEFAULT_AREA_WIDTH_MM);
        syncOffsetRowWidthUi(widthInp, rowMode, i);
        widthInp.addEventListener('change', function () {
          if (widthInp.disabled) return;
          OFFSET_AREA_WIDTHS_MM[i] = parseFloat(widthInp.value) || 0.1;
          sketchup.on_marking_setting_changed('offset_area_widths_mm[' + i + ']', widthInp.value);
          showStatus(true, 'saved');
        });
        var trimInp = document.createElement('input');
        trimInp.type = 'number';
        trimInp.step = '0.1';
        trimInp.className = 'form-control form-control-sm';
        trimInp.value = (trims && trims[i] != null) ? trims[i] : 0;
        trimInp.disabled = trimOff;
        trimInp.classList.toggle('bg-light', trimOff);
        trimInp.addEventListener('change', function () {
          if (trimInp.disabled) return;
          EDGE_END_OFFSETS_MM[i] = parseFloat(trimInp.value) || 0;
          sketchup.on_marking_setting_changed('edge_end_offsets_mm[' + i + ']', trimInp.value);
          showStatus(true, 'saved');
        });
        var layerInp = document.createElement('input');
        layerInp.type = 'text';
        layerInp.className = 'form-control form-control-sm';
        layerInp.placeholder = '{{MARKING_HUD_LAYER}}';
        layerInp.value = layers[i] || defaultLayerForMode(rowMode);
        layerInp.addEventListener('change', function () {
          OFFSET_LAYER_NAMES[i] = layerInp.value.trim();
          sketchup.on_marking_setting_changed('offset_layer_names[' + i + ']', layerInp.value);
          showStatus(true, 'saved');
        });
        modeSel.style.maxWidth = '72px';
        inp.style.maxWidth = '72px';
        widthInp.style.maxWidth = '72px';
        trimInp.style.maxWidth = '72px';
        layerInp.classList.add('flex-grow-1');
        row.appendChild(modeSel);
        row.appendChild(inp);
        row.appendChild(widthInp);
        row.appendChild(trimInp);
        row.appendChild(layerInp);
        if (offsets.length > 1) {
          var removeBtn = document.createElement('button');
          removeBtn.type = 'button';
          removeBtn.className = 'btn btn-sm btn-outline-danger flex-shrink-0';
          removeBtn.textContent = '−';
          removeBtn.addEventListener('click', function () {
            sketchup.on_marking_setting_changed('offsets_from_line_mm[-' + i + ']', '');
            OFFSETS_FROM_LINE_MM.splice(i, 1);
            OFFSET_LAYER_NAMES.splice(i, 1);
            OFFSET_MODES.splice(i, 1);
            OFFSET_AREA_WIDTHS_MM.splice(i, 1);
            EDGE_END_OFFSETS_MM.splice(i, 1);
            renderOffsetRows(OFFSETS_FROM_LINE_MM, OFFSET_LAYER_NAMES, OFFSET_MODES, OFFSET_AREA_WIDTHS_MM, EDGE_END_OFFSETS_MM);
            showStatus(true, 'saved');
          });
          row.appendChild(removeBtn);
        }
        list.appendChild(row);
      });
    }

    function showStatus(ok, key) {
      var st = document.getElementById('marking-save-status');
      if (!st) return;
      st.className = ok ? 'small text-success' : 'small text-danger';
      st.textContent = ok ? (GG_MARKING_STRINGS[key] || GG_MARKING_STRINGS.saved) : GG_MARKING_STRINGS.save_failed;
    }

    function readNum(key) {
      var el = document.querySelector('.js-marking-num[data-marking-key="' + key + '"]');
      return el ? parseFloat(el.value) || 0 : 0;
    }

    function readStr(key) {
      var el = document.querySelector('.js-marking-str[data-marking-key="' + key + '"]');
      return el ? el.value.trim() : '';
    }

    function readRing() {
      var el = document.getElementById('marking-preset-ring');
      return el ? !!el.checked : false;
    }

    function setRing(val) {
      var el = document.getElementById('marking-preset-ring');
      if (el) el.checked = !!val;
    }

    function readBackFace() {
      var el = document.getElementById('marking-mark-back-face');
      return el ? !!el.checked : false;
    }

    function setBackFace(val) {
      var el = document.getElementById('marking-mark-back-face');
      if (el) el.checked = !!val;
    }

    function isCustomProfile(p) {
      return !!(p && p.profile_kind === 'custom_profile' && p.profile_ring && p.profile_ring.length >= 3);
    }

    function isGroupProfile(p) {
      return !!(p && p.profile_kind === 'group' && p.group_definition_name);
    }

    function isProfilePreset(p) {
      return isCustomProfile(p) || isGroupProfile(p);
    }

    function profilePreviewSvgData(ring) {
      if (!ring || ring.length < 3) return null;
      var xs = [];
      var ys = [];
      ring.forEach(function (row) {
        xs.push(Number(row[0]));
        ys.push(Number(row[1]));
      });
      var minX = Math.min.apply(null, xs);
      var maxX = Math.max.apply(null, xs);
      var minY = Math.min.apply(null, ys);
      var maxY = Math.max.apply(null, ys);
      var spanX = Math.max(maxX - minX, 1e-6);
      var spanY = Math.max(maxY - minY, 1e-6);
      var pad = Math.max(spanX, spanY) * PROFILE_PREVIEW_PAD;
      var width = spanX + (2 * pad);
      var height = spanY + (2 * pad);
      var points = ring.map(function (row) {
        var x = (Number(row[0]) - minX + pad).toFixed(4);
        var y = (maxY - Number(row[1]) + pad).toFixed(4);
        return x + ',' + y;
      }).join(' ');
      return { viewBox: '0 0 ' + width.toFixed(4) + ' ' + height.toFixed(4), points: points };
    }

    function fillProfileSvg(svg, ring) {
      if (!svg) return false;
      while (svg.firstChild) svg.removeChild(svg.firstChild);
      var data = profilePreviewSvgData(ring);
      if (!data) return false;
      svg.setAttribute('viewBox', data.viewBox);
      var poly = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');
      poly.setAttribute('points', data.points);
      svg.appendChild(poly);
      return true;
    }

    function profileEdgesSvgData(edges) {
      if (!edges || !edges.length) return null;
      var xs = [];
      var ys = [];
      edges.forEach(function (seg) {
        if (!seg || seg.length < 2) return;
        xs.push(Number(seg[0][0]), Number(seg[1][0]));
        ys.push(Number(seg[0][1]), Number(seg[1][1]));
      });
      if (!xs.length) return null;
      var minX = Math.min.apply(null, xs);
      var maxX = Math.max.apply(null, xs);
      var minY = Math.min.apply(null, ys);
      var maxY = Math.max.apply(null, ys);
      var spanX = Math.max(maxX - minX, 1e-6);
      var spanY = Math.max(maxY - minY, 1e-6);
      var pad = Math.max(spanX, spanY) * PROFILE_PREVIEW_PAD;
      var width = spanX + (2 * pad);
      var height = spanY + (2 * pad);
      var lines = edges.map(function (seg) {
        return {
          x1: (Number(seg[0][0]) - minX + pad).toFixed(4),
          y1: (maxY - Number(seg[0][1]) + pad).toFixed(4),
          x2: (Number(seg[1][0]) - minX + pad).toFixed(4),
          y2: (maxY - Number(seg[1][1]) + pad).toFixed(4)
        };
      });
      return { viewBox: '0 0 ' + width.toFixed(4) + ' ' + height.toFixed(4), lines: lines };
    }

    function fillProfileEdgesSvg(svg, edges) {
      if (!svg) return false;
      while (svg.firstChild) svg.removeChild(svg.firstChild);
      var data = profileEdgesSvgData(edges);
      if (!data) return false;
      svg.setAttribute('viewBox', data.viewBox);
      data.lines.forEach(function (ln) {
        var line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
        line.setAttribute('x1', ln.x1);
        line.setAttribute('y1', ln.y1);
        line.setAttribute('x2', ln.x2);
        line.setAttribute('y2', ln.y2);
        svg.appendChild(line);
      });
      return true;
    }

    function editingPreset() {
      if (!IS_EDITING || !EDITING_PRESET_ID) return null;
      return PRESETS.find(function (p) { return p.id === EDITING_PRESET_ID; }) || null;
    }

    function syncEditingUi() {
      var paramsEl = document.getElementById('marking-params-section');
      if (paramsEl) paramsEl.classList.toggle('d-none', !IS_EDITING);
      var nameRow = document.getElementById('marking-preset-name-row');
      if (nameRow) nameRow.classList.toggle('d-none', !IS_EDITING);
      var saveBtn = document.getElementById('marking-save-preset-btn');
      if (saveBtn) saveBtn.classList.toggle('d-none', !IS_EDITING);
      syncCustomProfileUi();
    }

    function clientSchematicRing(p) {
      var inchToMm = 25.4;
      var lengthMm = 40;
      var halfL = (lengthMm / 2) / inchToMm;
      if (p && p.mode === 'line') {
        var halfT = (0.5 / 2) / inchToMm;
        return [[-halfL, -halfT, 0], [halfL, -halfT, 0], [halfL, halfT, 0], [-halfL, halfT, 0]];
      }
      var widthMm = (p && p.area_width_mm != null) ? Number(p.area_width_mm) : 20;
      if (!(widthMm > 0)) widthMm = 20;
      var halfW = (widthMm / 2) / inchToMm;
      return [[-halfL, -halfW, 0], [halfL, -halfW, 0], [halfL, halfW, 0], [-halfL, halfW, 0]];
    }

    function rotateRingClient(ring, quarters) {
      var q = ((Number(quarters) % 4) + 4) % 4;
      var out = ring.slice();
      for (var i = 0; i < q; i++) {
        out = out.map(function (row) {
          var x = Number(row[0]);
          var y = Number(row[1]);
          var z = row[2] != null ? Number(row[2]) : 0;
          return [-y, x, z];
        });
      }
      return out;
    }

    function previewRingForPreset(p) {
      if (!p) return null;
      if (p.preview_ring && p.preview_ring.length >= 3) return p.preview_ring;
      if (isCustomProfile(p)) return p.profile_ring;
      var base = clientSchematicRing(p);
      return rotateRingClient(base, p.profile_rotation_quarters || 0);
    }

    // Ring markers offset a whole closed loop; the 90° profile rotation does
    // not apply to them, so the rotate arrows are disabled while a ring preset
    // is being edited. Driven by the ring checkbox (the live UI state).
    function syncRotateButtonsEnabled() {
      var ringEl = document.getElementById('marking-preset-ring');
      var isRing = !!(ringEl && ringEl.checked);
      ['marking-rotate-ccw-btn', 'marking-rotate-cw-btn'].forEach(function (id) {
        var b = document.getElementById(id);
        if (b) b.disabled = isRing;
      });
    }

    function renderProfilePreview(p) {
      var wrap = document.getElementById('marking-profile-preview-wrap');
      var svg = document.getElementById('marking-profile-preview-svg');
      var hint = document.getElementById('marking-profile-preview-hint');
      if (!wrap || !svg) return;
      wrap.classList.toggle('d-none', !IS_EDITING);
      syncRotateButtonsEnabled();
      if (!IS_EDITING) return;
      var ok = false;
      if (isGroupProfile(p) && p.preview_edges && p.preview_edges.length) {
        ok = fillProfileEdgesSvg(svg, p.preview_edges);
      } else {
        ok = fillProfileSvg(svg, previewRingForPreset(p));
      }
      if (hint) hint.classList.toggle('d-none', ok);
    }

    window.applyRotatedProfileRing = function (payload) {
      var data = payload;
      if (typeof payload === 'string') {
        try { data = JSON.parse(payload); } catch (e) { return; }
      }
      if (!data) return;
      var id = data.id || EDITING_PRESET_ID;
      PRESETS.forEach(function (p) {
        if (p.id !== id) return;
        if (data.profile_ring) p.profile_ring = data.profile_ring;
        if (data.preview_ring) p.preview_ring = data.preview_ring;
        if (data.preview_edges) p.preview_edges = data.preview_edges;
        if (data.profile_rotation_quarters != null) {
          p.profile_rotation_quarters = data.profile_rotation_quarters;
        }
        if (data.mode) p.mode = data.mode;
        if (data.profile_kind) p.profile_kind = data.profile_kind;
        if (data.area_width_mm != null) p.area_width_mm = data.area_width_mm;
      });
      var editing = editingPreset();
      if (editing && data.preview_ring) editing.preview_ring = data.preview_ring;
      if (editing && data.preview_edges) editing.preview_edges = data.preview_edges;
      if (editing && data.profile_ring) editing.profile_ring = data.profile_ring;
      if (editing && data.profile_rotation_quarters != null) {
        editing.profile_rotation_quarters = data.profile_rotation_quarters;
      }
      renderProfilePreview(editing || data);
      renderPresetList();
    };

    function syncEdgeEndOffsetVisibility() {
      // Re-render the offset rows so the per-row end-trim inputs enable/disable
      // (they are disabled for ring / profile presets — see endTrimDisabled).
      renderOffsetRows(OFFSETS_FROM_LINE_MM, OFFSET_LAYER_NAMES, OFFSET_MODES, OFFSET_AREA_WIDTHS_MM, EDGE_END_OFFSETS_MM);
    }

    function syncCustomProfileUi() {
      var p = editingPreset();
      var custom = isCustomProfile(p);
      var prof = isProfilePreset(p);
      renderProfilePreview(p);
      document.querySelectorAll('.js-marking-hide-custom').forEach(function (el) {
        el.style.display = prof ? 'none' : '';
      });
      document.querySelectorAll('.js-marking-profile-locked-offset').forEach(function (el) {
        el.style.display = prof ? '' : 'none';
      });
      syncEdgeEndOffsetVisibility();
    }

    function isDefaultPresetEditing() {
      return EDITING_PRESET_ID === DEFAULT_PRESET_ID;
    }

    function syncDefaultPresetUi() {
      var locked = isDefaultPresetEditing();
      var nameEl = document.getElementById('marking-preset-name');
      if (nameEl) {
        nameEl.readOnly = locked;
        nameEl.classList.toggle('bg-light', locked);
      }
      renderOffsetRows(OFFSETS_FROM_LINE_MM, OFFSET_LAYER_NAMES, OFFSET_MODES, OFFSET_AREA_WIDTHS_MM, EDGE_END_OFFSETS_MM);
    }

    function setNum(key, val) {
      var el = document.querySelector('.js-marking-num[data-marking-key="' + key + '"]');
      if (el) el.value = val;
    }

    function setStr(key, val) {
      var el = document.querySelector('.js-marking-str[data-marking-key="' + key + '"]');
      if (el) el.value = val;
    }

    function startNewPreset() {
      IS_EDITING = true;
      EDITING_PRESET_ID = '';
      var nameEl = document.getElementById('marking-preset-name');
      if (nameEl) {
        nameEl.value = '';
        nameEl.focus();
      }
      setRing(false);
      OFFSET_MODES = ['area'];
      OFFSET_AREA_WIDTHS_MM = [DEFAULT_AREA_WIDTH_MM];
      EDGE_END_OFFSETS_MM = [0];
      renderPresetList();
      syncDefaultPresetUi();
      syncEditingUi();
      if (window.sketchup && sketchup.on_marking_new_preset) {
        sketchup.on_marking_new_preset();
      }
    }

    function loadPresetIntoForm(p) {
      if (!p) return;
      IS_EDITING = true;
      EDITING_PRESET_ID = p.id || '';
      document.getElementById('marking-preset-name').value = p.name || '';
      setNum('edge_end_offset_mm', p.edge_end_offset_mm);
      OFFSETS_FROM_LINE_MM = (p.offsets_from_line_mm && p.offsets_from_line_mm.length) ? p.offsets_from_line_mm.slice() : [p.offset_from_line_mm || 0];
      var legacyMode = p.mode === 'line' ? 'line' : 'area';
      OFFSET_MODES = (p.offset_modes && p.offset_modes.length) ? p.offset_modes.slice() : [legacyMode];
      if (isCustomProfile(p)) {
        OFFSET_MODES = OFFSETS_FROM_LINE_MM.map(function () { return 'area'; });
      } else {
        while (OFFSET_MODES.length < OFFSETS_FROM_LINE_MM.length) {
          OFFSET_MODES.push(OFFSET_MODES[OFFSET_MODES.length - 1] || legacyMode);
        }
      }
      OFFSET_LAYER_NAMES = (p.offset_layer_names && p.offset_layer_names.length) ? p.offset_layer_names.slice() : [p.layer_name || DEFAULT_LAYER];
      OFFSET_AREA_WIDTHS_MM = (p.offset_area_widths_mm && p.offset_area_widths_mm.length) ? p.offset_area_widths_mm.slice() : [p.area_width_mm || DEFAULT_AREA_WIDTH_MM];
      while (OFFSET_AREA_WIDTHS_MM.length < OFFSETS_FROM_LINE_MM.length) {
        OFFSET_AREA_WIDTHS_MM.push(OFFSET_AREA_WIDTHS_MM[OFFSET_AREA_WIDTHS_MM.length - 1] || DEFAULT_AREA_WIDTH_MM);
      }
      EDGE_END_OFFSETS_MM = (p.edge_end_offsets_mm && p.edge_end_offsets_mm.length) ? p.edge_end_offsets_mm.slice() : [p.edge_end_offset_mm || 0];
      while (EDGE_END_OFFSETS_MM.length < OFFSETS_FROM_LINE_MM.length) {
        EDGE_END_OFFSETS_MM.push(EDGE_END_OFFSETS_MM[EDGE_END_OFFSETS_MM.length - 1] || 0);
      }
      OFFSET_MODES.forEach(function (m, idx) {
        if (m === 'line') OFFSET_AREA_WIDTHS_MM[idx] = 0;
      });
      renderOffsetRows(OFFSETS_FROM_LINE_MM, OFFSET_LAYER_NAMES, OFFSET_MODES, OFFSET_AREA_WIDTHS_MM, EDGE_END_OFFSETS_MM);
      setNum('profile_offset_from_locked_line_mm', p.profile_offset_from_locked_line_mm != null ? p.profile_offset_from_locked_line_mm : p.offset_from_line_mm);
      setRing(p.ring);
      setBackFace(p.mark_back_face);
      syncDefaultPresetUi();
      syncEditingUi();
      if (window.sketchup && sketchup.on_marking_apply_preset && p.id) {
        sketchup.on_marking_apply_preset(p.id);
      }
    }

    function renderPresetList() {
      var root = document.getElementById('marking-preset-list');
      if (!root) return;
      root.innerHTML = '';
      if (!PRESETS.length) {
        root.innerHTML = '<p class="text-muted small mb-0">â€”</p>';
        return;
      }
      PRESETS.forEach(function (p) {
        var row = document.createElement('div');
        row.className = 'd-flex align-items-center justify-content-between border rounded px-2 py-1 mb-1 marking-preset-row gap-2';
        row.style.cursor = 'pointer';
        if (p.id === EDITING_PRESET_ID && IS_EDITING) {
          row.classList.add('border-primary', 'bg-light');
        } else if (!IS_EDITING && p.id === ACTIVE_PRESET_ID) {
          row.classList.add('border-secondary');
        }
        // Eye toggle at the START of the row: default visible; turning it off
        // hides this preset from the on-screen HUD preset row. Same icons/look as
        // the Layer Manager (LM_EYE.svg / LM_EYE_OFF.svg).
        var eyeBtn = document.createElement('button');
        eyeBtn.type = 'button';
        eyeBtn.className = 'eye-btn';
        var setEye = function () {
          eyeBtn.innerHTML = '';
          var img = document.createElement('img');
          img.src = ICON_BASE + (p.hud_hidden ? 'LM_EYE_OFF.svg' : 'LM_EYE.svg');
          img.width = 18;
          img.height = 18;
          img.alt = '';
          eyeBtn.appendChild(img);
          eyeBtn.classList.toggle('off', !!p.hud_hidden);
          eyeBtn.title = p.hud_hidden ? 'Hiện trên HUD' : 'Ẩn khỏi HUD';
        };
        setEye();
        eyeBtn.addEventListener('click', function (ev) {
          ev.stopPropagation();
          p.hud_hidden = !p.hud_hidden;
          setEye();
          sketchup.on_marking_toggle_preset_hud(p.id, p.hud_hidden ? '1' : '0');
          showStatus(true, 'saved');
        });
        row.appendChild(eyeBtn);
        var left = document.createElement('div');
        left.className = 'd-flex align-items-center gap-2 flex-grow-1 min-w-0';
        // Two INDEPENDENT thumbs (user spec 2026-07-18): the drawn-profile
        // preview always shows for custom profiles, and the admin illustration
        // — when present — shows BESIDE it. The illustration renders ONLY via
        // an <img> src (scripts inside an SVG data URL can't run there);
        // clicking zooms it in the overlay.
        if (isCustomProfile(p)) {
          var thumb = document.createElement('div');
          thumb.className = 'marking-preset-thumb border';
          var thumbSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
          thumbSvg.setAttribute('preserveAspectRatio', 'xMidYMid meet');
          fillProfileSvg(thumbSvg, p.profile_ring);
          thumb.appendChild(thumbSvg);
          left.appendChild(thumb);
        }
        if (p.illustration && p.illustration.indexOf('data:image/') === 0) {
          var illu = document.createElement('img');
          illu.className = 'marking-illu-thumb';
          illu.src = p.illustration;
          illu.alt = '';
          illu.title = GG_MARKING_STRINGS.illu_title;
          illu.addEventListener('click', function (ev) {
            ev.stopPropagation();
            openIllustrationOverlay(p.illustration);
          });
          left.appendChild(illu);
        }
        var label = document.createElement('span');
        label.className = 'small text-truncate';
        var ringTag = p.ring ? ', ring' : '';
        var shapeTag = isCustomProfile(p) ? ', shape' : (isGroupProfile(p) ? ', group' : '');
        label.textContent = (isProfilePreset(p) ? '\u25C6 ' : '') + p.name + ' (' + p.mode + ringTag + shapeTag + ')';
        left.appendChild(label);
        row.appendChild(left);
        row.addEventListener('click', function (ev) {
          if (ev.target.tagName === 'BUTTON') return;
          loadPresetIntoForm(p);
          renderPresetList();
        });
        if (!isBuiltinPreset(p.id)) {
          var btn = document.createElement('button');
          btn.type = 'button';
          btn.className = 'btn btn-sm btn-outline-danger flex-shrink-0';
          btn.textContent = GG_MARKING_STRINGS.delete;
          btn.addEventListener('click', function (ev) {
            ev.stopPropagation();
            sketchup.on_marking_delete_preset(p.id);
          });
          row.appendChild(btn);
        }
        root.appendChild(row);
      });
    }

    document.querySelectorAll('.js-marking-num').forEach(function (el) {
      el.addEventListener('change', function () {
        sketchup.on_marking_setting_changed(el.dataset.markingKey, el.value);
        showStatus(true, 'saved');
      });
    });

    document.querySelectorAll('.js-marking-str').forEach(function (el) {
      el.addEventListener('change', function () {
        sketchup.on_marking_setting_changed(el.dataset.markingKey, el.value);
        showStatus(true, 'saved');
      });
    });

    var ringEl = document.getElementById('marking-preset-ring');
    if (ringEl) {
      ringEl.addEventListener('change', function () {
        sketchup.on_marking_setting_changed('ring', ringEl.checked ? '1' : '0');
        syncEdgeEndOffsetVisibility();
        syncRotateButtonsEnabled();
        showStatus(true, 'saved');
      });
    }

    var backFaceEl = document.getElementById('marking-mark-back-face');
    if (backFaceEl) {
      backFaceEl.addEventListener('change', function () {
        sketchup.on_marking_setting_changed('mark_back_face', backFaceEl.checked ? '1' : '0');
        showStatus(true, 'saved');
      });
    }

    function wireRotateBtn(id, direction) {
      var el = document.getElementById(id);
      if (!el) return;
      el.addEventListener('click', function () {
        if (window.sketchup && sketchup.on_marking_rotate_profile) {
          sketchup.on_marking_rotate_profile(direction);
          showStatus(true, 'saved');
        }
      });
    }
    wireRotateBtn('marking-rotate-ccw-btn', 'ccw');
    wireRotateBtn('marking-rotate-cw-btn', 'cw');

    document.getElementById('marking-new-preset-btn').addEventListener('click', startNewPreset);

    var resetBtn = document.getElementById('marking-reset-presets-btn');
    if (resetBtn) {
      resetBtn.addEventListener('click', function () {
        if (!window.confirm(GG_MARKING_STRINGS.reset_confirm)) return;
        if (window.sketchup && sketchup.on_marking_reset_presets) {
          sketchup.on_marking_reset_presets();
          showStatus(true, 'saved');
        }
      });
    }

    var addOffsetBtn = document.getElementById('marking-offset-add');
    if (addOffsetBtn) {
      addOffsetBtn.addEventListener('click', function () {
        var lastVal = OFFSETS_FROM_LINE_MM.length > 0 ? OFFSETS_FROM_LINE_MM[OFFSETS_FROM_LINE_MM.length - 1] : 0;
        var lastMode = isCustomProfile(editingPreset()) ? 'area' : (OFFSET_MODES.length > 0 ? OFFSET_MODES[OFFSET_MODES.length - 1] : 'area');
        var lastLayer = OFFSET_LAYER_NAMES.length > 0 ? OFFSET_LAYER_NAMES[OFFSET_LAYER_NAMES.length - 1] : defaultLayerForMode(lastMode);
        var lastWidth = lastMode === 'line' ? 0 : (OFFSET_AREA_WIDTHS_MM.length > 0 ? OFFSET_AREA_WIDTHS_MM[OFFSET_AREA_WIDTHS_MM.length - 1] : DEFAULT_AREA_WIDTH_MM);
        var lastTrim = EDGE_END_OFFSETS_MM.length > 0 ? EDGE_END_OFFSETS_MM[EDGE_END_OFFSETS_MM.length - 1] : 0;
        sketchup.on_marking_setting_changed('offsets_from_line_mm[+]', String(lastVal));
        sketchup.on_marking_setting_changed('offset_layer_names[+]', lastLayer);
        sketchup.on_marking_setting_changed('offset_modes[+]', lastMode);
        sketchup.on_marking_setting_changed('offset_area_widths_mm[+]', String(lastWidth));
        sketchup.on_marking_setting_changed('edge_end_offsets_mm[+]', String(lastTrim));
        OFFSETS_FROM_LINE_MM.push(lastVal);
        OFFSET_LAYER_NAMES.push(lastLayer);
        OFFSET_MODES.push(lastMode);
        OFFSET_AREA_WIDTHS_MM.push(lastWidth);
        EDGE_END_OFFSETS_MM.push(lastTrim);
        renderOffsetRows(OFFSETS_FROM_LINE_MM, OFFSET_LAYER_NAMES, OFFSET_MODES, OFFSET_AREA_WIDTHS_MM, EDGE_END_OFFSETS_MM);
        showStatus(true, 'saved');
      });
    }

    document.getElementById('marking-save-preset-btn').addEventListener('click', function () {
      var nameEl = document.getElementById('marking-preset-name');
      var name = isDefaultPresetEditing()
        ? (PRESETS.find(function (p) { return p.id === DEFAULT_PRESET_ID; }) || {}).name || 'Default'
        : nameEl.value.trim();
      if (!name) return;
      var existing = editingPreset();
      var mode = isCustomProfile(existing) ? 'area' : (OFFSET_MODES[0] || 'area');
      var saveModes = isCustomProfile(existing) ? OFFSET_MODES.map(function () { return 'area'; }) : OFFSET_MODES.slice();
      var firstAreaWidth = 0;
      saveModes.forEach(function (m, idx) {
        if (m === 'area' && OFFSET_AREA_WIDTHS_MM[idx] > 0 && !firstAreaWidth) firstAreaWidth = OFFSET_AREA_WIDTHS_MM[idx];
      });
      var payload = {
        id: EDITING_PRESET_ID || '',
        name: name,
        mode: mode,
        edge_end_offset_mm: EDGE_END_OFFSETS_MM[0] || 0,
        edge_end_offsets_mm: EDGE_END_OFFSETS_MM.slice(),
        area_width_mm: firstAreaWidth || DEFAULT_AREA_WIDTH_MM,
        offsets_from_line_mm: OFFSETS_FROM_LINE_MM.slice(),
        offset_from_line_mm: OFFSETS_FROM_LINE_MM[0] || 0,
        offset_modes: saveModes,
        offset_area_widths_mm: OFFSET_AREA_WIDTHS_MM.slice(),
        offset_layer_names: OFFSET_LAYER_NAMES.slice(),
        layer_name: OFFSET_LAYER_NAMES[0] || DEFAULT_LAYER,
        profile_offset_from_locked_line_mm: readNum('profile_offset_from_locked_line_mm'),
        ring: readRing(),
        mark_back_face: readBackFace(),
        layer: (OFFSET_LAYER_NAMES[0] || DEFAULT_LAYER).trim()
      };
      if (existing && isCustomProfile(existing)) {
        payload.profile_kind = existing.profile_kind;
        payload.profile_centroid = existing.profile_centroid;
        payload.profile_ring = existing.profile_ring;
        payload.profile_label_text = existing.profile_label_text;
        payload.profile_label_height_mm = existing.profile_label_height_mm;
        payload.profile_label_layer_name = existing.profile_label_layer_name;
      } else if (existing && isGroupProfile(existing)) {
        payload.profile_kind = existing.profile_kind;
        payload.group_definition_name = existing.group_definition_name;
        payload.profile_centroid = existing.profile_centroid;
      }
      payload.profile_rotation_quarters = existing && existing.profile_rotation_quarters != null
        ? existing.profile_rotation_quarters
        : 0;
      sketchup.on_marking_save_preset(JSON.stringify(payload));
      EDITING_PRESET_ID = payload.id || EDITING_PRESET_ID;
      showStatus(true, 'preset_saved');
    });

    renderOffsetRows(OFFSETS_FROM_LINE_MM, OFFSET_LAYER_NAMES, OFFSET_MODES, OFFSET_AREA_WIDTHS_MM, EDGE_END_OFFSETS_MM);
    syncDefaultPresetUi();
    // ── Illustration enlarge overlay (created lazily; closes on any click) ──
    function openIllustrationOverlay(url) {
      if (!url || url.indexOf('data:image/') !== 0) return;
      var overlay = document.getElementById('marking-illu-overlay');
      if (!overlay) {
        overlay = document.createElement('div');
        overlay.id = 'marking-illu-overlay';
        var big = document.createElement('img');
        big.id = 'marking-illu-overlay-img';
        big.alt = '';
        overlay.appendChild(big);
        overlay.addEventListener('click', function () {
          overlay.classList.remove('is-open');
        });
        document.body.appendChild(overlay);
      }
      document.getElementById('marking-illu-overlay-img').src = url;
      overlay.classList.add('is-open');
    }

    syncEditingUi();
    renderPresetList();
  })();
  </script>
</body>
</html>
