/* ===========================================================================
   Backoffice — theme
   Boutique palette: ivory ground, plum ink, rose accent, gold for anything
   precious. Per-client branding is the name and logo, not these colours.
   =========================================================================== */

:root {
  --ivory: #FAF3EC;
  --plum: #2A1420;
  --plum-soft: #3D2530;
  --rose: #9C3B52;
  --rose-deep: #7C2C40;
  --gold: #B08D57;
  --gold-soft: #D8BD8E;
  --blush: #F0DCD1;
  --line: #DCC7B8;
  --white: #FFFDFB;
  --gold-text: #8A6A3D;
  --muted: #6E4C53;
  --body: #3D2530;

  --ok: #4A7C59;
  --warn: #B8791F;
  --danger: #A8324A;

  --radius: 12px;
  --radius-sm: 8px;
  --shadow-sm: 0 1px 2px rgba(42, 20, 32, 0.06);
  --shadow: 0 8px 24px rgba(42, 20, 32, 0.10);
  --shadow-lg: 0 24px 60px rgba(42, 20, 32, 0.22);

  --sidebar-w: 236px;

  /* Spacing scale. Every gap, pad and margin in a table, form or modal comes
     from here, so vertical rhythm is decided once instead of per component —
     which is how two components end up a couple of pixels apart and the whole
     screen reads as slightly off. */
  --s1: .25rem;
  --s2: .5rem;
  --s3: .75rem;
  --s4: 1rem;
  --s5: 1.5rem;
  --s6: 2rem;

  /* Table cells. The x value is deliberately larger than the y: a row reads
     as a line, and horizontal air is what separates columns into columns.
     Compact trims both, but the vertical far harder — losing vertical air only
     costs comfort, whereas taking too much horizontal air runs the columns
     together and costs legibility. */
  --cell-y: .85rem;
  --cell-x: 1.1rem;

  /* An opaque version of the header's tint. A sticky header has rows sliding
     underneath it, so it cannot be the translucent wash it was when nothing
     ever passed behind it. */
  --table-head: #FBF4EF;

  /* Every control that sits on a form line shares one height, or a select
     next to a text input lands a pixel or two off and the row looks broken. */
  --control-h: 2.6rem;
}

* { box-sizing: border-box; }

html, body { height: 100%; }

body {
  margin: 0;
  background: var(--ivory);
  color: var(--body);
  font-family: 'Jost', system-ui, -apple-system, sans-serif;
  font-size: 15px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  /* Cormorant Garamond ships old-style figures by default: the 1 sits at
     x-height and reads as a capital I, and 3 4 7 9 drop below the baseline.
     Beautiful in a paragraph, wrong for a stock count or a price. Inherited
     from here so every number in the app gets lining figures; Jost has no
     old-style set, so the sans is unaffected. */
  font-variant-numeric: lining-nums;
}

body.no-scroll { overflow: hidden; }

h1, h2, h3 { margin: 0; font-weight: 500; }
p { margin: 0; }
a { color: var(--rose); text-decoration: none; }
a:hover { text-decoration: underline; }

button { font: inherit; }

:focus-visible {
  outline: 2px solid var(--rose);
  outline-offset: 2px;
  border-radius: 3px;
}

/* ---------------------------------------------------------------- login -- */
/* The UA's [hidden] { display: none } is a bare attribute selector, so any
   class rule that sets display beats it. .login and .shell both do, which
   made el.hidden = true a no-op — you would sign in and the login screen
   would simply stay on top of the app. Restate it with enough specificity
   to win. */
[hidden] {
  display: none !important;
}

/* An eight-point star lattice, laid under the gradients at a few percent. Two
   squares, one rotated over the other — the same construction as the medallion,
   so the page and its ornament are visibly the same idea. Kept faint enough
   that it reads as texture in the paper rather than as a pattern competing with
   the card. */
:root {
  --lattice: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='96' height='96' viewBox='0 0 96 96'%3E%3Cg fill='none' stroke='%23B08D57' stroke-width='1.2'%3E%3Crect x='24' y='24' width='48' height='48'/%3E%3Crect x='24' y='24' width='48' height='48' transform='rotate(45 48 48)'/%3E%3C/g%3E%3C/svg%3E");
}

.login {
  min-height: 100dvh;
  display: grid;
  place-items: center;
  padding: 1.5rem;
  position: relative;
  background:
    radial-gradient(34rem 26rem at 78% -10%, rgba(156, 59, 82, 0.10), transparent 62%),
    radial-gradient(28rem 24rem at -6% 40%, rgba(176, 141, 87, 0.14), transparent 62%),
    var(--ivory);
}

.login::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: var(--lattice);
  background-size: 96px 96px;
  opacity: .10;
  /* Fades out towards the middle so the card never sits on a busy ground. */
  -webkit-mask-image: radial-gradient(60% 55% at 50% 50%, transparent 20%, #000 78%);
  mask-image: radial-gradient(60% 55% at 50% 50%, transparent 20%, #000 78%);
  pointer-events: none;
}

.login__card { position: relative; }

.login__card {
  width: min(400px, 100%);
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 2rem 1.75rem 1.5rem;
  box-shadow: var(--shadow);
}

.login__card form { display: grid; gap: 1rem; margin-top: 1.5rem; }

.login__foot {
  margin-top: 1.25rem;
  text-align: center;
  font-size: .8rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
}

.brandmark { display: flex; align-items: center; gap: .75rem; }

.brandmark__name {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-size: 1.3rem;
  color: var(--plum);
  line-height: 1.1;
}

.brandmark__sub {
  font-size: .68rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--gold-text);
}

/* Last-resort error surface — must be visible before any app CSS loads or
   any view renders, so it is deliberately loud and pinned to the top. */
.fatal-error {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 9999;
  background: #A8324A;
  color: #fff;
  font: 500 .9rem/1.4 system-ui, sans-serif;
  padding: .75rem 1rem;
  white-space: pre-wrap;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

.section-title {
  font-family: "Cormorant Garamond", Georgia, serif;
  font-size: 1.35rem;
  font-weight: 600;
  margin: 1.6rem 0 .7rem;
  color: var(--plum);
}

.hint {
  margin-top: 1rem;
  font-size: .84rem;
  color: var(--muted);
  max-width: 60ch;
}

.import-summary {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem 1.2rem;
  margin-bottom: .8rem;
  font-size: .9rem;
}

.import-summary b { color: var(--plum); }

.form-error {
  background: rgba(168, 50, 74, 0.08);
  border: 1px solid rgba(168, 50, 74, 0.25);
  color: var(--danger);
  padding: .6rem .8rem;
  border-radius: var(--radius-sm);
  font-size: .88rem;
}

/* ---------------------------------------------------------------- shell -- */
.shell { display: flex; min-height: 100dvh; }

.sidebar {
  width: var(--sidebar-w);
  flex-shrink: 0;
  background: var(--plum);
  color: var(--blush);
  padding: 1.5rem 1rem;
  display: flex;
  flex-direction: column;
  gap: 2rem;
  position: sticky;
  top: 0;
  height: 100dvh;
}

/* The lattice again, this time as an overlay with its own opacity. Blending it
   into the background instead lit the gold to near-full strength against plum
   and the nav labels had to compete with it — texture has to sit under the
   type, not beside it. 4% is the point where you stop seeing a pattern and
   start seeing woven cloth. */
.sidebar::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: var(--lattice);
  /* Smaller than the login's tile on purpose. Gold on dark plum carries far
     more contrast than gold on ivory, so at 140px the eye tracks each star as a
     shape; at 88px the same lines read as weave. */
  background-size: 88px 88px;
  opacity: .028;
  pointer-events: none;
}

.sidebar > * { position: relative; }

.brandmark--side .brandmark__name { color: var(--white); }
.brandmark--side .brandmark__sub { color: var(--gold-soft); }

.nav { display: grid; gap: .15rem; flex: 1; }

.nav__item {
  display: flex;
  align-items: center;
  gap: .65rem;
  padding: .6rem .75rem;
  border-radius: var(--radius-sm);
  color: rgba(240, 220, 209, 0.72);
  font-size: .93rem;
  transition: background .18s ease, color .18s ease;
}

.nav__item:hover { background: rgba(255, 253, 251, 0.06); color: var(--white); text-decoration: none; }

.nav__item.is-active {
  background: rgba(216, 189, 142, 0.14);
  color: var(--white);
  font-weight: 500;
}

.nav__group {
  margin: 1.1rem 0 .35rem;
  padding: 0 .75rem;
  font-size: .66rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: rgba(216, 189, 142, 0.65);
}

.nav__dot {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: currentColor;
  opacity: .35;
  flex-shrink: 0;
}

.nav__item.is-active .nav__dot { background: var(--gold-soft); opacity: 1; }

.sidebar__foot { border-top: 1px solid rgba(216, 189, 142, 0.18); padding-top: 1rem; }
.who__name { color: var(--white); font-size: .9rem; }
.who__role {
  font-size: .68rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--gold-soft);
  margin-bottom: .5rem;
}

.main { flex: 1; min-width: 0; display: flex; flex-direction: column; }

.topbar {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: 1.25rem clamp(1rem, 3vw, 2rem);
  border-bottom: 1px solid var(--line);
  background: rgba(250, 243, 236, 0.92);
  backdrop-filter: blur(8px);
  position: sticky;
  top: 0;
  z-index: 20;
}

/* The lattice again, at the very edge of visible. The top bar is the one strip
   of every page that carries no data, so it can hold texture without anything
   having to compete with it — and it ties each page back to the login without
   putting a pattern behind a table. */
.topbar::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: var(--lattice);
  /* Finer and fainter than first tried. The bar is only ~90px tall, so a 104px
     tile showed one big star per screen-width and the page title had a shape
     sitting behind it; at 64px and 3% it is a texture the eye passes over. */
  background-size: 64px 64px;
  opacity: .03;
  pointer-events: none;
}

.topbar > * { position: relative; }

.topbar h1 {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-size: 1.6rem;
  color: var(--plum);
}

.view {
  padding: clamp(var(--s4), 3vw, var(--s6));
  display: grid;
  gap: var(--s5);
  align-content: start;
}

/* Grid children default to min-width:auto and refuse to shrink below their
   content, so a wide table pushes the whole page sideways instead of scrolling
   inside its own .table-wrap. The views nest the table one level down, so the
   constraint belongs on the direct children, not on .table-wrap itself. */
.view > * { min-width: 0; }

.scrim { display: none; }

/* --------------------------------------------------------------- stats -- */
.stat-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 1rem;
}

.stat {
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.1rem 1.15rem;
  box-shadow: var(--shadow-sm);
}

.stat--warn { border-color: rgba(184, 121, 31, 0.45); background: rgba(184, 121, 31, 0.05); }

.stat__label {
  font-size: .72rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--gold-text);
}

.stat__value {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-size: 2rem;
  line-height: 1.15;
  color: var(--plum);
  margin: .2rem 0;
}

.stat__sub { font-size: .82rem; color: var(--muted); }

/* -------------------------------------------------------------- panels -- */
.grid-2 {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 1.25rem;
}

.panel {
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}

.panel__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s4);
  padding: var(--s4) var(--cell-x);
  border-bottom: 1px solid var(--line);
}

.panel__head h2 {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-size: 1.25rem;
  color: var(--plum);
}

.panel__empty { padding: var(--s5) var(--cell-x); color: var(--muted); font-size: .9rem; }

/* ---------------------------------------------------------------- list -- */
.list { list-style: none; margin: 0; padding: 0; }

.list__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: .8rem 1.15rem;
  border-bottom: 1px solid rgba(220, 199, 184, 0.5);
}

.list__row:last-child { border-bottom: none; }
.list__title { font-size: .93rem; color: var(--plum); }
.list__meta { font-size: .8rem; color: var(--muted); }
.list__right { display: flex; align-items: center; gap: .75rem; flex-shrink: 0; }
.list__amount { font-variant-numeric: tabular-nums; color: var(--plum); font-weight: 500; }

/* ---------------------------------------------------------------- bars -- */
.bars { list-style: none; margin: 0; padding: 1rem 1.15rem; display: grid; gap: .85rem; }
.bar__head { display: flex; justify-content: space-between; gap: 1rem; font-size: .87rem; margin-bottom: .35rem; }
.bar__name { color: var(--plum); }
.bar__value { color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
.bar__track { height: 7px; background: var(--blush); border-radius: 99px; overflow: hidden; }
.bar__fill { height: 100%; background: linear-gradient(90deg, var(--rose), var(--gold)); border-radius: 99px; }

/* ------------------------------------------------------------- toolbar -- */
.toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3) var(--s4);
  flex-wrap: wrap;
}

.toolbar__filters {
  display: flex;
  align-items: center;
  gap: var(--s2);
  flex-wrap: wrap;
  /* Take the room the actions do not, so the filters keep one line for as long
     as they can instead of breaking after the first control. */
  flex: 1 1 auto;
}

/* The toolbar is space-between, so it only behaves with exactly two children.
   Views with more than one action button group them in here. */
.toolbar__actions {
  display: flex;
  align-items: center;
  gap: var(--s2);
  flex-wrap: wrap;
  /* Never the thing that wraps first: an action is one control, the filters
     are several, and a lone button on its own line looks like a mistake. */
  flex: 0 0 auto;
  margin-left: auto;
}

.toolbar > .btn:last-child { margin-left: auto; }

/* Every control in a toolbar shares the row's height, so a search box, a
   select and a checkbox line up on one baseline instead of three. */
.toolbar .input,
.toolbar .btn { min-height: var(--control-h); }
.toolbar .check { min-height: var(--control-h); display: flex; align-items: center; gap: var(--s2); }

.input {
  font: inherit;
  color: var(--body);
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: .6rem .8rem;
  min-width: 0;
  min-height: var(--control-h);
  box-shadow: inset 0 1px 2px rgba(42, 20, 32, 0.04);
  transition: border-color .16s ease, box-shadow .16s ease, background .16s ease;
}

.input:hover:not(:disabled) { border-color: var(--gold-soft); }

.input:focus,
.input:focus-visible {
  outline: none;
  border-color: var(--rose);
  /* A ring rather than a hard outline — reads as attention, not as an error. */
  box-shadow: 0 0 0 3px rgba(156, 59, 82, 0.12), inset 0 1px 2px rgba(42, 20, 32, 0.04);
}

.input:disabled {
  background: rgba(220, 199, 184, 0.18);
  color: var(--muted);
  cursor: not-allowed;
}

.input::placeholder { color: rgba(110, 76, 83, 0.5); }
.input--search { min-width: 240px; }
textarea.input { resize: vertical; font-family: inherit; }

input[type="file"].input { padding: .35rem .4rem; }
input[type="file"].input::file-selector-button {
  font: inherit;
  color: var(--body);
  background: var(--blush);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: .3rem .7rem;
  margin-right: .7rem;
  cursor: pointer;
}
input[type="file"].input::file-selector-button:hover { border-color: var(--rose); }

.check { display: flex; align-items: center; gap: .4rem; font-size: .88rem; color: var(--muted); cursor: pointer; }

.segmented {
  display: flex;
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: 99px;
  padding: 3px;
  gap: 2px;
}

.segmented button {
  border: none;
  background: transparent;
  color: var(--muted);
  padding: .35rem .8rem;
  border-radius: 99px;
  cursor: pointer;
  font-size: .85rem;
  transition: background .18s ease, color .18s ease;
}

.segmented button:hover { color: var(--plum); }
.segmented button.is-active { background: var(--plum); color: var(--white); }

/* ------------------------------------------------------------- buttons -- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .4rem;
  border: 1px solid transparent;
  border-radius: 99px;
  padding: .55rem 1.2rem;
  font-size: .9rem;
  cursor: pointer;
  transition: background .18s ease, color .18s ease, border-color .18s ease;
  white-space: nowrap;
}

.btn:hover { text-decoration: none; }
.btn:disabled { opacity: .55; cursor: not-allowed; }

.btn--primary { background: var(--rose); color: var(--white); }
.btn--primary:hover:not(:disabled) { background: var(--rose-deep); }

.btn--ghost { background: transparent; border-color: var(--plum); color: var(--plum); }
.btn--ghost:hover:not(:disabled) { background: var(--plum); color: var(--ivory); }

.btn--danger { background: var(--danger); color: var(--white); }
.btn--danger:hover:not(:disabled) { background: #8C2740; }

.btn--block { width: 100%; }
.btn--sm { padding: .4rem .9rem; font-size: .84rem; }

.link-btn {
  background: none;
  border: none;
  /* No horizontal padding: these sit inside table cells, and .35rem of it put
     every name a few pixels right of the meta line beneath it — the kind of
     misalignment you feel before you can point at it. Gaps between adjacent
     actions come from an explicit margin instead. */
  padding: 0;
  color: var(--rose);
  cursor: pointer;
  font-size: .87rem;
  text-align: inherit;
}

.link-btn:hover { text-decoration: underline; }
.link-btn--muted { color: var(--muted); }
.link-btn--danger { color: var(--danger); }
/* Pushed to the left only in a modal footer, where it is the danger zone.
   In a table row it sits inline with the other actions. */
.modal__foot .link-btn--danger { margin-right: auto; }
.link-btn--onDark { color: var(--gold-soft); padding: 0; }

.icon-btn {
  background: none;
  border: none;
  font-size: 1.4rem;
  line-height: 1;
  color: var(--muted);
  cursor: pointer;
  padding: .2rem .4rem;
  border-radius: var(--radius-sm);
}

.icon-btn:hover { color: var(--plum); background: var(--blush); }

.icon-btn--nav { display: none; flex-direction: column; gap: 4px; padding: .5rem; }
.icon-btn--nav span { display: block; width: 18px; height: 2px; background: var(--plum); border-radius: 2px; }

/* --------------------------------------------------------------- table -- */
.table-wrap {
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);

  /* Both axes. overflow-x alone already computes overflow-y to auto, but the
     box never scrolls vertically without a height to run out of — and a sticky
     header only sticks against a container that actually scrolls. Capping the
     height gives it one: the toolbar stays put, the header stays put, and only
     the rows move. Short tables never reach the cap and behave as before. */
  overflow: auto;
  max-height: max(22rem, calc(100dvh - 15rem));

  /* Grid items default to min-width:auto, which means this box refuses to
     shrink below its table and the whole page scrolls sideways instead of the
     table scrolling inside it. */
  min-width: 0;
}

.table { width: 100%; border-collapse: collapse; font-size: .91rem; }

.table th {
  text-align: left;
  font-size: .7rem;
  font-weight: 500;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--gold-text);
  background: var(--table-head);
  padding: var(--cell-y) var(--cell-x);
  white-space: nowrap;

  /* Sticky within .table-wrap, which is the scroll container. A border on a
     sticky cell scrolls away with the cell's own box in some engines, so the
     rule under the header is drawn as a shadow instead. */
  position: sticky;
  top: 0;
  z-index: 2;
  box-shadow: inset 0 -1px 0 var(--line);
}

.table td {
  padding: var(--cell-y) var(--cell-x);
  border-bottom: 1px solid rgba(220, 199, 184, 0.45);
  vertical-align: middle;
}

/* The first and last columns sit against the card's rounded edge, so they get
   the corner back as breathing room rather than hugging the border. */
.table th:first-child, .table td:first-child { padding-left: var(--s5); }
.table th:last-child, .table td:last-child { padding-right: var(--s5); }

.table tbody tr:last-child td { border-bottom: none; }
.table tbody tr { transition: background .14s ease; }
.table tbody tr:hover { background: rgba(240, 220, 209, 0.18); }
.table .num { text-align: right; font-variant-numeric: lining-nums tabular-nums; white-space: nowrap; }

/* Row actions. Relying on the whitespace between two buttons gives a gap that
   depends on the font, and it differs from table to table; this makes the
   spacing explicit and identical everywhere. */
.table td .link-btn + .link-btn { margin-left: var(--s3); }

/* The title link is the row's name, not an action: same size and colour as
   plain title text, with the rose reserved for hover. */
.table .cell-title .link-btn {
  font-size: inherit;
  color: var(--plum);
  font-weight: inherit;
}
.table .cell-title .link-btn:hover { color: var(--rose); }

/* A two-line cell (title over meta) next to a one-line cell used to sit a
   little high, because the meta line inherits the body line-height. */
.table .cell-title { line-height: 1.35; }
.table .cell-meta { line-height: 1.35; margin-top: .1rem; }

.table--tight { font-size: .88rem; }
.table--tight td, .table--tight th { padding: .55rem .7rem; }
.table--tight th:first-child, .table--tight td:first-child { padding-left: .7rem; }
.table--tight th:last-child, .table--tight td:last-child { padding-right: .7rem; }

.table tr.is-archived { opacity: .55; }

.cell-title { color: var(--plum); }
.cell-meta { display: block; font-size: .79rem; color: var(--muted); }
.cell-product { display: flex; align-items: center; gap: .7rem; }

/* The product name doubles as the way into its catalog card, so it has to look
   clickable without turning the table into a wall of links. */
.link-title {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
}
.link-title:hover { color: var(--rose); text-decoration: underline; }

/* ------------------------------------------------------------- catalog -- */
.catalog { display: grid; grid-template-columns: minmax(0, 16rem) minmax(0, 1fr); gap: 1.5rem; }

.catalog__media {
  display: grid;
  gap: .5rem;
  align-content: start;
  justify-items: center;
}

.catalog__media img {
  width: 100%;
  aspect-ratio: 1;
  object-fit: contain;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  background: var(--white);
  padding: .35rem;
}

.catalog__placeholder {
  width: 100%;
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  border-radius: var(--radius);
  border: 1px dashed var(--line);
  background: var(--blush);
  color: var(--gold-text);
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-size: 3rem;
}

.catalog__ar { font-size: 1.05rem; color: var(--muted); }

.catalog__price {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-size: 2rem;
  color: var(--plum);
  margin: .1rem 0 1rem;
}

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

@media (max-width: 700px) {
  .catalog { grid-template-columns: 1fr; }
}

/* Product names run long ("Air Freshener 300ML ACR-DLX Yara Candy") and were
   wrapping to five lines in a column the browser had squeezed. Scoped to the
   product cell rather than every table's first column — the staff and expense
   tables want their own widths. */
.cell-product { min-width: 13rem; }
.cell-product .cell-title { line-height: 1.3; }

/* A 28-character UID is reference data, not something to read — let it shrink
   rather than push the row's actions off the edge. */
.cell-uid {
  font-size: .74rem;
  color: var(--muted);
  max-width: 9rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.thumb {
  width: 38px; height: 38px;
  border-radius: var(--radius-sm);
  /* The one place that still crops. A 416x1022 bottle contained in a 38px box
     is a 15px sliver — technically the whole image, visually nothing. At this
     size the picture is an identifier, not something you examine, so filling
     the square is the more useful of the two. Everywhere the photo is meant to
     be looked at — the card, the detail, the edit preview — contains it. */
  object-fit: cover;
  flex-shrink: 0;
  border: 1px solid var(--line);
  background: var(--white);
}

.thumb--empty {
  display: grid;
  place-items: center;
  background: var(--blush);
  color: var(--gold-text);
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-size: 1.1rem;
}

.chip {
  display: inline-block;
  font-size: .76rem;
  padding: .2rem .6rem;
  border-radius: 99px;
  background: var(--blush);
  color: var(--gold-text);
}

.tag {
  font-size: .68rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
  border: 1px solid var(--line);
  border-radius: 99px;
  padding: .05rem .45rem;
  margin-left: .35rem;
}

.wa-link { font-variant-numeric: tabular-nums; }

/* ------------------------------------------------------------- stepper -- */
.stepper { display: inline-flex; align-items: center; gap: .3rem; }

.stepper__btn {
  width: 24px; height: 24px;
  border: 1px solid var(--line);
  background: var(--white);
  border-radius: 6px;
  color: var(--plum);
  cursor: pointer;
  line-height: 1;
}

.stepper__btn:hover:not(:disabled) { background: var(--blush); }
.stepper__btn:disabled { opacity: .4; cursor: not-allowed; }
.stepper__value { min-width: 2ch; text-align: center; font-variant-numeric: tabular-nums; }
.stepper__value.is-low { color: var(--warn); font-weight: 600; }
.stepper__value.is-out { color: var(--danger); font-weight: 600; }

/* -------------------------------------------------------------- status -- */
.pill {
  display: inline-block;
  font-size: .76rem;
  padding: .18rem .65rem;
  border-radius: 99px;
  border: 1px solid;
  white-space: nowrap;
}

.pill--new { color: var(--warn); border-color: rgba(184, 121, 31, .4); background: rgba(184, 121, 31, .09); }
.pill--confirmed { color: var(--gold-text); border-color: rgba(176, 141, 87, .45); background: rgba(176, 141, 87, .10); }
.pill--shipped { color: var(--rose); border-color: rgba(156, 59, 82, .35); background: rgba(156, 59, 82, .08); }
.pill--delivered { color: var(--ok); border-color: rgba(74, 124, 89, .4); background: rgba(74, 124, 89, .09); }
.pill--cancelled { color: var(--muted); border-color: var(--line); background: transparent; }

.status-select {
  font: inherit;
  font-size: .84rem;
  padding: .28rem 1.6rem .28rem .6rem;
  border-radius: 99px;
  border: 1px solid var(--line);
  background: var(--white);
  color: var(--plum);
  cursor: pointer;
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M3 5l3 3 3-3' stroke='%236E4C53' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right .45rem center;
  background-size: 12px;
}

.status-select--new { border-color: rgba(184, 121, 31, .5); background-color: rgba(184, 121, 31, .08); }
.status-select--delivered { border-color: rgba(74, 124, 89, .45); background-color: rgba(74, 124, 89, .08); }
.status-select--cancelled { color: var(--muted); }

.stock-badge { font-size: .78rem; padding: .18rem .6rem; border-radius: 99px; white-space: nowrap; }
.stock-badge--low { background: rgba(184, 121, 31, .12); color: var(--warn); }
.stock-badge--out { background: rgba(168, 50, 74, .1); color: var(--danger); }

/* --------------------------------------------------------------- modal -- */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(42, 20, 32, 0.44);
  backdrop-filter: blur(3px);
  display: grid;
  place-items: center;
  padding: 1rem;
  z-index: 100;
  animation: fade .16s ease;
}

@keyframes fade { from { opacity: 0; } }

.modal {
  background: var(--white);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  width: min(520px, 100%);
  max-height: 90dvh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.modal--wide { width: min(760px, 100%); }

.modal__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.1rem 1.25rem;
  border-bottom: 1px solid var(--line);
}

.modal__head h2 {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-size: 1.35rem;
  color: var(--plum);
}

.modal__form { display: flex; flex-direction: column; min-height: 0; }
.modal__body { padding: 1.25rem; overflow-y: auto; display: grid; gap: 1rem; }

.modal__foot {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: var(--s2);
  padding: var(--s4) 1.4rem;
  border-top: 1px solid var(--line);
  background: rgba(250, 243, 236, .6);
}

.modal__error {
  margin: 0 1.25rem;
  background: rgba(168, 50, 74, 0.08);
  border: 1px solid rgba(168, 50, 74, 0.25);
  color: var(--danger);
  padding: .55rem .75rem;
  border-radius: var(--radius-sm);
  font-size: .87rem;
}

.confirm-text { color: var(--body); }

/* -------------------------------------------------------------- fields -- */
.field-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s4) 1.1rem; }
.field-grid .field--wide { grid-column: 1 / -1; }

.field { display: grid; gap: var(--s1); min-width: 0; align-content: start; }
.field--wide { grid-column: 1 / -1; }

.field > span {
  font-size: .78rem;
  letter-spacing: .04em;
  font-weight: 500;
  color: var(--muted);
}

.field > span em { font-style: normal; color: rgba(110, 76, 83, 0.65); font-weight: 400; }

/* A checkbox row has no label line above it, so on a grid line beside a text
   field it floats. Pinning it to the control height lines the two up. */
.check--field { min-height: var(--control-h); align-items: center; }

@media (max-width: 620px) {
  .field-grid { grid-template-columns: 1fr; }
}

/* ------------------------------------------------------- order details -- */
.detail-head {
  display: flex;
  align-items: flex-start;
  gap: 1.5rem;
  flex-wrap: wrap;
  padding-bottom: .5rem;
  border-bottom: 1px solid var(--line);
}

.detail-head > *:last-child { margin-left: auto; }

.detail-label {
  font-size: .7rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--gold-text);
  margin-bottom: .15rem;
}

.detail-value { color: var(--plum); font-size: 1rem; }
.detail-meta { font-size: .82rem; color: var(--muted); }

.note-box {
  background: var(--blush);
  border-radius: var(--radius-sm);
  padding: .75rem .9rem;
  font-size: .9rem;
}

.totals { margin: 0; display: grid; gap: .3rem; justify-items: end; }
.totals > div { display: flex; gap: 2.5rem; justify-content: space-between; min-width: 220px; }
.totals dt { color: var(--muted); font-size: .87rem; }
.totals dd { margin: 0; font-variant-numeric: tabular-nums; color: var(--body); }

.totals__grand {
  border-top: 1px solid var(--line);
  padding-top: .35rem;
  margin-top: .2rem;
}

.totals__grand dt { color: var(--plum); font-weight: 500; }
.totals__grand dd { color: var(--plum); font-weight: 600; font-size: 1.05rem; }

.line-builder { display: grid; gap: .6rem; }
.line-add { display: flex; gap: .5rem; }
.line-add .input { flex: 1; }
.totals-live { display: flex; justify-content: flex-end; }

/* -------------------------------------------------------------- states -- */
.empty, .error-state, .first-run {
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 2.5rem var(--s5);
  text-align: center;
  color: var(--muted);
  display: grid;
  gap: var(--s3);
  justify-items: center;
}

.first-run h2 {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-size: 1.7rem;
  color: var(--plum);
}

.first-run p { max-width: 46ch; }
.first-run__actions { display: flex; gap: .6rem; flex-wrap: wrap; justify-content: center; margin-top: .5rem; }

.error-state h2 { font-family: 'Cormorant Garamond', Georgia, serif; font-size: 1.5rem; color: var(--plum); }

.skeleton { display: grid; gap: .5rem; }

.skeleton__row {
  height: 52px;
  border-radius: var(--radius-sm);
  background: linear-gradient(90deg, rgba(240,220,209,.35), rgba(240,220,209,.7), rgba(240,220,209,.35));
  background-size: 200% 100%;
  animation: shimmer 1.4s ease-in-out infinite;
}

@keyframes shimmer {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

@media (prefers-reduced-motion: reduce) {
  .skeleton__row { animation: none; }
  * { transition-duration: .01ms !important; }
}

/* -------------------------------------------------------------- toasts -- */
.toasts {
  position: fixed;
  bottom: 1.25rem;
  right: 1.25rem;
  display: grid;
  gap: .5rem;
  z-index: 200;
  pointer-events: none;
}

.toast {
  background: var(--plum);
  color: var(--white);
  padding: .7rem 1.1rem;
  border-radius: 99px;
  box-shadow: var(--shadow);
  font-size: .88rem;
  animation: rise .22s ease;
  max-width: 360px;
}

.toast--error { background: var(--danger); }
.toast--out { opacity: 0; transition: opacity .3s ease; }

@keyframes rise {
  from { opacity: 0; transform: translateY(8px); }
}

/* ------------------------------------------------------------ responsive */
@media (max-width: 860px) {
  .sidebar {
    position: fixed;
    left: 0; top: 0;
    z-index: 60;
    transform: translateX(-100%);
    transition: transform .22s ease;
  }

  body.nav-open .sidebar { transform: translateX(0); }

  body.nav-open .scrim {
    display: block;
    position: fixed;
    inset: 0;
    background: rgba(42, 20, 32, .4);
    z-index: 50;
  }

  .icon-btn--nav { display: flex; }
  .field-grid { grid-template-columns: 1fr; }
  .input--search { min-width: 0; flex: 1; }
  .toolbar { align-items: stretch; }
  .toolbar__filters { width: 100%; }
  .segmented { overflow-x: auto; }
  .toasts { left: 1rem; right: 1rem; }
  .toast { max-width: none; }
}

/* ------------------------------------------------- additions (batch 4) -- */

/* Reseller badge — distinct from the category chip it sits beside. */
.chip--reseller {
  background: rgba(176, 141, 87, 0.18);
  color: var(--gold-text);
  border: 1px solid rgba(176, 141, 87, 0.35);
}

/* Checkbox styled as a form field so it lines up in .field-grid. */
.check--field {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: .55rem;
  padding: .4rem 0;
}

/* Shop logo picker: preview beside the file input. */
.logo-field { display: flex; align-items: flex-start; gap: 1.2rem; flex-wrap: wrap; }

.logo-field__preview {
  width: 84px;
  height: 84px;
  flex-shrink: 0;
  display: grid;
  place-items: center;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  background: var(--blush);
  color: var(--gold-text);
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-size: 2.2rem;
  overflow: hidden;
}
.logo-field__preview img { width: 100%; height: 100%; object-fit: contain; padding: .3rem; }

/* Sidebar brandmark, once a real logo replaces the lettermark SVG. */
.brandmark__mark { display: inline-flex; flex-shrink: 0; }

/* Real logos are rarely square — a wordmark is wide, a crest is tall. Fixing
   the height and letting the width follow shows one at the size it was drawn
   for, instead of contain-ing a 512x397 mark into a 40px box where it renders
   at 40x31 with dead air either side and reads as a smudge. */
.brandmark__mark img {
  height: 34px;
  width: auto;
  max-width: 130px;
  border-radius: 8px;
  object-fit: contain;
}

/* Catalog photo: phone photos are multi-megabyte, so the frame holds its
   shape and shows it is working rather than sitting blank. */
.catalog__frame {
  position: relative;
  width: 100%;
  aspect-ratio: 1;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  background: var(--white);
  overflow: hidden;
  display: grid;
  place-items: center;
}
.catalog__frame img { width: 100%; height: 100%; object-fit: contain; display: block; padding: .5rem; }
.catalog__frame.is-loading { background: var(--blush); }
.catalog__frame.is-loading::after {
  content: "Loading photo…";
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-size: .82rem;
  color: var(--gold-text);
}
.catalog__frame.is-loading img { opacity: 0; }

/* Dashboard rankings. */
.rank { list-style: none; margin: 0; padding: 0; }

.rank__row {
  display: flex;
  align-items: center;
  gap: .8rem;
  padding: .7rem 1.15rem;
  border-top: 1px solid var(--line);
}
.rank__row:first-child { border-top: 0; }

.rank__pos {
  width: 1.6rem;
  height: 1.6rem;
  flex-shrink: 0;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--blush);
  color: var(--gold-text);
  font-size: .78rem;
}

.rank__body { flex: 1; min-width: 0; }
.rank__body .list__title { overflow: hidden; text-overflow: ellipsis; }

/* ============================================================== polish ==
   A pass over the surfaces you spend the most time in — forms, modals,
   inputs, buttons. The palette is unchanged; what changes is depth,
   spacing rhythm and how things respond to being touched.
   ====================================================================== */

select.input {
  appearance: none;
  background-image:
    linear-gradient(45deg, transparent 50%, var(--gold-text) 50%),
    linear-gradient(135deg, var(--gold-text) 50%, transparent 50%);
  background-position: calc(100% - 18px) 52%, calc(100% - 13px) 52%;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  padding-right: 2.2rem;
}

/* --- buttons --------------------------------------------------------- */
.btn {
  border-radius: 999px;
  transition: transform .12s ease, box-shadow .16s ease, background .16s ease,
              border-color .16s ease;
}

.btn:active { transform: translateY(1px); }

.btn--primary {
  background: linear-gradient(180deg, var(--rose) 0%, var(--rose-deep) 100%);
  border-color: transparent;
  box-shadow: 0 1px 2px rgba(124, 44, 64, 0.28), 0 6px 16px rgba(124, 44, 64, 0.18);
}

.btn--primary:hover:not(:disabled) {
  box-shadow: 0 2px 4px rgba(124, 44, 64, 0.3), 0 10px 22px rgba(124, 44, 64, 0.24);
}

.btn--primary:disabled { opacity: .55; box-shadow: none; cursor: not-allowed; }

.btn--ghost:hover:not(:disabled) {
  border-color: var(--gold);
  background: rgba(216, 189, 142, 0.12);
}

/* --- modals ---------------------------------------------------------- */
.modal-overlay { backdrop-filter: blur(3px); }

.modal {
  border-radius: 16px;
  box-shadow: var(--shadow-lg);
  overflow: hidden;
}

.modal__head {
  padding: 1.15rem 1.4rem;
  border-bottom: 1px solid var(--line);
  background: linear-gradient(180deg, rgba(240, 220, 209, 0.35) 0%, transparent 100%);
}

.modal__head h2 {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-size: 1.4rem;
  color: var(--plum);
}

.modal__body { padding: 1.3rem 1.4rem; }

/* --- panels and stats ------------------------------------------------ */
.panel, .stat, .table-wrap {
  transition: box-shadow .18s ease, border-color .18s ease;
}

.stat:hover { box-shadow: 0 4px 14px rgba(42, 20, 32, 0.08); }

/* --- misc ------------------------------------------------------------ */
.mono {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .85em;
  color: var(--muted);
}

.chip, .pill, .tag { border-radius: 999px; }

/* Toasts sit above the modal so a save confirmation is never hidden. */
.toasts { z-index: 10000; }

/* --------------------------------------------------------- tag editor -- */
.tags { display: grid; gap: .7rem; }

.tags__list { display: flex; flex-wrap: wrap; gap: .4rem; }

.tags__empty { font-size: .85rem; color: var(--muted); font-style: italic; }

.tag-chip {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  padding: .3rem .5rem .3rem .7rem;
  border-radius: 999px;
  background: var(--white);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-sm);
  font-size: .88rem;
  color: var(--plum);
}

.tag-chip__x {
  border: 0;
  background: none;
  cursor: pointer;
  color: var(--muted);
  font-size: 1rem;
  line-height: 1;
  padding: 0 .1rem;
  border-radius: 50%;
}
.tag-chip__x:hover { color: var(--danger); }

.tags__add { display: flex; gap: .5rem; max-width: 26rem; }
.tags__input { flex: 1; }

/* Customer notes stay one line in the table; the full text is on hover. */
.cell-notes {
  max-width: 18rem;
  color: var(--muted);
  font-size: .88rem;
}
.cell-notes span {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ============================================================== charts ==
   Series hues validated against the card surface (#FFFDFB) with the palette
   checker: rose vs gold separate at ΔE 17.7 deuteranopia / 20.9 normal.
   Text never wears a series colour — the mark beside it carries identity.
   ====================================================================== */
:root {
  --chart-1: #9C3B52;   /* revenue / primary magnitude */
  --chart-2: #B5821A;   /* expenses */
  --chart-grid: #EADFD5;
}

.chart { width: 100%; }
.chart svg { display: block; overflow: visible; }

.chart-grid { stroke: var(--chart-grid); stroke-width: 1; }
.chart-rule { stroke: var(--line); stroke-width: 1; }
.chart-axis { fill: var(--muted); font-size: 10px; font-family: inherit; }

.chart-empty {
  padding: 2rem 1rem;
  text-align: center;
  color: var(--muted);
  font-size: .88rem;
  font-style: italic;
}

.chart-tip {
  position: fixed;
  z-index: 10001;
  pointer-events: none;
  background: var(--plum);
  color: var(--white);
  border-radius: var(--radius-sm);
  padding: .5rem .65rem;
  font-size: .8rem;
  line-height: 1.45;
  box-shadow: var(--shadow);
  max-width: 16rem;
}
.chart-tip strong { display: block; margin-bottom: .2rem; color: var(--gold-soft); }
.chart-tip__row { display: flex; align-items: center; gap: .4rem; }
.chart-tip__row i { width: 8px; height: 8px; border-radius: 2px; flex-shrink: 0; }

/* Ranked bars. One hue for every bar — length is the encoding. */
.barlist { display: grid; gap: .55rem; }

.barlist__row {
  display: grid;
  grid-template-columns: minmax(6rem, 11rem) 1fr auto;
  align-items: center;
  gap: .75rem;
}

.barlist__label {
  font-size: .88rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.barlist__track { background: rgba(220, 199, 184, .28); border-radius: 4px; height: 18px; }

.barlist__bar {
  height: 100%;
  /* Square where it meets the baseline, rounded at the data end. */
  border-radius: 0 4px 4px 0;
  min-width: 3px;
  transition: width .25s ease;
}

.barlist__value {
  font-size: .86rem;
  color: var(--plum);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

@media (max-width: 620px) {
  .barlist__row { grid-template-columns: minmax(5rem, 8rem) 1fr auto; }
}

/* --------------------------------------------------------- page rhythm -- */
/* Reports and the dashboard were a stack of stat rows with inconsistent gaps.
   One grid, one gap, sections that announce themselves. */
/* Fixed counts rather than auto-fit: auto-fit left a single orphan tile on a
   second row at common widths, which reads as a mistake. */
.kpi-row {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 1rem;
}

@media (max-width: 1180px) {
  .kpi-row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 560px) {
  .kpi-row { grid-template-columns: 1fr; }
}

.section { display: grid; gap: .85rem; margin-top: 1.75rem; }
.section:first-child { margin-top: 0; }

.section__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
}

.section__head h2 {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-size: 1.3rem;
  color: var(--plum);
}

.section__note { font-size: .8rem; color: var(--muted); }

.hero-figure {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-size: clamp(2.4rem, 5vw, 3.2rem);
  line-height: 1.05;
  color: var(--plum);
}

.delta { font-size: .85rem; display: inline-flex; align-items: center; gap: .3rem; }
.delta--up { color: var(--ok); }
.delta--down { color: var(--danger); }
.delta--flat { color: var(--muted); }

/* A panel whose content is charts and figures rather than a list, so it needs
   its own padding — the list panels get theirs from .list__row. */
.panel--pad { padding: 1.15rem 1.25rem 1.35rem; }
.panel--pad .chart { margin-top: .9rem; }
.panel--pad .stat__label + .hero-figure { margin-top: .15rem; }

.chart-legend {
  display: flex;
  flex-wrap: wrap;
  gap: .25rem 1rem;
  margin-bottom: .5rem;
  font-size: .82rem;
  color: var(--muted);
}
.chart-legend__item { display: inline-flex; align-items: center; gap: .4rem; }
.chart-legend__item i { width: 10px; height: 3px; border-radius: 2px; }

/* ---------------------------------------------------------- danger zone -- */
.danger-zone {
  margin-top: 2.5rem;
  padding: 1.25rem 1.35rem 1.4rem;
  border: 1px solid rgba(168, 50, 74, .3);
  border-radius: var(--radius);
  background: rgba(168, 50, 74, .03);
}

.danger-zone .section-title { margin-top: 0; color: var(--danger); }

.danger-zone__row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1.25rem;
  padding: .9rem 0;
  border-top: 1px solid rgba(168, 50, 74, .18);
}

.danger-zone__row > div { flex: 1; }
.danger-zone__row .hint { max-width: 46ch; }
.danger-zone__title { font-weight: 500; color: var(--plum); margin-bottom: .15rem; }

/* An outlined danger button. Distinct from .btn--danger, which is the solid
   one — reusing that name here made rose text sit on a rose fill. */
.btn--danger-outline {
  background: transparent;
  border-color: rgba(168, 50, 74, .45);
  color: var(--danger);
}
.btn--danger-outline:hover:not(:disabled) {
  background: rgba(168, 50, 74, .08);
  border-color: var(--danger);
}

.danger-list {
  margin: .4rem 0 .8rem;
  padding-left: 1.1rem;
  font-size: .9rem;
  color: var(--plum);
}
.danger-list li { margin: .15rem 0; }

@media (max-width: 620px) {
  .danger-zone__row { flex-direction: column; align-items: stretch; }
}

/* ------------------------------------------------------ product combobox -- */
.combo { position: relative; flex: 1; min-width: 0; }
.combo .input { width: 100%; }

.combo__list {
  position: absolute;
  z-index: 30;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  margin: 0;
  padding: .25rem;
  list-style: none;
  max-height: 15rem;
  overflow-y: auto;
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow);
}

.combo__item {
  display: grid;
  gap: .1rem;
  padding: .45rem .55rem;
  border-radius: 6px;
  cursor: pointer;
  font-size: .9rem;
}
.combo__item:hover,
.combo__item.is-active { background: rgba(240, 220, 209, .5); }
.combo__item.is-out { opacity: .55; }
.combo__meta { font-size: .78rem; color: var(--muted); }
.combo__empty { padding: .6rem .55rem; color: var(--muted); font-size: .88rem; font-style: italic; }

.login__by {
  margin-top: .5rem;
  text-align: center;
  font-size: .74rem;
  letter-spacing: .06em;
  color: var(--muted);
}
.login__by strong { color: var(--gold-text); font-weight: 500; }

/* --------------------------------------------------- cash on delivery -- */
.cod { border-color: rgba(176, 141, 87, .5); }
.cod .panel__head { background: rgba(216, 189, 142, .14); }

.cod__total {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-size: 1.5rem;
  color: var(--plum);
}

/* The whole row is the target, not just a link inside it — a figure worth
   chasing should not need a precise tap. */
.cod__row { cursor: pointer; transition: background .14s ease; }
.cod__row:hover,
.cod__row:focus-visible { background: rgba(240, 220, 209, .35); }

.cod__note {
  padding: .85rem 1.15rem 1rem;
  font-size: .8rem;
  color: var(--muted);
  border-top: 1px solid var(--line);
}

/* A stat tile that navigates. It is a <button>, so the browser's own defaults
   have to be undone before it looks like the tiles beside it. */
.stat--link {
  width: 100%;
  text-align: left;
  font: inherit;
  cursor: pointer;
  color: inherit;
}
.stat--link:hover {
  border-color: var(--gold);
  box-shadow: 0 4px 16px rgba(42, 20, 32, .1);
}
.stat--link:hover .stat__arrow { transform: translateX(2px); }

.stat__arrow {
  display: inline-block;
  color: var(--rose);
  transition: transform .16s ease;
}

/* List rows that open something. */
.list__row--link { cursor: pointer; transition: background .14s ease; }
.list__row--link:hover,
.list__row--link:focus-visible { background: rgba(240, 220, 209, .3); }

.chip--pay {
  background: rgba(176, 141, 87, .14);
  color: var(--gold-text);
  border: 1px solid rgba(176, 141, 87, .3);
  white-space: nowrap;
}

/* ------------------------------------------------------- photo guide -- */
.photo-guide { max-width: 52ch; }

.photo-check {
  margin-top: .35rem;
  font-size: .82rem;
  padding: .35rem .55rem;
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
}
.photo-check--ok { color: var(--ok); background: rgba(74, 124, 89, .08); border-color: rgba(74, 124, 89, .25); }
.photo-check--warn { color: var(--warn); background: rgba(184, 121, 31, .08); border-color: rgba(184, 121, 31, .3); }
.photo-check--bad { color: var(--danger); background: rgba(168, 50, 74, .08); border-color: rgba(168, 50, 74, .3); }

/* ----------------------------------------------------------- restocking -- */
.restock-now {
  display: flex;
  gap: 2rem;
  padding: .8rem 1rem;
  margin-bottom: 1rem;
  background: rgba(240, 220, 209, .35);
  border-radius: var(--radius-sm);
}

.restock-preview {
  margin-top: 1rem;
  padding: .7rem .85rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
  background: var(--ivory);
  font-size: .88rem;
  color: var(--muted);
}
.restock-preview--up { border-color: rgba(184, 121, 31, .4); background: rgba(184, 121, 31, .07); color: var(--warn); }
.restock-preview--down { border-color: rgba(74, 124, 89, .4); background: rgba(74, 124, 89, .07); color: var(--ok); }

.cost-move { white-space: nowrap; font-size: .86rem; color: var(--muted); }
.cost-move strong { color: var(--plum); }
.cost-move .cell-meta { display: block; }
.cost-move--up strong { color: var(--warn); }
.cost-move--down strong { color: var(--ok); }

/* The restock table carries six columns of mostly-short values; only the
   product name earns the leftover width. */
.table--restocks td,
.table--restocks th { white-space: nowrap; }
.table--restocks td:nth-child(2) { white-space: normal; width: 100%; min-width: 8.5rem; }

.table--restocks .cell-notes {
  white-space: normal;
  min-width: 7rem;
  font-size: .88rem;
}
.table--restocks .cell-notes .cell-meta { display: block; }
.qty-in { color: var(--ok); }
.table--restocks .num .cell-meta { display: block; font-weight: 400; }

/* Product images are contained, not cropped: a perfume bottle is tall, and
   filling a square box with one cuts off either the cap or the base. The box
   stays square so the grid keeps its rhythm; the photo sits inside it whole. */

/* --------------------------------------------------- product photo edit -- */
.photo-current {
  display: flex;
  align-items: center;
  gap: .85rem;
  padding: .6rem;
  margin-bottom: .6rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--white);
}
.photo-current img {
  width: 64px;
  height: 64px;
  object-fit: contain;
  border-radius: var(--radius-sm);
  flex-shrink: 0;
  background: var(--white);
  border: 1px solid var(--line);
}
.photo-current__label {
  font-size: .8rem;
  color: var(--muted);
  margin-bottom: .1rem;
}
.link-btn--danger { color: var(--danger); }
.photo-picker { display: block; }
[data-photo-removed] { display: flex; gap: .5rem; align-items: baseline; flex-wrap: wrap; }

/* Send and Print sit together in the order's header, since the row now offers
   a single Open rather than three competing links. */
.detail-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem;
}

/* Eight columns of short values plus one list of item names. Only the item
   names may grow, and they truncate rather than stacking into a tower that
   makes every row four lines tall. */
.table--orders td,
.table--orders th { white-space: nowrap; }
/* Customer holds its name on one line; Items takes whatever is left and is the
   column allowed to grow, since it is the one with something to say. Both
   truncate rather than wrap, so every row is the same height however long a
   product name runs. */
.table--orders .cell-clip {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 9rem;
  color: var(--plum);
}

/* Not width:100%. On a table that already overflows, telling one column it
   wants the full width makes it take 309px and push the status and the action
   off the edge — the same trap this column fell into when it held item names
   before. A max-width plus truncation lets it use the slack without demanding
   more than exists. */
.table--orders .cell-items { min-width: 8rem; max-width: 12rem; }

.cell-line {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--body);
}

.table--orders .status-select { min-width: 5.75rem; }

.table--orders .num .cell-meta { display: block; font-weight: 400; margin-top: .15rem; }

/* A payment chip is a label, not a heading — smaller than the total it sits
   under, so a long method like "Cash on delivery" does not set the column's
   width. */
.table .chip--pay { font-size: .72rem; padding: .15rem .5rem; }

/* A chip is a label: it wraps to two lines only if the column is genuinely too
   narrow for it, and when it does the row grows and the table loses its rhythm.
   Keep them on one line and let the column take the width it needs. */
.table .chip,
.table .tag { white-space: nowrap; }

/* The items box sits between two form fields, so its empty state should start
   on the same left edge as the labels above and below it, not indented by the
   padding a panel would normally give it. */
.line-builder .panel__empty { padding-left: 0; padding-right: 0; }

/* Section labels inside a form get the same air as a field, so a form does not
   tighten up wherever it stops being a grid of inputs. */
.line-builder { display: grid; gap: var(--s2); }

/* --------------------------------------------------- sortable headers -- */
.th-sort {
  display: inline-flex;
  align-items: baseline;
  gap: .35rem;
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  color: inherit;
  cursor: pointer;
  white-space: nowrap;
}

.th-sort:hover { color: var(--rose); }
.th-sort.is-active { color: var(--plum); }

/* The mark holds its width whether or not this column is the sorted one, so
   headers do not shift sideways as you click between them. */
.th-sort__mark {
  display: inline-block;
  min-width: .7em;
  font-size: .9em;
  color: var(--rose);
}

.num .th-sort { flex-direction: row-reverse; }

/* ------------------------------------------------------------- density -- */
/* Compact trades vertical air for rows on screen — roughly a third more of
   them — and nothing else. Type size, colour and column padding are unchanged,
   so a compact table is the same table, closer together. */
:root.is-compact {
  --cell-y: .45rem;
  /* Enough off the sides to bring a six-column table back inside a laptop
     screen, without the columns touching: .8rem still leaves a clear 1.6rem
     between one column's text and the next. */
  --cell-x: .8rem;
  --s5: 1.1rem;
}

:root.is-compact .table { font-size: .88rem; }
:root.is-compact .cell-meta { font-size: .76rem; }
:root.is-compact .thumb { width: 30px; height: 30px; }
:root.is-compact .view { gap: var(--s4); }

.density {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  padding: .35rem .7rem .35rem .5rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--white);
  color: var(--muted);
  font-size: .78rem;
  letter-spacing: .04em;
  cursor: pointer;
  transition: border-color .16s ease, color .16s ease;
}

.density:hover { border-color: var(--gold-soft); color: var(--plum); }

/* Two bars for comfortable, three for compact — the control shows what it
   does rather than relying on the word alone. */
.density__mark {
  width: 14px;
  height: 12px;
  display: grid;
  gap: 3px;
  align-content: center;
}
.density__mark::before,
.density__mark::after {
  content: "";
  height: 2px;
  border-radius: 1px;
  background: currentColor;
}
:root.is-compact .density__mark { gap: 2px; }
:root.is-compact .density__mark::before { box-shadow: 0 4px 0 currentColor; }

@media (max-width: 620px) {
  .density span:last-child { display: none; }
  .density { padding: .35rem .5rem; }
}

/* ---------------------------------------------------------- pagination -- */
.pager {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3) var(--s4);
  flex-wrap: wrap;
  margin-top: var(--s3);
  font-size: .85rem;
  color: var(--muted);
}

.pager__count strong { color: var(--plum); font-weight: 500; }

.pager__controls {
  display: flex;
  align-items: center;
  gap: var(--s2);
  margin-left: auto;
}

.pager__pos { white-space: nowrap; font-variant-numeric: lining-nums tabular-nums; }

/* The row-count select is a setting, not a filter, so it stays quieter than the
   controls in the toolbar above the table. */
.pager__size .input {
  min-height: 2.1rem;
  padding: .25rem 1.6rem .25rem .6rem;
  font-size: .82rem;
  box-shadow: none;
}

.btn--sm { padding: .35rem .8rem; font-size: .82rem; min-height: 2.1rem; }

/* The window the orders query fetched. Quiet, but always present when a range
   is in force — a search that silently covers only part of the records is the
   one thing this feature could get badly wrong. */
.scope-note {
  margin-top: var(--s2);
  font-size: .8rem;
}

/* Every date column, in every table: the date holds one line and its time or
   relative stamp sits underneath, rather than the whole thing wrapping mid
   month and making one row twice the height of its neighbours. */
.table .cell-when {
  white-space: nowrap;
  font-variant-numeric: lining-nums tabular-nums;
}

/* The login card's mark is larger than the sidebar's, and an uploaded logo is
   contained rather than cropped — a wordmark is usually wide, and filling a
   square with one clips its ends. */
/* The login card has room the sidebar does not, and it is the first thing a
   shop sees of its own app. */
.brandmark__mark--lg img {
  height: 46px;
  width: auto;
  max-width: 170px;
}

/* The default mark: the shop's initial, drawn by ui.js whenever no logo is
   set. The markup ships this empty so a clone carries no other shop's brand. */
.brandmark__letter {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 8px;
  background: var(--gold-soft);
  color: var(--plum);
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-size: 1.2rem;
}
.brandmark__mark--lg .brandmark__letter { width: 40px; height: 40px; font-size: 1.4rem; }

/* Inverted on the login card, which sits on light ground — the sidebar's gold
   tile would wash out there, so the plum one carries the mark instead. */
.login .brandmark__letter { background: var(--plum); color: var(--gold-soft); }

/* The CSV picker names the dataset the button will download, so "Download CSV"
   never means "some arrangement of everything". */
/* The report picker is labelled in the open, not just to a screen reader: it
   drives both buttons beside it, and a bare dropdown between two exports reads
   as belonging to whichever one you press. */
.report-picker {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  font-size: .78rem;
  letter-spacing: .04em;
  color: var(--muted);
}
.report-picker .input {
  min-height: var(--control-h);
  font-size: .85rem;
  max-width: 16rem;
}

/* ---------------------------------------------------------------- ornament -- */
.ornament { color: var(--gold-soft); opacity: .85; }

.rule-orn { display: flex; align-items: center; gap: .6rem; }
.rule-orn i { flex: 1; height: 1px; background: currentColor; opacity: .5; }
.rule-orn svg { flex: none; }

.login__rule { margin: 1.25rem 0 .25rem; color: var(--gold-soft); }

/* The empty state's motif: present enough to make the panel feel considered,
   quiet enough that the sentence under it is still the thing you read. */
.empty .ornament {
  color: var(--gold-soft);
  opacity: .55;
  margin-bottom: .35rem;
}

/* Section headings carry a diamond and a hairline that fades as it runs out.
   It is the smallest ornament that still does a job — the eye gets a rule to
   separate one block of the page from the next, and the diamond keeps it from
   reading as a plain border. */
.section-title,
.section__head h2 {
  display: flex;
  align-items: center;
  gap: .8rem;
  flex: 1;
  min-width: 0;
}

.section-title::after,
.section__head h2::after {
  content: "";
  flex: 1;
  min-width: 2rem;
  height: 12px;
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath d='M6 1.5 L10.5 6 L6 10.5 L1.5 6 Z' fill='none' stroke='%23B08D57' stroke-width='1'/%3E%3C/svg%3E")
      no-repeat left center / 11px 11px,
    linear-gradient(to right, var(--line), transparent)
      no-repeat 17px center / calc(100% - 17px) 1px;
  opacity: .75;
}
