@tailwind base;
@tailwind components;

@layer components {
  /* ── Data Table Defaults ──
     :where() gives zero specificity — any Tailwind class on an element wins.
     Use data: { table: "" } on <table> (or equivalent) to opt in. */

  :where([data-table]) {
    @apply border-collapse;
  }

  :where([data-table]) :where(th) {
    @apply px-1.5 py-0.5 whitespace-nowrap font-medium text-left bg-gray-100 border border-gray-200;
  }

  :where([data-table]) :where(td) {
    @apply px-1.5 py-0.5 border border-gray-200;
  }

  :where([data-table]) :where(tbody tr) {
    @apply text-gray-700;
  }

  :where([data-table]) :where(tbody tr):hover {
    @apply bg-gray-100;
  }

  /* Crudable::DetailActions renders a sticky action bar as the last row; its BAR
     div owns the top border that separates it from the body and travels with it
     during sticky scroll. Drop only the edges that would double that top line:
     the bottom of the row above and the top of the bar's own cell. The bar cell
     keeps its side and bottom edges so it stays framed in the table grid. */
  :where([data-table]) tr:has(+ tr[data-detail-actions]) > :where(th, td) {
    border-bottom-width: 0;
  }

  :where([data-table]) tr[data-detail-actions] > :where(td) {
    border-top-width: 0;
  }

  /* Fixed-layout tables: enforce uniform row height via truncation */
  :where([data-table].data-table-fixed) :where(th),
  :where([data-table].data-table-fixed) :where(td) {
    @apply whitespace-nowrap overflow-hidden;
    /* Lift the browser's content-min-content floor so a user-set
       `width + max-width` rule on a column with unbreakable content
       (long emails, UUIDs) actually clips rather than the column being
       refused below its content's intrinsic min-content. */
    min-width: 0;
  }

  :where([data-table].data-table-fixed) :where(thead th) {
    @apply sticky top-0 z-10;
    /* 1px gray-200 skirt above the th: doubles as the table's top border
       (which sticky+z-index paints over) and plugs the sub-pixel bleed
       that border-collapse:collapse leaves during scroll. */
    box-shadow: 0 -1px 0 0 theme("colors.gray.200");
  }

  :where([data-table].data-table-fixed) :where(tbody tr) {
    content-visibility: auto;
    contain-intrinsic-block-size: auto 1.625rem;
    height: 1.625rem;
  }

  /* ── Skeleton placeholder rows ── */
  :where([data-table]) :where(tr[data-skeleton] > td) {
    padding: 0;
    background-image: linear-gradient(90deg,
        theme("colors.gray.50") 0%,
        theme("colors.gray.100") 50%,
        theme("colors.gray.50") 100%);
    background-size: 200% 100%;
    animation: skeleton-shimmer 5s ease-in-out infinite;
  }

  @keyframes skeleton-shimmer {
    0% {
      background-position: 100% 0;
    }

    100% {
      background-position: -100% 0;
    }
  }

  @media (prefers-reduced-motion: reduce) {
    :where([data-table]) :where(tr[data-skeleton] > td) {
      animation: none;
      background: theme("colors.gray.50");
    }
  }

  /* ── Data Table Error Styles ──
     Fixed styles — not overridable. Normal specificity is fine.
     Keyed off data-error attribute on the relevant element. */

  [data-table] tr[data-error] td {
    @apply bg-red-50 text-red-800 text-sm p-1.5;
  }

  [data-table] td[data-error] {
    @apply bg-red-50;
  }

  [data-table] tbody[data-error] {
    @apply outline outline-1 outline-red-200;
  }
}

@tailwind utilities;

@layer utilities {
  .scrollbar-none {
    -ms-overflow-style: none;
    scrollbar-width: none;
  }

  .scrollbar-none::-webkit-scrollbar {
    display: none;
  }

  .decoration-opacity-30 {
    text-decoration-color: color-mix(in srgb, currentColor 30%, transparent);
  }

  .decoration-opacity-50 {
    text-decoration-color: color-mix(in srgb, currentColor 50%, transparent);
  }

  .decoration-opacity-90 {
    text-decoration-color: color-mix(in srgb, currentColor 90%, transparent);
  }

  /* Row highlight animation — standalone, referenced by data-table controller via Stimulus classes API */
  @keyframes row-highlight {

    0%,
    33% {
      background-color: theme("colors.yellow.50");
    }

    100% {
      background-color: transparent;
    }
  }

  .animate-row-highlight {
    animation: row-highlight 3s ease-out forwards;
  }

  /* Crudable table: Quick Edit (click-to-edit) toggles */
  .crudable-quick-edit td[data-editable] {
    cursor: pointer;
  }

  .crudable-quick-edit td[data-editable]:hover {
    background-color: theme("colors.gray.100");
  }

  /* Mobile bottom-sheet (Disclosure panels opted in via `sheet: true`, marked
     data-sheet). Scoped to data-sheet so anchored top-layer popups (navbar
     dropdown, hovercards) are untouched. The native top-layer ::backdrop is
     transparent by default; dim it, and slide the sheet up on open. */
  body[data-mobile] [data-sheet]:popover-open::backdrop {
    background: rgba(0, 0, 0, 0.4);
  }

  @media (prefers-reduced-motion: no-preference) {
    body[data-mobile] [data-sheet]:popover-open {
      animation: sheet-up 0.2s ease-out;
    }

    /* Non-top-layer sheets (combobox / tags-combobox in edit fields) toggle
       visibility via the `hidden` class rather than the popover API, so they
       can't key off :popover-open — animate on reveal instead. */
    body[data-mobile] [data-sheet]:not(.hidden):not(:popover-open) {
      animation: sheet-up 0.2s ease-out;
    }
  }

  @keyframes sheet-up {
    from {
      transform: translateY(100%);
    }

    to {
      transform: translateY(0);
    }
  }

  /* The "Shift" column (Shifts::ShiftWithUser) shows the compact nickname in
     mobile list rows; the detail layout (a non-fixed data-table) keeps the full
     name on every width. Higher specificity than the spans' mobile: utilities,
     and in the same layer, so it wins. */
  body[data-mobile] [data-table]:not(.data-table-fixed) [data-shift-name="full"] {
    display: inline;
  }

  body[data-mobile] [data-table]:not(.data-table-fixed) [data-shift-name="nick"] {
    display: none;
  }

  /* The data-popover-target="panel" declarations are to create the triangle indicator on the popover */
  [data-popover-target="panel"]::after {
    content: "";
    position: absolute;
    width: 0;
    height: 0;
    border-style: solid;
    border-color: transparent;
    border-width: theme("spacing[2]");
    pointer-events: none;
  }

  [data-popover-target="panel"][data-popover-placement="top"]::after {
    top: 100%;
    left: 50%;
    transform: translateX(-50%);
    border-top-color: inherit;
  }

  [data-popover-target="panel"][data-popover-placement="bottom"]::after {
    bottom: 100%;
    left: 50%;
    transform: translateX(-50%);
    border-bottom-color: inherit;
  }

  [data-popover-target="panel"][data-popover-placement="left"]::after {
    left: 100%;
    top: 50%;
    transform: translateY(-50%);
    border-left-color: inherit;
  }

  [data-popover-target="panel"][data-popover-placement="right"]::after {
    right: 100%;
    top: 50%;
    transform: translateY(-50%);
    border-right-color: inherit;
  }
}
