:root {
  --bg: #f5f5f3; --panel: #ffffff; --ink: #1c1c1a; --muted: #6b6b66; --line: #e2e2dd;
  --accent: #2d5bff; --ok: #1f8a4c; --warn: #b7791f; --bad: #c43d3d; --chip: #ececea;
  font-family: -apple-system, "PingFang SC", "Helvetica Neue", "Microsoft YaHei", sans-serif;
}
@media (prefers-color-scheme: dark) {
  :root { --bg: #16161a; --panel: #1f1f25; --ink: #ececec; --muted: #9a9aa3; --line: #2f2f38; --chip: #2a2a33; }
}
* { box-sizing: border-box; }
body { margin: 0; background: var(--bg); color: var(--ink); font-size: 14px; }
button, input, textarea { font: inherit; color: inherit; }
.topbar { display: flex; align-items: center; gap: 16px; padding: 10px 20px; background: var(--panel); border-bottom: 1px solid var(--line); position: sticky; top: 0; z-index: 5; }
.brand { font-weight: 700; font-size: 17px; }
.who input { border: 1px solid var(--line); border-radius: 6px; padding: 4px 8px; background: var(--bg); width: 140px; }
.chip { border: 1px solid var(--line); background: var(--chip); border-radius: 999px; padding: 4px 12px; font-size: 13px; cursor: pointer; }
.chip.active { background: var(--accent); color: #fff; border-color: var(--accent); }
.chip.ok { border-color: var(--ok); color: var(--ok); } .chip.bad { border-color: var(--bad); color: var(--bad); }
main { max-width: 1500px; margin: 0 auto; padding: 16px 20px 60px; }
.dropzone { border: 2px dashed var(--line); border-radius: 12px; padding: 22px; text-align: center; background: var(--panel); transition: border-color .15s; }
.dropzone.over { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 8%, var(--panel)); }
.link { background: none; border: 0; color: var(--accent); text-decoration: underline; cursor: pointer; padding: 0; }
.muted { color: var(--muted); } .sm { font-size: 12px; } .center { text-align: center; margin-top: 40px; }
.toolbar { display: flex; align-items: center; gap: 10px; margin: 16px 0 12px; flex-wrap: wrap; }
.filters { display: flex; gap: 6px; flex-wrap: wrap; }
.search { border: 1px solid var(--line); border-radius: 8px; padding: 6px 10px; background: var(--panel); min-width: 200px; }
.spacer { flex: 1; }
.btn { border: 1px solid var(--line); background: var(--panel); border-radius: 8px; padding: 7px 14px; cursor: pointer; }
.btn:hover { border-color: var(--accent); } .btn:disabled { opacity: .45; cursor: not-allowed; }
.btn.primary { background: var(--accent); color: #fff; border-color: var(--accent); }
.btn.ok { background: var(--ok); color: #fff; border-color: var(--ok); }
.btn.danger { color: var(--bad); border-color: var(--bad); } .btn.danger:not(.ghost) { background: var(--bad); color: #fff; }
.btn.ghost { background: transparent; } .btn.sm { padding: 4px 10px; font-size: 12px; border-radius: 6px; }
.btn.active { background: var(--ink); color: var(--bg); }
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(270px, 1fr)); gap: 14px; }
.card-item { background: var(--panel); border: 1px solid var(--line); border-radius: 12px; overflow: hidden; display: flex; flex-direction: column; position: relative; }
.card-item.selected { outline: 2px solid var(--accent); }
.card-item model-viewer { width: 100%; aspect-ratio: 1; background: linear-gradient(#f0f0ee, #dcdcd8); cursor: pointer; }
@media (prefers-color-scheme: dark) { .card-item model-viewer { background: linear-gradient(#5a5a62, #3c3c44); } } /* 深色主题下卡片背景调亮一些，黑色家具才看得见 */
.card-item .sel { position: absolute; top: 8px; left: 8px; width: 20px; height: 20px; z-index: 2; accent-color: var(--accent); }
.card-item .badge { position: absolute; top: 8px; right: 8px; }
.card-meta { padding: 10px 12px 12px; display: flex; flex-direction: column; gap: 4px; }
.card-meta .id { font-weight: 600; word-break: break-all; }
.badge { display: inline-block; padding: 2px 8px; border-radius: 999px; font-size: 12px; color: #fff; background: var(--muted); }
.badge.pending { background: var(--warn); } .badge.approved { background: var(--ok); } .badge.rejected { background: var(--bad); } .badge.published { background: var(--accent); }
.tag { display: inline-block; font-size: 11px; padding: 1px 6px; border-radius: 4px; border: 1px solid var(--line); color: var(--muted); margin-right: 4px; }
.tag.ok { color: var(--ok); border-color: var(--ok); } .tag.bad { color: var(--bad); border-color: var(--bad); } .tag.warn { color: var(--warn); border-color: var(--warn); }
.detail, .compare { position: fixed; inset: 0; background: var(--bg); z-index: 10; overflow: auto; }
.detail-head { display: flex; align-items: center; gap: 14px; padding: 10px 20px; background: var(--panel); border-bottom: 1px solid var(--line); position: sticky; top: 0; z-index: 2; }
.detail-head h2 { margin: 0; font-size: 18px; cursor: pointer; }
.detail-body { display: grid; grid-template-columns: minmax(380px, 1.3fr) minmax(360px, 1fr); gap: 16px; padding: 16px 20px; max-width: 1500px; margin: 0 auto; }
@media (max-width: 900px) { .detail-body { grid-template-columns: 1fr; } }
.viewer-col { display: flex; flex-direction: column; gap: 14px; position: sticky; top: 64px; align-self: start; }
.viewer-wrap { background: var(--panel); border: 1px solid var(--line); border-radius: 12px; overflow: hidden; }
.viewer-stage { position: relative; }
.dv-overlay { position: absolute; left: 0; top: 0; width: 100%; height: 100%; pointer-events: none; overflow: visible; }
.dv-overlay .box { stroke: #e8780a; stroke-width: 1.2; opacity: 0.75; fill: none; }
.dv-overlay .dim { stroke: #e8780a; stroke-width: 2.5; }
.dv-overlay .ax-x { stroke: #d62828; stroke-width: 1; } .dv-overlay .ax-y { stroke: #2a9d2a; stroke-width: 1; } .dv-overlay .ax-z { stroke: #2a62d6; stroke-width: 1; }
.dv-overlay text { font: 600 13px system-ui, sans-serif; paint-order: stroke; stroke: rgba(255,255,255,0.9); stroke-width: 4px; stroke-linejoin: round; }
.dv-overlay .dim-label { fill: #b45309; } .dv-overlay .ax-label { font-size: 12px; font-weight: 700; }
.dv-overlay .ax-label.x { fill: #d62828; } .dv-overlay .ax-label.y { fill: #2a9d2a; } .dv-overlay .ax-label.z { fill: #2a62d6; }
.hs-anchor { width: 0; height: 0; pointer-events: none; }
.num.cur { font-weight: 600; }
.unit-lbl { float: right; font-weight: 400; } .unit-lbl select { border: 1px solid var(--line); border-radius: 6px; padding: 2px 6px; background: var(--bg); color: inherit; }
.dv-overlay .origin { fill: #fff; stroke: #e8780a; stroke-width: 2; }
.dv-overlay .tbox-label { fill: #c2410c; } .dv-overlay .mbox-label { fill: #15803d; } .dv-overlay .cbox-label { font-size: 12px; }
.box-row .swatch { display: inline-block; width: 10px; height: 10px; border-radius: 3px; margin-right: 4px; vertical-align: middle; }
.box-row .box-name { width: 92px; border: 1px solid transparent; border-radius: 6px; padding: 2px 4px; background: transparent; color: inherit; font-weight: 600; }
.box-row .box-name:hover, .box-row .box-name:focus { border-color: var(--line); background: var(--bg); }
.box-row .box-del { border: none; background: none; color: var(--muted); cursor: pointer; padding: 0 4px; } .box-row .box-del:hover { color: var(--bad); }
/* 复选框和它的文字永远在同一行、框在字前面；一行放不下时整个标签一起换行 */
.box-row label.sm { display: inline-flex; align-items: center; gap: 3px; white-space: nowrap; margin-right: 6px; } .box-row label.sm input { margin: 0; }
#tgt-src.tag.sm { font-size: 11px; padding: 0 6px; margin-left: 4px; }
.viewer-stage.dragmode model-viewer { cursor: grab; } .viewer-stage.dragmode.dragging model-viewer { cursor: grabbing; }
.viewer-stage.dragmode::after { content: "拖动旋转模型"; position: absolute; right: 10px; top: 10px; font-size: 12px; padding: 2px 8px; border-radius: 999px; background: #e8780a; color: #fff; pointer-events: none; }
.cur-note { color: var(--warn); margin: 4px 0; }
.viewer-wrap model-viewer { width: 100%; height: min(60vh, 560px); background: radial-gradient(circle at 50% 40%, #fafaf8, #d9d9d4); }
@media (prefers-color-scheme: dark) { .viewer-wrap model-viewer { background: radial-gradient(circle at 50% 40%, #2c2c34, #15151a); } }
.viewer-tools { display: flex; gap: 6px; align-items: center; padding: 8px 10px; flex-wrap: wrap; }
.photo-wrap { background: var(--panel); border: 1px solid var(--line); border-radius: 12px; padding: 10px 12px; }
.photo-wrap img { max-width: 100%; max-height: 300px; display: block; margin: 6px auto 0; border-radius: 6px; }
.panel-col { display: flex; flex-direction: column; gap: 12px; }
.card { background: var(--panel); border: 1px solid var(--line); border-radius: 12px; padding: 12px 14px; }
.section-title { font-weight: 600; margin-bottom: 8px; }
.row { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin: 6px 0; }
.lbl { width: 92px; color: var(--muted); font-size: 12px; }
.dims { width: 100%; border-collapse: collapse; } .dims th, .dims td { text-align: right; padding: 4px 6px; border-bottom: 1px solid var(--line); }
.dims td:first-child, .dims th:first-child { text-align: left; color: var(--muted); }
.num { width: 80px; text-align: right; border: 1px solid var(--line); border-radius: 6px; padding: 3px 6px; background: var(--bg); }
.good { color: var(--ok); font-weight: 600; } .poor { color: var(--bad); font-weight: 600; }
.versions, .comments { list-style: none; padding: 0; margin: 0; }
.versions li, .comments li { padding: 6px 0; border-bottom: 1px solid var(--line); display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.versions li.current { font-weight: 600; }
.comments li { flex-direction: column; align-items: flex-start; gap: 2px; }
textarea { flex: 1; border: 1px solid var(--line); border-radius: 8px; padding: 6px 8px; background: var(--bg); resize: vertical; }
.compare-row { display: flex; gap: 12px; padding: 16px 20px; overflow-x: auto; }
.compare-cell { flex: 1 0 min(45vw, 520px); background: var(--panel); border: 1px solid var(--line); border-radius: 12px; overflow: hidden; }
.compare-cell model-viewer { width: 100%; height: 60vh; }
.compare-cell .card-meta { border-top: 1px solid var(--line); }
.toast { position: fixed; bottom: 22px; left: 50%; transform: translateX(-50%); background: var(--ink); color: var(--bg); padding: 10px 16px; border-radius: 10px; z-index: 50; max-width: 80vw; box-shadow: 0 6px 24px rgba(0,0,0,.25); white-space: pre-wrap; }
.toast.err { background: var(--bad); color: #fff; }
.photos { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 6px; }
.photos figure { margin: 0; flex: 1 1 160px; max-width: 48%; }
.photos img { width: 100%; max-height: 260px; object-fit: contain; border-radius: 6px; background: #fff; }
.photos figcaption { font-size: 12px; color: var(--muted); text-align: center; margin-top: 2px; }
.deg { width: 64px; margin-left: 6px; }

/* 在查看器里拖盒子的边/角 */
.edge-msg { color: var(--warn); }
.viewer-stage.cur-ns model-viewer { cursor: ns-resize; } .viewer-stage.cur-ew model-viewer { cursor: ew-resize; }
.viewer-stage.cur-corner model-viewer { cursor: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='28' height='28' viewBox='0 0 28 28'><g stroke='white' stroke-width='4' fill='none' stroke-linecap='round'><path d='M14 14 L14 3 M10 7 L14 3 L18 7 M14 14 L25 14 M21 10 L25 14 L21 18 M14 14 L5 23 M5 17 L5 23 L11 23'/></g><g stroke='black' stroke-width='2' fill='none' stroke-linecap='round'><path d='M14 14 L14 3 M10 7 L14 3 L18 7 M14 14 L25 14 M21 10 L25 14 L21 18 M14 14 L5 23 M5 17 L5 23 L11 23'/></g></svg>") 14 14, move; }
.viewer-stage.cur-no model-viewer { cursor: not-allowed; }
.dv-overlay .hover-edge { stroke: #fff; stroke-width: 4; opacity: 0.9; } .dv-overlay .hover-pt { fill: #fff; stroke: #333; stroke-width: 1.5; }

.action-bar { position: sticky; top: 64px; z-index: 5; border-color: var(--accent); }

.zoom-ctl { position: absolute; left: 10px; top: 10px; z-index: 6; display: flex; align-items: center; gap: 4px; padding: 4px 6px; border-radius: 10px; background: color-mix(in srgb, var(--panel) 85%, transparent); border: 1px solid var(--line); }
.zoom-ctl .num { width: 58px; }

.viewer-stage.cur-move model-viewer { cursor: move; } .viewer-stage.cur-move.dragging model-viewer { cursor: grabbing; }

.box-target-row td { padding-top: 0; } .box-target-row .lbl2 { font-size: 11px; color: var(--muted); padding-left: 18px; }
.box-match { font-size: 11px; margin-left: 6px; } .box-match.good { color: var(--ok); } .box-match.poor { color: var(--bad); }
.box-row.deleted .box-name { text-decoration: line-through; color: var(--muted); } .box-row.deleted .num { opacity: 0.5; }

/* sign-in (REVIEW_AUTH=medusa) */
.login { position: fixed; inset: 0; z-index: 60; background: var(--bg); display: flex; align-items: center; justify-content: center; padding: 16px; }
.login[hidden] { display: none; }
.login-card { background: var(--panel); border: 1px solid var(--line); border-radius: 14px; padding: 28px 28px 24px; width: 360px; max-width: 100%; display: flex; flex-direction: column; gap: 12px; box-shadow: 0 10px 40px rgba(0,0,0,.12); }
.login-card h2 { margin: 0; font-size: 20px; }
.login-card p { margin: 0 0 6px; }
.login-card label { display: flex; flex-direction: column; gap: 4px; font-size: 13px; color: var(--muted); }
.login-card input { border: 1px solid var(--line); border-radius: 8px; padding: 8px 10px; background: var(--bg); color: var(--ink); font-size: 14px; }
.login-card .btn { margin-top: 6px; padding: 9px; }
.login-error { color: var(--bad); font-size: 13px; }

/* 3D generation jobs */
.gen { margin-top: 14px; border: 1px solid var(--line); border-radius: 12px; background: var(--panel); padding: 14px 18px; }
.gen-head { display: flex; gap: 12px; align-items: baseline; flex-wrap: wrap; margin-bottom: 10px; }
.gen-form { display: flex; gap: 16px; align-items: flex-end; flex-wrap: wrap; }
.gen-field { display: flex; flex-direction: column; gap: 4px; font-size: 13px; color: var(--muted); }
.gen-field select, .gen-field input { border: 1px solid var(--line); border-radius: 8px; padding: 6px 8px; background: var(--bg); color: var(--ink); font-size: 13px; min-width: 260px; }
.gen-jobs { margin-top: 12px; display: flex; flex-direction: column; gap: 6px; }
.gen-job { display: grid; grid-template-columns: 170px 110px 1fr; gap: 10px; align-items: baseline; padding: 6px 10px; border: 1px solid var(--line); border-radius: 8px; font-size: 13px; }
.gen-job .st { font-weight: 600; } .gen-job.done .st { color: var(--ok); } .gen-job.failed .st { color: var(--bad); } .gen-job.running .st, .gen-job.queued .st { color: var(--warn); }
.gen-job .res { display: flex; gap: 6px; flex-wrap: wrap; }
.gen-job .res span { border: 1px solid var(--line); border-radius: 999px; padding: 1px 8px; }
.gen-job .res span.done { border-color: var(--ok); } .gen-job .res span.failed { border-color: var(--bad); color: var(--bad); }
