/*
 * Saxiy Market design system
 * Source of truth for the admin panel and the NFC desktop app.
 * Spec: docs/superpowers/specs/2026-05-03-saxiy-redesign-design.md
 *
 * The NFC app receives a build-time copy at nfc_app/ui/assets/css/theme.css
 * (gitignored — see nfc_app/build.sh).
 */

:root {
  color-scheme: light dark;

  /* ----- Color tokens (spec §4.1 light theme) ----- */
  --bg-page:       #FAF6EA;
  --surface:       #FFFFFF;
  --surface-alt:   #F2EBD8;
  --side-bg:       #0A2E1E;
  --side-bg-2:     #0F462D;
  --brand:         #0F462D;
  --brand-hover:   #1F5C3D;
  --on-brand:      #FAF6EA;
  --display-fg:    #0F462D;
  --accent:        #C9A24B;
  --accent-hi:     #E5C77B;
  --accent-deep:   #8B6420;
  --ink-1:         #0F1F18;
  --ink-2:         #2A3B33;
  --ink-3:         #5A6A60;
  --ink-4:         #8A968F;
  --hairline:      rgba(15, 70, 45, 0.08);
  --hairline-2:    rgba(15, 70, 45, 0.16);
  --success:       #2A6440;
  --success-bg:    rgba(15, 70, 45, 0.08);
  --warning:       #8B5A1F;
  --warning-bg:    rgba(180, 90, 30, 0.10);
  --danger:        #B43A2E;
  --danger-bg:     rgba(180, 58, 46, 0.08);
  --shadow-modal:  0 24px 48px -28px rgba(15, 70, 45, 0.35);
}

/* When the user explicitly picks light theme, lock native controls to light too
   so the calendar icon stays visible even if the OS is in dark mode. */
:root[data-theme="light"] {
  color-scheme: light;
}

/* ----- Color tokens (spec §4.2 dark theme — explicit selector) ----- */
:root[data-theme="dark"] {
  /* Lock native form-control rendering (calendar icon, scrollbars, etc.) to dark
     so they are visible against the dark input background regardless of OS setting. */
  color-scheme: dark;
  --bg-page:       #142822;
  --surface:       #1F3A30;
  --surface-alt:   #2A4A3D;
  --side-bg:       #0A1612;
  --side-bg-2:     #142822;
  --brand:         #E5C77B;
  --brand-hover:   #F0D896;
  --on-brand:      #0F1F18;
  --display-fg:    #FAF6EA;
  --accent:        #C9A24B;
  --accent-hi:     #E5C77B;
  --accent-deep:   #B68838;
  --ink-1:         #FAF6EA;
  --ink-2:         rgba(250, 246, 234, 0.85);
  --ink-3:         rgba(250, 246, 234, 0.55);
  --ink-4:         rgba(250, 246, 234, 0.35);
  --hairline:      rgba(229, 199, 123, 0.10);
  --hairline-2:    rgba(229, 199, 123, 0.20);
  --success:       #6BBF7E;
  --success-bg:    rgba(107, 191, 126, 0.14);
  --warning:       #E5C77B;
  --warning-bg:    rgba(229, 199, 123, 0.14);
  --danger:        #E58474;
  --danger-bg:    rgba(229, 132, 116, 0.14);
  --shadow-modal:  0 24px 48px -28px rgba(0, 0, 0, 0.6);
}

/* Auto theme: when no [data-theme] attribute is set, follow OS preference */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):not([data-theme="dark"]) {
    color-scheme: dark;
    --bg-page:       #142822;
    --surface:       #1F3A30;
    --surface-alt:   #2A4A3D;
    --side-bg:       #0A1612;
    --side-bg-2:     #142822;
    --brand:         #E5C77B;
    --brand-hover:   #F0D896;
    --on-brand:      #0F1F18;
    --display-fg:    #FAF6EA;
    --accent:        #C9A24B;
    --accent-hi:     #E5C77B;
    --accent-deep:   #B68838;
    --ink-1:         #FAF6EA;
    --ink-2:         rgba(250, 246, 234, 0.85);
    --ink-3:         rgba(250, 246, 234, 0.55);
    --ink-4:         rgba(250, 246, 234, 0.35);
    --hairline:      rgba(229, 199, 123, 0.10);
    --hairline-2:    rgba(229, 199, 123, 0.20);
    --success:       #6BBF7E;
    --success-bg:    rgba(107, 191, 126, 0.14);
    --warning:       #E5C77B;
    --warning-bg:    rgba(229, 199, 123, 0.14);
    --danger:        #E58474;
    --danger-bg:    rgba(229, 132, 116, 0.14);
    --shadow-modal:  0 24px 48px -28px rgba(0, 0, 0, 0.6);
  }
}

/* Reset */
*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  background: var(--bg-page);
  color: var(--ink-1);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

/* ----- @font-face (spec §4.3) ----- */
@font-face {
  font-family: "Literata";
  src: url("/static/fonts/Literata%5Bopsz%2Cwght%5D.woff2") format("woff2-variations"),
       url("/static/fonts/Literata%5Bopsz%2Cwght%5D.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("/static/fonts/Inter%5Bwght%5D.woff2") format("woff2-variations"),
       url("/static/fonts/Inter%5Bwght%5D.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

/* ----- Type scale (spec §4.3) ----- */
:root {
  --font-serif: "Literata", ui-serif, Georgia, "Times New Roman", serif;
  --font-sans:  "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-mono:  ui-monospace, "SF Mono", Monaco, Menlo, Consolas, monospace;

  --t-display:    700 30px/33px var(--font-serif);
  --t-display-sm: 700 24px/28px var(--font-serif);
  --t-stat:       700 30px/33px var(--font-serif);
  --t-card-title: 600 14px/20px var(--font-serif);
  --t-h2:         600 18px/24px var(--font-sans);
  --t-h3:         600 15px/22px var(--font-sans);
  --t-body:       500 13px/20px var(--font-sans);
  --t-body-sm:    500 12px/18px var(--font-sans);
  --t-label:      600 9.5px/13px var(--font-sans);
  --t-eyebrow:    600 10px/13px var(--font-sans);
  --t-button:     600 12.5px/16px var(--font-sans);
  --t-mono:       500 12px/18px var(--font-mono);
}

body {
  font: var(--t-body);
  font-feature-settings: "tnum" 1, "lnum" 1;
}
h1 { font: var(--t-display); color: var(--display-fg); margin: 0; letter-spacing: -0.005em; }
h2 { font: var(--t-h2); color: var(--ink-1); margin: 0; }
h3 { font: var(--t-h3); color: var(--ink-1); margin: 0; }
p  { margin: 0; }
a  { color: var(--accent-deep); text-decoration: none; }
:root[data-theme="dark"] a { color: var(--accent-hi); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):not([data-theme="dark"]) a {
    color: var(--accent-hi);
  }
}
a:hover { text-decoration: underline; }

.cm-eyebrow {
  font: var(--t-eyebrow);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--accent-deep);
}
.cm-label {
  font: var(--t-label);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.cm-mono {
  font: var(--t-mono);
  font-feature-settings: "tnum" 1, "lnum" 1;
}

/* ----- Spacing (spec §4.4) ----- */
:root {
  --s-1: 4px;  --s-2: 8px;  --s-3: 12px; --s-4: 14px; --s-5: 18px;
  --s-6: 22px; --s-7: 28px; --s-8: 36px; --s-9: 48px;
}

/* ----- Radii (spec §4.5) ----- */
:root {
  --r-1: 4px; --r-2: 6px; --r-3: 8px; --r-4: 10px; --r-5: 14px;
  --r-full: 9999px;
}

/* ----- Motion (spec §4.6) ----- */
:root {
  --ease-out: cubic-bezier(0.2, 0.8, 0.2, 1);
  --d-fast: 120ms;
  --d-base: 180ms;
  --d-slow: 240ms;
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition-duration: 10ms !important;
    animation-duration:  10ms !important;
  }
}

/* ----- Shadow (spec §4.7) ----- */
/* --shadow-modal is the only shadow token; defined in :root and :root[data-theme="dark"] above. */

/* ----- Breakpoints (spec §4.8) — values for documentation only;
        the actual @media rules below use literal pixel values
        because CSS variables are not allowed in media query conditions. ----- */
:root {
  --bp-xs: 0;
  --bp-sm: 600px;
  --bp-md: 768px;
  --bp-lg: 1024px;
  --bp-xl: 1280px;
  --bp-2xl: 1600px;
}

/* Container query opt-in for cards (spec §8.6) */
.cm-card { container-type: inline-size; container-name: card; }

/* ----- POS form factor (spec §8.7): square + coarse pointer ----- */
@media (min-aspect-ratio: 9/10) and (max-aspect-ratio: 10/9) and (pointer: coarse) {
  :root { --form-factor: pos; }
}
:root[data-form-factor="pos"] { --form-factor: pos; }

/* Touch floor (spec §4.8) */
@media (pointer: coarse) {
  .cm-btn        { min-height: 44px; }
  .cm-row        { min-height: 48px; }
  .cm-side__link { min-height: 44px; }
  .cm-pill       { min-height: 24px; }
}

/* ----- Buttons (spec §5.3) ----- */
.cm-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 36px;
  padding: 0 16px;
  border: none;
  border-radius: var(--r-2);
  font: var(--t-button);
  letter-spacing: 0.04em;
  cursor: pointer;
  transition:
    background-color var(--d-fast) var(--ease-out),
    border-color     var(--d-fast) var(--ease-out),
    color            var(--d-fast) var(--ease-out),
    transform        var(--d-fast) var(--ease-out);
}
.cm-btn:active { transform: scale(0.98); }
.cm-btn[disabled],
.cm-btn:disabled {
  opacity: 0.45;
  cursor: not-allowed;
  transform: none;
}

.cm-btn--primary {
  background: var(--brand);
  color: var(--on-brand);
  font-weight: 600;
}
.cm-btn--primary:hover { background: var(--brand-hover); }

.cm-btn--ghost {
  background: transparent;
  color: var(--ink-1);
  border: 1px solid var(--hairline-2);
}
.cm-btn--ghost:hover {
  background: var(--surface-alt);
  border-color: var(--hairline-2);
}

.cm-btn--subtle {
  background: var(--surface-alt);
  color: var(--ink-2);
}
.cm-btn--subtle:hover { background: var(--surface); }

.cm-btn--danger {
  background: var(--danger);
  color: #FFFFFF;
  font-weight: 600;
}
.cm-btn--danger:hover { filter: brightness(1.05); }

/* Semantic action variants — used on the user-detail action row.
   These are theme-stable: the colour is the meaning. NFC = gold, positive
   action (add) = green, destructive = red. Hover keeps the same hue and
   leans slightly brighter via filter so the colour identity is preserved. */
.cm-btn--gold {
  background: var(--accent-hi);
  color: #0F1F18;
  font-weight: 600;
  box-shadow: inset 0 -2px 0 var(--accent-deep);
}
.cm-btn--gold:hover { background: #F0D896; }

.cm-btn--success {
  background: var(--success);
  color: var(--on-brand);
  font-weight: 600;
}
.cm-btn--success:hover { filter: brightness(1.05); }

.cm-btn--link {
  background: transparent;
  color: var(--accent-deep);
  height: auto;
  padding: 0;
}
:root[data-theme="dark"] .cm-btn--link { color: var(--accent-hi); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):not([data-theme="dark"]) .cm-btn--link {
    color: var(--accent-hi);
  }
}
.cm-btn--link:hover { text-decoration: underline; }

/* POS form factor: bigger primary, taller height
   (`.cm-btn--link` is excluded via :not — link buttons keep `height: auto`
   so they read as inline text even on POS terminals.) */
@media (min-aspect-ratio: 9/10) and (max-aspect-ratio: 10/9) and (pointer: coarse) {
  .cm-btn:not(.cm-btn--link) { height: 48px; }
  .cm-btn--ghost             { height: 44px; }
}
:root[data-form-factor="pos"] .cm-btn:not(.cm-btn--link) { height: 48px; }
:root[data-form-factor="pos"] .cm-btn--ghost             { height: 44px; }

/* ----- Cards (spec §5.4) ----- */
.cm-card {
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--r-4);
  /* container-type set above in breakpoints section */
}
.cm-card__head {
  padding: var(--s-4) var(--s-5);
  border-bottom: 1px solid var(--hairline);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
}
.cm-card__title { font: var(--t-card-title); color: var(--display-fg); }
.cm-card__meta  { font: var(--t-body-sm); color: var(--ink-3); }
.cm-card__body  { padding: var(--s-5); }

/* Container-aware split layout inside cards (spec §8.6) */
@container card (min-width: 480px) {
  .cm-card__split { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-4); }
}

/* ----- Stat cards (spec §5.5) ----- */
.cm-stat {
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--r-4);
  padding: 18px 18px 16px;
  display: flex; flex-direction: column; gap: 6px;
}
.cm-stat__label { font: var(--t-label); letter-spacing: 0.16em; text-transform: uppercase; color: var(--ink-3); }
.cm-stat__value { font: var(--t-stat); color: var(--display-fg); letter-spacing: -0.01em; }
.cm-stat__trend {
  font: var(--t-body-sm); color: var(--ink-3);
  display: inline-flex; align-items: center; gap: 6px;
}
.cm-stat__trend::before {
  content: ""; width: 6px; height: 6px; border-radius: 50%;
  background: currentColor; opacity: 0.85;
}
.cm-stat__trend--up    { color: var(--success); }
.cm-stat__trend--warn  { color: var(--warning); }
.cm-stat__trend--down  { color: var(--danger); }

/* Stat grid (spec §5.5) */
.cm-stats {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--s-4);
}
@media (min-width: 600px)  { .cm-stats { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .cm-stats { grid-template-columns: repeat(4, 1fr); } }

/* Tighter padding on small screens */
@media (max-width: 599px)  { .cm-stat { padding: 16px; } }

/* POS form factor */
:root[data-form-factor="pos"] .cm-stat { padding: 16px; }
@media (min-aspect-ratio: 9/10) and (max-aspect-ratio: 10/9) and (pointer: coarse) {
  .cm-stat { padding: 16px; }
}

/* ----- Pills (spec §5.7) ----- */
.cm-pill {
  display: inline-flex; align-items: center; justify-content: center;
  font: var(--t-label);
  letter-spacing: 0.10em;
  text-transform: uppercase;
  padding: 3px 9px;
  border-radius: var(--r-full);
  white-space: nowrap;
}
.cm-pill--active,
.cm-pill--ok {
  background: color-mix(in oklab, var(--success) 18%, transparent);
  color: var(--success);
  border: 1px solid color-mix(in oklab, var(--success) 32%, transparent);
  font-weight: 700;
  padding-left: 7px;
}
/* Leading status dot — tells the eye "alive / now" without needing copy.
   Uses currentColor so dark theme picks up the brighter --success automatically. */
.cm-pill--active::before,
.cm-pill--ok::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 999px;
  background: currentColor;
  margin-right: 6px;
  box-shadow: 0 0 0 3px color-mix(in oklab, currentColor 22%, transparent);
  flex: none;
}
.cm-pill--gold     { background: rgba(201,162,75,0.18); color: var(--accent-deep); }
:root[data-theme="dark"] .cm-pill--gold { color: var(--accent-hi); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):not([data-theme="dark"]) .cm-pill--gold {
    color: var(--accent-hi);
  }
}
.cm-pill--warn     { background: var(--warning-bg); color: var(--warning); }
.cm-pill--danger   { background: var(--danger-bg);  color: var(--danger); }
.cm-pill--neutral  { background: var(--surface-alt); color: var(--ink-3); }

/* POS: taller pill */
:root[data-form-factor="pos"] .cm-pill { min-height: 28px; padding: 5px 11px; }
@media (min-aspect-ratio: 9/10) and (max-aspect-ratio: 10/9) and (pointer: coarse) {
  .cm-pill { min-height: 28px; padding: 5px 11px; }
}

/* ----- Inputs (spec §5.8) ----- */
.cm-field {
  display: flex; flex-direction: column; gap: var(--s-2);
}
.cm-field__label {
  font: var(--t-label); letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 2px;
}
.cm-input,
.cm-select,
.cm-textarea {
  height: 36px;
  padding: 0 14px;
  background: var(--surface);
  border: 1px solid var(--hairline-2);
  border-radius: var(--r-2);
  font: var(--t-body);
  color: var(--ink-1);
  outline: none;
  transition: border-color var(--d-fast) var(--ease-out),
              box-shadow  var(--d-fast) var(--ease-out);
}
.cm-textarea { height: auto; min-height: 96px; padding: 10px 14px; }
.cm-input::placeholder,
.cm-textarea::placeholder { color: var(--ink-4); }
/* Focus rings derive from the active theme via color-mix() so the halo
   automatically picks up gold in dark mode and red on error — no per-theme
   override needed. WebView2 ≥120 / Chrome 111+ / Safari 16.2+ all support
   `color-mix()`. */
.cm-input:focus,
.cm-select:focus,
.cm-textarea:focus {
  border-color: var(--brand);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand) 16%, transparent);
}
.cm-input--error,
.cm-input.is-error {
  border-color: var(--danger);
}
.cm-input--error:focus,
.cm-input.is-error:focus {
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--danger) 24%, transparent);
}

/* Search input variant: 14×14 leading icon slot */
.cm-input--search { padding-left: 36px; background-position: 12px center; background-repeat: no-repeat; }

/* POS: 48 px tall fields (textarea stays content-driven via its own
   `height: auto; min-height: 96px` rule above; we exclude it explicitly
   so POS doesn't pin the multi-line input to a single line). */
:root[data-form-factor="pos"] .cm-input,
:root[data-form-factor="pos"] .cm-select {
  height: 48px;
}
:root[data-form-factor="pos"] .cm-textarea { min-height: 120px; }
@media (min-aspect-ratio: 9/10) and (max-aspect-ratio: 10/9) and (pointer: coarse) {
  .cm-input, .cm-select { height: 48px; }
  .cm-textarea          { min-height: 120px; }
}

/* ----- File input (used for optional sign_photo upload in subscription modal) -----
   Native <input type=file> stays focusable for keyboard/AT users, but is
   visually hidden in favor of a styled label. The label visually mirrors
   .cm-input height/border so the field belongs to the same family, and gets a
   filled accent when a file has been picked. The trailing × button clears the
   selection without dismissing the form. */
.cm-field__optional {
  font-weight: 400;
  text-transform: none;
  letter-spacing: 0;
  color: var(--ink-3);
}
.cm-fileinput {
  position: relative;
  display: flex;
  align-items: stretch;
  height: 40px;
  border: 1px dashed var(--ink-3);
  border-radius: var(--r-2);
  background: var(--surface);
  transition: border-color var(--motion-fast) var(--ease-emphatic), background var(--motion-fast) var(--ease-emphatic);
}
.cm-fileinput.is-filled {
  border-style: solid;
  border-color: var(--accent);
  background: color-mix(in oklab, var(--accent) 6%, var(--surface));
}
.cm-fileinput__input {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  opacity: 0;
  cursor: pointer;
}
.cm-fileinput__input:focus-visible + .cm-fileinput__trigger {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.cm-fileinput__trigger {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  padding: 0 var(--s-3);
  flex: 1;
  font: var(--t-body-sm);
  color: var(--ink-2);
  cursor: pointer;
  min-width: 0;
}
.cm-fileinput__cta {
  font-weight: 600;
  color: var(--ink-1);
  flex: none;
}
.cm-fileinput__filename {
  color: var(--ink-3);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
.cm-fileinput.is-filled .cm-fileinput__filename { color: var(--ink-1); }
.cm-fileinput__icon { flex: none; opacity: 0.7; }
.cm-fileinput__clear {
  position: relative;
  z-index: 1;
  border: none;
  background: transparent;
  color: var(--ink-3);
  font-size: 18px;
  line-height: 1;
  width: 36px;
  cursor: pointer;
  border-left: 1px solid var(--hairline);
}
.cm-fileinput__clear:hover { color: var(--danger); }
.cm-fileinput__preview {
  margin-top: var(--s-2);
  max-width: 100%;
  max-height: 180px;
  object-fit: contain;
  border-radius: var(--r-2);
  border: 1px solid var(--hairline);
  background: var(--surface-alt);
  display: block;
}
:root[data-form-factor="pos"] .cm-fileinput { height: 48px; }
@media (min-aspect-ratio: 9/10) and (max-aspect-ratio: 10/9) and (pointer: coarse) {
  .cm-fileinput { height: 48px; }
}

/* ----- Data row (spec §5.6) ----- */
.cm-rows {
  display: flex; flex-direction: column;
}
.cm-row {
  display: grid;
  grid-template-columns: 28px 1.5fr 1fr 100px 90px;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-3) var(--s-4);
  border-radius: var(--r-2);
  cursor: default;
}
.cm-row + .cm-row { border-top: 1px solid var(--hairline); }
.cm-row__rank { text-align: center; font: 700 12px/1 var(--font-serif); color: var(--accent-deep); }
.cm-row__name { font: 600 13px/20px var(--font-sans); color: var(--ink-1); }
.cm-row__sub  { font: var(--t-body-sm); color: var(--ink-3); margin-top: 2px; }
.cm-row__count { font: 700 13px/1 var(--font-serif); color: var(--display-fg); }
.cm-row__count-unit { font: var(--t-body-sm); color: var(--ink-3); margin-left: 4px; letter-spacing: 0.05em; }

/* Hover only on cursor-fine devices */
@media (hover: hover) and (pointer: fine) {
  .cm-row[data-href]:hover,
  .cm-row.is-clickable:hover {
    background: var(--surface-alt);
    cursor: pointer;
  }
}

/* Per-page row shape overrides (spec §5.6 — exact shapes) */
.cm-row--users {
  grid-template-columns: 44px 1.4fr 130px 100px 100px;
}
.cm-row--subs {
  grid-template-columns: 100px 1.4fr 70px 130px 100px;
}
.cm-row--user-history {
  grid-template-columns: 40px 110px 90px 70px 130px 100px;
}

/* Responsive: collapse to card layout below sm (spec §5.6) */
@media (max-width: 767px) {
  .cm-row,
  .cm-row--users,
  .cm-row--subs,
  .cm-row--user-history {
    grid-template-columns: 44px 1fr auto;
    grid-auto-flow: row;
  }
}

/* POS: 56 px row */
:root[data-form-factor="pos"] .cm-row { min-height: 56px; }
@media (min-aspect-ratio: 9/10) and (max-aspect-ratio: 10/9) and (pointer: coarse) {
  .cm-row { min-height: 56px; }
}

/* ----- Sidebar (spec §5.1) ----- */
.cm-app {
  display: grid;
  grid-template-columns: 1fr;
  min-height: 100dvh;
  background: var(--bg-page);
}
@media (min-width: 1024px) { .cm-app { grid-template-columns: 72px 1fr; } }
@media (min-width: 1280px) { .cm-app { grid-template-columns: 248px 1fr; } }

.cm-side {
  background: var(--side-bg);
  color: #FAF6EA;
  display: flex; flex-direction: column;
  padding: 20px 0 18px;
}
/* Pin sidebar to viewport on desktop so the bottom prefs/logout never drops below the fold
   when the main column scrolls (long lists on 14" laptops, etc). */
@media (min-width: 1024px) {
  .cm-side {
    position: sticky;
    top: 0;
    align-self: start;
    height: 100dvh;
    max-height: 100dvh;
    overflow-y: auto;
    overscroll-behavior: contain;
  }
}
@media (max-width: 1023px) {
  .cm-side {
    position: fixed; inset: 0 auto 0 0;
    width: 248px;
    transform: translateX(-100%);
    transition: transform var(--d-slow) var(--ease-out);
    z-index: 30;
    overflow-y: auto;
    overscroll-behavior: contain;
  }
  .cm-side.is-open { transform: translateX(0); }
}

.cm-side__brand {
  display: flex; align-items: center; gap: 12px;
  padding: 0 22px var(--s-5);
  border-bottom: 1px solid rgba(255,255,255,0.06);
  margin-bottom: var(--s-4);
}
.cm-side__mark {
  width: 38px; height: 38px;
  border-radius: 9px;
  background-image: url("/logo.jpg");
  background-size: cover;
  flex-shrink: 0;
}
.cm-side__brand-tag {
  font: var(--t-eyebrow);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--accent-hi);
  margin-bottom: 2px;
}
.cm-side__brand-name {
  font: 700 16px/1.05 var(--font-serif);
  color: #FAF6EA;
  letter-spacing: 0.005em;
}

.cm-side__nav    { padding: 0 12px; display: flex; flex-direction: column; gap: 1px; flex: 1; }
.cm-side__group  {
  font: var(--t-eyebrow);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(229, 199, 123, 0.55);
  padding: 14px 12px 6px;
}
.cm-side__link {
  display: flex; align-items: center; gap: 11px;
  padding: 8px 12px;
  border-radius: var(--r-2);
  font: 500 13px/1.2 var(--font-sans);
  color: rgba(250, 246, 234, 0.72);
  text-decoration: none;
}
.cm-side__link:hover { color: #FAF6EA; }
.cm-side__link.is-active {
  background: rgba(229, 199, 123, 0.10);
  color: #FAF6EA;
  font-weight: 600;
  box-shadow: inset 2px 0 0 var(--accent);
}
.cm-side__icon { width: 14px; height: 14px; flex-shrink: 0; color: currentColor; }
.cm-side__count {
  margin-left: auto;
  font: 600 10px/1 var(--font-sans);
  background: rgba(229, 199, 123, 0.12);
  color: var(--accent-hi);
  padding: 2px 7px;
  border-radius: var(--r-full);
}

.cm-side__bottom {
  margin-top: auto;
  padding: 14px 18px 4px;
  border-top: 1px solid rgba(255,255,255,0.06);
  display: flex; flex-direction: column;
  gap: 12px;
}

/* Rail mode (1024–1279) — collapse labels and group headers */
@media (min-width: 1024px) and (max-width: 1279px) {
  .cm-side__brand        { padding: 0 16px var(--s-4); justify-content: center; }
  .cm-side__brand-text   { display: none; }
  .cm-side__group        { display: none; }
  .cm-side__link         { justify-content: center; }
  .cm-side__link > span:not([data-icon]) { display: none; }
  .cm-side__link.is-active { box-shadow: inset 0 2px 0 var(--accent); }
  .cm-side__bottom       { padding: 14px 8px; align-items: center; gap: 10px; }

  /* Stack lang + theme switcher vertically, shrink to fit 72px column */
  .cm-side__prefs        { flex-direction: column; align-items: center; gap: 8px; width: 100%; }
  .cm-side__prefs .cm-lang {
    padding: 0 6px;
    min-width: 40px;
    text-align: center;
    text-align-last: center;
  }

  /* User card: avatar only — hide name + role + their wrapper */
  .cm-side__user         { justify-content: center; gap: 0; }
  .cm-side__user > div:not(.cm-avatar) { display: none; }

  /* Logout button: icon-only square */
  .cm-side .cm-btn--ghost {
    width: 40px;
    height: 40px;
    padding: 0;
    aspect-ratio: 1;
  }
  .cm-side .cm-btn--ghost > span:not([data-icon]) { display: none; }
}

/* Drawer backdrop (under 1024) */
.cm-side-backdrop {
  position: fixed; inset: 0;
  background: rgba(0,0,0,0.5);
  z-index: 25;
  opacity: 0; pointer-events: none;
  transition: opacity var(--d-base) var(--ease-out);
}
.cm-side-backdrop.is-active { opacity: 1; pointer-events: auto; }

/* Hamburger trigger (drawer only) */
.cm-mobile-trigger {
  display: none;
  width: 44px; height: 44px;
  border-radius: var(--r-3);
  background: var(--surface);
  border: 1px solid var(--ink-3);
  color: var(--ink-1);
  align-items: center; justify-content: center;
  cursor: pointer;
  transition: background var(--d-fast) var(--ease-out), border-color var(--d-fast) var(--ease-out);
}
.cm-mobile-trigger:hover { background: var(--surface-alt); border-color: var(--ink-1); }
.cm-mobile-trigger:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (max-width: 1023px) { .cm-mobile-trigger { display: inline-flex; } }
:root[data-form-factor="pos"] .cm-mobile-trigger { width: 56px; height: 56px; }
@media (min-aspect-ratio: 9/10) and (max-aspect-ratio: 10/9) and (pointer: coarse) {
  .cm-mobile-trigger { width: 56px; height: 56px; }
}

/* ----- Main content area + Top bar (spec §5.2) ----- */
.cm-main {
  background: var(--bg-page);
  padding: var(--s-7) var(--s-8) var(--s-8);
  display: flex; flex-direction: column;
  gap: var(--s-6);
  min-width: 0;
}
@media (max-width: 1279px) { .cm-main { padding: var(--s-6) var(--s-7); } }
@media (max-width: 1023px) { .cm-main { padding: var(--s-5) var(--s-6); } }
@media (max-width: 767px)  { .cm-main { padding: var(--s-5) var(--s-5); gap: var(--s-5); } }
@media (max-width: 599px)  { .cm-main { padding: var(--s-4) var(--s-4); gap: var(--s-4); } }
:root[data-form-factor="pos"] .cm-main { padding: var(--s-5) var(--s-5); }
@media (min-aspect-ratio: 9/10) and (max-aspect-ratio: 10/9) and (pointer: coarse) {
  .cm-main { padding: var(--s-5) var(--s-5); }
}

.cm-topbar {
  display: flex; align-items: center; gap: var(--s-4);
}
.cm-topbar__title-block { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.cm-topbar__eyebrow { font: var(--t-eyebrow); letter-spacing: 0.18em; text-transform: uppercase; color: var(--accent-deep); }
:root[data-theme="dark"] .cm-topbar__eyebrow { color: var(--accent); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):not([data-theme="dark"]) .cm-topbar__eyebrow {
    color: var(--accent);
  }
}
.cm-topbar__title { font: var(--t-display); color: var(--display-fg); letter-spacing: -0.005em; }
.cm-topbar__spacer { flex: 1; }
.cm-topbar__actions { display: inline-flex; align-items: center; gap: var(--s-3); }

/* Global NFC status pill — injected by _topbar.html, driven by cm-nfc.js.
   `margin-left: auto` parks it on the right edge of the topbar row even when
   the .cm-topbar__spacer is hidden by responsive rules below 1024px, so the
   pill never visually glues to the page title. */
.cm-nfc-pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-left: auto;
  padding: 6px 12px 6px 10px;
  border-radius: 999px;
  font: 500 12px/1 var(--font-sans);
  letter-spacing: 0.02em;
  background: color-mix(in oklab, var(--ink-1) 6%, transparent);
  color: var(--ink-2);
  border: 1px solid var(--ink-3);
  white-space: nowrap;
  transition: background var(--motion-fast) var(--ease-emphatic), color var(--motion-fast) var(--ease-emphatic), border-color var(--motion-fast) var(--ease-emphatic);
}
.cm-nfc-pill__dot {
  width: 8px;
  height: 8px;
  border-radius: 999px;
  background: var(--ink-3);
  flex: none;
}
.cm-nfc-pill[data-state="online"] {
  background: color-mix(in oklab, var(--success) 14%, transparent);
  color: var(--success);
  border-color: color-mix(in oklab, var(--success) 35%, transparent);
}
.cm-nfc-pill[data-state="online"] .cm-nfc-pill__dot {
  background: var(--success);
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--success) 22%, transparent);
}
.cm-nfc-pill[data-state="reader-disconnected"] {
  background: color-mix(in oklab, var(--accent) 12%, transparent);
  color: var(--accent);
  border-color: color-mix(in oklab, var(--accent) 35%, transparent);
}
.cm-nfc-pill[data-state="reader-disconnected"] .cm-nfc-pill__dot { background: var(--accent); }
.cm-nfc-pill[data-state="waiting"],
.cm-nfc-pill[data-state="writing"] {
  background: color-mix(in oklab, var(--accent) 14%, transparent);
  color: var(--accent);
  border-color: color-mix(in oklab, var(--accent) 40%, transparent);
}
.cm-nfc-pill[data-state="waiting"] .cm-nfc-pill__dot,
.cm-nfc-pill[data-state="writing"] .cm-nfc-pill__dot {
  background: var(--accent);
  animation: cmNfcPulse 1.4s ease-in-out infinite;
}
.cm-nfc-pill[data-state="success"] {
  background: color-mix(in oklab, var(--success) 18%, transparent);
  color: var(--success);
  border-color: color-mix(in oklab, var(--success) 50%, transparent);
}
.cm-nfc-pill[data-state="success"] .cm-nfc-pill__dot { background: var(--success); }
.cm-nfc-pill[data-state="error"] {
  background: color-mix(in oklab, var(--danger) 14%, transparent);
  color: var(--danger);
  border-color: color-mix(in oklab, var(--danger) 40%, transparent);
}
.cm-nfc-pill[data-state="error"] .cm-nfc-pill__dot { background: var(--danger); }

@keyframes cmNfcPulse {
  0%, 100% { transform: scale(1);   opacity: 1;   }
  50%      { transform: scale(1.4); opacity: 0.65;}
}

/* On narrow screens, only show the dot to save horizontal room */
@media (max-width: 559px) {
  .cm-nfc-pill { padding: 6px; }
  .cm-nfc-pill__label { display: none; }
}

/* Smaller layouts: stack into 2 rows */
@media (max-width: 1023px) {
  .cm-topbar { flex-wrap: wrap; }
  .cm-topbar__spacer { display: none; }
  .cm-topbar__actions { width: 100%; justify-content: flex-end; flex-wrap: wrap; }
}

/* Two-column section grid (spec §9 dashboard) */
.cm-grid-2 { display: grid; grid-template-columns: 1fr; gap: var(--s-4); }
@media (min-width: 1024px) { .cm-grid-2 { grid-template-columns: 1.6fr 1fr; } }

/* ----- Modal (spec §5.9) ----- */
.cm-modal-backdrop {
  position: fixed; inset: 0;
  background: rgba(0,0,0,0.5);
  display: none;
  align-items: center; justify-content: center;
  padding: var(--s-7);
  z-index: 50;
}
:root[data-theme="dark"] .cm-modal-backdrop { background: rgba(0,0,0,0.7); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):not([data-theme="dark"]) .cm-modal-backdrop {
    background: rgba(0,0,0,0.7);
  }
}
.cm-modal-backdrop.is-open { display: flex; }

.cm-modal {
  background: var(--surface);
  border-radius: var(--r-5);
  box-shadow: var(--shadow-modal);
  width: 100%;
  max-width: 520px;
  display: flex; flex-direction: column;
  max-height: calc(100dvh - 48px);
  overflow: hidden;
}
.cm-modal--md { max-width: 720px; }
.cm-modal--lg { max-width: 880px; }

.cm-modal__head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--s-3);
  padding: var(--s-5) var(--s-6);
  border-bottom: 1px solid var(--hairline);
}
.cm-modal__head-text { min-width: 0; flex: 1; }
.cm-modal__eyebrow {
  display: block;
  font: 600 9.5px/1 var(--font-sans);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--accent-deep);
  margin-bottom: 6px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
:root[data-theme="dark"] .cm-modal__eyebrow { color: var(--accent-hi); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):not([data-theme="dark"]) .cm-modal__eyebrow {
    color: var(--accent-hi);
  }
}
.cm-modal__eyebrow--danger { color: var(--danger); }
:root[data-theme="dark"] .cm-modal__eyebrow--danger { color: var(--danger); }
.cm-modal__title { font: var(--t-display-sm); color: var(--display-fg); }
.cm-modal__close {
  width: 36px; height: 36px;
  border: 1px solid var(--hairline);
  border-radius: var(--r-2);
  background: color-mix(in oklab, var(--ink-1) 4%, transparent);
  color: var(--ink-3);
  cursor: pointer;
  flex-shrink: 0;
  font: 400 22px/1 var(--font-sans);
  display: inline-flex; align-items: center; justify-content: center;
  transition: background var(--motion-fast) var(--ease-emphatic), color var(--motion-fast) var(--ease-emphatic);
}
.cm-modal__close:hover {
  background: color-mix(in oklab, var(--ink-1) 8%, transparent);
  color: var(--ink-1);
}
.cm-modal__body   {
  display: flex; flex-direction: column; gap: var(--s-4);
  padding: var(--s-5) var(--s-6); overflow: auto; flex: 1;
}
/* Margins inside the body are gap-driven now; null inline `margin-top` resets
   on hint/banner/paragraphs so siblings space evenly via the flex gap. */
.cm-modal__body > * { margin: 0; }
.cm-modal__footer {
  display: flex; align-items: center; justify-content: flex-end;
  gap: var(--s-3);
  padding: var(--s-4) var(--s-6) var(--s-5);
  border-top: 1px solid var(--hairline);
}

/* Bottom-sheet under sm (spec §5.9) */
@media (max-width: 599px) {
  .cm-modal-backdrop { padding: 0; align-items: flex-end; }
  .cm-modal {
    max-width: none;
    border-radius: var(--r-5) var(--r-5) 0 0;
    animation: cm-slide-up var(--d-slow) var(--ease-out);
    max-height: 90dvh;
  }
  .cm-modal__footer { flex-direction: column; align-items: stretch; gap: var(--s-2); }
  .cm-modal__footer .cm-btn { width: 100%; }
}
@keyframes cm-slide-up { from { transform: translateY(100%); } to { transform: translateY(0); } }

/* POS form factor: top-anchored, full-width minus 16 px gutter, all corners rounded */
:root[data-form-factor="pos"] .cm-modal-backdrop,
:root[data-form-factor="pos"] .cm-modal-backdrop.is-open {
  padding: 0;
  align-items: flex-start;
}
:root[data-form-factor="pos"] .cm-modal {
  margin: 16px;
  border-radius: var(--r-5);
  max-width: none;
  max-height: calc(100dvh - 32px);
}
:root[data-form-factor="pos"] .cm-modal__footer {
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-3);
}
:root[data-form-factor="pos"] .cm-modal__footer .cm-btn { height: 48px; width: 100%; }
:root[data-form-factor="pos"] .cm-modal__close { width: 44px; height: 44px; }
@media (min-aspect-ratio: 9/10) and (max-aspect-ratio: 10/9) and (pointer: coarse) {
  .cm-modal-backdrop { padding: 0; align-items: flex-start; }
  .cm-modal {
    margin: 16px;
    border-radius: var(--r-5);
    max-width: none;
    max-height: calc(100dvh - 32px);
  }
  .cm-modal__footer { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-3); }
  .cm-modal__footer .cm-btn { height: 48px; width: 100%; }
  .cm-modal__close { width: 44px; height: 44px; }
}

/* ===========================================================================
   Modal polish (cashier brainstorm 11)
   - .cm-hint     : note/explanation box with colored left accent
   - .cm-btn--save: green primary CTA with the signature gold underline
   =========================================================================== */
.cm-hint {
  font: 500 12.5px/1.55 var(--font-sans);
  color: var(--ink-2);
  padding: var(--s-3) var(--s-4);
  background: color-mix(in oklab, var(--ink-1) 5%, transparent);
  border-radius: var(--r-3);
  border-left: 3px solid color-mix(in oklab, var(--success) 55%, transparent);
}
.cm-hint strong { color: var(--success); font-weight: 700; }
.cm-hint code {
  background: color-mix(in oklab, var(--success) 8%, transparent);
  padding: 1px 6px; border-radius: 4px;
  font: 500 11px/1 var(--font-mono, ui-monospace, "SF Mono", Monaco, Menlo, monospace);
  color: var(--success);
}
.cm-hint--danger {
  border-left-color: color-mix(in oklab, var(--danger) 70%, transparent);
  background: color-mix(in oklab, var(--danger) 6%, transparent);
}
.cm-hint--danger strong { color: var(--danger); }
.cm-hint--gold {
  border-left-color: color-mix(in oklab, var(--accent) 70%, transparent);
  background: color-mix(in oklab, var(--accent) 6%, transparent);
}
.cm-hint--gold strong { color: var(--accent-deep); }
:root[data-theme="dark"] .cm-hint                { color: var(--ink-1); }
:root[data-theme="dark"] .cm-hint strong         { color: var(--ink-1); }
:root[data-theme="dark"] .cm-hint--gold strong   { color: var(--accent-hi); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):not([data-theme="dark"]) .cm-hint              { color: var(--ink-1); }
  :root:not([data-theme="light"]):not([data-theme="dark"]) .cm-hint strong       { color: var(--ink-1); }
  :root:not([data-theme="light"]):not([data-theme="dark"]) .cm-hint--gold strong { color: var(--accent-hi); }
}

/* The signature green-with-gold-underline save CTA. Use either .cm-btn--save
   or just rely on the modal footer auto-promoting --primary buttons. In dark
   theme --brand becomes gold, so the underline switches to the success green
   to preserve contrast. */
.cm-btn--save {
  background: var(--brand);
  color: var(--on-brand);
  font-weight: 600;
  border: none;
  box-shadow: inset 0 -2px 0 var(--accent);
}
.cm-btn--save:hover { background: var(--brand-hover); }
:root[data-theme="dark"] .cm-btn--save        { box-shadow: inset 0 -2px 0 var(--success); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):not([data-theme="dark"]) .cm-btn--save {
    box-shadow: inset 0 -2px 0 var(--success);
  }
}
.cm-modal__footer .cm-btn--primary,
.cm-modal__footer .cm-btn--save {
  box-shadow: inset 0 -2px 0 var(--accent);
}
:root[data-theme="dark"] .cm-modal__footer .cm-btn--primary,
:root[data-theme="dark"] .cm-modal__footer .cm-btn--save {
  box-shadow: inset 0 -2px 0 var(--success);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):not([data-theme="dark"]) .cm-modal__footer .cm-btn--primary,
  :root:not([data-theme="light"]):not([data-theme="dark"]) .cm-modal__footer .cm-btn--save {
    box-shadow: inset 0 -2px 0 var(--success);
  }
}

/* ----- Avatar (spec §5.13) ----- */
.cm-avatar {
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--r-full);
  font: 600 14px/1 var(--font-serif);
  color: #FAF6EA;
  background: linear-gradient(135deg, var(--accent), var(--accent-deep));
  flex-shrink: 0;
  overflow: hidden;
}
.cm-avatar--xs { width: 24px; height: 24px; font-size: 10px; }
.cm-avatar--sm { width: 28px; height: 28px; font-size: 11px; }
.cm-avatar--md { width: 32px; height: 32px; font-size: 12px; }
.cm-avatar--lg { width: 40px; height: 40px; font-size: 14px; }
.cm-avatar--xl { width: 64px; height: 64px; font-size: 22px; }
.cm-avatar--2xl{ width: 96px; height: 96px; font-size: 30px; }
.cm-avatar--3xl{ width: 150px; height: 150px; font-size: 56px; }
.cm-avatar img { width: 100%; height: 100%; object-fit: cover; }

/* POS avatar bump on user_detail */
:root[data-form-factor="pos"] .cm-avatar--user-detail { width: 180px; height: 180px; font-size: 64px; }
@media (min-aspect-ratio: 9/10) and (max-aspect-ratio: 10/9) and (pointer: coarse) {
  .cm-avatar--user-detail { width: 180px; height: 180px; font-size: 64px; }
}

/* ----- Empty state (spec §5.14) ----- */
.cm-empty {
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--r-4);
  padding: 48px;
  text-align: center;
  display: flex; flex-direction: column; align-items: center; gap: var(--s-3);
}
.cm-empty__icon { width: 32px; height: 32px; color: var(--ink-4); }
.cm-empty__title { font: var(--t-h2); color: var(--display-fg); }
.cm-empty__body { font: var(--t-body); color: var(--ink-3); max-width: 360px; }

/* ----- Pagination (spec §5.15) ----- */
.cm-pagination {
  display: flex; align-items: center; justify-content: center;
  gap: var(--s-4);
  padding: var(--s-3) 0;
}
.cm-pagination__meta { font: var(--t-body-sm); color: var(--ink-3); font-feature-settings: "tnum" 1, "lnum" 1; }
@media (max-width: 767px) {
  .cm-pagination__meta { font-size: 11px; }
}

/* ----- Theme switcher (spec §5.11) ----- */
.cm-theme-switcher {
  display: inline-flex;
  background: rgba(255,255,255,0.05);
  border: 1px solid rgba(229, 199, 123, 0.18);
  border-radius: var(--r-full);
  padding: 2px;
  width: 60px; height: 30px;
  cursor: pointer;
}
.cm-theme-switcher__seg {
  flex: 1;
  display: inline-flex; align-items: center; justify-content: center;
  border: none; background: transparent;
  color: var(--ink-3);
  border-radius: var(--r-full);
  cursor: pointer;
}
.cm-theme-switcher__seg svg { width: 14px; height: 14px; }
.cm-theme-switcher__seg.is-active {
  background: rgba(229, 199, 123, 0.18);
  color: var(--accent-hi);
  box-shadow: inset 0 0 0 1px var(--accent);
}

/* ----- Lang picker (spec §5.12) ----- */
.cm-lang {
  display: inline-flex; align-items: center; gap: 6px;
  height: 30px; padding: 0 10px;
  background: rgba(255,255,255,0.04);
  border: 1px solid rgba(229, 199, 123, 0.12);
  border-radius: var(--r-full);
  font: var(--t-body-sm); color: rgba(250, 246, 234, 0.85);
  cursor: pointer; appearance: none;
}
.cm-lang option { background: var(--surface); color: var(--ink-1); }

/* ----- Status banner (spec §9 user_detail) ----- */
.cm-banner {
  display: flex; align-items: center; gap: var(--s-3);
  padding: 14px 18px;
  border-radius: var(--r-3);
  border-left: 3px solid;
}
.cm-banner--ok      { background: var(--success-bg); border-left-color: var(--success); color: var(--success); }
.cm-banner--warn    { background: var(--warning-bg); border-left-color: var(--warning); color: var(--warning); }
.cm-banner--danger  { background: var(--danger-bg);  border-left-color: var(--danger);  color: var(--danger); }
.cm-banner__title   { font: 700 14px/1.2 var(--font-sans); }
.cm-banner__sub     { font: var(--t-body-sm); color: var(--ink-3); margin-top: 2px; }

/* ----- Toast (placeholder for NFC) ----- */
.cm-toast {
  position: fixed; right: 16px; bottom: 16px;
  background: #1A1A1A;
  color: #FAF6EA;
  border-radius: var(--r-4);
  padding: var(--s-4);
  border-left: 4px solid var(--accent);
  box-shadow: var(--shadow-modal);
  max-width: 460px;
}

/* Theme switcher container layout (placed in sidebar bottom) */
.cm-side__prefs {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s-2);
}
.cm-side__user {
  display: flex; align-items: center; gap: 10px;
}
.cm-side__user-name { font: 600 12px/1 var(--font-sans); color: #FAF6EA; }
.cm-side__user-role { font: 500 10px/1 var(--font-sans); color: rgba(229, 199, 123, 0.7); margin-top: 1px; }

/* Login (spec §9 admin login) */
.cm-login-body {
  min-height: 100dvh;
  display: grid; place-items: center;
  background: var(--bg-page);
  padding: var(--s-5);
}
.cm-login {
  width: 100%;
  max-width: 420px;
}
.cm-login__card { padding: var(--s-7) var(--s-7); display: flex; flex-direction: column; gap: var(--s-5); }
.cm-login__brand { display: flex; align-items: center; gap: var(--s-3); }
.cm-login__brand-text { display: flex; flex-direction: column; gap: 2px; }
.cm-login__title { font: var(--t-display-sm); color: var(--display-fg); margin: var(--s-2) 0 0; }
.cm-login__form { display: flex; flex-direction: column; gap: var(--s-3); }
.cm-login__submit { width: 100%; height: 44px; }
.cm-login__prefs { display: flex; align-items: center; justify-content: space-between; gap: var(--s-3); padding-top: var(--s-3); border-top: 1px solid var(--hairline); }
@media (max-width: 599px) {
  .cm-login { max-width: none; padding: 0 var(--s-2); }
}
:root[data-form-factor="pos"] .cm-login { max-width: none; padding: 0 var(--s-2); }
@media (min-aspect-ratio: 9/10) and (max-aspect-ratio: 10/9) and (pointer: coarse) {
  .cm-login { max-width: none; padding: 0 var(--s-2); }
}

/* ============================================================
 * Contrast fixes for canary scope
 * - Login brand block: replace borrowed .cm-side__* (cream-on-cream).
 * - Login lang picker + theme switcher: scope to light card surface.
 * - Sidebar ghost button: sidebar bg is always dark, so always cream text.
 * ============================================================ */

/* Login brand block — theme-aware, works on the white card */
.cm-login__mark {
  width: 64px; height: 64px;
  border-radius: 14px;
  background-image: url("/logo.jpg");
  background-size: cover;
  flex-shrink: 0;
}
.cm-login__brand-tag {
  font: var(--t-eyebrow);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--accent-deep);
}
:root[data-theme="dark"] .cm-login__brand-tag { color: var(--accent); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):not([data-theme="dark"]) .cm-login__brand-tag {
    color: var(--accent);
  }
}
.cm-login__brand-name {
  font: 700 22px/1.05 var(--font-serif);
  color: var(--display-fg);
  letter-spacing: 0.005em;
}

/* Lang picker on the login card — light bg → dark text */
.cm-login__prefs .cm-lang {
  background: var(--surface-alt);
  border-color: var(--hairline-2);
  color: var(--ink-1);
}
.cm-login__prefs .cm-lang option {
  background: var(--surface);
  color: var(--ink-1);
}

/* Theme switcher segs on the login card — adopt theme-aware ink colors */
.cm-login__prefs .cm-theme-switcher__seg { color: var(--ink-3); }
.cm-login__prefs .cm-theme-switcher__seg:hover { color: var(--ink-1); }
.cm-login__prefs .cm-theme-switcher__seg.is-active {
  color: var(--accent-deep);
  background: rgba(201, 162, 75, 0.16);
  box-shadow: inset 0 0 0 1px var(--accent-deep);
}
:root[data-theme="dark"] .cm-login__prefs .cm-theme-switcher__seg.is-active {
  color: var(--accent-hi);
  background: rgba(229, 199, 123, 0.18);
  box-shadow: inset 0 0 0 1px var(--accent);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):not([data-theme="dark"]) .cm-login__prefs .cm-theme-switcher__seg.is-active {
    color: var(--accent-hi);
    background: rgba(229, 199, 123, 0.18);
    box-shadow: inset 0 0 0 1px var(--accent);
  }
}

/* Sidebar ghost button (logout) — sidebar bg is always dark, so always cream */
.cm-side .cm-btn--ghost {
  background: transparent;
  color: rgba(250, 246, 234, 0.92);
  border: 1px solid rgba(229, 199, 123, 0.20);
}
.cm-side .cm-btn--ghost:hover {
  color: #FAF6EA;
  background: rgba(229, 199, 123, 0.10);
  border-color: rgba(229, 199, 123, 0.32);
}


/* ============================================================
 * Plan 2 — shared list/detail component classes + Quill skin
 * Used by: users / subscriptions / managers / feedbacks /
 * partner_offers list pages, all detail pages, and offer_policy
 * Quill editor.
 * ============================================================ */

/* Filter strip — used by users / managers / subscriptions / feedbacks / partner_offers / manager_detail */
.cm-filter-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--s-3);
  align-items: end;
}
@media (min-width: 600px) { .cm-filter-grid { grid-template-columns: 1.4fr 1fr 1fr auto; } }
@media (min-width: 1024px) { .cm-filter-grid { grid-template-columns: 1.4fr 1fr 1fr 1fr auto; } }

/* Detail-page meta grid — used by user_detail / manager_detail / subscription_detail / feedback_detail / partner_offer_detail */
.cm-meta-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: var(--s-3) var(--s-5);
}
.cm-meta-grid__cell    { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.cm-meta-grid__label   { font: var(--t-eyebrow); letter-spacing: 0.18em; text-transform: uppercase; color: var(--ink-3); }
.cm-meta-grid__value   { font: var(--t-body); color: var(--ink-1); overflow-wrap: anywhere; }

/* Detail-page header */
.cm-detail-head        { display: flex; align-items: center; gap: var(--s-4); flex-wrap: wrap; }
.cm-detail-head__text  { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.cm-detail-head__sub   { font: var(--t-eyebrow); letter-spacing: 0.18em; text-transform: uppercase; color: var(--accent-deep); }
.cm-detail-head__name  { font: var(--t-display-sm); color: var(--display-fg); }
:root[data-theme="dark"] .cm-detail-head__sub { color: var(--accent); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):not([data-theme="dark"]) .cm-detail-head__sub { color: var(--accent); }
}

/* Action row — Add subscription / Write to NFC / Reset password / etc.
   All buttons share one fixed height so they baseline-align cleanly when the
   row wraps; primary remains visually emphasized via colour, not size. */
.cm-action-row { display: flex; gap: var(--s-3); flex-wrap: wrap; }
.cm-action-row > .cm-btn { flex: 1 1 200px; height: 48px; }
:root[data-form-factor="pos"] .cm-action-row > .cm-btn { flex: 1; height: 56px; }
@media (min-aspect-ratio: 9/10) and (max-aspect-ratio: 10/9) and (pointer: coarse) {
  .cm-action-row > .cm-btn { flex: 1; height: 56px; }
}

/* Reply block — feedback_detail / partner_offer_detail */
.cm-reply             { display: flex; flex-direction: column; gap: var(--s-3); }
.cm-reply__textarea   { min-height: 120px; resize: vertical; }
.cm-reply__meta       { font: var(--t-body-sm); color: var(--ink-3); }

/* Quill skin — offer_policy */
/* Quill toolbar/container — :root prefix gives 0,3,0 specificity so we beat
   quill.snow.css which loads after theme.css from offer_policy.html's body.
   Without this, Quill's hard-coded #444 strokes win in dark mode and the
   B/I/U/list/heading/link/clean glyphs become near-invisible. */
:root .ql-toolbar.ql-snow,
:root .ql-container.ql-snow { border-color: var(--hairline-2); }
:root .ql-toolbar.ql-snow   { background: var(--surface-alt); border-radius: var(--r-3) var(--r-3) 0 0; }
:root .ql-container.ql-snow { background: var(--surface); border-radius: 0 0 var(--r-3) var(--r-3); }
:root .ql-snow .ql-editor   { color: var(--ink-1); }
:root .ql-snow .ql-editor.ql-blank::before { color: var(--ink-3); font-style: normal; }
.ql-editor            { color: var(--ink-1); font: var(--t-body); min-height: 280px; }
:root .ql-snow .ql-stroke   { stroke: var(--ink-2); }
:root .ql-snow .ql-fill     { fill: var(--ink-2); }
:root .ql-snow .ql-stroke.ql-fill { fill: var(--ink-2); }
:root .ql-snow .ql-picker   { color: var(--ink-2); }
:root .ql-snow .ql-picker-options { background: var(--surface); border-color: var(--hairline-2); }
:root .ql-snow .ql-picker-item   { color: var(--ink-2); }

/* Hover / active glyphs adopt the gold accent, theme-aware */
:root .ql-snow .ql-active .ql-stroke,
:root .ql-snow button:hover .ql-stroke,
:root .ql-snow .ql-picker-label:hover .ql-stroke,
:root .ql-snow .ql-picker-label.ql-active .ql-stroke,
:root .ql-snow .ql-picker-item:hover .ql-stroke,
:root .ql-snow .ql-picker-item.ql-selected .ql-stroke { stroke: var(--accent-deep); }
:root .ql-snow .ql-active .ql-fill,
:root .ql-snow button:hover .ql-fill,
:root .ql-snow .ql-picker-label:hover .ql-fill,
:root .ql-snow .ql-picker-label.ql-active .ql-fill,
:root .ql-snow .ql-picker-item:hover .ql-fill,
:root .ql-snow .ql-picker-item.ql-selected .ql-fill { fill: var(--accent-deep); }
:root .ql-snow button:hover, :root .ql-snow .ql-picker-label:hover,
:root .ql-snow .ql-picker-label.ql-active, :root .ql-snow .ql-picker-item:hover,
:root .ql-snow .ql-picker-item.ql-selected { color: var(--accent-deep); }

:root[data-theme="dark"] .ql-snow .ql-active .ql-stroke,
:root[data-theme="dark"] .ql-snow button:hover .ql-stroke,
:root[data-theme="dark"] .ql-snow .ql-picker-label:hover .ql-stroke,
:root[data-theme="dark"] .ql-snow .ql-picker-label.ql-active .ql-stroke,
:root[data-theme="dark"] .ql-snow .ql-picker-item:hover .ql-stroke,
:root[data-theme="dark"] .ql-snow .ql-picker-item.ql-selected .ql-stroke { stroke: var(--accent); }
:root[data-theme="dark"] .ql-snow .ql-active .ql-fill,
:root[data-theme="dark"] .ql-snow button:hover .ql-fill,
:root[data-theme="dark"] .ql-snow .ql-picker-label:hover .ql-fill,
:root[data-theme="dark"] .ql-snow .ql-picker-label.ql-active .ql-fill,
:root[data-theme="dark"] .ql-snow .ql-picker-item:hover .ql-fill,
:root[data-theme="dark"] .ql-snow .ql-picker-item.ql-selected .ql-fill { fill: var(--accent); }
:root[data-theme="dark"] .ql-snow button:hover, :root[data-theme="dark"] .ql-snow .ql-picker-label:hover,
:root[data-theme="dark"] .ql-snow .ql-picker-label.ql-active, :root[data-theme="dark"] .ql-snow .ql-picker-item:hover,
:root[data-theme="dark"] .ql-snow .ql-picker-item.ql-selected { color: var(--accent); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):not([data-theme="dark"]) .ql-snow .ql-active .ql-stroke,
  :root:not([data-theme="light"]):not([data-theme="dark"]) .ql-snow button:hover .ql-stroke,
  :root:not([data-theme="light"]):not([data-theme="dark"]) .ql-snow .ql-picker-label:hover .ql-stroke,
  :root:not([data-theme="light"]):not([data-theme="dark"]) .ql-snow .ql-picker-label.ql-active .ql-stroke,
  :root:not([data-theme="light"]):not([data-theme="dark"]) .ql-snow .ql-picker-item:hover .ql-stroke,
  :root:not([data-theme="light"]):not([data-theme="dark"]) .ql-snow .ql-picker-item.ql-selected .ql-stroke { stroke: var(--accent); }
  :root:not([data-theme="light"]):not([data-theme="dark"]) .ql-snow .ql-active .ql-fill,
  :root:not([data-theme="light"]):not([data-theme="dark"]) .ql-snow .ql-picker-label:hover .ql-fill,
  :root:not([data-theme="light"]):not([data-theme="dark"]) .ql-snow .ql-picker-label.ql-active .ql-fill { fill: var(--accent); }
}

/* ============================================================
 * Plan 2 — list-page data row primitive
 * Used by: users / subscriptions / managers / feedbacks /
 * partner_offers list pages, and any detail-page sub-list.
 * ============================================================ */
.cm-data-rows {
  display: flex;
  flex-direction: column;
}
.cm-data-row {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-3) var(--s-4);
  min-height: 56px;
}
.cm-data-row + .cm-data-row { border-top: 1px solid var(--hairline); }
.cm-data-row__text  { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.cm-data-row__title { font: 600 14px/1.3 var(--font-sans); color: var(--ink-1); overflow-wrap: anywhere; }
.cm-data-row__meta  { font: var(--t-body-sm); color: var(--ink-3); display: flex; flex-wrap: wrap; gap: var(--s-2); align-items: center; }
.cm-data-row__pills { display: inline-flex; flex-wrap: wrap; gap: var(--s-2); align-items: center; justify-self: end; }
.cm-data-row__trail { display: flex; align-items: center; gap: var(--s-3); justify-self: end; flex-wrap: wrap; }

/* Mobile: stack avatar+text on top, trail below */
@media (max-width: 640px) {
  .cm-data-row {
    grid-template-columns: auto 1fr;
    grid-template-areas: "avatar text" "trail trail";
    gap: var(--s-2) var(--s-3);
  }
  .cm-data-row > .cm-avatar,
  .cm-data-row > .cm-thumb  { grid-area: avatar; }
  .cm-data-row__text        { grid-area: text; }
  .cm-data-row__trail,
  .cm-data-row__pills       { grid-area: trail; justify-self: start; }
}

/* Thumb — small clickable image preview used in data rows for sign_photo and
   similar attachments. Rounded square, hairline frame, fills the avatar slot
   so the row layout doesn't shift when present. Subtle hover accent invites
   the click without competing with the row's primary link. */
.cm-thumb {
  width: 32px; height: 32px;
  flex: none;
  display: inline-flex;
  align-items: center; justify-content: center;
  border-radius: var(--r-2);
  overflow: hidden;
  background: var(--surface-alt);
  border: 1px solid var(--hairline);
  transition: border-color var(--motion-fast) var(--ease-emphatic), transform var(--motion-fast) var(--ease-emphatic);
}
.cm-thumb > img { width: 100%; height: 100%; object-fit: cover; display: block; }
.cm-thumb:hover { border-color: var(--accent); transform: scale(1.04); }
:root[data-form-factor="pos"] .cm-thumb { width: 40px; height: 40px; }

/* Photo frame — large preview block used on detail pages. Locks the image to a
   readable aspect ratio while preserving the full content (object-fit: contain
   over a soft surface), and turns the whole frame into the open-in-new-tab
   target for fast cashier verification. */
.cm-photo-frame {
  display: block;
  width: 100%;
  max-width: 720px;
  aspect-ratio: 4 / 3;
  border-radius: var(--r-3);
  overflow: hidden;
  background: var(--surface-alt);
  border: 1px solid var(--hairline);
  transition: border-color var(--motion-fast) var(--ease-emphatic);
}
.cm-photo-frame:hover { border-color: var(--accent); }
.cm-photo-frame > img { width: 100%; height: 100%; object-fit: contain; display: block; }

/* POS form factor: roomier rows + larger touch targets */
:root[data-form-factor="pos"] .cm-data-row { padding: var(--s-4) var(--s-5); min-height: 64px; }
@media (min-aspect-ratio: 9/10) and (max-aspect-ratio: 10/9) and (pointer: coarse) {
  .cm-data-row { padding: var(--s-4) var(--s-5); min-height: 64px; }
}

/* Pill name aliases — Plan 2 spec uses --ok / --muted; theme.css has --active / --neutral.
   The active styling itself lives next to .cm-pill--active above so the
   status-dot decoration applies consistently to both classes. */
.cm-pill--muted { background: var(--surface-alt); color: var(--ink-3); }
.cm-pill--danger-soft {
  background: color-mix(in oklab, var(--danger) 14%, transparent);
  color: var(--danger);
}

/* ===========================================================================
   Polished list card (cashier brainstorm 10) — used by users.html
   Adds: card title + meta header, column headers, denser rows with grid
   layout, status dot on avatar.
   =========================================================================== */
.cm-list-card { padding: 0; overflow: hidden; }
.cm-list-card__head {
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--s-4) var(--s-5);
  border-bottom: 1px solid var(--hairline);
}
.cm-list-card__title {
  font: 600 14px/1.2 var(--font-serif);
  color: var(--display-fg);
  margin: 0;
}
.cm-list-card__meta {
  font: 600 10px/1 var(--font-sans);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent-deep);
  font-feature-settings: "tnum" 1;
}
:root[data-theme="dark"] .cm-list-card__meta  { color: var(--accent-hi); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):not([data-theme="dark"]) .cm-list-card__meta  { color: var(--accent-hi); }
}

.cm-list-card__cols {
  display: grid;
  gap: var(--s-3);
  padding: var(--s-2) var(--s-5);
  border-bottom: 1px solid var(--hairline);
  font: 600 9.5px/1 var(--font-sans);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-3);
  align-items: center;
}
.cm-list-card__cols--users {
  grid-template-columns: 44px minmax(0, 1.4fr) 130px 130px 110px;
}

.cm-list-card__rows {
  display: flex; flex-direction: column;
}
.cm-list-row {
  display: grid;
  gap: var(--s-3);
  align-items: center;
  padding: var(--s-3) var(--s-5);
  min-height: 56px;
  text-decoration: none;
  color: var(--ink-1);
  transition: background var(--motion-fast) var(--ease-emphatic);
}
.cm-list-row + .cm-list-row {
  border-top: 1px solid var(--hairline);
}
.cm-list-row:hover  { background: color-mix(in oklab, var(--accent) 8%, transparent); }
.cm-list-row:focus-visible {
  outline: none;
  background: color-mix(in oklab, var(--accent) 14%, transparent);
  box-shadow: inset 3px 0 0 var(--accent);
}
.cm-list-row--users {
  grid-template-columns: 44px minmax(0, 1.4fr) 130px 130px 110px;
}
.cm-list-row__primary { min-width: 0; }
.cm-list-row__name {
  font: 600 14px/1.25 var(--font-sans);
  color: var(--ink-1);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cm-list-row__sub {
  font: 500 12px/1.3 var(--font-sans);
  color: var(--ink-3);
  margin-top: 2px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cm-list-row__phone {
  font: 500 13px/1 var(--font-mono, ui-monospace, "SF Mono", Monaco, Menlo, monospace);
  color: var(--ink-2);
  font-feature-settings: "tnum" 1;
  white-space: nowrap;
}
.cm-list-row__birth {
  font: 500 12.5px/1.25 var(--font-sans);
  color: var(--ink-2);
  font-feature-settings: "tnum" 1, "lnum" 1;
}
.cm-list-row__birth-age {
  font: 500 10.5px/1 var(--font-sans);
  color: var(--ink-3);
  margin-top: 3px;
  letter-spacing: 0.02em;
}
.cm-list-row__dim { color: var(--ink-3); }
.cm-list-row__trail {
  display: inline-flex;
  justify-content: flex-end;
  gap: var(--s-2);
}

/* Status dot on avatars — anchored to a wrapper that does NOT clip,
   so the dot can sit on the outer edge of the avatar circle without being
   cut off by the avatar's own `overflow: hidden` (needed for the photo crop).
   Legacy `.cm-avatar--with-dot` rules retained for any other call sites. */
/* Avatar wrapper sized to match its child avatar exactly. `width: max-content`
   prevents the parent grid track (e.g. the 44px users-list avatar column)
   from stretching the wrapper, which used to push the dot off the photo's
   south-east corner. */
.cm-avatar-stack { position: relative; display: inline-block; flex: none; line-height: 0; width: max-content; }
.cm-avatar-stack > .cm-avatar { display: block; }

/* Half-in / half-out: dot center lands on the circle's south-east tangent.
   For a circle of radius R the tangent point at 45° is at (R, R) from the
   center, i.e. (R + R/√2 - R) ≈ R·0.293 inside the bounding box from the
   bottom-right corner. With dot size D, dot center should be at distance
   ≈ R·0.293 from corner inward = R·0.293; dot bottom-right past the corner
   by D/2 - R·0.293. For 32px avatar / 12px dot: D/2 = 6, R·0.293 = 4.69 →
   bottom: -1.31px ≈ -1px. Per-size overrides below tune the same logic. */
.cm-avatar-stack__dot {
  position: absolute;
  width: 12px; height: 12px;
  right: -2px; bottom: -1px;
  border-radius: 999px;
  border: 2px solid var(--surface);
  box-shadow: 0 0 0 1px color-mix(in oklab, var(--ink-1) 10%, transparent);
  pointer-events: none;
  z-index: 1;
}
.cm-avatar-stack:has(.cm-avatar--xs) .cm-avatar-stack__dot { width: 9px;  height: 9px;  right: -2px; bottom: -1px; }
.cm-avatar-stack:has(.cm-avatar--sm) .cm-avatar-stack__dot { width: 10px; height: 10px; right: -2px; bottom: -1px; }
.cm-avatar-stack:has(.cm-avatar--lg) .cm-avatar-stack__dot { width: 14px; height: 14px; right: 0;    bottom: 0;    }
.cm-avatar-stack:has(.cm-avatar--xl) .cm-avatar-stack__dot { width: 18px; height: 18px; right: 4px;  bottom: 4px;  }
.cm-avatar-stack__dot--active   { background: var(--success); }
.cm-avatar-stack__dot--inactive { background: var(--danger); }

/* Legacy fallback (kept so unrelated pages don't break). The dot lives
   inside `.cm-avatar` here, so it WILL be partially clipped — prefer the
   `.cm-avatar-stack` wrapper above for new usages. */
.cm-avatar--with-dot { position: relative; }
.cm-avatar__dot {
  position: absolute;
  bottom: 0; right: 0;
  width: 12px; height: 12px;
  border-radius: 999px;
  border: 2px solid var(--surface);
}
.cm-avatar__dot--active   { background: var(--success); }
.cm-avatar__dot--inactive { background: var(--danger); }

/* Compact at narrow widths: hide phone + birth, keep avatar/name/status */
@media (max-width: 767px) {
  .cm-list-card__cols--users,
  .cm-list-row--users {
    grid-template-columns: 40px minmax(0, 1fr) 90px;
  }
  .cm-list-card__cols--users > :nth-child(3),
  .cm-list-card__cols--users > :nth-child(4),
  .cm-list-row--users     > .cm-list-row__phone,
  .cm-list-row--users     > .cm-list-row__birth { display: none; }
}

/* ─── Photo zoom / lightbox ─────────────────────────────────────────────── */
.cm-photo-modal {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 9000;
  background: oklch(0% 0 0 / 0.82);
  align-items: center;
  justify-content: center;
  cursor: zoom-out;
  backdrop-filter: blur(6px);
}
.cm-photo-modal.is-open { display: flex; }
.cm-photo-modal__img {
  max-width: min(90vw, 720px);
  max-height: 90dvh;
  border-radius: var(--r-3);
  box-shadow: 0 32px 80px oklch(0% 0 0 / 0.5);
  object-fit: contain;
  animation: cmPhotoZoomIn 0.2s ease;
  cursor: default;
}
@keyframes cmPhotoZoomIn {
  from { opacity: 0; transform: scale(0.88); }
  to   { opacity: 1; transform: scale(1); }
}
.cm-photo-modal__close {
  position: absolute;
  top: var(--s-4);
  right: var(--s-4);
  width: 36px; height: 36px;
  border-radius: var(--r-full);
  background: oklch(100% 0 0 / 0.12);
  border: 1px solid oklch(100% 0 0 / 0.2);
  color: #fff;
  font-size: 20px;
  line-height: 1;
  display: grid;
  place-items: center;
  cursor: pointer;
  transition: background 0.15s;
}
.cm-photo-modal__close:hover { background: oklch(100% 0 0 / 0.22); }
/* Clickable avatar hint */
.cm-avatar--zoomable { cursor: zoom-in; }

/* POS form factor: roomier rows */
:root[data-form-factor="pos"] .cm-list-row { min-height: 64px; padding: var(--s-3) var(--s-5); }
@media (min-aspect-ratio: 9/10) and (max-aspect-ratio: 10/9) and (pointer: coarse) {
  .cm-list-row { min-height: 64px; padding: var(--s-3) var(--s-5); }
}
