/* ============================================================================
   Data grid — the spreadsheet LENS for records (Transactions, Invoices).
   An alternative view to the cards for accountants doing bulk/power work.

   Principles (Peter, 24 Jul 2026):
   - Real <table> for the a11y floor (th/td, aria-sort). Wide = scroll inside
     .data-grid__wrap, never the page body.
   - QUIET WHEN FINE, LOUD WHEN NOT. A fully-reconciled row is calm (a faint
     tick, plain text). Gaps — no receipt, VAT?, uncategorised, unlinked — carry
     ALL the visual weight (.data-grid__gap / .data-grid__flag). Never a wall of
     icons: category + VAT shout in their OWN columns; the Status column only
     carries what those columns don't (receipt, unlinked).
   - Editing is DRAWER-ONLY. No inline cell editing, no per-cell dropdowns. The
     gap markers are read-only <span>s; the whole row click opens the edit drawer.
   - Multi-select reuses the app's select convention: selected = grey subtle
     fill + text border (same as the .row-card select mode), NOT the yellow
     highlighter (that's reserved for the just-acted flash).
   ============================================================================ */

/* Smooth Card ⇄ Grid swap — fade the old view down + out, switch, then settle the new one in with a
   little VERTICAL bounce only (no horizontal motion, so the body never shifts sideways). The grid
   stays in the same centered frame as the cards — it never widens, so it can't slide under the sidebar. */
.view-exit { animation: viewExit .17s cubic-bezier(0.32, 0, 0.1, 1) both; }
.view-enter { animation: viewEnter .5s cubic-bezier(0.34, 1.34, 0.64, 1) both; }
@keyframes viewExit { to { opacity: 0; transform: translateY(6px); } }
@keyframes viewEnter { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .view-exit, .view-enter { animation: none; } }

.data-grid__wrap {
  /* No scroll container on desktop: an overflow container would anchor the sticky <thead> to the
     wrap (which scrolls away) instead of the page header. The widened frame fits every column, so
     we only need horizontal scroll on narrow screens (where the sticky header relaxes). */
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  margin-bottom: 88px;   /* clearance so the floating bulk bar never hides the last rows */
}
@media (max-width: 680px) {
  /* Mobile only: fixed columns can't fit, so allow horizontal scroll (the sticky header relaxes here;
     the grid gets a dedicated mobile pass later). */
  .data-grid__wrap { overflow-x: auto; }
}

.data-grid {
  width: 100%;
  /* Fixed layout: columns fit any width and truncate rather than overflow, so there is NO scroll
     container — that's the only way the sticky <thead> can anchor to the page header at every width.
     (An overflow container would re-anchor it to the wrap, which scrolls away.) */
  table-layout: fixed;
  border-collapse: collapse;
  font-size: var(--text-sm);
  color: var(--color-text);
  font-variant-numeric: tabular-nums;
}

/* Header — muted, quiet; docks right under the page's sticky header (the Missing-information card),
   tracking its live height so it never slides beneath it. --tx-gridhead-top is kept in sync in JS. */
.data-grid thead th {
  position: sticky;
  top: var(--tx-gridhead-top, 0px);
  z-index: 2;
  background: var(--color-surface);
  text-align: left;
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  color: var(--color-text-muted);
  padding: 10px 10px;
  border-bottom: var(--border-width) solid var(--color-border);
  white-space: nowrap;
}
.data-grid thead th.data-grid__th--amount { text-align: right; }
.data-grid thead th.data-grid__th--check { width: 44px; padding-right: 0; }

/* Sortable header = a button filling the cell, with a caret that appears on
   hover / when the column is the active sort. */
.data-grid__sort {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  font: inherit;
  color: inherit;
  cursor: pointer;
}
.data-grid__th--amount .data-grid__sort { flex-direction: row-reverse; }
/* Caret only reserves space on the ACTIVE sort column, so short headers (VAT, Date) never clip. */
.data-grid__sort .data-grid__caret { width: 14px; height: 14px; flex: none; display: none; }
.data-grid thead th[aria-sort] .data-grid__caret { display: inline-flex; }
.data-grid thead th[aria-sort="ascending"] .data-grid__caret { transform: rotate(180deg); }
.data-grid thead th[aria-sort] .data-grid__sort { color: var(--color-text); font-weight: var(--weight-medium); }

/* Body cells */
.data-grid tbody td {
  padding: 10px 10px;
  border-bottom: var(--border-width) solid var(--color-border);
  vertical-align: middle;
  white-space: nowrap;
}
/* Truncate ONLY the free-text columns — never the checkbox/status/amount cells (their flex/short
   content was rendering a stray "…" when the whole cell got text-overflow). */
.data-grid__desc, .data-grid__td--muted, .data-grid__td--ell { overflow: hidden; text-overflow: ellipsis; }
.data-grid tbody tr:last-child td { border-bottom: none; }
.data-grid__row { cursor: pointer; }
.data-grid__row:hover td { background: var(--color-bg-subtle-light); }

.data-grid__desc { font-weight: var(--weight-medium); }
.data-grid__td--muted { color: var(--color-text-muted); }
.data-grid__td--amount { text-align: right; font-variant-numeric: tabular-nums; }
.data-grid__amt-in { color: var(--color-success); }

/* Checkbox cell — real <input> (no per-cell affordance smell; it's selection). */
.data-grid__td--check { width: 44px; padding-right: 0; }
.data-grid__cb { display: inline-flex; }
.data-grid__cb input {
  appearance: none; -webkit-appearance: none;
  width: 20px; height: 20px; margin: 0;
  border: 2px solid var(--color-border-strong);
  border-radius: 6px;
  background: var(--color-surface);
  cursor: pointer;
  position: relative;
  flex: none;
}
.data-grid__cb input:checked {
  background: var(--color-text);
  border-color: var(--color-text);
}
.data-grid__cb input:checked::after {
  content: "";
  position: absolute; inset: 0;
  background: no-repeat center/12px url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E");
}
.data-grid__cb input:focus-visible { outline: 2px solid var(--color-hilite-strong); outline-offset: 2px; }

/* Selected row — the app's select-mode look (grey subtle + text border), NOT
   the yellow highlighter. */
.data-grid__row.is-selected td { background: var(--color-bg-subtle); }
.data-grid__row.is-selected td:first-child { box-shadow: inset 3px 0 0 var(--color-text); }

/* Quiet "done" states */
.data-grid__ok {
  display: inline-flex; align-items: center; gap: 6px;
  color: var(--color-success);
  opacity: .55;                 /* faint — reassurance, not a shout */
  font-size: var(--text-xs);
}
.data-grid__ok svg { width: 15px; height: 15px; }

/* SUGGESTED value — a category/VAT the system guessed but the user hasn't confirmed.
   Shown muted with a dotted underline (matches the card view, which also shows the
   suggestion) so the row doesn't read as blank — but it's clearly "confirm me", not done. */
.data-grid__sugg {
  color: var(--color-text-muted);
  border-bottom: 1px dotted var(--color-border-strong);
}

/* Row currently open in the edit drawer — a steady yellow box so you can see WHICH
   row the drawer is editing while you walk prev/next (connect the views). Ring, no fill. */
.data-grid__row.is-editing td {
  box-shadow: inset 0 1px 0 var(--color-hilite-strong), inset 0 -1px 0 var(--color-hilite-strong);
}
.data-grid__row.is-editing td:first-child {
  box-shadow: inset 0 1px 0 var(--color-hilite-strong), inset 0 -1px 0 var(--color-hilite-strong), inset 1px 0 0 var(--color-hilite-strong);
}
.data-grid__row.is-editing td:last-child {
  box-shadow: inset 0 1px 0 var(--color-hilite-strong), inset 0 -1px 0 var(--color-hilite-strong), inset -1px 0 0 var(--color-hilite-strong);
}

/* LOUD gap markers — the eye-drawers. Read-only (spans), the row opens the drawer. */
.data-grid__gap {
  display: inline-flex; align-items: center;
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  color: var(--color-danger);
  border: 1px dashed var(--color-danger-border);
  background: var(--color-danger-bg);
  border-radius: var(--radius-full);
  padding: 3px 10px;
}
.data-grid__flag {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  color: var(--color-active);
}
.data-grid__flag::before {
  content: ""; width: 7px; height: 7px; border-radius: 50%;
  background: var(--color-active); flex: none;
}
.data-grid__flag--unlinked { color: var(--color-info); }
.data-grid__flag--unlinked::before { background: var(--color-info); }

/* Plain-English explanation on hover/focus — "Unlinked" is jargon on its own. */
.data-grid__flag[data-tip] { position: relative; cursor: help; }
.data-grid__flag[data-tip]::after {
  content: attr(data-tip);
  position: absolute; bottom: calc(100% + 8px); left: 0;
  white-space: nowrap;
  background: var(--color-text); color: var(--color-surface);
  font-size: var(--text-xs); font-weight: var(--weight-regular);
  padding: 5px 9px; border-radius: var(--radius-sm);
  box-shadow: var(--shadow-dropdown);
  opacity: 0; pointer-events: none; transition: opacity .15s ease; z-index: 9;
}
.data-grid__flag[data-tip]:hover::after, .data-grid__flag[data-tip]:focus-visible::after { opacity: 1; }
@media (hover: none) { .data-grid__flag[data-tip]::after { display: none; } }
.data-grid__statuscell { display: inline-flex; align-items: center; flex-wrap: wrap; gap: 4px 12px; }

/* Locked / filed-period row — bulk heavier actions skip these. */
.data-grid__row.is-locked { }
.data-grid__lock {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: var(--text-xs); color: var(--color-text-muted);
}
.data-grid__lock svg { width: 13px; height: 13px; }

/* Just-acted flash — the yellow highlighter, then fades (rings flash, never stay). */
.data-grid__row.is-flash td { animation: dgFlash 2.4s ease both; }
@keyframes dgFlash {
  0%, 55% { box-shadow: inset 0 1px 0 var(--color-hilite-strong), inset 0 -1px 0 var(--color-hilite-strong); background: var(--color-hilite); }
  100% { box-shadow: none; background: transparent; }
}
@media (prefers-reduced-motion: reduce) { .data-grid__row.is-flash td { animation: none; } }

/* ---- Bulk-action bar ("Bulk edit") ----------------------------------------
   The point of the grid: select rows, then act on many at once (categorise, set
   VAT, tag, reconcile, export). A titled floating panel in the MOBILE APP's
   FloatingMenu language — white, black icons/text, transparent item buttons,
   16px radius, soft lift. Appears the moment a row is selected. */
.data-gridbar {
  position: fixed;
  left: 50%;
  bottom: 24px;
  transform: translateX(-50%);
  z-index: 9995;
  display: flex;
  flex-direction: column;
  gap: 2px;
  max-width: calc(100vw - 32px);
  /* Slightly translucent, frosted — the mobile app feel. */
  background: rgba(255, 255, 255, 0.82);
  -webkit-backdrop-filter: saturate(180%) blur(16px);
  backdrop-filter: saturate(180%) blur(16px);
  color: var(--color-text);
  border-radius: var(--radius-lg);
  padding: 9px 12px;
  box-shadow: 0 12px 34px rgba(12, 12, 13, 0.16);
}
.data-gridbar__head { display: flex; align-items: baseline; gap: 8px; padding: 0 6px; }
.data-gridbar__title { font-weight: var(--weight-bold); font-size: var(--text-sm); }
.data-gridbar__n { font-size: var(--text-xs); color: var(--color-text-muted); white-space: nowrap; }
.data-gridbar__acts { display: flex; align-items: center; gap: 2px; flex-wrap: wrap; }
.data-gridbar__act {
  display: inline-flex; align-items: center; gap: 7px;
  background: none; border: none;
  color: var(--color-text);
  font: inherit; font-size: var(--text-sm); font-weight: var(--weight-medium);
  padding: 7px 10px; border-radius: var(--radius-md);
  cursor: pointer;
  white-space: nowrap;
}
.data-gridbar__act:hover { background: var(--color-bg-subtle); }
.data-gridbar__act:active { transform: scale(0.96); }   /* the FloatingMenu's press feel */
.data-gridbar__act svg { width: 16px; height: 16px; flex: none; color: var(--color-text); }
/* Clear sits top-right in the head, quiet, so the panel stays short. */
.data-gridbar__clear {
  margin-left: auto;
  background: none; border: none; color: var(--color-text-muted);
  font: inherit; font-size: var(--text-xs); cursor: pointer;
  padding: 2px 4px; border-radius: var(--radius-sm);
}
.data-gridbar__clear:hover { color: var(--color-text); text-decoration: underline; }

/* ---- Progress overlay (large sync batches) -------------------------------- */
.data-gridprog {
  position: fixed; left: 50%; bottom: 32px; transform: translateX(-50%);
  z-index: 10050;
  background: var(--color-text); color: var(--color-surface);
  border-radius: var(--radius-md); box-shadow: var(--shadow-dropdown);
  padding: 14px 20px; min-width: 280px;
  font-size: var(--text-sm);
}
.data-gridprog__label { display: flex; justify-content: space-between; gap: 16px; margin-bottom: 8px; }
.data-gridprog__track { height: 6px; border-radius: var(--radius-full); background: rgba(255,255,255,.22); overflow: hidden; }
.data-gridprog__fill { height: 100%; width: 0; background: var(--color-surface); transition: width .12s linear; }

/* ---- View toggle (Cards | Grid) ------------------------------------------- */
.view-toggle {
  display: inline-flex;
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-md);
  overflow: hidden;
  flex: none;
}
.view-toggle__btn {
  display: inline-flex; align-items: center; gap: 7px;
  background: var(--color-surface);
  border: none;
  padding: 8px 14px;
  font-size: var(--text-sm); font-weight: var(--weight-medium);
  color: var(--color-text);
  cursor: pointer;
}
.view-toggle__btn:hover { background: var(--color-bg-subtle); }
.view-toggle__ico { display: inline-flex; }
.view-toggle__btn svg { width: 16px; height: 16px; flex: none; }
.view-toggle__btn:focus-visible { outline: 2px solid var(--color-hilite-strong); outline-offset: -2px; }

@media (max-width: 640px) {
  .data-grid__desc { max-width: 140px; }
  .data-gridbar { gap: 4px; padding: 8px 10px; }
  .view-toggle__btn span { display: none; }   /* icon-only on narrow */
}
