/* app.css — 喺 Bootstrap 5 之上做 override(藍圖 §9;唔重複大段樣式)*/
:root { --ty-accent: #0d6efd; --ty-topbar-h: 56px; --ty-sb-w: 220px; }
body { background: #f6f7f9; }
.ty-brand { font-weight: 600; letter-spacing: .5px; }

/* ── 版面:頂部薄列 + 可收合左側欄(2026-06-06)───────────────────────── */
.ty-topbar { position: sticky; top: 0; z-index: 1040; min-height: var(--ty-topbar-h); }

/* store-scope T5(spec §7.3):頂列門市切換器 — 唯讀徽章 / 下拉。⛔ 唔跟用戶名 d-none d-sm-inline,
   手機寬度一樣要見到可用(brief:390px 切換器可見可用)。*/
.ty-store-switcher { position: relative; }
.ty-store-badge { font-size: .85rem; white-space: nowrap; }
.ty-store-select { max-width: 150px; }
.ty-store-switcher-error {
  position: absolute; top: 100%; right: 0; margin-top: .25rem;
  background: #fff; color: var(--ty-color-danger); padding: .2rem .5rem; border-radius: 4px;
  white-space: nowrap; box-shadow: 0 2px 8px rgba(0, 0, 0, .18); z-index: 1050;
}
@media (max-width: 575.98px) {
  .ty-store-select { max-width: 84px; font-size: .78rem; padding-top: .2rem; padding-bottom: .2rem; }
  .ty-store-badge { font-size: .72rem; padding: .3rem .45rem; }
}
/* store-scope (T5 fix round 1, I-1): this 84px select width was only ever measured alongside the
   home page's topbar (no "🏠 主目錄" button there, #133). Verified by direct measurement it also fits
   every OTHER page's topbar (toggler + brand + this select + the home button) at 390px without wrapping
   -- but only once the home button's own label text is hidden at this width too; see the
   `d-none d-sm-inline` span around "主目錄" in _layout.php (that part had to be a markup change: CSS
   alone cannot hide half of a plain text node). No extra rule was needed here. */

.ty-sidebar {
  position: fixed; top: var(--ty-topbar-h); left: 0; bottom: 0;
  width: var(--ty-sb-w); z-index: 1035; overflow-y: auto;
  background: #fff; border-right: 1px solid #dee2e6; padding: .5rem 0;
  transition: transform .2s ease;
}
/* B2 2.1:側欄轉直向 flex,令 .ty-nav-logout 用 margin-top:auto 推到最底。
   桌面收合(`html.ty-sidebar-collapsed .ty-sidebar`)同手機 off-canvas(`@media(max-width:767.98px)` 內嘅 `.ty-sidebar` / `html.ty-sidebar-open .ty-sidebar`)
   全部用 transform,唔碰 display → 同 flex 零衝突。*/
.ty-sidebar { display: flex; flex-direction: column; }
.ty-sidebar > .nav { flex: 1 1 auto; }
.ty-sidebar .ty-nav-logout { margin-top: auto; border-top: 1px solid var(--ty-color-border-soft); padding-top: .4rem; }
.ty-sidebar .ty-nav-logout .nav-link { color: var(--ty-color-danger); font-weight: 600; }
.ty-sidebar .ty-nav-logout .nav-link:hover { background: #eef2f7; color: var(--ty-color-danger); }
.ty-sidebar .nav-link { color: #343a40; border-radius: 0; padding: .6rem 1.1rem; }
.ty-sidebar .nav-link:hover { background: #eef2f7; color: var(--ty-accent); }
/* #133 主目錄根入口(側欄頂固定項;active = 身處主目錄頁)。
   必須自訂:Bootstrap 之 .nav-link.active 同 .ty-sidebar .nav-link 同 specificity,本檔排後會壓過佢 → 無此規則則 active 完全無視覺效果。*/
.ty-sidebar .ty-nav-home .nav-link { font-weight: 600; border-bottom: 1px solid #e5e9f0; }
.ty-sidebar .ty-nav-home .nav-link.active { background: #eef2f7; color: var(--ty-accent); }
/* 群組標頭:風格 B「深色實心帶」(藍漸層 + 白粗字 + icon + 陰影;2026-06-15 樹幹分支重組)*/
.ty-sidebar .nav-group-header { display: flex; align-items: center; gap: .5rem; cursor: pointer; user-select: none; font-weight: 700; font-size: .9rem; letter-spacing: 0; text-transform: none; color: #fff; background: linear-gradient(90deg, #0d6efd, #5b9bff); border-radius: 7px; margin: .4rem .55rem; padding: .6rem .8rem; box-shadow: 0 1px 3px rgba(13,110,253,.3); }
.ty-sidebar .nav-group-header:hover { filter: brightness(.97); }
.ty-sidebar .nav-group-header .bi { font-size: 1rem; }
.ty-sidebar .nav-group-caret { display: inline-block; width: 0; height: 0; border-left: 5px solid currentColor; border-top: 4px solid transparent; border-bottom: 4px solid transparent; transition: transform .15s ease; }
.ty-sidebar .nav-group-header .nav-group-caret { border-left-color: #fff; }
.ty-sidebar [aria-expanded="true"] > .nav-group-caret { transform: rotate(90deg); }
.ty-sidebar .nav-group-hidden { display: none !important; } /* 2026-07-11 fix:!important 壓過下面 .nav-subgroup-header 之 display:flex(同 specificity 但排後),否則二級標頭收唔埋 */
.ty-sidebar .nav-link-indent { padding-left: 1.9rem; }
.ty-sidebar .nav-link-indent-2 { padding-left: 3.1rem; }
/* 葉功能入口專屬 icon(2026-07-16):inline .nav-link 內前置字圖,微調間距與垂直對齊 */
.ty-sidebar .nav-link-icon { margin-right: .45rem; vertical-align: -.125em; opacity: .85; }

/* 樹幹分支導引線(│ ├─,組內末項 └):靠子項 .nav-link 之偽元素繪製 */
.ty-sidebar .nav-item[data-nav-group]:not(.nav-group-header):not(.nav-subgroup-header) > .nav-link { position: relative; }
.ty-sidebar .nav-item[data-nav-group]:not(.nav-group-header):not(.nav-subgroup-header) > .nav-link::before { content: ""; position: absolute; left: 1.15rem; top: 0; bottom: 0; border-left: 1px solid rgba(0,0,0,.20); }
.ty-sidebar .nav-item[data-nav-group]:not(.nav-group-header):not(.nav-subgroup-header) > .nav-link::after { content: ""; position: absolute; left: 1.15rem; top: 50%; width: .55rem; border-top: 1px solid rgba(0,0,0,.20); }
.ty-sidebar .nav-item[data-nav-group]:not(.nav-group-header):not(.nav-subgroup-header).is-last > .nav-link::before { bottom: 50%; }
/* 兩層葉(系統設定 → 子分類 → 葉):導引線右移,對齊二級標頭 */
.ty-sidebar .nav-item[data-nav-subgroup]:not(.nav-subgroup-header) > .nav-link::before,
.ty-sidebar .nav-item[data-nav-subgroup]:not(.nav-subgroup-header) > .nav-link::after { left: 2.35rem; }
/* 二級群組標頭(淺底藍字,細一號,縮排以示層級)*/
.ty-sidebar .nav-subgroup-header { display: flex; align-items: center; gap: .45rem; cursor: pointer; user-select: none; font-weight: 600; font-size: .85rem; color: #0d6efd; background: rgba(13,110,253,.08); border-radius: 6px; margin: .25rem .55rem .25rem 1.2rem; padding: .4rem .65rem; }
.ty-sidebar .nav-subgroup-header:hover { background: rgba(13,110,253,.14); }
.ty-sidebar .nav-subgroup-header .bi { font-size: .95rem; }

/* 內容區:讓出左側欄闊度;收合時填滿 */
.ty-content { margin-left: var(--ty-sb-w); padding-left: 1rem; padding-right: 1rem; transition: margin-left .2s ease; }
.ty-main { padding-top: 1rem; padding-bottom: 3rem; }

/* 桌面收合:側欄滑出、內容填滿(狀態記於 localStorage)*/
html.ty-sidebar-collapsed .ty-sidebar { transform: translateX(-100%); }
html.ty-sidebar-collapsed .ty-content { margin-left: 0; }

/* off-canvas 背景遮罩(預設由 [hidden] 收起;手機展開時顯示)*/
.ty-backdrop {
  position: fixed; inset: var(--ty-topbar-h) 0 0 0; z-index: 1034;
  background: rgba(0, 0, 0, .4);
}
.ty-backdrop[hidden] { display: none; }

/* 手機 (<768px):側欄改 off-canvas,預設收起,漢堡掣彈出 overlay */
@media (max-width: 767.98px) {
  .ty-content { margin-left: 0; }
  .ty-sidebar { transform: translateX(-100%); box-shadow: .25rem 0 1rem rgba(0,0,0,.15); }
  html.ty-sidebar-open .ty-sidebar { transform: translateX(0); }
}
/* ──────────────────────────────────────────────────────────────────── */

/* 2026-10-03 golive-preflight: R13 / D-12 / F-A5-09 — test-environment banner (config app.env_banner; markup only when set).
   Sticky at y=0 above the sticky top bar; while it is on, body.ty-has-env-banner shifts everything that is pinned to the
   top (top bar sticky top, fixed sidebar + backdrop top) down by --ty-env-banner-h, so nothing is covered at scroll 0 or
   after scrolling, desktop or off-canvas mobile. Without the class every rule below is inert (today's layout). Single line,
   text truncates. NOTE: product_form.css carries a copy of the base .ty-env-banner rule (that page does not load app.css). */
.ty-env-banner {
  position: sticky; top: 0; z-index: 1050; box-sizing: border-box;
  height: var(--ty-env-banner-h, 28px); line-height: 26px; padding: 0 .75rem;
  background: #ffc107; color: #212529; border-bottom: 2px solid #b02a37;
  font-size: .85rem; font-weight: 700; text-align: center; letter-spacing: .5px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
body.ty-has-env-banner { --ty-env-banner-h: 28px; }
body.ty-has-env-banner .ty-topbar { top: var(--ty-env-banner-h); }
body.ty-has-env-banner .ty-sidebar { top: calc(var(--ty-topbar-h) + var(--ty-env-banner-h)); }
body.ty-has-env-banner .ty-backdrop { top: calc(var(--ty-topbar-h) + var(--ty-env-banner-h)); }

.ty-toolbar { gap: .5rem; }
.table thead th { white-space: nowrap; }
.ty-pager { display: flex; gap: .25rem; flex-wrap: wrap; align-items: center; }
.ty-level-badge { font-variant-numeric: tabular-nums; }

/* ── 列表 hover 高對比反白(B1 §1.1,2026-07-16;預設主題防禦補)──────────────
   實測:Bootstrap 預設 hover(7.5% 黑)同 .table-striped(5% 黑)只差 2.5%,
   肉眼分唔出邊列 hover 緊 → 報價 / 存貨兩張列表統一深藍實底白字(同 classic 皮膚色)。
   classic 生效時由 themes/classic/*.css 覆蓋(同色),本規則只係走火通道之保底。*/
#quoteTable { --bs-table-hover-bg: #1b4965; --bs-table-hover-color: #fff; }
/* 逐欄色 / .text-muted 之 specificity 高過 --bs-table-hover-color,不覆蓋會喺深底變隱形 */
#quoteTable.table-hover tbody tr:hover td,
#quoteTable.table-hover tbody tr:hover td * { color: #fff !important; }
/* stock_ex 刻意唔用 --bs-table-hover-bg:BS 5.3 會將佢畫成 inset box-shadow(優先於
   --bs-table-bg-type),會實心蓋走「編號到達」高亮(stock_ex/list.php 之 .sx-jump-hit);
   改用直接 background,輸畀高亮嘅 !important → 兩者共存。故此處一律不加 !important。*/
#sxTable.table-hover tbody tr:hover > td { background: #1b4965; color: #fff; }
#sxTable.table-hover tbody tr:hover > td .text-muted,
#sxTable.table-hover tbody tr:hover > td.text-muted { color: #cfe2ff !important; }

/* Mobile-first:細螢幕將 table 轉做 card 堆疊(大螢幕維持 table)*/
@media (max-width: 767.98px) {
  table.ty-stack thead { display: none; }
  table.ty-stack tbody tr {
    display: block; margin-bottom: .75rem; background: #fff;
    border: 1px solid #dee2e6; border-radius: .5rem; overflow: hidden;
  }
  table.ty-stack tbody td {
    display: flex; justify-content: space-between; gap: 1rem;
    border: 0; border-bottom: 1px solid #f1f3f5; padding: .45rem .8rem;
  }
  table.ty-stack tbody td:last-child { border-bottom: 0; }
  table.ty-stack tbody td::before {
    content: attr(data-label); font-weight: 600; color: #6c757d;
  }
}

/* ===== 報表設計器(designer_report)===== */
.rpt-toolbar { gap: .4rem; }
.rpt-workspace { display: flex; gap: .5rem; align-items: flex-start; }
.rpt-side { flex: 0 0 200px; max-width: 210px; }
.rpt-side-right { flex: 0 0 235px; max-width: 245px; }
.rpt-canvas-wrap { flex: 1 1 auto; overflow: auto; background: #e9ecef; padding: 1rem; border-radius: .4rem; min-height: 62vh; }
.rpt-canvas { background: #fff; margin: 0 auto; box-shadow: 0 0 0 1px #adb5bd, 0 4px 12px rgba(0,0,0,.12); }
.rpt-design-band { position: relative; border-bottom: 1px dashed #c0c4c8; box-sizing: border-box; }
.rpt-band-label { position: absolute; left: 0; top: 0; font-size: 10px; color: #868e96; background: #f1f3f5; padding: 0 4px; border-bottom-right-radius: 4px; pointer-events: none; z-index: 1; }
.rpt-band-over { background: #e7f1ff; }
.rpt-band-resize { position: absolute; left: 0; right: 0; bottom: -3px; height: 6px; cursor: ns-resize; z-index: 1; }
.rpt-control { position: absolute; border: 1px solid #adb5bd; background: #fff; font-size: 12px; line-height: 1.3; padding: 1px 3px; overflow: hidden; cursor: move; user-select: none; box-sizing: border-box; white-space: nowrap; z-index: 2; }
.rpt-control.selected { outline: 2px solid #0d6efd; outline-offset: -1px; z-index: 3; }
.rpt-control-text { pointer-events: none; }
.rpt-ctl-resize { position: absolute; right: -2px; bottom: -2px; width: 9px; height: 9px; background: #0d6efd; cursor: nwse-resize; border-radius: 2px; }
.rpt-fieldlist { display: flex; flex-direction: column; gap: .25rem; max-height: 60vh; overflow: auto; }
.rpt-field-chip { border: 1px solid #ced4da; border-radius: .3rem; padding: .15rem .4rem; font-size: 12px; background: #f8f9fa; cursor: grab; }
.rpt-field-chip:hover { background: #e9ecef; }
.rpt-field-chip:active { cursor: grabbing; }
.rpt-props .form-label { margin-top: .1rem; }
.rpt-preview-host, .rpt-run-host { overflow: auto; padding: .5rem; }
@media (max-width: 991.98px) {
  .rpt-workspace { flex-wrap: wrap; }
  .rpt-side, .rpt-side-right { flex: 1 1 100%; max-width: none; }
}

/* ===== 已渲染報表(report_render_html 產生;預覽 + 列印 + report_run 共用)===== */
.rpt-doc { margin: 0 auto; background: #fff; color: #000; font-size: 12px; font-family: "Microsoft JhengHei", "PingFang TC", "PMingLiU", sans-serif; }
.rpt-doc .rpt-band { position: relative; }
.rpt-doc .rpt-band.rpt-reportHeader, .rpt-doc .rpt-band.rpt-groupHeader { border-bottom: 1px solid #ced4da; }
.rpt-doc .rpt-band.rpt-groupFooter, .rpt-doc .rpt-band.rpt-reportFooter { border-top: 1px solid #ced4da; }
.rpt-doc .rpt-ctl { position: absolute; overflow: hidden; line-height: 1.3; }

/* ===== 表單設計器(designer_layout)===== */
.fd-workspace { display: flex; gap: .5rem; align-items: flex-start; }
.fd-side { flex: 0 0 190px; max-width: 200px; }
.fd-side-right { flex: 0 0 250px; max-width: 260px; }
.fd-canvas-wrap { flex: 1 1 auto; background: #e9ecef; padding: .75rem; border-radius: .4rem; min-height: 60vh; overflow: auto; }
.fd-canvas { background: #fff; border: 1px solid #ced4da; border-radius: .3rem; min-height: 55vh; padding: .5rem; }
.fd-row { display: flex; align-items: center; gap: .5rem; padding: .35rem .5rem; border: 1px solid #dee2e6; border-radius: .3rem; background: #f8f9fa; margin-bottom: .35rem; cursor: pointer; }
.fd-row.selected { border-color: #0d6efd; box-shadow: 0 0 0 2px rgba(13,110,253,.25); background: #fff; }
.fd-row.fd-dragover { border-top: 2px solid #0d6efd; }
.fd-handle { cursor: grab; color: #adb5bd; user-select: none; font-weight: bold; }
.fd-row-label { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fd-field-chip { padding: .25rem .5rem; margin-bottom: .25rem; border: 1px solid #cfe2ff; border-radius: .3rem; background: #eef5ff; cursor: grab; font-size: .85rem; }
.fd-field-chip .fd-sg { color: #6c757d; font-size: .72rem; }
@media (max-width: 991px) { .fd-workspace { flex-wrap: wrap; } .fd-side, .fd-side-right { flex: 1 1 100%; max-width: none; } }
/* 屬性面板分組(摺疊 details/summary)*/
.fd-prop-group { border-top: 1px solid #e0e0e0; padding-top: .35rem; margin-top: .5rem; }
.fd-prop-group > summary { cursor: pointer; color: #495057; }
/* RWD 裝置預覽:設計畫布即時縮放(視覺回饋)*/
.fd-canvas-wrap.dev-tablet .fd-canvas { max-width: 768px; margin: 0 auto; }
.fd-canvas-wrap.dev-mobile .fd-canvas { max-width: 375px; margin: 0 auto; }
/* RWD 裝置預覽:預覽 iframe(其 viewport 真實反映 Bootstrap 響應式堆疊)*/
.fd-pv-stage { background: #e9ecef; padding: .5rem; border-radius: .3rem; text-align: center; }
.fd-pv-frame { width: 100%; height: 70vh; border: 0; background: #fff; display: inline-block; vertical-align: top; }
.fd-pv-frame.dev-tablet { width: 768px; max-width: 100%; border: 1px solid #ced4da; }
.fd-pv-frame.dev-mobile { width: 375px; max-width: 100%; border: 1px solid #ced4da; }

/* ===== 原始資料 Access 式資料表(raw_grid)===== */
/* 標題:欄名 + ▾ 排序/篩選掣 */
.ty-raw-grid thead th.ty-th { padding: .25rem .4rem; }
.ty-th-wrap { display: flex; align-items: center; gap: .25rem; justify-content: space-between; }
.ty-th-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ty-th-btn { border: 0; background: transparent; color: #6c757d; cursor: pointer; padding: 0 .2rem; line-height: 1; font-size: .9rem; border-radius: .2rem; }
.ty-th-btn:hover { background: #dee2e6; color: #0d6efd; }
.ty-th-filtered { background: #fff3cd !important; }      /* 已套篩選(似 Access 漏斗高亮)*/
.ty-th-sorted .ty-th-label { color: #0d6efd; font-weight: 600; }

/* 標題下拉面板(append 落 body,避免 table-responsive overflow 剪裁)*/
.ty-raw-menu {
  position: absolute; z-index: 2000; background: #fff; border: 1px solid #ced4da;
  border-radius: .4rem; box-shadow: 0 .4rem 1rem rgba(0,0,0,.18); padding: .5rem;
  max-height: 70vh; overflow-y: auto;
}
.ty-raw-menu-section { border-top: 1px solid #eee; padding-top: .4rem; margin-top: .4rem; }
.ty-raw-menu-section:first-child { border-top: 0; padding-top: 0; margin-top: 0; }
.ty-raw-menu-title { font-size: .72rem; color: #6c757d; text-transform: uppercase; margin-bottom: .25rem; }
.ty-menu-clear { color: #b02a37; }
.ty-menu-list { max-height: 11rem; overflow-y: auto; border: 1px solid #eee; border-radius: .3rem; padding: .2rem; }
.ty-menu-check { display: flex; align-items: center; gap: .4rem; padding: .1rem .2rem; font-size: .85rem; cursor: pointer; white-space: nowrap; }
.ty-menu-check:hover { background: #eef2f7; }
.ty-menu-check span { overflow: hidden; text-overflow: ellipsis; }

/* 內文格:可編輯 / 只讀 / 編輯中 / 存中 / 已存 / 錯誤 */
.ty-cell-edit { cursor: cell; }
.ty-cell-edit:hover { outline: 1px dashed #adb5bd; outline-offset: -1px; }
.ty-cell-readonly { color: #6c757d; background: #f8f9fa; }
.ty-cell-editing { padding: 0 !important; }
.ty-cell-input { min-width: 6rem; }
.ty-cell-saving { opacity: .6; }
.ty-cell-saved { animation: tyCellSaved .9s ease; }
.ty-cell-error { animation: tyCellError .9s ease; }
@keyframes tyCellSaved { 0% { background: #d1e7dd; } 100% { background: transparent; } }
@keyframes tyCellError { 0%,60% { background: #f8d7da; } 100% { background: transparent; } }
.ty-del-btn { border: 0; background: transparent; cursor: pointer; padding: 0 .2rem; line-height: 1; opacity: .55; }
.ty-del-btn:hover { opacity: 1; }

/* 新增列 Modal(自製,免依賴 Bootstrap JS 實例)*/
.ty-modal-backdrop { position: fixed; inset: 0; z-index: 2050; background: rgba(0,0,0,.45); display: flex; align-items: flex-start; justify-content: center; padding: 4vh 1rem; overflow-y: auto; }
.ty-modal { background: #fff; border-radius: .5rem; padding: 1rem; width: 100%; max-width: 32rem; box-shadow: 0 1rem 2rem rgba(0,0,0,.3); }
.ty-modal-body { max-height: 60vh; overflow-y: auto; }

/* ===== 視覺化拖拉查詢設計器(designer_visual / Access 風格 QBE)===== */
.vq-workspace { display: flex; gap: .5rem; align-items: stretch; }
.vq-side { flex: 0 0 180px; max-width: 190px; }
.vq-side-right { flex: 0 0 250px; max-width: 270px; }
.vq-table-list { max-height: 50vh; overflow: auto; display: flex; flex-direction: column; gap: .2rem; }
.vq-table-item { border: 1px solid #ced4da; border-radius: .3rem; padding: .2rem .45rem; font-size: .82rem; background: #f8f9fa; cursor: grab; user-select: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.vq-table-item:hover { background: #e9ecef; }
.vq-table-item.vq-on-canvas { opacity: .5; cursor: default; }
.vq-sql { font-family: monospace; font-size: .78rem; }

/* 畫布 */
.vq-canvas-wrap { flex: 1 1 auto; min-width: 0; background: #e9ecef; padding: .5rem; border-radius: .4rem; }
.vq-canvas { position: relative; background: #fff; border: 1px solid #ced4da; border-radius: .3rem; min-height: 46vh; height: 46vh; overflow: auto; }
.vq-canvas-hint { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; text-align: center; color: #adb5bd; font-size: .85rem; padding: 1rem; pointer-events: none; }
.vq-join-svg { position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; overflow: visible; z-index: 1; }
.vq-join-line { stroke: #0d6efd; stroke-width: 2; fill: none; pointer-events: stroke; cursor: pointer; }
.vq-join-line:hover { stroke: #0a58ca; stroke-width: 3; }
.vq-join-cap { fill: #0d6efd; }

/* 資料表方框 */
.vq-box { position: absolute; z-index: 2; width: 160px; background: #fff; border: 1px solid #0d6efd; border-radius: .35rem; box-shadow: 0 2px 6px rgba(0,0,0,.15); font-size: .78rem; }
.vq-box-head { display: flex; align-items: center; justify-content: space-between; gap: .25rem; padding: .2rem .45rem; background: #0d6efd; color: #fff; border-radius: .3rem .3rem 0 0; cursor: move; user-select: none; font-weight: 600; }
.vq-box-close { border: 0; background: transparent; color: #fff; cursor: pointer; line-height: 1; padding: 0 .15rem; }
.vq-box-cols { list-style: none; margin: 0; padding: .15rem; max-height: 180px; overflow: auto; }
.vq-box-col { padding: .1rem .35rem; border-radius: .2rem; cursor: grab; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.vq-box-col:hover { background: #eef5ff; }
.vq-box-col.vq-drop-target { background: #cfe2ff; outline: 1px dashed #0d6efd; }
.vq-box-col .vq-key { color: #d39e00; }

/* JOIN 類型小選單(自製 popover)*/
.vq-join-menu { position: absolute; z-index: 2100; background: #fff; border: 1px solid #ced4da; border-radius: .4rem; box-shadow: 0 .4rem 1rem rgba(0,0,0,.2); padding: .3rem; font-size: .8rem; }
.vq-join-menu button { display: block; width: 100%; text-align: left; border: 0; background: transparent; padding: .2rem .5rem; border-radius: .25rem; cursor: pointer; white-space: nowrap; }
.vq-join-menu button:hover:not(:disabled) { background: #eef2f7; }
.vq-join-menu button:disabled { color: #adb5bd; cursor: not-allowed; }
.vq-join-menu button.active { font-weight: 700; color: #0d6efd; }
.vq-join-menu .vq-jm-del { color: #b02a37; border-top: 1px solid #eee; margin-top: .2rem; padding-top: .3rem; }

/* QBE 網格(欄 = 欄位;列 = 屬性)*/
.vq-qbe-wrap { overflow-x: auto; }
.vq-qbe-table { border-collapse: collapse; font-size: .8rem; min-width: 100%; }
.vq-qbe-table th, .vq-qbe-table td { border: 1px solid #dee2e6; padding: .15rem .3rem; vertical-align: middle; }
.vq-rowhdr { background: #f1f3f5; color: #495057; font-weight: 600; white-space: nowrap; position: sticky; left: 0; z-index: 1; min-width: 3.2rem; }
.vq-qbe-table td { min-width: 9rem; }
.vq-col-field { display: flex; align-items: center; justify-content: space-between; gap: .3rem; font-weight: 600; white-space: nowrap; }
.vq-col-del { border: 0; background: transparent; color: #b02a37; cursor: pointer; line-height: 1; padding: 0 .15rem; }
.vq-qbe-table select, .vq-qbe-table input[type="text"] { width: 100%; border: 1px solid #ced4da; border-radius: .2rem; padding: .05rem .25rem; font-size: .78rem; }
.vq-qbe-table input[type="checkbox"] { display: block; margin: 0 auto; }
.vq-qbe-drop-on { outline: 2px dashed #0d6efd; outline-offset: -2px; }

@media (max-width: 991.98px) {
  .vq-workspace { flex-wrap: wrap; }
  .vq-side, .vq-side-right { flex: 1 1 100%; max-width: none; }
  .vq-canvas-wrap { flex: 1 1 100%; }
}

/* === 權限管理 授權編輯器(admin_permissions) === */
.ty-perm-tree { max-width: 980px; }
.perm-iface { border: 1px solid #dee2e6; border-radius: .5rem; margin-bottom: .5rem; background: #fff; overflow: hidden; }
.perm-iface-head { display: flex; align-items: center; gap: .75rem; padding: .5rem .75rem; cursor: pointer; background: #f8f9fa; }
.perm-iface-head .perm-nm { font-weight: 600; }
.perm-iface-head .perm-id { font-family: ui-monospace, monospace; font-size: .75rem; color: #6c757d; }
.perm-children { padding: .5rem .75rem .75rem; border-top: 1px solid #eee; }
.perm-sec { font-size: .7rem; text-transform: uppercase; letter-spacing: .04em; color: #6c757d; margin: .6rem 0 .25rem; }
.perm-row { display: flex; align-items: center; gap: .6rem; padding: .3rem 0; border-bottom: 1px dashed #eee; flex-wrap: wrap; }
.perm-row:last-child { border-bottom: 0; }
.perm-row .perm-nm { flex: 1; min-width: 8rem; }
.perm-row .perm-nm small { color: #6c757d; font-family: ui-monospace, monospace; font-size: .72rem; }
.perm-lv { display: inline-flex; border: 1px solid #ced4da; border-radius: .35rem; overflow: hidden; }
.perm-lv-cell { width: 26px; padding: 2px 0; font-size: .75rem; border: 0; border-right: 1px solid #ced4da; background: #fff; color: #adb5bd; cursor: pointer; }
.perm-lv-cell:last-child { border-right: 0; }
.perm-lv-cell.on { background: #d1e7dd; color: #0f5132; }
.perm-lv-cell.pick { box-shadow: 0 0 0 2px #198754 inset; font-weight: 700; }
/* 2026-08-19 新增(#M28-B):撳唔到嘅格要睇得出 —— 「讀」段控超過門檻嗰幾格、
   以及保底介面鎖死嘅段控,之前同可撳格外觀一模一樣,用戶只會覺得撳極冇反應。 */
.perm-lv-cell:disabled { opacity: .38; cursor: not-allowed; }
.perm-cap { font-size: .72rem; color: #198754; min-width: 2.5rem; }
.perm-op { font-size: .68rem; color: #6c757d; }
.perm-row.dirty { background: #fff8e1; }
/* 欄位摺疊組(#C5):有 field_group 之介面(如 product_form)按區塊收埋;無組者維持平鋪 */
.ty-perm-group { border: 1px solid #e9ecef; border-radius: .4rem; margin: .35rem 0; background: #fdfdfe; }
.ty-perm-group > summary { display: flex; align-items: center; gap: .6rem; padding: .35rem .6rem;
  cursor: pointer; font-size: .82rem; font-weight: 600; list-style: none; }
.ty-perm-group > summary::-webkit-details-marker { display: none; }
.ty-perm-group > summary::before { content: '▸'; font-size: .7rem; color: #6c757d; }
.ty-perm-group[open] > summary::before { content: '▾'; }
.ty-perm-group[open] > summary { border-bottom: 1px solid #eee; }
.ty-perm-group-cnt { font-size: .72rem; font-weight: 400; color: #6c757d; }
.ty-perm-group > div { padding: 0 .6rem .4rem; }
.ty-perm-group-bulk { display: flex; align-items: flex-end; gap: .6rem; flex-wrap: wrap;
  padding: .5rem .6rem !important; background: #f8f9fa; border-bottom: 1px dashed #dee2e6; }
.ty-perm-bulk-item { display: flex; flex-direction: column; gap: .1rem; font-size: .7rem; color: #6c757d; }
.ty-perm-bulk-item select { width: 5.5rem; }
.ty-perm-savebar { position: sticky; bottom: 0; display: flex; align-items: center; gap: .75rem;
  padding: .5rem .9rem; margin-top: 1rem; background: #fff; border-top: 2px solid #198754; box-shadow: 0 -2px 6px rgba(0,0,0,.06); }
