/* ---------------------------------------------------------------------------
   通用弹出层内核样式（配合 dist/ui-dialog.mjs，2026-10-29）

   基础卡片外观（背景、圆角、阴影、::backdrop）沿用 styles.css 里的
   `dialog{…}` / `.modal-head` / `.modal-body` / `.modal-footer`，
   本文件只补内核新增的几种形态：尺寸档位、说明段、数量胶囊、危险色调、
   表单字段、大图预览。这样老的 `.crop-modal` / `.catalog-editor-modal` 皮肤
   一行都不用改，新弹层又不必重复写一遍骨架样式。
--------------------------------------------------------------------------- */

/* 打开期间锁背景滚动。原生 showModal() 挡住的是交互，页面照样能滚，
   不锁的话滚轮一转背景就跑，弹层看起来像浮在动的纸片上。
   scrollbar-gutter 是为了避免「锁滚动 → 滚动条消失 → 整页横向抖一下」。 */
html.ui-dialog-open{overflow:hidden;scrollbar-gutter:stable}

/* 视口居中。不要依赖 UA 的 `position:absolute + inset:0 + margin:auto`：
   元素一旦被换成 absolute/fixed，居中就取决于「包含块」——只要 html/body 或某个
   祖先带了 transform / filter / contain，包含块就不再是视口，卡片会跑到文档中段，
   视口里看起来就是「贴在上方」（用户截图为证）。显式写 fixed + inset:0 + margin:auto，
   包含块永远是视口，打开时、页面滚到任何位置、两层叠加都是同一个位置。 */
.ui-dialog{position:fixed;inset:0;margin:auto;animation:ui-dialog-in .16s ease-out}
@keyframes ui-dialog-in{from{opacity:0;transform:translateY(8px) scale(.985)}to{opacity:1;transform:none}}
@media(prefers-reduced-motion:reduce){.ui-dialog{animation:none}}

/* 尺寸档位：sm 用于确认/提示，md 是默认，lg/xl 给表单与详情，full 给大图 */
.ui-dialog-sm{width:min(440px,calc(100vw - 30px))}
.ui-dialog-md{width:min(580px,calc(100vw - 30px))}
/* lg / xl 服务「长表单、详情」：默认就给到够用的高度，而不是先弹一个矮盒子、
   再让用户在里面滚一个只有三行的窗口。用 min-height 而不是 height ——
   内容少时不会留一大片空白（footer 会被 flex 顶到底部，看起来仍是完整卡片），
   内容多时正文自己滚，标题和按钮始终在位。 */
.ui-dialog-lg{width:min(760px,calc(100vw - 30px));min-height:min(520px,calc(100dvh - 48px))}
.ui-dialog-xl{width:min(1000px,calc(100vw - 30px));min-height:min(640px,calc(100dvh - 48px))}
.ui-dialog-full{width:calc(100vw - 30px);max-width:calc(100vw - 30px);height:calc(100dvh - 30px);max-height:calc(100dvh - 30px)}

/* 三段式：标题 / 正文 / 按钮区各自固定，只有正文滚动。
   没有这一层时正文再长也只是把整张卡片顶到 90dvh 然后整卡滚，
   标题栏靠 sticky 勉强撑住，按钮行在小屏上会被挤出去。 */
.ui-dialog[open]{display:flex;flex-direction:column}
.ui-dialog-head,.ui-dialog-foot{flex:0 0 auto}
.ui-dialog-body{flex:1;min-height:0;overflow:auto}

/* 最大化：桌面端把卡片撑到接近整窗（留一圈让遮罩还看得见），
   长表单/大表格不用再人肉滚一个小窗口。
   尺寸用 100vw/100dvh 而不是 100%：固定定位的包含块把右侧滚动条槽（15px）排除在外，
   用百分比算出来的卡片右边会多出这一条（实测左 14 / 右 29），四边不等宽。 */
.ui-dialog.is-maximized{left:14px;right:auto;top:14px;bottom:auto;width:calc(100vw - 28px);max-width:calc(100vw - 28px);height:calc(100dvh - 28px);max-height:calc(100dvh - 28px);min-height:0;margin:0}
/* 最大化时正文必须吃满剩余高度：老皮肤给 .modal-body 写了 max-height（如 calc(94vh - 130px)），
   不清掉的话最大化后正文仍停在那，按钮下面空出一截。 */
.ui-dialog.is-maximized .ui-dialog-body{max-height:none}

/* 标题栏：标题 + 一句说明；说明可省略。align-items:flex-start 让关闭键贴标题顶。
   .modal-head 原本是 space-between + 居中，多个说明段时会把它顶歪，这里改掉。 */
.ui-dialog-head{align-items:flex-start;gap:14px}
.ui-dialog-heading{display:flex;flex:1;flex-direction:column;gap:4px;min-width:0}
.ui-dialog-heading h2{margin:0}
.ui-dialog-desc{margin:0;color:var(--muted);font-size:var(--fs-control);line-height:1.6}
/* 右上角操作区：最大化 + 关闭。放在一个 flex 里，两个按钮的间距和右边缘对齐才稳定。 */
.ui-dialog-tools{display:flex;flex:0 0 auto;align-items:center;gap:2px;margin:-2px -4px 0 0}
.ui-dialog-close,.ui-dialog-maximize{flex:0 0 auto;width:32px;height:32px}
.ui-dialog-maximize{color:#8b9689}
.ui-dialog-maximize:hover{color:var(--ink)}
/* 已最大化时按钮保持「按下」的样子，用户能一眼看出再点一次是还原 */
.ui-dialog-maximize[aria-pressed="true"]{background:#f1f5eb;color:var(--green)}

/* 数量胶囊：批量操作时「3 个商品 · 共 12 个规格」这类摘要单独一行，
   不塞进正文段落里（塞进去以后数字和说明糊成一片，用户扫不到关键数量）。 */
.ui-dialog-summary{display:inline-block;margin:0;padding:5px 12px;border-radius:999px;background:#f1f5eb;color:var(--green);font-size:var(--fs-control);font-weight:600;line-height:1.6;font-variant-numeric:tabular-nums}
/* 在标题栏里（flex 列）时不能被拉伸成整行宽 */
.ui-dialog-heading .ui-dialog-summary{align-self:flex-start;margin:2px 0 0}

/* 拖拽：标题栏可拖（只有桌面精细指针才有这个手势），拖起来时不要顺手选中标题文字 */
.ui-dialog.is-draggable .ui-dialog-head{cursor:grab}
.ui-dialog.is-dragging .ui-dialog-head{cursor:grabbing}
.ui-dialog.is-dragging{user-select:none}
@media(max-width:640px),(pointer:coarse){.ui-dialog .ui-dialog-head{cursor:auto}}

/* 危险色调：标题栏左侧一道红条，标题保持深色（整块标红反而看不出重点在哪）。
   挂在 .ui-dialog-head 上而不是 dialog 上 —— 挂 dialog 会从标题一直拉到按钮区，
   看着像一条贯穿边框；只圈住标题栏才像「这层在警告你」。 */
.ui-dialog.is-danger .ui-dialog-head{position:relative}
.ui-dialog.is-danger .ui-dialog-head::before{content:"";position:absolute;left:0;top:16px;bottom:14px;width:3px;border-radius:0 3px 3px 0;background:#b33f36}

/* 按钮行：确认类弹层的主次按钮 */
.ui-dialog-foot .btn{margin-top:0;min-height:38px;padding:8px 18px}
.ui-dialog-foot .btn.danger{background:#b33f36;border-color:#b33f36;color:#fff}
.ui-dialog-foot .btn.danger:hover{background:#9c342c;border-color:#9c342c}
.ui-dialog-foot .btn:focus-visible{outline:2px solid var(--green);outline-offset:2px}

/* 弹层内的表单字段：活动日期、商品命名这类 2~4 个字段的小表单直接复用，
   不必每个弹层自己写一遍 input 样式。 */
.ui-dialog-fields{display:grid;gap:12px}
.ui-dialog-fields label{display:grid;gap:6px;font-size:var(--fs-control);color:var(--muted)}
.ui-dialog-fields input,.ui-dialog-fields select,.ui-dialog-fields textarea{box-sizing:border-box;width:100%;min-height:42px;padding:9px 11px;border:1px solid var(--line);border-radius:9px;font:inherit;color:var(--ink);background:#fff}
.ui-dialog-fields input:focus,.ui-dialog-fields select:focus,.ui-dialog-fields textarea:focus{outline:2px solid #b9cbb2;outline-offset:0}
.ui-dialog-hint{margin:-4px 0 0;font-size:var(--fs-caption);line-height:1.5;color:var(--muted)}

/* 单字段弹层（prompt）：一个标签 + 一个输入框，不需要 .ui-dialog-fields 那套网格 */
.ui-dialog-field{display:grid;gap:7px}
.ui-dialog-field-label{font-size:var(--fs-control);color:var(--muted)}
.ui-dialog-input{box-sizing:border-box;width:100%;min-height:42px;padding:9px 11px;border:1px solid var(--line);border-radius:9px;font:inherit;color:var(--ink);background:#fff}
textarea.ui-dialog-input{min-height:96px;line-height:1.7;resize:vertical}
.ui-dialog-input:focus{outline:2px solid #b9cbb2;outline-offset:0}
.ui-dialog-input::placeholder{color:#b3bab0}

/* 大图预览：整屏深色，图片居中；空白处可点，图片本身不关。
   dialog 用 flex 撑满，body 与 figure 都 pointer-events:none —— 这样点空白时
   target 直接是 dialog 本身，内核据此判断「点了遮罩」。
   （踩过：只给 figure 关掉指针事件还不够，.ui-dialog-body 本身铺满整层且有背景，
   点上去 target 是 body，于是「点空白关不掉」。） */
.ui-dialog.is-image{display:flex;flex-direction:column;width:100vw;max-width:100vw;height:100dvh;max-height:100dvh;padding:0;border:0;border-radius:0;background:transparent;box-shadow:none;overflow:visible}
.ui-dialog.is-image::backdrop{background:rgba(14,18,16,.9)}
.ui-dialog.is-image .ui-dialog-body{flex:1;min-height:0;display:flex;padding:0;overflow:visible;background:transparent;pointer-events:none}
.ui-lightbox{flex:1;display:grid;grid-template-rows:1fr auto;justify-items:center;align-items:center;gap:12px;width:100%;min-height:0;margin:0;padding:52px 20px 20px;pointer-events:none}
.ui-lightbox img{max-width:100%;max-height:100%;object-fit:contain;border-radius:10px;background:#fff;box-shadow:0 24px 80px rgba(0,0,0,.45);pointer-events:auto;cursor:default}
.ui-lightbox figcaption{max-width:min(900px,90vw);color:rgba(255,255,255,.86);font-size:var(--fs-control);line-height:1.6;text-align:center;pointer-events:auto}
.ui-lightbox-close{position:absolute;top:14px;right:14px;display:grid;place-items:center;width:38px;height:38px;border:1px solid rgba(255,255,255,.35);border-radius:50%;background:rgba(255,255,255,.12);color:#fff}
.ui-lightbox-close:hover{background:rgba(255,255,255,.22);filter:none}

/* 手机：弹层贴边、按钮平分一行（拇指不用横着找「确定」在哪） */
@media(max-width:640px){
  .ui-dialog-sm,.ui-dialog-md,.ui-dialog-lg,.ui-dialog-xl{width:calc(100vw - 20px);min-height:0}
  /* 手机屏幕上「最大化」没有意义（卡片本来就贴边），藏掉省一个误触目标 */
  .ui-dialog-maximize{display:none}
  .ui-dialog-head{padding:18px 18px 14px}
  .ui-dialog-body{padding:18px}
  .ui-dialog-foot{flex-wrap:wrap;padding:14px 18px}
  .ui-dialog-foot .btn{flex:1;min-height:40px;padding:9px 10px}
  .ui-lightbox{padding:48px 10px 14px}
}

/* 弹层内的错误提示：表单提交失败时显示在这里，而不是被弹层盖住的页面顶部 notice */
.ui-dialog-error{margin:0 0 12px;padding:9px 12px;border-radius:9px;background:#fdf0ee;color:#a5352b;font-size:var(--fs-control);line-height:1.6}
