/* js-grid shared styles (see ~/js/js-grid.js) */
.js-grid th.sortable { cursor: pointer; user-select: none; white-space: nowrap; }
.js-grid th.sortable::before { content: "\2195"; opacity: .3; margin-right: .35rem; font-size: .8em; }
.js-grid th.sortable.asc::before  { content: "\2191"; opacity: .9; }
.js-grid th.sortable.desc::before { content: "\2193"; opacity: .9; }
.js-grid th.sortable:focus-visible { outline: 2px solid var(--tblr-primary, #206bc4); outline-offset: -2px; }
.js-grid .grid-filters th {
    background-color: var(--tblr-bg-surface-tertiary, #f1f4f9);
    padding-top: .55rem; padding-bottom: .55rem;
    border-top: 1px solid var(--tblr-border-color, #e6e7e9);
    border-bottom: 1px solid var(--tblr-border-color, #e6e7e9);
}
.js-grid .grid-filters th .form-control { background-color: #fff; }
/* Filter-row inputs + Add button: full size to match the toolbar (override the -sm). */
.js-grid .grid-filters .form-control,
.js-grid .grid-filters .form-select { min-height: 2.25rem; height: 2.25rem; font-size: .875rem; padding: .4375rem .75rem; background-color: #fff; }
.js-grid .grid-filters .btn { min-height: 2.25rem; font-size: .875rem; padding: .4375rem .75rem; }
/* Filter placeholders: lighter / more subtle than the default. */
.js-grid .grid-filters .form-control::placeholder { color: #b6bcc6; opacity: 1; }
.js-grid tbody tr:hover { background-color: rgba(32,107,196,.06); }
.js-grid td.editable { cursor: text; }
.js-grid td.editable:hover { box-shadow: inset 0 0 0 1px rgba(32,107,196,.25); border-radius: 3px; }
.js-grid tr.row-flash > td { animation: rowflash 1.2s linear; }
@keyframes rowflash { from { background-color: rgba(47,179,68,.30); } to { background-color: transparent; } }
.js-grid tbody tr.sortable-ghost { opacity: .4; }
/* The grid scrolls vertically inside this box so the header can stick to its top. */
.js-grid-wrap { max-height: 72vh; overflow: auto; }
.js-grid thead th { position: sticky; z-index: 2; background-color: var(--tblr-bg-surface, #fff); }
.js-grid thead tr:first-child th { top: 0; }
.js-grid thead tr.grid-filters th { top: 2.55rem; }
/* Column-chooser popup must layer over the sticky table header (it drops down from the
   toolbar, so it naturally stays below the search/actions row). */
#gridColsMenu { z-index: 1030; }
/* "+N more columns" badge on the column-chooser button (neutral, informational — not a warning). */
.js-cols-count {
    position: absolute; top: -.35rem; right: -.35rem; min-width: 1.05rem; height: 1.05rem;
    padding: 0 .25rem; border-radius: .6rem; background: var(--tblr-secondary, #6c757d); color: #fff;
    font-size: .62rem; line-height: 1.05rem; text-align: center; font-weight: 600; pointer-events: none;
}
.btn-warning .js-cols-count { background: rgba(0,0,0,.45); }   /* stays legible on the orange state */
/* Bulk-action strip: sits between the search toolbar and the column filters.
   Uses display:flex (not the d-flex !important utility) so the JS can hide it
   via an inline display:none when nothing is selected. */
.js-grid-bulkbar { display: flex; background: var(--tblr-bg-surface-secondary, #f6f8fb); }
.js-grid td.cell-error { box-shadow: inset 0 0 0 2px rgba(214,57,57,.6); border-radius: 3px; }
/* Inline edit: input fills the cell; the save button floats just outside the right edge. */
.js-grid td.editing { position: relative; overflow: visible; }
/* Size the inline editor to match the header filter boxes (see .grid-filters .form-select). */
.js-grid td.editing .form-control,
.js-grid td.editing .form-select { min-height: 2.25rem; height: 2.25rem; font-size: .875rem; padding: .4375rem .75rem; }
.js-grid td.editing .js-cell-save {
    position: absolute; left: 100%; top: 50%; transform: translateY(-50%);
    margin-left: .25rem; z-index: 6; box-shadow: 0 1px 4px rgba(0,0,0,.25);
}
/* Rightmost editable cell: keep the save button inside so it never pushes horizontal scroll. */
.js-grid td.editing .js-cell-save.js-cell-save-inside { left: auto; right: .15rem; margin-left: 0; box-shadow: none; }
/* Frozen leading columns (name + the selector/handle before it) stay put on horizontal scroll. */
.js-grid .js-frozen { background: var(--tblr-bg-surface, #fff); }
.js-grid tbody tr:hover .js-frozen { background: #eef4fb; }
.js-grid thead .js-frozen { z-index: 4; }
/* Cell-select (spreadsheet) mode: highlighted cell you can arrow around. */
.js-grid td.cell-selected { box-shadow: inset 0 0 0 2px var(--tblr-primary, #206bc4); border-radius: 2px; }
/* Small clear (×) inside the catch-all search box. */
.js-search-clear {
    position: absolute; right: .15rem; top: 50%; transform: translateY(-50%);
    width: 1.3rem; height: 1.3rem; min-height: 1.3rem; padding: 0;
    border: 0; background: transparent; color: var(--tblr-secondary, #667382); z-index: 5;
}
.js-search-clear:hover { color: var(--tblr-red, #d63939); }
.js-search-clear i { font-size: .9rem; }
/* Row action buttons (edit / delete) — slightly bigger than btn-sm for easier clicking. */
.js-grid tbody td .btn-list .btn-icon { width: 2rem; height: 2rem; }
.js-grid tbody td .btn-list .btn-icon i { font-size: 1.05rem; }

/* ── The grid on a phone (mobile audit 2026-08-08) ───────────────────────────────────────────────────
   admin.css sets a phone floor for every control: 16px type (below which iOS Safari zooms the page on
   focus) and a 40px tap target. The rules above are written as `.js-grid .grid-filters .form-control` —
   three classes — so they OUTRANK that floor and the grid kept its .875rem/2.25rem desktop sizing. Every
   filter box on Projects, FAQ, Courses, Forms and Customers still zoomed the page when tapped.
   Restated here at matching specificity. Desktop is untouched. */
@media (max-width: 767.98px) {
    /* The shared grid toolbar (search + Search + Clear/Add/columns/Download) is a single non-wrapping flex
       row with a fixed 17rem search box — on a phone that runs off the right edge (e.g. Forms, ~672px).
       Let it wrap: the search fills row one and the action buttons drop below, instead of scrolling the page. */
    .js-grid-toolbar .input-icon { flex: 1 1 8rem; }
    .js-grid-toolbar .adm-input-17r { width: auto; min-width: 0; }
    .js-grid-toolbar .ms-auto { margin-left: 0 !important; }

    .js-grid .grid-filters .form-control,
    .js-grid .grid-filters .form-select,
    .js-grid td.editing .form-control,
    .js-grid td.editing .form-select {
        font-size: 16px; min-height: 40px; height: auto;
    }
    .js-grid .grid-filters .btn { font-size: 16px; min-height: 40px; }

    /* A data grid is genuinely wider than a phone — 671px on Customers, 783px on Courses. It should
       SCROLL, inside its own box, rather than stretching the page and dragging the toolbar and heading
       sideways with it. The frozen first column keeps the row identifiable while the rest slides. */
    .js-grid-wrap, .js-grid-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; max-width: 100%; }
    .card:has(> .js-grid), .card-body:has(> .js-grid),
    div:has(> table.js-grid) { overflow-x: auto; -webkit-overflow-scrolling: touch; }

    /* Row actions match the 40px floor exactly. 2.35rem looked close enough and computed to 37.6px —
       under the floor, so every row's edit and delete button was still a miss risk. */
    .js-grid tbody td .btn-list .btn-icon { width: 2.5rem; height: 2.5rem; min-height: 2.5rem; }
    /* The search clear (×) is a deliberate 1.3rem overlay INSIDE the search box — it must not inherit the
       40px floor, or it covers the text it sits on top of. */
    .js-search-clear { min-height: 1.3rem !important; height: 1.3rem; width: 1.3rem; }
}

/* ── js-grid CARD MODE on a phone (mobile audit P2, 2026-08-10) ───────────────────────────────────────
   The horizontal-scroll treatment above keeps every desk affordance reachable, but a data table read
   sideways is nobody's idea of mobile — the orders/customers grids still showed three rows and a scrollbar.
   So on a phone each row folds into a card, the same shape admin-cards.js gives the read-only lists:
   the column header labels each cell, the first field leads unlabelled, the row actions line the foot.
   The grid's genuinely desk-only chrome folds away — select-all + per-column filters + drag-reorder — and
   the toolbar's "Search all columns" box (which stays) is the filter that actually matters on a phone.
   admin-cards.js supplies the two things CSS can't: the per-cell labels and the identity cell; it tags the
   table .js-grid-cards. Inline edit, the active toggles and Add-new (full form) all keep working. */
@media (max-width: 767.98px) {
  .js-grid-cards { display: block; }
  .js-grid-cards thead { display: none; }                         /* title + filter rows are desk chrome */
  .js-grid-cards tbody, .js-grid-cards tbody tr, .js-grid-cards tbody td { display: block; width: 100%; }
  .js-grid-cards tbody tr {
    border: 1px solid var(--tblr-border-color, #e6e7e9); border-radius: 10px;
    margin-bottom: .6rem; padding: .15rem .25rem; background: #fff;
  }
  .js-grid-cards tbody tr:hover { background: #fff; }              /* no desk hover-tint on a tapped card */
  .js-grid-cards tbody td {
    display: flex; align-items: baseline; gap: .6rem; min-height: 0;
    padding: .4rem .6rem !important; border: 0 !important; text-align: left !important;
    white-space: normal;
  }
  /* Column name, from the header (admin-cards.js copies it onto data-label). Fixed width so values line up. */
  .js-grid-cards tbody td::before {
    content: attr(data-label); flex: 0 0 6.5rem;
    font-size: .72rem; font-weight: 600; text-transform: uppercase; letter-spacing: .02em;
    color: var(--tblr-secondary, #667382);
  }
  /* Cells with nothing to label (select box, drag handle, actions, no-match spanner) get no label gutter. */
  .js-grid-cards tbody td:not([data-label])::before,
  .js-grid-cards tbody td[data-label=""]::before { display: none; }
  /* Desk-only cells have no place on a phone card. */
  .js-grid-cards tbody td:has(.row-sel),
  .js-grid-cards tbody td.drag-handle { display: none; }
  /* Identity cell (first field, tagged by admin-cards.js): larger, unlabelled, leads the card. */
  .js-grid-cards tbody td.adm-gridkey { font-size: 1.02rem; font-weight: 600; padding-bottom: .1rem !important; }
  .js-grid-cards tbody td.adm-gridkey::before { display: none; }
  .js-grid-cards tbody td:empty { display: none; }                /* an empty cell is noise, not a line */
  .js-grid-cards tbody tr.no-match td { display: block; text-align: center !important; }
  .js-grid-cards tbody tr.no-match td::before { display: none; }
  /* Row actions (edit / delete) → one line along the foot of the card. */
  .js-grid-cards tbody td:has(.btn-list) {
    border-top: 1px solid var(--tblr-border-color, #e6e7e9) !important;
    margin-top: .2rem; padding-top: .45rem !important;
  }
  .js-grid-cards tbody td:has(.btn-list)::before { display: none; }
  .js-grid-cards tbody td .btn-list { display: flex; gap: .4rem; width: 100%; justify-content: flex-start !important; }
  /* Inline edit inside a stacked card: the desk floats the save button outside the cell (left:100%), which
     pushes it off a full-width block — keep it inside, and let the editor fill the card. */
  .js-grid-cards tbody td.editing { position: relative; }
  .js-grid-cards tbody td.editing .js-cell-save { left: auto !important; right: .3rem; margin-left: 0; box-shadow: none; }
  .js-grid-cards tbody td.editing .form-control,
  .js-grid-cards tbody td.editing .form-select { width: 100%; }
}
