/* ==========================================================================
   Promio — Anchor DS tokens + base layer
   Source: docs/design-system.md (Appendix — CSS tokens) + §01 Foundations.
   Every wireframe in docs/wireframe/ links to this file.

   THIS BUILD carries **palette D · Promio Warm Teal** (agreed 2026-08-03) and the
   **Plus Jakarta Sans + JetBrains Mono** pairing. Every deviation from the original
   Anchor is listed in docs/design-system.md, under "## Promio deviations".
   Tokens marked [+] are additions beyond the Anchor Appendix.
   ========================================================================== */

/* ==========================================================================
   @font-face — SELF-HOSTED, no CDN. These are the assets shipped to the Worker.
   Variable woff2, subset to latin + latin-ext + vietnamese, with the full OpenType
   layout feature set preserved (so "tnum" still works). Source: github.com/google/fonts
   (OFL 1.1), subset with fontTools. Two files, ~98 KB in total.
   ========================================================================== */

@font-face {
  font-family: "Plus Jakarta Sans";
  src: url("/assets/fonts/plus-jakarta-sans-var.woff2") format("woff2");
  font-weight: 200 800;          /* variable wght — covers 400/500/600/700 */
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "JetBrains Mono";
  src: url("/assets/fonts/jetbrains-mono-var.woff2") format("woff2");
  font-weight: 100 800;
  font-style: normal;
  font-display: swap;
}

:root {
  /* --- Deep Teal — foundation (Anchor §01.1, palette D values) ------------ */
  --teal-900: #023F47;
  --teal-800: #046B76;   /* primary brand: topbar, links, Dark buttons */
  --teal-700: #0B818C;
  --teal-600: #1A9AA4;
  --teal-500: #57B7BE;
  --teal-300: #C2E9EC;   /* AA fix: inactive nav on the topbar */
  --teal-100: #D6EFF0;

  /* --- Signal Green — INTERACTION ONLY (Anchor §00.2) --------------------- */
  --green-700: #009A5C;  /* focus ring — 3.64:1 on white, 3.11:1 on the app background */
  --green-600: #00BD70;  /* Primary button hover */
  --green-500: #00D47E;  /* Primary button fill, active nav underline, ring on dark surfaces */
  --green-100: #C9F6E1;  /* Ghost button hover fill */

  /* --- Neutrals — warm bone (palette D: hue 43° instead of cold-blue 206°) - */
  --ink-900: #161A17;
  --ink-700: #3D4642;
  --ink-500: #666B64;    /* AA fix: 4.66:1 on the app background (was #6A6F68 = 4.40) */
  --ink-400: #6E6A5E;    /* AA fix: 4.62:1 on the app background (was #8A989D = 2.41) */
  --gray-200: #E2DCD0;   /* dividers and decorative rules ONLY — never control borders */
  --gray-100: #F0EDE6;   /* app background — warm bone */
  --gray-50:  #F8F6F1;
  --white:    #FFFFFF;

  /* [+] the border of real controls (input, select, textarea, Secondary button).
     gray-200 only reaches 1.37:1 on white — it fails WCAG 1.4.11 (3:1 required). */
  --border-control: #928C7B;   /* 3.35:1 on white, 3.11:1 on gray-50 */

  /* --- State — there is no "success" token by design (Anchor §00.1) ------- */
  --state-neutral:        #61665F;  --state-neutral-bg:   #F5F3EE;
  --state-attention:      #9A4A05;  --state-attention-bg: #FCEBD4;
  --state-attention-mark: #C96A0B;
  --state-tracked:        #1A5FCC;  --state-tracked-bg:   #E4EEFB;
  --state-linked:         #046B76;  --state-linked-bg:    #D6EFF0;
  --state-fault:          #C4123C;  --state-fault-bg:     #FDE7ED;
  --state-absent:         #6E6A5E;

  /* --- Typography --------------------------------------------------------- */
  /* Plus Jakarta Sans: has "tnum" (verified with fontTools) and a complete
     diacritics set. JetBrains Mono: dotted zero, tailed l, serifed I — 0/O and
     1/l/I cannot be confused in a coupon code. See font-lab.html. */
  --font-sans: "Plus Jakarta Sans", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;

  --fs-metric: 26px; --fs-h1: 28px; --fs-h2: 20px; --fs-h3: 16px;
  --fs-body: 16px; --fs-dense: 14px; --fs-small: 13px; --fs-caption: 11px;
  --fs-mono: 13px; --fs-mono-sm: 12px;

  /* [+] palette D: discount figures and the store-page H1 grow — they are what
     people came to read. Dense 14/20 is unchanged, so table rows stay at 36px. */
  --fs-offer: 30px;   --lh-offer: 34px;
  --fs-store-h1: 26px; --lh-store-h1: 33px;

  /* [+] line-height split out of the §01.2 table (previously only as "size / LH") */
  --lh-metric: 32px; --lh-h1: 36px; --lh-h2: 28px; --lh-h3: 24px;
  --lh-body: 25px; --lh-dense: 20px; --lh-small: 20px; --lh-caption: 14px;
  --lh-mono: 20px; --lh-mono-sm: 18px;

  /* [+] weight + tracking split out (§01.2 describes them in prose) */
  --fw-regular: 400; --fw-medium: 500; --fw-semibold: 600; --fw-bold: 700;
  --tracking-tight: -0.01em;   /* Metric, H1 */
  --tracking-caption: 0.08em;  /* Caption, badge, chip, column header */

  /* --- Spacing (4px grid) -------------------------------------------------- */
  --sp-1: 4px;  --sp-2: 8px;  --sp-3: 12px; --sp-4: 16px;
  --sp-5: 20px; --sp-6: 24px; --sp-8: 32px; --sp-10: 40px; --sp-12: 48px;

  /* --- Density (Anchor §01.3) --------------------------------------------- */
  --row-h: 36px;          /* table row — Compact */
  /* [+] CHANGED from the Appendix: the Anchor lists --row-pad-y: 10px, but 10 + 20
     (Dense 14/20 line-height) + 10 = 40px, which cannot produce the 36px row §01.3
     claims. The 36px figure is kept (a visible promise: ~18 rows per screen) and the
     padding drops to 8px: 8 + 20 + 8 = 36. */
  --row-pad-y: 8px;
  --row-pad-x: 12px;
  --card-pad: 20px;       /* Comfortable */
  --drawer-pad: 24px;

  /* --- Radius ------------------------------------------------------------- */
  --r-sm: 8px; --r-md: 12px; --r-lg: 16px; --r-full: 999px;

  /* --- Elevation ----------------------------------------------------------
     [+] DEVIATION from §01.4 ("cards have NO shadow"): the app background and white
     cards only separate by 1.23:1, so banning shadows flattens the whole page. A soft
     warm-tinted shadow is allowed on cards. See design-system.md → "## Promio deviations". */
  --shadow-sm: 0 1px 2px rgba(64,48,20,.06);
  --shadow-md: 0 4px 12px rgba(64,48,20,.08);
  --shadow-lg: 0 12px 32px rgba(64,48,20,.16);
  --card-shadow:       0 1px 2px rgba(64,48,20,.05), 0 8px 22px -10px rgba(64,48,20,.24);
  --card-shadow-hover: 0 2px 4px rgba(64,48,20,.07), 0 14px 30px -12px rgba(64,48,20,.32);

  /* [+] topbar/sidebar background — a very light vertical gradient whose brightest
     point is still teal-800, so teal-300 nav keeps its 4.80:1 */
  --topbar-bg: linear-gradient(180deg, var(--teal-800) 0%, #035A64 100%);

  /* --- Motion ------------------------------------------------------------- */
  --ease: cubic-bezier(.4,0,.2,1);
  --t-fast: 120ms; --t-base: 200ms;

  /* --- Focus -------------------------------------------------------------- */
  --focus-ring: 2px solid var(--green-700);
  --focus-offset: 2px;
  /* [+] AA fix: green-700 on teal-800 is only 1.71:1. On dark teal surfaces use
     green-500 (3.18:1) — still green, so it keeps meaning "interactive". */
  --focus-ring-dark: 2px solid var(--green-500);

  /* [+] Layout — the Anchor has no layout tokens; Promio needs them for the public pages */
  --container: 1080px;        /* frontstore */
  --container-wide: 1280px;   /* admin */
  --container-pad: 24px;
  --topbar-h: 56px;
  --sidebar-w: 240px;         /* admin nav (Anchor §03.2 has no sidebar) */
  --tap-min: 44px;            /* minimum touch target */
}

/* ==========================================================================
   Reset + base
   ========================================================================== */

*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; padding: 0; }

html { -webkit-text-size-adjust: 100%; }

body {
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--ink-900);
  background: var(--gray-100);
  /* Anchor §01.2: every figure is tabular. Plus Jakarta Sans defaults to proportional
     figures, so "tnum" has to be enabled for real, not just declared as font-variant-numeric. */
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum";
  -webkit-font-smoothing: antialiased;
}

img, svg { display: block; max-width: 100%; }
button, input, select, textarea { font: inherit; color: inherit; }
ul, ol { list-style: none; }
a { color: var(--teal-800); text-decoration: none; }
a:hover { text-decoration: underline; }

*:focus-visible {
  outline: var(--focus-ring);
  outline-offset: var(--focus-offset);
}
/* AA fix: on dark teal surfaces switch to a green-500 ring (3.18:1 vs 1.71:1) */
.topbar *:focus-visible,
.admin-side *:focus-visible,
.sitefoot *:focus-visible { outline: var(--focus-ring-dark); }

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

/* ==========================================================================
   Typography scale (Anchor §01.2)
   ========================================================================== */

.t-metric { font-size: var(--fs-metric); line-height: var(--lh-metric); font-weight: var(--fw-bold); letter-spacing: var(--tracking-tight); }
.t-h1, h1 { font-size: var(--fs-h1); line-height: var(--lh-h1); font-weight: var(--fw-bold); letter-spacing: var(--tracking-tight); }
.t-h2, h2 { font-size: var(--fs-h2); line-height: var(--lh-h2); font-weight: var(--fw-bold); }
.t-h3, h3 { font-size: var(--fs-h3); line-height: var(--lh-h3); font-weight: var(--fw-semibold); }
h4 { font-size: var(--fs-dense); line-height: var(--lh-dense); font-weight: var(--fw-semibold); }
.t-body { font-size: var(--fs-body); line-height: var(--lh-body); }
.t-dense { font-size: var(--fs-dense); line-height: var(--lh-dense); }
.t-small { font-size: var(--fs-small); line-height: var(--lh-small); }
.t-caption {
  font-size: var(--fs-caption); line-height: var(--lh-caption);
  font-weight: var(--fw-medium); letter-spacing: var(--tracking-caption);
  text-transform: uppercase;
}
.t-mono { font-family: var(--font-mono); font-size: var(--fs-mono); line-height: var(--lh-mono); }
.t-mono-sm { font-family: var(--font-mono); font-size: var(--fs-mono-sm); line-height: var(--lh-mono-sm); }

.muted  { color: var(--ink-500); }
.dim    { color: var(--ink-400); }
.num    { font-variant-numeric: tabular-nums; }
.absent { color: var(--state-absent); font-style: italic; }   /* §03.4 */

/* ==========================================================================
   Layout
   ========================================================================== */

.wrap { max-width: var(--container); margin: 0 auto; padding: 0 var(--container-pad); }
.wrap-wide { max-width: var(--container-wide); margin: 0 auto; padding: 0 var(--container-pad); }

.stack   { display: flex; flex-direction: column; gap: var(--sp-6); }
.stack-3 { display: flex; flex-direction: column; gap: var(--sp-3); }
.stack-4 { display: flex; flex-direction: column; gap: var(--sp-4); }
.row     { display: flex; align-items: center; gap: var(--sp-3); }
.row-between { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4); }
.spacer  { flex: 1; }

.section { padding: var(--sp-8) 0; }
.section-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-4); margin-bottom: var(--sp-4); }

/* 2-column store page — collapses to one column below 900px (spec §4.2) */
.layout-2col { display: grid; grid-template-columns: 300px 1fr; gap: var(--sp-6); align-items: start; }
.layout-2col > .col-side { position: sticky; top: var(--sp-6); }

@media (max-width: 900px) {
  .layout-2col { grid-template-columns: 1fr; }
  .layout-2col > .col-side { position: static; }
}

/* Card — white, r-lg, soft warm-tinted shadow (an intentional §01.4 DEVIATION) */
.card { background: var(--white); border-radius: var(--r-lg); padding: var(--card-pad);
  box-shadow: var(--card-shadow); }
.card-flush { padding: 0; overflow: hidden; }

.divider { height: 1px; background: var(--gray-50); border: 0; }
.divider-strong { height: 1px; background: var(--gray-200); border: 0; }

/* ==========================================================================
   02.1 Button — Primary / Dark / Secondary / Ghost
   Green-500 appears here only (where things are clickable), on ≤10% of the screen.
   ========================================================================== */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
  font-size: var(--fs-body); line-height: 1; font-weight: var(--fw-medium);
  padding: 11px 22px; border: 1px solid transparent; border-radius: var(--r-md);
  cursor: pointer; white-space: nowrap; text-decoration: none;
  transition: background var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.btn:hover { text-decoration: none; }
.btn:active { transform: translateY(1px); }
.btn-sm { padding: 7px 14px; font-size: var(--fs-small); border-radius: var(--r-sm); }

.btn-primary   { background: var(--green-500); color: var(--ink-900); }
.btn-primary:hover { background: var(--green-600); }
.btn-dark      { background: var(--teal-800); color: var(--white); }
.btn-dark:hover{ background: var(--teal-700); }
.btn-secondary { background: var(--white); border-color: var(--border-control); color: var(--ink-900); }
.btn-secondary:hover { border-color: var(--ink-700); }
.btn-ghost     { background: transparent; color: var(--teal-800); }
.btn-ghost:hover { background: var(--teal-100); }
.btn[disabled], .btn.is-disabled { background: var(--gray-200); color: var(--ink-400); cursor: default; transform: none; }

/* icon-only — still keeps a 44px touch area on touch devices via ::after */
.btn-icon { width: 32px; height: 32px; padding: 0; border-radius: var(--r-sm); position: relative; }
@media (pointer: coarse) {
  .btn-icon::after { content: ""; position: absolute; inset: 50% auto auto 50%;
    width: var(--tap-min); height: var(--tap-min); transform: translate(-50%, -50%); }
}

/* ==========================================================================
   02.3 Badge — mapped 1:1 to state-*. There is NO green badge (§00.1).
   ========================================================================== */

.badge {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  font-size: var(--fs-caption); line-height: var(--lh-caption); font-weight: var(--fw-medium);
  letter-spacing: var(--tracking-caption); text-transform: uppercase;
  padding: 3px 8px; border-radius: var(--r-full); white-space: nowrap;
}
.badge-neutral   { color: var(--state-neutral);   background: var(--state-neutral-bg); }
.badge-attention { color: var(--state-attention); background: var(--state-attention-bg); }
.badge-tracked   { color: var(--state-tracked);   background: var(--state-tracked-bg); }
.badge-linked    { color: var(--state-linked);    background: var(--state-linked-bg); }
.badge-fault     { color: var(--state-fault);     background: var(--state-fault-bg); }

/* 02.4 Chip — metadata about how to read the data */
.chip {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  font-size: var(--fs-caption); line-height: var(--lh-caption); font-weight: var(--fw-medium);
  letter-spacing: var(--tracking-caption); text-transform: uppercase;
  padding: 3px 8px; border-radius: var(--r-full);
  background: var(--teal-100); color: var(--teal-800);
}

/* ==========================================================================
   02.2 Input + form field (Comfortable)
   ========================================================================== */

.input, .select, .textarea {
  width: 100%; background: var(--white); color: var(--ink-900);
  border: 1px solid var(--border-control); border-radius: var(--r-sm);   /* AA 1.4.11 */
  padding: 11px 14px; font-size: var(--fs-body); line-height: var(--lh-body);
  transition: border-color var(--t-fast) var(--ease);
}
.textarea { min-height: 96px; resize: vertical; }
.select { appearance: none; padding-right: 34px;
  background-image: linear-gradient(45deg, transparent 50%, var(--ink-500) 50%),
                    linear-gradient(135deg, var(--ink-500) 50%, transparent 50%);
  background-position: calc(100% - 18px) 20px, calc(100% - 13px) 20px;
  background-size: 5px 5px, 5px 5px; background-repeat: no-repeat; }
.input::placeholder, .textarea::placeholder { color: var(--ink-400); }
.input:focus, .select:focus, .textarea:focus {
  outline: 0; border-color: var(--teal-800);
  box-shadow: 0 0 0 3px rgba(0,154,92,.25);   /* ring green-700 @25% */
}
.input-mono { font-family: var(--font-mono); font-size: var(--fs-mono); }

.field { display: flex; flex-direction: column; gap: 6px; }
.field-label { font-size: var(--fs-small); line-height: var(--lh-small); color: var(--ink-500); }
.field-label .req { color: var(--state-fault); }
.field-help { font-size: var(--fs-small); line-height: var(--lh-small); color: var(--ink-400); }
.field.is-error .input { border-color: var(--state-fault); }
.field.is-error .field-help { color: var(--state-fault); }

/* search input — 16px icon 12px from the left, 36px left padding (§02.2) */
.search { position: relative; }
.search .input { padding-left: 36px; }
.search .search-icon {
  position: absolute; left: 12px; top: 50%; transform: translateY(-50%);
  width: 16px; height: 16px; color: var(--ink-400); font-size: 16px; line-height: 1;
  pointer-events: none;
}

/* checkbox row */
.check { display: flex; align-items: flex-start; gap: var(--sp-2); }
.check input { width: 18px; height: 18px; margin-top: 3px; accent-color: var(--green-700); }
.check span { font-size: var(--fs-body); }

/* ==========================================================================
   03.3 Copy field — signature pattern
   Mono 13px ink-700 · 24px Ghost copy button ALWAYS visible · ✓ stays 1200ms ·
   aria-live="polite" announces "Copied" · truncates in the MIDDLE (8 leading + 6 trailing), not at the end.
   ========================================================================== */

.copy-field { display: inline-flex; align-items: center; gap: var(--sp-2); max-width: 100%; }
.copy-field > code {
  font-family: var(--font-mono); font-size: var(--fs-mono); line-height: var(--lh-mono);
  color: var(--ink-700); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cf-btn {
  flex: 0 0 auto; width: 24px; height: 24px; display: inline-flex;
  align-items: center; justify-content: center;
  border: 0; background: transparent; color: var(--teal-800);
  border-radius: var(--r-sm); cursor: pointer; font-size: 14px; line-height: 1;
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.cf-btn:hover { background: var(--teal-100); }
.cf-btn.is-copied { color: var(--green-700); }
/* the copy icon is inline SVG; ✓ only appears after copying. Switched by class, not by
   innerHTML — keeps the handler cheap and avoids rebuilding the DOM. */
.cf-btn .cf-ok { display: none; font-size: 14px; line-height: 1; }
.cf-btn.is-copied .cf-ico { display: none; }
.cf-btn.is-copied .cf-ok { display: inline; }
.cf-ico { display: block; }
.search-icon svg { display: block; }

/* boxed variant — used for the coupon code on the reveal page and the blog coupon box */
.code-box {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
  background: var(--gray-50); border: 1px dashed var(--border-control);
  border-radius: var(--r-md); padding: var(--sp-3) var(--sp-4);
}
.code-box .copy-field > code { color: var(--ink-900); letter-spacing: .04em; }
.code-box .cf-btn { width: 32px; height: 32px; }

/* ==========================================================================
   02.9 Banner — full width, r-md, 3px left border
   ========================================================================== */

.banner {
  display: flex; gap: var(--sp-3); align-items: flex-start;
  padding: var(--sp-3) var(--sp-4); border-radius: var(--r-md);
  font-size: var(--fs-small); line-height: var(--lh-small); border-left: 3px solid;
}
.banner-icon { flex: 0 0 16px; line-height: var(--lh-small); }
.banner-info      { background: var(--state-tracked-bg);   border-color: var(--state-tracked);        color: var(--ink-700); }
.banner-attention { background: var(--state-attention-bg); border-color: var(--state-attention-mark); color: var(--ink-700); }
.banner-fault     { background: var(--state-fault-bg);     border-color: var(--state-fault);          color: var(--ink-700); }

/* ==========================================================================
   02.5 Table — Compact 36px for EVERY admin table
   ========================================================================== */

.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.tbl { width: 100%; border-collapse: collapse; background: var(--white); font-size: var(--fs-dense); }
.tbl th {
  position: sticky; top: 0; z-index: 1; background: var(--white); text-align: left;
  font-size: var(--fs-caption); line-height: var(--lh-caption); font-weight: var(--fw-medium);
  letter-spacing: var(--tracking-caption); text-transform: uppercase; color: var(--ink-400);
  padding: var(--row-pad-y) var(--row-pad-x); border-bottom: 1px solid var(--gray-200);
  white-space: nowrap;
}
/* Rows are exactly 36px: badges and copy fields are inline-flex with `vertical-align:
   middle`, so the line box swells to ~21.5px and 8+8 vertical padding would give ~37.5px.
   Dropping the vertical padding and letting the cell's `height` + `vertical-align: middle`
   centre the content locks the row at 36px regardless of font. `--row-pad-y` still applies to <th>. */
.tbl td {
  height: var(--row-h); padding: 0 var(--row-pad-x);
  border-bottom: 1px solid var(--gray-50); color: var(--ink-700);
  line-height: var(--lh-dense); vertical-align: middle;
  white-space: nowrap;                 /* Compact: cells never wrap, the table scrolls horizontally */
}
/* long text cells: truncate at the end + keep the full value in title (not IDs, so end-truncation is fine) */
.tbl .cell-name { max-width: 220px; overflow: hidden; text-overflow: ellipsis; }
.tbl td .t-strong { color: var(--ink-900); font-weight: var(--fw-medium); }
.tbl tbody tr:hover { background: var(--gray-50); }
.tbl tbody tr.is-selected { background: var(--gray-50); }
.tbl tbody tr.is-selected td:first-child { box-shadow: inset 3px 0 0 var(--green-500); }
.tbl .col-num { text-align: right; font-variant-numeric: tabular-nums; }
.tbl .col-drag { width: 32px; color: var(--ink-400); cursor: grab; text-align: center; }
/* Everything inside a cell has to fit the 20px content box, otherwise the row grows past 36px.
   The real touch area is widened with ::after on touch devices (see @media pointer: coarse). */
.tbl .cf-btn { width: 20px; height: 20px; font-size: 13px; }

.act-btn {
  position: relative; width: 20px; height: 20px; padding: 0; margin-left: 2px;
  display: inline-flex; align-items: center; justify-content: center; vertical-align: middle;
  border: 0; border-radius: var(--r-sm); background: transparent; color: var(--ink-500);
  font-size: 13px; line-height: 1; cursor: pointer;
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.act-btn:hover { background: var(--gray-200); color: var(--teal-800); }
.act-btn.danger:hover { background: var(--state-fault-bg); color: var(--state-fault); }
@media (pointer: coarse) {
  .act-btn::after { content: ""; position: absolute; inset: 50% auto auto 50%;
    width: var(--tap-min); height: var(--tap-min); transform: translate(-50%, -50%); }
}
/* inline-flex sitting on the baseline leaves a gap underneath → the row grows past 36px */
.tbl .badge, .tbl .copy-field, .tbl .chip { vertical-align: middle; }
.tbl td > .badge, .tbl td > .copy-field { display: inline-flex; }

/* the actions column sticks to the right edge: a 10-column table is always wider than the
   admin's 992px viewport, and the actions must stay reachable without scrolling all the way */
.tbl .col-actions {
  width: 1%; white-space: nowrap; text-align: right;
  position: sticky; right: 0; background: var(--white);
  border-left: 1px solid var(--gray-200);
}
.tbl th.col-actions { z-index: 2; }
.tbl tbody tr:hover .col-actions,
.tbl tbody tr.is-selected .col-actions { background: var(--gray-50); }

/* 02.13 Pagination */
.pagination {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4);
  flex-wrap: wrap; margin-top: var(--sp-3);
  font-size: var(--fs-small); color: var(--ink-500);
}

/* ==========================================================================
   Tabs (segmented) — used for the All / Verified / Codes / Deals tabs
   ========================================================================== */

.tabs { display: flex; gap: var(--sp-1); flex-wrap: wrap; }
.tab {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 14px; border: 0; border-radius: var(--r-sm); background: transparent;
  font-size: var(--fs-small); line-height: var(--lh-small); color: var(--ink-500); cursor: pointer;
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.tab:hover { background: var(--gray-50); }
.tab[aria-selected="true"] { background: var(--teal-800); color: var(--white); }
.tab .n { font-variant-numeric: tabular-nums; opacity: .75; }

/* ==========================================================================
   Accordion — About store / How to apply / FAQs
   ========================================================================== */

.acc { background: var(--white); border-radius: var(--r-lg); overflow: hidden; box-shadow: var(--card-shadow); }
.acc-item + .acc-item { border-top: 1px solid var(--gray-50); }
.acc-head {
  width: 100%; display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
  background: none; border: 0; cursor: pointer; text-align: left;
  padding: var(--card-pad); font-size: var(--fs-h3); line-height: var(--lh-h3); font-weight: var(--fw-semibold);
}
.acc-head .caret { color: var(--ink-400); transition: transform var(--t-fast) var(--ease); font-size: 12px; }
.acc-head[aria-expanded="true"] .caret { transform: rotate(180deg); }
.acc-body { padding: 0 var(--card-pad) var(--card-pad); color: var(--ink-700); }
.acc-head[aria-expanded="false"] + .acc-body { display: none; }

/* prose — HTML content entered by the admin (about, how to apply, posts) */
.prose { color: var(--ink-700); font-size: var(--fs-body); line-height: var(--lh-body); }
.prose > * + * { margin-top: var(--sp-3); }
.prose h2 { color: var(--ink-900); margin-top: var(--sp-6); }
.prose h3 { color: var(--ink-900); margin-top: var(--sp-5); }
.prose ul { list-style: disc; padding-left: 20px; }
.prose ol { list-style: decimal; padding-left: 20px; }
.prose li + li { margin-top: var(--sp-1); }
.prose strong { color: var(--ink-900); font-weight: var(--fw-semibold); }

/* ==========================================================================
   03.2 Topbar — 56px, teal-800
   ========================================================================== */

.topbar { background: var(--topbar-bg); }
.topbar .bar { display: flex; align-items: center; gap: var(--sp-8); height: var(--topbar-h); }
.wordmark { color: var(--white); font-size: 18px; font-weight: var(--fw-bold); letter-spacing: var(--tracking-tight); }
.wordmark:hover { text-decoration: none; }
.topnav { display: flex; gap: var(--sp-6); }
.topnav a {
  color: var(--teal-300); font-size: var(--fs-dense); line-height: var(--topbar-h);
  border-bottom: 2px solid transparent; text-decoration: none;
}
.topnav a:hover { color: var(--white); text-decoration: none; }
.topnav a[aria-current="page"] { color: var(--white); border-bottom-color: var(--green-500); }

/* 02.11 Empty state */
.empty { max-width: 400px; margin: 0 auto; text-align: center; padding: var(--sp-10) 0; }
.empty p { color: var(--ink-500); font-size: var(--fs-small); margin-top: var(--sp-2); }

/* ==========================================================================
   Image placeholders (wireframe) — R2 assets take their place
   ========================================================================== */

.ph {
  background: var(--gray-50); border-radius: var(--r-md);
  display: flex; align-items: center; justify-content: center;
  color: var(--ink-400); font-size: var(--fs-mono-sm); font-family: var(--font-mono);
  text-align: center; overflow: hidden;
}
.logo-tile {
  background: var(--teal-100); color: var(--teal-800); border-radius: var(--r-md);
  display: flex; align-items: center; justify-content: center;
  font-weight: var(--fw-bold); letter-spacing: var(--tracking-tight); flex: 0 0 auto;
}

/* rating — stars use teal-600/gray-200, NOT state colours (this is not a state) */
.rating { display: inline-flex; align-items: center; gap: 6px; font-size: var(--fs-small); color: var(--ink-500); }
.rating .stars { color: var(--teal-600); letter-spacing: 1px; }
.rating .stars .off { color: var(--gray-200); }
.rating .score { color: var(--ink-900); font-weight: var(--fw-semibold); font-variant-numeric: tabular-nums; }


/* ==========================================================================
   PROMIO — components shared across pages
   (built from the Anchor components above; no new colours or spacing)
   ========================================================================== */

/* --- the search bar under the topbar ------------------------------------- */
.searchbar { padding: var(--sp-5) 0 var(--sp-2); }
.searchbar .search { max-width: 560px; margin: 0 auto; }

/* --- breadcrumb ---------------------------------------------------------- */
.breadcrumb { display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: center;
  padding: var(--sp-4) 0; font-size: var(--fs-small); color: var(--ink-400); }
.breadcrumb a { color: var(--ink-500); }
.breadcrumb [aria-current] { color: var(--ink-700); }

/* --- auto-fitting grid --------------------------------------------------- */
.grid-auto { display: grid; gap: var(--sp-4); grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); }
.grid-auto-sm { display: grid; gap: var(--sp-3); grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
.grid-auto-lg { display: grid; gap: var(--sp-4); grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.grid-4 { display: grid; gap: var(--sp-4); grid-template-columns: repeat(4, 1fr); }
@media (max-width: 860px) { .grid-4 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 520px) { .grid-4 { grid-template-columns: 1fr; } }

/* --- OFFER CARD (spec §4.2) ---------------------------------------------
   left = large offer_label (teal-800) · middle = badge + name + description ·
   right = Get Code (Primary green) / Get Deal (Dark teal)
   ------------------------------------------------------------------------ */
.offer {
  display: flex; align-items: center; gap: var(--sp-4);
  background: var(--white); border-radius: var(--r-lg); padding: 18px var(--card-pad);
  box-shadow: var(--card-shadow);
  transition: box-shadow var(--t-base) var(--ease);
}
.offer:hover { box-shadow: var(--card-shadow-hover); }
.offer-label { flex: 0 0 96px; width: 96px; text-align: center; }
.offer-label .big {
  display: block; font-size: var(--fs-offer); line-height: var(--lh-offer); font-weight: var(--fw-bold);
  letter-spacing: var(--tracking-tight); color: var(--teal-800); font-variant-numeric: tabular-nums;
}
.offer-label .big.is-long { font-size: var(--fs-h2); line-height: 26px; }
.offer-label .sub {
  display: block; font-size: var(--fs-caption); line-height: var(--lh-caption);
  font-weight: var(--fw-medium); letter-spacing: var(--tracking-caption);
  text-transform: uppercase; color: var(--ink-400); margin-top: 2px;
}
.offer-mid { flex: 1 1 auto; min-width: 0; }
.offer-mid .badges { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 6px; }
.offer-mid h3 { color: var(--ink-900); }
.offer-mid p { font-size: var(--fs-small); line-height: var(--lh-small); color: var(--ink-500); margin-top: 2px; }
.offer-act { flex: 0 0 auto; display: flex; flex-direction: column; align-items: stretch; gap: 6px; }
.offer-act .terms { font-size: var(--fs-caption); color: var(--ink-400); text-align: center; }
.offer.is-revealed { outline: 1px solid var(--teal-100); }

@media (max-width: 600px) {
  .offer { flex-wrap: wrap; gap: var(--sp-3); }
  .offer-label { flex-basis: 84px; width: 84px; text-align: left; }
  .offer-label .big { font-size: var(--fs-metric); line-height: 30px; }
  .offer-act { flex: 1 1 100%; }
  .offer-act .btn { width: 100%; }
}

/* --- STORE CARD (home "Popular stores", category listing) ---------------- */
.store-card {
  display: flex; flex-direction: column; gap: var(--sp-2);
  background: var(--white); border-radius: var(--r-lg); padding: var(--card-pad);
  box-shadow: var(--card-shadow);
  transition: box-shadow var(--t-base) var(--ease);
}
.store-card:hover { box-shadow: var(--card-shadow-hover); text-decoration: none; }
.store-card .logo-tile { width: 48px; height: 48px; font-size: var(--fs-h3); }
.store-card h3 { color: var(--ink-900); }
.store-card .count { font-size: var(--fs-small); color: var(--ink-500); font-variant-numeric: tabular-nums; }
.store-card .more { font-size: var(--fs-small); color: var(--teal-800); margin-top: auto; padding-top: var(--sp-2); }

/* --- DEAL CARD (product deal, "Deals of Today") -------------------------- */
.deal-card { display: flex; flex-direction: column; background: var(--white); border-radius: var(--r-lg); padding: var(--sp-4); box-shadow: var(--card-shadow); }
.deal-card .ph { height: 140px; margin-bottom: var(--sp-3); }
.deal-card h4 { color: var(--ink-900); }
.deal-card .price { display: flex; align-items: baseline; gap: var(--sp-2); margin: var(--sp-2) 0 var(--sp-3); }
.deal-card .price .new { font-size: var(--fs-h3); font-weight: var(--fw-bold); color: var(--teal-800); font-variant-numeric: tabular-nums; }
.deal-card .price .old { font-size: var(--fs-small); color: var(--ink-400); text-decoration: line-through; font-variant-numeric: tabular-nums; }
.deal-card .price .save { font-size: var(--fs-caption); color: var(--ink-500); font-variant-numeric: tabular-nums; }
.deal-card .btn { margin-top: auto; }

/* --- POST CARD (blog teaser) --------------------------------------------- */
.post-card { display: flex; flex-direction: column; background: var(--white); border-radius: var(--r-lg); overflow: hidden; box-shadow: var(--card-shadow); }
.post-card .ph { height: 148px; border-radius: 0; }
.post-card .body { padding: var(--sp-4); display: flex; flex-direction: column; gap: var(--sp-2); flex: 1; }
.post-card h3 { color: var(--ink-900); }
.post-card .meta { font-size: var(--fs-small); color: var(--ink-400); margin-top: auto; }
.post-row { display: flex; gap: var(--sp-3); background: var(--white); border-radius: var(--r-lg); padding: var(--sp-3); box-shadow: var(--card-shadow); }
.post-row .ph { flex: 0 0 72px; width: 72px; height: 72px; }

/* --- footer site ---------------------------------------------------------- */
.sitefoot { background: var(--teal-900); color: var(--teal-300); margin-top: var(--sp-10); padding: var(--sp-8) 0; }
.sitefoot .cols { display: grid; gap: var(--sp-6); grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); }
.sitefoot h4 { color: var(--white); font-size: var(--fs-caption); line-height: var(--lh-caption);
  letter-spacing: var(--tracking-caption); text-transform: uppercase; font-weight: var(--fw-medium); margin-bottom: var(--sp-3); }
.sitefoot a { color: var(--teal-300); font-size: var(--fs-small); line-height: 26px; display: block; }
.sitefoot a:hover { color: var(--white); }
.sitefoot .legal { margin-top: var(--sp-6); padding-top: var(--sp-4);
  border-top: 1px solid rgba(157,194,197,.24); font-size: var(--fs-small); color: var(--teal-300); }

/* ==========================================================================
   ADMIN shell — sidebar + toolbar (spec §5)
   Anchor §03.2 prescribes a topbar and no sidebar; the admin has 5 nav groups, so it
   uses a teal-800 sidebar with active = 3px green-500 left border (borrowed from §02.5).
   ========================================================================== */

.admin { display: grid; grid-template-columns: var(--sidebar-w) 1fr; min-height: 100vh; }
/* the sidebar keeps a flat teal-800 fill: it spans the full page height, so a gradient would stretch */
.admin-side { background: var(--teal-800); min-height: 100vh; }
.admin-side-inner { position: sticky; top: 0; padding: var(--sp-5) 0; max-height: 100vh; overflow-y: auto; }
.admin-side .wordmark { padding: 0 var(--sp-5) var(--sp-5); display: block; }
.admin-nav-group { padding: var(--sp-4) var(--sp-5) 6px; color: var(--teal-300);
  font-size: var(--fs-caption); line-height: var(--lh-caption); font-weight: var(--fw-medium);
  letter-spacing: var(--tracking-caption); text-transform: uppercase; }
.admin-nav a {
  display: block; padding: 9px var(--sp-5); color: var(--teal-300); font-size: var(--fs-dense);
  border-left: 3px solid transparent; text-decoration: none;
}
.admin-nav a:hover { color: var(--white); background: rgba(1,51,58,.4); text-decoration: none; }
.admin-nav a[aria-current="page"] { color: var(--white); border-left-color: var(--green-500); background: rgba(1,51,58,.55); }
.admin-nav a .sub { padding-left: var(--sp-3); }

.admin-main { min-width: 0; background: var(--gray-100); padding: var(--sp-6); }
.admin-head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4); flex-wrap: wrap; margin-bottom: var(--sp-5); }
.toolbar { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; margin-bottom: var(--sp-4); }
.toolbar .search { flex: 1 1 260px; max-width: 320px; }
.toolbar .select { width: auto; min-width: 150px; }

.form-grid { display: grid; gap: var(--sp-5); grid-template-columns: 1fr 1fr; }
.form-grid .span-2 { grid-column: 1 / -1; }
.form-actions { display: flex; gap: var(--sp-3); align-items: center; }

@media (max-width: 900px) {
  .admin { grid-template-columns: 1fr; }
  .admin-side { min-height: 0; }
  .admin-side-inner { position: static; max-height: none; padding-bottom: var(--sp-3); }
  .admin-side .admin-nav { display: flex; flex-wrap: wrap; }
  .admin-nav-group { display: none; }
  .admin-nav a { border-left: 0; border-bottom: 3px solid transparent; }
  .admin-nav a[aria-current="page"] { border-left: 0; border-bottom-color: var(--green-500); }
  .form-grid { grid-template-columns: 1fr; }
}

/* ==========================================================================
   Motion preference
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  * { transition-property: opacity; transform: none !important; }
}

/* ==========================================================================
   PROMIO — component theo trang
   Ported from the inline <style> blocks of docs/wireframe/*.html. The CSP `style-src 'self'`
   forbids both inline <style> and style= attributes, so every page-specific value has to
   become a real class here.
   ========================================================================== */

/* --- campaign banner (home.html:9-17) — the only dark block outside topbar/footer -- */
.campaign { background: var(--teal-800); color: var(--white); border-radius: var(--r-lg);
  padding: var(--sp-8); display: flex; gap: var(--sp-6); align-items: center; flex-wrap: wrap; }
.campaign h1 { flex: 1 1 340px; color: var(--white); }
.campaign p { color: var(--teal-100); font-size: var(--fs-body); margin-top: var(--sp-2); }
.campaign .cta { display: flex; gap: var(--sp-3); flex-wrap: wrap; }
/* Ghost hovers to a teal-100 fill by default — on dark surfaces that has to invert so the label stays visible */
.campaign .btn-ghost { color: var(--teal-100); }
.campaign .btn-ghost:hover { background: var(--teal-700); color: var(--white); }
/* replaces style="flex:1 1 340px" at home.html:70 */
.campaign-copy { flex: 1 1 340px; min-width: 0; }
/* replaces style="background:var(--teal-700);color:var(--white)" at home.html:71 */
.campaign .chip { background: var(--teal-700); color: var(--white); }
/* replaces style="margin-top:var(--sp-3)" at home.html:72 */
.campaign-copy h1 { margin-top: var(--sp-3); }
/* replaces style="padding-top:var(--sp-4)" at home.html:68 */
.section--tight { padding-top: var(--sp-4); }

/* --- store tile compact, Popular stores (home.html:20-26) ------------------ */
.store-tile { display: flex; flex-direction: column; align-items: center; gap: var(--sp-2);
  background: var(--white); border-radius: var(--r-lg); padding: var(--sp-4); text-align: center;
  box-shadow: var(--card-shadow); transition: box-shadow var(--t-base) var(--ease); }
.store-tile:hover { box-shadow: var(--card-shadow-hover); text-decoration: none; }
.store-tile .logo-tile { width: 56px; height: 56px; font-size: var(--fs-h3); }
.store-tile .logo-img { width: 56px; height: 56px; border-radius: var(--r-md); object-fit: cover; }
.store-tile .name { font-size: var(--fs-dense); font-weight: var(--fw-semibold); color: var(--ink-900); }
.store-tile .count { font-size: var(--fs-caption); color: var(--ink-500); font-variant-numeric: tabular-nums; }

/* --- home page category list (home.html:28-33) --------------------------- */
.cat-list { display: grid; gap: var(--sp-2); grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); }
.cat-list a { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2);
  background: var(--white); border-radius: var(--r-sm); padding: 10px var(--sp-3);
  font-size: var(--fs-dense); color: var(--ink-900); }
.cat-list a:hover { background: var(--gray-50); text-decoration: none; }
.cat-list .n { color: var(--ink-400); font-size: var(--fs-small); font-variant-numeric: tabular-nums; }

/* --- store page: identity + summary (store.html:10-21) ------------------- */
.store-id { display: flex; flex-direction: column; align-items: flex-start; gap: var(--sp-3); }
.store-id .logo-tile { width: 64px; height: 64px; font-size: 22px; }
.store-id .logo-img { width: 64px; height: 64px; border-radius: var(--r-md); object-fit: cover; }
.store-id h1 { font-size: var(--fs-store-h1); line-height: var(--lh-store-h1); }
.store-id .rating { margin-top: 4px; }
.summary { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-3);
  margin-top: var(--sp-4); padding-top: var(--sp-4); border-top: 1px solid var(--gray-50); }
.summary .n { font-size: var(--fs-h2); line-height: var(--lh-h2); font-weight: var(--fw-bold);
  color: var(--ink-900); font-variant-numeric: tabular-nums; }
.summary .l { font-size: var(--fs-caption); line-height: var(--lh-caption); font-weight: var(--fw-medium);
  letter-spacing: var(--tracking-caption); text-transform: uppercase; color: var(--ink-400); }
.faq-q { font-weight: var(--fw-semibold); color: var(--ink-900); }
.faq-a { margin-top: var(--sp-1); }
.faq-list > li + li { margin-top: var(--sp-4); }
/* replaces style="margin-top:var(--sp-3)" at store.html:83 */
.store-side-desc { margin-top: var(--sp-3); }
/* dl Store info — thay cho style="display:grid;grid-template-columns:110px 1fr" (store.html:105) */
.store-meta { display: grid; grid-template-columns: 110px 1fr; row-gap: var(--sp-2); }
.store-meta dt { color: var(--ink-500); }
.card-label { margin-bottom: var(--sp-3); }
.offer-count { margin-top: 4px; }

/* --- panel reveal (store-reveal.html:19-25) ------------------------------- */
.reveal { border: 1px solid var(--teal-100); }
.reveal-top { display: flex; gap: var(--sp-4); align-items: flex-start; }
.reveal-top .offer-label { flex: 0 0 96px; }
.reveal-top .reveal-copy { flex: 1; min-width: 0; }
.reveal-top .badges { display: flex; gap: 6px; margin-bottom: 6px; }
.reveal .code-box { margin-top: var(--sp-4); }
.reveal .banner { margin-top: var(--sp-4); }
.reveal-actions { display: flex; flex-wrap: wrap; gap: var(--sp-3); align-items: center; margin-top: var(--sp-4); }
.code-box .copy-field > code { font-size: var(--fs-mono); letter-spacing: .12em; text-transform: uppercase; }
/* the copy field inside the offer card of the revealed offer (store-reveal.html:195) */
.offer-act .code-box { padding: 9px var(--sp-3); }

/* --- trang category (category.html:9-21) --------------------------------- */
.cat-head { background: var(--white); border-radius: var(--r-lg); padding: var(--sp-6);
  box-shadow: var(--card-shadow); }
.cat-head h1 { margin-bottom: var(--sp-3); }
.cat-stats { display: flex; flex-wrap: wrap; gap: var(--sp-6); margin-top: var(--sp-4);
  padding-top: var(--sp-4); border-top: 1px solid var(--gray-50); }
.cat-stats .n { font-size: var(--fs-h2); line-height: var(--lh-h2); font-weight: var(--fw-bold);
  font-variant-numeric: tabular-nums; }
.cat-stats .l { font-size: var(--fs-caption); line-height: var(--lh-caption); font-weight: var(--fw-medium);
  letter-spacing: var(--tracking-caption); text-transform: uppercase; color: var(--ink-400); }
.store-card .head { display: flex; gap: var(--sp-3); align-items: center; }
.store-card .logo-img { width: 48px; height: 48px; border-radius: var(--r-md); object-fit: cover; flex: 0 0 auto; }
.rel-list { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.rel-list a { background: var(--white); border-radius: var(--r-full); padding: 7px 14px;
  font-size: var(--fs-small); color: var(--ink-900); }
.rel-list a:hover { background: var(--gray-50); text-decoration: none; }

/* --- post detail (blog-detail.html:9-32) --------------------------------- */
.article { max-width: 720px; margin: 0 auto; }             /* ~70 characters per line */
.article .cover { height: 320px; border-radius: var(--r-lg); margin-bottom: var(--sp-6);
  width: 100%; object-fit: cover; }
.article h1 { margin-bottom: var(--sp-3); }
.article-head { margin-bottom: var(--sp-6); }
.article-head h1 { margin-top: var(--sp-3); }
.post-meta { display: flex; flex-wrap: wrap; gap: var(--sp-3); align-items: center;
  font-size: var(--fs-small); color: var(--ink-500); }
.article-body { background: var(--white); border-radius: var(--r-lg); padding: var(--sp-8);
  box-shadow: var(--card-shadow); }
.post-row .body { min-width: 0; }
.post-row h4 { margin-top: 6px; }
.post-row .date { margin-top: 4px; }
.post-card .cover-img, .post-row .cover-img { object-fit: cover; }
.post-card .cover-img { width: 100%; height: 148px; }
.post-row .cover-img { flex: 0 0 72px; width: 72px; height: 72px; border-radius: var(--r-md); }
.deal-card .cover-img { width: 100%; height: 140px; border-radius: var(--r-md);
  object-fit: cover; margin-bottom: var(--sp-3); }

/* the in-post coupon box — only rendered when posts.store_id is set */
.coupon-box { border: 1px solid var(--teal-100); border-radius: var(--r-lg);
  padding: var(--sp-5); margin: var(--sp-8) 0; background: var(--white); }
.coupon-box .cb-head { display: flex; align-items: center; gap: var(--sp-3); margin-bottom: var(--sp-4); }
.coupon-box .cb-head .logo-tile, .coupon-box .cb-head .logo-img { width: 44px; height: 44px;
  font-size: var(--fs-dense); border-radius: var(--r-md); object-fit: cover; flex: 0 0 auto; }
.coupon-box .cb-head .cb-title { flex: 1; min-width: 0; }
.coupon-box .cb-row { display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) 0; border-top: 1px solid var(--gray-50); }
.coupon-box .cb-label { flex: 0 0 72px; font-size: var(--fs-h2); line-height: var(--lh-h2);
  font-weight: var(--fw-bold); color: var(--teal-800); font-variant-numeric: tabular-nums; }
.coupon-box .cb-label.is-long { font-size: var(--fs-h3); }
.coupon-box .cb-mid { flex: 1; min-width: 0; }
.coupon-box .cb-mid .n { font-size: var(--fs-dense); font-weight: var(--fw-semibold); color: var(--ink-900); }
.coupon-box .cb-all { display: block; margin-top: var(--sp-3); font-size: var(--fs-small); }
@media (max-width: 600px) {
  .article-body { padding: var(--sp-5); }
  .coupon-box .cb-row { flex-wrap: wrap; }
  .coupon-box .cb-row .btn { width: 100%; }
}

/* --- spacing utilities replacing the style= attributes scattered in the wireframes --- */
.mt-1 { margin-top: var(--sp-1); }
.mt-2 { margin-top: var(--sp-2); }
.mt-3 { margin-top: var(--sp-3); }
.mt-4 { margin-top: var(--sp-4); }
.mt-6 { margin-top: var(--sp-6); }
.mb-4 { margin-bottom: var(--sp-4); }
.w-auto { width: auto; }

/* --- deal listing page --------------------------------------------------- */
.deal-grid { display: grid; gap: var(--sp-4); grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); }

/* ==========================================================================
   ADMIN — component theo trang (admin-list.html:10-15, admin-form.html:10-35)
   ========================================================================== */

.admin-card { background: var(--white); border-radius: var(--r-lg); overflow: hidden; box-shadow: var(--card-shadow); }
.tbl .col-type { width: 96px; }
.tbl .store-cell { color: var(--ink-900); }
.tbl .drag { font-size: 14px; }
.tbl .col-actions { padding-left: var(--sp-4); }
.tbl .thumb { width: 28px; height: 28px; border-radius: var(--r-sm); object-fit: cover; }

.form-wrap { max-width: 880px; }
.form-wrap .card + .card { margin-top: var(--sp-6); }
.card-title { display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-3); margin-bottom: var(--sp-5); }

/* rich text block — Tiptap mounts into .rt-body */
.rt { border: 1px solid var(--gray-200); border-radius: var(--r-sm); overflow: hidden; }
.rt-bar { display: flex; flex-wrap: wrap; gap: var(--sp-1); padding: 6px;
  background: var(--gray-50); border-bottom: 1px solid var(--gray-200); }
.rt-bar button { min-width: 30px; height: 30px; padding: 0 8px; border: 0; border-radius: var(--r-sm);
  background: transparent; color: var(--ink-700); font-size: var(--fs-small); cursor: pointer; }
.rt-bar button:hover { background: var(--white); }
.rt-bar button.is-active { background: var(--white); color: var(--teal-800); font-weight: var(--fw-semibold); }
.rt-bar .sep { width: 1px; background: var(--gray-200); margin: 4px 4px; }
.rt-body { min-height: 180px; padding: var(--sp-4); background: var(--white); }
.rt-body:focus-visible { outline-offset: -2px; }
.rt-body img { max-width: 100%; border-radius: var(--r-sm); }
.rt-foot { display: flex; justify-content: space-between; padding: 6px var(--sp-3);
  border-top: 1px solid var(--gray-50); font-size: var(--fs-caption); color: var(--ink-400); }

/* bottom-sticky action bar — top border, NO shadow (a shadow would fall over the scrolling content) */
.form-bar { position: sticky; bottom: 0; margin-top: var(--sp-6);
  background: var(--white); border-top: 1px solid var(--gray-200);
  border-radius: 0 0 var(--r-lg) var(--r-lg);
  padding: var(--sp-4) var(--card-pad);
  display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; }
.type-pill { margin-left: auto; display: flex; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-small); color: var(--ink-500); }
/* checkbox help text has to wrap, otherwise the label runs straight into the description */
.check .field-help { display: block; margin-top: 2px; }
/* the sticky bar covers the end of the form unless the form reserves room */
.form-wrap { padding-bottom: var(--sp-2); }

/* admin sign-in screen */
.login-wrap { min-height: 100vh; display: flex; align-items: center; justify-content: center;
  background: var(--gray-100); padding: var(--sp-6); }
.login-card { width: 100%; max-width: 380px; }
.login-card h1 { font-size: var(--fs-h2); line-height: var(--lh-h2); margin-bottom: var(--sp-2); }
.login-card .sub { color: var(--ink-500); font-size: var(--fs-small); margin-bottom: var(--sp-5); }
.login-card .btn { width: 100%; margin-top: var(--sp-4); }

/* image upload + FAQ repeater */
.upload-field { display: flex; gap: var(--sp-3); align-items: flex-start; }
.upload-field .preview { width: 72px; height: 72px; border-radius: var(--r-md); object-fit: cover;
  background: var(--gray-50); flex: 0 0 auto; }
.upload-field .ph { width: 72px; height: 72px; flex: 0 0 auto; font-size: var(--fs-caption); }
.faq-item { border: 1px solid var(--gray-200); border-radius: var(--r-sm); padding: var(--sp-3);
  display: flex; flex-direction: column; gap: var(--sp-2); }
.faq-item + .faq-item { margin-top: var(--sp-3); }
.faq-item .faq-item-head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); }

/* confirmation modal — the native <dialog> handles the focus trap and Escape */
dialog.confirm { border: 0; border-radius: var(--r-lg); padding: var(--card-pad); max-width: 420px;
  box-shadow: var(--shadow-lg); color: var(--ink-900); background: var(--white); }
dialog.confirm::backdrop { background: rgba(22, 26, 23, .45); }
dialog.confirm h3 { margin-bottom: var(--sp-2); }
dialog.confirm p { font-size: var(--fs-small); color: var(--ink-500); }
dialog.confirm .actions { display: flex; gap: var(--sp-3); justify-content: flex-end; margin-top: var(--sp-5); }

.hint { font-size: var(--fs-small); color: var(--ink-400); margin-top: var(--sp-2); }
.is-dragging { opacity: .6; }
