/*
  Asimo Shop: the shared stylesheet on Bootstrap 5.3 (docs/SPEC.md, "UI style: themes").
  Base, layout, components and page blocks. Every colour, shadow, radius, border and blur comes from a --ui-* token;
  the values live in themes/<name>.css under [data-theme="<name>"], set on <html> by the layouts (and on the
  admin's theme previews). The component classes (.neu-card, .neu-btn, .neu-input, .neu-choice, .btn-neu-primary,
  .table-stack) are the stable API the views use, whatever the theme. Later tasks add page blocks at the end under
  a comment naming the task, and a value to every theme file for any new token.
*/

:root {
  --ui-tap: 44px; /* tap targets: the same in every theme */
  --ui-sidebar-width: 240px; /* admin side menu from 992 px, and its offcanvas width below */
  --ui-content-gutter: clamp(1.5rem, 2vw, 3rem); /* admin content side gutter from 1400 px */
  --ui-content-max: 1920px; /* widest admin content from 1400 px; centred beyond */
  --ui-measure: 960px; /* admin forms and notes that must not stretch, from 1400 px */
  --ui-input-compact: 18rem; /* phone, price and tracking-number inputs from 1400 px */
  --ui-sticky-top: 1rem; /* gap above sticky admin columns from 1400 px */
}

/* Bootstrap reads its own variables; they follow the nearest theme. */
[data-theme] {
  --bs-body-bg: var(--ui-bg);
  --bs-body-color: var(--ui-text);
  --bs-link-color: var(--ui-accent-dark);
  --bs-link-hover-color: var(--ui-accent);
  --bs-border-radius: var(--ui-radius-sm);
}

/* ---------- Base ---------- */

body {
  background: var(--ui-bg);
  color: var(--ui-text);
  font-family: "Segoe UI", Tahoma, "Noto Sans Arabic", system-ui, -apple-system, Roboto, "Helvetica Neue", Arial, sans-serif;
  overflow-wrap: anywhere; /* long Arabic and French names wrap instead of scrolling the page */
}

img, video {
  max-width: 100%;
  height: auto;
}

.text-muted-neu {
  color: var(--ui-text-muted);
}

.neu-container {
  max-width: 1140px;
}

/* Every interactive element gets the same visible 2px accent ring. */
a:focus-visible,
button:focus-visible,
.btn:focus-visible,
.form-control:focus,
.form-select:focus,
.form-check-input:focus,
.btn-check:focus-visible + .neu-choice {
  outline: none;
  box-shadow: var(--ui-focus);
}

/* ---------- Page chrome ---------- */

.site-header,
.site-footer {
  background: var(--ui-surface);
}

.site-header {
  box-shadow: var(--ui-shadow-bar);
}

/* Public header: frosted when the theme blurs. The admin top bar stays plain; its menu panel is the frosted part. */
body:not(.admin) .site-header {
  -webkit-backdrop-filter: var(--ui-blur);
  backdrop-filter: var(--ui-blur);
}

.site-footer {
  color: var(--ui-text-muted);
  font-size: .9rem;
  text-align: center;
}

.site-brand {
  color: var(--ui-text);
  font-size: 1.25rem;
  font-weight: 700;
  text-decoration: none;
}

.site-brand:hover {
  color: var(--ui-accent-dark);
}

.admin-badge {
  background: var(--ui-accent);
  border-radius: 8px;
  color: var(--ui-on-accent);
  font-size: .7rem;
  font-weight: 600;
  padding: .1rem .4rem;
  text-transform: uppercase;
  vertical-align: middle;
}

/* ---------- Components ---------- */

.neu-card {
  -webkit-backdrop-filter: var(--ui-blur);
  backdrop-filter: var(--ui-blur);
  background: var(--ui-surface);
  border: 0;
  border-radius: var(--ui-radius);
  box-shadow: var(--ui-shadow-raised);
}

/* At most two glass levels: a card inside a card is a near-solid panel with no blur of its own. */
.neu-card .neu-card {
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  background: var(--ui-surface-strong);
}

.neu-btn {
  align-items: center;
  background: var(--ui-surface);
  border: 0;
  border-radius: var(--ui-radius-sm);
  box-shadow: var(--ui-shadow-raised-sm);
  color: var(--ui-text);
  display: inline-flex;
  justify-content: center;
  min-height: var(--ui-tap);
  min-width: var(--ui-tap);
  padding: .5rem 1rem;
}

.neu-btn:hover {
  background: var(--ui-surface);
  color: var(--ui-accent-dark);
}

.neu-btn:active,
.neu-btn.active {
  background: var(--ui-surface);
  box-shadow: var(--ui-shadow-inset);
  color: var(--ui-text);
}

.neu-btn:disabled,
.neu-btn.disabled {
  box-shadow: none;
  opacity: .6;
}

/* Bootstrap buttons keep the theme's transitions and get its hover lift (none in neumorph). */
.btn.neu-btn,
.btn.btn-neu-primary {
  transition: var(--ui-transition);
}

@media (hover: hover) {
  .btn.neu-btn:hover:not(:disabled, .disabled),
  .btn.btn-neu-primary:hover:not(:disabled) {
    transform: var(--ui-lift);
  }
}

.neu-input {
  background: var(--ui-surface-strong);
  border: 2px solid transparent;
  border-radius: var(--ui-radius-sm);
  box-shadow: var(--ui-shadow-inset);
  color: var(--ui-text);
  font-size: 1rem; /* 16 px minimum: iPhones do not zoom in */
  min-height: var(--ui-tap);
  padding: .5rem .75rem;
}

.neu-input:focus {
  background: var(--ui-surface-strong);
  border-color: var(--ui-accent);
  color: var(--ui-text);
}

.neu-input::placeholder {
  color: var(--ui-text-muted);
}

/* Size, colour and delivery-type pills, built on Bootstrap's .btn-check. */
.neu-choice {
  align-items: center;
  background: var(--ui-surface);
  border: 2px solid transparent;
  border-radius: 999px;
  box-shadow: var(--ui-shadow-raised-sm);
  color: var(--ui-text);
  cursor: pointer;
  display: inline-flex;
  min-height: var(--ui-tap);
  min-width: var(--ui-tap);
  padding: .4rem 1rem;
  justify-content: center;
}

.btn-check:checked + .neu-choice {
  background: var(--ui-accent-soft);
  border-color: var(--ui-accent); /* shadow alone is easy to miss in sunlight */
  box-shadow: var(--ui-shadow-inset);
  font-weight: 600;
}

.btn-check:disabled + .neu-choice {
  box-shadow: none;
  cursor: not-allowed;
  opacity: .5;
  text-decoration: line-through;
}

/* The one solid, high-contrast button: "Confirm order". */
.btn-neu-primary {
  background: var(--ui-accent);
  border: 0;
  border-radius: var(--ui-radius-sm);
  box-shadow: var(--ui-shadow-raised-sm);
  color: var(--ui-on-accent);
  font-weight: 700;
  min-height: var(--ui-tap);
  padding: .6rem 1.5rem;
}

.btn-neu-primary:hover,
.btn-neu-primary:focus-visible {
  background: var(--ui-accent-dark);
  color: var(--ui-on-accent);
}

.btn-neu-primary:active {
  box-shadow: var(--ui-shadow-inset);
  color: var(--ui-on-accent);
}

.btn-neu-primary:disabled {
  background: var(--ui-accent);
  color: var(--ui-on-accent);
  opacity: .75;
}

/* ---------- Validation (validation.js and the server share these slots) ---------- */

.invalid-feedback {
  color: var(--ui-danger);
  font-size: .9rem;
  font-weight: 600;
}

.is-invalid ~ .invalid-feedback,
.invalid-feedback.d-block {
  display: block;
}

.invalid-feedback:empty {
  display: none !important;
}

.invalid-feedback::before {
  content: "\26A0\FE0E"; /* warning sign: red text plus an icon, never colour alone */
  margin-inline-end: .35rem;
}

.neu-input.is-invalid,
.neu-input.is-invalid:focus {
  background-image: none; /* Bootstrap's own icon would overlap ours */
  border-color: var(--ui-danger);
  padding-inline-end: .75rem;
}

.error-summary {
  background: var(--ui-surface-strong);
  border: 2px solid var(--ui-danger);
  border-radius: var(--ui-radius-sm);
  color: var(--ui-danger);
}

.error-summary:focus {
  box-shadow: var(--ui-focus);
  outline: none;
}

.form-spinner {
  margin-inline-end: .5rem;
}

/* ---------- Images ---------- */

.img-fallback {
  align-items: center;
  aspect-ratio: 1 / 1;
  background: var(--ui-surface-strong);
  border-radius: var(--ui-radius-sm);
  box-shadow: var(--ui-shadow-inset);
  color: var(--ui-text-muted);
  display: flex;
  font-weight: 600;
  justify-content: center;
  padding: 1rem;
  text-align: center;
  width: 100%;
}

/* ---------- Error pages ---------- */

.error-page {
  margin-inline: auto;
  max-width: 560px;
}

.error-code {
  color: var(--ui-accent);
  font-size: 3.5rem;
  font-weight: 800;
  line-height: 1;
  margin-bottom: .5rem;
}

.reference-id {
  font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
  font-weight: 700;
  letter-spacing: .05em;
}

/* ---------- Admin ---------- */

/* A table sits in one .neu-card with flat rows: shadows on every row make long lists hard to scan. */
.admin .table {
  --bs-table-bg: transparent;
  --bs-table-color: var(--ui-text);
  --bs-table-border-color: var(--ui-border);
  margin-bottom: 0;
}

.admin .nav-link {
  color: var(--ui-text);
  min-height: var(--ui-tap);
  align-items: center;
  display: flex;
}

.admin .nav-link:hover {
  color: var(--ui-accent-dark);
}

/* Under 768 px each table row becomes a stacked block; labels come from the cell's data-label. */
@media (max-width: 767.98px) {
  .table-stack thead {
    border: 0;
    clip-path: inset(50%);
    height: 1px;
    overflow: hidden;
    position: absolute;
    white-space: nowrap;
    width: 1px;
  }

  .table-stack,
  .table-stack tbody,
  .table-stack tr,
  .table-stack td {
    display: block;
    width: 100%;
  }

  .table-stack tr {
    border-bottom: 1px solid var(--ui-border);
    padding: .75rem 0;
  }

  .table-stack tr:last-child {
    border-bottom: 0;
  }

  .table-stack td {
    align-items: baseline;
    border: 0;
    display: flex;
    gap: 1rem;
    justify-content: space-between;
    padding: .25rem 0;
    text-align: end;
  }

  .table-stack td::before {
    color: var(--ui-text-muted);
    content: attr(data-label);
    flex: 0 0 auto;
    font-weight: 600;
    text-align: start;
  }
}

/* ---------- Product page, order form and captcha (T7, T8, T5) ---------- */

/* Swipe gallery: CSS scroll-snap, no library. Photos keep a 4:5 frame so the page does not jump while loading. */
.gallery-track {
  border-radius: var(--ui-radius);
  box-shadow: var(--ui-shadow-raised);
  display: flex;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-behavior: smooth;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
}

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

.gallery-track:focus-visible {
  box-shadow: var(--ui-focus);
  outline: none;
}

.gallery-slide {
  flex: 0 0 100%;
  margin: 0;
  scroll-snap-align: center;
}

.gallery-slide img,
.gallery-thumb img {
  aspect-ratio: 4 / 5;
  display: block;
  object-fit: cover;
  width: 100%;
}

.gallery-empty {
  aspect-ratio: 4 / 5;
}

.gallery-counter {
  color: var(--ui-text-muted);
  font-size: .9rem;
  margin: .5rem 0 0;
  text-align: center;
}

.gallery-thumbs {
  flex-wrap: wrap;
  gap: .75rem;
  margin-top: 1rem;
}

.gallery-thumb {
  border: 2px solid transparent;
  border-radius: var(--ui-radius-sm);
  box-shadow: var(--ui-shadow-raised-sm);
  display: block;
  overflow: hidden;
  width: 72px;
}

.gallery-thumb[aria-current="true"] {
  border-color: var(--ui-accent);
}

.product-name {
  font-size: 1.5rem;
  font-weight: 700;
}

.product-price {
  align-items: baseline;
  display: flex;
  flex-wrap: wrap;
  gap: .25rem .75rem;
}

.price-now {
  color: var(--ui-secondary);
  font-size: 1.6rem;
  font-weight: 800;
}

.price-old {
  color: var(--ui-text-muted);
  font-size: 1.05rem;
}

.product-description {
  white-space: pre-line;
}

.order-form {
  padding: 1.25rem;
}

@media (min-width: 768px) {
  .order-form {
    padding: 1.75rem;
  }
}

.order-form fieldset legend {
  float: none;
  font-size: 1rem;
  margin-bottom: .5rem;
}

/* Size, colour and delivery pills wrap onto new lines on narrow screens. */
.choice-group {
  display: flex;
  flex-wrap: wrap;
  gap: .75rem;
}

.delivery-choice {
  border-radius: var(--ui-radius-sm);
  flex: 1 1 12rem;
  flex-direction: column;
  gap: .15rem;
  padding: .5rem 1rem;
  text-align: center;
}

.choice-fee {
  color: var(--ui-text-muted);
  font-size: .9rem;
  font-weight: 600;
}

.btn-check:checked + .neu-choice .choice-fee {
  color: var(--ui-accent-dark);
}

.qty-control {
  align-items: center;
  display: flex;
  gap: .75rem;
  max-width: 13rem;
}

.qty-control .neu-btn {
  flex: 0 0 auto;
  font-size: 1.25rem;
  font-weight: 700;
}

.qty-control .neu-input {
  min-width: 0;
  text-align: center;
}

.phone-input {
  text-align: right;
}

.order-summary {
  border-radius: var(--ui-radius-sm);
  box-shadow: var(--ui-shadow-inset);
  margin: 1.5rem 0;
  padding: .75rem 1rem;
}

.order-summary > div {
  display: flex;
  gap: 1rem;
  justify-content: space-between;
  padding: .25rem 0;
}

.order-summary dt {
  font-weight: 400;
}

.order-summary dd {
  font-weight: 600;
  margin: 0;
  text-align: end;
}

.order-total {
  border-top: 1px solid var(--ui-border);
  font-size: 1.15rem;
  margin-top: .25rem;
  padding-top: .5rem !important;
}

.order-total dt,
.order-total dd {
  font-weight: 800;
}

/* The captcha image sits in an inset frame on the page colour, so it looks part of the form. */
.captcha-row {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  gap: .75rem;
}

.captcha-frame {
  background: var(--ui-surface-solid); /* opaque in every theme, so the drawn sum stays readable */
  border-radius: var(--ui-radius-sm);
  box-shadow: var(--ui-shadow-inset);
  display: inline-flex;
  padding: .25rem;
}

.captcha-frame img {
  display: block;
  height: 56px;
  width: 168px;
}

.captcha-input {
  flex: 0 0 5.5rem;
  text-align: center;
  width: 5.5rem;
}

/* Honeypot: clipped to nothing, never display:none (some bots skip hidden fields) and never pushed off-screen
   (an offset can widen the page on phones). */
.hp-field {
  clip-path: inset(50%);
  height: 1px;
  overflow: hidden;
  position: absolute;
  white-space: nowrap;
  width: 1px;
}

.cod-note {
  color: var(--ui-text-muted);
  font-size: .95rem;
  margin: .75rem 0 0;
  text-align: center;
}

/* ---------- Thank-you page (T8) ---------- */

.thanks-page {
  margin-inline: auto;
  max-width: 560px;
}

.thanks-mark {
  color: var(--ui-accent);
  font-size: 3rem;
  font-weight: 800;
  line-height: 1;
  margin-bottom: .5rem;
}

.order-number {
  font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
  font-size: 1.5rem;
  font-weight: 700;
  letter-spacing: .05em;
}

/* ---------- Admin pages: login, suppliers, products, delivery, wilaya fees, blocklist (T6, T12-T16) ---------- */

.admin-page-head {
  align-items: flex-start;
  display: flex;
  flex-wrap: wrap;
  gap: .75rem 1rem;
  justify-content: space-between;
  margin-bottom: 1rem;
}

.login-card {
  max-width: 420px;
  margin-top: 2rem;
}

.admin .form-select.neu-input {
  padding-inline-end: 2.25rem;
}

/* Bootstrap's blue switch and check would be the only blue on the page. */
.admin .form-check-input {
  border-color: var(--ui-text-muted);
  height: 1.5rem;
  width: 1.5rem;
}

.admin .form-switch .form-check-input {
  height: 1.5rem;
  width: 2.75rem;
}

.admin .form-check-input:checked {
  background-color: var(--ui-accent);
  border-color: var(--ui-accent);
}

.admin .form-check-input:focus {
  border-color: var(--ui-accent);
  box-shadow: var(--ui-focus);
}

.status-pill {
  border-radius: 999px;
  box-shadow: var(--ui-shadow-inset);
  display: inline-block;
  font-size: .85rem;
  font-weight: 600;
  padding: .15rem .75rem;
}

.status-on {
  color: var(--ui-accent-dark);
}

.status-off {
  color: var(--ui-text-muted);
}

.row-actions {
  white-space: normal;
}

.row-actions .btn,
.row-actions form {
  margin: .15rem .25rem .15rem 0;
}

/* Inputs inside table cells: a fixed, readable width on wide screens; the cell's label sits beside it on phones. */
.table-field {
  max-width: 11rem;
}

@media (max-width: 767.98px) {
  .table-stack .table-field {
    max-width: 9rem;
    text-align: start;
  }

  .table-stack .row-actions {
    justify-content: flex-start;
    text-align: start;
  }

  .table-stack td:empty {
    display: none;
  }
}

.admin-thumb {
  border-radius: var(--ui-radius-sm);
  box-shadow: var(--ui-shadow-raised-sm);
  height: auto;
  width: 48px;
}

.photo-grid {
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  margin: 0 0 1.25rem;
  padding: 0;
}

.photo-grid img {
  aspect-ratio: 4 / 5;
  border-radius: var(--ui-radius-sm);
  box-shadow: var(--ui-shadow-raised-sm);
  display: block;
  margin-bottom: .6rem;
  object-fit: cover;
  width: 100%;
}

.count-chips {
  display: inline-flex;
  flex-wrap: wrap;
  gap: .35rem;
  justify-content: flex-end;
}

.count-chip {
  border-radius: 999px;
  box-shadow: var(--ui-shadow-inset);
  font-size: .85rem;
  padding: .15rem .65rem;
  white-space: nowrap;
}

/* The save button of a long table stays in reach while scrolling, on phones above all. */
.sticky-actions {
  background: var(--ui-surface-strong);
  bottom: 0;
  margin-top: 1rem;
  padding: .75rem 0;
  position: sticky;
  z-index: 5;
}

/* Row buttons on phones: they wrap onto new lines instead of being squeezed into slivers. */
@media (max-width: 767.98px) {
  .table-stack td.row-actions {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    justify-content: flex-start;
  }

  .table-stack td.row-actions::before {
    display: none;
  }

  .table-stack td.row-actions .btn {
    flex: 0 0 auto;
    white-space: nowrap;
  }

  .table-stack td.row-actions form {
    margin: 0;
  }
}

/* Action cells have no label: on phones they start at the left and wrap, instead of squeezing the buttons. */
@media (max-width: 767.98px) {
  .table-stack td.row-actions,
  .table-stack td[data-label=""] {
    flex-wrap: wrap;
    justify-content: flex-start;
    text-align: start;
  }

  .table-stack td.row-actions::before,
  .table-stack td[data-label=""]::before {
    display: none;
  }

  .table-stack td.row-actions .btn,
  .table-stack td[data-label=""] .btn {
    white-space: nowrap;
  }
}

/* ---------- Orders list and order page (T17) ---------- */

.status-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
}

.status-tabs .btn {
  gap: .4rem;
  padding-inline: .85rem;
}

.order-status {
  border-radius: 999px;
  box-shadow: var(--ui-shadow-inset);
  display: inline-block;
  font-size: .85rem;
  font-weight: 600;
  padding: .15rem .75rem;
  white-space: nowrap;
}

.order-status-lg {
  font-size: 1rem;
  padding: .35rem 1rem;
}

/* Every theme keeps these text colours at 4.5:1 or more on its surfaces. */
.order-status-created { color: var(--ui-info); }
.order-status-confirmed { color: var(--ui-accent-dark); }
.order-status-shipped { color: var(--ui-info-alt); }
.order-status-delivered { color: var(--ui-success); }
.order-status-cancelled { color: var(--ui-text-muted); }
.order-status-fake { color: var(--ui-danger); }
.order-status-returned { color: var(--ui-warning); }

.score-badge {
  border-radius: 999px;
  display: inline-block;
  font-size: .85rem;
  font-weight: 600;
  padding: .15rem .65rem;
  white-space: nowrap;
}

.score-none { box-shadow: var(--ui-shadow-inset); color: var(--ui-text-muted); }
.score-some { box-shadow: var(--ui-shadow-inset); color: var(--ui-warning); }
.score-suspicious { background: var(--ui-danger); color: var(--ui-on-accent); }

.score-reasons {
  color: var(--ui-text-muted);
  font-size: .8rem;
  margin: .3rem 0 0;
  padding-inline-start: 1rem;
  text-align: start;
}

.order-suspicious > td:first-child {
  box-shadow: inset 4px 0 0 var(--ui-danger);
}

.orders-table td {
  vertical-align: top;
}

.status-form {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
}

.status-form .form-select {
  min-height: var(--ui-tap);
  width: auto;
}

.filter-check {
  align-items: center;
  display: flex;
  gap: .5rem;
  min-height: var(--ui-tap);
}

.filter-check .form-check-input {
  margin: 0;
}

.pager {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  gap: .75rem;
  justify-content: center;
}

.detail-list {
  display: grid;
  gap: .35rem 1rem;
  grid-template-columns: minmax(7rem, max-content) 1fr;
}

.detail-list dt {
  color: var(--ui-text-muted);
  font-weight: 600;
}

.detail-list dd {
  margin: 0;
  min-width: 0;
}

.detail-totals dd {
  text-align: end;
}

.delivery-option {
  align-items: flex-start;
  display: flex;
  gap: .75rem;
  min-height: var(--ui-tap);
  padding: .5rem 0;
}

.delivery-option .form-check-input {
  flex: 0 0 auto;
  margin-top: .1rem;
}

.delivery-option label {
  cursor: pointer;
  display: flex;
  flex-wrap: wrap;
  gap: 0 .75rem;
}

.delivery-option-numbers {
  color: var(--ui-text-muted);
}

.related-orders {
  list-style: none;
  margin: 0;
  padding: 0;
}

.related-orders li {
  border-bottom: 1px solid var(--ui-border);
  padding: .6rem 0;
}

.related-orders li:last-child {
  border-bottom: 0;
}

.related-orders a {
  display: inline-flex;
  align-items: center;
  min-height: var(--ui-tap);
  margin-inline-end: .5rem;
}

.block-offer form {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
}

/* Call and WhatsApp: big, side by side, easy to hit with a thumb. */
@media (max-width: 767.98px) {
  .contact-actions .btn {
    flex: 1 1 8rem;
    min-height: 3rem;
  }

  .table-stack td.contact-actions .btn {
    flex: 1 1 8rem;
  }

  .orders-table td {
    vertical-align: baseline;
  }

  .detail-list {
    grid-template-columns: 1fr;
    gap: 0;
  }

  .detail-list dd {
    margin-bottom: .5rem;
  }

  .detail-totals {
    grid-template-columns: 1fr auto;
    gap: .35rem 1rem;
  }

  .detail-totals dd {
    margin-bottom: 0;
  }
}

/* ---------- Responsive pass: tap targets of at least 44 x 44 px (T24) ---------- */

.site-brand,
.back-link {
  align-items: center;
  display: inline-flex;
  min-height: var(--ui-tap);
}

/* Names and order numbers in table cells are the row's main link; on phones they are tapped, not clicked. */
.admin .table td a:not(.btn) {
  align-items: center;
  display: inline-flex;
  min-height: var(--ui-tap);
}

/* A switch or box alone in a table cell: the label around it is the 44 px target. */
.tap-check {
  align-items: center;
  cursor: pointer;
  display: inline-flex;
  justify-content: center;
  min-height: var(--ui-tap);
  min-width: var(--ui-tap);
  padding-left: 0;
}

.tap-check .form-check-input {
  float: none;
  margin: 0;
}

/* A switch or box with its label beside it: the whole row is the target. */
.admin .form-check:has(> .form-check-label) {
  align-items: center;
  display: flex;
  gap: .6rem;
  min-height: var(--ui-tap);
  padding-left: 0;
}

.admin .form-check:has(> .form-check-label) > .form-check-input {
  flex: 0 0 auto;
  float: none;
  margin: 0;
}

.admin .form-check:has(> .form-check-label) > .form-check-label {
  cursor: pointer;
}

/* The orders table has nine columns and needs about 1000 px: beside the admin sidebar (T29) it stays a list of cards
   below 1340 px (as .table-stack is under 768 px). */
.orders-table th,
.orders-table .order-link,
.orders-table .btn {
  overflow-wrap: normal;
  white-space: nowrap;
}

@media (min-width: 768px) and (max-width: 1339.98px) {
  .orders-table thead {
    border: 0;
    clip-path: inset(50%);
    height: 1px;
    overflow: hidden;
    position: absolute;
    white-space: nowrap;
    width: 1px;
  }

  .orders-table,
  .orders-table tbody,
  .orders-table tr,
  .orders-table td {
    display: block;
    width: 100%;
  }

  .orders-table tr {
    border-bottom: 1px solid var(--ui-border);
    padding: .75rem 0;
  }

  .orders-table tr:last-child {
    border-bottom: 0;
  }

  .orders-table td {
    align-items: baseline;
    border: 0;
    display: flex;
    gap: 1rem;
    justify-content: space-between;
    padding: .25rem 0;
    text-align: end;
  }

  .orders-table td::before {
    color: var(--ui-text-muted);
    content: attr(data-label);
    flex: 0 0 auto;
    font-weight: 600;
    text-align: start;
  }

  .orders-table td[data-label=""] {
    flex-wrap: wrap;
    gap: .5rem;
    justify-content: flex-start;
  }

  .orders-table td[data-label=""]::before,
  .orders-table td:empty {
    display: none;
  }

  .orders-table .contact-actions .btn {
    flex: 0 0 12rem;
    min-height: 3rem;
  }
}

/* ---------- Privacy notice under the order button (T19, Law 18-07) ---------- */

.privacy-note {
  color: var(--ui-text-muted);
  font-size: .85rem;
  margin: .75rem 0 0;
}

/* ---------- Referrals: referrers, rewards and the order page (T26) ---------- */

/* At least 4.5:1 in every theme; Earned (owed) stands out as the one to act on. */
.reward-status-pending { color: var(--ui-info); }
.reward-status-earned { color: var(--ui-warning); }
.reward-status-paid { color: var(--ui-success); }
.reward-status-cancelled { color: var(--ui-text-muted); }

.share-code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-weight: 700;
  letter-spacing: .08em;
}

.reward-counts {
  list-style: none;
  margin: 0;
  padding: 0;
}

.reward-counts li + li {
  margin-top: .25rem;
}

.reward-totals {
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
}

.reward-total {
  color: var(--ui-text);
  display: flex;
  flex-direction: column;
  gap: .25rem;
  text-decoration: none;
}

.reward-total.active {
  box-shadow: var(--ui-shadow-inset);
}

.reward-total .order-status {
  align-self: flex-start;
}

.reward-total-amount {
  font-size: 1.35rem;
  font-weight: 700;
}

.paid-form {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
}

.paid-form .form-control {
  flex: 1 1 11rem;
  min-height: var(--ui-tap);
  width: auto;
}

/* ---------- Friend discount on the product page (T27) ---------- */

/* The theme's secondary colour, like the price; at least 4.5:1. */
.friend-discount {
  background: var(--ui-surface-strong); /* it sits on the page itself, not on a card */
  border-radius: 999px;
  box-shadow: var(--ui-shadow-inset);
  color: var(--ui-secondary);
  display: inline-block;
  font-weight: 600;
  margin: 0 0 1rem;
  padding: .35rem .85rem;
}

.order-summary .order-discount dd {
  color: var(--ui-secondary);
}

/* ---------- Referral credit on the order page (T27, admin) ---------- */

.referral-credit {
  border-top: 1px solid var(--ui-border);
  margin-top: 1rem;
  padding-top: 1rem;
}

/* Alone under the panel title, it needs no divider. */
h2 + .referral-credit {
  border-top: 0;
  margin-top: 0;
  padding-top: 0;
}

.credit-rewards {
  margin-bottom: 1rem;
  padding-inline-start: 1.25rem;
}

/* ---------- Bootstrap overlays and paging, should a page use them (T28) ---------- */

.modal-content,
.dropdown-menu {
  -webkit-backdrop-filter: var(--ui-blur);
  backdrop-filter: var(--ui-blur);
  background: var(--ui-surface-strong);
  border: 0;
  border-radius: var(--ui-radius);
  box-shadow: var(--ui-shadow-raised);
  color: var(--ui-text);
}

.pagination {
  --bs-pagination-bg: var(--ui-surface);
  --bs-pagination-color: var(--ui-accent-dark);
  --bs-pagination-border-color: var(--ui-border);
  --bs-pagination-hover-bg: var(--ui-surface-strong);
  --bs-pagination-active-bg: var(--ui-accent);
  --bs-pagination-active-border-color: var(--ui-accent);
  --bs-pagination-active-color: var(--ui-on-accent);
  --bs-pagination-focus-box-shadow: var(--ui-focus);
}

/* ---------- Appearance: theme choice with live previews (T28, admin) ---------- */

.theme-option {
  border: 2px solid transparent;
  border-radius: var(--ui-radius);
  box-shadow: var(--ui-shadow-inset);
  height: 100%;
  padding: 1rem;
}

/* The chosen card: accent border, not only the radio dot. */
.theme-option:has(> .form-check > .form-check-input:checked) {
  border-color: var(--ui-accent);
}

/* The preview carries its own data-theme, so everything inside takes that theme's tokens. */
.theme-preview {
  background: var(--ui-bg-mesh), var(--ui-bg);
  border-radius: var(--ui-radius-sm);
  color: var(--ui-text);
  padding: 1rem;
  pointer-events: none;
}

.theme-preview .table {
  font-size: .9rem;
}

.theme-preview .table td {
  overflow-wrap: normal;
  padding-inline: .3rem;
  white-space: nowrap;
}

@media (max-width: 575.98px) {
  .theme-option,
  .theme-preview {
    padding: .6rem;
  }
}

/* ---------- Admin side menu (T29) ---------- */

/* One element (Bootstrap's offcanvas-lg): an offcanvas from the left under 992 px, a sticky sidebar from 992 px.
   Glass: nothing above it may get a backdrop-filter or transform, or the fixed offcanvas would be trapped inside. */
.admin-topbar {
  padding-block: .5rem;
}

.admin-menu-toggle {
  padding-inline: 1rem;
}

.admin-sidebar {
  --bs-offcanvas-width: calc(var(--ui-sidebar-width) + var(--ui-tap)); /* room for the close button beside the brand */
  -webkit-backdrop-filter: var(--ui-blur);
  backdrop-filter: var(--ui-blur);
  background: var(--ui-surface-strong);
  color: var(--ui-text);
}

.admin-sidebar .offcanvas-header {
  gap: .5rem;
}

/* Bootstrap's close button is about 24 px: padded out to the 44 px tap target, the cross stays the same size. */
.admin-sidebar .btn-close {
  box-sizing: content-box;
  flex: 0 0 auto;
  padding: calc((var(--ui-tap) - 1em) / 2);
}

.admin-sidebar .offcanvas-body {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

/* Menu words and the brand never break mid-word. */
.admin-sidebar .site-brand,
.admin-nav .nav-link {
  overflow-wrap: normal;
  white-space: nowrap;
}

/* The current page: an accent bar and a soft fill (none in neumorph), plus bold text; never colour alone. */
.admin-nav .nav-link {
  border-end-end-radius: var(--ui-radius-sm);
  border-inline-start: 3px solid transparent;
  border-start-end-radius: var(--ui-radius-sm);
  padding-inline: .75rem;
}

.admin-nav .nav-link[aria-current="page"] {
  background: var(--ui-accent-soft);
  border-inline-start-color: var(--ui-accent);
  color: var(--ui-accent-dark);
  font-weight: 600;
}

.admin-signout {
  margin-top: auto;
}

.admin-main {
  min-width: 0; /* a wide table scrolls inside its card instead of widening the page */
}

@media (min-width: 992px) {
  /* Bootstrap makes an offcanvas-lg transparent (!important) from 992 px; the sidebar is a top-level surface. */
  .admin-sidebar {
    align-self: flex-start;
    background-color: var(--ui-surface) !important;
    border-inline-end: 1px solid transparent; /* a real edge in forced-colors mode, where shadows are dropped */
    box-shadow: var(--ui-shadow-raised);
    display: flex;
    flex: 0 0 var(--ui-sidebar-width);
    flex-direction: column;
    height: 100vh;
    height: 100dvh;
    overflow-y: auto;
    position: sticky;
    top: 0;
    width: var(--ui-sidebar-width);
    z-index: 1;
  }

  .admin-sidebar .offcanvas-header {
    display: flex;
  }

  .admin-sidebar .offcanvas-body {
    flex-grow: 1;
    padding: 0 1rem 1rem;
  }

  .admin-content {
    max-width: 1320px;
    padding-inline: 1.5rem;
  }
}

/* ---------- Large admin screens: the full width from 1400 px (T30) ---------- */

/* Rows: a soft fill under the pointer, where rows are a table (the orders table is cards below 1340 px). */
@media (hover: hover) and (min-width: 768px) {
  .admin .table:not(.orders-table) > tbody > tr:hover > * {
    --bs-table-bg-state: var(--ui-row-hover);
  }
}

@media (hover: hover) and (min-width: 1340px) {
  .admin .orders-table > tbody > tr:hover > * {
    --bs-table-bg-state: var(--ui-row-hover);
  }

  .admin .orders-table > tbody > tr.order-suspicious:hover > td:first-child {
    box-shadow: inset 4px 0 0 var(--ui-danger), inset 0 0 0 9999px var(--ui-row-hover);
  }

  .admin .orders-table > tbody > tr.order-backorder:hover > td:first-child {
    box-shadow: inset 4px 0 0 var(--ui-backorder-border), inset 0 0 0 9999px var(--ui-row-hover);
  }

  .admin .orders-table > tbody > tr.order-suspicious.order-backorder:hover > td:first-child {
    box-shadow: inset 4px 0 0 var(--ui-danger), inset 8px 0 0 var(--ui-backorder-border), inset 0 0 0 9999px var(--ui-row-hover);
  }
}

/* Below 1400 px nothing here applies: the content keeps T29's layout. */
@media (min-width: 1400px) {
  /* The content fills the room right of the sidebar, up to one cap so 2560 px screens keep sane line lengths. */
  .admin-content {
    max-width: calc(var(--ui-content-max) + 2 * var(--ui-content-gutter));
    padding-inline: var(--ui-content-gutter);
  }

  /* Forms and notes keep a readable measure; short values keep a short input. */
  .admin-readable {
    max-width: var(--ui-measure);
  }

  .admin-input-compact {
    max-width: var(--ui-input-compact);
  }

  /* An action or photo column stays in view while the page scrolls; taller than the screen, it scrolls on its own.
     It reaches into its column's gutter so card shadows and focus rings are not cut off. */
  .admin-sticky-col {
    margin-inline: calc(var(--bs-gutter-x) * -.5);
    max-height: calc(100vh - 2 * var(--ui-sticky-top));
    max-height: calc(100dvh - 2 * var(--ui-sticky-top));
    overflow-y: auto;
    padding-inline: calc(var(--bs-gutter-x) * .5);
    position: sticky;
    scrollbar-width: thin;
    top: var(--ui-sticky-top);
  }

  /* Long tables scroll inside their card under a header that stays put. The room left (10rem) holds the card's
     padding, a save bar or pager below, and the page's own padding, so the whole box fits on screen at once. */
  .table-sticky {
    max-height: calc(100vh - 10rem);
    max-height: calc(100dvh - 10rem);
    overflow-y: auto;
  }

  .table-sticky > .table > thead > tr > th {
    --bs-table-bg: var(--ui-surface-solid);
    box-shadow: inset 0 -1px 0 var(--ui-border); /* a collapsed border would stay behind while scrolling */
    position: sticky;
    top: 0;
    z-index: 2;
  }

  /* Wide tables: the wilaya code and name stay at the start while scrolling sideways. */
  .table-sticky-col > .table > * > tr > :is(:first-child, :nth-child(2)) {
    --bs-table-bg: var(--ui-surface-solid);
    left: 0;
    position: sticky;
    z-index: 1;
  }

  .table-sticky-col > .table > * > tr > :first-child {
    min-width: 4.5rem;
    width: 4.5rem;
  }

  .table-sticky-col > .table > * > tr > :nth-child(2) {
    box-shadow: inset -1px 0 0 var(--ui-border), inset 0 0 0 9999px var(--bs-table-bg-state, transparent);
    left: 4.5rem;
  }

  .table-sticky-col > .table > thead > tr > :is(:first-child, :nth-child(2)) {
    z-index: 3;
  }

  .table-sticky-col > .table > thead > tr > :nth-child(2) {
    box-shadow: inset -1px 0 0 var(--ui-border), inset 0 -1px 0 var(--ui-border);
  }

  /* Sticky headers and columns never cover a field the browser scrolls to (validation, keyboard). */
  .table-sticky :is(a, button, input, select, textarea) {
    scroll-margin-block: 4rem;
  }

  .table-sticky-col :is(a, button, input, select, textarea) {
    scroll-margin-inline-start: 18rem;
  }

  .admin-main :is([id], .neu-card) {
    scroll-margin-top: var(--ui-sticky-top);
  }

  /* Notes and reasons wrap at a set width instead of widening the table. */
  .cell-text {
    max-width: 40ch;
    min-width: 12ch;
    overflow-wrap: anywhere;
  }
}

/* Orders: Call, WhatsApp and the status form each stay on one line once the table has room for them
   (about 1080 px of table, so from 1500 px with the sidebar, gutters and a scrollbar). */
@media (min-width: 1500px) {
  .orders-table .row-actions {
    white-space: nowrap;
  }

  .orders-table .status-form {
    flex-wrap: nowrap;
  }
}

/* ---------- Communes: the order form's list and the admin Communes page (T31) ---------- */

/* Long names are cut inside the closed select (the open list shows them whole), so it never pushes the page sideways. */
.commune-select {
  max-width: 100%;
  text-overflow: ellipsis;
}

/* "Could not load the communes" with its retry link, under the select. */
.commune-status {
  color: var(--ui-danger);
  margin-top: .25rem;
}

/* Wilaya fees under the 58-wilaya system: 59-69 stay editable, greyed out. */
.wilaya-outside-system > td {
  color: var(--ui-text-muted);
}

/* The communes that change wilaya between the two systems, in two columns where there is room. */
.commune-moves {
  columns: 2 14rem;
  padding-inline-start: 1.1rem;
}

.commune-search {
  min-width: min(100%, 18rem);
}

/* ---------- Colour swatches: the product page's colour buttons, the admin picker and order dots (T32) ---------- */

/* A colour button with a swatch: the dot, then the name, which stays for colour-blind customers. */
.swatch-choice {
  gap: .5rem;
}

/* An inline SVG circle; its colour is the circle's fill attribute (the CSP allows no style attributes). */
.swatch {
  border-radius: 50%;
  display: inline-block;
  flex: 0 0 auto;
  vertical-align: middle;
}

/* White, beige and the like get an outline, or they vanish on a light surface. */
.swatch-light circle {
  stroke: var(--ui-swatch-outline);
  stroke-width: 1.5;
}

/* Selected: the pill keeps its accent border and inset or tint; the dot gets a ring too. Never colour alone. */
.btn-check:checked + .neu-choice .swatch {
  box-shadow: var(--ui-swatch-ring);
}

/* Admin: a row without a swatch shows a dashed empty circle. */
.swatch-none circle {
  fill: none;
  stroke: var(--ui-text-muted);
  stroke-dasharray: 3 2.5;
  stroke-width: 1.5;
}

/* Order list and order page: a small dot before the colour name. */
.swatch-sm {
  margin-inline-end: .25rem;
  vertical-align: -1px;
}

/* Admin variants table: the swatch button, then the colour name or its input. */
.table-field-swatch {
  max-width: calc(11rem + var(--ui-tap) + .5rem);
}

.swatch-cell {
  align-items: center;
  display: flex;
  gap: .5rem;
}

.swatch-cell .neu-input {
  flex: 1 1 auto;
  min-width: 0;
}

.swatch-btn,
.swatch-option {
  align-items: center;
  background: transparent;
  border: 0;
  border-radius: 50%;
  display: inline-flex;
  flex: 0 0 auto;
  height: var(--ui-tap);
  justify-content: center;
  padding: 0;
  width: var(--ui-tap);
}

.swatch-btn[aria-expanded="true"] .swatch,
.swatch-option[aria-pressed="true"] .swatch,
.swatch-chip[aria-pressed="true"] .swatch {
  box-shadow: var(--ui-swatch-ring);
}

/* The picker panel, under the row being edited (admin-color-picker.js moves it there). */
.color-picker-row > td {
  padding: .25rem 0 .75rem;
}

.color-picker {
  background: var(--ui-surface-strong);
  border-radius: var(--ui-radius-sm);
  box-shadow: var(--ui-shadow-inset);
  max-width: 36rem;
  padding: 1rem;
  text-align: start;
}

.color-picker-title,
.color-picker-label {
  font-weight: 600;
  margin-bottom: .25rem;
}

.color-picker-label {
  color: var(--ui-text-muted);
  font-size: .875rem;
  margin-top: .75rem;
}

.swatch-options,
.swatch-chips,
.color-picker-custom,
.color-picker-actions {
  display: flex;
  flex-wrap: wrap;
  gap: .25rem .5rem;
}

.swatch-options {
  gap: .25rem;
}

.swatch-chip {
  align-items: center;
  background: var(--ui-surface);
  border: 1px solid var(--ui-border);
  border-radius: 999px;
  color: var(--ui-text);
  display: inline-flex;
  gap: .4rem;
  min-height: var(--ui-tap);
  padding: .25rem .85rem;
}

.swatch-chip[aria-pressed="true"] {
  border-color: var(--ui-accent);
  font-weight: 600;
}

.color-picker-custom {
  align-items: center;
}

.color-picker-input.form-control-color {
  height: var(--ui-tap);
  padding: .25rem;
  width: var(--ui-tap);
}

.color-picker-hex {
  font-family: var(--bs-font-monospace);
  max-width: 9rem;
}

.color-picker-actions {
  margin-top: .75rem;
}

@media (max-width: 767.98px) {
  .table-stack .table-field-swatch {
    max-width: calc(9rem + var(--ui-tap) + .5rem);
  }

  /* The panel row is one block, with no "Color" label of its own; the row above loses its divider. */
  .table-stack .color-picker-row > td {
    display: block;
    padding: 0;
  }

  .table-stack .color-picker-row > td::before {
    content: none;
  }

  .table-stack tr:has(+ .color-picker-row) {
    border-bottom: 0;
  }

  .color-picker {
    max-width: 100%;
    padding: .75rem;
  }
}

/* ---------- Profit, expenses and the order's profit panel (T34, admin) ---------- */

/* Gain and loss: a + or − sign is always written next to the colour. Both keep 4.5:1 in every theme. */
.profit-gain { color: var(--ui-success); }
.profit-loss { color: var(--ui-danger); }

.profit-tiles {
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
}

/* A tile sits inside the result card: a near-solid inset panel, never a second blur. */
.profit-tile {
  background: var(--ui-surface-strong);
  border-radius: var(--ui-radius-sm);
  box-shadow: var(--ui-shadow-inset);
  padding: .75rem 1rem;
}

.profit-tile-label {
  color: var(--ui-text-muted);
  font-size: .85rem;
  font-weight: 600;
}

.profit-tile-value {
  font-size: 1.5rem;
  font-weight: 700;
  white-space: nowrap;
}

.profit-warnings a {
  margin-inline-end: .5rem;
}

.profit-table .order-link,
.profit-breakdown th {
  white-space: nowrap;
}

/* Fourteen money columns fit beside the sidebar at 1366 px: a smaller size, tighter cells, headers wrap between words. */
@media (min-width: 768px) {
  .profit-table {
    font-size: .8125rem;
  }

  .profit-table > :is(thead, tbody, tfoot) > tr > * {
    padding-inline: .35rem;
  }

  .profit-table > thead > tr > th {
    overflow-wrap: normal;
    vertical-align: bottom;
    word-break: normal;
  }
}

.profit-sums > * {
  border-top: 2px solid var(--ui-border);
  font-weight: 700;
}

/* Phones: the sums row is one more stacked block under the orders. */
@media (max-width: 767.98px) {
  .profit-table tfoot,
  .profit-table tfoot th {
    display: block;
    width: 100%;
  }

  .profit-table tfoot th::before {
    content: none;
  }
}

/* T30's sticky table header starts at 1400 px; this wide table keeps its column names in view from 1200 px. */
@media (min-width: 1200px) and (max-width: 1399.98px) {
  .profit-scroll {
    max-height: calc(100vh - 10rem);
    max-height: calc(100dvh - 10rem);
    overflow-y: auto;
  }

  .profit-scroll > .table > thead > tr > th {
    --bs-table-bg: var(--ui-surface-solid);
    box-shadow: inset 0 -1px 0 var(--ui-border);
    position: sticky;
    top: 0;
    z-index: 2;
  }
}

/* ---------- Store: trust lines, WhatsApp contact and the public footer (T35) ---------- */

/* Short promises under the price: a check, then the line; two columns where there is room. */
.trust-list {
  display: grid;
  gap: .35rem 1rem;
  list-style: none;
  margin: 0 0 1rem;
  padding: 0;
}

@media (min-width: 576px) {
  .trust-list {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.trust-list li {
  align-items: flex-start;
  color: var(--ui-text);
  display: flex;
  gap: .5rem;
}

.trust-check {
  color: var(--ui-success);
  flex: none;
  margin-top: .2rem;
}

/* WhatsApp links: solid green with white text, the icon before the words. */
.btn.whatsapp-link,
.whatsapp-float {
  background: var(--ui-whatsapp);
  color: var(--ui-whatsapp-contrast);
}

.btn.whatsapp-link {
  align-items: center;
  border: 0;
  border-radius: var(--ui-radius-sm);
  box-shadow: var(--ui-shadow-raised-sm);
  display: inline-flex;
  font-weight: 600;
  gap: .5rem;
  justify-content: center;
  margin-top: .75rem;
  min-height: var(--ui-tap);
  padding: .5rem 1.25rem;
}

.btn.whatsapp-link:hover,
.btn.whatsapp-link:focus-visible,
.btn.whatsapp-link:active {
  background: var(--ui-whatsapp);
  color: var(--ui-whatsapp-contrast);
}

.whatsapp-icon {
  flex: none;
}

/* The round button: bottom-left, the corner away from the confirm button, inside the phone's safe area.
   whatsapp-float.js hides it while the order form is on screen. */
.whatsapp-float {
  align-items: center;
  border: 2px solid transparent; /* a real edge in forced-colors mode */
  border-radius: 50%;
  bottom: calc(1rem + env(safe-area-inset-bottom, 0px));
  box-shadow: var(--ui-shadow-raised);
  display: flex;
  height: 56px;
  justify-content: center;
  left: calc(1rem + env(safe-area-inset-left, 0px));
  position: fixed;
  width: 56px;
  z-index: 1030;
}

.whatsapp-float[hidden] {
  display: none;
}

.whatsapp-float:hover,
.whatsapp-float:focus-visible {
  color: var(--ui-whatsapp-contrast);
}

.whatsapp-float .whatsapp-icon {
  height: 30px;
  width: 30px;
}

/* The seller's legal lines keep the admin's line breaks; the text itself is HTML-encoded. */
.legal-footer {
  font-size: .85rem;
  white-space: pre-line;
}

/* ---------- Call attempts and the "To call" queue (T37) ---------- */

.call-line {
  margin-top: .25rem;
}

/* Where a cell is a label-and-value row (phones, and the orders cards up to 1340 px), the badge takes a line of its own
   instead of squeezing the name and phone. */
.table-stack td:has(> .call-line),
.orders-table td:has(> .call-line) {
  flex-wrap: wrap;
}

.table-stack td > .call-line,
.orders-table td > .call-line {
  flex-basis: 100%;
}

.call-badge {
  border-radius: 999px;
  box-shadow: var(--ui-shadow-inset);
  color: var(--ui-text-muted);
  display: inline-block;
  font-size: .8rem;
  font-weight: 600;
  padding: .1rem .6rem;
  white-space: nowrap;
}

/* A callback whose time has come: a coloured ring and bold text, and the badge itself says "due". */
.call-badge.call-due {
  box-shadow: inset 0 0 0 2px var(--ui-warning);
  color: var(--ui-warning);
  font-weight: 700;
}

.call-hint {
  color: var(--ui-warning);
  font-size: .85rem;
  font-weight: 600;
  white-space: normal;
}

/* No answer, Phone off and More… on their own line under Call and WhatsApp; they wrap, never squeeze. */
.call-actions-row {
  align-items: flex-start;
  display: flex;
  flex-basis: 100%;
  flex-wrap: wrap;
  gap: .5rem;
  margin-top: .25rem;
}

.call-actions-row .call-form {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  margin: 0;
}

.call-actions-row .btn {
  min-height: var(--ui-tap);
}

.call-more > summary {
  list-style: none;
}

.call-more > summary::-webkit-details-marker {
  display: none;
}

.call-more[open] {
  flex-basis: 100%;
}

.call-more-form {
  border-radius: var(--ui-radius-sm);
  box-shadow: var(--ui-shadow-inset);
  display: grid;
  gap: .5rem;
  margin: .5rem 0 0;
  max-width: 22rem;
  padding: .75rem;
  text-align: start;
  white-space: normal;
}

.call-more-form fieldset {
  margin: 0;
}

.call-more-form .form-check {
  align-items: center;
  display: flex;
  gap: .5rem;
  margin: 0;
  min-height: var(--ui-tap);
  padding-inline-start: 0;
}

.call-more-form .form-check-input {
  margin: 0;
}

.call-choices {
  display: flex;
  flex-wrap: wrap;
  gap: 0 1rem;
}

.call-history {
  margin: .75rem 0;
  padding-inline-start: 1.25rem;
}

.call-history li {
  padding: .25rem 0;
}

/* From 768 px the open panel keeps a readable width; in the orders table its cell widens while it is open. */
@media (min-width: 768px) {
  .call-more[open] {
    min-width: 17rem;
  }
}

/* Phones: the call buttons share the row's width, two per line, and the open panel spans it. */
@media (max-width: 767.98px) {
  .call-actions-row .call-form,
  .call-more {
    flex: 1 1 100%;
  }

  .call-actions-row .call-form .btn {
    flex: 1 1 8rem;
    min-height: 3rem;
  }

  .call-more > summary {
    min-height: 3rem;
    width: 100%;
  }

  .call-more-form {
    max-width: none;
  }
}

/* ---------- Stock: low-stock badges (T38) ---------- */

.stock-badge {
  border-radius: 999px;
  box-shadow: var(--ui-shadow-inset);
  color: var(--ui-warning);
  display: inline-block;
  font-size: .85rem;
  font-weight: 600;
  padding: .15rem .65rem;
  white-space: nowrap;
}

.item-stock {
  white-space: nowrap;
}

/* ---------- Accessibility (docs/SPEC.md "Accessibility") ---------- */

/* The first stop of the keyboard on every page: off screen until focused, then a solid accent pill over the header. */
.skip-link {
  background: var(--ui-accent);
  border-radius: var(--ui-radius-sm);
  color: var(--ui-on-accent);
  font-weight: 600;
  inset-inline-start: .75rem;
  line-height: var(--ui-tap);
  min-height: var(--ui-tap);
  padding: 0 1rem;
  position: absolute;
  text-decoration: none;
  top: .75rem;
  transform: translateY(-200%);
  z-index: 1090; /* above the sticky header and the admin offcanvas */
}

.skip-link:focus {
  transform: none;
}

.skip-link:focus,
.skip-link:hover {
  color: var(--ui-on-accent);
}

/* Bootstrap 5.3 colours links from --bs-link-color-rgb, so the --bs-link-color above never reached them: its default blue
   is 4.0:1 on the page. Plain links take the theme's accent; any class with its own colour (.btn, .nav-link,
   .site-brand) still wins, since this is an element selector. */
a {
  color: var(--ui-accent-dark);
}

a:hover {
  color: var(--ui-accent);
}

/* Bootstrap's own red is 4.4:1 on light surfaces; the theme's danger colour is above 4.5:1. */
.text-danger {
  color: var(--ui-danger) !important; /* Bootstrap's utility is !important too */
}

/* The skip link's target takes focus only so the next Tab starts there; it is not a control. */
main[tabindex="-1"]:focus {
  outline: none;
}

/* Forced colours (Windows contrast themes) drop box-shadow, which is the focus ring everywhere else: draw a real outline. */
@media (forced-colors: active) {
  a:focus-visible,
  button:focus-visible,
  .btn:focus-visible,
  .form-control:focus,
  .form-select:focus,
  .form-check-input:focus,
  .btn-check:focus-visible + .neu-choice,
  .gallery-track:focus-visible,
  .error-summary:focus {
    outline: 2px solid Highlight;
    outline-offset: 2px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .gallery-track {
    scroll-behavior: auto;
  }
}

/* ---------- Stock management: backorders and the stock pages (T39) ---------- */

/* An order waiting for stock: tinted row with a left bar, and a "No stock" badge, so colour is never the only signal. */
.orders-table > tbody > tr.order-backorder > * {
  --bs-table-bg: var(--ui-backorder-bg);
}

.order-backorder > td:first-child {
  box-shadow: inset 4px 0 0 var(--ui-backorder-border);
}

.order-suspicious.order-backorder > td:first-child {
  box-shadow: inset 4px 0 0 var(--ui-danger), inset 8px 0 0 var(--ui-backorder-border);
}

.stock-flag,
.stock-status {
  align-items: center;
  border-radius: 999px;
  display: inline-flex;
  font-size: .8rem;
  font-weight: 600;
  gap: .25rem;
  padding: .1rem .55rem;
  white-space: nowrap;
}

.stock-flag {
  margin-top: .25rem;
}

.stock-flag-missing,
.stock-status-backorder {
  background: var(--ui-backorder-bg);
  border: 1px solid var(--ui-backorder-border);
  color: var(--ui-backorder-text);
}

.stock-flag-was,
.stock-status-ok {
  box-shadow: var(--ui-shadow-inset);
  color: var(--ui-text-muted);
}

.stock-status-out {
  box-shadow: var(--ui-shadow-inset);
  color: var(--ui-danger);
}

.stock-status-low {
  box-shadow: var(--ui-shadow-inset);
  color: var(--ui-warning);
}

.stock-icon {
  flex: none;
}

.backorder-banner {
  background: var(--ui-backorder-bg);
  border: 2px solid var(--ui-backorder-border);
  border-radius: var(--ui-radius);
  color: var(--ui-backorder-text);
  padding: 1rem;
}

.backorder-banner .stock-icon {
  margin-inline-end: .35rem;
  vertical-align: -.15em;
}

.backorder-banner a {
  color: inherit;
  font-weight: 600;
}

.nav-count {
  background: var(--ui-backorder-bg);
  border: 1px solid var(--ui-backorder-border);
  border-radius: 999px;
  color: var(--ui-backorder-text);
  display: inline-block;
  font-size: .8rem;
  font-weight: 700;
  line-height: 1.4;
  margin-inline-start: .45rem;
  padding: 0 .45rem;
}

/* Header words wrap between words only ("Held by unconfirmed"), never inside one. */
.stock-table > thead > tr > th {
  overflow-wrap: normal;
  vertical-align: bottom;
}

.stock-row-backorder > td:first-child {
  box-shadow: inset 4px 0 0 var(--ui-backorder-border);
}

/* Receive, Count and Write off: three panels side by side; the open one takes the row's width. */
.stock-actions {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
}

.stock-action > summary {
  list-style: none;
}

.stock-action > summary::-webkit-details-marker {
  display: none;
}

.stock-action[open] {
  flex-basis: 100%;
}

.stock-action-form {
  background: var(--ui-surface-strong);
  border-radius: var(--ui-radius-sm);
  margin-top: .5rem;
  max-width: 24rem;
  padding: .75rem;
}

.variant-stock {
  align-items: center;
  display: flex;
  gap: .5rem;
}

.to-buy-message {
  white-space: pre-wrap;
}

.print-only {
  display: none;
}

@media print {
  .admin-topbar,
  .admin-sidebar,
  .skip-link,
  .no-print,
  .alert {
    display: none !important;
  }

  .print-only {
    display: block;
  }

  body.admin,
  .admin-main,
  .neu-card {
    background: var(--ui-surface-solid) !important;
    box-shadow: none !important;
  }

  .neu-card {
    border: 1px solid var(--ui-border);
    break-inside: avoid;
  }
}

@media (forced-colors: active) {
  .order-backorder > td:first-child,
  .stock-row-backorder > td:first-child {
    border-inline-start: 4px solid CanvasText;
  }
}

/* ---------- Country access: the admin page (T40) ---------- */

/* About 250 countries: a box that scrolls, in columns where there is room; the chosen ones come first. */
.country-list {
  border: 1px solid var(--ui-border);
  border-radius: var(--ui-radius-sm);
  columns: 2 14rem;
  column-gap: 1.5rem;
  max-height: 22rem;
  overflow-y: auto;
  padding: .5rem .75rem;
}

.country-list .form-check {
  break-inside: avoid;
}

/* A mode's hint sits under its radio, lined up with the label (the admin's form-check is a flex row). */
.country-mode-hint {
  padding-inline-start: 2rem;
}

.country-status {
  display: grid;
  gap: .25rem 1rem;
  grid-template-columns: max-content 1fr;
}

.country-status dd {
  margin: 0;
}

.country-test-input {
  flex: 1 1 12rem;
  max-width: 22rem;
}
