@charset "UTF-8";
/* =============================================================================
   TGR VN 官方管理控制台
   设计取向: 企业级 / 官方感 —— 黑色品牌侧栏, 克制的红色强调, 高密度数据表。
   红色只用于主操作与当前态, 不铺面积; 层级靠排版与分隔线, 不靠重阴影。
   所有颜色集中在 :root, 禁止在组件里散落写死色值。
   ============================================================================= */

:root {
    /* 品牌(取自官方 logo) */
    --ad-brand:        #D81319;
    --ad-brand-dark:   #9E0C0E;
    --ad-brand-light:  #F0231C;
    --ad-brand-soft:   #FDECEC;
    --ad-accent:       #ED7620;   /* 虎头橙, 仅用于次级强调 */

    /* 侧栏 */
    --ad-nav-bg:       #16181C;
    --ad-nav-bg-deep:  #0F1114;
    --ad-nav-text:     #A8AEB8;
    --ad-nav-text-hi:  #FFFFFF;
    --ad-nav-hover:    rgba(255, 255, 255, .06);
    --ad-nav-active:   rgba(216, 19, 25, .16);
    --ad-nav-border:   rgba(255, 255, 255, .07);

    /* 页面 */
    --ad-bg:           #F4F5F7;
    --ad-surface:      #FFFFFF;
    --ad-surface-alt:  #FAFBFC;
    --ad-border:       #E3E5E8;
    --ad-border-dark:  #D2D5DA;

    /* 文字 */
    --ad-text:         #1F2329;
    --ad-text-2:       #5A6169;
    --ad-text-3:       #8A9199;

    /* 语义 */
    --ad-success:      #12794F;
    --ad-success-bg:   #E6F4EC;
    --ad-warning:      #9A6700;
    --ad-warning-bg:   #FCF3DC;
    --ad-danger:       #B3261E;
    --ad-danger-bg:    #FCEAE8;
    --ad-info:         #1F5FA9;
    --ad-info-bg:      #E8F1FB;
    --ad-neutral:      #62696F;
    --ad-neutral-bg:   #EEF0F2;

    /* 度量 */
    --ad-nav-w:        236px;
    --ad-top-h:        56px;
    --ad-radius:       6px;
    --ad-radius-sm:    4px;
    --ad-shadow:       0 1px 2px rgba(16, 24, 40, .05);
    --ad-shadow-pop:   0 8px 24px rgba(16, 24, 40, .12);
    --ad-mono:         "SF Mono", SFMono-Regular, ui-monospace, Consolas, "Courier New", monospace;
}

* { box-sizing: border-box; }

html, body { height: 100%; }

/*
 * ★ 滚动条常驻, 别让页面左右弹 ★(2026-09-22)
 *
 * 页面变长一点就冒出竖滚动条、变短一点又收回去, 每收放一次内容区就宽窄 15 像素左右,
 * 整页所有东西横向跳一下。标签编辑器上最明显: 勾掉一个要素 -> 提醒少一条 -> 页面变短 ->
 * 滚动条消失 -> 画布连着整页往右弹。
 *
 * scrollbar-gutter 不认得的旧浏览器会忽略这一行, 行为与今天完全一样, 没有退化风险。
 */
html { scrollbar-gutter: stable; }

body {
    margin: 0;
    background: var(--ad-bg);
    color: var(--ad-text);
    font: 14px/1.55 -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
          "Hiragino Sans GB", "Microsoft YaHei", Roboto, "Helvetica Neue", Arial, sans-serif;
    -webkit-font-smoothing: antialiased;
}

a { color: var(--ad-brand); text-decoration: none; }
a:hover { color: var(--ad-brand-dark); }

img { max-width: 100%; }

/* =============================================================================
   1. 整体骨架
   ============================================================================= */

.tga-shell {
    display: flex;
    min-height: 100vh;
}

.tga-main {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

/* =============================================================================
   2. 品牌侧栏
   ============================================================================= */

.tga-sidebar {
    width: var(--ad-nav-w);
    flex-shrink: 0;
    background: var(--ad-nav-bg);
    color: var(--ad-nav-text);
    display: flex;
    flex-direction: column;
    position: sticky;
    top: 0;
    height: 100vh;
}

.tga-sidebar-brand {
    height: var(--ad-top-h);
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 0 18px;
    border-bottom: 1px solid var(--ad-nav-border);
    background: var(--ad-nav-bg-deep);
    flex-shrink: 0;
}

.tga-sidebar-brand img {
    height: 26px;
    width: auto;
    max-width: 140px;
    object-fit: contain;
    display: block;
}

.tga-sidebar-brand .tga-brand-text {
    font-size: 17px;
    font-weight: 800;
    letter-spacing: 2px;
    color: #fff;
}

.tga-sidebar-brand .tga-brand-env {
    margin-left: auto;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .6px;
    text-transform: uppercase;
    color: var(--ad-accent);
    border: 1px solid rgba(237, 118, 32, .45);
    border-radius: 3px;
    padding: 1px 5px;
    line-height: 1.5;
}

.tga-nav {
    flex: 1;
    overflow-y: auto;
    padding: 12px 0 24px;
}

.tga-nav::-webkit-scrollbar { width: 6px; }
.tga-nav::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, .13); border-radius: 3px; }

/* 分组: <details> 折叠, 默认只展开当前页面所在的组 */
.tga-nav-section { margin: 0; }

.tga-nav-group {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 14px 10px 18px;
    color: var(--ad-nav-text);
    font-size: 13.5px;
    line-height: 1.4;
    cursor: pointer;
    list-style: none;
    user-select: none;
    border-left: 3px solid transparent;
    transition: background .12s, color .12s;
}

.tga-nav-group::-webkit-details-marker { display: none; }
.tga-nav-group::marker { content: ''; }

.tga-nav-group:hover {
    background: var(--ad-nav-hover);
    color: var(--ad-nav-text-hi);
}

.tga-nav-group:focus-visible,
.tga-nav-item:focus-visible {
    outline: 2px solid var(--ad-brand);
    outline-offset: -2px;
}

/* 当前页面在这一组里: 组名提亮, 收起时也看得出「我在这儿」 */
.tga-nav-section.is-current > .tga-nav-group { color: var(--ad-nav-text-hi); font-weight: 600; }

/* 当前分组的标题会加粗到 600, 越南语「Quyết toán với cửa hàng」因此折成两行, 这一组比别的组高出一截
   (2026-09-20 布局修复 L18)。宁可截断也不换行, 全名放 title 里 */
.tga-nav-group-label {
    flex: 1;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.tga-nav-caret {
    display: inline-flex;
    opacity: .55;
    transition: transform .26s cubic-bezier(.4, 0, .2, 1);   /* 与分组高度动画同一条曲线、同样时长 */
}

/* 箭头跟着 is-open 走(脚本在动画开始时就切换它); 没有脚本时退回看 [open] */
.tga-nav-section.is-open > .tga-nav-group .tga-nav-caret,
.tga-nav:not(.is-scripted) .tga-nav-section[open] > .tga-nav-group .tga-nav-caret { transform: rotate(180deg); }

/* 展开 / 收起的高度动画作用在 .tga-nav-sub 上(见布局脚本), 所以它自己不能有内边距 */
.tga-nav-sub { padding: 0; }
.tga-nav-sub-inner { padding: 2px 0 6px; }

.tga-nav-top { margin-bottom: 2px; }

.tga-nav-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 18px;
    color: var(--ad-nav-text);
    font-size: 13.5px;
    line-height: 1.4;
    border-left: 3px solid transparent;
    transition: background .12s, color .12s;
}

.tga-nav-item:hover {
    background: var(--ad-nav-hover);
    color: var(--ad-nav-text-hi);
}

.tga-nav-item.is-active {
    background: var(--ad-nav-active);
    border-left-color: var(--ad-brand);
    color: #fff;
    font-weight: 600;
}

/* 组下面的条目不带图标, 对齐到组名文字 */
.tga-nav-subitem {
    padding: 7px 18px 7px 46px;
    font-size: 13px;
}

.tga-nav-icon {
    width: 18px;
    height: 18px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    opacity: .9;
}

.tga-nav-icon svg,
.tga-nav-caret svg { display: block; }

.tga-nav-foot {
    padding: 12px 18px;
    border-top: 1px solid var(--ad-nav-border);
    font-size: 11px;
    color: rgba(255, 255, 255, .3);
    flex-shrink: 0;
}

/* =============================================================================
   3. 顶栏
   ============================================================================= */

.tga-topbar {
    height: var(--ad-top-h);
    background: var(--ad-surface);
    border-bottom: 1px solid var(--ad-border);
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 0 24px;
    position: sticky;
    top: 0;
    z-index: 20;
}

.tga-topbar-title {
    font-size: 15px;
    font-weight: 600;
    color: var(--ad-text);
}

.tga-topbar-spacer { flex: 1; }

.tga-lang {
    display: flex;
    border: 1px solid var(--ad-border-dark);
    border-radius: var(--ad-radius-sm);
    overflow: hidden;
}

.tga-lang a {
    padding: 5px 10px;
    font-size: 12px;
    color: var(--ad-text-2);
    line-height: 1.4;
    background: var(--ad-surface);
    white-space: nowrap;
}

.tga-lang a + a { border-left: 1px solid var(--ad-border); }
.tga-lang a:hover { background: var(--ad-surface-alt); }

.tga-lang a.is-active {
    background: var(--ad-brand);
    color: #fff;
    font-weight: 600;
}

/* 头像菜单(<details>): 个人设置 / 退出登录 */
.tga-user-menu {
    position: relative;
    padding-left: 12px;
    border-left: 1px solid var(--ad-border);
}

.tga-user {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 4px 6px;
    border-radius: var(--ad-radius-sm);
    cursor: pointer;
    list-style: none;
    user-select: none;
}

.tga-user::-webkit-details-marker { display: none; }
.tga-user::marker { content: ''; }
.tga-user:hover { background: var(--ad-surface-alt); }
.tga-user:focus-visible { outline: 2px solid var(--ad-brand); outline-offset: 1px; }

.tga-user-meta { display: flex; flex-direction: column; }

.tga-user-caret {
    display: inline-flex;
    color: var(--ad-text-3);
    transition: transform .2s cubic-bezier(.2, .8, .2, 1);
}

.tga-user-caret svg { display: block; }
.tga-user-menu[open] .tga-user-caret { transform: rotate(180deg); }

.tga-user-pop {
    position: absolute;
    right: 0;
    top: calc(100% + 6px);
    min-width: 180px;
    padding: 6px 0;
    background: var(--ad-surface);
    border: 1px solid var(--ad-border);
    border-radius: var(--ad-radius);
    box-shadow: var(--ad-shadow-pop);
    z-index: 70;
    transform-origin: top right;
}

/* 展开时淡入并轻微下滑(收起是瞬间的: <details> 一关内容就不渲染了) */
.tga-user-menu[open] > .tga-user-pop { animation: tga-pop-in .18s cubic-bezier(.2, .8, .2, 1); }

@keyframes tga-pop-in {
    from { opacity: 0; transform: translateY(-6px) scale(.98); }
    to   { opacity: 1; transform: none; }
}

.tga-user-pop form { margin: 0; }

.tga-user-pop-item {
    display: block;
    width: 100%;
    padding: 8px 16px;
    border: 0;
    background: none;
    color: var(--ad-text);
    font: inherit;
    font-size: 13px;
    text-align: left;
    cursor: pointer;
}

.tga-user-pop-item:hover { background: var(--ad-surface-alt); }
.tga-user-pop-item.is-active { color: var(--ad-brand); font-weight: 600; }
.tga-user-pop form .tga-user-pop-item { border-top: 1px solid var(--ad-border); }

.tga-avatar {
    width: 30px;
    height: 30px;
    border-radius: 50%;
    background: var(--ad-brand);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 13px;
    font-weight: 700;
    flex-shrink: 0;
}

.tga-user-name { font-size: 13px; font-weight: 600; line-height: 1.3; }
.tga-user-role { font-size: 11px; color: var(--ad-text-3); line-height: 1.3; }

/* =============================================================================
   4. 内容区
   ============================================================================= */

.tga-content {
    flex: 1;
    padding: 20px 24px 40px;
    min-width: 0;
}

.tga-stack > * + * { margin-top: 16px; }

/* 左右两栏里一栏叠了多张卡片时, 这一摞的总高度和对面那张卡片对不上, 底边差出几十到上百像素
   (2026-09-20 布局修复 L22)。加 is-fill 让最后一张卡片吃掉剩余高度, 两栏底边就齐了。
   只给需要的页面加这个修饰类: SN 详情那种右栏本来就比左栏高的, 拉伸反而多出一块空白 */
.tga-stack.is-fill { display: flex; flex-direction: column; }
.tga-stack.is-fill > :last-child { flex: 1; }

.tga-page-head {
    display: flex;
    align-items: flex-start;
    gap: 16px;
    margin-bottom: 16px;
}

/* 标题块自己折行, 不去挤按钮区(2026-09-20 布局修复 L57):
   越南语副标题很长, 左块不写 flex 时它的 max-content 极大, flex 就去压右边的按钮区,
   压到单个按钮宽度后按钮开始竖排, 旁边却空着一大片 */
.tga-page-head > :first-child { flex: 1 1 auto; min-width: 0; }

.tga-page-title {
    font-size: 20px;
    font-weight: 700;
    letter-spacing: -.2px;
    line-height: 1.3;
    margin: 0;
}

.tga-page-sub {
    font-size: 13px;
    color: var(--ad-text-2);
    margin-top: 3px;
}

/* 按钮多的页头(SN 序列号有五个)放不下时换行, 不把标题挤没。
   不要加 min-width:0: 那样按钮区能被压得比单个按钮还窄, 按钮会向左溢出、压进标题;
   默认的 min-width:auto 对会换行的 flex 容器就是「最宽的那一个按钮」 */
.tga-page-actions {
    margin-left: auto;
    flex-shrink: 0;
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 8px;
}

.tga-breadcrumb {
    font-size: 12px;
    color: var(--ad-text-3);
    margin-bottom: 6px;
}

.tga-breadcrumb a { color: var(--ad-text-3); }
.tga-breadcrumb a:hover { color: var(--ad-brand); }
.tga-breadcrumb span + span::before { content: "/"; margin: 0 6px; opacity: .6; }

/* =============================================================================
   5. 卡片
   ============================================================================= */

.tga-card {
    background: var(--ad-surface);
    border: 1px solid var(--ad-border);
    border-radius: var(--ad-radius);
    box-shadow: var(--ad-shadow);
}

.tga-card-head {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 13px 18px;
    border-bottom: 1px solid var(--ad-border);
}

.tga-card-title {
    font-size: 14px;
    font-weight: 600;
    margin: 0;
}

/* 卡片头右侧放长提示时(SN 详情的扫码记录), 提示会把标题挤窄, 越南语标题折成两行
   (2026-09-20 布局修复 L29)。标题不让缩、不让换行, 要挤就挤右边的提示 */
.tga-card-head .tga-card-title { flex-shrink: 0; white-space: nowrap; }

.tga-card-head .tga-card-actions {
    margin-left: auto;
    display: flex;
    gap: 8px;
    min-width: 0;
    text-align: right;
}

.tga-card-body { padding: 18px; }
.tga-card-body.is-flush { padding: 0; }

/* =============================================================================
   6. 统计磁贴
   ============================================================================= */

.tga-stats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: 12px;
}

/* 半宽卡片里放 3 块磁贴时, auto-fit 在 1280 宽下只排得下 2 块, 第 3 块单独掉到第二行
   (2026-09-20 布局修复 L32)。这种固定块数的就别自适应了 */
.tga-stats.is-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }

/* 工作台那 6 块: auto-fit 在 1280 下排成 5+1, 第 6 块孤零零占左边、右侧空出约 800px
   (2026-09-20 布局修复 L68)。按 6 的因数分档, 每一档都排得满 */
.tga-stats.is-6 { grid-template-columns: repeat(6, minmax(0, 1fr)); }

@media (max-width: 1400px) {
    .tga-stats.is-6 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* 窄到这儿, 固定列数反而把每块压到放不下越南语标签(500px 下三块各 136px), 退回单列 */
@media (max-width: 560px) {
    .tga-stats.is-3,
    .tga-stats.is-6 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 400px) {
    .tga-stats.is-3,
    .tga-stats.is-6 { grid-template-columns: 1fr; }
}

/* 一排磁贴里, 标签换行的那块(越南语常见)会把数字往下推, 数字就不在一条线上了(2026-09-20 布局修复 L63 / L68)。
   用固定的三行轨道: 标签区高度统一(两行的高度), 数值行因此永远对齐, 说明挂在最后一行 */
.tga-stat {
    background: var(--ad-surface);
    border: 1px solid var(--ad-border);
    border-radius: var(--ad-radius);
    padding: 14px 16px;
    box-shadow: var(--ad-shadow);
    position: relative;
    overflow: hidden;
    display: grid;
    grid-template-rows: 36px auto 1fr;
    align-content: start;
}

.tga-stat::before {
    content: "";
    position: absolute;
    left: 0; top: 0; bottom: 0;
    width: 3px;
    background: var(--ad-border-dark);
}

.tga-stat.is-brand::before   { background: var(--ad-brand); }
.tga-stat.is-success::before { background: var(--ad-success); }
.tga-stat.is-warning::before { background: var(--ad-warning); }
.tga-stat.is-danger::before  { background: var(--ad-danger); }
.tga-stat.is-info::before    { background: var(--ad-info); }

.tga-stat-label {
    font-size: 12px;
    line-height: 1.4;
    color: var(--ad-text-2);
    margin-bottom: 0;
    align-self: start;
}

.tga-stat-value {
    font-size: 24px;
    font-weight: 700;
    line-height: 1.15;
    font-variant-numeric: tabular-nums;
    letter-spacing: -.4px;
}

.tga-stat-hint { font-size: 11px; color: var(--ad-text-3); margin-top: 4px; }

/* =============================================================================
   7. 筛选区
   ============================================================================= */

.tga-filter { padding: 16px 18px; }

/* 筛选栏: 每格是「标签 + 控件」, 底部对齐是为了让「搜索 / 重置」按钮与输入框齐平。
   但有的筛选格挂了 .tga-hint 说明, 底部对齐会把它的输入框整体顶高(收款账户列表错位过, 2026-09-20 布局修复 L56)。
   改法: 每格用固定的三行轨道(标签 / 控件 / 说明), 控件行永远在同一条水平线上, 说明挂在下面不影响别人 */
.tga-filter-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: 12px 14px;
    align-items: start;
}

.tga-filter-grid > .tga-field {
    display: grid;
    grid-template-rows: 22px auto auto;
    align-content: start;
}

.tga-filter-grid > .tga-field > .tga-label { margin-bottom: 0; align-self: end; }
.tga-filter-grid > .tga-field > .tga-hint { margin-top: 4px; }

/* 关键词搜索这类要宽一点的筛选格。原来各页写内联 style="grid-column:span 2",
   窄屏媒体查询盖不过内联样式, 500px 下整排筛选仍是两列、每列只剩 143px
   (2026-09-20 布局修复 L65)。改成类, 窄屏就能收回单列 */
.tga-filter-grid > .is-wide { grid-column: span 2; }

@media (max-width: 720px) {
    .tga-filter-grid { grid-template-columns: 1fr; }
    .tga-filter-grid > .is-wide { grid-column: auto; }
}

/* 表单网格(编辑 / 新建页用这个, 不要借筛选栏的 .tga-filter-grid, 2026-09-20 布局修复 L01)。
   与筛选栏的两点不同: 顶部对齐 —— 带说明的字段不会把同一行别的字段往下推;
   列更宽 —— 一行 3~4 列而不是 5~7 列, 越南语的说明不会被挤成一字一行。
   .is-wide 占两列(长名称、成对字段), .is-full 占整行(地址、备注) */
.tga-form-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    gap: 16px 20px;
    align-items: start;
}

.tga-form-grid > .is-wide { grid-column: span 2; }
.tga-form-grid > .is-full { grid-column: 1 / -1; }

/* 没有标签的格子(复选框、按钮): 与同行输入框顶部对齐, 不要再用 &nbsp; 假标签占位 */
.tga-form-grid > .is-check { padding-top: 27px; }

@media (max-width: 720px) {
    .tga-form-grid { grid-template-columns: 1fr; }
    .tga-form-grid > .is-wide { grid-column: auto; }
    .tga-form-grid > .is-check { padding-top: 0; }
}

.tga-field { min-width: 0; }

.tga-label {
    display: block;
    font-size: 12px;
    font-weight: 600;
    color: var(--ad-text-2);
    margin-bottom: 5px;
}

/* 必填星号原来只在 .tga-label 里是红的, 卡片标题里的星号(订单录入「商品明细*」)是黑的
   (2026-09-20 布局修复 L24)。改成只要是 .req 就红 */
.req { color: var(--ad-danger); margin-left: 2px; }
.tga-label .opt { color: var(--ad-text-3); font-weight: 400; margin-left: 4px; }

/* 表单操作栏: 各页原来自己拼(有的在卡片里、有的在卡片外、间距各不相同)
   (2026-09-20 布局修复 L19)。统一成「主按钮 + 取消」放在所有表单卡片之后 */
.tga-form-actions {
    display: flex;
    gap: 8px;
    align-items: center;
    margin-top: 16px;
}

/*
 * ★ 吸顶的保存条 ★(2026-09-22)
 *
 * 给很长的表单用(标签模板编辑页: 左栏一堆字段、右栏画布加面板加提示)。
 * 按钮摆在表单开头并跟着滚动条走, 改到哪都能当场存 ——
 * 用户原话:「提交按钮放页面上面, 每次提交都下拉到最下面操作不方便」。
 *
 * top 要避开那条同样 sticky 的顶栏(.tga-topbar, 高 --ad-top-h, z-index 20),
 * 所以这里贴在它下面、层级压它一级。左右各撑开 24px 的负边距再补回来,
 * 是为了让吸顶时的白条盖满整个内容栏, 不然滚动内容会从两边缝里透出来。
 */
.tga-form-actions.is-sticky {
    position: sticky;
    top: var(--ad-top-h);
    z-index: 15;
    margin: 0 -24px 16px;
    padding: 12px 24px;
    background: var(--ad-surface);
    border-bottom: 1px solid var(--ad-border);
}

/* 表单里直接堆叠的字段原来没有默认下边距, 售后详情的结案表单里文本域几乎贴着下一个标签
   (2026-09-20 布局修复 L27)。给表单的直接子元素补上纵向节奏 */
.tga-form-stack > .tga-field,
.tga-form-stack > .tga-form-grid,
.tga-form-stack > .tga-textarea { margin-bottom: 12px; }
.tga-form-stack > .tga-form-actions { margin-top: 0; }

.tga-input,
.tga-select,
.tga-textarea {
    width: 100%;
    min-height: 36px;
    padding: 7px 11px;
    border: 1px solid var(--ad-border-dark);
    border-radius: var(--ad-radius-sm);
    font-size: 13.5px;
    font-family: inherit;
    color: var(--ad-text);
    background: var(--ad-surface);
    -webkit-appearance: none;
    appearance: none;
}

.tga-textarea { min-height: 84px; resize: vertical; line-height: 1.6; }

.tga-select {
    background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath fill='none' stroke='%235A6169' stroke-width='1.6' d='M1 1.5l5 5 5-5'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 10px center;
    background-size: 11px;
    padding-right: 30px;
}

.tga-input:focus,
.tga-select:focus,
.tga-textarea:focus {
    outline: 0;
    border-color: var(--ad-brand);
    box-shadow: 0 0 0 3px rgba(216, 19, 25, .1);
}

.tga-input:disabled,
.tga-select:disabled { background: var(--ad-surface-alt); color: var(--ad-text-3); }

/* readonly 原来长得和可编辑的输入框一模一样(已锁定批次的批次号、生产日期), 用户看不出哪些改不了
   (2026-09-20 布局修复 L17)。与 :disabled 用同一套灰底, 只是文字不那么浅 —— 内容还是要能看清 */
.tga-input[readonly],
.tga-textarea[readonly] {
    background: var(--ad-surface-alt);
    color: var(--ad-text-2);
    cursor: default;
}

.tga-input[readonly]:focus,
.tga-textarea[readonly]:focus { box-shadow: none; border-color: var(--ad-border-dark); }

/* 文件选择框套 .tga-input 的内边距后有 42px 高, 比旁边 36px 的按钮高出一截
   (2026-09-20 布局修复 L20) */
.tga-input[type="file"] { padding: 3px 4px; line-height: 28px; }

.tga-input[type="file"]::-webkit-file-upload-button {
    height: 28px;
    margin-right: 10px;
    padding: 0 12px;
    border: 1px solid var(--ad-border-dark);
    border-radius: var(--ad-radius-sm);
    background: var(--ad-surface-alt);
    font: inherit;
    color: var(--ad-text-2);
    cursor: pointer;
}

.tga-input.is-mono { font-family: var(--ad-mono); letter-spacing: .3px; }

/* 等宽字体 + 字间距只该管用户填进去的编号, 占位文字用它会显著变宽被截断
   (2026-09-20 布局修复 L21) */
.tga-input.is-mono::placeholder { font-family: inherit; letter-spacing: 0; }

.tga-hint { font-size: 11.5px; color: var(--ad-text-3); margin-top: 4px; }

/* 字段旁边那一行红字。原来是 11.5px 的小字, 和它上面那行灰色说明一个体量 ——
   走查里两个人都没看见。加粗 + 前面一个红点, 12.5px: 它是「这一格错了」,
   不是「这一格的补充说明」, 不该和 .tga-hint 长得一样(2026-09-22 合并轮) */
.tga-error-text {
    font-size: 12.5px;
    font-weight: 600;
    color: var(--ad-danger);
    margin-top: 4px;
    line-height: 1.5;
}

/* 出入库页拿 .tga-error-text 当 JS 的消息槽(空着挂在那里), 空的时候不要那个点 */
.tga-error-text:empty::before { display: none; }

.tga-error-text::before {
    content: "";
    display: inline-block;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--ad-danger);
    margin-right: 6px;
    vertical-align: middle;
}

/* 出错的控件本身。只有一行小字的时候, 人得逐格对照才知道是哪一格;
   红边框 + 淡红光晕一眼就找得到。类由 assets/js/form-errors.js 挂上去,
   它顺着汇总条里的 data-name / 锚点找到真正的控件 */
.tga-input.is-error,
.tga-select.is-error,
.tga-textarea.is-error {
    border-color: var(--ad-danger);
    background: var(--ad-danger-bg);
}

.tga-input.is-error:focus,
.tga-select.is-error:focus,
.tga-textarea.is-error:focus {
    border-color: var(--ad-danger);
    box-shadow: 0 0 0 3px rgba(179, 38, 30, .16);
}

/* =============================================================================
   页顶错误汇总条(view/admin/_form_errors.php)
   -----------------------------------------------------------------------------
   为什么不复用 .tga-alert-danger: 那是一句话的提示条, 这里要摆一张可点的清单,
   而且要比提示条更重 —— 它是「这一次没存上」的唯一入口。
   ============================================================================= */

.tga-fe {
    background: var(--ad-danger-bg);
    border: 1px solid #F0C4C0;
    border-left: 4px solid var(--ad-danger);
    border-radius: var(--ad-radius-sm);
    padding: 12px 16px;
    margin-bottom: 16px;
}

/* 起手时脚本会把焦点放到整条上(tabindex=-1), 焦点环要看得见 —— 读屏之外,
   键盘用户下一个 Tab 就落在第一条错误上, 看不见焦点的话这一步是盲的 */
.tga-fe:focus { outline: 2px solid var(--ad-danger); outline-offset: 2px; }
.tga-fe:focus:not(:focus-visible) { outline: 2px solid var(--ad-danger); }

.tga-fe-head { display: flex; align-items: flex-start; gap: 10px; }

.tga-fe-icon {
    flex-shrink: 0;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: var(--ad-danger);
    color: #fff;
    font-size: 12px;
    font-weight: 700;
    line-height: 18px;
    text-align: center;
}

.tga-fe-headtext { min-width: 0; }
.tga-fe-title { font-size: 14px; font-weight: 600; color: var(--ad-danger); }
.tga-fe-hint { font-size: 12px; color: var(--ad-text-2); margin-top: 2px; }

.tga-fe-list {
    margin: 8px 0 0;
    padding-left: 28px;
    list-style: disc;
}

.tga-fe-list li { margin-top: 5px; }
.tga-fe-list li::marker { color: var(--ad-danger); }

.tga-fe-item {
    color: var(--ad-danger);
    font-size: 13px;
    line-height: 1.6;
    text-decoration: underline;
    text-underline-offset: 2px;
}

.tga-fe-item:hover { color: #8C1A14; }

/* 字段名由脚本从页面上真实的 <label> 读回来补在前面 —— 服务端不重复维护一份字段名表,
   也就不会出现「表单上叫 A、汇总条里叫 B」 */
.tga-fe-label { font-weight: 700; }
.tga-fe-label::after { content: ":"; margin-right: 5px; }

.tga-filter-actions {
    display: flex;
    gap: 8px;
    align-items: center;
}

/* =============================================================================
   8. 按钮
   ============================================================================= */

.tga-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    height: 36px;
    padding: 0 16px;
    border: 1px solid transparent;
    border-radius: var(--ad-radius-sm);
    font-size: 13.5px;
    font-weight: 600;
    font-family: inherit;
    line-height: 1;
    cursor: pointer;
    white-space: nowrap;
    transition: background .12s, border-color .12s, color .12s;
    -webkit-appearance: none;
}

.tga-btn-primary {
    background: var(--ad-brand);
    color: #fff;
}
.tga-btn-primary:hover { background: var(--ad-brand-dark); color: #fff; }

.tga-btn-default {
    background: var(--ad-surface);
    border-color: var(--ad-border-dark);
    color: var(--ad-text);
}
.tga-btn-default:hover { background: var(--ad-surface-alt); border-color: #B9BDC4; color: var(--ad-text); }

.tga-btn-danger {
    background: var(--ad-surface);
    border-color: #E6B4B0;
    color: var(--ad-danger);
}
.tga-btn-danger:hover { background: var(--ad-danger-bg); color: var(--ad-danger); }

.tga-btn-ghost {
    background: transparent;
    color: var(--ad-text-2);
    padding: 0 8px;
}
.tga-btn-ghost:hover { background: var(--ad-neutral-bg); color: var(--ad-text); }

.tga-btn-sm { height: 28px; padding: 0 10px; font-size: 12.5px; }

.tga-btn:disabled,
.tga-btn.is-disabled { opacity: .45; cursor: not-allowed; pointer-events: none; }

/* 上面的 display:inline-flex 会盖掉浏览器对 [hidden] 的 display:none ——
   与 .tga-alert[hidden] 是同一个坑(2026-09-22 在「检查全部模板」的停止按钮上又踩了一次:
   JS 把它设成 hidden, DOM 上 hidden=true, 屏幕上照样是两个按钮)。
   受益的不止这一页: view/admin/order/form.php 的「添加明细」本意是
   「没有 JS 时不显示」(JS 起来再 add.hidden = false), 这条补上之前它一直显示着,
   没有 JS 的人点它什么也不会发生。 */
.tga-btn[hidden] { display: none; }

/* 表格行内操作 */
.tga-row-actions { display: flex; gap: 2px; flex-wrap: wrap; }

/* 宽表横向滚动时把「操作」列钉在右边(2026-09-20 布局修复 L55):
   越南语下结算单、待结算、安装单列表的操作列本来整列滚到了屏幕外, 用户以为没有操作入口。
   表头和单元格都要钉, 背景不能透明, 否则底下的内容会透出来 */
.tga-table th.is-sticky-actions,
.tga-table td.is-sticky-actions {
    position: sticky;
    right: 0;
    z-index: 2;
    background: var(--ad-surface);
    box-shadow: -8px 0 8px -8px rgba(15, 23, 42, .18);
}

.tga-table th.is-sticky-actions { background: var(--ad-surface-alt); }
.tga-table tbody tr:hover td.is-sticky-actions { background: #FAFAFB; }

.tga-link-action {
    font-size: 12.5px;
    color: var(--ad-brand);
    padding: 2px 6px;
    border-radius: 3px;
    cursor: pointer;
    background: none;
    border: 0;
    font-family: inherit;
}
.tga-link-action:hover { background: var(--ad-brand-soft); }
.tga-link-action.is-muted { color: var(--ad-text-2); }
.tga-link-action.is-muted:hover { background: var(--ad-neutral-bg); }

/* =============================================================================
   9. 数据表
   ============================================================================= */

/* 宽表(越南语表头更长)会溢出。两件事必须同时做, 否则右边几列等于不存在(2026-09-20 布局修复 L55 / L60):
   1. 右侧渐变提示"还有内容": 隐藏滚动条的环境下, 用户根本不知道能横向滚
   2. 表格给最小宽度: 不给的话浏览器会把没有 nowrap 的正文列(产品名、客户名)压成一字一行, 反而永远不触发滚动 */
.tga-table-wrap {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    background:
        linear-gradient(to right, var(--ad-surface) 30%, rgba(255, 255, 255, 0)) left center / 28px 100% no-repeat,
        linear-gradient(to left, var(--ad-surface) 30%, rgba(255, 255, 255, 0)) right center / 28px 100% no-repeat,
        radial-gradient(farthest-side at 0 50%, rgba(15, 23, 42, .12), rgba(0, 0, 0, 0)) left center / 12px 100% no-repeat,
        radial-gradient(farthest-side at 100% 50%, rgba(15, 23, 42, .12), rgba(0, 0, 0, 0)) right center / 12px 100% no-repeat;
    background-attachment: local, local, scroll, scroll;
}

/* 列多的表原来根本不会横向滚, 而是把没有 nowrap 的正文列(产品名、客户名)压到一字一行 ——
   浏览器宁可压缩正文列也要迁就 nowrap 的表头(2026-09-20 布局修复 L60)。
   860px 这个下限比 1440 的内容区(1138)和 1280 的(978)都小, 等于没生效, 提到 980;
   min(100%, …) 是给窄屏兜底 —— 手机上不要因为这条下限被迫横向滚。
   注意: 这条下限会参与父级 grid 的最小内容宽度计算, 两栏容器必须是 minmax(0,1fr) 而不是 1fr,
   否则带表格的那一栏会被撑到 980px 把另一栏挤扁(工作台和 SN 详情就这么坏过一次) */
.tga-table {
    width: 100%;
    min-width: min(100%, 980px);
    border-collapse: collapse;
    font-size: 13.5px;
    background: var(--ad-surface);
}

/* 列特别多的表(结算单、待结算、安装单)单独给更大的下限 */
.tga-table.is-wide { min-width: min(100%, 1120px); }

/* 光有整表下限还不够: 表没到下限时, 被压碎的仍是正文列。
   给这几类正文列一个各自的下限, 让浏览器改去压别人(2026-09-20 布局修复 L60) */
.tga-table th.is-text { min-width: 150px; }
.tga-table th.is-text-wide { min-width: 190px; }

/* 数值列的表头是整句越南语时(「Số tin tính phí」= 计费条数), 不给下限会被压成四行,
   数字却只占一行, 整列高得莫名其妙(2026-09-21 短信发送记录)。
   比 is-text 窄 —— 数值列本身不需要宽, 只是表头需要 */
.tga-table th.is-num-wide { min-width: 92px; }

/* 短文本列(用途、类型这类固定词组)的下限, 比 is-text(150px)窄一档。
   132px 是量出来的: 越南语最长的用途值「Lấy lại mật khẩu」「Đăng ký cửa hàng」正好单行放下。
   为什么不取更窄的 96px —— 那个宽度会把「mật khẩu」(密码, 一个词组)拆成两行,
   看着像两个不相干的词; 宁可多给 36px 也别让词组断开(2026-09-21 实测折行点) */
.tga-table th.is-text-sm { min-width: 132px; }

/* 单独放开某一列的表头换行。
   注意 .tga-table th 默认就是 nowrap, 所以「把 th 上的 is-nowrap 去掉」是没有用的 ——
   必须显式写回 normal(2026-09-21 通道列表的 Brandname 列白试了一轮)。
   .is-wrap-head 是整表放开, 但只管 th.is-num; 这个类管单独一列, 不限数值列 */
.tga-table th.is-wrap { white-space: normal; }

.tga-table th {
    background: var(--ad-surface-alt);
    color: var(--ad-text-2);
    font-size: 12.5px;
    font-weight: 600;
    text-align: left;
    padding: 10px 14px;
    border-bottom: 1px solid var(--ad-border);
    white-space: nowrap;
    /* 注: 表头不换行会被越南语的长表头撑宽, 9 列以上的表会横向溢出。
       那种表给 <table> 加 .is-wrap-head, 让数值列表头换行(2026-09-20 布局修复 L26) */
    /* 这里原来写了 position:sticky; top:0, 但最近的滚动容器是 .tga-table-wrap ——
       它只有横向滚动、纵向永远不滚, 所以吸顶从来没生效过(2026-09-20 布局修复 L61 实测)。
       页面级吸顶要把横向滚动容器改成不产生纵向滚动容器才行, 那会牵动所有列表页的滚动行为;
       这一轮先去掉这条假吸顶, 免得以为有、实际没有 */
}

.tga-table td {
    padding: 11px 14px;
    border-bottom: 1px solid var(--ad-border);
    vertical-align: middle;
}

.tga-table tbody tr:hover td { background: #FAFAFB; }
.tga-table tbody tr:last-child td { border-bottom: 0; }

.tga-table .is-mono {
    font-family: var(--ad-mono);
    font-size: 12.5px;
    letter-spacing: .3px;
}

/* 金额 / 数量列不许折行: 「400,000 VND」断成两行会让整列的行高和基线都对不齐(2026-09-20 布局修复 L59) */
.tga-table .is-num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }

/* 列很多的金额表(结算明细 9 列), 越南语数值列表头本身就是一句话, 表头不换行就把列撑宽、整表横向溢出,
   最要紧的「Tiger 应付」被挤出可视区(2026-09-20 布局修复 L26)。
   只放开表头换行, 数值单元格仍然不换行 */
.tga-table.is-wrap-head th.is-num {
    white-space: normal;
    max-width: 112px;
    vertical-align: bottom;
    line-height: 1.35;
}
.tga-table .is-nowrap { white-space: nowrap; }
.tga-table .is-center { text-align: center; }

.tga-table-sub { font-size: 11.5px; color: var(--ad-text-3); margin-top: 2px; }

.tga-table-check { width: 36px; text-align: center; }

/* 主标识列(SN)加强 */
.tga-table .tga-key {
    font-family: var(--ad-mono);
    font-weight: 600;
    font-size: 13px;
    color: var(--ad-text);
    letter-spacing: .4px;
}

.tga-table .tga-key:hover { color: var(--ad-brand); }

/* =============================================================================
   10. 状态徽标
   ============================================================================= */

.tga-badge {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 2px 9px;
    border-radius: 999px;
    font-size: 12px;
    font-weight: 600;
    line-height: 1.7;
    white-space: nowrap;
}

.tga-badge::before {
    content: "";
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: currentColor;
    flex-shrink: 0;
}

.tga-badge-success { background: var(--ad-success-bg); color: var(--ad-success); }
.tga-badge-warning { background: var(--ad-warning-bg); color: var(--ad-warning); }
.tga-badge-danger  { background: var(--ad-danger-bg);  color: var(--ad-danger); }
.tga-badge-info    { background: var(--ad-info-bg);    color: var(--ad-info); }
.tga-badge-muted   { background: var(--ad-neutral-bg); color: var(--ad-neutral); }

/* =============================================================================
   11. 分页
   ============================================================================= */

.tga-pagination {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 18px;
    border-top: 1px solid var(--ad-border);
    flex-wrap: wrap;
}

.tga-pagination-info {
    font-size: 12.5px;
    color: var(--ad-text-2);
    font-variant-numeric: tabular-nums;
}

.tga-pagination-list {
    margin-left: auto;
    display: flex;
    gap: 4px;
    align-items: center;
    flex-wrap: wrap;
}

.tga-page-link {
    min-width: 30px;
    height: 30px;
    padding: 0 8px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--ad-border-dark);
    border-radius: var(--ad-radius-sm);
    font-size: 12.5px;
    color: var(--ad-text-2);
    background: var(--ad-surface);
    font-variant-numeric: tabular-nums;
}

.tga-page-link:hover { border-color: var(--ad-brand); color: var(--ad-brand); }

.tga-page-link.is-active {
    background: var(--ad-brand);
    border-color: var(--ad-brand);
    color: #fff;
    font-weight: 600;
}

.tga-page-link.is-disabled {
    opacity: .45;
    pointer-events: none;
}

.tga-page-ellipsis { padding: 0 4px; color: var(--ad-text-3); font-size: 12.5px; }

/* =============================================================================
   12. 详情描述列表
   ============================================================================= */

/* 多列之间原来 gap:0, 上一列的长值末尾紧贴下一列的标签, 连成一串看不出断在哪
   (2026-09-20 布局修复 L25) */
.tga-desc {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 0 24px;
    border-top: 1px solid var(--ad-border);
}

/* 分隔线是每项各画一条 border-bottom, 项数凑不满最后一行时右边空格子没有线, 看着像断了
   (2026-09-20 布局修复 L30)。补一条跨整行的伪元素, 列数是几都成立 */
.tga-desc::after {
    content: "";
    grid-column: 1 / -1;
    border-top: 1px solid var(--ad-border);
    margin-top: -1px;
}

/* 半宽卡片内宽约 541px, 恰好塞得下两列, 于是每个值只剩 140px 宽, 地址、预约时段全被折成好几行
   (2026-09-20 布局修复 L25)。半宽卡片里固定单列, 和 1280 宽下的现状一致 */
.tga-grid-2 .tga-desc { grid-template-columns: 1fr; }

.tga-desc-item {
    display: flex;
    gap: 12px;
    padding: 11px 4px;
    border-bottom: 1px solid var(--ad-border);
    font-size: 13.5px;
    min-width: 0;
}

/* 地址、问题描述、判定说明这类长字段占满整行 */
.tga-desc-item.is-wide { grid-column: 1 / -1; }

/* 104px 放不下越南语的常见标签(Giới hạn đơn mỗi ngày 之类), 一律折两行 */
.tga-desc-label {
    width: 120px;
    flex-shrink: 0;
    color: var(--ad-text-2);
    font-size: 12.5px;
}

.tga-desc-value {
    flex: 1;
    min-width: 0;
    word-break: break-word;
    font-weight: 500;
}

.tga-desc-value.is-mono { font-family: var(--ad-mono); letter-spacing: .3px; }
.tga-desc-value.is-empty { color: var(--ad-text-3); font-weight: 400; }

/* =============================================================================
   13. 时间线(状态历史)
   ============================================================================= */

.tga-timeline { position: relative; padding-left: 4px; }

.tga-timeline-item {
    position: relative;
    padding: 0 0 18px 24px;
    border-left: 2px solid var(--ad-border);
}

.tga-timeline-item:last-child { border-left-color: transparent; padding-bottom: 0; }

.tga-timeline-item::before {
    content: "";
    position: absolute;
    left: -6px;
    top: 4px;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: var(--ad-surface);
    border: 2px solid var(--ad-border-dark);
}

.tga-timeline-item.is-latest::before {
    border-color: var(--ad-brand);
    background: var(--ad-brand);
    box-shadow: 0 0 0 3px rgba(216, 19, 25, .14);
}

.tga-timeline-head {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    margin-bottom: 3px;
}

.tga-timeline-title { font-size: 13.5px; font-weight: 600; }
.tga-timeline-time { font-size: 12px; color: var(--ad-text-3); font-variant-numeric: tabular-nums; }
.tga-timeline-meta { font-size: 12.5px; color: var(--ad-text-2); }
.tga-timeline-arrow { color: var(--ad-text-3); font-size: 12px; }

/* =============================================================================
   14. 提示条 / 空态
   ============================================================================= */

.tga-alert {
    display: flex;
    align-items: flex-start;
    gap: 9px;
    padding: 11px 14px;
    border-radius: var(--ad-radius-sm);
    font-size: 13.5px;
    border: 1px solid transparent;
}

/* 上面的 display:flex 会盖掉浏览器对 [hidden] 的 display:none ——
   不补这一句, JS 把提示框设成 hidden 之后它照样显示。 */
.tga-alert[hidden] { display: none; }

/* 要让人抄走的号码(付款时的完整收款账号): 点一下整段选中, 等宽便于逐位核对 */
.tga-copyable {
    font-family: var(--ad-mono);
    font-size: 15px;
    letter-spacing: .5px;
    user-select: all;
}

.tga-alert-success { background: var(--ad-success-bg); color: var(--ad-success); border-color: #BFE3D0; }
.tga-alert-danger  { background: var(--ad-danger-bg);  color: var(--ad-danger);  border-color: #F0C4C0; }
.tga-alert-warning { background: var(--ad-warning-bg); color: var(--ad-warning); border-color: #EDD9A8; }
.tga-alert-info    { background: var(--ad-info-bg);    color: var(--ad-info);    border-color: #C3DAF3; }

.tga-empty {
    padding: 54px 24px;
    text-align: center;
    color: var(--ad-text-3);
}

.tga-empty-icon { font-size: 34px; opacity: .45; margin-bottom: 10px; }
.tga-empty-text { font-size: 13.5px; }

/* =============================================================================
   15. 弹窗
   ============================================================================= */

.tga-modal-mask {
    position: fixed;
    inset: 0;
    background: rgba(16, 24, 40, .45);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px;
    z-index: 100;
}

.tga-modal-mask[hidden] { display: none; }

.tga-modal {
    background: var(--ad-surface);
    border-radius: var(--ad-radius);
    box-shadow: var(--ad-shadow-pop);
    width: 100%;
    max-width: 460px;
    max-height: 90vh;
    display: flex;
    flex-direction: column;
}

.tga-modal-head {
    padding: 15px 18px;
    border-bottom: 1px solid var(--ad-border);
    font-size: 15px;
    font-weight: 600;
    display: flex;
    align-items: center;
    gap: 10px;
}

.tga-modal-close {
    margin-left: auto;
    border: 0;
    background: none;
    font-size: 18px;
    line-height: 1;
    color: var(--ad-text-3);
    cursor: pointer;
    padding: 2px 4px;
}
.tga-modal-close:hover { color: var(--ad-text); }

.tga-modal-body { padding: 18px; overflow-y: auto; }

.tga-modal-foot {
    padding: 13px 18px;
    border-top: 1px solid var(--ad-border);
    display: flex;
    justify-content: flex-end;
    gap: 8px;
}

/* =============================================================================
   16. 登录页
   ============================================================================= */

.tga-login {
    min-height: 100vh;
    display: flex;
}

.tga-login-visual {
    flex: 1.05;
    background:
        radial-gradient(circle at 78% 18%, rgba(216, 19, 25, .34) 0%, transparent 56%),
        radial-gradient(circle at 16% 84%, rgba(237, 118, 32, .20) 0%, transparent 52%),
        linear-gradient(145deg, #16181C 0%, #0B0C0E 100%);
    color: #fff;
    padding: 56px 56px 44px;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    position: relative;
    overflow: hidden;
}

.tga-login-visual::after {
    content: "";
    position: absolute;
    right: -120px;
    bottom: -120px;
    width: 420px;
    height: 420px;
    border: 1px solid rgba(255, 255, 255, .05);
    border-radius: 50%;
}

.tga-login-logo img { height: 46px; width: auto; }
.tga-login-logo .tga-brand-text { font-size: 30px; font-weight: 800; letter-spacing: 4px; color: #fff; }

.tga-login-claim {
    font-size: 27px;
    font-weight: 700;
    line-height: 1.42;
    letter-spacing: -.3px;
    max-width: 420px;
    /* 语言文件里的换行按原样渲染, 中越两种语言断行位置不同, 由文案自己控制 */
    white-space: pre-line;
}

.tga-login-claim em {
    font-style: normal;
    color: var(--ad-brand-light);
}

.tga-login-points {
    margin: 20px 0 0;
    padding: 0;
    list-style: none;
    font-size: 13.5px;
    color: rgba(255, 255, 255, .6);
    line-height: 2.1;
}

.tga-login-points li { display: flex; align-items: center; gap: 9px; }
.tga-login-points li::before { content: "—"; color: var(--ad-brand); }

.tga-login-foot { font-size: 12px; color: rgba(255, 255, 255, .34); }

.tga-login-panel {
    width: 440px;
    flex-shrink: 0;
    background: var(--ad-surface);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 40px 48px;
}

.tga-login-form { width: 100%; max-width: 320px; }

.tga-login-title { font-size: 21px; font-weight: 700; margin: 0 0 6px; }
.tga-login-sub { font-size: 13px; color: var(--ad-text-2); margin-bottom: 26px; }

.tga-login-form .tga-field { margin-bottom: 16px; }
.tga-login-form .tga-input { min-height: 40px; font-size: 14px; }
.tga-login-form .tga-btn { width: 100%; height: 42px; font-size: 14.5px; margin-top: 6px; }

.tga-login-lang {
    display: flex;
    justify-content: center;
    gap: 14px;
    margin-top: 24px;
    font-size: 12.5px;
}

.tga-login-lang a { color: var(--ad-text-3); }
.tga-login-lang a.is-active { color: var(--ad-brand); font-weight: 600; }

/* =============================================================================
   17. 工具类
   ============================================================================= */

.tga-mono { font-family: var(--ad-mono); }
.tga-muted { color: var(--ad-text-3); }
.tga-secondary { color: var(--ad-text-2); }
.tga-strong { font-weight: 600; }
.tga-nowrap { white-space: nowrap; }
.tga-num { font-variant-numeric: tabular-nums; }
.tga-hide { display: none !important; }
.tga-flex { display: flex; align-items: center; gap: 8px; }
.tga-flex-wrap { flex-wrap: wrap; }
.tga-gap-16 { gap: 16px; }
.tga-mt-0 { margin-top: 0; }
.tga-mt-8 { margin-top: 8px; }
.tga-mt-16 { margin-top: 16px; }

/* 1fr 等价于 minmax(auto,1fr): 列的下限是内容的最小宽度。.tga-table 有了 min-width:860px 之后,
   凡是某一栏里放了表格的两栏页(工作台、SN 详情), 这个下限会把两栏各撑到 862px ——
   工作台实测 862+862 塞进 1138px 的内容区, 右边那张卡整块被推出屏幕;
   SN 详情左栏被压到 262px, 产品名、质保规则全折行(2026-09-20 布局修复 L60 的回归)。
   下限改成 0, 两栏就永远是严格的对半, 表格自己在 .tga-table-wrap 里横向滚。 */
.tga-grid-2 { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 16px; }

/* =============================================================================
   18. 响应式
   ============================================================================= */

@media (max-width: 1100px) {
    .tga-grid-2 { grid-template-columns: 1fr; }
}

@media (max-width: 900px) {
    .tga-sidebar {
        position: fixed;
        left: 0; top: 0;
        z-index: 60;
        transform: translateX(-100%);
        transition: transform .26s cubic-bezier(.2, .8, .2, 1);
        box-shadow: var(--ad-shadow-pop);
    }

    .tga-shell.is-nav-open .tga-sidebar { transform: translateX(0); }

    .tga-nav-toggle { display: inline-flex !important; }

    .tga-content { padding: 16px 14px 32px; }
    .tga-topbar { padding: 0 14px; gap: 10px; }
    .tga-lang { flex-shrink: 0; }
    .tga-user-meta { display: none; }
    .tga-login-visual { display: none; }
    .tga-login-panel { width: 100%; padding: 32px 22px; }
}

.tga-nav-toggle {
    display: none;
    width: 34px;
    height: 34px;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--ad-border-dark);
    border-radius: var(--ad-radius-sm);
    background: var(--ad-surface);
    cursor: pointer;
    font-size: 15px;
    flex-shrink: 0;
}

/* 遮罩渐显: 用 opacity + visibility 而不是 display, 否则没法过渡 */
.tga-nav-mask {
    position: fixed;
    inset: 0;
    background: rgba(16, 24, 40, .4);
    z-index: 50;
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity .26s ease, visibility 0s linear .26s;
}

.tga-shell.is-nav-open .tga-nav-mask {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transition: opacity .26s ease, visibility 0s;
}

/* 系统设置了「减少动态效果」: 侧栏、抽屉、头像菜单都不做动画(分组的高度动画由脚本判断) */
@media (prefers-reduced-motion: reduce) {
    .tga-nav-caret,
    .tga-user-caret,
    .tga-nav-mask,
    .tga-shell.is-nav-open .tga-nav-mask,
    .tga-sidebar { transition: none !important; }
    .tga-user-menu[open] > .tga-user-pop { animation: none; }
}

@media (max-width: 560px) {
    /* 顶栏在手机上寸土寸金: 头像菜单去掉分隔线和箭头, 语言切换收紧内边距 */
    .tga-user-menu { padding-left: 0; border-left: 0; }
    .tga-user { padding: 2px; }
    .tga-user-caret { display: none; }
    .tga-lang a { padding: 5px 7px; }
    .tga-page-head { flex-direction: column; }
    .tga-page-actions { margin-left: 0; width: 100%; justify-content: stretch; }
    .tga-page-actions .tga-btn { flex: 1 1 auto; }
    .tga-filter-grid { grid-template-columns: 1fr; }
    .tga-desc { grid-template-columns: 1fr; }
    .tga-pagination { flex-direction: column; align-items: stretch; }
    .tga-pagination-list { margin-left: 0; justify-content: center; }
    .tga-pagination-info { text-align: center; }
}

/* --- 安装照片(后台安装订单详情) --- */

.tga-evidence-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    gap: 10px;
    margin-top: 8px;
}

.tga-evidence-item { margin: 0; }

.tga-evidence-item img {
    display: block;
    width: 100%;
    aspect-ratio: 4 / 3;
    object-fit: cover;
    border-radius: 6px;
    border: 1px solid var(--ad-border);
    background: var(--ad-bg);
}

/* 1280 宽下格子缩到 140px, 「上传人 · 时间」被省略号截断, 上传时间看不全
   (2026-09-20 布局修复 L34)。改成允许换行, 模板里把时间换到第二行 */
.tga-evidence-item figcaption {
    margin-top: 4px;
    font-size: 11.5px;
    color: var(--ad-text-3);
    text-align: center;
    white-space: normal;
    line-height: 1.35;
}

/* 表格操作列里上下两张「备注 + 按钮」的审核小表单(售后详情的门店扣款):
   两个按钮文字长短不同(Xác nhận khấu trừ 125px / Từ chối khấu trừ 116px), 输入框跟着差 9px,
   输入框和按钮的交界上下错开(2026-09-20 布局修复 L33)。按钮列定宽, 输入框吃剩下的宽度。
   132px 是按越南语里最长的那个按钮(125px)留出余量取的 */
.tga-review-row .tga-btn { flex: 0 0 132px; }
.tga-review-row .tga-input { flex: 1; }

/* 命中的那一行加底色 —— 费用规则模拟器里, 「哪条赢了」必须一眼看见 */
.tga-table tr.is-highlight > td {
    background: var(--ad-success-soft, #E8F6EE);
}

/* 表格里的负数(扣款)用危险色, 一眼能看出是减项 */
.tga-danger { color: var(--ad-danger); }
.tga-warning { color: var(--ad-warning); }
.tga-success { color: var(--ad-success); }

/* 表格单元格里的折叠小表单 —— 待结算列表的「添加扣款」用它。
   宽度给够, 否则金额输入框会被列宽挤成一条缝。 */
.tga-inline-form > summary {
    cursor: pointer;
    font-size: 12.5px;
    color: var(--ad-brand);
    list-style: none;
    white-space: nowrap;
}

.tga-inline-form > summary::-webkit-details-marker { display: none; }

/* 展开后面板宽度原来由内容决定, 操作列从 60px 一路撑到 327px(2026-09-20 布局修复 L28)。
   钉成 240px, 并且 white-space:normal —— 操作列的 td 是 .is-nowrap, 不解开的话
   面板里的文字继承了不换行, 会顶着 240px 往外溢, 列宽照样被撑开(验收实测 327px 就是这么来的)。
   注意: 收起态的宽度仍由 summary 决定, 所以展开时列宽还是会变一次,
   只是幅度固定在 240px 以内, 不再随内容长短乱跳。纯 CSS 做不到两态同宽, 除非做成浮层 ——
   而 .tga-table-wrap 是 overflow-x:auto 的滚动容器, 纵向同样会裁, 浮层会被切掉半截 */
.tga-inline-form > form {
    width: 240px;
    padding: 10px 0 4px;
    white-space: normal;
}

/* 展开后这一行会高到 400px, 同行其它单元格是 middle 对齐, 就漂在了 400px 的正中间,
   和右侧面板完全对不上(2026-09-20 布局修复 L28)。这张表改成整行顶部对齐。
   没有做成绝对定位的浮层: .tga-table-wrap 是 overflow-x:auto 的滚动容器,
   纵向同样会裁切, 浮层反而会被切掉半截 */
.tga-table.is-top-align td { vertical-align: top; }

.tga-inline-form > form .tga-field { margin-bottom: 8px; }

/* =============================================================================
   系统参数页(2026-09-21, 迁移 022 / admin.css v13 -> v14)
   =============================================================================
   这一页的结构和别的后台页不一样: 一张卡片里竖着排十几项, 每项都带
   「名字 + 一段说明 + 控件 + 默认值 + 恢复默认」。现有的公共类给不了两件东西 ——
   项与项之间的分界, 和一个尺寸可控的图片预览框。下面四条就是补这两件事,
   都只服务于这一页, 没有改动任何既有规则。
   ========================================================================== */

/* 分组导航(四个分组各一个入口)。没有借 .tga-row-actions: 那个是表格操作列用的,
   gap 只有 2px, 四个分组名贴在一起看不出是四个可点的入口。窄屏自动折行。 */
.tga-subnav { display: flex; flex-wrap: wrap; gap: 8px; }

/* 参数项之间的分界线。「安全与限流」一组有 17 项, 只靠间距的话, 一段说明到底属于
   上面还是下面那一项要靠数像素; 有了线就不会看错行, 也就不会改错参数。 */
.tga-setting-item { padding-top: 14px; border-top: 1px solid var(--ad-border); }
.tga-setting-item:first-child { padding-top: 0; border-top: 0; }

/* 当前 Logo / 浏览器图标的预览框。必须钉死高度: 传上来的原图可能是 2000px 高,
   不限制的话这一项会把整页顶开几屏。浅灰底是给白色透明图用的, 否则白图在白卡片上等于没显示。 */
.tga-setting-img {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    max-width: 100%;
    height: 56px;
    padding: 6px 10px;
    border: 1px solid var(--ad-border);
    border-radius: var(--ad-radius-sm);
    background: var(--ad-surface-alt);
}

.tga-setting-img img { max-height: 44px; max-width: 220px; object-fit: contain; }

/* 在输入框里按回车, 浏览器提交的是表单里**第一个** submit 按钮。这一页每一项旁边都有一个
   formaction 指向「恢复默认」的按钮, 不抢占这个位置的话, 回车就成了「把这一项恢复默认」。
   这个按钮只为占住第一顺位: 看不见、Tab 不到、读屏跳过(视图里还写了 aria-hidden)。 */
.tga-submit-guard {
    position: absolute;
    left: -9999px;
    width: 1px;
    height: 1px;
    opacity: 0;
}

/* =============================================================================
   拖动排版编辑器(2026-09-22, 迁移 026 / admin.css v14 -> v15)
   =============================================================================
   ★ 类名一律 tga-le-, 绝不用 ad- 前缀 ★
   广告拦截插件会按 .ad-* 一类的选择器直接 display:none。这一页尤其致命:
   画布和框一个都看不见, 用户会以为是自己把要素拖没了, 然后去改别的东西。
   文件名与类名里也不出现 ad / banner / sponsor。

   ★ overlay 里只有透明矩形和手柄 ★
   底图 .tga-le-plate 是渲染层出的真 PNG(与打印时同一份字节);
   盖在上面的 .tga-le-item / .tga-le-ink 全部 background:transparent,
   连感叹号角标都是 ::after 的 content 画的 —— overlay 里一个文本节点都没有。
   ========================================================================== */

/* 整幅宽模式(/editor): 外层那个两栏网格收成一栏, 画布那一栏排到最前面。
   写 minmax(0,1fr) 不写 1fr: 画布是个定宽的块, 用 1fr 的话窄屏上它会把整栏撑破 */
.tga-le-stack { grid-template-columns: minmax(0, 1fr); }
.tga-le-stack > .tga-le-col { order: -1; }

/*
 * 宽模式下, 编辑器底下那一列配置卡片(模板名 / 尺寸 / 码制)**并排**而不是竖着摞。
 * (2026-09-22「改紧凑一点」)
 *
 * 竖着摞是 297 + 479 + 204 ≈ 一整屏; 这三张卡片都是「进来填一次」的东西,
 * 它们本来就不该比编辑器占更多屏。
 *
 * **两列, 不是三列**: 实测 1366 屏上三列每张只有 345px, 「标签尺寸」那张被挤成
 * 843px 高的细条(里面的两列表单塌成一列、提示全部折行), 整行按最高的算, 反而只省了 150px。
 * 两列时它保持 ~479 的自然高度, 第三张绕到下面 —— 整块 ~700px。
 * 860 以下退回一列。minmax(0, 1fr) 同上面的理由: 卡片里有表格, 用 1fr 会被撑破。
 */
.tga-le-stack > :not(.tga-le-col) {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 16px;
    align-items: start;
}
@media (max-width: 860px) {
    .tga-le-stack > :not(.tga-le-col) { grid-template-columns: minmax(0, 1fr); }
}

/* 编辑器本体。窄模式(用户在工具条上手动收窄时)竖着摞: 画布 -> 数值 -> 图层。
   2026-09-22 起**默认是下面那个 is-wide**: 窄的那一版在 1366×768 上是三屏,
   属性面板和图层清单都在第三屏, 用户原话「要翻页添加内容, 再返回去修改」 */
.tga-le { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; }
.tga-le .tga-le-main { order: 1; min-width: 0; }
.tga-le .tga-le-props { order: 2; min-width: 0; }
.tga-le .tga-le-layers { order: 3; min-width: 0; }

/*
 * 整幅宽模式是**画布 + 一条右栏**, 不是「图层 | 画布 | 数值」三栏。
 *
 * 三栏是先写的, 实测在真尺寸上不成立: 后台侧栏本身就占 236px,
 * 1280 屏上三栏给画布只剩 383px —— 80x50 的标签在 300 DPI 下是 945 像素,
 * 只能缩到 **0.38 倍**。那个比例下一个模块不到半个屏幕像素, 谁也拖不准,
 * 而这一页存在的全部理由就是「拖一下就对」。
 *
 * 数值面板摆在右栏**上面**: 拖的时候眼睛要在画布和数字之间来回看, 越近越好;
 * 图层列表排在它下面, 那是「先选哪一项」的入口, 用得没那么频。
 *
 * 实测(80x50 @300, 945 像素宽):
 *   1440 屏  画布 805px  -> 0.85 倍
 *   1280 屏  画布 665px  -> 0.70 倍
 */
.tga-le.is-wide { grid-template-columns: minmax(0, 1fr) 272px; align-items: start; }
.tga-le.is-wide .tga-le-main { grid-column: 1; grid-row: 1 / span 2; order: 1; }
.tga-le.is-wide .tga-le-props { grid-column: 2; grid-row: 1; order: 2; }
.tga-le.is-wide .tga-le-layers { grid-column: 2; grid-row: 2; order: 3; }

@media (max-width: 1020px) {
    .tga-le.is-wide { grid-template-columns: minmax(0, 1fr); }
    .tga-le.is-wide .tga-le-main,
    .tga-le.is-wide .tga-le-props,
    .tga-le.is-wide .tga-le-layers { grid-column: 1; grid-row: auto; }
}

.tga-le-head { padding-bottom: 6px; border-bottom: 1px solid var(--ad-border); margin-bottom: 8px; }
.tga-le-headhint { margin-bottom: 8px; }

/* --- 图层列表 --- */
.tga-le-list { border-top: 1px solid var(--ad-border); }
.tga-le-row {
    display: flex;
    gap: 8px;
    align-items: flex-start;
    padding: 8px 6px;
    border-bottom: 1px solid var(--ad-border);
    cursor: pointer;
}
.tga-le-row.is-on { background: var(--ad-brand-soft); }
.tga-le-rowmain { display: flex; gap: 8px; align-items: flex-start; flex: 1; min-width: 0; cursor: pointer; }
.tga-le-rowmain > input { margin-top: 3px; flex: none; }
.tga-le-rowtext { min-width: 0; }
.tga-le-rowdesc { display: block; margin-top: 2px; }
.tga-le-rowbtns { display: flex; gap: 2px; flex-wrap: nowrap; flex: none; }

/* 列表里的状态角标。与画布上的红框是同一件事的两个位置:
   要素可能被拖到画布外面看不见了, 只有列表还指得出是哪一项 */
.tga-le-flag {
    flex: none;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    text-align: center;
    line-height: 18px;
    font-weight: 700;
    color: #fff;
    background: var(--ad-warning);
}
.tga-le-flag[data-status="error"], .tga-le-flag[data-status="risk"] { background: var(--ad-danger); }

/* --- 工具条 --- */
.tga-le-bar { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin-bottom: 10px; }
.tga-le-barlabel { color: var(--ad-text-3); }
.tga-le-bargap { flex: 1 1 12px; }
.tga-le-bar .tga-btn.is-on { border-color: var(--ad-brand); color: var(--ad-brand); }

/* 只读模式(设计定稿 §10, 2026-09-22): 画布上的透明矩形不接鼠标 ——
   拖一下再弹回去, 比一开始就不动更像坏了。手柄一并不画。
   这只是表层, 真正挡住拖动的是 label-editor.js 里的 readonly 闸(pointerdown 直接 return),
   挡住写入的是 POST 那一侧的 act() 要 label_template.manage */
.tga-le.is-readonly .tga-le-item { pointer-events: none; cursor: default; }

/* 写到 .is-on / :focus 这一层是为了压过下面那条「选中时显示手柄」——
   选择器权重相同的话后写的赢, 而那一条在这个文件里排在后面 */
.tga-le.is-readonly .tga-le-item.is-on .tga-le-h,
.tga-le.is-readonly .tga-le-item:focus .tga-le-h { display: none; }

/* --- 画布 --- */
.tga-le-viewport {
    /*
     * ★ 画布底色: 浅灰, 不是白 ★(2026-09-22 改)
     *
     * 原来这里是纯白, 注释写的是「深色卡片背景会让人误判标签的留白」。
     * 那个担心是对的 —— 但白底白纸的代价更大: **标签的边界彻底看不见了**,
     * 用户不知道自己的要素拖到纸外面去了没有(用户原话:「打印区域的边界现在看不请」)。
     *
     * 这里用的是整个后台的页面底色(--ad-bg #F4F5F7), 浅到不会被当成标签的一部分,
     * 又足够把白纸衬出来。纸的边界另有 outline 与投影(见下面 .tga-le-stage)。
     */
    background: var(--ad-bg);
    border: 1px solid var(--ad-border-dark);
    border-radius: var(--ad-radius);
    padding: 16px;
    overflow: auto;
}

/*
 * ★ 纸的边界: outline + 投影, 不能用 border ★
 *
 * 舞台的宽高由 JS 按标签像素算(paint() 里 stage.style.width/height),
 * 透明矩形那一层是 inset:0 贴着它铺的。全局是 border-box, 加 1px 边框会让**内容区
 * 缩掉 2px** —— 底图跟着被压扁, 框和墨迹就对不上了, 而这正是本项目最怕的那类错位。
 *
 * outline 画在盒子外面、不进盒模型, 投影同理。两者叠起来:
 * 实线给出「纸到这里为止」, 投影让白纸像放在桌面上, 一眼分得出纸内纸外。
 */
.tga-le-stage {
    position: relative;
    margin: 0 auto;
    background: #fff;
    outline: 1px solid var(--ad-text-3);
    box-shadow: 0 1px 8px rgba(31, 35, 41, .20);
}
.tga-le-plate { display: block; width: 100%; height: 100%; }

/* 放大时才用最近邻: 缩小时最近邻会吃掉笔画, 条形码反而看不清。
   100% 与 200% 下一个标签像素至少占一个屏幕像素, 这时才该看见真实的模块边界 */
.tga-le-plate.is-crisp { image-rendering: pixelated; }

.tga-le-overlay { position: absolute; inset: 0; }
.tga-le.is-bare .tga-le-overlay { display: none; }
.tga-le.is-busy .tga-le-viewport { opacity: .72; }

/* 多选对齐条(2026-09-22): 选够两项才显示 */
.tga-le-align {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
    margin-top: 8px;
    padding: 8px 10px;
    background: var(--ad-surface-alt);
    border: 1px solid var(--ad-border);
    border-radius: var(--ad-radius-sm);
}

/* 组里跟着一起动的那几个: 比主选中淡一档, 一眼分得出谁是主选中 */
.tga-le-item.is-co {
    border-color: var(--ad-info);
    border-style: dashed;
    background: rgba(31, 95, 169, .08);
}

/* 你拖的那个框: 实线。完全透明, 一个像素的标签内容都不画。
   2026-10-02: 平时不画线(画布上只留墨迹虚线, 不然每个要素两圈线叠在一起, 人照着哪一圈对都说不清),
   鼠标移上去 / 选中 / 有提醒时才显示。线是透明的, 框照样点得中、拖得动 */
.tga-le-item {
    position: absolute;
    background: transparent;
    border: 1px solid transparent;
    cursor: move;
    touch-action: none;
}
.tga-le-item:hover { border-color: var(--ad-info); }
.tga-le-item:focus { outline: none; }
.tga-le-item.is-on, .tga-le-item:focus { border-width: 2px; border-color: var(--ad-brand); z-index: 3; }
.tga-le-item.is-drag { z-index: 4; }

/* 放不下 / 印出来多半用不了: 红框 + 右上角感叹号角标。
   角标走 ::after 的 content —— overlay 里不许有文本节点 */
.tga-le-item[data-status="warn"] { border-color: var(--ad-warning); }
.tga-le-item[data-status="risk"], .tga-le-item[data-status="error"] {
    border-width: 2px;
    border-color: var(--ad-danger);
}
.tga-le-item[data-status="risk"] .tga-le-flag, .tga-le-item[data-status="error"] .tga-le-flag,
.tga-le-item[data-status="warn"] .tga-le-flag { display: block; }
.tga-le-item .tga-le-flag {
    display: none;
    position: absolute;
    top: -10px;
    right: -10px;
    background: var(--ad-danger);
}
.tga-le-item .tga-le-flag::after { content: "!"; }
.tga-le-item[data-status="warn"] .tga-le-flag { background: var(--ad-warning); }

/* plan() 说真会印上去的那一块墨: 虚线。**独立于框**, 所以拖框的时候它留在原地 ——
   那正是底图上墨还在的地方, 不跟着动才是诚实的 */
.tga-le-ink {
    position: absolute;
    background: transparent;
    border: 1px dashed var(--ad-success);
    pointer-events: none;
    z-index: 2;
}

/* 手柄: 视觉 11px, 命中区靠 ::before 撑到 21px —— 1280 屏上 11 个像素点不准 */
.tga-le-h {
    position: absolute;
    width: 11px;
    height: 11px;
    background: var(--ad-surface);
    border: 1px solid var(--ad-brand);
    border-radius: 2px;
    z-index: 5;
}
.tga-le-h::before { content: ""; position: absolute; inset: -5px; }
.tga-le-item .tga-le-h { display: none; }
.tga-le-item.is-on .tga-le-h, .tga-le-item:focus .tga-le-h { display: block; }
.tga-le-h.is-nw { left: -6px; top: -6px; cursor: nwse-resize; }
.tga-le-h.is-n  { left: 50%; top: -6px; margin-left: -6px; cursor: ns-resize; }
.tga-le-h.is-ne { right: -6px; top: -6px; cursor: nesw-resize; }
.tga-le-h.is-e  { right: -6px; top: 50%; margin-top: -6px; cursor: ew-resize; }
.tga-le-h.is-se { right: -6px; bottom: -6px; cursor: nwse-resize; }
.tga-le-h.is-s  { left: 50%; bottom: -6px; margin-left: -6px; cursor: ns-resize; }
.tga-le-h.is-sw { left: -6px; bottom: -6px; cursor: nesw-resize; }
.tga-le-h.is-w  { left: -6px; top: 50%; margin-top: -6px; cursor: ew-resize; }

/* 吸附参考线: 洋红贯穿线。看不出来的对齐等于没有对齐 ——
   下次拖歪 0.2 毫米用户也不会发现 */
.tga-le-guide { position: absolute; background: #E100C8; z-index: 6; pointer-events: none; }
.tga-le-guide.is-v { top: 0; bottom: 0; width: 1px; }
.tga-le-guide.is-h { left: 0; right: 0; height: 1px; }

/* 开单页: 会员卡片下面那一行信用额度(迁移 044); 有逾期 / 已超额时标成警示色 */
.tga-pos-credit { margin-top: 6px; }
.tga-pos-credit.is-warn { color: var(--ad-danger); font-weight: 600; }

/* 字高那一格: 减号 / 数字框 / 加号排成一行 */
.tga-le-stepper { display: flex; gap: 4px; align-items: center; }
.tga-le-stepper .tga-input { flex: 1 1 auto; min-width: 0; }
.tga-le-stepper .tga-btn { flex: 0 0 auto; min-width: 30px; }

/* --- 图例: 这一页上永远有两个矩形, 不解释的话用户会当成 bug --- */
.tga-le-legend { display: flex; flex-wrap: wrap; gap: 6px 14px; align-items: center; margin-top: 10px; color: var(--ad-text-2); }
.tga-le-key { display: inline-block; width: 22px; height: 0; border-top-width: 2px; }
.tga-le-key.is-box { border-top-style: solid; border-top-color: var(--ad-info); }
.tga-le-key.is-ink { border-top-style: dashed; border-top-color: var(--ad-success); }

/* --- 数值面板 --- */
.tga-le-title { margin-bottom: 8px; }
.tga-le-note { margin-bottom: 10px; }
.tga-le-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 10px; }
.tga-le-grid .is-wide { grid-column: 1 / -1; }
.tga-le-align { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 12px; }
.tga-le-convert { display: inline-block; margin-top: 10px; }

.tga-le-lang { display: flex; gap: 8px; align-items: center; }
.tga-select-sm { padding: 3px 8px; height: auto; }

.tga-le-msg { margin-bottom: 8px; }

/* 保存按钮旁边那句「有 N 个要素放不下」。只把按钮灰掉等于什么都没说:
   用户会以为页面坏了, 而不是自己的版面有问题 */
.tga-le-gate { color: var(--ad-danger); align-self: center; }

/* =============================================================================
   20. 标签模板列表的折叠说明 / 检查页(2026-09-22, admin.css v15 -> v16)
   =============================================================================
   这一组是「标签模板列表精简」带来的三样新东西:

     .tga-note        页头那几条说明收起来(读一次就记住的话, 不该天天跨过去)
     .tga-progress    「检查全部模板」的进度条 —— 三百套要跑一分多钟,
                      光有一行字看不出它到底在不在走
     .tga-check-item  检查结果里有问题的那一套

   为什么不借现成的类: <details> 那两处(侧栏分组 .tga-nav-group、头像菜单 .tga-user)
   都是深色侧栏里的东西, 颜色和内边距全对不上; 进度条项目里此前一个都没有。 */

.tga-note {
    background: var(--ad-surface);
    border: 1px solid var(--ad-border);
    border-radius: var(--ad-radius-sm);
}

.tga-note > summary {
    cursor: pointer;
    list-style: none;
    padding: 10px 14px;
    font-size: 13px;
    font-weight: 600;
    color: var(--ad-text-2);
}

.tga-note > summary::-webkit-details-marker { display: none; }

/* 收起态要一眼看得出「这里还有东西」—— 没有箭头的话它就是一行灰字, 没人会去点 */
.tga-note > summary::before {
    content: "▸";
    display: inline-block;
    margin-right: 6px;
    color: var(--ad-text-3);
}
.tga-note[open] > summary::before { content: "▾"; }
.tga-note > summary:hover { color: var(--ad-brand); }

.tga-note-body { padding: 0 14px 12px; }

/* --- 进度条 --- */
.tga-progress {
    margin-top: 14px;
    height: 6px;
    border-radius: 3px;
    background: var(--ad-neutral-bg, #EEF0F3);
    overflow: hidden;
}

/* width 由 JS 按「查了几套 / 一共几套」写, 这里只管长相。
   加过渡是因为一批 5 套、一批一两秒, 不过渡的话它是一格一格跳的 */
.tga-progress-bar {
    height: 100%;
    width: 0;
    background: var(--ad-brand);
    transition: width .25s ease;
}

.tga-progress[hidden] { display: none; }

/* --- 检查结果 --- */
.tga-check-list { border-top: 1px solid var(--ad-border); }

.tga-check-item {
    padding: 12px 18px;
    border-bottom: 1px solid var(--ad-border);
}

/* 左边一道色条: 排不下(红)和只是提醒(黄)要在扫一眼时就分得开 ——
   几十条结果堆在一起时, 光靠里面那条提示语的背景色分辨太慢 */
.tga-check-item.is-error { border-left: 3px solid var(--ad-danger); }
.tga-check-item.is-warning { border-left: 3px solid var(--ad-warning); }

.tga-check-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin-bottom: 8px;
}

.tga-check-item .tga-alert { margin-top: 6px; }

/* =============================================================================
   官网模块(迁移 029): 中越并排的译文字段、富文本编辑器、商品图库、价目网格、订单详情上的官网区块。
   类名一律 tga-web-*(不用 ad- / banner / promo, 广告拦截会整块隐藏)。
   ============================================================================= */
.tga-web-tr { display: flex; flex-direction: column; gap: 14px; }
.tga-web-tr-row { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 14px 20px; }
.tga-web-tr-row.is-html { grid-template-columns: minmax(0, 1fr); }
.tga-web-tr-hint { grid-column: 1 / -1; margin-top: -6px; }
.tga-web-locale { font-size: 11px; font-weight: 500; color: var(--ad-text-3); margin-left: 4px; }
@media (max-width: 900px) { .tga-web-tr-row { grid-template-columns: minmax(0, 1fr); } }

.tga-web-editor { border: 1px solid var(--ad-border-dark); border-radius: 4px; background: var(--ad-surface); }
.tga-web-editor-bar { display: flex; flex-wrap: wrap; gap: 2px; padding: 4px; border-bottom: 1px solid var(--ad-border); background: var(--ad-surface-alt); }
.tga-web-editor-btn { min-width: 30px; height: 28px; padding: 0 6px; border: 1px solid transparent; border-radius: 4px; background: none; color: var(--ad-text-2); font: 600 13px/1 inherit; cursor: pointer; }
.tga-web-editor-btn:hover, .tga-web-editor-btn.is-active { border-color: var(--ad-border-dark); background: var(--ad-surface); color: var(--ad-text); }
.tga-web-editor-area { min-height: 220px; max-height: 560px; overflow: auto; padding: 10px 12px; line-height: 1.6; outline: none; }
.tga-web-editor-area img { max-width: 100%; height: auto; }
.tga-web-editor-area blockquote { margin: 8px 0; padding-left: 12px; border-left: 3px solid var(--ad-border-dark); color: var(--ad-text-2); }
.tga-web-editor textarea { border: 0; border-radius: 0; min-height: 220px; font-family: var(--ad-mono, monospace); }

.tga-web-gallery { display: flex; flex-wrap: wrap; gap: 10px; margin: 0; padding: 0; list-style: none; }
.tga-web-gallery-item { position: relative; width: 112px; height: 112px; border: 1px solid var(--ad-border); border-radius: 6px; overflow: hidden; background: var(--ad-surface-alt); cursor: grab; }
.tga-web-gallery-item img { width: 100%; height: 100%; object-fit: contain; }
.tga-web-gallery-item.is-dragging { opacity: .4; }
.tga-web-gallery-main { display: none; position: absolute; left: 4px; top: 4px; padding: 1px 6px; border-radius: 3px; background: var(--ad-brand); color: #fff; font-size: 11px; }
.tga-web-gallery-item:first-child .tga-web-gallery-main { display: inline-block; }
.tga-web-gallery-remove { position: absolute; right: 4px; top: 4px; width: 22px; height: 22px; border: 0; border-radius: 50%; background: rgba(0, 0, 0, .55); color: #fff; font-size: 15px; line-height: 22px; cursor: pointer; }

.tga-web-thumb { display: block; width: 52px; height: 52px; border: 1px solid var(--ad-border); border-radius: 4px; object-fit: contain; background: var(--ad-surface-alt); }
.tga-web-slide-thumb { display: block; width: 144px; aspect-ratio: 16 / 6; border-radius: 4px; object-fit: cover; background: var(--ad-surface-alt); }
.tga-web-slide-preview { display: block; max-width: 420px; max-height: 180px; margin-bottom: 8px; border: 1px solid var(--ad-border); border-radius: 4px; object-fit: contain; }
.tga-web-slide-preview.is-mobile { max-width: 160px; max-height: 240px; }
.tga-web-checklist { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 6px 16px; max-height: 280px; overflow: auto; padding: 8px; border: 1px solid var(--ad-border); border-radius: 4px; }
.tga-web-copy { min-width: 280px; }

.tga-web-price-grid .tga-input { width: 120px; text-align: right; }
.tga-web-price-grid .tga-input.is-invalid { border-color: var(--ad-danger); background: var(--ad-danger-bg); }
.tga-web-price-grid .tga-field-error { color: var(--ad-danger); font-size: 12px; }

.tga-web-subtitle { display: flex; align-items: center; gap: 8px; margin: 0 0 10px; font-size: 14px; font-weight: 600; color: var(--ad-text); }
.tga-web-inline-form { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 10px; }
.tga-web-inline-form .tga-input, .tga-web-inline-form .tga-select { width: auto; min-width: 160px; }
.tga-web-cancel { margin-top: 18px; padding-top: 14px; border-top: 1px dashed var(--ad-border); }

/* =============================================================================
   订单详情「配货发货」面板(2026-09-29, view/admin/order/show.php + _pack_lines.php + order-pack.js)
   一屏里扫码绑定 + 发货: 左边一个扫码框 + 每行明细一条, 右边发货。
   两栏都用 minmax(0, ...): 明细里的长商品名 / 一串 SN 标签不能把栏撑宽(css-min-width 那次的坑)
   ============================================================================= */
.tga-pack-total { margin-left: auto; font-size: 13px; color: var(--ad-text-2); white-space: nowrap; }
.tga-pack-total strong { font-size: 16px; color: var(--ad-text); }

.tga-pack-grid { display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: 20px; }
.tga-pack-side { border-left: 1px solid var(--ad-border); padding-left: 20px; min-width: 0; }
.tga-pack-side-title { margin: 0 0 8px; font-size: 14px; font-weight: 600; }
.tga-pack-side .tga-desc { grid-template-columns: minmax(0, 1fr); margin-bottom: 12px; }
.tga-pack-side .tga-desc-item { padding: 7px 2px; }
.tga-pack-side .tga-desc-label { width: 84px; }
.tga-pack-side .tga-hint { margin-top: 0; }

@media (max-width: 1100px) {
    .tga-pack-grid { grid-template-columns: minmax(0, 1fr); }
    .tga-pack-side { border-left: 0; padding-left: 0; border-top: 1px solid var(--ad-border); padding-top: 14px; }
}

/* 扫码框: 比普通输入框高、字大, 扫码时一眼能看到焦点在不在它身上 */
.tga-scan-input { height: 44px; font-size: 16px; }
.tga-scan-input:focus { border-color: var(--ad-brand); box-shadow: 0 0 0 3px var(--ad-brand-soft); }
/* 框下这一行平时是用法提示, 扫完显示最新一条结果(按结果着色), 输入法开着时是警告 */
.tga-scan-status { min-height: 20px; margin-top: 4px; font-size: 12px; color: var(--ad-text-3); word-break: break-word; }
.tga-scan-status.is-warn    { color: var(--ad-warning); font-weight: 600; }
.tga-scan-status.is-bound   { color: var(--ad-success); font-size: 13px; font-weight: 600; }
.tga-scan-status.is-error   { color: var(--ad-danger); font-size: 13px; font-weight: 600; }
.tga-scan-status.is-already { color: var(--ad-text-2); font-size: 13px; }
.tga-scan-status.is-unbound { color: var(--ad-info); font-size: 13px; }

.tga-pack .tga-progress { margin-top: 10px; }
.tga-progress-bar.is-done { background: var(--ad-success); }

/* 明细: 商品 | 已绑的 SN | 件数, 一行一条 */
.tga-pack-lines { margin-top: 10px; border-top: 1px solid var(--ad-border); }
.tga-pack-line {
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(0, 3fr) 64px;
    gap: 6px 14px;
    align-items: center;
    padding: 6px 4px;
    border-bottom: 1px solid var(--ad-border);
}
/* 商品名和 SKU / 数量同一行, 窄了才折: 一行明细只占一行字高 */
.tga-pack-line-name { min-width: 0; word-break: break-word; line-height: 1.45; }
.tga-pack-line-name .tga-strong { margin-right: 6px; }
.tga-pack-line-sub { font-size: 11.5px; color: var(--ad-text-3); }
.tga-pack-count { text-align: right; font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; }
.tga-pack-line.is-full .tga-pack-count { color: var(--ad-success); }
.tga-pack-line.is-partial .tga-pack-count,
.tga-pack-line.is-empty .tga-pack-count { color: var(--ad-warning); }
.tga-pack-line.is-unmapped .tga-pack-count { color: var(--ad-danger); }
.tga-pack-line.is-flash { animation: tga-pack-flash 1.2s ease-out; }
@keyframes tga-pack-flash { from { background: var(--ad-success-bg); } to { background: transparent; } }
.tga-pack-empty { padding: 10px 4px; margin: 0; }

.tga-pack-sns { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; min-width: 0; }
.tga-pack-sns .tga-hint { margin: 0; }
.tga-sn-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    max-width: 100%;
    height: 24px;
    padding: 0 2px 0 8px;
    border: 1px solid var(--ad-border-dark);
    border-radius: var(--ad-radius-sm);
    background: var(--ad-surface-alt);
    font-size: 12px;
}
.tga-sn-chip a { color: var(--ad-text); text-decoration: none; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tga-sn-chip a:hover { color: var(--ad-brand); }
.tga-sn-chip.is-locked { padding-right: 8px; background: var(--ad-neutral-bg); }
.tga-sn-chip-status { color: var(--ad-info); font-size: 11px; white-space: nowrap; }
.tga-sn-chip-x {
    width: 20px;
    height: 20px;
    padding: 0;
    border: 0;
    border-radius: 3px;
    background: transparent;
    color: var(--ad-text-3);
    font-size: 15px;
    line-height: 20px;
    cursor: pointer;
}
.tga-sn-chip-x:hover,
.tga-sn-chip-x:focus-visible { background: var(--ad-danger-bg); color: var(--ad-danger); outline: none; }

/* 解绑小条: 展开在那一行下面, 占满整行 */
.tga-unbind-box {
    grid-column: 1 / -1;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    padding: 8px 10px;
    border-radius: var(--ad-radius-sm);
    background: var(--ad-danger-bg);
}
.tga-unbind-title { font-size: 12.5px; font-weight: 600; }
.tga-unbind-box .tga-input { flex: 1 1 200px; width: auto; min-width: 0; height: 28px; }
.tga-unbind-error { flex-basis: 100%; font-size: 12px; color: var(--ad-danger); }
.tga-unbind-error:empty { display: none; }

/* 扫码记录: 最新的在最上面 */
/* 扫码记录在右栏发货下面, 最新的在最上面 */
.tga-scan-log-box { margin-top: 16px; padding-top: 12px; border-top: 1px solid var(--ad-border); }
.tga-scan-log { list-style: none; max-height: 320px; margin: 0; padding: 0; overflow-y: auto; font-size: 12.5px; }
.tga-scan-log-item { display: flex; gap: 8px; padding: 3px 4px; border-bottom: 1px dashed var(--ad-border); }
.tga-scan-log-mark { width: 14px; flex-shrink: 0; text-align: center; font-weight: 700; }
.tga-scan-log-code { flex-shrink: 0; color: var(--ad-text); max-width: 45%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tga-scan-log-message { min-width: 0; word-break: break-word; }
.tga-scan-log-item.is-bound   { color: var(--ad-success); }
.tga-scan-log-item.is-already { color: var(--ad-text-3); }
.tga-scan-log-item.is-error   { color: var(--ad-danger); background: var(--ad-danger-bg); }
.tga-scan-log-item.is-unbound { color: var(--ad-info); }

.tga-ship-form .tga-select,
.tga-ship-form .tga-input { width: 100%; }
.tga-ship-form .tga-btn { width: 100%; }
.tga-ship-missing { margin: 0 0 10px; font-size: 12.5px; font-weight: 600; }

/* 分单发货(迁移 041): 「分成几个包裹发」+ 包裹小卡片 */
.tga-shipment-split { margin-top: 10px; font-size: 13px; }
.tga-shipment-split > summary { cursor: pointer; color: var(--ad-brand); font-weight: 600; }
.tga-shipment-split > form { margin-top: 8px; }
.tga-shipment-qty { display: grid; grid-template-columns: minmax(0, 1fr) auto 72px; align-items: center; gap: 8px; }
.tga-shipment-qty .tga-input { width: 72px; }
.tga-shipment-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tga-shipments { margin-top: 16px; }
.tga-shipment { margin-top: 10px; padding: 10px 12px; border: 1px solid var(--ad-border); border-radius: var(--ad-radius); background: var(--ad-surface); font-size: 13px; }
.tga-shipment.is-cancelled { background: var(--ad-surface-alt); color: var(--ad-text-3); }
.tga-shipment-head { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; }
.tga-shipment-print { margin-left: auto; font-size: 12.5px; }
.tga-shipment-meta { display: flex; flex-wrap: wrap; gap: 4px 10px; margin-top: 6px; font-size: 12.5px; }
.tga-shipment-lines { margin: 8px 0 0; padding: 0; list-style: none; }
.tga-shipment-lines li { display: grid; grid-template-columns: minmax(0, 1fr) auto auto; gap: 8px; padding: 2px 0; }
.tga-shipment-sns { margin-top: 6px; font-size: 12px; color: var(--ad-text-2); word-break: break-all; }
.tga-shipment-form { margin-top: 10px; padding-top: 10px; border-top: 1px dashed var(--ad-border); }
.tga-shipment-form .tga-select,
.tga-shipment-form .tga-input,
.tga-shipment-edit .tga-select,
.tga-shipment-edit .tga-input { width: 100%; }
.tga-shipment-pick-title { font-weight: 600; margin-bottom: 4px; }
.tga-shipment-pick-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 4px 8px; max-height: 180px; overflow-y: auto; }
.tga-shipment-sn { display: flex; align-items: center; gap: 6px; min-width: 0; font-size: 12.5px; cursor: pointer; }
.tga-shipment-sn .tga-mono { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tga-shipment-actions { display: flex; gap: 8px; }
.tga-shipment-actions .tga-btn { flex: 1 1 auto; }
.tga-shipment-inline { display: inline-block; margin-top: 8px; margin-right: 8px; }
.tga-shipment-edit { margin-top: 8px; }
.tga-shipment-edit > summary { cursor: pointer; color: var(--ad-text-2); font-size: 12.5px; }
.tga-shipment-edit > form { margin-top: 6px; }

@media (max-width: 720px) {
    .tga-pack-line { grid-template-columns: minmax(0, 1fr) auto; }
    .tga-pack-sns { grid-column: 1 / -1; grid-row: 2; }
    .tga-pack-total strong { font-size: 14px; }
}

/* 配货发货面板右栏: 平台单(Shopee / TikTok)发货区(2026-09-29, _platform_ship.php) */
.tga-platform-shop { margin: 0 0 8px; }
.tga-platform-methods { display: flex; flex-wrap: wrap; gap: 6px 16px; }
.tga-platform-arranged { margin-bottom: 10px; }
.tga-platform-actions { display: flex; flex-wrap: wrap; gap: 8px; margin: 4px 0 8px; }
.tga-platform-reload { display: block; margin-top: 8px; padding: 0; border: 0; background: none; cursor: pointer; font-size: 12.5px; }

/* 订单列表(2026-09-29 重做): 订单状态标签页 + 商品明细行 */
.tga-tabs {
    display: flex;
    gap: 2px;
    padding: 0 12px;
    border-bottom: 1px solid var(--ad-border);
    overflow-x: auto;
    scrollbar-width: thin;
}
.tga-tab {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    flex-shrink: 0;
    padding: 12px 12px 10px;
    border-bottom: 2px solid transparent;
    color: var(--ad-text-2);
    font-size: 13.5px;
    white-space: nowrap;
    text-decoration: none;
}
.tga-tab:hover { color: var(--ad-text); text-decoration: none; }
.tga-tab.is-active { color: var(--ad-brand); border-bottom-color: var(--ad-brand); font-weight: 600; }
.tga-tab-count {
    min-width: 20px;
    padding: 0 6px;
    border-radius: 10px;
    background: var(--ad-bg);
    color: var(--ad-text-3);
    font-size: 12px;
    font-weight: 500;
    line-height: 18px;
    text-align: center;
}
.tga-tab.is-active .tga-tab-count { background: var(--ad-brand-soft); color: var(--ad-brand); }
.tga-order-line { display: flex; align-items: center; gap: 10px; }
.tga-order-line + .tga-order-line { margin-top: 8px; }
.tga-order-line-text { min-width: 0; }
.tga-order-line-name { max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tga-order-thumb {
    flex-shrink: 0;
    width: 40px;
    height: 40px;
    border: 1px solid var(--ad-border);
    border-radius: var(--ad-radius-sm);
    background: var(--ad-bg);
    object-fit: cover;
}

/* 官网运费模版(迁移 040): 分档表最后的「其余省份」行、分档表单的省份勾选格(34 个省) */
.tga-shipping-rest td { background: var(--ad-surface-alt); font-weight: 600; }
.tga-shipping-provinces { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 6px 12px; }
.tga-shipping-province {
    display: flex;
    align-items: flex-start;
    gap: 6px;
    min-width: 0;
    padding: 6px 8px;
    border: 1px solid var(--ad-border);
    border-radius: var(--ad-radius-sm);
    cursor: pointer;
    font-size: 13px;
    line-height: 1.4;
}
.tga-shipping-province input { margin-top: 2px; flex-shrink: 0; }
.tga-shipping-province:has(input:checked) { border-color: var(--ad-brand); background: var(--ad-brand-soft); }
.tga-shipping-province.is-taken { cursor: not-allowed; color: var(--ad-text-3); background: var(--ad-bg); }
/* 占着这个省的分档名(最长 64 字)放不下就省略, 全名在 label 的 title 里 */
.tga-shipping-province > span:first-of-type { min-width: 0; }
.tga-shipping-province .tga-table-sub { margin: 0 0 0 auto; min-width: 0; max-width: 50%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* 销售统计(2026-09-29 重排): 快捷日期、磁贴 / 趋势 / 两张排行之间的间距、合计行、趋势柱、占比条、名次 */
.tga-report-block { margin-top: 12px; }
.tga-report-note { margin: 12px 0 0; }
.tga-report-ranges { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 12px; }
.tga-report-ranges .tga-btn.is-active { border-color: var(--ad-brand); background: var(--ad-brand-soft); color: var(--ad-brand); }
.tga-report-total td { background: var(--ad-brand-soft); font-weight: 700; }
.tga-report-trend-sum { margin-left: auto; min-width: 0; font-size: 12.5px; color: var(--ad-text-3); text-align: right; }
.tga-trend {
    display: flex;
    align-items: flex-end;
    gap: 3px;
    height: 160px;
    border-bottom: 1px solid var(--ad-border);
}
/* 柱子少(比如按月只有两三个月)时每根最宽 64px、整组居中, 不然一根占半张卡片; 标签格同宽才对得齐 */
.tga-trend, .tga-trend-labels { justify-content: center; }
.tga-trend-col { flex: 1 1 0; min-width: 0; max-width: 64px; height: 100%; display: flex; flex-direction: column; justify-content: flex-end; cursor: default; }
.tga-trend-labels > span { max-width: 64px; }
.tga-trend-fill { display: block; min-height: 2px; border-radius: 3px 3px 0 0; background: var(--ad-brand); opacity: .55; transition: opacity .15s; }
.tga-trend-fill.is-top { opacity: .9; }
.tga-trend-fill.is-zero { background: var(--ad-border); opacity: 1; }
.tga-trend-col:hover .tga-trend-fill { opacity: 1; }
.tga-trend-scroll { overflow-x: auto; scrollbar-width: thin; }
.tga-trend-labels { display: flex; gap: 3px; margin-top: 6px; }
/* 标签隔几根出一个(视图里按柱子数算好 hide-w / hide-n), 露出来的可以伸到两边藏着的空位里, 不会被裁成半截 */
.tga-trend-labels span {
    flex: 1 1 0;
    min-width: 0;
    display: flex;
    justify-content: center;   /* 文字比柱子宽时用 flex 居中, 两边均匀伸出去(text-align 对放不下的文字不起作用, 只会往右伸) */
    overflow: visible;
    font-size: 10.5px;
    color: var(--ad-text-3);
    text-align: center;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}
.tga-trend-labels .hide-w { visibility: hidden; }
/* 首尾两个往里靠, 不伸出图表(伸出去会让滚动层多出几像素、冒一条横向滚动条) */
.tga-trend-labels span:first-child { justify-content: flex-start; }
.tga-trend-labels span:last-child { justify-content: flex-end; }
/* 4 块磁贴: auto-fit 在内容区 504 ~ 675px 时排成 3 + 1(2026-09-29 审查, 同 L32 / L68 的老问题), 固定 4 / 2 / 1 列 */
.tga-report-kpis { grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (max-width: 1279px) {
    .tga-report-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
/* 标题里带人名(「某某卖了哪些商品」), 全站卡片标题不折行的规则会让它在手机上撑出卡片 */
.tga-report-block .tga-card-title { flex-shrink: 1; min-width: 0; white-space: normal; overflow-wrap: anywhere; }
/* 金额列: 金额在上、占比条在下; 给个下限, 不然条被挤没 */
.tga-table .tga-report-share-col { min-width: 170px; text-align: right; }
.tga-report-amount { white-space: nowrap; font-variant-numeric: tabular-nums; }
.tga-report-product { max-width: 280px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tga-share-row { display: flex; align-items: center; gap: 8px; margin-top: 6px; }
.tga-share { flex: 1 1 auto; height: 6px; border-radius: 3px; background: var(--ad-bg); overflow: hidden; }
.tga-share > span { display: block; height: 100%; border-radius: 3px; background: var(--ad-brand); }
.tga-share-pct { min-width: 38px; font-size: 11.5px; color: var(--ad-text-3); text-align: right; font-variant-numeric: tabular-nums; }
.tga-rank {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: var(--ad-bg);
    color: var(--ad-text-2);
    font-size: 12px;
    font-weight: 700;
}
.tga-rank.is-top { background: var(--ad-brand-soft); color: var(--ad-brand); }
/* 磁贴里是「53,693,000 VND」这种长金额, 手机上两列会折成两行, 窄到这儿就一列 */
@media (max-width: 560px) {
    .tga-report-kpis { grid-template-columns: 1fr; }
}
@media (max-width: 720px) {
    .tga-trend { gap: 2px; height: 120px; }
    .tga-trend-labels { gap: 2px; }
    .tga-trend-labels .hide-w { visibility: visible; }
    .tga-trend-labels .hide-n { visibility: hidden; }
    .tga-report-trend-sum { display: none; }
    .tga-report-product { max-width: 160px; }
}

/* 工作台(2026-09-29 按整个平台重做): 待办磁贴 + 分块小标题 + 能点的统计磁贴 */
.tga-dash-block { margin-bottom: 16px; }
.tga-dash-heading { margin: 20px 0 10px; font-size: 14px; font-weight: 600; color: var(--ad-text-2); }
.tga-todo-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 12px; }
.tga-todo {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
    padding: 12px 14px;
    border: 1px solid var(--ad-border);
    border-radius: var(--ad-radius);
    background: var(--ad-surface-alt);
    color: var(--ad-text-3);
    text-decoration: none;
}
.tga-todo:hover { border-color: var(--ad-border-dark); text-decoration: none; }
.tga-todo-label { font-size: 13px; color: var(--ad-text-2); }
.tga-todo-count { font-size: 24px; font-weight: 700; line-height: 1.2; color: var(--ad-text-3); }
.tga-todo-hint { font-size: 12px; color: var(--ad-text-3); }
.tga-todo.is-hot { background: var(--ad-surface); border-color: var(--ad-brand-soft); box-shadow: inset 3px 0 0 var(--ad-brand); }
.tga-todo.is-hot .tga-todo-count { color: var(--ad-brand); }
.tga-todo.is-hot:hover { border-color: var(--ad-brand); }
a.tga-stat-link { color: inherit; text-decoration: none; }
a.tga-stat-link:hover { border-color: var(--ad-border-dark); text-decoration: none; }
/* 手机上待办排两列(一列十块要翻很久); 数字稍小一点, 标签允许折行 */
@media (max-width: 560px) {
    .tga-todo-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
    .tga-todo { padding: 10px 12px; }
    .tga-todo-count { font-size: 20px; }
}

/* 权限组编辑页(2026-09-29): 权限按模块分组打勾 */
.tga-perm-groups { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 12px; }
.tga-perm-group { margin: 0; padding: 10px 14px 12px; border: 1px solid var(--ad-border); border-radius: var(--ad-radius); min-width: 0; }
.tga-perm-group legend { padding: 0 6px; }
.tga-perm-group > .tga-check { display: flex; margin-top: 6px; }
.tga-check.is-disabled { opacity: .5; cursor: not-allowed; }

/* =============================================================================
 * 线下开单(迁移 039): 收银台。左边商品货架, 右边开单栏(大屏吸顶); 窄屏单列, 底部常驻「已选 n 件 · 合计」
 * 两栏用 minmax(0, 1fr): 子元素有最小宽度时父级不会被撑破(见 CSS min-width 撑坏两栏布局的教训)
 * ========================================================================== */
.tga-pos { display: grid; grid-template-columns: minmax(0, 1fr) 400px; gap: 16px; align-items: start; }
.tga-pos-shelf { padding: 14px; min-width: 0; }
.tga-pos-cats { display: flex; gap: 8px; overflow-x: auto; padding: 12px 0 4px; scrollbar-width: thin; }
.tga-pos-cat {
    flex: 0 0 auto; padding: 5px 12px; border: 1px solid var(--ad-border); border-radius: 999px;
    background: var(--ad-surface); color: var(--ad-text-2); font: inherit; font-size: 13px; white-space: nowrap; cursor: pointer;
}
.tga-pos-cat:hover { border-color: var(--ad-border-dark); color: var(--ad-text); }
.tga-pos-cat.is-active { background: var(--ad-brand); border-color: var(--ad-brand); color: #fff; }
.tga-pos-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(128px, 1fr)); gap: 10px; margin-top: 12px; }
.tga-pos-grid-empty { grid-column: 1 / -1; padding: 32px 0; color: var(--ad-text-3); text-align: center; }
.tga-pos-item {
    position: relative; display: flex; flex-direction: column; gap: 3px; min-width: 0; padding: 8px;
    border: 1px solid var(--ad-border); border-radius: var(--ad-radius); background: var(--ad-surface);
    color: var(--ad-text); font: inherit; text-align: left; cursor: pointer; transition: border-color .12s, box-shadow .12s;
}
.tga-pos-item:hover { border-color: var(--ad-brand); box-shadow: var(--ad-shadow-pop); }
.tga-pos-item:active { transform: scale(.98); }
.tga-pos-item.is-picked { border-color: var(--ad-brand); background: var(--ad-brand-soft); box-shadow: 0 0 0 1px var(--ad-brand), var(--ad-shadow-pop); }
.tga-pos-item-img {
    display: block; width: 100%; aspect-ratio: 1 / 1; margin-bottom: 6px; padding: 8px; object-fit: contain;
    border: 1px solid var(--ad-border); border-radius: var(--ad-radius-sm); background: #fff; transition: transform .15s;
}
.tga-pos-item:hover .tga-pos-item-img { transform: scale(1.02); }
.tga-pos-item-name { display: -webkit-box; min-height: 2.7em; overflow: hidden; font-size: 13px; line-height: 1.35; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.tga-pos-item-sku { overflow: hidden; color: var(--ad-text-3); font-size: 11px; text-overflow: ellipsis; white-space: nowrap; }
.tga-pos-item-price { color: var(--ad-brand); font-size: 14px; font-weight: 600; }
.tga-pos-item-price.is-none { color: var(--ad-text-3); font-weight: 400; }
.tga-pos-item-stock { color: var(--ad-text-3); font-size: 11px; }
.tga-pos-item-stock.is-out { color: var(--ad-warning); }
.tga-pos-item-qty {
    position: absolute; top: 2px; right: 2px; z-index: 1; min-width: 30px; height: 30px; padding: 0 8px; border: 2px solid #fff; border-radius: 999px;
    background: var(--ad-brand); color: #fff; font-size: 14px; font-weight: 700; line-height: 26px; text-align: center; box-shadow: 0 2px 6px rgba(216, 19, 25, .35);
}
.tga-pos-more { margin-top: 12px; text-align: center; }

.tga-pos-ticket {
    position: sticky; top: calc(var(--ad-top-h) + 16px); display: flex; flex-direction: column;
    max-height: calc(100vh - var(--ad-top-h) - 32px); overflow-y: auto;
}
.tga-pos-block { padding: 14px 16px; border-bottom: 1px solid var(--ad-border); }
.tga-pos-block-title { margin-bottom: 8px; font-weight: 600; }
.tga-pos-member { display: flex; align-items: center; gap: 10px; }
.tga-pos-member-main { flex: 1; min-width: 0; }
.tga-pos-results { max-height: 220px; margin-top: 6px; overflow-y: auto; border: 1px solid var(--ad-border); border-radius: var(--ad-radius); }
.tga-pos-result {
    display: flex; align-items: center; gap: 8px; width: 100%; padding: 8px 10px; border: 0; border-bottom: 1px solid var(--ad-border);
    background: var(--ad-surface); color: var(--ad-text); font: inherit; text-align: left; cursor: pointer;
}
.tga-pos-result:last-child { border-bottom: 0; }
.tga-pos-result:hover { background: var(--ad-surface-alt); }
.tga-pos-result .tga-badge { margin-left: auto; }
.tga-pos-result-none { padding: 10px; color: var(--ad-text-3); font-size: 13px; }
.tga-pos-link { margin-top: 8px; padding: 0; border: 0; background: none; color: var(--ad-brand); font: inherit; font-size: 13px; cursor: pointer; }
.tga-pos-link:hover { text-decoration: underline; }
.tga-pos-newmember .tga-hint { margin-top: 6px; }
.tga-pos-row2 { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 10px; }
.tga-pos-pay { display: flex; flex-direction: column; gap: 4px; min-height: 36px; }
.tga-pos-error { color: var(--ad-danger); font-size: 13px; }
.tga-pos-error:not(:empty) { margin-top: 6px; }
.tga-pos-cart-block { background: var(--ad-surface-alt); }
.tga-pos-cart-head { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; margin-bottom: 10px; }
.tga-pos-cart-head > * { white-space: nowrap; }
.tga-pos-cart-title { font-size: 15px; font-weight: 700; }
.tga-pos-cart-count { padding: 2px 10px; border-radius: 999px; background: var(--ad-brand); color: #fff; font-size: 12px; font-weight: 600; }
.tga-pos-cart-count:empty { display: none; }
.tga-pos-cart-clear { margin: 0 0 0 auto; }
.tga-pos-cart { display: flex; flex-direction: column; gap: 8px; }
.tga-pos-cart-empty {
    display: flex; flex-direction: column; align-items: center; gap: 6px; padding: 20px 12px;
    border: 2px dashed var(--ad-border-dark); border-radius: var(--ad-radius); background: var(--ad-surface); color: var(--ad-text-2); font-size: 13px; text-align: center;
}
.tga-pos-cart-empty svg { color: var(--ad-text-3); }
.tga-pos-line {
    display: flex; gap: 10px; padding: 10px; border: 1px solid var(--ad-border); border-left: 3px solid var(--ad-brand);
    border-radius: var(--ad-radius); background: var(--ad-surface); box-shadow: var(--ad-shadow);
}
.tga-pos-line.is-flash { animation: tga-pos-flash 1.2s ease-out; }
@keyframes tga-pos-flash {
    0%   { background: var(--ad-brand-soft); box-shadow: 0 0 0 3px rgba(216, 19, 25, .25); }
    100% { background: var(--ad-surface); box-shadow: var(--ad-shadow); }
}
.tga-pos-line-img { flex-shrink: 0; width: 56px; height: 56px; padding: 3px; object-fit: contain; border: 1px solid var(--ad-border); border-radius: var(--ad-radius-sm); background: #fff; }
.tga-pos-line-main { flex: 1; min-width: 0; }
.tga-pos-line-head { display: flex; align-items: flex-start; gap: 8px; }
.tga-pos-line-name { display: flex; flex: 1; flex-direction: column; min-width: 0; }
.tga-pos-line-name > span:first-child { display: -webkit-box; overflow: hidden; font-size: 14px; font-weight: 600; line-height: 1.35; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.tga-pos-line-sku { color: var(--ad-text-3); font-size: 11px; }
.tga-pos-line-remove {
    flex-shrink: 0; width: 24px; height: 24px; padding: 0; border: 0; border-radius: 50%; background: var(--ad-neutral-bg);
    color: var(--ad-text-2); font-size: 16px; line-height: 24px; cursor: pointer;
}
.tga-pos-line-remove:hover { background: var(--ad-danger-bg); color: var(--ad-danger); }
/* 两行: 数量 | 单价; 下一行 价目表价提示(左) + 小计(右) */
.tga-pos-line-body { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 6px 8px; align-items: center; margin-top: 8px; }
.tga-pos-line-foot { display: flex; grid-column: 1 / -1; align-items: baseline; justify-content: space-between; gap: 8px; }
.tga-pos-line-foot .tga-pos-line-hint { min-width: 0; margin-top: 0; }
.tga-pos-stepper { display: inline-flex; overflow: hidden; border: 1px solid var(--ad-border-dark); border-radius: var(--ad-radius-sm); }
.tga-pos-stepper button { width: 30px; border: 0; background: var(--ad-surface-alt); color: var(--ad-text); font-size: 16px; font-weight: 600; cursor: pointer; }
.tga-pos-stepper button:hover { background: var(--ad-brand-soft); color: var(--ad-brand); }
.tga-pos-stepper .tga-input { width: 46px; height: 32px; padding: 4px; border: 0; border-radius: 0; font-weight: 600; text-align: center; }
.tga-pos-price { height: 34px; text-align: right; }
.tga-pos-line-sub { min-width: 90px; color: var(--ad-text); font-size: 14px; font-weight: 700; text-align: right; white-space: nowrap; }
.tga-pos-line-hint { margin-top: 4px; color: var(--ad-text-3); font-size: 12px; }
.tga-pos-line-hint.is-warn { color: var(--ad-warning); }
.tga-pos-settle { position: sticky; bottom: 0; margin-top: auto; padding: 14px 16px; background: var(--ad-surface-alt); }
.tga-pos-total { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 10px; }
.tga-pos-total strong { color: var(--ad-brand); font-size: 22px; }
.tga-pos-submit { width: 100%; height: 44px; font-size: 16px; }
.tga-pos-bar { display: none; }
/* 收款方式 / 交付方式(迁移 058): 一排可点的方块单选; 已收款的明细块(账户、找零) */
.tga-pos-methods { display: flex; flex-wrap: wrap; gap: 6px; }
.tga-pos-method { display: inline-flex; align-items: center; gap: 6px; padding: 6px 10px; border: 1px solid var(--ad-border-dark); border-radius: var(--ad-radius-sm); background: var(--ad-surface); font-size: 13px; cursor: pointer; }
.tga-pos-method:has(input:checked) { border-color: var(--ad-brand); background: var(--ad-brand-soft); color: var(--ad-brand); font-weight: 600; }
.tga-pos-paydetail { display: grid; gap: 10px; margin-top: 10px; padding: 10px 12px; border: 1px solid var(--ad-border); border-radius: var(--ad-radius); background: var(--ad-surface-alt); }
.tga-pos-cash { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 10px; align-items: end; }
.tga-pos-change { padding-bottom: 8px; color: var(--ad-text-2); font-size: 13px; white-space: nowrap; }
.tga-pos-change strong { margin-left: 4px; color: var(--ad-success); font-size: 18px; }
.tga-pos-change strong.is-short { color: var(--ad-danger); }
/* 扫码 / 快捷键提示、挂单 / 取单、恢复草稿提示、开单成功面板(2026-10-06) */
.tga-pos-keys { margin-top: 6px; font-size: 12px; }
.tga-pos-keys.is-ok { color: var(--ad-success); font-weight: 600; }
.tga-pos-hold { margin: 0; }
.tga-pos-held { display: grid; gap: 6px; margin-bottom: 10px; padding: 8px; border: 1px solid var(--ad-border); border-radius: var(--ad-radius); background: var(--ad-surface); }
.tga-pos-held-row { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; font-size: 13px; }
.tga-pos-held-row .tga-pos-link { margin: 0; }
.tga-pos-held-text { flex: 1 1 180px; min-width: 0; }
.tga-pos-restored { margin-bottom: 10px; padding: 6px 10px; border-radius: var(--ad-radius-sm); background: var(--ad-info-bg, #EAF2FF); color: var(--ad-text-2); font-size: 12px; }
.tga-pos-done-mask { position: fixed; inset: 0; z-index: 60; display: flex; align-items: center; justify-content: center; padding: 16px; background: rgba(16, 24, 40, .45); }
.tga-pos-done-panel { width: 100%; max-width: 380px; padding: 24px 22px 20px; border-radius: 10px; background: var(--ad-surface); box-shadow: 0 12px 32px rgba(16, 24, 40, .25); text-align: center; }
.tga-pos-done-icon { width: 48px; height: 48px; margin: 0 auto 10px; border-radius: 50%; background: var(--ad-success-bg); color: var(--ad-success); font-size: 26px; line-height: 48px; }
.tga-pos-done-title { margin: 0; font-size: 18px; }
.tga-pos-done-no { margin-top: 6px; font-size: 15px; font-weight: 700; }
.tga-pos-done-amount { margin-top: 4px; color: var(--ad-brand); font-size: 24px; font-weight: 700; }
.tga-pos-done-msg { margin: 8px 0 0; color: var(--ad-text-2); font-size: 13px; }
.tga-pos-done-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 16px; }
.tga-pos-done-actions #posDoneNext { grid-column: 1 / -1; height: 42px; font-size: 15px; }

/* 配货面板「按批次整批配货」 */
.tga-pack-batch { margin-top: 12px; }
.tga-pack-batch-row { display: flex; gap: 8px; }
.tga-pack-batch-row .tga-input { flex: 1; min-width: 0; }

@media (max-width: 1100px) {
    .tga-pos { grid-template-columns: minmax(0, 1fr) 320px; }
}
@media (max-width: 860px) {
    .tga-pos { grid-template-columns: minmax(0, 1fr); }
    .tga-pos-ticket { position: static; max-height: none; overflow: visible; }
    .tga-pos-settle { position: static; }
    .tga-pos-grid { grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); }
    .tga-pos-bar.is-shown {
        position: fixed; right: 0; bottom: 0; left: 0; z-index: 30; display: flex; align-items: center; justify-content: space-between;
        gap: 12px; padding: 10px 16px; border-top: 1px solid var(--ad-border); background: var(--ad-surface); box-shadow: 0 -4px 12px rgba(16, 24, 40, .08);
    }
    /* 底部条盖住的那一截留出来 */
    .tga-pos-bar.is-shown + .tga-card { margin-bottom: 72px; }
}
@media (max-width: 400px) {
    .tga-pos-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
    .tga-pos-row2 { grid-template-columns: minmax(0, 1fr); }
}

/* 线下开单的收货地址(2026-09-29): 会员地址簿单选列表 + 新地址表单 */
.tga-pos-addrs { display: flex; flex-direction: column; gap: 6px; margin-bottom: 10px; }
.tga-pos-addr {
    display: flex; align-items: flex-start; gap: 8px; padding: 8px 10px; border: 1px solid var(--ad-border);
    border-radius: var(--ad-radius); cursor: pointer;
}
.tga-pos-addr:hover { border-color: var(--ad-border-dark); }
.tga-pos-addr:has(input:checked) { border-color: var(--ad-brand); background: var(--ad-brand-soft); }
.tga-pos-addr input { margin-top: 3px; flex-shrink: 0; }
.tga-pos-addr-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.tga-pos-addr-title { display: flex; align-items: center; gap: 6px; font-size: 13px; font-weight: 600; }
.tga-pos-addr-sub { color: var(--ad-text-2); font-size: 12px; overflow-wrap: anywhere; }
.tga-pos-addr-form .tga-field { margin-bottom: 8px; }
.tga-pos-addr-form .tga-pos-row2 { margin-bottom: 0; }
.tga-pos-save-addr { font-size: 13px; }

/* 订单详情「配货发货」里的收货信息(线下开单): 仓库按它配送 */
.tga-pack-address { margin-bottom: 14px; padding: 10px 12px; border: 1px solid var(--ad-border); border-radius: var(--ad-radius); background: var(--ad-surface-alt); font-size: 13px; line-height: 1.6; }
.tga-pack-address-title { margin-bottom: 4px; color: var(--ad-text-3); font-size: 12px; }
.tga-pack-address-main { font-weight: 600; }

/* 打印拣货单(2026-09-29): 订单列表的勾选列、配货面板标题栏右侧(打印按钮 + 已绑件数) */
.tga-pick-cell { width: 36px; text-align: center; }
.tga-pick-cell input { width: 16px; height: 16px; cursor: pointer; }
.tga-pack-head-right { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 12px; }

/* ---------- 线下开单改价待审核(迁移 053): 用户说原来不显眼、会漏 ---------- */
/* 左侧菜单的待办数字: 条目上一个, 组收起时组名后面一个(展开后由条目显示, 不重复) */
.tga-nav-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    margin-left: auto;
    border-radius: 9px;
    background: var(--ad-brand);
    color: #fff;
    font-size: 11px;
    font-weight: 700;
    line-height: 1;
}
.tga-nav-badge-group { margin-left: 0; }
.tga-nav-group-label + .tga-nav-badge-group { margin-left: auto; }
.tga-nav-group-label + .tga-nav-badge-group + .tga-nav-caret { margin-left: 6px; }
.tga-nav-section.is-open > .tga-nav-group .tga-nav-badge-group,
.tga-nav:not(.is-scripted) .tga-nav-section[open] > .tga-nav-group .tga-nav-badge-group { display: none; }
/* 订单列表最上面的横条 */
.tga-review-banner {
    display: flex;
    align-items: center;
    gap: 14px;
    margin-bottom: 16px;
    padding: 14px 16px;
    border: 1px solid #F3C27A;
    border-left: 5px solid #E07B00;
    border-radius: var(--ad-radius-sm);
    background: #FFF4E0;
}
.tga-review-banner-count {
    flex: 0 0 auto;
    min-width: 40px;
    height: 40px;
    padding: 0 8px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 20px;
    background: #E07B00;
    color: #fff;
    font-size: 18px;
    font-weight: 700;
}
.tga-review-banner-text { flex: 1 1 auto; display: grid; gap: 2px; min-width: 0; }
.tga-review-banner-text strong { color: #8A4B00; font-size: 15px; }
.tga-review-banner-text span { color: #8A5A1F; font-size: 13px; }
/* 状态标签栏: 「改价待审核」靠右, 有单时数字是红底白字 */
.tga-tab-review { margin-left: auto; }
.tga-tab-count.is-alert { background: var(--ad-brand); color: #fff; font-weight: 700; }
/* 列表行: 整行浅橙底 + 左边一道橙条(已驳回是红) */
.tga-table tbody tr.tga-row-review td,
.tga-table tbody tr.tga-row-review:hover td { background: #FFF6E5; }
.tga-table tbody tr.tga-row-review td:first-child { box-shadow: inset 4px 0 0 #E07B00; }
.tga-table tbody tr.tga-row-review.is-rejected td,
.tga-table tbody tr.tga-row-review.is-rejected:hover td { background: #FDEEEC; }
.tga-table tbody tr.tga-row-review.is-rejected td:first-child { box-shadow: inset 4px 0 0 var(--ad-danger); }
.tga-review-pill {
    display: inline-block;
    padding: 2px 9px;
    border-radius: 999px;
    background: #E07B00;
    color: #fff;
    font-size: 12px;
    font-weight: 700;
    white-space: nowrap;
}
.tga-review-pill:hover { color: #fff; text-decoration: none; filter: brightness(.95); }
.tga-review-pill.is-rejected { background: var(--ad-danger); }
.tga-review-hold { color: #B45309; font-weight: 600; }

/* ---------- 待发货(2026-10-06): 仓库一眼看出哪些单现在要发 ---------- */
.tga-tab-count.is-go { background: var(--ad-success); color: #fff; font-weight: 700; }
.tga-ship-state { margin-top: 3px; font-size: 12px; font-weight: 700; white-space: nowrap; }
.tga-ship-state.is-ready { color: var(--ad-success); }
.tga-ship-state.is-wait { color: #B45309; }
.tga-ship-age { font-size: 12px; color: var(--ad-text-3); }
.tga-ship-age.is-late { color: var(--ad-danger); font-weight: 700; }
.tga-ship-hint { padding: 10px 16px; border-bottom: 1px solid var(--ad-border); font-size: 13px; }
.tga-ship-hint.is-ready { background: var(--ad-success-bg); color: var(--ad-success); }
.tga-ship-hint.is-waiting { background: var(--ad-warning-bg); color: var(--ad-warning); }

/* ---------- 报销审批(2026-10-06): 附件缩略图 + 灯箱, 等我审批的提示 ---------- */
/* 「待我审批」这类红底数字在当前页签上也保持红底(原来会被 is-active 的浅色盖掉) */
.tga-tab.is-active .tga-tab-count.is-alert { background: var(--ad-brand); color: #fff; }
/* 详情页: 轮到我审批的同意 / 驳回卡片, 和顶部提醒条同一个橙色; 点「去审批」跳过来时不被顶栏挡住 */
.tga-approve-card { border-color: #F3C27A; box-shadow: inset 4px 0 0 #E07B00; scroll-margin-top: 80px; }
.tga-approve-card .tga-card-head { background: #FFF4E0; }
.tga-approve-card .tga-card-title { color: #8A4B00; }
/* 附件格子: 图片点开是灯箱; PDF 是文件块 */
.tga-claim-files .tga-evidence-item > a { border-radius: 6px; }
.tga-claim-files .tga-evidence-item > a[data-lightbox] { display: block; }
/* 票据多是竖拍: 方格 + 整张显示(不裁), 抬头和合计都看得到 */
.tga-claim-files .tga-evidence-item img { aspect-ratio: 1 / 1; object-fit: contain; background: var(--ad-surface-alt); }
.tga-claim-files .tga-evidence-item > a[data-lightbox] { cursor: zoom-in; }
.tga-claim-files .tga-evidence-item > a[data-lightbox]:hover img { border-color: var(--ad-brand); }
.tga-claim-files .tga-evidence-item > a:focus-visible { outline: 2px solid var(--ad-brand); outline-offset: 2px; }
.tga-file-tile {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    aspect-ratio: 1 / 1;
    border: 1px solid var(--ad-border);
    background: var(--ad-surface-alt);
    color: var(--ad-text-2);
}
.tga-file-tile:hover { border-color: var(--ad-brand); text-decoration: none; }
.tga-file-tile-ext { padding: 4px 10px; border-radius: 4px; background: var(--ad-danger); color: #fff; font-size: 13px; font-weight: 700; letter-spacing: .5px; }
.tga-file-tile-open { font-size: 12px; }
/* 灯箱 */
html.tga-lightbox-open { overflow: hidden; }
.tga-lightbox { position: fixed; inset: 0; z-index: 1000; background: rgba(12, 12, 14, .92); }
.tga-lightbox[hidden], .tga-lightbox [hidden] { display: none !important; }
.tga-lightbox-stage { position: absolute; inset: 52px 64px 56px; display: flex; align-items: center; justify-content: center; overflow: auto; }
.tga-lightbox-img { display: block; max-width: 100%; max-height: 100%; object-fit: contain; background: #fff; box-shadow: 0 8px 40px rgba(0, 0, 0, .5); cursor: zoom-in; transition: opacity .15s; }
.tga-lightbox.is-zoomed .tga-lightbox-stage { display: block; }
.tga-lightbox.is-zoomed .tga-lightbox-img { max-width: none; max-height: none; margin: 0 auto; cursor: zoom-out; }
.tga-lightbox.is-loading .tga-lightbox-img { opacity: .2; }
.tga-lightbox.is-loading::after {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    width: 36px;
    height: 36px;
    margin: -18px 0 0 -18px;
    border: 3px solid rgba(255, 255, 255, .3);
    border-top-color: #fff;
    border-radius: 50%;
    animation: tga-lightbox-spin .8s linear infinite;
}
@keyframes tga-lightbox-spin { to { transform: rotate(360deg); } }
.tga-lightbox-nav, .tga-lightbox-close {
    position: absolute;
    border: 0;
    border-radius: 6px;
    background: rgba(255, 255, 255, .12);
    color: #fff;
    line-height: 1;
    cursor: pointer;
}
.tga-lightbox-nav:hover, .tga-lightbox-close:hover { background: rgba(255, 255, 255, .25); }
.tga-lightbox-nav:focus-visible, .tga-lightbox-close:focus-visible, .tga-lightbox-original:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.tga-lightbox-nav { top: 50%; width: 48px; height: 72px; margin-top: -36px; font-size: 40px; }
.tga-lightbox-nav.is-prev { left: 8px; }
.tga-lightbox-nav.is-next { right: 8px; }
.tga-lightbox-close { top: 8px; right: 8px; width: 40px; height: 40px; font-size: 30px; }
.tga-lightbox-bar { position: absolute; right: 0; bottom: 0; left: 0; height: 56px; display: flex; align-items: center; gap: 14px; padding: 0 16px; color: #E8E8E8; font-size: 13px; }
.tga-lightbox-counter { flex: 0 0 auto; font-weight: 700; }
.tga-lightbox-caption { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tga-lightbox-original { flex: 0 0 auto; color: #fff; text-decoration: underline; }
.tga-lightbox-original:hover { color: #fff; }
@media (max-width: 600px) {
    .tga-lightbox-stage { inset: 52px 0 56px; }
    .tga-lightbox-nav { width: 38px; height: 56px; margin-top: -28px; font-size: 32px; background: rgba(0, 0, 0, .45); }
    .tga-lightbox-nav.is-prev { left: 4px; }
    .tga-lightbox-nav.is-next { right: 4px; }
}

/* ---------- 开单页(2026-10-06): 三种价一起显示、一键设价、会员搜索下拉多显示信息 ---------- */
.tga-pos-item-price { display: grid; gap: 1px; }
/* 紧凑商品卡(2026-10-06 收银台优化): 当前会员等级的价大字, 另两档并成一行小字; 图片改 4:3, 一屏多看一倍 */
.tga-pos-item-main { color: var(--ad-brand); font-size: 14px; font-weight: 700; }
.tga-pos-item-others { color: var(--ad-text-3); font-size: 11px; font-weight: 400; line-height: 1.35; }
/* 2026-10-07 用户「商品价格排版怎么错了」: 每档价一行、两段 —— 等级名(放不下省略号)+ 金额(永远完整);
   原来另两档拼成一整串, 卡片窄时「核心门店」和金额被拆到两行, 越南语等级名还会撑出卡片 */
.tga-pos-item-main,
.tga-pos-item-other { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: baseline; column-gap: 4px; }
/* 收银台以越南语为主(2026-10-07 用户): 等级名不许截, 「Cửa hàng thân thiết」放不下就折成两行; 金额不折行、右对齐 */
.tga-pos-item-tier { min-width: 0; overflow-wrap: anywhere; }
.tga-pos-item-amount { white-space: nowrap; text-align: right; }
.tga-pos-item-main .tga-pos-item-tier { font-size: 11px; font-weight: 500; }
.tga-pos-item-others { display: grid; }
.tga-pos-item { padding: 6px; gap: 2px; }
.tga-pos-item-img { aspect-ratio: auto; height: 76px; margin-bottom: 4px; padding: 4px; }
.tga-pos-item-name { min-height: 2.6em; font-size: 12.5px; }
.tga-pos-grid { grid-template-columns: repeat(auto-fill, minmax(118px, 1fr)); gap: 8px; }
/* 平板档(861~1100): 右栏 300, 卡片再窄一点。860 以下原来的单栏规则不动(写在前面, 这里不能盖掉它) */
@media (min-width: 861px) and (max-width: 1100px) {
    .tga-pos { grid-template-columns: minmax(0, 1fr) 320px; }
    .tga-pos-grid { grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); }
    /* 收银台以越南语为主(2026-10-07): 平板横屏右栏窄, 两列字段改单列, 越南语提示文字 / 「Chưa thu (công nợ)」才放得下 */
    .tga-pos-row2 { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 400px) {
    .tga-pos-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.tga-pos-tierbar { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-bottom: 8px; }
.tga-pos-tierbar-label { color: var(--ad-text-3); font-size: 12px; }
.tga-pos-chip {
    padding: 2px 8px; border: 1px solid var(--ad-border); border-radius: 999px; background: var(--ad-surface);
    color: var(--ad-text-2); font: inherit; font-size: 12px; line-height: 1.6; white-space: nowrap; cursor: pointer;
}
.tga-pos-chip:hover { border-color: var(--ad-brand); color: var(--ad-brand); }
.tga-pos-chip.is-on { border-color: var(--ad-brand); background: var(--ad-brand-soft); color: var(--ad-brand); font-weight: 600; }
.tga-pos-chips { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 6px; }
/* 价格和会员等级不一致 = 改价(要审核时橙色提醒) */
.tga-pos-price-notice {
    margin-top: 8px; padding: 8px 10px; border: 1px solid #F3C27A; border-left: 4px solid #E07B00; border-radius: var(--ad-radius-sm);
    background: #FFF4E0; color: #8A4B00; font-size: 12.5px; line-height: 1.5;
}
.tga-pos-results { max-height: 320px; }
.tga-pos-result { flex-direction: column; align-items: stretch; gap: 2px; }
.tga-pos-result-top { display: flex; align-items: center; gap: 8px; }
.tga-pos-result-top .tga-badge { margin-left: auto; }
.tga-pos-result-sub { color: var(--ad-text-3); font-size: 12px; }
.tga-pos-result-sub.is-warn { color: var(--ad-warning); }

/* ---------- 修改订单(迁移 055): 金额明细、新会员申请的等级 / 额度 ---------- */
.tga-pos-breakdown { display: grid; gap: 4px; margin-bottom: 6px; color: var(--ad-text-2); font-size: 13px; }
.tga-pos-breakdown > div { display: flex; justify-content: space-between; gap: 8px; }
.tga-pos-review-terms { margin-top: 10px; padding: 10px 12px; border: 1px solid #F3C27A; border-left: 4px solid #E07B00; border-radius: var(--ad-radius-sm); background: #FFF8EC; }

/* ---------- 订单详情页布局(2026-10-06 用户: 紧凑一点、更符合使用习惯) ---------- */
/* 第一排: 左「商品与金额」2/3, 右「新会员审核 / 客户与付款」1/3; 1100 以下上下排 */
.tga-order-layout { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); gap: 16px; align-items: start; margin-bottom: 16px; }
.tga-order-main, .tga-order-side { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; min-width: 0; }
.tga-order-side .tga-desc { grid-template-columns: minmax(0, 1fr); }
.tga-desc-compact .tga-desc-item { padding: 7px 2px; }
.tga-desc-compact .tga-desc-label { width: 96px; }
/* 改价审核条: 放在商品表格上面, 待审核标橙、驳回标红 */
.tga-order-review-wrap { padding-bottom: 0; }
.tga-order-review { padding: 10px 14px; border: 1px solid var(--ad-border); border-left-width: 4px; border-radius: var(--ad-radius-sm); background: var(--ad-bg, #F7F8FA); scroll-margin-top: 80px; }
.tga-order-review.is-pending { border-color: #F3C27A; border-left-color: #E07B00; background: #FFF8EC; }
.tga-order-review.is-rejected { border-color: #F2B8B5; border-left-color: #D92D20; background: #FEF3F2; }
.tga-order-review.is-approved { border-left-color: #12B76A; }
.tga-order-review-head { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 14px; font-size: 13.5px; }
/* 改过价的行(和价目表价不一样 / 没有价目表价): 单价标橙 */
.tga-table tr.is-changed .tga-order-price, .tga-quick-table tr.is-changed input[data-price] { color: #B54708; font-weight: 600; }
.tga-quick-table tr.is-changed input[data-price] { border-color: #F3C27A; background: #FFF8EC; }
.tga-quick-table input[data-price] { width: 130px; text-align: right; }
.tga-quick-table input[data-qty] { width: 76px; text-align: right; }
/* 表格下方: 左边整单优惠, 右边金额合计 */
.tga-order-foot { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: flex-start; gap: 16px 24px; border-top: 1px solid var(--ad-border); }
.tga-order-totals { display: grid; gap: 6px; min-width: 240px; margin-left: auto; font-size: 13.5px; }
.tga-order-totals > div { display: flex; justify-content: space-between; gap: 24px; }
.tga-order-totals > div > span:first-child { color: var(--ad-text-2); }
.tga-order-totals .is-pay { padding-top: 6px; border-top: 1px solid var(--ad-border); font-size: 16px; font-weight: 600; }
.tga-order-totals .is-pay > span:first-child { color: inherit; }
.tga-quick-discount { min-width: 0; }
.tga-quick-discount-row { display: flex; gap: 8px; }
.tga-quick-discount-row .tga-select { width: auto; min-width: 150px; }
.tga-quick-discount-row .tga-input { width: 150px; }
.tga-order-save { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 16px; padding-top: 0; }
.tga-order-save .tga-hint { flex: 1 1 280px; margin: 0; }
/* 第三排: 订单信息 2/3(字段排两列)、修改状态 1/3, 状态卡不再被拉成和详情一样高; 只有详情一张时占满 */
.tga-grid-2.tga-order-cols { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); align-items: start; }
.tga-order-cols > .tga-card:only-child { grid-column: 1 / -1; }
.tga-grid-2.tga-order-cols .tga-desc { grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr)); }
.tga-order-cols .tga-desc-item { padding: 8px 4px; }
@media (max-width: 1100px) {
    .tga-order-layout, .tga-grid-2.tga-order-cols { grid-template-columns: minmax(0, 1fr); }
}

/* ---------- 订单详情页: 进度条 / 订单操作 / 关闭的单配货面板折叠(迁移 056, 2026-10-06 全面检查) ---------- */
.tga-order-steps { display: flex; flex-wrap: wrap; gap: 4px 2px; margin: 10px 0 0; padding: 0; list-style: none; font-size: 12.5px; }
.tga-order-steps li { position: relative; padding: 3px 10px 3px 20px; color: var(--ad-text-2); background: var(--ad-bg); }
.tga-order-steps li::before { content: ""; position: absolute; left: 7px; top: 50%; width: 7px; height: 7px; margin-top: -4.5px; border-radius: 50%; border: 1.5px solid currentColor; }
.tga-order-steps li:first-child { border-radius: 12px 0 0 12px; }
.tga-order-steps li:last-child { border-radius: 0 12px 12px 0; }
.tga-order-steps li.is-done { color: var(--ad-success); }
.tga-order-steps li.is-done::before { background: currentColor; }
.tga-order-steps li.is-current { color: #fff; background: var(--ad-brand); font-weight: 600; }
.tga-order-steps li.is-current::before { background: #fff; border-color: #fff; }
.tga-order-steps li.is-closed { color: #fff; background: #667085; }
.tga-order-steps li.is-closed::before { display: none; }
.tga-order-steps li.is-closed { padding-left: 10px; }
.tga-order-steps.is-closed li.is-muted { opacity: .6; }
/* 关闭的单: 配货发货面板折叠成一行, 点开才看 */
summary.tga-card-head { list-style: none; cursor: pointer; }
summary.tga-card-head::-webkit-details-marker { display: none; }
summary.tga-card-head .tga-card-title::before { content: "\25B8"; display: inline-block; width: 14px; color: var(--ad-text-2); }
details[open] > summary.tga-card-head .tga-card-title::before { content: "\25BE"; }
details.tga-pack:not([open]) > summary.tga-card-head { border-bottom: 0; }
/* 订单操作(线下单): 每个动作一行, 取消在红框里 */
.tga-order-ops-list { display: grid; gap: 10px; }
.tga-order-ops-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.tga-order-ops-row .tga-input { flex: 1 1 160px; min-width: 0; }
.tga-order-ops-row .tga-hint { flex: 1 1 100%; margin: 0; }
.tga-order-ops-row.is-danger { padding: 10px 12px; border: 1px solid #F2B8B5; border-radius: var(--ad-radius-sm); background: var(--ad-danger-bg); }
.tga-order-ops .tga-input.is-readonly { display: flex; align-items: center; background: var(--ad-bg); color: var(--ad-text-2); }
