/* Common Admin UI. Uses design tokens (tokens.css) only; no client-specific values here. */

/* Roadmap modules: disabled, not clickable, with a separate "Coming Soon" badge. */
.menu-item.app-coming-soon > .menu-link {
  cursor: default;
  pointer-events: none;
  opacity: 0.6;
}

.app-coming-soon-badge {
  margin-inline-start: auto;
  background-color: var(--app-coming-soon-bg);
  color: var(--app-coming-soon-color);
  font-weight: 500;
}

/* A line that sets an untitled sidebar section (Help) apart from the section above it. */
.app-menu-divider {
  align-self: stretch;
  flex: 0 0 auto;
  margin: 1rem 1.5rem 0.5rem;
  border-top: 1px solid var(--bs-border-color);
}

/* Brand block in the sidebar and on authentication pages. */
.app-brand-logo img {
  display: block;
  max-height: 2.25rem;
  width: auto;
}

.app-brand-name {
  font-weight: 700;
  font-size: 1.125rem;
  color: var(--bs-heading-color);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Dashboard statistics. */
.app-stat-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 0.5rem;
  background-color: var(--app-stat-icon-bg);
  color: var(--app-stat-icon-color);
  font-size: 1.5rem;
}

/*
 * Validation messages and invalid fields, for every Admin form: rendered by the validation tag helpers on the
 * server and toggled by jQuery Unobtrusive Validation in the browser, which use the same class names.
 */
.field-validation-error {
  display: block;
  margin-top: 0.25rem;
  color: var(--bs-danger);
  font-size: 0.8125rem;
}

.input-validation-error {
  border-color: var(--bs-danger);
}

/* A searchable select (Tom Select, searchable-select.js) shows the hidden select's validation error too. */
select.input-validation-error + .ts-wrapper .ts-control {
  border-color: var(--bs-danger);
}

/* Searchable select: long lists scroll inside the dropdown. */
.ts-dropdown .ts-dropdown-content {
  max-height: 18rem;
}

/*
 * The Translate button in an English field's input-group (_TranslateButton, translate.js). Beside a multi-line field
 * its content stays at the top, level with the first line, instead of the middle of the tall button.
 */
textarea + .app-translate {
  align-items: flex-start;
}

/* Server-rendered list pages (search, filters, sortable headers, paging). */
.app-list-search {
  flex: 1 1 auto;
  max-inline-size: 28rem;
}

.app-sort-link {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  color: inherit;
  white-space: nowrap;
}

.app-sort-link:hover,
.app-sort-link.active {
  color: var(--bs-primary);
}

.app-list-loading {
  opacity: 0.5;
  pointer-events: none;
  transition: opacity 0.15s ease-in-out;
}

.app-empty-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 3.5rem;
  height: 3.5rem;
  border-radius: 50%;
  background-color: var(--app-stat-icon-bg);
  color: var(--app-stat-icon-color);
  font-size: 1.75rem;
}

.app-product-name {
  display: inline-block;
  max-inline-size: 22rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Catalog management lists: a long path or name is cut off; its full text is in the title. */
.app-category-path,
.app-brand-list-name,
.app-color-list-name,
.app-specification-list-name,
.app-group-list-name,
.app-group-member-name,
.app-tag-list-name,
.app-product-type-list-name {
  display: inline-block;
  max-inline-size: 32rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: middle;
}

/* Category form: the preview of a newly chosen icon file. */
.app-icon-preview {
  display: block;
  max-inline-size: 100%;
  max-block-size: 10rem;
  padding: 0.25rem;
  border: 1px solid var(--bs-border-color);
  border-radius: var(--bs-border-radius);
  background-color: var(--bs-body-bg);
}

.app-icon-preview[hidden] {
  display: none;
}

/* Compact list tables: slightly narrower cells, and short-value columns whose header may wrap. */
.app-list-table > :not(caption) > * > * {
  padding-inline: 1rem;
}

.app-list-table th.app-th-wrap {
  width: 1%;
  white-space: normal;
}

.app-list-table th.app-th-wrap .app-sort-link {
  white-space: normal;
}

/* Product form: the box that makes SKU, Model Number and Barcode stand out, with codes in a fixed-width font. */
.app-identifiers {
  padding: 1rem;
  border: 1px solid rgba(var(--bs-primary-rgb), 0.3);
  border-radius: var(--bs-border-radius-lg);
  background-color: rgba(var(--bs-primary-rgb), 0.04);
}

.app-identifiers .form-label {
  font-weight: 500;
}

.app-code-input {
  font-family: var(--bs-font-monospace);
  letter-spacing: 0.03em;
}

/* Product form, Return Policy preview: each condition line with its check or cross icon. */
.app-return-conditions > li {
  display: flex;
  gap: 0.5rem;
  align-items: flex-start;
  margin-bottom: 0.5rem;
}

.app-return-conditions > li > i {
  flex: 0 0 auto;
  margin-top: 0.125rem;
}

/* A Color swatch (the Color List and the Product Group members show the small one). */
.app-color-swatch {
  flex: 0 0 auto;
  width: 2.375rem;
  height: 2.375rem;
  border: 1px solid var(--bs-border-color);
  border-radius: var(--bs-border-radius);
}

/* Create and Edit Color: the large preview of the hex code; an invalid or empty code shows a message instead. */
.app-color-preview {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 8rem;
  border: 1px solid var(--bs-border-color);
  border-radius: var(--bs-border-radius-lg);
}

.app-color-preview-empty {
  display: none;
  color: var(--bs-secondary-color);
}

.app-color-preview[data-empty="true"] {
  background-color: var(--bs-body-bg) !important;
  border-style: dashed;
}

.app-color-preview[data-empty="true"] .app-color-preview-empty {
  display: inline;
}

/* Create and Edit Color: the inline Coloris picker fills its column, with a taller color area. */
.app-color-picker-host .clr-picker {
  width: 100%;
  max-width: 22rem;
  border: 1px solid var(--bs-border-color);
  box-shadow: none;
}

.app-color-picker-host .clr-gradient {
  height: 10rem;
}

/* Color List: a smaller swatch beside the Color name. */
.app-color-swatch-sm {
  display: inline-block;
  width: 1.25rem;
  height: 1.25rem;
  vertical-align: middle;
}

/*
 * Product form, Color specification: the dropdown that shows each Color's swatch, name and hex code. The select it
 * sets stays in the form (for posting and validation) but is visually hidden.
 */
.app-color-picker {
  position: relative;
}

.app-color-native {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
  opacity: 0;
}

.app-color-toggle,
.app-color-option {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  text-align: start;
}

.app-color-toggle {
  width: 100%;
}

.app-color-toggle .app-color-text,
.app-color-option .app-color-text {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.app-color-dot {
  flex: 0 0 auto;
  width: 1.25rem;
  height: 1.25rem;
  border: 1px solid rgba(0, 0, 0, 0.15);
  border-radius: 50%;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.35);
}

.app-color-dot[hidden] {
  display: none;
}

.app-color-hex {
  flex: 0 0 auto;
  font-family: var(--bs-font-monospace);
  font-size: 0.8125rem;
  color: var(--bs-secondary-color);
}

.app-color-option.active .app-color-hex {
  color: inherit;
}

.app-color-menu {
  width: 100%;
  padding-top: 0.5rem;
}

.app-color-options {
  max-height: 16rem;
  overflow-y: auto;
}

.app-color-option[hidden] {
  display: none;
}

/* The invalid state is on the hidden select, so the visible button right after it shows it. */
.app-color-native.input-validation-error + .app-color-toggle {
  border-color: var(--bs-form-invalid-border-color, var(--bs-danger));
}

/* Product form: the Feature and Specification rows that the Admin adds, removes and drags into order. */
.app-row-list > * + * {
  margin-top: 1rem;
}

/*
 * Each Specification sits in its own box, so its controls are not mistaken for the next one's: a tinted border with a
 * thick accent on the start side, a light shadow, and a tinted header strip that carries the Specification's name.
 */
.app-spec-row {
  padding: 1rem 1.25rem 1.25rem;
  border: 1px solid var(--app-spec-border);
  border-inline-start: 4px solid var(--app-spec-accent);
  border-radius: var(--bs-border-radius-lg);
  background-color: var(--bs-paper-bg, var(--bs-body-bg));
  box-shadow: 0 0.125rem 0.375rem rgba(34, 48, 62, 0.06);
}

.app-spec-header {
  margin: -1rem -1.25rem 1rem;
  padding: 0.625rem 1.25rem;
  border-bottom: 1px solid var(--app-spec-header-border);
  border-start-end-radius: calc(var(--bs-border-radius-lg) - 1px);
  background-color: var(--app-spec-header-bg);
}

/* The Specification's name stands out from its type badge and controls. */
.app-spec-header .app-spec-name,
.app-spec-header .app-variant-name,
.app-type-definition-name {
  font-size: 1rem;
  font-weight: 600;
  color: var(--bs-heading-color);
}

.app-drag-handle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 2.375rem;
  color: var(--bs-secondary-color);
  cursor: grab;
  touch-action: none;
}

.app-spec-header .app-drag-handle {
  height: 1.75rem;
}

.app-drag-handle:hover {
  color: var(--bs-heading-color);
}

/* The place a dragged row will drop into. */
.app-sortable-ghost {
  opacity: 0.4;
}

/* A read-only Edit Product form (disabled fieldset) has no add, remove or drag controls. */
fieldset:disabled .app-edit-only {
  display: none !important;
}

/* The Product description boxes keep their size. */
.app-no-resize {
  resize: none;
}

/* Product form: the Product's Tags, each with its remove button. */
.app-tag-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  max-inline-size: 100%;
  font-size: 0.8125rem;
}

.app-tag-chip .btn-close {
  width: 0.5rem;
  height: 0.5rem;
  padding: 0.25rem;
  background-size: 0.5rem;
}

/* Product list: a Product's first Tags, then "+N". */
.app-product-tags {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 0.25rem;
  max-inline-size: 16rem;
}

/* Product form, Images: the drop area and the image cards; the first card is the main image. */
.app-image-dropzone {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
  border: 2px dashed var(--bs-border-color);
  border-radius: var(--bs-border-radius);
  color: var(--bs-secondary-color);
  text-align: center;
  cursor: pointer;
}

.app-image-dropzone.app-dragover {
  border-color: var(--bs-primary);
  color: var(--bs-primary);
}

.app-image-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(8.5rem, 1fr));
  gap: 1rem;
}

.app-image-card {
  position: relative;
  aspect-ratio: 1;
  overflow: hidden;
  border: 1px solid var(--bs-border-color);
  border-radius: var(--bs-border-radius);
  background-color: var(--bs-body-bg);
  cursor: grab;
}

.app-image-card img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  -webkit-user-drag: none;
  user-select: none;
  -webkit-touch-callout: none;
}

.app-image-card .app-main-badge {
  position: absolute;
  inset-block-end: 0.5rem;
  inset-inline-start: 0.5rem;
  display: none;
}

.app-image-card.app-image-main .app-main-badge {
  display: inline-block;
}

.app-image-card.app-image-main {
  border-color: var(--bs-primary);
}

.app-image-card .app-image-remove {
  position: absolute;
  inset-block-start: 0.375rem;
  inset-inline-end: 0.375rem;
}

.app-image-card .app-image-progress {
  position: absolute;
  inset-inline: 0.75rem;
  inset-block-end: 50%;
}

.app-image-card .app-image-error {
  position: absolute;
  inset: 2.5rem 0.5rem 0.5rem;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.8125rem;
  color: var(--bs-danger);
  text-align: center;
}

.app-image-card .app-image-error[hidden] {
  display: none;
}

fieldset:disabled .app-image-card {
  cursor: default;
}

/* A card with an uploaded image opens the preview; in a read-only form that is all a click does. */
fieldset:disabled .app-image-card[data-large-url] {
  cursor: zoom-in;
}

.app-image-card:focus-visible {
  outline: 2px solid var(--bs-primary);
  outline-offset: 2px;
}

/* The Large-image preview: the image fits the window without cropping, with previous/next on its sides. */
.app-preview-body {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 12rem;
  padding: 1rem 3.75rem;
  background-color: var(--bs-gray-100, #f5f5f9);
}

.app-preview-image {
  max-width: 100%;
  max-height: calc(100vh - 12rem);
  object-fit: contain;
}

.app-preview-nav {
  position: absolute;
  inset-block-start: 50%;
  transform: translateY(-50%);
  background-color: var(--bs-body-bg);
  box-shadow: var(--bs-box-shadow-sm);
}

.app-preview-prev {
  inset-inline-start: 0.75rem;
}

.app-preview-next {
  inset-inline-end: 0.75rem;
}

.app-preview-nav[hidden] {
  display: none;
}

/* List thumbnails: a stored image (or a placeholder when there is none), scaled to fit without cropping. */
.app-thumb {
  display: inline-flex;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  inline-size: 2.5rem;
  block-size: 2.5rem;
  border: 1px solid var(--bs-border-color);
  border-radius: var(--bs-border-radius-sm);
  background-color: var(--bs-body-bg);
  color: var(--bs-secondary-color);
  object-fit: contain;
}

/* Brand logos are usually wide. */
.app-thumb-wide {
  inline-size: 5rem;
  block-size: 2rem;
}

/* Edit forms: the current image of a field, or the newly chosen file that replaces it. */
.app-image-preview {
  display: block;
  inline-size: 8rem;
  block-size: 8rem;
  border: 1px solid var(--bs-border-color);
  border-radius: var(--bs-border-radius);
  background-color: var(--bs-body-bg);
  object-fit: contain;
}

.app-image-preview-wide {
  inline-size: 12rem;
  block-size: 6rem;
}

/* A logo that will be removed when the form is saved. */
.app-image-preview.app-image-removing {
  opacity: 0.35;
}

.app-image-preview[hidden] {
  display: none;
}

/* Reordering Product images: the dragged card stays in place, dimmed; a smaller copy follows the pointer and a line
   marks the gap it will be dropped into. */
.app-image-card.app-image-dragging {
  opacity: 0.35;
}

.app-image-ghost {
  position: fixed;
  z-index: 2000;
  pointer-events: none;
  opacity: 0.9;
  box-shadow: var(--bs-box-shadow);
  transform: translate(-50%, -50%) rotate(2deg);
}

.app-image-drop-indicator {
  position: fixed;
  z-index: 1999;
  inline-size: 4px;
  border-radius: 2px;
  background-color: var(--bs-primary);
  pointer-events: none;
}

.app-image-drop-indicator[hidden] {
  display: none;
}

body.app-image-sorting,
body.app-image-sorting * {
  cursor: grabbing !important;
  user-select: none;
}

/* Help side panel: a short explanation with a small heading for this page. */
.app-help-panel {
  --bs-offcanvas-width: 26rem;
}

.app-help-heading {
  margin-bottom: 0.5rem;
  color: var(--bs-heading-color);
  font-weight: 600;
}

.app-help-screen {
  padding-inline-start: 0.75rem;
  border-inline-start: 3px solid var(--bs-primary);
}

/* The Help button beside a page title keeps the small button size inside the heading. */
.app-help-button {
  font-size: 0.8125rem;
}
