/* ============================================================================
   Contour · Grid view
   Every rule is scoped under .view-grid. Every colour, size and duration comes
   from css/tokens.css — there is not one literal colour in this file.

   Layering inside the scroller (sticky is why these numbers exist):
     1  frozen body cell        3  header / footer row
     2  frozen group cell       4  frozen header / footer cell
   ========================================================================== */

.view-grid {
  --vg-row: var(--row-h);          /* shell drives --row-h from View.density */
  --vg-head: var(--col-header-h);
  --vg-foot: 32px;
  --vg-pad: var(--sp-2);
  font-size: var(--fs-base);
  line-height: var(--lh-base);
  color: var(--text);
}

.view-grid.vg-root {
  position: absolute;
  inset: 0;
  background: var(--canvas);
  outline: none;
}

.view-grid .vg-scroll {
  position: absolute;
  inset: 0;
  overflow: auto;
  overscroll-behavior: contain;
}

.view-grid.is-resizing { cursor: col-resize; user-select: none; }

/* ------------------------------------------------------------------ table -- */

.view-grid .vg-table {
  border-collapse: separate;
  border-spacing: 0;
  min-width: 100%;
  table-layout: fixed;
  background: var(--surface);
}

.view-grid .vg-th,
.view-grid .vg-td {
  box-sizing: border-box;
  padding: 0 var(--vg-pad);
  text-align: left;
  font-weight: var(--fw-regular);
  vertical-align: middle;
  background: var(--surface);
  border-right: var(--border-w) solid var(--line-2);
  border-bottom: var(--border-w) solid var(--line-2);
  overflow: hidden;
}

/* Element-qualified on purpose: .vg-cell and .vg-colhead also set `position`, and at
   equal specificity the later rule would win — turning the inline `left` offset into
   a relative shift that pushes the frozen column on top of its neighbour. */
.view-grid td.vg-frozen,
.view-grid th.vg-frozen { position: sticky; z-index: 1; }
.view-grid .vg-frozen-edge { border-right: var(--border-w) solid var(--line); }
.view-grid .vg-spacer-cell,
.view-grid .vg-col-spacer { border-right: 0; padding: 0; }
.view-grid .vg-spacer-cell { background: var(--canvas); }

/* ----------------------------------------------------------------- header -- */

.view-grid thead .vg-th {
  position: sticky;
  top: 0;
  z-index: 3;
  height: var(--vg-head);
  padding: 0;
  background: var(--canvas);
  border-bottom: var(--border-w) solid var(--line);
  color: var(--text-2);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
}
.view-grid thead .vg-th.vg-frozen { z-index: 4; }

/* visible, or the resize grip that straddles the column border gets clipped away */
.view-grid .vg-colhead { position: relative; overflow: visible; }

.view-grid .vg-colbtn {
  display: flex;
  align-items: center;
  gap: var(--sp-1);
  width: 100%;
  height: var(--vg-head);
  padding: 0 var(--sp-2);
  border: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.view-grid .vg-colbtn:hover { background: var(--hover); }
.view-grid .vg-colbtn:focus-visible {
  outline: var(--focus-ring-w) solid var(--focus-ring);
  outline-offset: -2px;
}
.view-grid .vg-colname { flex: 1 1 auto; min-width: 0; color: var(--text); }
.view-grid .vg-type-ic { color: var(--text-3); }
.view-grid .vg-req { color: var(--danger); font-weight: var(--fw-semibold); }
.view-grid .vg-flag { color: var(--accent); width: 12px; height: 12px; }
.view-grid .vg-sortflag { display: inline-flex; align-items: center; gap: 1px; }
.view-grid .vg-sortn { font-size: var(--fs-xs); color: var(--accent); }
.view-grid .vg-colcaret { color: var(--text-3); opacity: 0; transition: opacity var(--dur-fast) var(--ease); }
.view-grid .vg-colhead:hover .vg-colcaret,
.view-grid .vg-colbtn[aria-expanded="true"] .vg-colcaret { opacity: 1; }

.view-grid .vg-colhead.is-dragging { opacity: .5; }
.view-grid .vg-colhead.drop-before { box-shadow: inset 2px 0 0 0 var(--accent); }
.view-grid .vg-colhead.drop-after { box-shadow: inset -2px 0 0 0 var(--accent); }

.view-grid .vg-resize {
  position: absolute;
  top: 0;
  right: -3px;
  width: 7px;
  height: 100%;
  cursor: col-resize;
  z-index: 1;
}
.view-grid .vg-resize:hover { background: var(--accent); opacity: .5; }

.view-grid .vg-addcol { padding: 0; text-align: center; background: var(--canvas); }
.view-grid tbody .vg-addcol,
.view-grid tfoot .vg-addcol { background: var(--surface); }
.view-grid .vg-addbtn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: var(--vg-head);
  border: 0;
  background: transparent;
  color: var(--text-2);
  cursor: pointer;
}
.view-grid .vg-addbtn:hover { background: var(--hover); color: var(--text); }

/* ----------------------------------------------------------------- gutter -- */

.view-grid .vg-gutter {
  padding: 0 var(--sp-1);
  background: var(--surface);
}
.view-grid thead .vg-gutter,
.view-grid tfoot .vg-gutter { background: var(--canvas); }

/* A <td> must stay display:table-cell, so the gutter's row of controls lives in
   this wrapper instead of on the cell itself. */
.view-grid .vg-gut {
  display: flex;
  align-items: center;
  gap: 2px;
  height: var(--vg-row);
}
.view-grid .vg-gut-group { justify-content: center; height: auto; }

/* Row number and its checkbox share one slot. Hover swaps which is PAINTED —
   neither is ever display:none, so the checkbox stays tabbable and announced. */
.view-grid .vg-rowid {
  position: relative;
  flex: none;
  width: 22px;
  height: 16px;
}
.view-grid .vg-rownum {
  position: absolute;
  inset: 0;
  color: var(--text-2);
  font-size: var(--fs-sm);
  line-height: 16px;
  text-align: right;
}
.view-grid .vg-check {
  position: absolute;
  right: 2px;
  top: 1px;
  width: 14px;
  height: 14px;
  margin: 0;
  accent-color: var(--accent);
  cursor: pointer;
  opacity: 0;
}
.view-grid .vg-row:hover .vg-check,
.view-grid .vg-row.is-selected .vg-check,
.view-grid .vg-check:focus-visible { opacity: 1; }
.view-grid .vg-row:hover .vg-rownum,
.view-grid .vg-row.is-selected .vg-rownum,
.view-grid .vg-check:focus-visible ~ .vg-rownum { opacity: 0; }
.view-grid thead .vg-check { position: static; opacity: 1; }

.view-grid .vg-rowact {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  padding: 0;
  border: var(--border-soft);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text-2);
  cursor: pointer;
  opacity: 0;
}
.view-grid .vg-rowact:hover { background: var(--hover); color: var(--text); }
.view-grid .vg-row:hover .vg-rowact,
.view-grid .vg-rowact:focus-visible { opacity: 1; }

/* ------------------------------------------------------------------- rows -- */

.view-grid .vg-row .vg-td { height: var(--vg-row); }
.view-grid .vg-row:hover .vg-td { background: var(--hover); }
.view-grid .vg-row.is-selected .vg-td { background: color-mix(in srgb, var(--accent) 8%, var(--surface)); }

/* colour rules — first match wins, applied by the view from View.colorRules */
.view-grid .vg-row.rc-row .vg-td { background: color-mix(in srgb, var(--rc) var(--tint-weak), var(--surface)); }
.view-grid .vg-row.rc-row:hover .vg-td { background: color-mix(in srgb, var(--rc) var(--tint-chip), var(--surface)); }
.view-grid .vg-row.rc-marker .vg-gutter { box-shadow: inset 3px 0 0 0 var(--rc); }
.view-grid .vg-row.rc-cell .vg-cell:first-of-type { background: color-mix(in srgb, var(--rc) var(--tint-chip), var(--surface)); }
.view-grid .vg-row.rc-text .vg-text { color: color-mix(in srgb, var(--rc) 78%, var(--text)); }

.view-grid .vg-cell { position: relative; cursor: cell; outline: none; }
.view-grid .vg-cell.in-range { background: color-mix(in srgb, var(--accent) 9%, var(--surface)); }
.view-grid .vg-cell.in-fill { background: color-mix(in srgb, var(--accent) 5%, var(--surface)); box-shadow: inset 0 0 0 1px var(--accent-line); }
.view-grid .vg-cell.is-cursor {
  box-shadow: inset 0 0 0 2px var(--focus-ring);
  border-radius: 2px;
  z-index: 2;
}
.view-grid .vg-cell.is-computed { background: var(--sunken); }
.view-grid .vg-row:hover .vg-cell.is-computed { background: var(--active); }
.view-grid .vg-cell.is-computed .vg-text { color: var(--text-2); }
.view-grid .vg-fx {
  position: absolute;
  right: 3px;
  bottom: 2px;
  width: 10px;
  height: 10px;
  color: var(--text-3);
  opacity: 0;
}
.view-grid .vg-cell.is-computed:hover .vg-fx { opacity: 1; }

.view-grid .vg-cell.is-restricted { background: repeating-linear-gradient(135deg, var(--sunken) 0 6px, var(--surface) 6px 12px); }
.view-grid .vg-restricted {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  color: var(--text-2);
  font-size: var(--fs-sm);
  font-style: italic;
}

.view-grid .vg-text { display: block; min-width: 0; }
.view-grid .vg-right { text-align: right; }
.view-grid .vg-c-center { text-align: center; }
.view-grid .vg-a { color: var(--accent); text-decoration: none; }
.view-grid .vg-a:hover { text-decoration: underline; }
.view-grid .vg-text.is-suggested { color: var(--warning); display: inline-flex; align-items: center; gap: var(--sp-1); }

.view-grid[data-density="tall"] .vg-cell .vg-text {
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  white-space: normal;
  overflow: hidden;
}

/* value renderers */
.view-grid .vg-chips { display: flex; align-items: center; gap: var(--sp-1); min-width: 0; }
.view-grid .vg-chip { max-width: 100%; flex: 0 1 auto; }
.view-grid .vg-chip.is-unknown { border: var(--border-w) dashed color-mix(in srgb, var(--c) 55%, transparent); }

.view-grid .vg-person { display: inline-flex; align-items: center; gap: var(--sp-1); min-width: 0; font-size: var(--fs-sm); }
.view-grid .vg-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 20px;
  height: 20px;
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--c) var(--tint-chip), var(--surface));
  color: color-mix(in srgb, var(--c) 55%, var(--text));
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
}

.view-grid .vg-link {
  display: inline-flex;
  align-items: center;
  max-width: 100%;
  height: 24px;
  padding: 0 var(--sp-2);
  border: var(--border-soft);
  border-radius: var(--radius-sm);
  background: var(--sunken);
  color: var(--text);
  font-size: var(--fs-sm);
  cursor: pointer;
}
.view-grid .vg-link:hover { background: var(--active); border-color: var(--line); }

/* archived: kept in the references, marked rather than dropped */
.view-grid .vg-archived-tag {
  flex: none;
  padding: 0 var(--sp-1);
  border-radius: var(--radius-sm);
  background: var(--sunken); color: var(--text-2);
  font-size: var(--fs-xs); line-height: 16px; white-space: nowrap;
}
.view-grid .vg-link.is-archived { color: var(--text-2); gap: var(--sp-1); }
.view-grid .vg-link.is-archived .truncate { text-decoration: line-through; }

.view-grid .vg-files { display: flex; align-items: center; gap: var(--sp-1); min-width: 0; }
.view-grid .vg-thumb {
  flex: none;
  width: calc(var(--vg-row) - 10px);
  height: calc(var(--vg-row) - 10px);
  max-width: 44px;
  max-height: 44px;
  object-fit: cover;
  border-radius: var(--radius-sm);
  border: var(--border-soft);
  background: var(--sunken);
}
.view-grid .vg-file {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  min-width: 0;
  padding: 0 var(--sp-1);
  color: var(--text-2);
  font-size: var(--fs-sm);
}

.view-grid .vg-cb {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  padding: 0;
  border: var(--border-w) solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--on-accent);
  cursor: pointer;
}
.view-grid .vg-cb.is-on { background: var(--accent); border-color: var(--accent); }
.view-grid .vg-cb.is-unknown { border-style: dashed; }
.view-grid .vg-cb:hover { border-color: var(--accent); }

.view-grid .vg-stars { display: inline-flex; gap: 1px; }
.view-grid .vg-star {
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--line);
  cursor: pointer;
  line-height: 0;
}
.view-grid .vg-star.is-on { color: var(--obj-amber, var(--accent)); }
.view-grid .vg-star.is-on svg { fill: currentColor; }
.view-grid .vg-stars:hover .vg-star { color: color-mix(in srgb, var(--obj-amber, var(--accent)) 40%, var(--line)); }

/* -------------------------------------------------------------- group row -- */

.view-grid .vg-grouprow .vg-td {
  height: calc(var(--vg-row) + 4px);
  background: var(--sunken);
  border-bottom: var(--border-w) solid var(--line);
  border-top: var(--border-w) solid var(--line);
}
.view-grid .vg-grouprow .vg-gutter { text-align: center; }

.view-grid .vg-twisty {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  padding: 0;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-2);
  cursor: pointer;
}
.view-grid .vg-twisty:hover { background: var(--active); color: var(--text); }

.view-grid .vg-grouplabel {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  width: 100%;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--text);
  font: inherit;
  font-weight: var(--fw-semibold);
  text-align: left;
  cursor: pointer;
}
.view-grid .vg-grouphead { display: flex; align-items: center; gap: var(--sp-2); min-width: 0; }
.view-grid .vg-grouphead .vg-grouplabel { flex: 1 1 auto; min-width: 0; }

/* Opacity, never display:none — the control stays in the accessibility tree and on the
   Tab order whether or not a pointer is anywhere near the row. */
.view-grid .vg-groupadd {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 20px;
  height: 20px;
  padding: 0;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-3);
  cursor: pointer;
  opacity: 0;
}
.view-grid .vg-grouprow:hover .vg-groupadd,
.view-grid .vg-groupadd:focus-visible { opacity: 1; }
.view-grid .vg-groupadd:hover { background: var(--hover); color: var(--text); }

.view-grid .vg-groupdot {
  flex: none;
  width: 8px;
  height: 8px;
  border-radius: var(--radius-pill);
  background: var(--c, var(--accent));
}
.view-grid .vg-grouptext { min-width: 0; }
.view-grid .vg-groupcell { color: var(--text-2); font-size: var(--fs-sm); }
.view-grid .vg-aggv { display: block; text-align: right; color: var(--text-2); }

/* ------------------------------------------------------------- new + empty -- */

.view-grid .vg-newcell,
.view-grid .vg-emptycell {
  position: relative;
  padding: 0;
  background: var(--surface);
  border-right: 0;
}
.view-grid .vg-sticky { position: sticky; left: 0; width: min(100%, 100vw); }

.view-grid .vg-newbtn {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  width: 100%;
  height: var(--vg-row);
  padding: 0 var(--sp-3);
  border: 0;
  background: transparent;
  color: var(--text-2);
  font: inherit;
  cursor: pointer;
}
.view-grid .vg-newbtn:hover { background: var(--hover); color: var(--text); }

.view-grid .vg-emptybox {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-12) var(--sp-6);
  text-align: center;
}
.view-grid .vg-emptymark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: var(--radius-lg);
  background: var(--sunken);
  color: var(--text-3);
}
.view-grid .vg-ic-24 { width: 22px; height: 22px; }
.view-grid .vg-emptytitle {
  margin: 0;
  font-size: var(--fs-lg);
  line-height: var(--lh-lg);
  font-weight: var(--fw-semibold);
}
.view-grid .vg-emptybody {
  margin: 0;
  max-width: 460px;
  color: var(--text-2);
  font-size: var(--fs-md);
  line-height: var(--lh-md);
}
.view-grid .vg-emptyactions { display: flex; gap: var(--sp-2); margin-top: var(--sp-2); }

/* ----------------------------------------------------------------- footer -- */

.view-grid tfoot .vg-td {
  position: sticky;
  bottom: 0;
  z-index: 3;
  height: var(--vg-foot);
  background: var(--canvas);
  border-top: var(--border-w) solid var(--line);
  border-bottom: 0;
}
.view-grid tfoot .vg-td.vg-frozen { z-index: 4; }
.view-grid .vg-count { color: var(--text-2); font-size: var(--fs-sm); }

.view-grid .vg-summary {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--sp-1);
  width: 100%;
  height: var(--vg-foot);
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--text-2);
  font: inherit;
  font-size: var(--fs-sm);
  cursor: pointer;
}
.view-grid .vg-summary:hover { color: var(--text); }
.view-grid .vg-aggname { color: var(--text-2); font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: var(--tracking-caps); }
.view-grid .vg-aggadd { display: inline-flex; align-items: center; gap: var(--sp-1); opacity: 0; }
.view-grid .vg-summary:hover .vg-aggadd { opacity: 1; }
.view-grid .vg-summary.has-fn .vg-aggv { color: var(--text); font-weight: var(--fw-medium); }

/* ------------------------------------------------------------- fill handle -- */

.view-grid .vg-fill {
  position: absolute;
  right: -3px;
  bottom: -3px;
  width: 7px;
  height: 7px;
  border: var(--border-w) solid var(--surface);
  border-radius: 1px;
  background: var(--accent);
  cursor: crosshair;
  z-index: 3;
}

/* ---------------------------------------------------------------- editors -- */

.view-grid .vg-cell.is-editing {
  padding: 0;
  overflow: visible;
  z-index: 5;
  box-shadow: inset 0 0 0 2px var(--focus-ring);
}
.view-grid .vg-editwrap {
  position: relative;
  min-height: var(--vg-row);
  background: var(--surface);
}
.view-grid .vg-editwrap.is-long {
  position: absolute;
  inset: 0 auto auto 0;
  width: max(100%, 260px);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-md);
  z-index: 5;
}
.view-grid .vg-editor {
  display: block;
  width: 100%;
  height: var(--vg-row);
  padding: 0 var(--vg-pad);
  border: 0;
  background: transparent;
  color: var(--text);
  font: inherit;
  outline: none;
}
.view-grid .vg-editor-long {
  height: auto;
  min-height: calc(var(--vg-row) * 2);
  padding: var(--sp-1) var(--vg-pad);
  resize: vertical;
  line-height: var(--lh-md);
}

/* --------------------------------------------------------------- popovers -- */

.view-grid .vg-pop { z-index: var(--z-popover); }
.view-grid .vg-ghost-anchor { position: fixed; width: 1px; height: 1px; pointer-events: none; }
.view-grid .vg-ic { width: 16px; height: 16px; flex: none; }
.view-grid .vg-ic-on { color: var(--accent); margin-left: auto; }

.view-grid .vg-picker .vg-search { margin-bottom: var(--sp-1); }
.view-grid .vg-optlist { display: flex; flex-direction: column; gap: 1px; }
.view-grid .vg-optrow { gap: var(--sp-2); }
.view-grid .vg-optadd { display: flex; gap: var(--sp-1); padding-top: var(--sp-1); border-top: var(--border-soft); }
.view-grid .vg-optadd .input { flex: 1 1 auto; min-width: 0; }

.view-grid .vg-chosen { display: flex; flex-wrap: wrap; gap: var(--sp-1); }
.view-grid .vg-chosenchip {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  max-width: 100%;
  height: 22px;
  padding: 0 var(--sp-1) 0 var(--sp-2);
  border: var(--border-soft);
  border-radius: var(--radius-sm);
  background: var(--sunken);
  font-size: var(--fs-sm);
}
.view-grid .vg-chipx {
  display: inline-flex;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--text-3);
  cursor: pointer;
}
.view-grid .vg-chipx:hover { color: var(--danger); }

.view-grid .vg-flabel { display: flex; flex-direction: column; gap: var(--sp-1); }
.view-grid .vg-flabel .caps {
  font-size: var(--fs-xs);
  line-height: var(--lh-xs);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  color: var(--text-2);
}

/* ---------------------------------------------------------------- confirm -- */

/* One panel for every delete this view offers: the row menu and the bulk bar
   open the same thing, so there is one set of copy to keep true. */
.view-grid .vg-confirm-title { margin: 0; font-weight: var(--fw-semibold); }
/* The LIST scrolls, never the popover. A cascade can name a lot of records, and
   when the whole panel scrolls the autofocused footer button drags the heading
   — the sentence naming what is about to be deleted — off the top on a short
   viewport. Measured at 780x437: without this cap the title was not on screen
   when the panel opened. */
.view-grid .vg-confirm-list {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  max-height: 30vh;
  overflow-y: auto;
  margin: 0;
  padding-left: var(--sp-4);
  font-size: var(--fs-sm);
  color: var(--text-2);
}
.view-grid .vg-confirm-list li { margin: 0; }
.view-grid .vg-confirm-error {
  gap: var(--sp-2);
  align-items: flex-start;
  margin: 0;
  padding: var(--sp-2);
  border: var(--border-w) solid var(--danger-line);
  border-radius: var(--radius-sm);
  background: var(--danger-soft);
  color: var(--danger);
  font-size: var(--fs-sm);
}
.view-grid .vg-confirm-error .vg-ic { flex: none; margin-top: 1px; }

/* Same solid destructive button the builders and the record modal use, so the
   one delete flow does not wear a different face here. `.btn.primary.danger`
   alone paints red text on the accent fill. */
.view-grid .btn.primary.danger-solid {
  background: var(--danger);
  border-color: transparent;
  color: var(--text-inverse);
}
.view-grid .btn.primary.danger-solid:hover { background: var(--danger); opacity: 0.9; }

/* ----------------------------------------------------------- field editor -- */

.view-grid .vg-fe { gap: var(--sp-3); }
.view-grid .vg-fe-name { font-weight: var(--fw-medium); }
.view-grid .vg-fe-typebtn {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  width: 100%;
  height: var(--control-h);
  padding: 0 var(--sp-2);
  border: var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  cursor: pointer;
}
.view-grid .vg-fe-typebtn:hover { background: var(--hover); }
.view-grid .vg-fe-options { display: flex; flex-direction: column; gap: var(--sp-2); }
.view-grid .vg-sub { display: flex; flex-direction: column; gap: var(--sp-2); }
.view-grid .vg-vocabprev { flex-wrap: wrap; gap: var(--sp-1); }
.view-grid .vg-fe-toggles { display: flex; gap: var(--sp-4); }
.view-grid .vg-toggle { display: inline-flex; align-items: center; gap: var(--sp-1); font-size: var(--fs-sm); color: var(--text-2); }
.view-grid .vg-toggle input { accent-color: var(--accent); }
.view-grid .vg-fe-status { margin: 0; min-height: var(--lh-sm); }
.view-grid .vg-fe-status.is-bad { color: var(--danger); }

/* The consequence, said before the write — in the type menu, then in the panel. */
.view-grid .vg-fe-warn {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  margin: var(--sp-1);
  padding: var(--sp-2);
  border: var(--border-w) solid var(--warning-line);
  border-radius: var(--radius);
  background: var(--warning-soft);
  color: var(--warning);
  font-size: var(--fs-sm);
  line-height: var(--lh-sm);
}
.view-grid .vg-fe-warn .vg-ic { flex: none; margin-top: 1px; }
.view-grid .vg-fe-guard {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding: var(--sp-2);
  border: var(--border-w) solid var(--warning-line);
  border-radius: var(--radius);
  background: var(--warning-soft);
}
.view-grid .vg-fe-guard[hidden] { display: none; }
.view-grid .vg-fe-guardline {
  margin: 0;
  color: var(--warning);
  font-size: var(--fs-sm);
  line-height: var(--lh-sm);
}
.view-grid .vg-fe-guardacts { display: flex; flex-wrap: wrap; gap: var(--sp-2); }

.view-grid .vg-fe-create { display: flex; gap: var(--sp-2); padding-top: var(--sp-2); border-top: var(--border-soft); }
.view-grid .vg-fe-actions { border-top: var(--border-soft); border-radius: 0; }
.view-grid .vg-formula { font-family: var(--font-mono); font-size: var(--fs-sm); }
.view-grid .vg-formula-err { margin: 0; }
.view-grid .vg-formula-err.is-bad { color: var(--danger); }
.view-grid .vg-fieldrefs { display: flex; flex-wrap: wrap; gap: var(--sp-1); }
.view-grid .vg-ref {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  max-width: 140px;
  height: 22px;
  padding: 0 var(--sp-2);
  border: var(--border-soft);
  border-radius: var(--radius-sm);
  background: var(--sunken);
  color: var(--text-2);
  font-size: var(--fs-xs);
  cursor: pointer;
}
.view-grid .vg-ref:hover { background: var(--active); color: var(--text); }

/* ------------------------------------------------------- bulk bar + toast -- */

.view-grid .vg-bulkhost,
.view-grid .vg-toasthost {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  justify-content: center;
  pointer-events: none;
  z-index: var(--z-sticky);
}
/* Both hosts clear the FOOTER *and* the last body row, because the last body row is
   "+ Add <record>" — the primary affordance of the whole view — and it lands directly
   above the sticky footer whenever the table is shorter than the scroller. Offsetting
   by the footer alone parked a toast on top of it for the six seconds it lives:
     cannot click ".vg-newbtn": covered at (788,753) by <div.vg-toast.vg-toast-good>
   --vg-row is the height of that row (.vg-newbtn), so this tracks row density.

   The gap is --sp-6 rather than --sp-3 because these hosts are positioned against the
   view ROOT, and the root's bottom edge is below the scroller's horizontal scrollbar.
   A 12px gap measured -3px — i.e. still 3px into the add row — against chromium's 15px
   scrollbar. --sp-6 clears it with the bar and reads as ordinary air without one.
   The 36px that separates the two hosts when both are up is unchanged. */
.view-grid .vg-bulkhost { bottom: calc(var(--vg-foot) + var(--vg-row) + var(--sp-6)); }
.view-grid .vg-toasthost { bottom: calc(var(--vg-foot) + var(--vg-row) + var(--sp-6)); }
.view-grid .vg-bulkhost:not(:empty) ~ .vg-toasthost { bottom: calc(var(--vg-foot) + var(--vg-row) + var(--sp-12) + var(--sp-3)); }
.view-grid .vg-bulkhost > *,
.view-grid .vg-toasthost > * { pointer-events: auto; }

.view-grid .vg-bulk,
.view-grid .vg-toast {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  max-width: min(720px, calc(100vw - 48px));
  padding: var(--sp-2) var(--sp-2) var(--sp-2) var(--sp-3);
  border: var(--border);
  border-radius: var(--radius-lg);
  background: var(--raised);
  box-shadow: var(--shadow-lg);
  animation: vg-rise var(--dur-panel) var(--ease);
}
.view-grid .vg-bulkn { font-weight: var(--fw-semibold); }
.view-grid .vg-toast-msg { font-size: var(--fs-sm); }
.view-grid .vg-toast-bad { border-color: var(--danger-line); background: var(--danger-soft); color: var(--text); }
.view-grid .vg-toast-bad > .vg-ic { color: var(--danger); }
.view-grid .vg-toast-good > .vg-ic { color: var(--success); }
.view-grid .vg-toast-info > .vg-ic { color: var(--info); }

@keyframes vg-rise {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: none; }
}

.view-grid .vg-live {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* ----------------------------------------------------------- config panel -- */

.view-grid.vg-cfg { display: flex; flex-direction: column; gap: var(--sp-2); }
.view-grid .vg-cfg-list { display: flex; flex-direction: column; gap: var(--sp-1); max-height: 260px; overflow-y: auto; }
.view-grid .vg-cfg-row { display: flex; align-items: center; gap: var(--sp-2); }
.view-grid .vg-cfg-row .select { flex: none; width: 104px; }
.view-grid .vg-cfg-foot { margin: 0; }
