/*! IronedBeads · 赛博烫豆 — https://ironedbeads.com
 *  Copyright (c) 2026. All rights reserved. 保留所有权利。
 *  Proprietary, not open source — see /LICENSE. 专有代码，非开源，详见 /LICENSE。
 */
/* hidden 属性必须真的能藏住东西。
 *
 * 浏览器自带的 [hidden] { display: none } 写在 UA 样式表里，优先级低于任何
 * 类选择器。所以 `.login-tabs { display: grid }` 或 `.dropdown-menu button
 * { display: grid }` 会把它盖掉——元素明明 hidden = true，却照样显示在页面上。
 * 这个坑今天踩了三次（登录框的昵称字段、页签栏、账号菜单里的「验证邮箱」）。
 *
 * 加 !important 在这里是安全的：全站只有登录框和账号菜单那几处用 hidden 属性，
 * 其余显隐一律走 .is-hidden 类，不受影响。 */
[hidden] {
  display: none !important;
}

@font-face {
  font-family: "Fredoka One";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("./assets/fonts/fredoka-one.023cf4e467.ttf") format("truetype");
}

:root {
  color-scheme: light;
  --bg: #f1f4f2;
  --surface: #ffffff;
  --surface-soft: #f7f9f8;
  --surface-strong: #e9eeeb;
  --text: #202928;
  --muted: #68726f;
  --line: #d7dedb;
  --line-strong: #b9c5c0;
  --ink: #1d2929;
  --teal: #27877f;
  --teal-dark: #17665f;
  --coral: #e45b64;
  --coral-dark: #c74450;
  --yellow: #f4c84a;
  --blue: #4f7fbe;
  /* 页面级背景：米白渐变到淡黄，原来是三张 webp 背景图（狗 / 散落的豆子），
     现统一用这一个渐变，改色只改这里。 */
  --bg-cream-gradient:
    radial-gradient(90% 70% at 22% 18%, rgba(255, 255, 255, 0.55) 0%, rgba(255, 255, 255, 0) 65%),
    linear-gradient(135deg, #fbf9f2 0%, #f8f3e3 52%, #faefcb 100%);
  --shadow: 0 14px 36px rgba(31, 44, 41, 0.09);
  /* 原来第一项是 Inter，但项目从未加载过它（只有 Fredoka One 有 @font-face），
     于是数字走系统 SF Pro、汉字走 PingFang，两个家族混排显得不统一。
     把中文字体提前，让中西文出自同一家族。 */
  font-family:
    "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", ui-sans-serif, system-ui,
    -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  font-variant-numeric: tabular-nums;
}

/* Infinite editor workspace */
body[data-view="editor"] {
  overflow: hidden;
}

.history-cluster {
  display: flex;
  gap: 5px;
}

.history-cluster .icon-button {
  height: 38px;
  min-height: 38px;
  width: 38px;
}

.workspace {
  gap: 10px;
  grid-template-columns: minmax(480px, 1fr) 324px;
  height: calc(100vh - 72px);
  max-width: none;
  padding: 10px;
}

.recent-color-button.active {
  border-color: #ffffff;
  box-shadow: 0 0 0 2px #1f2a2b, 0 3px 8px rgba(31, 42, 43, 0.16);
}

.recent-color-button.active::after {
  background: #1f2a2b;
  border-radius: 999px;
  bottom: -7px;
  content: "";
  height: 2px;
  left: 50%;
  position: absolute;
  transform: translateX(-50%);
  width: 18px;
}

#patternCanvas {
  background: transparent;
  height: 100%;
  inset: 0;
  position: absolute;
  width: 100%;
}

.editor-command-bar,
.selection-actions,
.floating-toolbox {
  align-items: stretch;
  backdrop-filter: blur(14px);
  background: rgba(255, 255, 255, 0.94);
  border: 1px solid rgba(213, 222, 231, 0.92);
  box-shadow: 0 8px 24px rgba(32, 48, 67, 0.14);
  display: flex;
  position: absolute;
  z-index: 8;
}

.editor-command-bar {
  border-radius: 8px;
  left: 50%;
  max-width: calc(100% - 28px);
  overflow-x: auto;
  top: 12px;
  transform: translateX(-50%);
}

.editor-command-bar button,
.selection-actions button,
.floating-toolbox .tool-button {
  align-items: center;
  background: transparent;
  border: 0;
  border-radius: 6px;
  color: #647080;
  display: grid;
  flex: 0 0 auto;
  gap: 4px;
  justify-items: center;
  min-height: 58px;
  min-width: 66px;
  padding: 7px 9px;
}

.editor-command-bar button > span,
.selection-actions button > span,
.floating-toolbox .tool-button > span {
  font-size: 20px;
  line-height: 1;
}

.editor-command-bar .colors-tool-icon,
.editor-command-bar .grid-tool-icon,
.editor-command-bar .layers-tool-icon,
.editor-command-bar .locate-tool-icon,
.editor-command-bar .mirror-tool-icon,
.editor-command-bar .size-tool-icon,
.selection-actions .mirror-tool-icon,
.completion-actions .locate-tool-icon,
.completion-actions .grid-tool-icon,
.completion-actions .colors-tool-icon {
  display: inline-grid;
  height: 22px;
  place-items: center;
  width: 22px;
}

.editor-command-bar .colors-tool-icon svg,
.editor-command-bar .grid-tool-icon svg,
.editor-command-bar .layers-tool-icon svg,
.editor-command-bar .locate-tool-icon svg,
.editor-command-bar .mirror-tool-icon svg,
.editor-command-bar .size-tool-icon svg,
.selection-actions .mirror-tool-icon svg,
.completion-actions .locate-tool-icon svg,
.completion-actions .grid-tool-icon svg,
.completion-actions .colors-tool-icon svg {
  display: block;
  fill: none;
  height: 22px;
  stroke: currentColor;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-width: 2;
  width: 22px;
}

.editor-command-bar .colors-tool-icon circle,
.completion-actions .colors-tool-icon circle {
  fill: currentColor;
  stroke: none;
}

.editor-command-bar .grid-tool-accent,
.editor-command-bar .tool-icon-accent,
.selection-actions .tool-icon-accent,
.completion-actions .tool-icon-accent,
.completion-actions .grid-tool-accent {
  stroke: #2f73df;
  stroke-width: 2.8;
}

.editor-command-bar .grid-tool-icon svg,
.editor-command-bar .layers-tool-icon svg,
.editor-command-bar .locate-tool-icon svg,
.editor-command-bar .mirror-tool-icon svg,
.editor-command-bar .size-tool-icon svg,
.selection-actions .mirror-tool-icon svg,
.completion-actions .locate-tool-icon svg,
.completion-actions .grid-tool-icon svg {
  stroke-width: 2.6;
}

.editor-command-bar small,
.selection-actions small,
.floating-toolbox small {
  font-size: 10px;
  font-weight: 850;
  white-space: nowrap;
}

.editor-command-bar button:hover,
.selection-actions button:hover,
.floating-toolbox .tool-button:hover {
  background: #eef4ff;
  color: #2868df;
}

.editor-command-bar button.active,
.floating-toolbox .tool-button.active,
.selection-actions button.active {
  background: #2868df;
  color: #ffffff;
}

.editor-command-bar .command-done {
  background: #2868df;
  color: #ffffff;
  margin-left: 5px;
}

.background-preset-grid button.active {
  border-color: #3478ee;
  box-shadow: 0 0 0 2px rgba(52, 120, 238, 0.2);
}

input[type="color"] {
  border: 1px solid #d8e0ea;
  height: 34px;
  min-height: 34px;
  padding: 3px;
  width: 54px;
}

.board-size-presets button.active {
  background: #eef5ff;
  border-color: #347be6;
  box-shadow: inset 0 0 0 1px rgba(52, 123, 230, 0.36);
}

.legacy-line-fields.is-hidden {
  display: none;
}

.line-control-button:hover,
.line-control-button.active {
  border-color: #8eb5f5;
  box-shadow: 0 0 0 2px rgba(52, 120, 238, 0.12);
}

.line-color-presets button.active {
  border-color: #3478ee;
  box-shadow: 0 0 0 2px rgba(52, 120, 238, 0.18);
}

.line-style-options button:hover,
.line-style-options button.active {
  background: #f4f8ff;
  color: #2f6ee5;
}

.line-width-options button.active {
  background: #3478ee;
  color: #ffffff;
}

.color-stat-row.pending {
  background: #eef4ff;
  border-radius: 6px;
}

.layer-import-wrap {
  min-width: 0;
  position: relative;
}

.layer-import-wrap > button {
  width: 100%;
}

.layer-row.active {
  border-color: #4c8af1;
  box-shadow: 0 0 0 2px rgba(76, 138, 241, 0.14);
}

.layer-row:not(.active) .layer-controls {
  display: none;
}

.layer-row:not(.active) {
  gap: 0;
  padding-bottom: 8px;
  padding-top: 8px;
}

.layer-row:not(.active) .layer-thumbnail {
  height: 36px;
  width: 36px;
}

.layer-row:not(.active) .layer-main {
  grid-template-columns: 22px 18px 22px 36px minmax(90px, 1fr) auto 32px;
}

.confirm-dialog {
  background: transparent;
  border: 0;
  padding: 0;
}

.confirm-dialog::backdrop {
  background: rgba(26, 37, 51, 0.38);
  backdrop-filter: blur(2px);
}

.confirm-card {
  background: #ffffff;
  border: 1px solid #dce3ec;
  border-radius: 8px;
  box-shadow: 0 18px 54px rgba(30, 43, 59, 0.2);
  display: grid;
  gap: 20px;
  padding: 22px;
  width: min(420px, calc(100vw - 28px));
}

.confirm-card strong {
  font-size: 18px;
}

.confirm-card p {
  color: var(--muted);
  font-size: 12px;
  line-height: 1.6;
  margin: 8px 0 0;
}

.confirm-card .button-row {
  align-items: center;
  justify-content: flex-end;
}

/* 确认框右上角的关闭叉、左下角的「不再提示」。手机和电脑共用一套。 */
.confirm-card {
  position: relative;
}

/* 标题那一行给关闭叉让出位置，别让长标题压到它下面 */
.confirm-card > div:first-child {
  padding-right: 28px;
}

.confirm-close {
  background: none;
  border: 0;
  border-radius: 8px;
  color: #68726f;
  cursor: pointer;
  font-size: 15px;
  line-height: 1;
  padding: 6px 8px;
  position: absolute;
  right: 8px;
  top: 8px;
}

.confirm-close:hover,
.confirm-close:focus-visible {
  background: #f1f4f2;
  color: #202928;
}

/* margin-right: auto 把它顶到最左，右边那两颗按钮仍然贴右 */
.confirm-never {
  align-items: center;
  color: #68726f;
  cursor: pointer;
  display: inline-flex;
  font-size: 13px;
  font-weight: 700;
  gap: 6px;
  margin-right: auto;
}

/* 复选框本身走全站那一套自绘样式（见上面 .direct-check-row 那一组，
   .confirm-never 已经并进去了）。这里不再单独设尺寸和描边——之前漏了这一步，
   通用的 input 规则给它套上了 37px 高、带边框的外框，很难看。 */

.home-save-card .button-row {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
}

.home-save-card .button-row button {
  min-height: 38px;
}

.inspector {
  min-height: 0;
}

@media (max-width: 1040px) {
  .workspace {
    grid-template-columns: minmax(420px, 1fr) 286px;
  }

  .editor-center .top-status span:nth-child(4) {
    display: none;
  }
}

@media (max-width: 900px) {
  body[data-view="editor"] {
    overflow: auto;
  }

  body[data-view="editor"] .topbar {
    position: sticky;
  }

  .editor-center {
    margin-left: auto;
  }

  .editor-center .top-status {
    display: none;
  }

  .workspace {
    display: grid;
    grid-template-areas: "board" "inspector";
    grid-template-columns: 1fr;
    height: auto;
    min-height: calc(100vh - 72px);
  }

  .board-panel {
    grid-area: board;
    min-height: 700px;
  }

  .inspector {
    grid-area: inspector;
    max-height: 560px;
  }

  .editor-command-bar button,
  .selection-actions button,
  .floating-toolbox .tool-button {
    min-width: 60px;
  }

  .palette-grid {
    grid-template-columns: repeat(8, minmax(0, 1fr));
  }
}

@media (max-width: 620px) {
  .workspace {
    padding: 6px;
  }

  .board-panel {
    min-height: 650px;
  }

  .board-toolbar {
    align-items: center;
    flex-direction: row;
    min-height: 64px;
  }

  .board-toolbar-actions .ghost-button {
    display: none;
  }

  .recent-colors > span {
    display: none;
  }

  .recent-color-list {
    max-width: 210px;
  }

  .footer-brush-control {
    display: none;
  }

  .canvas-wrap {
    min-height: 520px;
  }

  .editor-command-bar button,
  .selection-actions button,
  .floating-toolbox .tool-button {
    min-height: 54px;
    min-width: 56px;
    padding: 6px;
  }

  .editor-detail-panel {
    left: 8px;
    max-height: calc(100% - 104px);
    top: 78px;
    width: calc(100% - 16px);
  }

  .grid-line-row {
    grid-template-columns: 52px minmax(102px, 1fr) 48px;
  }

  .grid-line-row select {
    grid-column: 2 / -1;
  }

  .palette-grid {
    grid-template-columns: repeat(5, minmax(0, 1fr));
  }

  /* 徽章现在要区分「图片 / 像素」，窄屏下缩小而不是藏掉 */
  .layer-type {
    font-size: 9px;
    padding: 2px 4px;
  }
}

/* Confirmed editor, palette, completion, and project library layout */
body[data-view="editor"][data-editor-mode="edit"] .topbar {
  display: grid;
  gap: 14px;
  grid-template-columns: auto minmax(0, 1fr) auto;
  min-height: 86px;
  padding: 8px 18px;
}

body[data-view="editor"][data-editor-mode="edit"] .brand-button {
  min-width: 174px;
}

body[data-view="editor"][data-editor-mode="edit"] .history-cluster {
  flex: 0 0 auto;
}

body[data-view="editor"][data-editor-mode="edit"] .history-cluster .icon-button {
  background: #ffffff;
  border-color: #d9dfdc;
  color: #66716e;
  height: 44px;
  min-height: 44px;
  width: 40px;
}

body[data-view="editor"][data-editor-mode="edit"] .top-actions {
  flex: 0 0 auto;
}

body[data-view="editor"][data-editor-mode="edit"] .top-actions button {
  font-size: 11px;
  min-height: 42px;
  padding: 8px 10px;
  white-space: nowrap;
}

body[data-view="editor"][data-editor-mode="edit"] .workspace {
  display: grid;
  gap: 0;
  grid-template-columns: minmax(0, 1fr);
  height: calc(100dvh - 86px);
  min-height: 0;
  padding: 8px;
}

body[data-view="editor"][data-editor-mode="edit"] .inspector {
  display: none !important;
}

.quick-palette-chip.active {
  border-color: #ffffff;
  box-shadow: 0 0 0 2px #1f2a2b, 0 3px 8px rgba(31, 42, 43, 0.16);
}

.quick-palette-chip.active::after {
  background: #1f2a2b;
  border-radius: 999px;
  bottom: -8px;
  content: "";
  height: 2px;
  left: 50%;
  position: absolute;
  transform: translateX(-50%);
  width: 18px;
}

.palette-preset-buttons button.active {
  background: #347be6;
  border-color: #347be6;
  color: #ffffff;
}

.palette-dialog-brands button:hover:not(.active) {
  background: #f4f8ff;
  color: #2868df;
}

.palette-dialog-brands button.active {
  background: #eef4ff;
  border-bottom-color: transparent;
  color: #2f73df;
}

.palette-dialog-brands button.active em {
  color: #5b8ad6;
}

.palette-dialog-brands button.active::before {
  background: #2f73df;
  border-radius: 2px;
  content: "";
  height: 17px;
  left: 0;
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 3px;
}

.palette-dialog-brands button.active b {
  padding-left: 9px;
}

.palette-dialog-tabs button.active {
  border-bottom-color: #347be6;
  color: #347be6;
}

.palette-family-grid button.active {
  border-color: #77a7ff;
  box-shadow: 0 0 0 2px rgba(52, 123, 230, 0.22);
}

/* Independent project library */
body[data-view="projects"] {
  background: #f6f8f7;
}

body[data-view="projects"] .topbar {
  min-height: 72px;
}

body[data-view="projects"] .top-actions {
  margin-left: auto;
}

.project-view-toggle button.active {
  background: #347be6;
  color: #ffffff;
}

.project-select-button.active {
  background: #eef5ff;
  border-color: #8eb5ee;
  color: #2868df;
}

.projects-view .project-card:hover,
.projects-view .project-card.selected {
  border-color: #75a5ed;
  box-shadow: 0 8px 22px rgba(36, 77, 132, 0.1);
  transform: translateY(-1px);
}

.project-sync-badge.synced {
  background: rgba(234, 247, 240, 0.96);
  border-color: #b9dfc9;
  color: #157453;
}

.project-card-meta span.made {
  background: #eaf7f0;
  border-color: #b9dfc9;
  color: #157453;
}

/* Completion toolbar and read-only panels */
.completion-actions button.active {
  background: #eef4ff;
  color: #2868df;
}

@media (max-width: 1450px) {
  body[data-view="editor"][data-editor-mode="edit"] .topbar {
    gap: 9px;
    padding-left: 12px;
    padding-right: 12px;
  }

  body[data-view="editor"][data-editor-mode="edit"] .brand-button {
    min-width: 142px;
    width: 142px;
  }

  body[data-view="editor"][data-editor-mode="edit"] .header-command-bar button {
    min-width: 52px;
    padding-left: 5px;
    padding-right: 5px;
  }

  body[data-view="editor"][data-editor-mode="edit"] .top-actions button {
    font-size: 10px;
    padding-left: 8px;
    padding-right: 8px;
  }

  body[data-view="editor"][data-editor-mode="complete"] .topbar {
    display: grid;
    grid-template-areas:
      "brand actions"
      "summary summary";
    grid-template-columns: auto minmax(0, 1fr);
    min-height: 142px;
    row-gap: 6px;
  }

  body[data-view="editor"][data-editor-mode="complete"] .brand-button {
    grid-area: brand;
  }

  body[data-view="editor"][data-editor-mode="complete"] .completion-actions {
    grid-area: actions;
    justify-self: end;
  }

  body[data-view="editor"][data-editor-mode="complete"] .completion-summary {
    grid-area: summary;
    justify-self: center;
    left: auto;
    position: static;
    top: auto;
    transform: none;
  }

  body[data-view="editor"][data-editor-mode="complete"] .workspace {
    height: calc(100dvh - 142px);
  }
}

@media (max-width: 1120px) {
  body[data-view="editor"][data-editor-mode="edit"] {
    overflow: hidden;
  }

  body[data-view="editor"][data-editor-mode="edit"] .topbar {
    grid-template-areas:
      "brand actions"
      "commands commands";
    grid-template-columns: auto minmax(0, 1fr);
    min-height: 146px;
  }

  body[data-view="editor"][data-editor-mode="edit"] .brand-button {
    grid-area: brand;
  }

  body[data-view="editor"][data-editor-mode="edit"] .editor-center {
    grid-area: commands;
    justify-content: center;
  }

  body[data-view="editor"][data-editor-mode="edit"] .top-actions {
    grid-area: actions;
    justify-self: end;
  }

  body[data-view="editor"][data-editor-mode="edit"] .workspace {
    height: calc(100dvh - 146px);
    min-height: 0;
  }

  .projects-toolbar {
    align-items: stretch;
    flex-direction: column;
  }

  .projects-controls {
    justify-content: flex-start;
  }

  .project-search {
    flex: 1;
  }

  .palette-family-grid {
    gap: 12px 14px;
    grid-template-columns: repeat(6, 56px);
  }
}

@media (max-width: 720px) {
  body[data-view="editor"][data-editor-mode="edit"] .topbar {
    gap: 6px;
    grid-template-areas:
      "brand actions"
      "commands commands";
    min-height: 140px;
    padding: 6px 8px;
  }

  body[data-view="editor"][data-editor-mode="edit"] .brand-button {
    min-width: 112px;
    width: 112px;
  }

  body[data-view="editor"][data-editor-mode="edit"] .brand-lockup {
    gap: 6px;
  }

  body[data-view="editor"][data-editor-mode="edit"] .brand-symbol {
    height: 34px;
  }

  body[data-view="editor"][data-editor-mode="edit"] .brand-wordmark-image {
    height: 25px;
  }

  body[data-view="editor"][data-editor-mode="edit"] .top-actions {
    gap: 4px;
    overflow-x: auto;
  }

  body[data-view="editor"][data-editor-mode="edit"] .top-actions button {
    font-size: 0;
    height: 38px;
    min-height: 38px;
    padding: 6px 9px;
  }

  body[data-view="editor"][data-editor-mode="edit"] .top-actions button span {
    font-size: 15px;
  }

  body[data-view="editor"][data-editor-mode="edit"] .editor-center {
    gap: 5px;
    justify-content: stretch;
    min-width: 0;
  }

  body[data-view="editor"][data-editor-mode="edit"] .history-cluster .icon-button {
    height: 40px;
    min-height: 40px;
    width: 34px;
  }

  body[data-view="editor"][data-editor-mode="edit"] .header-command-bar {
    display: flex;
    flex: 1;
    left: auto;
    max-width: none;
    overflow-x: auto;
    padding: 0;
    position: static;
    right: auto;
    transform: none;
  }

  body[data-view="editor"][data-editor-mode="edit"] .header-command-bar button {
    min-height: 48px;
    min-width: 46px;
  }

  body[data-view="editor"][data-editor-mode="edit"] .header-command-bar .command-done {
    min-height: 42px;
  }

  body[data-view="editor"][data-editor-mode="edit"] .workspace {
    height: calc(100dvh - 140px);
    min-height: 0;
    padding: 4px;
  }

  body[data-view="editor"][data-editor-mode="edit"] .board-panel {
    min-height: 0;
  }

  body[data-view="editor"][data-editor-mode="edit"] .canvas-wrap {
    min-height: 0;
  }

  .palette-quick-row,
  .recent-toolbar-row {
    padding-left: 8px;
    padding-right: 8px;
  }

  .recent-toolbar-row .board-toolbar-actions .ghost-button {
    display: none;
  }

  .floating-toolbox .tool-button {
    min-width: 54px;
  }

  .floating-brush-control {
    flex-basis: 96px;
  }

  .palette-dialog {
    width: calc(100vw - 16px);
  }

  .palette-dialog-card {
    max-height: 92dvh;
  }

  .palette-dialog-header,
  .share-dialog-card > header {
    min-height: 60px;
    padding: 12px 16px;
  }

  .palette-dialog-header h2,
  .share-dialog-card h2 {
    font-size: 20px;
  }

  .palette-dialog-controls {
    padding: 12px 14px 10px;
  }

  .palette-dialog-body {
    gap: 10px;
    grid-template-columns: 1fr;
    padding: 0 14px 14px;
  }

  .palette-dialog-sidebar {
    padding-top: 0;
  }

  .palette-dialog-brands {
    display: flex;
    gap: 8px;
    overflow-x: auto;
    padding-bottom: 5px;
  }

  .palette-dialog-brands > span {
    flex: 0 0 auto;
    font-size: 18px;
    margin: 0;
    padding-top: 14px;
  }

  .palette-dialog-brands button {
    flex: 0 0 auto;
    font-size: 16px;
    min-height: 46px;
    padding: 8px 14px;
  }

  .palette-group-list {
    padding-left: 0;
    padding-right: 0;
  }

  .palette-family-grid {
    gap: 10px 12px;
    grid-template-columns: repeat(4, 54px);
  }

  body[data-view="projects"] .topbar {
    min-height: 72px;
    padding: 8px 12px;
  }

  body[data-view="projects"] .brand-button {
    min-width: 130px;
    width: 130px;
  }

  .projects-view {
    min-height: calc(100dvh - 68px);
    padding: 20px 14px 42px;
  }

  .projects-controls {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto auto;
  }

  .project-search {
    min-width: 0;
  }

  .project-collection {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px;
    padding-left: 0;
    padding-right: 0;
  }

  .projects-view .project-card {
    grid-template-rows: 118px auto;
    min-height: 212px;
  }

  .project-thumbnail-button,
  .projects-view .project-thumbnail {
    height: 118px;
  }

  .project-card-meta span:last-child {
    display: none;
  }

  .project-collection.list-view .project-card {
    grid-template-columns: 124px minmax(0, 1fr);
  }

  body[data-view="editor"][data-editor-mode="complete"] .topbar {
    display: grid;
    grid-template-areas:
      "brand"
      "actions"
      "summary";
    grid-template-columns: minmax(0, 1fr);
    min-height: 198px;
    padding: 6px 8px;
  }

  body[data-view="editor"][data-editor-mode="complete"] .brand-button {
    width: 124px;
  }

  body[data-view="editor"][data-editor-mode="complete"] .completion-actions {
    justify-self: stretch;
    margin: 0;
    overflow-x: auto;
    width: 100%;
  }

  body[data-view="editor"][data-editor-mode="complete"] .completion-actions button {
    flex: 0 0 50px;
    width: 50px;
  }

  body[data-view="editor"][data-editor-mode="complete"] .completion-actions .completion-projects-button {
    flex-basis: 68px;
    width: 68px;
  }

  body[data-view="editor"][data-editor-mode="complete"] .completion-summary {
    justify-self: stretch;
    width: 100%;
  }

  body[data-view="editor"][data-editor-mode="complete"] .workspace {
    height: calc(100dvh - 198px);
  }
}

@media (max-width: 430px) {
  .projects-controls {
    grid-template-columns: minmax(0, 1fr) auto;
  }

  .project-select-button,
  .project-create-menu-wrap {
    grid-row: 2;
  }

  .project-search {
    grid-column: 1 / -1;
  }

  .project-collection {
    grid-template-columns: minmax(0, 1fr);
  }

  .projects-view .project-card {
    grid-template-rows: 160px auto;
  }

  .project-thumbnail-button,
  .projects-view .project-thumbnail {
    height: 160px;
  }

  .project-collection.list-view .project-card {
    grid-template-columns: 112px minmax(0, 1fr);
    grid-template-rows: 104px;
  }

  .project-collection.list-view .project-thumbnail-button,
  .project-collection.list-view .project-thumbnail {
    height: 104px;
  }
}

* {
  box-sizing: border-box;
}

html,
body {
  min-height: 100%;
}

/* 手机浏览器点按时会在元素上盖一块半透明色块（点按高亮），按元素的矩形铺、不管圆角——
   圆按钮外面就露出一个浅蓝 / 浅灰的方块，看着像多了一圈带颜色的框。
   这个属性会一路继承，写在 html 上全站所有按钮、链接、可点的元素都关掉了，脚本后来生成的也算。
   点下去的反馈交给各个按钮自己的按下样式（下沉、阴影变浅之类）。 */
html {
  -webkit-tap-highlight-color: transparent;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
}

button,
input,
select {
  font: inherit;
  letter-spacing: 0;
}

button:disabled {
  cursor: not-allowed;
  opacity: 0.48;
}

h1,
h2,
p {
  margin-top: 0;
}

h1,
h2 {
  color: var(--ink);
  margin-bottom: 0;
}

.is-hidden {
  display: none !important;
}

.app-shell {
  min-height: 100vh;
}

.topbar {
  align-items: center;
  background: rgba(255, 255, 255, 0.96);
  border-bottom: 1px solid var(--line);
  display: flex;
  gap: 18px;
  justify-content: space-between;
  min-height: 72px;
  padding: 10px 22px;
  position: sticky;
  top: 0;
  z-index: 20;
}

.direct-header-title {
  color: #2f73df;
  flex: 1 1 auto;
  font-size: 24px;
  font-weight: 900;
  letter-spacing: 0;
  line-height: 1.2;
  margin-left: 8px;
  text-align: left;
}

.brand-button {
  align-items: center;
  background: transparent;
  color: var(--ink);
  display: inline-flex;
  gap: 11px;
  min-width: 206px;
  padding: 0;
  text-align: left;
}

.top-actions,
.home-heading-actions,
.source-actions,
.button-row,
.export-actions,
.board-toolbar-actions {
  align-items: center;
  display: flex;
  gap: 8px;
}

.primary-button,
.ghost-button,
.danger-button,
.icon-button,
.text-button {
  align-items: center;
  border-radius: 6px;
  display: inline-flex;
  font-size: 13px;
  font-weight: 800;
  gap: 6px;
  justify-content: center;
  min-height: 38px;
  padding: 8px 12px;
  text-decoration: none;
  transition: background 150ms ease, border-color 150ms ease, color 150ms ease, transform 150ms ease;
  white-space: nowrap;
}

.primary-button {
  background: var(--ink);
  color: #ffffff;
}

.primary-button:hover {
  background: #30403f;
}

.ghost-button {
  background: var(--surface);
  border: 1px solid var(--line);
  color: var(--ink);
}

.ghost-button:hover {
  background: var(--surface-strong);
  border-color: var(--line-strong);
}

.ghost-button.active {
  background: var(--ink);
  border-color: var(--ink);
  color: #ffffff;
}

.danger-button {
  background: #fff0f1;
  border: 1px solid #f2c8cc;
  color: #a8323e;
}

.danger-button:hover {
  background: #fbe2e5;
}

.primary-button:active,
.ghost-button:active,
.danger-button:active,
.icon-button:active {
  transform: translateY(1px);
}

.setup-view {
  margin: 0 auto;
  max-width: 1380px;
  padding: 34px 24px 52px;
}

.source-card,
.setup-panel,
.tool-rail,
.board-panel,
.inspector {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow: 0 8px 26px rgba(31, 44, 41, 0.06);
  min-width: 0;
}

.source-stage {
  aspect-ratio: 4 / 3;
  background: #edf1ef;
  border: 1px dashed var(--line-strong);
  border-radius: 8px;
  min-height: 360px;
  overflow: hidden;
  position: relative;
}

.source-preview-toggle.active {
  background: var(--ink);
  border-color: var(--ink);
  color: #ffffff;
}

.direct-upload-overlay input,
#patternImport {
  display: none;
}

.upload-icon {
  align-items: center;
  background: var(--ink);
  border-radius: 50%;
  color: #ffffff;
  display: inline-flex;
  font-size: 24px;
  height: 52px;
  justify-content: center;
  width: 52px;
}

body[data-view="setup"][data-module="style"] {
  overflow: hidden;
}

body[data-view="setup"][data-module="style"] .app-shell,
body[data-view="setup"][data-module="direct"] .app-shell {
  display: grid;
  grid-template-rows: auto minmax(0, 1fr);
  height: 100vh;
  height: 100dvh;
  min-height: 0;
  overflow: hidden;
}

body[data-view="setup"][data-module="style"] .setup-view {
  height: 100%;
  max-width: none;
  min-height: 0;
  overflow: hidden;
  padding: 18px clamp(14px, 2vw, 28px) 20px;
  width: 100%;
}

body[data-view="setup"][data-module="style"] .source-stage {
  aspect-ratio: auto;
  height: 100%;
  min-height: 0;
}

body[data-view="setup"][data-module="direct"] {
  overflow: hidden;
}

.setup-view.direct-setup-active {
  max-width: none;
  padding: 12px;
}

body[data-view="setup"][data-module="direct"] .setup-view.direct-setup-active {
  height: 100%;
  min-height: 0;
  overflow: hidden;
  padding: 58px 12px 12px;
  width: 100%;
}

.setup-view.direct-align-active {
  max-width: none;
  padding: 12px;
}

.direct-wizard {
  display: grid;
  gap: 14px;
  margin: 0 auto;
  max-width: 1180px;
  position: relative;
}

.direct-recognition-overlay {
  align-items: center;
  backdrop-filter: blur(1.5px);
  background: rgba(246, 249, 248, 0.72);
  display: flex;
  inset: 72px 0 0;
  justify-content: center;
  pointer-events: auto;
  position: fixed;
  z-index: 29;
}

.direct-recognition-card {
  align-items: center;
  background: rgba(255, 255, 255, 0.97);
  border: 1px solid #e2e8ef;
  border-radius: 14px;
  box-shadow: 0 16px 40px rgba(31, 44, 41, 0.16);
  display: grid;
  gap: 4px;
  justify-items: center;
  padding: 20px 28px;
}

.direct-recognition-spinner {
  animation: direct-recognition-spin 0.8s linear infinite;
  border: 2.5px solid #dfe6ef;
  border-radius: 50%;
  border-top-color: #2868df;
  height: 26px;
  margin-bottom: 6px;
  width: 26px;
}

@keyframes direct-recognition-spin {
  to { transform: rotate(360deg); }
}

.direct-recognition-overlay strong {
  color: #1d2734;
  font-size: 15px;
  font-weight: 800;
  letter-spacing: 0.02em;
}

.direct-recognition-overlay small {
  color: #8a94a4;
  font-size: 12px;
}

@media (prefers-reduced-motion: reduce) {
  .direct-recognition-spinner { animation-duration: 2.4s; }
}

.direct-wizard.direct-recognizing .direct-stage[data-direct-panel="align"] {
  filter: saturate(0.88);
  user-select: none;
}

.direct-setup-active .direct-wizard {
  padding-top: 0;
}

.direct-wizard.direct-align-workspace {
  max-width: none;
  width: 100%;
}

.setup-view.direct-setup-active .direct-wizard {
  max-width: none;
  width: 100%;
}

body[data-view="setup"][data-module="direct"] .setup-view.direct-setup-active .direct-wizard {
  grid-template-rows: minmax(0, 1fr);
  height: 100%;
  min-height: 0;
  overflow: hidden;
}

/* 无外框：每个步骤按钮自己有底色和描边，外面再套一层框是多余的一圈。 */
.direct-stepper {
  align-items: center;
  display: flex;
  gap: 6px;
  justify-content: center;
  padding: 8px 12px;
}

/* 识别流程从顶栏中间下沉为第二行。右上角的 控制台/上一步/下一步 仍沿用
   .direct-footer 的原位置和样式，这里只让步骤变成低噪声的进度提示。 */
.direct-setup-active .direct-stepper {
  align-items: center;
  background: rgba(247, 249, 248, 0.96);
  border-bottom: 1px solid var(--line);
  border-top: 1px solid var(--line);
  box-shadow: 0 8px 20px rgba(31, 44, 41, 0.04);
  height: 46px;
  left: 0;
  max-width: none;
  min-width: 0;
  overflow-x: auto;
  padding: 0 18px;
  pointer-events: none;
  position: fixed;
  top: 72px;
  transform: none;
  width: 100%;
  z-index: 19;
}

.direct-setup-active .direct-stepper > * {
  pointer-events: auto;
}

.direct-setup-active .direct-step-button {
  background: transparent;
  border-color: transparent;
  color: #68726f;
  gap: 6px;
  min-height: 28px;
  min-width: 0;
  padding: 2px 0;
}

.direct-setup-active .direct-step-button::before {
  background: #ffffff;
  border: 1px solid #9cbbee;
  border-radius: 50%;
  content: "";
  height: 8px;
  width: 8px;
}

/* 箭头也走 flex 居中：字形在行盒里本来就不居中，靠 line-height 对不准。 */
.direct-stepper > span {
  align-items: center;
  color: #7aa3e3;
  display: inline-flex;
  font-size: 18px;
  line-height: 1;
}

.direct-step-button,
.direct-outline-button,
.direct-board-sizes button,
.direct-icon-button,
.direct-round-button {
  background: #ffffff;
  border: 1px solid #b9cbe6;
  border-radius: 6px;
  color: #243033;
  cursor: pointer;
  font: inherit;
  font-size: 12px;
  font-weight: 850;
  line-height: 1.1;
  min-height: 32px;
  padding: 5px 8px;
}

.direct-step-button {
  align-items: center;
  display: inline-flex;
  justify-content: center;
  min-width: 92px;
  padding: 6px 12px;
}

.direct-step-button.reached {
  background: #eef5ff;
  border-color: #8eb2ea;
  color: #255da8;
}

.direct-step-button.active,
.direct-outline-button.active,
.direct-board-sizes button.active {
  background: #2f73df;
  border-color: #2f73df;
  color: #ffffff;
}

.direct-setup-active .direct-step-button.reached,
.direct-setup-active .direct-step-button.active {
  background: transparent;
  border-color: transparent;
}

.direct-setup-active .direct-step-button.reached {
  color: #255da8;
}

.direct-setup-active .direct-step-button.reached::before {
  background: #2f73df;
  border-color: #2f73df;
}

.direct-setup-active .direct-step-button.active {
  color: #1f2a37;
  font-weight: 950;
}

.direct-setup-active .direct-step-button.active::before {
  background: #2f73df;
  border-color: #2f73df;
  box-shadow: 0 0 0 4px #eef5ff;
}

.direct-setup-active .direct-stepper > span {
  background: #b9d2f7;
  flex: 0 0 38px;
  font-size: 0;
  height: 1px;
}

.direct-stage {
  align-items: stretch;
  display: grid;
  gap: 14px;
  grid-template-columns: 286px minmax(0, 1fr);
  min-height: min(620px, calc(100vh - 230px));
}

.direct-stage[data-direct-panel="align"] {
  gap: 12px;
  grid-template-columns: 228px minmax(0, 1fr);
  min-height: min(690px, calc(100vh - 186px));
}

.setup-view.direct-setup-active .direct-stage:not([data-direct-panel="proof"]):not(.direct-finish-stage) {
  gap: 12px;
  grid-template-columns: 340px minmax(0, 1fr);
  height: calc(100vh - 96px);
  min-height: 560px;
}

body[data-view="setup"][data-module="direct"] .setup-view.direct-setup-active .direct-stage:not(.is-hidden) {
  height: 100%;
  min-height: 0;
}

.direct-wizard.direct-align-workspace .direct-stage[data-direct-panel="align"] {
  grid-template-columns: 228px minmax(0, 1fr);
  height: calc(100vh - 96px);
  min-height: 560px;
}

.direct-stage[data-direct-panel="proof"],
.direct-finish-stage {
  display: grid;
  grid-template-columns: 1fr;
  min-height: 0;
}

.direct-stage[data-direct-panel="proof"] {
  gap: 8px;
  grid-template-rows: minmax(0, 2fr) minmax(240px, 1fr);
  height: calc(100vh - 104px);
}

.direct-side-panel,
.direct-main-panel,
.direct-replace-panel,
.direct-proof-area,
.direct-proof-workbench,
.direct-finish-preview {
  background: #ffffff;
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow: 0 8px 26px rgba(31, 44, 41, 0.05);
}

.direct-side-panel {
  align-content: start;
  display: grid;
  gap: 12px;
  min-width: 0;
  overflow: hidden;
  padding: 16px;
}

.direct-side-panel h2 {
  color: var(--ink);
  font-size: 16px;
  margin-bottom: 4px;
}

.direct-advanced-panel label {
  color: var(--muted);
  display: grid;
  font-size: 11px;
  font-weight: 850;
  gap: 6px;
}

/* 九个牌子原来是九个同样大小的圆角方块摞在一起，眼睛没有落点，只能逐个读文字。
   改成一份清单：每项只用一条细分隔线隔开，名字靠左、色数靠右，
   只有选中那一项上底色。九项里只有一项是「重」的，一眼看得出当前选的是谁。
   排版和色盘对话框里的色系列表一致。 */
.direct-brand-list {
  background: transparent;
  border: 0;
  border-radius: 0;
  display: grid;
  gap: 0;
  min-width: 0;
  padding: 0;
}

.direct-brand-list button {
  align-items: center;
  background: transparent;
  border: 0;
  border-bottom: 1px solid #eef2f7;
  border-radius: 7px;
  color: #243033;
  display: flex;
  gap: 10px;
  justify-content: space-between;
  min-height: 42px;
  padding: 0 10px;
  position: relative;
  text-align: left;
  width: 100%;
}

.direct-brand-list button:last-child {
  border-bottom: 0;
}

.direct-brand-list button b {
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0.01em;
}

.direct-brand-list button em {
  color: #96a0ac;
  font-size: 12px;
  font-style: normal;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}

.direct-brand-list button:hover:not(.active),
.direct-brand-list button:focus-visible:not(.active) {
  background: #f4f8ff;
  color: #2868df;
  outline: 0;
}

.direct-brand-list button.active {
  background: #eef4ff;
  border-bottom-color: transparent;
  color: #2f73df;
}

.direct-brand-list button.active em {
  color: #5b8ad6;
}

/* 选中项左侧那道竖条 */
.direct-brand-list button.active::before {
  background: #2f73df;
  border-radius: 2px;
  content: "";
  height: 18px;
  left: 0;
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 3px;
}

.direct-brand-list button.active b {
  padding-left: 9px;
}

.direct-advanced-panel {
  max-height: min(620px, calc(100vh - 230px));
  overflow: auto;
}

.direct-advanced-panel .switch-row {
  color: var(--muted);
}

.direct-main-panel {
  display: grid;
  gap: 10px;
  min-width: 0;
  padding: 14px;
}

.direct-stage[data-direct-panel="align"] .direct-main-panel {
  gap: 0;
  padding: 10px;
  position: relative;
}

.setup-view.direct-setup-active .direct-main-panel,
.setup-view.direct-setup-active .direct-side-panel {
  height: 100%;
  min-height: 0;
}

.setup-view.direct-setup-active .direct-advanced-panel {
  max-height: none;
}

.direct-wizard.direct-align-workspace .direct-stage[data-direct-panel="align"] .direct-main-panel,
.direct-wizard.direct-align-workspace .direct-stage[data-direct-panel="align"] .direct-side-panel {
  min-height: 0;
}

/* 侧栏比这一屏高时自己滚，而不是被 overflow: hidden 裁掉——被裁掉的部分是够不着的，
   而整页滚动又是我们要避免的。 */
.direct-wizard.direct-align-workspace .direct-stage[data-direct-panel="align"] .direct-side-panel {
  overflow-y: auto;
  scrollbar-width: thin;
}

.direct-wizard.direct-align-workspace .direct-stage[data-direct-panel="align"] .direct-side-panel {
  overflow-y: auto;
  overscroll-behavior: contain;
}

.direct-upload-box,
.direct-crop-box,
.direct-align-box {
  background: #f6f8fa;
  border: 1px dashed #a9bad3;
  border-radius: 8px;
  min-height: min(560px, calc(100vh - 270px));
  overflow: hidden;
  position: relative;
}

.direct-stage[data-direct-panel="align"] .direct-align-box {
  min-height: min(650px, calc(100vh - 206px));
}

.setup-view.direct-setup-active .direct-upload-box,
.setup-view.direct-setup-active .direct-crop-box,
.setup-view.direct-setup-active .direct-align-box {
  height: 100%;
  min-height: 0;
}

.direct-wizard.direct-align-workspace .direct-stage[data-direct-panel="align"] .direct-align-box {
  height: 100%;
  min-height: 0;
}

.direct-preview-canvas,
.direct-finish-preview canvas {
  display: block;
  min-height: min(560px, calc(100vh - 270px));
  width: 100%;
}

.direct-finish-preview canvas {
  background-color: #ffffff;
  background-image:
    linear-gradient(45deg, #d7d7d7 25%, transparent 25%),
    linear-gradient(-45deg, #d7d7d7 25%, transparent 25%),
    linear-gradient(45deg, transparent 75%, #d7d7d7 75%),
    linear-gradient(-45deg, transparent 75%, #d7d7d7 75%);
  background-position:
    0 0,
    0 var(--finish-checker-cell, 12px),
    var(--finish-checker-cell, 12px) calc(0px - var(--finish-checker-cell, 12px)),
    calc(0px - var(--finish-checker-cell, 12px)) 0;
  background-size:
    calc(var(--finish-checker-cell, 12px) + var(--finish-checker-cell, 12px))
    calc(var(--finish-checker-cell, 12px) + var(--finish-checker-cell, 12px));
  height: auto;
  image-rendering: pixelated;
  min-height: 0;
  width: auto;
}

.direct-import-image,
.direct-crop-image {
  display: block;
  height: 100%;
  inset: 0;
  object-fit: contain;
  object-position: center;
  position: absolute;
  width: 100%;
}

.direct-upload-overlay {
  align-items: center;
  background: rgba(255, 255, 255, 0.72);
  color: #141819;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  gap: 8px;
  inset: 0;
  justify-content: center;
  padding: 24px;
  position: absolute;
  text-align: center;
}

.direct-upload-overlay strong {
  background: #ffffff;
  border: 1px solid #2f73df;
  border-radius: 6px;
  color: #255da8;
  font-size: 14px;
  padding: 8px 16px;
}

.direct-wizard.source-loaded .direct-upload-overlay {
  display: none;
}

/* 导入这一步的说明文字，跟在蓝框按钮正下方居中。
   PC 端说明照旧在左下角，所以这一份默认不露，只在窄屏打开（见 900px 那一段）。 */
.direct-upload-hint {
  display: none;
}

.direct-crop-box,
.direct-align-box,
.direct-finish-preview {
  align-items: center;
  display: grid;
  justify-items: center;
}

.direct-crop-box {
  cursor: move;
  touch-action: none;
}

.direct-align-viewport {
  cursor: grab;
  inset: 0;
  overflow: hidden;
  position: absolute;
  touch-action: none;
}

.direct-align-viewport.is-panning {
  cursor: grabbing;
}

.direct-align-viewport.is-aligning {
  cursor: move;
}

.direct-align-viewport.space-held {
  cursor: grab;
}

.direct-align-image {
  display: block;
  object-fit: initial;
  position: absolute;
  -webkit-user-drag: none;
  pointer-events: none;
  user-select: none;
}

.direct-align-grid {
  box-sizing: border-box;
  display: block;
  height: 100%;
  inset: 0;
  pointer-events: none;
  position: absolute;
  width: 100%;
}

.direct-crop-frame {
  border: 3px solid #2f73df;
  box-shadow: 0 0 0 9999px rgba(20, 24, 25, 0.34);
  box-sizing: border-box;
  position: absolute;
  z-index: 2;
}

.direct-crop-frame::before,
.direct-crop-frame::after {
  content: "";
  inset: 0;
  pointer-events: none;
  position: absolute;
}

.direct-crop-frame::before {
  background:
    linear-gradient(90deg, transparent 33.333%, rgba(255, 255, 255, 0.82) 33.333%, rgba(255, 255, 255, 0.82) calc(33.333% + 1px), transparent calc(33.333% + 1px), transparent 66.666%, rgba(255, 255, 255, 0.82) 66.666%, rgba(255, 255, 255, 0.82) calc(66.666% + 1px), transparent calc(66.666% + 1px));
}

.direct-crop-frame::after {
  background:
    linear-gradient(transparent 33.333%, rgba(255, 255, 255, 0.82) 33.333%, rgba(255, 255, 255, 0.82) calc(33.333% + 1px), transparent calc(33.333% + 1px), transparent 66.666%, rgba(255, 255, 255, 0.82) 66.666%, rgba(255, 255, 255, 0.82) calc(66.666% + 1px), transparent calc(66.666% + 1px));
}

.direct-crop-frame span {
  background: #ffffff;
  border: 3px solid #2f73df;
  border-radius: 999px;
  box-sizing: border-box;
  height: 18px;
  position: absolute;
  width: 18px;
  z-index: 3;
}

.direct-crop-frame span[data-crop-handle="nw"] { cursor: nwse-resize; left: -10px; top: -10px; }
.direct-crop-frame span[data-crop-handle="n"] { cursor: ns-resize; left: 50%; top: -10px; transform: translateX(-50%); }
.direct-crop-frame span[data-crop-handle="ne"] { cursor: nesw-resize; right: -10px; top: -10px; }
.direct-crop-frame span[data-crop-handle="w"] { cursor: ew-resize; left: -10px; top: 50%; transform: translateY(-50%); }
.direct-crop-frame span[data-crop-handle="e"] { cursor: ew-resize; right: -10px; top: 50%; transform: translateY(-50%); }
.direct-crop-frame span[data-crop-handle="sw"] { bottom: -10px; cursor: nesw-resize; left: -10px; }
.direct-crop-frame span[data-crop-handle="s"] { bottom: -10px; cursor: ns-resize; left: 50%; transform: translateX(-50%); }
.direct-crop-frame span[data-crop-handle="se"] { bottom: -10px; cursor: nwse-resize; right: -10px; }

.direct-crop-box strong,
.direct-align-box strong,
.direct-finish-preview strong {
  background: rgba(255, 255, 255, 0.78);
  border-radius: 6px;
  color: #384241;
  font-size: 15px;
  padding: 8px 12px;
  pointer-events: none;
  position: absolute;
  left: 14px;
  top: 14px;
  text-align: center;
  z-index: 1;
}

.direct-crop-box strong {
  background: rgba(255, 255, 255, 0.62);
  color: #255da8;
}

.direct-align-tools {
  gap: 8px;
}

.direct-align-tools .direct-outline-button {
  width: 100%;
}

.direct-tool-card {
  background: #ffffff;
  border: 1px solid #dde6f2;
  border-radius: 8px;
  display: grid;
  gap: 8px;
  padding: 8px;
}

.direct-card-head {
  align-items: center;
  color: #5d6878;
  display: flex;
  font-size: 12px;
  font-weight: 900;
  justify-content: space-between;
}

.direct-card-head strong {
  color: #243033;
  font-size: 13px;
}

.direct-card-head b,
.direct-card-head span {
  color: #2f73df;
  font-size: 13px;
  font-weight: 950;
}

.direct-card-head.is-red strong,
.direct-card-head.is-red span {
  color: #ff4e63;
}

.direct-card-head.is-blue strong,
.direct-card-head.is-blue span {
  color: #3b82f6;
}

.direct-mode-row {
  display: grid;
  gap: 6px;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.direct-nudge-pad {
  align-items: center;
  display: grid;
  gap: 4px;
  grid-template-areas:
    ". up ."
    "left . right"
    ". down .";
  justify-items: center;
}

.direct-nudge-pad button {
  background: #f6f8fa;
  border: 1px solid var(--line);
  border-radius: 6px;
  color: #333333;
  cursor: pointer;
  font-size: 18px;
  font-weight: 900;
  height: 30px;
  line-height: 1;
  width: 38px;
}

.direct-nudge-pad [data-direct-nudge="up"] { grid-area: up; }
.direct-nudge-pad [data-direct-nudge="left"] { grid-area: left; }
.direct-nudge-pad [data-direct-nudge="right"] { grid-area: right; }
.direct-nudge-pad [data-direct-nudge="down"] { grid-area: down; }

.direct-icon-button {
  font-size: 20px;
}

.direct-check-row,
.direct-slider-row {
  color: #384241;
  font-size: 12px;
  font-weight: 850;
}

.direct-check-row {
  align-items: center;
  display: flex;
  gap: 8px;
}

.direct-check-row input {
  accent-color: #2f73df;
  height: 16px;
  width: 16px;
}

.direct-view-zoom-row {
  align-items: center;
  display: grid;
  gap: 6px;
  grid-template-columns: 44px 30px 1fr 30px;
}

.direct-view-zoom-row span {
  color: #233033;
  font-size: 13px;
  font-weight: 850;
}

.direct-view-zoom-row input {
  accent-color: #2f73df;
  min-width: 0;
}

.direct-view-zoom-row .direct-icon-button {
  min-height: 30px;
  padding: 0;
}

.direct-stage[data-direct-panel="align"] .direct-panel-title {
  background: rgba(255, 255, 255, 0.78);
  border: 1px solid rgba(185, 203, 230, 0.72);
  border-radius: 6px;
  left: 50%;
  margin: 0;
  padding: 6px 10px;
  position: absolute;
  top: 12px;
  transform: translateX(-50%);
  z-index: 8;
}

.direct-proof-area {
  min-height: 0;
  overflow: auto;
  padding: 10px 10px 38px;
  position: relative;
}

.direct-proof-grid {
  align-content: start;
  display: grid;
  gap: 6px;
  grid-template-columns: repeat(auto-fill, 54px);
  justify-content: start;
}

.direct-proof-cell {
  align-items: center;
  aspect-ratio: 1;
  background-color: var(--proof-color);
  background-image: var(--proof-thumb, none);
  background-position: center;
  background-size: cover;
  border: 1px solid rgba(30, 41, 43, 0.22);
  border-radius: 6px;
  color: #141819;
  cursor: pointer;
  display: inline-flex;
  font-size: 11px;
  font-weight: 900;
  justify-content: center;
  min-width: 0;
  position: relative;
}

.direct-proof-cell.selected {
  border-color: #2868df;
  box-shadow: inset 0 0 0 2px #ffffff, 0 0 0 2px rgba(40, 104, 223, 0.26);
}

.direct-proof-cell.selected::after {
  align-items: center;
  background: #ffffff;
  border: 1px solid #2868df;
  border-radius: 50%;
  color: #2868df;
  content: "✓";
  display: flex;
  font-size: 13px;
  height: 18px;
  justify-content: center;
  position: absolute;
  right: -5px;
  top: -5px;
  width: 18px;
  z-index: 4;
}

.direct-proof-workbench {
  display: grid;
  grid-template-rows: auto minmax(0, 1fr);
  min-height: 0;
  overflow: hidden;
}

.direct-proof-summary {
  align-items: center;
  border-bottom: 1px solid var(--line);
  color: var(--ink);
  display: flex;
  font-size: 14px;
  font-weight: 900;
  gap: 10px;
  justify-content: space-between;
  line-height: 1.2;
  padding: 8px 10px;
}

/* Which palette the codes above came from. The recognition flow hides the whole
   setup sidebar, so this was the one screen where the active brand decided every
   code on it and nothing said which brand that was. */
.direct-proof-palette {
  background: var(--surface-muted, #f1f4f7);
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--muted, #5a6472);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.02em;
  padding: 3px 9px;
  white-space: nowrap;
}

.direct-proof-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.direct-proof-center {
  align-items: center;
  background: transparent;
  border: 0;
  border-radius: 0;
  display: flex;
  gap: 8px;
  justify-content: center;
  place-self: start stretch;
  min-height: 44px;
  padding: 6px 8px;
}

.direct-proof-center span {
  color: var(--muted);
  font-size: 13px;
  font-weight: 900;
  white-space: nowrap;
}

.direct-proof-center b {
  color: var(--ink);
  margin-left: 2px;
}

.direct-outline-button {
  font-size: 12px;
  min-height: 30px;
  padding: 6px 10px;
}

.direct-replace-panel {
  display: grid;
  gap: 8px;
  grid-template-rows: auto minmax(0, 1fr) auto;
  height: 100%;
  max-height: none;
  min-height: 0;
  overflow: hidden;
  padding: 10px;
}

.direct-replace-head {
  align-items: center;
  display: grid;
  gap: 8px;
  grid-template-columns: 1fr auto;
}

.direct-replace-head strong,
.direct-all-colors {
  color: var(--ink);
  font-size: 12px;
  font-weight: 900;
}

.direct-all-colors {
  align-items: center;
  display: inline-flex;
  gap: 4px;
  min-width: max-content;
  white-space: nowrap;
}

.direct-all-colors input {
  height: 14px;
  width: 14px;
}

.direct-proof-color-list {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
  min-height: 0;
  overflow: auto;
  padding-right: 4px;
}

.direct-replacement-colors {
  align-content: start;
  display: grid;
  gap: 10px;
  min-height: 0;
  overflow: auto;
  overscroll-behavior: contain;
  padding-right: 6px;
  scrollbar-gutter: stable;
}

.direct-replace-family {
  display: grid;
  gap: 8px;
}

.direct-replace-family-title {
  background: transparent;
  border: 0;
  color: var(--muted);
  cursor: pointer;
  font-size: 13px;
  font-weight: 950;
  line-height: 1;
  padding: 2px 0;
  text-align: left;
}

.direct-replace-family-title::after {
  content: "⌄";
  float: right;
  font-size: 15px;
}

.direct-replace-family.collapsed .direct-replace-family-title::after {
  content: "›";
}

.direct-replace-family-grid {
  display: grid;
  gap: 7px;
  grid-template-columns: repeat(auto-fill, minmax(42px, 1fr));
}

.direct-replace-chip,
.direct-color-chip {
  align-items: center;
  aspect-ratio: 1;
  background-color: var(--replace-color, var(--chip-color, #dfe4e8));
  background-image: none;
  border: 1px solid rgba(30, 41, 43, 0.22);
  border-radius: 7px;
  color: var(--replace-text-color, var(--chip-text-color, #26302f));
  cursor: pointer;
  display: inline-flex;
  font-size: 12px;
  font-weight: 900;
  justify-content: center;
  width: 42px;
}

.direct-color-chip {
  border-radius: 6px;
  width: 40px;
}

.direct-color-chip.empty {
  background-color: #ffffff;
  background-image:
    linear-gradient(45deg, #d8dcdf 25%, transparent 25%),
    linear-gradient(-45deg, #d8dcdf 25%, transparent 25%),
    linear-gradient(45deg, transparent 75%, #d8dcdf 75%),
    linear-gradient(-45deg, transparent 75%, #d8dcdf 75%);
  background-position: 0 0, 0 7px, 7px -7px, -7px 0;
  background-size: 14px 14px;
}

.direct-proof-pager {
  align-items: center;
  background: rgba(255, 255, 255, 0.94);
  border: 1px solid var(--line);
  border-radius: 999px;
  bottom: 10px;
  box-shadow: 0 6px 18px rgba(31, 44, 41, 0.1);
  color: var(--ink);
  display: flex;
  gap: 8px;
  padding: 5px 8px;
  position: absolute;
  right: 12px;
}

.direct-proof-pager:empty {
  display: none;
}

.direct-proof-pager button {
  align-items: center;
  background: #ffffff;
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--ink);
  cursor: pointer;
  display: inline-flex;
  font-size: 16px;
  font-weight: 950;
  height: 24px;
  justify-content: center;
  padding: 0;
  width: 24px;
}

.direct-proof-pager button:disabled {
  color: #aeb8b4;
  cursor: not-allowed;
}

.direct-proof-pager span {
  font-size: 12px;
  font-weight: 950;
  min-width: 34px;
  text-align: center;
}

.direct-replace-chip.active,
.direct-color-chip.active {
  border-color: #2868df;
  box-shadow: 0 0 0 3px rgba(40, 104, 223, 0.2);
}

.direct-replace-actions {
  border-top: 1px solid var(--line);
  display: grid;
  gap: 10px;
  grid-template-columns: 1fr 1fr;
  padding-top: 8px;
}

.direct-primary-small {
  background: #2868df;
  border: 1px solid #2868df;
  border-radius: 7px;
  color: #ffffff;
  cursor: pointer;
  font-size: 13px;
  font-weight: 950;
  padding: 8px 12px;
}

.direct-primary-small:disabled {
  background: #dfe3e7;
  border-color: #dfe3e7;
  color: #96a0a8;
  cursor: not-allowed;
}

.direct-empty-note {
  color: var(--muted);
  font-size: 14px;
  font-weight: 850;
}

.direct-finish-stage {
  height: calc(100vh - 104px);
  justify-items: stretch;
}

.direct-finish-preview {
  display: grid;
  gap: 0;
  height: 100%;
  min-height: 0;
  overflow: hidden;
  padding: 10px;
  width: 100%;
}

.direct-finish-viewport {
  --finish-checker-cell: 12px;
  background-color: #ffffff;
  background-image: none;
  border: 1px solid #e2e5e7;
  border-radius: 8px;
  display: grid;
  height: 100%;
  min-height: 0;
  overflow: auto;
  place-items: center;
  width: 100%;
}

.direct-footer {
  align-items: center;
  background: rgba(247, 249, 248, 0.94);
  border: 1px solid var(--line);
  border-radius: 8px;
  display: flex;
  gap: 10px;
  justify-content: flex-end;
  padding: 10px;
  position: sticky;
  bottom: 12px;
  z-index: 12;
}

body[data-view="setup"][data-module="direct"] .top-actions {
  display: none;
}

body[data-view="setup"][data-module="direct"] .direct-footer {
  background: transparent;
  border: 0;
  border-radius: 0;
  bottom: auto;
  box-shadow: none;
  gap: 8px;
  padding: 0;
  position: fixed;
  right: 22px;
  top: 17px;
  z-index: 28;
}

body[data-view="setup"][data-module="direct"] .direct-footer .direct-outline-button {
  min-height: 38px;
  min-width: 82px;
  padding: 7px 14px;
}

.direct-footer #directNextButton,
.direct-footer #directSaveButton,
.direct-footer #directSaveEditButton {
  background: #2f73df;
  border-color: #2f73df;
  color: #ffffff;
}

.direct-footer #directNextButton:disabled {
  background: #d7dde0;
  border-color: #d7dde0;
  color: #7a8482;
  cursor: not-allowed;
}

.direct-step-button:disabled,
.direct-outline-button:disabled,
.direct-board-sizes button:disabled,
.direct-icon-button:disabled,
.direct-round-button:disabled {
  cursor: not-allowed;
  opacity: 0.54;
}

.direct-save-prompt {
  background: rgba(20, 24, 25, 0.9);
  border-radius: 8px;
  color: #ffffff;
  font-size: 16px;
  font-weight: 900;
  left: 50%;
  min-width: 240px;
  padding: 16px 22px;
  position: fixed;
  text-align: center;
  top: 50%;
  transform: translate(-50%, -50%);
  z-index: 80;
}

.palette-brand-picker {
  display: grid;
  gap: 7px;
}

.palette-brand-picker > span,
.palette-brand-picker label {
  color: var(--muted);
  display: grid;
  font-size: 11px;
  font-weight: 800;
  gap: 6px;
}

.palette-brand-menu button.active {
  background: #eef5ff;
  color: #2868df;
}

.palette-brand-button.active {
  background: #2868df;
  border-color: #2868df;
  color: #ffffff;
}

.quick-size-grid {
  display: grid;
  gap: 7px;
  grid-template-columns: repeat(3, minmax(0, 1fr));
}

.style-button.active,
.size-button.active {
  background: var(--ink);
  border-color: var(--ink);
  color: #ffffff;
}

.ai-size-button.active {
  background: var(--yellow);
  border-color: #d4ab31;
  color: var(--ink);
}

input,
select {
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: 6px;
  color: var(--text);
  min-height: 37px;
  outline: none;
  padding: 7px 9px;
  width: 100%;
}

input:focus,
select:focus {
  border-color: var(--teal);
  box-shadow: 0 0 0 3px rgba(39, 135, 127, 0.12);
}

input[type="range"] {
  /* accent-color 在此已失效：下方用 appearance:none 自绘轨道与滑块 */
  border: 0;
  padding: 0;
}

.workspace {
  display: grid;
  gap: 10px;
  grid-template-columns: 70px minmax(420px, 1fr) 324px;
  height: calc(100vh - 72px);
  margin: 0 auto;
  max-width: 1800px;
  min-height: 540px;
  padding: 10px;
}

.tool-button.active {
  background: var(--ink);
  border-color: var(--ink);
  color: #ffffff;
}

#patternCanvas {
  background: #fffdfa;
  border: 0;
  box-shadow: none;
  cursor: crosshair;
  display: block;
  flex: 0 0 auto;
  image-rendering: pixelated;
  touch-action: none;
}

.inspector {
  min-height: 0;
  overflow: hidden;
}

.inspector-tab.active {
  background: var(--surface);
  box-shadow: 0 2px 8px rgba(31, 44, 41, 0.08);
  color: var(--ink);
}

.palette-chip.active {
  border-color: var(--ink);
  box-shadow: inset 0 0 0 2px var(--ink);
}

.chip-color {
  border: 1px solid rgba(0, 0, 0, 0.15);
  border-radius: 4px;
  height: 20px;
}

.chip-code {
  font-size: 10px;
  font-weight: 900;
  line-height: 1;
}

/* Sits in the line of sight, not at the foot of the window.
   On the align step the eye is on the grid in the middle of the canvas, so a
   toast pinned to the bottom edge was simply never looked at. Held a little
   above centre so it announces itself without covering the exact spot being
   inspected. */
.app-toast {
  background: var(--ink);
  border-radius: 10px;
  box-shadow: 0 10px 30px rgba(15, 23, 42, 0.28);
  color: #ffffff;
  font-size: 14px;
  font-weight: 800;
  left: 50%;
  letter-spacing: 0.01em;
  max-width: min(460px, calc(100vw - 48px));
  opacity: 0;
  padding: 14px 22px;
  pointer-events: none;
  position: fixed;
  text-align: center;
  top: 38%;
  transform: translate(-50%, -50%) scale(0.96);
  transition: opacity 160ms ease, transform 160ms ease;
  z-index: 50;
}

.app-toast.visible {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1);
}

@media (prefers-reduced-motion: reduce) {
  .app-toast {
    transition: opacity 160ms ease;
    transform: translate(-50%, -50%);
  }

  .app-toast.visible {
    transform: translate(-50%, -50%);
  }
}

@media (max-width: 1180px) {
  .project-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .workspace {
    grid-template-columns: 68px minmax(380px, 1fr) 286px;
  }

  .board-toolbar-actions .ghost-button {
    font-size: 11px;
    padding: 7px 8px;
  }
}

@media (max-width: 900px) {
  .topbar {
    flex-wrap: wrap;
    padding: 9px 14px;
  }

  .brand-button {
    min-width: 0;
  }

  .top-status {
    display: none;
  }

  .home-view,
  .setup-view {
    padding-left: 14px;
    padding-right: 14px;
  }

  .module-launcher {
    grid-template-columns: 1fr;
  }

  .module-entry-card {
    display: grid;
    grid-template-columns: minmax(180px, 0.8fr) 1.2fr;
  }

  .module-preview-wrap {
    height: 100%;
    min-height: 180px;
  }

  .project-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .setup-layout {
    grid-template-columns: 1fr;
  }

  body[data-view="setup"][data-module="style"] .setup-view {
    height: auto;
  }

  body[data-view="setup"][data-module="style"] .setup-layout {
    height: auto;
  }

  body[data-view="setup"][data-module="style"] .source-card {
    height: auto;
  }

  body[data-view="setup"][data-module="style"] .source-stage {
    height: auto;
    min-height: min(420px, calc(100svh - 180px));
  }

  .setup-panel {
    max-height: none;
    position: static;
  }

  .direct-stepper {
    justify-content: flex-start;
    max-width: none;
    min-width: 0;
    overflow-x: auto;
    position: static;
    transform: none;
    width: 100%;
  }

  .direct-stepper > span {
    flex: 0 0 auto;
  }

  .direct-step-button {
    flex: 0 0 auto;
  }

  .direct-setup-active .direct-stepper > span {
    flex: 0 0 38px;
  }

  .direct-stage {
    grid-template-columns: 1fr;
  }

  .direct-advanced-panel {
    max-height: none;
  }

  .direct-proof-controls {
    grid-template-columns: 1fr;
  }

  .direct-proof-center {
    justify-content: space-between;
  }

  .workspace {
    grid-template-areas:
      "board"
      "tools"
      "inspector";
    grid-template-columns: 1fr;
    height: auto;
    min-height: calc(100vh - 72px);
  }

  .board-panel {
    grid-area: board;
    min-height: 620px;
  }

  .tool-rail {
    flex-direction: row;
    grid-area: tools;
  }

  .tool-rail-group {
    display: grid;
    flex: 1;
    grid-template-columns: repeat(5, minmax(0, 1fr));
  }

  .brush-control {
    align-content: center;
    grid-template-columns: auto minmax(90px, 1fr) auto;
    justify-items: stretch;
    margin-left: 10px;
    width: min(220px, 32vw);
  }

  .brush-control input {
    height: 24px;
    writing-mode: horizontal-tb;
    width: 100%;
  }

  .inspector {
    grid-area: inspector;
  }

  .inspector-panel {
    max-height: min(640px, 72vh);
  }

  .palette-grid {
    grid-template-columns: repeat(8, minmax(0, 1fr));
  }
}

@media (max-width: 620px) {
  .topbar {
    position: static;
  }

  .brand-copy strong {
    font-size: 14px;
  }

  .top-actions {
    margin-left: auto;
  }

  .top-actions .ghost-button,
  .top-actions .primary-button {
    font-size: 11px;
    min-height: 34px;
    padding: 6px 8px;
  }

  .home-view {
    padding-top: 26px;
  }

  .home-heading {
    align-items: stretch;
    flex-direction: column;
    gap: 14px;
  }

  .home-heading h1 {
    font-size: 28px;
  }

  .home-heading-actions {
    flex-wrap: wrap;
  }

  .module-entry-card {
    display: block;
  }

  .module-preview-wrap {
    height: 150px;
    min-height: 0;
  }

  .entry-copy {
    min-height: 142px;
  }

  .project-grid {
    grid-template-columns: 1fr;
  }

  .project-card {
    grid-template-columns: 132px minmax(0, 1fr);
    grid-template-rows: 112px;
    min-height: 112px;
  }

  .project-thumbnail {
    height: 112px;
  }

  .setup-view {
    padding-top: 24px;
  }

  .source-stage {
    min-height: 270px;
  }

  .two-column,
  .switch-list {
    grid-template-columns: 1fr;
  }

  .setup-footer {
    grid-template-columns: 1fr;
  }

  .workspace {
    padding: 6px;
  }

  .board-panel {
    min-height: 520px;
  }

  .board-toolbar {
    align-items: stretch;
    flex-direction: column;
  }

  .board-toolbar-actions {
    flex-wrap: wrap;
  }

  .canvas-wrap {
    min-height: 350px;
    padding: 0;
  }

  .tool-rail {
    align-items: stretch;
    flex-direction: column;
  }

  .brush-control {
    grid-template-columns: auto 1fr auto;
    margin: 8px 4px 2px;
    width: auto;
  }

  .tool-button {
    min-height: 50px;
  }

  .palette-grid {
    grid-template-columns: repeat(5, minmax(0, 1fr));
  }

  .history-item {
    grid-template-columns: 1fr;
  }
}

/* Landing entry and creation hub */
.visually-hidden {
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  height: 1px;
  overflow: hidden;
  position: absolute;
  white-space: nowrap;
  width: 1px;
}

.landing-view {
  background: #ffffff;
  display: block;
  min-height: 100svh;
  overflow: visible;
  scroll-behavior: smooth;
}

.landing-topbar {
  align-items: center;
  background: #08090b;
  border-bottom: 1px solid #17191f;
  display: grid;
  /* 导航和登录都已下线，顶栏只剩 logo 和语言切换：左右两列，语言靠右 */
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 24px;
  min-height: 78px;
  padding: 0 clamp(24px, 7vw, 150px);
}

.landing-brand {
  background: transparent;
  border: 0;
  justify-self: start;
  padding: 0;
}

.landing-brand .brand-lockup {
  gap: 12px;
}

.landing-brand .brand-symbol {
  height: 58px;
}

.landing-brand .brand-wordmark-image {
  filter: invert(1);
  height: 46px;
}

.landing-nav button:hover,
.landing-nav button:focus-visible,
.landing-nav a:hover,
.landing-nav a:focus-visible,
.landing-nav a.active {
  color: #ffffff;
}

.landing-actions {
  align-items: center;
  display: flex;
  gap: 12px;
  justify-self: end;
}

.landing-login-button,
.landing-language-button {
  background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.24);
  border-radius: 7px;
  color: rgba(255, 255, 255, 0.82);
  cursor: pointer;
  font-size: 14px;
  font-weight: 750;
  min-height: 38px;
  min-width: 70px;
  padding: 7px 14px;
  white-space: nowrap;
}

/* 语言开关：一个圆里画「中／A」，中间一道斜杠。
   亮的那半是现在在用的语言，另一半压暗——按钮上写的是「现在用的是哪个」，
   不是「点了会切到哪个」。和顶栏里其它圆形图标按钮成一套。 */
.landing-language-button {
  align-items: center;
  border-radius: 50%;
  display: inline-flex;
  height: 32px;
  justify-content: center;
  min-height: 32px;
  min-width: 0;
  padding: 0;
  width: 32px;
}

.landing-language-button:hover {
  background: rgba(255, 255, 255, 0.12);
}

.landing-language-glyph {
  display: block;
  /* SVG 里的 text 不继承 body 那套字体栈，得自己写一遍，
     否则「中」会掉到衬线体上，和旁边的黑体对不齐 */
  font-family: system-ui, -apple-system, "PingFang SC", sans-serif;
}

.landing-language-glyph line {
  stroke: rgba(255, 255, 255, 0.34);
}

/* 默认（中文界面）：「中」亮、「A」暗。英文界面反过来 */
.landing-language-glyph .lang-zh {
  fill: #fdfcf7;
}

.landing-language-glyph .lang-en {
  fill: rgba(255, 255, 255, 0.38);
}

body[data-language="en"] .landing-language-glyph .lang-zh {
  fill: rgba(255, 255, 255, 0.38);
}

body[data-language="en"] .landing-language-glyph .lang-en {
  fill: #fdfcf7;
}

.landing-login-button:hover,
.landing-language-button:hover,
.landing-login-button:focus-visible,
.landing-language-button:focus-visible {
  border-color: rgba(255, 255, 255, 0.48);
  color: #ffffff;
}

.landing-hero {
  align-items: center;
  background: var(--bg-cream-gradient);
  border: 0;
  border-radius: 0;
  display: grid;
  justify-items: center;
  margin: 0;
  min-height: calc(100svh - 78px);
  overflow: hidden;
  padding: clamp(54px, 11vh, 150px) 24px;
}

.landing-content {
  align-items: center;
  display: flex;
  flex-direction: column;
  max-width: 900px;
  text-align: center;
  width: 100%;
}

.landing-content h1 {
  /* h1 现在装两样东西：品牌舞台 + 那句主张（原来是下面单独的 <p>）。
     所以从一行 flex 改成两行 column。nowrap 挪到 .landing-title-stage 上——
     品牌名断行会毁掉熨斗的动画对位，但主张是完整句子，窄屏必须能换行。 */
  align-items: center;
  color: #17202b;
  display: flex;
  flex-direction: column;
  font-family: "Fredoka One", "Arial Rounded MT Bold", ui-rounded, system-ui, sans-serif;
  font-weight: 400;
  justify-content: center;
  letter-spacing: 0;
  line-height: 0.92;
  margin: 0;
  max-width: min(100%, 1100px);
  width: 100%;
}

.landing-title-main {
  font-size: clamp(66px, 9.8vw, 146px);
}

html[lang="en"] .landing-title-main {
  font-size: clamp(48px, 7.2vw, 112px);
}

.landing-title-claim {
  color: #2e6dcc;
  font-size: clamp(18px, 1.7vw, 28px);
  font-weight: 800;
  line-height: 1.5;
  margin: 26px 0 0;
}

.landing-enter-button {
  align-items: center;
  background: #ffffff;
  border: 1px solid #d1a43a;
  border-radius: 8px;
  box-shadow: 0 16px 38px rgba(25, 38, 61, 0.08);
  color: #111820;
  display: inline-flex;
  font-size: 18px;
  font-weight: 900;
  gap: 12px;
  justify-content: center;
  margin-top: 46px;
  min-height: 58px;
  min-width: 200px;
  padding: 14px 28px;
  transition: background 160ms ease, box-shadow 160ms ease, transform 160ms ease;
}

.landing-enter-button:hover {
  background: #f8fbff;
  box-shadow: 0 18px 44px rgba(25, 38, 61, 0.12);
  transform: translateY(-2px);
}

.landing-enter-button:active {
  transform: translateY(0);
}

.landing-flow-tabs button.active {
  background: #111820;
  border-color: #111820;
  box-shadow: 0 12px 26px rgba(17, 24, 32, 0.14);
  color: #ffffff;
}

.landing-flow-panel.active {
  opacity: 1;
  pointer-events: auto;
  visibility: visible;
}

.flow-tool-rail span.active {
  background: #111820;
  color: #ffffff;
}

.flow-bead-board .bead {
  box-shadow: inset 0 -4px 0 rgba(17, 24, 32, 0.14);
}

.brand-wordmark {
  min-width: 0;
}

.brand-lockup {
  align-items: center;
  display: flex;
  gap: 10px;
  min-width: 0;
}

.brand-cyber-logo {
  display: block;
  flex: 0 0 auto;
  height: 46px;
  object-fit: contain;
  width: auto;
}

body[data-view="home"] .brand-lockup {
  gap: 12px;
}

body[data-view="home"] .brand-cyber-logo,
.landing-brand .brand-cyber-logo {
  filter: drop-shadow(0 0 8px rgba(0, 209, 255, 0.42)) drop-shadow(0 0 10px rgba(255, 45, 161, 0.24));
  height: 58px;
}

body[data-view="home"] {
  background: #ffffff;
  overflow: hidden;
}

body[data-view="home"] .app-shell {
  display: grid;
  grid-template-rows: auto minmax(0, 1fr);
  height: 100vh;
  height: 100dvh;
  min-height: 0;
  overflow: hidden;
}

body[data-view="home"] .topbar {
  background: #08090b;
  border-bottom: 1px solid #17191f;
  justify-content: flex-start;
  min-height: 78px;
  padding: 0 clamp(24px, 7vw, 150px);
  position: relative;
}

body[data-view="home"] .top-actions {
  display: none;
}

.module-button:focus-visible,
.module-button:active,
.module-button.active {
  border-color: #d69b00;
  box-shadow:
    0 0 0 4px rgba(244, 200, 74, 0.34),
    0 20px 52px rgba(32, 43, 56, 0.14);
  outline: 0;
  transform: none;
}

.login-card > .primary-button {
  margin-top: 4px;
  width: 100%;
}

.login-tab.is-active {
  background: #ffffff;
  box-shadow: 0 1px 3px rgba(20, 29, 40, 0.14);
  color: var(--text);
}

.login-card .primary-button[aria-busy="true"] {
  opacity: 0.65;
  pointer-events: none;
}

@media (max-width: 1040px) {
  .module-button {
    gap: 22px;
    grid-template-columns: 1fr;
    min-height: 238px;
    padding: 28px 24px 26px;
  }

  .module-dog {
    height: 60px;
    width: 60px;
  }

  .module-button .entry-copy > strong {
    font-size: 22px;
  }
}

@media (max-width: 900px) {
  .landing-view {
    grid-template-rows: auto minmax(0, 1fr);
  }

  .landing-topbar {
    grid-template-columns: 1fr auto;
    padding: 16px 22px;
  }

  .landing-nav {
    gap: 22px;
    grid-column: 1 / -1;
    justify-content: flex-start;
    overflow-x: auto;
    padding: 2px 0;
  }

  .landing-actions {
    align-self: start;
  }

  .landing-hero {
    margin: 0;
    padding: 74px 20px;
  }

  .landing-page {
    min-height: auto;
    padding: 72px 24px;
  }

  .landing-flow-tabs {
    max-width: none;
  }

  .landing-flow-panel {
    grid-template-columns: 1fr;
  }

  .landing-flow-preview {
    min-height: 360px;
  }

  .flow-editor-mock {
    grid-template-columns: 48px minmax(180px, 1fr) 150px;
    min-width: 0;
  }

  body[data-view="home"] .topbar {
    min-height: 78px;
    padding: 0 24px;
  }

  .home-navigation {
    gap: 20px;
  }

  .nav-link {
    font-size: 15px;
  }

  .home-view {
    min-height: calc(100svh - 78px);
    padding: 66px 24px 52px;
  }

  .creation-hub {
    gap: 22px;
    min-height: auto;
  }

  .gallery-launch-card {
    max-width: 420px;
    min-height: 108px;
    padding: 44px 22px 22px;
  }

  .gallery-dog-row {
    gap: 6px;
    top: -40px;
  }

  .gallery-dog-row img {
    height: 58px;
    width: 58px;
  }

  .module-launcher {
    gap: 14px;
    grid-template-columns: 1fr;
    max-width: 620px;
  }

  .module-button {
    gap: 20px;
    min-height: 220px;
    padding: 26px 24px 24px;
  }
}

@media (max-width: 620px) {
  .landing-topbar {
    gap: 14px;
    padding: 14px 16px;
  }

  .landing-brand .brand-lockup {
    gap: 8px;
  }

  .landing-brand .brand-symbol {
    height: 42px;
  }

  .landing-brand .brand-wordmark-image {
    height: 32px;
  }

  .landing-brand .brand-cyber-logo {
    height: 42px;
  }

  .landing-login-button,
  .landing-language-button {
    font-size: 12px;
    min-height: 34px;
    min-width: 54px;
    padding: 6px 10px;
  }

  /* 窄屏上圆圈缩一档 */
  .landing-language-button {
    height: 30px;
    min-height: 30px;
    min-width: 0;
    padding: 0;
    width: 30px;
  }

  .landing-nav {
    gap: 18px;
  }

  .landing-nav button,
  .landing-nav a {
    font-size: 14px;
  }

  .landing-hero {
    margin: 0;
    padding: 66px 18px;
  }

  .landing-page {
    padding: 58px 18px;
  }

  .landing-page h2 {
    font-size: 32px;
  }

  .landing-page-copy p {
    font-size: 15px;
  }

  .landing-flow-tabs {
    grid-template-columns: 1fr;
  }

  .landing-flow-tabs button {
    min-height: 42px;
  }

  .landing-flow-panel {
    padding: 18px;
  }

  .landing-flow-copy h3 {
    font-size: 24px;
  }

  .landing-flow-steps li {
    align-items: start;
    grid-template-columns: 34px minmax(0, 1fr);
  }

  .landing-flow-steps span {
    grid-column: 2;
  }

  .landing-flow-preview {
    min-height: auto;
    padding: 8px;
  }

  .landing-real-preview figcaption {
    align-items: start;
    border-bottom: 0;
    border-left: 0;
    border-radius: 0;
    border-right: 0;
    bottom: auto;
    box-shadow: none;
    display: grid;
    left: auto;
    max-width: none;
    padding: 10px;
    position: static;
  }

  .landing-real-preview figcaption span {
    justify-self: start;
  }

  .flow-editor-mock,
  .flow-direct-mock,
  .flow-generate-mock {
    grid-template-columns: 1fr;
    padding: 16px;
  }

  .flow-tool-rail {
    display: flex;
    justify-content: center;
  }

  .flow-tool-rail span {
    width: 34px;
  }

  .flow-bead-board {
    padding: 44px;
  }

  .flow-palette-mock div {
    grid-template-columns: repeat(6, 1fr);
  }

  .flow-generate-mock {
    justify-items: center;
  }

  .flow-convert-arrow {
    transform: rotate(90deg);
  }

  .flow-result-grid {
    max-width: 260px;
    padding: 42px;
    width: 100%;
  }

  .flow-style-settings {
    grid-template-columns: 1fr;
    justify-self: stretch;
  }

  .landing-content h1 {
    margin-top: 0;
  }

  .landing-title-main {
    font-size: clamp(39px, 11.2vw, 49px);
  }

  html[lang="en"] .landing-title-main {
    font-size: clamp(31px, 8.8vw, 43px);
  }

  .landing-title-sub {
    font-size: clamp(39px, 11.2vw, 49px);
    margin-left: 0.12em;
  }

  html[lang="en"] .landing-title-sub {
    font-size: clamp(39px, 11.2vw, 49px);
  }

  .landing-title-claim {
    font-size: 15px;
    line-height: 1.6;
    margin-top: 16px;
  }

  .landing-enter-button {
    margin-top: 34px;
    min-height: 52px;
    min-width: 170px;
  }

  body[data-view="home"] .topbar {
    align-items: center;
    gap: 14px;
    min-height: 78px;
    padding: 0 16px;
  }

  body[data-view="home"] .brand-lockup {
    gap: 8px;
  }

  body[data-view="home"] .brand-symbol {
    height: 58px;
  }

  body[data-view="home"] .brand-wordmark-image {
    height: 46px;
  }

  body[data-view="home"] .brand-cyber-logo {
    height: 44px;
  }

  .home-navigation {
    gap: 18px;
    justify-content: flex-end;
    width: auto;
  }

  .nav-link {
    font-size: 14px;
    min-height: 36px;
  }

  #loginButton {
    max-width: 82px;
  }

  .dropdown-menu {
    max-width: calc(100vw - 28px);
    min-width: 228px;
    right: -8px;
  }

  .home-view {
    min-height: calc(100svh - 78px);
    padding: 58px 18px 46px;
  }

  .gallery-launch-card {
    max-width: 300px;
    min-height: 96px;
    padding: 38px 18px 18px;
  }

  .gallery-launch-card > strong {
    font-size: 22px;
  }

  .gallery-dog-row {
    gap: 4px;
    top: -34px;
    width: auto;
  }

  .gallery-dog-row img {
    height: 50px;
    width: 50px;
  }

  .module-button {
    gap: 16px;
    grid-template-columns: 1fr;
    min-height: 204px;
    padding: 22px 20px 22px;
  }

  .module-dog {
    height: 54px;
    width: 54px;
  }

  .module-button .entry-copy > strong {
    font-size: 20px;
  }

  .module-button .entry-copy > span {
    font-size: 13px;
  }

  .module-button .entry-copy b {
    font-size: 15px;
    margin-top: 6px;
  }
}

.blog-filter:hover,
.blog-filter:focus-visible,
.blog-filter.active {
  border-color: #d69b00;
  color: #111820;
  box-shadow: 0 10px 24px rgba(32, 43, 56, 0.08);
}

@media (min-width: 961px) {
  .article-toc-mobile {
    display: none;
  }
}

@media (max-width: 1040px) {
  .blog-layout,
  .article-layout {
    grid-template-columns: 1fr;
  }

  .blog-search-intent,
  .article-toc {
    position: static;
  }

  .article-toc {
    display: none;
  }
}

@media (max-width: 760px) {
  .blog-hero {
    grid-template-columns: 1fr;
  }

  .blog-grid,
  .article-related-grid {
    grid-template-columns: 1fr;
  }

  .blog-card {
    grid-template-rows: 170px minmax(0, 1fr);
  }

  .article-content {
    background: transparent;
    border: 0;
    padding-left: 0;
    padding-right: 0;
  }
}

@media (max-width: 620px) {
  .blog-topbar .landing-actions {
    display: none;
  }

  .blog-hub,
  .article-page {
    padding-left: 18px;
    padding-right: 18px;
  }

  .blog-toolbar {
    flex-wrap: nowrap;
    overflow-x: auto;
    padding-bottom: 4px;
  }

  .blog-filter {
    flex: 0 0 auto;
  }
}

/* Final editor layout overrides */
body[data-view="editor"] {
  overflow: hidden;
}

body[data-view="editor"] .workspace {
  display: grid;
  gap: 10px;
  grid-template-areas: none;
  grid-template-columns: minmax(480px, 1fr) 324px;
  height: calc(100vh - 72px);
  margin: 0;
  max-width: none;
  min-height: 540px;
  padding: 10px;
}

body[data-view="editor"] #patternCanvas {
  background: transparent;
  height: 100%;
  inset: 0;
  position: absolute;
  width: 100%;
}

body[data-view="editor"] .inspector {
  grid-area: auto;
  max-height: none;
  min-height: 0;
  overflow: hidden;
}

body[data-view="editor"] .canvas-wrap:has(.grid-settings-panel:not(.is-hidden))::before {
  background: rgba(20, 28, 36, 0.34);
  content: "";
  inset: 0;
  pointer-events: none;
  position: absolute;
  z-index: 11;
}

.layer-row.selected {
  background: #eef4ff;
  border-color: #8eb5f5;
}

@media (max-width: 1040px) {
  body[data-view="editor"] .workspace {
    grid-template-columns: minmax(420px, 1fr) 286px;
  }
}

@media (max-width: 900px) {
  body[data-view="editor"] {
    overflow: auto;
  }

  body[data-view="editor"] .workspace {
    grid-template-areas: "board" "inspector";
    grid-template-columns: 1fr;
    height: auto;
    min-height: calc(100vh - 72px);
  }

  body[data-view="editor"] .board-panel {
    grid-area: board;
    min-height: 700px;
  }

  body[data-view="editor"] .inspector {
    grid-area: inspector;
    max-height: 560px;
  }

  body[data-view="editor"] .palette-grid {
    grid-template-columns: repeat(8, minmax(0, 1fr));
  }
}

@media (max-width: 620px) {
  body[data-view="editor"] .editor-command-bar {
    display: grid;
    gap: 0;
    grid-template-columns: repeat(7, minmax(0, 1fr));
    left: 10px;
    max-width: none;
    overflow: visible;
    padding: 4px;
    right: 10px;
    transform: none;
  }

  body[data-view="editor"] .editor-command-bar button {
    min-height: 52px;
    min-width: 0;
    padding: 5px 1px;
  }

  body[data-view="editor"] .editor-command-bar button > span {
    font-size: 17px;
  }

  body[data-view="editor"] .editor-command-bar small {
    font-size: 9px;
  }

  body[data-view="editor"] .editor-command-bar .command-done {
    margin-left: 2px;
  }
}

@media (max-width: 620px) {
  body[data-view="editor"] .workspace {
    padding: 6px;
  }

  body[data-view="editor"] .board-panel {
    min-height: 650px;
  }

  body[data-view="editor"] .canvas-wrap {
    min-height: 520px;
  }

  body[data-view="editor"] .board-toolbar {
    align-items: center;
    flex-direction: row;
  }

  body[data-view="editor"] .palette-grid {
    grid-template-columns: repeat(5, minmax(0, 1fr));
  }
}

body[data-view="editor"][data-editor-mode="complete"] {
  overflow: hidden;
}

body[data-view="editor"][data-editor-mode="complete"] .topbar {
  min-height: 72px;
  padding-bottom: 7px;
  padding-top: 7px;
}

body[data-view="editor"][data-editor-mode="complete"] .top-actions,
body[data-view="editor"][data-editor-mode="complete"] .editor-center,
body[data-view="editor"][data-editor-mode="complete"] .board-toolbar,
body[data-view="editor"][data-editor-mode="complete"] .editor-command-bar,
body[data-view="editor"][data-editor-mode="complete"] .selection-summary,
body[data-view="editor"][data-editor-mode="complete"] .selection-actions,
body[data-view="editor"][data-editor-mode="complete"] .magic-tolerance-panel,
body[data-view="editor"][data-editor-mode="complete"] .floating-toolbox,
body[data-view="editor"][data-editor-mode="complete"] .inspector {
  display: none !important;
}

body[data-view="editor"][data-editor-mode="complete"] .workspace {
  display: block;
  height: calc(100dvh - 72px);
  min-height: 0;
  padding: 0;
}

body[data-view="editor"][data-editor-mode="complete"] #patternCanvas {
  cursor: grab !important;
}

body[data-view="editor"][data-editor-mode="complete"] #patternCanvas:active {
  cursor: grabbing !important;
}

@media (max-width: 1100px) {
  body[data-view="editor"][data-editor-mode="complete"] .topbar {
    display: grid;
    grid-template-areas:
      "brand actions"
      "summary summary";
    grid-template-columns: auto minmax(0, 1fr);
    min-height: 136px;
    row-gap: 5px;
  }

  body[data-view="editor"][data-editor-mode="complete"] .brand-button {
    grid-area: brand;
  }

  .completion-actions {
    grid-area: actions;
    justify-self: end;
  }

  .completion-summary {
    grid-area: summary;
    justify-self: center;
    left: auto;
    min-height: 54px;
    position: static;
    top: auto;
    transform: none;
  }

  body[data-view="editor"][data-editor-mode="complete"] .workspace {
    height: calc(100dvh - 136px);
  }
}

@media (max-width: 620px) {
  body[data-view="editor"][data-editor-mode="complete"] .topbar {
    min-height: 126px;
    padding: 6px 8px;
    position: sticky;
  }

  body[data-view="editor"][data-editor-mode="complete"] .brand-button {
    width: 126px;
  }

  body[data-view="editor"][data-editor-mode="complete"] .brand-lockup {
    gap: 7px;
  }

  body[data-view="editor"][data-editor-mode="complete"] .brand-symbol {
    height: 36px;
  }

  body[data-view="editor"][data-editor-mode="complete"] .brand-wordmark-image {
    height: 26px;
  }

  .completion-actions {
    gap: 3px;
  }

  .completion-actions button {
    height: 46px;
    padding: 4px 5px;
    width: 45px;
  }

  .completion-actions button > span {
    font-size: 16px;
  }

  .completion-actions button small {
    font-size: 9px;
  }

  .completion-summary {
    gap: 6px;
    justify-self: stretch;
    min-height: 52px;
    padding: 5px 6px 5px 9px;
  }

  .completion-mode-copy {
    min-width: 56px;
  }

  .completion-mode-copy strong {
    font-size: 10px;
  }

  .completion-mode-copy span,
  .completion-size small {
    font-size: 8px;
  }

  .completion-size {
    gap: 3px;
    padding-left: 7px;
  }

  .completion-size strong {
    font-size: 17px;
  }

  body[data-view="editor"][data-editor-mode="complete"] .workspace {
    height: calc(100dvh - 126px);
    min-height: 0;
    padding: 0;
  }

  body[data-view="editor"][data-editor-mode="complete"] .board-panel,
  body[data-view="editor"][data-editor-mode="complete"] .canvas-wrap {
    min-height: 0;
  }
}

/* Narrow-screen fixes kept last to override legacy responsive rules. */
@media (max-width: 720px) {
  body[data-view="editor"][data-editor-mode="complete"] .topbar {
    display: grid;
    grid-template-areas:
      "brand"
      "actions"
      "summary";
    grid-template-columns: minmax(0, 1fr);
    min-height: 180px;
    padding: 6px 8px;
    row-gap: 5px;
  }

  body[data-view="editor"][data-editor-mode="complete"] .brand-button {
    grid-area: brand;
    min-width: 118px;
    width: 118px;
  }

  body[data-view="editor"][data-editor-mode="complete"] .completion-actions {
    display: flex;
    gap: 2px;
    grid-area: actions;
    justify-self: stretch;
    justify-content: space-between;
    margin: 0;
    overflow: visible;
    width: 100%;
  }

  body[data-view="editor"][data-editor-mode="complete"] .completion-actions button {
    flex: 1 1 0;
    height: 46px;
    min-width: 0;
    padding: 3px 2px;
    width: auto;
  }

  body[data-view="editor"][data-editor-mode="complete"] .completion-actions .completion-projects-button {
    flex: 1.3 1 0;
    min-width: 0;
    width: auto;
  }

  body[data-view="editor"][data-editor-mode="complete"] .completion-actions button > span {
    font-size: 15px;
  }

  body[data-view="editor"][data-editor-mode="complete"] .completion-actions button small {
    font-size: 8px;
  }

  body[data-view="editor"][data-editor-mode="complete"] .completion-summary {
    grid-area: summary;
    justify-self: stretch;
    left: auto;
    position: static;
    top: auto;
    transform: none;
    width: 100%;
  }

  body[data-view="editor"][data-editor-mode="complete"] .workspace {
    height: calc(100dvh - 180px);
  }
}

@media (max-width: 430px) {
  body[data-view="editor"][data-editor-mode="edit"] .editor-center {
    gap: 3px;
  }

  body[data-view="editor"][data-editor-mode="edit"] .history-cluster {
    gap: 2px;
  }

  body[data-view="editor"][data-editor-mode="edit"] .history-cluster .icon-button {
    min-width: 28px;
    padding: 0;
    width: 28px;
  }

  body[data-view="editor"][data-editor-mode="edit"] .header-command-bar button {
    min-width: 39px;
    padding-left: 2px;
    padding-right: 2px;
  }

  body[data-view="editor"][data-editor-mode="edit"] .header-command-bar button > span {
    font-size: 15px;
  }

  body[data-view="editor"][data-editor-mode="edit"] .header-command-bar small {
    font-size: 8px;
  }

  body[data-view="editor"][data-editor-mode="edit"] .floating-toolbox .tool-button {
    min-width: 43px;
    padding-left: 3px;
    padding-right: 3px;
  }

  body[data-view="editor"][data-editor-mode="edit"] .floating-toolbox .tool-button > span {
    font-size: 17px;
  }

  body[data-view="editor"][data-editor-mode="edit"] .floating-brush-control {
    flex-basis: 68px;
    grid-template-columns: 1fr auto;
    padding-left: 5px;
    padding-right: 5px;
  }

  body[data-view="editor"][data-editor-mode="edit"] .floating-brush-control small {
    display: none;
  }

  body[data-view="editor"][data-editor-mode="edit"] .recent-colors > span {
    display: inline;
  }

  .projects-view .project-card {
    grid-template-columns: minmax(0, 1fr);
  }

  .project-collection.list-view .project-card {
    grid-template-columns: 112px minmax(0, 1fr);
  }
}

body[data-view="editor"][data-editor-mode="edit"] .topbar {
  display: grid;
  gap: 12px;
  grid-template-columns: auto minmax(0, 1fr) auto;
  min-height: 72px;
  padding: 8px 18px;
}

body[data-view="editor"][data-editor-mode="edit"] .history-cluster {
  display: flex;
  gap: 4px;
}

body[data-view="editor"][data-editor-mode="edit"] .top-actions {
  grid-column: 3;
  justify-self: end;
}

body[data-view="editor"][data-editor-mode="edit"] .workspace {
  height: calc(100dvh - 72px);
}

.brush-size-toggle:hover,
.floating-brush-control.open .brush-size-toggle {
  background: #eef4ff;
  color: #2868df;
}

.floating-brush-control.open .brush-size-popover {
  display: block;
}

@media (max-width: 1120px) {
  body[data-view="editor"][data-editor-mode="edit"] .topbar {
    grid-template-areas: "brand commands actions";
    grid-template-columns: auto minmax(0, 1fr) auto;
    min-height: 72px;
  }

  body[data-view="editor"][data-editor-mode="edit"] .brand-button {
    grid-area: brand;
  }

  body[data-view="editor"][data-editor-mode="edit"] .editor-center {
    grid-area: commands;
  }

  body[data-view="editor"][data-editor-mode="edit"] .top-actions {
    grid-area: actions;
  }

  body[data-view="editor"][data-editor-mode="edit"] .workspace {
    height: calc(100dvh - 72px);
  }
}

@media (max-width: 720px) {
  body[data-view="editor"][data-editor-mode="edit"] .topbar {
    gap: 6px;
    grid-template-areas:
      "brand actions"
      "commands commands";
    grid-template-columns: auto minmax(0, 1fr);
    min-height: 136px;
    padding: 6px 8px;
  }

  body[data-view="editor"][data-editor-mode="edit"] .brand-button {
    grid-area: brand;
    min-width: 112px;
    width: 112px;
  }

  body[data-view="editor"][data-editor-mode="edit"] .top-actions {
    justify-self: end;
  }

  body[data-view="editor"][data-editor-mode="edit"] .editor-center {
    width: 100%;
  }

  body[data-view="editor"][data-editor-mode="edit"] .workspace {
    height: calc(100dvh - 136px);
  }

  body[data-view="editor"][data-editor-mode="edit"] .palette-quick-row {
    flex-wrap: wrap;
    min-height: 104px;
  }

  .inline-recent-colors {
    order: 2;
  }

  body[data-view="editor"][data-editor-mode="edit"] .palette-quick-list {
    order: 3;
    width: 100%;
  }

  .brush-size-toggle {
    min-width: 56px;
  }

  .brush-size-toggle small {
    font-size: 9px;
  }
}

body[data-view="editor"][data-editor-mode="edit"] .header-command-bar button.active {
  background: #edf4ff;
  color: #2868df;
}

body[data-view="editor"][data-editor-mode="edit"] .header-command-bar .command-done.active {
  background: #2868df;
  color: #ffffff;
}

@media (max-width: 1120px) {
  body[data-view="editor"][data-editor-mode="edit"] .editor-center {
    justify-content: flex-end;
    overflow-x: auto;
    width: 100%;
  }
}

@media (max-width: 720px) {
  body[data-view="editor"][data-editor-mode="edit"] .editor-center {
    justify-content: flex-start;
  }

  body[data-view="editor"][data-editor-mode="edit"] .header-command-bar {
    overflow-x: auto;
  }

  body[data-view="editor"][data-editor-mode="edit"] .header-command-bar button,
  body[data-view="editor"][data-editor-mode="edit"] .header-command-bar .command-done {
    flex: 0 0 auto;
    min-width: 48px;
    padding-left: 6px;
    padding-right: 6px;
  }
}

/* Keep undo and redo icons visually centered inside their buttons. */
body[data-view="editor"][data-editor-mode="edit"] .history-cluster .history-button {
  align-items: center;
  display: inline-grid;
  justify-content: center;
  line-height: 1;
  padding: 0;
  place-items: center;
  text-align: center;
}

body[data-view="editor"][data-editor-mode="edit"] .history-cluster .history-button svg {
  display: block;
  fill: none;
  height: 22px;
  margin: 0;
  overflow: visible;
  stroke: currentColor;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-width: 2;
  width: 22px;
}

/* Place undo and redo at the visual center of the editor header. */
body[data-view="editor"][data-editor-mode="edit"] .topbar {
  position: sticky;
}

body[data-view="editor"][data-editor-mode="edit"] .history-cluster {
  left: 50%;
  position: absolute;
  top: 50%;
  transform: translate(-50%, -50%);
  z-index: 4;
}

@media (max-width: 720px) {
body[data-view="editor"][data-editor-mode="edit"] .history-cluster {
  left: auto;
  position: static;
  top: auto;
  transform: none;
}
}

/* Compact single-row editor header: palette controls move into the top blank area. */
body[data-view="editor"][data-editor-mode="edit"] .topbar {
  align-items: center;
  gap: 12px;
  grid-template-columns: auto minmax(0, 1fr) auto;
  min-height: 60px;
  padding: 4px 14px;
}

body[data-view="editor"][data-editor-mode="edit"] .history-cluster {
  display: inline-flex;
  flex: 0 0 auto;
  gap: 3px;
  left: auto;
  position: static;
  top: auto;
  transform: none;
  z-index: auto;
}

body[data-view="editor"][data-editor-mode="edit"] .history-cluster .history-button {
  background: #ffffff;
  border: 1px solid #dfe6e3;
  border-radius: 7px;
  color: #9aa3a0;
  height: 32px;
  min-height: 32px;
  width: 32px;
}

body[data-view="editor"][data-editor-mode="edit"] .history-cluster .history-button svg {
  height: 18px;
  width: 18px;
}

body[data-view="editor"][data-editor-mode="edit"] .quick-palette-chip.active::after {
  bottom: -6px;
  width: 15px;
}

body[data-view="editor"][data-editor-mode="edit"] .recent-color-button.active::after {
  bottom: -6px;
  width: 15px;
}

body[data-view="editor"][data-editor-mode="edit"] .top-actions {
  grid-column: 3;
  justify-self: end;
}

body[data-view="editor"][data-editor-mode="edit"] .workspace {
  height: calc(100dvh - 60px);
  padding-top: 6px;
}

@media (max-width: 1180px) {
  body[data-view="editor"][data-editor-mode="edit"] .editor-palette-strip {
    max-width: 520px;
  }

  body[data-view="editor"][data-editor-mode="edit"] .palette-quick-list {
    max-width: 155px;
  }
}

@media (max-width: 860px) {
  body[data-view="editor"][data-editor-mode="edit"] .topbar {
    grid-template-areas:
      "brand actions"
      "commands commands";
    grid-template-columns: auto minmax(0, 1fr);
    min-height: 104px;
  }

  body[data-view="editor"][data-editor-mode="edit"] .editor-center {
    grid-area: commands;
    overflow-x: auto;
  }

  body[data-view="editor"][data-editor-mode="edit"] .editor-palette-strip {
    flex: 0 0 auto;
    max-width: none;
  }

  body[data-view="editor"][data-editor-mode="edit"] .workspace {
    height: calc(100dvh - 104px);
  }
}

/* DOCX cleanup pass 2026-07-27 */
body[data-view="editor"][data-editor-mode="edit"] .topbar {
  grid-template-columns: auto minmax(0, 1fr) auto;
  min-height: 50px;
  padding: 4px 10px;
}

body[data-view="editor"][data-editor-mode="edit"] .editor-palette-strip .editor-back-button,
body[data-view="editor"][data-editor-mode="edit"] .switch-palette-button,
body[data-view="editor"][data-editor-mode="edit"] .history-cluster .history-button {
  height: 30px;
  min-height: 30px;
  min-width: 30px;
  padding: 0 8px;
}

body[data-view="editor"][data-editor-mode="edit"] .history-cluster {
  display: inline-flex;
  gap: 4px;
  justify-self: auto;
  left: auto;
  margin: 0;
  position: static;
  top: auto;
  transform: none;
}

body[data-view="editor"][data-editor-mode="edit"] .recent-color-button.active::after,
body[data-view="editor"][data-editor-mode="edit"] .quick-palette-chip.active::after {
  bottom: -5px;
  height: 2px;
  width: 14px;
}

body[data-view="editor"][data-editor-mode="edit"] .header-command-bar button:hover,
body[data-view="editor"][data-editor-mode="edit"] .header-command-bar button:focus-visible,
body[data-view="editor"][data-editor-mode="edit"] .header-command-bar button.active,
body[data-view="editor"][data-editor-mode="edit"] #homeButton:hover,
body[data-view="editor"][data-editor-mode="edit"] #homeButton:focus-visible {
  background: #f3f7ff;
  border-color: #dce6f5;
  box-shadow: 0 0 0 2px rgba(52, 120, 238, 0.1);
}

body[data-view="editor"][data-editor-mode="edit"] .workspace {
  height: calc(100dvh - 52px);
  padding-top: 4px;
}

/* 面板打开时罩在画布上的点击拦截层。
   图层 / 大小 / 颜色 三个面板要允许继续画画，所以只对网格和镜像生效，
   这份名单必须和 app.js 里的 canvasFriendlyPanels 保持一致。 */
body[data-view="editor"] .canvas-wrap:has(#gridSettingsPanel:not(.is-hidden))::before,
body[data-view="editor"] .canvas-wrap:has(#mirrorPanel:not(.is-hidden))::before {
  background: transparent;
  content: "";
  inset: 0;
  pointer-events: auto;
  position: absolute;
  z-index: 11;
}

body[data-view="editor"] .canvas-wrap:has(.grid-settings-panel:not(.is-hidden))::before {
  background: rgba(20, 28, 36, 0.34);
}

body[data-view="editor"][data-editor-mode="edit"] .workspace {
  height: calc(100dvh - 48px);
  padding-top: 3px;
}

body[data-view="editor"][data-editor-mode="edit"] .editor-palette-strip .editor-back-button,
body[data-view="editor"][data-editor-mode="edit"] .switch-palette-button,
body[data-view="editor"][data-editor-mode="edit"] .history-cluster .history-button {
  height: 28px;
  min-height: 28px;
  min-width: 28px;
}

@media (max-width: 860px) {
  body[data-view="editor"][data-editor-mode="edit"] .topbar {
    min-height: 92px;
  }

  body[data-view="editor"][data-editor-mode="edit"] .workspace {
    height: calc(100dvh - 92px);
  }
}

/* 新建空白画布修改3：layout and interaction cleanup */
body[data-view="editor"] .topbar {
  min-height: 48px;
}

body[data-view="editor"][data-editor-mode="edit"] .workspace {
  height: calc(100dvh - 48px);
}

body[data-view="editor"][data-editor-mode="edit"] .header-command-bar button:hover,
body[data-view="editor"][data-editor-mode="edit"] .header-command-bar button:focus-visible,
body[data-view="editor"][data-editor-mode="edit"] .header-command-bar button.active,
body[data-view="editor"][data-editor-mode="complete"] .completion-actions button:hover,
body[data-view="editor"][data-editor-mode="complete"] .completion-actions button:focus-visible,
body[data-view="editor"][data-editor-mode="complete"] .completion-actions button.active,
body[data-view="editor"][data-editor-mode="complete"] #homeButton:hover,
body[data-view="editor"][data-editor-mode="complete"] #homeButton:focus-visible {
  background: #f3f7ff;
  border-radius: 12px;
  color: #2868df;
}

body[data-view="editor"][data-editor-mode="edit"] .header-command-bar .command-done,
body[data-view="editor"][data-editor-mode="complete"] .completion-actions .active,
body[data-view="editor"][data-editor-mode="complete"] .completion-actions button[data-completion-command].active {
  background: #2f6de4;
  border-radius: 16px;
  box-shadow: 0 8px 18px rgba(47, 109, 228, 0.22);
  color: #ffffff;
  height: 44px;
  min-height: 44px;
  min-width: 44px;
  padding: 4px 10px;
}

@media (max-width: 900px) {
  body[data-view="editor"][data-editor-mode="edit"] .editor-center {
    grid-template-columns: 1fr;
    left: 86px;
  }

  body[data-view="projects"] .projects-toolbar {
    align-items: stretch;
    flex-direction: column;
  }

  body[data-view="projects"] .projects-controls {
    grid-template-columns: 1fr;
  }
}

/* Final editor visibility guard: keep the compressed header fully inside the viewport. */
body[data-view="editor"][data-editor-mode="edit"] .topbar {
  align-items: center;
  min-height: 72px;
  overflow: visible;
  padding-bottom: 6px;
  padding-top: 6px;
}

body[data-view="editor"][data-editor-mode="edit"] .workspace {
  height: calc(100dvh - 72px);
}

body[data-view="editor"][data-editor-mode="edit"] .quick-palette-chip.active::after {
  bottom: -10px;
}

body[data-view="editor"][data-editor-mode="edit"] .recent-color-button.active::after {
  bottom: -9px;
}

body[data-view="editor"] .layers-panel .layer-row:not(.active) .layer-main {
  grid-template-columns: 22px 18px 22px 36px minmax(120px, 1fr) auto 32px;
}

@media (max-width: 620px) {
  body[data-view="editor"] .layers-panel {
    height: auto;
    max-height: calc(100% - 18px);
    right: 9px;
    top: 9px;
    width: calc(100% - 18px);
  }

  body[data-view="editor"] .layers-panel .layer-list {
    max-height: min(430px, calc(100dvh - 190px));
  }

  body[data-view="editor"] .layers-panel .layer-main,
  body[data-view="editor"] .layers-panel .layer-row:not(.active) .layer-main {
    gap: 5px;
    grid-template-columns: 18px 15px 20px 34px minmax(70px, 1fr) auto 24px;
  }

  body[data-view="editor"] .layers-panel .layer-thumbnail,
  body[data-view="editor"] .layers-panel .layer-row:not(.active) .layer-thumbnail {
    height: 34px;
    width: 34px;
  }

  .layer-project-item {
    grid-template-columns: 72px minmax(0, 1fr) 16px;
  }

  .layer-project-thumbnail {
    height: 48px;
    width: 72px;
  }
}

body[data-view="editor"] .layers-panel.layer-multi-mode .layer-import-wrap,
body[data-view="editor"] .layers-panel.layer-multi-mode #layerNewButton {
  display: none;
}

body[data-view="editor"] .layers-panel .layer-main,
body[data-view="editor"] .layers-panel .layer-row:not(.active) .layer-main {
  gap: 4px;
  grid-template-columns: 22px 12px 18px 30px minmax(0, 1fr) auto 22px;
}

body[data-view="editor"] .layers-panel .layer-select-toggle.selected {
  background: #3478ee;
  border-color: #3478ee;
}

body[data-view="editor"] .layers-panel .layer-thumbnail,
body[data-view="editor"] .layers-panel .layer-row:not(.active) .layer-thumbnail {
  border-radius: 5px;
  height: 30px;
  width: 30px;
}

body[data-view="editor"] .layers-panel .layer-row:not(.active) {
  gap: 0;
  padding-bottom: 6px;
  padding-top: 6px;
}

body[data-view="editor"] .layers-panel .layer-row:not(.active) .layer-controls {
  display: none;
}

@media (max-width: 620px) {
  body[data-view="editor"] .layers-panel {
    max-height: min(340px, calc(100% - 18px));
    width: min(300px, calc(100% - 18px));
  }
}

@media (max-width: 1180px) {
  body[data-view="editor"][data-editor-mode="edit"] .top-zoom-controls span {
    min-width: 40px;
    padding: 0 6px;
  }
}

@media (max-width: 860px) {
  body[data-view="editor"][data-editor-mode="edit"] .top-zoom-controls {
    margin-left: 0;
  }
}

/* Keep the blank-canvas editor brand aligned with the setup pages. */
body[data-view="editor"][data-editor-mode="edit"] .topbar {
  padding-left: 22px;
}

body[data-view="editor"][data-editor-mode="edit"] .brand-button {
  min-width: 116px;
  transform: translateY(5px);
  width: 116px;
}

body[data-view="setup"][data-module="style"] .topbar,
body[data-view="setup"][data-module="direct"] .topbar {
  gap: 24px;
  justify-content: flex-start;
  min-height: 72px;
  padding: 7px 42px;
}

body[data-view="setup"][data-module="direct"] .topbar {
  padding-right: 330px;
}

body[data-view="setup"][data-module="style"] .brand-button,
body[data-view="setup"][data-module="direct"] .brand-button {
  flex: 0 0 auto;
  min-width: 136px;
  transform: none;
  width: auto;
}

body[data-view="setup"][data-module="style"] .direct-header-title,
body[data-view="setup"][data-module="direct"] .direct-header-title {
  color: #2f73df;
  flex: 0 1 auto;
  font-size: 28px;
  font-weight: 950;
  line-height: 1.15;
  margin-left: 10px;
  white-space: nowrap;
}

body[data-view="setup"][data-module="style"] .setup-header-hint {
  color: #68726f;
  flex: 1 1 auto;
  font-size: 16px;
  font-weight: 800;
  line-height: 1.45;
  margin-left: 2px;
  min-width: 240px;
}

body[data-view="setup"][data-module="style"] .top-actions {
  margin-left: auto;
}

@media (max-width: 900px) {
  body[data-view="setup"][data-module="style"] .topbar,
  body[data-view="setup"][data-module="direct"] .topbar {
    gap: 12px;
    padding: 7px 16px;
  }

  body[data-view="setup"][data-module="direct"] .topbar {
    align-content: flex-start;
    flex-wrap: wrap;
    min-height: 72px;
  }

  body[data-view="setup"][data-module="style"] .direct-header-title,
  body[data-view="setup"][data-module="direct"] .direct-header-title {
    flex: 0 1 auto;
    font-size: 22px;
    margin-left: 0;
    order: 2;
  }

  body[data-view="setup"][data-module="direct"] .direct-credit-balance {
    order: 3;
  }

  body[data-view="setup"][data-module="direct"] .brand-button {
    flex-basis: 100%;
    order: 1;
  }

  body[data-view="setup"][data-module="style"] .setup-header-hint {
    flex-basis: 100%;
    font-size: 13px;
    min-width: 0;
  }

  body[data-view="setup"][data-module="style"] .setup-layout {
    align-content: start;
    display: block;
    grid-template-columns: 1fr;
    height: 100%;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
  }

  body[data-view="setup"][data-module="style"] .source-card {
    height: auto;
    margin-bottom: 12px;
  }

  body[data-view="setup"][data-module="style"] .source-stage {
    height: auto;
    min-height: min(420px, calc(100dvh - 220px));
  }

  body[data-view="setup"][data-module="style"] .setup-panel {
    max-height: none;
  }
}

@media (max-width: 900px) {
  body[data-view="setup"][data-module="direct"] .setup-view.direct-setup-active {
    padding: 12px 16px;
  }

  body[data-view="setup"][data-module="direct"] .direct-setup-active .direct-stepper {
    left: auto;
    margin-left: -16px;
    margin-right: -16px;
    position: static;
    top: auto;
    width: calc(100% + 32px);
  }

  body[data-view="setup"][data-module="direct"] .setup-view.direct-setup-active .direct-stage:not(.is-hidden) {
    align-content: start;
    grid-template-columns: 1fr;
    overflow-y: auto;
    overscroll-behavior: contain;
  }

  body[data-view="setup"][data-module="direct"] .setup-view.direct-setup-active .direct-stage:not(.is-hidden) > .direct-main-panel,
  body[data-view="setup"][data-module="direct"] .setup-view.direct-setup-active .direct-stage:not(.is-hidden) > .direct-side-panel {
    height: auto;
  }

  body[data-view="setup"][data-module="direct"] .setup-view.direct-setup-active .direct-stage:not([data-direct-panel="proof"]):not(.direct-finish-stage) > .direct-main-panel {
    min-height: min(560px, calc(100dvh - 180px));
  }
}

.direct-tool-note {
  color: #6b7686;
  font-size: 11px;
  line-height: 1.5;
  margin: 0;
}

.direct-size-fields {
  display: grid;
  gap: 6px;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.direct-size-fields label {
  align-items: center;
  background: #f4f7fb;
  border: 1px solid #dde6f2;
  border-radius: 6px;
  color: #5d6878;
  display: flex;
  font-size: 12px;
  font-weight: 800;
  gap: 4px;
  padding: 4px 6px;
}

.direct-size-fields input {
  background: transparent;
  border: 0;
  color: #1f2a37;
  font: inherit;
  font-weight: 900;
  min-width: 0;
  padding: 2px 0;
  width: 100%;
}

.direct-size-fields input:focus {
  outline: 2px solid #2f73df;
  outline-offset: 1px;
}

.direct-pattern-size-card .direct-board-sizes {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}

.direct-chart-size-card .direct-size-fields input {
  font-size: 15px;
}

/* 色块预览浮在画布右上角。它是拿来和图纸比对的，放在侧栏意味着每次比对
   都要横穿整个屏幕；贴在图纸边上，比对就只是一次短扫视。 */
.direct-tile-hud {
  backdrop-filter: blur(8px);
  background: rgba(255, 255, 255, 0.9);
  border: 1px solid #d7e2f0;
  border-radius: 10px;
  box-shadow: 0 6px 20px rgba(15, 23, 42, 0.12);
  display: grid;
  gap: 6px;
  padding: 8px;
  position: absolute;
  right: 10px;
  top: 10px;
  transition: opacity 140ms ease;
  width: 186px;
  z-index: 4;
}

/* 拖动画布或网格时让开，别挡住正在看的地方 */
.direct-align-viewport.is-panning ~ .direct-tile-hud,
.direct-align-viewport.is-aligning ~ .direct-tile-hud {
  opacity: 0.25;
}

.direct-tile-hud:hover {
  opacity: 1;
}

.direct-tile-hud-head {
  align-items: baseline;
  display: flex;
  gap: 6px;
  justify-content: space-between;
}

.direct-tile-hud-head span {
  color: #2f73df;
  font-size: 11px;
  font-weight: 900;
}

.direct-tile-hud .direct-tile-preview {
  aspect-ratio: 1;
}

.direct-tile-hud-toggle {
  font-size: 11px;
}

.direct-tile-hud-toggle input {
  height: 13px;
  width: 13px;
}

.direct-tile-hud .direct-coverage-hint {
  font-size: 10px;
  padding: 4px 6px;
}

/* 按钮紧贴它的输入框，占满整行——两者的从属关系靠位置表达，不靠文字说明。 */
.direct-size-apply {
  width: 100%;
}

/* 阶段小标题：把一张卡片内的若干段落分开 */
.direct-phase-sub {
  align-items: baseline;
  border-top: 1px solid #eef3f9;
  color: #6b7686;
  display: flex;
  font-size: 11px;
  font-weight: 800;
  gap: 6px;
  justify-content: space-between;
  margin-top: 2px;
  padding-top: 6px;
}

.direct-phase-sub:first-of-type {
  border-top: 0;
  margin-top: 0;
  padding-top: 0;
}

.direct-phase-sub b {
  color: #1f2a37;
  font-size: 13px;
  font-weight: 900;
}

/* 闸门。它现在是「网格范围」卡片的首行——一个组的标题式开关，勾上才启用
   下面的内容，是设置面板里最常见的写法。放在「单格格距」组的末行则相反：
   控件把自己所在的组关掉，读起来是拧的。 */
.direct-pitch-gate {
  align-items: flex-start;
  background: #eef4ff;
  border: 1px solid #c9dcfb;
  border-radius: 8px;
  cursor: pointer;
  gap: 8px;
  margin-bottom: 2px;
  padding: 8px 9px;
}

.direct-pitch-gate:has(input:checked) {
  background: #e6f6ec;
  border-color: #b4e0c4;
}

.direct-pitch-gate input {
  margin-top: 1px;
}

.direct-pitch-gate-text {
  display: grid;
  gap: 2px;
}

.direct-pitch-gate-text b {
  color: #1f2a37;
  font-size: 12px;
  font-weight: 900;
}

.direct-pitch-gate-text em {
  color: #6b7686;
  font-size: 11px;
  font-style: normal;
  line-height: 1.4;
}

/* 未锁定时只压暗加格控件。标题、格数读数、以及闸门那一行都保持全对比度——
   闸门是这张卡片上唯一需要用户注意的东西，压暗它等于把入口藏起来。 */
.direct-tool-card.is-locked-off .direct-grow-pad {
  opacity: 0.5;
  pointer-events: none;
}

/* 「应用」和宽高同行，占最右一列——按钮和它的输入框在一条线上，
   原来按钮独占一行，高度那一格右边还空出一块。 */
.direct-apply-row {
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto;
}

.direct-apply-row .direct-size-apply {
  padding: 0 16px;
  width: auto;
}

/* 格距的 ＋－ 和两个输入框同行，上下堆叠占最右一窄列——
   原来 ＋－ 单独占一行，右边空出一块，两个数字框也被挤窄。 */
.direct-pitch-row {
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto;
}

.direct-pitch-step {
  display: grid;
  gap: 3px;
  grid-template-rows: 1fr 1fr;
}

.direct-pitch-step button {
  line-height: 1;
  min-height: 0;
  padding: 0 10px;
}

/* 锁定后第一阶段收成这一条。点它就是解锁并展开。 */
.direct-aligned-summary {
  align-items: center;
  background: #e6f6ec;
  border: 1px solid #b4e0c4;
  border-radius: 8px;
  cursor: pointer;
  display: flex;
  font: inherit;
  gap: 8px;
  padding: 10px 11px;
  text-align: left;
  width: 100%;
}

.direct-aligned-summary.is-hidden {
  display: none;
}

.direct-aligned-summary:hover {
  border-color: #8ecfa8;
}

.direct-aligned-summary-main {
  color: #16794a;
  font-size: 12px;
  font-weight: 900;
}

.direct-aligned-summary-sub {
  color: #5a7a68;
  flex: 1;
  font-size: 11px;
  font-weight: 700;
}

.direct-aligned-summary-sub b {
  color: #16794a;
  font-weight: 900;
}

.direct-aligned-summary-caret {
  color: #16794a;
  font-size: 13px;
  font-weight: 900;
}

/* 按钮紧贴它的输入框，占满整行——两者的从属关系靠位置表达，不靠文字说明。 */
.direct-size-apply {
  width: 100%;
}

/* 阶段小标题：把一张卡片内的若干段落分开 */
.direct-phase-sub {
  align-items: baseline;
  border-top: 1px solid #eef3f9;
  color: #6b7686;
  display: flex;
  font-size: 11px;
  font-weight: 800;
  gap: 6px;
  justify-content: space-between;
  margin-top: 2px;
  padding-top: 6px;
}

.direct-phase-sub:first-of-type {
  border-top: 0;
  margin-top: 0;
  padding-top: 0;
}

.direct-phase-sub b {
  color: #1f2a37;
  font-size: 13px;
  font-weight: 900;
}

/* 闸门：两个阶段之间的分隔条，本身就是那个开关 */
.direct-pitch-gate {
  align-items: center;
  background: #eef4ff;
  border: 1px solid #c9dcfb;
  border-radius: 8px;
  cursor: pointer;
  display: flex;
  gap: 8px;
  padding: 9px 10px;
}

.direct-pitch-gate:has(input:checked) {
  background: #e6f6ec;
  border-color: #b4e0c4;
}

.direct-pitch-gate input {
  accent-color: #2f73df;
  height: 16px;
  width: 16px;
}

.direct-pitch-gate-text {
  display: grid;
  gap: 2px;
}

.direct-pitch-gate-text b {
  color: #1f2a37;
  font-size: 12px;
  font-weight: 900;
}

.direct-pitch-gate-text em {
  color: #6b7686;
  font-size: 11px;
  font-style: normal;
  line-height: 1.4;
}

.direct-grow-pad {
  background: #f8fafc;
  border: 1px solid #dde6f2;
  border-radius: 8px;
  display: grid;
  gap: 6px;
  grid-template-areas:
    "top top top"
    "left center right"
    "bottom bottom bottom";
  grid-template-columns: minmax(0, 1fr) 42px minmax(0, 1fr);
  padding: 8px;
}

.direct-grow-pad.is-hidden {
  display: none;
}

.direct-grow-row {
  align-items: center;
  background: #ffffff;
  border: 1px solid #e3eaf4;
  border-radius: 7px;
  display: flex;
  gap: 6px;
  justify-content: space-between;
  min-height: 34px;
  padding: 4px 5px 4px 8px;
}

.direct-grow-top {
  grid-area: top;
  justify-self: center;
  max-width: 100%;
  width: 118px;
}

.direct-grow-left {
  grid-area: left;
}

.direct-grow-right {
  grid-area: right;
}

.direct-grow-bottom {
  grid-area: bottom;
  justify-self: center;
  max-width: 100%;
  width: 118px;
}

.direct-grow-row > span {
  color: #475569;
  font-size: 11px;
  font-weight: 900;
  min-width: 25px;
  text-align: left;
}

.direct-grow-stepper {
  background: #eef2f7;
  border: 1px solid #e2e8f0;
  border-radius: 6px;
  display: grid;
  gap: 1px;
  grid-template-columns: repeat(2, 24px);
  overflow: hidden;
}

.direct-grow-row .direct-grow-stepper {
  min-width: 49px;
}

.direct-grow-stepper .direct-icon-button {
  background: #ffffff;
  border: 0;
  border-radius: 0;
  color: #2f73df;
  font-size: 17px;
  font-weight: 900;
  line-height: 1;
  min-height: 24px;
  padding: 0;
}

.direct-grow-stepper .direct-icon-button:hover {
  background: #eff6ff;
}

.direct-grow-stepper .direct-icon-button:disabled {
  background: #f8fafc;
  color: #c2c9d2;
}

.direct-grow-center {
  align-items: center;
  background: #ffffff;
  border: 1px dashed #cdd8e7;
  border-radius: 7px;
  color: #94a3b8;
  display: grid;
  grid-area: center;
  justify-items: center;
  min-height: 44px;
}

.direct-grow-center span,
.direct-grow-center b {
  font-size: 10px;
  line-height: 1.15;
}

.direct-grow-center b {
  color: #64748b;
  font-size: 12px;
  font-weight: 950;
}

/* ── 「范围」这一段的四边增减 · 手机版 ─────────────────────────────────
   原来窄屏是「上边」占一行、「左/右」并排、「下边」占一行，中间的预览藏掉，
   四条挤成一坨，＋／− 只有 24px 见方，也看不出哪个按钮管哪条边。
   这里把十字摆回来：上下居中、左右分居两侧、中间放回那块预览（顺带显示
   「已锁定」），四边各自成一张卡，按钮放到 36×34，行距 10px。

   选择器都带上 .direct-align-tools：文件后面（「对齐页：四边增减」那一段）
   还有一条同名的 .direct-grow-pad，同权重且写在更后面，不加前缀会被它盖掉。 */
@media (max-width: 520px) {
  .direct-align-tools .direct-grow-pad {
    background: transparent;
    border: 0;
    gap: 8px;
    grid-template-areas:
      "top top top"
      "left center right"
      "bottom bottom bottom";
    grid-template-columns: minmax(0, 1fr) 66px minmax(0, 1fr);
    justify-content: stretch;
    padding: 2px 0 0;
  }

  /* 上下两条横跨三列再居中，宽度跟左右两条看齐，围出一个正十字 */
  .direct-align-tools .direct-grow-top,
  .direct-align-tools .direct-grow-bottom {
    justify-self: center;
    max-width: 100%;
    width: 148px;
  }

  /* 名字在左、＋／− 在右：左右两列有 130px 宽，横着排装得下，
     四条一共能省 40 多像素，整个十字就不用滚了 */
  .direct-align-tools .direct-grow-row {
    align-items: center;
    background: #ffffff;
    border: 1px solid #e3eaf4;
    border-radius: 10px;
    display: flex;
    gap: 6px;
    justify-content: space-between;
    padding: 5px 6px 5px 10px;
  }

  .direct-align-tools .direct-grow-row > span:first-child {
    color: #475569;
    font-size: 12px;
    font-weight: 900;
    text-align: left;
  }

  .direct-align-tools .direct-grow-row .direct-grow-stepper {
    grid-template-columns: repeat(2, 36px);
    min-width: 0;
  }

  .direct-align-tools .direct-grow-stepper .direct-icon-button {
    font-size: 19px;
    min-height: 30px;
  }

  /* 「微调」那四个方向键原来只有 32×27，而它是这一步点得最多的控件 */
  .direct-align-tools .direct-nudge-pad button {
    min-height: 36px;
    min-width: 40px;
  }

  /* 「对齐」「画面」这两段的卡片标题和分段名重复（点的就是那个分段），
     窄屏收掉，省下的高度让这一段不用滚。控件本身都自带说明：
     宽×高 有标签，自动对齐、缩放、透明度 按钮和拉杆上都写着名字。 */
  .direct-align-tools [data-align-group="size"] > .direct-card-head,
  .direct-align-tools [data-align-group="view"] > .direct-card-head {
    display: none;
  }

  /* 「网格 / 图片」上下排（和 PC 一样）。原来为了省高度让它们并排，
     但这是一组二选一的开关，竖着排更像一列选项，横着排容易读成两个动作。 */
  .direct-align-tools .direct-move-split .direct-mode-row {
    grid-template-columns: minmax(0, 1fr);
  }

  .direct-align-tools .direct-move-split .direct-align-mode {
    font-size: 12px;
    min-height: 36px;
    width: auto;
  }


  .direct-align-tools .direct-grow-center {
    background: #f8fafc;
    border-radius: 10px;
    display: grid;
    padding: 4px;
  }

  .direct-align-tools .direct-extent-lock {
    font-size: 9px;
    padding: 2px 5px;
    white-space: nowrap;
  }

  /* 「✓ 已对准 · 格距」这一条在手机上收起来：下面那条「锁定对齐结果」
     已经说了同一件事，而分段条本身就是回去改对齐的入口。省下的高度
     刚好够十字完整露出来。 */
  .direct-align-tools .direct-aligned-summary {
    display: none;
  }

}

.direct-tile-preview {
  background:
    linear-gradient(45deg, #eef2f7 25%, transparent 25%, transparent 75%, #eef2f7 75%),
    linear-gradient(45deg, #eef2f7 25%, #ffffff 25%, #ffffff 75%, #eef2f7 75%);
  background-position: 0 0, 6px 6px;
  background-size: 12px 12px;
  border: 1px solid #dde6f2;
  border-radius: 6px;
  display: grid;
  min-height: 0;
  overflow: hidden;
  place-items: center;
}

.direct-tile-preview canvas {
  display: block;
  height: 132px;
  width: 100%;
}

.direct-tile-preview.is-hidden {
  display: none;
}

/* Amber corner dot on cells the colour match and the OCR disagreed about, or
   where two palette colours were nearly equidistant. ::before is used because
   .direct-proof-cell.selected already owns ::after for the check mark. */
.direct-proof-cell.uncertain::before {
  background: #f59e0b;
  border: 1px solid #ffffff;
  border-radius: 50%;
  content: "";
  height: 7px;
  left: 2px;
  position: absolute;
  top: 2px;
  width: 7px;
  z-index: 1;
}

.direct-coverage-hint {
  background: #fff7ed;
  border: 1px solid #fed7aa;
  border-radius: 6px;
  color: #9a3412;
  font-size: 11px;
  line-height: 1.5;
  margin: 0;
  padding: 6px 8px;
}

.direct-coverage-hint.is-hidden {
  display: none;
}

.checkin-day.is-done {
  background: linear-gradient(160deg, #3f7ff5, #2f5fe0);
  color: #ffffff;
}

.outline-color-chip.active {
  border-color: #2868df;
  box-shadow: 0 0 0 2px rgba(40, 104, 223, 0.22);
}

.outline-choice button.active {
  background: #2868df;
  border-color: #2868df;
  color: #ffffff;
}

/* ---- 画布浮层：禁止文字选中 -------------------------------------------- */
/* 在画布上拖动时，指针扫过这些浮层会把里面的文字选中，出现一片蓝色高亮 */
.canvas-bottom-stack,
.floating-toolbox,
.editor-command-bar,
#patternCanvas {
  -webkit-user-select: none;
  user-select: none;
}

/* 按钮选中时底色是蓝的，强调色再用蓝就看不见了；清除是红的，蓝也不搭 */
.floating-toolbox .tool-button.active .tool-glyph .tool-icon-accent,
.selection-actions button.active .tool-glyph .tool-icon-accent,
.selection-actions .danger-action .tool-glyph .tool-icon-accent,
.editor-command-bar button.active .tool-glyph .tool-icon-accent {
  stroke: currentColor;
}

/* ---- 我的图库顶栏：logo 与标题的排布对齐拼豆图纸识别 / 生成页 ---------- */
body[data-view="projects"] .topbar {
  gap: 24px;
  justify-content: flex-start;
  min-height: 72px;
  padding: 7px 42px;
}

body[data-view="projects"] .brand-button {
  flex: 0 0 auto;
  min-width: 136px;
  transform: none;
  width: auto;
}

/* 窄屏只收 gap 和内边距，min-height 与 logo 宽度一路保持，和识别页一致 */
@media (max-width: 900px) {
  body[data-view="projects"] .topbar {
    gap: 12px;
    padding: 7px 16px;
  }

  body[data-view="projects"] .projects-header-title {
    font-size: 20px;
  }

  body[data-view="projects"] .projects-header-group {
    margin-left: 0;
  }
}

.project-sync-badge.synced {
  display: none;
}

.grid-theme-menu button.active {
  background: #2868df;
  color: #ffffff;
}

/* ---- 滑杆统一为细轨蓝色 + 数值胶囊（方案 2）--------------------------- */
/* input 本身保持 16px 高以留出点击区，可见轨道用伪元素画成 4px；
   直接把 input 压成 4px 的话触屏上几乎按不中 */
input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  background: transparent;
  border: 0;
  cursor: pointer;
  height: 16px;
  min-height: 16px;
  padding: 0;
  width: 100%;
}

/* 填充百分比由 syncRangeFill() 写进 --range-fill */
input[type="range"]::-webkit-slider-runnable-track {
  background: linear-gradient(
    to right,
    #2868df 0 var(--range-fill, 0%),
    #dfe3eb var(--range-fill, 0%) 100%
  );
  border-radius: 99px;
  height: 4px;
}

input[type="range"]::-moz-range-track {
  background: linear-gradient(
    to right,
    #2868df 0 var(--range-fill, 0%),
    #dfe3eb var(--range-fill, 0%) 100%
  );
  border-radius: 99px;
  height: 4px;
}

input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  background: #ffffff;
  border: 2px solid #2868df;
  border-radius: 50%;
  box-shadow: 0 1px 4px rgba(31, 46, 64, 0.22);
  cursor: pointer;
  height: 13px;
  margin-top: -4.5px;
  width: 13px;
}

input[type="range"]::-moz-range-thumb {
  background: #ffffff;
  border: 2px solid #2868df;
  border-radius: 50%;
  box-shadow: 0 1px 4px rgba(31, 46, 64, 0.22);
  cursor: pointer;
  height: 13px;
  width: 13px;
}

input[type="range"]:focus-visible {
  outline: 0;
}

input[type="range"]:focus-visible::-webkit-slider-thumb {
  box-shadow: 0 0 0 3px rgba(40, 104, 223, 0.25);
}

input[type="range"]:disabled {
  cursor: default;
  filter: grayscale(1);
  opacity: 0.5;
}

/* 笔刷数值原本是墨绿实心胶囊、setup 页那几个继承正文深色，统一到同一套 */
.brush-size-value b.range-value,
.setup-panel .range-value,
.setup-view .range-value,
b.range-value {
  background: #eef4ff;
  border-radius: 99px;
  color: #2868df;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  font-weight: 800;
  height: auto;
  min-width: 34px;
  padding: 2px 9px;
}

/* ---- 撤销/重做：原来固定浅灰且无 :disabled 规则，可用与不可用长得一样 ---- */
body[data-view="editor"][data-editor-mode="edit"] .history-cluster .history-button {
  color: #46536a;
  transition: color 0.15s ease, background 0.15s ease, border-color 0.15s ease;
}

body[data-view="editor"][data-editor-mode="edit"] .history-cluster .history-button:hover:not(:disabled) {
  background: #eef4ff;
  border-color: #b9cdf0;
  color: #2868df;
}

body[data-view="editor"][data-editor-mode="edit"] .history-cluster .history-button:disabled {
  background: #f7f9fb;
  border-color: #e8edf3;
  color: #c3cad3;
  cursor: not-allowed;
}

/* ---- 裁剪步骤的一次性提示 ---------------------------------------------- */
/* 排版向「是否保存当前作品？」那种对话卡片看齐：加粗标题 ＋ 灰色说明 ＋
   底部一行操作，整体左对齐。「不再提示」从按钮改成勾选框，勾上不会立刻关掉，
   点「知道了」时才落盘。 */
.direct-crop-hint {
  align-items: stretch;
  background: #ffffff;
  border: 1px solid #dce3ec;
  border-radius: 8px;
  box-shadow: 0 18px 54px rgba(30, 43, 59, 0.2);
  display: grid;
  gap: 18px;
  justify-items: stretch;
  left: 50%;
  padding: 22px;
  position: absolute;
  top: 46%;
  transform: translate(-50%, -50%);
  width: min(420px, calc(100vw - 28px));
  z-index: 24;
}

.direct-crop-hint-copy strong {
  color: #1d2734;
  display: block;
  font-size: 18px;
  font-weight: 900;
  line-height: 1.35;
}

.direct-crop-hint p {
  color: var(--muted);
  font-size: 12px;
  font-weight: 500;
  line-height: 1.6;
  margin: 8px 0 0;
  text-align: left;
  white-space: normal;
}

.direct-crop-hint-actions {
  align-items: center;
  display: flex;
  gap: 12px;
  justify-content: space-between;
}

.direct-crop-hint-never {
  align-items: center;
  color: var(--muted);
  cursor: pointer;
  display: inline-flex;
  font-size: 12px;
  font-weight: 800;
  gap: 7px;
  user-select: none;
}

.direct-crop-hint button {
  background: #1d2734;
  border: 0;
  border-radius: 8px;
  color: #ffffff;
  flex: none;
  font-size: 13px;
  font-weight: 800;
  min-height: 38px;
  padding: 0 26px;
}

.direct-crop-hint button:hover {
  background: #12202c;
}

@media (max-width: 620px) {
  .direct-crop-hint {
    gap: 14px;
    min-height: 120px;
    padding: 20px 18px;
    width: min(460px, calc(100vw - 32px));
  }

  .direct-crop-hint p {
    font-size: 16px;
    white-space: normal;
  }
}

/* ── 色号校对页：左 2/3 色块、右 1/3 操作 ──────────────────────────────
   原来是上下两块（色块在上、工作台在下），色块区被挤成扁条，翻页特别频繁。
   改成左右分栏后色块区拿到整个高度，同时色块本身从 54px 缩到 36px，
   一页能装下的格子大约是原来的 3 倍。右栏在「挑格子」和「选替换色」
   两个状态间原地切换，两边的方格样式和位置一致，切换时视线不用重找。 */
.direct-stage[data-direct-panel="proof"] {
  gap: 10px;
  grid-template-columns: minmax(0, 3.5fr) minmax(248px, 1fr);
  grid-template-rows: minmax(0, 1fr);
  height: calc(100vh - 104px);
}

.direct-stage[data-direct-panel="proof"] .direct-proof-area {
  display: grid;
  gap: 8px;
  /* 翻页条那一行给死高度，网格的可用高度才不会随它有没有内容而变 */
  grid-template-rows: minmax(0, 1fr) 34px;
  overflow: hidden;
  padding: 10px;
}

/* 列数由 JS 按实际宽度算好写进 --proof-cols，格子用 1fr 把整行填满，
   每页恰好是 列 × 行 个格子，所以不会再留半行或者底下一条空带 */
.direct-stage[data-direct-panel="proof"] .direct-proof-grid {
  /* 行数是向下取整的，竖向总会剩下不到一格的余量；装满的整页把它摊到行间距里，
     底部就不会留一条空白带。没装满的页（最后一页）必须从顶部排起——否则两三行
     会被推成一上一下、中间空一大块。 */
  align-content: start;
  gap: 5px;
  grid-template-columns: repeat(var(--proof-cols, 10), minmax(0, 1fr));
  justify-content: stretch;
  min-height: 0;
  overflow: hidden;
}

.direct-stage[data-direct-panel="proof"] .direct-proof-grid .direct-empty-note {
  grid-column: 1 / -1;
}

.direct-stage[data-direct-panel="proof"] .direct-proof-pager {
  align-self: center;
  bottom: auto;
  justify-self: end;
  position: static;
  right: auto;
}

/* touch-action:none 让手指按在格子上直接开始连选，而不是拖动滚动条 */
.direct-stage[data-direct-panel="proof"] .direct-proof-cell {
  border-radius: 5px;
  font-size: 10px;
  touch-action: none;
}

.direct-stage[data-direct-panel="proof"] .direct-proof-cell.selected::after {
  font-size: 10px;
  height: 16px;
  right: -4px;
  top: -4px;
  width: 16px;
}

/* 两个子面板叠在同一个格子里，靠 is-hidden 决定谁露面 */
.direct-stage[data-direct-panel="proof"] .direct-proof-workbench {
  display: grid;
  gap: 10px;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto minmax(0, 1fr);
  min-height: 0;
  overflow: hidden;
  padding: 12px;
}

/* 提示语常驻第一行，「挑格子」和「选替换色」两块叠在第二行同一个格子里 */
.direct-stage[data-direct-panel="proof"] .direct-proof-workbench > .direct-proof-task {
  grid-area: 1 / 1;
}

.direct-stage[data-direct-panel="proof"] .direct-proof-side,
.direct-stage[data-direct-panel="proof"] .direct-replace-panel {
  grid-area: 2 / 1;
  min-height: 0;
  min-width: 0;
}

.direct-stage[data-direct-panel="proof"] .direct-replace-panel {
  background: transparent;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  gap: 10px;
  grid-template-rows: auto minmax(0, 1fr) auto;
  height: auto;
  padding: 0;
}

/* 底部不留白，「已选 N · 改为…」这一行贴住面板底边。
   曾经留过 54px 给右下角那个问号浮标，其实是多留的：浮标是 position: fixed、
   bottom: 18px，钉在视口右下角，而这个面板的底边总在底部那条「上一步 / 下一步」
   之上，两者根本不重叠（2026-09-22 实测：浮标 712–750，面板底 688）。
   窄屏那套规则本来就把它设成 0，桌面这条是对不上的。 */
.direct-proof-side {
  display: grid;
  gap: 10px;
  grid-template-rows: auto minmax(0, 1fr) auto auto;
  min-height: 0;
  overflow: hidden;
  padding: 0;
}

.direct-stage[data-direct-panel="proof"] .direct-replace-panel {
  padding-bottom: 54px;
}

.direct-proof-task {
  background: var(--surface-muted, #f1f4f7);
  border-radius: 8px;
  color: var(--muted);
  font-size: 12px;
  font-weight: 800;
  line-height: 1.5;
  margin: 0;
  padding: 8px 10px;
}

.direct-proof-task b {
  color: var(--ink);
  font-weight: 950;
}

.direct-proof-task b.direct-proof-task-code {
  background: var(--task-code-bg, #eef1f4);
  border: 1px solid rgba(30, 41, 43, 0.2);
  border-radius: 4px;
  color: var(--task-code-text, #26302f);
  padding: 1px 6px;
}

.direct-proof-side .direct-proof-summary {
  border-bottom: 1px solid var(--line);
  font-size: 12px;
  gap: 8px;
  padding: 0 2px 9px;
}

.direct-proof-side .direct-proof-color-list {
  align-content: start;
  gap: 9px 10px;
  overflow: auto;
  padding: 2px 4px 2px 0;
}

/* 方格保持正方形，豆数挂在正下方 */
.direct-color-chip-cell {
  display: grid;
  gap: 3px;
  justify-items: center;
  width: 40px;
}

.direct-color-chip-count {
  color: var(--muted);
  font-size: 10px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

.direct-color-chip-cell:has(.direct-color-chip.active) .direct-color-chip-count {
  color: #7b4b99;
}

/* 前 4 个按钮两个一行，排序/下一组/移除 挤在最后一行 */
.direct-proof-side .direct-proof-actions {
  border-top: 1px solid var(--line);
  display: grid;
  gap: 5px;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  padding-top: 10px;
}

.direct-proof-side .direct-proof-actions > * {
  font-size: 11px;
  grid-column: span 3;
  letter-spacing: -0.01em;
  min-height: 28px;
  min-width: 0;
  padding: 5px 2px;
}

.direct-proof-side .direct-proof-center {
  align-items: center;
  border-top: 1px solid var(--line);
  display: flex;
  gap: 10px;
  justify-content: space-between;
  min-height: 0;
  padding: 10px 2px 0;
  place-self: auto;
}

.direct-proof-side .direct-proof-center > span {
  font-size: 13px;
  min-height: 0;
  padding: 0;
}

.direct-proof-more {
  display: none;
}

.direct-change-button {
  flex: none;
  min-height: 34px;
  padding: 0 18px;
}

.direct-change-button:disabled {
  background: #dfe3e7;
  border-color: #dfe3e7;
  color: #96a0a8;
  cursor: not-allowed;
}

@media (max-width: 980px) {
  .direct-stage[data-direct-panel="proof"] {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: minmax(0, 1.4fr) minmax(260px, 1fr);
    height: auto;
  }
}

/* ── 校色页 · 手机版 ───────────────────────────────────────────────────
   照参考图重排（方案 A：只换工作区，向导的顶栏和上一步/下一步一点不动）：
     1. 不分页。原来 375px 上是 7×7 一页、翻 1/7 页；现在一组色号一路竖着滑完。
        一组可能有两千多格，所以按屏分批铺，滑到底再续一屏（见 app.js）。
     2. 格子 7 列 → 8 列，和参考图一致。
     3. 八个批量按钮缩成三个文字链接：全选 / 反选 / 排序。带「本页」的三个
        随分页一起消失；「下一组」用不着了——底下那条色号条本来就是切组的；
        「移除」并进「改为…」的面板里。
     4. 色号条和动作条各占一行，排在格子下面。
   紫色是参考图那个 app 的主色，这里一律用站里原本的蓝（--blue / #2868df）。 */
@media (max-width: 520px) {
  .direct-stage[data-direct-panel="proof"] {
    grid-template-rows: minmax(0, 1fr) auto;
  }

  /* 点「改为…」之后：替换面板只占下半屏，上半屏留给图纸，看得见自己选了哪几格。
     以前工作区这一行是 auto，勾上「全部色号」那一长串 A–Y 把它撑得比屏幕还高，图纸被挤到 0。
     两行各占一半之后面板有了确定的高度，色号列表就在面板里上下滑（它本来就是 overflow: auto）；
     打开时列表会先滚到当前色号那一组（app.js 的 revealReplaceTargets）。 */
  .direct-stage[data-direct-panel="proof"].is-replacing {
    grid-template-rows: minmax(0, 1fr) minmax(0, 1fr);
  }

  /* 翻页条那一行的预留高度还给格子 */
  .direct-stage[data-direct-panel="proof"] .direct-proof-area {
    grid-template-rows: minmax(0, 1fr);
    padding: 6px;
  }

  .direct-stage[data-direct-panel="proof"] .direct-proof-pager {
    display: none;
  }

  .direct-stage[data-direct-panel="proof"] .direct-proof-grid {
    overflow-y: auto;
    overscroll-behavior: contain;
  }

  .direct-stage[data-direct-panel="proof"] .direct-proof-workbench {
    padding: 8px 10px 10px;
  }

  /* 色号条一行、三个链接一行、已选 + 改为一行。
     链接和「已选 / 改为」原本挤在同一行，中文放得下，英文
     「Select all · Invert · Default sort」加上「Selected 0 · Change…」
     就撞到一起了——分成两行，哪种语言都不会挤。 */
  /* 手机上这块改成可换行的 flex：色号条自己占满一行，
     「全选 / 反选 / 排序」和「已选 N · 改为…」放得下就并成一行，
     放不下（英文 Select all · Invert · Similarity sort 就放不下）
     自动折成两行。用 grid 做不到这个——同一格里的两个元素只会叠在一起。 */
  .direct-proof-side {
    align-items: center;
    column-gap: 10px;
    display: flex;
    flex-wrap: wrap;
    overflow: visible;
    padding-bottom: 0;
    row-gap: 6px;
  }

  /* 「6 色号 · 529 豆 · MARD-291」这一行在手机上让位：
     任务句已经说了当前是哪个色号，条上每个色号也各自带着数量 */
  .direct-proof-side .direct-proof-summary {
    display: none;
  }

  .direct-proof-side .direct-proof-color-list {
    flex: 0 0 100%;
    flex-wrap: nowrap;
    height: 58px;
    overflow-x: auto;
    overflow-y: hidden;
    padding-bottom: 2px;
  }

  .direct-proof-side .direct-proof-actions {
    align-items: center;
    border-top: 0;
    display: flex;
    flex: 0 1 auto;
    gap: 14px;
    padding-top: 0;
  }

  /* 分页没了，「本页」三个也就没意义；下一组由色号条代劳；移除并进替换面板 */
  .direct-proof-side .direct-proof-actions > [data-direct-proof-action="select-page"],
  .direct-proof-side .direct-proof-actions > [data-direct-proof-action="invert-page"],
  .direct-proof-side .direct-proof-actions > [data-direct-proof-action="clear-page"],
  .direct-proof-side .direct-proof-actions > [data-direct-proof-action="clear"],
  .direct-proof-side .direct-proof-actions > [data-direct-proof-action="next-group"] {
    display: none;
  }

  /* 剩下三个画成文字链接。
     三条都要显式写死：底色、描边、投影、圆角、点按高亮、焦点框，
     少写一条就会出现「有的带框有的不带」——iOS 上点过的按钮会留一层
     -webkit-tap-highlight 的圆角色块，截图里看着就像多了个边框。 */
  .direct-proof-side .direct-proof-actions > * {
    -webkit-tap-highlight-color: transparent;
    background: none;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    color: #2868df;
    font-size: 13px;
    font-weight: 800;
    grid-column: auto;
    min-height: 30px;
    padding: 0;
    white-space: nowrap;
    width: auto;
  }

  .direct-proof-side .direct-proof-actions > *:hover,
  .direct-proof-side .direct-proof-actions > *:active,
  .direct-proof-side .direct-proof-actions > *.active {
    background: none;
    border: 0;
    box-shadow: none;
    color: #1b4ea8;
  }

  .direct-proof-side .direct-proof-actions > *:focus {
    outline: none;
  }

  .direct-proof-side .direct-proof-actions > *:focus-visible {
    outline: 2px solid #2868df;
    outline-offset: 2px;
  }

  /* 三个链接和「已选 N · 改为…」并到同一行：链接靠左，已选和改为靠右。
     原来分两行是怕英文挤（Select all · Invert · Default sort + Selected 0 ·
     Change…），所以英文的「默认排序 / 色号排序」译文缩短了，见 app.js 的词表。 */
  .direct-proof-side .direct-proof-center {
    border-top: 0;
    flex: 1 1 auto;
    justify-content: flex-end;
    min-height: 38px;
    padding: 0;
  }

  /* 「批量操作」那颗按钮和它的抽屉都不需要了 */
  .direct-proof-more {
    display: none;
  }

  .direct-replace-clear {
    background: #ffffff;
    border: 1px solid var(--line);
    border-radius: 999px;
    color: var(--ink);
    font-size: 12px;
    font-weight: 800;
    min-height: 30px;
    padding: 0 12px;
  }

  .direct-stage[data-direct-panel="proof"] .direct-replace-panel {
    padding-bottom: 0;
  }

  body[data-view="setup"][data-module="direct"][data-direct-step="proof"] .direct-caption {
    display: none;
  }
}

/* 「移除」只在手机版的替换面板里出现；宽屏它还在批量按钮那一排 */
.direct-replace-clear {
  display: none;
}

@media (max-width: 520px) {
  .direct-replace-head {
    grid-template-columns: 1fr auto auto;
  }

  .direct-replace-clear {
    display: inline-flex;
    align-items: center;
  }
}

/* 「全部色号」原来用的是系统原生复选框，各平台长得都不一样、还带一层
   浏览器自己的底色。这里自己画一个：方角圆润的小方块，勾上就填主色蓝，
   对勾用两笔边框旋转 45° 画出来，不依赖字体里的 ✓ 字形。 */
.direct-replace-panel .direct-all-colors {
  align-items: center;
  color: var(--muted);
  cursor: pointer;
  display: inline-flex;
  font-size: 12px;
  font-weight: 800;
  gap: 6px;
  user-select: none;
}

/* 选择器都带上 [type="checkbox"]，比 .switch-row input / .direct-check-row input
   这些老规则更强一点，但仍然弱于 .grid-settings-panel 里的胶囊开关，
   网格设置面板那套不受影响。 */
.direct-all-colors input[type="checkbox"],
.direct-check-row input[type="checkbox"],
.checkin-hide-row input[type="checkbox"],
.welcome-never input[type="checkbox"],
.confirm-never input[type="checkbox"],
.direct-crop-hint-never input[type="checkbox"],
.export-option input[type="checkbox"],
.switch-row input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  background: #ffffff;
  border: 1.5px solid #c6cdd4;
  border-radius: 5px;
  box-shadow: none;
  box-sizing: border-box;
  cursor: pointer;
  flex: none;
  height: 16px;
  margin: 0;
  min-height: 0;
  min-width: 0;
  padding: 0;
  position: relative;
  transition: background 0.12s ease, border-color 0.12s ease;
  width: 16px;
}

.direct-all-colors input[type="checkbox"]:hover,
.direct-check-row input[type="checkbox"]:hover,
.checkin-hide-row input[type="checkbox"]:hover,
.welcome-never input[type="checkbox"]:hover,
.confirm-never input[type="checkbox"]:hover,
.direct-crop-hint-never input[type="checkbox"]:hover,
.export-option input[type="checkbox"]:hover,
.switch-row input[type="checkbox"]:hover {
  border-color: #2868df;
}

.direct-all-colors input[type="checkbox"]:checked,
.direct-check-row input[type="checkbox"]:checked,
.checkin-hide-row input[type="checkbox"]:checked,
.welcome-never input[type="checkbox"]:checked,
.confirm-never input[type="checkbox"]:checked,
.direct-crop-hint-never input[type="checkbox"]:checked,
.export-option input[type="checkbox"]:checked,
.switch-row input[type="checkbox"]:checked {
  background: #2868df;
  border-color: #2868df;
}

.direct-all-colors input[type="checkbox"]:checked::after,
.direct-check-row input[type="checkbox"]:checked::after,
.checkin-hide-row input[type="checkbox"]:checked::after,
.welcome-never input[type="checkbox"]:checked::after,
.confirm-never input[type="checkbox"]:checked::after,
.direct-crop-hint-never input[type="checkbox"]:checked::after,
.export-option input[type="checkbox"]:checked::after,
.switch-row input[type="checkbox"]:checked::after {
  border: solid #ffffff;
  border-width: 0 2px 2px 0;
  content: "";
  height: 8px;
  left: 4.5px;
  position: absolute;
  top: 1.5px;
  transform: rotate(45deg);
  width: 4px;
}

.direct-all-colors input[type="checkbox"]:focus-visible,
.direct-check-row input[type="checkbox"]:focus-visible,
.checkin-hide-row input[type="checkbox"]:focus-visible,
.welcome-never input[type="checkbox"]:focus-visible,
.confirm-never input[type="checkbox"]:focus-visible,
.direct-crop-hint-never input[type="checkbox"]:focus-visible,
.export-option input[type="checkbox"]:focus-visible,
.switch-row input[type="checkbox"]:focus-visible {
  outline: 2px solid rgba(40, 104, 223, 0.35);
  outline-offset: 1px;
}

.direct-replace-panel .direct-all-colors:has(input:checked) {
  color: #2868df;
}

/* 右栏收窄了，替换面板里的方格也跟着排密一点 */
.direct-stage[data-direct-panel="proof"] .direct-replace-family-grid {
  gap: 6px;
  grid-template-columns: repeat(auto-fill, minmax(38px, 1fr));
}

.direct-stage[data-direct-panel="proof"] .direct-replace-actions {
  gap: 8px;
}

/* ── 对齐页：画面设置 ────────────────────────────────────────────────
   原来两条拉杆只有一个百分比数字，看不出哪条管什么。名字和数值分踞
   一行的两端，拉杆独占下面一行，这样名字能写全、拉杆也拿到完整宽度。 */
.direct-view-slider {
  display: grid;
  gap: 4px;
}

.direct-view-slider + .direct-view-slider {
  margin-top: 8px;
}

.direct-view-slider-head {
  align-items: baseline;
  display: flex;
  justify-content: space-between;
}

.direct-view-slider-head span:first-child {
  color: #5a6472;
  font-size: 12px;
  font-weight: 800;
}

.direct-view-slider-head span:last-child {
  color: #233033;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  font-weight: 900;
}

.direct-view-slider .direct-view-zoom-row {
  grid-template-columns: 30px 1fr 30px;
}

/* ── 对齐页：网格范围 ────────────────────────────────────────────────
   四组增减从「文字和按钮挤在一行的白卡片」改成「文字在上、按钮在下」的
   小块，卡片外壳去掉，四个方向就能贴到中间缩略图边上；中间那块原来是写死
   的虚线「边缘调格」占位，现在换成跟着 state.width×state.height 实时重画的
   缩略图，外圈一格用蓝色标出来，正是 ＋／− 会动的那一圈。 */
.direct-grow-pad {
  gap: 4px;
  /* 三列都收成内容宽再整体居中，左右两组按钮才会贴着缩略图，
     用 1fr 的话中间列会吃掉全部富余宽度、把按钮推到卡片两端 */
  grid-template-columns: auto auto auto;
  justify-content: center;
  padding: 10px 8px;
}

.direct-grow-row {
  /* 左右两组会被拉到和中间缩略图一样高，不居中的话文字顶在最上、
     按钮沉到最下，中间空一大截 */
  align-content: center;
  background: transparent;
  border: 0;
  border-radius: 0;
  display: grid;
  gap: 3px;
  justify-items: center;
  min-height: 0;
  padding: 0;
}

.direct-grow-top,
.direct-grow-bottom {
  width: auto;
}

.direct-grow-row > span:first-child {
  min-width: 0;
  text-align: center;
}

.direct-grow-center {
  align-items: center;
  background: transparent;
  border: 0;
  justify-items: center;
  min-height: 0;
  padding: 0 2px;
  position: relative;
}

.direct-extent-preview {
  display: grid;
  place-items: center;
  width: 100%;
}

.direct-extent-preview svg {
  display: block;
  height: auto;
  max-width: 100%;
}

.direct-extent-lock {
  background: rgba(255, 255, 255, 0.9);
  border-radius: 5px;
  color: #2f73df;
  font-size: 11px;
  font-weight: 900;
  left: 50%;
  padding: 2px 9px;
  position: absolute;
  top: 50%;
  transform: translate(-50%, -50%);
  white-space: nowrap;
}

/* 没点过「知道了」之前拦住「下一步」，拦下来时整个提示框闪一下边框 */
@keyframes directCropHintPulse {
  0%, 100% { box-shadow: 0 16px 40px rgba(31, 44, 41, 0.16), 0 0 0 0 rgba(40, 104, 223, 0); }
  30% { box-shadow: 0 16px 40px rgba(31, 44, 41, 0.16), 0 0 0 5px rgba(40, 104, 223, 0.35); }
  65% { box-shadow: 0 16px 40px rgba(31, 44, 41, 0.16), 0 0 0 0 rgba(40, 104, 223, 0); }
}

.direct-crop-hint.is-flash {
  animation: directCropHintPulse 0.62s ease-in-out;
  border-color: #2868df;
}

@media (prefers-reduced-motion: reduce) {
  .direct-crop-hint.is-flash {
    animation: none;
    box-shadow: 0 16px 40px rgba(31, 44, 41, 0.16), 0 0 0 4px rgba(40, 104, 223, 0.35);
  }
}

/* 单格格距：藏掉原生数字框的上下箭头，旁边已经有 ＋／− 了，
   两套加减挤在一起既难点又难看 */
.direct-pitch-row input[type="number"] {
  appearance: textfield;
  -moz-appearance: textfield;
}

.direct-pitch-row input[type="number"]::-webkit-outer-spin-button,
.direct-pitch-row input[type="number"]::-webkit-inner-spin-button {
  appearance: none;
  -webkit-appearance: none;
  margin: 0;
}

/* 工具卡标题左边一道竖条。原来标题 13px、下面的输入框文字 11px，只差 2px 又都很粗，
   往下扫时分不出哪是标题哪是内容。竖条是纯图形信号，不靠字号就能把标题拎出来，
   顺带标出每张卡的起点。颜色跟着 is-red / is-blue 变体走。 */
.direct-tool-card .direct-card-head strong {
  border-left: 3px solid #2f73df;
  line-height: 1.35;
  padding-left: 9px;
}

.direct-tool-card .direct-card-head.is-red strong {
  border-left-color: #ff4e63;
}

.direct-tool-card .direct-card-head.is-blue strong {
  border-left-color: #3b82f6;
}

/* 小步长同时管方向键和格距 ＋／−，所以放到卡片标题那一行的右端——
   位置上它就统管整张卡，不会被读成只管紧挨着的那一段。
   标题行是 space-between，不用额外对齐。 */
.direct-tool-card .direct-card-head .direct-fine-step-row {
  border-top: 0;
  color: var(--muted);
  cursor: pointer;
  flex: none;
  font-size: 11px;
  font-weight: 800;
  gap: 6px;
  margin: 0;
  padding: 0;
}

/* 裁剪页的「示例」侧栏删掉了（两个示意槽从来没画过内容，重置裁剪也挪到了顶栏），
   这一步现在只剩裁剪框，让它吃满整行宽度。
   选择器要写这么长，是因为上面
   .setup-view.direct-setup-active .direct-stage:not([data-direct-panel="proof"]):not(.direct-finish-stage)
   已经占到 (0,5,0)，短选择器压不住它那条 340px 侧栏。 */
body[data-view="setup"][data-module="direct"] .setup-view.direct-setup-active .direct-stage[data-direct-panel="crop"] {
  grid-template-columns: minmax(0, 1fr);
}

.brush-shape-option.active {
  background: #eef4ff;
  border-color: #2868df;
  color: #2868df;
}

/* 导入页只剩一列品牌清单，340px 是当初按「品牌名＋色数一行」量的，
   现在右边留了一大片白。收到约三分之二宽。 */
body[data-view="setup"][data-module="direct"] .setup-view.direct-setup-active .direct-stage[data-direct-panel="import"] {
  grid-template-columns: 227px minmax(0, 1fr);
}

/* 移动对象改成左右分栏：对象竖着排在左，方向键菱形留在右。
   原来是「一整条切换 ＋ 三行菱形」共五行，中间还空着一个洞；
   换成横向排布之后高度减半，菱形的方位感也保住了。 */
/* 富余宽度给左边那列（让网格／图片两个按钮撑开），而不是留在两者中间。
   这样方向键仍然贴右、左边仍然贴左，中间的空当只剩一个 gap。 */
.direct-move-split {
  align-items: center;
  display: grid;
  gap: 10px;
  grid-template-columns: minmax(0, 1fr) auto;
}

.direct-move-split .direct-mode-row {
  gap: 5px;
  grid-template-columns: minmax(0, 1fr);
}

/* 侧栏只有 228px，左边占掉一截之后按钮得收窄 */
.direct-move-split .direct-align-mode {
  font-size: 11px;
  min-height: 30px;
  padding: 5px 12px;
  white-space: nowrap;
}

.direct-move-split .direct-nudge-pad {
  gap: 3px;
  justify-self: center;
}

.direct-move-split .direct-nudge-pad button {
  font-size: 15px;
  height: 27px;
  width: 32px;
}

/* 按尺寸对齐：宽和高之间加一个真的「×」把它们连成一对尺寸；
   「应用」原来是个窄边框按钮，最该点的东西反而最不显眼，换成实心对勾。 */
.direct-apply-row {
  align-items: center;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr) auto;
}

.direct-size-times {
  color: #96a0ac;
  font-size: 12px;
  line-height: 1;
  padding: 0 1px;
}

.direct-size-apply-icon {
  background: #2f73df;
  border: 1px solid #2f73df;
  border-radius: 7px;
  color: #ffffff;
  cursor: pointer;
  font-size: 15px;
  font-weight: 900;
  line-height: 1;
  min-height: 34px;
  width: 34px;
}

.direct-size-apply-icon:hover:not(:disabled) {
  background: #245fbb;
  border-color: #245fbb;
}

.direct-size-apply-icon:disabled {
  background: #dfe3e7;
  border-color: #dfe3e7;
  color: #96a0a8;
  cursor: not-allowed;
}

/* 单格格距：横竖已经联动，两个永远相同的数字框收成一个，
   加减并排放在右边。输入框因此拿到整行剩余宽度。 */
/* 框子按内容收窄，不再撑满整列——里面只有一个数字加单位，撑满就显得空 */
.direct-pitch-row {
  align-items: center;
  grid-template-columns: auto auto;
  justify-content: space-between;
}

/* 数字原来贴着左边、单位贴着右边，中间空一大段。改成「数字 ＋ 单位」作为
   一组整体居中，数字自己右对齐，这样小数点的位置也稳定，不会跳来跳去。 */
.direct-pitch-row label {
  gap: 5px;
  justify-content: center;
  padding: 3px 10px;
}

.direct-pitch-row label input {
  flex: 0 1 auto;
  min-height: 28px;
  min-width: 0;
  text-align: right;
  width: 56px;
}

.direct-pitch-row label small {
  color: #96a0ac;
  flex: none;
  font-size: 10px;
  font-weight: 700;
  white-space: nowrap;
}

.direct-pitch-step {
  gap: 4px;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: none;
}

.direct-pitch-step .direct-icon-button {
  min-height: 34px;
  width: 34px;
}

/* 圆角小按钮里只有一个符号，原来靠 line-height 摆位：line-height 20px 装在
   34px 高的盒子里，字就贴着上沿，看着「没在方框中心」。改成 grid 居中，
   和盒子多高、padding 多少都无关。 */
.direct-icon-button {
  display: grid;
  line-height: 1;
  place-items: center;
}

/* 格距那两个符号换成 U+2212 减号和普通加号：全角的 －（U+FF0D）在多数字体里
   是按文字基线画的、不在数学中心，和 ＋ 并排就会一高一低。 */
.direct-pitch-step .direct-icon-button {
  font-size: 18px;
  padding: 0;
}

/* 对齐页侧栏。227px（比原来的 340 少三分之一）会把「按尺寸对齐」那一行压塌——
   宽高两个输入框只剩 27px，连三位数都放不下。这里先取 270px 作为不破坏内容的
   中间值，真正的宽度等那一行改完再定。 */
.direct-wizard.direct-align-workspace .direct-stage[data-direct-panel="align"],
body[data-view="setup"][data-module="direct"] .setup-view.direct-setup-active .direct-stage[data-direct-panel="align"] {
  grid-template-columns: 270px minmax(0, 1fr);
}

/* 方向键原来在自己那一列里居中，右边空出 64px，而同一张卡里其它行都是通栏，
   一眼看去就这一行「没到边」。改成靠右，整张卡的右边界就齐了。 */
.direct-move-split .direct-nudge-pad {
  justify-self: end;
}

/* .direct-apply-row .direct-size-apply 是 (0,2,0)，把裸类名的 34px 压掉了，
   所以对勾按钮一直是 48 宽。这里用同样的作用域拿回来。 */
.direct-apply-row .direct-size-apply-icon {
  padding: 0;
  width: 34px;
}

/* 装满的整页才摊余量，见 renderDirectProof 里的 is-full-page */
.direct-stage[data-direct-panel="proof"] .direct-proof-grid.is-full-page {
  align-content: space-between;
}

/* ── 新手导航 ────────────────────────────────────────────────────────
   遮罩只压暗、不拦操作：挖空的那块是 pointer-events:none，点下去直接落在
   真控件上。所以用户想跳着做也不会被卡住。 */
.tour-overlay {
  inset: 0;
  pointer-events: none;
  position: fixed;
  z-index: 400;
}

.tour-overlay.is-hidden {
  display: none;
}

/* 原来这里用超大扩散阴影把四周压暗。去掉了：对齐那一步你必须盯着画布看格线
   压没压准，遮罩挡的正是唯一要看的东西。高亮环本来就够指明位置了。 */
.tour-spotlight {
  border-radius: 10px;
  box-shadow: 0 0 0 3px rgba(55, 138, 221, 0.9), 0 0 0 7px rgba(55, 138, 221, 0.18);
  pointer-events: none;
  position: absolute;
  transition: top 180ms ease, left 180ms ease, width 180ms ease, height 180ms ease;
}

.tour-bubble {
  background: #ffffff;
  border-radius: 10px;
  box-shadow: 0 18px 54px rgba(15, 23, 32, 0.32);
  display: grid;
  gap: 8px;
  max-width: calc(100vw - 24px);
  padding: 14px 16px;
  pointer-events: auto;
  position: absolute;
  width: 300px;
}

.tour-bubble strong {
  color: #1d2734;
  font-size: 14px;
  font-weight: 900;
  line-height: 1.35;
}

.tour-bubble p {
  color: #5a6472;
  font-size: 12px;
  line-height: 1.6;
  margin: 0;
}

.tour-foot {
  align-items: center;
  display: flex;
  gap: 10px;
  justify-content: space-between;
  margin-top: 2px;
}

.tour-count {
  color: #96a0ac;
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  font-weight: 700;
}

.tour-actions {
  display: flex;
  gap: 6px;
}

.tour-ghost,
.tour-primary {
  border-radius: 7px;
  cursor: pointer;
  font-size: 12px;
  font-weight: 800;
  min-height: 30px;
  padding: 0 12px;
}

.tour-ghost {
  background: transparent;
  border: 1px solid #dce3ec;
  color: #5a6472;
}

.tour-ghost:hover:not(:disabled) {
  border-color: #2868df;
  color: #2868df;
}

.tour-ghost:disabled {
  color: #c2cad4;
  cursor: not-allowed;
}

.tour-primary {
  background: #2868df;
  border: 1px solid #2868df;
  color: #ffffff;
}

.tour-primary:hover {
  background: #1f5cc4;
}

/* 全站固定在右下角的帮助浮标。z-index 压在导航遮罩之下，导航开着的时候
   不会盖住气泡。 */
.tour-replay-button {
  align-items: center;
  background: #ffffff;
  border: 1px solid #e3eaf4;
  border-radius: 50%;
  bottom: 18px;
  box-shadow: 0 6px 18px rgba(15, 23, 32, 0.16);
  color: #2f73df;
  cursor: pointer;
  display: flex;
  height: 38px;
  justify-content: center;
  padding: 0;
  position: fixed;
  right: 18px;
  transition: box-shadow 160ms ease, transform 160ms ease;
  width: 38px;
  z-index: 380;
}

.tour-replay-button svg {
  height: 20px;
  width: 20px;
}

.tour-replay-button:hover {
  box-shadow: 0 10px 24px rgba(15, 23, 32, 0.22);
  transform: translateY(-1px);
}

/* 校色页改成在面板底部留一条空带（见 .direct-proof-side），浮标不用再避让，
   全站保持同一个位置 */

/* ── 签到成功卡片 ────────────────────────────────────────────────────
   原来最大的字是「成功」，可它不携带信息；用户真正关心的积分反而是小灰字。
   改成积分当主角，下面一条七格的连签进度，并写清「再签几天有额外奖励」。 */
.checkin-success-card {
  gap: 0;
  padding: 26px 26px 22px;
  width: min(300px, calc(100vw - 40px));
}

.checkin-streak-track i.is-done {
  background: #2f73df;
}

.selection-bar.is-hidden {
  display: none;
}

/* 识别的提示行跟着步骤换。强制单行 + 省略号：顶栏一旦被撑高，下面 position:fixed
   的步骤条（top:72px）和 calc(100vh - 96px) 的画布高度就全错位了。 */
body[data-view="setup"][data-module="direct"] .setup-header-hint {
  color: #68726f;
  flex: 1 1 auto;
  font-size: 13px;
  font-weight: 700;
  line-height: 1.45;
  margin-left: 8px;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ══ 说明模式 ═══════════════════════════════════════════════════════════
   平时界面上一个问号都没有——有名有姓的控件一百八十多个，撒一把问号进去会
   把版面弄碎。只有开了说明模式，写过说明的控件才亮起来。 */
.has-help {
  box-shadow: 0 0 0 2px rgba(55, 138, 221, 0.55), 0 0 0 5px rgba(55, 138, 221, 0.14) !important;
  border-radius: 6px;
  cursor: help !important;
  position: relative;
}

.is-help-open {
  box-shadow: 0 0 0 2px rgba(55, 138, 221, 1), 0 0 0 7px rgba(55, 138, 221, 0.24) !important;
}

/* 模式里所有点击都被拦在 document 捕获阶段，光标统一提示「这是在问，不是在用」 */
body.help-mode-on .has-help,
body.help-mode-on .has-help * {
  cursor: help !important;
}

.help-bubble {
  background: #ffffff;
  border-radius: 10px;
  box-shadow: 0 18px 54px rgba(15, 23, 32, 0.32);
  display: grid;
  gap: 8px;
  max-width: calc(100vw - 24px);
  padding: 14px 16px;
  pointer-events: auto;
  position: fixed;
  width: 300px;
  z-index: 420;
}

.help-bubble.is-hidden {
  display: none;
}

.help-bubble strong {
  color: #1d2734;
  font-size: 14px;
  font-weight: 900;
  line-height: 1.35;
}

.help-bubble p {
  color: #5a6472;
  font-size: 12px;
  line-height: 1.6;
  margin: 0;
}

/* 贴着右下角那个问号往上叠，不放屏幕正中间——编辑器的工具栏就在底部中间，
   放中间会把「点亮起的控件」这句话正在指的那排按钮盖住。 */
.help-mode-bar {
  align-items: center;
  background: #1d2734;
  border-radius: 999px;
  bottom: 96px;
  box-shadow: 0 12px 32px rgba(15, 23, 32, 0.28);
  color: #e7edf5;
  display: flex;
  font-size: 12px;
  gap: 10px;
  max-width: calc(100vw - 36px);
  padding: 8px 10px 8px 16px;
  position: fixed;
  right: 18px;
  z-index: 430;
}

.help-mode-bar.is-hidden {
  display: none;
}

.help-mode-tip {
  white-space: nowrap;
}

.help-mode-link,
.help-mode-exit {
  background: rgba(255, 255, 255, 0.14);
  border: 0;
  border-radius: 999px;
  color: #ffffff;
  cursor: pointer;
  font-size: 12px;
  font-weight: 700;
  min-height: 0;
  padding: 5px 12px;
  white-space: nowrap;
}

.help-mode-link:hover,
.help-mode-exit:hover {
  background: rgba(255, 255, 255, 0.26);
}

.tour-replay-button.is-active {
  background: #2868df;
  border-color: #2868df;
  color: #ffffff;
}

@media (max-width: 900px) {
  .help-mode-tip {
    display: none;
  }
}

.landing-shot-stack img.is-active {
  opacity: 1;
}

.landing-shot-tabs button.active {
  background: #2868df;
  border-color: #2868df;
  color: #ffffff;
}

/* fixed 能用的前提是先把 #workbench 藏掉——编辑器 904px 宽的内容会把布局视口
   撑开，而 fixed 是贴着布局视口算的，不藏就会变成 904 宽、卡片被推出屏幕。
   藏掉之后视口缩回设备宽度，这里就正常了。 */
.narrow-notice {
  align-items: center;
  background: rgba(247, 249, 248, 0.98);
  display: flex;
  inset: 0;
  justify-content: center;
  padding: 24px;
  position: fixed;
  z-index: 900;
}

.narrow-notice.is-hidden {
  display: none;
}

.narrow-notice-card {
  background: #ffffff;
  box-sizing: border-box;
  width: 100%;
  border: 1px solid #e3eaf4;
  border-radius: 18px;
  box-shadow: 0 24px 60px rgba(15, 23, 32, 0.16);
  max-width: 420px;
  padding: 26px 24px 22px;
  text-align: center;
}

.narrow-notice-card strong {
  color: #1d2734;
  display: block;
  font-size: 19px;
  font-weight: 900;
  margin-bottom: 10px;
}

.narrow-notice-card p {
  color: #5a6472;
  font-size: 13px;
  line-height: 1.7;
  margin: 0 0 8px;
}

.narrow-notice-sub {
  color: #8a94a3 !important;
  font-size: 12px !important;
}

.narrow-notice-actions {
  display: grid;
  gap: 8px;
  margin-top: 16px;
}

/* 挡板亮着时藏掉编辑器：它的宽度会撑开布局视口，害得 position:fixed 的挡板
   跟着变宽、卡片被推出屏幕。藏掉之后视口缩回设备宽度，挡板就正常居中了。 */
body.narrow-blocked #workbench,
body.narrow-blocked #appHeader {
  display: none !important;
}

body.narrow-blocked {
  overflow: hidden;
}

body.cyber-page {
  background: #eef4f9;
  color: #17202c;
  min-height: 100vh;
}

.cyber-page-brand .brand-cyber-logo {
  filter: drop-shadow(0 0 8px rgba(0, 209, 255, 0.42)) drop-shadow(0 0 10px rgba(255, 45, 161, 0.24));
  height: 54px;
}

.cyber-simulator-viewport {
  height: 100%;
  min-height: 420px;
  overflow: hidden;
  position: relative;
  width: 100%;
}

.cyber-simulator-viewport canvas {
  display: block;
  height: 100%;
  inset: 0;
  position: absolute;
  width: 100%;
}

.cyber-simulator-fallback {
  align-items: center;
  background: rgba(248, 251, 255, 0.9);
  color: #4d5b68;
  display: flex;
  font-size: 14px;
  font-weight: 700;
  inset: 0;
  justify-content: center;
  position: absolute;
  z-index: 2;
}

.cyber-simulator-hud {
  align-items: center;
  background: rgba(255, 255, 255, 0.86);
  border: 1px solid rgba(211, 222, 232, 0.9);
  border-radius: 8px;
  bottom: 14px;
  color: #4d5b68;
  display: flex;
  font-size: 12px;
  font-weight: 800;
  gap: 8px;
  left: 14px;
  padding: 8px 10px;
  position: absolute;
}

.cyber-empty-state {
  background: #fff7ed;
  border: 1px solid #fed7aa;
  border-radius: 8px;
  color: #7c2d12;
  display: grid;
  gap: 8px;
  padding: 12px;
}

.cyber-empty-state span {
  color: #9a3412;
  font-size: 13px;
  line-height: 1.5;
}

.cyber-empty-state a {
  color: #0f5ba8;
  font-size: 13px;
  font-weight: 900;
  text-decoration: none;
}

.cyber-finish-options {
  display: grid;
  gap: 8px;
}

.cyber-finish-tabs {
  background: #eef4f9;
  border: 1px solid #d8e2ec;
  border-radius: 8px;
  display: grid;
  gap: 3px;
  grid-template-columns: repeat(auto-fit, minmax(48px, 1fr));
  margin-top: 10px;
  padding: 3px;
}

.cyber-finish-tabs button {
  background: transparent;
  border: 0;
  border-radius: 6px;
  color: #5d6b7a;
  cursor: pointer;
  font-size: 11px;
  min-width: 0;
  overflow: hidden;
  padding: 0 2px;
  white-space: nowrap;
  font-weight: 900;
  min-height: 34px;
}

.cyber-finish-tabs button.active,
.cyber-finish-tabs button:hover {
  background: #ffffff;
  box-shadow: 0 1px 6px rgba(17, 28, 42, 0.1);
  color: #17202c;
}

.cyber-unironed-button.active,
.cyber-unironed-button:hover {
  background: #f6f9fc;
  border-color: #8db9e8;
  color: #0f5ba8;
}

.cyber-finish-options button {
  align-items: center;
  background: #f6f9fc;
  border: 1px solid #d7e1eb;
  border-radius: 8px;
  color: #253142;
  cursor: pointer;
  display: grid;
  gap: 3px;
  justify-items: start;
  min-height: 58px;
  padding: 10px 12px;
  text-align: left;
}

.cyber-finish-options button.is-hidden {
  display: none;
}

.cyber-finish-options button small {
  color: #008d86;
  font-size: 10px;
  font-weight: 900;
  letter-spacing: 0.08em;
}

.cyber-finish-options button b,
.cyber-finish-options button strong {
  font-size: 13px;
}

.cyber-finish-options button span {
  color: #667486;
  font-size: 12px;
}

.cyber-finish-options button.active,
.cyber-finish-options button:hover {
  background: #effcf9;
  border-color: #00a99d;
}

.cyber-simulator-actions .primary-button,
.cyber-simulator-actions .ghost-button {
  min-height: 42px;
  width: 100%;
}

@media (max-width: 860px) {
  .cyber-page-shell {
    gap: 10px;
    padding: 8px;
  }

  .cyber-page-header {
    grid-template-columns: auto 1fr;
  }

  .cyber-page-home {
    grid-column: 1 / -1;
  }

  .cyber-page-brand .brand-cyber-logo {
    height: 44px;
  }

  .cyber-page-work {
    min-height: calc(100vh - 150px);
  }

  .cyber-simulator-body {
    grid-template-columns: 1fr;
  }

  .cyber-simulator-stage {
    min-height: 48vh;
  }

  .cyber-simulator-viewport {
    min-height: 330px;
  }

  .cyber-simulator-panel {
    border-left: 0;
    border-top: 1px solid #dce6ef;
    max-height: 42vh;
  }

  .cyber-simulator-header {
    align-items: start;
    flex-direction: column;
    gap: 8px;
  }
}

/* ------------------------------------------------ 落地页入口 · 我的拼豆 · 烫豆提示 */
.landing-hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  justify-content: center;
  margin-top: 46px;
}

.landing-hero-actions .landing-enter-button {
  margin-top: 0;
}

.landing-enter-secondary {
  border-color: #d3dbe3;
  text-decoration: none;
}

.landing-enter-secondary:hover {
  border-color: #d1a43a;
}

.direct-primary-outline {
  border-color: var(--ink);
  color: var(--ink);
  font-weight: 900;
}

.bead-prompt-backdrop {
  align-items: center;
  background: rgba(17, 28, 42, 0.42);
  display: flex;
  inset: 0;
  justify-content: center;
  padding: 20px;
  position: fixed;
  z-index: 400;
}

.bead-prompt {
  background: #ffffff;
  border: 1px solid #dce6ef;
  border-radius: 12px;
  box-shadow: 0 24px 60px rgba(17, 28, 42, 0.22);
  display: grid;
  gap: 10px;
  max-width: 380px;
  padding: 22px;
  width: 100%;
}

.bead-prompt small {
  color: #008d86;
  font-size: 11px;
  font-weight: 900;
  letter-spacing: 0.08em;
}

.bead-prompt strong {
  font-size: 18px;
  line-height: 1.3;
}

.bead-prompt > span {
  color: #5d6b7a;
  font-size: 13px;
  line-height: 1.5;
}

.bead-prompt-actions {
  display: grid;
  gap: 10px;
  grid-template-columns: 1fr 1fr;
  margin-top: 8px;
}

.bead-prompt-actions button {
  border-radius: 8px;
  cursor: pointer;
  font-size: 14px;
  font-weight: 900;
  min-height: 42px;
}

.bead-prompt-secondary {
  background: #ffffff;
  border: 1px solid #d7e1eb;
  color: #1d2734;
}

.bead-prompt-primary {
  background: #1d2734;
  border: 0;
  color: #ffffff;
}

/* 提示条放在画面正中，不压底部的按钮 */
.cyber-toast {
  background: rgba(29, 39, 52, 0.94);
  border-radius: 10px;
  color: #ffffff;
  font-size: 14px;
  font-weight: 800;
  left: 50%;
  max-width: calc(100% - 40px);
  padding: 12px 20px;
  position: fixed;
  text-align: center;
  top: 50%;
  transform: translate(-50%, -50%);
  z-index: 420;
}

.cyber-simulator-hud-stack {
  align-items: flex-start;
  flex-direction: column;
  gap: 4px;
}

.cyber-simulator-hud-stack span {
  display: block;
}

/* 图纸信息卡的收起／展开开关：PC 上卡片常驻，用不到这两个按钮 */
.cyber-hud-toggle,
.cyber-hud-close {
  display: none;
}

/* 我的拼豆页 */
.mine-page {
  background: #f1f4f2;
  margin: 0;
}

.mine-shell {
  display: grid;
  gap: 18px;
  min-height: 100vh;
  padding: 18px;
}

.mine-topbar {
  align-items: center;
  background: rgba(255, 255, 255, 0.86);
  border: 1px solid #dce6ef;
  border-radius: 8px;
  display: grid;
  gap: 14px;
  grid-template-columns: auto 1fr auto;
  padding: 10px 14px;
}

.mine-back,
.mine-enter {
  align-items: center;
  background: #ffffff;
  border: 1px solid #d7e1eb;
  border-radius: 8px;
  color: #253142;
  display: inline-flex;
  font-size: 13px;
  font-weight: 900;
  gap: 6px;
  justify-content: center;
  min-height: 38px;
  padding: 0 14px;
  text-decoration: none;
}

.mine-brand .brand-cyber-logo {
  height: 40px;
  width: auto;
}

.mine-sidebar button.active {
  background: #ffffff;
  border-color: #d7e1eb;
  color: #1d2734;
}

.mine-grid {
  display: grid;
  gap: 14px;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
}

.mine-card {
  background: #ffffff;
  border: 1px solid #dce6ef;
  border-radius: 10px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.mine-card-figure {
  align-items: center;
  aspect-ratio: 4 / 3;
  background: linear-gradient(180deg, #eef4f9, #fbfdff);
  display: flex;
  justify-content: center;
  overflow: hidden;
  padding: 12px;
}

.mine-card-figure canvas {
  image-rendering: pixelated;
  max-height: 100%;
  max-width: 100%;
  object-fit: contain;
}

.mine-card-figure img {
  max-height: 100%;
  max-width: 100%;
  object-fit: contain;
}

.mine-card-body {
  display: grid;
  gap: 4px;
  padding: 12px 14px 6px;
}

.mine-card-body strong {
  font-size: 15px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.mine-card-body span {
  color: #5d6b7a;
  font-size: 12px;
  font-weight: 800;
}

.mine-card-body small {
  color: #94a3b8;
  font-size: 11px;
}

.mine-card-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  padding: 10px 14px 14px;
}

.mine-primary,
.mine-ghost {
  align-items: center;
  border-radius: 8px;
  cursor: pointer;
  display: inline-flex;
  font-size: 12px;
  font-weight: 900;
  justify-content: center;
  min-height: 34px;
  padding: 0 12px;
  text-decoration: none;
}

.mine-primary {
  background: #1d2734;
  border: 0;
  color: #ffffff;
}

.mine-ghost {
  background: #ffffff;
  border: 1px solid #d7e1eb;
  color: #1d2734;
}

.mine-empty {
  align-items: center;
  border: 1px dashed #d7e1eb;
  border-radius: 10px;
  color: #5d6b7a;
  display: grid;
  gap: 8px;
  justify-items: center;
  padding: 48px 20px;
  text-align: center;
}

.mine-empty strong {
  color: #1d2734;
  font-size: 16px;
}

.mine-empty a {
  background: #1d2734;
  border-radius: 8px;
  color: #ffffff;
  font-size: 13px;
  font-weight: 900;
  margin-top: 6px;
  padding: 10px 16px;
  text-decoration: none;
}

@media (max-width: 720px) {
  .mine-body {
    grid-template-columns: 1fr;
  }

  .mine-sidebar {
    border-bottom: 1px solid #dce6ef;
    border-right: 0;
    flex-direction: row;
  }

  .mine-sidebar button {
    flex: 1;
  }

  .mine-topbar {
    grid-template-columns: 1fr auto;
  }

  .mine-brand {
    grid-column: 1 / -1;
    justify-content: flex-start;
    order: -1;
  }
}

/* ------------------------------------------------ 落地页字体与按钮（参考图：衬线大标题 + 灰色无衬线副标题 + 硬阴影胶囊按钮） */
.landing-title-main,
html[lang="en"] .landing-title-main {
  color: #111820;
  font-family: "Playfair Display", "Times New Roman", Georgia, "Songti SC", serif;
  font-weight: 800;
  letter-spacing: -0.01em;
  line-height: 1.08;
}

/* 英文大标题和 logo 旁的站名一样用衬线斜体，粗细不变（800）。中文没有真正的斜体，照旧正体。
   纹路层用的也是 .landing-title-main，跟着一起斜，字形对得上。 */
html[lang="en"] .landing-title-main {
  font-style: italic;
}

/* 大标题双色，中英文一样：前半截「赛博 / Ironed」墨色（继承上面），后半截「烫豆 / Beads」青色——
   和浅底页面上 logo 旁站名的配法一样。英文是斜体，中文正体。
   纹路层是 ::before 里另画的一份字，熨过之后布纹盖住底色，不受影响。 */
.landing-title-main .brand-b {
  color: var(--teal, #27877f);
}

.landing-title-claim {
  color: #6b6b6b;
  font-family: "Poppins", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
  font-weight: 400;
}

.landing-enter-button {
  background: #7c9aab;
  border: 1.5px solid #111820;
  border-radius: 999px;
  box-shadow: 4px 4px 0 #111820;
  color: #111820;
  font-family: "Poppins", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
  font-weight: 700;
  min-height: 56px;
  padding: 12px 34px;
}

.landing-enter-button:hover {
  background: #8aa8b8;
  box-shadow: 2px 2px 0 #111820;
  transform: translate(2px, 2px);
}

.landing-enter-button:active {
  box-shadow: 0 0 0 #111820;
  transform: translate(4px, 4px);
}

.landing-enter-secondary {
  background: #ffffff;
  border-color: #111820;
}

.landing-enter-secondary:hover {
  background: #f4f7f9;
  border-color: #111820;
}

/* 新 logo：抠图后的卡通烫斗，横向构图，按高度定尺寸 */
.brand-iron-logo {
  height: 32px;
  object-fit: contain;
  width: auto;
}

.landing-topbar .brand-iron-logo {
  height: 38px;
}

/* ------------------------------------------------ 落地页标题上的 3D 熨斗与布料纹路（交互见 iron-hero.js） */
.landing-title-stage {
  cursor: pointer;
  display: inline-block;
  white-space: nowrap;   /* 从 h1 挪下来的：品牌名断行会让熨斗的位置算错 */
  position: relative;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  -webkit-user-select: none;
  user-select: none;
}

.landing-title-stage:focus-visible {
  border-radius: 12px;
  outline: 3px solid #2e6dcc;
  outline-offset: 14px;
}

.landing-title-stage.is-ironing {
  cursor: default;
}

/* 纹路层：叠在黑字上的同一段字。文字本身放在 ::before 里、从 data-text 取
   （iron-hero.js 会跟着主标题同步），这样 DOM 里的标题只有一份，
   爬虫和读屏都不会读到三遍；也不会被 html[lang="en"] .landing-title-main 的字色盖掉。
   尺寸全按字号走，手机上不糊。 */
.landing-title-texture {
  --cell: max(0.075em, 6px);
  --line: calc(var(--cell) * 0.22);
  --bead: max(0.25em, 18px); /* 模拟器样块里一颗豆在文字上占多大 */
  display: none;
  inset: 0;
  pointer-events: none;
  position: absolute;
}

.landing-title-texture.is-on {
  display: block;
}

/* 斜体的最后一个字母 s 会探出文字盒子右边一截。纹路层靠 clip-path 按盒子裁，
   不放宽的话 s 的尾巴只剩底下的黑字、没有纹路。往右多伸一点；左边不动，
   文字起点要和底下的黑字对齐（熨斗分界线 --iron-reveal 也是从左边量的，不受影响）。
   标题整体是居中的，盒子一放宽，纹路那段字会跟着往右挪半截，和黑字错开——所以这里钉成靠左。 */
html[lang="en"] .landing-title-texture {
  inset: 0 -0.3em 0 0;
  text-align: left;
}

/* prev：当前纹路，从左边裁掉已经熨过的；next：下一种纹路，从右边裁掉还没熨到的 */
.landing-title-texture[data-layer="prev"] {
  clip-path: inset(0 0 0 var(--iron-reveal, 0px));
}

.landing-title-texture[data-layer="next"] {
  clip-path: inset(0 calc(100% - var(--iron-reveal, 0px)) 0 0);
}

/* 用 background-clip 把渐变裁成文字形状；描一圈深色边，浅色布料在米白背景上也认得出字 */
.landing-title-texture::before {
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  content: attr(data-text);
  -webkit-text-stroke: 0.018em #111820;
}

/* 毛巾：细密绒圈，淡粉色，和陶瓷底板一个色系 */
.landing-title-texture.texture-towel::before {
  background-color: #f2c4c0;
  background-image:
    radial-gradient(circle, #fff3f0 0 calc(var(--cell) * 0.2), transparent calc(var(--cell) * 0.3)),
    radial-gradient(circle, #fff3f0 0 calc(var(--cell) * 0.2), transparent calc(var(--cell) * 0.3)),
    radial-gradient(circle, rgba(184, 118, 112, 0.62) 0 calc(var(--cell) * 0.18), transparent calc(var(--cell) * 0.3)),
    radial-gradient(circle, rgba(184, 118, 112, 0.62) 0 calc(var(--cell) * 0.18), transparent calc(var(--cell) * 0.3));
  background-position:
    0 0,
    calc(var(--cell) / 2) calc(var(--cell) / 2),
    calc(var(--cell) * 0.18) calc(var(--cell) * 0.2),
    calc(var(--cell) * 0.68) calc(var(--cell) * 0.7);
  background-size: var(--cell) var(--cell);
}

/* 澡巾：粗一点的斜纹网格，蓝绿色尼龙 */
.landing-title-texture.texture-scrub {
  --cell: max(0.1em, 8px);
}

.landing-title-texture.texture-scrub::before {
  background-color: #3f9fc4;
  background-image:
    repeating-linear-gradient(45deg, rgba(255, 255, 255, 0.62) 0 var(--line), transparent var(--line) var(--cell)),
    repeating-linear-gradient(-45deg, rgba(255, 255, 255, 0.62) 0 var(--line), transparent var(--line) var(--cell)),
    repeating-linear-gradient(
      45deg,
      transparent 0 calc(var(--cell) / 2),
      rgba(18, 74, 102, 0.55) calc(var(--cell) / 2) calc(var(--cell) / 2 + var(--line)),
      transparent calc(var(--cell) / 2 + var(--line)) var(--cell)
    ),
    repeating-linear-gradient(
      -45deg,
      transparent 0 calc(var(--cell) / 2),
      rgba(18, 74, 102, 0.55) calc(var(--cell) / 2) calc(var(--cell) / 2 + var(--line)),
      transparent calc(var(--cell) / 2 + var(--line)) var(--cell)
    );
}

/* 菱格纹：大格菱形绗缝，黄色，和熨斗机身呼应。
   前两层是 25%/75% 的对角渐变拼出菱形棋盘，后两层是穿过菱形中心的细线。 */
.landing-title-texture.texture-argyle {
  --d: max(0.44em, 22px);
  --thin: max(0.014em, 1.2px);
}

.landing-title-texture.texture-argyle::before {
  background-color: #f2c94c;
  background-image:
    linear-gradient(45deg, rgba(255, 255, 255, 0.62) 25%, transparent 25% 75%, rgba(255, 255, 255, 0.62) 75%),
    linear-gradient(-45deg, rgba(255, 255, 255, 0.62) 25%, transparent 25% 75%, rgba(255, 255, 255, 0.62) 75%),
    linear-gradient(
      45deg,
      transparent calc(50% - var(--thin) / 2),
      rgba(122, 74, 10, 0.72) calc(50% - var(--thin) / 2) calc(50% + var(--thin) / 2),
      transparent calc(50% + var(--thin) / 2)
    ),
    linear-gradient(
      -45deg,
      transparent calc(50% - var(--thin) / 2),
      rgba(122, 74, 10, 0.72) calc(50% - var(--thin) / 2) calc(50% + var(--thin) / 2),
      transparent calc(50% + var(--thin) / 2)
    );
  background-size: var(--d) var(--d);
}

/* cyber 模拟器把烫法渲染成样块之后，iron-hero.js 把图片写进 --swatch，替换上面的渐变。
   写在渐变规则后面，优先级相同、后者生效。 */
.landing-title-texture.has-swatch::before {
  background-image: var(--swatch);
  background-position: 0 0;
  background-repeat: repeat;
  background-size: var(--swatch-size);
}

/* 熨斗容器：位置和尺寸由 iron-hero.js 按字号算好写成内联样式 */
.iron-hero {
  pointer-events: none;
  position: absolute;
  z-index: 2;
}

.iron-hero-img,
.iron-hero-canvas {
  display: block;
  position: absolute;
}

.iron-hero-img {
  left: 0;
  top: 0;
  will-change: transform;
}

.iron-hero-canvas {
  height: 100% !important;
  inset: 0;
  width: 100% !important;
}

.iron-hero.is-webgl .iron-hero-img {
  display: none;
}

/* ------------------------------------------------ 烫豆页 · 方案 C：工具条 + 左侧烫法栏 + 通栏舞台 */
.cyber-studio-page {
  margin: 0;
  overflow: hidden;
}

.cyber-studio {
  display: grid;
  grid-template-rows: 56px minmax(0, 1fr);
  height: 100vh;
  height: 100dvh;
}

.cyber-toolbar {
  align-items: center;
  background: rgba(255, 255, 255, 0.94);
  border-bottom: 1px solid #dce6ef;
  display: grid;
  gap: 12px;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  padding: 0 14px;
  position: relative;
  z-index: 5;
}

.cyber-toolbar-left {
  align-items: center;
  display: flex;
  gap: 8px;
  min-width: 0;
}

.cyber-toolbar-logo {
  height: 22px;
}

.cyber-toolbar-title .brand-name-zh {
  font-size: 18px;
}

html[lang="en"] .cyber-toolbar-title .brand-name-en {
  font-size: 19px;
}

.cyber-tool-icon {
  align-items: center;
  background: #ffffff;
  border: 1px solid #d7e1eb;
  border-radius: 8px;
  color: #1d2734;
  cursor: pointer;
  display: inline-flex;
  font-size: 16px;
  height: 34px;
  justify-content: center;
  width: 34px;
}

.cyber-toolbar-tabs {
  display: flex;
  gap: 2px;
  justify-self: center;
  margin-top: 0;
  padding: 3px;
}

.cyber-toolbar-tabs button {
  font-size: 13px;
  min-height: 32px;
  padding: 0 12px;
}

.cyber-toolbar-right {
  align-items: center;
  display: flex;
  gap: 6px;
  justify-content: flex-end;
  min-width: 0;
}

.cyber-tool-button {
  background: #ffffff;
  border: 1px solid #d7e1eb;
  border-radius: 8px;
  color: #1d2734;
  cursor: pointer;
  font-size: 12px;
  font-weight: 900;
  min-height: 34px;
  padding: 0 12px;
  white-space: nowrap;
}

.cyber-tool-button:hover,
.cyber-tool-icon:hover {
  background: #eef5fb;
}

.cyber-toolbar-divider {
  background: #dce6ef;
  height: 22px;
  margin: 0 4px;
  width: 1px;
}

.cyber-toolbar-link {
  color: #5d6b7a;
  font-size: 12px;
  font-weight: 900;
  padding: 0 4px;
  text-decoration: none;
  white-space: nowrap;
}

.cyber-toolbar-link:hover {
  color: #1d2734;
}

.cyber-download {
  position: relative;
}

.cyber-download-menu {
  background: #ffffff;
  border: 1px solid #d7e1eb;
  border-radius: 10px;
  box-shadow: 0 16px 40px rgba(17, 28, 42, 0.16);
  display: grid;
  min-width: 150px;
  padding: 6px;
  position: absolute;
  right: 0;
  top: calc(100% + 6px);
  z-index: 20;
}

.cyber-download-menu button {
  background: transparent;
  border: 0;
  border-radius: 6px;
  color: #1d2734;
  cursor: pointer;
  font-size: 13px;
  font-weight: 800;
  padding: 9px 12px;
  text-align: left;
}

.cyber-download-menu button:hover {
  background: #eef5fb;
}

.cyber-download-menu button:disabled {
  color: #94a3b8;
  cursor: wait;
}

.cyber-studio-stage {
  background: linear-gradient(180deg, #eef4f9, #fbfdff);
  min-height: 0;
  overflow: hidden;
  position: relative;
}

.cyber-studio-stage .cyber-simulator-viewport {
  height: 100%;
  min-height: 0;
  position: absolute;
  inset: 0;
}

.cyber-studio-empty {
  left: 50%;
  position: absolute;
  top: 50%;
  transform: translate(-50%, -50%);
  z-index: 4;
}

/* 左侧色样栏 */
.cyber-finish-rail {
  background: rgba(255, 255, 255, 0.9);
  border: 1px solid rgba(211, 222, 232, 0.9);
  border-radius: 14px;
  left: 16px;
  max-height: calc(100% - 140px);
  overflow-y: auto;
  padding: 8px 6px;
  position: absolute;
  top: 16px;
  width: 92px;
  z-index: 3;
}

.cyber-finish-rail .cyber-finish-options {
  gap: 4px;
}

.cyber-finish-rail .cyber-finish-options button {
  align-items: center;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 10px;
  cursor: pointer;
  display: grid;
  gap: 4px;
  justify-items: center;
  padding: 6px 2px;
  text-align: center;
}

.cyber-finish-rail .cyber-finish-options button.is-hidden {
  display: none;
}

.cyber-finish-rail .cyber-finish-options button small,
.cyber-finish-rail .cyber-finish-options button span {
  display: none;
}

.cyber-finish-rail .cyber-finish-options button b {
  color: #5d6b7a;
  font-size: 11px;
  font-weight: 800;
  line-height: 1.2;
  max-width: 76px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.cyber-finish-swatch {
  background: linear-gradient(135deg, #e6eef6, #cbd6e2);
  background-position: center;
  background-size: cover;
  border: 2px solid #ffffff;
  border-radius: 50%;
  box-shadow: 0 2px 8px rgba(17, 28, 42, 0.18);
  display: block;
  height: 46px;
  width: 46px;
}

.cyber-finish-rail .cyber-finish-options button:hover {
  background: #eef5fb;
}

.cyber-finish-rail .cyber-finish-options button.active {
  background: #e6f4f3;
  border-color: #b7dedb;
}

.cyber-finish-rail .cyber-finish-options button.active b {
  color: #008d86;
}

.cyber-finish-rail .cyber-finish-options button.active .cyber-finish-swatch {
  box-shadow: 0 0 0 2px #008d86, 0 2px 8px rgba(17, 28, 42, 0.18);
}

/* 色样旁的说明卡 */
.cyber-finish-info {
  background: rgba(255, 255, 255, 0.94);
  border: 1px solid rgba(211, 222, 232, 0.9);
  border-radius: 10px;
  display: grid;
  gap: 2px;
  left: 120px;
  max-width: 220px;
  padding: 8px 12px;
  pointer-events: none;
  position: absolute;
  top: 16px;
  z-index: 3;
}

.cyber-finish-info b {
  font-size: 13px;
}

.cyber-finish-info span {
  color: #5d6b7a;
  font-size: 12px;
}

/* 底部胶囊 */
.cyber-stage-cta {
  align-items: center;
  background: rgba(255, 255, 255, 0.94);
  border: 1px solid rgba(211, 222, 232, 0.9);
  border-radius: 999px;
  bottom: 20px;
  box-shadow: 0 12px 30px rgba(17, 28, 42, 0.14);
  display: flex;
  gap: 6px;
  left: 50%;
  padding: 6px;
  position: absolute;
  transform: translateX(-50%);
  z-index: 3;
}

.cyber-cta-main {
  background: #1d2734;
  border: 0;
  border-radius: 999px;
  color: #ffffff;
  cursor: pointer;
  font-size: 14px;
  font-weight: 900;
  min-height: 42px;
  min-width: 150px;
  padding: 0 22px;
  white-space: nowrap;
}

.cyber-cta-main:disabled {
  background: #94a3b8;
  cursor: wait;
}

/* 切烫法时这颗按钮会被禁用一小会儿（准备新烫法，实测 0.5–0.7 秒）。以前一禁用就立刻变灰变淡、
   半秒后又变回深色，看着一闪一闪。现在变灰要等禁用满 1 秒才开始（和换成「正在准备…」同一个门槛），
   平常切烫法根本不变色；恢复可用时立刻变回。 */
.cyber-cta-main {
  transition: background-color 0.15s ease, opacity 0.15s ease;
}

.cyber-cta-main:disabled {
  transition-delay: 1s;
}

.cyber-cta-toggle {
  background: #ffffff;
  border: 1px solid #d7e1eb;
  border-radius: 999px;
  color: #5d6b7a;
  cursor: pointer;
  font-size: 12px;
  font-weight: 900;
  min-height: 42px;
  padding: 0 14px;
  white-space: nowrap;
}

.cyber-cta-toggle.active {
  border-color: #008d86;
  color: #008d86;
}

.cyber-studio-stage .cyber-simulator-hud {
  bottom: 20px;
  left: 16px;
  z-index: 3;
}

@media (max-width: 900px) {
  .cyber-studio {
    grid-template-rows: auto minmax(0, 1fr);
  }

  .cyber-toolbar {
    gap: 8px;
    grid-template-columns: minmax(0, 1fr) auto;
    padding: 8px 10px;
  }

  .cyber-toolbar-tabs {
    grid-column: 1 / -1;
    grid-row: 2;
    justify-self: stretch;
    overflow-x: auto;
  }

  .cyber-toolbar-tabs button {
    flex: 1 0 auto;
  }

  /* 有 logo 的地方后面必须带站名，窄屏也一样，只把字号收一点 */
  .cyber-toolbar-title .brand-name-zh {
    font-size: 16px;
  }

  html[lang="en"] .cyber-toolbar-title .brand-name-en {
    font-size: 17px;
  }

  .cyber-toolbar-link,
  .cyber-toolbar-divider {
    display: none;
  }

  .cyber-tool-button {
    padding: 0 9px;
  }

  /* 手机上色样栏改成底部横滑一排 */
  .cyber-finish-rail {
    border-radius: 12px;
    bottom: 84px;
    left: 10px;
    max-height: none;
    overflow-x: auto;
    overflow-y: hidden;
    padding: 6px;
    right: 10px;
    top: auto;
    width: auto;
  }

  .cyber-finish-rail .cyber-finish-options {
    display: flex;
    gap: 2px;
  }

  .cyber-finish-rail .cyber-finish-options button {
    flex: 0 0 72px;
  }

  /* 分类（烘焙布 / 常用烫布…）在手机上搬进这条，排在最上面（cyber.html 开头的 placeCategoryTabs 负责搬）。
     横向滚动从整条挪到各自那一行：分类一行、烫法一行各滑各的，不会一滑两排一起走。 */
  .cyber-finish-rail {
    display: flex;
    flex-direction: column;
    gap: 6px;
    overflow: hidden;
  }

  .cyber-finish-rail .cyber-toolbar-tabs {
    flex: 0 0 auto;
    margin: 0;
    overflow-x: auto;
  }

  .cyber-finish-rail .cyber-finish-options {
    overflow-x: auto;
    overflow-y: hidden;
  }

  .cyber-finish-info {
    display: none;
  }

  /* 手机上图纸信息卡默认收起，舞台左上角只留一枚 ⓘ 圆钮，点开在原地展开。
     卡片是查一眼就走的东西，常驻会一直压着图纸。 */
  .cyber-studio-stage .cyber-simulator-hud {
    bottom: auto;
    left: 10px;
    padding-right: 24px;
    top: 10px;
  }

  .cyber-studio-stage:not(.is-hud-open) .cyber-simulator-hud {
    display: none;
  }

  .cyber-hud-toggle {
    align-items: center;
    background: rgba(255, 255, 255, 0.92);
    border: 1px solid rgba(211, 222, 232, 0.9);
    border-radius: 50%;
    color: var(--teal);
    cursor: pointer;
    display: flex;
    font-family: Georgia, "Times New Roman", serif;
    font-size: 16px;
    font-style: italic;
    font-weight: 700;
    height: 32px;
    justify-content: center;
    left: 10px;
    line-height: 1;
    padding: 0;
    position: absolute;
    top: 10px;
    width: 32px;
    z-index: 4;
  }

  .cyber-studio-stage.is-hud-open .cyber-hud-toggle {
    display: none;
  }

  .cyber-hud-close {
    align-items: center;
    background: none;
    border: 0;
    color: #7c8793;
    cursor: pointer;
    display: flex;
    font-size: 12px;
    height: 22px;
    justify-content: center;
    padding: 0;
    position: absolute;
    right: 1px;
    top: 1px;
    width: 22px;
  }

  .cyber-stage-cta {
    bottom: 12px;
    max-width: calc(100% - 20px);
  }

  .cyber-cta-main {
    min-width: 0;
    padding: 0 18px;
  }
}

/* ============================================================
   烫豆工坊（cyber.html?animate=1）
   机器是纯 DOM：顶部面板（屏幕 + 三个按钮）、中间的进料口、底座；
   托盘从下面推进去，加热完再弹出来，然后掀开烘焙布看到 3D 成品。
   ============================================================ */
body.is-workshop .cyber-studio {
  grid-template-rows: minmax(0, 1fr);
}

body.is-workshop .cyber-toolbar,
body.is-workshop .cyber-finish-rail,
body.is-workshop .cyber-finish-info,
body.is-workshop .cyber-studio-stage .cyber-simulator-hud,
body.is-workshop .cyber-hud-toggle,
body.is-workshop .cyber-stage-cta,
body.is-workshop .cyber-toast {
  display: none !important;
}

.cyber-workshop {
  display: none;
  inset: 0;
  position: fixed;
  z-index: 60;
}

.cyber-workshop.is-open {
  display: block;
}

.cyber-workshop-backdrop {
  background:
    radial-gradient(circle at 1px 1px, rgba(17, 28, 42, 0.08) 1px, transparent 1.6px) 0 0 / 18px 18px,
    var(--bg-cream-gradient);
  inset: 0;
  position: absolute;
  transition: opacity 480ms ease;
}

.cyber-workshop[data-stage="reveal"] .cyber-workshop-backdrop,
.cyber-workshop[data-stage="born"] .cyber-workshop-backdrop {
  opacity: 0;
  pointer-events: none;
}

.cyber-workshop-exit {
  background: #ffffff;
  border: 1.5px solid #111820;
  border-radius: 999px;
  box-shadow: 3px 3px 0 #111820;
  color: #111820;
  cursor: pointer;
  font-size: 13px;
  font-weight: 800;
  left: 18px;
  min-height: 38px;
  padding: 0 16px;
  position: absolute;
  top: 18px;
  z-index: 6;
}

.cyber-workshop-exit:hover {
  box-shadow: 1px 1px 0 #111820;
  transform: translate(2px, 2px);
}

/* ---------- 机器场景 ---------- */
.cyber-workshop-scene {
  align-items: center;
  display: flex;
  flex-direction: column;
  gap: 26px;
  inset: 0;
  justify-content: center;
  overflow: auto;
  padding: 72px 20px 32px;
  position: absolute;
  transition: opacity 420ms ease, visibility 0s linear 420ms;
  z-index: 2;
}

.cyber-workshop[data-stage="reveal"] .cyber-workshop-scene,
.cyber-workshop[data-stage="born"] .cyber-workshop-scene {
  opacity: 0;
  pointer-events: none;
  visibility: hidden;
}

.cyber-workshop-head {
  max-width: 420px;
  text-align: center;
}

.cyber-workshop-head small {
  color: var(--teal);
  display: block;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.32em;
  margin-bottom: 10px;
}

.cyber-workshop-head h2 {
  color: #111820;
  font-family: "Playfair Display", "Times New Roman", Georgia, "Songti SC", serif;
  font-size: 30px;
  font-weight: 800;
  line-height: 1.15;
  margin: 0 0 8px;
}

.cyber-workshop-head p {
  color: #6b6b6b;
  font-size: 14px;
  line-height: 1.6;
  margin: 0;
  min-height: 1.6em;
}

.cyber-machine {
  position: relative;
  width: min(360px, 92vw);
}

.cyber-machine-shell {
  filter: drop-shadow(0 20px 34px rgba(17, 28, 42, 0.16));
  position: relative;
  z-index: 2;
}

.cyber-machine-top {
  background: #ffffff;
  border: 2px solid #111820;
  border-bottom: 0;
  border-radius: 34px 34px 0 0;
  padding: 24px 26px 16px;
}

.cyber-machine-screen {
  align-items: center;
  background:
    repeating-linear-gradient(180deg, rgba(255, 255, 255, 0.035) 0 2px, transparent 2px 4px),
    linear-gradient(180deg, #17202b, #0f151d);
  border: 2px solid #111820;
  border-radius: 16px;
  box-shadow: inset 0 0 0 1px rgba(159, 242, 223, 0.12), inset 0 10px 30px rgba(0, 0, 0, 0.5);
  color: #9ff2df;
  display: flex;
  flex-direction: column;
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  gap: 6px;
  height: 104px;
  justify-content: center;
  transition: color 300ms ease;
}

.cyber-machine-screen b {
  font-size: 30px;
  font-weight: 800;
  letter-spacing: 0.14em;
  line-height: 1;
}

.cyber-machine-screen span {
  font-size: 10px;
  letter-spacing: 0.34em;
  opacity: 0.62;
}

.cyber-workshop[data-stage="heat"] .cyber-machine-screen {
  color: #ffb257;
}

.cyber-workshop[data-stage="eject"] .cyber-machine-screen,
.cyber-workshop[data-stage="reveal"] .cyber-machine-screen {
  color: #a8ff8a;
}

.cyber-machine-buttons {
  display: flex;
  gap: 10px;
  margin-top: 16px;
}

.cyber-machine-buttons i {
  background: var(--coral);
  border: 1.5px solid #111820;
  border-radius: 50%;
  display: block;
  height: 13px;
  width: 13px;
}

.cyber-machine-buttons i:nth-child(2) {
  background: var(--yellow);
}

.cyber-machine-buttons i:nth-child(3) {
  background: var(--teal);
}

.cyber-workshop[data-stage="heat"] .cyber-machine-buttons i:first-child {
  animation: cyber-blink 700ms steps(2, start) infinite;
}

.cyber-machine-band {
  display: grid;
  grid-template-columns: 30px minmax(0, 1fr) 30px;
  height: 74px;
}

.cyber-machine-pillar {
  background: #ffffff;
  border-left: 2px solid #111820;
  display: block;
}

.cyber-machine-pillar:last-child {
  border-left: 0;
  border-right: 2px solid #111820;
}

/* 进料口：半透明，托盘推进来时能隐约看见它在里面 */
.cyber-machine-mouth {
  background: rgba(17, 28, 42, 0.74);
  border-bottom: 2px solid #111820;
  border-top: 2px solid #111820;
  box-shadow: inset 0 12px 18px rgba(0, 0, 0, 0.45);
  overflow: hidden;
  position: relative;
}

.cyber-machine-press {
  background: linear-gradient(180deg, #4a5665, #1d2734);
  border: 2px solid #111820;
  border-radius: 0 0 10px 10px;
  border-top: 0;
  height: 30px;
  left: 10px;
  position: absolute;
  right: 10px;
  top: 0;
  transform: translateY(-120%);
  transition: transform 620ms cubic-bezier(0.2, 0.8, 0.2, 1);
}

.cyber-workshop[data-stage="press"] .cyber-machine-press,
.cyber-workshop[data-stage="heat"] .cyber-machine-press {
  transform: translateY(24px);
}

.cyber-machine-heat {
  background: #f0a13a;
  border-radius: 999px;
  bottom: -3px;
  box-shadow: 0 0 14px 3px rgba(240, 161, 58, 0.75);
  display: block;
  height: 4px;
  left: 6px;
  opacity: 0;
  position: absolute;
  right: 6px;
  transition: opacity 300ms ease;
}

.cyber-workshop[data-stage="heat"] .cyber-machine-heat {
  animation: cyber-heat-pulse 900ms ease-in-out infinite alternate;
  opacity: 1;
}

.cyber-machine-foot {
  background: #ffffff;
  border: 2px solid #111820;
  border-radius: 0 0 24px 24px;
  border-top: 0;
  height: 22px;
}

.cyber-workshop[data-stage="lock"] .cyber-machine-shell {
  animation: cyber-clack 260ms ease-out;
}

/* ---------- 托盘 ---------- */
.cyber-machine-tray {
  cursor: grab;
  margin: -6px auto 0;
  outline: none;
  position: relative;
  touch-action: none;
  user-select: none;
  width: 82%;
  z-index: 1;
}

.cyber-machine-tray:focus-visible .cyber-tray-bed {
  box-shadow: 0 0 0 3px rgba(39, 135, 127, 0.35);
}

.is-tray-dragging .cyber-machine-tray {
  cursor: grabbing;
}

.cyber-tray-bed {
  background: #ffffff;
  border: 2px solid #111820;
  border-radius: 0 0 16px 16px;
  box-shadow: 0 14px 26px rgba(17, 28, 42, 0.14);
  overflow: hidden;
  padding: 12px;
  position: relative;
}

.cyber-tray-pattern {
  background:
    repeating-conic-gradient(rgba(17, 28, 42, 0.05) 0 25%, transparent 0 50%) 0 0 / 12px 12px,
    #f7f5ef;
  border-radius: 8px;
  display: block;
  height: 150px;
  image-rendering: pixelated;
  object-fit: contain;
  width: 100%;
}

.cyber-tray-cloth {
  align-items: flex-end;
  background:
    radial-gradient(circle at 3px 3px, rgba(120, 112, 100, 0.2) 1px, transparent 1.5px) 0 0 / 10px 10px,
    rgba(246, 244, 238, 0.86);
  border-radius: 8px;
  display: flex;
  inset: 12px;
  justify-content: center;
  padding-bottom: 8px;
  position: absolute;
}

.cyber-tray-cloth span {
  color: rgba(93, 107, 122, 0.75);
  font-size: 10px;
  font-weight: 900;
  letter-spacing: 0.32em;
}

.cyber-tray-handle {
  color: #111820;
  font-size: 13px;
  font-weight: 800;
  padding: 14px 0 0;
  text-align: center;
  transition: opacity 240ms ease;
}

.cyber-tray-handle span {
  display: inline-block;
  margin-right: 4px;
}

.cyber-workshop[data-stage="load"] .cyber-tray-handle span {
  animation: cyber-bob 1s ease-in-out infinite;
}

.cyber-workshop:not([data-stage="load"]) .cyber-tray-handle {
  opacity: 0;
}

/* ---------- 状态点 ---------- */
.cyber-machine-status {
  align-items: center;
  color: #6b6b6b;
  display: flex;
  font-size: 12px;
  font-weight: 700;
  gap: 12px;
  justify-content: center;
  margin-top: 18px;
}

.cyber-machine-dots {
  display: flex;
  gap: 6px;
}

.cyber-machine-dots i {
  background: #dfe5e2;
  border-radius: 50%;
  display: block;
  height: 8px;
  transition: background 200ms ease, transform 200ms ease;
  width: 8px;
}

.cyber-machine-dots i.is-active {
  background: #f0a13a;
  transform: scale(1.35);
}

.cyber-machine-dots i.is-done {
  background: var(--teal);
}

/* ---------- 掀布 ---------- */
.cyber-workshop-peel {
  display: none;
  inset: 0;
  position: absolute;
  z-index: 3;
}

.cyber-workshop[data-stage="reveal"] .cyber-workshop-peel {
  display: block;
}

.cyber-peel-canvas {
  cursor: grab;
  display: block;
  height: 100%;
  inset: 0;
  position: absolute;
  touch-action: none;
  width: 100%;
}

.cyber-peel-copy {
  left: 50%;
  max-width: 460px;
  opacity: calc(1 - var(--peel-progress, 0) * 2.2);
  padding: 0 20px;
  pointer-events: none;
  position: absolute;
  text-align: center;
  top: 14%;
  transform: translateX(-50%);
  width: 100%;
}

.cyber-peel-copy small {
  color: var(--teal);
  display: block;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.32em;
  margin-bottom: 10px;
}

.cyber-peel-copy h2 {
  color: #111820;
  font-family: "Playfair Display", "Times New Roman", Georgia, "Songti SC", serif;
  font-size: 30px;
  font-weight: 800;
  margin: 0 0 8px;
}

.cyber-peel-copy p {
  color: #6b6b6b;
  font-size: 14px;
  margin: 0;
}

.cyber-peel-hint {
  background: #ffffff;
  border: 1.5px solid #111820;
  border-radius: 999px;
  bottom: 30px;
  box-shadow: 3px 3px 0 #111820;
  color: #111820;
  font-size: 12px;
  font-weight: 800;
  opacity: calc(1 - var(--peel-progress, 0) * 2.2);
  padding: 9px 16px;
  pointer-events: none;
  position: absolute;
  right: 30px;
}

/* ---------- 新作品诞生 ---------- */
.cyber-workshop-birth {
  display: none;
  inset: 0;
  pointer-events: none;
  position: absolute;
  z-index: 4;
}

.cyber-workshop[data-stage="born"] .cyber-workshop-birth {
  display: block;
}

.cyber-birth-confetti {
  display: block;
  height: 100%;
  inset: 0;
  position: absolute;
  width: 100%;
}

.cyber-birth-card {
  animation: cyber-rise 520ms cubic-bezier(0.2, 0.8, 0.2, 1);
  background: rgba(255, 255, 255, 0.96);
  border: 1.5px solid #111820;
  border-radius: 20px;
  box-shadow: 4px 4px 0 #111820;
  left: 50%;
  max-width: calc(100% - 40px);
  padding: 14px 26px 16px;
  pointer-events: auto;
  position: absolute;
  text-align: center;
  top: 22px;
  transform: translateX(-50%);
}

.cyber-birth-card small {
  color: var(--teal);
  display: block;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.32em;
  margin-bottom: 6px;
}

.cyber-birth-card h2 {
  color: #111820;
  font-family: "Playfair Display", "Times New Roman", Georgia, "Songti SC", serif;
  font-size: 24px;
  font-weight: 800;
  margin: 0 0 4px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.cyber-birth-card p {
  color: #6b6b6b;
  font-size: 13px;
  margin: 0;
}

.cyber-birth-actions {
  animation: cyber-rise 520ms cubic-bezier(0.2, 0.8, 0.2, 1) 120ms both;
  bottom: 26px;
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  justify-content: center;
  left: 50%;
  pointer-events: auto;
  position: absolute;
  transform: translateX(-50%);
  width: max-content;
  max-width: calc(100% - 40px);
}

.cyber-birth-primary,
.cyber-birth-secondary {
  align-items: center;
  border: 1.5px solid #111820;
  border-radius: 999px;
  box-shadow: 4px 4px 0 #111820;
  color: #111820;
  cursor: pointer;
  display: inline-flex;
  font-size: 14px;
  font-weight: 800;
  min-height: 46px;
  padding: 0 24px;
  text-decoration: none;
  white-space: nowrap;
}

.cyber-birth-primary {
  background: #7c9aab;
}

.cyber-birth-secondary {
  background: #ffffff;
}

.cyber-birth-primary:hover,
.cyber-birth-secondary:hover {
  box-shadow: 2px 2px 0 #111820;
  transform: translate(2px, 2px);
}

@keyframes cyber-bob {
  0%,
  100% {
    transform: translateY(0);
  }

  50% {
    transform: translateY(-5px);
  }
}

@keyframes cyber-clack {
  0% {
    transform: translateY(0);
  }

  35% {
    transform: translateY(3px);
  }

  70% {
    transform: translateY(-1px);
  }

  100% {
    transform: translateY(0);
  }
}

@keyframes cyber-heat-pulse {
  from {
    box-shadow: 0 0 10px 2px rgba(240, 161, 58, 0.55);
  }

  to {
    box-shadow: 0 0 22px 6px rgba(240, 161, 58, 0.95);
  }
}

@keyframes cyber-blink {
  to {
    opacity: 0.25;
  }
}

@keyframes cyber-rise {
  from {
    opacity: 0;
    transform: translate(-50%, 14px);
  }

  to {
    opacity: 1;
    transform: translate(-50%, 0);
  }
}

@media (max-width: 900px) {
  .cyber-workshop-scene {
    gap: 18px;
    padding-top: 64px;
  }

  .cyber-workshop-head h2,
  .cyber-peel-copy h2 {
    font-size: 24px;
  }

  .cyber-machine-top {
    padding: 18px 20px 14px;
  }

  .cyber-machine-screen {
    height: 88px;
  }

  .cyber-tray-pattern {
    height: 120px;
  }

  .cyber-peel-hint {
    bottom: 22px;
    right: 18px;
  }

  .cyber-birth-actions {
    bottom: 18px;
  }

  /* 手机上「退出」在左上角，作品卡片往下让一让 */
  .cyber-birth-card {
    top: 68px;
  }

  .cyber-toast {
    max-width: calc(100% - 32px);
  }
}

/* ---------- 工坊第二轮：启动压合按钮、四角掀布、出场效果选择、3D 可操作 ---------- */
.cyber-effect-back {
  inset: 0;
  pointer-events: none;
  position: absolute;
  z-index: 0;
}

.cyber-machine-row {
  align-items: center;
  display: flex;
  justify-content: space-between;
  margin-top: 16px;
}

.cyber-machine-row .cyber-machine-buttons {
  margin-top: 0;
}

.cyber-machine-start {
  background: #111820;
  border: 1.5px solid #111820;
  border-radius: 999px;
  color: #ffb257;
  cursor: pointer;
  font-size: 12px;
  font-weight: 900;
  letter-spacing: 0.08em;
  min-height: 32px;
  opacity: 0.3;
  padding: 0 16px;
  pointer-events: none;
  transition: opacity 200ms ease;
}

.cyber-workshop[data-stage="lock"] .cyber-machine-start {
  animation: cyber-start-pulse 1.1s ease-out infinite;
  opacity: 1;
  pointer-events: auto;
}

.cyber-workshop[data-stage="lock"] .cyber-machine-start:hover {
  background: #26313f;
}

.cyber-machine-start:focus-visible {
  outline: 3px solid rgba(240, 161, 58, 0.6);
  outline-offset: 2px;
}

@keyframes cyber-start-pulse {
  from {
    box-shadow: 0 0 0 0 rgba(240, 161, 58, 0.65);
  }

  to {
    box-shadow: 0 0 0 12px rgba(240, 161, 58, 0);
  }
}

/* 掀布提示改成四角通用，胶囊居中 */
.cyber-peel-hint {
  left: 50%;
  right: auto;
  transform: translateX(-50%);
}

/* 诞生以后整层放开鼠标，3D 可以旋转、平移、缩放；只有卡片、按钮、退出还能点 */
.cyber-workshop[data-stage="born"] {
  pointer-events: none;
}

.cyber-workshop[data-stage="born"] .cyber-workshop-exit,
.cyber-workshop[data-stage="born"] .cyber-birth-card,
.cyber-workshop[data-stage="born"] .cyber-birth-actions {
  pointer-events: auto;
}

.cyber-birth-card {
  transition: opacity 520ms ease, transform 520ms ease, visibility 0s linear 520ms;
}

.cyber-birth-card.is-gone {
  opacity: 0;
  pointer-events: none !important;
  transform: translate(-50%, -14px);
  visibility: hidden;
}

.cyber-birth-actions {
  align-items: center;
  flex-direction: column;
  gap: 10px;
}

.cyber-birth-buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  justify-content: center;
}

.cyber-effect-picker {
  align-items: center;
  background: rgba(255, 255, 255, 0.94);
  border: 1.5px solid #111820;
  border-radius: 999px;
  box-shadow: 3px 3px 0 #111820;
  display: flex;
  gap: 2px;
  padding: 4px 6px 4px 14px;
}

.cyber-effect-picker span {
  color: #6b6b6b;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.08em;
  margin-right: 6px;
}

.cyber-effect-picker button {
  align-items: center;
  background: transparent;
  border: 0;
  border-radius: 999px;
  color: #111820;
  cursor: pointer;
  display: inline-flex;
  font-size: 12px;
  font-weight: 800;
  gap: 5px;
  min-height: 28px;
  padding: 0 11px;
}

.cyber-effect-picker button i {
  color: #f0a13a;
  font-style: normal;
}

.cyber-effect-picker button:hover {
  background: #eef2f0;
}

.cyber-effect-picker button.active {
  background: #111820;
  color: #ffffff;
}

.cyber-effect-picker button.active i {
  color: #ffb257;
}

.cyber-effect-picker button:focus-visible {
  outline: 2px solid var(--teal);
  outline-offset: 1px;
}

@media (max-width: 900px) {
  .cyber-machine-start {
    font-size: 11px;
    padding: 0 12px;
  }

  .cyber-effect-picker {
    padding-left: 10px;
  }

  .cyber-effect-picker button {
    padding: 0 8px;
  }
}

/* ============================================================
   选烫画机页（machine.html）+ 工坊里的 3D 烫画机
   ============================================================ */
.machine-page {
  background: var(--bg-cream-gradient);
  color: #111820;
  margin: 0;
  min-height: 100vh;
}

.machine-shell {
  margin: 0 auto;
  max-width: 1180px;
  padding: 18px 22px 48px;
}

.machine-topbar {
  align-items: center;
  display: grid;
  gap: 12px;
  grid-template-columns: 1fr auto 1fr;
  margin-bottom: 30px;
}

.machine-back,
.machine-link {
  background: #ffffff;
  border: 1.5px solid #111820;
  border-radius: 999px;
  box-shadow: 3px 3px 0 #111820;
  color: #111820;
  cursor: pointer;
  font-size: 13px;
  font-weight: 800;
  justify-self: start;
  min-height: 38px;
  padding: 0 16px;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.machine-link {
  justify-self: end;
}

.machine-back:hover,
.machine-link:hover,
.machine-choose:hover {
  box-shadow: 1px 1px 0 #111820;
  transform: translate(2px, 2px);
}

.machine-brand {
  align-items: center;
  display: flex;
  font-family: "Playfair Display", "Times New Roman", Georgia, "Songti SC", serif;
  font-size: 18px;
  font-weight: 800;
  gap: 8px;
  justify-self: center;
}

.machine-brand .brand-iron-logo {
  height: 22px;
  width: auto;
}

.machine-hero {
  margin: 0 auto 26px;
  max-width: 560px;
  text-align: center;
}

.machine-hero h1 {
  font-family: "Playfair Display", "Times New Roman", Georgia, "Songti SC", serif;
  font-size: 36px;
  font-weight: 800;
  line-height: 1.1;
  margin: 0 0 10px;
}

.machine-hero p {
  color: #6b6b6b;
  font-size: 14px;
  line-height: 1.6;
  margin: 0;
}

.machine-missing {
  align-items: center;
  background: #ffffff;
  border: 1.5px solid #111820;
  border-radius: 18px;
  box-shadow: 4px 4px 0 #111820;
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 0 auto 24px;
  max-width: 460px;
  padding: 20px;
  text-align: center;
}

.machine-missing a {
  color: var(--teal);
  font-weight: 800;
}

/* 烫后预览页：从图库兜底拿图纸时的说明，挂在左上角那张信息卡的最后一行 */
.cyber-fallback-note {
  color: var(--muted, #6b7686);
  font-size: 11px;
}

.cyber-fallback-note a {
  margin-left: 6px;
  white-space: nowrap;
}

.cyber-fallback-note.is-hidden {
  display: none;
}

.cyber-fallback-note a {
  color: var(--teal);
  font-weight: 800;
}

.cyber-empty-links {
  display: flex;
  gap: 18px;
  justify-content: center;
  margin: 2px 0 0;
}

.machine-fallback {
  align-items: center;
  color: var(--muted, #6b7686);
  display: flex;
  flex-wrap: wrap;
  font-size: 12px;
  gap: 4px 10px;
  justify-content: center;
  margin: 0 auto 10px;
  max-width: 460px;
}

.machine-fallback.is-hidden {
  display: none;
}

.machine-fallback a {
  color: var(--teal);
  font-weight: 800;
}

.machine-missing-links {
  display: flex;
  gap: 18px;
  justify-content: center;
  margin: 2px 0 0;
}

.machine-view {
  aspect-ratio: 4 / 3;
  background:
    radial-gradient(circle at 1px 1px, rgba(17, 28, 42, 0.07) 1px, transparent 1.6px) 0 0 / 18px 18px,
    linear-gradient(180deg, #f6f2e6, #efe8d6);
  border-bottom: 1.5px solid #111820;
  position: relative;
  touch-action: none;
}

.machine-view canvas {
  display: block;
  height: 100%;
  inset: 0;
  position: absolute;
  width: 100%;
}

.machine-loading,
.cyber-machine-loading {
  color: #6b6b6b;
  font-size: 13px;
  font-weight: 700;
  left: 50%;
  pointer-events: none;
  position: absolute;
  top: 50%;
  transform: translate(-50%, -50%);
  white-space: nowrap;
}

.machine-choose {
  align-self: flex-start;
  background: #7c9aab;
  border: 1.5px solid #111820;
  border-radius: 999px;
  box-shadow: 4px 4px 0 #111820;
  color: #111820;
  cursor: pointer;
  font-size: 14px;
  font-weight: 800;
  margin-top: 6px;
  min-height: 46px;
  padding: 0 26px;
}

.machine-choose:disabled {
  background: #d3dbe3;
  box-shadow: 2px 2px 0 #111820;
  cursor: default;
  transform: none;
}

@media (max-width: 860px) {
  .machine-grid {
    grid-template-columns: 1fr;
  }

  .machine-hero h1 {
    font-size: 28px;
  }

  .machine-topbar {
    grid-template-columns: auto 1fr auto;
  }

  /* 站名原来在窄屏整个藏起来，顶栏只剩一个熨斗图标，看不出是哪个站。
     实测 375px 上「← 返回 / IronedBeads / 我的拼豆」三块合计 319px，装得下
     （英文那版最长）；字号收到 16px 再留点余量。 */
  .machine-brand {
    font-size: 16px;
    min-width: 0;
  }

  .machine-brand .brand-name {
    min-width: 0;
  }
}

/* ---------- 工坊里的 3D 机器 ---------- */
.cyber-machine-3d {
  display: flex;
  flex-direction: column;
  gap: 14px;
  width: min(820px, 94vw);
}

.cyber-machine-3d[hidden] {
  display: none;
}

.cyber-machine-viewport {
  background:
    radial-gradient(circle at 1px 1px, rgba(17, 28, 42, 0.06) 1px, transparent 1.6px) 0 0 / 18px 18px,
    linear-gradient(180deg, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0));
  border: 1.5px solid #111820;
  border-radius: 24px;
  box-shadow: 4px 4px 0 #111820;
  height: clamp(280px, 52vh, 520px);
  overflow: hidden;
  position: relative;
  touch-action: none;
}

.cyber-machine-viewport canvas {
  display: block;
  height: 100%;
  inset: 0;
  position: absolute;
  width: 100%;
}

.cyber-machine-hud {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  justify-content: center;
}

.cyber-machine-start-hud {
  min-height: 40px;
}

.cyber-workshop[data-machine="manual"] .cyber-machine-start-hud {
  display: none;
}

.cyber-machine-coverage {
  align-items: center;
  background: #ffffff;
  border: 1.5px solid #111820;
  border-radius: 999px;
  box-shadow: 3px 3px 0 #111820;
  display: inline-flex;
  gap: 10px;
  min-height: 40px;
  padding: 0 14px;
}

.cyber-machine-coverage[hidden] {
  display: none;
}

.cyber-machine-coverage i {
  background: #eceee9;
  border-radius: 999px;
  display: block;
  height: 8px;
  overflow: hidden;
  width: 120px;
}

.cyber-machine-coverage i b {
  background: linear-gradient(90deg, #f0a13a, #e45b64);
  border-radius: 999px;
  display: block;
  height: 100%;
  /* 进度事件每 100ms 来一次（cyber-machines.js 的 paintTimer > 0.1）。
     过渡时长必须 ≤ 这个间隔，否则上一段还没走完就被下一段打断，条会一顿一顿的。 */
  transition: width 90ms linear;
  width: 0;
}

.cyber-machine-coverage > span {
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  font-weight: 800;
  white-space: nowrap;
  /* 胶囊是 inline-flex，父容器 justify-content: center。百分比从 1 位数变 2 位、
     2 位变 3 位时这段文字会变宽，整个胶囊跟着左右缩放——每 100ms 一次，看着就是在弹跳。

     定死一个宽度，位数再变胶囊也不动；读数在框里变是应该的，旁边那个词不该动。
     对齐方向要按语言分，因为数字和词的前后顺序是反的：
       英文「100% ironed」词在右 → 靠右对齐，钉住右边缘，数字往左长
       中文「已烫 100%」  词在左 → 靠左对齐，钉住左边缘，数字往右长
     同一个方向伺候不了两边，这是这条规则要分两半写的唯一原因。

     用 min-width 不用 width：万一用户机器上字体回退得比较宽，撑开总比
     文字溢出去压到进度条上好。实测（12px / PingFang SC）最宽的是
     「100% ironed」71.3px ≈ 5.94em，中文最宽 59.3px ≈ 4.94em，各留一点余量。
     tabular-nums 留着：这套字体不支持也无害，支持的字体上数字跳动会更小。 */
  display: inline-block;
  min-width: 6.4em;
  text-align: right;
}

html[lang="zh-CN"] .cyber-machine-coverage > span {
  min-width: 5.4em;
  text-align: left;
}

@media (max-width: 900px) {
  .cyber-machine-viewport {
    height: clamp(240px, 44vh, 420px);
  }

  .cyber-machine-setting {
    padding-left: 10px;
  }

  .cyber-machine-setting b {
    min-width: 56px;
  }
}

/* ---------- 3D 机器：视角切换和按键提示 ---------- */
.cyber-machine-views {
  background: rgba(255, 255, 255, 0.94);
  border: 1.5px solid #111820;
  border-radius: 999px;
  box-shadow: 3px 3px 0 #111820;
  display: flex;
  gap: 2px;
  padding: 3px;
  position: absolute;
  right: 12px;
  top: 12px;
  z-index: 2;
}

.cyber-machine-views button {
  background: transparent;
  border: 0;
  border-radius: 999px;
  color: #111820;
  cursor: pointer;
  font-size: 12px;
  font-weight: 800;
  min-height: 28px;
  padding: 0 12px;
}

.cyber-machine-views button.active {
  background: #111820;
  color: #ffffff;
}

.cyber-machine-tip {
  background: rgba(17, 24, 32, 0.92);
  border-radius: 8px;
  color: #ffffff;
  font-size: 12px;
  font-weight: 800;
  left: 0;
  padding: 5px 9px;
  pointer-events: none;
  position: absolute;
  top: 0;
  white-space: nowrap;
  z-index: 3;
}

.cyber-machine-tip[hidden] {
  display: none;
}

/* ============================================================
   工坊 A 版式（3D 机器）：机器铺满整页，其余板块悬浮
   退出 左上 · 进度标签 顶部居中 · 整体/控制台 右上 · 字幕 左下 · 启动 / 进度 底部居中
   ============================================================ */
.cyber-workshop[data-machine="auto"] .cyber-workshop-scene,
.cyber-workshop[data-machine="manual"] .cyber-workshop-scene {
  display: block;
  overflow: hidden;
  padding: 0;
}

.cyber-workshop[data-machine="auto"] .cyber-machine-3d,
.cyber-workshop[data-machine="manual"] .cyber-machine-3d {
  display: block;
  inset: 0;
  position: absolute;
  width: auto;
}

.cyber-workshop[data-machine="auto"] .cyber-machine-viewport,
.cyber-workshop[data-machine="manual"] .cyber-machine-viewport {
  background: transparent;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  height: auto;
  inset: 0;
  position: absolute;
}

.cyber-workshop[data-machine="auto"] .cyber-machine-views,
.cyber-workshop[data-machine="manual"] .cyber-machine-views {
  right: 18px;
  top: 18px;
}

/* 字幕：左下角 */
.cyber-workshop[data-machine="auto"] .cyber-workshop-head,
.cyber-workshop[data-machine="manual"] .cyber-workshop-head {
  bottom: 30px;
  left: 30px;
  max-width: 380px;
  pointer-events: none;
  position: absolute;
  text-align: left;
  z-index: 3;
}

.cyber-workshop[data-machine="auto"] .cyber-workshop-head small,
.cyber-workshop[data-machine="manual"] .cyber-workshop-head small {
  font-size: 10px;
  margin-bottom: 6px;
}

.cyber-workshop[data-machine="auto"] .cyber-workshop-head h2,
.cyber-workshop[data-machine="manual"] .cyber-workshop-head h2 {
  font-size: 24px;
  margin-bottom: 6px;
}

.cyber-workshop[data-machine="auto"] .cyber-workshop-head p,
.cyber-workshop[data-machine="manual"] .cyber-workshop-head p {
  font-size: 13px;
  line-height: 1.55;
}

.cyber-workshop[data-machine="auto"] .cyber-machine-dots i,
.cyber-workshop[data-machine="manual"] .cyber-machine-dots i {
  flex: 0 0 auto;
  white-space: nowrap;
}

/* 进度标签：顶部居中的四个胶囊；状态文字挪到底部按钮上方 */
.cyber-workshop[data-machine="auto"] .cyber-machine-status,
.cyber-workshop[data-machine="manual"] .cyber-machine-status {
  display: contents;
}

.cyber-workshop[data-machine="auto"] .cyber-machine-dots,
.cyber-workshop[data-machine="manual"] .cyber-machine-dots {
  gap: 6px;
  left: 50%;
  position: absolute;
  top: 22px;
  transform: translateX(-50%);
  z-index: 3;
}

.cyber-workshop[data-machine="auto"] .cyber-machine-dots i,
.cyber-workshop[data-machine="manual"] .cyber-machine-dots i {
  background: rgba(255, 255, 255, 0.94);
  border: 1.5px solid #111820;
  border-radius: 999px;
  color: #6b6b6b;
  font-size: 12px;
  font-style: normal;
  font-weight: 800;
  height: auto;
  padding: 5px 13px;
  transform: none;
  width: auto;
}

.cyber-workshop[data-machine="auto"] .cyber-machine-dots i.is-active,
.cyber-workshop[data-machine="manual"] .cyber-machine-dots i.is-active {
  background: #f0a13a;
  color: #111820;
  transform: none;
}

.cyber-workshop[data-machine="auto"] .cyber-machine-dots i.is-done,
.cyber-workshop[data-machine="manual"] .cyber-machine-dots i.is-done {
  background: var(--teal);
  border-color: var(--teal);
  color: #ffffff;
}

.cyber-workshop[data-machine="auto"] .cyber-machine-status em,
.cyber-workshop[data-machine="manual"] .cyber-machine-status em {
  bottom: 96px;
  color: #6b6b6b;
  font-size: 13px;
  font-style: italic;
  font-weight: 700;
  left: 50%;
  position: absolute;
  transform: translateX(-50%);
  white-space: nowrap;
  z-index: 3;
}

/* 启动 / 熨烫进度：底部正中 */
.cyber-workshop[data-machine="auto"] .cyber-machine-hud,
.cyber-workshop[data-machine="manual"] .cyber-machine-hud {
  bottom: 30px;
  left: 50%;
  position: absolute;
  transform: translateX(-50%);
  z-index: 4;
}

.cyber-workshop[data-machine="auto"] .cyber-machine-start-hud {
  border-radius: 999px;
  box-shadow: 4px 4px 0 #111820;
  font-size: 16px;
  letter-spacing: 0.16em;
  min-height: 54px;
  padding: 0 44px;
}

.cyber-workshop[data-machine="auto"][data-stage="lock"] .cyber-machine-start-hud:hover {
  box-shadow: 2px 2px 0 #111820;
  transform: translate(2px, 2px);
}

/* 加热、弹出阶段按钮退场，只留状态文字 */
.cyber-workshop[data-machine="auto"][data-stage="press"] .cyber-machine-start-hud,
.cyber-workshop[data-machine="auto"][data-stage="heat"] .cyber-machine-start-hud,
.cyber-workshop[data-machine="auto"][data-stage="eject"] .cyber-machine-start-hud {
  display: none;
}

.cyber-workshop[data-machine="auto"][data-stage="press"] .cyber-machine-status em,
.cyber-workshop[data-machine="auto"][data-stage="heat"] .cyber-machine-status em,
.cyber-workshop[data-machine="auto"][data-stage="eject"] .cyber-machine-status em {
  background: rgba(255, 255, 255, 0.94);
  border: 1.5px solid #111820;
  border-radius: 999px;
  bottom: 30px;
  box-shadow: 3px 3px 0 #111820;
  color: #111820;
  font-size: 14px;
  font-style: normal;
  padding: 12px 26px;
}

.cyber-workshop[data-machine="manual"] .cyber-machine-coverage {
  min-height: 48px;
  padding: 0 18px;
}

.cyber-workshop[data-machine="manual"] .cyber-machine-coverage i {
  width: 180px;
}

@media (max-width: 900px) {
  .cyber-workshop[data-machine="auto"] .cyber-workshop-head,
  .cyber-workshop[data-machine="manual"] .cyber-workshop-head {
    bottom: 118px;
    left: 16px;
    max-width: calc(100% - 32px);
    right: 16px;
  }

  .cyber-workshop[data-machine="auto"] .cyber-workshop-head h2,
  .cyber-workshop[data-machine="manual"] .cyber-workshop-head h2 {
    font-size: 20px;
  }

  .cyber-workshop[data-machine="auto"] .cyber-workshop-head p,
  .cyber-workshop[data-machine="manual"] .cyber-workshop-head p {
    font-size: 12px;
  }

  .cyber-workshop[data-machine="auto"] .cyber-machine-dots,
  .cyber-workshop[data-machine="manual"] .cyber-machine-dots {
    top: 70px;
  }

  .cyber-workshop[data-machine="auto"] .cyber-machine-dots i,
  .cyber-workshop[data-machine="manual"] .cyber-machine-dots i {
    flex: 0 0 auto;
    font-size: 11px;
    padding: 4px 10px;
    white-space: nowrap;
  }

  /* 手机上字幕压在机器上，垫一层半透明底保证能读 */
  .cyber-workshop[data-machine="auto"] .cyber-workshop-head,
  .cyber-workshop[data-machine="manual"] .cyber-workshop-head {
    backdrop-filter: blur(6px);
    background: rgba(251, 248, 240, 0.78);
    border-radius: 14px;
    padding: 10px 12px;
  }

  .cyber-workshop[data-machine="auto"] .cyber-machine-views,
  .cyber-workshop[data-machine="manual"] .cyber-machine-views {
    top: 18px;
  }

  .cyber-workshop[data-machine="auto"] .cyber-machine-status em,
  .cyber-workshop[data-machine="manual"] .cyber-machine-status em {
    bottom: 92px;
  }

  .cyber-workshop[data-machine="auto"] .cyber-machine-hud,
  .cyber-workshop[data-machine="manual"] .cyber-machine-hud {
    bottom: 22px;
  }
}

/* ---------- 掀布页 C 版式：只有布，说明印在布上 ---------- */
.cyber-peel-copy,
.cyber-peel-hint {
  display: none !important;
}

.cyber-peel-chip {
  background: rgba(255, 255, 255, 0.94);
  border: 1.5px solid #111820;
  border-radius: 999px;
  box-shadow: 3px 3px 0 #111820;
  color: #111820;
  font-size: 12px;
  font-weight: 800;
  padding: 8px 14px;
  pointer-events: none;
  position: absolute;
  right: 18px;
  top: 18px;
  z-index: 4;
}

.cyber-peel-chip:empty {
  display: none;
}

/* ---------- 半自动机的工具块（右下角） ---------- */
.cyber-machine-tool {
  align-items: center;
  background: rgba(255, 255, 255, 0.96);
  border: 1.5px solid #111820;
  border-radius: 18px;
  bottom: 96px;
  box-shadow: 4px 4px 0 #111820;
  cursor: grab;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 12px 14px 10px;
  position: absolute;
  right: 22px;
  touch-action: none;
  transition: opacity 200ms ease, transform 200ms ease;
  user-select: none;
  z-index: 4;
}

.cyber-machine-tool[hidden] {
  display: none;
}

.cyber-machine-tool.is-docked {
  animation: cyber-tool-bob 1.6s ease-in-out infinite;
}

.cyber-machine-tool.is-out {
  cursor: default;
  opacity: 0.5;
  animation: none;
}

.cyber-machine-tool-icon {
  background: #ffffff;
  border: 1.5px solid #111820;
  border-radius: 22%;
  display: block;
  height: 64px;
  position: relative;
  width: 72px;
}

.cyber-machine-tool-icon i {
  background: #f3e3a0;
  border: 1px solid rgba(17, 24, 32, 0.25);
  border-radius: 999px;
  display: block;
  height: 12px;
  left: 10px;
  position: absolute;
  right: 10px;
}

.cyber-machine-tool-icon i:first-child {
  top: 18px;
}

.cyber-machine-tool-icon i:nth-child(2) {
  top: 38px;
}

.cyber-machine-tool-icon b {
  background: #111820;
  border-radius: 3px;
  display: block;
  height: 6px;
  left: 27px;
  position: absolute;
  top: 7px;
  width: 18px;
}

.cyber-machine-tool-label {
  color: #111820;
  font-size: 12px;
  font-weight: 800;
}

@keyframes cyber-tool-bob {
  0%,
  100% {
    transform: translateY(0);
  }

  50% {
    transform: translateY(-4px);
  }
}

@media (max-width: 900px) {
  /* 手机上字幕在底部，工具块挪到字幕上方 */
  .cyber-machine-tool {
    bottom: 236px;
    padding: 9px 10px 8px;
    right: 14px;
  }

  .cyber-machine-tool-icon {
    height: 48px;
    width: 54px;
  }

  .cyber-machine-tool-icon i {
    height: 9px;
    left: 8px;
    right: 8px;
  }

  .cyber-machine-tool-icon i:first-child {
    top: 14px;
  }

  .cyber-machine-tool-icon i:nth-child(2) {
    top: 29px;
  }

  .cyber-machine-tool-icon b {
    left: 20px;
    top: 5px;
    width: 14px;
  }

  .cyber-machine-tool-label {
    font-size: 11px;
  }
}

/* ---------- 烘焙布包边选择器（工坊右下角） ---------- */
.cyber-edge-picker {
  bottom: 30px;
  position: absolute;
  right: 22px;
  z-index: 5;
}

.cyber-edge-picker[hidden] {
  display: none;
}

.cyber-edge-toggle {
  align-items: center;
  background: #111820;
  border: 1.5px solid #111820;
  border-radius: 999px;
  box-shadow: 3px 3px 0 rgba(17, 24, 32, 0.35);
  color: #ffffff;
  cursor: pointer;
  display: flex;
  font-size: 12px;
  font-weight: 800;
  gap: 8px;
  min-height: 40px;
  padding: 4px 14px 4px 6px;
}

.cyber-edge-toggle b {
  color: #ffb257;
  font-weight: 800;
}

.cyber-edge-toggle i {
  font-style: normal;
  opacity: 0.7;
}

.cyber-edge-swatch {
  border-radius: 6px;
  display: block;
  height: 30px;
  width: 44px;
}

.cyber-edge-menu {
  background: rgba(255, 255, 255, 0.97);
  border: 1.5px solid #111820;
  border-radius: 16px;
  bottom: 50px;
  box-shadow: 4px 4px 0 #111820;
  display: grid;
  gap: 6px;
  grid-template-columns: repeat(3, 1fr);
  padding: 10px;
  position: absolute;
  right: 0;
  width: 318px;
}

.cyber-edge-menu[hidden] {
  display: none;
}

.cyber-edge-menu button {
  align-items: center;
  background: transparent;
  border: 1.5px solid transparent;
  border-radius: 10px;
  color: #111820;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  font-size: 11px;
  font-weight: 800;
  gap: 4px;
  padding: 6px 4px;
}

.cyber-edge-menu button canvas {
  border-radius: 6px;
  display: block;
  height: 58px;
  width: 84px;
}

.cyber-edge-menu button:hover {
  background: #f1f4f2;
}

.cyber-edge-menu button.active {
  background: rgba(39, 135, 127, 0.1);
  border-color: var(--teal);
}

/* 视口里的 canvas 有一条「铺满」规则，选择器里的小样画布要按自己的尺寸来 */
.cyber-machine-viewport .cyber-edge-picker canvas {
  inset: auto;
  position: static;
}

.cyber-machine-viewport .cyber-edge-toggle canvas {
  height: 30px;
  width: 44px;
}

.cyber-machine-viewport .cyber-edge-menu button canvas {
  height: 58px;
  width: 84px;
}

/* 压合 / 加热 / 弹出阶段收起来 */
.cyber-workshop[data-stage="press"] .cyber-edge-picker,
.cyber-workshop[data-stage="heat"] .cyber-edge-picker,
.cyber-workshop[data-stage="eject"] .cyber-edge-picker {
  display: none;
}

/* 半自动例外：全自动是机器自己压，人只能等；半自动是自己按住机器来回熨，
   熨的过程中还会想换包边，所以这一台熨烫时包边选择器留着不收。 */
.cyber-workshop[data-machine="manual"][data-stage="heat"] .cyber-edge-picker {
  display: block;
}

@media (max-width: 900px) {
  .cyber-edge-picker {
    bottom: 236px;
    right: 14px;
  }

  .cyber-edge-toggle {
    font-size: 11px;
    min-height: 36px;
  }

  .cyber-edge-menu {
    bottom: 46px;
    width: min(318px, calc(100vw - 28px));
  }
}

/* ============================================================
   识别页：图纸铺满整页，工具浮在四角
   左上 返回 · 顶部居中 五步 · 右上 当前步骤的工具（点开浮层）
   左下 这一步该做什么 · 底部居中 上一步 / 下一步
   和烫豆工坊、掀布页是同一套语言：满屏 + 四角控件 + 底部正中主按钮。
   ============================================================ */
body[data-view="setup"][data-module="direct"] .topbar {
  display: none;
}

body[data-view="setup"][data-module="direct"] .app-shell {
  grid-template-rows: minmax(0, 1fr);
}

body[data-view="setup"][data-module="direct"] .setup-view.direct-setup-active {
  padding: 0;
}

body[data-view="setup"][data-module="direct"] .setup-view.direct-setup-active .direct-wizard {
  display: block;
  gap: 0;
  position: relative;
}

body[data-view="setup"][data-module="direct"] .direct-recognition-overlay {
  inset: 0;
}

/* 每一步都铺满整页，四周留出浮动控件的位置。
   顶部这个值要压过左上角那排浮动控件（品牌块 + 返回首页 + 步骤条）。
   返回首页那个键最高，底边落在 52px；56px 只剩 4px 净空，看着像贴在一起。
   68px 留出 16px，框和按钮才分得开。 */
body[data-view="setup"][data-module="direct"] .direct-wizard .direct-stage:not(.is-hidden) {
  height: 100%;
  inset: 0;
  min-height: 0;
  padding: 68px 14px 80px;
  position: absolute;
}

body[data-view="setup"][data-module="direct"] .direct-wizard .direct-stage:not(.is-hidden):not([data-direct-panel="proof"]) {
  gap: 0;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: minmax(0, 1fr);
}

/* 画布本身不再是一张卡片，它就是页面 */
body[data-view="setup"][data-module="direct"] .direct-stage .direct-main-panel {
  background: transparent;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  height: 100%;
  min-height: 0;
  padding: 0;
}

body[data-view="setup"][data-module="direct"] .direct-stage .direct-crop-box,
body[data-view="setup"][data-module="direct"] .direct-stage .direct-align-box {
  background: transparent;
  border: 0;
  height: 100%;
  min-height: 0;
}

/* 导入这一步的上传区和裁剪页一样大：铺满整块画布，只留一圈虚线表示可以拖进来 */
body[data-view="setup"][data-module="direct"] .direct-stage[data-direct-panel="import"] .direct-upload-box {
  border-radius: 14px;
  border-width: 2px;
  height: 100%;
  min-height: 0;
  width: 100%;
}

/* ---------- 顶部居中的五步 ---------- */
body[data-view="setup"][data-module="direct"] .direct-setup-active .direct-stepper {
  background: transparent;
  border: 0;
  box-shadow: none;
  gap: 4px;
  height: auto;
  left: 50%;
  max-width: calc(100vw - 220px);
  overflow: visible;
  padding: 0;
  top: 14px;
  transform: translateX(-50%);
  width: auto;
  z-index: 24;
}

body[data-view="setup"][data-module="direct"] .direct-stepper > span[aria-hidden="true"] {
  display: none;
}

body[data-view="setup"][data-module="direct"] .direct-setup-active .direct-step-button {
  background: rgba(255, 255, 255, 0.94);
  border: 1.5px solid rgba(17, 24, 32, 0.35);
  border-radius: 999px;
  color: #5d6b7a;
  font-size: 12px;
  font-weight: 800;
  min-height: 30px;
  padding: 0 13px;
  white-space: nowrap;
}

body[data-view="setup"][data-module="direct"] .direct-setup-active .direct-step-button::before {
  display: none;
}

body[data-view="setup"][data-module="direct"] .direct-setup-active .direct-step-button.reached {
  background: rgba(39, 135, 127, 0.14);
  border-color: var(--teal);
  color: var(--teal);
}

body[data-view="setup"][data-module="direct"] .direct-setup-active .direct-step-button.active {
  background: #2f73df;
  border-color: #2f73df;
  color: #ffffff;
}

/* ---------- 右上角：当前步骤的工具 ---------- */
.direct-tool-toggle {
  align-items: center;
  background: #111820;
  border: 1.5px solid #111820;
  border-radius: 999px;
  color: #ffffff;
  cursor: pointer;
  display: flex;
  font-size: 12px;
  font-weight: 800;
  gap: 6px;
  min-height: 34px;
  padding: 0 14px;
  position: fixed;
  right: 18px;
  top: 14px;
  z-index: 27;
}

.direct-tool-toggle[hidden] {
  display: none;
}

.direct-tool-toggle i {
  font-style: normal;
  opacity: 0.72;
}

body[data-view="setup"][data-module="direct"] .direct-stage .direct-side-panel {
  background: rgba(255, 255, 255, 0.97);
  border: 1.5px solid #111820;
  border-radius: 16px;
  box-shadow: 4px 4px 0 #111820;
  display: none;
  height: auto;
  max-height: min(64vh, 540px);
  overflow-y: auto;
  padding: 12px;
  position: fixed;
  right: 18px;
  top: 56px;
  width: min(330px, calc(100vw - 36px));
  z-index: 26;
}

body[data-view="setup"][data-module="direct"] .direct-wizard.direct-tools-open .direct-stage:not(.is-hidden) .direct-side-panel {
  display: grid;
}

/* ---- 对齐这一步 · 手机版：分段切换，一次一件事 ----
   这块面板在 375px 上高 520px、内容 982px，盖住画布的八成——而对齐是纯看眼睛的活，
   面板一开就看不见格线压没压准。更要命的是「锁定对齐结果」排在第六组里，
   要往下滚 460px 才露面，可它是这一步的唯一出口（不勾点下一步会被拦下）。

   改法：面板变成底部定高抽屉（232px），顶上四个分段各管一件事，
   下面永远只显示一组控件；「锁定对齐结果」抽到抽屉最底一行常驻，
   紧挨着「上一步 / 下一步」——对准了就勾，勾了就走。
   图纸因此拿回六成以上的屏幕。 */
.direct-align-tabs {
  display: none;
  gap: 5px;
  flex: 0 0 auto;
  margin-bottom: 8px;
}

.direct-align-tabs button {
  background: #ffffff;
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--muted);
  cursor: pointer;
  flex: 1;
  font-size: 12px;
  font-weight: 800;
  min-height: 30px;
  padding: 0 4px;
}

.direct-align-tabs button.is-on {
  background: #111820;
  border-color: #111820;
  color: #ffffff;
}

@media (max-width: 520px) {
  /* 从右上角的浮层改成贴底的抽屉；bottom 留出「上一步 / 下一步」那一行。
     选择器要带上 .direct-side-panel：识别页满屏版式里有一条
     `.setup-view.direct-setup-active .direct-stage:not(.is-hidden) > .direct-side-panel { height: auto }`，
     权重比一般写法高，不压过它这里的定高就不生效。 */
  body[data-view="setup"][data-module="direct"] .setup-view.direct-setup-active .direct-stage:not(.is-hidden) > .direct-side-panel.direct-align-tools {
    border-radius: 14px 14px 0 0;
    border-width: 1.5px 0 0;
    bottom: 60px;
    box-shadow: 0 -10px 30px rgba(17, 24, 32, 0.18);
    /* 高度交给内容，别写死。
       原来这里是 264px，另外两段各自再覆盖成 356 / 344——那几个数字是按
       「底部还钉着一条 60px 的锁定勾选」算出来的。勾选收回「范围」自己那一段
       之后，那块高度没人用，四个页签底下就各空出 37～72px。
       改成 auto，抽屉贴着内容收；只留一个上限，免得哪天内容变多顶穿屏幕。 */
    height: auto;
    left: 0;
    max-height: calc(100vh - 210px);
    overflow-y: auto;
    padding: 10px 12px;
    right: 0;
    top: auto;
    width: auto;
  }

  body[data-view="setup"][data-module="direct"] .direct-wizard.direct-tools-open .direct-stage:not(.is-hidden) .direct-align-tools {
    display: flex;
    flex-direction: column;
  }

  /* 分段和「锁定」两头钉住，中间那一组自己滚。没有包裹层可用，
     所以不靠 flex 分配高度，而是让整块抽屉滚、两头 sticky。 */
  .direct-align-tabs {
    background: #ffffff;
    display: flex;
    position: sticky;
    top: 0;
    z-index: 3;
  }

  /* 当前分段以外的组整组不出场 */
  .direct-align-tools[data-align-tab="size"] [data-align-group]:not([data-align-group="size"]),
  .direct-align-tools[data-align-tab="nudge"] [data-align-group]:not([data-align-group="nudge"]),
  .direct-align-tools[data-align-tab="view"] [data-align-group]:not([data-align-group="view"]),
  .direct-align-tools[data-align-tab="extent"] [data-align-group] {
    display: none;
  }

  /* 「网格范围」这张卡拆开用：display: contents 让它的三个孩子直接成为抽屉的
     子项，这样「锁定对齐结果」才能用 order 钉在最底下，而标题和四边增减
     只在「范围」分段时才出场。整张卡若用 display: none，锁定也跟着没了。 */
  .direct-align-tools #directExtentCard {
    display: contents;
  }

  /* 手机上「范围」这一段只留「锁定对齐结果」一个勾选：
     卡片标题和那盘四边增减格子都收起来——锁定之后加减整格由图纸上那枚
     浮动控件代劳（见 .direct-lock-puck），不必在抽屉里再来一盘。 */
  .direct-align-tools #directExtentCard > .direct-card-head,
  .direct-align-tools #directExtentCard > .direct-grow-pad {
    display: none;
  }

  /* 原来这一条是 sticky 钉在抽屉最下面的，四个页签下都露着，正好压在
     「上一步／下一步」上方。现在收回「范围」自己那一段里，跟着页签走。 */
  .direct-align-tools:not([data-align-tab="extent"]) #directExtentCard > .direct-pitch-gate {
    display: none;
  }

  .direct-align-tools #directExtentCard > .direct-pitch-gate {
    background: #ffffff;
    border: 1.5px solid #2f73df;
    border-radius: 10px;
    bottom: auto;
    flex: 0 0 auto;
    order: 0;
    padding: 8px 10px;
    position: static;
    z-index: 3;
  }

  .direct-align-tools .direct-tool-card,
  .direct-align-tools #directExtentCard > .direct-grow-pad {
    flex: 0 0 auto;
  }

  .direct-align-tools .direct-aligned-summary {
    flex: 0 0 auto;
  }

  /* 这段说明写的是鼠标操作（按住空格拖动平移视图），手机上没有空格键 */
  .direct-align-tools .direct-size-card .direct-tool-note {
    display: none;
  }

  /* 面板贴底之后，左下角那条浮动说明正好压在抽屉上 */
  body[data-view="setup"][data-module="direct"][data-direct-step="align"] .direct-caption {
    display: none;
  }

  /* 这颗按钮是 position: fixed 钉在右上角的，中文「画面设置」放得下，
     英文「View settings」加上「IronedBeads ← Back to home」就压到站名上了。
     抽屉现在常驻在底部，这颗按钮只剩「收起/展开」一个用处，收成一个圆点就够。 */
  .direct-tool-toggle {
    gap: 0;
    min-height: 30px;
    padding: 0 10px;
  }

  .direct-tool-toggle #directToolLabel {
    display: none;
  }

  .direct-tool-toggle i {
    font-size: 13px;
    opacity: 1;
  }
}

/* ---------- 左下角：这一步该做什么 ---------- */
.direct-caption {
  bottom: 22px;
  display: none;
  left: 20px;
  max-width: min(340px, 34vw);
  pointer-events: none;
  position: fixed;
  z-index: 22;
}

body[data-view="setup"][data-module="direct"] .direct-caption {
  display: block;
}

.direct-caption small {
  color: var(--teal);
  display: block;
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.28em;
  margin-bottom: 5px;
}

.direct-caption strong {
  color: #111820;
  display: block;
  font-size: 14px;
  font-weight: 800;
  line-height: 1.5;
}

.direct-caption strong:empty {
  display: none;
}

/* ---------- 底部居中：上一步 / 下一步 ---------- */
/* 这一条不能用 transform 居中：带 transform 的祖先会变成 fixed 子元素的定位基准，
   里面的「返回首页」就跑不到左上角了。用 left/right + justify-content 居中。 */
body[data-view="setup"][data-module="direct"] .direct-footer {
  bottom: 18px;
  justify-content: center;
  left: 0;
  right: 0;
  top: auto;
  transform: none;
}

/* 识别向导顶部左上角：返回首页 + 品牌块。
   向导是满屏的，站点顶栏被整个盖住，所以这里单独补一次品牌。
   两者都 fixed：返回键在最左，品牌让开它的宽度——和窄屏那套的顺序一致。 */
/* 品牌块只属于识别向导。别的视图下 .direct-wizard 整个是 is-hidden，
   但保险起见显式收起，免得将来有人把它挪出去。 */
.direct-brand {
  display: none;
}

body[data-view="setup"][data-module="direct"] .direct-brand {
  align-items: center;
  display: inline-flex;
  gap: 8px;
  /* 让开左边的返回键；宽度随语言变（「← 首页」和「← Home」不一样宽），
     所以用 calc 跟着变量走，别写死一个值。 */
  left: calc(18px + var(--direct-back-w, 84px));
  position: fixed;
  text-decoration: none;
  top: 14px;
  z-index: 13;
}

body[data-view="setup"][data-module="direct"] .direct-brand .brand-iron-logo {
  height: 30px;
}

body[data-view="setup"][data-module="direct"] .direct-brand .brand-name {
  font-size: 15px;
  font-weight: 800;
  letter-spacing: 0.01em;
  line-height: 1;
  white-space: nowrap;
}

body[data-view="setup"][data-module="direct"] .direct-footer #directConsoleButton {
  left: 18px;
  position: fixed;
  top: 14px;
  white-space: nowrap;
}

body[data-view="setup"][data-module="direct"] .direct-footer .direct-outline-button {
  border-radius: 999px;
  box-shadow: 3px 3px 0 rgba(17, 24, 32, 0.18);
  white-space: nowrap;
}

body[data-view="setup"][data-module="direct"] .direct-footer #directNextButton,
body[data-view="setup"][data-module="direct"] .direct-footer #directSaveButton,
body[data-view="setup"][data-module="direct"] .direct-footer #cyberBeadButton {
  font-size: 14px;
  min-height: 46px;
  padding: 0 26px;
}

/* 对齐这一步右上角原来就有实时预览卡，和工具浮层是同一个位置，把它挪到左边 */
body[data-view="setup"][data-module="direct"] .direct-stage[data-direct-panel="align"] .direct-tile-hud {
  left: 4px;
  right: auto;
  top: 48px;
}

body[data-view="setup"][data-module="direct"] .direct-stage[data-direct-panel="align"] .direct-align-box > strong {
  left: auto;
  right: 10px;
}

@media (max-width: 900px) {
  body[data-view="setup"][data-module="direct"] .direct-wizard .direct-stage:not(.is-hidden) {
    padding: 92px 10px 72px;
  }

  body[data-view="setup"][data-module="direct"] .direct-stage[data-direct-panel="align"] .direct-tile-hud {
    top: 4px;
    width: 150px;
  }

  /* 手机上原来有一条规则把步骤条放回文档流（position: static），这里要一并盖掉 */
  body[data-view="setup"][data-module="direct"] .setup-view.direct-setup-active {
    padding: 0;
  }

  body[data-view="setup"][data-module="direct"] .setup-view.direct-setup-active .direct-stepper {
    left: 50%;
    margin: 0;
    max-width: calc(100vw - 24px);
    overflow-x: auto;
    position: fixed;
    top: 56px;
    transform: translateX(-50%);
    width: auto;
  }

  body[data-view="setup"][data-module="direct"] .setup-view.direct-setup-active .direct-stage:not(.is-hidden) {
    align-content: stretch;
    overflow: hidden;
  }

  body[data-view="setup"][data-module="direct"] .setup-view.direct-setup-active .direct-stage:not(.is-hidden) > .direct-main-panel {
    height: 100%;
    min-height: 0;
  }

  body[data-view="setup"][data-module="direct"] .direct-setup-active .direct-step-button {
    flex: 0 0 auto;
    font-size: 11px;
    padding: 0 10px;
  }

  /* 说明文字在窄屏一律居中（PC 仍是左下角） */
  .direct-caption {
    bottom: 74px;
    left: 0;
    max-width: none;
    padding: 0 16px;
    right: 0;
    text-align: center;
  }

  .direct-caption strong {
    font-size: 12px;
  }

  .direct-upload-hint {
    color: #5b6670;
    display: block;
    font-size: 12px;
    font-weight: 700;
    line-height: 1.5;
    max-width: 260px;
  }

  /* 导入这一步的说明已经跟在蓝框按钮下面了，左下角那一份收起来免得说两遍；
     完成这一步画面里就一张成品图，底下不再压一行小字。 */
  body[data-view="setup"][data-module="direct"][data-direct-step="import"] .direct-caption,
  body[data-view="setup"][data-module="direct"][data-direct-step="finish"] .direct-caption {
    display: none;
  }

  /* 顶栏：返回首页贴最左，logo + 站名居中 */
  body[data-view="setup"][data-module="direct"] .direct-footer #directConsoleButton {
    left: 12px;
  }

  body[data-view="setup"][data-module="direct"] .direct-brand {
    left: 50%;
    transform: translateX(-50%);
  }

  body[data-view="setup"][data-module="direct"] .direct-stage[data-direct-panel="import"] .direct-upload-box {
    height: 100%;
    width: 100%;
  }
}

/* ============================================================
   2026-09-14
   站名 / 我的拼豆画廊 / 选机器一屏对开 / 保存询问框 / 声音开关
   ============================================================ */

/* ---- logo 旁的站名：中文思源宋体特粗，英文 Playfair 斜体 ---- */
.brand-name {
  display: inline-flex;
  flex-direction: column;
  justify-content: center;
  line-height: 1;
  min-width: 0;
}

.brand-name-zh {
  color: #111820;
  font-family: "Noto Serif SC", "Songti SC", "STSong", serif;
  font-size: 22px;
  font-weight: 900;
  letter-spacing: 0.02em;
  white-space: nowrap;
}

.brand-name-en {
  color: #111820;
  font-family: "Playfair Display", Georgia, serif;
  font-size: 13px;
  font-style: italic;
  font-weight: 700;
  letter-spacing: 0.04em;
  margin-top: 3px;
  white-space: nowrap;
}

/*
 * 站名双色字标，全站所有 logo 旁边都是这一套（首页三处、选工具页、烫后预览页、
 * 我的拼豆手机版、隐私 / 条款 / 404）：
 *   前半截「赛博 / Ironed」墨色，后半截「烫豆 / Beads」青色；
 *   落地页顶栏是深色的，前半截换成金色（墨色在黑底上看不见，青色两种底都读得清）。
 * 字体：英文衬线斜体（Playfair Display 700），中文思源宋体粗体正体——中文没有真正的斜体，硬斜会变形。
 * 以前英文站名有金黄、青、墨和两种近似黑五种颜色，字体也有斜体、正体、系统黑体三种。
 */
.brand-name .brand-a {
  color: #111820;
}

.brand-name .brand-b {
  color: var(--teal, #27877f);
}

/* 同一处把两种语言都写好、按 html[lang] 只露一种，不走词典翻译。
   用在会高频刷新的读数旁边（烫豆进度「已烫 91%」、倒计时「剩余 5 秒」）：
   数字单独一格，每次只换数字，字不动，也就不会等翻译、闪一帧中文。 */
html[lang="en"] .only-zh,
html:not([lang="en"]) .only-en {
  display: none;
}

/* 中文界面只看中文名，英文界面只看英文名；html[lang] 由 app.js 切 */
html[lang="en"] .brand-name-zh,
html:not([lang="en"]) .brand-name-en {
  display: none;
}

html[lang="en"] .brand-name-en {
  font-size: 21px;
  margin-top: 0;
}

@media (max-width: 640px) {
  .brand-name-zh { font-size: 18px; }
  .brand-name-en { font-size: 11px; }
  html[lang="en"] .brand-name-en { font-size: 17px; }
}

/* ---- 我的拼豆：画廊版（两颗胶囊 + 整片大卡片） ---- */
.mine-topbar {
  grid-template-columns: 1fr auto 1fr;
}

.mine-topbar-spacer {
  display: block;
}

.mine-switch {
  align-items: center;
  align-self: center;
  background: rgba(255, 255, 255, 0.9);
  border: 1px solid #dce6ef;
  border-radius: 999px;
  display: inline-flex;
  gap: 4px;
  justify-self: center;
  padding: 4px;
}

.mine-switch button {
  align-items: center;
  background: transparent;
  border: 0;
  border-radius: 999px;
  color: #46566b;
  cursor: pointer;
  display: inline-flex;
  font-size: 14px;
  font-weight: 700;
  gap: 8px;
  min-height: 38px;
  padding: 0 18px;
  transition: background 140ms ease, color 140ms ease;
}

.mine-switch button:hover {
  color: #111820;
}

.mine-switch button.active {
  background: #111820;
  color: #ffffff;
}

.mine-switch em {
  background: rgba(17, 24, 32, 0.08);
  border-radius: 999px;
  font-size: 12px;
  font-style: normal;
  font-weight: 800;
  min-width: 22px;
  padding: 2px 7px;
  text-align: center;
}

.mine-switch button.active em {
  background: rgba(255, 255, 255, 0.22);
}

.mine-gallery {
  padding-bottom: 24px;
}

/* 作品图占满卡片，名字压在图片底部，按钮平时收着 */
/* 32px 是量出来的，不是拍的：列定义是 minmax(260px, 1fr)，间距跨过某个坎同样的
   屏幕就会少排一列。实测容器 1180 / 1290 / 1440 / 1600 / 1840 五档，18px（原值）
   和 32px 的列数完全一样；36px 在 1440（常见笔记本）会从 5 列掉到 4 列，48px 在
   1180 会从 4 列掉到 3 列。所以松到 32px 为止。 */
.mine-grid {
  display: grid;
  gap: 32px;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
}

.mine-card {
  background: #ffffff;
  border: 1px solid #dce6ef;
  border-radius: 14px;
  display: block;
  overflow: hidden;
  padding: 0;
  transition: box-shadow 160ms ease, transform 160ms ease;
}

.mine-card:hover {
  box-shadow: 0 14px 28px rgba(17, 24, 32, 0.16);
  transform: translateY(-2px);
}

/* 菜单开着的时候必须去掉这个位移。
   带 transform 的祖先会变成 position: fixed 后代的包含块——「⋯」的菜单是 fixed
   定位的，一旦卡片有 transform，它就改成相对卡片定位，然后被卡片的
   overflow: hidden 剪掉，只露出一条。PC 上用鼠标点「⋯」时卡片必然处于 hover，
   所以这是必现的；脚本点击不触发 :hover，本地测不出来。
   transition 也要一起去掉：过渡到 none 的中途 transform 仍是非 none 的。 */
.mine-card.is-menu-open,
.mine-card.is-menu-open:hover {
  transform: none;
  transition: box-shadow 160ms ease;
}

.mine-card-figure {
  aspect-ratio: 1 / 1;
  background: linear-gradient(160deg, #f4f7fa, #e7edf3);
  border-radius: 0;
  display: block;
  overflow: hidden;
  position: relative;
}

.mine-card-figure img,
.mine-card-figure canvas {
  display: block;
  height: 100%;
  object-fit: cover;
  width: 100%;
}

.mine-card-figure canvas {
  image-rendering: pixelated;
  object-fit: contain;
  padding: 10%;
}

.mine-card-body {
  background: linear-gradient(to top, rgba(8, 12, 18, 0.86), rgba(8, 12, 18, 0.52) 58%, rgba(8, 12, 18, 0));
  bottom: 0;
  display: grid;
  gap: 2px;
  left: 0;
  padding: 34px 14px 12px;
  position: absolute;
  right: 0;
}

.mine-card-body strong {
  color: #ffffff;
  font-size: 15px;
  font-weight: 800;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.mine-card-body span {
  color: rgba(255, 255, 255, 0.82);
  font-size: 12px;
}

.mine-card-body small {
  color: rgba(255, 255, 255, 0.58);
  font-size: 11px;
}

.mine-card-actions {
  background: rgba(8, 12, 18, 0.55);
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  inset: 0;
  justify-content: center;
  align-content: center;
  opacity: 0;
  padding: 14px;
  position: absolute;
  transition: opacity 160ms ease;
}

.mine-card:hover .mine-card-actions,
.mine-card:focus-within .mine-card-actions,
/* 菜单开着时也要撑住这一层：鼠标往菜单上移的路上一旦离开卡片，
   只靠 :hover 的话整层连同菜单一起消失。 */
.mine-card.is-menu-open .mine-card-actions {
  opacity: 1;
}

/* 手机没有悬停：按钮就一直摆在图片下沿 */
@media (hover: none) {
  .mine-card-actions {
    align-content: end;
    background: linear-gradient(to top, rgba(8, 12, 18, 0.8), rgba(8, 12, 18, 0) 46%);
    inset: auto 0 0 0;
    opacity: 1;
    padding: 10px;
  }
  .mine-card-body {
    padding-bottom: 52px;
  }
}

.mine-card-actions .mine-primary,
.mine-card-actions .mine-ghost {
  min-height: 34px;
  font-size: 13px;
}

.mine-card-actions .mine-ghost {
  background: rgba(255, 255, 255, 0.92);
}

/* ==========================================================================
   我的拼豆：搜索 / 多选 / 排列切换
   顶栏中段常驻三颗 40×40 的图标，右上角那一片（页签 + 去识别图纸）在选中 ≥ 1
   件时被批量操作顶掉，回到 0 件原样回来。
   ========================================================================== */

.mine-tools {
  align-items: center;
  display: inline-flex;
  flex: 0 0 auto;
  gap: 8px;
}

.mine-tool {
  align-items: center;
  background: #ffffff;
  border: 1.5px solid #111820;
  border-radius: 999px;
  box-shadow: 3px 3px 0 #111820;
  color: #111820;
  cursor: pointer;
  display: inline-flex;
  flex: 0 0 auto;
  height: 40px;
  justify-content: center;
  padding: 0;
  width: 40px;
}

.mine-tool svg {
  height: 17px;
  width: 17px;
}

/* 选择模式开着的时候这颗填黑，表示「再点一下退出」 */
.mine-tool[aria-pressed="true"] {
  background: #111820;
  color: #ffffff;
}

.mine-tool:hover {
  transform: translate(1px, 1px);
  box-shadow: 2px 2px 0 #111820;
}

/* 排列按钮上叠着两个图标，显示的是「点了会变成什么」 */
.mine-tool .icon-grid { display: none; }
body[data-mine-layout="list"] .mine-tool .icon-list { display: none; }
body[data-mine-layout="list"] .mine-tool .icon-grid { display: block; }

/* 搜索：点图标原地展成输入框 */
.mine-search {
  align-items: center;
  display: inline-flex;
  position: relative;
}

.mine-search.is-hidden { display: none; }

.mine-search > svg {
  color: #7d8b95;
  height: 16px;
  left: 12px;
  pointer-events: none;
  position: absolute;
  width: 16px;
}

.mine-search input {
  appearance: none;
  background: #ffffff;
  border: 1.5px solid #111820;
  border-radius: 999px;
  box-shadow: 3px 3px 0 #111820;
  color: #111820;
  font-size: 13px;
  font-weight: 600;
  height: 40px;
  padding: 0 34px;
  width: 226px;
}

.mine-search input::placeholder {
  color: #9aa7b0;
  font-weight: 500;
}

.mine-search-clear {
  background: #dfe6ea;
  border: 0;
  border-radius: 50%;
  color: #54636b;
  cursor: pointer;
  font-size: 11px;
  font-weight: 800;
  height: 18px;
  line-height: 18px;
  padding: 0;
  position: absolute;
  right: 11px;
  width: 18px;
}

/* 命中提示条 */
.mine-hits {
  align-items: center;
  color: #48565e;
  display: flex;
  font-size: 13px;
  font-weight: 600;
  gap: 8px;
  margin: 0 0 12px;
}

.mine-hits.is-hidden { display: none; }
.mine-hits b { color: #111820; }

.mine-hits button {
  background: none;
  border: 0;
  border-bottom: 1.5px solid #9ecbcd;
  color: #2f7f86;
  cursor: pointer;
  font-size: 13px;
  font-weight: 800;
  padding: 0;
}

/* 批量操作：顶掉右上角那一片 */
.mine-bulk {
  align-items: center;
  display: inline-flex;
  flex: 0 0 auto;
  gap: 9px;
}

.mine-bulk.is-hidden { display: none; }

.mine-bulk-count {
  color: #111820;
  font-size: 14px;
  font-weight: 800;
  white-space: nowrap;
}

.mine-bulk-count b { color: #2f7f86; }

.mine-bulk-btn {
  align-items: center;
  background: #ffffff;
  border: 1.5px solid #111820;
  border-radius: 999px;
  box-shadow: 3px 3px 0 #111820;
  color: #111820;
  cursor: pointer;
  display: inline-flex;
  font-size: 14px;
  font-weight: 800;
  gap: 6px;
  min-height: 42px;
  padding: 0 17px;
  white-space: nowrap;
}

.mine-bulk-btn svg { height: 15px; width: 15px; }
.mine-bulk-btn.is-teal { background: var(--teal, #2f7f86); color: #ffffff; }
.mine-bulk-btn.is-danger { background: #c8453f; color: #ffffff; }
.mine-bulk-btn:disabled { cursor: not-allowed; opacity: 0.5; }

.mine-bulk-btn:not(:disabled):hover {
  transform: translate(1px, 1px);
  box-shadow: 2px 2px 0 #111820;
}

/* 下载的下拉：逐张 / 打包 ZIP。
   往左展开（right: 0），因为这颗按钮贴着顶栏右边，往右展会顶出屏幕。 */
.mine-dd {
  display: inline-flex;
  position: relative;
}

.mine-dd-caret {
  font-size: 10px;
  margin-left: 1px;
}

.mine-dd-menu {
  background: #ffffff;
  border: 1.5px solid #111820;
  border-radius: 10px;
  box-shadow: 4px 4px 0 #111820;
  max-width: calc(100vw - 32px);
  padding: 5px;
  position: absolute;
  right: 0;
  top: calc(100% + 9px);
  width: 250px;
  z-index: 30;
}

.mine-dd-menu.is-hidden {
  display: none;
}

.mine-dd-menu button {
  align-items: flex-start;
  appearance: none;
  background: transparent;
  border: 0;
  border-radius: 7px;
  cursor: pointer;
  display: flex;
  gap: 9px;
  padding: 9px 10px;
  text-align: left;
  width: 100%;
}

.mine-dd-menu button:hover,
.mine-dd-menu button:focus-visible {
  background: #eaf3f3;
}

.mine-dd-menu svg {
  color: var(--teal, #2f7f86);
  flex: 0 0 auto;
  height: 16px;
  margin-top: 1px;
  width: 16px;
}

.mine-dd-menu b {
  color: #1d2929;
  display: block;
  font-size: 13px;
  font-weight: 800;
  line-height: 1.3;
}

.mine-dd-menu i {
  color: #8794a0;
  display: block;
  font-size: 11.5px;
  font-style: normal;
  font-weight: 600;
  line-height: 1.45;
  margin-top: 2px;
}

/* 删除框里的「同时从云端删除」 */
.mine-dialog-opt {
  align-items: flex-start;
  border-top: 1px solid #eef1f4;
  cursor: pointer;
  display: flex;
  gap: 10px;
  margin-top: 14px;
  padding-top: 14px;
  text-align: left;
}

.mine-dialog-opt.is-hidden {
  display: none;
}

.mine-dialog-opt input {
  accent-color: var(--teal, #2f7f86);
  flex: 0 0 auto;
  height: 17px;
  margin: 2px 0 0;
  width: 17px;
}

.mine-dialog-opt span {
  color: #48565e;
  font-size: 13px;
  font-weight: 600;
  line-height: 1.55;
}

.mine-dialog-opt i {
  color: #8794a0;
  display: block;
  font-size: 12px;
  font-style: normal;
  margin-top: 2px;
}

/* 卡片上的勾选圈 */
.mine-pick {
  align-items: center;
  background: rgba(17, 24, 32, 0.32);
  border: 2px solid #ffffff;
  border-radius: 50%;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
  display: flex;
  height: 22px;
  justify-content: center;
  left: 9px;
  padding: 0;
  position: absolute;
  top: 9px;
  width: 22px;
  z-index: 4;
}

.mine-pick svg { height: 12px; opacity: 0; width: 12px; color: #ffffff; }
.mine-card.is-picked .mine-pick { background: var(--teal, #2f7f86); }
.mine-card.is-picked .mine-pick svg { opacity: 1; }

.mine-card.is-picked {
  border-radius: 14px;
  outline: 2.5px solid var(--teal, #2f7f86);
  outline-offset: 2px;
}

body[data-mine-picking="1"] .mine-card { cursor: pointer; position: relative; }

/* 方格模式下选择时藏掉卡片上的操作层：那一层和「点卡片＝勾选」是冲突的。
   列表行够宽，两者能共存，所以只藏方格的。 */
body[data-mine-picking="1"][data-mine-layout="grid"] .mine-card-actions { display: none; }

/* 列表行里勾选圈排在缩略图左边，得在最前面插一列，后面每列跟着右移一格 */
body[data-mine-picking="1"] .mine-feed .mine-card .mine-pick {
  align-self: center;
  background: #dfe6ea;
  border-color: #dfe6ea;
  box-shadow: none;
  grid-column: 1;
  grid-row: 1;
  justify-self: center;
  position: static;
}

body[data-mine-picking="1"] .mine-feed .mine-card.is-picked .mine-pick {
  background: var(--teal, #2f7f86);
  border-color: var(--teal, #2f7f86);
}

body[data-mine-picking="1"] .mine-feed .mine-card-figure {
  grid-template-columns: 22px auto minmax(0, 1fr) auto auto;
}

body[data-mine-picking="1"] .mine-feed .mine-card-figure > img,
body[data-mine-picking="1"] .mine-feed .mine-card-figure > canvas { grid-column: 2; }
body[data-mine-picking="1"] .mine-feed .mine-card-body { grid-column: 3; }
body[data-mine-picking="1"] .mine-feed .mine-cloud { grid-column: 4; }
body[data-mine-picking="1"] .mine-feed .mine-card-actions { grid-column: 5; }

/* 宽屏切成列表时：缩略图放大到 76px。窄屏那套是 56px——手机上够用，
   但宽屏看烫后的纹理，56px 分不出雪花和豹纹。
   只作用在 data-mine-view="tabs"（宽屏）上，手机那套一个字不动。 */
body[data-mine-view="tabs"][data-mine-layout="list"] .mine-feed .mine-card-figure > img,
body[data-mine-view="tabs"][data-mine-layout="list"] .mine-feed .mine-card-figure > canvas {
  /* 224：用户要的，比 76 那版大三倍，行高跟着到 242。
     图源：已烫作品存的是 640px 宽的 JPEG，够；待烫图纸的 canvas 从 320 提到 480，
     不然 224 在视网膜屏上是 448 个物理像素，320 的画布会糊。 */
  height: 224px;
  width: 224px;
}

/* 光把图片改大没用：缩略图那一列是写死的 56px，图片再宽也被列宽卡住
   （实测会得到 56×76 的扁图）。列宽要跟着一起放。 */
body[data-mine-view="tabs"][data-mine-layout="list"] .mine-feed .mine-card-figure {
  grid-template-columns: 224px minmax(0, 1fr) auto auto;
}

/* 宽屏横条：勾选圈那一列给 34px、圈在列里居中，离卡片左边缘就有 15px，
   不贴着框。窄屏还是 22px 那套，地方紧。 */
body[data-mine-view="tabs"][data-mine-layout="list"][data-mine-picking="1"] .mine-feed .mine-card-figure {
  grid-template-columns: 34px 224px minmax(0, 1fr) auto auto;
}

/* 手机上那一组批量按钮排成一行是 432px，放不进 375px 的屏，会顶出横向滚动条。
   顶栏本身已经 flex-wrap，但这一组是一个整体，得让它自己也能折，并且收窄一档。 */
@media (max-width: 520px) {
  .mine-bulk {
    flex-wrap: wrap;
    gap: 6px;
    justify-content: flex-end;
    width: 100%;
  }

  .mine-bulk-count {
    font-size: 13px;
    margin-right: auto;
  }

  .mine-bulk-btn {
    box-shadow: 2px 2px 0 #111820;
    font-size: 13px;
    min-height: 36px;
    padding: 0 12px;
  }

  /* 三颗工具图标也跟着收一档，否则加上搜索框那一行会挤 */
  .mine-tool {
    box-shadow: 2px 2px 0 #111820;
    height: 36px;
    width: 36px;
  }

  .mine-search input {
    box-shadow: 2px 2px 0 #111820;
    height: 36px;
    width: min(56vw, 200px);
  }
}

/* ---- 我的拼豆 · 手机版：两个页签合成一条时间线 ----
   手机上原来是「已烫展示 / 未烫待加工」两个页签，各自一个空状态，空的时候
   两边都是 0，看不出区别；虚线空状态盒还写死了 48px 上下内边距，撑掉半屏。
   这里合成一条按时间倒序的列表：筛选降级成三颗胶囊，待烫的卡片带角标和
   「开始烫豆」直达按钮。卡片从方格改成横条，同样的高度能多看三四件。
   宽屏一行不受影响——所有规则都挂在 body[data-mine-view="feed"] 或 .mine-feed 下，
   这个标记只有窄屏的 render() 会打上。 */
.mine-filters {
  display: none;
  gap: 8px;
  margin-bottom: 12px;
}

.mine-filters button {
  background: #ffffff;
  border: 1px solid #dce6ef;
  border-radius: 999px;
  color: #5d6b7a;
  cursor: pointer;
  font-size: 13px;
  font-weight: 800;
  min-height: 34px;
  padding: 0 14px;
}

.mine-filters button.active {
  background: #1d2734;
  border-color: #1d2734;
  color: #ffffff;
}

.mine-filters em {
  font-style: normal;
  margin-left: 4px;
  opacity: 0.7;
}

.mine-feed {
  display: grid;
  gap: 16px;
}

body[data-mine-view="feed"] .mine-switch {
  display: none;
}

body[data-mine-view="feed"] .mine-filters {
  display: flex;
}

body[data-mine-view="feed"] .mine-empty {
  padding: 28px 18px;
}

/* 卡片横过来：缩略图 / 文字 / 云朵 / 操作，四列一行 */
.mine-feed .mine-card {
  border-radius: 12px;
  /* 竖版卡片靠 overflow: hidden 裁缩略图的圆角，横条不需要——缩略图自己有
     border-radius。这里必须放开，否则「⋯」的菜单一弹出来就被卡片裁掉：
     行高只有 74px，菜单 114px，怎么弹都在卡片外面。 */
  overflow: visible;
}

/* 菜单的位置由 mine.html 的 place() 用 position: fixed 现算（祖先里有两层
   overflow: hidden，absolute 定位怎么摆都会被剪掉）。这里只留层级。 */
.mine-feed .mine-more-menu {
  z-index: 6;
}

/* 光给菜单 z-index 不够：它上面几层全是 z-index: auto，实测下面两张卡片
   仍旧盖在它上面。把「正开着菜单的那张卡片」整个抬起来，菜单跟着一起上去。
   is-menu-open 是开菜单时 JS 挂在卡片上的类（见 mine.html 的 buildMoreMenu）。 */
.mine-feed .mine-card.is-menu-open {
  position: relative;
  z-index: 20;
}

.mine-feed .mine-card:hover {
  box-shadow: none;
  transform: none;
}

.mine-feed .mine-card-figure {
  align-items: center;
  aspect-ratio: auto;
  background: #ffffff;
  display: grid;
  gap: 10px;
  grid-template-columns: 56px minmax(0, 1fr) auto auto;
  /* 横条模式下这一层就是整行，它自带的 overflow: hidden 会把「⋯」的菜单
     齐着行的下边缘剪掉（行 74px，菜单 114px）。缩略图自己有圆角，这里不需要裁。 */
  overflow: visible;
  padding: 8px;
}

.mine-feed .mine-card-figure > img,
.mine-feed .mine-card-figure > canvas {
  background: linear-gradient(160deg, #f4f7fa, #e7edf3);
  border-radius: 8px;
  grid-column: 1;
  grid-row: 1;
  height: 56px;
  width: 56px;
}

.mine-feed .mine-card-figure > canvas {
  padding: 4px;
}

.mine-feed .mine-card-body {
  background: none;
  grid-column: 2;
  grid-row: 1;
  padding: 0;
  position: static;
}

.mine-feed .mine-card-body strong {
  color: #1d2734;
  font-size: 14px;
}

.mine-feed .mine-card-body span {
  color: #5d6b7a;
  font-size: 12px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.mine-feed .mine-card-body small {
  color: #8b98a6;
  font-size: 11px;
  overflow: hidden;
  text-overflow: ellipsis;
  /* 日期折成两行会把整条撑高，宁可截断 */
  white-space: nowrap;
}

.mine-feed .mine-cloud {
  box-shadow: none;
  grid-column: 3;
  grid-row: 1;
  position: static;
}

.mine-feed .mine-card-actions {
  background: none;
  flex-wrap: nowrap;
  grid-column: 4;
  grid-row: 1;
  inset: auto;
  opacity: 1;
  padding: 0;
  position: static;
}

.mine-feed .mine-card-actions .mine-primary {
  font-size: 12px;
  min-height: 34px;
  padding: 0 10px;
  white-space: nowrap;
}

/* 「⋯」在横条上不需要和主按钮一样宽 */
.mine-feed .mine-card-actions .mine-more-toggle {
  min-width: 0;
  padding: 0 8px;
}

/* 宽屏横条：缩略图放到 224 之后，14 / 12 / 11 的字和 34px 的按钮在旁边显得太小，
   整组放大一档。只作用在 data-mine-view="tabs"（宽屏）上，手机那套一个字不动。 */
body[data-mine-view="tabs"][data-mine-layout="list"] .mine-feed .mine-card-body {
  gap: 6px;
}

body[data-mine-view="tabs"][data-mine-layout="list"] .mine-feed .mine-card-body strong {
  font-size: 20px;
  line-height: 1.25;
}

body[data-mine-view="tabs"][data-mine-layout="list"] .mine-feed .mine-card-body span {
  font-size: 15px;
}

body[data-mine-view="tabs"][data-mine-layout="list"] .mine-feed .mine-card-body small {
  font-size: 13px;
}

body[data-mine-view="tabs"][data-mine-layout="list"] .mine-feed .mine-card-actions .mine-primary,
body[data-mine-view="tabs"][data-mine-layout="list"] .mine-feed .mine-card-actions .mine-more-toggle {
  font-size: 15px;
  min-height: 42px;
}

body[data-mine-view="tabs"][data-mine-layout="list"] .mine-feed .mine-card-actions .mine-primary {
  padding: 0 16px;
}

body[data-mine-view="tabs"][data-mine-layout="list"] .mine-feed .mine-card-actions .mine-more-toggle {
  font-size: 16px;
  min-width: 42px;
}

body[data-mine-view="tabs"][data-mine-layout="list"] .mine-feed .mine-cloud {
  height: 40px;
  width: 40px;
}

body[data-mine-view="tabs"][data-mine-layout="list"] .mine-feed .mine-cloud svg {
  height: 22px;
  width: 22px;
}

/* 待烫的角标：压在缩略图左上角，一眼区分两类 */
.mine-kind {
  background: #1d2734;
  border-radius: 999px;
  color: #ffffff;
  font-size: 10px;
  font-weight: 800;
  grid-column: 1;
  grid-row: 1;
  justify-self: start;
  align-self: start;
  margin: 3px;
  padding: 2px 6px;
}

/* ---- 选烫画机：一大两小，整页不滚动 ----
   左边大舞台只摆选中的那一样（整页一个 3D 画布），右边三张小卡切换。
   四块用 grid 区域摆：宽屏「舞台 | 小卡」两栏，手机上排成一列，小卡变成舞台下面的一排缩略图，
   「用这台烫」永远在最后。 */
.machine-page {
  overflow: hidden;
}

.machine-shell {
  display: flex;
  flex-direction: column;
  height: 100vh;
  height: 100dvh;
  max-width: 1280px;
  padding: 14px 22px 18px;
}

.machine-topbar {
  margin-bottom: 10px;
}

.machine-hero {
  flex: 0 0 auto;
  margin: 0 auto 10px;
}

.machine-hero h1 {
  font-family: "Noto Serif SC", "Songti SC", serif;
  font-weight: 900;
  margin-bottom: 4px;
}

.machine-hero p {
  margin: 0;
}

/* 没有图纸：一行字顶替标题下那行说明，不再是一张大卡 */
.machine-hero .machine-missing {
  align-items: baseline;
  background: rgba(255, 255, 255, 0.78);
  border: 1px solid #dce6ef;
  border-radius: 999px;
  box-shadow: none;
  color: #46566b;
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  font-size: 13px;
  gap: 4px 16px;
  justify-content: center;
  margin: 4px auto 0;
  max-width: none;
  padding: 6px 18px;
  width: fit-content;
}

.machine-hero .machine-missing.is-hidden {
  display: none;
}

.machine-hero .machine-missing strong {
  color: #111820;
  font-weight: 800;
}

/* 宽屏：舞台占满左边整个高度；右边一列上下居中放小卡和按钮 */
.machine-picker {
  display: grid;
  flex: 1 1 auto;
  gap: 14px 26px;
  grid-template-areas:
    "view ."
    "view tiles"
    "view choose"
    "view .";
  grid-template-columns: minmax(0, 1fr) 300px;
  grid-template-rows: minmax(0, 1fr) auto auto minmax(0, 1fr);
  min-height: 0;
}

.machine-picker .machine-view {
  aspect-ratio: auto;
  background: transparent;
  border: 0;
  border-radius: 16px;
  grid-area: view;
  min-height: 0;
  overflow: hidden;
}

.machine-picker .machine-view canvas {
  transition: opacity 220ms ease;
}

/* 模型还没摆上台时画布先藏着，舞台正中只有「正在搬出机器… 43%」；摆上台以后画布淡入。
   以前这段时间先亮一张静态截图，它和 3D 模型的大小、位置、角度都对不上，模型一出来就像跳了一下。 */
.machine-view.is-loading canvas {
  opacity: 0;
}

/* 位置用 .machine-loading 本来的：舞台正中 */
.machine-picker .machine-loading {
  background: rgba(255, 255, 255, 0.86);
  border-radius: 999px;
  padding: 6px 14px;
}

/* 宽屏上不显示：同样的字在小卡里（见 .machine-tile em）。手机版才用它 */
.machine-info {
  display: none;
  grid-area: info;
  text-align: center;
}

.machine-info h2 {
  font-family: "Noto Serif SC", "Songti SC", serif;
  font-size: 24px;
  font-weight: 900;
  margin: 4px 0;
}

.machine-info p {
  color: #46566b;
  display: grid;
  font-size: 13px;
  gap: 2px;
  margin: 0;
}

.machine-info p span {
  color: #8494a7;
  font-size: 12px;
}

.machine-picker > .machine-choose {
  grid-area: choose;
  justify-self: stretch;
  margin: 0;
}

.machine-tiles {
  display: flex;
  flex-direction: column;
  gap: 12px;
  grid-area: tiles;
}

.machine-tile {
  align-items: center;
  background: rgba(255, 255, 255, 0.72);
  border: 1.5px solid #dce6ef;
  border-radius: 14px;
  color: #111820;
  cursor: pointer;
  display: flex;
  font: inherit;
  gap: 12px;
  padding: 10px 12px;
  text-align: left;
  transition: background 160ms ease, border-color 160ms ease, box-shadow 160ms ease, transform 160ms ease;
}

.machine-tile:hover {
  background: #ffffff;
  border-color: rgba(17, 24, 32, 0.45);
}

.machine-tile:focus-visible {
  outline: 2px solid var(--teal, #2f7f86);
  outline-offset: 3px;
}

.machine-tile.is-on {
  background: #ffffff;
  border-color: #111820;
  box-shadow: 3px 3px 0 #111820;
}

.machine-tile img {
  flex: 0 0 88px;
  height: 68px;
  object-fit: contain;
  width: 88px;
}

.machine-tile span {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.machine-tile b {
  font-family: "Noto Serif SC", "Songti SC", serif;
  font-size: 16px;
  font-weight: 900;
  line-height: 1.3;
  margin: 0 0 2px;
}

.machine-tile i,
.machine-tile em {
  color: #8494a7;
  font-size: 12px;
  font-style: normal;
  font-weight: 600;
  line-height: 1.4;
}

.machine-tile em {
  color: #46566b;
  margin-top: 1px;
}

/* ---- 选烫画机 · 手机版：舞台在上，三张小卡排成一行缩略图，按钮垫底 ---- */
@media (max-width: 860px) {
  .machine-shell {
    padding: 12px 16px 12px;
  }

  .machine-hero p {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    overflow: hidden;
  }

  .machine-picker {
    gap: 8px;
    grid-template-areas:
      "view"
      "info"
      "tiles"
      "choose";
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: minmax(150px, 1fr) auto auto auto;
  }

  .machine-info {
    display: block;
  }

  .machine-info h2 {
    font-size: 20px;
  }

  /* 默认参数那行在手机上让位给机器图，进了工坊一样看得到 */
  .machine-info p span {
    display: none;
  }

  .machine-tiles {
    display: grid;
    gap: 8px;
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .machine-tile {
    border-radius: 12px;
    flex-direction: column;
    gap: 2px;
    padding: 6px 4px 7px;
    text-align: center;
  }

  .machine-tile.is-on {
    box-shadow: 2px 2px 0 #111820;
  }

  .machine-tile img {
    flex: 0 0 auto;
    height: 42px;
    width: 100%;
  }

  .machine-tile span {
    align-items: center;
  }

  .machine-tile i,
  .machine-tile em {
    display: none;
  }

  .machine-tile b {
    font-size: 12px;
    margin: 0;
  }

  .machine-picker > .machine-choose {
    width: 100%;
  }

  .machine-hero .machine-missing {
    border-radius: 14px;
    font-size: 12px;
    gap: 2px 12px;
    padding: 5px 12px;
  }
}

/* ---- 预览页：保存按钮的气泡提示 ---- */
.cyber-stage-cta [data-tip],
.cyber-birth-buttons [data-tip] {
  position: relative;
}

.cyber-stage-cta [data-tip]::after,
.cyber-birth-buttons [data-tip]::after {
  background: #111820;
  border-radius: 8px;
  bottom: calc(100% + 8px);
  color: #ffffff;
  content: attr(data-tip);
  font-size: 12px;
  font-weight: 600;
  left: 50%;
  opacity: 0;
  padding: 6px 10px;
  pointer-events: none;
  position: absolute;
  transform: translate(-50%, 4px);
  transition: opacity 140ms ease, transform 140ms ease;
  white-space: nowrap;
  z-index: 40;
}

.cyber-stage-cta [data-tip]:hover::after,
.cyber-stage-cta [data-tip]:focus-visible::after,
.cyber-birth-buttons [data-tip]:hover::after,
.cyber-birth-buttons [data-tip]:focus-visible::after {
  opacity: 1;
  transform: translate(-50%, 0);
}

/* ---- 诞生页按钮：保存 / 换烫法 / 去我的拼豆 ---- */
.cyber-birth-link {
  align-items: center;
  color: #46566b;
  display: inline-flex;
  font-size: 13px;
  font-weight: 700;
  min-height: 46px;
  padding: 0 10px;
  text-decoration: none;
  text-underline-offset: 3px;
}

.cyber-birth-link:hover {
  color: #111820;
  text-decoration: underline;
}

.cyber-birth-primary[disabled] {
  cursor: default;
  opacity: 0.7;
}

/* ---- 工坊里的声音开关：跟退出按钮同一套外形，叠在它下面 ---- */
.cyber-workshop-sound {
  /* 描边、投影、文字共用这一个颜色，静音时整颗按钮一起变灰（见下面的
     [aria-pressed="false"]），不用把三处各改一遍 */
  --sound-ink: #111820;
  background: #ffffff;
  border: 1.5px solid var(--sound-ink);
  border-radius: 999px;
  box-shadow: 3px 3px 0 var(--sound-ink);
  color: var(--sound-ink);
  cursor: pointer;
  font-size: 13px;
  font-weight: 800;
  left: 18px;
  min-height: 38px;
  padding: 0 16px;
  position: absolute;
  top: 66px;
  z-index: 6;
}

/* 375px 上这颗按钮（left 18 / 宽 92）正好压在 Load/Start/Heat/Eject 那条
   居中的步骤带左端（x 81 起）上，「Load」被盖掉一半。窄屏只留喇叭，
   收成一颗 38px 的圆钮，右边界退到 56，步骤带就露出来了。 */
@media (max-width: 520px) {
  .cyber-workshop-sound {
    align-items: center;
    display: inline-flex;
    justify-content: center;
    min-width: 38px;
    padding: 0;
  }

  .cyber-workshop-sound-label {
    display: none;
  }
}

/* :active 和 :hover 一起写：触屏没有 hover，手指按下去也得看见按钮陷下去，
   否则点完没动静会以为没点中 */
.cyber-workshop-sound:hover,
.cyber-workshop-sound:active {
  box-shadow: 1px 1px 0 var(--sound-ink);
  transform: translate(2px, 2px);
}

/* 声音默认是开的（cyber-sound.js：localStorage 没值就当开），点一下关掉。
   窄屏上按钮只剩一个喇叭 emoji，而 emoji 不吃 color——光改文字色看不出
   开关，所以静音时整颗按钮变灰底灰边，再把喇叭本身去色。 */
.cyber-workshop-sound[aria-pressed="false"] {
  --sound-ink: #8494a7;
  background: #eef1f4;
}

.cyber-workshop-sound[aria-pressed="false"] span[aria-hidden="true"] {
  filter: grayscale(1);
  opacity: 0.6;
}

/* ---- 覆盖 / 保存新烫法 的询问框 ---- */
.cyber-ask {
  align-items: center;
  background: rgba(10, 14, 20, 0.56);
  display: flex;
  inset: 0;
  justify-content: center;
  padding: 20px;
  position: fixed;
  z-index: 120;
}

.cyber-ask.is-hidden {
  display: none;
}

.cyber-ask-card {
  background: #ffffff;
  border: 1.5px solid #111820;
  border-radius: 16px;
  box-shadow: 8px 8px 0 rgba(17, 24, 32, 0.9);
  max-width: 440px;
  padding: 22px 22px 18px;
  position: relative;
  width: 100%;
}

.cyber-ask-card small {
  color: var(--teal, #2f7f86);
  display: block;
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.3em;
  margin-bottom: 8px;
}

/* 只有「已经存过」那种情况才显示（见 cyber.html 的 askSave）；上面那条 display: block 会压过 hidden 属性 */
.cyber-ask-card small[hidden] {
  display: none;
}

.cyber-ask-card h3 {
  font-family: "Noto Serif SC", "Songti SC", serif;
  font-size: 19px;
  font-weight: 900;
  margin: 0 0 8px;
}

.cyber-ask-card p {
  color: #46566b;
  font-size: 14px;
  line-height: 1.6;
  margin: 0 0 18px;
}

.cyber-ask-buttons {
  display: flex;
  gap: 10px;
  justify-content: flex-end;
}

.cyber-ask-primary,
.cyber-ask-secondary {
  border-radius: 999px;
  cursor: pointer;
  font-size: 14px;
  font-weight: 800;
  min-height: 42px;
  padding: 0 20px;
}

.cyber-ask-primary {
  background: #111820;
  border: 1.5px solid #111820;
  color: #ffffff;
}

.cyber-ask-secondary {
  background: #ffffff;
  border: 1.5px solid #111820;
  color: #111820;
}

.cyber-ask-primary:hover,
.cyber-ask-secondary:hover {
  transform: translateY(1px);
}

/* 命名框里的「另存为 / 覆盖」 */
.cyber-ask-how {
  margin: 0 0 16px;
}
.cyber-ask-how.is-hidden {
  display: none;
}
.cyber-ask-radio {
  align-items: flex-start;
  cursor: pointer;
  display: flex;
  gap: 9px;
  padding: 8px 0;
}
/* 全局那条 `input, select` 会给所有 input 塞背景、边框、圆角、内边距和
   focus 光晕（styles.css 里靠前的位置），单选框被它套成一个圆角方块，
   选中时还顶着一圈青色光晕。这里把那些逐条撤掉，只留原生的圆点。 */
.cyber-ask-radio input {
  accent-color: var(--teal, #2f7f86);
  background: transparent;
  border: 0;
  border-radius: 0;
  flex: 0 0 auto;
  height: 17px;
  margin: 2px 0 0;
  min-height: 0;
  padding: 0;
  width: 17px;
}
.cyber-ask-radio input:focus {
  border-color: transparent;
  box-shadow: none;
}
/* 键盘走到它身上还是要看得见 */
.cyber-ask-radio input:focus-visible {
  outline: 2px solid var(--teal, #2f7f86);
  outline-offset: 2px;
}
.cyber-ask-radio span {
  color: #46566b;
  font-size: 13px;
  font-weight: 600;
  line-height: 1.5;
}
.cyber-ask-radio span b {
  color: #111820;
  font-weight: 800;
}
.cyber-ask-radio span i {
  color: #8494a7;
  display: block;
  font-size: 11.5px;
  font-style: normal;
  margin-top: 2px;
}

/* 名字输入 */
.cyber-ask-field {
  margin: 0 0 16px;
}
.cyber-ask-field label {
  color: #46566b;
  display: block;
  font-size: 12px;
  font-weight: 800;
  margin: 0 0 7px;
}
/* 没有边框，靠浅灰底把输入区划出来。
   原来是黑框 + 3px 硬阴影（站里按钮那一套），放在白底弹框里太重。 */
.cyber-ask-input {
  align-items: center;
  background: #f1f5f8;
  border: 0;
  border-radius: 10px;
  display: flex;
  gap: 8px;
  padding: 0 14px;
}
.cyber-ask-input:focus-within {
  background: #ffffff;
  box-shadow: 0 0 0 2px var(--teal, #2f7f86);
}
/* 到顶了：描边和计数一起变红，光看数字容易漏 */
.cyber-ask-input.is-full {
  box-shadow: 0 0 0 2px #c8453f;
}
.cyber-ask-input input {
  background: transparent;
  border: 0;
  border-radius: 0;
  padding: 0;
  color: #111820;
  flex: 1;
  font-size: 16px;
  font-weight: 700;
  min-height: 46px;
  min-width: 0;
  outline: 0;
}
/* 全站的 input:focus 会给输入框加一圈 3px 浅青光晕。这里聚焦的描边画在外面那层
   .cyber-ask-input 上，里面的 input 再套一圈：上下被外框盖住，只剩左右两条竖条露在
   输入区的两头（左边贴着框、右边贴着 0/10），很难看。里面这圈关掉，只留外框。 */
.cyber-ask-input input:focus {
  box-shadow: none;
}

.cyber-ask-input input::placeholder {
  color: #b3c0cc;
  font-weight: 600;
}
.cyber-ask-count {
  color: #8494a7;
  flex: 0 0 auto;
  font-size: 12px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.cyber-ask-input.is-full .cyber-ask-count {
  color: #c8453f;
}

.cyber-ask-buttons {
  align-items: center;
}
/* 「跳过」靠左，和右边那两颗拉开 */
.cyber-ask-skip {
  background: none;
  border: 0;
  color: #8494a7;
  cursor: pointer;
  font-size: 13px;
  font-weight: 700;
  margin-right: auto;
  padding: 6px 2px;
  text-decoration: underline;
}
.cyber-ask-skip.is-hidden {
  display: none;
}
/* 覆盖会抹掉一版，按钮给红 */
.cyber-ask-primary.is-danger {
  background: #c8453f;
  border-color: #c8453f;
}

.cyber-ask-close {
  background: transparent;
  border: 0;
  color: #8494a7;
  cursor: pointer;
  font-size: 16px;
  line-height: 1;
  padding: 6px;
  position: absolute;
  right: 10px;
  top: 10px;
}

.cyber-ask-close:hover {
  color: #111820;
}

.mine-back {
  justify-self: start;
}

/* 落地页顶栏是深色的：双色字标的前半截换成金色，后半截照旧青色 */
.landing-topbar .brand-name .brand-a {
  color: #f2c14e;
}

/* 「已烫 / 未烫」两边条目数不一样多，滚动条一出一收会把整页横向推 7~15px，
   顶栏和中间那两颗胶囊就跟着跳。一直给滚动条留着位置，切换时就不动了。 */
.mine-page {
  overflow-y: scroll;
  scrollbar-gutter: stable;
}

/* 顶栏改成像首页那样的通栏：贴着页面最上沿、左右拉满、滚动时钉在原地。
   负的外边距是用来抵消 .mine-shell 那 18px 内边距的，不然做不到通栏。 */
.mine-topbar {
  background: rgba(253, 252, 247, 0.92);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: 0;
  border-bottom: 1px solid #dce6ef;
  border-radius: 0;
  margin: -18px -18px 0;
  min-height: 66px;
  padding: 8px clamp(16px, 4vw, 40px);
  position: sticky;
  top: 0;
  z-index: 20;
}

.mine-shell {
  padding-top: 0;
}

@media (max-width: 640px) {
  .mine-topbar {
    margin: -18px -18px 0;
    padding: 8px 14px;
  }
}

/* ============================================================
   我的拼豆 · 画廊页头版（方案 B）
   顶栏压薄只留返回和站名；标题左对齐单独成一块，切换和主动作靠右；
   作品名从图片上挪到图片下面的实心条里，图上不再压任何东西。
   ============================================================ */
.mine-topbar {
  display: flex;
  align-items: center;
  gap: 14px;
  min-height: 56px;
  padding: 6px clamp(16px, 4vw, 40px);
}

.mine-topbar-brand {
  align-items: center;
  display: inline-flex;
  gap: 10px;
  text-decoration: none;
}

.mine-topbar-brand .brand-iron-logo {
  height: 20px;
  width: auto;
}

.mine-topbar .brand-name-zh {
  font-size: 18px;
}

.mine-topbar .brand-name-en {
  font-size: 11px;
}

/* 胶囊不再居中，跟着页头靠右 */
.mine-switch {
  align-self: auto;
  justify-self: auto;
}

.mine-new {
  align-items: center;
  background: var(--teal, #2f7f86);
  border: 1.5px solid #111820;
  border-radius: 999px;
  box-shadow: 3px 3px 0 #111820;
  color: #ffffff;
  display: inline-flex;
  font-size: 14px;
  font-weight: 800;
  min-height: 42px;
  padding: 0 18px;
  text-decoration: none;
}

.mine-new:hover {
  box-shadow: 1px 1px 0 #111820;
  transform: translate(2px, 2px);
}

/* 卡片放大，一行少一点，每件看得更仔细 */
.mine-grid {
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
}

/* 名字挪到图下面：实心白条，深色作品也不会把字糊掉 */
.mine-card-body {
  background: transparent;
  bottom: auto;
  color: inherit;
  display: grid;
  gap: 1px;
  left: auto;
  padding: 11px 13px 13px;
  position: static;
  right: auto;
  border-top: 1px solid #dce6ef;
}

.mine-card-body strong {
  color: #111820;
  font-size: 15px;
}

.mine-card-body span {
  color: #46566b;
  font-size: 13px;
}

.mine-card-body small {
  color: #8494a7;
  font-size: 11px;
}

/* 悬停时按钮浮在图片上，信息条不受影响 */
@media (hover: none) {
  .mine-card-actions {
    align-content: center;
    background: rgba(8, 12, 18, 0.45);
    inset: 0;
    padding: 14px;
  }
  .mine-card-body {
    padding-bottom: 13px;
  }
}

/* .mine-shell 是 grid 又带 min-height:100vh，条目少的时候（比如待加工是空的）
   行会被拉开把顶栏撑高。行按内容高度排，多出来的空间留在底部。 */
.mine-shell {
  align-content: start;
}

/* 四颗按钮排一行：原来「删除」带着 margin-left:auto 被推到最右，
   加上 flex-wrap 就会被挤到第二行。这里改成不换行、按钮挨在一起。 */
.mine-card-actions {
  /* 不换行之后 align-content 就不起作用了，得用 align-items 压住高度，
     不然按钮会被拉成和整张图一样高的竖条。 */
  align-items: center;
  flex-wrap: nowrap;
  gap: 6px;
  justify-content: center;
  padding: 12px 10px;
}

.mine-card-actions .mine-primary,
.mine-card-actions .mine-ghost {
  flex: 0 0 auto;
  font-size: 12px;
  min-height: 32px;
  padding: 0 10px;
  white-space: nowrap;
}

.mine-card-actions .mine-danger {
  margin-left: 0;
}

/* ============================================================
   我的拼豆 · 方案 A：胶囊收进固定顶栏，一条通栏管到底
   页头整块去掉，说明那行也去掉，作品网格直接顶上来。
   （这一段写在方案 B 后面，把 B 里只属于页头的规则盖回去）
   ============================================================ */
.mine-topbar {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  gap: 10px 14px;
  min-height: 64px;
  padding: 8px clamp(14px, 3vw, 32px);
}

.mine-topbar-brand {
  align-items: center;
  display: inline-flex;
  gap: 10px;
}

.mine-topbar-brand h1 {
  font-family: "Noto Serif SC", "Songti SC", serif;
  font-size: 20px;
  font-weight: 900;
  letter-spacing: 0.02em;
  margin: 0;
  white-space: nowrap;
}

.mine-topbar-brand .brand-iron-logo {
  height: 22px;
  width: auto;
}

/* PC 上 logo 后面跟的是页名，站名收着；窄屏反过来（见下面 720px 那一段） */
.mine-topbar-sitename {
  display: none;
}

.mine-topbar-spacer {
  display: block;
  flex: 1 1 auto;
}

.mine-topbar .mine-switch {
  flex: 0 0 auto;
  padding: 3px;
}

.mine-topbar .mine-switch button {
  font-size: 13px;
  min-height: 34px;
  padding: 0 14px;
}

.mine-topbar .mine-new {
  flex: 0 0 auto;
  font-size: 13px;
  min-height: 36px;
  padding: 0 14px;
}

/* 作品网格紧跟在顶栏下面 */
.mine-gallery {
  /* 第一张卡离吸顶栏得留够地方：选中态的绿框是 outline 2.5px 再往外偏 2px，
     总共往外探 4.5px。原来只留 2px，第一张卡一选中，绿框顶上那一段就压在
     吸顶栏（z-index 20）底下，看着像没画完。12px 够它露全，也不至于空一截。 */
  padding-top: 12px;
}

/* 名字回到图片上：A 的卡片是整张图，标题压在底部的渐变里 */
.mine-grid {
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
}

.mine-card-body {
  background: linear-gradient(to top, rgba(8, 12, 18, 0.86), rgba(8, 12, 18, 0.52) 58%, rgba(8, 12, 18, 0));
  border-top: 0;
  bottom: 0;
  display: grid;
  gap: 2px;
  left: 0;
  padding: 34px 14px 12px;
  position: absolute;
  right: 0;
}

.mine-card-body strong {
  color: #ffffff;
  font-size: 15px;
}

.mine-card-body span {
  color: rgba(255, 255, 255, 0.82);
  font-size: 12px;
}

.mine-card-body small {
  color: rgba(255, 255, 255, 0.58);
  font-size: 11px;
}

@media (hover: none) {
  .mine-card-actions {
    align-content: end;
    align-items: center;
    background: linear-gradient(to top, rgba(8, 12, 18, 0.8), rgba(8, 12, 18, 0) 46%);
    inset: auto 0 0 0;
    opacity: 1;
    padding: 10px;
  }
  .mine-card-body {
    padding-bottom: 52px;
  }
}

/* 窄屏：顶栏东西多，logo 后面只留站名（页名让位），胶囊换行到第二排 */
@media (max-width: 720px) {
  .mine-topbar-brand h1 {
    display: none;
  }
  .mine-topbar-sitename {
    display: inline-flex;
  }
  .mine-topbar-sitename .brand-name .brand-name-zh,
  .mine-topbar-sitename .brand-name .brand-name-en {
    font-size: 17px;
  }
  .mine-topbar-spacer {
    display: none;
  }
  .mine-topbar .mine-switch {
    order: 3;
    width: 100%;
    justify-content: center;
  }
  .mine-topbar .mine-new {
    margin-left: auto;
  }
}

/* ---------------------------------------------------------------
   我的拼豆的两个弹窗：重命名 / 删除
   外形跟烫豆页那个「覆盖还是另存」的询问框一套，硬阴影 + 描边。
   --------------------------------------------------------------- */
.mine-dialog {
  align-items: center;
  background: rgba(10, 14, 20, 0.52);
  display: flex;
  inset: 0;
  justify-content: center;
  padding: 20px;
  position: fixed;
  z-index: 200;
}

.mine-dialog.is-hidden {
  display: none;
}

.mine-dialog-card {
  background: #ffffff;
  border: 1.5px solid #111820;
  border-radius: 16px;
  box-shadow: 8px 8px 0 rgba(17, 24, 32, 0.9);
  max-width: 400px;
  padding: 22px 22px 18px;
  position: relative;
  width: 100%;
}

.mine-dialog-card h3 {
  font-family: "Noto Serif SC", "Songti SC", serif;
  font-size: 19px;
  font-weight: 900;
  margin: 0 0 8px;
}

.mine-dialog-card p {
  color: #46566b;
  font-size: 14px;
  line-height: 1.6;
  margin: 0 0 16px;
}

.mine-dialog-input {
  background: #fdfcf7;
  border: 1.5px solid #111820;
  border-radius: 10px;
  box-sizing: border-box;
  color: #111820;
  display: block;
  font-family: inherit;
  font-size: 15px;
  margin-bottom: 18px;
  min-height: 44px;
  padding: 0 14px;
  width: 100%;
}

.mine-dialog-input:focus {
  outline: 2px solid var(--teal, #2f7f86);
  outline-offset: 2px;
}

.mine-dialog-buttons {
  display: flex;
  gap: 10px;
  justify-content: flex-end;
}

.mine-dialog-primary,
.mine-dialog-ghost,
.mine-dialog-danger {
  border-radius: 999px;
  cursor: pointer;
  font-family: inherit;
  font-size: 14px;
  font-weight: 800;
  min-height: 42px;
  padding: 0 20px;
}

.mine-dialog-primary {
  background: #111820;
  border: 1.5px solid #111820;
  color: #ffffff;
}

.mine-dialog-ghost {
  background: #ffffff;
  border: 1.5px solid #111820;
  color: #111820;
}

.mine-dialog-danger {
  background: #c8402f;
  border: 1.5px solid #111820;
  color: #ffffff;
}

.mine-dialog-primary:hover,
.mine-dialog-ghost:hover,
.mine-dialog-danger:hover {
  transform: translateY(1px);
}

.mine-dialog-close {
  background: transparent;
  border: 0;
  color: #8494a7;
  cursor: pointer;
  font-size: 16px;
  line-height: 1;
  padding: 6px;
  position: absolute;
  right: 10px;
  top: 10px;
}

.mine-dialog-close:hover {
  color: #111820;
}

/* 「跳过烫豆动画」这个弹窗右上角的关闭按钮。
   .bead-prompt 是 grid，按钮得脱离文档流，不然会自己占一行。 */
.bead-prompt {
  position: relative;
}

.bead-prompt-close {
  background: transparent;
  border: 0;
  border-radius: 8px;
  color: #8494a7;
  cursor: pointer;
  font-size: 15px;
  line-height: 1;
  padding: 7px;
  position: absolute;
  right: 8px;
  top: 8px;
}

.bead-prompt-close:hover {
  background: rgba(17, 24, 32, 0.06);
  color: #111820;
}

.bead-prompt-close:focus-visible {
  outline: 2px solid #008d86;
  outline-offset: 2px;
}

/* 「这一步请用电脑打开」那张卡的关闭按钮，和烫豆提示框的 ✕ 一套 */
.narrow-notice-card {
  position: relative;
}

.narrow-notice-close {
  background: transparent;
  border: 0;
  border-radius: 8px;
  color: #8494a7;
  cursor: pointer;
  font-size: 15px;
  line-height: 1;
  padding: 7px;
  position: absolute;
  right: 8px;
  top: 8px;
}

.narrow-notice-close:hover {
  background: rgba(17, 24, 32, 0.06);
  color: #111820;
}

.narrow-notice-close:focus-visible {
  outline: 2px solid #008d86;
  outline-offset: 2px;
}

/* ============================================================
   赛博烫豆自己的登录入口和登录 / 注册弹窗
   （首页顶栏那个 landingAccountNavMenu 是 gogopixelbeads 带过来的，一直关着，
     这一套和它没有关系，样式也另起了一组类名）
   ============================================================ */
.cyber-account-nav {
  position: relative;
}

.cyber-account-button {
  background: rgba(255, 255, 255, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.24);
  border-radius: 999px;
  color: #fdfcf7;
  cursor: pointer;
  font-family: inherit;
  font-size: 13px;
  font-weight: 700;
  max-width: 160px;
  min-height: 36px;
  overflow: hidden;
  padding: 0 16px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.cyber-account-button:hover {
  background: rgba(255, 255, 255, 0.18);
}

.cyber-account-button.is-signed {
  background: rgba(242, 193, 78, 0.16);
  border-color: rgba(242, 193, 78, 0.5);
  color: #f2c14e;
}

.cyber-account-menu {
  background: #ffffff;
  border: 1px solid #dce6ef;
  border-radius: 12px;
  box-shadow: 0 18px 44px rgba(8, 12, 18, 0.28);
  display: grid;
  gap: 2px;
  min-width: 206px;
  padding: 10px;
  position: absolute;
  right: 0;
  top: calc(100% + 8px);
  z-index: 60;
}

.cyber-account-menu.is-hidden {
  display: none;
}

.cyber-account-who {
  display: grid;
  gap: 1px;
  padding: 4px 8px 8px;
}

.cyber-account-who strong {
  font-size: 14px;
}

.cyber-account-who small {
  color: #6b7c91;
  font-size: 12px;
  overflow: hidden;
  text-overflow: ellipsis;
}

.cyber-account-state {
  border-top: 1px solid #eef3f7;
  color: #2f7f86;
  font-size: 12px;
  padding: 8px 8px 6px;
}

.cyber-account-item {
  background: transparent;
  border: 0;
  border-radius: 8px;
  color: #253142;
  cursor: pointer;
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  padding: 9px 8px;
  text-align: left;
  text-decoration: none;
}

.cyber-account-item:hover {
  background: #f2f6fa;
}

/* ---------- 登录 / 注册弹窗 ---------- */
.cyber-auth {
  align-items: center;
  background: rgba(8, 10, 14, 0.6);
  display: flex;
  inset: 0;
  justify-content: center;
  padding: 20px;
  position: fixed;
  z-index: 500;
}

.cyber-auth.is-hidden {
  display: none;
}

.cyber-auth-card {
  background: #ffffff;
  border: 1.5px solid #111820;
  border-radius: 16px;
  box-shadow: 8px 8px 0 rgba(17, 24, 32, 0.9);
  max-width: 400px;
  padding: 24px 24px 20px;
  position: relative;
  width: 100%;
}

.cyber-auth-card small {
  color: #2f7f86;
  display: block;
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.26em;
  margin-bottom: 8px;
}

.cyber-auth-card h3 {
  font-family: "Noto Serif SC", "Songti SC", serif;
  font-size: 21px;
  font-weight: 900;
  margin: 0 0 8px;
}

.cyber-auth-card > p {
  color: #46566b;
  font-size: 13px;
  line-height: 1.65;
  margin: 0 0 16px;
}

.cyber-auth-tabs {
  background: #f2f6fa;
  border-radius: 999px;
  display: flex;
  gap: 4px;
  margin-bottom: 16px;
  padding: 4px;
}

.cyber-auth-tabs button {
  background: transparent;
  border: 0;
  border-radius: 999px;
  color: #46566b;
  cursor: pointer;
  flex: 1 1 0;
  font-family: inherit;
  font-size: 14px;
  font-weight: 700;
  min-height: 36px;
}

.cyber-auth-tabs button.active {
  background: #111820;
  color: #ffffff;
}

.cyber-auth-card form {
  display: grid;
  gap: 6px;
}

.cyber-auth-card label {
  color: #46566b;
  font-size: 12px;
  font-weight: 700;
}

.cyber-auth-card input {
  background: #fdfcf7;
  border: 1.5px solid #111820;
  border-radius: 10px;
  box-sizing: border-box;
  color: #111820;
  font-family: inherit;
  font-size: 15px;
  margin-bottom: 8px;
  min-height: 44px;
  padding: 0 14px;
  width: 100%;
}

.cyber-auth-card input:focus {
  outline: 2px solid #2f7f86;
  outline-offset: 2px;
}

.cyber-auth-error {
  background: #fdecea;
  border-radius: 8px;
  color: #b3261e;
  font-size: 13px;
  margin: 0 0 10px;
  padding: 8px 10px;
}

.cyber-auth-submit {
  background: #111820;
  border: 1.5px solid #111820;
  border-radius: 999px;
  color: #ffffff;
  cursor: pointer;
  font-family: inherit;
  font-size: 15px;
  font-weight: 800;
  min-height: 46px;
  margin-top: 4px;
}

.cyber-auth-submit:disabled {
  cursor: default;
  opacity: 0.6;
}

.cyber-auth-close {
  background: transparent;
  border: 0;
  border-radius: 8px;
  color: #8494a7;
  cursor: pointer;
  font-size: 15px;
  line-height: 1;
  padding: 7px;
  position: absolute;
  right: 10px;
  top: 10px;
}

.cyber-auth-close:hover {
  background: rgba(17, 24, 32, 0.06);
  color: #111820;
}

.machine-topbar .cyber-lang-toggle {
  justify-self: end;
  margin-left: 8px;
}

/* ============================================================
   云端名额：卡片右上角那朵云 + 顶栏的 x/10
   没登录时这两样都不出现——那时候「云」这件事还不存在。
   ============================================================ */
.mine-cloud {
  align-items: center;
  background: rgba(255, 255, 255, 0.94);
  border: 0;
  border-radius: 999px;
  box-shadow: 0 2px 8px rgba(8, 12, 18, 0.24);
  cursor: pointer;
  display: inline-flex;
  height: 30px;
  justify-content: center;
  padding: 0;
  position: absolute;
  right: 8px;
  top: 8px;
  transition: transform 120ms ease;
  width: 30px;
  z-index: 3;
}

.mine-cloud svg {
  height: 17px;
  width: 17px;
}

.mine-cloud:hover {
  transform: scale(1.08);
}

.mine-cloud.is-on {
  color: #2f7f86;
}

.mine-cloud.is-off {
  color: #8fa0b2;
}

.mine-cloud.is-full {
  color: #c8402f;
}

.mine-cloud:focus-visible {
  outline: 2px solid #2f7f86;
  outline-offset: 2px;
}

/* 手机上悬停的按钮层是常驻的，云朵要压在它上面才点得到 */
@media (hover: none) {
  .mine-cloud {
    height: 34px;
    width: 34px;
  }
  .mine-cloud svg {
    height: 19px;
    width: 19px;
  }
}

/* 云端名额：一颗 76px 的小胶囊「☁ 3/10」。原来那颗带十格进度条的 165px，
   顶栏摆不下搜索 / 选择 / 排列三颗图标，进度条那点信息也是数字已经说过的。 */
.mine-quota {
  align-items: center;
  background: rgba(255, 255, 255, 0.9);
  border: 1px solid #dce6ef;
  border-radius: 999px;
  color: #2f7f86;
  display: inline-flex;
  flex: 0 0 auto;
  font-size: 13px;
  font-weight: 800;
  gap: 6px;
  min-height: 34px;
  padding: 0 12px;
}

.mine-quota svg {
  height: 15px;
  width: 15px;
}

.mine-quota.is-full {
  border-color: #c8402f;
  color: #c8402f;
}

/* 名额满了之类的提示 */
.mine-toast {
  background: #111820;
  border-radius: 999px;
  bottom: 24px;
  color: #ffffff;
  font-size: 13px;
  left: 50%;
  max-width: calc(100% - 40px);
  padding: 11px 20px;
  position: fixed;
  transform: translateX(-50%);
  z-index: 300;
}

/* ---------- 登录框里的 Google 按钮 ---------- */
.cyber-auth-google {
  align-items: center;
  background: #ffffff;
  border: 1.5px solid #111820;
  border-radius: 999px;
  box-sizing: border-box;
  color: #111820;
  cursor: pointer;
  display: flex;
  font-family: inherit;
  font-size: 15px;
  font-weight: 700;
  gap: 10px;
  justify-content: center;
  margin-bottom: 14px;
  min-height: 46px;
  text-decoration: none;
  width: 100%;
}

.cyber-auth-google:hover {
  background: #f6f9fc;
}

.cyber-auth-google svg {
  flex: 0 0 auto;
}

.cyber-auth-or {
  align-items: center;
  color: #8494a7;
  display: flex;
  font-size: 12px;
  gap: 10px;
  margin-bottom: 14px;
}

.cyber-auth-or::before,
.cyber-auth-or::after {
  background: #dce6ef;
  content: "";
  flex: 1 1 auto;
  height: 1px;
}

/* ---------------------------------------------------------------
   隐私政策 / 服务条款
   中英各写一份实文，按 html[lang] 显示——法律条款不适合用词条拼。
   --------------------------------------------------------------- */
html[lang="en"] .legal-zh,
html:not([lang="en"]) .legal-en {
  display: none;
}

.legal {
  margin: 0 auto;
  max-width: 68ch;
  padding: 28px 4px 72px;
}

.legal h1 {
  font-family: "Noto Serif SC", "Songti SC", serif;
  font-size: clamp(26px, 4.5vw, 34px);
  font-weight: 900;
  line-height: 1.2;
  margin: 0 0 6px;
}

.legal-date {
  color: #8494a7;
  font-size: 13px;
  margin: 0 0 22px;
}

.legal-lede {
  border-left: 2px solid var(--gold, #f2c14e);
  color: #46566b;
  font-size: 15px;
  line-height: 1.75;
  margin: 0 0 30px;
  padding: 2px 0 2px 16px;
}

.legal h2 {
  font-family: "Noto Serif SC", "Songti SC", serif;
  font-size: 19px;
  font-weight: 900;
  margin: 32px 0 10px;
}

.legal p,
.legal li {
  color: #253142;
  font-size: 15px;
  line-height: 1.78;
}

.legal p {
  margin: 0 0 12px;
}

.legal ul {
  margin: 0 0 12px;
  padding-left: 20px;
}

.legal li {
  margin-bottom: 8px;
}

.legal strong {
  font-weight: 700;
}

.legal code {
  background: rgba(17, 24, 32, 0.06);
  border-radius: 5px;
  font-size: 13px;
  padding: 2px 6px;
}

.legal a {
  color: var(--teal, #2f7f86);
  text-underline-offset: 3px;
}

.legal-foot {
  border-top: 1px solid #dce6ef;
  color: #8494a7;
  font-size: 14px;
  margin-top: 40px;
  padding-top: 20px;
}

/* 法律页不需要给滚动条留位置（没有切换标签这回事） */
.legal-page {
  overflow-y: auto;
}

/* 首页底部的法律链接和登录框里那句同意声明 */
.landing-legal {
  align-items: center;
  color: rgba(37, 49, 66, 0.55);
  display: flex;
  flex-wrap: wrap;          /* 从 3 项变成 5 项了，窄屏要能换行 */
  font-size: 12px;
  gap: 8px;
  justify-content: center;
  margin-top: 36px;
}

.landing-legal small {
  font-size: inherit;
}

.landing-legal a {
  color: inherit;
  text-decoration: none;
  text-underline-offset: 3px;
}

.landing-legal a:hover {
  color: #111820;
  text-decoration: underline;
}

.cyber-auth-legal {
  color: #8494a7;
  font-size: 12px;
  line-height: 1.6;
  margin: 0 0 12px;
}

.cyber-auth-legal a {
  color: var(--teal, #2f7f86);
  text-underline-offset: 2px;
}

/* ============================================================
   首页的语言切换：圆里画「中／A」，中间一道斜杠
   亮的那半是现在在用的语言。原来是「国旗 + 语言名 + 两项下拉菜单」——
   国旗在不少设备上渲染不出来（所以早先已经 display:none 藏掉了），
   剩下文字顶着一个 70px 的框；而只有两种语言，点一下直接切就够，不用先开菜单。
   语言开关只在首页出现，内页不放——选择存在 localStorage 里，走到哪一页都跟着。
   ============================================================ */
.landing-language-button {
  align-items: center;
  background: rgba(255, 255, 255, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.24);
  border-radius: 50%;
  color: #fdfcf7;
  display: inline-flex;
  height: 32px;
  justify-content: center;
  min-height: 32px;
  min-width: 0;
  padding: 0;
  width: 32px;
}

.landing-language-button:hover {
  background: rgba(255, 255, 255, 0.18);
}

/* ============================================================
   我的拼豆 · 卡片操作：主操作 + 「⋯」菜单
   四个按钮并排时中文刚好放得下（242px / 卡片 315px），英文要 343px，
   最后那个「删除」被挤出可视区。收进菜单之后以后加操作也不会撑爆。
   ============================================================ */
.mine-more {
  position: relative;
  flex: 0 0 auto;
}

.mine-more-toggle {
  /* 三个点，做成正方形，和主操作按钮同高 */
  letter-spacing: 1px;
  line-height: 1;
  min-width: 34px;
  padding: 0 8px;
}

.mine-more-menu {
  background: #ffffff;
  border: 1px solid rgba(17, 24, 32, 0.14);
  border-radius: 10px;
  bottom: calc(100% + 6px);
  box-shadow: 0 10px 28px rgba(12, 18, 28, 0.22);
  display: flex;
  flex-direction: column;
  min-width: 140px;
  padding: 4px;
  position: absolute;
  /* 往左开：按钮在操作区右侧，往右开会顶出卡片 */
  right: 0;
  /* fixed 定位之后它和卡片不在同一个层叠上下文里比高低了，要压过所有卡片 */
  z-index: 60;
}

.mine-more-menu.is-hidden {
  display: none;
}

.mine-menu-item {
  background: transparent;
  border: 0;
  border-radius: 6px;
  color: #111820;
  cursor: pointer;
  font: inherit;
  font-size: 13px;
  padding: 8px 10px;
  text-align: left;
  text-decoration: none;
  white-space: nowrap;
}

.mine-menu-item:hover,
.mine-menu-item:focus-visible {
  background: rgba(17, 24, 32, 0.07);
}

.mine-menu-danger {
  color: #c0392b;
}

.mine-menu-danger:hover,
.mine-menu-danger:focus-visible {
  background: rgba(192, 57, 43, 0.1);
}

/* ── 烫豆工坊 · 手机版 ──────────────────────────────────────────────────
   375×812 上原来下半屏吃掉 255px：包边条 41 + 提示卡 106 + 状态行 24 + 启动键 54，
   加上顶部两行 104px，机器只剩 431px——而机器才是这一页要看的东西。

   改法（方案 B）：
     1. 「推入 / 启动 / 加热 / 弹出」那排胶囊缩成四颗 5px 的圆点，挪到顶行
        「退出 · 声音」右边，省掉整整一行；
     2. 提示卡去掉「CYBER WORKSHOP」眉标，正文只留一行，点一下展开（右侧 ▾）；
     3. 底部收成一条 58px 的操作栏：左边包边选择器，右边按阶段换内容——
        全自动是「启动」，压合之后按钮本来就会退场，那一格换成「剩余 N 秒」；
        半自动没有启动键，放「已烫 N%」的覆盖率条。
   机器因此从 431px 涨到约 700px。 */
@media (max-width: 520px) {
  /* ---- 顶行 ---- */
  .cyber-workshop-sound {
    left: 112px;
    top: 18px;
  }

  .cyber-workshop[data-machine="auto"] .cyber-machine-dots,
  .cyber-workshop[data-machine="manual"] .cyber-machine-dots {
    align-items: center;
    gap: 4px;
    left: 164px;
    top: 31px;
    transform: none;
  }

  /* 标签文字收掉（这一串本来就 aria-hidden），只留点 */
  .cyber-workshop[data-machine="auto"] .cyber-machine-dots i,
  .cyber-workshop[data-machine="manual"] .cyber-machine-dots i {
    background: rgba(17, 24, 32, 0.22);
    border: 0;
    border-radius: 999px;
    box-shadow: none;
    color: transparent;
    font-size: 0;
    height: 5px;
    min-width: 0;
    padding: 0;
    transition: width 160ms ease, background 160ms ease;
    width: 5px;
  }

  .cyber-workshop[data-machine="auto"] .cyber-machine-dots i.is-done,
  .cyber-workshop[data-machine="manual"] .cyber-machine-dots i.is-done {
    background: rgba(17, 24, 32, 0.5);
  }

  .cyber-workshop[data-machine="auto"] .cyber-machine-dots i.is-active,
  .cyber-workshop[data-machine="manual"] .cyber-machine-dots i.is-active {
    background: #111820;
    width: 14px;
  }

  /* ---- 提示条 ---- */
  .cyber-workshop[data-machine="auto"] .cyber-workshop-head,
  .cyber-workshop[data-machine="manual"] .cyber-workshop-head {
    bottom: 66px;
    left: 8px;
    padding: 8px 26px 8px 11px;
    pointer-events: auto;
    right: 8px;
  }

  .cyber-workshop[data-machine="auto"] .cyber-workshop-head small,
  .cyber-workshop[data-machine="manual"] .cyber-workshop-head small {
    display: none;
  }

  .cyber-workshop[data-machine="auto"] .cyber-workshop-head h2,
  .cyber-workshop[data-machine="manual"] .cyber-workshop-head h2 {
    font-size: 16px;
    margin-bottom: 2px;
  }

  /* 正文默认一行，点整条展开 */
  .cyber-workshop[data-machine="auto"] .cyber-workshop-head p,
  .cyber-workshop[data-machine="manual"] .cyber-workshop-head p {
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 1;
    display: -webkit-box;
    font-size: 11px;
    line-height: 1.45;
    min-height: 0;
    overflow: hidden;
  }

  .cyber-workshop[data-machine="auto"] .cyber-workshop-head.is-open p,
  .cyber-workshop[data-machine="manual"] .cyber-workshop-head.is-open p {
    -webkit-line-clamp: 6;
  }

  /* 展开箭头。用符号不用文字，免得又欠一条词条 */
  .cyber-workshop[data-machine="auto"] .cyber-workshop-head::after,
  .cyber-workshop[data-machine="manual"] .cyber-workshop-head::after {
    color: #7d8a86;
    content: "▾";
    font-size: 12px;
    line-height: 1;
    position: absolute;
    right: 10px;
    top: 10px;
    transition: transform 160ms ease;
  }

  .cyber-workshop-head.is-open::after {
    transform: rotate(180deg);
  }

  /* ---- 底部操作栏 ---- */
  .cyber-workshop[data-machine="auto"] .cyber-machine-hud,
  .cyber-workshop[data-machine="manual"] .cyber-machine-hud {
    align-items: center;
    background: rgba(255, 255, 255, 0.94);
    border-top: 1px solid #dfe3df;
    bottom: 0;
    display: flex;
    gap: 10px;
    justify-content: flex-end;
    left: 0;
    min-height: 58px;
    padding: 9px 12px 10px;
    right: 0;
    transform: none;
  }

  .cyber-workshop[data-machine="auto"] .cyber-machine-start-hud {
    box-shadow: 3px 3px 0 #111820;
    font-size: 13px;
    letter-spacing: 0.12em;
    min-height: 40px;
    padding: 0 24px;
  }

  /* 包边名长短不一，给它一个上限，免得顶到右边那一格 */
  .cyber-edge-toggle {
    max-width: 44vw;
  }

  /* 半自动的操作栏里只有两样东西：左边绝对定位的包边选择器，右边的已烫进度条。
     两边一人一半——操作栏内容宽减去中间 10px 的空当，各拿一半，进度条就和包边
     一样长，不会缩成一小截。
       包边：左内边距 12 + 半个空当 5 = 17，所以 calc(50vw - 17px)
       进度条：它排在流里，50% 已经是内容宽的一半，再减半个空当 */
  .cyber-workshop[data-machine="manual"] .cyber-edge-toggle {
    max-width: calc(50vw - 17px);
  }

  .cyber-workshop[data-machine="manual"] .cyber-machine-coverage {
    flex: 0 0 auto;
    max-width: none;
    padding: 0 12px;
    width: calc(50% - 5px);
  }

  /* 进度条本身吃掉胶囊里剩下的宽度（读数那段是定宽的，见上面的 min-width） */
  .cyber-workshop[data-machine="manual"] .cyber-machine-coverage i {
    flex: 1 1 auto;
    min-width: 36px;
    width: auto;
  }

  .cyber-edge-toggle span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  /* 包边选择器挪进操作栏左边（压合阶段它本来就会收起来） */
  .cyber-edge-picker {
    bottom: 11px;
    left: 12px;
    right: auto;
    z-index: 5;
  }

  .cyber-edge-menu {
    bottom: 44px;
    left: 0;
    right: auto;
  }

  /* 状态文字：全自动在有按钮的阶段用不上（灰按钮就是「在等你」），
     按钮退场的三个阶段把它放回操作栏右边，正好是「剩余 N 秒」。
     半自动没有按钮，全程都要它。 */
  .cyber-workshop[data-machine="auto"] .cyber-machine-status em,
  .cyber-workshop[data-machine="manual"] .cyber-machine-status em {
    background: none;
    border: 0;
    bottom: 20px;
    box-shadow: none;
    font-size: 12px;
    font-style: normal;
    font-weight: 800;
    left: auto;
    padding: 0;
    right: 14px;
    transform: none;
  }

  /* 半自动的操作栏右边是「已烫 N%」那条覆盖率，从一进来就在；
     状态文字会跟它叠在一起，而且说的是同一件事，收掉。
     全自动在有按钮的阶段同理——灰按钮就是「在等你」。 */
  .cyber-workshop[data-machine="auto"] .cyber-machine-status em,
  .cyber-workshop[data-machine="manual"] .cyber-machine-status em {
    display: none;
  }

  /* 这三步原来把状态做成一颗浮在半空的胶囊（带底色和黑边），现在它进了操作栏，
     底色和边框都不要了。选择器要跟那条一样带上 [data-stage]，否则压不过去。 */
  .cyber-workshop[data-machine="auto"][data-stage="press"] .cyber-machine-status em,
  .cyber-workshop[data-machine="auto"][data-stage="heat"] .cyber-machine-status em,
  .cyber-workshop[data-machine="auto"][data-stage="eject"] .cyber-machine-status em {
    background: none;
    border: 0;
    border-radius: 0;
    bottom: 20px;
    box-shadow: none;
    display: block;
    left: auto;
    padding: 0;
    right: 14px;
    transform: none;
  }
}

/* ============================================================
   2026-09-16 · 识别向导手机版：顶行圆点步骤 + 底部同款操作栏
   （方案 C + 方案 B）

   放在文件最后，是因为上面已经有好几条同特异度的规则在管这几个元素，
   同分靠后写的赢——挪走就会被前面那些盖掉。
   PC 端一个字都不碰，整段都在 900px 的媒体查询里。
   ============================================================ */
@media (max-width: 900px) {
  /* ---------- 顶行：← 圆钮 · logo+站名 · 圆点步骤 · 工具 ---------- */

  /* 顶行要塞四样东西，「返回首页」收成一枚箭头圆钮。
     font-size: 0 把「返回首页」四个字收掉，里面那个箭头 span 再调回来——
     按钮里的文字是裸文本节点，没法单独选中，只能这么收。 */
  body[data-view="setup"][data-module="direct"] .direct-footer #directConsoleButton {
    border-radius: 50%;
    font-size: 0;
    left: 12px;
    min-height: 32px;
    min-width: 0;
    padding: 0;
    top: 12px;
    width: 32px;
  }

  body[data-view="setup"][data-module="direct"] .direct-footer #directConsoleButton span {
    font-size: 15px;
    line-height: 1;
  }

  /* 品牌块夹在返回圆钮和圆点串中间。不能用 left:50% 居中——圆点串占了右上角，
     「导入」那枚胶囊会压到站名最后一个字上。改成撑在两者之间的一条带子里居中，
     带子右边留的 166px 是圆点串最宽时（英文 Finish）的占位。 */
  body[data-view="setup"][data-module="direct"] .direct-brand {
    justify-content: center;
    left: 52px;
    right: 196px;
    top: 12px;
    transform: none;
  }

  /* 320 这类老窄屏上，「IronedBeads + Proof colors」两头都放不下，
     把站名和步名各收一号，谁也不压谁 */
  @media (max-width: 360px) {
    body[data-view="setup"][data-module="direct"] .direct-brand .brand-name-zh {
      font-size: 15px;
    }

    html[lang="en"] body[data-view="setup"][data-module="direct"] .direct-brand .brand-name-en {
      font-size: 14px;
    }

    body[data-view="setup"][data-module="direct"] .direct-setup-active .direct-step-button.active {
      font-size: 10px;
      max-width: 88px;
      overflow: hidden;
      padding: 0 7px;
      text-overflow: ellipsis;
      white-space: nowrap;
    }
  }

  /* 五颗胶囊 → 圆点串，挪到右上角，让开右边那颗工具按钮。
     走过的点是主题绿，没走到的是浅灰，当前那颗拉成深色胶囊写着步名——
     名字在串里的位置本身就是进度。 */
  body[data-view="setup"][data-module="direct"] .setup-view.direct-setup-active .direct-stepper {
    gap: 5px;
    left: auto;
    margin: 0;
    max-width: none;
    overflow: visible;
    position: fixed;
    right: 56px;
    top: 17px;
    transform: none;
    width: auto;
  }

  body[data-view="setup"][data-module="direct"] .setup-view.direct-setup-active .direct-stepper > span[aria-hidden="true"] {
    display: none;
  }

  body[data-view="setup"][data-module="direct"] .direct-setup-active .direct-step-button {
    background: #c3ccc9;
    border: 0;
    border-radius: 50%;
    box-shadow: none;
    color: transparent;
    flex: 0 0 auto;
    font-size: 0;
    height: 6px;
    min-height: 0;
    min-width: 0;
    padding: 0;
    position: relative;
    width: 6px;
  }

  /* 6px 的点太小按不中，用一层看不见的伪元素把热区撑到 24×20，不影响排版 */
  body[data-view="setup"][data-module="direct"] .direct-setup-active .direct-step-button::after {
    content: "";
    inset: -10px -6px;
    position: absolute;
  }

  body[data-view="setup"][data-module="direct"] .direct-setup-active .direct-step-button.reached {
    background: var(--teal);
  }

  /* .active 必须写在 .reached 后面：当前这一步两个类都有，要让胶囊赢 */
  body[data-view="setup"][data-module="direct"] .direct-setup-active .direct-step-button.active {
    background: #111820;
    border-radius: 999px;
    color: #ffffff;
    font-size: 11px;
    font-weight: 800;
    height: 22px;
    letter-spacing: 0.02em;
    padding: 0 9px;
    width: auto;
  }

  /* ---------- 底部：五步同款的一行操作栏 ---------- */
  /* 左边是这一步的次要操作（文字链 / 细边胶囊），右边一颗通栏主按钮。
     实心贴底带上边框，视觉上就是上面那块面板的最后一行。 */
  body[data-view="setup"][data-module="direct"] .direct-footer {
    background: #ffffff;
    border-top: 1px solid #dfe3df;
    bottom: 0;
    gap: 8px;
    justify-content: flex-start;
    left: 0;
    padding: 5px 12px;
    padding-bottom: calc(5px + env(safe-area-inset-bottom, 0px));
    right: 0;
    top: auto;
  }

  /* 次要键：去掉描边和投影，收成文字链 */
  body[data-view="setup"][data-module="direct"] .direct-footer .direct-outline-button {
    background: none;
    border: 0;
    box-shadow: none;
    color: var(--muted);
    flex: 0 0 auto;
    font-size: 12px;
    min-height: 34px;
    min-width: 0;
    padding: 0 6px;
  }

  /* 重置裁剪 / 保存：比文字链重一点，细边胶囊。
     背景要显式写白——上面 .direct-footer #directSaveButton 那条给它刷了蓝底。 */
  body[data-view="setup"][data-module="direct"] .direct-footer #directCropResetButton,
  body[data-view="setup"][data-module="direct"] .direct-footer #directSaveButton {
    background: #ffffff;
    border: 1px solid var(--line-strong);
    border-radius: 999px;
    color: #111820;
    padding: 0 12px;
  }

  /* 排序：不管这一步有哪几颗，「上一步」永远在最左，主按钮永远在最右。
     HTML 里的顺序是 重置裁剪 → 上一步 → 重新导入 → 下一步 → 保存 → 开始烫豆，
     和这个规矩对不上，所以用 order 摆一遍。 */
  body[data-view="setup"][data-module="direct"] .direct-footer #directPrevButton,
  body[data-view="setup"][data-module="direct"] .direct-footer #directReimportButton {
    order: 1;
  }

  body[data-view="setup"][data-module="direct"] .direct-footer #directCropResetButton {
    order: 2;
  }

  body[data-view="setup"][data-module="direct"] .direct-footer #directSaveButton {
    order: 3;
  }

  body[data-view="setup"][data-module="direct"] .direct-footer #directNextButton,
  body[data-view="setup"][data-module="direct"] .direct-footer #cyberBeadButton {
    order: 9;
  }

  /* 主按钮：吃掉剩下的宽度 */
  body[data-view="setup"][data-module="direct"] .direct-footer #directNextButton,
  body[data-view="setup"][data-module="direct"] .direct-footer #cyberBeadButton {
    background: #111820;
    border: 0;
    border-radius: 999px;
    color: #ffffff;
    flex: 1 1 auto;
    font-size: 13px;
    min-height: 34px;
    padding: 0 16px;
  }

  body[data-view="setup"][data-module="direct"] .direct-footer #directNextButton:disabled {
    background: #c3ccc9;
    color: #ffffff;
  }

  /* ---------- 省下来的地方还给画面 ---------- */
  /* 顶行 12+32=44，底栏 44：上下各留一点余量 */
  body[data-view="setup"][data-module="direct"] .direct-wizard .direct-stage:not(.is-hidden) {
    padding: 54px 10px 52px;
  }

  /* 对齐页的抽屉跟着底栏上移，正好压在它上沿，不再和按钮重叠 */
  body[data-view="setup"][data-module="direct"] .setup-view.direct-setup-active .direct-stage:not(.is-hidden) > .direct-side-panel.direct-align-tools {
    bottom: calc(44px + env(safe-area-inset-bottom, 0px));
  }

  /* 说明文字也跟着抬到底栏上面 */
  .direct-caption {
    bottom: 52px;
  }
}

/* ============================================================
   2026-09-16 · 对齐页锁定之后：收起抽屉，图纸正中放一枚可拖的小控件
   方向键选边 → ＋／− 在那条边上加减整格 → 中间的 🔒 解锁。
   只在手机上；PC 仍旧用右边那一整盘「范围」。
   ============================================================ */
/* 这枚控件只属于手机版：PC 上「范围」那一整盘一直开着，用不到它。
   基础样式必须写在媒体查询外面，否则宽屏下它没有任何 display 规则，
   会当成普通块级元素铺在对齐面板里。 */
.direct-lock-puck {
  display: none;
}

@media (max-width: 900px) {
  /* 小控件是相对这块绝对定位的，所以这里得起一个定位上下文 */
  body[data-view="setup"][data-module="direct"] .direct-stage[data-direct-panel="align"] .direct-main-panel {
    position: relative;
  }

  .direct-lock-puck {
    background: rgba(255, 255, 255, 0.97);
    border: 1.5px solid #111820;
    border-radius: 16px;
    box-shadow: 0 8px 22px rgba(17, 24, 32, 0.24);
    display: grid;
    gap: 4px;
    grid-template-areas:
      ".    up   ."
      "left lock right"
      ".    down ."
      "step step step";
    grid-template-columns: repeat(3, 34px);
    left: 50%;
    padding: 6px;
    position: absolute;
    top: 50%;
    /* 拖动靠 pointermove，交给浏览器滚动就拖不动了 */
    touch-action: none;
    transform: translate(-50%, -50%);
    z-index: 8;
  }

  /* 写在 display: grid 后面，否则同分靠后的那条会把 .is-hidden 盖掉 */
  .direct-lock-puck.is-hidden {
    display: none;
  }

  .direct-lock-puck-key {
    align-items: center;
    background: #f4f6f8;
    border: 1px solid #d7e1eb;
    border-radius: 9px;
    color: #111820;
    cursor: pointer;
    display: flex;
    font-size: 16px;
    font-weight: 800;
    justify-content: center;
    line-height: 1;
    min-height: 34px;
    padding: 0;
  }

  .direct-lock-puck-key:active {
    background: #e3e8ee;
  }

  /* 选中的那条边：＋／− 加减的就是它 */
  .direct-lock-puck-key.active {
    background: #2f73df;
    border-color: #2f73df;
    color: #ffffff;
  }

  .direct-lock-puck-up { grid-area: up; }
  .direct-lock-puck-left { grid-area: left; }
  .direct-lock-puck-right { grid-area: right; }
  .direct-lock-puck-down { grid-area: down; }

  .direct-lock-puck-lock {
    background: #111820;
    border-color: #111820;
    color: #ffffff;
    font-size: 15px;
    grid-area: lock;
  }

  .direct-lock-puck-lock:active {
    background: #333e4a;
  }

  .direct-lock-puck-step {
    display: grid;
    gap: 4px;
    grid-area: step;
    grid-template-columns: 1fr 1fr;
    margin-top: 2px;
  }

  /* 锁上之后抽屉整个收起来，把图纸让出来 */
  body[data-view="setup"][data-module="direct"][data-direct-locked="1"] .setup-view.direct-setup-active .direct-stage:not(.is-hidden) > .direct-side-panel.direct-align-tools,
  body[data-view="setup"][data-module="direct"][data-direct-locked="1"] .direct-align-tabs {
    display: none;
  }

  body[data-view="setup"][data-module="direct"][data-direct-locked="1"] .direct-tool-toggle {
    display: none;
  }
}

/* ============================================================
   2026-09-16 · 进站提示
   每次进落地页弹一次，勾了「不再提示」写进 localStorage 就不再出现。
   ============================================================ */
.welcome-dialog {
  align-items: center;
  background: rgba(16, 22, 26, 0.45);
  display: flex;
  inset: 0;
  justify-content: center;
  padding: 24px 16px;
  position: fixed;
  z-index: 140;
}

.welcome-dialog.is-hidden {
  display: none;
}

/* 弹窗开着的时候锁住背景滚动，否则手机上滑弹窗会连带页面一起动 */
body.welcome-open {
  overflow: hidden;
}

.welcome-card {
  background: #ffffff;
  border: 1px solid var(--line);
  border-radius: 16px;
  box-shadow: 0 24px 60px rgba(16, 22, 26, 0.28);
  display: flex;
  flex-direction: column;
  max-height: calc(100vh - 48px);
  max-width: 470px;
  overflow: hidden;
  width: 100%;
}

.welcome-head {
  align-items: center;
  display: flex;
  flex: 0 0 auto;
  gap: 11px;
  padding: 18px 20px 12px;
}

.welcome-head .brand-iron-logo {
  height: 36px;
  width: auto;
}

.welcome-head span {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.welcome-head strong {
  color: #111820;
  font-family: "Noto Serif SC", "Songti SC", serif;
  font-size: 18px;
  font-weight: 900;
}

.welcome-head small {
  color: var(--muted);
  font-size: 12px;
  margin-top: 2px;
}

/* 内容可滚，头尾固定：小屏放不下五段，「不再提示」得永远够得着 */
.welcome-body {
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-height: 0;
  overflow-y: auto;
  padding: 0 20px 4px;
}

.welcome-body h4 {
  align-items: center;
  color: #111820;
  display: flex;
  font-size: 13px;
  font-weight: 900;
  gap: 6px;
  margin: 0 0 3px;
}

.welcome-body h4 i {
  font-size: 13px;
  font-style: normal;
}

.welcome-body p {
  color: var(--muted);
  font-size: 12.5px;
  line-height: 1.6;
  margin: 0;
}

.welcome-body p b {
  color: #111820;
  font-weight: 800;
}

/* 流程：八步连成一条，后四步换成主题绿，轻重靠颜色分，不靠文字说明 */
.welcome-steps {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  margin-bottom: 5px;
}

.welcome-steps span {
  background: var(--bg);
  border-radius: 999px;
  color: #202928;
  font-size: 11.5px;
  font-weight: 800;
  padding: 3px 9px;
}

.welcome-steps span.key {
  background: var(--teal);
  color: #ffffff;
}

.welcome-steps i {
  color: var(--muted);
  font-size: 10px;
  font-style: normal;
}

.welcome-steps i.lead {
  color: var(--teal);
  font-weight: 900;
}

.welcome-hero {
  background: #eef7f4;
  border-left: 3px solid var(--teal);
  border-radius: 0 10px 10px 0;
  padding: 10px 12px;
}

.welcome-hero p + p {
  margin-top: 4px;
}

/* 粗体那半句和后半句在 HTML 里是紧挨着的两个节点。中文的「。」自带间距，
   英文的 "." 后面不补空格就会连成 "finishes.Each"。只给英文加。 */
html[lang="en"] .welcome-hero b,
html[lang="en"] .welcome-note b {
  margin-right: 4px;
}

.welcome-note {
  background: #fdf6e7;
  border-left: 3px solid #b7791f;
  border-radius: 0 10px 10px 0;
  padding: 9px 12px;
}

.welcome-note h4 {
  color: #b7791f;
}

.welcome-foot {
  align-items: center;
  border-top: 1px solid var(--line);
  display: flex;
  flex: 0 0 auto;
  gap: 10px;
  justify-content: space-between;
  margin-top: 12px;
  padding: 11px 20px 15px;
}

.welcome-never {
  align-items: center;
  color: var(--muted);
  cursor: pointer;
  display: inline-flex;
  /* 不加这两条会被右边的按钮挤成一字一行 */
  flex: 0 0 auto;
  font-size: 12px;
  font-weight: 700;
  gap: 7px;
  white-space: nowrap;
}

.welcome-actions {
  display: flex;
  gap: 8px;
}

.welcome-actions button {
  background: #ffffff;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  color: #202928;
  cursor: pointer;
  font-size: 13px;
  font-weight: 800;
  min-height: 38px;
  padding: 0 15px;
  white-space: nowrap;
}

.welcome-actions button:hover {
  border-color: #111820;
}

.welcome-actions .welcome-primary {
  background: #111820;
  border-color: #111820;
  color: #ffffff;
}

.welcome-actions .welcome-primary:hover {
  background: #333e4a;
}

/* 手机：底栏排两行——按钮一行各占一半，「不再提示」单独一行。
   不能为了省一行就把登录入口砍掉，手机是流量大头。 */
@media (max-width: 520px) {
  .welcome-dialog {
    padding: 16px 12px;
  }

  .welcome-card {
    max-height: calc(100vh - 32px);
  }

  .welcome-head {
    padding: 15px 15px 10px;
  }

  .welcome-head .brand-iron-logo {
    height: 30px;
  }

  .welcome-head strong {
    font-size: 16px;
  }

  .welcome-head small {
    font-size: 11px;
  }

  .welcome-body {
    gap: 10px;
    padding: 0 15px 4px;
  }

  .welcome-foot {
    align-items: stretch;
    flex-direction: column;
    gap: 9px;
    padding: 11px 15px 14px;
  }

  .welcome-actions button {
    flex: 1;
    padding: 0;
  }
}

/* ============================================================
   2026-09-16 · 未登录时保存/下载置灰的那行提示
   规则：谁被禁就贴在谁旁边。措辞按场景变（只涉及下载就写「可下载」），
   一句话套所有位置会让人在下载菜单里找保存。
   ============================================================ */
.gate-hint {
  align-items: center;
  background: #fdf6e7;
  border-radius: 7px;
  color: #8a6412;
  display: flex;
  flex: 1 0 100%;
  font-size: 11.5px;
  font-weight: 700;
  gap: 5px;
  justify-content: center;
  margin: 0;
  padding: 6px 9px;
}

.gate-hint[hidden] {
  display: none;
}

.gate-hint a {
  color: #8a6412;
  cursor: pointer;
  font-weight: 900;
  text-decoration: underline;
  white-space: nowrap;
}

/* 菜单里的那一行：贴着菜单内边距，占满宽度 */
.cyber-download-menu .gate-hint,
.mine-more-menu .gate-hint {
  border-radius: 6px;
  margin-bottom: 2px;
}

/* 我的拼豆：被禁的三条和「重命名 / 删除」之间断开 */
.mine-more-menu .gate-sep {
  background: rgba(17, 24, 32, 0.1);
  display: block;
  height: 1px;
  margin: 3px 0;
}

/* 底部按钮排：让提示自己占一行，落在按钮上方 */
.direct-footer,
.cyber-stage-cta {
  flex-wrap: wrap;
}

/* 烫豆页那个胶囊是 absolute + left:50%，宽度靠收缩算出来，
   可用宽度只有右半屏。一开 wrap，手机上就被挤成一列，
   按钮全叠到色卡条上。显式按内容取宽把它掰回来。 */
.cyber-stage-cta {
  width: max-content;
}

.cyber-stage-cta > .gate-hint,
.direct-footer > .gate-hint {
  flex: 0 0 100%;
  justify-content: center;
}

/* 胶囊是全圆角的，提示跟着圆才不会从边上冒出来 */
.cyber-stage-cta > .gate-hint {
  border-radius: 999px;
}

/* 禁用态统一压暗，别让人以为按钮坏了——旁边那行字负责解释 */
.gate-off:disabled,
button.gate-off[disabled] {
  cursor: not-allowed;
  opacity: 0.45;
}

/* 手机上色样栏贴着底部胶囊，胶囊多出一行提示就得让位 */
@media (max-width: 900px) {
  body.is-save-gated .cyber-finish-rail {
    bottom: 118px;
  }
}

/* 诞生卡是深色描边的白卡片，链接用琥珀色和那行提示保持一致 */
.cyber-birth-login {
  color: #8a6412;
  font-weight: 900;
  text-decoration: underline;
}

/* ------------------------------------------------ 首页首屏下面的说明（index.html #landingMore）
   字体、墨色、青色、硬阴影都跟首屏的大标题和胶囊按钮一套：标题 Playfair Display（中文落到 Noto Serif SC），
   正文 Poppins。只有六张烫法卡片是「立起来」的东西（墨线 + 硬阴影，和按钮同款），
   品牌、步骤、问答都压低，免得一屏全是卡片。 */
.landing-more-link {
  align-items: center;
  color: var(--teal, #27877f);
  display: inline-flex;
  font-family: "Poppins", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
  font-size: 14px;
  font-weight: 700;
  gap: 6px;
  margin-top: 30px;
  text-decoration: none;
  text-underline-offset: 4px;
}

.landing-more-link:hover {
  text-decoration: underline;
}

.landing-more-link:focus-visible {
  border-radius: 6px;
  outline: 2px solid var(--teal, #27877f);
  outline-offset: 4px;
}

.landing-more-link span {
  display: inline-block;
  transition: transform 160ms ease;
}

.landing-more-link:hover span {
  transform: translateY(3px);
}

.landing-more {
  background: #fbf9f2;
  border-top: 1px solid rgba(17, 24, 32, 0.08);
  color: #111820;
  font-family: "Poppins", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
  padding: 8px clamp(16px, 5vw, 56px) 24px;
  scroll-margin-top: 0;
}

.landing-more-block {
  margin: 0 auto;
  max-width: 1120px;
  padding: clamp(36px, 6vw, 60px) 0 clamp(8px, 2vw, 16px);
}

.landing-more-block + .landing-more-block {
  border-top: 1px solid rgba(17, 24, 32, 0.1);
}

.landing-more-kicker {
  color: var(--teal, #27877f);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.16em;
  margin: 0 0 10px;
  text-transform: uppercase;
}

.landing-more h2 {
  color: #111820;
  font-family: "Playfair Display", "Noto Serif SC", "Songti SC", Georgia, serif;
  font-size: clamp(25px, 3.1vw, 36px);
  font-weight: 800;
  line-height: 1.2;
  margin: 0 0 12px;
  text-wrap: balance;
}

.landing-more-lead {
  color: #46566b;
  font-size: 16px;
  line-height: 1.65;
  margin: 0 0 24px;
  max-width: 62ch;
  text-wrap: pretty;
}

/* 六类烫法：3 列 → 2 列 → 1 列 */
.landing-families {
  display: grid;
  gap: 18px;
  grid-template-columns: repeat(3, minmax(0, 1fr));
}

.landing-family {
  background: #ffffff;
  border: 1.5px solid #111820;
  border-radius: 14px;
  box-shadow: 3px 3px 0 #111820;
  display: flex;
  flex-direction: column;
  gap: 10px;
  overflow: hidden;
  padding: 0 16px 16px;
}

/* 纹理带是站里真实渲染的烫法样块，8×3 颗豆，按原比例铺满卡片宽度 */
.landing-family img {
  aspect-ratio: 8 / 3;
  border-bottom: 1.5px solid #111820;
  display: block;
  height: auto;
  margin: 0 -16px 4px;
  max-width: none;
  object-fit: cover;
  width: calc(100% + 32px);
}

.landing-family-head {
  align-items: baseline;
  display: flex;
  gap: 10px;
  justify-content: space-between;
}

.landing-family h3 {
  font-family: "Playfair Display", "Noto Serif SC", "Songti SC", Georgia, serif;
  font-size: 20px;
  font-weight: 800;
  line-height: 1.2;
  margin: 0;
}

.landing-family-head small {
  color: var(--teal, #27877f);
  flex: 0 0 auto;
  font-size: 12px;
  font-weight: 700;
}

.landing-family p {
  color: #46566b;
  font-size: 14px;
  line-height: 1.55;
  margin: 0;
}

.landing-family ul {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  list-style: none;
  margin: auto 0 0;
  padding: 4px 0 0;
}

.landing-family li {
  background: #eef4f3;
  border-radius: 999px;
  color: #1f5f59;
  font-size: 12px;
  font-weight: 600;
  line-height: 1;
  padding: 6px 10px;
}

/* 品牌：名字靠左、色数靠右，和识别向导里的品牌列表同一个读法。
   9 个牌子固定排 3×3，任何宽度都排满、不剩孤零零的一两个 */
.landing-brands {
  display: grid;
  gap: 10px;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  list-style: none;
  margin: 0;
  max-width: 760px;
  padding: 0;
}

.landing-brands li {
  align-items: baseline;
  background: #ffffff;
  border: 1px solid #e3dccd;
  border-radius: 10px;
  display: flex;
  gap: 8px;
  justify-content: space-between;
  padding: 12px 14px;
}

.landing-brands b {
  font-size: 15px;
  font-weight: 700;
}

.landing-brands span {
  color: #8494a7;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  white-space: nowrap;
}

/* 四步是真的先后顺序，所以有编号；编号用 CSS 计数器画，不进文本、也就不用翻译 */
.landing-steps {
  counter-reset: landing-step;
  display: grid;
  gap: 22px;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  list-style: none;
  margin: 8px 0 0;
  padding: 0;
}

.landing-steps li {
  align-content: start;   /* 四步等高时，多出来的高度留在底下，别把说明挤离标题 */
  counter-increment: landing-step;
  display: grid;
  gap: 4px 12px;
  grid-template-columns: 30px minmax(0, 1fr);
}

.landing-steps li::before {
  background: #111820;
  border-radius: 50%;
  color: #ffffff;
  content: counter(landing-step);
  font-size: 14px;
  font-weight: 700;
  grid-row: 1 / span 2;
  height: 30px;
  line-height: 30px;
  text-align: center;
  width: 30px;
}

.landing-steps h3 {
  font-size: 16px;
  font-weight: 700;
  line-height: 1.3;
  margin: 4px 0 0;
}

.landing-steps p {
  color: #46566b;
  font-size: 14px;
  line-height: 1.55;
  margin: 0;
}

/* 常见问题：原生 <details>，不用脚本 */
.landing-faq {
  display: grid;
  gap: 10px;
  max-width: 800px;
}

.landing-faq details {
  background: #ffffff;
  border: 1px solid #e3dccd;
  border-radius: 12px;
}

.landing-faq summary {
  align-items: center;
  cursor: pointer;
  display: flex;
  font-size: 15px;
  font-weight: 700;
  gap: 12px;
  justify-content: space-between;
  line-height: 1.4;
  list-style: none;
  padding: 14px 16px;
}

.landing-faq summary::-webkit-details-marker {
  display: none;
}

.landing-faq summary::after {
  color: var(--teal, #27877f);
  content: "+";
  flex: 0 0 auto;
  font-size: 20px;
  font-weight: 400;
  line-height: 1;
  transition: transform 160ms ease;
}

.landing-faq details[open] summary::after {
  transform: rotate(45deg);
}

.landing-faq summary:focus-visible {
  border-radius: 12px;
  outline: 2px solid var(--teal, #27877f);
  outline-offset: 2px;
}

.landing-faq details p {
  color: #46566b;
  font-size: 14px;
  line-height: 1.65;
  margin: 0;
  padding: 0 16px 16px;
}

/* 法律链接从首屏底部挪到了整页最底下 */
.landing-view > .landing-legal {
  background: #fbf9f2;
  margin-top: 0;
  padding: 20px 16px 32px;
}

@media (max-width: 960px) {
  .landing-families {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .landing-steps {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 600px) {
  .landing-families,
  .landing-steps {
    grid-template-columns: 1fr;
  }

  .landing-more-lead {
    font-size: 15px;
  }

  /* 手机上一格放不下「名字 + 色数」一行，改成上下两行，仍然 3×3 */
  .landing-brands li {
    align-items: flex-start;
    flex-direction: column;
    gap: 2px;
    padding: 10px 12px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .landing-more-link span,
  .landing-faq summary::after {
    transition: none;
  }
}

/* ------------------------------------------------ 首页 · 指南入口（#landingMore 最后一块） */
.landing-guides {
  display: grid;
  gap: 12px;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  list-style: none;
  margin: 4px 0 0;
  padding: 0;
}

.landing-guides a {
  background: #ffffff;
  border: 1px solid #e3dccd;
  border-radius: 12px;
  color: #111820;
  display: grid;
  gap: 4px;
  height: 100%;
  padding: 14px 16px;
  text-decoration: none;
  transition: border-color 160ms ease, transform 160ms ease;
}

.landing-guides a:hover {
  border-color: #111820;
  transform: translateY(-2px);
}

.landing-guides a:focus-visible {
  outline: 2px solid var(--teal, #27877f);
  outline-offset: 2px;
}

.landing-guides b {
  font-size: 15px;
  font-weight: 700;
  line-height: 1.35;
}

.landing-guides span {
  color: var(--teal, #27877f);
  font-size: 13px;
  font-weight: 600;
  line-height: 1.45;
}

.landing-guides span::after {
  content: " →";
}

@media (max-width: 760px) {
  .landing-guides {
    grid-template-columns: 1fr;
  }
}

/* ------------------------------------------------ 指南页（三篇：烫法图鉴 / 怎么烫 / 纸还是布）
   外壳借「我的拼豆」那套（.mine-page / .mine-shell / .mine-topbar），和隐私政策一样；
   正文中英各一份，按 html[lang] 显示。字体、墨色、青色、硬阴影和首页那段说明是一套。 */
html[lang="en"] .guide-zh,
html:not([lang="en"]) .guide-en {
  display: none;
}

.guide-page {
  background: #fbf9f2;
}

/* 语言开关：首页同款「中／A」图标，浅色顶栏上用墨色。亮的那半是现在用的语言 */
.guide-lang {
  align-items: center;
  background: #ffffff;
  border: 1px solid #d7dedb;
  border-radius: 50%;
  cursor: pointer;
  display: inline-flex;
  flex: 0 0 auto;
  height: 34px;
  justify-content: center;
  padding: 0;
  width: 34px;
}

.guide-lang:hover {
  border-color: #111820;
}

.guide-lang:focus-visible {
  outline: 2px solid var(--teal, #27877f);
  outline-offset: 2px;
}

.guide-lang svg {
  display: block;
  font-family: system-ui, -apple-system, "PingFang SC", sans-serif;
}

.guide-lang text {
  fill: rgba(17, 24, 32, 0.3);
}

.guide-lang line {
  stroke: rgba(17, 24, 32, 0.3);
}

html:not([lang="en"]) .guide-lang .lang-zh,
html[lang="en"] .guide-lang .lang-en {
  fill: #111820;
}

.guide {
  color: #111820;
  font-family: "Poppins", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
  justify-self: center;
  max-width: 760px;
  /* 外壳 .mine-shell 是 grid，网格项默认不肯比内容窄：表格的 min-width 会把整篇文章撑出屏幕。
     放开之后表格只在自己的 .guide-table 里横向滚 */
  min-width: 0;
  padding: 0 4px 24px;
  width: 100%;
}

.guide-wide {
  max-width: 1120px;
}

.guide-head {
  padding: clamp(24px, 5vw, 52px) 0 4px;
}

.guide-kicker {
  color: var(--teal, #27877f);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.16em;
  margin: 0 0 12px;
  text-transform: uppercase;
}

.guide h1 {
  color: #111820;
  font-family: "Playfair Display", "Noto Serif SC", "Songti SC", Georgia, serif;
  font-size: clamp(30px, 5vw, 48px);
  font-weight: 800;
  letter-spacing: -0.01em;
  line-height: 1.12;
  margin: 0 0 14px;
  text-wrap: balance;
}

.guide-lede {
  color: #46566b;
  font-size: clamp(15px, 1.6vw, 18px);
  line-height: 1.65;
  margin: 0;
  max-width: 62ch;
}

.guide-date {
  color: #8494a7;
  font-size: 13px;
  margin: 12px 0 0;
}

.guide h2 {
  color: #111820;
  font-family: "Playfair Display", "Noto Serif SC", "Songti SC", Georgia, serif;
  font-size: clamp(22px, 2.8vw, 28px);
  font-weight: 800;
  line-height: 1.25;
  margin: 0 0 10px;
  text-wrap: balance;
}

.guide section {
  border-top: 1px solid rgba(17, 24, 32, 0.1);
  margin-top: 30px;
  padding-top: 26px;
}

.guide p {
  font-size: 15px;
  line-height: 1.7;
}

.guide section > p {
  margin: 0;
  max-width: 68ch;
}

.guide a {
  color: inherit;
}

.guide-jump {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  list-style: none;
  margin: 20px 0 0;
  padding: 0;
}

.guide-jump a {
  border: 1.5px solid #111820;
  border-radius: 999px;
  display: inline-block;
  font-size: 13px;
  font-weight: 600;
  line-height: 1;
  padding: 8px 13px;
  text-decoration: none;
}

.guide-jump a:hover {
  background: #111820;
  color: #ffffff;
}

.guide-family {
  scroll-margin-top: 80px;
}

.guide-family h2 small {
  color: var(--teal, #27877f);
  font-family: "Poppins", "PingFang SC", sans-serif;
  font-size: 12px;
  font-weight: 700;
  margin-left: 6px;
  vertical-align: middle;
}

.guide .guide-family > p {
  color: #46566b;
  margin: 0 0 16px;
}

/* 23 种烫法的小样：4 列 → 3 列 → 2 列 */
.guide-finishes {
  display: grid;
  gap: 14px;
  grid-template-columns: repeat(4, minmax(0, 1fr));
}

.guide-finish {
  background: #ffffff;
  border: 1.5px solid #111820;
  border-radius: 12px;
  box-shadow: 3px 3px 0 #111820;
  margin: 0;
  overflow: hidden;
}

.guide-finish img {
  aspect-ratio: 4 / 3;
  border-bottom: 1.5px solid #111820;
  display: block;
  height: auto;
  object-fit: cover;
  width: 100%;
}

.guide-finish figcaption {
  display: grid;
  gap: 2px;
  padding: 10px 12px 12px;
}

.guide-finish b {
  font-size: 14px;
  font-weight: 700;
  line-height: 1.3;
}

.guide-finish span {
  color: #46566b;
  font-size: 12.5px;
  line-height: 1.45;
}

.guide-need {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  list-style: none;
  margin: 4px 0 0;
  padding: 0;
}

.guide-need li {
  background: #ffffff;
  border: 1px solid #e3dccd;
  border-radius: 999px;
  font-size: 13.5px;
  line-height: 1.2;
  padding: 9px 14px;
}

/* 步骤是真的先后顺序，编号用计数器画 */
.guide-steps {
  counter-reset: guide-step;
  display: grid;
  gap: 16px;
  list-style: none;
  margin: 6px 0 0;
  padding: 0;
}

.guide-steps li {
  align-content: start;
  counter-increment: guide-step;
  display: grid;
  gap: 2px 14px;
  grid-template-columns: 32px minmax(0, 1fr);
}

.guide-steps li::before {
  background: #111820;
  border-radius: 50%;
  color: #ffffff;
  content: counter(guide-step);
  font-size: 14px;
  font-weight: 700;
  grid-row: 1 / span 2;
  height: 32px;
  line-height: 32px;
  text-align: center;
  width: 32px;
}

.guide-steps h3 {
  font-size: 16px;
  font-weight: 700;
  line-height: 1.35;
  margin: 5px 0 0;
}

.guide-steps p {
  color: #46566b;
  font-size: 14px;
  margin: 0;
}

/* 出处：点得开的小胶囊，链到品牌官网那一页 */
.guide-src {
  background: #eef4f3;
  border-radius: 999px;
  color: #1f5f59 !important;
  display: inline-block;
  font-size: 10.5px;
  font-weight: 700;
  line-height: 1;
  margin-left: 2px;
  padding: 4px 8px;
  text-decoration: none;
  vertical-align: 1px;
  white-space: nowrap;
}

.guide-src:hover {
  background: #d9ebe8;
}

.guide-note {
  background: #fff8e2;
  border-left: 3px solid #f2c14e;
  border-radius: 0 10px 10px 0;
  font-size: 14px !important;
  margin: 20px 0 0 !important;
  padding: 12px 14px;
}

.guide-table {
  overflow-x: auto;
}

.guide table {
  background: #ffffff;
  border: 1px solid #e3dccd;
  border-collapse: separate;
  border-radius: 12px;
  border-spacing: 0;
  font-size: 14px;
  line-height: 1.5;
  min-width: 520px;
  overflow: hidden;
  width: 100%;
}

.guide th,
.guide td {
  border-bottom: 1px solid #e3dccd;
  padding: 11px 14px;
  text-align: left;
  vertical-align: top;
}

.guide tbody tr:last-child th,
.guide tbody tr:last-child td {
  border-bottom: 0;
}

.guide thead th {
  background: #faf6ec;
  font-size: 12.5px;
  font-weight: 700;
}

.guide tbody th {
  font-weight: 700;
  white-space: nowrap;
}

.guide-sources {
  color: #8494a7;
  font-size: 12.5px !important;
  margin: 10px 0 0 !important;
}

.guide-tools {
  display: grid;
  gap: 12px;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  margin-top: 16px;
}

.guide-tools figure {
  background: #ffffff;
  border: 1px solid #e3dccd;
  border-radius: 12px;
  margin: 0;
  padding: 8px;
  text-align: center;
}

.guide-tools img {
  aspect-ratio: 4 / 3;
  display: block;
  height: auto;
  object-fit: contain;
  width: 100%;
}

.guide-tools figcaption {
  font-size: 12.5px;
  font-weight: 600;
  line-height: 1.3;
  padding-top: 4px;
}

.guide-caption {
  color: #8494a7;
  font-size: 13px !important;
  margin: 10px 0 0;
}

.guide-trouble {
  display: grid;
  gap: 10px;
  list-style: none;
  margin: 4px 0 0;
  padding: 0;
}

.guide-trouble li {
  background: #ffffff;
  border: 1px solid #e3dccd;
  border-radius: 12px;
  display: grid;
  gap: 3px;
  padding: 12px 14px;
}

.guide-trouble b {
  font-size: 14.5px;
  font-weight: 700;
  line-height: 1.4;
}

.guide-trouble span {
  color: #46566b;
  font-size: 14px;
  line-height: 1.55;
}

.guide-compare {
  display: grid;
  gap: 12px;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  margin-top: 26px;
}

.guide-compare figure {
  margin: 0;
}

.guide-compare img {
  aspect-ratio: 5 / 4;
  border: 1.5px solid #111820;
  border-radius: 10px;
  display: block;
  height: auto;
  object-fit: cover;
  width: 100%;
}

.guide-compare figcaption {
  font-size: 12.5px;
  font-weight: 600;
  line-height: 1.35;
  padding-top: 6px;
}

.guide-short {
  background: #ffffff;
  border: 1.5px solid #111820;
  border-radius: 14px;
  box-shadow: 3px 3px 0 #111820;
  display: grid;
  gap: 4px;
  margin-top: 22px;
  padding: 16px 18px;
}

.guide-short b {
  color: var(--teal, #27877f);
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.guide-short span {
  font-size: 16px;
  font-weight: 600;
  line-height: 1.55;
}

.guide-cta {
  align-items: center;
  background: #111820;
  border-radius: 16px;
  color: #ffffff;
  display: flex;
  flex-wrap: wrap;
  gap: 14px 24px;
  justify-content: space-between;
  margin-top: 40px;
  padding: 22px 24px;
}

.guide .guide-cta h2 {
  color: #ffffff;
  font-size: clamp(20px, 2.4vw, 26px);
  margin: 0 0 4px;
}

.guide-cta p {
  color: #c9d2dc;
  font-size: 14px;
  margin: 0;
  max-width: 52ch;
}

.guide .guide-cta-button {
  background: #f2c14e;
  border: 1.5px solid #ffffff;
  border-radius: 999px;
  box-shadow: 3px 3px 0 #ffffff;
  color: #111820;
  font-size: 14px;
  font-weight: 700;
  line-height: 1;
  padding: 13px 22px;
  text-decoration: none;
  transition: box-shadow 160ms ease, transform 160ms ease;
  white-space: nowrap;
}

.guide .guide-cta-button:hover {
  box-shadow: 1px 1px 0 #ffffff;
  transform: translate(2px, 2px);
}

.guide-cta-button:focus-visible,
.guide-more a:focus-visible,
.guide-jump a:focus-visible,
.guide-src:focus-visible {
  outline: 2px solid var(--teal, #27877f);
  outline-offset: 2px;
}

.guide-more {
  margin-top: 34px;
}

.guide .guide-more h2 {
  font-size: 20px;
}

.guide-more ul {
  display: grid;
  gap: 12px;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  list-style: none;
  margin: 0;
  padding: 0;
}

.guide-more a {
  background: #ffffff;
  border: 1px solid #e3dccd;
  border-radius: 12px;
  display: grid;
  gap: 3px;
  height: 100%;
  padding: 14px 16px;
  text-decoration: none;
}

.guide-more a:hover {
  border-color: #111820;
}

.guide-more b {
  font-size: 15px;
  font-weight: 700;
  line-height: 1.35;
}

.guide-more span {
  color: #46566b;
  font-size: 13px;
  line-height: 1.45;
}

.guide-foot {
  color: #8494a7;
  font-size: 12px !important;
  margin: 36px 0 0;
  text-align: center;
}

.guide-foot a {
  text-decoration: none;
}

.guide-foot a:hover {
  color: #111820;
  text-decoration: underline;
}

@media (max-width: 960px) {
  .guide-finishes {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (max-width: 600px) {
  .guide-finishes,
  .guide-compare {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .guide-more ul {
    grid-template-columns: 1fr;
  }

  .guide-tools {
    gap: 8px;
  }

  .guide-cta {
    padding: 20px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .landing-guides a,
  .guide .guide-cta-button {
    transition: none;
  }
}

/* 首页正文里指向指南的两个链接：烫法卡片下面一个、「纸还是布」那条问答里一个。
   和指南入口卡片同一个青色，箭头用伪元素画，不进文本、也就不用翻译 */
.landing-more-inline,
.landing-faq-link {
  color: var(--teal, #27877f);
  display: inline-block;
  font-size: 14px;
  font-weight: 700;
  text-decoration: none;
  text-underline-offset: 3px;
}

.landing-more-inline {
  margin-top: 18px;
}

.landing-faq-link {
  margin: -6px 16px 16px;
}

.landing-more-inline::after,
.landing-faq-link::after {
  content: " →";
}

.landing-more-inline:hover,
.landing-faq-link:hover {
  text-decoration: underline;
}

.landing-more-inline:focus-visible,
.landing-faq-link:focus-visible {
  border-radius: 4px;
  outline: 2px solid var(--teal, #27877f);
  outline-offset: 3px;
}
