/* designer-v2.css — Designer v2 modules (SPEC-DESIGNER-V2). One clearly commented section per
   module; append your own section, never rewrite another module's. Linked after designer.css. */

/* ================================================================== */
/* Check panel (checkPanel.js, SPEC-DESIGNER-V2 §4.1)                  */
/* ================================================================== */

:root { --check-h: 220px; }

/* Toolbar button + badge */
.tb-btn .check-badge {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 16px; height: 16px; padding: 0 4px; margin-left: 2px;
  border-radius: 8px; font-size: 10.5px; font-weight: 600; line-height: 1;
  background: var(--warning); color: #fff; font-variant-numeric: tabular-nums;
}
.tb-btn .check-badge.check-badge-error { background: var(--danger); }
.tb-btn .check-badge.check-badge-warning { background: var(--warning); }
.tb-btn .check-ico-btn svg { width: 16px; height: 16px; }

/* Bottom drawer: a flex-column child of .app between the workspace and the status bar */
.check-drawer {
  flex: none; height: var(--check-h); min-height: 96px; max-height: calc(100vh - 200px);
  display: flex; flex-direction: column; position: relative;
  background: var(--panel); border-top: 1px solid var(--border);
}
.check-drawer .check-grip { position: absolute; left: 0; right: 0; top: -3px; height: 6px; cursor: row-resize; z-index: 3; }
.check-drawer .check-grip:hover, .check-drawer .check-grip.active { background: var(--accent-soft); }
.check-drawer .check-head {
  display: flex; align-items: center; gap: 10px; padding: 4px 10px; flex: none;
  border-bottom: 1px solid var(--border); min-height: 32px;
}
.check-drawer .check-head h3 { margin: 0; font-size: 13px; white-space: nowrap; }
.check-drawer .check-summary { font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.check-drawer .check-status { font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex: 1; min-width: 0; color: var(--muted); }
.check-drawer .check-status.loading { color: var(--accent-2); }
.check-drawer .check-status.error { color: var(--danger); }
.check-drawer .check-actions { margin-left: auto; flex: none; }
.check-drawer .check-body { flex: 1; min-height: 0; overflow: auto; }
.check-drawer .check-empty { margin: 0; padding: 12px; color: var(--muted); font-size: 12.5px; }
.check-drawer .check-empty-ok { color: var(--success); }
.check-drawer .check-list { list-style: none; margin: 0; padding: 0; }
.check-drawer .check-issue {
  display: flex; align-items: center; gap: 8px; padding: 4px 10px;
  border-bottom: 1px solid var(--border); border-left: 3px solid transparent;
  font-size: 12.5px; cursor: default;
}
.check-drawer .check-issue.has-el { cursor: pointer; }
.check-drawer .check-issue:hover, .check-drawer .check-issue:focus-visible { background: var(--panel-2); outline: none; }
.check-drawer .check-issue.check-error { border-left-color: var(--danger); }
.check-drawer .check-issue.check-error .check-ico { color: var(--danger); }
.check-drawer .check-issue.check-warning { border-left-color: var(--warning); }
.check-drawer .check-issue.check-warning .check-ico { color: var(--warning); }
.check-drawer .check-issue.check-render { border-left-color: var(--accent); }
.check-drawer .check-issue.check-render .check-ico { color: var(--accent); }
.check-drawer .check-issue.check-hint { border-left-color: var(--border-strong); }
.check-drawer .check-issue.check-hint .check-ico { color: var(--muted); }
.check-drawer .check-ico { flex: none; display: inline-flex; width: 16px; height: 16px; align-items: center; justify-content: center; }
.check-drawer .check-msg { flex: 1; min-width: 0; line-height: 1.35; word-break: break-word; }
.check-drawer .check-el { flex: none; max-width: 30%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text-2); font-size: 11.5px; }
.check-drawer .check-fix { flex: none; }
@media (max-width: 900px) {
  .check-drawer .check-el { display: none; }
}

/* ================================================================== */
/* Format bar (formatBar.js, SPEC-DESIGNER-V2 §1)                      */
/* ================================================================== */

/* Row 2 of the toolbar: a static DOM whose controls are hidden per selection (never disabled). */
/* Structure only (colours / border come from the shell's .fmtbar rule in designer.css). ONE row
   of fixed height: the table borders / cell padding live in the popover (`.fb-pop-table`), so a
   table selection never shifts the rulers and the page down. */
.fmtbar {
  flex: none; display: flex; flex-direction: column; align-items: stretch; gap: 0; padding: 0;
  height: calc(var(--fmtbar-h, 36px) + 1px); min-height: calc(var(--fmtbar-h, 36px) + 1px); /* one row + the shell's bottom border */
  overflow-x: auto; overflow-y: hidden; scrollbar-width: thin;
  white-space: nowrap; font-size: 12.5px;
}
.fmtbar.fb-disabled { opacity: 0.55; pointer-events: none; }
.fb-row { display: flex; align-items: center; gap: 2px; height: var(--fmtbar-h, 36px); padding: 0 10px; min-width: max-content; }
.fb-group { display: inline-flex; align-items: center; gap: 2px; }
.fb-sep { width: 1px; height: 20px; background: var(--border); margin: 0 6px; flex: none; }
.fb-target {
  display: inline-flex; align-items: center; min-width: 96px; max-width: 200px; margin-right: 4px;
  font-weight: 600; color: var(--text-2); overflow: hidden; text-overflow: ellipsis;
}
.fb-label { font-size: 11px; color: var(--muted); margin: 0 4px 0 2px; }

/* buttons */
.fb-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 4px;
  min-width: 28px; height: 28px; padding: 0 6px;
  background: transparent; border: 1px solid transparent; border-radius: 4px; color: var(--text-2);
  font-weight: 600; line-height: 1;
}
.fb-btn:hover:not(:disabled) { background: var(--panel-2); border-color: var(--border); color: var(--text); }
.fb-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: -1px; }
.fb-btn.active, .fb-btn[aria-pressed="true"] { background: var(--accent-soft); color: var(--accent-2); }
.fb-btn.mixed, .fb-btn[aria-pressed="mixed"] { background: repeating-linear-gradient(135deg, var(--accent-soft) 0 3px, transparent 3px 6px); color: var(--text-2); }
.fb-btn svg { width: 16px; height: 16px; }
.fb-btn b { font-weight: 800; }
.fb-btn i { font-family: Georgia, "Times New Roman", serif; font-style: italic; font-weight: 600; }
.fb-btn u { text-decoration: underline; text-underline-offset: 2px; }
.fb-btn.fb-mini { min-width: 18px; width: 18px; height: 22px; padding: 0; margin-left: -2px; color: var(--muted); }
.fb-btn.fb-mini svg { width: 11px; height: 11px; }
.fb-seg { display: inline-flex; align-items: center; gap: 0; border: 1px solid var(--border); border-radius: 4px; padding: 1px; }
.fb-seg .fb-btn { height: 24px; min-width: 26px; border-radius: 3px; }
.fb-parts .fb-btn { font-weight: 500; padding: 0 8px; }
.fb-size .fb-btn { min-width: 24px; width: 24px; padding: 0; font-size: 15px; }

/* inputs */
.fb-select, .fb-num {
  height: 28px; padding: 0 6px; border: 1px solid var(--border); border-radius: 4px;
  background: var(--panel); color: var(--text); min-width: 0;
}
.fb-select:focus, .fb-num:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-soft); }
.fb-select.warn { border-color: var(--warning); }
.fb-font { width: 136px; }
/* wide enough for "(mặc định)" next to the native dropdown arrow */
.fb-lh { width: 104px; }
.fb-num { width: 56px; text-align: center; font-variant-numeric: tabular-nums; -moz-appearance: textfield; appearance: textfield; }
.fb-num::-webkit-outer-spin-button, .fb-num::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.fb-size .fb-num { width: 50px; border-radius: 0; margin: 0 -1px; }
.fb-num.inherited { color: var(--text-2); }
.fb-num.mixed::placeholder { color: var(--text-2); font-weight: 600; }
.fb-unit .fb-num { width: 52px; }
.fb-unit .fb-label { margin-right: 2px; }

/* colour: a glyph + swatch bar with the native picker stretched invisibly over it */
.fb-color {
  position: relative; display: inline-flex; flex-direction: column; align-items: center; justify-content: center;
  width: 30px; height: 28px; border: 1px solid transparent; border-radius: 4px; color: var(--text-2); cursor: pointer;
}
.fb-color:hover { background: var(--panel-2); border-color: var(--border); }
.fb-color-glyph { display: inline-flex; align-items: center; justify-content: center; height: 16px; font-weight: 700; font-size: 13px; line-height: 1; }
.fb-color-glyph svg { width: 15px; height: 15px; }
.fb-swatch { display: block; width: 18px; height: 4px; margin-top: 2px; border-radius: 1px; background: #000; box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.12); }
.fb-color.empty .fb-swatch { background: repeating-linear-gradient(135deg, #d1d5db 0 2px, transparent 2px 4px); }
.fb-color.mixed .fb-swatch { background: repeating-linear-gradient(135deg, var(--accent) 0 3px, #d1d5db 3px 6px); }
.fb-color.inherited .fb-swatch { opacity: 0.55; }
.fb-color input[type="color"] { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; border: 0; padding: 0; }
.fb-color input[type="color"]:focus-visible + * { outline: 2px solid var(--accent); }

/* border popover (fixed under its button, like the toolbar menus) */
.fb-popover {
  position: fixed; top: 0; left: 0; z-index: 510; min-width: 220px; padding: 8px 10px;
  background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow);
  display: flex; flex-direction: column; gap: 6px; font-size: 12.5px;
}
.fb-pop-section { display: flex; flex-direction: column; gap: 6px; }
.fb-pop-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.fb-pop-row .fb-label { min-width: 84px; margin: 0; }
.fb-pop-row .fb-seg .fb-btn { font-weight: 500; padding: 0 7px; font-size: 12px; }
.fb-pop-row .fb-num { width: 64px; }
.fb-pop-row .fb-color { border-color: var(--border); }

/* narrow windows: drop the text labels of unit fields */
@media (max-width: 1200px) {
  .fb-unit .fb-label { display: none; }
  .fb-font { width: 110px; }
  .fb-lh { width: 96px; }
}
/* print view (printView.js) keeps the bar: it edits the document, not the canvas chrome */

/* ================================================================== */
/* Groups (groups.js, SPEC-DESIGNER-V2 §3.1)                           */
/* ================================================================== */

/* Dashed, colour-coded outline around every group with a selected member (overlay, unscaled). */
.grp-outline {
  position: absolute; pointer-events: none; box-sizing: content-box;
  margin: -3px 0 0 -3px; padding: 3px;
  border: 1px dashed var(--grp-color, var(--accent)); border-radius: 3px;
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.6);
}
.ov-groups { position: absolute; inset: 0; pointer-events: none; }
.grp-hover-box {
  position: absolute; pointer-events: none; box-sizing: content-box;
  margin: -3px 0 0 -3px; padding: 3px;
  border: 2px solid var(--grp-color, var(--accent)); border-radius: 3px;
  background: color-mix(in srgb, var(--grp-color, var(--accent)) 10%, transparent);
}
/* Layers list: badge + hover highlight of the whole group */
.layer-group {
  flex: none; width: 9px; height: 9px; border-radius: 2px;
  background: var(--grp-color, var(--accent)); box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.15);
}
.layer.grp-hover { background: color-mix(in srgb, var(--grp-color, var(--accent)) 14%, var(--panel)); }
.layer.grp-hover.selected { background: color-mix(in srgb, var(--grp-color, var(--accent)) 22%, var(--accent-soft)); }
.layer.grp-hover::before { content: ""; position: absolute; left: 0; top: 2px; bottom: 2px; width: 2px; border-radius: 1px; background: var(--grp-color, var(--accent)); }
/* toolbar (fallback buttons created by groups.js, and the shell's data-action buttons) */
.tb-btn .grp-label { margin-left: 4px; }
body.print-view .grp-outline { display: none; }

/* ================================================================== */
/* Format painter (formatPainter.js, SPEC-DESIGNER-V2 §3.3)            */
/* ================================================================== */

/* paintbrush cursor while a format is armed; sticky mode adds a small "+" (second brush) */
body.fp-active #canvas-area .viewport,
body.fp-active #canvas-area .viewport .el,
body.fp-active #canvas-area .viewport .el * {
  cursor: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='22' height='22' viewBox='0 0 22 22'><path d='M4 3h11v4.5a1.5 1.5 0 0 1-1.5 1.5H5.5A1.5 1.5 0 0 1 4 7.5z' fill='%23ffffff' stroke='%23111827' stroke-width='1.5' stroke-linejoin='round'/><path d='M15 5h2.5a1.5 1.5 0 0 1 1.5 1.5v4a1.5 1.5 0 0 1-1.5 1.5H11v2' fill='none' stroke='%23111827' stroke-width='1.5' stroke-linejoin='round'/><rect x='9' y='14' width='4' height='6' rx='1' fill='%232563eb' stroke='%23111827' stroke-width='1.5'/></svg>") 4 3, copy !important;
}
body.fp-sticky #canvas-area .viewport,
body.fp-sticky #canvas-area .viewport .el,
body.fp-sticky #canvas-area .viewport .el * {
  cursor: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='24' height='22' viewBox='0 0 24 22'><path d='M4 3h11v4.5a1.5 1.5 0 0 1-1.5 1.5H5.5A1.5 1.5 0 0 1 4 7.5z' fill='%23ffffff' stroke='%23111827' stroke-width='1.5' stroke-linejoin='round'/><path d='M15 5h2.5a1.5 1.5 0 0 1 1.5 1.5v4a1.5 1.5 0 0 1-1.5 1.5H11v2' fill='none' stroke='%23111827' stroke-width='1.5' stroke-linejoin='round'/><rect x='9' y='14' width='4' height='6' rx='1' fill='%232563eb' stroke='%23111827' stroke-width='1.5'/><path d='M17 15h5M19.5 12.5v5' stroke='%23111827' stroke-width='1.8' stroke-linecap='round'/></svg>") 4 3, copy !important;
}
body.fp-active #canvas-area .viewport .el:hover { outline: 2px solid var(--accent); outline-offset: 1px; }
.tb-btn[data-action="formatPainter:start"].active { background: var(--accent-soft); color: var(--accent-2); }
.tb-btn[data-action="formatPainter:start"].fp-sticky { box-shadow: inset 0 0 0 2px var(--accent); }
.tb-btn .fp-label { margin-left: 4px; }
/* transient painter state lives in the status bar, not in a stack of toasts */
#status-msg.fp-status { color: var(--accent-2); font-weight: 600; opacity: 1; }

/* ================================================================== */
/* Find bar (findBar.js, SPEC-DESIGNER-V2 §3.4)                        */
/* ================================================================== */

.find-bar {
  display: flex; align-items: center; gap: 4px; flex: none;
  padding: 6px 8px 6px 10px; border-bottom: 1px solid var(--border); background: var(--panel-2);
}
.find-ico { display: inline-flex; color: var(--muted); flex: none; }
.find-ico svg { width: 14px; height: 14px; }
.find-input {
  flex: 1; min-width: 0; height: 26px; padding: 0 6px;
  border: 1px solid var(--border); border-radius: 4px; background: var(--panel); color: var(--text); font-size: 12.5px;
}
.find-input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-soft); }
.find-input::-webkit-search-cancel-button { -webkit-appearance: none; }
.find-count { flex: none; font-size: 11px; color: var(--muted); font-variant-numeric: tabular-nums; min-width: 28px; text-align: right; }
.find-count.find-none { color: var(--danger); }
.find-bar .icon-btn { flex: none; width: 22px; height: 22px; }
/* the layers list while a query is active: misses collapse, hits keep a marker, the current hit is outlined */
#layers.find-filtered .layer.find-miss { display: none; }
#layers.find-filtered .layer.find-hit .layer-name { font-weight: 600; }
#layers.find-filtered .layer.find-current { outline: 1px solid var(--accent); outline-offset: -1px; }
.tb-btn[data-action="find:open"][aria-pressed="true"] { background: var(--accent-soft); color: var(--accent-2); }
@media (max-width: 900px) {
  .side-left .find-bar { flex: none; }
}

/* ================================================================== */
/* Insert menu + popup engine (insertMenu.js, SPEC-DESIGNER-V2 §2.1)   */
/* ================================================================== */

.menu-insert { min-width: 220px; }
.menu .pm-item {
  display: flex; align-items: center; gap: 8px; width: 100%; min-width: 0;
  padding: 6px 10px; border: 0; background: transparent; border-radius: 4px; text-align: left; color: var(--text);
  white-space: nowrap;
}
.menu .pm-item:hover:not(:disabled), .pm-item.open, .pm-row.open > .pm-item { background: var(--panel-2); }
.pm-item:disabled { opacity: 0.45; cursor: not-allowed; }
.pm-item .ico { display: inline-flex; width: 16px; height: 16px; flex: none; color: var(--text-2); }
.pm-item .ico:empty { display: none; }
.pm-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.pm-meta { color: var(--muted); font-size: 11px; max-width: 140px; overflow: hidden; text-overflow: ellipsis; }
.pm-key { color: var(--muted); font-size: 11px; margin-left: 12px; font-variant-numeric: tabular-nums; }
.pm-arrow { color: var(--muted); margin-left: 6px; font-size: 11px; }
/* a row = the item button + an optional extra button ("Chèn bảng"); grid, because a flex <button>
   with a min-width:0 label collapses to its padding when it is itself a shrink-to-fit flex item */
.pm-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 4px; }
.pm-row > .pm-item { width: 100%; min-width: 0; }
.pm-row > .pm-item .pm-label { flex: 0 0 auto; min-width: auto; overflow: visible; }
.pm-row > .pm-item .pm-meta, .pm-row > .pm-item .pm-key, .pm-row > .pm-item .pm-arrow { margin-left: auto; }
.pm-row > .pm-item .pm-meta ~ .pm-key, .pm-row > .pm-item .pm-meta ~ .pm-arrow, .pm-row > .pm-item .pm-key ~ .pm-arrow { margin-left: 6px; }
.pm-row.danger > .pm-item { color: var(--danger); }
.pm-row.danger > .pm-item .ico { color: var(--danger); }
.pm-extra { flex: none; margin-right: 4px; gap: 4px; display: inline-flex; align-items: center; }
.pm-extra svg { width: 14px; height: 14px; }
.pm-search { padding: 4px 6px 6px; }
.pm-search input {
  width: 100%; height: 28px; padding: 0 8px; border: 1px solid var(--border); border-radius: 4px; background: var(--panel); min-width: 0;
}
.pm-search input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-soft); }
.pm-search .pm-empty { margin: 6px 4px 0; }
.rd-popup {
  position: fixed; z-index: 600; min-width: 220px; max-width: min(360px, calc(100vw - 16px)); max-height: calc(100vh - 24px); overflow-y: auto;
  padding: 4px; background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow);
}
.rd-popup hr { border: 0; border-top: 1px solid var(--border); margin: 4px 0; }
.rd-popup .menu-hint, .ctx-menu .menu-hint { white-space: normal; }
/* the shell's #canvas-menu container gets the same row layout when this module fills it */
#canvas-menu.ctx-menu { max-width: min(360px, calc(100vw - 16px)); }
.tb-insert .tb-btn .ico svg { width: 16px; height: 16px; }

/* ================================================================== */
/* Image dialog (imageDialog.js, SPEC-DESIGNER-V2 §2.2)                */
/* ================================================================== */

.dlg-image { width: 520px; }
.dlg-image.busy .dlg-body { opacity: 0.7; }
.dlg-image .dlg-body { display: flex; flex-direction: column; gap: 10px; }
.img-tabs { display: flex; gap: 2px; border-bottom: 1px solid var(--border); }
.img-tab {
  padding: 6px 12px; border: 0; border-bottom: 2px solid transparent; background: transparent; color: var(--text-2); font-weight: 600; margin-bottom: -1px;
}
.img-tab:hover { color: var(--text); }
.img-tab.active { color: var(--accent-2); border-bottom-color: var(--accent); }
.img-pane { display: flex; flex-direction: column; gap: 8px; }
.img-drop {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px;
  padding: 16px 12px; border: 2px dashed var(--border-strong); border-radius: var(--radius); background: var(--panel-2); color: var(--text-2); text-align: center;
  cursor: pointer;
}
.img-drop:focus-visible { outline: none; border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-soft); }
.img-drop.over { border-color: var(--accent); background: var(--accent-soft); }
.img-drop svg { width: 24px; height: 24px; color: var(--muted); }
.img-drop-hint { margin: 0; display: flex; align-items: center; gap: 6px; flex-wrap: wrap; justify-content: center; }
.img-accept { margin: 0; font-size: 11px; }
.img-file-info { margin: 0; font-size: 12px; min-height: 1em; }
.img-mode { display: flex; gap: 14px; flex-wrap: wrap; }
.img-mode .field.check { padding: 0; }
.img-warn { margin: 0; font-size: 12px; color: var(--warning); }
.img-pane .field-hint { margin: 0; font-size: 11.5px; line-height: 1.4; }
.img-preview {
  position: relative; display: flex; align-items: center; justify-content: center; height: 150px;
  border: 1px solid var(--border); border-radius: var(--radius);
  background-color: var(--panel-2);
  background-image: linear-gradient(45deg, var(--border) 25%, transparent 25%), linear-gradient(-45deg, var(--border) 25%, transparent 25%), linear-gradient(45deg, transparent 75%, var(--border) 75%), linear-gradient(-45deg, transparent 75%, var(--border) 75%);
  background-size: 16px 16px; background-position: 0 0, 0 8px, 8px -8px, -8px 0;
  overflow: hidden;
}
.img-preview img { max-width: 100%; max-height: 100%; object-fit: contain; }
.img-preview-empty { font-size: 12px; background: var(--panel); padding: 2px 8px; border-radius: 4px; }
.img-natural { position: absolute; right: 6px; bottom: 4px; font-size: 11px; background: var(--panel); padding: 1px 6px; border-radius: 4px; }
.img-options { display: grid; grid-template-columns: 1fr 1fr 1fr auto; gap: 8px; align-items: end; }
.img-options .field { grid-column: auto; }
.img-options .img-keep-wrap { padding-bottom: 6px; }
@media (max-width: 600px) { .img-options { grid-template-columns: 1fr 1fr; } }
/* properties panel: "Chọn ảnh…" next to the src input */
.image-field .pick-image { display: inline-flex; align-items: center; gap: 4px; white-space: nowrap; flex: none; }
.image-field .pick-image svg { width: 14px; height: 14px; }

/* ================================================================== */
/* Drop & paste (dropPaste.js, SPEC-DESIGNER-V2 §2.4)                  */
/* ================================================================== */

.viewport.drop-target { outline: 2px dashed var(--accent); outline-offset: -3px; }
.viewport.drop-target .page-wrap { box-shadow: 0 0 0 3px var(--accent-soft); }

/* ================================================================== */
/* Canvas context menu (contextMenu.js, SPEC-DESIGNER-V2 §2.1)         */
/* ================================================================== */

.rd-popup.ctx-menu { min-width: 220px; }

/* ================================================================== */
/* Shell (main.js / index.html, SPEC-DESIGNER-V2 §0, §3.2, §4.4)        */
/* Toolbar rows, zoom slider, lock/hide buttons, context menu           */
/* ================================================================== */

/* Lock / hide toggles reflect the selection (aria-pressed set by main.js syncToolbar) */
.toolbar [data-action="lock:toggle"][aria-pressed="true"] .ico, .toolbar [data-action="hide:toggle"][aria-pressed="true"] .ico { color: var(--accent-2); }
.toolbar [data-action="hide:toggle"][aria-pressed="true"] { background: var(--warning-soft); color: #92400e; }
/* Row-1 button that opens a dropdown: caret hidden when icon-only (no room) */
@media (max-width: 1500px) { .toolbar .tb-caret { display: none; } }

/* ================================================================== */
/* Print view (printView.js, SPEC-DESIGNER-V2 §4.2)                     */
/* Base rules (body.print-view hides grid/rulers/lines) live in         */
/* designer.css; only the toolbar toggle state is here.                 */
/* ================================================================== */

.toolbar [data-action="printView:toggle"][aria-pressed="true"] { background: var(--success-soft); color: #166534; }

/* ================================================================== */
/* Shortcuts dialog (shortcutsDialog.js, SPEC-DESIGNER-V2 §4.3)         */
/* ================================================================== */

.dlg-shortcuts .dlg-body { max-height: 70vh; padding: 10px 16px 12px; }
.sc-dialog { display: flex; flex-direction: column; gap: 8px; }
.sc-toolbar { display: flex; align-items: center; gap: 10px; }
.sc-toolbar .sc-filter { flex: 1; }
.sc-count { white-space: nowrap; font-size: 12px; }
.sc-group { margin: 6px 0 0; }
.sc-group-title { margin: 0 0 4px; font-size: 11.5px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); }
.sc-table { width: 100%; border-collapse: collapse; }
.sc-table td { padding: 3px 6px; border-bottom: 1px solid var(--border); vertical-align: middle; font-size: 12.5px; }
.sc-table tr:last-child td { border-bottom: 0; }
.sc-keys { width: 38%; white-space: nowrap; }
.sc-keys kbd {
  display: inline-block; padding: 1px 6px; border: 1px solid var(--border-strong); border-bottom-width: 2px; border-radius: 4px;
  background: var(--panel-2); font-family: var(--font-ui); font-size: 11.5px; line-height: 1.5; color: var(--text);
}
.sc-or { margin: 0 4px; color: var(--muted); }
.sc-label { color: var(--text); }
.sc-empty { padding: 12px 4px; }

/* ================================================================== */
/* Table groups, column groups, presets (tableGroups.js /              */
/* tablePresets.js / canvas.js, SPEC-TABLE-GROUPS §5, §8.3, §9)         */
/* ================================================================== */

/* Properties panel: "Nhóm & sắp xếp" section */
.tg-body { display: flex; flex-direction: column; gap: 6px; }
.tg-sub { margin: 8px 0 0; font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); }
.tg-sub:first-child { margin-top: 0; }
.tg-groups, .tg-sorts { display: flex; flex-direction: column; gap: 6px; }
.tg-card .grid2 .check-row { grid-column: 1 / -1; }
.tg-card .tg-footer-fields { grid-column: 1 / -1; }
.tg-card .tg-tgl { grid-column: auto; }
.tg-card .field > .tg-tgl { margin-top: 2px; }
.tg-empty { margin: 0; }
.tg-sort-row { display: grid; grid-template-columns: 1fr 1fr auto; gap: 6px 8px; align-items: end; padding: 6px 8px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--panel-2); }
.tg-sort-row .field.half { grid-column: auto; }
.tg-sort-row .col-actions { padding-bottom: 2px; }
.tg-merge { margin-top: 0; }
.tg-merge .field.check span { font-family: var(--font-mono, monospace); font-size: 11.5px; }
.tg-excel .field.check { width: 100%; }
/* [groupTotals] segmented control "Dòng tổng nhóm: Trên · Dưới · Cả hai · Không" (SPEC-LIBRARY §1) — reuses the .tp-tabs look */
.tg-card .tg-totals-field { grid-column: 1 / -1; }
.tg-card .tg-totals { margin: 2px 0 0; flex-wrap: wrap; }   /* "Trên (gộp với tiêu đề)" wraps onto a second row in the narrow panel */
.tg-card .tg-totals .tp-tab { height: 24px; padding: 0 6px; font-size: 11.5px; flex: 1 1 auto; }

/* Column cards: expression validation + header preview */
.tg-expr-msg.ok { color: var(--success); }
.tg-columns-footer { display: flex; flex-direction: column; gap: 6px; margin-top: 2px; }
.tg-columns-footer .grid2 { margin-top: 2px; }
.tg-header-preview { overflow-x: auto; border: 1px solid var(--border); border-radius: var(--radius); background: var(--panel); }
.tg-header-preview table { border-collapse: collapse; width: 100%; font-size: 10.5px; }
.tg-header-preview th { border: 1px solid var(--border-strong); padding: 2px 4px; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 120px; }
.tg-header-preview th.tg-h-group { font-weight: 600; }

/* Preset picker dialog */
.dlg-presets { width: 560px; }
.dlg-presets .dlg-body { max-height: 66vh; }
.tp-list .dlg-row-main { gap: 3px; }
.tp-list .dlg-row-sub.tp-meta { color: var(--text-2); font-variant-numeric: tabular-nums; }

/* Canvas preview: group header / footer rows, merged cells, column-group header cells */
.el-table tr.tg-gh td { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.el-table tr.tg-gf td { font-variant-numeric: tabular-nums; }
.el-table td.tg-merged { overflow: visible; }
.el-table th.tg-hgc { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Inline badge on a table whose group field is missing from the sample rows (the level is skipped, like the PDF/XLSX) */
.el-table .el-badge { position: absolute; right: 0; top: 100%; z-index: 2; font: 9px/13px var(--font-ui); color: #92400e; background: var(--warning-soft, #fef3c7); border: 1px solid #fcd34d; border-top: 0; border-radius: 0 0 3px 3px; padding: 0 5px; white-space: nowrap; pointer-events: none; }

/* Format bar: group parts + level selector */
.fb-parts .fb-btn[data-value="groupHeader"], .fb-parts .fb-btn[data-value="groupFooter"], .fb-parts .fb-btn[data-value="colGroup"] { white-space: nowrap; }
.fb-group-level { width: 74px; }
/* Below 1500 px (row 1 goes icon-only there too) the group parts use short labels and the
   "Áp dụng cho:" label hides, so the bar keeps its single row without scrolling at 1366 px. */
.fb-parts .fb-lbl-short { display: none; }
@media (max-width: 1500px) {
  .fb-parts:has(.fb-parts-extra:not([hidden])) .fb-seg .fb-btn { padding: 0 5px; }
  .fb-parts .fb-parts-extra { margin-left: 2px; }
  .fb-parts:has(.fb-parts-extra:not([hidden])) > .fb-label { display: none; }
  .fb-parts-extra .fb-lbl-full { display: none; }
  .fb-parts-extra .fb-lbl-short { display: inline; }
  /* ≥ 2 group levels add the level selector (~70 px): give the space back by dropping the
     target label's minimum width and narrowing the selector + font select, so the bar still
     keeps one row at 1366 px with "Tiêu đề nhóm" / "Chân nhóm" active. */
  .fmtbar:has(.fb-group-level:not([hidden])) .fb-target { min-width: 0; }
  .fmtbar:has(.fb-group-level:not([hidden])) .fb-group-level { width: 68px; }
  .fmtbar:has(.fb-group-level:not([hidden])) .fb-font { width: 112px; }
}

/* ================================================================== */
/* Font manager (fontManager.js, SPEC-FONT-MANAGER §2)                 */
/* ================================================================== */

.dlg-fonts { width: 720px; }
.dlg-fonts .dlg-body { max-height: 74vh; padding: 12px 16px; }
.fm { display: flex; flex-direction: column; gap: 10px; }
.fm-toolbar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.fm-toolbar .fm-count { margin-left: auto; font-size: 12px; }
.fm-drop {
  padding: 10px 12px; border: 2px dashed var(--border-strong); border-radius: var(--radius); background: var(--panel-2);
  color: var(--text-2); font-size: 12px; text-align: center; cursor: pointer;
}
.fm-drop:focus-visible { outline: none; border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-soft); }
.fm-drop.over { border-color: var(--accent); background: var(--accent-soft); }

/* family list */
.fm-list { display: flex; flex-direction: column; gap: 6px; }
.fm-row { border: 1px solid var(--border); border-radius: var(--radius); padding: 8px 10px; background: var(--panel); display: flex; flex-direction: column; gap: 6px; }
.fm-row.is-default { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent-soft) inset; }
.fm-row-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.fm-name { font-size: 13.5px; }
.fm-badges { display: inline-flex; gap: 2px; }
.fm-face {
  display: inline-flex; align-items: center; justify-content: center; min-width: 20px; height: 18px; padding: 0 4px;
  border: 1px solid var(--border); border-radius: 4px; font-size: 10.5px; font-weight: 700; color: var(--muted); background: var(--panel-2); opacity: 0.55;
}
.fm-face.on { opacity: 1; color: var(--accent-2); border-color: var(--accent); background: var(--accent-soft); }
.fm-tag { font-size: 11px; padding: 1px 6px; border-radius: 999px; background: var(--panel-2); border: 1px solid var(--border); white-space: nowrap; }
.fm-tag.fm-builtin { color: var(--text-2); }
.fm-tag.fm-vn.ok { color: #166534; background: var(--success-soft); border-color: #bbf7d0; }
.fm-tag.fm-vn.warn { color: #92400e; background: var(--warning-soft); border-color: #fde68a; }
.fm-tag.fm-default { color: var(--accent-2); background: var(--accent-soft); border-color: var(--accent); }
.fm-size { margin-left: auto; font-size: 11.5px; white-space: nowrap; }
.fm-preview { font-size: 18px; line-height: 1.3; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: var(--text); }
.fm-preview.small { font-size: 14px; color: var(--text-2); }
.fm-row-foot { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.fm-excel-field { display: inline-flex; align-items: center; gap: 6px; font-size: 11.5px; color: var(--muted); }
.fm-excel-field .fm-excel { width: 170px; height: 26px; }
.fm-row-foot .fm-btn { height: 26px; padding: 0 10px; font-size: 12px; margin-left: auto; }
.fm-row-foot .fm-btn + .fm-btn, .fm-row-foot .fm-tag + .fm-btn { margin-left: 0; }
.fm-row-foot .fm-tag.fm-default { margin-left: auto; }

/* pending uploads */
.fm-add { border: 1px solid var(--border); border-radius: var(--radius); padding: 8px 10px; background: var(--panel-2); display: flex; flex-direction: column; gap: 6px; }
.fm-add-head { display: flex; align-items: center; gap: 10px; }
.fm-table-wrap { overflow-x: auto; }
.fm-table { width: 100%; border-collapse: collapse; font-size: 12px; }
.fm-table th { text-align: left; font-weight: 600; color: var(--muted); font-size: 11px; padding: 2px 6px 4px; }
.fm-table td { padding: 3px 6px; vertical-align: middle; border-top: 1px solid var(--border); }
.fm-table .fm-in { height: 26px; font-size: 12px; width: 100%; min-width: 90px; }
.fm-table select.fm-in { padding: 0 4px; border: 1px solid var(--border); border-radius: 4px; background: var(--panel); }
.fm-pending-file { max-width: 200px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fm-pending-meta { font-size: 10.5px; }
.fm-pending-status { white-space: nowrap; }
.fm-pending-row.error .fm-pending-file { color: var(--danger); }
.fm-st.ok { color: #166534; }
.fm-st.err { color: var(--danger); }
.fm-add-actions { display: flex; align-items: center; gap: 8px; }
.fm-x { width: 22px; height: 22px; font-size: 14px; }

/* installed (local) fonts */
.fm-local { border: 1px solid var(--border); border-radius: var(--radius); padding: 8px 10px; background: var(--panel); display: flex; flex-direction: column; gap: 6px; }
.fm-local-head { display: flex; align-items: center; gap: 10px; }
.fm-local-head .fm-local-close { margin-left: auto; }
.fm-local-hint { margin: 0; }
.fm-local-list { max-height: 220px; overflow: auto; border: 1px solid var(--border); border-radius: var(--radius); }
.fm-local-item { display: flex; align-items: center; gap: 8px; padding: 4px 8px; border-bottom: 1px solid var(--border); cursor: pointer; font-size: 12.5px; }
.fm-local-item:last-child { border-bottom: 0; }
.fm-local-item:hover { background: var(--panel-2); }
.fm-local-item .fm-local-name { flex: 1; font-size: 15px; }
.fm-local-item .muted { font-size: 11px; white-space: nowrap; }

/* Page tab: "Quản lý font…" next to the default font select; the extra option of every font select */
.field.fm-full { grid-column: 1 / -1; }
.fm-select-row { display: flex; gap: 4px; align-items: center; min-width: 0; }
.fm-select-row select { flex: 1; min-width: 0; }
.fm-manage-btn { height: 26px; padding: 0 8px; font-size: 11.5px; flex: none; }
option.fm-add-option { font-style: italic; color: var(--accent-2); }
.dlg-font-confirm .fm-confirm { white-space: pre-line; }

/* ================================================================== */
/* Data API panel (dataApiPanel.js, SPEC-DATA-API-PANEL §3 / §5)       */
/* Postman-like request builder inside the Dữ liệu tab                 */
/* ================================================================== */

.data-api .api-body { display: flex; flex-direction: column; gap: 8px; }
.data-api .api-line { display: flex; align-items: center; gap: 6px; }
.data-api .api-method { flex: none; width: 70px; height: 28px; padding: 0 2px; border: 1px solid var(--border); border-radius: 4px; background: var(--panel); font-family: var(--font-mono); font-size: 11.5px; }
.data-api .api-url { flex: 1; min-width: 0; height: 28px; padding: 0 8px; border: 1px solid var(--border); border-radius: 4px; background: var(--panel); font-family: var(--font-mono); font-size: 12px; }
.data-api .api-url:focus, .data-api .api-method:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-soft); }
.data-api .api-send { flex: none; }
.data-api .api-history-btn { flex: none; padding: 0 6px; }
.data-api .api-history-btn svg { width: 14px; height: 14px; }
.data-api .api-actions { margin-top: -2px; }

/* Tabs: label + counter badge ("Tham số 1"), the Cài đặt tab drops to its icon on a narrow panel */
.data-api .api-tabs { display: flex; flex-wrap: wrap; gap: 0 2px; border-bottom: 1px solid var(--border); }
.data-api .api-tab { flex: none; display: inline-flex; align-items: center; gap: 4px; padding: 4px 7px; border: 0; border-bottom: 2px solid transparent; margin-bottom: -1px; background: transparent; color: var(--text-2); font-size: 12px; cursor: pointer; white-space: nowrap; }
.data-api .api-tab-n { display: inline-block; min-width: 16px; padding: 0 4px; border-radius: 999px; background: var(--panel-2); color: var(--text-2); font-size: 10px; line-height: 15px; font-weight: 600; text-align: center; font-variant-numeric: tabular-nums; }
.data-api .api-tab.active .api-tab-n { background: var(--accent-soft); color: var(--accent-2); }
.data-api .api-tab-ico { display: none; }
.data-api .api-tab-ico svg { width: 14px; height: 14px; }
.data-api .api-tab:hover { color: var(--text); background: var(--panel-2); }
.data-api .api-tab.active { color: var(--accent-2); border-bottom-color: var(--accent); font-weight: 600; }
.data-api .api-tab-body { display: flex; flex-direction: column; gap: 6px; }
.data-api .api-sub { margin: 4px 0 0; font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); }

/* Key / value rows */
.data-api .api-rows { display: flex; flex-direction: column; gap: 4px; }
.data-api .api-row { display: grid; grid-template-columns: 16px minmax(70px, 1fr) minmax(90px, 1.6fr) auto auto; align-items: center; gap: 4px; }
.data-api .api-row.off .api-row-key, .data-api .api-row.off .api-row-val { color: var(--muted); text-decoration: line-through; }
.data-api .api-row input[type="checkbox"] { width: 14px; height: 14px; margin: 0; accent-color: var(--accent); }
.data-api .api-row input[type="text"], .data-api .api-param input, .data-api .api-path, .data-api .api-timeout, .data-api .api-auth-field {
  height: 26px; padding: 0 6px; border: 1px solid var(--border); border-radius: 4px; background: var(--panel); min-width: 0; width: 100%; font-size: 12px;
}
.data-api input.secret { font-family: var(--font-mono); color: var(--accent-2); }
.data-api .api-row-valwrap { position: relative; display: flex; align-items: center; min-width: 0; }
.data-api .api-row-valwrap input { padding-right: 22px; }
.data-api .api-lock { position: absolute; right: 5px; top: 50%; transform: translateY(-50%); width: 13px; height: 13px; color: var(--muted); pointer-events: none; display: inline-flex; }
.data-api .api-lock svg { width: 13px; height: 13px; }
.data-api .api-row-env { white-space: nowrap; padding: 0 5px; color: #92400e; background: var(--warning-soft); border-color: #fcd34d; }
.data-api .api-row-env svg { width: 11px; height: 11px; }
.data-api .api-auth-env { align-self: flex-start; margin-top: 2px; color: #92400e; background: var(--warning-soft); border-color: #fcd34d; }
.data-api .api-auth-env svg { width: 11px; height: 11px; }
.data-api .api-row-add { align-self: flex-start; }
.data-api .api-params { display: flex; flex-direction: column; gap: 4px; }
.data-api .api-param { display: grid; grid-template-columns: minmax(60px, 0.8fr) 1.4fr; align-items: center; gap: 6px; }
.data-api .api-param .mono { font-size: 12px; color: var(--accent-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Narrow panel (the 319 px right panel at 1366 px, SPEC-DATA-API-PANEL §3): the URL gets its
   own full-width row under method + Gửi + history, key / value inputs stack, the Cài đặt tab is
   icon-only — so the tab strip keeps one line and a real URL is editable without caret scrolling. */
.data-api .api-body { container-type: inline-size; }
@container (max-width: 420px) {
  .data-api .api-line { flex-wrap: wrap; }
  .data-api .api-method { flex: 1 1 auto; }
  .data-api .api-url { order: 1; flex: 1 1 100%; }
  .data-api .api-tab { padding: 4px 5px; gap: 3px; }
  .data-api .api-tab[data-tab="settings"] .api-tab-lbl { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .data-api .api-tab[data-tab="settings"] .api-tab-ico { display: inline-flex; }
  .data-api .api-row { display: flex; flex-wrap: wrap; gap: 2px 4px; }
  .data-api .api-row .api-row-key { flex: 1 1 60px; width: auto; }
  .data-api .api-row-valwrap { order: 10; flex: 1 1 100%; }
  .data-api .api-param { grid-template-columns: 1fr; gap: 2px; }
}

/* Body */
.data-api .api-radios { display: flex; flex-wrap: wrap; gap: 10px; font-size: 12px; }
.data-api .api-radio { display: inline-flex; align-items: center; gap: 4px; cursor: pointer; }
.data-api .api-radio input { margin: 0; accent-color: var(--accent); }
.data-api .api-body-json, .data-api .api-body-raw { width: 100%; font-size: 12px; }
.data-api .api-body-status { font-size: 12px; }
.data-api .api-body-status.ok { color: var(--success); }
.data-api .api-body-status.error { color: var(--danger); }

/* Response */
.data-api .api-response { border-top: 1px dashed var(--border); padding-top: 6px; display: flex; flex-direction: column; gap: 4px; }
.data-api .api-response-body { display: flex; flex-direction: column; gap: 4px; }
.data-api .api-resp-line { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; font-size: 12px; }
.data-api .api-status { font-weight: 600; padding: 1px 6px; border-radius: 999px; font-variant-numeric: tabular-nums; }
.data-api .api-status.ok { background: var(--success-soft); color: #166534; }
.data-api .api-status.info { background: var(--accent-soft); color: var(--accent-2); }
.data-api .api-status.warn { background: var(--warning-soft); color: #92400e; }
.data-api .api-status.err { background: var(--danger-soft); color: #991b1b; }
.data-api .api-meta { color: var(--muted); }
.data-api .api-resp-actions { display: flex; gap: 4px; flex-wrap: wrap; margin-left: auto; }
.data-api .api-warn { font-size: 12px; color: #92400e; background: var(--warning-soft); padding: 3px 6px; border-radius: 4px; }
.data-api .api-warn.info { color: #1e3a8a; background: var(--accent-soft); }
.data-api .api-error { font-size: 12px; color: #991b1b; background: var(--danger-soft); padding: 4px 6px; border-radius: 4px; word-break: break-word; }
.data-api .api-hint { font-size: 12px; color: #1e3a8a; background: var(--accent-soft); padding: 4px 6px; border-radius: 4px; word-break: break-word; }
.data-api .api-details summary { font-size: 12px; color: var(--text-2); cursor: pointer; }
.data-api .api-pre { margin: 2px 0 0; padding: 6px 8px; max-height: 180px; overflow: auto; border: 1px solid var(--border); border-radius: 4px; background: var(--panel-2); font-family: var(--font-mono); font-size: 11.5px; white-space: pre-wrap; word-break: break-all; }
.data-api .api-textbody .api-pre { max-height: 240px; }

/* JSON tree (path picker) */
.data-api .api-tree { max-height: 320px; overflow: auto; border: 1px solid var(--border); border-radius: 4px; padding: 4px 6px; background: var(--panel-2); font-family: var(--font-mono); font-size: 11.5px; line-height: 1.5; }
.data-api .jt-node { margin: 0; }
.data-api .jt-node > summary { list-style: none; }
.data-api .jt-node > summary::-webkit-details-marker { display: none; }
.data-api .jt-node > summary::before { content: ''; display: inline-block; width: 5px; height: 5px; margin: 0 6px 1px 0; border-right: 1.5px solid var(--muted); border-bottom: 1.5px solid var(--muted); transform: rotate(-45deg); transition: transform 0.12s; }
.data-api .jt-node[open] > summary::before { transform: rotate(45deg); }
.data-api .jt-children { padding-left: 14px; border-left: 1px dotted var(--border); margin-left: 2px; }
.data-api .jt-row { display: block; padding: 0 3px; border-radius: 3px; cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.data-api .jt-row:hover { background: var(--accent-soft); }
.data-api .jt-row.picked { background: var(--accent-soft); outline: 1px solid var(--accent); }
.data-api .jt-key { color: #6d28d9; }
.data-api .jt-colon { color: var(--muted); }
.data-api .jt-meta { color: var(--muted); }
.data-api .jt-str { color: #047857; }
.data-api .jt-num { color: #1d4ed8; }
.data-api .jt-bool { color: #b45309; }
.data-api .jt-null { color: var(--muted); }
.data-api .jt-more { color: var(--muted); cursor: default; }

/* History menu (fixed, next to Gửi) */
.api-history-menu { min-width: 260px; max-width: 360px; }
.api-history-menu button { display: flex; align-items: center; gap: 6px; width: 100%; padding: 6px 10px; border: 0; background: transparent; border-radius: 4px; text-align: left; color: var(--text); cursor: pointer; }
.api-history-menu button:hover { background: var(--panel-2); }
.api-history-menu .api-hist-m { flex: none; width: 48px; color: var(--accent-2); font-size: 11px; }
.api-history-menu .api-hist-url { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12px; }
.api-history-menu .api-hist-time { flex: none; color: var(--muted); font-size: 11px; }

/* Dialogs */
.api-curl-input { width: 100%; font-size: 12px; }
.api-curl-status { min-height: 14px; font-size: 12px; margin-top: 4px; }
.api-secret-list { margin: 6px 0; padding-left: 18px; font-size: 12.5px; }
.api-env-line { margin-top: 4px; }

/* Page tab summary */
.ds-summary { margin: 2px 0 6px; word-break: break-all; }

/* ================================================================== */
/* Layer groups (layers.js / groups.js, SPEC-DESIGNER-V3 §1)           */
/* Group nodes in the "Lớp" tree, inline rename, drop zones, the       */
/* "Nhóm" header of the properties panel and the outline name tag.    */
/* ================================================================== */

/* Node row: chevron + folder (group colour) + name + (count); same height / hover as element rows */
.layer-node {
  display: flex; align-items: center; gap: 6px; padding: 4px 4px 4px 2px; border-radius: 4px; cursor: pointer;
  border: 1px solid transparent; position: relative; user-select: none;
}
.layer-node:hover { background: var(--panel-2); }
.layer-node.node-selected { background: var(--accent-soft); }
.layer-node.node-partial { background: color-mix(in srgb, var(--accent-soft) 45%, transparent); }
.layer-node.locked .node-name, .layer-node.hidden-el .node-name { color: var(--muted); }
.layer-node.hidden-el .node-name { opacity: 0.55; text-decoration: line-through; }
.layer-node .node-toggle {
  display: inline-flex; align-items: center; justify-content: center; flex: none; width: 16px; height: 16px;
  border: 0; background: transparent; padding: 0; color: var(--muted); border-radius: 3px; cursor: pointer;
}
.layer-node .node-toggle:hover { background: rgba(0, 0, 0, 0.06); color: var(--text); }
.layer-node .node-toggle svg { transition: transform 0.12s; transform: rotate(90deg); }
.layer-node.collapsed .node-toggle svg { transform: rotate(0deg); }
.layer-node .node-icon { color: var(--grp-color, var(--accent)); }
.layer-node .node-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12.5px; font-weight: 600; }
.layer-node .node-count { flex: none; font-size: 11px; color: var(--muted); font-variant-numeric: tabular-nums; }
/* a node row also carries the count, so its buttons are a little narrower than the element rows' */
.layer-node .layer-actions { display: none; gap: 0; flex: none; }
.layer-node:hover .layer-actions, .layer-node.node-selected .layer-actions, .layer-node.node-partial .layer-actions { display: inline-flex; }
.layer-node .layer-actions .icon-btn { width: 22px; height: 26px; border-radius: 4px; }
.layer-node .layer-actions .icon-btn:hover { background: rgba(37, 99, 235, 0.12); }
.layer-node .layer-actions .icon-btn svg { width: 16px; height: 16px; }
.layer-node.locked .layer-actions { display: inline-flex; }
.layer-node.locked .layer-actions .icon-btn:not([data-act="lock"]) { display: none; }
.layer-node.locked:hover .layer-actions .icon-btn, .layer-node.locked.node-selected .layer-actions .icon-btn { display: inline-flex; }
/* Names stay readable while a row is selected (a selected group shows EVERY member selected): only
   lock / hide stay visible on selected rows, ▲ ▼ 🗑 appear when the pointer or the keyboard focus is
   on the row; member / node buttons are 22 px. Loose selected rows keep ≥ 150 px, members ≥ 120 px. */
.layer.selected:not(:hover):not(:focus-within) .layer-actions .icon-btn:is([data-act="up"], [data-act="down"], [data-act="delete"]),
.layer-node.node-selected:not(:hover):not(:focus-within) .layer-actions .icon-btn:is([data-act="up"], [data-act="down"], [data-act="delete"]),
.layer-node.node-partial:not(:hover):not(:focus-within) .layer-actions .icon-btn:is([data-act="up"], [data-act="down"], [data-act="delete"]) { display: none; }
.layer.layer-member .layer-actions .icon-btn { width: 22px; }
/* while the name is being renamed the input takes the whole row */
.layer-node.renaming .layer-actions, .layer-node.renaming .node-count { display: none; }
/* Members: indented under their node with a coloured guide line; hidden while the node is collapsed */
.layer.layer-member { margin-left: 14px; padding-left: 8px; border-left: 2px solid color-mix(in srgb, var(--grp-color, var(--accent)) 45%, transparent); border-radius: 0 4px 4px 0; }
.layer.layer-member.in-collapsed { display: none; }
/* a search (findBar.js) shows matching members even inside a collapsed node and hides the nodes */
#layers.find-filtered .layer.layer-member.in-collapsed.find-hit { display: flex; }
#layers.find-filtered .layer-node { display: none; }
/* Inline rename (double-click the name / F2) */
.layer-rename {
  flex: 1; min-width: 0; height: 22px; padding: 0 6px; font: inherit; font-size: 12.5px;
  border: 1px solid var(--accent); border-radius: 4px; background: var(--panel); color: var(--text); outline: none;
  box-shadow: 0 0 0 2px var(--accent-soft);
}
/* Drop zones: a line above / below a row, a filled frame when dropping INTO a node */
.layer-node.drop-before::before { content: ""; position: absolute; left: 4px; right: 4px; height: 2px; background: var(--accent); top: -1px; }
.layer-node.drop-into { box-shadow: inset 0 0 0 2px var(--accent); background: var(--accent-soft); }
.layer-node.dragging, .layer.dragging { opacity: 0.4; }
/* Context menu of the layers list (insertMenu.js popup engine) */
.layers-menu { min-width: 200px; }

/* Properties panel: "Nhóm" header above the element sections when a whole group is selected */
.grp-head { margin: 0 12px 6px; padding: 8px 10px; border: 1px solid color-mix(in srgb, var(--grp-color, var(--accent)) 45%, var(--border)); border-left-width: 3px; border-radius: var(--radius); background: color-mix(in srgb, var(--grp-color, var(--accent)) 6%, var(--panel)); }
.grp-head-row { display: flex; align-items: center; gap: 6px; }
.grp-head-ico { display: inline-flex; flex: none; color: var(--grp-color, var(--accent)); }
.grp-head-ico svg { width: 16px; height: 16px; }
.grp-name-input { flex: 1; min-width: 0; height: 26px; padding: 0 8px; font: inherit; font-size: 12.5px; font-weight: 600; border: 1px solid var(--border); border-radius: 4px; background: var(--panel); color: var(--text); }
.grp-name-input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-soft); }
.grp-head-count { flex: none; font-size: 11.5px; }
.grp-head-actions { display: flex; gap: 6px; margin-top: 6px; flex-wrap: wrap; }
.grp-head-actions .btn svg { width: 14px; height: 14px; }
.grp-head-geo { display: grid; grid-template-columns: repeat(4, 1fr); gap: 4px; margin-top: 6px; }
.grp-geo-field { display: flex; align-items: center; gap: 4px; min-width: 0; }
.grp-geo-field > span { font-size: 11px; color: var(--muted); flex: none; width: 12px; }
.grp-geo-field input { width: 100%; min-width: 0; height: 24px; padding: 0 4px; font: inherit; font-size: 12px; border: 1px solid var(--border); border-radius: 4px; background: var(--panel); color: var(--text); }
.grp-geo-field input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-soft); }

/* Canvas: group name tag at the top-left of the selected group outline (Xem → "Hiện tên nhóm") */
.grp-outline .grp-tag {
  position: absolute; left: -1px; bottom: 100%; margin-bottom: 2px; max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  padding: 1px 6px; border-radius: 3px; font: 600 10.5px/1.4 var(--font-ui); color: #fff; background: var(--grp-color, var(--accent)); pointer-events: none;
}
body.print-view .grp-outline .grp-tag { display: none; }
/* Xem menu row: the check mark of the toggle */
.menu button[data-action="groupNames:toggle"][aria-pressed="true"]::after { content: "✓"; margin-left: auto; font-size: 11px; }
.menu button[data-action="groupNames:toggle"] .grp-label { margin-left: 0; }

/* ================================================================== */
/* Conditional styles (styleRules.js, SPEC-TABLE-GROUPS §12.3)         */
/* Rule-list editor: properties panel sections "Định dạng theo điều    */
/* kiện" / "Tô màu theo điều kiện" (tableProps.js mounts it too)        */
/* ================================================================== */

.sr-root { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.sr-list { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.sr-list + .sr-list { margin-top: 6px; }
.sr-head { display: flex; align-items: center; flex-wrap: wrap; gap: 4px 8px; }
.sr-head .sr-title { margin: 0; flex: 1 1 auto; }
.sr-head .sr-count { font-size: 11px; white-space: nowrap; }
.sr-head-actions { display: inline-flex; gap: 4px; margin-left: auto; }
.sr-empty, .sr-hint, .sr-warn { margin: 0; }
.sr-rules { display: flex; flex-direction: column; gap: 6px; }

/* one rule card */
.sr-rule { display: flex; flex-direction: column; gap: 6px; padding: 6px 8px 8px; }
.sr-rule.off > :not(.sr-rule-head) { opacity: 0.55; }
.sr-rule.flash { animation: sr-flash 1.5s ease-out; }
@keyframes sr-flash { 0% { box-shadow: 0 0 0 3px var(--accent); } 100% { box-shadow: 0 0 0 0 transparent; } }
/* head: checkbox + name on the first line (the name keeps ≥ 110 px so a typed name / the
   placeholder stay readable), preview chip + ▲ ▼ 🗑 on a second line at the panel width */
.sr-rule-head { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 6px; min-width: 0; }
.sr-enabled { display: inline-flex; align-items: center; flex: none; }
.sr-enabled input { width: 14px; height: 14px; margin: 0; accent-color: var(--accent); }
.sr-rule-head .sr-name { flex: 1 1 160px; min-width: 110px; height: 26px; padding: 0 6px; border: 1px solid var(--border); border-radius: 4px; background: var(--panel); font-size: 12px; }
.sr-rule-head .sr-name:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-soft); }
.sr-rule-head .col-actions { flex: none; margin-left: auto; }
/* live preview chip "Aa 1.234.567 đ" */
.sr-chip {
  flex: none; display: inline-flex; align-items: center; max-width: 118px; height: 24px; padding: 0 8px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
  border: 1px solid var(--border); border-radius: 4px; background: var(--panel); font-size: 12px; line-height: 22px; font-variant-numeric: tabular-nums; color: var(--text);
}

/* condition row: input + field picker button, operator chips under it */
.sr-cond { display: flex; gap: 4px; align-items: center; min-width: 0; }
.sr-cond .sr-when { flex: 1 1 auto; min-width: 0; height: 28px; padding: 0 8px; border: 1px solid var(--border); border-radius: 4px; background: var(--panel); font-family: var(--font-mono); font-size: 12px; }
.sr-cond .sr-when:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-soft); }
.sr-cond .sr-fields-btn { flex: none; padding: 0 6px; font-family: var(--font-mono); font-weight: 600; }
.sr-cond .sr-fields-btn svg { width: 14px; height: 14px; }
.sr-ops { display: flex; flex-wrap: wrap; gap: 3px; }
.sr-op {
  height: 20px; min-width: 26px; padding: 0 6px; border: 1px solid var(--border); border-radius: 999px; background: var(--panel); color: var(--text-2);
  font-family: var(--font-mono); font-size: 11px; line-height: 18px; cursor: pointer;
}
.sr-op:hover { border-color: var(--accent); color: var(--accent-2); background: var(--accent-soft); }
/* validation / match message */
.sr-msg { margin: 0; font-size: 11.5px; line-height: 1.4; }
.sr-msg.ok { color: var(--success); }
.sr-msg.error { color: var(--danger); background: var(--danger-soft); padding: 3px 6px; border-radius: 4px; word-break: break-word; }
.sr-msg.hint, .sr-msg.muted { color: var(--muted); }
.sr-msg.warn, .tg-expr-msg.braces { color: #92400e; background: var(--warning-soft, #fef3c7); padding: 3px 6px; border-radius: 4px; word-break: break-word; }
.sr-level { max-width: 160px; }

/* in-flow popovers: field picker (filter + list) and presets */
.sr-pop { display: flex; flex-direction: column; gap: 4px; padding: 6px; border: 1px solid var(--border-strong); border-radius: var(--radius); background: var(--panel); box-shadow: var(--shadow); }
.sr-pop-filter { height: 26px; padding: 0 6px; border: 1px solid var(--border); border-radius: 4px; font-size: 12px; }
.sr-pop-filter:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-soft); }
.sr-pop-list { display: flex; flex-direction: column; max-height: 180px; overflow: auto; }
.sr-pop-item { display: block; width: 100%; padding: 4px 8px; border: 0; border-radius: 4px; background: transparent; color: var(--text); text-align: left; font-size: 12px; cursor: pointer; }
.sr-pop-item.mono { font-family: var(--font-mono); font-size: 11.5px; }
.sr-pop-item:hover, .sr-pop-item:focus-visible { background: var(--accent-soft); color: var(--accent-2); outline: none; }
.sr-pop-item[data-kind="system"], .sr-pop-item[data-kind="root"] { color: var(--accent-2); }
.sr-pop-item[data-kind="agg"], .sr-pop-item[data-kind="group"] { color: #6d28d9; }
.sr-pop-empty { margin: 0; }

/* style controls (reuse the panel's field / color-field / tgl look) */
.sr-style { margin-top: 2px; }
.sr-style .sr-biu { grid-column: 1 / -1; }
.sr-style .tgl { min-width: 30px; }
.sr-col-picker { margin-bottom: 2px; }

/* check panel: rule rows show the rule location; the drawer row already has the element name */
.check-issue.check-rule .check-el { max-width: 46%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ================================================================== */
/* Table properties: sub-tabs, column chip strip, column form, inline  */
/* header editing (tableProps.js / canvas.js, SPEC-TABLE-GROUPS §10-11) */
/* ================================================================== */

/* Segmented control "Thuộc tính bảng" / "Thuộc tính cột" */
.tp-tabs { display: flex; gap: 2px; margin: 4px 12px 6px; padding: 2px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--panel-2); }
.tp-tab { flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 5px; height: 26px; padding: 0 8px; border: 0; border-radius: 4px; background: transparent; color: var(--text-2); font-size: 12px; font-weight: 500; cursor: pointer; white-space: nowrap; }
.tp-tab:hover { color: var(--text); }
.tp-tab.active { background: var(--panel); color: var(--accent-2); font-weight: 600; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08); }
.tp-tab:focus-visible { outline: 2px solid var(--accent-soft); }
.tp-tab-n { display: inline-block; min-width: 16px; padding: 0 4px; border-radius: 999px; background: var(--panel-2); color: var(--text-2); font-size: 10px; line-height: 15px; font-weight: 600; text-align: center; font-variant-numeric: tabular-nums; }
.tp-tab.active .tp-tab-n { background: var(--accent-soft); color: var(--accent-2); }
.tp-pane { display: flex; flex-direction: column; }
.tp-pane .tp-rules:empty { display: none; }

/* Column strip: chips (drag to reorder) + ◀ ▶ ➕ ✕. The chips WRAP (every column stays visible
   and reachable by drag at the panel's ~300 px) — a scrolling one-row strip hid all but the first
   two. `.tp-chips` (the tablist) lays its chips out as items of the strip itself, so the action
   buttons follow the last chip and only drop to their own line when that row is full. */
.tp-strip { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; padding: 6px 12px 6px; position: sticky; top: 0; z-index: 2; background: var(--panel); border-bottom: 1px solid var(--border); }
.tp-chips { display: contents; }
.tp-chip { flex: none; display: inline-flex; align-items: center; gap: 4px; max-width: 110px; height: 24px; padding: 0 7px 0 4px; border: 1px solid var(--border); border-radius: 999px; background: var(--panel-2); color: var(--text-2); font-size: 11.5px; cursor: pointer; white-space: nowrap; position: relative; }
.tp-chip:hover { border-color: var(--border-strong); color: var(--text); }
.tp-chip.active { background: var(--accent-soft); border-color: var(--accent); color: var(--accent-2); font-weight: 600; }
.tp-chip:focus-visible { outline: 2px solid var(--accent-soft); outline-offset: 1px; }
.tp-chip-n { display: inline-flex; align-items: center; justify-content: center; min-width: 16px; height: 16px; padding: 0 3px; border-radius: 999px; background: var(--panel); color: var(--muted); font-size: 10px; font-variant-numeric: tabular-nums; }
.tp-chip.active .tp-chip-n { background: var(--panel); color: var(--accent-2); }
.tp-chip-t { overflow: hidden; text-overflow: ellipsis; }
.tp-chip.dragging { opacity: 0.45; }
.tp-chip.drop-before::before, .tp-chip.drop-after::after { content: ""; position: absolute; top: -3px; bottom: -3px; width: 2px; background: var(--accent); border-radius: 1px; }
.tp-chip.drop-before::before { left: -3px; }
.tp-chip.drop-after::after { right: -3px; }
.tp-strip-actions { display: inline-flex; flex: none; gap: 1px; margin-left: auto; }
.tp-strip-actions .icon-btn { width: 24px; height: 24px; }
.tp-strip-actions .icon-btn:disabled { opacity: 0.35; cursor: default; }

/* ------------------------------------------------------------------ */
/* [strip] Compact column strip for wide tables (tableProps.js,        */
/* SPEC-TABLE-FIELDS-UI §2): a top row "Cột: [combobox ▾] ◀ ▶ ⊟", a    */
/* chip row with the active column, its neighbours and "+N" overflow   */
/* chips; the expanded strip of a wide table caps its wrapping chips   */
/* at 6 rows with an inner scroll. The column form starts with the     */
/* sticky mini-header "◀ Cột 12/78 — Thành tiền ▶" (`--tp-strip-h`).   */
/* ------------------------------------------------------------------ */
.tp-strip-top { flex: 1 1 100%; display: flex; align-items: center; gap: 4px; min-width: 0; }
.tp-combo-label { flex: none; font-size: 11.5px; color: var(--text-2); }
.tp-combo { position: relative; flex: 1 1 auto; min-width: 0; }
.tp-combo-input { width: 100%; height: 26px; padding: 0 20px 0 7px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--panel-2); color: var(--text); font: inherit; font-size: 12px; box-sizing: border-box; }
.tp-combo-input:focus { outline: 2px solid var(--accent-soft); border-color: var(--accent); background: var(--panel); }
.tp-combo-caret { position: absolute; right: 6px; top: 50%; transform: translateY(-50%); pointer-events: none; color: var(--muted); font-size: 11px; }
.tp-combo-list { position: absolute; left: 0; right: 0; top: calc(100% + 2px); z-index: 30; margin: 0; padding: 3px; list-style: none; max-height: 240px; overflow-y: auto; border: 1px solid var(--border); border-radius: var(--radius); background: var(--panel); box-shadow: 0 6px 18px rgba(0, 0, 0, 0.14); }
.tp-combo-opt { display: flex; align-items: center; gap: 6px; padding: 3px 6px; border-radius: 4px; font-size: 12px; color: var(--text); cursor: pointer; white-space: nowrap; }
.tp-combo-opt .tp-chip-n { flex: none; background: var(--panel-2); }
.tp-combo-opt .tp-combo-t { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.tp-combo-opt .tp-combo-f { flex: 0 1 auto; max-width: 45%; overflow: hidden; text-overflow: ellipsis; color: var(--muted); font-size: 11px; }
.tp-combo-opt:hover { background: var(--panel-2); }
.tp-combo-opt.hl { background: var(--accent-soft); color: var(--accent-2); }
.tp-combo-opt.current .tp-combo-t { font-weight: 600; }
.tp-combo-empty { padding: 4px 6px; font-size: 11.5px; color: var(--muted); }
.tp-nav { display: inline-flex; flex: none; gap: 1px; }
.tp-nav .icon-btn, .tp-strip-toggle { width: 24px; height: 24px; }
.tp-nav .icon-btn:disabled { opacity: 0.35; cursor: default; }
.tp-strip-toggle[aria-pressed="true"] { color: var(--accent-2); background: var(--accent-soft); }
.tp-strip-pick { height: 24px; padding: 0 7px; font-size: 11.5px; white-space: nowrap; }
/* compact: the chip row is a single non-wrapping line; "+N" chips open the combobox */
.tp-strip[data-mode="compact"] .tp-chips { display: flex; flex: 1 1 auto; min-width: 0; gap: 4px; overflow: hidden; }
.tp-strip[data-mode="compact"] .tp-chip { min-width: 54px; flex: 0 1 auto; }
.tp-strip[data-mode="compact"] .tp-chip.active { flex-shrink: 0; }
.tp-chip-more { flex: none !important; padding: 0 7px; font-variant-numeric: tabular-nums; color: var(--muted); border-style: dashed; }
.tp-chip-more:hover { color: var(--accent-2); border-color: var(--accent); }
/* expanded wide strip: wrapping chips capped at 6 rows (24 px chips + 4 px gap) with an inner scroll */
.tp-strip[data-mode="expanded"][data-wide="1"] .tp-chips { display: flex; flex-wrap: wrap; flex: 1 1 100%; gap: 4px; max-height: 164px; overflow-y: auto; padding-right: 2px; }
/* the sticky mini-header of the column form sits right under the strip */
.tp-col-form .tp-col-head { position: sticky; top: var(--tp-strip-h, 0px); z-index: 1; display: flex; align-items: center; gap: 4px; margin: -6px -8px 6px; padding: 4px 6px; border-bottom: 1px solid var(--border); border-radius: var(--radius) var(--radius) 0 0; background: var(--panel); }
.tp-col-form .tp-col-head .icon-btn { flex: none; width: 22px; height: 22px; }
.tp-col-form .tp-col-head .icon-btn:disabled { opacity: 0.35; cursor: default; }
.tp-col-form .tp-col-head-text { flex: 1 1 auto; min-width: 0; display: flex; align-items: baseline; gap: 4px; overflow: hidden; white-space: nowrap; font-size: 12px; }
.tp-col-form .tp-col-head-text .tp-col-pos { flex: none; }
.tp-col-form .tp-col-head-text .tp-col-name { flex: 0 1 auto; overflow: hidden; text-overflow: ellipsis; }
.tp-col-form .tp-col-head .tp-col-id { flex: 0 1 auto; max-width: 40%; margin-left: auto; }

/* Column form */
#tp-pane-columns > .tp-col-form, #tp-pane-columns > .tp-empty, #tp-pane-columns > .tp-col-buttons, #tp-pane-columns > .tg-columns-footer { margin: 8px 12px 0; }
#tp-pane-columns > .tg-columns-footer { margin-bottom: 12px; }
.tp-col-form .col-head .tp-col-id { max-width: 60%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 11px; }
.tp-width-row { display: flex; gap: 4px; align-items: center; }
.tp-width-row input[type="number"] { flex: 1; min-width: 0; }
.tp-width-row .btn-sm { flex: none; height: 28px; padding: 0 7px; }
.tp-width-total { margin: 0; }
.tp-width-total.warn { grid-column: 1 / -1; }
.tp-col-form .tp-sub-section { margin: 8px -8px -8px; border-top: 1px solid var(--border); border-bottom: 0; border-radius: 0 0 var(--radius) var(--radius); }
.tp-col-form .tp-sub-section .prop-section-title { padding: 6px 8px; }
.tp-col-form .tp-sub-section .prop-section-body { padding: 0 8px 8px; }
.tp-col-style .substyle { margin-bottom: 6px; background: var(--panel); }
.tp-col-style > .side-hint { margin-top: 0; }
.tp-col-form .tp-rules:not(:empty) { margin: 8px -8px -8px; border-top: 1px solid var(--border); }

/* rd:focus-column highlight (~1.5 s) of the column form / a group card / the binding field */
@keyframes tp-flash { 0% { box-shadow: 0 0 0 3px var(--accent-soft); background-color: var(--accent-soft); } 100% { box-shadow: 0 0 0 0 transparent; } }
.col-card.flash, .tg-card.flash, .col-row.flash { animation: tp-flash 1.5s ease-out; }
.field.flash > input, .field.flash > select { animation: tp-flash 1.5s ease-out; }

/* Canvas: a header cell / group header row being edited in place */
.el-table th.el-cell-editing, .el-table td.el-cell-editing { overflow: visible; outline: 1px solid var(--accent); outline-offset: -1px; }
.el-table .el-cell-editing .el-text-inner.editing { display: block; min-height: 1em; white-space: pre-wrap; word-break: break-word; }

/* ================================================================== */
/* Report banding (banding.js / canvas.js / pagePanel.js / tableProps  */
/* .js, SPEC-CONSTRAINTS §3)                                           */
/* ================================================================== */

/* Canvas background: labels of the repeating header / footer regions and the two report bands
   (unscaled px inside .page-bg, positioned by canvas.js renderBands). The labels are small
   vertical tabs in the RIGHT MARGIN GUTTER next to the region (`.page-bg[data-band-gutter="1"]`,
   set by renderBands when the margin is wide enough), so they never paint over the region's own
   content ("CỘNG HÒA XÃ HỘI …" at the top-right of a report header band); with a narrow margin
   they fall back to the inside corner. The long print-order note (`data-note`) is not painted on
   the canvas any more — the Page tab's "Băng báo cáo" section explains the same thing. */
.page-header-region, .page-footer-region, .page-band-region { overflow: visible; }
.page-band-region { position: absolute; pointer-events: none; box-sizing: border-box; background: repeating-linear-gradient(135deg, rgba(217, 119, 6, 0.07) 0 6px, transparent 6px 12px); border-top: 1px dashed #d97706; border-bottom: 1px dashed #d97706; }
.page-header-region::before, .page-footer-region::before, .page-band-region::before { content: attr(data-label); position: absolute; right: 0; top: 0; font: 600 9px/12px var(--font-ui); letter-spacing: 0.02em; text-transform: uppercase; padding: 0 5px; border-radius: 0 0 0 3px; white-space: nowrap; pointer-events: none; }
.page-header-region::before, .page-footer-region::before { color: var(--accent-2); background: rgba(219, 234, 254, 0.9); }
.page-band-region::before { color: #92400e; background: rgba(254, 243, 199, 0.95); }
.page-bg[data-band-gutter="1"] .page-header-region::before, .page-bg[data-band-gutter="1"] .page-footer-region::before, .page-bg[data-band-gutter="1"] .page-band-region::before {
  right: auto; left: 100%; top: 0; margin-left: 2px; max-height: 100%; overflow: hidden; text-overflow: ellipsis;
  writing-mode: vertical-rl; padding: 4px 0; border-radius: 0 3px 3px 0; opacity: 0.9;
}
/* the per-page print-order note stays available as data (tests / tooltips) but is not painted */
.page-band-region::after, .page-header-region::after { content: none; display: none; }

/* Overlay badges: a repeating header / footer element whose "Điều kiện hiển thị" depends on the page */
.ov-bands { pointer-events: none; }
.band-badge { position: absolute; transform: translate(-100%, -100%); display: inline-flex; align-items: center; font: 600 9.5px/14px var(--font-ui); color: #fff; background: #d97706; padding: 0 5px; border-radius: 3px 3px 0 0; white-space: nowrap; pointer-events: none; }
.band-badge.band-first { background: var(--accent); }
.band-badge.band-notFirst { background: #7c3aed; }
.band-badge.band-last { background: #059669; }
.band-badge.band-group { background: #6b7280; }

/* print view: no band chrome */
body.print-view .page-band-region, body.print-view .ov-bands { display: none; }

/* Page tab: "Băng báo cáo" section */
.page-bands .page-bands-note { grid-column: 1 / -1; margin: 0; padding: 4px 6px; border-left: 3px solid #d97706; background: rgba(254, 243, 199, 0.5); color: #92400e; }
.page-bands .page-region-cond-hint { grid-column: 1 / -1; }

/* code row without any code yet: muted "(1) (2) …" placeholders (canvas only) */
.el-table tr.tg-code-empty .tg-code-ph { opacity: 0.4; font-style: italic; }

/* Thuộc tính bảng: "Băng tiêu đề bảng" section (code row style controls) */
.tp-code-style { grid-column: 1 / -1; }
.tp-code-style .tgl-group { margin-bottom: 4px; }

/* ================================================================== */
/* Anchors: properties section, canvas links, pick mode, suggestion   */
/* chips, wizard (anchorsPanel.js / anchorLinks.js / anchorSuggest.js, */
/* SPEC-CONSTRAINTS §2 / §5)                                           */
/* ================================================================== */

/* "Ràng buộc (neo)" section: one row per side, the whole body spans the panel grid */
.anc-section .prop-section-body.anc-body { display: block; }
.anc-section .anc-count { margin-left: 6px; font-size: 10.5px; font-weight: 500; color: var(--accent-2); background: var(--accent-soft); border-radius: 999px; padding: 0 6px; }
.anc-rows { display: flex; flex-direction: column; gap: 5px; }
/* row 1: side · target · pick · ✕ — row 2 (anchored sides only): edge · gap mm · pin */
.anc-row { display: grid; grid-template-columns: 34px minmax(0, 1fr) 24px 22px; align-items: center; gap: 3px 4px; padding-bottom: 4px; border-bottom: 1px dashed var(--border); }
.anc-row:last-child { border-bottom: 0; padding-bottom: 0; }
.anc-row .anc-side { font-size: 11px; color: var(--muted); white-space: nowrap; }
.anc-row:not(.anc-empty) .anc-side { color: var(--accent-2); font-weight: 600; }
.anc-row select, .anc-row input[type="number"] { height: 26px; min-width: 0; font-size: 12px; }
.anc-row .anc-pick { width: 24px; height: 24px; color: var(--muted); }
.anc-row .anc-pick.active, .anc-row .anc-pick[aria-pressed="true"] { color: var(--accent-2); background: var(--accent-soft); box-shadow: inset 0 0 0 1px var(--accent); }
.anc-row .anc-clear { width: 22px; height: 22px; }
.anc-row .anc-clear:disabled, .anc-row select:disabled, .anc-row input:disabled { opacity: 0.45; }
.anc-row .anc-detail { grid-column: 2 / -1; display: flex; flex-wrap: wrap; align-items: center; gap: 4px; }
.anc-row .anc-detail .anc-edge { flex: 1 1 96px; min-width: 0; }
.anc-row .anc-detail .anc-gap { flex: 0 0 58px; width: 58px; text-align: right; padding: 0 4px; }
.anc-row .anc-unit { font-size: 11px; color: var(--muted); }
.anc-row .anc-pin { flex: 1 1 100%; display: inline-flex; align-items: center; gap: 5px; font-size: 11.5px; color: var(--text-2); }
.anc-row .anc-pin input { margin: 0; }
.anc-row.flash, .anc-section.flash { animation: tp-flash 1.5s ease-out; border-radius: 4px; }
.anc-hint { margin: 0 0 6px; }
.anc-stretch { margin-top: 2px; }
.anc-actions { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 8px; }
.anc-actions .btn { flex: 1 1 auto; justify-content: center; white-space: nowrap; }
.anc-actions .anc-wizard { flex-basis: 100%; }
.anc-mute { margin-top: 6px; }
/* a group member: the group's anchors move the block — hint + "Chọn cả nhóm" */
.anc-member-hint .anc-select-group { margin-left: 4px; height: 20px; padding: 0 6px; font-size: 11px; vertical-align: middle; }
/* multi-selection: compact section, actions apply to every selected element */
.anc-section.anc-multi .anc-actions { margin-top: 4px; }
/* check panel: «Neo» / «Bỏ qua» on a W_ANCHOR_SUGGEST row */
.check-issue .check-anchor-apply, .check-issue .check-anchor-mute { flex: none; margin-left: 4px; }
#status-msg.anc-status { color: var(--accent-2); font-weight: 600; opacity: 1; }

/* Canvas links (unscaled overlay layer below the selection) */
.ov-anchors { position: absolute; inset: 0; pointer-events: none; }
.ov-anchors .anc-svg { position: absolute; left: 0; top: 0; overflow: visible; }
/* link = dashed line (gap long) + anchor glyph on the anchored edge (bracket + chevron, drawn
   whatever the gap so a 0–2 mm anchor is still recognisable) + tick on the target edge + label
   with unit ("2 mm", tabular digits; beside the glyph for short links) */
.ov-anchors .anc-link line { stroke: #7c3aed; stroke-width: 1.25; stroke-dasharray: 4 3; opacity: 0.75; }
.ov-anchors .anc-link .anc-tick { stroke-dasharray: none; stroke-width: 1.5; }
.ov-anchors .anc-link .anc-glyph { fill: none; stroke: #7c3aed; stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; opacity: 0.95; }
.ov-anchors .anc-link .anc-dot { fill: #fff; stroke: #7c3aed; stroke-width: 1; opacity: 0.8; }
.ov-anchors .anc-link .anc-label { font: 10px/1 var(--font-ui); font-variant-numeric: tabular-nums; fill: #6d28d9; opacity: 0.9; paint-order: stroke; stroke: #fff; stroke-width: 3px; stroke-linejoin: round; }
.ov-anchors .anc-link.anc-sel line { stroke-width: 1.75; opacity: 1; }
.ov-anchors .anc-link.anc-sel .anc-glyph { stroke-width: 2.25; }
.ov-anchors .anc-link.anc-sel .anc-label { font-size: 11px; font-weight: 600; opacity: 1; }
.ov-anchors .anc-link.anc-missing line { stroke: var(--danger); stroke-dasharray: 2 2; opacity: 1; }
.ov-anchors .anc-ghost { fill: rgba(124, 58, 237, 0.06); stroke: #7c3aed; stroke-width: 1; stroke-dasharray: 3 3; opacity: 0.8; }
.ov-anchors .anc-ghost.anc-sel { stroke-width: 1.5; }
.ov-anchors .anc-ghost-label { font: italic 9.5px/1 var(--font-ui); fill: #6d28d9; opacity: 0.85; paint-order: stroke; stroke: #fff; stroke-width: 3px; stroke-linejoin: round; }
.ov-anchors .anc-pick-page { fill: none; stroke: var(--accent); stroke-width: 1.5; stroke-dasharray: 6 4; opacity: 0.6; }
.ov-anchors .anc-pick-paper { fill: none; stroke: var(--accent); stroke-width: 1.5; stroke-dasharray: 2 3; opacity: 0.5; }
.ov-anchors .anc-pick-page.anc-hover-on, .ov-anchors .anc-pick-paper.anc-hover-on { opacity: 1; stroke-width: 2.5; fill: rgba(37, 99, 235, 0.06); }
.ov-anchors .anc-hover { position: absolute; box-sizing: content-box; margin: -2px 0 0 -2px; padding: 2px; border: 2px solid var(--accent); border-radius: 3px; background: rgba(37, 99, 235, 0.10); pointer-events: none; }
body.anchor-pick #canvas-area .viewport, body.anchor-pick #canvas-area .viewport .el, body.anchor-pick #canvas-area .viewport .el * { cursor: crosshair !important; }
body.print-view .ov-anchors { display: none; }

/* Drop / insert suggestion chip (own overlay layer, above everything on the page) */
.ov-anchor-chips { position: absolute; inset: 0; pointer-events: none; }
.anc-chip {
  position: absolute; z-index: 5; display: inline-flex; align-items: center; gap: 6px; max-width: 460px;
  padding: 4px 6px 4px 8px; border: 1px solid #c4b5fd; border-radius: 6px; background: #fff; color: var(--text);
  font-size: 12px; box-shadow: 0 4px 14px rgba(0, 0, 0, 0.14); pointer-events: auto; white-space: nowrap;
  animation: anc-chip-in 0.15s ease-out;
}
.anc-chip .anc-chip-text { overflow: hidden; text-overflow: ellipsis; }
.anc-chip .btn-xs { height: 22px; padding: 0 8px; font-size: 11.5px; }
@keyframes anc-chip-in { from { opacity: 0; transform: translateY(-3px); } to { opacity: 1; transform: none; } }
/* the ↓ badge of the flow overlay opens the same chip */
.ov-flow .flow-box .flow-tag { pointer-events: auto; cursor: pointer; }
.ov-flow .flow-box .flow-tag:hover { filter: brightness(1.12); text-decoration: underline; }

/* Wizard dialog */
.anc-wizard .anc-wiz-intro { margin: 0 0 8px; }
.anc-wizard .anc-wiz-tools { display: flex; align-items: center; gap: 6px; margin-bottom: 6px; }
.anc-wizard .anc-wiz-count { margin-left: auto; font-size: 12px; font-variant-numeric: tabular-nums; }
.anc-wizard .anc-wiz-list { max-height: 50vh; overflow: auto; border: 1px solid var(--border); border-radius: var(--radius); padding: 4px 8px; }
.anc-wizard .anc-wiz-kind { margin: 8px 0 4px; font-size: 12px; display: flex; align-items: center; gap: 6px; }
.anc-wizard .anc-wiz-kind input { margin: 0; }
.anc-wizard .anc-wiz-row { display: flex; align-items: flex-start; gap: 8px; padding: 3px 0 3px 18px; font-size: 12.5px; cursor: pointer; }
.anc-wizard .anc-wiz-row input { margin: 2px 0 0; flex: none; }
.anc-wizard .anc-wiz-row span { flex: 1; min-width: 0; }
.anc-wizard .anc-wiz-tag { flex: none; font-size: 10.5px; color: var(--accent-2); background: var(--accent-soft); border-radius: 999px; padding: 0 6px; }


/* ------------------------------------------------------------------ */
/* [columnHighlight] active column tint (public/js/columnHighlight.js) */
/* ------------------------------------------------------------------ */
.el-table td.col-focus, .el-table th.col-focus {
  box-shadow: inset 0 0 0 999px rgba(37, 99, 235, 0.13);   /* tint without changing the layout */
}
.el-table th.col-focus { box-shadow: inset 0 0 0 999px rgba(37, 99, 235, 0.22); }
body.print-view .el-table .col-focus { box-shadow: none; }

/* ================================================================== */
/* [watermark] Page watermarks "Logo chìm" (watermarkPanel.js /        */
/* canvas.js, SPEC-LIBRARY §3.3)                                       */
/* ================================================================== */

/* Canvas: one layer under the elements, one above (stamps); never selectable, clipped to the page */
.page .wm-layer { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
.page .wm-layer .wm-inst { position: absolute; transform-origin: center center; pointer-events: none; user-select: none; }
.page .wm-layer .wm-img { display: block; max-width: none; }
.page .wm-layer .wm-text { white-space: pre; text-align: center; }
/* Drag handle of the open card (overlay, unscaled): the dashed box of the instance + a grip at its centre */
.ov-watermark { position: absolute; inset: 0; pointer-events: none; }
.ov-watermark .wm-box { position: absolute; border: 1px dashed #0e7490; border-radius: 2px; pointer-events: none; transform-origin: center center; opacity: 0.8; }
.ov-watermark .wm-handle {
  position: absolute; width: 18px; height: 18px; margin: -9px 0 0 -9px; border-radius: 50%; box-sizing: border-box;
  border: 2px solid #fff; background: #0e7490; box-shadow: 0 0 0 1px #0e7490, 0 2px 6px rgba(0, 0, 0, 0.25);
  cursor: move; pointer-events: auto; touch-action: none;
}
.ov-watermark .wm-handle.dragging { background: #155e75; }
.ov-watermark .wm-handle .wm-handle-label {
  position: absolute; left: 22px; top: -1px; padding: 1px 6px; border-radius: 3px; background: #0e7490; color: #fff;
  font: 10.5px/16px var(--font-ui); white-space: nowrap; pointer-events: none;
}
body.print-view .ov-watermark { display: none; }

/* Page tab section */
.wm-section .wm-list { display: flex; flex-direction: column; gap: 6px; }
.wm-section .wm-empty { margin: 0; }
.wm-section .wm-actions { margin-top: 2px; }
.wm-section .wm-actions .btn { white-space: nowrap; }
.wm-section .wm-presets { height: 26px; padding: 0 4px; border: 1px solid var(--border); border-radius: 4px; background: var(--panel); font-size: 12px; max-width: 100%; }
.wm-card { margin-bottom: 0; }
.wm-card .wm-head { cursor: pointer; margin-bottom: 0; gap: 6px; }
.wm-card.open .wm-head { margin-bottom: 6px; }
.wm-card .wm-head:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 3px; }
.wm-card .wm-title { min-width: 0; flex: 1; }
.wm-card .wm-title strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.wm-card .wm-kind { display: inline-flex; color: var(--muted); flex: none; }
.wm-card .wm-kind svg { width: 14px; height: 14px; }
.wm-card .wm-meta { font-size: 10.5px; color: var(--muted); white-space: nowrap; flex: none; }
.wm-card .wm-body { display: flex; flex-direction: column; gap: 6px; }
.wm-card .wm-body .field > span { white-space: normal; }
.wm-card .wm-seg { margin: 0; }
.wm-card .wm-seg .tp-tab { height: 24px; padding: 0 6px; font-size: 11.5px; }
.wm-card textarea { min-height: 44px; }
.wm-card .wm-textstyle .wm-tgl { grid-column: auto; margin-top: 2px; }
/* image source: thumbnail + file / URL / data field */
.wm-source-row { display: flex; gap: 8px; align-items: flex-start; }
.wm-source-fields { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 6px; }
.wm-thumb { flex: none; width: 48px; height: 48px; object-fit: contain; border: 1px solid var(--border); border-radius: 4px; background: repeating-conic-gradient(rgba(0, 0, 0, 0.06) 0 25%, transparent 0 50%) 0 0 / 12px 12px; }
.wm-thumb.broken { opacity: 0.3; }
.wm-thumb-empty { display: inline-flex; align-items: center; justify-content: center; color: var(--muted); }
.wm-thumb-empty svg { width: 20px; height: 20px; }
/* position: 9-grid picker + x / y */
.wm-posrow { display: flex; gap: 10px; align-items: flex-start; }
.wm-posgrid { flex: none; display: grid; grid-template-columns: repeat(3, 18px); gap: 3px; padding: 4px; border: 1px solid var(--border); border-radius: 4px; background: var(--panel); }
.wm-pos { width: 18px; height: 18px; padding: 0; border: 1px solid var(--border); border-radius: 3px; background: var(--panel-2); cursor: pointer; display: inline-flex; align-items: center; justify-content: center; }
.wm-pos i { width: 6px; height: 6px; border-radius: 50%; background: var(--border-strong); }
.wm-pos:hover { border-color: var(--accent); }
.wm-pos.active { border-color: var(--accent); background: var(--accent-soft); }
.wm-pos.active i { background: var(--accent); }
.wm-xy { flex: 1; min-width: 0; }
/* opacity slider with a live value */
.wm-opacity input[type="range"] { width: 100%; margin: 6px 0 0; accent-color: var(--accent); }
.wm-opacity output { color: var(--text); font-variant-numeric: tabular-nums; }
/* Excel */
.wm-excel { padding-top: 4px; border-top: 1px dashed var(--border); }
.wm-excel .tg-sub { display: block; margin: 0 0 4px; }
.wm-excel .side-hint { margin: 0; }
.wm-excel-ok { display: inline-flex; align-items: center; gap: 4px; font-size: 11.5px; color: #15803d; }
.wm-excel-ok svg { width: 13px; height: 13px; }
/* stale bake: the settings changed since "Tạo ảnh nền cho Excel" (watermarkPanel.js excelState) */
.wm-excel .wm-excel-stale { flex-basis: 100%; font-size: 11.5px; line-height: 1.4; }
.wm-excel[data-excel="stale"] .tg-sub { color: #92400e; }
.wm-pages-list { grid-column: 1 / -1; }

/* ------------------------------------------------------------------ */
/* [repeat] Lặp theo mảng (SPEC-LIBRARY §4): canvas badge + item      */
/* switcher (canvas.js), page-break line, Page-tab section            */
/* (pagePanel.js), Data-tab "(mục hiện tại)" markers (dataPanel.js)   */
/* ------------------------------------------------------------------ */
.ov-repeat { position: absolute; inset: 0; pointer-events: none; }
.repeat-badge { position: absolute; transform: translate(-100%, -100%); display: inline-flex; align-items: center; gap: 2px; margin-top: -2px; font: 600 10px/16px var(--font-ui); color: #fff; background: #0e7490; padding: 1px 4px 1px 6px; border-radius: 4px 4px 0 0; white-space: nowrap; pointer-events: auto; box-shadow: 0 1px 2px rgba(0, 0, 0, .2); }
.repeat-badge .repeat-label b { font-weight: 700; }
.repeat-badge .repeat-nav { appearance: none; border: 0; background: rgba(255, 255, 255, .18); color: #fff; font: 600 9px/14px var(--font-ui); width: 16px; height: 16px; border-radius: 3px; cursor: pointer; padding: 0; }
.repeat-badge .repeat-nav:hover:not(:disabled) { background: rgba(255, 255, 255, .35); }
.repeat-badge .repeat-nav:disabled { opacity: .35; cursor: default; }
.repeat-break { position: absolute; height: 0; border-top: 2px dashed #0e7490; opacity: .75; pointer-events: none; }
.repeat-break > span { position: absolute; right: 0; top: 2px; font: 600 9px/12px var(--font-ui); color: #0e7490; background: rgba(255, 255, 255, .85); padding: 0 4px; border-radius: 2px; white-space: nowrap; }
.repeat-break.flow { border-top-style: dotted; }
body.print-view .ov-repeat { display: none; }
.page-repeat .prop-section-body > .side-hint { grid-column: 1 / -1; }
.page-repeat .page-repeat-count { margin: 0; }
.page-repeat .page-repeat-count[data-count=""] { color: var(--danger, #b91c1c); }
.tree-item-mark { margin-left: 4px; font-size: 10px; color: #0e7490; font-weight: 600; white-space: nowrap; }
.tree-row[data-item-relative] .tree-key { color: #0e7490; }
/* [repeat] groupBy: the synthesised item { value, key, count, first, Rows } listed under the array (dataPanel.js) */
.tree-synth > .tree-node > .tree-row .tree-meta { font-style: italic; }

/* ================================================================== */
/* [pagePreview] Xem theo trang (pagePreview.js, SPEC-PHASE8 §1):      */
/* laid-out pages stacked on the canvas, page badges, hover / selected */
/* outlines, in-place text edit, status-bar pager, banner, drawer      */
/* ================================================================== */

/* Page view: the design paper / grid, the overlays and the design watermark layers are off;
   the pages carry their own paper */
body.pages-view .page-bg, body.pages-view .overlay, body.pages-view .page > .wm-layer { display: none; }
body.pages-view #status-pages { display: none; }
body.pages-view .viewport { cursor: default; }
body.pages-view .viewport.pan-ready { cursor: grab; }
body.pages-view .viewport.panning { cursor: grabbing; }
.pv-page { position: absolute; left: 0; overflow: hidden; background: #fff; box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1), 0 6px 20px rgba(0, 0, 0, 0.14); }
.pv-page .pv-scale { position: absolute; left: 0; top: 0; }
.pv-page .pv-items { position: absolute; inset: 0; }
.pv-page.pv-page-loading { display: flex; align-items: center; justify-content: center; color: var(--muted); font: 14px var(--font-ui); }
/* page number badge: drawn inside the scaled page but kept at screen size (--pv-inv = 1 / zoom) */
.pv-page-badge {
  position: absolute; right: 0; top: 0; transform-origin: 100% 0; transform: scale(var(--pv-inv, 1));
  font: 600 11px/18px var(--font-ui); color: #fff; background: rgba(15, 23, 42, 0.62); padding: 0 8px; border-radius: 0 0 0 6px;
  white-space: nowrap; pointer-events: none; z-index: 2;
}
body.print-view .pv-page-badge { background: rgba(15, 23, 42, 0.35); }
/* Items: same box model as the design elements, no move cursor; hover outline, selection outline */
.pv-item { position: absolute; box-sizing: border-box; overflow: hidden; cursor: pointer; user-select: none; font-synthesis: none; }
.pv-item:hover { outline: 1px dashed var(--accent); outline-offset: 0; }
.pv-item.pv-selected { outline: 1px solid var(--accent); box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.7) inset; }
.pv-text { display: flex; flex-direction: column; }
.pv-text-inner { width: 100%; word-wrap: break-word; overflow-wrap: break-word; min-height: 1em; }
.pv-text-inner.editing { outline: none; user-select: text; cursor: text; caret-color: var(--accent); background: rgba(37, 99, 235, 0.06); }
.pv-item.pv-editing { overflow: visible; outline: 1px solid var(--accent); }
.pv-image img { display: block; width: 100%; height: 100%; pointer-events: none; }
.pv-image.img-broken img { opacity: 0.2; }
.pv-checkbox { display: flex; align-items: center; gap: 6px; white-space: nowrap; }
.pv-line { overflow: visible; }
.pv-line svg, .pv-qrcode svg, .pv-barcode svg { display: block; }
.pv-table { overflow: visible; }
.pv-table table { border-collapse: collapse; table-layout: fixed; }
.pv-table td { overflow: hidden; word-wrap: break-word; white-space: pre-wrap; }
.pv-subtable table { width: 100%; }
.pv-continued {
  position: absolute; left: 0; bottom: 100%; transform-origin: 0 100%; transform: scale(var(--pv-inv, 1));
  font: 10px/14px var(--font-ui); color: #fff; background: var(--warning); padding: 0 5px; border-radius: 3px 3px 0 0; white-space: nowrap; pointer-events: none;
}
body.print-view .pv-continued { display: none; }
.pv-barcode-invalid { background: repeating-linear-gradient(45deg, rgba(220, 38, 38, 0.06) 0 6px, transparent 6px 12px); }
.pv-block { outline: 1px dotted var(--border-strong); }
.pv-unknown { border: 1px dashed var(--danger); color: var(--danger); font-size: 10px; }
.pv-unknown .pv-unknown-size { margin-left: 4px; color: var(--muted); }

/* Banner over the canvas: approximate fallback / row cap / loading */
.pv-banner {
  position: absolute; top: 30px; left: 50%; transform: translateX(-50%); z-index: 6; max-width: calc(100% - 60px);
  padding: 4px 12px; border-radius: 6px; font-size: 12px; line-height: 1.4; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
  background: var(--panel); color: var(--text); border: 1px solid var(--border); pointer-events: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.pv-banner[data-kind="warn"] { background: var(--warning-soft); color: #92400e; border-color: rgba(217, 119, 6, 0.4); }
.pv-banner[data-kind="info"] { background: var(--accent-soft); color: var(--accent-2); border-color: rgba(37, 99, 235, 0.3); }

/* Status-bar pager: ◀ 3/8 ▶ · Tới trang [ ] · i · + N trang nữa · đang cập nhật */
.status-pager { display: inline-flex; align-items: center; gap: 4px; }
.status-pager .pv-nav {
  appearance: none; border: 1px solid var(--border); background: var(--panel); color: var(--text); border-radius: 4px;
  font: 600 10px/16px var(--font-ui); min-width: 20px; height: 18px; padding: 0 4px; cursor: pointer;
}
.status-pager .pv-nav:hover:not(:disabled) { background: var(--panel-2); border-color: var(--accent); }
.status-pager .pv-nav:disabled { opacity: 0.4; cursor: default; }
.status-pager .pv-nav.pv-info { border-radius: 50%; width: 18px; min-width: 18px; padding: 0; font-family: Georgia, serif; font-style: italic; }
.status-pager .pv-pos { font-variant-numeric: tabular-nums; padding: 0 2px; }
.status-pager .pv-goto { display: inline-flex; align-items: center; gap: 4px; margin-left: 6px; }
.status-pager .pv-goto input { width: 44px; height: 18px; padding: 0 4px; font: inherit; font-size: 11px; border: 1px solid var(--border); border-radius: 4px; background: var(--panel); color: var(--text); }
.status-pager .pv-goto input:focus { outline: none; border-color: var(--accent); }
.status-pager .pv-more { margin-left: 6px; color: #92400e; font-weight: 600; white-space: nowrap; }
.status-pager .pv-state { margin-left: 6px; color: var(--accent-2); white-space: nowrap; }

/* "Kiểm tra phân trang" drawer: reuses the check-drawer frame; one row per page */
.pages-drawer .pv-drawer-source.error { color: #92400e; }
.pages-drawer .pv-sum { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.pages-drawer .pv-sum th, .pages-drawer .pv-sum td { padding: 4px 8px; border-bottom: 1px solid var(--border); text-align: left; vertical-align: top; font-variant-numeric: tabular-nums; }
.pages-drawer .pv-sum thead th { position: sticky; top: 0; background: var(--panel-2); font-weight: 600; z-index: 1; white-space: nowrap; }
.pages-drawer .pv-sum-row { cursor: pointer; }
.pages-drawer .pv-sum-row:hover, .pages-drawer .pv-sum-row:focus-visible { background: var(--panel-2); outline: none; }
.pages-drawer .pv-sum-row.current > td { background: var(--accent-soft); }
.pages-drawer .pv-sum-row.has-warn .pv-warn-count { display: inline-block; min-width: 16px; padding: 0 5px; border-radius: 8px; background: var(--warning); color: #fff; font-size: 10.5px; font-weight: 600; line-height: 16px; text-align: center; }
.pages-drawer .pv-sum-cont { color: var(--warning); font-weight: 600; }
.pages-drawer .pv-sum-total td { background: var(--panel-2); font-weight: 600; }
.pages-drawer .pv-warns { list-style: none; margin: 4px 0 0; padding: 0; }
.pages-drawer .pv-warn { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; padding: 2px 0; font-size: 12px; }
.pages-drawer .pv-warn.has-el { cursor: pointer; }
.pages-drawer .pv-warn.has-el:hover { color: var(--accent); }
.pages-drawer .pv-warn-code { color: var(--muted); font-size: 11px; }
.pages-drawer .pv-warn-msg { flex: 1; min-width: 200px; }
.pages-drawer .pv-hint .pv-warn-code { color: var(--accent-2); }
/* Xem menu rows: the check mark of the toggle (like groupNames:toggle) */
.menu button[data-action="pages:toggle"][aria-pressed="true"]::after { content: "✓"; margin-left: auto; font-size: 11px; }

/* ------------------------------------------------------------------ */
/* [barcode] Mã vạch + lưới nhãn (SPEC-PHASE8 §5): canvas element     */
/* (canvas.js renderBarcode), grid cells of repeat.grid (ov-repeat),  */
/* Page-tab grid fields (pagePanel.js)                                */
/* ------------------------------------------------------------------ */
.el-barcode { overflow: hidden; box-sizing: border-box; }
.el-barcode > svg { display: block; position: absolute; left: 0; top: 0; }
.el-barcode.el-barcode-invalid { outline: 1px dashed #b91c1c; outline-offset: -1px; }
.el-barcode.el-barcode-invalid::after { content: '!'; position: absolute; right: 2px; top: 0; font: 700 10px/12px var(--font-ui); color: #b91c1c; }
.repeat-cell { position: absolute; box-sizing: border-box; border: 1px dashed rgba(14, 116, 144, .55); pointer-events: none; }
.repeat-cell.first { border-style: solid; border-color: #0e7490; }
.repeat-cell > span { position: absolute; right: 2px; bottom: 1px; font: 600 9px/11px var(--font-ui); color: #0e7490; opacity: .7; }
.repeat-cell.first > span { opacity: 1; }
.page-repeat .page-grid-fields { grid-column: 1 / -1; display: grid; grid-template-columns: 1fr 1fr; gap: 6px 8px; }

/* ================================================================== */
/* History — "Lịch sử phiên bản" (historyDialog.js, SPEC-PHASE8 §2):   */
/* read-only banner + dimming, version table, compare panel           */
/* ================================================================== */

/* Banner above the workspace while a snapshot is on view */
.hist-banner { border-top: 1px solid #93c5fd; gap: 8px; }
.hist-banner .banner-text strong { font-weight: 600; }
.hist-banner .btn { flex: none; }

/* Read-only view: the editing surfaces are dimmed and inert (state.readOnly); the canvas keeps
   pointer events so a click still selects (interactions.js gate) and the compare panel works */
body.rd-readonly #toolbox, body.rd-readonly #layers, body.rd-readonly #panel-props, body.rd-readonly #panel-page,
body.rd-readonly #panel-data, body.rd-readonly #panel-json, body.rd-readonly #fmtbar,
body.rd-readonly #toolbar .tb-group[data-group="edit"],
body.rd-readonly #toolbar .tb-group[data-group="insert"], body.rd-readonly #toolbar .tb-group[data-group="page"] {
  pointer-events: none; opacity: 0.55;
}
/* the file group stays clickable so the "…" menu (Lịch sử phiên bản…, Xuất JSON) can browse to
   another version; the editing entries are inert (main.js READONLY_BLOCKED_ACTIONS guards them too) */
body.rd-readonly #toolbar .tb-group[data-group="file"] > .tb-btn[data-action],
body.rd-readonly .menu[data-menu-for="file"] [data-action="import"], body.rd-readonly .menu[data-menu-for="file"] [data-action="importXlsx"],
body.rd-readonly .menu[data-menu-for="file"] [data-action="importPdf"], body.rd-readonly .menu[data-menu-for="file"] [data-action="parameterize"],
body.rd-readonly .menu[data-menu-for="file"] [data-action="delete"], body.rd-readonly .menu[data-menu-for="file"] [data-action="history:saveNote"] {
  pointer-events: none; opacity: 0.55;
}
.hist-banner .hist-nav { display: inline-flex; align-items: center; gap: 2px; flex: none; }
.hist-banner .hist-nav .btn { min-width: 26px; padding-inline: 6px; }
.hist-banner .hist-nav .hist-nav-v { font-weight: 600; font-variant-numeric: tabular-nums; padding: 0 4px; }
body.rd-readonly .canvas-area { background: repeating-linear-gradient(135deg, var(--bg) 0 14px, #e9ebef 14px 16px); }
body.rd-readonly .sel-handle { display: none; }

/* Version dialog */
.dlg.dlg-history { width: 900px; }
.dlg-history .dlg-body { max-height: 70vh; }
.hist-dlg .hist-summary { margin: 0 0 8px; font-size: 12px; }
.hist-table-wrap { overflow: auto; border: 1px solid var(--border); border-radius: var(--radius); }
.hist-table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.hist-table th, .hist-table td { padding: 6px 8px; border-bottom: 1px solid var(--border); text-align: left; vertical-align: middle; white-space: nowrap; }
.hist-table th { background: var(--panel-2); font-weight: 600; font-size: 11.5px; color: var(--text-2); position: sticky; top: 0; z-index: 1; }
.hist-table tbody tr:hover { background: var(--panel-2); }
.hist-table tr.is-current { background: var(--accent-soft); }
.hist-table tr.is-viewing .hist-v { color: var(--accent-2); }
.hist-table .hist-v { font-weight: 600; font-variant-numeric: tabular-nums; }
.hist-table .hist-num { text-align: right; font-variant-numeric: tabular-nums; }
.hist-table .hist-note { max-width: 240px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hist-table .hist-by { max-width: 120px; overflow: hidden; text-overflow: ellipsis; }
.hist-table .hist-actions { text-align: right; }
.hist-table .hist-actions .btn { margin-left: 2px; }
.hist-table .hist-del { margin-left: 4px; color: var(--muted); }
.hist-table .hist-del:hover { color: var(--danger); background: var(--danger-soft); }
.hist-badge { display: inline-block; margin-left: 4px; padding: 0 6px; border-radius: 999px; font-size: 10.5px; font-weight: 500; color: var(--accent-2); background: #fff; border: 1px solid #93c5fd; vertical-align: 1px; }
.hist-reason-restore { color: #0e7490; }
.hist-reason-delete { color: var(--danger); }
.hist-reason-import { color: #7c3aed; }
.hist-empty { padding: 12px 0; }
@media (max-width: 1000px) {
  .hist-table .hist-by, .hist-table th:nth-child(3) { display: none; }
}

/* Save with note dialog */
.dlg-history-note .hist-note-field { gap: 4px; }
.dlg-history-note textarea.hist-note-input { height: auto; min-height: 64px; padding: 6px 8px; resize: vertical; line-height: 1.4; }
.dlg-history-note .hist-note-count { font-size: 11px; text-align: right; }

/* Compare panel over the right side of the canvas area */
.hist-compare {
  position: absolute; top: 0; right: 0; bottom: 0; width: 340px; max-width: 80%; z-index: 6;
  display: flex; flex-direction: column; background: var(--panel); border-left: 1px solid var(--border);
  box-shadow: -6px 0 16px rgba(0, 0, 0, 0.08); font-size: 12.5px;
}
.hist-compare[hidden] { display: none; }
.hist-cmp-head { display: flex; align-items: center; gap: 8px; padding: 8px 10px; border-bottom: 1px solid var(--border); flex: none; }
.hist-cmp-head h3 { margin: 0; font-size: 13px; flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hist-cmp-sub { margin: 6px 10px 0; font-size: 11.5px; color: var(--muted); }
.hist-cmp-summary { margin: 4px 10px 6px; font-weight: 600; }
.hist-cmp-status { margin: 10px; color: var(--muted); }
.hist-cmp-body { flex: 1; min-height: 0; overflow: auto; padding: 0 6px 6px; }
.hist-cmp-none { margin: 10px 4px; color: var(--success); }
.hist-cmp-hint { margin: 0; padding: 6px 10px; border-top: 1px solid var(--border); color: var(--muted); font-size: 11.5px; flex: none; }
.hist-cmp-section { margin: 4px 0; border: 1px solid var(--border); border-radius: var(--radius); }
.hist-cmp-section > summary { padding: 5px 8px; cursor: pointer; font-weight: 600; background: var(--panel-2); border-radius: var(--radius); list-style: none; }
.hist-cmp-section > summary::-webkit-details-marker { display: none; }
.hist-cmp-section > summary::before { content: '▸'; display: inline-block; width: 12px; color: var(--muted); }
.hist-cmp-section[open] > summary { border-radius: var(--radius) var(--radius) 0 0; border-bottom: 1px solid var(--border); }
.hist-cmp-section[open] > summary::before { content: '▾'; }
.hist-el-list { list-style: none; margin: 0; padding: 4px; }
.hist-el-list > li { padding: 2px 0; }
.hist-el {
  display: flex; align-items: center; gap: 6px; width: 100%; padding: 3px 6px; border: 0; border-radius: 4px;
  background: transparent; color: var(--text); text-align: left; cursor: pointer; font: inherit;
}
.hist-el:hover, .hist-el:focus-visible { background: var(--accent-soft); outline: none; }
.hist-el-mark { flex: none; width: 8px; height: 8px; border-radius: 2px; background: var(--muted); }
.hist-el-added .hist-el-mark { background: var(--success); }
.hist-el-removed .hist-el-mark { background: var(--danger); }
.hist-el-changed .hist-el-mark { background: var(--warning); }
.hist-el-moved .hist-el-mark { background: var(--accent); }
.hist-el-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hist-el-type { flex: none; font-size: 10.5px; color: var(--muted); }
.hist-changes { list-style: none; margin: 0 0 4px 20px; padding: 0 0 0 6px; border-left: 2px solid var(--border); font-size: 11.5px; color: var(--text-2); }
.hist-changes > li { padding: 1px 0; word-break: break-word; }
.hist-move { display: block; margin: 0 0 4px 20px; font-size: 11.5px; color: var(--text-2); }
body.print-view .hist-compare { top: 0; }
/* Row-1 toggle only from 1500 px (below, row 1 is full: the Xem menu row + Ctrl+Alt+P serve); when the
   shell collapses the Xem group into its menu the moved row-1 button replaces the menu's own row */
@media (max-width: 1499px) { #toolbar .tb-view-items > [data-action="pages:toggle"] { display: none; } }
body.tb-collapse-view #view-menu > [data-action="pages:toggle"] { display: none; }

/* ---------------------------------------------------------------------- */
/* importDialog.js — "Nhập từ PDF" page picker (SPEC-PHASE8 §4)            */
/* ---------------------------------------------------------------------- */
.dlg-import-pdf .dlg-body { max-height: min(70vh, 640px); overflow: auto; }
.pdf-pages { display: flex; flex-direction: column; gap: 6px; }
.pdf-pages .field { flex-direction: row; align-items: center; gap: 8px; }
.pdf-page-input { width: 72px; }
.pdf-thumbs { display: flex; flex-wrap: wrap; gap: 8px; padding: 6px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--bg-2, #f6f7f9); min-height: 48px; align-items: flex-start; }
.pdf-thumbs-status { font-size: 12px; padding: 4px; }
.pdf-thumb { display: flex; flex-direction: column; align-items: center; gap: 3px; padding: 4px; border: 2px solid transparent; border-radius: 6px; background: #fff; cursor: pointer; font: inherit; color: var(--text); }
.pdf-thumb canvas { display: block; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25); background: #fff; }
.pdf-thumb-label { font-size: 11px; color: var(--muted); }
.pdf-thumb:hover, .pdf-thumb:focus-visible { border-color: var(--accent-soft, #c7d2fe); outline: none; }
.pdf-thumb.selected { border-color: var(--accent, #2563eb); }
.pdf-thumb.selected .pdf-thumb-label { color: var(--accent, #2563eb); font-weight: 600; }
.pdf-thumb:disabled { opacity: 0.6; cursor: default; }
.import-pdf-notext { margin: 0; font-weight: 600; }

/* ---------------------------------------------------------------------- */
/* [nested] subreports.js — sub-reports, nested tables, group detail bands */
/* (SPEC-PHASE8 §3.4): canvas previews, nested editing bar, column crumbs  */
/* ---------------------------------------------------------------------- */
.el-subreport { position: absolute; box-sizing: border-box; border: 1px dashed var(--accent, #2563eb); border-radius: 2px; background: rgba(37, 99, 235, 0.03); overflow: hidden; }
.el-subreport .sr-caption { position: absolute; top: 0; right: 0; z-index: 2; padding: 1px 6px; font: 600 9px/1.4 system-ui, sans-serif; color: #fff; background: var(--accent, #2563eb); border-bottom-left-radius: 4px; opacity: 0.85; pointer-events: none; white-space: nowrap; max-width: 100%; overflow: hidden; text-overflow: ellipsis; }
.el-subreport .sr-body { position: absolute; inset: 0; pointer-events: none; }
.el-subreport .sr-item { position: absolute; height: 100%; }
.el-subreport .sr-item .el { pointer-events: none; }
.el-subreport .sr-empty, .sr-band .sr-empty { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; padding: 4px 12px; text-align: center; font: italic 11px/1.4 system-ui, sans-serif; color: var(--muted, #6b7280); }
.el-subreport .sr-empty.warn, .sr-band .sr-empty.warn { color: var(--danger, #b91c1c); }
.el-subreport.selected, .el.selected.el-subreport { border-style: solid; }
/* nested table inside a cell (first rows) */
.tg-subcell { padding: 0 !important; }
.tg-subcell .sr-subtable { width: 100%; border-collapse: collapse; table-layout: fixed; margin: 0; }
.tg-subcell .sr-subtable th, .tg-subcell .sr-subtable td { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; line-height: 1.25; }
.tg-subcell .sr-subtable td.ph.warn { color: var(--danger, #b91c1c); font-style: italic; }
.tg-subcell .sr-subtable td.sr-more { color: var(--muted, #6b7280); font-style: italic; }
/* group detail band row of the table preview */
.tg-detail .tg-detail-cell { padding: 0 !important; vertical-align: top; }
.sr-band { position: relative; overflow: hidden; border-top: 1px dashed rgba(37, 99, 235, 0.45); border-bottom: 1px dashed rgba(37, 99, 235, 0.45); background: rgba(37, 99, 235, 0.03); }
.sr-band .el { pointer-events: none; }
.sr-band .sr-band-tag { position: absolute; top: 0; right: 0; z-index: 2; padding: 0 5px; font: 600 8px/1.5 system-ui, sans-serif; color: var(--accent, #2563eb); background: rgba(255, 255, 255, 0.85); border-bottom-left-radius: 3px; pointer-events: none; }
/* nested editing bar above the canvas */
/* the canvas area is a rulers grid: the bar overlays its top edge and the grid is pushed down by the same height */
.nested-bar { position: absolute; top: 0; left: 0; right: 0; height: 32px; box-sizing: border-box; z-index: 30; display: flex; align-items: center; gap: 10px; padding: 0 12px; background: var(--accent-soft, #eef2ff); border-bottom: 1px solid var(--accent, #2563eb); font-size: 12.5px; }
body.rd-nested .canvas-area { padding-top: 32px; }
.nested-bar .nested-crumbs { display: flex; align-items: center; gap: 6px; min-width: 0; }
.nested-bar .crumb { border: 0; background: transparent; padding: 2px 6px; border-radius: 4px; color: var(--accent, #2563eb); font: inherit; font-weight: 600; cursor: pointer; }
.nested-bar .crumb:hover, .nested-bar .crumb:focus-visible { background: rgba(37, 99, 235, 0.12); outline: none; }
.nested-bar .crumb.current { color: var(--text); cursor: default; }
.nested-bar .crumb.current:hover { background: transparent; }
.nested-bar .sep { color: var(--muted, #6b7280); }
.nested-bar .nested-hint { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nested-bar .nested-actions { display: flex; gap: 6px; flex: none; }
body.rd-nested #canvas-area .page { outline: 2px dashed var(--accent, #2563eb); outline-offset: 2px; }
/* nested: the page / repeat / name of a sub-template come from the parent — the Page tab and the
   toolbar page-size select are inert (exitNested only writes elements / formats / defaultStyle /
   groups back), a banner at the top of the tab explains it */
body.rd-nested #panel-page > :not(.nested-page-lock) { pointer-events: none; opacity: 0.45; }
body.rd-nested #toolbar .tb-group[data-group="page"] { pointer-events: none; opacity: 0.55; }
.nested-page-lock { margin: 0 0 10px; border-radius: var(--radius, 6px); border: 1px solid #93c5fd; font-size: 12px; }
.nested-page-lock .btn { flex: none; }
/* properties: sub-report section, nested column crumbs, detail band block */
.sr-source, .sr-detail-mode {
  /* segmented controls inside the 320 px panel: fill the row and wrap instead of overflowing it */
  display: flex; flex-wrap: wrap; width: 100%; box-sizing: border-box; margin-left: 0; margin-right: 0;
}
.sr-source .tp-tab, .sr-detail-mode .tp-tab { flex: 1 1 auto; min-width: 0; padding: 4px 6px; font-size: 12px; white-space: nowrap; }
.sr-param { display: grid; grid-template-columns: 1fr 1.4fr auto; gap: 4px; align-items: center; margin-bottom: 4px; }
.sr-param input { min-width: 0; width: 100%; }
.sr-param-list:empty + .row { margin-top: 0; }
.tp-crumbs { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; padding: 4px 6px; margin: 0 0 6px; border: 1px solid var(--accent-soft, #c7d2fe); border-radius: var(--radius, 6px); background: rgba(37, 99, 235, 0.06); font-size: 12px; }
.tp-crumbs .crumb { border: 0; background: transparent; padding: 1px 4px; border-radius: 4px; color: var(--accent, #2563eb); font: inherit; font-weight: 600; cursor: pointer; }
.tp-crumbs .crumb.current { color: var(--text); cursor: default; }
.tp-crumbs .sep { color: var(--muted, #6b7280); }
.tp-strip[data-nested="1"] { border-left: 3px solid var(--accent, #2563eb); }
.sr-subtable-section .sr-sub-actions { margin: 4px 0 6px; }
.sr-detail .sr-detail-fields { margin-top: 6px; }

/* ------------------------------------------------------------------ */
/* [pagePreview] always-visible "Xem theo trang" button (next to Xem trước) keeps its label */
/* ------------------------------------------------------------------ */
/* label kept from 1500 px up (below that the toolbar strips labels to stay on one row — the icon + tooltip remain) */
@media (min-width: 1500px) { #toolbar .tb-pages-main .tb-lbl { display: inline !important; } }
@media (max-width: 1499px) { #toolbar .tb-pages-main .tb-lbl { display: none !important; } }   /* icon + tooltip only, so row 1 keeps every other label at 1366 px */
#toolbar .tb-pages-main[aria-pressed="true"] { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); }

/* ------------------------------------------------------------------ */
/* [layers] group node + row action buttons: full-size icons, red lock when locked */
/* ------------------------------------------------------------------ */
#layers .layer-node .layer-actions { gap: 1px; }
#layers .layer-node .layer-actions .icon-btn, #layers .layer .layer-actions .icon-btn {
  width: 24px; height: 26px; padding: 0; border-radius: 4px; flex: none;   /* no `display` here: the row/node rules decide which buttons show */
  align-items: center; justify-content: center;
}
#layers .layer-node .layer-actions .icon-btn svg, #layers .layer .layer-actions .icon-btn svg { width: 16px; height: 16px; min-width: 16px; flex: none; }
#layers .layer-node.locked .layer-actions .icon-btn[data-act="lock"], #layers .layer.locked .layer-actions .icon-btn[data-act="lock"] {
  color: var(--danger); background: var(--danger-soft);
}
#layers .layer-node.locked .layer-actions .icon-btn[data-act="lock"]:hover, #layers .layer.locked .layer-actions .icon-btn[data-act="lock"]:hover { background: #fecaca; }

/* ================================================================== */
/* [fieldPicker] "Chọn trường hiển thị" dialog (fieldPicker.js,        */
/* SPEC-TABLE-FIELDS-UI §1) + Data-tab tree search / "Hiện tất cả" (§3) */
/* ================================================================== */
.dlg.dlg-fieldpicker { width: 900px; max-width: calc(100vw - 32px); }
.dlg-fieldpicker .dlg-body { max-height: 72vh; padding: 10px 12px; }
.fpk { display: grid; grid-template-columns: minmax(0, 3fr) minmax(280px, 2fr); gap: 12px; min-height: 360px; }
.fpk-left, .fpk-right { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.fpk-tools { display: flex; align-items: center; gap: 8px; }
.fpk-search { flex: 1; min-width: 0; height: 28px; padding: 0 8px; border: 1px solid var(--border); border-radius: var(--radius); font: inherit; font-size: 12.5px; background: var(--panel); color: var(--text); }
.fpk-search:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-soft); }
.fpk-count { flex: none; font-weight: 600; font-variant-numeric: tabular-nums; font-size: 12px; color: var(--accent); padding: 2px 8px; border-radius: 999px; background: var(--accent-soft); }
.fpk-bulk { display: flex; flex-wrap: wrap; gap: 4px; }
.fpk-list { flex: 1; min-height: 240px; max-height: 52vh; overflow: auto; border: 1px solid var(--border); border-radius: var(--radius); background: var(--panel); }
.fpk-row { display: grid; grid-template-columns: 22px minmax(90px, 1.2fr) 44px minmax(60px, 1fr) minmax(90px, 1fr); align-items: center; gap: 6px; padding: 3px 6px; border-bottom: 1px solid var(--border); font-size: 12px; cursor: pointer; }
.fpk-row:last-of-type { border-bottom: 0; }
.fpk-row:hover { background: var(--accent-soft); }
.fpk-row.checked { background: rgba(37, 99, 235, 0.07); }
.fpk-row.disabled { opacity: 0.55; cursor: default; }
.fpk-row.disabled:hover { background: transparent; }
.fpk-row.used .fpk-path::after { content: ' ●'; color: var(--accent); font-size: 8px; vertical-align: middle; }
.fpk-check { margin: 0; }
.fpk-path { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 11.5px; }
.fpk-kind, .fpk-okind { font-size: 10px; line-height: 1; padding: 3px 5px; border-radius: 999px; text-align: center; white-space: nowrap; background: var(--panel-2); color: var(--muted); border: 1px solid var(--border); }
.fpk-kind-number { color: #1d4ed8; background: #dbeafe; border-color: #bfdbfe; }
.fpk-kind-date { color: #7c2d12; background: #ffedd5; border-color: #fed7aa; }
.fpk-kind-bool { color: #166534; background: #dcfce7; border-color: #bbf7d0; }
.fpk-kind-array, .fpk-kind-object { color: #6b21a8; background: #f3e8ff; border-color: #e9d5ff; }
.fpk-sample { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--muted); font-size: 11.5px; }
.fpk-row.missing .fpk-sample.fpk-missing { color: #b45309; font-style: italic; }
.fpk-row.missing .fpk-path { color: #b45309; }
.fpk-header { height: 24px; min-width: 0; padding: 0 6px; border: 1px solid var(--border); border-radius: 4px; font: inherit; font-size: 12px; background: var(--panel); color: var(--text); }
.fpk-header:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-soft); }
.fpk-empty { padding: 12px; text-align: center; }
.fpk-kbd { margin: 0; font-size: 11px; }
.fpk-right-head { display: flex; flex-direction: column; gap: 2px; }
.fpk-right-head .side-hint { margin: 0; font-size: 11px; }
.fpk-order { list-style: none; margin: 0; padding: 0; flex: 1; min-height: 240px; max-height: 46vh; overflow: auto; border: 1px solid var(--border); border-radius: var(--radius); background: var(--panel); counter-reset: fpcol; }
.fpk-order-empty { padding: 12px; }
.fpk-ocol { display: grid; grid-template-columns: 14px minmax(0, 1.2fr) minmax(0, 1fr) auto auto auto; align-items: center; gap: 6px; padding: 3px 6px; border-bottom: 1px solid var(--border); font-size: 12px; background: var(--panel); counter-increment: fpcol; }
.fpk-ocol:last-child { border-bottom: 0; }
.fpk-ocol.dragging { opacity: 0.4; }
.fpk-ocol.drop-before { box-shadow: inset 0 2px 0 var(--accent); }
.fpk-ocol.drop-after { box-shadow: inset 0 -2px 0 var(--accent); }
.fpk-grip { color: var(--muted); cursor: grab; user-select: none; }
.fpk-ohead { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fpk-ohead::before { content: counter(fpcol) '. '; font-weight: 400; color: var(--muted); }
.fpk-opath { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--muted); font-size: 11px; }
.fpk-owidth { font-variant-numeric: tabular-nums; color: var(--muted); font-size: 11px; white-space: nowrap; }
.fpk-obtns { display: inline-flex; gap: 1px; }
.fpk-obtns .icon-btn { width: 22px; height: 22px; font-size: 10px; }
.fpk-opts { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; font-size: 12px; }
.fpk-opt { display: inline-flex; align-items: center; gap: 4px; cursor: pointer; }
.fpk-total { margin-left: auto; color: var(--muted); font-size: 11.5px; font-variant-numeric: tabular-nums; }
@media (max-width: 900px) { .fpk { grid-template-columns: 1fr; } }

/* Data tab (§3): search box above the field tree, "Hiện tất cả (n)" row */
#panel-data .tree-search { width: 100%; box-sizing: border-box; height: 26px; margin: 0 0 6px; padding: 0 8px; border: 1px solid var(--border); border-radius: var(--radius); font: inherit; font-size: 12px; background: var(--panel); color: var(--text); }
#panel-data .tree-search:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-soft); }
#panel-data .tree-more { list-style: none; padding: 2px 0 2px 18px; }
#panel-data .tree-nomatch { padding: 6px 0; }

/* ------------------------------------------------------------------ */
/* [tableProps] sticky sub-tab header "Thuộc tính bảng / Thuộc tính cột" */
/* ------------------------------------------------------------------ */
#panel-props #tp-tabs {
  position: sticky; top: 0; z-index: 3;
  /* the panel colour around the segmented control hides content scrolling under its margins */
  box-shadow: 0 -6px 0 6px var(--panel), 0 6px 0 6px var(--panel);
}
/* the column chip strip sticks right below the tabs (tabs ≈ 30 px + 4 px top + 6 px bottom margin) */
#panel-props #tp-tabs ~ .tp-pane .tp-strip { top: 40px; }

/* ------------------------------------------------------------------ */
/* [perf] SPEC-PERF-DESIGNER §2.3 — canvas / page view with large data  */
/* ------------------------------------------------------------------ */
/* "(mẫu)" tag on aggregate cells computed over the first 50 sample rows (canvas.js) */
.el-table .tg-agg-sample {
  font-size: 0.75em; font-weight: 400; font-style: italic; color: #92400e; opacity: 0.85;
  white-space: nowrap; margin-left: 2px; vertical-align: baseline;
}
body.print-view .el-table .tg-agg-sample { display: none; }
/* pager "Tải thêm N trang" of a partial server tree (options.maxPages) */
.status-pager .pv-load-more { margin-left: 6px; padding: 0 8px; white-space: nowrap; font-weight: 600; color: var(--accent); }
.status-pager .pv-load-more:disabled { opacity: 0.6; }

/* ================================================================== */
/* [perf] Large sample data (SPEC-PERF-DESIGNER §2.2): the trim banner   */
/* of the Data tab, the read-only summary of big data, the JSON tab's  */
/* "Hiện dữ liệu mẫu" toggle (dataPanel.js / jsonPanel.js)              */
/* ================================================================== */
#panel-data .data-trim-banner { margin: 0 0 8px; padding: 6px 8px; border-radius: var(--radius); border: 1px solid #93c5fd; font-size: 12px; flex-wrap: wrap; gap: 6px 10px; }
#panel-data .data-trim-banner.banner-warning { border-color: #fcd34d; }
#panel-data .data-trim-banner .banner-text { flex: 1 1 160px; }
#panel-data .data-trim-actions { display: inline-flex; flex-wrap: wrap; gap: 4px; }
#panel-data .data-summary-title { margin: 0 0 4px; font-size: 12px; font-weight: 600; }
#panel-data .data-summary-scroll { max-height: 220px; overflow: auto; border: 1px solid var(--border); border-radius: var(--radius); margin: 4px 0 6px; }
#panel-data .data-summary-table { width: 100%; border-collapse: collapse; font-size: 11.5px; }
#panel-data .data-summary-table th, #panel-data .data-summary-table td { padding: 3px 6px; border-bottom: 1px solid var(--border); text-align: left; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 160px; }
#panel-data .data-summary-table th { position: sticky; top: 0; background: var(--panel); font-weight: 600; color: var(--muted); }
#panel-data .data-summary-table .num { text-align: right; font-variant-numeric: tabular-nums; }
#panel-json .json-sample-toggle { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; cursor: pointer; margin-left: auto; white-space: nowrap; }
#panel-json .json-sample-hint { margin: 0 0 4px; }

/* ------------------------------------------------------------------ */
/* [panelResize] resizable side panels (panelResize.js, SPEC-PHASE11   */
/* §2): a 6 px grip on the inner edge of #left / #right sets --left-w  */
/* / --right-w (inline on <html>); body.panel-resizing blocks text     */
/* selection and pointer events on the canvas / iframes while dragging. */
/* ------------------------------------------------------------------ */
.side-left, .side-right { position: relative; }
.panel-grip { position: absolute; top: 0; bottom: 0; width: 6px; cursor: col-resize; z-index: 6; touch-action: none; background: transparent; border-radius: 2px; }
.side-left .panel-grip { right: -3px; }
.side-right .panel-grip { left: -3px; }
.panel-grip:hover, .panel-grip.active, .panel-grip:focus-visible { background: var(--accent-soft); }
.panel-grip.active { background: color-mix(in srgb, var(--accent) 35%, transparent); }
.panel-grip:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
body.panel-resizing { user-select: none; -webkit-user-select: none; cursor: col-resize; }
body.panel-resizing .canvas-area, body.panel-resizing iframe, body.panel-resizing .drawer { pointer-events: none; }
@media (max-width: 800px) { .panel-grip { display: none; } }
/* A wider right panel is used by the forms: chips of the column strip may grow with the panel
   (more readable headers, more chips per row when wrapping), textareas / code editors already
   fill (`width: 100%`), the 2-column grids scale with the panel. */
.side-right .tp-chip { max-width: clamp(110px, calc(var(--right-w) * 0.42), 220px); }
.side-right .sr-chip { max-width: clamp(118px, calc(var(--right-w) * 0.4), 200px); }
.side-right #panel-data .data-summary-table th, .side-right #panel-data .data-summary-table td { max-width: clamp(160px, calc(var(--right-w) * 0.5), 320px); }

/* ================================================================== */
/* [columnTree] "Cấu trúc cột" — the column structure tree            */
/* (columnTree.js, SPEC-PHASE11 §1): field picker "Cột sẽ hiển thị",  */
/* the card on top of Thuộc tính bảng (#tp-coltree), check-panel link  */
/* ================================================================== */
.ct { --ct-indent: 16px; --ct-row-h: 26px; --ct-d1: #2563eb; --ct-d2: #7c3aed; --ct-d3: #059669; --ct-d4: #d97706; display: flex; flex-direction: column; gap: 6px; min-width: 0; font-size: 12px; }
.ct-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 3px; }
.ct-toolbar-gap { width: 6px; }
.ct-btn { display: inline-flex; align-items: center; gap: 4px; padding: 0 6px; height: 24px; }
.ct-btn svg { flex: none; }
.ct-btn[data-icon-only] .ct-btn-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.ct-btn[data-icon-only] { width: 26px; padding: 0; justify-content: center; }
.ct-tree { position: relative; max-height: 46vh; overflow: auto; border: 1px solid var(--border); border-radius: var(--radius); background: var(--panel); outline: none; }
.ct-empty { margin: 0; padding: 10px 12px; }
.ct-row { position: relative; display: flex; align-items: center; gap: 5px; min-height: var(--ct-row-h); padding: 2px 6px 2px calc(6px + var(--ct-indent) * var(--ct-depth, 0)); border-bottom: 1px solid var(--border); cursor: default; user-select: none; -webkit-user-select: none; outline: none; }
.ct-row:last-child { border-bottom: 0; }
.ct-row:hover { background: var(--panel-2); }
.ct-row.selected { background: var(--accent-soft); }
.ct-row:focus-visible { box-shadow: inset 0 0 0 2px var(--accent); }
.ct-row.flash { animation: ct-flash 1.6s ease-out; }
@keyframes ct-flash { 0% { background: #fde68a; } 100% { background: transparent; } }
.ct-grip { flex: none; width: 10px; color: var(--muted); font-size: 12px; line-height: 1; cursor: grab; touch-action: none; text-align: center; }
.ct-readonly .ct-grip { cursor: default; }
.ct-chev { flex: none; width: 16px; height: 16px; padding: 0; border: 0; border-radius: 3px; background: transparent; color: var(--muted); font: inherit; font-size: 11px; line-height: 16px; cursor: pointer; }
.ct-chev:hover { background: var(--border); color: var(--text); }
.ct-stripe { flex: none; width: 3px; align-self: stretch; border-radius: 2px; background: var(--ct-d1); }
.ct-stripe.ct-d2 { background: var(--ct-d2); }
.ct-stripe.ct-d3 { background: var(--ct-d3); }
.ct-stripe.ct-d4 { background: var(--ct-d4); }
.ct-group .ct-name { font-weight: 600; }
.ct-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ct-field { flex: 0 1 auto; max-width: 38%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--muted); font-size: 11px; }
.ct-count, .ct-width { flex: none; color: var(--muted); font-size: 11px; font-variant-numeric: tabular-nums; white-space: nowrap; }
.ct-badge { flex: none; font-size: 10px; line-height: 1; padding: 3px 5px; border-radius: 999px; white-space: nowrap; background: var(--panel-2); color: var(--muted); border: 1px solid var(--border); }
.ct-badge-number { color: #1d4ed8; background: #dbeafe; border-color: #bfdbfe; }
.ct-badge-date { color: #7c2d12; background: #ffedd5; border-color: #fed7aa; }
.ct-badge-bool { color: #166534; background: #dcfce7; border-color: #bbf7d0; }
.ct-badge-expr, .ct-badge-content { color: #6b21a8; background: #f3e8ff; border-color: #e9d5ff; }
.ct-badge-index { color: #374151; background: #f3f4f6; border-color: #d1d5db; }
.ct-badge-subtable { color: #0f766e; background: #ccfbf1; border-color: #99f6e4; }
.ct-warn { flex: none; color: var(--warning); font-size: 12px; cursor: help; }
.ct-row.duplicate .ct-name { color: #b45309; }
.ct-rename { flex: 1 1 auto; min-width: 60px; height: 22px; padding: 0 6px; border: 1px solid var(--accent); border-radius: 4px; font: inherit; font-size: 12px; font-weight: 600; background: var(--panel); color: var(--text); box-shadow: 0 0 0 2px var(--accent-soft); outline: none; }
.ct-pending { background: var(--accent-soft); }
/* drag & drop: the pressed row fades, the drop line / the target group highlights, a ghost follows the pointer */
.ct.dragging { cursor: grabbing; }
.ct.dragging .ct-row { cursor: grabbing; }
.ct-row.drag-source { opacity: 0.45; }
.ct-row.drop-before { box-shadow: inset 0 2px 0 var(--accent); }
.ct-row.drop-after { box-shadow: inset 0 -2px 0 var(--accent); }
.ct-row.drop-into { background: var(--accent-soft); box-shadow: inset 0 0 0 2px var(--accent); }
.ct-ghost { position: fixed; z-index: 10000; pointer-events: none; max-width: 240px; padding: 3px 8px; border-radius: 4px; background: var(--text); color: var(--panel); font-size: 12px; box-shadow: var(--shadow); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; opacity: 0.92; }
/* header preview: the resulting N-level header (same cells as the canvas), the focused node's cell highlighted */
.ct-preview { overflow: auto; border: 1px solid var(--border); border-radius: var(--radius); background: var(--panel); padding: 4px; }
.ct-preview table { border-collapse: collapse; min-width: 100%; font-size: 10.5px; }
.ct-preview th { border: 1px solid var(--border-strong); padding: 2px 5px; font-weight: 400; white-space: nowrap; max-width: 140px; overflow: hidden; text-overflow: ellipsis; color: var(--text); }
.ct-preview th.ct-h-group { background: var(--panel-2); }
.ct-preview th.hot { outline: 2px solid var(--accent); outline-offset: -2px; background: var(--accent-soft); }
.ct-preview th.dup { color: #b45309; }
.ct-preview th .ct-warn { margin-left: 3px; }
.ct-kbd { margin: 0; font-size: 11px; }
/* compact mode (the properties card): tighter rows, icon-only toolbar labels */
.ct-compact { --ct-row-h: 24px; --ct-indent: 14px; }
.ct-compact .ct-tree { max-height: 40vh; }
.ct-compact .ct-btn .ct-btn-label { display: none; }
.ct-compact .ct-btn { width: 26px; padding: 0; justify-content: center; }
.ct-compact .ct-badge { padding: 2px 4px; }
/* the "Cấu trúc cột" card of Thuộc tính bảng */
.ct-section .prop-section-body { display: block; }
.ct-section .ct-n { display: inline-flex; align-items: center; justify-content: center; min-width: 16px; height: 16px; margin-left: 6px; padding: 0 4px; border-radius: 8px; font-size: 10.5px; font-weight: 600; line-height: 1; background: var(--accent-soft); color: var(--accent); font-variant-numeric: tabular-nums; }
.ct-section .ct-section-hint { margin: 6px 0 0; font-size: 11px; }
/* the field picker's right-hand side hosts the tree instead of the old ordered list */
.fpk-tree { flex: 1; min-height: 240px; max-height: 52vh; overflow: auto; display: flex; flex-direction: column; }
.fpk-tree .ct { flex: 1; min-height: 0; }
.fpk-tree .ct-tree { flex: 1; min-height: 160px; max-height: none; }
.fpk-tree .ct-btn .ct-btn-label { display: inline; }
.fpk-tree .ct-btn { width: auto; padding: 0 6px; }
.fpk-tree .ct-btn[data-icon-only] { width: 26px; padding: 0; }
.fpk-tree .ct-btn[data-icon-only] .ct-btn-label { display: none; }
/* the picker's toolbar: the labelled actions on one line, the icon-only move / fold buttons on the next */
.fpk-tree .ct-toolbar-gap:first-of-type { flex-basis: 100%; width: auto; height: 0; }
.fpk-tree.fpk-order { border: 0; background: transparent; padding: 0; counter-reset: none; }

/* ================================================================== */
/* [keepTogether] "Giữ liền khối" / "Luôn bắt đầu trang mới"           */
/* (groups.js group header, canvas badge, check panel — SPEC-KEEP-TOGETHER §3) */
/* ================================================================== */
.grp-head-pag { margin-top: 8px; padding-top: 6px; border-top: 1px dashed color-mix(in srgb, var(--grp-color, var(--accent)) 35%, var(--border)); }
.grp-head-pag-title { font-size: 11px; font-weight: 600; color: var(--muted); text-transform: uppercase; letter-spacing: 0.03em; margin-bottom: 4px; }
.grp-flag { display: flex; align-items: flex-start; gap: 6px; margin: 2px 0; font-size: 12px; line-height: 1.35; cursor: pointer; }
.grp-flag input { flex: none; margin: 2px 0 0; }
.grp-keep-hint { margin: 4px 12px 6px; font-size: 11px; line-height: 1.4; }
.grp-head .grp-keep-hint { margin: 4px 0 0; }
/* canvas: the "⛓ Giữ liền" badge at the top-right of the selected group outline */
.grp-outline .grp-keep-badge {
  position: absolute; right: -1px; bottom: 100%; margin-bottom: 2px; white-space: nowrap;
  padding: 1px 6px; border-radius: 3px; font: 600 10.5px/1.4 var(--font-ui); color: var(--grp-color, var(--accent));
  background: color-mix(in srgb, var(--grp-color, var(--accent)) 12%, var(--panel)); border: 1px solid var(--grp-color, var(--accent)); pointer-events: none;
}
body.print-view .grp-outline .grp-keep-badge { display: none; }
/* check panel: the "Bật giữ liền khối" action next to a W_GROUP_SPLIT row */
.check-issue .check-keep-on { flex: none; margin-left: 4px; }
/* [keepTogether] flags the layout would ignore (group anchored to the page bottom / pinned, or outside the body flow): disabled + reason */
.grp-flag.grp-flag-off { opacity: 0.55; cursor: not-allowed; }
.grp-flag.grp-flag-off input { cursor: not-allowed; }
.grp-head .grp-keep-ignored { color: var(--warning, #b26a00); }

/* ---------------------------------------------------------------------- */
/* [importPdfPages] "Nhập từ PDF" multi-page picker (SPEC-PHASE12 §2):     */
/* order badges on the thumbnails, page-list input, toolbar + counter      */
/* ---------------------------------------------------------------------- */
.pdf-pages .field { flex-wrap: wrap; }
.pdf-pages .field input.pdf-pages-input { width: 140px; flex: 0 0 auto; } /* beats `.field input[type="text"] { width: 100% }` so "/ n" and the counter stay on the input's row */
.pdf-pages-counter { font-size: 12px; color: var(--muted); padding: 2px 8px; border-radius: 999px; background: var(--bg-2, #f6f7f9); border: 1px solid var(--border); }
.pdf-pages-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.pdf-pages-toolbar .btn-sm { padding: 2px 8px; font-size: 12px; }
.pdf-pages-status { font-size: 12px; min-height: 1.2em; }
.pdf-pages-status:not(:empty) { color: var(--warning, #b26a00); }
.pdf-thumb { position: relative; }
.pdf-thumb-badge { position: absolute; top: 2px; left: 2px; min-width: 20px; height: 20px; padding: 0 5px; border-radius: 999px; background: var(--accent, #2563eb); color: #fff; font-size: 12px; font-weight: 700; line-height: 20px; text-align: center; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3); display: none; }
.pdf-thumb.selected .pdf-thumb-badge { display: block; }
.pdf-thumb[aria-selected="true"]:focus-visible { outline: 2px solid var(--accent, #2563eb); outline-offset: 2px; }

/* ---------------------------------------------------------------------- */
/* [designPages] "Trang thiết kế nhiều trang" (SPEC-PHASE12 §1.2):        */
/* stacked design sheets with a 12 mm gap, per-sheet label / tint / grid, */
/* Page-tab stepper, layers page badge, check-panel actions               */
/* ---------------------------------------------------------------------- */
/* the stack: the background node itself is transparent and shadow-less, every sheet carries its own paper */
.page-bg.dp-stack { background: transparent !important; box-shadow: none; }
.dp-sheet { position: absolute; box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.08), 0 6px 20px rgba(0, 0, 0, 0.12); }
.dp-sheet > .page-grid, .dp-sheet > .page-margin, .dp-sheet > .page-header-region, .dp-sheet > .page-footer-region { position: absolute; }
.dp-sheet > .page-grid { inset: 0; }
body.print-view .dp-sheet > .page-grid, body.print-view .dp-sheet > .page-margin, body.print-view .dp-sheet > .page-header-region, body.print-view .dp-sheet > .page-footer-region { display: none; }
body.print-view .dp-sheet { box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.12), 0 12px 32px rgba(0, 0, 0, 0.28), 0 2px 6px rgba(0, 0, 0, 0.16); }
/* "Trang thiết kế 2/3" at the top-left corner of every sheet (screen size, above the paper, never over an element's pointer) */
.dp-sheet-label {
  position: absolute; z-index: 1; transform: translateY(-100%); padding: 1px 8px 2px; border-radius: 6px 6px 0 0;
  font: 600 11px/16px var(--font-ui); color: #fff; background: rgba(15, 23, 42, 0.62); white-space: nowrap; pointer-events: none; letter-spacing: 0.01em;
}
body.print-view .dp-sheet-label { background: rgba(15, 23, 42, 0.35); }
/* the sheet area of the scaled page keeps its transparent gaps (the viewport colour shows through) */
body.dp-multi .page { background: transparent; }
/* Page tab: "Số trang thiết kế" stepper + actions */
.page-design-pages .dp-stepper { display: inline-flex; align-items: center; gap: 4px; }
.page-design-pages .dp-stepper .dp-count { width: 56px; text-align: center; }
.page-design-pages .dp-stepper .dp-btn { min-width: 28px; height: 28px; padding: 0; justify-content: center; font-weight: 700; line-height: 1; }
.page-design-pages .dp-actions { margin-top: 10px; }
.page-design-pages .dp-actions .btn { flex: 1; }
.page-design-pages .side-hint.warn { color: var(--warning, #b26a00); }
/* Layers: "T2" badge on rows of elements beyond design page 1 */
.layer .layer-page { flex: none; font: 700 9px/14px var(--font-ui); color: var(--accent, #2563eb); background: color-mix(in srgb, var(--accent, #2563eb) 12%, var(--panel, #fff)); border: 1px solid color-mix(in srgb, var(--accent, #2563eb) 40%, transparent); border-radius: 3px; padding: 0 3px; margin-right: 4px; letter-spacing: 0.02em; }
/* check panel: the "Đặt vừa trang" / "Xóa trang cuối" / "Tab Trang" actions */
.check-issue .check-dp-fit, .check-issue .check-dp-remove, .check-issue .check-dp-page { flex: none; margin-left: 4px; }

/* ---------------------------------------------------------------------- */
/* [pageTotals] "Cộng trang" — page carry-forward totals (SPEC-PHASE13 §2): */
/* the table-properties card, the canvas sample row, the pages-view tags   */
/* ---------------------------------------------------------------------- */
.pt2-section .prop-section-body { display: block; }
.pt2-section .pt2-badge { margin-left: 6px; font-size: 9px; color: var(--accent, #2563eb); vertical-align: 1px; }
.pt2-section .pt2-enable { margin-bottom: 2px; }
.pt2-section .pt2-fields { display: flex; flex-wrap: wrap; gap: 2px 10px; }
.pt2-section .pt2-fields .field.check { margin: 0; }
.pt2-section .pt2-fields-default { font-weight: 400; text-transform: none; letter-spacing: 0; }
.pt2-section .pt2-row .grid2 { align-items: start; }
.pt2-section .pt2-style { grid-column: 1 / -1; }
.pt2-section .pt2-style .tgl-group { margin-bottom: 4px; }
.pt2-section .pt2-flags { display: block; margin-top: 6px; }
.pt2-section .pt2-flags .field.check { margin: 2px 0; }
.pt2-section .side-hint.warn { color: var(--warning, #b26a00); }
.pt2-section .mono-hint { font-family: var(--font-mono, ui-monospace, monospace); font-size: 10.5px; }
.pt2-section.flash { animation: tp-flash 1.5s ease-out; }
/* canvas: the one sample "(cộng trang)" row after the preview rows — a dotted rule above marks it as generated */
.el-table tr.tg-pt > td { border-top-style: dotted !important; }
.el-table tr.tg-pt .pt2-tag { font-style: italic; opacity: 0.7; }
/* pages view: the real rows keep the print style; the drawer's per-page tag */
.pv-sum .pv-pt { display: block; font-size: 10px; white-space: nowrap; }
.check-issue .check-pt { flex: none; margin-left: 4px; }

/* ---------------------------------------------------------------------- */
/* [richText] "Định dạng trong đoạn" (SPEC-PHASE13 §3): rich runs on the  */
/* canvas / pages view, the rich inline editor, the format bar target     */
/* ---------------------------------------------------------------------- */
/* runs: bold / italic / underline / strike / sup / sub come from the tags; colour, background, size and font from the span */
.el-text-inner .rt-run, .pv-text-inner .rt-run, .el-table td .rt-run, .el-table th .rt-run, .pv-table td .rt-run { line-height: inherit; }
.el-text-inner sup, .el-text-inner sub, .pv-text-inner sup, .pv-text-inner sub, .el-table sup, .el-table sub, .pv-table sup, .pv-table sub { font-size: 65%; line-height: 0; position: relative; vertical-align: baseline; }
.el-text-inner sup, .pv-text-inner sup, .el-table sup, .pv-table sup { top: -0.33em; }
.el-text-inner sub, .pv-text-inner sub, .el-table sub, .pv-table sub { top: 0.12em; }
/* the rich editor: real formatting while typing, the browser's own <b>/<i>/<u> tags inherit the canvas font */
.el-text-inner.editing-rich { user-select: text; }
.el-text-inner.editing-rich b, .el-text-inner.editing-rich strong { font-weight: 700; }
.el-text-inner.editing-rich i, .el-text-inner.editing-rich em { font-style: italic; }
.el-text-inner.editing-rich u { text-decoration: underline; }
.el-text-inner.editing-rich s, .el-text-inner.editing-rich strike { text-decoration: line-through; }
/* the same editor on a pages-view item (pagePreview.js startItemEdit) */
.pv-text-inner.editing-rich b, .pv-text-inner.editing-rich strong { font-weight: 700; }
.pv-text-inner.editing-rich i, .pv-text-inner.editing-rich em { font-style: italic; }
.pv-text-inner.editing-rich u { text-decoration: underline; }
.pv-text-inner.editing-rich s, .pv-text-inner.editing-rich strike { text-decoration: line-through; }
/* format bar while a rich editor is open: the target reads "Áp dụng cho: chữ đang chọn" */
#fmtbar.fb-rich .fb-target { color: var(--accent, #2563eb); font-weight: 600; }
#fmtbar.fb-rich .fb-target::before { content: '¶'; margin-right: 4px; opacity: 0.7; }
/* properties: the markup cheat-sheet hint under the checkbox wraps the long sample */
.field-hint.rich-hint { white-space: normal; }

/* ---------------------------------------------------------------------- */
/* [pivot] "Bảng xoay (cột động)" (SPEC-PHASE13 §1.3, pivotCard.js): the  */
/* card of Thuộc tính bảng, the "động" chips under the column strip, the  */
/* dynamic block node of the column tree, the canvas badge                 */
/* ---------------------------------------------------------------------- */
.pvt-section .prop-section-title svg { width: 14px; height: 14px; margin-right: 4px; vertical-align: -2px; color: var(--accent, #2563eb); }
.pvt-section .pvt-n { display: inline-flex; align-items: center; margin-left: 6px; padding: 1px 6px; border-radius: 999px; font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; background: #dbeafe; color: #1d4ed8; border: 1px solid #bfdbfe; }
.pvt-body .field.pvt-on { grid-column: 1 / -1; }
.pvt-body .field.pvt-rows, .pvt-body .field.pvt-values-field, .pvt-body .field.pvt-keys-field, .pvt-body .field.pvt-fit, .pvt-body .pvt-live { grid-column: 1 / -1; }
.pvt-section.flash { animation: tp-flash 1.5s ease-out; }
/* chips of the row fields / fixed keys */
.pvt-chips { display: flex; flex-wrap: wrap; gap: 4px; min-height: 26px; padding: 3px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--panel-2); }
.pvt-chip { display: inline-flex; align-items: center; gap: 4px; max-width: 100%; height: 22px; padding: 0 2px 0 7px; border: 1px solid var(--border); border-radius: 999px; background: var(--panel); color: var(--text); font-size: 11.5px; white-space: nowrap; }
.pvt-chip > span { overflow: hidden; text-overflow: ellipsis; }
.pvt-chip-key { border-color: #93c5fd; background: #eff6ff; }
.pvt-chip em { font-style: normal; font-size: 9.5px; text-transform: uppercase; letter-spacing: 0.04em; color: #1d4ed8; }
.pvt-chip .pvt-x { width: 18px; height: 18px; padding: 0; border: 0; border-radius: 999px; background: transparent; color: var(--muted); font-size: 14px; line-height: 1; cursor: pointer; }
.pvt-chip .pvt-x:hover { background: var(--danger, #dc2626); color: #fff; }
.pvt-chips .pvt-empty { padding: 2px 4px; }
.pvt-body input.pvt-add { margin-top: 4px; width: 100%; }
/* value rows */
.pvt-values { display: flex; flex-direction: column; gap: 6px; }
.pvt-value { padding: 6px 8px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--panel-2); }
.pvt-value-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 4px; font-size: 11.5px; }
.pvt-value .grid2 { gap: 4px 8px; }
/* keys: segmented control + helpers */
.pvt-seg { margin: 2px 0 4px; }
.pvt-seg .tp-tab { height: 24px; padding: 0 8px; font-size: 11.5px; flex: 1 1 auto; }
.pvt-key-helpers { margin-top: 4px; }
/* live status: configuration issues, sample-data notes, column preview */
.pvt-status { display: flex; flex-direction: column; gap: 6px; margin-top: 2px; font-size: 11.5px; }
.pvt-issues, .pvt-warnings { padding: 6px 8px; border-radius: var(--radius); border: 1px solid #fecaca; background: #fef2f2; color: #991b1b; }
.pvt-warnings { border-color: #fde68a; background: #fffbeb; color: #92400e; }
.pvt-issues ul, .pvt-warnings ul { margin: 4px 0 0; padding-left: 16px; }
.pvt-preview { padding: 6px 8px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--panel); }
.pvt-preview-head { display: flex; align-items: center; gap: 6px; margin-bottom: 4px; }
.pvt-preview-keys { display: block; color: var(--muted); margin-bottom: 4px; word-break: break-word; }
.pvt-pchips { display: flex; flex-wrap: wrap; gap: 3px; }
.pvt-pchip { display: inline-flex; flex-direction: column; align-items: center; min-width: 34px; padding: 2px 6px; border: 1px solid #bfdbfe; border-radius: 4px; background: #eff6ff; color: #1e3a8a; font-size: 11px; line-height: 1.2; }
.pvt-pchip small { font-size: 9px; color: #3b82f6; }
.pvt-pchip-total { border-color: #a7f3d0; background: #ecfdf5; color: #065f46; }
.pvt-pchip-ph { border-style: dashed; color: var(--muted); background: var(--panel-2); }
.pvt-pchip-more { justify-content: center; color: var(--muted); background: var(--panel-2); border-color: var(--border); }
/* the read-only "động" chips under the column strip (Thuộc tính cột) */
.tp-strip .tp-chips-dyn { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; width: 100%; padding-top: 4px; border-top: 1px dashed var(--border); }
.tp-strip .tp-chips-dyn-label { font-size: 11px; color: var(--muted); margin-right: 2px; white-space: nowrap; }
.tp-chip-dyn { border-style: dashed; border-color: #93c5fd; background: #eff6ff; color: #1e3a8a; padding-right: 4px; cursor: pointer; }
.tp-chip-dyn .tp-chip-badge { display: inline-flex; align-items: center; height: 14px; padding: 0 4px; border-radius: 999px; background: #dbeafe; color: #1d4ed8; font-size: 9.5px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; }
.tp-chip-dyn-total { border-color: #6ee7b7; background: #ecfdf5; color: #065f46; }
.tp-chip-dyn-total .tp-chip-badge { background: #d1fae5; color: #047857; }
.tp-chip-dyn.tp-chip-more { border-style: dashed; }
/* column tree: the dynamic block node */
.ct-badge-dynamic { color: #1d4ed8; background: #dbeafe; border-color: #bfdbfe; }
.ct-row[data-field="$pivot"] .ct-name { color: #1e3a8a; font-style: italic; }
/* field picker: "Dùng làm cột động…" — a sixth grid cell of every field row while the picker edits a table (fpk[data-pivot]) */
.fpk[data-pivot="1"] .fpk-row { grid-template-columns: 22px minmax(90px, 1.2fr) 44px minmax(60px, 1fr) minmax(90px, 1fr) auto; }
.fpk-row .fpk-pivot { height: 22px; padding: 0 6px; font-size: 10.5px; white-space: nowrap; opacity: 0.75; }
.fpk-row:hover .fpk-pivot, .fpk-row:focus-within .fpk-pivot, .fpk-row .fpk-pivot:focus { opacity: 1; }
/* canvas: the placeholder-keys badge shares the warn badge look */
.el-table-pivot .el-badge[data-badge="pivotNoData"] { border-style: dashed; }

/* ---------------------------------------------------------------------- */
/* [richBubble] "Định dạng trong đoạn" selection bubble (SPEC-PHASE13     */
/* §3.4, richBubble.js): the floating mini-toolbar above / below the text  */
/* selection of the inline editors and of the properties content fields,  */
/* the "{}" field popup, the hint line under the content fields            */
/* ---------------------------------------------------------------------- */
:root {
  --rb-bg: #ffffff; --rb-fg: #374151; --rb-border: #d1d5db; --rb-hover: #f3f4f6; --rb-sep: #e5e7eb;
  --rb-on-bg: #dbeafe; --rb-on-fg: #1d4ed8; --rb-shadow: 0 2px 6px rgba(0, 0, 0, 0.12), 0 8px 24px rgba(0, 0, 0, 0.14);
}
@media (prefers-color-scheme: dark) {
  :root {
    --rb-bg: #1f2937; --rb-fg: #e5e7eb; --rb-border: #374151; --rb-hover: #374151; --rb-sep: #4b5563;
    --rb-on-bg: #1e3a8a; --rb-on-fg: #bfdbfe; --rb-shadow: 0 2px 6px rgba(0, 0, 0, 0.5), 0 8px 24px rgba(0, 0, 0, 0.5);
  }
}
.rich-bubble {
  position: fixed; top: 0; left: 0; z-index: 590; /* above the canvas overlays and the menus (500 / 510), below the field popup (600) and the toasts */
  display: flex; align-items: center; gap: 1px; padding: 3px 4px;
  background: var(--rb-bg); color: var(--rb-fg); border: 1px solid var(--rb-border); border-radius: 8px; box-shadow: var(--rb-shadow);
  font: 12.5px/1 var(--font-ui, system-ui, sans-serif); white-space: nowrap; user-select: none; -webkit-user-select: none;
  touch-action: manipulation;
}
.rich-bubble[hidden] { display: none; }
/* the small arrow towards the selection (above by default, below with .rb-below) */
.rich-bubble::after {
  content: ''; position: absolute; left: 50%; bottom: -6px; width: 10px; height: 10px; margin-left: -5px;
  background: var(--rb-bg); border-right: 1px solid var(--rb-border); border-bottom: 1px solid var(--rb-border); transform: rotate(45deg);
}
.rich-bubble.rb-below::after { bottom: auto; top: -6px; border: 0; border-left: 1px solid var(--rb-border); border-top: 1px solid var(--rb-border); }
.rb-btn {
  display: inline-flex; align-items: center; justify-content: center; min-width: 26px; height: 26px; padding: 0 5px;
  background: transparent; border: 1px solid transparent; border-radius: 5px; color: inherit; font: inherit; font-weight: 600; cursor: pointer;
}
.rb-btn:hover { background: var(--rb-hover); border-color: var(--rb-border); }
.rb-btn:focus-visible { outline: 2px solid var(--accent, #2563eb); outline-offset: -1px; }
.rb-btn[aria-pressed="true"], .rb-btn.active { background: var(--rb-on-bg); color: var(--rb-on-fg); }
.rb-btn[aria-pressed="mixed"], .rb-btn.mixed { background: repeating-linear-gradient(135deg, var(--rb-on-bg) 0 3px, transparent 3px 6px); }
.rb-btn b { font-weight: 800; }
.rb-btn i { font-family: Georgia, "Times New Roman", serif; font-style: italic; }
.rb-btn u { text-decoration: underline; text-underline-offset: 2px; }
.rb-btn s { text-decoration: line-through; }
.rb-btn sup, .rb-btn sub { font-size: 9px; line-height: 0; }
.rb-btn svg { width: 14px; height: 14px; }
.rb-braces { font-family: var(--font-mono, monospace); font-weight: 700; letter-spacing: -1px; }
.rb-sep { width: 1px; height: 18px; margin: 0 3px; background: var(--rb-sep); }
/* colours: a glyph + swatch with the native picker stretched invisibly over it (like the format bar) */
.rb-color { position: relative; display: inline-flex; flex-direction: column; align-items: center; justify-content: center; width: 28px; height: 26px; border: 1px solid transparent; border-radius: 5px; cursor: pointer; }
.rb-color:hover { background: var(--rb-hover); border-color: var(--rb-border); }
.rb-glyph { display: inline-flex; align-items: center; justify-content: center; height: 14px; font-weight: 700; font-size: 13px; line-height: 1; }
.rb-glyph svg { width: 14px; height: 14px; }
.rb-swatch { display: block; width: 16px; height: 3px; margin-top: 2px; border-radius: 1px; background: #000; box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.12); }
.rb-swatch.empty { background: repeating-linear-gradient(135deg, #d1d5db 0 2px, transparent 2px 4px); }
.rb-swatch.mixed { background: repeating-linear-gradient(135deg, var(--accent, #2563eb) 0 3px, #d1d5db 3px 6px); }
.rb-color input[type="color"] { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; border: 0; padding: 0; }
/* size − / pt / + */
.rb-size { display: inline-flex; align-items: center; }
.rb-size .rb-btn { min-width: 22px; padding: 0; font-size: 15px; }
.rb-pt { display: inline-block; min-width: 26px; text-align: center; font-variant-numeric: tabular-nums; font-weight: 600; }
/* font */
.rb-font { max-width: 120px; height: 24px; padding: 0 2px; border: 1px solid var(--rb-border); border-radius: 4px; background: var(--rb-bg); color: inherit; font: inherit; }
.rb-font:focus { outline: none; border-color: var(--accent, #2563eb); box-shadow: 0 0 0 2px var(--accent-soft, #dbeafe); }
/* the "{}" popup reuses the menu popup (insertMenu.js) under the bubble */
.rd-popup.rb-popup { min-width: 260px; }
/* properties: the hint under the content fields of a rich element / column / group */
.field-hint.rb-hint { color: var(--muted); font-style: italic; }
@media (max-width: 900px) { .rb-font { max-width: 90px; } }
@media (pointer: coarse) { .rb-btn, .rb-color { min-width: 32px; height: 32px; } .rb-font { height: 30px; } }

/* ---------------------------------------------------------------------- */
/* [importFit] "Khi nội dung rộng hơn trang" (SPEC-FIT-TO-WIDTH §3,        */
/* importDialog.js): the fit radio group replacing the fit-page checkbox,  */
/* the "Nâng cao ▸ Giới hạn ô" disclosure and the result line naming the  */
/* page the importer settled on ("Khổ giấy: A4 ngang, thu nhỏ 60 %").      */
/* ---------------------------------------------------------------------- */
.import-fit { gap: 0; }
.import-fit .field.check { padding: 2px 0; }
.import-fit .field.check input[type="radio"] { margin: 0; }
.import-fit .import-fit-hint { margin: 2px 0 4px 20px; }
.import-fit .import-fit-hint[hidden] { display: none; }
.import-advanced { border: 1px dashed var(--border); border-radius: var(--radius); padding: 4px 10px 6px; }
.import-advanced > summary { cursor: pointer; font-size: 11.5px; color: var(--muted); user-select: none; }
.import-advanced > summary:hover { color: var(--text); }
.import-advanced .field { margin-top: 6px; }
.import-advanced .field-hint { margin: 2px 0 0; font-size: 11px; }
.import-advanced #import-max-cells { max-width: 160px; font-variant-numeric: tabular-nums; }
.import-fit-result { margin: 0; font-weight: 600; }

/* [pageScale] "In thu nhỏ" — print scaling like Excel's fit to page width (SPEC-FIT-TO-WIDTH §2): */
/* the Page tab section with the live factor, the pages view badge, the check-panel one-click buttons */
.page-scale .prop-section-body > .side-hint { grid-column: 1 / -1; }
.page-scale .page-scale-now { margin-top: 2px; font-variant-numeric: tabular-nums; color: var(--text); }
.page-scale .page-scale-now[data-scale="1"] { color: var(--muted); }
.page-scale .side-hint.warn { color: var(--warning, #b26a00); }
.status-pager .pv-scale-badge { margin-left: 6px; padding: 0 6px; border-radius: 9px; background: var(--accent-soft, #dbeafe); color: var(--accent, #2563eb); font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; }
.check-issue .check-fit-width, .check-issue .check-landscape, .check-issue .check-scale-page { margin-left: 4px; white-space: nowrap; }

/* [repeatGroup] "Lặp theo mảng" → nhóm theo khóa (SPEC-REPEAT-GROUP §3): the key / keep chips, */
/* the group + row order rows, the totals editor and the live "5 dòng → 3 nhóm" preview.        */
/* ---------------------------------------------------------------------- */
.page-repeat-group { grid-column: 1 / -1; display: grid; gap: 6px; min-width: 0; }
.page-repeat-group > .field { margin: 0; }
.repeat-chips { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; }
.repeat-chips > select { flex: 1 1 110px; min-width: 0; }
.repeat-chip { display: inline-flex; align-items: center; gap: 2px; padding: 1px 2px 1px 7px; border: 1px solid var(--border); border-radius: 10px; background: var(--accent-soft, #dbeafe); color: var(--text); font-size: 11.5px; cursor: grab; user-select: none; }
.repeat-chip:active { cursor: grabbing; }
/* [repeatGroup] the chips are focusable (← / → reorder them without a mouse) — show the focus ring */
.repeat-chip:focus-visible { outline: 2px solid var(--accent, #2563eb); outline-offset: 1px; }
.repeat-chip-name { font-variant-numeric: tabular-nums; }
.repeat-chip-x { border: 0; background: none; color: var(--muted); font-size: 13px; line-height: 1; padding: 0 3px; cursor: pointer; }
.repeat-chip-x:hover { color: var(--danger, #dc2626); }
.repeat-sub-title { display: block; font-size: 11.5px; color: var(--muted); margin-bottom: 2px; }
.repeat-gs-agg { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.repeat-rowsort, .repeat-agg { display: grid; gap: 4px; }
.repeat-rowsort .repeat-row { display: grid; grid-template-columns: 1fr 96px 20px; gap: 4px; align-items: center; }
.repeat-agg .repeat-row { display: grid; grid-template-columns: 1fr 86px 1fr 20px; gap: 4px; align-items: center; }
/* grid children default to min-width: auto — a select as wide as its longest option would overflow the panel */
.page-repeat-group .field, .repeat-gs-agg > *, .repeat-rowsort .repeat-row > *, .repeat-agg .repeat-row > * { min-width: 0; }
.repeat-row .repeat-del { padding: 0; width: 20px; line-height: 1.4; color: var(--muted); }
.repeat-row .repeat-del:hover { color: var(--danger, #dc2626); }
.repeat-agg .repeat-add-agg { justify-self: start; }
.repeat-agg .side-hint { margin: 0; }
.repeat-preview { margin: 2px 0 0; font-weight: 600; color: var(--text); }
.repeat-preview-fields { margin: 0; font-family: ui-monospace, SFMono-Regular, Consolas, monospace; font-size: 11px; }

/* [datasets] "Biến đổi dữ liệu" — the dataset pipeline card of the Data tab                */
/* (public/js/datasetPanel.js, SPEC-DATASETS §5): the step chain, the per-step form and the */
/* live "vào N dòng → ra M dòng" preview.                                                    */
/* ---------------------------------------------------------------------- */
.data-ext:empty { display: none; }
.ds-section .prop-section-body { display: grid; gap: 6px; min-width: 0; }
.ds-section .field, .ds-section .ds-form-body > * { min-width: 0; }
.ds-section .ds-toolbar > select { flex: 1 1 120px; min-width: 0; }
.ds-sub-title { display: block; font-size: 11.5px; font-weight: 600; color: var(--muted); margin-top: 2px; }
.ds-steps { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
.ds-steps > li.side-hint { padding: 4px 2px; }
.ds-step { display: grid; grid-template-columns: 16px 18px 1fr auto; gap: 4px; align-items: center; padding: 2px 3px; border: 1px solid transparent; border-radius: 4px; background: var(--panel-alt, rgba(127, 127, 127, 0.06)); cursor: grab; }
.ds-step:active { cursor: grabbing; }
.ds-step.active { border-color: var(--accent, #2563eb); background: var(--accent-soft, #dbeafe); }
.ds-step-n { font-size: 10.5px; color: var(--muted); text-align: right; font-variant-numeric: tabular-nums; }
.ds-step-ico { font-size: 11px; color: var(--muted); text-align: center; }
.ds-step-main { display: grid; gap: 0; text-align: left; border: 0; background: none; padding: 1px 2px; cursor: pointer; min-width: 0; color: inherit; }
.ds-step-kind { font-size: 11.5px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ds-step-sum { font-size: 11px; color: var(--muted); font-family: ui-monospace, SFMono-Regular, Consolas, monospace; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ds-step-btns { display: flex; gap: 1px; }
.ds-step-btns .btn { padding: 0 2px; }
.ds-steps-sub .ds-step { grid-template-columns: 16px auto 1fr auto; cursor: default; }
.ds-del:hover { color: var(--danger, #dc2626); }
.ds-form { display: grid; gap: 4px; padding: 5px 6px; border: 1px solid var(--border); border-radius: 5px; }
.ds-form-body { display: grid; grid-template-columns: 1fr 1fr; gap: 5px 8px; align-items: start; }
.ds-form-body > .field.wide, .ds-form-body > .side-hint, .ds-form-body > .ds-list, .ds-form-body > .wide { grid-column: 1 / -1; }
.ds-list { display: grid; gap: 3px; }
.ds-list .ds-row { display: grid; grid-template-columns: 1fr 1fr 20px; gap: 4px; align-items: center; }
.ds-agg .ds-row { grid-template-columns: 1fr 96px 1fr 20px; }
.ds-sort .ds-row { grid-template-columns: 1fr 96px 20px; }
.ds-list .ds-row > *, .ds-list .ds-row .side-hint { min-width: 0; }
.ds-list .ds-row .side-hint { grid-column: 1 / -1; margin: 0; }
.ds-list .btn { justify-self: start; }
.ds-chips { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; }
.ds-chip { display: inline-flex; align-items: center; gap: 2px; padding: 1px 2px 1px 7px; border: 1px solid var(--border); border-radius: 10px; background: var(--accent-soft, #dbeafe); font-size: 11.5px; }
.ds-chip-name { font-variant-numeric: tabular-nums; }
.ds-chip-x { border: 0; background: none; color: var(--muted); font-size: 13px; line-height: 1; padding: 0 3px; cursor: pointer; }
.ds-chip-x:hover { color: var(--danger, #dc2626); }
.ds-chip-add { flex: 1 1 100px; min-width: 70px; }
.ds-preview { display: grid; gap: 3px; }
.ds-io { font-weight: 600; color: var(--text); font-variant-numeric: tabular-nums; }
.ds-preview-table { overflow: auto; max-height: 190px; border: 1px solid var(--border); border-radius: 4px; }
.ds-preview-table table { border-collapse: collapse; width: 100%; font-size: 11px; }
.ds-preview-table th, .ds-preview-table td { border-bottom: 1px solid var(--border); padding: 1px 5px; text-align: left; white-space: nowrap; }
.ds-preview-table thead th { position: sticky; top: 0; background: var(--panel, #fff); font-weight: 600; z-index: 1; }
.ds-preview-table tbody tr:nth-child(even) { background: var(--panel-alt, rgba(127, 127, 127, 0.05)); }
.ds-usage, .ds-core-note { font-family: ui-monospace, SFMono-Regular, Consolas, monospace; font-size: 10.5px; }
.ds-core-note { font-family: inherit; font-style: italic; }
/* [datasets] the two extra field-tree branches of the Data tab (dataPanel.js) */
.tree-branch { margin-top: 8px; }
.tree-branch-title { display: block; font-size: 11.5px; font-weight: 600; color: var(--muted); margin-bottom: 2px; }
.tree-branch-ds .tree-key, .tree-branch-prm .tree-key { font-family: ui-monospace, SFMono-Regular, Consolas, monospace; }

/* [params] "Tham số in" — the print-parameter card of the Page tab and the value dialog    */
/* (public/js/paramsPanel.js, SPEC-DATASETS §2 / §5).                                        */
/* ---------------------------------------------------------------------- */
.page-ext:empty { display: none; }
.page-params .prop-section-body { display: grid; gap: 6px; min-width: 0; }
.prm-card { border: 1px solid var(--border); border-radius: 5px; padding: 4px 6px 6px; display: grid; gap: 4px; }
.prm-card-head { display: flex; align-items: center; justify-content: space-between; gap: 6px; }
.prm-card-name { font-size: 11.5px; font-weight: 600; }
.prm-card-body { align-items: start; }
.prm-card-body > .field.wide, .prm-card-body > .side-hint, .prm-card-body > .wide { grid-column: 1 / -1; }
.prm-card-body .field, .prm-card-body select, .prm-card-body input { min-width: 0; }
.prm-flags { display: flex; flex-wrap: wrap; gap: 4px 12px; }
.prm-flags .field.check { padding: 0; }
.prm-del:hover { color: var(--danger, #dc2626); }
.prm-current { font-family: ui-monospace, SFMono-Regular, Consolas, monospace; font-size: 10.5px; }
.prm-dialog { display: grid; gap: 7px; }
.prm-dialog .prm-v { margin: 0; }
.prm-dialog select[multiple] { min-height: 62px; }
.prm-req { color: var(--danger, #dc2626); }
.tb-btn.tb-params[hidden] { display: none; }
.check-issue .check-new-card { margin-left: 4px; white-space: nowrap; }

/* [formulas] "Công thức" — the named-formula table of the Properties tab (empty state)      */
/* (public/js/formulasPanel.js, SPEC-DATASETS §3 / §5).                                      */
/* ---------------------------------------------------------------------- */
.prop-ext:empty { display: none; }
.prop-formulas .prop-section-body { display: grid; gap: 6px; min-width: 0; }
.fml-list { display: grid; gap: 3px; }
.fml-row { display: grid; grid-template-columns: 1fr 1.6fr 22px 22px; gap: 4px; align-items: center; }
.fml-row > * { min-width: 0; }
.fml-row .fml-msg { grid-column: 1 / -1; margin: 0; }
.fml-row .btn { padding: 0 2px; }
.fml-row input { font-size: 11.5px; }
.fml-del:hover { color: var(--danger, #dc2626); }
.fml-funcs { font-size: 10.5px; }

/* ------------------------------------------------------------------------------------------ */
/* [dsfix-fulldata] "Biến đổi dữ liệu": the preview runs the pipeline on the FULL sample data,  */
/* so the card says so next to the step title when the canvas is drawing the trimmed 200-row    */
/* view — the numbers in this card are the PRINT's, not the canvas's.                           */
/* ------------------------------------------------------------------------------------------ */
.ds-io.ds-io-full { font-weight: 400; color: var(--muted, #6b7280); font-size: 10.5px; }

/* ============================================================================================ */
/* [integrator] SPEC-AUTH-TENANT §3.2 / §5: the session chip on the toolbar, the "Báo cáo công   */
/* ty" card in the Data tab (public/js/reportSourcePanel.js), and viewer read-only hiding.        */
/* ============================================================================================ */

/* --- Toolbar session chip -------------------------------------------------------------------- */
.tb-session { display: flex; align-items: center; gap: 6px; margin-left: auto; padding-left: 8px; }
.session-chip { display: inline-flex; align-items: center; gap: 5px; max-width: 240px; padding: 2px 8px;
  border: 1px solid var(--border, #e5e7eb); border-radius: 999px; background: var(--panel-2, #f3f4f6);
  font-size: 12px; color: var(--text, #111827); white-space: nowrap; overflow: hidden; }
.session-chip .ico { flex: 0 0 auto; opacity: .75; }
.session-chip .session-user { font-weight: 600; overflow: hidden; text-overflow: ellipsis; }
.session-chip .session-unit { color: var(--muted, #6b7280); overflow: hidden; text-overflow: ellipsis; }
.session-chip .session-sep { color: var(--muted, #9ca3af); }
.session-station { max-width: 160px; }
.session-logout .tb-lbl { margin-left: 4px; }

/* --- "Báo cáo công ty" card ------------------------------------------------------------------ */
.rs-panel .rs-row { display: grid; gap: 4px; margin: 6px 0; }
.rs-panel .rs-row > label { display: grid; gap: 3px; font-size: 12px; color: var(--text-2, #374151); }
.rs-mini { font-size: 10.5px; color: var(--muted, #6b7280); }
.rs-warn { margin: 6px 0; font-size: 11.5px; }
.rs-preset-btns { margin-top: 4px; }
.rs-preset-btns .btn { padding: 0 6px; }
.rs-fields { display: grid; grid-template-columns: 1fr 1fr; gap: 6px 8px; margin: 8px 0; }
.rs-field { display: grid; gap: 2px; min-width: 0; }
.rs-field .rs-flabel { font-size: 11px; color: var(--muted, #6b7280); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rs-req { color: var(--danger, #dc2626); }
.rs-input { width: 100%; box-sizing: border-box; font-size: 12px; padding: 3px 6px;
  border: 1px solid var(--border, #d1d5db); border-radius: var(--radius, 6px);
  background: var(--panel, #fff); color: var(--text, #111827); }
.rs-input:focus { outline: 2px solid var(--accent, #2563eb); outline-offset: -1px; }
.rs-datewrap { display: grid; grid-template-columns: 1fr auto; gap: 4px; align-items: center; }
.rs-datepick { width: auto; padding: 2px 4px; }
.rs-actions { margin: 8px 0 4px; }
.rs-result { margin-top: 6px; }
.rs-status { font-size: 12px; font-weight: 600; padding: 3px 0; }
.rs-status.rs-ok { color: var(--success, #16a34a); }
.rs-status.rs-err { color: var(--danger, #dc2626); }
.rs-runlist { margin: 4px 0 0; padding-left: 16px; font-size: 11.5px; display: grid; gap: 2px; }
.rs-runlist li.rs-ok { color: var(--success, #16a34a); }
.rs-runlist li.rs-err { color: var(--danger, #dc2626); }
.rs-tree { max-height: 260px; overflow: auto; margin-top: 4px; padding: 4px 6px;
  border: 1px solid var(--border, #e5e7eb); border-radius: var(--radius, 6px);
  background: var(--panel-2, #f9fafb); font-family: var(--font-mono, monospace); font-size: 11.5px; }
.rs-sample { margin: 0; white-space: pre-wrap; word-break: break-word; }
.jt-list { list-style: none; margin: 0; padding-left: 12px; }
.jt-list > li { line-height: 1.5; }
.jt-key { background: none; border: none; padding: 0; margin: 0; cursor: pointer;
  color: var(--accent, #2563eb); font: inherit; }
.jt-key:hover { text-decoration: underline; }
.jt-val.jt-string { color: var(--success, #16a34a); }
.jt-val.jt-number { color: var(--accent-2, #7c3aed); }
.jt-null, .jt-empty { color: var(--muted, #9ca3af); }

/* --- Viewer read-only: hide edit controls (Open / Preview / Print / lang / help / session stay) */
body.role-viewer #toolbar [data-group="edit"],
body.role-viewer #toolbar [data-group="insert"],
body.role-viewer #toolbar [data-group="page"],
body.role-viewer #toolbar [data-group="check"],
body.role-viewer #fmtbar,
body.role-viewer #toolbox,
body.role-viewer [data-action="new"],
body.role-viewer [data-action="save"],
body.role-viewer [data-action="saveAs"],
body.role-viewer [data-action="delete"],
body.role-viewer [data-action="import"],
/* [viewer-fix] SPEC-AUTH-TENANT §5: the remaining template-editing entries the old rule left visible. */
body.role-viewer [data-action="importXlsx"],
body.role-viewer [data-action="importPdf"],
body.role-viewer [data-action="parameterize"],
body.role-viewer [data-action="history:saveNote"],
body.role-viewer .rs-actions [data-rs-act="save"],
body.role-viewer .rs-actions [data-rs-act="use-sample"],
body.role-viewer .rs-preset-btns { display: none !important; }

/* [viewer-fix] SPEC-AUTH-TENANT §5: a viewer may inspect the Properties / Layers panels but must not
   edit through them (inputs, toggles, per-row lock/hide). Read-only already refuses the commit; this
   removes the misleading affordance so a click does not look like it should have worked. */
body.role-viewer #panel-props input,
body.role-viewer #panel-props select,
body.role-viewer #panel-props textarea,
body.role-viewer #panel-props button,
body.role-viewer #layers button[data-action] {
  pointer-events: none !important;
  opacity: .55;
}
