/* Tailwind utilities used by the custom backoffice/admin/reporting templates
 * that are MISSING from Unfold's precompiled stylesheet (it is purged against
 * Unfold's own templates, so any class Unfold itself does not use is silently
 * dead). Loaded after unfold/css/styles.css via UNFOLD["STYLES"].
 *
 * Values follow the Tailwind defaults; base/primary colors reference the same
 * CSS custom properties Unfold's stylesheet uses, so theme colors stay in sync.
 */

/* --- layout / sizing ------------------------------------------------------ */
.items-end { align-items: flex-end; }
.items-stretch { align-items: stretch; }
.min-w-max { min-width: max-content; }
.min-w-48 { min-width: 12rem; }
.w-8 { width: 2rem; }
.w-14 { width: 3.5rem; }
.w-20 { width: 5rem; }
.w-28 { width: 7rem; }
.border-b-0 { border-bottom-width: 0; }
.rounded-t-default { border-top-left-radius: 0.375rem; border-top-right-radius: 0.375rem; }
.max-h-\[80vh\] { max-height: 80vh; }
.py-0\.5 { padding-top: 0.125rem; padding-bottom: 0.125rem; }
.py-1\.5 { padding-top: 0.375rem; padding-bottom: 0.375rem; }
.tracking-wide { letter-spacing: 0.025em; }
.whitespace-pre-line { white-space: pre-line; }

/* --- vertical rhythm / separators ----------------------------------------- */
.space-y-1 > * + * { margin-top: 0.25rem; }
.space-y-2 > * + * { margin-top: 0.5rem; }
.space-y-4 > * + * { margin-top: 1rem; }
.space-y-5 > * + * { margin-top: 1.25rem; }
.space-y-6 > * + * { margin-top: 1.5rem; }
.divide-y > * + * { border-top-width: 1px; border-top-style: solid; }
.divide-base-100 > * + * { border-color: var(--color-base-100); }
.dark .dark\:divide-base-800\/60 > * + * {
  border-color: color-mix(in srgb, var(--color-base-800) 60%, transparent);
}

/* --- responsive grids ------------------------------------------------------ */
@media (min-width: 640px) {
  .sm\:grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .sm\:grid-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .sm\:grid-cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
@media (min-width: 1024px) {
  .lg\:col-span-2 { grid-column: span 2 / span 2; }
  .lg\:grid-cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* --- effects ---------------------------------------------------------------- */
.shadow-xl {
  box-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
}
.hover\:shadow-sm:hover {
  box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
}
.hover\:underline:hover { text-decoration-line: underline; }
.bg-black\/40 { background-color: rgb(0 0 0 / 0.4); }

/* --- changelist filter popup -------------------------------------------------
 * Replaces Unfold's full-height filter sheet: the overrides in
 * templates/unfold/helpers/change_list_filter_*.html render the filters as a
 * popup anchored below the "Filters" button (top/right set by script; the
 * values here are the pre-positioning fallback).
 */
#changelist-filter.filter-popup .filter-popup-backdrop {
  position: absolute;
  inset: 0;
}
#changelist-filter.filter-popup .filter-popup-panel {
  position: absolute;
  top: 9rem;
  right: 1rem;
  max-height: calc(100vh - 11rem);
  box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.15), 0 4px 6px -4px rgb(0 0 0 / 0.1);
}

/* --- light-mode colors ------------------------------------------------------ */
.text-red-500 { color: #ef4444; }
.text-green-600 { color: #16a34a; }
.text-orange-600 { color: #ea580c; }
.text-orange-800 { color: #9a3412; }
.text-amber-700 { color: #b45309; }
.text-amber-800 { color: #92400e; }
.text-gray-700 { color: #374151; }
.bg-amber-50 { background-color: #fffbeb; }
.bg-amber-100 { background-color: #fef3c7; }
.bg-gray-100 { background-color: #f3f4f6; }
.border-amber-300 { border-color: #fcd34d; }
.border-orange-100 { border-color: #ffedd5; }
.border-orange-200 { border-color: #fed7aa; }
.hover\:bg-orange-100\/60:hover { background-color: rgb(255 237 213 / 0.6); }

/* --- dark: variants referenced in templates --------------------------------- */
.dark .dark\:bg-primary-500\/10 {
  background-color: color-mix(in srgb, var(--color-primary-500) 10%, transparent);
}
.dark .dark\:border-base-800\/60 {
  border-color: color-mix(in srgb, var(--color-base-800) 60%, transparent);
}
.dark .dark\:hover\:bg-base-800\/40:hover {
  background-color: color-mix(in srgb, var(--color-base-800) 40%, transparent);
}
.dark .dark\:bg-amber-900\/20 { background-color: rgb(120 53 15 / 0.2); }
.dark .dark\:bg-amber-900\/40 { background-color: rgb(120 53 15 / 0.4); }
.dark .dark\:text-amber-300 { color: #fcd34d; }
.dark .dark\:bg-orange-950\/30 { background-color: rgb(67 20 7 / 0.3); }
.dark .dark\:border-orange-900\/30 { border-color: rgb(124 45 18 / 0.3); }
.dark .dark\:border-orange-900\/50 { border-color: rgb(124 45 18 / 0.5); }
.dark .dark\:text-orange-300 { color: #fdba74; }
.dark .dark\:hover\:bg-orange-900\/20:hover { background-color: rgb(124 45 18 / 0.2); }
.dark .dark\:bg-green-900\/40 { background-color: rgb(20 83 45 / 0.4); }
.dark .dark\:text-green-300 { color: #86efac; }
.dark .dark\:text-green-400 { color: #4ade80; }
.dark .dark\:text-red-400 { color: #f87171; }
.dark .dark\:bg-gray-900\/40 { background-color: rgb(17 24 39 / 0.4); }
.dark .dark\:text-gray-300 { color: #d1d5db; }

/* --- dark-mode remap of light-only status pills ------------------------------
 * The view-side tone tables (bg-*-100 text-*-700) carry no dark: classes, so in
 * dark mode those pills would stay light. Remap them here instead of touching
 * every _TONE table and template.
 */
.dark .bg-green-100 { background-color: rgb(20 83 45 / 0.4); }
.dark .text-green-700 { color: #86efac; }
.dark .bg-orange-100 { background-color: rgb(124 45 18 / 0.4); }
.dark .text-orange-700 { color: #fdba74; }
.dark .bg-red-100 { background-color: rgb(127 29 29 / 0.4); }
.dark .text-red-700 { color: #fca5a5; }
.dark .bg-blue-100 { background-color: rgb(30 58 138 / 0.4); }
.dark .text-blue-700 { color: #93c5fd; }
.dark .bg-amber-100 { background-color: rgb(120 53 15 / 0.4); }
.dark .text-amber-700 { color: #fcd34d; }
.dark .bg-gray-100 { background-color: rgb(55 65 81 / 0.5); }
.dark .text-gray-700 { color: #d1d5db; }

/* --- global accessibility + motion (design-system foundation) -------------- */
/* Visible keyboard focus on every interactive element (WCAG 2.4.7). */
*:focus-visible {
  outline: 2px solid var(--color-primary-500, #0EA5E9);
  outline-offset: 2px;
}

/* Honor the user's reduced-motion preference (WCAG 2.3.3 / 2.2.2). */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* Screen-reader-only text (visually hidden, still announced). */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Skip-to-content link: off-screen until focused. */
.skip-link {
  position: absolute;
  left: 0.5rem; top: -3rem;
  z-index: 1000;
  padding: 0.5rem 0.9rem;
  background: var(--color-primary-700, #0369A1);
  color: #fff;
  border-radius: 0.375rem;
  transition: top 150ms ease-out;
}
.skip-link:focus {
  top: 0.5rem;
}

/* --- pill radio groups (customer mask) -------------------------------------
 * Radio stays focusable (sr-only style, not display:none); the label span is
 * the visual pill. Selected = filled primary; keyboard focus rings the pill. */
.pill input[type="radio"] {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0, 0, 0, 0); white-space: nowrap;
}
.pill span {
  display: inline-flex; align-items: center; cursor: pointer;
  padding: 0.375rem 0.9rem; border-radius: 9999px; font-size: 0.875rem;
  border: 1px solid var(--color-base-200); min-height: 36px;
  color: var(--color-base-700); background: transparent;
  transition: background 150ms ease-out, color 150ms ease-out;
}
.dark .pill span { border-color: var(--color-base-700); color: var(--color-base-300); }
.pill input[type="radio"]:checked + span {
  background: var(--color-primary-700); border-color: var(--color-primary-700);
  color: #fff;
}
.pill input[type="radio"]:focus-visible + span {
  outline: 2px solid var(--color-primary-500); outline-offset: 2px;
}

/* --- pack plan row selection (backoffice packing viewer) -------------------
 * Highlights the position row matching the carton selected in the 3D viewer
 * (and vice versa). Its own class, not a Tailwind utility: this file only
 * carries what Unfold's purged bundle is missing.
 */
.pack-row-selected { background-color: rgb(219 234 254); }
.dark .pack-row-selected { background-color: rgb(30 58 138); }

/* The plan page must not scroll as a whole: a long position list scrolls inside
   its own column instead. The height is set from the viewport by the viewer
   script, which knows where the column starts. */
.pack-side { overflow-y: auto; }

/* Pallet tabs. Own rules rather than Tailwind utilities: the purged Unfold
   bundle does not carry classes only our own templates use. */
.pack-tabs { overflow-x: auto; }
.pack-tab {
  padding: 0.25rem 0.625rem;
  border: 1px solid var(--color-base-200);
  border-radius: var(--radius-default, 0.375rem);
  font-size: 0.8125rem;
  white-space: nowrap;
}
.pack-tab-active {
  background-color: rgb(219 234 254);
  border-color: rgb(147 197 253);
  font-weight: 600;
}
.pack-tab-weight { opacity: 0.65; margin-left: 0.375rem; }
.dark .pack-tab { border-color: var(--color-base-700); }
.dark .pack-tab-active { background-color: rgb(30 58 138); border-color: rgb(30 64 175); }

/* Canvas and layer slider side by side. Above the canvas the slider stretched
   the toolbar row to 128 px and the preview lost that height; beside it the
   slider costs width, which the card has to spare, and the row is a thin strip
   again. */
.pack-canvas-row {
  display: flex;
  align-items: stretch;
  gap: 0.5rem;
}
.pack-canvas {
  /* min-width keeps the canvas from pushing the row wider than the card: a flex
     item refuses to shrink below its content by default, and the renderer sizes
     itself from this element's width. */
  flex: 1 1 auto;
  min-width: 0;
}
.pack-layer-column {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.25rem;
}

/* The layer slider runs the way the height it limits does: bottom to top, with
   the maximum at the top. ``direction: rtl`` flips the axis so the highest layer
   is up, not down. No fixed height: it stretches to the canvas next to it. */
.pack-layer-vertical {
  writing-mode: vertical-lr;
  direction: rtl;
  flex: 1 1 auto;
  min-height: 4rem;
  width: 1.25rem;
}

/* Constraint panel fields side by side instead of stacked, so the panel no
   longer eats half the position column. */
.pack-constraint-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.5rem;
}

/* The file input itself stays in the form and keeps working for keyboard and
   screen readers; only its default control is replaced by the label above it.
   Hence the input is shrunk to a transparent pixel rather than removed with
   `display: none`, which would drop it out of the tab order. */
.pack-file-button {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.5rem 0.875rem;
  border: 1px solid var(--color-base-200);
  /* Unfold's own name for this is --border-radius, and it only emits the
     variable when UNFOLD["BORDER_RADIUS"] is configured — which this project
     does not do, so today the fallback always applies. Naming it correctly
     costs nothing and makes the button follow the theme if that ever changes. */
  border-radius: var(--border-radius, 0.375rem);
  font-size: 0.875rem;
  cursor: pointer;
}
.pack-file-button + span + input[type="file"] {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
}
/* The input keeps its own focus ring, but `opacity: 0` paints that away along
   with the control, so the label shows the focus in its place. Without this a
   keyboard user reaches this page's main entrance and sees nothing happen.

   The match is on `:focus-visible` rather than `:focus`, so a plain mouse
   click on the button leaves no ring behind. No test pins that difference
   down — telling the two apart needs a real pointer interaction.

   Accepted limit: a browser without `:has()` (Chrome < 105, Safari < 15.4,
   Firefox < 121) drops this rule as an invalid selector while still applying
   the plain rule above that hides the control — the field stays reachable but
   its focus becomes invisible again. This backoffice is used on current
   browsers, and the alternative (moving the input in front of the label so a
   plain sibling selector suffices) would put the bare control ahead of its own
   heading in the reading order. */
.pack-file-button:has(+ span + input[type="file"]:focus-visible) {
  outline: 2px solid var(--color-primary-600, #2563eb);
  outline-offset: 2px;
}
.dark .pack-file-button {
  border-color: var(--color-base-700);
}
