#tool-body {
  --sk-primary: #5b5ce6;
  --sk-primary-hover: #494acb;
  --sk-card: #ffffff;
  --sk-border: #e5e7eb;
  --sk-text: #1f2937;
  --sk-muted: #6b7280;
  --sk-soft: #f6f7fb;
  --sk-input: #ffffff;
  --sk-code: #111827;
  --sk-code-text: #e5e7eb;
  --sk-tip: #f5f3ff;
  --sk-tip-border: #ddd6fe;
  color: var(--sk-text);
  max-width: 1120px;
  margin: 0 auto;
  font-family: "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif;
}
.theme-dark-mode #tool-body {
  --sk-card: #252528;
  --sk-border: #3a3a3f;
  --sk-text: #e5e7eb;
  --sk-muted: #9ca3af;
  --sk-soft: #1f1f22;
  --sk-input: #1b1b1d;
  --sk-code: #0f172a;
  --sk-code-text: #e5e7eb;
  --sk-tip: #29253d;
  --sk-tip-border: #403a5c;
}
#tool-body * {
  box-sizing: border-box;
}
#tool-body .sg-tip {
  padding: 13px 15px;
  margin-bottom: 16px;
  border: 1px solid var(--sk-tip-border);
  border-radius: 12px;
  background: var(--sk-tip);
  color: var(--sk-text);
  font-size: 13px;
  line-height: 1.7;
}
#tool-body .sg-tip i {
  margin-right: 7px;
  color: var(--sk-primary);
}
#tool-body .sg-card {
  margin-bottom: 16px;
  border: 1px solid var(--sk-border);
  border-radius: 12px;
  background: var(--sk-card);
  overflow: hidden;
}
#tool-body .sg-card-body {
  padding: 16px;
}
#tool-body .sg-toolbar,
#tool-body .sg-actions,
#tool-body .sg-output-head,
#tool-body .sg-preview-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}
#tool-body .sg-toolbar {
  justify-content: space-between;
  margin-bottom: 10px;
}
#tool-body .sg-examples {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
#tool-body .sg-example,
#tool-body .sg-tab {
  height: 32px;
  padding: 0 12px;
  border: 1px solid var(--sk-border);
  border-radius: 999px;
  background: var(--sk-soft);
  color: var(--sk-text);
  cursor: pointer;
  font-size: 12px;
}
#tool-body .sg-example:hover,
#tool-body .sg-tab:hover {
  border-color: var(--sk-primary);
  color: var(--sk-primary);
}
#tool-body .sg-example.is-active,
#tool-body .sg-tab.is-active {
  border-color: var(--sk-primary);
  background: var(--sk-primary);
  color: #ffffff;
}
#tool-body .sg-label {
  display: block;
  margin-bottom: 7px;
  color: var(--sk-text);
  font-size: 13px;
  font-weight: 600;
}
#tool-body .sg-source {
  min-height: 190px;
  resize: vertical;
  background: var(--sk-input);
  color: var(--sk-text);
  font: 12px/1.6 ui-monospace, SFMono-Regular, Consolas, monospace;
}
#tool-body .sg-help {
  margin: 7px 0 0;
  color: var(--sk-muted);
  font-size: 12px;
  line-height: 1.6;
}
#tool-body .sg-actions {
  margin-top: 12px;
}
#tool-body .sg-primary {
  border-color: var(--sk-primary) !important;
  background: var(--sk-primary) !important;
}
#tool-body .sg-primary:hover {
  border-color: var(--sk-primary-hover) !important;
  background: var(--sk-primary-hover) !important;
}
#tool-body .sg-options-toggle {
  width: 100%;
  padding: 13px 16px;
  border: 0;
  background: transparent;
  color: var(--sk-text);
  cursor: pointer;
  text-align: left;
  font-size: 14px;
  font-weight: 600;
}
#tool-body .sg-options-toggle .fa-sliders {
  margin-right: 7px;
  color: var(--sk-primary);
}
#tool-body .sg-options-toggle .fa-angle-down {
  float: right;
  transition: transform .2s;
}
#tool-body .sg-options.is-open .fa-angle-down {
  transform: rotate(180deg);
}
#tool-body .sg-options-body {
  display: none;
  padding: 16px;
  border-top: 1px solid var(--sk-border);
}
#tool-body .sg-options.is-open .sg-options-body {
  display: block;
}
#tool-body .sg-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px 20px;
}
#tool-body .sg-span-2 {
  grid-column: 1 / -1;
}
#tool-body .sg-inline,
#tool-body .sg-colors {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 16px;
}
#tool-body .sg-size {
  display: flex;
  align-items: center;
  gap: 6px;
}
#tool-body .sg-size span,
#tool-body .sg-color-item span {
  color: var(--sk-muted);
  font-size: 12px;
}
#tool-body .sg-size .layui-input {
  width: 88px;
  background: var(--sk-input);
  color: var(--sk-text);
}
#tool-body .sg-color-item {
  display: flex;
  align-items: center;
  gap: 8px;
}
#tool-body .sg-slider {
  padding-top: 6px;
  max-width: 480px;
}
#tool-body .sg-previews {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
  margin-bottom: 16px;
}
#tool-body .sg-preview-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  height: 50px;
  min-height: 50px;
  padding: 9px 13px;
  align-items: center;
  gap: 8px;
  border-bottom: 1px solid var(--sk-border);
}
#tool-body .sg-title {
  grid-column: 1;
  min-width: 0;
  overflow: hidden;
  font-size: 13px;
  font-weight: 600;
  text-overflow: ellipsis;
  white-space: nowrap;
}
#tool-body .sg-meta {
  grid-column: 3;
  justify-self: end;
  min-width: 0;
  overflow: hidden;
  color: var(--sk-muted);
  font-size: 12px;
  text-overflow: ellipsis;
  white-space: nowrap;
}
#tool-body .sg-preview-head .sg-tabs {
  grid-column: 2;
  justify-self: center;
  flex-wrap: nowrap;
  flex-shrink: 0;
  margin-left: 0;
}
#tool-body .sg-preview-head .sg-tab {
  height: 26px;
  padding: 0 9px;
}
#tool-body .sg-preview-stage {
  min-height: 300px;
  padding: 14px;
  background: var(--sk-soft);
  overflow: auto;
}
#tool-body .sg-empty {
  padding: 75px 16px;
  color: var(--sk-muted);
  text-align: center;
  font-size: 13px;
  line-height: 1.7;
}
#tool-body .sg-frame-slot {
  margin: 0 auto;
  transform-origin: top left;
}
#tool-body .sg-frame {
  display: block;
  border: 0;
  border-radius: 9px;
  background: #ffffff;
  box-shadow: 0 7px 22px rgba(15, 23, 42, .12);
  transform-origin: top left;
  pointer-events: none;
}
#tool-body .sg-output-head {
  justify-content: space-between;
  margin-bottom: 10px;
}
#tool-body .sg-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
}
#tool-body .sg-tab {
  border-radius: 8px;
}
#tool-body .sg-output-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
#tool-body .sg-code {
  min-height: 230px;
  resize: vertical;
  border-color: var(--sk-border);
  background: var(--sk-code) !important;
  color: var(--sk-code-text) !important;
  font: 12px/1.6 ui-monospace, SFMono-Regular, Consolas, monospace;
}
@media (max-width: 900px) {
  #tool-body .sg-previews {
    grid-template-columns: 1fr;
  }
}
@media (max-width: 768px) {
  #tool-body .sg-grid {
    grid-template-columns: 1fr;
  }
  #tool-body .sg-span-2 {
    grid-column: auto;
  }
  #tool-body .sg-preview-stage {
    min-height: 250px;
    padding: 10px;
  }
}

樣式"></textarea>
<p class="sg-help">建議同時包含頁面的關鍵 CSS，生成的佈局和尺寸會更準確。</p>

<div class="sg-actions">
<button type="button" class="layui-btn sg-primary" id="toolshu-submit">
<i class="fa fa-magic"></i> 生成骨架屏
</button>
<button type="button" class="layui-btn layui-btn-primary" id="sg-clear">
<i class="fa fa-eraser"></i> 清空輸入
</button>
</div>
</div>
</section>

<section class="sg-card sg-options" id="sg-options">
<button type="button" class="sg-options-toggle" id="sg-options-toggle">
<i class="fa fa-sliders"></i>生成設置
<i class="fa fa-angle-down"></i>
</button>
<div class="sg-options-body">
<div class="sg-grid">
<div class="sg-span-2">
<label class="sg-label">預覽設備與首屏尺寸</label>
<div class="sg-inline">
<input type="radio" name="device" value="mobile" title="手機" lay-filter="sg-device" checked>
<input type="radio" name="device" value="tablet" title="平板" lay-filter="sg-device">
<input type="radio" name="device" value="desktop" title="電腦" lay-filter="sg-device">
<input type="radio" name="device" value="custom" title="自定義" lay-filter="sg-device">
<label class="sg-size"><span>寬</span><input class="layui-input" type="number" name="viewW" value="390" min="280" max="1920" lay-affix="number"></label>
<label class="sg-size"><span>高</span><input class="layui-input" type="number" name="viewH" value="844" min="400" max="2400" lay-affix="number"></label>
</div>
<p class="sg-help">自適應代碼不會鎖定此寬高；該尺寸用於預覽頁面，並決定「首屏貼圖」截取多大的可見區域。</p>
</div>

<div class="sg-span-2">
<label class="sg-label">頁面與骨架顏色</label>
<div class="sg-colors">
<div class="sg-color-item"><span>骨架色</span><div id="sg-bone-picker"></div><input type="hidden" name="boneColor" value="#e5e7eb"></div>
<div class="sg-color-item"><span>頁面底色</span><div id="sg-page-picker"></div><input type="hidden" name="pageColor" value="#ffffff"></div>
</div>
</div>

<div class="sg-span-2">
<label class="sg-label">文字處理方式</label>
<div class="sg-inline">
<input type="radio" name="textMode" value="privacy" title="隱私優先（推薦）" lay-filter="sg-option" checked>
<input type="radio" name="textMode" value="fidelity" title="精準排版" lay-filter="sg-option">
</div>
<p class="sg-help">隱私優先會按實際行寬生成純骨條，結果中不包含原文；精準排版會保留不可見原文，以便在不同容器寬度下獲得最接近原頁面的換行效果。</p>
</div>

<div>
<label class="sg-label">動畫效果</label>
<select name="animation" lay-filter="sg-option">
<option value="shimmer">柔和掃光</option>
<option value="pulse">呼吸閃爍</option>
<option value="none">不使用動畫</option>
</select>
</div>

<div>
<label class="sg-label">圓角方式</label>
<select name="radiusMode" lay-filter="sg-option">
<option value="follow">跟隨原元素</option>
<option value="unified">使用統一圓角</option>
<option value="none">不使用圓角</option>
</select>
</div>

<div class="sg-span-2">
<label class="sg-label">統一圓角大小</label>
<div class="sg-slider" id="sg-radius-slider"></div>
<input type="hidden" name="radius" value="8">
</div>

<div class="sg-span-2">
<label class="sg-label" for="sg-ignore">不生成骨架的選擇器</label>
<input id="sg-ignore" type="text" name="ignore" class="layui-input" storage placeholder=".advertisement, .floating-button, #back-to-top">
<p class="sg-help">多個 CSS 選擇器請用英文逗號分隔。停止輸入約半秒後會自動更新預覽；匹配到的元素及其子元素會從兩種結果中移除。</p>
</div>
</div>

<div class="sg-actions">
<button type="button" class="layui-btn layui-btn-primary layui-btn-sm" id="sg-defaults">
<i class="fa fa-undo"></i> 恢復默認設置
</button>
</div>
</div>
</section>

<div class="sg-previews" id="sg-preview">
<section class="sg-card">
<div class="sg-preview-head">
<span class="sg-title">原頁面預覽</span>
<span class="sg-meta" id="sg-source-meta"></span>
</div>
<div class="sg-preview-stage" id="sg-source-stage">
<div class="sg-empty" id="sg-source-empty">生成後，這裏會顯示經過安全處理的原頁面</div>
<div class="sg-frame-slot" id="sg-source-slot" hidden><iframe class="sg-frame" id="sg-source-frame" sandbox="allow-same-origin" src="about:blank"></iframe></div>
</div>
</section>

<section class="sg-card">
<div class="sg-preview-head">
<span class="sg-title">骨架屏預覽</span>
<span class="sg-tabs">
<button type="button" class="sg-tab is-active" data-preview="adaptive" data-tooltip="保留原頁面的 DOM、Flex、Grid 和媒體查詢，文字會按容器寬度重新換行，適合直接嵌入響應式頁面。">自適應</button>
<button type="button" class="sg-tab" data-preview="snapshot" data-tooltip="按當前預覽寬高提取首屏可見色塊，生成固定比例佈局，適合固定尺寸的首屏佔位。">首屏貼圖</button>
</span>
<span class="sg-meta" id="sg-output-meta"></span>
</div>
<div class="sg-preview-stage" id="sg-output-stage">
<div class="sg-empty" id="sg-output-empty">生成後，可在自適應骨架與首屏貼圖之間切換查看</div>
<div class="sg-frame-slot" id="sg-output-slot" hidden><iframe class="sg-frame" id="sg-output-frame" sandbox="allow-same-origin" src="about:blank"></iframe></div>
</div>
</section>
</div>

<section class="sg-card" id="sg-result" hidden>
<div class="sg-card-body">
<div class="sg-output-head">
<div class="sg-tabs">
<button type="button" class="sg-tab is-active" data-output="adaptive" data-tooltip="完整的自適應骨架代碼，包含原佈局結構、原頁面樣式和骨架樣式，可直接複製使用。">自適應代碼</button>
<button type="button" class="sg-tab" data-output="styles" data-tooltip="可供多個自適應骨架共用的 CSS。頁面已有一份時，無需重複添加。">公共樣式</button>
<button type="button" class="sg-tab" data-output="snapshot" data-tooltip="按當前預覽尺寸生成的完整固定比例首屏貼圖代碼。">首屏貼圖</button>
</div>
<div class="sg-output-actions">
<button type="button" class="layui-btn layui-btn-sm sg-primary" id="sg-copy"><i class="fa fa-copy"></i> 複製當前代碼</button>
<button type="button" class="layui-btn layui-btn-sm layui-btn-primary" id="sg-download"><i class="fa fa-download"></i> 下載 HTML</button>
</div>
</div>
<textarea class="layui-textarea sg-code" id="sg-code" readonly></textarea>
</div>
</section>
</form>

<script>
layui.use(function() {
  var form = layui.form;
  var slider = layui.slider;
  var colorpicker = layui.colorpicker;
  var layer = layui.layer;
  var $root = $('#tool-body');
  var devices = {
    mobile: { w: 390, h: 844 },
    tablet: { w: 768, h: 1024 },
    desktop: { w: 1280, h: 800 }
  };
  var transparentPixel = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=';
  var state = {
    adaptive: '',
      styles: '',
      snapshot: '',
      snapshotBody: '',
      snapshotCss: '',
      blockCount: 0,
      lastIgnore: '',
      preview: 'adaptive',
      output: 'adaptive',
      busy: false,
      generationId: 0,
      pendingScroll: false
  };

  var examples = {
    article: [
      '<style>',
      '.demo-page { max-width: 720px; margin: 0 auto; padding: 24px; font-family: Arial, sans-serif; color: #1f2937; }',
      '.demo-author { display: flex; align-items: center; gap: 12px; margin-bottom: 18px; }',
      '.demo-avatar { width: 48px; height: 48px; border-radius: 50%; object-fit: cover; }',
      '.demo-author strong { display: block; font-size: 15px; }',
      '.demo-author span { display: block; margin-top: 4px; color: #6b7280; font-size: 12px; }',
      '.demo-page h1 { margin: 0 0 16px; font-size: 28px; line-height: 1.35; }',
      '.demo-cover { display: block; width: 100%; aspect-ratio: 16 / 9; border-radius: 12px; object-fit: cover; }',
      '.demo-page p { margin: 16px 0 0; font-size: 15px; line-height: 1.8; color: #374151; }',
      '@media (max-width: 520px) { .demo-page { padding: 16px; } .demo-page h1 { font-size: 23px; } }',
      '
      ',
      '.card-page { padding: 20px; background: #f3f4f6; font-family: Arial, sans-serif; }',
      '.card-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; }',
      '.demo-card { padding: 12px; border-radius: 12px; background: #fff; box-shadow: 0 1px 3px rgba(0,0,0,.08); }',
      '.demo-card img { display: block; width: 100%; aspect-ratio: 4 / 3; border-radius: 9px; object-fit: cover; }',
      '.demo-card h3 { margin: 12px 0 7px; font-size: 16px; line-height: 1.4; }',
      '.demo-card p { margin: 0; color: #6b7280; font-size: 13px; line-height: 1.65; }',
      '@media (max-width: 760px) { .card-grid { grid-template-columns: 1fr; } }',
      '
      ',
      '.product { max-width: 760px; margin: 0 auto; padding: 24px; font-family: Arial, sans-serif; }',
      '.product-layout { display: grid; grid-template-columns: 1.15fr 1fr; gap: 28px; align-items: start; }',
      '.product-image { display: block; width: 100%; aspect-ratio: 1 / 1; border-radius: 14px; object-fit: cover; }',
      '.product h1 { margin: 0; font-size: 24px; line-height: 1.45; }',
      '.product-desc { margin: 12px 0; color: #6b7280; font-size: 14px; line-height: 1.7; }',
      '.product-price { margin: 18px 0; color: #dc2626; font-size: 28px; font-weight: 700; }',
      '.product-buy { width: 100%; height: 44px; border: 0; border-radius: 9px; background: #111827; color: #fff; font-size: 15px; }',
      '.product-spec { display: flex; justify-content: space-between; padding: 12px 0; border-bottom: 1px solid #e5e7eb; font-size: 13px; }',
      '@media (max-width: 640px) { .product { padding: 16px; } .product-layout { grid-template-columns: 1fr; gap: 18px; } }',
      '
      \n' + css + '\n
      html,body{margin:0;min-height:100%;background:' + o.page + ';}
    \n' + state.snapshotCss + '\n
    \n' + state.styles + '\n