/* ─────────────────────────────────────────────────────────────────────────
   utilities.css — layout primitives, small helpers, the opt-in .dense density
   layer, and print rules. var(--token) only. Loaded last so utilities win.
   ───────────────────────────────────────────────────────────────────────── */

/* ═══════════════ Layout & text helpers ════════════════════════════════════*/
.container { max-width: var(--maxw); margin-inline: auto; }
.stack > * + * { margin-top: var(--space-4); }
.cluster { display: flex; gap: var(--space-3); align-items: center; flex-wrap: wrap; }
.between { display: flex; justify-content: space-between; align-items: center; gap: var(--space-3); }
.grow { flex: 1; }
.spacer { flex: 1 1 auto; }

.muted  { color: var(--text-soft); }
.faint  { color: var(--text-muted); }
.mono   { font-family: var(--font-mono); }
.tnum   { font-variant-numeric: tabular-nums; }
.nowrap { white-space: nowrap; }        /* dates + IDs: never wrap */
.text-xs { font-size: var(--fs-xs); }
.text-sm { font-size: var(--fs-sm); }
.text-danger  { color: var(--st-danger-fg); }
.text-warning { color: var(--st-warning-fg); }
.text-success { color: var(--st-success-fg); }

.mt-2 { margin-top: var(--space-2); }
.mt-3 { margin-top: var(--space-3); }
.mt-4 { margin-top: var(--space-4); }
.mt-5 { margin-top: var(--space-5); }
.mb-2 { margin-bottom: var(--space-2); }
.mb-4 { margin-bottom: var(--space-4); }
.float-right { float: right; }

/* Visibility toggles (JS-driven). .is-hidden and [hidden] win over any display -
   a .btn is inline-flex, which otherwise beats the UA [hidden] rule (the Edit
   button showed on tabs with nothing to edit). */
.is-hidden, [hidden] { display: none !important; }
.cluster > .form-input { width: auto; flex: 1 1 200px; }
.sr-only, .vh {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* Card / KPI grids that establish a query container for their children. */
.card-grid {
  display: grid; gap: var(--space-4);
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  container-type: inline-size;
}

/* ═══════════════════════════════════════════════════════════════════════════
   Density layer (opt-in) — add `.dense` to a page container to compact the
   vertical rhythm on data-heavy internal-tool pages.

   Research-backed values ported verbatim from farmbelt (2026-07): mouse-first
   32px controls (WCAG 2.2 target-size ≥24px, comfortably clear), input font
   held at 16px so iOS never zooms, line-height ≥1.35. Compaction comes ONLY
   from cutting margins/padding — never from shrinking fonts or crushing
   line-height. Scoped so untouched pages keep comfortable spacing.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Sticky action bar + back link */
.dense .page-action-bar         { padding: 0.65rem 0; margin-bottom: 0.6rem; }
.dense .page-action-bar-actions { gap: 0.4rem; }
.dense .back-link               { min-height: 36px; padding: 0.3rem 0.45rem; font-size: var(--fs-sm); }
.dense .page-action-bar .btn    { min-height: 36px; }

/* Cards */
.dense .card + .card { margin-bottom: var(--space-2); }
.dense .card-header  { padding: 0.4rem var(--space-3); }     /* 16/20 → ~6/12 */
.dense .card-body    { padding: var(--space-3); }            /* 20 → 12 */
.dense .card-body > * + * { margin-top: var(--space-3); }

/* Fields — 32px control, 16px font kept (inherited), tighter box only */
.dense .form-group  { margin-bottom: var(--space-2); }       /* 20 → 8 */
.dense .form-label  { margin-bottom: 0.125rem; font-size: var(--fs-sm); }   /* 6 → 2 */
.dense .form-input,
.dense .form-select,
.dense .form-textarea {
  min-height: var(--control-dense);                          /* 44 → 32 */
  padding: 0.25rem 0.5rem;                                   /* 10/12 → 4/8 */
  line-height: 1.35;
  /* font-size stays 16px (inherited) — keeps iOS zoom off */
}
.dense .form-textarea { min-height: 52px; }                  /* 96 → 52 */
.dense .form-select   { min-width: 0; padding-right: 1.75rem; }
.dense .form-help     { margin-top: 0.0625rem; font-size: var(--fs-xs); }
.dense .form-row      { gap: 0.4rem 0.75rem; }
.dense .form-actions  { padding-top: var(--space-2); margin-top: var(--space-3); }

/* Buttons — still ≥24px (WCAG 2.2 floor) */
.dense .btn    { min-height: var(--control-dense); padding: 0.3rem 0.7rem; }
.dense .btn-sm { min-height: 28px; padding: 0.2rem 0.55rem; }

/* Tables + tiles pull their block padding in (inline padding/type untouched) */
.dense .data-table th,
.dense .data-table td { padding-block: var(--space-2); }
.dense .kpi-card { padding: var(--space-3) var(--space-4); gap: var(--space-1); }
.dense .kpi-grid { gap: var(--space-3); margin-bottom: var(--space-4); }

/* ═══════════════════════════════════════════════════════════════════════════
   Print — strip app chrome, flatten to black-on-white documents.
   ═══════════════════════════════════════════════════════════════════════════ */
@media print {
  .sidebar, .bottom-nav, .mobile-topbar,
  .page-action-bar, .filter-bar, .toast-region,
  .app-search, .back-link, .danger-zone { display: none !important; }

  body { background: #fff; color: #000; }
  .app { display: block; }
  .main { padding: 0; }
  .card { border: 1px solid #000; box-shadow: none; break-inside: avoid; }

  .table-scroll { overflow: visible; border: none; }
  .data-table { font-size: 11pt; }
  .data-table thead th { color: #000; border-bottom: 1px solid #000; }
  .data-table td { border-bottom: 1px solid #999; }
  .data-table tbody tr:nth-child(even) { background: #fff; }
  a { color: #000; text-decoration: none; }
}
