/* ============================================================================
   S4 — Catalogue.
   Served as _content/ClientSharedLibrary/css/catalog.css.
   Depends on tokens.css; expects bootstrap-bridge.css to load before it.

   Covers /products (ProductGrid), /categories (CategoryGrid), ProductEdit,
   /category/edit/{id} (CategoryEdit), /productclassification, /images and
   /WebstoreManagement, plus the ProductView, CatagoryCard1, ProductPricingTable,
   CloneProducts, PricingUnitPicker and ProductSearchSelect components.

   SPECIFICITY — same strategy as S2/S3/S6. Every rule is prefixed .mp-catalog,
   added to each page's root, which takes it to (0,2,0) and beats a component
   style block at equal weight without a blanket !important. Page roots carry
   `class="mp-ui mp-catalog"`; .mp-ui pulls in the shared Bootstrap layer.

   WHAT THIS SEGMENT IS FOR
   This is where the catalogue is *built and maintained*, not where it is sold
   from. The operator is doing bulk data entry: renaming twenty products,
   repricing a category, dragging things into order, pasting images. So:

     · rows are dense and the header stays put, because the unit of work is a
       screenful of rows, not one record;
     · an edited-but-unsaved cell has to be obvious at a glance — this page can
       hold dozens of pending changes before anything is written;
     · the two grids look like each other, because they are the same job on two
       kinds of record (see the note on .pg-*/.cg-* below).

   DENSITY: `compact` on the two desktop grids, default on the edit forms and
   the mobile card views.
   ========================================================================= */

/* ============================================================================
   1. Page frame
   ========================================================================= */
.mp-catalog {
  font-family: var(--mp-font);
  font-size: var(--mp-text-ui);
  color: var(--mp-ink);
}

/* .product-header was `font-size: 2.5rem` centred, in the business's own brand
   colour — a 40px display heading on a data-entry screen, pushing the first row
   of actual work below the fold on a laptop. It is a page title. */
.mp-catalog .product-header {
  text-align: left;
  font-size: var(--mp-text-xl);
  font-weight: var(--mp-weight-bold);
  line-height: var(--mp-leading-tight);
  color: var(--mp-ink);
  margin: 0;
}

.mp-catalog h4,
.mp-catalog h5,
.mp-catalog h6 { color: var(--mp-ink); line-height: var(--mp-leading-tight); }

/* ============================================================================
   2. The grid tables  (.pg-* on /products, .cg-* on /categories)

   These two were written separately and ended up as near-duplicates: toolbar,
   scroll box, near-black header band, dirty/new/drag-over row states, thumb,
   empty-thumb, cell input, edited input, sort spinner, drag handle — the same
   fourteen ideas twice, differing only in arbitrary numbers (42px vs 44px
   thumbs, .83rem vs .84rem type, 4px vs 5px cell padding). They are the same
   control doing the same job on two kinds of record, so they are defined once
   here against the density tokens and both prefixes are listed.

   The only difference kept is .pg-table's larger min-width: it carries roughly
   three times the columns and genuinely needs the room.
   ========================================================================= */
.mp-catalog .pg-desktop,
.mp-catalog .cg-desktop { width: 100%; min-height: 0; }

/* ---- Toolbar ------------------------------------------------------------- */
.mp-catalog .pg-toolbar,
.mp-catalog .cg-toolbar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--mp-gap-tight);
  padding: var(--mp-space-2);
  background: var(--mp-surface-2);
  border: 1px solid var(--mp-line);
  border-radius: var(--mp-radius) var(--mp-radius) 0 0;
  position: sticky;
  top: 0;
  z-index: 3;
}

.mp-catalog .pg-save-btn   { min-width: 130px; }
.mp-catalog .pg-add-btn    { min-width: 110px; }
.mp-catalog .pg-column-sel { max-width: 160px; }
.mp-catalog .pg-cat-sel    { max-width: 180px; }
.mp-catalog .pg-search-box { max-width: 240px; }
.mp-catalog .pg-count-badge { font-size: var(--mp-text-xs); }

.mp-catalog .pg-col-picker {
  background: var(--mp-surface) !important;   /* .bg-white is a utility */
  border-color: var(--mp-line) !important;
  border-radius: var(--mp-radius-sm);
  box-shadow: var(--mp-shadow-lg) !important;
  color: var(--mp-ink);
}

/* ---- Scroll box ---------------------------------------------------------- */
/* The box has to be BOUNDED, not just overflow-x: auto.

   `position: sticky` resolves against the nearest scrolling ancestor, and
   `overflow-x: auto` makes this box that ancestor for everything inside it. So
   long as the box is as tall as its own content it never scrolls, and a sticky
   header inside it can never move — which is why the `position: sticky` that
   was already on .pg-thead th had never actually stuck to anything. Capping the
   height makes this the real scrollport in both axes, and the header works.

   Measured in the running app: 49 products give a 5,670px table inside a box
   that was 5,670px tall. */
.mp-catalog .pg-table-scroll,
.mp-catalog .cg-table-scroll {
  overflow: auto;
  max-height: calc(100dvh - 220px);
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  border: 1px solid var(--mp-line);
  border-top: none;
  border-radius: 0 0 var(--mp-radius) var(--mp-radius);
  background: var(--mp-surface);
}

.mp-catalog .pg-table,
.mp-catalog .cg-table {
  width: 100%;
  table-layout: auto;
  border-collapse: separate;
  border-spacing: 0;
  font-size: var(--mp-text-ui);
  color: var(--mp-ink-2);
  margin-bottom: 0 !important;
}
.mp-catalog .pg-table { min-width: 900px; }
.mp-catalog .cg-table { min-width: 500px; }

/* ---- Header band --------------------------------------------------------- */
/* Was `background: #343a40; color: #f8f9fa` — a near-black bar across the top
   of a light page, which reads as the heaviest thing on screen when the rows
   below it are the content. Same quiet header S6 gave the report tables, and it
   stays sticky so a column keeps its meaning 200 rows down. */
.mp-catalog .pg-thead th,
.mp-catalog .pg-th,
.mp-catalog .cg-thead th,
.mp-catalog .cg-th {
  background: var(--mp-surface-2);
  color: var(--mp-muted);
  font-size: var(--mp-text-xs);
  font-weight: var(--mp-weight-bold);
  letter-spacing: var(--mp-track-label);
  white-space: nowrap;
  padding: var(--mp-space-2) var(--mp-space-3);
  border-bottom: 1px solid var(--mp-line-strong) !important;
  position: sticky;
  top: 0;
  z-index: 2;
}

/* The column-visibility checkbox that lives inside several headings. */
.mp-catalog .pg-th input[type="checkbox"],
.mp-catalog .cg-th input[type="checkbox"] {
  accent-color: var(--mp-accent);
  vertical-align: middle;
  margin-left: var(--mp-space-1);
}

/* Column width hints — unchanged, they encode real content widths. */
.mp-catalog .pg-th-sort   { width: 80px; }
.mp-catalog .pg-th-img    { width: 56px; }
.mp-catalog .pg-th-name   { min-width: 140px; }
.mp-catalog .pg-th-cat    { min-width: 110px; }
.mp-catalog .pg-th-price  { width: 76px; }
.mp-catalog .pg-th-tax    { width: 100px; }
.mp-catalog .pg-th-chk    { width: 44px; }
.mp-catalog .pg-th-ing    { width: 72px; }
.mp-catalog .pg-th-act    { width: 100px; }
.mp-catalog .cg-th-drag   { width: 54px; }
.mp-catalog .cg-th-img    { width: 60px; }
.mp-catalog .cg-th-name   { min-width: 160px; }
.mp-catalog .cg-th-act    { width: 110px; }

/* ---- Body rows ----------------------------------------------------------- */
.mp-catalog .pg-row td,
.mp-catalog .cg-row td {
  padding: var(--mp-space-1) var(--mp-space-2);
  vertical-align: middle;
  border-bottom: 1px solid var(--mp-line);
  background: var(--mp-surface);
}
.mp-catalog .pg-row:hover td,
.mp-catalog .cg-row:hover td { background: var(--mp-surface-2); }

/* ---- Row states ---------------------------------------------------------
   Three states, and they must not be told apart by hue alone: an operator with
   forty pending edits needs to see which rows are unsaved from across the
   table. Each gets a coloured left rail as well as a tint.  */
.mp-catalog .pg-row-dirty td,
.mp-catalog .cg-row-dirty td { background: var(--mp-warn-soft) !important; }
.mp-catalog .pg-row-dirty > td:first-child,
.mp-catalog .cg-row-dirty > td:first-child { box-shadow: inset 3px 0 0 var(--mp-warn); }

.mp-catalog .pg-row-new td,
.mp-catalog .cg-row-new td { background: var(--mp-good-soft) !important; }
.mp-catalog .pg-row-new > td:first-child,
.mp-catalog .cg-row-new > td:first-child { box-shadow: inset 3px 0 0 var(--mp-good); }

.mp-catalog .pg-row-drag-over td,
.mp-catalog .cg-row-drag-over td { background: var(--mp-accent-soft) !important; }
.mp-catalog .pg-row-drag-over > td:first-child,
.mp-catalog .cg-row-drag-over > td:first-child { box-shadow: inset 3px 0 0 var(--mp-accent); }

/* ---- Cell inputs --------------------------------------------------------- */
.mp-catalog .pg-cell-input,
.mp-catalog .cg-cell-input {
  padding: 0 var(--mp-space-2) !important;
  min-height: var(--mp-control-h);
  font-size: var(--mp-text-ui) !important;
  min-width: 54px;
  background: var(--mp-surface);
  color: var(--mp-ink);
  border: 1px solid var(--mp-line);
  border-radius: var(--mp-radius-sm);
}
.mp-catalog .pg-cell-input:focus,
.mp-catalog .cg-cell-input:focus {
  border-color: var(--mp-accent);
  box-shadow: var(--mp-focus);
  outline: none;
}

/* An input whose value differs from what is stored. Warn-coloured, matching
   the row rail, so a changed cell and its changed row say the same thing. */
.mp-catalog .pg-edited,
.mp-catalog .cg-edited {
  border-color: var(--mp-warn) !important;
  background: var(--mp-warn-soft) !important;
  color: var(--mp-ink) !important;
  font-weight: var(--mp-weight-medium);
}

/* ---- Sort control -------------------------------------------------------- */
.mp-catalog .pg-sort-ctrl {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1px;
}
.mp-catalog .pg-sort-btn {
  background: var(--mp-surface);
  border: 1px solid var(--mp-line-strong);
  border-radius: var(--mp-radius-sm);
  padding: 0 var(--mp-space-1);
  line-height: 1.4;
  font-size: var(--mp-text-xs);
  cursor: pointer;
  color: var(--mp-ink-2);
}
.mp-catalog .pg-sort-btn:hover { background: var(--mp-surface-2); color: var(--mp-ink); }

.mp-catalog .pg-sort-num,
.mp-catalog .cg-sort-input {
  width: 46px;
  text-align: center;
  background: var(--mp-surface);
  color: var(--mp-ink);
  border: 1px solid var(--mp-line-strong);
  border-radius: var(--mp-radius-sm);
  font-family: var(--mp-font-num);
  font-variant-numeric: tabular-nums;
  font-size: var(--mp-text-xs);
  padding: 1px 3px;
}
.mp-catalog .cg-sort-input { margin-top: 2px; }
.mp-catalog .pg-sort-num::-webkit-inner-spin-button,
.mp-catalog .pg-sort-num::-webkit-outer-spin-button,
.mp-catalog .cg-sort-input::-webkit-inner-spin-button,
.mp-catalog .cg-sort-input::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
.mp-catalog .pg-sort-num,
.mp-catalog .cg-sort-input { -moz-appearance: textfield; }

/* ---- Thumbnails ---------------------------------------------------------- */
.mp-catalog .pg-thumb,
.mp-catalog .cg-thumb {
  width: 44px;
  height: 44px;
  object-fit: cover;
  border-radius: var(--mp-radius-sm);
  border: 1px solid var(--mp-line);
  background: var(--mp-surface-2);
  display: block;
}

/* The empty slot is a target, not a failure — dashed, and it says so on hover
   because clicking it opens the image search. */
.mp-catalog .pg-thumb-empty,
.mp-catalog .cg-thumb-empty {
  width: 44px;
  height: 44px;
  border: 1px dashed var(--mp-line-strong);
  border-radius: var(--mp-radius-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--mp-muted);
  font-size: var(--mp-text-md);
  cursor: pointer;
}
.mp-catalog .pg-thumb-empty:hover,
.mp-catalog .cg-thumb-empty:hover {
  border-color: var(--mp-accent);
  color: var(--mp-accent);
  background: var(--mp-accent-soft);
}

/* ---- Drag handles -------------------------------------------------------- */
.mp-catalog .pg-drag-handle,
.mp-catalog .cg-drag-handle {
  cursor: grab;
  font-size: var(--mp-text-md);
  color: var(--mp-muted);
  line-height: 1;
  padding: 0 2px;
  user-select: none;
}
.mp-catalog .pg-drag-handle:hover,
.mp-catalog .cg-drag-handle:hover { color: var(--mp-ink); }
.mp-catalog .pg-drag-handle:active,
.mp-catalog .cg-drag-handle:active { cursor: grabbing; }

/* ---- Ingredient expansion row -------------------------------------------- */
.mp-catalog .pg-ing-row td {
  padding: 0 !important;
  background: var(--mp-surface-sunk);
  border-top: none !important;
}
.mp-catalog .pg-ing-panel {
  padding: var(--mp-space-3) var(--mp-space-4);
  border-top: 1px dashed var(--mp-line-strong);
}
.mp-catalog .pg-ing-name { min-width: 140px; max-width: 200px; }
.mp-catalog .pg-ing-qty  { width: 70px; }
.mp-catalog .pg-ing-unit { font-size: var(--mp-text-xs); min-width: 36px; }

/* Marks a value still inheriting the business-wide amount rather than one this
   branch set — otherwise identical to a branch that typed the same number. */
.mp-catalog .cg-shared {
  display: inline-block;
  font-size: var(--mp-text-xs);
  text-transform: none;
  letter-spacing: normal;
  padding: 0 var(--mp-space-1);
  margin-top: 2px;
  border-radius: var(--mp-radius-pill);
  background: var(--mp-surface-sunk);
  color: var(--mp-muted);
}

.mp-catalog .category-controls .btn { min-width: 56px; padding: 0 var(--mp-space-2); }

/* ============================================================================
   3. Image search panel (used by the new-product row)
   ========================================================================= */
.mp-catalog .pg-imgsearch-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(9, 12, 17, .62);
  z-index: 1200;
}

.mp-catalog .pg-imgsearch-panel {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: min(680px, 96vw);
  max-height: 85vh;
  background: var(--mp-surface);
  color: var(--mp-ink);
  border: 1px solid var(--mp-line);
  border-radius: var(--mp-radius-lg);
  box-shadow: var(--mp-shadow-lg);
  z-index: 1201;
  padding: var(--mp-space-5);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.mp-catalog .pg-imgsearch-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
  gap: var(--mp-space-2);
  overflow-y: auto;
  flex: 1;
  padding-right: var(--mp-space-1);
}

.mp-catalog .pg-imgsearch-thumb {
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: var(--mp-radius-sm);
  border: 2px solid transparent;
  background: var(--mp-surface-2);
  transition: border-color .15s, transform .15s;
}
.mp-catalog .pg-imgsearch-thumb:hover { border-color: var(--mp-accent); transform: scale(1.04); }
.mp-catalog .pg-imgsearch-thumb.disabled { pointer-events: none; }

/* ============================================================================
   4. Full-screen editor shell

   Both grids open their editor as a fixed full-screen panel over a backdrop,
   with identical rules declared in each page. One definition, and the panel now
   takes the theme surface instead of a hardcoded white — the editor was the one
   place in the app that stayed white in dark mode with themed controls on it.
   ========================================================================= */
.mp-catalog .fullscreen-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(9, 12, 17, .62);
  z-index: 1040;
}

.mp-catalog .fullscreen-modal {
  position: fixed;
  inset: 0;
  background: var(--mp-surface);
  color: var(--mp-ink);
  z-index: 1050;
  display: flex;
  flex-direction: column;
  padding: var(--mp-space-4);
  overflow-y: auto;
}
.mp-catalog .fullscreen-modal .modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-bottom: 1px solid var(--mp-line);
  padding: 0 0 var(--mp-space-3) 0;
  margin-bottom: var(--mp-space-4);
}
.mp-catalog .fullscreen-modal .modal-title {
  margin: 0;
  font-size: var(--mp-text-lg);
  font-weight: var(--mp-weight-bold);
  line-height: 1.2;
}
.mp-catalog .fullscreen-modal .btn-close {
  margin: 0;
}

/* ============================================================================
   5. Keywords

   Draggable keyword chips: dragged from the panel onto a product card to tag
   it. The drop target has to read as a target while a drag is in flight.
   ========================================================================= */
.mp-catalog .keywords-panel,
.mp-catalog .keyword-suggestions,
.mp-catalog .clone-products-section,
.mp-catalog .product-count-info {
  background: var(--mp-surface-2);
  border: 1px solid var(--mp-line);
  border-radius: var(--mp-radius);
  padding: var(--mp-space-4);
  box-shadow: none;
}
.mp-catalog .clone-products-section h4 {
  margin-bottom: var(--mp-space-4);
  color: var(--mp-ink);
  font-size: var(--mp-text-md);
}

.mp-catalog .keywords-container {
  display: flex;
  flex-wrap: wrap;
  gap: var(--mp-space-2);
  padding: var(--mp-space-2) 0 0;
  margin-top: 0;
}

.mp-catalog .keyword-badge {
  display: inline-flex;
  align-items: center;
  padding: var(--mp-space-1) var(--mp-space-3);
  border-radius: var(--mp-radius-pill);
  background: var(--mp-surface);
  border: 1px solid var(--mp-line-strong);
  color: var(--mp-ink-2);
  font-size: var(--mp-text-sm);
  cursor: grab;
  transition: background-color .15s ease, border-color .15s ease;
  user-select: none;
}
.mp-catalog .keyword-badge:hover {
  background: var(--mp-accent-soft);
  border-color: var(--mp-accent);
  color: var(--mp-accent);
  transform: none;
  box-shadow: none;
}
.mp-catalog .keyword-badge:active { cursor: grabbing; }
.mp-catalog .keyword-badge.dragging { opacity: .6; }

.mp-catalog .keyword-remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
  color: var(--mp-muted);
  margin-left: var(--mp-space-1);
  padding: 0;
  cursor: pointer;
  font-size: var(--mp-text-md);
}
.mp-catalog .keyword-remove:hover { color: var(--mp-danger); }

/* The column has to be a flex box for the card inside it to stretch to the
   line's height — otherwise the tallest card in a row sets the row height and
   the shorter ones float with their "Ingredients" footer stranded mid-tile. */
.mp-catalog #product-grid-container-mobile > [class*="col"] { display: flex; }
.mp-catalog .product-drop-target { position: relative; transition: outline-color .15s ease; height: 100%; width: 100%; }
.mp-catalog .active-drop-target {
  outline: 2px dashed var(--mp-accent);
  outline-offset: 4px;
  background: var(--mp-accent-soft);
  border-radius: var(--mp-radius);
  transform: none;
  box-shadow: none;
}

.mp-catalog .category-drop-target {
  border: 2px dashed var(--mp-line-strong);
  border-radius: var(--mp-radius);
  background: var(--mp-surface-2);
  transition: border-color .15s ease, background-color .15s ease;
  cursor: default;
}
.mp-catalog .category-drop-target:hover,
.mp-catalog .active-category-drop {
  border-color: var(--mp-accent);
  background: var(--mp-accent-soft);
  transform: none;
  box-shadow: none;
}
.mp-catalog .category-drop-target i { font-size: var(--mp-text-xl); color: var(--mp-muted); }
.mp-catalog .category-drop-target p { margin-bottom: 0; color: var(--mp-ink-2); }

/* ============================================================================
   6. Draggable category strip (mobile reorder)
   ========================================================================= */
.mp-catalog .category-container-dragable {
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  gap: var(--mp-space-2);
  overflow-x: auto;
  padding-bottom: var(--mp-space-2);
  max-width: 100%;
}

.mp-catalog .category-card-dragable {
  display: flex;
  align-items: center;
  min-width: 170px;
  max-width: 250px;
  gap: var(--mp-space-3);
  padding: var(--mp-space-3) var(--mp-space-4);
  background: var(--mp-surface);
  border: 1px solid var(--mp-line);
  border-radius: var(--mp-radius);
  box-shadow: var(--mp-shadow-sm);
  cursor: grab;
  touch-action: none;
  user-select: none;
  transition: border-color .15s ease, box-shadow .15s ease;
}
.mp-catalog .category-card-dragable:hover { border-color: var(--mp-line-strong); box-shadow: var(--mp-shadow); transform: none; }
.mp-catalog .category-card-dragable:active { cursor: grabbing; }
.mp-catalog .category-card-dragable.dragging { opacity: .5; cursor: grabbing !important; transform: none; }
.mp-catalog .drag-handle-dragable { font-size: var(--mp-text-md); color: var(--mp-muted); }
.mp-catalog .category-name-dragable { font-weight: var(--mp-weight-medium); font-size: var(--mp-text-ui); color: var(--mp-ink); }

.mp-catalog .category-scroll-btn {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 36px;
  height: 36px;
  border-radius: var(--mp-radius-pill);
  background: var(--mp-surface);
  border: 1px solid var(--mp-line-strong);
  box-shadow: var(--mp-shadow);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 10;
  cursor: pointer;
  color: var(--mp-ink-2);
  transition: background-color .15s ease, color .15s ease;
}
.mp-catalog .category-scroll-btn:hover { background: var(--mp-surface-2); color: var(--mp-ink); }
.mp-catalog .category-scroll-btn:focus-visible { outline: 2px solid var(--mp-accent); outline-offset: 2px; }
.mp-catalog .category-scroll-btn:active { transform: translateY(-50%) scale(.95); }
.mp-catalog .category-scroll-btn-left  { left: -8px; }
.mp-catalog .category-scroll-btn-right { right: -8px; }

/* ============================================================================
   7. Catalogue cards — ProductView and CatagoryCard1

   EXTRACTED FROM THEIR COMPONENTS. Both render inside a @foreach / <Virtualize>
   over the catalogue, so Blazor was emitting one copy of each block per record:
   on a 200-product catalogue that is ~20,000 lines of duplicated CSS in the DOM,
   re-parsed on every render. Same problem S2 found in the till, same fix.

   Neither block contained Razor interpolation, so both lifted as-is. The
   per-record values that *are* interpolated stay inline on the elements:
   `background-color: @_home.backgroundcolor` and `font-size: @fontsize`.

   Both cards are painted with the business's own colour, so everything drawn on
   them takes --mp-on-brand rather than --mp-ink — the same rule the till's
   product tiles and the nav header follow.
   ========================================================================= */

/* ---- ProductView (the mobile product card) ------------------------------- */
.mp-catalog .product-card-view {
  height: 100%;
  display: flex;
  flex-direction: column;
  transition: box-shadow .2s ease;
}
.mp-catalog .product-card-view.expanded { height: auto; z-index: 1; position: relative; }
.mp-catalog .product-card-view.expanded .collapse.show { position: relative; background: inherit; }

.mp-catalog .product-card-view .image-container {
  position: relative;
  width: 100%;
  padding-top: 100%;
}
.mp-catalog .product-card-view .product-image {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}

.mp-catalog .product-card-view .card-body {
  flex: 1 0 auto;
  display: flex;
  flex-direction: column;
  min-height: 120px;
  color: var(--mp-on-brand);
}
.mp-catalog .product-card-view .card-footer {
  margin-top: auto;
  border-top: 1px solid rgba(255, 255, 255, .16);
  background: transparent;
  color: var(--mp-on-brand);
}
.mp-catalog .product-card-view .toggle-btn { color: var(--mp-on-brand); text-decoration: none; }
.mp-catalog .product-card-view .toggle-btn:focus { outline: none; box-shadow: none; }
.mp-catalog .product-card-view .toggle-btn:focus-visible { outline: 2px solid var(--mp-on-brand); outline-offset: 2px; }

.mp-catalog .product-card-view .price-container {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: var(--mp-space-2);
  margin-bottom: var(--mp-space-2);
}
.mp-catalog .product-card-view .price-container .card-title,
.mp-catalog .product-card-view .price-container .card-text {
  margin: 0;
  min-width: 0;
  word-wrap: break-word;
  overflow-wrap: break-word;
  color: var(--mp-on-brand);
}

.mp-catalog .product-card-view .ingredients-section {
  border-top: 1px solid rgba(255, 255, 255, .16);
  margin-top: auto;
}

/* The topping list carried Bootstrap's .text-muted, which is a grey tuned for a
   light page — on a dark brand card it dropped close to the background, and the
   bridge's !important recolour cannot know it is sitting on brand paint. It
   uses the dim on-brand token instead, which is defined against that surface. */
.mp-catalog .on-brand-dim { color: var(--mp-on-brand-dim); }

@media (max-width: 576px) {
  .mp-catalog .product-card-view .price-container { flex-direction: column; align-items: flex-start; }
  .mp-catalog .product-card-view .card-body { padding: var(--mp-space-2) !important; min-height: 100px; }
}

/* ---- CatagoryCard1 (the category tile on /categories) -------------------- */
.mp-catalog .card-container {
  cursor: pointer;
  transition: transform .2s ease;
  min-height: 200px;
  height: auto;
}

.mp-catalog .card-container .card-custom {
  overflow: visible;
  height: 100%;
  display: flex;
  flex-direction: column;
  transition: box-shadow .2s ease;
}

.mp-catalog .card-container .image-container {
  aspect-ratio: 4/3;
  overflow: hidden;
  flex: 0 0 75%;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
}

.mp-catalog .card-container .img-fluid1 {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform .4s ease;
}
.mp-catalog .card-container:hover .img-fluid1 { transform: scale(1.04); }

/* A category with no image showed nothing at all — an empty coloured block with
   the name underneath. It shows its initial, so the tiles stay tellable apart
   while images are still being filled in. */
.mp-catalog .card-container .cat-initial {
  font-size: 2rem;
  font-weight: var(--mp-weight-bold);
  color: var(--mp-on-brand-dim);
  line-height: 1;
}

.mp-catalog .card-container .card-body {
  flex: 1 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100px;
  padding: var(--mp-space-3) !important;
  word-wrap: break-word;
  overflow: visible;
}

.mp-catalog .card-container .product-name {
  display: block;
  color: var(--mp-on-brand);
  font-weight: var(--mp-weight-bold);
  transition: none;
  word-break: break-word;
  text-shadow: none;
}

/* STATE INDICATOR — the only thing that says which category is selected.

   Two separate ways this was being erased, both caught in the browser:
     · S2's failure mode — an ancestor-scoped rule outranking .selected. Idle is
       :not(.selected) here so the two can never collide.
     · the markup's own Bootstrap utilities. `.border-0` is `border: 0
       !important` and killed the selection border outright, while `.shadow`
       gave the *idle* card a heavier 8px/16px drop than the selected one had —
       so the selected tile read as the less prominent of the two. Both utilities
       were removed from CatagoryCard1's markup rather than out-specified.

   The ring is a white inner edge on the brand colour plus an accent halo, so it
   survives whatever colour the business has chosen for its tiles. */
.mp-catalog .card-container:not(.selected) .card-custom {
  border: 3px solid transparent;
  box-shadow: var(--mp-shadow-sm);
}
.mp-catalog .card-container.selected .card-custom {
  border: 3px solid var(--mp-on-brand);
  box-shadow: 0 0 0 3px var(--mp-accent), var(--mp-shadow);
}

@media (max-width: 767px) {
  .mp-catalog .card-container { min-height: 1px; height: auto; }
  .mp-catalog .card-container .image-container { aspect-ratio: 3/2; flex: 0 0 70%; }
  .mp-catalog .card-container .card-body { flex: 1 0 30%; min-height: 70px; padding: var(--mp-space-2) !important; }
}

/* ============================================================================
   8. The product editor (ProductEdit)

   Single-instance — one editor is open at a time — so its block stays with the
   component. What moved here is everything that was a colour literal, plus the
   rules it was declaring against bare Bootstrap classes.
   ========================================================================= */
.mp-catalog .product-edit-container {
  padding-bottom: 60px;
  height: 100%;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}

.mp-catalog .product-image { border: 1px solid var(--mp-line); overflow: hidden; }

.mp-catalog .overlay-text {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  color: #FFFFFF;
  background: rgba(9, 12, 17, .62);
  padding: var(--mp-space-3);
  border-radius: var(--mp-radius-sm);
  cursor: pointer;
  text-align: center;
}

.mp-catalog .cost-summary {
  border: 1px solid var(--mp-line);
  border-radius: var(--mp-radius-sm);
  margin-top: var(--mp-space-4);
  background: var(--mp-surface-2);
}
.mp-catalog .cost-summary .badge { font-size: var(--mp-text-ui); padding: var(--mp-space-2) var(--mp-space-4); }

/* ---- Image picker inside the editor -------------------------------------- */
.mp-catalog .image-layout { display: flex; gap: var(--mp-space-5); min-height: 100px; justify-content: center; }
.mp-catalog .image-layout.with-suggestions { justify-content: flex-start; }

.mp-catalog .main-image {
  width: 100px;
  height: 100px;
  position: relative;
  border-radius: var(--mp-radius);
  overflow: hidden;
  box-shadow: var(--mp-shadow);
  flex-shrink: 0;
}
/* The preview fills its box. Without this the picture drew at its own size (the
   hosted "medium" is several hundred pixels), so the box showed only its top-left corner. */
.mp-catalog .main-image img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.mp-catalog .main-image > label {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  margin: 0;
  cursor: pointer;
}

.mp-catalog .suggestions-panel {
  height: auto;
  min-height: 300px;
  display: flex;
  flex-direction: column;
  flex: 1;
  padding: var(--mp-space-1);
  border: 1px solid var(--mp-line);
  border-radius: var(--mp-radius-sm);
  background: var(--mp-surface-2);
  overflow: hidden;
}
.mp-catalog .suggestions-header { display: flex; justify-content: flex-end; padding: 0 0 var(--mp-space-1); }

.mp-catalog .image-suggestions {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(70px, 1fr));
  gap: var(--mp-space-2);
  overflow-y: auto;
  max-height: 300px;
  margin-top: var(--mp-space-2);
}
.mp-catalog .suggestion-image {
  width: 100%;
  height: 70px;
  object-fit: cover;
  cursor: pointer;
  border: 2px solid transparent;
  border-radius: var(--mp-radius-sm);
  background: var(--mp-surface);
  transition: border-color .15s;
}
.mp-catalog .suggestion-image:hover { border-color: var(--mp-accent); }
.mp-catalog .suggestion-image.disabled { pointer-events: none; opacity: .6; cursor: not-allowed; }
.mp-catalog .no-suggestions-message { text-align: center; color: var(--mp-muted); font-size: var(--mp-text-sm); margin-bottom: var(--mp-space-1); }

.mp-catalog .choose-photo-btn {
  margin-top: auto;
  padding: var(--mp-space-2) var(--mp-space-3);
  font-size: var(--mp-text-sm);
  background: var(--mp-accent);
  color: var(--mp-accent-ink);
  border: none;
  border-radius: var(--mp-radius-sm);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: none;
}
.mp-catalog .choose-photo-btn:hover { background: var(--mp-accent-hover); }

.mp-catalog .camera-icon {
  position: absolute;
  bottom: 8px;
  right: 8px;
  background: rgba(9, 12, 17, .72);
  color: #FFFFFF;
  width: 32px;
  height: 32px;
  border-radius: var(--mp-radius-pill);
  display: flex;
  justify-content: center;
  align-items: center;
  cursor: pointer;
  z-index: 10;
  transition: background-color .15s ease;
  box-shadow: var(--mp-shadow-sm);
}
.mp-catalog .camera-icon:hover { background: var(--mp-accent); transform: none; }
.mp-catalog .camera-icon i { font-size: 16px; }

.mp-catalog .image-loading-overlay {
  position: absolute;
  inset: 0;
  background: color-mix(in srgb, var(--mp-surface) 80%, transparent);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 20;
}

.mp-catalog .close-btn {
  cursor: pointer;
  display: flex;
  justify-content: center;
  align-items: center;
  background: var(--mp-surface-2);
  color: var(--mp-ink-2);
  border-radius: var(--mp-radius-pill);
  width: 24px;
  height: 24px;
  transition: background-color .15s ease;
}
.mp-catalog .close-btn:hover { background: var(--mp-line); color: var(--mp-ink); transform: none; }

/* ---- A newly-added ingredient row ---------------------------------------
   Was a dashed amber box with an infinite `highlight-pulse` animation — a
   never-ending attention pull on a form the operator is still typing into. It
   keeps the amber, loses the animation, and the pulse is honoured only for
   users who have not asked for reduced motion (see the reduced-motion block).  */
.mp-catalog .new-ingredient-row {
  background: var(--mp-warn-soft);
  border: 2px dashed var(--mp-warn);
  border-radius: var(--mp-radius-sm);
  padding: var(--mp-space-3);
  margin-bottom: var(--mp-space-4) !important;
  box-shadow: none;
  animation: none;
}
.mp-catalog .new-ingredient {
  border-color: var(--mp-warn) !important;
  background: var(--mp-warn-soft) !important;
  color: var(--mp-ink) !important;
  font-weight: var(--mp-weight-medium);
}
.mp-catalog .new-badge {
  position: absolute;
  top: -10px;
  right: -5px;
  background: var(--mp-warn);
  color: var(--mp-warn-ink);
  font-size: var(--mp-text-xs);
  font-weight: var(--mp-weight-bold);
  padding: 2px 6px;
  border-radius: var(--mp-radius-pill);
  box-shadow: var(--mp-shadow-sm);
  z-index: 5;
}

/* ---- Area pricing rows --------------------------------------------------- */
.mp-catalog .area-price-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: var(--mp-space-3);
  background: var(--mp-surface-2);
  border: 1px solid var(--mp-line);
  border-left: 4px solid var(--mp-accent);
  border-radius: var(--mp-radius-sm);
  margin-bottom: var(--mp-space-2);
  transition: background-color .15s ease;
}
.mp-catalog .area-price-item:hover { background: var(--mp-surface-sunk); box-shadow: none; }
.mp-catalog .area-price-info { display: flex; flex-direction: column; gap: var(--mp-space-1); }
.mp-catalog .area-price-name { font-weight: var(--mp-weight-bold); color: var(--mp-ink); }
.mp-catalog .area-price-value {
  font-family: var(--mp-font-num);
  font-variant-numeric: tabular-nums;
  font-size: var(--mp-text-sm);
  color: var(--mp-ink-2);
}

/* ---- CategoryEdit's image picker ----------------------------------------
   A second copy of the same idea as ProductEdit's, written independently. Both
   are defined here so a category and a product are edited through the same
   control.  */
.mp-catalog .main-image-container {
  flex: 1;
  position: relative;
  width: 100px;
  height: 100px;
  border: 1px solid var(--mp-line);
  border-radius: var(--mp-radius-sm);
  overflow: hidden;
  display: flex;
  justify-content: center;
  align-items: center;
  margin: 0 auto;
  background: var(--mp-surface-2);
}
.mp-catalog .main-image-container.small { height: 100px; }
.mp-catalog .main-image-container.large { height: 300px; }
.mp-catalog .main-image-container img { width: 100px; height: 100px; object-fit: cover; }

.mp-catalog .placeholder-image {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--mp-surface-2);
  color: var(--mp-muted);
}

.mp-catalog .suggestions-container { flex: 1; display: none; height: 300px; overflow-y: auto; }
.mp-catalog .suggestions-container.show { display: block; }

.mp-catalog .button-controls {
  position: absolute;
  top: var(--mp-space-2);
  right: var(--mp-space-2);
  display: flex;
  flex-direction: column;
  gap: var(--mp-space-2);
  z-index: 10;
}

/* These sit on top of the product photo, so their ground is the image, not the
   page — a token surface would vanish against a light photo. They keep an
   opaque light chip with a dark glyph in both themes, which is the same reason
   --mp-on-brand is fixed. */
.mp-catalog .camera-button,
.mp-catalog .upload-button {
  background: rgba(255, 255, 255, .92);
  color: #171A21;
  border: none;
  border-radius: var(--mp-radius-pill);
  width: 35px;
  height: 35px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: background-color .15s ease;
  box-shadow: var(--mp-shadow);
}
.mp-catalog .camera-button:hover,
.mp-catalog .upload-button:hover { background: #FFFFFF; transform: none; }
.mp-catalog .camera-button:focus-visible,
.mp-catalog .upload-button:focus-visible { outline: 2px solid var(--mp-accent); outline-offset: 2px; }

.mp-catalog .product-details { padding: var(--mp-space-3); margin-top: var(--mp-space-3); }
.mp-catalog .input-file { display: none; }

/* ============================================================================
   9. Small components
   ========================================================================= */
/* PricingUnitPicker — the bar that says which branch's prices you are editing.
   Getting this wrong means repricing the wrong shop, so it is tinted, not
   plain, and the "shared" note is warn-coloured because it is the surprising
   case (the number you see belongs to every branch, not this one). */
.mp-catalog .pu-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--mp-space-2);
  padding: var(--mp-space-2) var(--mp-space-3);
  margin-bottom: var(--mp-space-2);
  border: 1px solid var(--mp-line);
  border-left: 3px solid var(--mp-accent);
  border-radius: var(--mp-radius-sm);
  background: var(--mp-accent-soft);
}
.mp-catalog .pu-label { font-size: var(--mp-text-sm); font-weight: var(--mp-weight-bold); color: var(--mp-ink-2); margin: 0; }
.mp-catalog .pu-select { width: auto; min-width: 10rem; }
.mp-catalog .pu-note { font-size: var(--mp-text-sm); }
.mp-catalog .pu-note-shared { color: var(--mp-warn); font-weight: var(--mp-weight-medium); }
.mp-catalog .pu-note-unit { color: var(--mp-muted); }

/* CloneProducts' .custom-select was a hand-copied form control — and an
   unscoped `.custom-select`, which collides by name with the report toolbar's.
   Pointed at the same tokens as every other control. */
.mp-catalog .custom-select {
  background: var(--mp-surface);
  color: var(--mp-ink);
  border: 1px solid var(--mp-line-strong);
  border-radius: var(--mp-radius-sm);
  min-height: var(--mp-control-h);
  padding: 0 var(--mp-space-3);
  font-family: inherit;
  font-size: var(--mp-text-ui);
}
.mp-catalog .custom-select:focus { border-color: var(--mp-accent); box-shadow: var(--mp-focus); outline: none; }
.mp-catalog .custom-label { color: var(--mp-ink-2); font-weight: var(--mp-weight-bold); font-size: var(--mp-text-sm); margin-bottom: var(--mp-space-1); display: block; }

.mp-catalog .file-label { cursor: pointer; display: inline-block; }

/* ---- /images (the Unsplash gallery) --------------------------------------
   Its block redefined `.container` — a Bootstrap *layout* class — capping every
   container in the app at 1200px and adding 20px of padding while the gallery
   was open, and `.modal-content`, `.pagination` and `.close-button` on top of
   that. The page's own frame is .images-page now.  */
.mp-catalog .images-page {
  max-width: 1200px;
  margin: 0 auto;
  padding: var(--mp-space-5);
}

.mp-catalog .search-container {
  display: flex;
  justify-content: center;
  gap: var(--mp-space-2);
  margin-bottom: var(--mp-space-6);
}
.mp-catalog .search-input {
  width: min(400px, 100%);
  min-height: var(--mp-control-h);
  padding: 0 var(--mp-space-3);
  background: var(--mp-surface);
  color: var(--mp-ink);
  border: 1px solid var(--mp-line-strong);
  border-radius: var(--mp-radius-sm);
  font-family: inherit;
  font-size: var(--mp-text-ui);
}
.mp-catalog .search-input:focus { border-color: var(--mp-accent); box-shadow: var(--mp-focus); outline: none; }
.mp-catalog .search-button {
  padding: 0 var(--mp-space-5);
  min-height: var(--mp-control-h);
  background: var(--mp-accent);
  color: var(--mp-accent-ink);
  border: none;
  border-radius: var(--mp-radius-sm);
  cursor: pointer;
  font-family: inherit;
  font-size: var(--mp-text-ui);
  font-weight: var(--mp-weight-medium);
}
.mp-catalog .search-button:hover { background: var(--mp-accent-hover); }
.mp-catalog .search-button:disabled { opacity: .55; cursor: default; }

.mp-catalog .image-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: var(--mp-gap);
  margin-bottom: var(--mp-space-6);
}
.mp-catalog .image-card {
  position: relative;
  border-radius: var(--mp-radius);
  overflow: hidden;
  background: var(--mp-surface-2);
  box-shadow: var(--mp-shadow-sm);
  transition: box-shadow .15s ease;
  cursor: pointer;
}
.mp-catalog .image-card:hover { box-shadow: var(--mp-shadow); transform: none; }
.mp-catalog .image-item { width: 100%; height: 200px; object-fit: cover; display: block; }

.mp-catalog .images-page .pagination {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: var(--mp-space-4);
  margin-top: var(--mp-space-6);
}
.mp-catalog .page-info {
  font-family: var(--mp-font-num);
  font-variant-numeric: tabular-nums;
  font-size: var(--mp-text-ui);
  color: var(--mp-ink-2);
}

.mp-catalog .loading-overlay {
  position: fixed;
  inset: 0;
  background: color-mix(in srgb, var(--mp-bg) 80%, transparent);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 1000;
}

.mp-catalog .img-modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(9, 12, 17, .82);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 2000;
}
.mp-catalog .img-modal-box { position: relative; max-width: 90vw; max-height: 90vh; }
.mp-catalog .modal-image { max-width: 100%; max-height: 90vh; object-fit: contain; display: block; }
.mp-catalog .img-modal-close {
  position: absolute;
  top: -44px;
  right: 0;
  background: var(--mp-surface);
  color: var(--mp-ink);
  border: none;
  border-radius: var(--mp-radius-pill);
  width: 36px;
  height: 36px;
  cursor: pointer;
  font-size: var(--mp-text-lg);
  display: flex;
  align-items: center;
  justify-content: center;
}
.mp-catalog .img-modal-close:focus-visible { outline: 2px solid var(--mp-accent); outline-offset: 2px; }

/* ---- /WebstoreManagement tabs ------------------------------------------- */
.mp-catalog .webstore-tabs { border-bottom: 1px solid var(--mp-line); }
.mp-catalog .webstore-tabs .nav-link {
  color: var(--mp-ink-2) !important;      /* the markup rule was !important too */
  font-weight: var(--mp-weight-medium);
  border: none;
  border-bottom: 2px solid transparent;
  background: none;
  transition: color .15s ease, border-color .15s ease;
}
.mp-catalog .webstore-tabs .nav-link:hover { color: var(--mp-ink) !important; background: var(--mp-surface-2); }
.mp-catalog .webstore-tabs .nav-link.active {
  color: var(--mp-accent) !important;
  font-weight: var(--mp-weight-bold);
  border-bottom-color: var(--mp-accent);
  background: none;
}

/* ============================================================================
   10. Loading and empty states
   ========================================================================= */
.mp-catalog .loading-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 200px;
  width: 100%;
  gap: var(--mp-space-3);
  padding: var(--mp-space-6);
}
.mp-catalog .loading-spinner,
.mp-catalog .spinner { border-color: var(--mp-line); border-top-color: var(--mp-accent); }
.mp-catalog .loading-text { color: var(--mp-muted); font-size: var(--mp-text-ui); margin: 0; }

/* ============================================================================
   11. Responsive & motion
   ========================================================================= */
@media (max-width: 767.98px) {
  .mp-catalog .product-edit-container { padding-bottom: 250px; }
  .mp-catalog .button-group {
    position: sticky;
    bottom: 0;
    background: var(--mp-surface);
    border-top: 1px solid var(--mp-line);
    padding: var(--mp-space-4);
    box-shadow: 0 -2px 10px rgba(16, 24, 40, .1);
    z-index: 1000;
  }
  .mp-catalog .ingredients-section { margin-bottom: var(--mp-space-7); }
  .mp-catalog .pg-toolbar,
  .mp-catalog .cg-toolbar { position: static; }
}

@media (prefers-reduced-motion: reduce) {
  .mp-catalog *,
  .mp-catalog *::before,
  .mp-catalog *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
}
