/* spcaeo/ui (data-grid/data-grid.css), from github.com/spcaeo/ui at ad51155, vendored by Skald.
   Changes and the reason for each: VERSION.md beside this folder.

   MIT License. Copyright (c) 2026 spcaeo.
   Permission is hereby granted, free of charge, to any person obtaining a copy of this software
   and associated documentation files (the "Software"), to deal in the Software without
   restriction, including without limitation the rights to use, copy, modify, merge, publish,
   distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:
   The above copyright notice and this permission notice shall be included in all copies or
   substantial portions of the Software.
   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
   BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
   DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*
 * DATA GRID — one stylesheet. No Tailwind, no build step, no UI library.
 *
 * HOW THIS AVOIDS DUPLICATING YOUR DESIGN SYSTEM
 *
 * Every colour is `var(--host-token, <our measured fallback>)`. If the page
 * already defines shadcn/ui's tokens — `--background`, `--border`, `--primary`
 * and friends — the grid picks them up and looks native. If nothing defines
 * them, the fallbacks take over and the grid still works on a blank HTML page.
 *
 * That is the whole integration story. The grid imports NO components from your
 * app, so it cannot collide with your Button, your Dialog, or your Radix
 * version. Popovers use the native `popover` attribute and dialogs use
 * `<dialog>`; neither needs a library.
 *
 * ON THE MEASURED NUMBERS: `npm run contrast data-grid` measures the FALLBACK
 * palette below, which is what a standalone page renders. When you inherit a
 * host theme, the host owns the contrast — we cannot measure colours we do not
 * define, and pretending otherwise would be the kind of unverified claim this
 * collection exists to avoid.
 */

:root {
  --dg-bg: var(--background, oklch(1 0 0));
  --dg-fg: var(--foreground, oklch(0.21 0 0));
  --dg-muted: var(--muted, oklch(0.97 0 0));
  --dg-muted-fg: var(--muted-foreground, oklch(0.44 0 0));
  /* A divider between rows. Decorative: the table's structure is carried by
     markup, so this does not have to clear 3:1 and forcing it to would make an
     ordinary table look like a spreadsheet from 1998. */
  --dg-border: var(--border, oklch(0.85 0 0));
  /* The edge of an interactive control. This one IS required to identify the
     component — without it you cannot see that a text field is a text field —
     so it is measured against the background at 3:1. */
  --dg-control-border: var(--input, oklch(0.58 0 0));
  --dg-accent: var(--accent, oklch(0.96 0 0));
  --dg-primary: var(--primary, oklch(0.21 0 0));
  --dg-primary-fg: var(--primary-foreground, oklch(0.99 0 0));
  --dg-popover: var(--popover, oklch(1 0 0));
  --dg-ring: var(--ring, oklch(0.45 0 0));
  --dg-danger: var(--destructive, oklch(0.44 0.17 27));
  --dg-radius: var(--radius, 8px);
}

.dark,
[data-theme="dark"] {
  --dg-bg: var(--background, oklch(0.18 0 0));
  --dg-fg: var(--foreground, oklch(0.98 0 0));
  --dg-muted: var(--muted, oklch(0.26 0 0));
  --dg-muted-fg: var(--muted-foreground, oklch(0.75 0 0));
  --dg-border: var(--border, oklch(0.4 0 0));
  --dg-control-border: var(--input, oklch(0.55 0 0));
  --dg-accent: var(--accent, oklch(0.28 0 0));
  --dg-primary: var(--primary, oklch(0.92 0 0));
  --dg-primary-fg: var(--primary-foreground, oklch(0.2 0 0));
  --dg-popover: var(--popover, oklch(0.22 0 0));
  --dg-ring: var(--ring, oklch(0.72 0 0));
  --dg-danger: var(--destructive, oklch(0.7 0.17 25));
}

@media (prefers-color-scheme: dark) {
  :root:not(.light):not([data-theme="light"]) {
    --dg-bg: var(--background, oklch(0.18 0 0));
    --dg-fg: var(--foreground, oklch(0.98 0 0));
    --dg-muted: var(--muted, oklch(0.26 0 0));
    --dg-muted-fg: var(--muted-foreground, oklch(0.75 0 0));
    --dg-border: var(--border, oklch(0.4 0 0));
    --dg-control-border: var(--input, oklch(0.55 0 0));
    --dg-accent: var(--accent, oklch(0.28 0 0));
    --dg-primary: var(--primary, oklch(0.92 0 0));
    --dg-primary-fg: var(--primary-foreground, oklch(0.2 0 0));
    --dg-popover: var(--popover, oklch(0.22 0 0));
    --dg-ring: var(--ring, oklch(0.72 0 0));
    --dg-danger: var(--destructive, oklch(0.7 0.17 25));
  }
}

/* --- shell ---------------------------------------------------------------- */

.dg {
  display: flex;
  flex-direction: column;
  gap: 10px;
  color: var(--dg-fg);
  font: inherit;
  font-size: 14px;
}
.dg *,
.dg *::before,
.dg *::after {
  box-sizing: border-box;
}

/*
  A class that sets `display` outranks the user-agent rule for [hidden], so a
  container we hid by attribute keeps rendering as an empty bordered strip. This
  puts the attribute back in charge. It cost a screenshot to notice.
*/
.dg [hidden] {
  display: none !important;
}

/* --- toolbar -------------------------------------------------------------- */

.dg-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
}
.dg-toolbar-spacer {
  flex: 1 1 auto;
}

.dg-search {
  position: relative;
  flex: 0 1 280px;
  min-width: 180px;
}
.dg-search input {
  width: 100%;
  padding: 7px 30px 7px 30px;
  border: 1px solid var(--dg-control-border);
  border-radius: calc(var(--dg-radius) - 2px);
  background: var(--dg-bg);
  color: var(--dg-fg);
  font: inherit;
  font-size: 13px;
}
.dg-search input::placeholder {
  color: var(--dg-muted-fg);
}
.dg-search-icon,
.dg-search-clear {
  position: absolute;
  top: 50%;
  translate: 0 -50%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--dg-muted-fg);
}
.dg-search-icon {
  left: 9px;
  pointer-events: none;
}
.dg-search-clear {
  right: 5px;
  width: 20px;
  height: 20px;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: none;
  cursor: pointer;
}
.dg-search-clear:hover {
  background: var(--dg-accent);
  color: var(--dg-fg);
}

.dg-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 11px;
  border: 1px solid var(--dg-control-border);
  border-radius: calc(var(--dg-radius) - 2px);
  background: var(--dg-bg);
  color: var(--dg-fg);
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  white-space: nowrap;
}
.dg-btn:hover:not(:disabled) {
  background: var(--dg-accent);
}
.dg-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
.dg-btn-primary {
  background: var(--dg-primary);
  color: var(--dg-primary-fg);
  border-color: var(--dg-primary);
}
.dg-btn-primary:hover:not(:disabled) {
  filter: brightness(1.15);
}
.dg-btn[aria-pressed="true"] {
  background: var(--dg-accent);
}

.dg :focus-visible {
  outline: 2px solid var(--dg-ring);
  outline-offset: 2px;
}

/* --- segments ------------------------------------------------------------- */

.dg-segments {
  display: flex;
  gap: 2px;
  border-bottom: 1px solid var(--dg-border);
}
.dg-segment {
  padding: 7px 12px;
  border: 0;
  border-bottom: 2px solid transparent;
  background: none;
  color: var(--dg-muted-fg);
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
}
.dg-segment:hover {
  color: var(--dg-fg);
}
.dg-segment[aria-selected="true"] {
  color: var(--dg-fg);
  border-bottom-color: var(--dg-primary);
}
.dg-segment-count {
  margin-left: 6px;
  padding: 1px 6px;
  border-radius: 999px;
  background: var(--dg-muted);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}

/* --- filter chips --------------------------------------------------------- */

.dg-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
}
.dg-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 4px 3px 9px;
  border: 1px solid var(--dg-border);
  border-radius: 999px;
  background: var(--dg-muted);
  font-size: 12px;
}
.dg-chip button {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: none;
  color: var(--dg-muted-fg);
  cursor: pointer;
}
.dg-chip button:hover {
  background: var(--dg-border);
  color: var(--dg-fg);
}
.dg-chip-warn {
  border-color: var(--dg-danger);
  color: var(--dg-danger);
  background: none;
}

/* --- popover: native, no library ------------------------------------------ */

.dg-pop {
  position: fixed;
  margin: 0;
  padding: 6px;
  min-width: 200px;
  max-height: min(340px, 60vh);
  overflow-y: auto;
  border: 1px solid var(--dg-border);
  border-radius: var(--dg-radius);
  background: var(--dg-popover);
  color: var(--dg-fg);
  box-shadow: 0 8px 26px -8px rgb(0 0 0 / 0.28);
}
.dg-pop:not(:popover-open) {
  display: none;
}
.dg-pop-title {
  padding: 4px 8px 6px;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--dg-muted-fg);
}
.dg-opt {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 6px 8px;
  border: 0;
  border-radius: calc(var(--dg-radius) - 4px);
  background: none;
  color: inherit;
  font: inherit;
  font-size: 13px;
  text-align: left;
  cursor: pointer;
}
.dg-opt:hover {
  background: var(--dg-accent);
}
.dg-opt input {
  margin: 0;
  accent-color: var(--dg-primary);
}
.dg-pop-actions {
  display: flex;
  gap: 6px;
  padding: 6px 4px 2px;
  margin-top: 4px;
  border-top: 1px solid var(--dg-border);
}

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

.dg-frame {
  border: 1px solid var(--dg-border);
  border-radius: var(--dg-radius);
  background: var(--dg-bg);
  overflow: hidden;
}
.dg-scroll {
  overflow-x: auto;
}
.dg-table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-size: 13px;
}
.dg-table th,
.dg-table td {
  padding: 9px 12px;
  text-align: left;
  border-bottom: 1px solid var(--dg-border);
  vertical-align: middle;
  white-space: nowrap;
}
.dg-table thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--dg-muted);
  font-size: 12px;
  font-weight: 600;
  color: var(--dg-muted-fg);
}
.dg-table tbody tr:last-child td {
  border-bottom: 0;
}
.dg-table tbody tr:hover {
  background: var(--dg-accent);
}
.dg-table tbody tr[aria-selected="true"] {
  background: var(--dg-accent);
}
.dg-num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.dg-checkbox {
  width: 1%;
}
.dg-checkbox input {
  accent-color: var(--dg-primary);
}

/* A sortable header is a button, so it is reachable and announceable. */
.dg-sort {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  font-weight: inherit;
  cursor: pointer;
}
.dg-sort:hover {
  color: var(--dg-fg);
}
.dg-sort-arrow {
  opacity: 0;
  transition: opacity 120ms;
}
.dg-sort:hover .dg-sort-arrow {
  opacity: 0.4;
}
th[aria-sort] .dg-sort {
  color: var(--dg-fg);
}
th[aria-sort] .dg-sort-arrow {
  opacity: 1;
}
th[aria-sort="descending"] .dg-sort-arrow {
  rotate: 180deg;
}

/* --- states --------------------------------------------------------------- */

/*
  Eight states, and they must look different from each other. Collapsing them
  into one "No results" card is the most common grid bug there is: it tells a
  user their data is gone when the truth is that a request failed, or that they
  lack permission, or that a filter is hiding everything.
*/
.dg-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 52px 24px;
  text-align: center;
}
.dg-state-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 999px;
  background: var(--dg-muted);
  color: var(--dg-muted-fg);
}
.dg-state-title {
  font-size: 15px;
  font-weight: 600;
}
.dg-state-body {
  max-width: 46ch;
  color: var(--dg-muted-fg);
  font-size: 13px;
}
.dg-state-actions {
  display: flex;
  gap: 8px;
  margin-top: 4px;
}
.dg-state-error .dg-state-icon {
  background: color-mix(in oklch, var(--dg-danger) 14%, transparent);
  color: var(--dg-danger);
}

/* The diagnostic line. An error the user cannot quote is an error support
   cannot trace, so the code and request id are always visible. */
.dg-state-meta {
  margin-top: 6px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11px;
  color: var(--dg-muted-fg);
}

.dg-skeleton-cell {
  display: block;
  height: 11px;
  border-radius: 4px;
  background: var(--dg-muted);
}
.dg-skeleton-row td {
  padding: 11px 12px;
}
@keyframes dg-pulse {
  50% {
    opacity: 0.45;
  }
}
.dg-skeleton-cell {
  animation: dg-pulse 1.6s ease-in-out infinite;
}

/* Refreshing keeps the rows on screen — replacing them with a spinner throws
   away the thing the user was reading. */
.dg-refreshing {
  position: relative;
}
.dg-refreshing::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  top: 0;
  height: 2px;
  background: linear-gradient(90deg, transparent, var(--dg-primary), transparent);
  animation: dg-sweep 1.1s linear infinite;
}
@keyframes dg-sweep {
  from {
    translate: -100% 0;
  }
  to {
    translate: 100% 0;
  }
}

.dg-banner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  border: 1px solid var(--dg-border);
  border-radius: calc(var(--dg-radius) - 2px);
  background: var(--dg-muted);
  font-size: 13px;
}
.dg-banner-danger {
  border-color: var(--dg-danger);
  color: var(--dg-danger);
  background: none;
}

/* --- selection bar -------------------------------------------------------- */

.dg-selection {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  border: 1px solid var(--dg-primary);
  border-radius: calc(var(--dg-radius) - 2px);
  background: var(--dg-accent);
  font-size: 13px;
}
.dg-selection strong {
  font-variant-numeric: tabular-nums;
}

/* --- pagination ----------------------------------------------------------- */

.dg-pagination {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  padding: 8px 2px;
  font-size: 13px;
  color: var(--dg-muted-fg);
}
.dg-pagination select {
  padding: 4px 6px;
  border: 1px solid var(--dg-control-border);
  border-radius: calc(var(--dg-radius) - 4px);
  background: var(--dg-bg);
  color: var(--dg-fg);
  font: inherit;
  font-size: 13px;
}
.dg-page-buttons {
  display: flex;
  gap: 4px;
}
.dg-page-buttons .dg-btn {
  padding: 5px 9px;
}
.dg-count {
  font-variant-numeric: tabular-nums;
}

/* --- cards ---------------------------------------------------------------- */

.dg-cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: 10px;
  padding: 12px;
}
.dg-card {
  padding: 12px;
  border: 1px solid var(--dg-border);
  border-radius: calc(var(--dg-radius) - 2px);
  background: var(--dg-bg);
}
.dg-card dt {
  font-size: 11px;
  color: var(--dg-muted-fg);
}
.dg-card dd {
  margin: 0 0 6px;
  font-size: 13px;
}

/* --- environment ---------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .dg-skeleton-cell,
  .dg-refreshing::after {
    animation: none;
  }
  .dg-sort-arrow {
    transition: none;
  }
}

@media (forced-colors: active) {
  .dg-frame,
  .dg-pop,
  .dg-chip,
  .dg-banner,
  .dg-selection {
    border: 1px solid ButtonBorder;
  }
  .dg-table thead th {
    background: Canvas;
  }
  .dg-table tbody tr:hover,
  .dg-table tbody tr[aria-selected="true"] {
    background: Highlight;
    color: HighlightText;
  }
  .dg-segment[aria-selected="true"] {
    border-bottom-color: Highlight;
  }
  .dg :focus-visible {
    outline: 2px solid CanvasText;
  }
}

@media print {
  .dg-toolbar,
  .dg-pagination,
  .dg-selection,
  .dg-pop {
    display: none !important;
  }
  .dg-frame {
    border: 1px solid #000;
  }
  .dg-scroll {
    overflow: visible;
  }
  .dg-table th,
  .dg-table td {
    white-space: normal;
  }
}
