/* The console's palette (see apps/agency/ecommerce-control's layout). */
:root {
  --bg: #faf7f2;
  --surface: #fbf8f3;
  --text: #241e18;
  --muted: #7a6f62;
  --border: #e7ddd0;
  --accent: #241e18;
  --accent-dark: #3a332b;
  --danger: #b4432f;
  --radius: 8px;
}
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body { background: var(--bg); color: var(--text); font-family: var(--font-body, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif); accent-color: var(--accent); }
/* Form controls don't inherit the page font-family by default in any
   browser (they use the browser's own UI font instead) - several buttons
   below already had their own one-off "font-family: inherit", this makes
   it universal so nothing is missed. */
button, input, select, textarea { font-family: inherit; }
a { color: inherit; text-decoration: none; }
h1, h2, h3 { margin: 0 0 .5em; }

/* Billing tab: a soft pulsing dot when a payment is due (amber) or overdue (red). */
.tabbar a.tab-due, .tabbar a.tab-overdue { position: relative; }
.tabbar a.tab-due::after, .tabbar a.tab-overdue::after { content: ""; position: absolute; top: 2px; right: -9px; width: 7px; height: 7px; border-radius: 50%; animation: billing-tab-pulse 2.4s ease-in-out infinite; }
.tabbar a.tab-due::after { background: #d9a03b; }
.tabbar a.tab-overdue { color: var(--danger); }
.tabbar a.tab-overdue::after { background: var(--danger); }
@keyframes billing-tab-pulse { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: .35; transform: scale(.8); } }
@media (prefers-reduced-motion: reduce) { .tabbar a::after { animation: none; } }

.topbar { display: flex; align-items: center; gap: 20px; padding: 12px 20px; background: var(--surface); border-bottom: 1px solid var(--border); position: sticky; top: 0; z-index: 10; }
.topbar-brand { font-weight: 700; }
.tabbar { display: flex; gap: 16px; margin-left: 10px; }
.tabbar a { color: var(--muted); font-weight: 600; padding: 4px 0; border-bottom: 2px solid transparent; font-size: 14px; }
.tabbar a.active { color: var(--text); border-bottom-color: var(--accent); }
.icon-btn { margin-left: auto; background: none; border: 1px solid var(--border); border-radius: var(--radius); padding: 8px 14px; cursor: pointer; }

#content { max-width: 1200px; margin: 0 auto; padding: 24px 20px 60px; }
.page-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 20px; gap: 12px; flex-wrap: wrap; }

.card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 18px; margin-bottom: 16px; }

/* ─── Collapsible settings-style card (Settings tab) ────────────────────── */
/* Same raised-3D language as .card-3d (bevelled edge + soft drop shadow) so
   a collapsed block reads as a physical, pressable bar rather than a flat
   row of text - hover lifts it further, a click presses it back in before
   the section opens. */
.collapsible-card .card-head {
  display: flex; align-items: center; justify-content: space-between; gap: 12px; cursor: pointer;
  padding: 12px 16px; margin: -4px -4px 0; border-radius: 12px;
  background: linear-gradient(165deg, color-mix(in srgb, var(--surface) 100%, #fff 14%), var(--surface) 65%);
  border: 1px solid var(--border);
  border-top-color: rgba(255, 255, 255, .9);
  box-shadow:
    inset 0 1.5px 0 rgba(255, 255, 255, .9),
    inset -1px -1px 2px rgba(0, 0, 0, .04),
    0 3px 8px rgba(0, 0, 0, .08),
    0 1px 2px rgba(0, 0, 0, .06);
  transition: transform 120ms ease, box-shadow 120ms ease, background 150ms ease;
}
.collapsible-card .card-head:hover {
  background: linear-gradient(165deg, color-mix(in srgb, var(--surface) 100%, var(--accent) 6%), var(--surface) 65%);
  transform: translateY(-2px);
  box-shadow:
    inset 0 1.5px 0 rgba(255, 255, 255, .9),
    inset -1px -1px 2px rgba(0, 0, 0, .04),
    0 8px 18px rgba(0, 0, 0, .12),
    0 2px 6px rgba(0, 0, 0, .08);
}
.collapsible-card .card-head:active {
  transform: translateY(0) scale(.99);
  box-shadow:
    inset 0 2px 4px rgba(0, 0, 0, .12),
    inset 0 -1px 0 rgba(255, 255, 255, .5),
    0 1px 2px rgba(0, 0, 0, .06);
  transition: transform 60ms ease, box-shadow 60ms ease;
}
.collapsible-card .card-head h3 { margin: 0; }
.card-toggle-btn {
  flex-shrink: 0; width: 30px; height: 30px; border-radius: 50%; border: 1px solid var(--border);
  background: var(--surface); color: var(--muted); cursor: pointer; display: flex; align-items: center; justify-content: center;
  transition: background 150ms ease, color 150ms ease, border-color 150ms ease;
}
.card-toggle-btn:hover { background: var(--bg); color: var(--accent); border-color: color-mix(in srgb, var(--border) 45%, var(--accent) 55%); }
.card-toggle-btn svg { transition: transform 150ms ease; }
.collapsible-card.is-open .card-toggle-btn svg { transform: rotate(180deg); }
.collapsible-card .card-body { margin-top: 14px; }

/* ─── Appearance tab: settings + sticky preview side by side, so nothing
   ever scrolls "behind" the preview - it only ever covers its own empty
   column, never the settings the admin is actively working in. ────────── */
.appearance-layout { display: flex; gap: 20px; align-items: flex-start; }
.appearance-main { flex: 1; min-width: 0; }
.appearance-preview-col { width: 380px; flex-shrink: 0; position: sticky; top: 70px; }
@media (max-width: 900px) {
  .appearance-layout { flex-direction: column; }
  .appearance-preview-col { width: 100%; position: static; }
}
.stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 14px; margin-bottom: 20px; }

/* ─── First-run Setup checklist (/admin/setup) ───────────────────────────── */
.setup-progress-bar { height: 8px; border-radius: 999px; background: var(--border); overflow: hidden; margin-bottom: 22px; }
.setup-progress-fill { height: 100%; background: var(--accent); border-radius: 999px; transition: width 300ms ease; }
.setup-steps { display: flex; flex-direction: column; gap: 12px; margin-bottom: 20px; }
.setup-step { display: flex; align-items: center; gap: 16px; padding: 16px 18px; cursor: pointer; }
.setup-step.is-done { opacity: .8; }
.setup-step-badge {
  flex-shrink: 0; width: 30px; height: 30px; border-radius: 50%; border: 1.5px solid var(--border);
  display: flex; align-items: center; justify-content: center; font-weight: 700; color: #fff;
}
.setup-step.is-done .setup-step-badge { background: var(--accent); border-color: var(--accent); }
.setup-step-body { flex: 1; min-width: 0; }
.setup-step-title { font-weight: 700; margin-bottom: 3px; }
.setup-step-body p { margin: 0; font-size: 13px; }
.setup-step-cta { flex-shrink: 0; }
.setup-payment-note, .setup-ready { padding: 16px 18px; margin-bottom: 12px; }
.setup-ready { border: 1.5px solid var(--accent); }
@media (max-width: 560px) {
  .setup-step { flex-wrap: wrap; }
  .setup-step-cta { margin-left: 46px; }
}
.stat-tile { padding: 16px; }
.stat-tile .value { font-size: 24px; font-weight: 700; }
.stat-tile .label { color: var(--muted); font-size: 13px; margin-top: 4px; }

/* Raised "3D" card - a light inset bevel along the top edge plus a soft
   drop shadow, so cards read as physically raised rather than flat rectangles. */
.card-3d {
  background: linear-gradient(165deg, color-mix(in srgb, var(--surface) 100%, #fff 12%), var(--surface) 60%);
  border: 1px solid var(--border);
  border-top-color: rgba(255, 255, 255, .9);
  border-left-color: color-mix(in srgb, var(--border) 60%, white);
  border-radius: 14px;
  padding: 18px 20px;
  box-shadow:
    inset 0 1.5px 0 rgba(255, 255, 255, .9),
    inset -1px -1px 2px rgba(0, 0, 0, .04),
    0 14px 28px rgba(0, 0, 0, .1),
    0 4px 10px rgba(0, 0, 0, .07);
  transition: transform 150ms ease, box-shadow 150ms ease;
}
.card-3d:hover {
  transform: translateY(-4px);
  box-shadow:
    inset 0 1.5px 0 rgba(255, 255, 255, .9),
    inset -1px -1px 2px rgba(0, 0, 0, .04),
    0 22px 40px rgba(0, 0, 0, .14),
    0 6px 14px rgba(0, 0, 0, .09);
}
.card-3d table { box-shadow: none; border: 1px solid var(--border); }

.dashboard-section-title { margin: 30px 0 6px; }
/* Breaks "Where Orders Come From" out of #content's 1200px reading-width
   cap - this section is a data grid, not prose, and was cramped enough to
   force truncated headings. Viewport-relative math (not the parent's own
   width) so it escapes the cap regardless of ancestor constraints. */
.qual-section-breakout { width: 100vw; margin-left: calc(50% - 50vw); padding: 0 32px; box-sizing: border-box; }
.qual-filters { display: flex; flex-wrap: wrap; align-items: end; gap: 14px; margin: 16px 0; }
.qual-filters .field { max-width: 220px; min-width: 160px; flex: 1; }
/* Anchored to the far right of its filter row via margin-left:auto - keeps
   it from wrapping onto its own line looking like a stray orphan when the
   row runs out of horizontal space; it still lands on the right edge of
   whichever line it ends up sharing. */
#clear-filters-btn { height: 44px; margin-left: auto; flex: 0 0 auto; }

/* ─── Searchable multi-select filter (public/admin/js/multi-select.js) ── */
.ms-filter { position: relative; min-width: 170px; flex: 1; max-width: 220px; }
.ms-filter label { display: block; font-size: 13px; font-weight: 600; color: var(--muted); margin-bottom: 4px; }
.ms-trigger {
  width: 100%; text-align: left; padding: 10px 14px; border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface); font: inherit; cursor: pointer; color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  box-shadow: 0 2px 5px rgba(0, 0, 0, .16), inset 0 2px 4px rgba(0, 0, 0, .15), inset 0 -1px 0 rgba(255, 255, 255, .85);
  transition: border-color 150ms ease, box-shadow 150ms ease;
}
.ms-trigger:hover { border-color: color-mix(in srgb, var(--border) 45%, var(--accent) 55%); }
.ms-trigger:focus-visible {
  outline: none; border-color: var(--accent);
  box-shadow: 0 2px 5px rgba(0, 0, 0, .16), inset 0 2px 4px rgba(0, 0, 0, .15), inset 0 -1px 0 rgba(255, 255, 255, .85), 0 0 0 4px color-mix(in srgb, var(--accent) 35%, transparent);
}
.ms-trigger.ms-active { border-color: var(--accent); color: var(--accent); font-weight: 600; }
.ms-panel {
  position: absolute; top: calc(100% + 4px); left: 0; z-index: 30; width: max(100%, 240px);
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: 0 14px 32px rgba(0, 0, 0, .16); padding: 8px; max-height: 320px; display: flex; flex-direction: column;
}
/* `.ms-panel{display:flex}` and the browser's own `[hidden]{display:none}`
   are equal specificity (one class, one attribute selector) - author CSS
   wins the tie over the UA stylesheet, so every panel rendered open on
   load regardless of the `hidden` attribute JS was toggling. Pairing the
   attribute with the class here outranks the plain `.ms-panel` rule. */
.ms-panel[hidden] { display: none; }
.ms-search { margin-bottom: 6px; }
.ms-select-all {
  align-self: flex-start; margin: 0 0 6px; padding: 2px 0; border: 0; background: none; font: inherit;
  font-size: 12px; font-weight: 600; color: var(--accent); cursor: pointer;
}
.ms-select-all:hover { text-decoration: underline; }
.ms-options { overflow-y: auto; flex: 1; }
.ms-option {
  display: flex; align-items: center; gap: 8px; padding: 7px 6px; border-radius: 6px; cursor: pointer; font-size: 14px;
}
.ms-option:hover { background: var(--bg); }
.ms-option input { margin: 0; }
.ms-empty { padding: 10px 6px; color: var(--muted); font-size: 13px; }
.quant-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); gap: 18px; margin: 16px 0 8px; }
/* Exactly 5 breakdown cards (Pincode/State/District/Category/Customer) - 
   fixed column counts per breakpoint, not auto-fit. auto-fit computes its
   track count from the container width alone, with no idea how many grid
   items actually exist; on a wide-enough monitor it reserved a 5th (or
   6th) track that had no item to fill it, which auto-fit is supposed to
   collapse and redistribute but visibly didn't - the cards sat left-
   aligned with a dead gap on the right instead of spanning full width.
   repeat(N, 1fr) has no such ambiguity: every defined track always gets an
   item and always shares the row evenly. */
.qual-grid { display: grid; grid-template-columns: 1fr; gap: 18px; margin: 16px 0 8px; }
@media (min-width: 640px) { .qual-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1000px) { .qual-grid { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 1500px) { .qual-grid { grid-template-columns: repeat(5, 1fr); } }
/* Grid items default to min-width:auto - without this, a card whose table
   has an unbreakable long value (an email address in the Customer column)
   refuses to shrink below that width, forcing the whole grid wider than
   the viewport instead of the card just wrapping/scrolling its own content. */
.quant-grid > *, .qual-grid > * { min-width: 0; }

.tic-label { font-weight: 700; margin-bottom: 10px; }
.tic-revenue-row { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.tic-revenue { font-size: 26px; font-weight: 700; }
.tic-sub { font-size: 13px; margin: 4px 0 12px; }
.tic-orders-row { display: flex; align-items: center; gap: 8px; font-size: 14px; padding-top: 12px; border-top: 1px solid var(--border); }

.change-badge { display: inline-flex; align-items: center; gap: 3px; font-size: 13px; font-weight: 700; padding: 3px 9px; border-radius: 999px; white-space: nowrap; }
.change-up { background: #e5f4ea; color: #1f7a3d; }
.change-down { background: #fbe7e4; color: #a3352a; }
.change-flat { background: var(--bg); color: var(--muted); }
.change-new { background: #e6f0fb; color: #1c5f9e; }

.breakdown-card h3 { margin-bottom: 12px; }
.breakdown-note { margin: -8px 0 12px; font-size: 12px; }
/* Fixed column ratios (not content-driven) so one very long place name
   can't force the table wider than the card - but the ratios themselves
   (plus the wider card min-width above) are generous enough that normal
   content, headings included, never actually needs to truncate. Ellipsis
   stays on td only, as a safety net for a genuinely long outlier, never on
   th - a heading is always a short fixed word and truncating it to "Or…"
   serves nobody. */
.breakdown-card table { table-layout: fixed; width: 100%; }
.breakdown-card .table-scroll { overflow-x: hidden; }
.breakdown-card th, .breakdown-card td { padding: 8px 10px; font-size: 13px; }
.breakdown-card td { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.breakdown-card th:first-child, .breakdown-card td:first-child { width: 50%; }
.breakdown-card th:nth-child(2), .breakdown-card td:nth-child(2) { width: 22%; text-align: right; }
.breakdown-card th:last-child, .breakdown-card td:last-child { width: 28%; text-align: right; }
/* Total box below the scrollable table (see mountBreakdownCard) - not a
   table row, so it's never subject to the fixed 22%/28% column widths
   above that clip a table cell's content. */
.breakdown-total {
  margin-top: 10px; padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--radius);
  background: color-mix(in srgb, var(--accent) 6%, var(--surface));
}
.breakdown-total-heading { font-weight: 700; font-size: 13px; margin-bottom: 6px; }
.breakdown-total-heading .muted { font-weight: 500; }
.breakdown-total-row { display: flex; justify-content: space-between; align-items: baseline; font-size: 13px; padding: 2px 0; }
.breakdown-total-row span { color: var(--muted); }
.breakdown-total-row strong { font-size: 15px; }
.breakdown-sort-btn {
  background: none; border: none; cursor: pointer; font: inherit; font-weight: 600; color: inherit;
  padding: 0; display: inline-flex; align-items: center; gap: 3px;
}
.breakdown-sort-btn:hover { color: var(--text); }
.breakdown-sort-arrow { font-size: 10px; opacity: .5; }
.breakdown-sort-arrow.active { opacity: 1; color: var(--accent); }
/* Compact - was one full-width row per status; a table with headers reads
   just as clearly at a fraction of the height. */
.status-card { max-width: 420px; padding: 8px; }
.status-card table { width: 100%; }
.status-card th, .status-card td { padding: 7px 12px; font-size: 13px; }
.status-card td:last-child, .status-card th:last-child { text-align: right; }
.qual-totals {
  display: flex; flex-wrap: wrap; justify-content: center; align-items: stretch; gap: 0;
  padding: 26px 20px; margin-bottom: 18px; text-align: center;
  background: linear-gradient(165deg, color-mix(in srgb, var(--accent) 10%, var(--surface)), var(--surface) 65%);
}
.qual-totals-item { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; padding: 0 44px; }
.qual-totals-item + .qual-totals-item { border-left: 1px solid var(--border); }
.qual-totals-value { font-size: 34px; font-weight: 800; line-height: 1; color: var(--accent-dark); }
.qual-totals-label { font-size: 13px; font-weight: 600; color: var(--muted); text-transform: uppercase; letter-spacing: .06em; }
.card-3d .table-scroll table { border: none; }
.card-3d .table-scroll { box-shadow: none; }

table { width: 100%; border-collapse: collapse; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }
th, td { text-align: left; padding: 12px 14px; border-bottom: 1px solid var(--border); font-size: 15px; }
th { background: var(--bg); font-weight: 600; color: var(--muted); }
tr:last-child td { border-bottom: none; }
tbody tr:nth-child(even) { background: #faf8f5; }
tr.clickable { cursor: pointer; }
tr.clickable:hover { background: var(--bg); }
tfoot td { background: var(--bg); border-top: 2px solid var(--border); }
.table-scroll tfoot td { position: sticky; bottom: 0; }

/* "Chat on WhatsApp" button (Customers/Orders/Admins tabs) - the icon
   graphic itself (see js/utils.js's WHATSAPP_ICON_URL) already is a
   complete bevelled 3D disc, so this wrapper is just a positioned,
   clickable frame around it with its own lift-on-hover feedback. */
.wa-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; flex-shrink: 0;
  transition: transform 120ms ease, filter 120ms ease;
}
.wa-btn img { width: 100%; height: 100%; object-fit: contain; }
.wa-btn:hover { transform: translateY(-1px) scale(1.05); }
.wa-btn:active { transform: translateY(0) scale(.94); }

/* "Call" button (Customers/Orders) - sits next to .wa-btn but, unlike that
   one, has no pre-made icon artwork to lean on, so the bevelled-disc look
   is built here directly: an outer drop shadow to lift it off the row,
   plus inset highlight/shadow pairs on the disc itself for the pressed-
   metal depth used everywhere else in this admin (see .field's box-shadow
   recipe). */
.call-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; flex-shrink: 0; border-radius: 50%;
  background: linear-gradient(180deg, color-mix(in srgb, var(--accent) 92%, #fff), var(--accent));
  color: #fff;
  box-shadow:
    0 3px 6px rgba(0, 0, 0, .28),
    0 1px 2px rgba(0, 0, 0, .18),
    inset 0 1px 1px rgba(255, 255, 255, .55),
    inset 0 -2px 3px rgba(0, 0, 0, .3);
  transition: transform 120ms ease, box-shadow 120ms ease;
}
.call-btn:hover { transform: translateY(-1px) scale(1.05); }
.call-btn:active {
  transform: translateY(0) scale(.94);
  box-shadow: 0 1px 2px rgba(0, 0, 0, .22), inset 0 2px 3px rgba(0, 0, 0, .35);
}

/* ─── Column customizer (Customers/Orders/Categories/Admins grids) ──────── */
.col-cust-wrap { position: relative; display: inline-block; }
.col-cust-panel {
  position: absolute; top: calc(100% + 6px); right: 0; z-index: 30; width: 300px;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: 0 14px 32px rgba(0, 0, 0, .16); padding: 12px;
}
.col-cust-head { margin-bottom: 8px; }
.col-cust-list { max-height: 300px; overflow-y: auto; display: flex; flex-direction: column; gap: 2px; }
.col-cust-row {
  display: flex; align-items: center; gap: 8px; padding: 6px 4px; border-radius: 6px; cursor: grab;
}
.col-cust-row:hover { background: var(--bg); }
.col-cust-row.dragging { opacity: .4; }
.col-cust-drag { color: var(--muted); flex-shrink: 0; cursor: grab; }
.col-cust-row .checkbox-row { cursor: pointer; }
.col-cust-foot { display: flex; justify-content: space-between; margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--border); }

.table-scroll { max-height: 480px; overflow-y: auto; overflow-x: auto; border: 1px solid var(--border); border-radius: var(--radius); }
.table-scroll table { border: none; border-radius: 0; overflow: visible; }
.table-scroll thead th { position: sticky; top: 0; z-index: 1; }

.btn { display: inline-flex; align-items: center; justify-content: center; padding: 9px 16px; border-radius: var(--radius); border: 1px solid transparent; font-size: 14px; font-weight: 600; cursor: pointer; }
.btn-primary { background: var(--accent); color: #fff; }
.btn-primary:hover { background: var(--accent-dark); }
.btn-secondary { background: var(--surface); border-color: var(--border); color: var(--text); }
.btn-danger { background: none; color: var(--danger); border-color: var(--danger); }
.btn:disabled { opacity: .5; cursor: not-allowed; }
.btn-block { width: 100%; }

/* Zero-specificity base layer (:where) so every plain input/select/textarea
   gets the same pronounced 3D + focus treatment even outside a .field
   wrapper (a toolbar search box, an unwrapped filter <select>) - .field's
   own rules below naturally win wherever they also apply, no specificity
   fights. Deliberately strong, not subtle: a real drop shadow outside the
   field plus a carved-in groove look inside it (inset shadow along the top,
   inset highlight along the bottom), the same recipe every other 3D field
   below (.field input/select/textarea, .ms-trigger, .df-trigger) repeats. */
:where(input, textarea, select):not([type="checkbox"], [type="radio"], [type="file"], [type="color"], [type="submit"], [type="button"], [type="range"], [type="hidden"]) {
  border: 1px solid var(--border); border-radius: var(--radius); font: inherit;
  background: var(--surface); color: var(--text); padding: 9px 12px;
  box-shadow: 0 2px 5px rgba(0, 0, 0, .16), inset 0 2px 4px rgba(0, 0, 0, .15), inset 0 -1px 0 rgba(255, 255, 255, .85);
  transition: border-color 150ms ease, box-shadow 150ms ease;
}
:where(input, textarea, select):not([type="checkbox"], [type="radio"], [type="file"], [type="color"], [type="submit"], [type="button"], [type="range"], [type="hidden"]):hover {
  border-color: color-mix(in srgb, var(--border) 45%, var(--accent) 55%);
}
/* "Highlight the field when clicked" - a bold, clearly-visible ring (35%
   accent, not the barely-there 16% this used to be) stacked on top of the
   same resting shadow, so focus reads as "this exact field is active", not
   just a thin border-color change. */
:where(input, textarea, select):not([type="checkbox"], [type="radio"], [type="file"], [type="color"], [type="submit"], [type="button"], [type="range"], [type="hidden"]):focus {
  outline: none; border-color: var(--accent);
  box-shadow: 0 2px 5px rgba(0, 0, 0, .16), inset 0 2px 4px rgba(0, 0, 0, .15), inset 0 -1px 0 rgba(255, 255, 255, .85), 0 0 0 4px color-mix(in srgb, var(--accent) 35%, transparent);
}
.btn-sm { padding: 5px 10px; font-size: 12px; }
/* Icon-only variant (the red trash-can "Remove"/"Delete" buttons) - equal
   padding so the icon centers in a small square rather than the wider
   text-button padding. */
.btn-icon-only.btn-sm { padding: 7px; line-height: 0; }
.btn-icon-only svg { display: block; }

/* Quick palettes grid (Appearance > Colors & Fonts) - a fixed column grid
   rather than flex-wrap, so buttons form clean rows regardless of how long
   each palette's label is (flex-wrap let longer labels push rows out of
   alignment with shorter ones above/below them). */
.preset-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 10px; margin-bottom: 20px; }
.preset-grid .btn { justify-content: flex-start; width: 100%; }

.field { margin-bottom: 14px; display: flex; flex-direction: column; gap: 5px; }
/* .field's own `display: flex` ties [hidden]'s default display:none on
   specificity, and author styles win ties - without this, a hidden .field
   would silently stay visible. */
.field[hidden] { display: none; }
.field label { font-size: 13px; font-weight: 600; color: var(--muted); }
/* A field whose own visibility is independently toggleable (the 4 homepage
   content pieces) - the Show switch sits inline with the label instead of
   as a separate row, so it reads as "this field, on/off" rather than a
   whole extra setting. */
.field-head-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.field-head-row label { margin: 0; }
.field-show-toggle { display: flex; align-items: center; gap: 5px; font-size: 12px; font-weight: 500; color: var(--muted); cursor: pointer; }
.field-show-toggle input { margin: 0; cursor: pointer; }
.field input, .field select, .field textarea {
  padding: 9px 12px; border: 1px solid var(--border); border-radius: var(--radius); font: inherit; background: var(--surface); color: var(--text);
  box-shadow: 0 2px 5px rgba(0, 0, 0, .16), inset 0 2px 4px rgba(0, 0, 0, .15), inset 0 -1px 0 rgba(255, 255, 255, .85);
  transition: border-color 150ms ease, box-shadow 150ms ease;
  /* A lone .field (not in a .field-row) is a flex child of its parent form,
     and flex items default to min-width:auto - they refuse to shrink below
     their own content's width even when told width:100%. A <select> with
     "appearance: base-select" (below) renders as its own flex box
     internally, which made this bite for the first time here: a field
     like Occasion could spill past its card instead of wrapping/ellipsing.
     width:100% + min-width:0 overrides that default so every field input
     actually respects its container. */
  width: 100%;
  min-width: 0;
  box-sizing: border-box;
}
.field input:hover, .field select:hover, .field textarea:hover {
  border-color: color-mix(in srgb, var(--border) 45%, var(--accent) 55%);
}
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none; border-color: var(--accent);
  box-shadow: 0 2px 5px rgba(0, 0, 0, .16), inset 0 2px 4px rgba(0, 0, 0, .15), inset 0 -1px 0 rgba(255, 255, 255, .85), 0 0 0 4px color-mix(in srgb, var(--accent) 35%, transparent);
}
.field input::placeholder, .field textarea::placeholder { color: var(--muted); opacity: .8; }

.field input[type="color"] {
  width: 64px; height: 42px; padding: 4px; cursor: pointer; box-shadow: none;
}
.field input[type="color"]::-webkit-color-swatch-wrapper { padding: 0; }
.field input[type="color"]::-webkit-color-swatch { border: none; border-radius: 5px; }
.field input[type="color"]::-moz-color-swatch { border: none; border-radius: 5px; }

input[type="file"] {
  padding: 6px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); color: var(--muted); font-size: 13px; cursor: pointer;
}
input[type="file"]::file-selector-button {
  padding: 8px 14px; margin-right: 12px; border: none; border-radius: 6px;
  background: var(--accent); color: #fff; font-weight: 600; font-size: 13px; font-family: inherit; cursor: pointer;
  transition: background 120ms ease;
}
input[type="file"]::file-selector-button:hover { background: var(--accent-dark); }

/* Native <select> popups are OS-rendered and normally immune to CSS (sharp
   corners, flat, OS-blue option highlight). This opts supporting browsers
   (Chrome/Edge) into full CSS control of the popup; unsupported browsers
   just keep the ordinary native dropdown - no breakage either way. */
@supports (appearance: base-select) {
  select { appearance: base-select; }
  ::picker(select) {
    appearance: base-select;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: 0 12px 28px rgba(0, 0, 0, 0.14);
    padding: 4px;
  }
  select option {
    padding: 9px 12px;
    border-radius: 6px;
    color: var(--text);
  }
  select option:hover,
  select option:focus,
  select option:checked {
    background: var(--accent);
    color: #fff;
  }
}
.field-row { display: flex; gap: 12px; flex-wrap: wrap; }
.field-row .field { flex: 1; min-width: 140px; }
.checkbox-row { display: flex; align-items: center; gap: 8px; font-size: 14px; }

.badge { font-size: 11px; padding: 3px 9px; border-radius: 999px; background: var(--bg); border: 1px solid var(--border); font-weight: 600; }
.badge-ACTIVE, .badge-CONFIRMED, .badge-DELIVERED, .badge-PAID { background: #e5f4ea; color: #1f7a3d; border-color: #bfe6cc; }
.badge-DRAFT, .badge-PENDING, .badge-PENDING_PAYMENT { background: #fdf3e2; color: #9a6b12; border-color: #f3ddad; }
.badge-ARCHIVED, .badge-CANCELLED, .badge-RETURNED, .badge-FAILED { background: #fbe7e4; color: #a3352a; border-color: #f3c9c3; }
.badge-SHIPPED, .badge-OUT_FOR_DELIVERY { background: #e6f0fb; color: #1c5f9e; border-color: #c7ddf4; }

/* The orders list's status cell - a real <select> (see orders.js) wearing
   the same .badge/.badge-X colors as the read-only badge everywhere else,
   so it reads as "just the status pill" until tapped. Higher-specificity
   `select.status-select` (not just `.status-select`) so its own padding
   reliably wins over .badge's regardless of which rule the cascade sees
   last. */
select.status-select { cursor: pointer; padding: 5px 26px 5px 10px; }
select.status-select:disabled { cursor: wait; opacity: .7; }

.account-form-foot { text-align: center; margin-top: 14px; font-size: 14px; }
.account-form { max-width: 380px; margin: 60px auto; }

.variant-row { display: grid; grid-template-columns: 1fr 1fr 1fr 1fr 1fr auto; gap: 8px; align-items: end; margin-bottom: 10px; }
.variant-row .field { margin-bottom: 0; }
.variant-row-actions { grid-column: 1 / -1; display: flex; justify-content: flex-end; gap: 8px; }
.image-thumb-list { display: flex; gap: 12px; flex-wrap: wrap; margin: 10px 0; }
.image-thumb {
  position: relative; width: 110px; cursor: grab; background: var(--surface); border: 1px solid var(--border);
  border-radius: 8px; padding: 6px; transition: box-shadow 150ms ease, opacity 150ms ease;
}
.image-thumb:active { cursor: grabbing; }
.image-thumb.dragging { opacity: .4; }
.image-thumb img { width: 98px; height: 110px; object-fit: cover; border-radius: 6px; border: 1px solid var(--border); display: block; }
.image-thumb-badge {
  position: absolute; top: 4px; left: 4px; background: var(--accent); color: var(--btn-text); font-size: 10px;
  font-weight: 700; text-transform: uppercase; letter-spacing: .03em; padding: 2px 7px; border-radius: 4px; z-index: 1;
}
.image-thumb-footer { display: flex; align-items: center; justify-content: space-between; gap: 4px; margin-top: 6px; }
.image-thumb-tag { font-size: 11px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.image-thumb-actions { display: flex; gap: 4px; flex-shrink: 0; }
.image-thumb-actions button {
  border: none; border-radius: 50%; width: 20px; height: 20px; cursor: pointer; font-size: 12px; line-height: 1;
  display: flex; align-items: center; justify-content: center;
}
.image-thumb-actions [data-make-main] { background: var(--border); color: var(--text); }
.image-thumb-actions [data-remove-image] { background: var(--danger); color: #fff; }

.image-dropzone {
  display: flex; align-items: center; justify-content: center; gap: 10px; flex-wrap: wrap;
  border: 2px dashed var(--border); border-radius: 8px; padding: 20px; min-height: 56px;
  width: 100%; box-sizing: border-box; background: var(--bg, transparent);
  transition: border-color .15s, background-color .15s;
}
.image-dropzone.drag-over { border-color: var(--accent); background: var(--surface); }
.image-dropzone-hint { font-size: 13px; font-weight: 600; color: var(--muted); }

.spinner { width: 26px; height: 26px; border-radius: 50%; border: 3px solid var(--border); border-top-color: var(--accent); animation: spin 700ms linear infinite; margin: 40px auto; }
@keyframes spin { to { transform: rotate(360deg); } }
.loading { text-align: center; }
.empty { text-align: center; padding: 40px; color: var(--muted); }

#toast-root { position: fixed; bottom: 24px; left: 50%; transform: translateX(-50%); z-index: 100; display: flex; flex-direction: column; gap: 8px; align-items: center; }
.toast { background: var(--text); color: #fff; padding: 10px 18px; border-radius: 999px; font-size: 14px; box-shadow: 0 8px 20px rgba(0,0,0,.2); }
.muted { color: var(--muted); }

@media (max-width: 640px) {
  #content { padding: 18px 14px 40px; }
  .stat-grid, .quant-grid { grid-template-columns: 1fr; }
  .card-3d { padding: 16px 16px; }
  .tic-revenue { font-size: 22px; }
  .qual-totals-item { padding: 8px 18px; }
  .qual-totals-item + .qual-totals-item { border-left: none; border-top: 1px solid var(--border); }
  .qual-totals { flex-direction: column; align-items: center; }
  .qual-totals-value { font-size: 26px; }
  .ms-filter { max-width: none; }
  .topbar { gap: 10px; padding: 10px 14px; }
  .tabbar { overflow-x: auto; -webkit-overflow-scrolling: touch; min-width: 0; flex-shrink: 1; }
  .tabbar a { white-space: nowrap; }
  .icon-btn { flex-shrink: 0; }
  /* Every list table becomes a stack of cards, one per row, instead of
     scrolling sideways - each <td> keeps its column header as a label via
     data-label (set per-row in each view's render function) using a ::before,
     so no markup duplication is needed for the mobile-only label text. */
  .table-scroll { max-height: none; overflow: visible; border: none; }
  table { display: block; border: none; background: none; }
  thead { display: none; }
  tbody { display: block; }
  tr {
    display: block; margin-bottom: 12px; padding: 4px 14px;
    background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
    box-shadow: 0 1px 3px rgba(0, 0, 0, .05);
  }
  tbody tr:nth-child(even) { background: var(--surface); }
  td {
    display: flex; align-items: center; justify-content: space-between; gap: 14px;
    padding: 9px 0; border-bottom: 1px solid var(--border); text-align: right; font-size: 14px;
  }
  tr td:last-child { border-bottom: none; }
  td::before {
    content: attr(data-label); font-weight: 600; color: var(--muted); text-align: left; flex-shrink: 0;
  }
  td:not([data-label])::before, td[data-label=""]::before { content: none; }
  /* .breakdown-card's fixed 50%/22%/28% column split (desktop-only, sized
     for a real <table> row) otherwise survives into this stacked-card
     layout too, squeezing the Orders/Revenue cell so narrow its value gets
     clipped by the "td { overflow: hidden }" rule above - same label-left/
     value-right flex row every other admin table already gets on mobile. */
  .breakdown-card td:first-child, .breakdown-card td:nth-child(2), .breakdown-card td:last-child { width: auto; }
  .breakdown-card td { white-space: normal; }
}

/* ─── Modal (stock adjustment, and any future admin dialog) ────────────── */
.modal-backdrop { position: fixed; inset: 0; background: rgba(0, 0, 0, .4); z-index: 200; }
.modal-panel {
  position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 201;
  width: min(420px, calc(100vw - 32px)); max-height: calc(100vh - 48px); overflow-y: auto;
  background: var(--surface); border-radius: 12px; box-shadow: 0 24px 60px rgba(0, 0, 0, .25);
}
.modal-head { display: flex; align-items: center; justify-content: space-between; padding: 16px 18px; border-bottom: 1px solid var(--border); }
.modal-head h3 { margin: 0; font-size: 16px; }
.modal-body { padding: 16px 18px; }
.modal-body .field, .modal-body .field-row { margin-bottom: 12px; }
.modal-foot { display: flex; justify-content: flex-end; gap: 10px; padding: 14px 18px; border-top: 1px solid var(--border); }

/* ─── Custom date picker (native <input type="date"> popups render with
   unstyleable OS chrome - see date-field.js) - same trigger+floating-panel
   language as the multi-select filter above, so every "date-shaped" and
   "list-shaped" control in the admin looks and behaves the same way. ── */
.df-wrap { position: relative; }
.df-native { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.df-trigger {
  display: flex; align-items: center; justify-content: space-between; gap: 8px; width: 100%;
  background: var(--surface); border: 1px solid var(--border); color: var(--text);
  border-radius: var(--radius); padding: 9px 12px; font-size: 14px; font-family: inherit; cursor: pointer;
  box-shadow: 0 2px 5px rgba(0, 0, 0, .16), inset 0 2px 4px rgba(0, 0, 0, .15), inset 0 -1px 0 rgba(255, 255, 255, .85);
  transition: border-color 150ms ease, box-shadow 150ms ease;
}
.df-trigger:hover { border-color: color-mix(in srgb, var(--border) 45%, var(--accent) 55%); }
.df-wrap.df-open .df-trigger,
.df-trigger:focus-visible {
  border-color: var(--accent);
  outline: none;
  box-shadow: 0 2px 5px rgba(0, 0, 0, .16), inset 0 2px 4px rgba(0, 0, 0, .15), inset 0 -1px 0 rgba(255, 255, 255, .85), 0 0 0 4px color-mix(in srgb, var(--accent) 35%, transparent);
}
.df-trigger-label.df-placeholder { color: var(--muted); }
.df-icon { flex-shrink: 0; color: var(--muted); }

/* Fixed + centered horizontally (not anchored under the trigger field) - a
   field on the left half of a .field-row would otherwise push a
   left-anchored popup off the right edge of the screen on mobile. Vertical
   position is set from JS (date-field.js), clamped to the viewport so it's
   never clipped top or bottom either. */
.df-popup {
  position: fixed; left: 50%; transform: translateX(-50%); z-index: 210;
  width: 280px; max-width: calc(100vw - 32px); max-height: calc(100vh - 24px); overflow-y: auto;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: 0 14px 32px rgba(0, 0, 0, .16); padding: 12px;
  animation: df-pop 140ms ease;
}
@keyframes df-pop {
  from { opacity: 0; transform: translateX(-50%) translateY(-4px) scale(.98); }
  to { opacity: 1; transform: translateX(-50%) translateY(0) scale(1); }
}
.df-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.df-month-label { font-weight: 700; font-size: 14px; }
.df-nav {
  width: 28px; height: 28px; border-radius: 50%; border: 1px solid var(--border);
  background: var(--surface); color: var(--text); cursor: pointer; font-size: 16px; line-height: 1;
  display: flex; align-items: center; justify-content: center; font-family: inherit;
  box-shadow: 0 1px 3px rgba(0, 0, 0, .08); transition: transform 120ms ease;
}
.df-nav:active { transform: scale(.9); }
.df-weekdays { display: grid; grid-template-columns: repeat(7, 1fr); text-align: center; font-size: 11px; font-weight: 700; color: var(--muted); margin-bottom: 4px; }
.df-days { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.df-day {
  aspect-ratio: 1; border: none; background: none; color: var(--text); border-radius: 50%;
  font-size: 13px; font-family: inherit; cursor: pointer; display: flex; align-items: center; justify-content: center;
  transition: background 100ms ease, color 100ms ease;
}
.df-day:hover:not(:disabled) { background: color-mix(in srgb, var(--accent) 16%, transparent); }
.df-day.df-outside { color: var(--muted); opacity: .35; cursor: default; }
.df-day.df-today { box-shadow: inset 0 0 0 1px var(--accent); }
.df-day.active { background: var(--accent); color: #fff; font-weight: 700; }
.df-today-btn {
  width: 100%; margin-top: 8px; padding: 8px; border-radius: var(--radius); border: 1px solid var(--border);
  background: var(--surface); color: var(--accent-dark); font-weight: 700; font-size: 13px; cursor: pointer; font-family: inherit;
}
.df-today-btn:active { transform: scale(.98); }

/* Hero banner drag-to-pan/pinch-to-zoom editor (Appearance > Homepage
   Banner) - the viewport clips an <img> whose width/height/position are set
   directly in JS (see the crop-editor script below, mirrored exactly by
   public/store/js/hero-crop.js on the real storefront) rather than via
   object-fit/object-position, so that zooming in genuinely creates
   pannable room in whichever direction the frame's own aspect ratio didn't
   already provide it. Free pan in any direction - grab/grabbing hints that,
   like dragging a photo under glass. */
.hero-crop-viewport {
  position: relative; width: 100%; max-width: 480px; aspect-ratio: 16 / 5; overflow: hidden;
  border-radius: var(--radius); border: 1px solid var(--border); background: #1a1a1a;
  cursor: grab; touch-action: none; user-select: none;
}
.hero-crop-viewport.dragging { cursor: grabbing; }
.hero-crop-viewport img {
  position: absolute; left: 50%; top: 50%;
  pointer-events: none; -webkit-user-drag: none;
}
.hero-crop-controls { display: flex; align-items: center; gap: 10px; margin-top: 10px; flex-wrap: wrap; }
.hero-crop-controls input[type="range"] { flex: 1; min-width: 120px; max-width: 220px; }

/* The console's look, across the whole store admin: the tree artwork behind
   every page, a dark brown top bar, off-white panels and tables, dark buttons.
   Kept at the end so it overrides the defaults above. */
body { background: #faf7f2; }
body::before { content: ""; position: fixed; inset: 0; background: url("/admin/bg-tree.jpg") center / cover no-repeat; opacity: .42; z-index: -1; pointer-events: none; }
.topbar { background: #241e18; border-bottom: none; }
.topbar-brand { color: #faf7f2; }
.tabbar a { color: #d8cdbd; }
.tabbar a:hover { color: #fff; }
.tabbar a.active { color: #fff; border-bottom-color: #c49a5a; }
.icon-btn { color: #faf7f2; border-color: #7a6f62; background: none; }
.icon-btn:hover { background: rgba(255, 255, 255, .08); border-color: #faf7f2; }
.btn-primary { background: #241e18; color: #faf7f2; }
.btn-primary:hover { background: #3a332b; }
.btn-secondary { background: #fbf8f3; color: #241e18; border-color: #d8cdbd; }
th { background: #f1e9dd; }

/* Readability: every data grid alternates its rows, so the eye can follow a
   line across; secondary text is darker and a little larger, since the lighter
   grey was hard to read at the small sizes the admin uses. */
table tbody tr:nth-child(even) td { background: #f4eee4; }
table tbody tr:hover td { background: #ece3d3; }
th { color: #3d342a; }
.muted, .setup-step-body p { color: #4f463a; font-size: 14px; }
.badge { font-size: 12px; }

/* Frozen first column: the name stays put on the left while the other columns
   scroll sideways (only when a grid is wider than the screen). Off on phones,
   where tables stack into cards. Shaded to match the row striping. */
.table-scroll td.frozen-col, .table-scroll th.frozen-col { position: sticky; left: 0; z-index: 2; box-shadow: 6px 0 8px -6px rgba(36, 30, 24, .2); }
.table-scroll th.frozen-col { z-index: 3; background: #f1e9dd; }
.table-scroll td.frozen-col { background: #fbf8f3; }
.table-scroll tbody tr:nth-child(even) td.frozen-col { background: #f4eee4; }
.table-scroll tbody tr:hover td.frozen-col { background: #ece3d3; }
/* The products grid has more columns than most, so it keeps a minimum width and scrolls sooner. */
.products-grid table { min-width: 980px; }
@media (max-width: 640px) {
  .products-grid table { min-width: 0; }
  .table-scroll td.frozen-col, .table-scroll th.frozen-col { position: static; box-shadow: none; }
}
