/* ============================================================================
   JustKnits — "Mill" redesign theme  (ported from the Claude Design handoff
   assets/theme.css + assets/swatch.css)
   ----------------------------------------------------------------------------
   A warm, editorial operations system. Parchment surfaces, ink + terracotta +
   pine palette pulled from the yarn-swatch tones, Spectral display serif over a
   Hanken Grotesk UI grotesk. Reuses the knit-swatch texture + the existing
   censor mechanic (.jk-censored / .jk-money — see accounting-censor.js).

   Loaded globally from base.html (after base.css so Mill tokens win). Component
   classes are authored bare (.btn/.card/.pill/.field…) exactly as the prototype
   so templates read like the design source.
   ============================================================================ */

:root {
  /* ---- Surfaces (warm neutrals) ---- */
  --paper:        #F4F1EA;   /* app background — warm parchment */
  --paper-2:      #EDE8DC;   /* sunken wells, rails */
  --surface:      #FCFAF4;   /* cards, panels — paperwhite */
  --surface-2:    #FBF9F4;   /* tinted surface, table head */
  --border:       #E5DFD1;   /* hairline */
  --border-2:     #D8D0BD;   /* stronger / inputs */

  /* ---- Ink ramp (warm near-blacks) ---- */
  --ink:          #211C16;   /* headings, primary text */
  --ink-2:        #514A3E;   /* body */
  --ink-3:        #837A69;   /* muted labels */
  --ink-4:        #A89E89;   /* faint meta, placeholder */

  /* ---- Brand accent: terracotta (knit-clay) ---- */
  --clay:         #B0492B;
  --clay-hover:   #97391F;
  --clay-50:      #FBEDE6;
  --clay-100:     #F4D8CA;
  --clay-700:     #7E3019;

  /* ---- Semantic (warmed) ---- */
  --pine:         #2F6B4F;   /* revenue / positive / in-stock */
  --pine-50:      #E5EFE8;
  --pine-100:     #CFE4D5;
  --pine-700:     #1F4F39;

  --brick:        #C13A37;   /* danger / negative / sale tag */
  --brick-50:     #FBE9E7;
  --brick-100:    #F5D2CE;
  --brick-700:    #8F2A28;

  --ochre:        #C0871A;   /* caution / low-stock */
  --ochre-50:     #F8EFD7;
  --ochre-100:    #EFDFB3;
  --ochre-700:    #8A5E0E;

  --plum:         #6D4A8A;   /* admin / re-orders */
  --plum-50:      #EFE8F3;
  --plum-100:     #DFD0E6;
  --plum-700:     #4E3266;

  --slate:        #3E5C7E;   /* info / calendar */
  --slate-50:     #E7ECF2;
  --slate-100:    #CFDAE6;

  /* ---- Radii ---- */
  --r-sm:  6px;
  --r:     10px;
  --r-lg:  14px;
  --r-xl:  20px;
  --r-pill: 999px;

  /* ---- Shadows (warm, low) ---- */
  --sh-sm: 0 1px 2px rgba(60,48,30,.06);
  --sh:    0 1px 3px rgba(60,48,30,.08), 0 1px 2px rgba(60,48,30,.05);
  --sh-md: 0 6px 16px -6px rgba(60,48,30,.16), 0 2px 6px rgba(60,48,30,.06);
  --sh-lg: 0 18px 40px -12px rgba(50,40,24,.26), 0 6px 14px rgba(50,40,24,.08);

  /* ---- Motion ---- */
  --ease:       cubic-bezier(.22,.61,.36,1);
  --ease-press: cubic-bezier(.34,1.4,.5,1.01);
  --dur-fast: .16s;
  --dur:      .28s;

  /* ---- Type ---- */
  --font-ui:      'Hanken Grotesk', ui-sans-serif, system-ui, -apple-system, sans-serif;
  --font-display: 'Spectral', Georgia, 'Times New Roman', serif;
  --font-mono:    'Spectral', ui-monospace, monospace;
}

/* ============================ Base ============================ */
.jk-mill,
.jk-mill * { box-sizing: border-box; }
body.jk-mill {
  margin: 0;
  font-family: var(--font-ui);
  background: var(--paper);
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  font-feature-settings: "tnum" 0;
}
.font-display { font-family: var(--font-display); font-weight: 600; letter-spacing: -.01em; }
.tnum { font-variant-numeric: tabular-nums; }
.font-mono { font-family: var(--font-mono); }

/* Eyebrow / uppercase label */
.eyebrow {
  font-size: 11px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .12em; color: var(--ink-3);
}

.jk-mill ::selection { background: var(--clay-100); color: var(--clay-700); }

/* Focus ring */
.jk-mill .focusable:focus-visible,
.jk-mill input:focus-visible, .jk-mill select:focus-visible,
.jk-mill textarea:focus-visible, .jk-mill button:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px var(--clay-50), 0 0 0 1px var(--clay);
}

/* ============================ Scrollbars ============================ */
.thin-scroll::-webkit-scrollbar { height: 8px; width: 8px; }
.thin-scroll::-webkit-scrollbar-thumb { background: var(--border-2); border-radius: 99px; }
.thin-scroll::-webkit-scrollbar-track { background: transparent; }

/* ============================ Buttons ============================ */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  font-family: var(--font-ui); font-weight: 600; font-size: 14px;
  border-radius: var(--r); border: 1px solid transparent; cursor: pointer;
  padding: 9px 16px; transition: background var(--dur-fast) var(--ease),
    border-color var(--dur-fast), color var(--dur-fast), transform var(--dur-fast) var(--ease-press), box-shadow var(--dur-fast);
  white-space: nowrap; user-select: none; line-height: 1.1; text-decoration: none;
}
.btn:active { transform: scale(.97); }
.btn-primary { background: var(--clay); color: #fff; box-shadow: var(--sh-sm); }
.btn-primary:hover { background: var(--clay-hover); color: #fff; }
.btn-ink { background: var(--ink); color: var(--paper); }
.btn-ink:hover { background: #34291c; color: var(--paper); }
.btn-danger { background: var(--brick); color: #fff; box-shadow: var(--sh-sm); }
.btn-danger:hover { background: var(--brick-700); color: #fff; }
.btn-ghost { background: var(--surface); color: var(--ink-2); border-color: var(--border-2); box-shadow: var(--sh-sm); }
.btn-ghost:hover { background: var(--surface-2); border-color: var(--ink-4); color: var(--ink-2); }
.btn-outline { background: var(--surface); color: var(--clay-700); border-color: var(--clay); box-shadow: var(--sh-sm); }
.btn-outline:hover { background: var(--clay-50); color: var(--clay-700); }
.btn-quiet { background: transparent; color: var(--ink-2); }
.btn-quiet:hover { background: var(--paper-2); color: var(--ink-2); }
.btn-sm { padding: 6px 12px; font-size: 13px; border-radius: var(--r-sm); }
.btn-lg { padding: 12px 22px; font-size: 15px; }
.btn-block { width: 100%; }
.btn:disabled { opacity: .5; cursor: not-allowed; }

/* icon press */
.press { transition: transform var(--dur-fast) var(--ease-press), background var(--dur-fast), color var(--dur-fast); }
.press:active { transform: scale(.9); }

/* ============================ Cards ============================ */
.card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); box-shadow: var(--sh);
}
.card-hover { transition: box-shadow var(--dur) var(--ease), transform var(--dur) var(--ease), border-color var(--dur); }
.card-hover:hover { box-shadow: var(--sh-md); border-color: var(--border-2); }

/* ============================ Pills / chips ============================ */
.pill {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; font-weight: 600; padding: 3px 10px; border-radius: var(--r-pill);
  line-height: 1.4; white-space: nowrap;
}
.dot { width: 6px; height: 6px; border-radius: 99px; flex: none; }

.chip {
  display: inline-flex; align-items: center; gap: 6px; white-space: nowrap;
  font-size: 13px; font-weight: 600; padding: 7px 14px; border-radius: var(--r-pill);
  border: 1px solid var(--border-2); background: var(--surface); color: var(--ink-2);
  cursor: pointer; transition: all var(--dur-fast) var(--ease); text-decoration: none;
}
.chip:hover { border-color: var(--ink-4); }
.chip.is-active { background: var(--ink); color: var(--paper); border-color: var(--ink); }

/* ============================ Inputs ============================ */
.field {
  width: 100%; font-family: var(--font-ui); font-size: 14px; color: var(--ink);
  background: var(--surface); border: 1px solid var(--border-2); border-radius: var(--r);
  padding: 10px 13px; transition: box-shadow var(--dur-fast), border-color var(--dur-fast);
}
.field::placeholder { color: var(--ink-4); }
.field:focus { outline: none; border-color: var(--clay); box-shadow: 0 0 0 3px var(--clay-50); }
.select {
  appearance: none; -webkit-appearance: none; cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23837A69' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 11px center; padding-right: 36px;
}
/* A `.select` inside a `.jk-fields` wrapper: the wrapper's `background` shorthand (specificity
   0,1,1) would otherwise wipe `.select`'s chevron image and override its padding-right. Re-assert
   them at `.jk-fields select.select` (0,2,1). `appearance:none` still comes from `.select`, so the
   native arrow stays hidden. Opt-in — only affects selects that carry the `.select` class. */
.jk-fields select.select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23837A69' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 11px center; padding-right: 34px;
}

/* qty stepper */
.stepper { display: inline-flex; align-items: stretch; border: 1px solid var(--border-2); border-radius: var(--r); overflow: hidden; background: var(--surface); }
.stepper button { width: 32px; display: grid; place-items: center; color: var(--ink-2); background: transparent; border: none; cursor: pointer; }
.stepper button:hover { background: var(--surface-2); }
.stepper input { width: 40px; border: none; border-left: 1px solid var(--border); border-right: 1px solid var(--border); text-align: center; font-weight: 600; font-size: 14px; color: var(--ink); font-family: var(--font-ui); }
.stepper input:focus { outline: none; background: var(--clay-50); }

/* ============================ Tables ============================ */
.th {
  font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .08em;
  color: var(--ink-3); text-align: center; padding: 10px 14px; white-space: nowrap;
}
.trow { transition: background var(--dur-fast); }
.trow:hover { background: var(--surface-2); }
/* Row cells: content sits in the center of the cell, both axes (mirrors .th).
   Scoped to .jk-mill (the <body> class from base.html) so standalone print/PDF
   documents keep their own layout. Specificity (0,1,2) intentionally beats
   per-cell text-left/right utilities (0,1,0). */
.jk-mill table td { text-align: center; vertical-align: middle; }
/* Block-level flex wrappers directly inside cells ignore the cell's text-align —
   center them too. Deeper flexes need no help: their wrappers are inline-flex
   (centered by text-align) or content-sized flex items. .justify-between is
   spared: it spans the cell on purpose. */
.jk-mill table td > .flex:not(.justify-between) { justify-content: center; }
/* Documents printed from inside the app shell (e.g. the D.D.T. transport
   document) opt out of the centered-cell default: their layout tables read as
   classic left-aligned paper forms. Wrap the document in .jk-doc-flow. */
.jk-mill .jk-doc-flow table td { text-align: left; vertical-align: middle; }

/* ---- Mobile table density (≤640px) ----
   The tables that still scroll horizontally on a phone — the .jk-no-stack editor
   tables — get tighter cell padding + typography here (plus momentum scrolling) so
   more fits at once. Read-only list tables instead collapse into labeled cards (see
   the ≤900px block below), so this density no longer applies to them. .jk-table-wrap
   / .overflow-x-auto are the reusable horizontal-scroll containers. */
.jk-table-wrap { width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; }
.jk-mill .overflow-x-auto { -webkit-overflow-scrolling: touch; }
@media (max-width: 640px) {
  .jk-mill table.jk-no-stack { font-size: 12px; }
  .jk-mill table.jk-no-stack .th { padding: 7px 9px; font-size: 10px; letter-spacing: .04em; }
  .jk-mill table.jk-no-stack td { padding: 7px 9px; }
}

/* ---- Mobile: stack wide tables into labeled cards (≤900px) ----
   Below 900px every read-only list table collapses from a horizontally-scrolling
   grid into a vertical stack of cards: <thead> is hidden and each tbody/tfoot row
   becomes a card whose cells are "LABEL  value" rows (mirroring the .kv-row idiom).
   Column labels come from data-label="…" written by mobile-tables.js, which also
   wraps each labeled cell's content in .jk-cellval so multi-child cells (e.g. name
   + barcode) stay tidy. Rows the labeler skips (colspan totals / empty-state /
   header-less tables) fall back to plain centered blocks. Result: every column is
   readable with no horizontal scroll. Desktop (≥901px) is untouched. Opt out with
   .jk-no-stack — the interactive editor tables and the .jk-doc-flow transport
   document both carry it, so this never touches a print/paper layout. NOTE: do NOT
   add a blanket `.overflow-x-auto { overflow-x: visible }` here — that class is the
   horizontal scroller for every sub-nav and the shop category row. */
.jk-only-stacked { display: none !important; }   /* shown only inside the ≤900px block */
@media (max-width: 900px) {
  .jk-mill table:not(.jk-no-stack) { display: block; width: 100%; min-width: 0 !important; }
  .jk-mill table:not(.jk-no-stack) > thead { display: none; }
  .jk-mill table:not(.jk-no-stack) > tbody,
  .jk-mill table:not(.jk-no-stack) > tfoot { display: block; }

  .jk-mill table:not(.jk-no-stack) > tbody > tr,
  .jk-mill table:not(.jk-no-stack) > tfoot > tr {
    display: block; margin: 0 0 10px; padding: 2px 12px;
    border: 1px solid var(--border); border-radius: var(--r);
    background: var(--surface); box-shadow: var(--sh-sm);
  }
  .jk-mill table:not(.jk-no-stack) > tbody > tr:last-child,
  .jk-mill table:not(.jk-no-stack) > tfoot > tr:last-child { margin-bottom: 0; }

  /* base cell: a plain centered block. Rows the labeler skips (colspan totals,
     empty-state, header-less tables) keep this and read as simple stacked lines. */
  .jk-mill table:not(.jk-no-stack) > tbody > tr > td,
  .jk-mill table:not(.jk-no-stack) > tfoot > tr > td {
    display: block; text-align: center; padding: 9px 0 !important;
    border: 0 !important; border-bottom: 1px solid var(--border) !important;
    white-space: normal; font-size: 13.5px;
  }
  .jk-mill table:not(.jk-no-stack) > tbody > tr > td:last-child,
  .jk-mill table:not(.jk-no-stack) > tfoot > tr > td:last-child { border-bottom: 0 !important; }
  /* drop empty placeholder cells (common in colspan totals rows) */
  .jk-mill table:not(.jk-no-stack) > tbody > tr > td:empty,
  .jk-mill table:not(.jk-no-stack) > tfoot > tr > td:empty { display: none; }

  /* labeled cells become "LABEL : value" rows (label left, value right) */
  .jk-mill table:not(.jk-no-stack) > tbody > tr > td[data-label],
  .jk-mill table:not(.jk-no-stack) > tfoot > tr > td[data-label] {
    display: flex; align-items: flex-start; justify-content: space-between;
    gap: 16px; text-align: right;
  }
  .jk-mill table:not(.jk-no-stack) > tbody > tr > td[data-label]::before,
  .jk-mill table:not(.jk-no-stack) > tfoot > tr > td[data-label]::before {
    content: attr(data-label); flex: 0 0 auto; text-align: left; padding-top: 1px;
    font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
    color: var(--ink-3); white-space: nowrap;
  }
  /* checkbox / icon-only columns have an empty header → no label chip */
  .jk-mill table:not(.jk-no-stack) > tbody > tr > td[data-label=""]::before,
  .jk-mill table:not(.jk-no-stack) > tfoot > tr > td[data-label=""]::before { content: none; }

  /* value wrapper (added by mobile-tables.js): stacks a cell's content right-aligned
     so multi-child cells aren't torn to opposite edges by space-between. min-width:0
     + overflow-wrap let a long unbreakable value (long names, tokens) break instead
     of spilling over the label. */
  .jk-mill table:not(.jk-no-stack) .jk-cellval {
    display: flex; flex-direction: column; align-items: flex-end; gap: 2px;
    min-width: 0; text-align: right;
    white-space: normal; overflow-wrap: anywhere; word-break: break-word;
  }

  .jk-mill .jk-only-stacked { display: inline-flex !important; }   /* mobile-only controls */
}
/* .jk-doc-flow paper documents (transport_document) never stack: their tables carry
   .jk-no-stack in the template, and mobile-tables.js also tags any .jk-doc-flow table
   .jk-no-stack at mobile width — so the cell rules above never touch their inline
   borders/padding. (A CSS revert can't restore inline styles past the !important
   cell rules, hence the class-based opt-out instead.) */

/* ============================ Censor (hide figures) ============================
   Reuses the app's existing mechanic: accounting-censor.js toggles .jk-censored
   on #jkRoot and .revealed on individual .jk-money spans. We restyle the blur. */
/* padding enlarges the hover/click hit area (~matching the 7px blur bleed) so the
   cursor needn't be pixel-perfect on the text; the equal negative margin keeps
   layout unchanged (horizontal cancels exactly; inline boxes ignore the vertical
   margin, but the small vertical padding doesn't grow the line box). */
.jk-censored .jk-money { filter: blur(7px); cursor: pointer; user-select: none; border-radius: 4px; padding: 0.2em 0.5em; margin: -0.2em -0.5em; }
/* Once a figure is revealed (click-to-reveal, or "Show amounts" off), it must be
   selectable so prices/costs can be copied — the blur rule above kills user-select. */
.jk-censored .jk-money.revealed { filter: none; user-select: text; cursor: auto; }
/* Hover-to-peek: on pointer devices, moving the cursor over a fogged figure
   reveals it transiently (no click needed); it re-fogs on mouse-out. Click still
   toggles a persistent reveal. Guarded to (hover: hover) so touch taps keep the
   click-to-toggle behaviour instead of a sticky hover. Loaded after output.css so
   this full reveal wins over that layer's partial-blur hover rule. opacity:1 is
   set explicitly so the reveal is self-contained (not reliant on output.css). */
@media (hover: hover) {
  .jk-censored .jk-money:hover { filter: none; opacity: 1; user-select: text; }
  .censored .money:hover { filter: none; opacity: 1; user-select: text; }
}
/* Keyboard parity: reveal a fogged figure when a link/control inside it gains
   focus, so tab users can read what they're about to activate (hover is mouse-
   only). Not gated on (hover: hover) — keyboard focus applies on every device. */
.jk-censored .jk-money:focus-within { filter: none; opacity: 1; user-select: text; }
.censored .money:focus-within { filter: none; opacity: 1; user-select: text; }
.jk-money { transition: none; }
/* prototype-native aliases (bare .money inside .censored) */
.censored .money { filter: blur(7px); cursor: pointer; user-select: none; border-radius: 4px; padding: 0.2em 0.5em; margin: -0.2em -0.5em; }
.censored .money.revealed { filter: none; user-select: text; cursor: auto; }

/* ============================ Avatars ============================ */
.avatar { border-radius: 999px; display: grid; place-items: center; font-weight: 700; flex: none; letter-spacing: .01em; }

/* ============================ Motion ============================ */
@keyframes jk-view-in { from { transform: translateY(8px); } to { transform: none; } }
.view-in { animation: jk-view-in var(--dur) var(--ease); }
@keyframes jk-reveal-up { from { transform: translateY(12px); } to { transform: none; } }
@keyframes jk-pop { 0% { transform: scale(.4); opacity: 0; } 60% { transform: scale(1.12); } 100% { transform: scale(1); opacity: 1; } }
.pop { animation: jk-pop .42s var(--ease-press) both; }
@keyframes jk-spin { to { transform: rotate(360deg); } }
.spin { animation: jk-spin .7s linear infinite; }
@keyframes jk-toast-in { from { opacity: 0; transform: translateX(24px); } to { opacity: 1; transform: none; } }
.toast-in { animation: jk-toast-in .3s var(--ease) both; }

/* staggered card reveal — visible state is the base style (print/reduced-motion safe) */
.stagger > * { animation: jk-reveal-up .5s var(--ease); }

@media (prefers-reduced-motion: reduce) {
  .jk-mill *, .jk-mill *::before, .jk-mill *::after { animation-duration: .001ms !important; animation-delay: 0ms !important; transition-duration: .001ms !important; }
}

/* ============================ Sticky frosted bars ============================ */
.glass { background: color-mix(in srgb, var(--paper) 78%, transparent); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); }

/* hairline divider */
.hr { height: 1px; background: var(--border); border: 0; }

/* link */
.link { color: var(--clay); font-weight: 600; cursor: pointer; }
.link:hover { color: var(--clay-hover); text-decoration: underline; text-underline-offset: 2px; }

/* detail page main + side layout */
.detail-2col { display: grid; grid-template-columns: minmax(0, 1.7fr) minmax(260px, 1fr); gap: 16px; align-items: start; }
@media (max-width: 880px) { .detail-2col { grid-template-columns: 1fr; } }
.kv-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 11px 0; border-bottom: 1px solid var(--border); }
.kv-row:last-child { border-bottom: 0; }
.kv-row .kv-k { font-size: 13px; color: var(--ink-3); }
.kv-row .kv-v { font-size: 13.5px; font-weight: 600; color: var(--ink); text-align: right; }

/* number flair: ledger column */
.ledger { font-variant-numeric: tabular-nums; font-family: var(--font-ui); }

/* ============================ Responsive helpers ============================ */
.desktop-only { display: flex; }
.mobile-only { display: none; }
@media (max-width: 880px) {
  .desktop-only { display: none !important; }
  .mobile-only { display: grid !important; place-items: center; }
}

/* Staff section nav: condense labels → icon-only before the bar overflows. */
.secbtn { padding: 7px 9px; }
.staff-sections .nav-label { font-size: 13px; }
@media (max-width: 1180px) {
  .staff-sections .secbtn { padding: 8px 8px; }
  .staff-sections .nav-label { display: none !important; }
}

/* cart layout: two columns on wide, stacked on narrow */
.cart-grid { grid-template-columns: minmax(0, 1fr); }
@media (min-width: 860px) {
  .cart-grid { grid-template-columns: 1fr 330px; }
  .cart-summary { position: sticky; top: 84px; }
}

/* mobile drawer */
.drawer-scrim { position: fixed; inset: 0; background: rgba(33,28,22,.45); z-index: 1500; animation: jk-view-in .2s var(--ease) both; }
.drawer {
  position: fixed; top: 0; right: 0; bottom: 0; width: min(320px, 86vw); z-index: 1600;
  background: var(--surface); box-shadow: var(--sh-lg); padding: 18px;
  display: flex; flex-direction: column; gap: 4px;
  animation: jk-drawer-in .28s var(--ease) both;
}
@keyframes jk-drawer-in { from { transform: translateX(100%); } to { transform: none; } }
.drawer-item {
  display: flex; align-items: center; gap: 12px; padding: 13px 14px; border-radius: var(--r);
  font-size: 15px; font-weight: 600; color: var(--ink-2); background: transparent; border: none;
  cursor: pointer; text-align: left; width: 100%; transition: background var(--dur-fast); text-decoration: none;
}
.drawer-item:hover { background: var(--paper-2); }
.drawer-item.is-active { background: var(--clay-50); color: var(--clay-700); }

/* nav dropdown */
.navdrop {
  position: absolute; top: calc(100% + 6px); left: 0; min-width: 200px; z-index: 1200;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r);
  box-shadow: var(--sh-lg); padding: 6px; animation: jk-view-in .16s var(--ease) both;
}
.navdrop a, .navdrop button {
  display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  padding: 9px 11px; border-radius: var(--r-sm); border: none; background: transparent;
  font-size: 13.5px; font-weight: 500; color: var(--ink-2); cursor: pointer; white-space: nowrap; text-decoration: none;
}
.navdrop a:hover, .navdrop button:hover { background: var(--paper-2); color: var(--ink); }
.navdrop a.is-active, .navdrop button.is-active { color: var(--clay); font-weight: 600; }

/* lang switch */
.lang-switch { display: inline-flex; border: 1px solid var(--border-2); border-radius: var(--r-sm); overflow: hidden; }
.lang-switch button { padding: 5px 10px; font-size: 12px; font-weight: 600; border: none; cursor: pointer; background: var(--surface); color: var(--ink-3); }
.lang-switch button.is-active { background: var(--ink); color: var(--paper); }

/* ============================ Login (centered card) ============================ */
.login-page { min-height: 100vh; display: grid; place-items: center; padding: 40px 20px; background: var(--paper); }
.login-card { width: 100%; max-width: 392px; background: var(--surface); border: 1px solid var(--border); border-radius: 16px; box-shadow: 0 18px 40px -24px rgba(50,40,24,.45); overflow: hidden; }
/* 6px three-band knit strip — the lone brand signal in the minimal card */
.login-strip { display: flex; height: 6px; }
.login-strip > span { flex: 1; }
.login-body { padding: 32px 32px 28px; }
/* password field + show/hide toggle */
.login-pw { position: relative; }
.login-pw input { padding-right: 48px; min-height: 46px; }
.login-toggle { position: absolute; right: 5px; top: 50%; transform: translateY(-50%); width: 44px; height: 44px; min-width: 44px; display: grid; place-items: center; border: none; background: transparent; color: var(--ink-3); cursor: pointer; border-radius: var(--r-sm); }
.login-toggle:hover { color: var(--ink-2); background: var(--paper-2); }
.login-toggle:focus-visible { outline: 2px solid var(--clay); outline-offset: 1px; }
/* caps-lock note — muted, not an error (caps lock isn't a failure) */
.login-caps { margin-top: 6px; font-size: 12px; color: var(--ink-3); align-items: center; gap: 6px; display: none; }
.login-caps.is-on { display: flex; }
/* submit spinner — swaps in for the arrow while the form posts */
.login-spin { display: none; width: 15px; height: 15px; border: 2px solid currentColor; border-right-color: transparent; border-radius: 50%; animation: login-spin .6s linear infinite; }
.btn.is-loading .login-spin { display: inline-block; }
.btn.is-loading .login-arrow { display: none; }
@keyframes login-spin { to { transform: rotate(360deg); } }

/* ============================ Forced mobile (device=phone preview) ============================ */
body.force-mobile { max-width: 402px; margin: 0 auto; min-height: 100vh; box-shadow: 0 0 0 1px var(--border), 0 30px 60px -20px rgba(50,40,24,.4); background: var(--paper); overflow-x: hidden; }
html:has(body.force-mobile) { background: #E4DDCD; }
body.force-mobile .desktop-only { display: none !important; }
body.force-mobile .mobile-only { display: grid !important; place-items: center; }
body.force-mobile .cart-grid { grid-template-columns: minmax(0, 1fr) !important; }
body.force-mobile .cart-summary { position: static !important; }

/* ============================================================================
   Generated knit-swatch texture (from assets/swatch.css)
   A muted heathered yarn color overlaid with two crossing rib lines + a darker
   ribbed hem band. Fills shop product tiles with no photo. Set base tone via the
   inline `--swatch` var:  <div class="jk-swatch" style="--swatch:#a8593f"></div>
   ============================================================================ */
.jk-swatch {
  position: relative;
  background-color: var(--swatch, #6b7f99);
  background-image:
    radial-gradient(120% 75% at 50% -8%, rgba(255, 255, 255, .42), transparent 58%),
    radial-gradient(110% 70% at 50% 120%, rgba(0, 0, 0, .18), transparent 55%),
    repeating-linear-gradient(63deg, rgba(255, 255, 255, .13) 0 2px, transparent 2px 9px),
    repeating-linear-gradient(-63deg, rgba(255, 255, 255, .13) 0 2px, transparent 2px 9px),
    repeating-linear-gradient(0deg, rgba(0, 0, 0, .05) 0 1px, transparent 1px 18px);
  background-size: 100% 100%, 100% 100%, 18px 18px, 18px 18px, 100% 18px;
  overflow: hidden;
}
.jk-swatch::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 26px;
  background-image: repeating-linear-gradient(90deg, rgba(0, 0, 0, .10) 0 2px, rgba(255, 255, 255, .06) 2px 6px);
  opacity: .6;
}
.jk-swatch--thumb::after { height: 12px; }

/* ============================================================================
   Global chrome — top nav + mobile sidebar (base.html)
   Restyles the existing nav structure (dropdown hooks for dropdowns.js are
   preserved in the markup; these classes only re-skin it to Mill).
   ============================================================================ */
.jk-topnav { background: var(--surface); border-bottom: 1px solid var(--border); box-shadow: var(--sh-sm); }
/* The nav holds a lot (8 top-level links for admins + the user cluster). Stop the
   two groups (links / user cluster) from shrinking into each other: with both
   non-shrinking the links can never spill over the user controls — at worst the
   row overflows the (already minimal) gutters instead of overlapping. */
.jk-topnav > div > .flex.justify-between > div { flex-shrink: 0; }
/* Top-level links are text-only so all eight app labels fit without overlapping;
   the per-section icons still appear in the mobile sidebar. Dropdown chevrons are
   kept (.jk-chev) so the menus still read as expandable. */
.jk-navrail .jk-navlink > .jk-ic { display: none; }
.jk-navrail { gap: 3px; }
.jk-wordmark { display: inline-flex; align-items: baseline; gap: 1px; text-decoration: none; line-height: 1; }
.jk-wordmark .w1 { font-family: var(--font-display); font-size: 22px; font-weight: 700; color: var(--ink); letter-spacing: -.02em; }
.jk-wordmark .w2 { font-family: var(--font-display); font-size: 22px; font-weight: 700; color: var(--clay); letter-spacing: -.02em; }

.jk-navlink {
  display: inline-flex; align-items: center; gap: 5px; height: 38px; padding: 0 8px;
  border-radius: var(--r); font-size: 13.5px; font-weight: 500; color: var(--ink-3);
  text-decoration: none; white-space: nowrap; flex-shrink: 0;
  transition: background var(--dur-fast), color var(--dur-fast);
}
/* The top nav holds many items; keep its chevron tight so labels have room. */
.jk-navlink .jk-chev { margin-left: -1px; }
.jk-navlink:hover { background: var(--paper-2); color: var(--ink); }
.jk-navlink.is-active { background: var(--paper-2); color: var(--ink); font-weight: 700; }

/* dropdown menu card (keeps .{section}-dropdown-menu + hidden for the JS) */
.jk-menu { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r); box-shadow: var(--sh-lg); padding: 6px; }
.jk-menu .jk-menu-label { padding: 8px 11px 4px; font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .1em; color: var(--ink-4); }
.jk-menu a { display: flex; align-items: center; gap: 9px; padding: 8px 11px; border-radius: var(--r-sm); font-size: 13.5px; font-weight: 500; color: var(--ink-2); text-decoration: none; white-space: nowrap; }
.jk-menu a:hover { background: var(--paper-2); color: var(--clay); }
.jk-menu .jk-menu-sep { height: 1px; background: var(--border); margin: 5px 0; }

/* Quick Pages star toggle (sits next to page titles on list/index pages) */
.jk-star-form { margin: 0; display: inline-flex; line-height: 0; }
.jk-star { display: inline-flex; align-items: center; justify-content: center; width: 38px; height: 38px; padding: 0; border: none; background: transparent; color: var(--ink-4); cursor: pointer; border-radius: var(--r-sm); transition: color .12s ease, background .12s ease; }
.jk-star:hover { color: var(--clay); background: var(--clay-50); }
.jk-star svg { fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linejoin: round; }
.jk-star.is-on { color: var(--clay); }
.jk-star.is-on svg { fill: currentColor; stroke: currentColor; }
/* Quick Pages links inside the app-dropdown menus: user labels are free text, so
   ellipsis rather than let them blow out the fixed-width (w-64) menu. Overrides
   .jk-menu a's flex/nowrap (later + equal specificity). The current page's pin
   gets the clay accent so you can see where you are. */
.jk-menu a.jk-menu-pin { display: block; overflow: hidden; text-overflow: ellipsis; }
.jk-menu a.jk-menu-pin.is-active { color: var(--clay); font-weight: 700; }

/* nav badge (cart count / unread) */
.jk-navbadge { background: var(--brick); color: #fff; font-size: 10px; font-weight: 700; min-width: 17px; height: 17px; border-radius: 99px; display: inline-grid; place-items: center; padding: 0 4px; line-height: 1; }
/* jk-mill.css loads after Tailwind, so this component class would out-order .hidden;
   re-assert hiding so the count badges collapse to nothing at zero. */
.jk-navbadge.hidden { display: none; }

/* icon button (mobile hamburger / anon controls) */
.jk-iconbtn { width: 40px; height: 40px; border-radius: var(--r); border: none; background: var(--paper-2); color: var(--ink); cursor: pointer; display: grid; place-items: center; }
.jk-iconbtn:hover { background: var(--border); }

/* mobile sidebar (Mill) */
.jk-msidebar { background: var(--surface); }
.jk-mlink { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 11px 12px; border-radius: var(--r); font-size: 15px; font-weight: 600; color: var(--ink-2); text-decoration: none; }
.jk-mlink:hover { background: var(--paper-2); }
.jk-mlink.is-active { background: var(--clay-50); color: var(--clay-700); }
.jk-msub { display: flex; align-items: center; gap: 8px; padding: 9px 12px; border-radius: var(--r-sm); font-size: 13.5px; color: var(--ink-3); text-decoration: none; }
.jk-msub:hover { background: var(--paper-2); color: var(--ink); }

/* form fields — restyle native/Django-widget inputs inside a .jk-fields wrapper
   (reused by auth + every create/edit form so we never touch the Python forms) */
.jk-fields input[type=text], .jk-fields input[type=email], .jk-fields input[type=password],
.jk-fields input[type=number], .jk-fields input[type=tel], .jk-fields input[type=date],
.jk-fields input[type=search], .jk-fields input[type=url], .jk-fields textarea, .jk-fields select {
  width: 100%; font-family: var(--font-ui); font-size: 14px; color: var(--ink);
  background: var(--surface); border: 1px solid var(--border-2); border-radius: var(--r);
  padding: 10px 13px; transition: box-shadow var(--dur-fast), border-color var(--dur-fast);
  box-shadow: none;
}
.jk-fields input::placeholder, .jk-fields textarea::placeholder { color: var(--ink-4); }
.jk-fields input:focus, .jk-fields textarea:focus, .jk-fields select:focus {
  outline: none; border-color: var(--clay); box-shadow: 0 0 0 3px var(--clay-50);
}
.jk-fields input[type=checkbox], .jk-fields input[type=radio] { accent-color: var(--clay); width: 15px; height: 15px; }
.jk-field-label { display: block; font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .1em; color: var(--ink-3); margin-bottom: 6px; }
.jk-field-err { margin-top: 6px; font-size: 12.5px; color: var(--brick-700); }

/* App-wide de-blue: color-only field treatment for inputs that are NOT inside a
   .jk-fields wrapper (forms across accounting/sales/inventory). Element-qualified
   (specificity 0,1,1) so it deterministically beats `border-gray-300` and the
   colorless `focus:ring-2` default-blue ring regardless of stylesheet load order.
   Sets ONLY border-color + the terracotta focus ring — never width/padding/
   background — so existing Tailwind sizing utils (w-24, px-2, bg-gray-100,
   text-center) are preserved. Apply by adding `jk-input` to a blue input and
   stripping its border-gray-300 / focus:ring-* / *-blue-* utils. */
input.jk-input, textarea.jk-input, select.jk-input { border-color: var(--border-2); }
input.jk-input:focus, textarea.jk-input:focus, select.jk-input:focus {
  outline: none; border-color: var(--clay); box-shadow: 0 0 0 3px var(--clay-50);
}
/* checkboxes/radios carry a blue check via text-blue-600; clay accent replaces it */
input.jk-input[type=checkbox], input.jk-input[type=radio] { accent-color: var(--clay); }

/* period filter chips (dashboards: Today / This Week / This Month / Custom) */
.jk-period { padding: 8px 16px; font-size: 14px; font-weight: 600; border-radius: var(--r); background: var(--paper-2); color: var(--ink-2); text-decoration: none; border: none; cursor: pointer; transition: background var(--dur-fast), color var(--dur-fast); white-space: nowrap; }
.jk-period:hover { background: var(--border); }
.jk-period.is-active { background: var(--ink); color: var(--paper); }

/* autocomplete suggestion dropdown items (sales/inventory search boxes) */
.jk-sugg { padding: 8px 14px; cursor: pointer; }
.jk-sugg:hover, .jk-sugg.is-active { background: var(--paper-2); }

/* sticky section sub-nav tabs (staff sections) */
.jk-subtab { color: var(--ink-3); border-bottom: 2px solid transparent; font-weight: 500; text-decoration: none; transition: color var(--dur-fast), border-color var(--dur-fast); }
.jk-subtab:hover { color: var(--ink); }
.jk-subtab.is-active { color: var(--clay); border-bottom-color: var(--clay); font-weight: 700; }

/* flash messages (Mill tones) */
.jk-flash { border-radius: var(--r); padding: 13px 16px; margin-bottom: 12px; font-size: 13.5px; display: flex; gap: 10px; align-items: flex-start; border: 1px solid var(--border); background: var(--surface); color: var(--ink-2); }
/* jk-mill.css loads after Tailwind, so .jk-flash's display:flex would out-order
   .hidden; re-assert so a JS-toggled flash (e.g. #uploadError) can actually hide. */
.jk-flash.hidden { display: none; }
.jk-flash.is-error { background: var(--brick-50); border-color: var(--brick-100); color: var(--brick-700); }
.jk-flash.is-success { background: var(--pine-50); border-color: var(--pine-100); color: var(--pine-700); }
.jk-flash.is-warning { background: var(--ochre-50); border-color: var(--ochre-100); color: var(--ochre-700); }
.jk-flash.is-info { background: var(--slate-50); border-color: var(--slate-100); color: #2c4259; }

/* App-wide de-blue (Tier 3) ----------------------------------------------------
   jk-mill.css loads after Tailwind output.css, so these win on source order.
   (1) Warm the neutral Tailwind border utility to the Mill hairline in ONE rule
       (replaces ~60 cool-gray card/container borders without per-site edits).
   (2) .jk-info — a Mill "info" surface (slate), mirroring .jk-flash.is-info, for
       the blue info callouts. Children inherit the slate text/icon color. */
.border-gray-300 { border-color: var(--border); }
.jk-info { background: var(--slate-50); border: 1px solid var(--slate-100); color: #34465c; }
.jk-info h1, .jk-info h2, .jk-info h3, .jk-info h4, .jk-info strong { color: #2c3e54; }
/* Balance-sheet status bar — JS toggles these instead of Tailwind bg-blue/red/gray.
   Balanced was BLUE (off-brand); de-blued to pine (positive). */
.jk-status { border-top-width: 4px; border-top-style: solid; }
.jk-status-neutral { background: var(--paper-2); border-top-color: var(--border-2); }
.jk-status-balanced { background: var(--pine-50); border-top-color: var(--pine); }
.jk-status-unbalanced { background: var(--brick-50); border-top-color: var(--brick); }
/* purple -> Mill plum (the account / admin accent), incl. JS-built dropdown rows */
.jk-plum { color: var(--plum); }
.jk-plum-surface { background: var(--plum-50); }

/* ============================================================================
   Compatibility shim — re-color legacy Tailwind utilities to Mill on pages
   still authored in the old blue palette (applied via .jk-shim on the section
   #jkRoot). Hand-converted pages use inline Mill styles + .card/.btn and don't
   carry these color utilities, so the shim is a no-op there. Lets large form
   pages adopt the warm look without a full markup rewrite.
   ============================================================================ */
.jk-shim h1, .jk-shim h2, .jk-shim h3 { font-family: var(--font-display); }
/* surfaces / text ramp */
.jk-shim .bg-white { background-color: var(--surface) !important; }
.jk-shim .bg-gray-50 { background-color: var(--surface-2) !important; }
.jk-shim .bg-gray-100 { background-color: var(--paper-2) !important; }
.jk-shim .bg-gray-200 { background-color: var(--border) !important; }
.jk-shim .text-gray-900, .jk-shim .text-gray-800 { color: var(--ink) !important; }
.jk-shim .text-gray-700, .jk-shim .text-gray-600 { color: var(--ink-2) !important; }
.jk-shim .text-gray-500 { color: var(--ink-3) !important; }
.jk-shim .text-gray-400, .jk-shim .text-gray-300 { color: var(--ink-4) !important; }
.jk-shim .border-gray-100, .jk-shim .border-gray-200 { border-color: var(--border) !important; }
.jk-shim .border-gray-300 { border-color: var(--border-2) !important; }
.jk-shim .divide-gray-200 > :not([hidden]) ~ :not([hidden]) { border-color: var(--border) !important; }
.jk-shim .hover\:bg-gray-50:hover { background-color: var(--surface-2) !important; }
.jk-shim .hover\:bg-gray-100:hover { background-color: var(--paper-2) !important; }
.jk-shim .hover\:bg-gray-200:hover { background-color: var(--border) !important; }
/* brand blue → terracotta */
.jk-shim .bg-blue-600 { background-color: var(--clay) !important; }
.jk-shim .bg-blue-700, .jk-shim .hover\:bg-blue-700:hover { background-color: var(--clay-hover) !important; }
.jk-shim .bg-blue-50 { background-color: var(--clay-50) !important; }
.jk-shim .hover\:bg-blue-50:hover { background-color: var(--clay-50) !important; }
.jk-shim .bg-blue-100 { background-color: var(--clay-100) !important; }
.jk-shim .text-blue-600, .jk-shim .hover\:text-blue-600:hover { color: var(--clay) !important; }
.jk-shim .text-blue-700, .jk-shim .text-blue-800, .jk-shim .hover\:text-blue-700:hover, .jk-shim .hover\:text-blue-800:hover { color: var(--clay-700) !important; }
.jk-shim .border-blue-200 { border-color: var(--clay-100) !important; }
.jk-shim .border-blue-500, .jk-shim .border-blue-600 { border-color: var(--clay) !important; }
/* semantics */
.jk-shim .text-green-600, .jk-shim .text-green-700, .jk-shim .text-emerald-600 { color: var(--pine) !important; }
.jk-shim .bg-green-600, .jk-shim .hover\:bg-green-700:hover { background-color: var(--pine) !important; }
.jk-shim .bg-green-50 { background-color: var(--pine-50) !important; }
.jk-shim .bg-green-100 { background-color: var(--pine-50) !important; }
.jk-shim .text-green-800 { color: var(--pine-700) !important; }
.jk-shim .border-green-200 { border-color: var(--pine-100) !important; }
.jk-shim .text-red-600, .jk-shim .text-red-700, .jk-shim .hover\:text-red-700:hover { color: var(--brick) !important; }
.jk-shim .bg-red-600, .jk-shim .hover\:bg-red-700:hover { background-color: var(--brick) !important; }
.jk-shim .bg-red-50, .jk-shim .hover\:bg-red-50:hover { background-color: var(--brick-50) !important; }
.jk-shim .bg-red-100 { background-color: var(--brick-50) !important; }
.jk-shim .text-red-800 { color: var(--brick-700) !important; }
.jk-shim .border-red-200, .jk-shim .border-red-300 { border-color: var(--brick-100) !important; }
.jk-shim .text-amber-600, .jk-shim .text-amber-700, .jk-shim .text-amber-800, .jk-shim .text-amber-900, .jk-shim .text-yellow-600, .jk-shim .text-yellow-800 { color: var(--ochre-700) !important; }
.jk-shim .bg-amber-50, .jk-shim .bg-yellow-50 { background-color: var(--ochre-50) !important; }
.jk-shim .bg-amber-100, .jk-shim .bg-yellow-100 { background-color: var(--ochre-50) !important; }
.jk-shim .border-amber-200, .jk-shim .border-yellow-200 { border-color: var(--ochre-100) !important; }
.jk-shim .bg-purple-100, .jk-shim .bg-indigo-100 { background-color: var(--plum-50) !important; }
.jk-shim .text-purple-800, .jk-shim .text-indigo-800, .jk-shim .text-purple-600, .jk-shim .text-indigo-600 { color: var(--plum-700) !important; }
.jk-shim .bg-purple-50, .jk-shim .bg-indigo-50 { background-color: var(--plum-50) !important; }
.jk-shim .bg-teal-50 { background-color: var(--pine-50) !important; }
.jk-shim .text-teal-600 { color: var(--pine) !important; }
.jk-shim .bg-orange-50 { background-color: var(--clay-50) !important; }
.jk-shim .text-orange-600, .jk-shim .text-orange-700 { color: var(--clay-700) !important; }
.jk-shim .border-orange-300 { border-color: var(--clay-100) !important; }
/* native inputs → Mill fields */
.jk-shim input[type=text], .jk-shim input[type=email], .jk-shim input[type=password], .jk-shim input[type=number], .jk-shim input[type=date], .jk-shim input[type=month], .jk-shim input[type=search], .jk-shim input[type=tel], .jk-shim input[type=url], .jk-shim select, .jk-shim textarea {
  background-color: var(--surface) !important; border-color: var(--border-2) !important; color: var(--ink) !important;
}
.jk-shim input:focus, .jk-shim select:focus, .jk-shim textarea:focus { border-color: var(--clay) !important; box-shadow: 0 0 0 3px var(--clay-50) !important; outline: none !important; }
.jk-shim input[type=checkbox], .jk-shim input[type=radio] { accent-color: var(--clay); }
/* focus rings that used blue */
.jk-shim .focus\:ring-blue-500:focus, .jk-shim .focus\:ring-blue-600:focus { --tw-ring-color: var(--clay) !important; }
.jk-shim .focus\:border-blue-500:focus { border-color: var(--clay) !important; }

/* ---- Sale form: out-of-stock line ----
   Toggled by checkInventoryAvailability() on the sale create/edit pages: the
   Boxes quantity input of an out-of-stock line goes bold red alongside the red
   product field, so the quantity that will turn into a Sale ReOrder is
   unmissable. Declared after the .jk-shim input overrides on purpose so the
   red border wins over the shim's neutral field styling. */
input.oos-boxes, .jk-shim input.oos-boxes {
  border-color: var(--brick) !important;
  border-width: 2px !important;
  color: var(--brick-700) !important;
  font-weight: 700;
}
input.oos-boxes:focus, .jk-shim input.oos-boxes:focus {
  border-color: var(--brick) !important;
  box-shadow: 0 0 0 3px var(--brick-50) !important;
}
/* Companion to .oos-boxes: the legacy inline red background on the product
   search field is defeated by the .jk-shim "input background !important"
   override above, so the same JS toggles this class to keep the product field
   visibly red as well (the inline style remains the JS-readable state). */
input.oos-product, .jk-shim input.oos-product {
  background-color: rgb(222, 171, 175) !important;
}
