/* TaemDee — global design tokens and screen-specific styles
 * Reflects designer drop in `taemdee-final-thai.html` (S1 Login + global system).
 * Subsequent releases will append more screen-specific blocks below.
 *
 * The Google Fonts <@import> used to live here; moved into pwa_head.html
 * as a parallel <link rel="stylesheet"> so the font CSS download no
 * longer serialises behind app.css parsing — both stylesheets fetch
 * concurrently and first paint arrives sooner.
 */

* { box-sizing: border-box; margin: 0; padding: 0; }
[x-cloak] { display: none !important; }

html, body {
  height: 100%;
  background: #F6F1E5;
}

/* ==========================================================
   Native-app feel — kill the "this is a website" tells.
   Applied at the .td root so both shop and customer surfaces
   pick it up. Text selection is restored on inputs and on the
   handful of read-text contexts (messages, voucher/reward
   labels, customer + product names) where the user might want
   to copy a string.
   ==========================================================
   - overscroll-behavior: none stops the iOS rubber-band on the
     body so vertical drags don't reveal a grey backdrop.
   - -webkit-tap-highlight-color: transparent removes the grey
     flash on every tap.
   - -webkit-touch-callout: none disables the long-press preview
     menu on links + images.
   - user-select: none stops accidental text-selection drags;
     restored to text on inputs/textareas/messages/copyable
     labels so reading + editing copy still works.
*/
html:has(.td),
body:has(.td) {
  overscroll-behavior: none;
}
.td {
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}
.td input,
.td textarea,
.td [contenteditable="true"],
.td .selectable,
.td .msg-body,
.td .st-preview,
.td .vc-reward,
.td .vc-shop,
.td .cust-name,
.td .row-name,
.td .row-meta {
  -webkit-user-select: text;
  user-select: text;
  -webkit-touch-callout: default;
}

/* No mobile zoom — viewport tag pins user-scalable=no, but Safari
   iOS still auto-zooms when an input's font-size is below 16px.
   Force the minimum across every text-entry field so focusing one
   never re-frames the page. */
.td input[type="text"],
.td input[type="tel"],
.td input[type="email"],
.td input[type="password"],
.td input[type="search"],
.td input[type="number"],
.td input[type="url"],
.td textarea,
.td select {
  font-size: max(16px, 1em);
}
/* Kill the 300ms double-tap-zoom delay on tappable surfaces so the
   PWA reads as native. Anchors and buttons inside .td are the
   common case; leave inputs alone so caret placement still works. */
.td a,
.td button {
  touch-action: manipulation;
}

/* Press feedback — quick scale(0.97) on :active for the common
   tappable surfaces so taps feel like presses, not link clicks.
   Per-element :active rules elsewhere in this file (e.g. .gl-hero,
   .pe-save, .sap-action) override or stack as the cascade allows.
   Inputs / textareas and the floating glass-nav are deliberately
   left out — text fields shouldn't deform, and the dock has its
   own gn-tab:active opacity tint. */
.td .s1-btn,
.td .s10-row,
.td .s10-logout,
.td .cust-row,
.td .cl-mini,
.td .cl-other-row,
.td .cl-add,
.td .cl-todo,
.td .cl-todo-cta,
.td .cl-todo-skip-x,
.td .cl-voucher-card,
.td .cl-voucher-cta,
.td .cce-btn,
.td .gl-hero,
.td .gl-mini,
.td .gl-used-toggle,
.td .gl-used-row,
.td .s2-cta,
.td .s2-cta-final,
.td .s2-goal-pill,
.td .s2-reward,
.td .s3-cust-stat,
.td .s3-todo,
.td .s3-skip-btn,
.td .sap-action,
.td .fc,
.td .mp,
.td .pe-save,
.td .pe-cancel,
.td .pe-default-btn,
.td .pe-avatar,
.td .send,
.td .cancel,
.td .vc-card,
.td button[type="submit"]:not(:disabled),
.td button[type="button"]:not(:disabled) {
  transition: transform 0.08s ease;
}
.td .s1-btn:active,
.td .s10-row:active,
.td .s10-logout:active,
.td .cust-row:active,
.td .cl-mini:active,
.td .cl-other-row:active,
.td .cl-add:active,
.td .cl-todo:active,
.td .cl-todo-cta:active,
.td .cl-todo-skip-x:active,
.td .cl-voucher-card:active,
.td .cl-voucher-cta:active,
.td .cce-btn:active,
.td .gl-used-toggle:active,
.td .gl-used-row:active,
.td .s2-cta:active,
.td .s2-goal-pill:active,
.td .s2-reward:active,
.td .s3-cust-stat:active,
.td .s3-todo:active,
.td .s3-skip-btn:active,
.td .fc:active,
.td .mp:active,
.td .pe-default-btn:active,
.td .pe-avatar:active,
.td .send:active,
.td .cancel:active,
.td .vc-card:active,
.td button[type="submit"]:not(:disabled):active,
.td button[type="button"]:not(:disabled):active {
  transform: scale(0.97);
}

/* Reserve the scrollbar gutter so switching between tabs of different
   heights doesn't shift content horizontally when the vertical
   scrollbar appears or disappears. `stable` keeps the gutter present
   on long pages too; on mobile (no visible scrollbar) it's a no-op. */
html {
  scrollbar-gutter: stable;
}

/* Cross-document View Transitions — browser fades between same-origin
   navigations automatically (no JS / no SPA needed). Falls back to a
   regular page load on browsers that don't support it (Firefox, Safari
   < 18.2, Chrome < 126). */
@view-transition { navigation: auto; }

/* Glass nav stability across tab navigations — we deliberately do NOT
   set view-transition-name on the dock. Naming a backdrop-filter element
   makes Chrome snapshot it without the backdrop content, so during the
   transition the dock briefly looks washed out / blurry until the live
   element reappears. Instead we kill the root fade entirely (animation:
   none) so the new page just paints in place. With Speculation Rules
   prefetch warming the cache, the swap is effectively instant, and the
   fixed-position dock with identical chassis across pages stays put. */
::view-transition-old(root),
::view-transition-new(root) { animation: none; }

body {
  font-family: 'Prompt', system-ui, sans-serif;
  color: #111;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

/* ==========================================================
   TaemDee mobile shell — every shop/customer screen lives in .td
   ========================================================== */

.td {
  --bg: #F6F1E5;
  --surface: #FDFAF2;
  --ink: #111111;
  --ink-soft: #6B6660;
  --ink-softer: #A39D92;
  --accent: #FF5E3A;
  --accent-soft: #FFE6DF;
  --butter: #FFD952;
  --butter-soft: #FFF1B8;
  --mint: #C8E8D0;
  --mint-ink: #1A6B3A;
  --line-green: #06C755;
  --line: rgba(17, 17, 17, 0.10);
  /* Text-size scale (Apr 30 design refresh — rem-based so the C6
     ขนาดตัวอักษร picker can swap font-size on <html> and any rule
     using these vars scales naturally). 1rem = 16px default. */
  --text-2xs:    0.625rem;  /* 10px · labels, ids */
  --text-xs:     0.75rem;   /* 12px · caption, meta */
  --text-sm:     0.8125rem; /* 13px · secondary body */
  --text-base:   0.875rem;  /* 14px · body, row name (DEFAULT) */
  --text-md:     1rem;      /* 16px · emphasis */
  --text-lg:     1.125rem;  /* 18px · subtitle */
  --text-xl:     1.375rem;  /* 22px · page title (h1) */
  --text-2xl:    2.25rem;   /* 36px · hero number */
  --text-display: 4rem;     /* 64px · DeeCard hero */
  font-family: 'Prompt', sans-serif;
  color: var(--ink);
  background: var(--bg);
  min-height: 100vh;
  min-height: 100dvh;        /* dvh respects iOS Safari toolbar */
  width: 100%;
  position: relative;
  overflow-x: hidden;
  display: flex;
  flex-direction: column;
}

.td::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image:
    radial-gradient(circle at 85% 12%, rgba(255, 217, 82, 0.5) 0%, rgba(255, 217, 82, 0) 35%),
    radial-gradient(circle at 10% 85%, rgba(255, 94, 58, 0.08) 0%, transparent 45%);
  pointer-events: none;
  z-index: 0;
}

.td::after {
  content: '';
  position: absolute;
  inset: 0;
  background-image: radial-gradient(circle, rgba(17, 17, 17, 0.07) 1px, transparent 1.5px);
  background-size: 18px 18px;
  opacity: 0.4;
  pointer-events: none;
  z-index: 0;
}

.td > * { position: relative; z-index: 1; }

/* ==========================================================
   S1 — Login (shop tab default)
   ========================================================== */

.s1-tab.active {
  background: var(--ink);
  color: var(--bg);
  font-weight: 700;
  box-shadow: 0 2px 6px -2px rgba(17, 17, 17, 0.4);
}

.s1-tab:not(.active) .tab-pill.optional {
  background: transparent;
  color: var(--ink-soft);
  border: 1px solid var(--line);
}

.s1-hero {
  text-align: center;
  padding: 28px 30px 16px;
  position: relative;
}
.s1-hero::before {
  content: '';
  position: absolute;
  top: 0; left: 50%;
  transform: translateX(-50%);
  width: 220px; height: 220px;
  background: radial-gradient(circle, var(--butter) 0%, transparent 60%);
  opacity: 0.55;
  border-radius: 50%;
  z-index: 0;
}
.s1-hero > * { position: relative; z-index: 1; }

.s1-logo-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 22px;
  position: relative;
}

.s1-name {
  font-weight: 800;
  font-size: 40px;
  letter-spacing: -0.035em;
  line-height: 1;
  margin-bottom: 10px;
}
.s1-name .dot { color: var(--accent); }

.s1-tag {
  font-weight: 500;
  font-size: 14px;
  color: var(--ink-soft);
  line-height: 1.55;
}

.s1-buttons {
  padding: 24px 22px 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

/* S1 — Branch info note */
.s1-branch-note {
  margin: 18px 22px 0;
  padding: 12px 14px;
  border: 1.5px dashed var(--ink-softer);
  border-radius: 14px;
  display: flex;
  align-items: flex-start;
  gap: 10px;
  background: var(--surface);
}
.s1-branch-note .bn-icon {
  flex-shrink: 0;
  width: 22px;
  height: 22px;
  color: var(--ink-soft);
  display: flex;
  align-items: center;
  justify-content: center;
  margin-top: 1px;
}
.s1-branch-note .bn-icon svg { width: 18px; height: 18px; }
.s1-branch-note .bn-text {
  flex: 1;
  line-height: 1.35;
}
.s1-branch-note .bn-h {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 12px;
  color: var(--ink);
  margin-bottom: 2px;
}
.s1-branch-note .bn-s {
  font-family: 'Prompt', sans-serif;
  font-size: 11px;
  color: var(--ink-soft);
}

.s1-btn {
  width: 100%;
  padding: 14px 16px;
  border-radius: 16px;
  border: 1px solid rgba(17, 17, 17, 0.18);
  font-family: inherit;
  font-size: 14.5px;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  cursor: pointer;
  box-shadow: none;
  text-decoration: none;
  color: inherit;
}
.s1-btn-line { background: var(--line-green); color: #fff; }
.s1-btn-line svg { width: 20px; height: 20px; }
.s1-btn-phone { background: var(--ink); color: var(--bg); }
.s1-btn-phone svg { width: 18px; height: 18px; }

.s1-no-pwd .icon {
  color: var(--accent);
  font-weight: 700;
  margin-right: 4px;
}

.s1-foot {
  text-align: center;
  padding: 20px 30px;
  font-size: 13px;
  color: var(--ink-softer);
  line-height: 1.5;
  margin-top: auto;
}
.s1-foot a {
  color: var(--accent);
  text-decoration: underline;
  text-decoration-color: rgba(255, 94, 58, 0.4);
  text-underline-offset: 2px;
}

/* ==========================================================
   S1 — phone OTP entry sub-state (reveals after tapping
   "ใช้เบอร์โทร · รับ OTP")
   ========================================================== */

.s1-otp-form {
  padding: 28px 22px 0;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.s1-otp-form label {
  font-weight: 600;
  font-size: 14px;
  color: var(--ink-soft);
}
.s1-otp-form input {
  width: 100%;
  padding: 14px 16px;
  border-radius: 14px;
  border: 1px solid rgba(17, 17, 17, 0.18);
  background: var(--surface);
  font-family: inherit;
  font-size: 18px;
  font-weight: 600;
  color: var(--ink);
  letter-spacing: 0.04em;
}
.s1-otp-form input:focus {
  outline: none;
  box-shadow: none;
  transform: translate(-1px, -1px);
}
.s1-otp-form .back {
  text-align: center;
  font-size: 14px;
  color: var(--ink-softer);
  cursor: pointer;
  background: none;
  border: none;
  font-family: inherit;
  text-decoration: underline;
}
.s1-otp-form .err {
  background: var(--accent-soft);
  border: 1.5px solid var(--accent);
  color: var(--ink);
  padding: 10px 12px;
  border-radius: 12px;
  font-size: 14px;
  font-weight: 500;
}

/* ==========================================================
   S2.1 — Onboarding step 1 of 4 (shop name + reward + goal)
   ========================================================== */

.s2-steps {
  padding: 18px 20px 0;
  display: flex;
  align-items: center;
  gap: 6px;
}
.s2-steps .step {
  flex: 1;
  height: 8px;
  background: var(--line);
  border-radius: 999px;
}
.s2-steps .step.done { background: var(--ink); }
.s2-steps .step.active { background: var(--accent); }

.s2-counter {
  padding: 8px 20px 0;
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px;
  letter-spacing: 0.16em;
  color: var(--ink-soft);
  text-transform: uppercase;
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 14px;
}
.s2-counter .step-num strong { color: var(--accent); }

.s2-q {
  padding: 14px 20px 4px;
}
.s2-q .ask {
  font-weight: 700;
  font-size: 26px;
  letter-spacing: -0.02em;
  line-height: 1.15;
  margin-bottom: 4px;
}
.s2-q .ask em {
  font-style: italic;
  font-weight: 700;
  color: var(--accent);
}
.s2-q .sub {
  font-weight: 400;
  font-size: 15px;
  color: var(--ink-soft);
  line-height: 1.4;
}

.s2-field { margin: 22px 20px 0; }
.s2-field label {
  display: block;
  font-weight: 600;
  font-size: 14px;
  color: var(--ink-soft);
  margin-bottom: 6px;
  padding-left: 4px;
}
.s2-field input[type="text"],
.s2-field input[type="tel"] {
  width: 100%;
  background: var(--surface);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 14px;
  box-shadow: none;
  padding: 14px 16px;
  font-family: inherit;
  font-size: 16px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--ink);
}
.s2-field:focus-within input,
.s2-field input:focus {
  border-color: var(--accent);
  outline: none;
  box-shadow: none;
}
.s2-hint {
  margin-top: 8px;
  padding-left: 4px;
  font-style: italic;
  font-weight: 400;
  font-size: 13px;
  color: var(--ink-soft);
}

/* Goal pills are CIRCLES per the latest design — was rectangular pills.
   4 buttons (5 / 10 / 20 / กำหนดเอง) sit in a row, equal-spaced. */
.s2-goal-pills {
  margin: 14px 20px 0;
  display: flex;
  gap: 12px;
  justify-content: space-between;
}
.s2-goal-pill {
  flex: 1;
  aspect-ratio: 1;
  max-width: 76px;
  padding: 0;
  background: var(--surface);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 50%;
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: 22px;
  letter-spacing: -0.02em;
  text-align: center;
  cursor: pointer;
  box-shadow: none;
  color: var(--ink);
  display: flex;
  align-items: center;
  justify-content: center;
  appearance: none;
  -webkit-appearance: none;
}
.s2-goal-pill.selected { background: var(--butter); }
.s2-goal-pill.custom {
  background: transparent;
  border-style: dashed;
  box-shadow: none;
  color: var(--ink-soft);
  font-family: 'Prompt', sans-serif;
  font-weight: 500;
  font-size: 11px;
  flex-direction: column;
  gap: 0;
  line-height: 1.15;
}
.s2-goal-pill.custom .plus {
  color: var(--accent);
  font-weight: 700;
  font-size: 14px;
}

.s2-onboard-form {
  display: flex;
  flex-direction: column;
  flex: 1;
  /* Reserve space for the fixed-position .s2-foot so the last form
     field isn't hidden behind it on short viewports. ~76px foot
     height + breathing room. */
  padding-bottom: 96px;
}

/* Foot is fixed (was sticky — broke on iOS Safari with long forms +
   any overflow ancestor). Pinning to the viewport keeps the back/
   next buttons reachable regardless of scroll position. The
   safe-area-inset-bottom padding handles the iPhone home-bar gap. */
.s2-foot {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 10;
  background: var(--bg);
  padding: 16px 20px calc(20px + env(safe-area-inset-bottom));
  display: flex;
  align-items: stretch;
  gap: 12px;
  border-top: 1px solid var(--line);
}

.s2-foot .s2-cta-final {
  margin: 0;
  flex: 1;
}

.s2-foot .back {
  height: auto; /* Allow it to match button height */
  margin: 0;
}
.s2-foot .next {
  flex: 1;
  background: var(--ink);
  color: var(--bg);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 14px;
  padding: 14px 16px;
  font-family: inherit;
  font-weight: 700;
  font-size: 16px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  cursor: pointer;
  box-shadow: none;
}
.s2-foot .next .arrow {
  width: 26px;
  height: 26px;
  background: var(--accent);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-size: 16px;
}

/* ==========================================================
   S3 — shop dashboard (most-used shop screen)
   ========================================================== */

/* Mirrors the customer .page-head shape: left text block (greeting on
   top, sub-line below), right action row, both centered vertically.
   Earlier the s3-top kept greeting + actions in row 1 and the day
   caption was a separate sibling row, which left the greeting visually
   floating above the actions on its own line. */
.s3-top {
  padding: 14px 20px 14px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
}
.s3-top .hi {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.s3-top .hi-greet {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 19px;
  letter-spacing: -0.02em;
}
.s3-top .hi .td-greet {
  font-family: 'Prompt', sans-serif;
  font-weight: 500;
  font-size: 22px;
  letter-spacing: -0.02em;
  color: var(--ink-soft);
  line-height: 1.1;
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
}
.s3-top .hi .td-brand {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 22px;
  letter-spacing: -0.02em;
  color: var(--ink);
  line-height: 1;
}
.s3-top .hi .td-brand .dot { color: var(--accent); }
.s3-top .hi-sub {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.s3-top .hi-sub .dc-text {
  font-family: 'Prompt', sans-serif;
  font-size: 13px;
  color: var(--ink-soft);
  font-style: italic;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.s3-top .hi-sub .dc-text .smile-inline {
  width: 16px;
  height: 9px;
  color: var(--accent);
  font-style: normal;
}
.s3-top .hi-sub .branch-pill {
  padding: 6px 12px 6px 8px;
  font-size: 11px;
}
.s3-top .actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
.s3-top .branch-pill {
  display: flex;
  align-items: center;
  gap: 6px;
  background: var(--surface);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 999px;
  padding: 8px 14px 8px 10px;
  font-weight: 600;
  font-size: 15px;
  box-shadow: none;
  text-decoration: none;
  color: var(--ink);
}
.s3-top .branch-pill::before {
  content: '';
  width: 6px;
  height: 6px;
  background: var(--accent);
  border-radius: 50%;
}
.s3-top .avatar {
  width: 44px;
  height: 44px;
  background: var(--accent);
  color: #fff;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: 16px;
  box-shadow: 0 4px 12px -4px rgba(255, 94, 58, 0.4);
  border: 1px solid rgba(17, 17, 17, 0.18);
}

/* S3 hero — compact, centered. Delta lives inline in the hero-top row. */
.s3-hero .label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: 'Prompt', sans-serif;
  font-style: italic;
  font-weight: 500;
  font-size: 14px;
  color: var(--ink-soft);
  background: var(--butter-soft);
  padding: 4px 10px;
  border-radius: 999px;
  border: 1px dashed var(--butter);
}
.s3-hero .delta {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 14px;
  color: var(--mint-ink);
  background: var(--mint);
  padding: 4px 10px;
  border-radius: 999px;
}
.s3-hero .delta.is-down {
  color: var(--accent);
  background: var(--accent-soft);
}
.s3-hero .num {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 700;
  font-size: 110px;
  letter-spacing: -0.065em;
  line-height: 0.95;
  color: var(--ink);
  position: relative;
  display: inline-block;
  margin: 0;
}
.s3-hero .num .accent { color: var(--accent); }
.s3-hero .num .star {
  position: absolute;
  top: 6px;
  right: -22px;
  width: 22px;
  height: 22px;
  color: var(--butter);
  stroke: var(--ink);
  stroke-width: 2;
  animation: gentle-spin 6s linear infinite;
}
@keyframes gentle-spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}
.s3-hero .caption {
  font-family: 'Prompt', sans-serif;
  font-size: 16px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--ink-soft);
  margin-top: 2px;
}

/* Single-line stats pill — replaces the 3-stat grid. */
/* Brief-card now links to the S13 list (not a per-suggestion send form),
   so the previous .reach-btn is replaced by a non-button .reach-cta strip. */
/* DeeReach empty-state placeholder — shown when the suggestion engine
   has nothing to recommend (no lapsed customers, no near-full cards). */
.s3-reach.placeholder {
  background: var(--butter-soft);
  border-style: dashed;
  box-shadow: none;
  opacity: 0.92;
}
.s3-reach.placeholder::before { content: ''; }
.s3-reach.placeholder .reach-kicker {
  background: rgba(17, 17, 17, 0.06);
  color: var(--ink-soft);
}
.s3-reach.placeholder .reach-head { color: var(--ink-soft); }

/* ==========================================================
   Shared — section header + live feed rows (used in S3)
   ========================================================== */

.ph-section-h {
  padding: 0 20px 8px;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
}
.ph-section-h .label {
  font-style: italic;
  font-weight: 500;
  font-size: 15px;
  color: var(--ink);
}
.ph-section-h .live {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-family: 'JetBrains Mono', monospace;
  font-size: 11px;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--accent);
  font-weight: 600;
}
.ph-section-h .live::before {
  content: '';
  width: 6px;
  height: 6px;
  background: var(--accent);
  border-radius: 50%;
  animation: dot-pulse 1.2s ease-in-out infinite;
}
@keyframes dot-pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.4; transform: scale(0.8); }
}

/* The old .feed-row was a 3-column grid card (display:grid + border +
   box-shadow) used when feed rows were standalone <div>s. Now they're
   <tr>s inside .sap-table — those styles forced tr→grid which broke
   table layout (each row rendered as a stacked rounded card). All
   row styling now lives under .s3-dock .sap-table tr.feed-row above. */

/* ==========================================================
   App bar (back / title / right action) — used in S5, S8, S10+
   ========================================================== */

.app-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 16px;
  position: sticky;
  top: 0;
  background: var(--bg);
  z-index: 5;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  flex-shrink: 0;
}
.app-bar .x {
  width: 36px;
  height: 36px;
  background: rgba(17, 17, 17, 0.05);
  border: none;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  color: var(--ink);
  text-decoration: none;
}
.app-bar .x svg { width: 16px; height: 16px; }
.app-bar .title-mid {
  font-family: 'Prompt', sans-serif;
  font-weight: 600;
  font-size: var(--text-base);
  color: var(--ink);
}
.app-bar .placeholder { width: 36px; height: 36px; }

/* Three-dot overflow menu in app-bar's right slot. The button itself
   reuses .x's circular chrome so it sits balanced opposite the back
   arrow; the popover is a small rounded card anchored bottom-right
   of the button. */
.appbar-menu { position: relative; }
.appbar-menu-btn {
  width: 36px;
  height: 36px;
  background: rgba(17, 17, 17, 0.05);
  border: none;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  color: var(--ink);
  padding: 0;
}
.appbar-menu-btn svg { width: 18px; height: 18px; }
.appbar-menu-pop {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  min-width: 180px;
  background: var(--surface);
  border: 1px solid rgba(17, 17, 17, 0.10);
  border-radius: 12px;
  box-shadow: 0 12px 28px -8px rgba(17, 17, 17, 0.22);
  padding: 4px;
  z-index: 20;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.appbar-menu-pop a {
  padding: 10px 12px;
  border-radius: 8px;
  text-decoration: none;
  color: var(--ink);
  font-family: 'Prompt', sans-serif;
  font-weight: 500;
  font-size: 13.5px;
}
.appbar-menu-pop a:hover { background: rgba(17, 17, 17, 0.04); }

/* Credit-log row delta — green tint when credits arrived (topup,
   welcome credit), red tint when they left (deereach send). The
   number sits where .arrow-r usually does in a settings row. */
.credit-delta {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 700;
  font-size: 14px;
  letter-spacing: -0.01em;
  white-space: nowrap;
}
.credit-delta.up { color: var(--mint-ink, #1A6B3A); }
.credit-delta.down { color: var(--ink-soft); }
.credit-delta .cdl-unit {
  font-family: 'Prompt', sans-serif;
  font-weight: 500;
  font-size: 10.5px;
  color: var(--ink-softer);
  margin-left: 3px;
}

/* Settings-list empty state — used by topup history + credit log when
   the section has no rows. Lives outside the s10-row chrome so the
   text doesn't wrap into a tiny meta column. */
.s10-empty {
  margin: 0;
  padding: 16px 14px;
  background: var(--surface);
  border-radius: 12px;
  font-family: 'Prompt', sans-serif;
  font-size: 13px;
  color: var(--ink-soft);
  text-align: center;
}
.s10-empty a { color: var(--accent); font-weight: 600; }

/* ==========================================================
   S8 — Shop QR (printable / shareable)
   ========================================================== */

.s8-actions {
  display: flex;
  gap: 8px;
  padding: 18px 20px 0;
}
.s8-actions .pill {
  flex: 1;
  padding: 10px 12px;
  background: var(--surface);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 999px;
  box-shadow: none;
  font-family: inherit;
  font-weight: 700;
  font-size: 14px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  cursor: pointer;
  color: var(--ink);
}
.s8-actions .pill svg { width: 13px; height: 13px; }
.s8-actions .pill.primary { background: var(--ink); color: var(--bg); }

.qr-card {
  width: 100%;
  max-width: 280px;
  background: #fff;
  border: none;
  border-radius: 24px;
  padding: 32px 24px 24px;
  position: relative;
  box-shadow: 0 4px 20px rgba(0,0,0,0.06);
  display: flex;
  flex-direction: column;
  align-items: center;
}

.qr-card .cut-mark { position: absolute; width: 12px; height: 12px; border: 0.5px solid var(--ink-soft); z-index: 10; opacity: 0.4; }
.qr-card .cut-mark.tl { top: 8px; left: 8px; border-right: none; border-bottom: none; }
.qr-card .cut-mark.br { bottom: 8px; right: 8px; border-left: none; border-top: none; }


.qr-card .card-head {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-top: 12px;
  margin-bottom: 24px;
}
.qr-card .shop-logo-mark {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: 32px;
  letter-spacing: -0.04em;
  color: var(--ink);
  line-height: 1;
  margin-bottom: 6px;
}
.qr-card .shop-logo-mark.is-thai,
.qr-card .shop-logo-mark.is-thai span {
  font-family: 'Prompt', sans-serif !important;
  font-weight: 800 !important;
  font-size: 28px !important;
  letter-spacing: 0 !important;
  font-style: normal !important;
  text-transform: none !important;
  color: var(--ink) !important;
}
.qr-card .shop-logo-mark .dot { color: var(--accent); }
.qr-card .shop-logo-img { width: 44px; height: 44px; border-radius: 10px; object-fit: cover; }

.qr-card .shop-sub {
  font-family: 'Prompt', sans-serif;
  font-weight: 500;
  font-size: 12px;
  color: var(--ink-soft);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  opacity: 0.8;
}
.qr-card .shop-sub .dotsep { width: 3px; height: 3px; background: var(--accent); border-radius: 50%; }

.qr-card .qr-wrap { display: flex; justify-content: center; margin-bottom: 16px; position: relative; }
.qr-card .qr-main {
  width: 170px; height: 170px;
  background: #fff;
  border: 1px solid rgba(17, 17, 17, 0.12);
  border-radius: 16px;
  padding: 10px;
  position: relative;
  filter: drop-shadow(0 4px 12px rgba(255, 94, 58, 0.15));
}
.qr-card.mode-preview .qr-main { width: 140px; height: 140px; border-radius: 14px; }
.qr-card .qr-main svg { width: 100%; height: 100%; display: block; }
.qr-card .qr-center {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: 44px; height: 44px;
  background: var(--accent);
  border-radius: 12px;
  border: 4px solid #fff;
  box-shadow: 0 4px 10px rgba(0,0,0,0.15);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  color: #fff;
  z-index: 5;
}
.qr-card .qr-center.brand-mark { padding: 0; }
.qr-card .qr-center .smile-center { width: 22px; height: 13px; color: #fff; }
.qr-card .qr-center { width: 44px; height: 44px; font-size: 18px; border-radius: 12px; }
.qr-card .qr-center .dot { color: var(--butter); }

.qr-card .trust-strip {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  font-family: 'Prompt', sans-serif;
  font-weight: 600;
  font-size: 10px;
  letter-spacing: -0.01em;
  color: var(--ink);
  margin-bottom: 16px;
  white-space: nowrap;
  width: 100%;
}
.qr-card .trust-strip .dotsep { width: 4px; height: 4px; background: var(--accent); border-radius: 50%; opacity: 0.8; }

.qr-card .brand-foot {
  display: flex;
  align-items: center;
  justify-content: center;
  margin-top: 16px;
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: 13px;
  letter-spacing: -0.02em;
  color: var(--ink);
  line-height: 1;
  opacity: 0.9;
}
.qr-card.mode-preview .brand-foot { margin-top: 10px; font-size: 12px; }
.qr-card .brand-foot .dot { color: var(--accent); }

/* Print stylesheet — what actually goes on the wall. */
@media print {
  body, html { background: #fff; }
  .td::before, .td::after { display: none; }
  .topbar, .td-badge, .app-bar, .s8-actions { display: none !important; }
  .qr-card { border: none; padding: 0; margin: 0; background: transparent; }
  .qr-card .cut-mark { display: none; }
  .qr-card.mode-preview { display: none; } /* Hide the preview version if it exists on a print page */
  .qr-card.mode-print { display: block !important; }
    box-shadow: none;
    margin: 0;
    page-break-inside: avoid;
  }
  }

/* ==========================================================
   C1 — DeeCard (the customer's stamp card)
   Includes shared customer chrome: shop-head, hero-num,
   stamps, reward-pill, footer-mark, install-pill
   ========================================================== */

/* Common shop head used in C1/C2/C4 */
.shop-head {
  padding: 48px 20px 0;
  text-align: center;
  position: relative;
}
/* Default sizing for the wordmark + sub-line, used outside of the .hero
   variant. Block-level on both so the sub-line always wraps below the
   wordmark — earlier inline-block/inline-flex on these two siblings let
   them collapse onto the same row on wider phones. text-align center
   stays explicit so an <img> logo (inline replaced element) and a
   <span class="lt-*"> wordmark both end up centered horizontally. */
.shop-head .shop-logo-mark {
  display: block;
  text-align: center;
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: 30px;
  letter-spacing: -0.04em;
  margin-bottom: 4px;
}
.shop-head .shop-logo-img { display: block; margin: 0 auto; }
.shop-head .shop-logo-mark .dot { color: var(--accent); }
/* Thai wordmark — same trick as .qr-card .shop-logo-mark.is-thai. The
   latin Host Grotesk that lt-* styles inherit has no Thai glyphs and
   falls back to the OS default; force Prompt at a slightly smaller size
   so it reads as the same visual weight as the latin variant. */
.shop-head .shop-logo-mark.is-thai,
.shop-head .shop-logo-mark.is-thai span {
  font-family: 'Prompt', sans-serif !important;
  font-weight: 800 !important;
  font-style: normal !important;
  letter-spacing: 0 !important;
  text-transform: none !important;
  color: var(--ink) !important;
}
.shop-head .shop-logo-mark.is-thai { font-size: 28px; }
.shop-head.hero .shop-logo-mark.is-thai { font-size: 38px; }
.shop-head .shop-sub {
  font-family: 'Prompt', sans-serif;
  font-weight: 400;
  font-size: var(--text-sm);
  color: var(--ink-soft);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}
.shop-head .shop-sub .dotsep {
  width: 3px;
  height: 3px;
  background: var(--accent);
  border-radius: 50%;
  flex-shrink: 0;
}
/* Larger version for the C1/C2 first-impression hero. Flex column so the
   .shop-avatar chip (inline-flex — text-align alone doesn't reliably
   centre it across the .td flex context) and the name / sub lines stack
   centred regardless of their own display type. */
.shop-head.hero {
  padding: 50px 20px 0;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.shop-head.hero .shop-logo-mark {
  font-size: 44px;
  letter-spacing: -0.035em;
  margin-bottom: 8px;
}
.shop-head.hero .shop-sub {
  font-size: var(--text-md);
  letter-spacing: 0.01em;
}
/* Shop name displayed under the .shop-avatar chip on /card. The chip
   itself may render the wordmark or an image; the name line is the
   plain customer-facing text so both readings line up. */
.shop-head .shop-name {
  font-family: 'Prompt', sans-serif;
  font-weight: 800;
  font-size: 22px;
  color: var(--ink);
  letter-spacing: -0.01em;
  margin-top: 12px;
  margin-bottom: 4px;
  line-height: 1.2;
}
.shop-head.hero .shop-name {
  font-size: 26px;
  margin-top: 14px;
}

/* C1 top-left back arrow → /my-cards. Always visible — PWA in standalone
   mode has no browser back, so an explicit affordance is required. */
.c1-avatar {
  position: absolute;
  top: 18px;
  right: 18px;
  z-index: 5;
  width: 36px;
  height: 36px;
  background: var(--accent);
  color: #FFF;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: var(--text-base);
  box-shadow: 0 4px 12px -4px rgba(255, 94, 58, 0.4);
  cursor: pointer;
  text-decoration: none;
}

/* C1 greeting line — น้องแต้ม welcomes the returning customer by name.
   Block layout (not flex) so text-align:center centers each <br>-wrapped
   line independently. With display:flex the span's content width matched
   the longest line, leaving shorter lines visually left-aligned. */
.c1-greet-bubble {
  margin: 12px 18px 4px;
  padding: 8px 12px;
  text-align: center;
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-base);
  color: var(--ink-soft);
  line-height: 1.45;
}
.c1-greet-bubble .cgb-text strong {
  color: var(--ink);
  font-weight: 700;
}

/* C2.1 welcome — mascot avatar above the nickname prompt sheet. */
/* ==========================================================
   C2 Onboarding canvas (C2.1 / C2.2 / C2.3) — full-page flow
   ========================================================== */
.td.onboarding {
  display: flex;
  flex-direction: column;
  background: var(--bg);
  position: relative;
  overflow: hidden;
}
/* Atmospheric background — soft butter mesh + decorative dot grid */
.td.onboarding::before {
  content: '';
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse 60% 50% at 50% 30%, rgba(255, 217, 82, 0.22), transparent 60%),
    radial-gradient(ellipse 80% 60% at 20% 90%, rgba(255, 94, 58, 0.08), transparent 60%),
    radial-gradient(ellipse 70% 50% at 100% 60%, rgba(255, 217, 82, 0.12), transparent 60%);
  pointer-events: none;
  z-index: 0;
}
.td.onboarding::after {
  content: '';
  position: absolute;
  inset: 0;
  background-image: radial-gradient(circle at 50% 50%, rgba(17,17,17,0.04) 1px, transparent 1px);
  background-size: 24px 24px;
  opacity: 0.5;
  pointer-events: none;
  z-index: 0;
}
.td.onboarding > * { position: relative; z-index: 1; }

/* Step 2 mood — celebration: warmer butter glow */
.td.onboarding.step-2::before {
  background:
    radial-gradient(ellipse 70% 60% at 50% 35%, rgba(255, 217, 82, 0.45), transparent 65%),
    radial-gradient(ellipse 50% 40% at 30% 70%, rgba(255, 94, 58, 0.12), transparent 60%),
    radial-gradient(ellipse 50% 40% at 70% 70%, rgba(255, 217, 82, 0.2), transparent 60%);
}
/* Step 3 mood — trust: calm cream + soft mint hint */
.td.onboarding.step-3::before {
  background:
    radial-gradient(ellipse 60% 50% at 50% 30%, rgba(200, 232, 208, 0.3), transparent 65%),
    radial-gradient(ellipse 70% 50% at 50% 90%, rgba(255, 217, 82, 0.12), transparent 60%);
}

.ob-shop-mark .dot { color: var(--accent); }
/* Compact context strip · used when shop-head.hero is too heavy */
.ob-shop-strip {
  padding: 36px 20px 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  flex-shrink: 0;
}
.ob-shop-strip .strip-logo {
  width: 32px; height: 32px;
  border-radius: 9px;
  background: var(--ink);
  color: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: 15px;
  letter-spacing: -0.04em;
}
.ob-shop-strip .strip-name {
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-md);
  color: var(--ink-soft);
}
.ob-shop-strip .strip-name strong {
  color: var(--ink);
  font-weight: 700;
}

.ob-step-dots {
  display: flex; justify-content: center; align-items: center; gap: 8px;
  padding: 12px 20px 0;
  flex-shrink: 0;
}
.ob-step-dots .ob-dot {
  width: 10px; height: 10px;
  border-radius: 50%;
  background: var(--ink-softer);
  opacity: 0.4;
  transition: all 0.2s ease;
}
.ob-step-dots .ob-dot.active {
  background: var(--accent);
  opacity: 1;
  width: 28px;
  border-radius: 999px;
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.ob-step-dots .ob-dot.done {
  background: var(--ink);
  opacity: 1;
}
.ob-canvas {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: stretch;
  padding: 16px 22px;
  text-align: center;
}

.ob-avatar-wrap {
  position: relative;
  width: 80px; height: 80px;
  margin: 0 auto 20px;
  animation: ob-avatar-breathe 3.2s ease-in-out infinite;
}
@keyframes ob-avatar-breathe {
  0%, 100% { transform: scale(1) translateY(0); }
  50% { transform: scale(1.04) translateY(-2px); }
}
.ob-avatar-wrap::before {
  content: '';
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: 160px; height: 160px;
  background: radial-gradient(circle, var(--butter) 0%, transparent 65%);
  opacity: 0.5;
  border-radius: 50%;
  z-index: 0;
}
.ob-avatar {
  position: relative;
  z-index: 1;
  width: 80px; height: 80px;
  border-radius: 22px;
  overflow: hidden;
  display: flex; align-items: center; justify-content: center;
}
.ob-avatar svg {
  width: 100%; height: 100%;
  display: block;
}
.ob-spark {
  position: absolute;
  z-index: 2;
  animation: ob-spark-pulse 2.4s ease-in-out infinite;
}
.ob-spark.s-1 {
  width: 14px; height: 14px;
  top: -6px; left: -10px;
  color: var(--butter);
  animation-delay: 0s;
}
.ob-spark.s-2 {
  width: 10px; height: 10px;
  top: 14px; right: -12px;
  color: var(--accent);
  animation-delay: 0.6s;
}
.ob-spark.s-3 {
  width: 12px; height: 12px;
  bottom: -2px; left: -4px;
  color: var(--butter);
  animation-delay: 1.2s;
}
@keyframes ob-spark-pulse {
  0%, 100% { opacity: 0.4; transform: scale(0.85) rotate(0); }
  50% { opacity: 1; transform: scale(1.15) rotate(20deg); }
}

.ob-greet .ob-name {
  font-weight: 700;
  color: var(--accent);
}
/* C2.1 — speech-bubble greeting (replaces the older free-text .ob-greet
   in onboarding step 1). Surface card with a tail pointing up to the
   น้องแต้ม avatar. */
.ob-bubble {
  position: relative;
  background: var(--surface);
  border: none;
  border-radius: 16px;
  padding: 12px 16px;
  margin: 0 0 24px;
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-md);
  line-height: 1.6;
  color: var(--ink-soft);
  text-align: center;
}
.ob-bubble::before {
  content: '';
  position: absolute;
  top: -5px;
  left: 50%;
  transform: translateX(-50%) rotate(45deg);
  width: 11px;
  height: 11px;
  background: var(--surface);
}
.ob-bubble .ob-name { font-weight: 700; color: var(--accent); }
.ob-bubble strong { font-weight: 700; color: var(--ink); }

/* C2.1 — italic skip hint under the nickname input. */
.ob-skip-hint {
  text-align: center;
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-xs);
  color: var(--ink-softer);
  margin-top: 10px;
  font-style: italic;
}
.ob-q {
  font-family: 'Prompt', sans-serif;
  font-weight: 600;
  font-size: var(--text);
  color: var(--ink);
  margin-bottom: 10px;
}
.ob-input-wrap { margin-bottom: 0; }
.ob-input {
  appearance: none; -webkit-appearance: none;
  width: 100%;
  padding: 16px 14px;
  background: var(--surface);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 12px;
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-md);
  color: var(--ink);
  text-align: center;
  box-shadow: none;
}

.ob-big-num {
  margin-bottom: 16px;
  position: relative;
}
.ob-big-num::before {
  content: '';
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: 200px; height: 200px;
  background: radial-gradient(circle, var(--butter) 0%, transparent 60%);
  opacity: 0.4;
  border-radius: 50%;
  z-index: 0;
}
.ob-big-num > * { position: relative; z-index: 1; }
.ob-num-label {
  font-family: 'Prompt', sans-serif;
  font-style: italic;
  /* var(--text-md) = 1rem · flexes with the html.fs-sm/md/lg picker
     (was hardcoded 15px which felt small at default 16px root). */
  font-size: var(--text-md);
  color: var(--ink-soft);
  margin-bottom: 6px;
}
.ob-num {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 700;
  font-size: 100px;
  letter-spacing: -0.05em;
  line-height: 0.9;
  color: var(--accent);
  display: inline-block;
  position: relative;
}
.ob-num-star {
  position: absolute;
  top: 2px; right: -18px;
  width: 22px; height: 22px;
  color: var(--butter);
  stroke: var(--ink); stroke-width: 1.5;
}
.ob-num-sub {
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-md);
  color: var(--ink-soft);
  margin-top: 6px;
}
.ob-num-sub strong {
  font-weight: 700;
  color: var(--ink);
}
.ob-stamp.on {
  background: var(--ink);
  border-color: var(--ink);
}

.ob-reward-card {
  padding: 12px 14px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  text-align: center;
}
.ob-rc-line {
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-md);
  color: var(--ink-soft);
  line-height: 1.4;
}
.ob-rc-line strong {
  font-weight: 700;
  color: var(--ink);
}
.ob-rc-reward {
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-lg);
  color: var(--ink);
  line-height: 1.3;
}
.ob-rc-reward strong { font-weight: 700; }
/* Reward icon on C2.2 — wraps the _partials/reward_svg illustration
   (coffee_cup / latte_art / iced / card / star / gift_box / custom URL).
   The illustration has its own background colour, so the wrapper just
   provides the rounded square + border. */
.ob-rc-icon {
  width: 52px;
  height: 52px;
  border-radius: 12px;
  border: 1px solid rgba(17,17,17,0.18);
  overflow: hidden;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
.ob-rc-icon .reward-svg {
  width: 100%;
  height: 100%;
  display: block;
}
/* Same story as .reward-pill .gift — uploaded photos need real estate
   that the 52px line-art chip can't give them. */
.ob-rc-icon:has(img) {
  width: 160px;
  height: 160px;
  border-radius: 20px;
}

.ob-warn-s {
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-md);
  line-height: 1.5;
  color: var(--ink-soft);
  margin-bottom: 18px;
}
.ob-protect-card {
  padding: 20px 14px;
  background: var(--butter-soft);
  border: 1px dashed rgba(17,17,17,0.18);
  border-radius: 14px;
  text-align: center;
}
.ob-pc-h {
  font-family: 'Prompt', sans-serif;
  font-weight: 700; font-size: var(--text-lg);
  color: var(--ink);
  margin-bottom: 4px;
}
.ob-pc-h strong { color: var(--accent); }
.ob-pc-s {
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-base);
  color: var(--ink-soft);
  line-height: 1.5;
}

.ob-bottom {
  margin-top: auto;
  padding: 0 22px 12px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-shrink: 0;
}
.ob-bottom.stack {
  flex-direction: column;
  align-items: stretch;
  gap: 8px;
}
/* "ผูกบัญชีแต้มดีด้วย" label sitting at the top of the step-3 social
   stack, just above the 4-pill row. */
.ob-link-label {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: var(--text-md);
  color: var(--ink);
  text-align: center;
  margin-top: 8px;
}
.ob-link-label strong { color: var(--accent); }
.ob-link-label + .ob-social-row { margin-top: 6px; }

.ob-footer-mark {
  position: relative;
  padding: 14px 20px 18px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  flex-shrink: 0;
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: var(--text-base);
  letter-spacing: -0.025em;
  color: var(--ink);
  line-height: 1;
}
.ob-footer-mark .smile-stamp {
  flex-shrink: 0;
  width: 16px;
  height: 16px;
  display: block;
}
.ob-footer-mark .dot { color: var(--accent); }
.ob-skip {
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-md);
  color: var(--ink-soft);
  text-decoration: underline;
  cursor: pointer;
  padding: 8px 12px;
}
.ob-skip.center { text-align: center; margin-top: 4px; }
.ob-next {
  appearance: none; -webkit-appearance: none;
  flex: 1;
  background: var(--accent); color: #fff;
  border: 1px solid rgba(17,17,17,0.18);
  border-radius: 14px;
  padding: 16px 20px;
  font-family: 'Prompt', sans-serif;
  font-weight: 700; font-size: var(--text-md);
  box-shadow: none;
  cursor: pointer;
  display: inline-flex; align-items: center; justify-content: space-between;
  gap: 8px;
}
.ob-next.full { width: 100%; flex: none; }
.ob-next .arrow {
  color: var(--butter);
  font-size: var(--text-md); font-weight: 800;
  flex-shrink: 0;
}

.ob-pill.primary { background: var(--line-green); color: #fff; }
.ob-pill.secondary { background: var(--ink); color: #fff; }
/* onboard.link_account — 4-row social pill stack (LINE / Google /
   Facebook / phone). Replaces the 2-pill .ob-pill primary+secondary
   layout for step 3. Vertical, 100% width, lighter visual weight than
   .ob-pill since 4 options need to breathe. Ports verbatim from
   design/taemdee-customer.html. */
.ob-social-row {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-top: 24px;
  margin-bottom: 4px;
  width: 100%;
}
.ob-social-pill {
  appearance: none; -webkit-appearance: none;
  background: var(--surface);
  border: 1px solid rgba(17,17,17,0.12);
  border-radius: 14px;
  padding: 14px 18px;
  cursor: pointer;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  gap: 12px;
  font-family: 'Prompt', sans-serif;
  font-weight: 600;
  font-size: var(--text-sm);
  color: var(--ink);
  text-decoration: none;
  transition: transform 0.15s ease;
}
.ob-social-pill:active { transform: scale(0.98); }
.ob-social-pill svg {
  width: 22px;
  height: 22px;
  display: block;
  flex-shrink: 0;
}
.ob-social-pill.line svg { color: #06C755; }
.shop-head .side-spark {
  position: absolute;
  top: 56px;
  color: var(--accent);
  width: 12px;
  height: 12px;
}
.shop-head .side-spark.l { left: 30px; transform: rotate(-15deg); }
.shop-head .side-spark.r { right: 30px; transform: rotate(15deg); color: var(--butter); stroke: #141414; }
.shop-logo-mark {
  /* block (not inline-block) so .shop-sub always wraps below it on
     wider viewports — design's text-align centering makes the wordmark
     and sub look stacked on phone width, but they collapse onto one
     line on desktop unless we force a row break. */
  display: block;
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  /* Hero wordmark — kept px so it stays bold at the design size
     regardless of fs-* picker (var(--text-xl) shrinks too far). */
  font-size: 30px;
  letter-spacing: -0.04em;
  margin-bottom: 4px;
}
.shop-logo-img {
  width: 50px;
  height: 50px;
  object-fit: cover;
  border-radius: 12px;
  vertical-align: middle;
}
.shop-logo-mark .dot { color: var(--accent); }
.shop-sub {
  font-weight: 400;
  font-size: var(--text-base);
  color: var(--ink-soft);
  /* flex (centered) instead of inline-flex — same reason as
     .shop-logo-mark above, so the sub line never sidles up next to
     the wordmark on a wide viewport. */
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 6px;
}
.shop-sub .dotsep {
  width: 3px;
  height: 3px;
  background: var(--accent);
  border-radius: 50%;
}

.hero-num-wrap {
  text-align: center;
  padding: 26px 20px 12px;
  position: relative;
}
.hero-num-wrap::before {
  content: '';
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -40%);
  width: 170px; height: 170px;
  background: radial-gradient(circle, var(--butter) 0%, transparent 65%);
  opacity: 0.55;
  border-radius: 50%;
  z-index: 0;
}
.hero-num-wrap > * { position: relative; z-index: 1; }

.hero-label {
  font-style: italic;
  font-weight: 500;
  font-size: var(--text-base);
  color: var(--ink-soft);
  margin-bottom: 2px;
}
.hero-num {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 700;
  font-size: 128px;
  letter-spacing: -0.065em;
  line-height: 0.85;
  color: var(--accent);
  margin-bottom: 4px;
  position: relative;
  display: inline-block;
}
.hero-num .mini-star {
  position: absolute;
  top: 6px;
  right: -16px;
  width: 16px;
  height: 16px;
  color: var(--butter);
  stroke: #141414;
  stroke-width: 2;
  animation: gentle-spin 6s linear infinite;
}
.hero-num-sub {
  font-size: var(--text-base);
  font-weight: 500;
  color: var(--ink);
  letter-spacing: -0.005em;
}
.hero-num-sub em {
  font-style: italic;
  font-weight: 600;
  color: var(--accent);
}
.hero-num-sub .of {
  font-weight: 400;
  color: var(--ink-softer);
  font-size: var(--text-sm);
  margin-left: 4px;
}

.stamps-wrap { padding: 12px 20px 10px; }
.stamps {
  display: grid;
  grid-template-columns: repeat(10, 1fr);
  gap: 6px;
  justify-items: center;
}
.stamp {
  width: 100%;
  max-width: 36px;
  aspect-ratio: 1 / 1;
  border-radius: 50%;
  background: var(--line);
}
.stamp.on {
  background: var(--accent);
  position: relative;
  overflow: hidden;
}
.stamp.on::after {
  content: '';
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: 5px; height: 5px;
  background: rgba(255, 255, 255, 0.6);
  border-radius: 50%;
}
.stamp.on.butter { background: var(--butter); }
.stamp.on.butter::after { background: rgba(17, 17, 17, 0.5); }

/* Different goal counts keep the same circle shape; only the column count and max size shift. */
.stamps[data-goal="8"]  { grid-template-columns: repeat(8, 1fr); }
.stamps[data-goal="15"] { grid-template-columns: repeat(15, 1fr); gap: 3px; }
.stamps[data-goal="15"] .stamp { max-width: 22px; }

.reward-pill {
  margin: 24px 20px 0;
  background: var(--surface);
  border-radius: 20px;
  padding: 18px;
  display: flex;
  align-items: center;
  gap: 14px;
  border: 1px solid rgba(17, 17, 17, 0.18);
  box-shadow: none;
  position: relative;
}
.reward-pill .badge-tilted {
  position: absolute;
  top: -11px; right: 14px;
  transform: rotate(6deg);
  background: var(--butter);
  color: var(--ink);
  padding: 4px 11px;
  border-radius: 999px;
  font-weight: 700;
  font-size: var(--text-2xs);
  letter-spacing: 0.04em;
  border: 1px solid rgba(17, 17, 17, 0.18);
}
.reward-pill .gift {
  width: 88px;
  height: 88px;
  background: var(--accent);
  color: #fff;
  border-radius: 18px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.reward-pill .gift svg { width: 42px; height: 42px; }
/* Built-in SVG illustrations are decorative line art that read fine in
   the 34px chip. Uploaded photos in the same chip just look like tiny
   blobs, so when the gift contains an <img> we bump the chip to 64px
   and drop the accent-soft tint that would show through any letterbox. */
.reward-pill .gift:has(img) {
  width: 96px;
  height: 96px;
  background: transparent;
  border-radius: 16px;
  overflow: hidden;
}
/* When the reward chip is a photo (tall), the rtxt looks adrift if
   it's vertically centered against 96px of image. Pin it to the top
   so "รางวัล / <name>" reads as a label paired with the photo. */
.reward-pill:has(.gift img) {
  align-items: flex-start;
}
.reward-pill .rtxt { flex: 1; line-height: 1.3; }
.reward-pill .rlabel {
  font-family: 'JetBrains Mono', monospace;
  font-size: var(--text-2xs);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-softer);
  margin-bottom: 2px;
}
.reward-pill .rname {
  font-size: var(--text-md);
  font-weight: 600;
  letter-spacing: -0.01em;
}

/* "ไปที่ร้าน" — explicit secondary link beneath the reward pill that
   sends the customer to the shop story page. The shop-head wordmark
   already links there, but doesn't read as tappable; this text link
   removes the guesswork. */
.c1-shop-link {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  margin: 18px 20px 0;
  padding: 10px 12px;
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--accent);
  text-decoration: none;
  border-radius: 12px;
}
.c1-shop-link:active { transform: scale(0.98); opacity: 0.7; }

/* Role picker — shown on / when both shop + customer cookies validate
   (one device shared by an owner who also collects points elsewhere).
   Two big tiles instead of an auto-redirect tug-of-war. */
.role-picker-page .rp-brand .dot { color: var(--accent); }
.role-picker-page .rp-tile.shop .rp-icon { background: var(--ink); color: var(--bg); }
.role-picker-page .rp-tile.customer .rp-icon { background: var(--accent); color: #FFF; }
.footer-mark {
  padding: 18px 18px 20px;
  padding-bottom: max(20px, env(safe-area-inset-bottom));
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-top: auto;
  position: sticky;
  bottom: 0;
  background: rgba(246, 241, 229, 0.85);
  border-top: 1px solid rgba(17, 17, 17, 0.12);
  z-index: 5;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.footer-mark .fm-brand {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}
.footer-mark .smile-stamp {
  flex-shrink: 0;
}
.footer-mark .brand {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: 16px;
  letter-spacing: -0.025em;
  color: var(--ink);
  line-height: 1;
}
.footer-mark .brand .dot { color: var(--accent); }
.footer-mark .fm-install {
  display: flex;
  align-items: center;
  gap: 5px;
  font-weight: 600;
  font-size: 11.5px;
  color: var(--ink);
  text-decoration: underline;
  text-decoration-color: rgba(17, 17, 17, 0.25);
  text-underline-offset: 3px;
  cursor: pointer;
  flex-shrink: 0;
}
.footer-mark .fm-install svg {
  width: 12px;
  height: 12px;
  color: var(--accent);
  flex-shrink: 0;
}
.footer-mark .smile-foot {
  width: 13px;
  height: 7.5px;
  color: var(--accent);
  margin-left: 3px;
  vertical-align: -1px;
  display: inline-block;
}

/* ==========================================================
   Scan celebration — one-shot overlay after a successful scan
   (every scan, not just the first; suppressed when is_first_visit
   so the C2 banner carries the moment instead).
   ========================================================== */

.scan-cel {
  position: fixed;
  inset: 0;
  z-index: 200;
  pointer-events: none;          /* never block taps; auto-removed after 2.6s */
  display: flex;
  align-items: center;
  justify-content: center;
  animation: cel-fade 2.6s ease-out forwards;
}
@keyframes cel-fade {
  0%, 70% { opacity: 1; }
  100% { opacity: 0; }
}

/* Subtle card scale-pulse so the whole DeeCard reacts to the win */
.cel-shake { animation: cel-pulse 600ms ease-out 0s 1; }
@keyframes cel-pulse {
  0%   { transform: scale(1); }
  20%  { transform: scale(1.02); }
  60%  { transform: scale(0.995); }
  100% { transform: scale(1); }
}

/* Center "+1 แต้ม!" badge — bouncy entrance, fades with the parent */
.scan-cel-badge {
  position: relative;
  z-index: 2;
  background: var(--accent);
  color: #fff;
  padding: 18px 32px;
  border-radius: 28px;
  border: 2.5px solid var(--ink);
  box-shadow: 0 12px 30px -6px rgba(255, 94, 58, 0.55);
  text-align: center;
  transform: scale(0.4) rotate(-8deg);
  animation: cel-badge-in 700ms cubic-bezier(.34,1.56,.64,1) forwards;
}
@keyframes cel-badge-in {
  0%   { transform: scale(0.4) rotate(-8deg); opacity: 0; }
  60%  { transform: scale(1.08) rotate(-3deg); opacity: 1; }
  100% { transform: scale(1) rotate(-3deg); opacity: 1; }
}
.scan-cel-badge .cel-plus {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: 64px;
  letter-spacing: -0.04em;
  line-height: 1;
  margin-bottom: 2px;
  text-shadow: 2px 3px 0 var(--ink);
}
.scan-cel-badge .cel-label {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 18px;
  letter-spacing: 0.02em;
  color: #fff;
  text-shadow: 1px 2px 0 rgba(17, 17, 17, 0.4);
}

/* Confetti burst — 14 pieces fanning out from center */
.scan-cel-burst {
  position: absolute;
  top: 50%; left: 50%;
  width: 0; height: 0;
}
.cel-piece {
  position: absolute;
  top: 0; left: 0;
  width: 12px; height: 12px;
  border-radius: 3px;
  --tx: 0px;
  --ty: 0px;
  --rot: 0deg;
  animation: cel-piece-fly 1.2s cubic-bezier(.18,.7,.34,1) forwards;
}
@keyframes cel-piece-fly {
  0%   { transform: translate(0, 0) rotate(0deg) scale(0.4); opacity: 0; }
  20%  { opacity: 1; }
  100% { transform: translate(var(--tx), var(--ty)) rotate(var(--rot)) scale(1); opacity: 0; }
}
.cel-piece.p0  { background: var(--accent); --tx: -120px; --ty: -180px; --rot: -480deg; animation-delay: 0ms; }
.cel-piece.p1  { background: var(--butter); --tx:  140px; --ty: -160px; --rot:  420deg; animation-delay: 40ms; border-radius: 50%; }
.cel-piece.p2  { background: var(--mint);   --tx: -200px; --ty:  -60px; --rot: -360deg; animation-delay: 80ms; }
.cel-piece.p3  { background: var(--accent); --tx:  220px; --ty:  -40px; --rot:  540deg; animation-delay: 0ms; border-radius: 50%; }
.cel-piece.p4  { background: var(--butter); --tx: -160px; --ty:  100px; --rot: -300deg; animation-delay: 120ms; }
.cel-piece.p5  { background: var(--accent); --tx:  180px; --ty:  140px; --rot:  360deg; animation-delay: 80ms; border-radius: 50%; }
.cel-piece.p6  { background: var(--mint);   --tx:  -80px; --ty: -240px; --rot: -540deg; animation-delay: 160ms; }
.cel-piece.p7  { background: var(--butter); --tx:   90px; --ty: -210px; --rot:  300deg; animation-delay: 200ms; }
.cel-piece.p8  { background: var(--accent); --tx: -260px; --ty:   40px; --rot: -360deg; animation-delay: 40ms; }
.cel-piece.p9  { background: var(--butter); --tx:  240px; --ty:   60px; --rot:  300deg; animation-delay: 140ms; border-radius: 50%; }
.cel-piece.p10 { background: var(--mint);   --tx: -110px; --ty:  220px; --rot: -420deg; animation-delay: 100ms; }
.cel-piece.p11 { background: var(--accent); --tx:  130px; --ty:  240px; --rot:  480deg; animation-delay: 60ms; border-radius: 50%; }
.cel-piece.p12 { background: var(--butter); --tx:  -30px; --ty: -260px; --rot: -300deg; animation-delay: 240ms; }
.cel-piece.p13 { background: var(--mint);   --tx:   60px; --ty: -250px; --rot:  360deg; animation-delay: 220ms; }

/* 4 big sparkle stars rotating slowly behind the badge */
.cel-star {
  position: absolute;
  width: 30px; height: 30px;
  top: 0; left: 0;
  color: var(--butter);
  opacity: 0;
  animation: cel-star-spin 1.6s ease-out forwards;
}
@keyframes cel-star-spin {
  0%   { transform: translate(var(--sx, 0), var(--sy, 0)) scale(0) rotate(0deg); opacity: 0; }
  35%  { opacity: 1; }
  100% { transform: translate(var(--sx, 0), var(--sy, 0)) scale(1.3) rotate(360deg); opacity: 0; }
}
.cel-star.s1 { --sx: -90px; --sy: -90px; animation-delay: 0ms; }
.cel-star.s2 { --sx:  80px; --sy: -100px; animation-delay: 120ms; }
.cel-star.s3 { --sx:  100px; --sy:  80px; animation-delay: 240ms; }
.cel-star.s4 { --sx: -100px; --sy:  70px; animation-delay: 360ms; }

/* ==========================================================
   Guest signup — green banner + bottom-sheet picker
   Reused on C1.guest, C2 (first scan), C7 (My Cards). The picker is
   the single signup entry point; the banner just opens it.
   ========================================================== */

.guest-banner-bottom {
  margin: 14px 18px 0;
  padding: 10px 12px;
  background: var(--surface);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 14px;
  display: flex;
  align-items: center;
  gap: 10px;
  box-shadow: none;
  text-decoration: none;
  color: var(--ink);
}
.guest-banner-bottom .gb-icon {
  flex-shrink: 0;
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.guest-banner-bottom .gb-icon svg { width: 22px; height: 22px; display: block; }
.guest-banner-bottom .gb-text { flex: 1; line-height: 1.25; }
.guest-banner-bottom .gb-h {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 12.5px;
  color: var(--ink);
}
.guest-banner-bottom .gb-s {
  font-family: 'Prompt', sans-serif;
  font-size: 10.5px;
  color: var(--ink-soft);
  margin-top: 1px;
}
.guest-banner-bottom .gb-arrow {
  font-size: 16px;
  font-weight: 700;
  color: var(--ink-soft);
  flex-shrink: 0;
}

.signup-sheet-overlay {
  position: fixed;
  inset: 0;
  background: rgba(17, 17, 17, 0.55);
  z-index: 100;
  display: flex;
  align-items: flex-end;
  justify-content: center;
}
.signup-sheet-overlay[hidden] { display: none; }
.signup-sheet {
  background: var(--bg);
  border-top: 1px solid rgba(17, 17, 17, 0.18);
  border-top-left-radius: 22px;
  border-top-right-radius: 22px;
  padding: 14px 18px max(16px, env(safe-area-inset-bottom));
  width: 100%;
  box-shadow: 0 -8px 24px -8px rgba(0, 0, 0, 0.25);
  animation: signup-sheet-in 240ms cubic-bezier(.34, 1.56, .64, 1);
}
@keyframes signup-sheet-in {
  from { transform: translateY(20px); opacity: 0; }
  to { transform: translateY(0); opacity: 1; }
}
.signup-sheet .sheet-handle {
  width: 36px;
  height: 4px;
  border-radius: 999px;
  background: var(--ink-softer);
  margin: 0 auto 14px;
  opacity: 0.4;
}
.signup-head {
  text-align: center;
  margin-bottom: 14px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--line);
}
.signup-title {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: var(--text-md);
  line-height: 1.25;
  letter-spacing: -0.02em;
  color: var(--ink);
  margin-bottom: 3px;
}
.signup-title em {
  font-style: italic;
  color: var(--accent);
}
.signup-sub {
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-sm);
  line-height: 1.4;
  color: var(--ink-soft);
}
.signup-btn {
  appearance: none;
  -webkit-appearance: none;
  width: 100%;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 11px 14px;
  border-radius: 14px;
  font-family: 'Prompt', sans-serif;
  cursor: pointer;
  margin: 0 0 8px;
  text-align: left;
  border: 1px solid rgba(17, 17, 17, 0.18);
  line-height: 1.2;
  text-decoration: none;
}
/* link.prompt + push.prompt — soft sheet overlay pattern. The page
   underneath gets dimmed + desaturated via .pp-page-fade, the sheet
   slides up with a backdrop. Used for link.prompt (cookie-anonymous
   customer with ≥3 stamps) + push.prompt (PWA install moment). */
.pp-overlay {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  pointer-events: none;
}
.pp-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(17, 17, 17, 0.4);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
  z-index: 1;
  pointer-events: auto;
}
.pp-sheet {
  position: relative;
  z-index: 2;
  background: var(--bg);
  border-radius: 24px 24px 0 0;
  padding: 12px 22px 28px;
  box-shadow: 0 -4px 30px -8px rgba(17, 17, 17, 0.3);
  pointer-events: auto;
}
.pp-handle {
  width: 36px;
  height: 4px;
  background: rgba(17, 17, 17, 0.18);
  border-radius: 999px;
  margin: 0 auto 16px;
}
.pp-avatar {
  position: relative;
  width: 64px;
  height: 64px;
  margin: 0 auto 14px;
}
.pp-avatar::before {
  content: '';
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: 110px; height: 110px;
  background: radial-gradient(circle, var(--butter) 0%, transparent 65%);
  opacity: 0.5;
  border-radius: 50%;
  z-index: 0;
}
.pp-avatar svg {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
  display: block;
}
.pp-headline {
  text-align: center;
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-md);
  font-weight: 600;
  color: var(--ink);
  line-height: 1.4;
  margin-bottom: 6px;
}
.pp-sub {
  text-align: center;
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-sm);
  color: var(--ink-soft);
  line-height: 1.55;
  margin-bottom: 16px;
}
.pp-secondary {
  display: block;
  text-align: center;
  padding: 10px;
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-sm);
  color: var(--ink-soft);
  text-decoration: underline;
  text-decoration-color: rgba(17, 17, 17, 0.25);
  text-underline-offset: 3px;
  cursor: pointer;
  background: transparent;
  border: none;
  width: 100%;
}

.signup-btn.line {
  background: #06C755;
  color: #fff;
  box-shadow: none;
}
.signup-btn.google,
.signup-btn.facebook,
.signup-btn.phone-btn {
  background: var(--surface);
  color: var(--ink);
  box-shadow: none;
}
.signup-btn svg {
  width: 22px;
  height: 22px;
  flex-shrink: 0;
}
.signup-btn .bn-text {
  flex: 1;
  display: flex;
  flex-direction: column;
  line-height: 1.2;
}
.signup-btn .bn-name {
  font-weight: 700;
  font-size: var(--text-md);
  letter-spacing: -0.015em;
}
.signup-btn .bn-meta {
  font-weight: 500;
  font-size: var(--text-2xs);
  opacity: 0.85;
  margin-top: 1px;
}
.signup-btn.phone-btn .bn-meta,
.signup-btn.google .bn-meta,
.signup-btn.facebook .bn-meta { color: var(--ink-soft); opacity: 1; }

/* Nickname input + save — used by the C2.welcome auto-open sheet. */
.signup-btn.nickname-save {
  justify-content: center;
  background: var(--accent);
  color: #fff;
  box-shadow: none;
  font-weight: 700;
  font-size: var(--text-md);
  text-decoration: none;
}

.signup-skip {
  display: block;
  text-align: center;
  font-family: 'Prompt', sans-serif;
  font-style: italic;
  font-size: var(--text-base);
  color: var(--ink-softer);
  padding: 8px 0 2px;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-style: dashed;
}

/* ==========================================================
   C4 — Ready to redeem (full DeeCard)
   ========================================================== */

/* reward.almost — Redeem gate (May 1 design rev: guests can redeem,
   signup is a soft optional link below the primary CTA). */
.c4 .redeem-gate {
  margin: 18px 20px 0;
  padding: 0;
  background: transparent;
  border: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
}
.c4 .redeem-cta {
  appearance: none; -webkit-appearance: none;
  width: 100%;
  background: var(--ink);
  color: var(--bg);
  border: none;
  border-radius: 999px;
  padding: 18px 22px;
  font-family: 'Prompt', sans-serif;
  font-weight: 700; font-size: 17.5px;
  display: flex; align-items: center; justify-content: center;
  gap: 10px;
  cursor: pointer;
}
.c4 .redeem-cta .redeem-arrow {
  width: 24px; height: 24px;
  background: var(--accent);
  color: #FFF;
  border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: var(--text-base);
}
.c4 .redeem-cta:active { transform: scale(0.98); }
.c4 .redeem-soft-link {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: 'Prompt', sans-serif;
  font-size: 12.5px;
  color: var(--ink-soft);
  text-decoration: underline;
  text-decoration-color: rgba(17,17,17,0.2);
  text-underline-offset: 3px;
  cursor: pointer;
}
.c4 .redeem-soft-link .rsl-spark {
  color: var(--accent);
  font-size: var(--text-xs);
}

.c4 .ready-banner {
  display: flex;
  justify-content: center;
  padding: 16px 20px 0;
  position: relative;
}
.c4 .ready-banner .pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: var(--accent);
  color: #FFF;
  padding: 7px 14px;
  border-radius: 999px;
  font-weight: 700;
  font-style: italic;
  font-size: var(--text-base);
  letter-spacing: -0.005em;
  box-shadow: 0 8px 20px -6px rgba(255, 94, 58, 0.5);
  transform: rotate(-3deg);
}
.c4 .ready-banner .pill .sparkle-dot {
  width: 6px;
  height: 6px;
  background: #FFF;
  border-radius: 50%;
  animation: pop 1.4s ease-in-out infinite;
}
@keyframes pop {
  0%, 100% { transform: scale(1); opacity: 0.9; }
  50% { transform: scale(1.5); opacity: 1; }
}
.c4 .sparks {
  position: absolute;
  top: 16px; left: 0; right: 0; height: 80px;
  pointer-events: none;
}
.c4 .sparks .s {
  position: absolute;
  color: var(--butter);
  stroke: #141414;
  stroke-width: 1.5;
  animation: twinkle-c 2.2s ease-in-out infinite;
}
.c4 .sparks .s-1 { top: 8px; left: 22%; width: 12px; height: 12px; }
.c4 .sparks .s-2 { top: 40px; left: 14%; width: 9px; height: 9px; color: var(--accent); stroke: none; animation-delay: 0.6s; }
.c4 .sparks .s-3 { top: 8px; right: 20%; width: 10px; height: 10px; animation-delay: 1.1s; }
.c4 .sparks .s-4 { top: 46px; right: 12%; width: 9px; height: 9px; color: var(--accent); stroke: none; animation-delay: 1.6s; }

.c4 .redeem-num {
  text-align: center;
  padding: 12px 20px 8px;
  position: relative;
}
.c4 .redeem-num::before {
  content: '';
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -40%);
  width: 200px; height: 200px;
  background: radial-gradient(circle, var(--butter) 0%, transparent 60%);
  opacity: 0.5;
  border-radius: 50%;
  z-index: 0;
}
.c4 .redeem-num > * { position: relative; z-index: 1; }
.c4 .redeem-num .big {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 700;
  font-size: 138px;
  letter-spacing: -0.075em;
  line-height: 0.82;
  color: var(--accent);
  margin-bottom: 6px;
}
.c4 .redeem-num .done {
  font-style: italic;
  font-weight: 700;
  font-size: var(--text-md);
  color: var(--ink);
}

/* ==========================================================
   C5 — Reward claimed
   ========================================================== */

.c5 .claimed-hero {
  padding: 24px 22px 16px;
  text-align: center;
  position: relative;
}
.c5 .claimed-hero::before {
  content: '';
  position: absolute;
  top: 12px; left: 50%;
  transform: translateX(-50%);
  width: 200px; height: 200px;
  background: radial-gradient(circle, var(--butter) 0%, transparent 60%);
  opacity: 0.55;
  border-radius: 50%;
  z-index: 0;
}
.c5 .claimed-hero > * { position: relative; z-index: 1; }

/* Achievement ribbon · "10/10 ครั้งสำเร็จ" */
.c5 .claimed-streak {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 14px;
  background: var(--ink);
  color: var(--butter);
  border-radius: 99px;
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: var(--text-2xs);
  letter-spacing: 0.04em;
  margin-bottom: 16px;
  box-shadow: 0 4px 12px -4px rgba(0,0,0,0.3);
}
.c5 .claimed-streak .num {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: 14px;
  letter-spacing: -0.02em;
  color: var(--butter);
}
.c5 .claimed-streak svg {
  width: 12px; height: 12px;
  fill: var(--butter);
}

/* Big gift-box hero icon (May 1 redesign — replaces the small accent
   checkmark dot). Gradient + shine + animated bob. */
.c5 .claimed-mark {
  width: 110px; height: 110px;
  margin: 0 auto 18px;
  border-radius: 28px;
  background: linear-gradient(145deg, #FF7A55 0%, #FF5E3A 50%, #E04020 100%);
  color: #fff;
  border: 2px solid var(--ink);
  box-shadow:
    0 16px 40px -8px rgba(255, 94, 58, 0.55),
    6px 6px 0 var(--ink),
    inset 0 -4px 0 rgba(0,0,0,0.15);
  display: flex; align-items: center; justify-content: center;
  position: relative;
  transform: rotate(-3deg);
  animation: gift-bob 2.5s ease-in-out infinite;
}
.c5 .claimed-mark svg { width: 56px; height: 56px; }
.c5 .claimed-mark::after {
  content: '';
  position: absolute;
  top: 8px; left: 12px;
  width: 26px; height: 14px;
  background: rgba(255,255,255,0.45);
  border-radius: 50%;
  filter: blur(2px);
}
.c5 .claimed-mark::before {
  content: '';
  position: absolute;
  top: -8px; left: -8px; right: -8px; bottom: -8px;
  border: 2px dashed var(--accent);
  opacity: 0.45;
  border-radius: 32px;
  animation: pulse-ring 2s ease-in-out infinite;
}
@keyframes pulse-ring {
  0%, 100% { transform: scale(1); opacity: 0.45; }
  50% { transform: scale(1.18); opacity: 0.05; }
}
@keyframes gift-bob {
  0%, 100% { transform: rotate(-3deg) translateY(0); }
  50% { transform: rotate(2deg) translateY(-4px); }
}

.c5 .claimed-hero .confetti {
  position: absolute;
  color: var(--butter);
  stroke: var(--ink);
  stroke-width: 1.5;
  animation: twinkle-c 2s ease-in-out infinite;
}
.c5 .claimed-hero .confetti.c1 { top: 16px;  left: 12%;  width: 14px; height: 14px; color: var(--accent); stroke: none; }
.c5 .claimed-hero .confetti.c2 { top: 24px;  right: 14%; width: 10px; height: 10px; animation-delay: 0.5s; }
.c5 .claimed-hero .confetti.c3 { top: 60px;  right: 8%;  width: 11px; height: 11px; animation-delay: 1.2s; color: var(--accent); stroke: none; }
.c5 .claimed-hero .confetti.c4 { top: 80px;  left: 6%;   width: 9px;  height: 9px;  animation-delay: 1.6s; }
.c5 .claimed-hero .confetti.c5 { top: 130px; left: 18%;  width: 11px; height: 11px; animation-delay: 0.9s; color: var(--accent); stroke: none; }
.c5 .claimed-hero .confetti.c6 { top: 130px; right: 18%; width: 12px; height: 12px; animation-delay: 1.4s; }
.c5 .claimed-hero .confetti.c7 { top: 175px; left: 8%;   width: 10px; height: 10px; animation-delay: 0.3s; color: var(--mint-ink, #2D8050); stroke: none; }
.c5 .claimed-hero .confetti.c8 { top: 175px; right: 10%; width: 9px;  height: 9px;  animation-delay: 1.8s; color: var(--accent); stroke: none; }

.c5 .claimed-title {
  font-family: 'Prompt', sans-serif;
  font-weight: 800;
  font-size: 32px;
  letter-spacing: -0.035em;
  line-height: 1.05;
  margin-bottom: 6px;
  color: var(--ink);
}
.c5 .claimed-title em {
  font-style: italic;
  font-weight: 800;
  color: var(--accent);
}

.c5 .claimed-sub {
  font-family: 'Prompt', sans-serif;
  font-weight: 500;
  font-size: var(--text-sm);
  color: var(--ink-soft);
  margin-top: 4px;
  text-align: center;
  position: relative;
  z-index: 1;
}
.c5 .claimed-sub strong {
  color: var(--ink);
  font-weight: 700;
}

/* Voucher floating particles (anti-screenshot animation per the revised
   C5 design — replaces the older "0 sec ago" live-pulse counter). The
   continuous rise/rotate of 8 sparkles can't be reproduced by a static
   capture, so staff can tell at a glance that they're looking at a live
   redemption screen. */
.c5 .voucher .v-particles {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
  border-radius: 12px;
}
.c5 .voucher .v-particles .p {
  position: absolute;
  bottom: -8px;
  width: 10px;
  height: 10px;
  color: var(--ink);
  opacity: 0;
  animation: particle-rise 3.4s ease-in infinite;
}
.c5 .voucher .v-particles .p1 { left: 8%;  animation-delay: 0.0s; width: 11px; height: 11px; }
.c5 .voucher .v-particles .p2 { left: 22%; animation-delay: 0.6s; width: 7px;  height: 7px; }
.c5 .voucher .v-particles .p3 { left: 36%; animation-delay: 1.2s; width: 9px;  height: 9px; }
.c5 .voucher .v-particles .p4 { left: 50%; animation-delay: 0.3s; width: 8px;  height: 8px; }
.c5 .voucher .v-particles .p5 { left: 64%; animation-delay: 1.8s; width: 10px; height: 10px; }
.c5 .voucher .v-particles .p6 { left: 78%; animation-delay: 0.9s; width: 7px;  height: 7px; }
.c5 .voucher .v-particles .p7 { left: 88%; animation-delay: 2.4s; width: 9px;  height: 9px; }
.c5 .voucher .v-particles .p8 { left: 14%; animation-delay: 1.5s; width: 8px;  height: 8px; color: var(--accent); }
@keyframes particle-rise {
  0%   { transform: translateY(0) translateX(0) rotate(0deg); opacity: 0; }
  10%  { opacity: 1; }
  50%  { opacity: 0.85; transform: translateY(-50px) translateX(6px) rotate(180deg); }
  90%  { opacity: 0.4; }
  100% { transform: translateY(-110px) translateX(-4px) rotate(360deg); opacity: 0; }
}

.c5 .voucher {
  margin: 0 22px;
  padding: 16px 18px;
  background: var(--butter);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 14px;
  box-shadow: none;
  position: relative;
  transform: rotate(-1.5deg);
}
.c5 .voucher::before, .c5 .voucher::after {
  content: '';
  position: absolute;
  width: 14px;
  height: 14px;
  background: var(--bg);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 50%;
}
.c5 .voucher::before { left: -8px; top: 50%; transform: translateY(-50%); }
.c5 .voucher::after { right: -8px; top: 50%; transform: translateY(-50%); }
/* Voucher text needs position:relative so it stacks above the absolutely-
   positioned .v-particles overlay (which sits at z-index implicit 0). */
.c5 .voucher .v-label,
.c5 .voucher .v-title,
.c5 .voucher .v-id { position: relative; }
.c5 .voucher .v-label {
  font-family: 'JetBrains Mono', monospace;
  font-size: var(--text-2xs);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ink);
  margin-bottom: 4px;
  text-align: center;
  font-weight: 600;
}
.c5 .voucher .v-title {
  font-weight: 700;
  font-size: var(--text-md);
  letter-spacing: -0.015em;
  text-align: center;
  margin-bottom: 6px;
}
.c5 .voucher .v-id {
  font-family: 'JetBrains Mono', monospace;
  font-size: var(--text-2xs);
  color: var(--ink);
  opacity: 0.6;
  text-align: center;
  letter-spacing: 0.08em;
}

.c5 .reset {
  margin: 24px 20px 0;
  padding-top: 18px;
  border-top: 1.5px dashed rgba(17, 17, 17, 0.2);
  text-align: center;
}
.c5 .reset .kicker {
  font-style: italic;
  font-weight: 500;
  font-size: var(--text-sm);
  color: var(--ink-soft);
  margin-bottom: 10px;
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.c5 .reset .kicker .arrow-down {
  display: inline-flex;
  width: 12px;
  height: 12px;
}
.c5 .reset .mini-card {
  background: var(--surface);
  border-radius: 12px;
  padding: 12px 12px 14px;
  border: 1px solid rgba(17, 17, 17, 0.18);
  box-shadow: none;
}
.c5 .reset .mini-num {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 700;
  font-size: var(--text-xl);
  color: var(--accent);
  text-align: center;
  letter-spacing: -0.03em;
  margin-bottom: 6px;
  line-height: 1;
}
.c5 .reset .mini-num .of {
  color: var(--ink-softer);
  font-weight: 400;
  font-size: var(--text-md);
}
.c5 .reset .mini-stamps {
  display: grid;
  grid-template-columns: repeat(10, 1fr);
  gap: 3px;
}
.c5 .reset .mini-stamps .mini-stamp {
  height: 14px;
  border-radius: 4px;
  background: var(--line);
}
.c5 .farewell {
  text-align: center;
  margin: 16px 20px 0;
  font-style: italic;
  font-weight: 500;
  font-size: var(--text-md);
  color: var(--ink);
}

/* ==========================================================
   Feed-row void state (after the [Void] button is tapped)
   ========================================================== */

/* Voided state on dock feed rows — table-scoped variant lives under
   .s3-dock .sap-table tr.voided. (.feed-row.voided + .void selector were
   for the old div-based feed; .void button no longer exists.) */

/* ==========================================================
   C3 — Soft Wall (claim account: LINE or phone)
   ========================================================== */

.c3 { --bg: #E8E0CE; background: #E8E0CE !important; }
.c3 .close-x {
  position: absolute;
  top: 48px;
  right: 20px;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--ink);
  color: #FFF;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
  font-weight: 700;
  cursor: pointer;
  z-index: 3;
  text-decoration: none;
}
.c3 .sheet {
  margin: 76px 14px 0;
  background: var(--surface);
  border-radius: 24px;
  padding: 22px 20px 20px;
  border: 1px solid rgba(17, 17, 17, 0.18);
  box-shadow: none;
  position: relative;
}
.c3 .illo {
  display: flex;
  justify-content: center;
  position: relative;
  height: 80px;
  margin-bottom: 14px;
}
.c3 .illo-card {
  position: absolute;
  width: 54px;
  height: 66px;
  background: var(--bg);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 8px;
  box-shadow: none;
  padding: 6px 5px;
}
.c3 .illo-card.a { transform: rotate(-12deg) translateX(-22px); }
.c3 .illo-card.b { background: var(--surface); z-index: 1; }
.c3 .illo-card.c { transform: rotate(12deg) translateX(22px); background: var(--butter-soft); }
.c3 .illo-card .dots {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 3px;
}
.c3 .illo-card .d {
  aspect-ratio: 1;
  border-radius: 50%;
  background: rgba(17, 17, 17, 0.2);
}
.c3 .illo-card.a .d.on { background: var(--accent); }
.c3 .illo-card.b .d.on { background: var(--accent); }
.c3 .illo-card.c .d.on { background: var(--ink); }
.c3 .illo .sparkle-illo {
  position: absolute;
  color: var(--butter);
  stroke: var(--ink);
  stroke-width: 1.5;
  animation: twinkle-c 2s ease-in-out infinite;
}
.c3 .illo .s1 { top: -2px; left: 16%; width: 10px; height: 10px; }
.c3 .illo .s2 { top: 40%; left: 8%; width: 8px; height: 8px; color: var(--accent); stroke: none; animation-delay: 0.7s; }
.c3 .illo .s3 { top: -4px; right: 14%; width: 12px; height: 12px; animation-delay: 1.2s; }

.c3 .headline {
  font-weight: 700;
  font-size: 22px;
  letter-spacing: -0.025em;
  text-align: center;
  line-height: 1.15;
  margin-bottom: 10px;
}
.c3 .headline em {
  font-style: italic;
  font-weight: 700;
  color: var(--accent);
}
.c3 .body-copy {
  font-size: 14px;
  text-align: center;
  color: var(--ink-soft);
  line-height: 1.5;
  margin-bottom: 18px;
}
.c3 .btn {
  width: 100%;
  padding: 13px 14px;
  border-radius: 14px;
  border: 1px solid rgba(17, 17, 17, 0.18);
  font-family: inherit;
  font-size: 16px;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  cursor: pointer;
  margin-bottom: 8px;
  box-shadow: none;
  text-decoration: none;
}
.c3 .btn-line { background: var(--accent); color: #fff; margin-top: 20px;}
.c3 .btn-line svg { width: 18px; height: 18px; }
.c3 .btn-phone { background: var(--ink); color: var(--bg); }
.c3 .btn-phone svg { width: 16px; height: 16px; }
.c3 .btn:disabled { opacity: 0.5; cursor: not-allowed; }
.c3 .btn-primary { background: var(--accent); color: #fff; }
.c3 .btn-primary .arr { font-weight: 700; }

.c3 .skip {
  display: block;
  text-align: center;
  margin-top: 12px;
  font-style: italic;
  font-size: 14px;
  color: var(--ink-soft);
  text-decoration: underline;
  text-decoration-color: rgba(17, 17, 17, 0.3);
  text-underline-offset: 3px;
  cursor: pointer;
}
.c3 .trust {
  text-align: center;
  margin-top: 14px;
  padding: 10px 12px;
  background: var(--butter-soft);
  border-radius: 10px;
  font-size: 10.5px;
  color: var(--ink);
  line-height: 1.5;
}
.c3 .trust .lock {
  display: inline-block;
  color: var(--accent);
  font-weight: 700;
  margin-right: 4px;
}

/* C3 — Phone-OTP form (refactored from soft wall) */
.c3 .c3-bar {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 40px 20px 0;
}
.c3 .c3-bar .back {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: var(--surface);
  border: 1px solid rgba(17, 17, 17, 0.18);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  color: var(--ink);
  flex-shrink: 0;
  padding: 0;
}
.c3 .c3-bar .back svg { width: 14px; height: 14px; }
.c3 .c3-title {
  font-weight: 700;
  font-size: var(--text-md);
  letter-spacing: -0.015em;
  color: var(--ink);
}
.c3 .c3-field {
  padding-top: 14px;
}
.c3 .c3-field-label {
  display: block;
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-sm);
  font-weight: 500;
  color: var(--ink-soft);
  margin-bottom: 6px;
}
.c3 .c3-input {
  width: 100%;
  padding: 12px 14px;
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 12px;
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-md);
  font-weight: 600;
  color: var(--ink);
  background: var(--bg);
  outline: none;
  box-sizing: border-box;
}
.c3 .c3-input:focus {
  border-color: var(--accent);
}
.c3 .c3-name-options {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.c3 .c3-name-opt {
  display: flex;
  align-items: center;
  gap: 10px;
  cursor: pointer;
  padding: 10px 12px;
  border: 1px solid rgba(17, 17, 17, 0.12);
  border-radius: 12px;
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-sm);
  color: var(--ink);
}
.c3 .c3-name-opt input[type="radio"] {
  accent-color: var(--accent);
  width: 16px; height: 16px;
  flex-shrink: 0;
}
.c3 .c3-name-opt-label {
  font-weight: 500;
  color: var(--ink);
  white-space: nowrap;
}
.c3 .c3-name-opt-value {
  color: var(--ink-soft);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.c3 .c3-input-inline {
  padding: 6px 10px;
  font-size: var(--text-sm);
  border: none;
  background: transparent;
  flex: 1;
  min-width: 0;
  outline: none;
}
.c3 .c3-input-inline::placeholder { color: var(--ink-softer); }
.c3 .c3-input-inline:focus { border-bottom: 1px solid var(--accent); border-radius: 0; }
.c3 .phone-input {
  display: flex;
  align-items: stretch;
  margin-bottom: 14px;
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 14px;
  box-shadow: none;
  background: var(--bg);
  overflow: hidden;
}
.c3 .phone-input .prefix {
  padding: 13px 14px;
  font-family: 'JetBrains Mono', monospace;
  font-weight: 700;
  font-size: 15px;
  background: var(--ink);
  color: #fff;
  display: flex;
  align-items: center;
  letter-spacing: 0.04em;
}
.c3 .phone-input input {
  flex: 1;
  min-width: 0;
  border: none;
  outline: none;
  padding: 13px 12px;
  font-family: 'JetBrains Mono', monospace;
  font-size: 17px;
  font-weight: 600;
  background: transparent;
  color: var(--ink);
  letter-spacing: 0.05em;
}
.c3 .alt-line {
  text-align: center;
  margin-top: 14px;
  font-size: 14px;
  color: var(--ink-soft);
  line-height: 1.5;
}
.c3 .alt-line .alt-link {
  color: var(--ink);
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}

.c3 .otp-input {
  width: 100%;
  padding: 14px 16px;
  border-radius: 14px;
  border: 1px solid rgba(17, 17, 17, 0.18);
  background: var(--bg);
  font-family: inherit;
  font-size: 18px;
  font-weight: 600;
  letter-spacing: 0.04em;
  margin-bottom: 10px;
  color: var(--ink);
}
.c3 .otp-input:focus { outline: none; border-color: var(--accent); }

/* ==========================================================
   C7 — My Cards (logged-in customer's home)
   ========================================================== */

/* Page head is now a standardized system component above */

/* Customer inbox list — DeeReach messages that landed in the inbox channel.
   Card-style rows; unread rows get a soft accent stripe + bolder text. */
.inbox-list {
  margin: 14px 20px 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.inbox-row.unread {
  background: var(--accent-soft);
  border-color: rgba(255, 94, 58, 0.32);
}
.inbox-row.unread::before {
  content: '';
  position: absolute;
  left: 6px;
  top: 50%;
  transform: translateY(-50%);
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent);
}
.inbox-row .ib-shop .dot { color: var(--accent); }
.inbox-row.unread .ib-body { font-weight: 600; }
.inbox-empty {
  margin: 60px 22px 0;
  text-align: center;
  font-family: 'Prompt', sans-serif;
  color: var(--ink-soft);
}
.inbox-empty .h {
  font-weight: 700;
  font-size: 17px;
  color: var(--ink);
  margin-bottom: 8px;
}
.inbox-empty .s {
  font-size: 13px;
  line-height: 1.5;
}
/* /shop/issue/scan — S3.scan camera viewfinder for the shop to scan
   the customer's identity QR (from /my-id) and issue a stamp. */
.scan-page {
  padding: 16px 18px 22px;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.scan-viewfinder {
  width: 100%;
  max-width: 320px;
  aspect-ratio: 1;
  background: #1a1a1a;
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 18px;
  position: relative;
  overflow: hidden;
}
.scan-viewfinder video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.scan-viewfinder::before {
  content: '';
  position: absolute;
  top: 12%; left: 12%; right: 12%; bottom: 12%;
  border: 2px solid var(--butter);
  border-radius: 14px;
  pointer-events: none;
}
.scan-corners {
  position: absolute;
  top: 12%; left: 12%; right: 12%; bottom: 12%;
  pointer-events: none;
}
.scan-corners > span {
  position: absolute;
  width: 22px;
  height: 22px;
  border-color: var(--butter);
  border-style: solid;
  border-width: 0;
}
.scan-corners .tl { top: -2px; left: -2px; border-top-width: 4px; border-left-width: 4px; border-top-left-radius: 8px; }
.scan-corners .tr { top: -2px; right: -2px; border-top-width: 4px; border-right-width: 4px; border-top-right-radius: 8px; }
.scan-corners .bl { bottom: -2px; left: -2px; border-bottom-width: 4px; border-left-width: 4px; border-bottom-left-radius: 8px; }
.scan-corners .br { bottom: -2px; right: -2px; border-bottom-width: 4px; border-right-width: 4px; border-bottom-right-radius: 8px; }
.scan-line {
  position: absolute;
  top: 12%; left: 12%; right: 12%;
  height: 2px;
  background: var(--accent);
  box-shadow: 0 0 8px var(--accent);
  animation: scan-line-sweep 2s ease-in-out infinite;
  pointer-events: none;
}
@keyframes scan-line-sweep {
  0%, 100% { top: 12%; }
  50% { top: calc(88% - 2px); }
}
.scan-hint {
  margin: 16px 0 6px;
  text-align: center;
  font-family: 'Prompt', sans-serif;
  font-size: 15px;
  color: var(--ink-soft);
  line-height: 1.45;
}
.scan-status {
  margin: 10px 18px;
  padding: 12px 16px;
  border-radius: 14px;
  border: 1px solid rgba(17, 17, 17, 0.18);
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 15px;
  text-align: center;
  max-width: 320px;
}
.scan-status.ok { background: var(--mint); color: var(--mint-ink); }
.scan-status.err { background: var(--accent); color: #fff; }
.scan-fallback {
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px dashed var(--line);
  width: 100%;
  max-width: 320px;
  text-align: center;
}
.scan-fallback a {
  font-family: 'Prompt', sans-serif;
  font-size: 15px;
  font-weight: 600;
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* C8 — /my-id fullscreen QR for the shop to scan. Layout matches the
   revised customer design (taemdee-customer.html C8 mockup). */
.c8-stage {
  padding: 32px 24px 0;
  text-align: center;
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.c8-instruction {
  margin-bottom: 22px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
}
.c8-icon {
  width: 44px;
  height: 28px;
  color: var(--accent);
  display: flex;
  align-items: center;
  justify-content: center;
}
.c8-icon svg { width: 100%; height: 100%; }
.c8-msg {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: var(--text-lg);
  line-height: 1.3;
  letter-spacing: -0.02em;
  color: var(--ink);
}
.c8-qr-card {
  background: #FDFAF2;
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 22px;
  padding: 18px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  width: 100%;
  max-width: 320px;
}
.c8-qr {
  width: 100%;
  aspect-ratio: 1;
  max-width: 220px;
  background: #FDFAF2;
  border-radius: 8px;
  padding: 6px;
}
.c8-qr svg { display: block; width: 100%; height: 100%; }
.c8-id {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding-top: 6px;
  border-top: 1px dashed var(--ink-softer);
  width: 100%;
  justify-content: center;
}
.c8-id-label {
  font-family: 'Prompt', sans-serif;
  font-size: 9px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-softer);
}
.c8-id-num {
  font-family: 'JetBrains Mono', monospace;
  font-weight: 700;
  font-size: 15px;
  letter-spacing: 0.05em;
  color: var(--ink);
}
.c8-refresh {
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-xs);
  color: var(--ink-soft);
  display: inline-flex;
  align-items: center;
  gap: 5px;
}
.c8-refresh svg {
  width: 11px;
  height: 11px;
  animation: c8-spin 4s linear infinite;
}
@keyframes c8-spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

/* ============================================================
   cards.list (.cl-*) — multi-shop loyalty card landing.
   Three vertical zones:
     1. .cl-hero        — single full-bleed gradient tile for the
                          most-progressed ready (≥ threshold) card.
                          Pulsing tag, big "10/10", inline CTA.
     2. .cl-section-h + .cl-carousel — "ใกล้แล้ว" horizontal scroll
                          of mid-progress cards (.cl-mini), each
                          tinted by --shop-color via inline style.
     3. .cl-section-h + .cl-search + .cl-other — "เก็บแต้มอยู่"
                          compact list with search input.
   Then .cl-add (dashed CTA to scan more) closes the page.
   Replaces the old .c7-* layout that had a stats hero + flat card
   grid — design moved to a more navigable, prioritised flow.
   ============================================================ */
.cl-stat .num {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: 20px;
  color: var(--ink);
  line-height: 1;
  letter-spacing: -0.02em;
}
.cl-stat .num.accent { color: var(--accent); }
.cl-stat .label {
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-2xs);
  color: var(--ink-soft);
  margin-top: 4px;
}

.cl-section-h {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 14px 20px 12px;
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: var(--text-md);
  color: var(--ink);
  letter-spacing: -0.01em;
}
.cl-section-h .icon {
  width: 18px; height: 18px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--accent);
}
.cl-section-h .icon svg { width: 100%; height: 100%; fill: currentColor; }
.cl-section-h .count {
  margin-left: auto;
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 600;
  font-size: 12px;
  color: var(--ink-soft);
  letter-spacing: 0.02em;
}

.cl-hero {
  margin: 0 14px;
  position: relative;
  border-radius: 22px;
  padding: 20px;
  background: linear-gradient(135deg, #FF8A5C 0%, #FF5E3A 55%, #E04020 100%);
  color: #fff;
  overflow: hidden;
  box-shadow: 0 12px 28px -10px rgba(255, 94, 58, 0.55);
  text-decoration: none;
  display: block;
}
.cl-hero::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image:
    radial-gradient(circle at 18% 30%, rgba(255,255,255,0.22) 0, transparent 8%),
    radial-gradient(circle at 82% 18%, rgba(255,255,255,0.18) 0, transparent 12%),
    radial-gradient(circle at 60% 85%, rgba(255,255,255,0.20) 0, transparent 9%),
    radial-gradient(circle at 30% 75%, rgba(255,255,255,0.15) 0, transparent 8%),
    radial-gradient(circle at 90% 60%, rgba(255,217,82,0.30) 0, transparent 14%);
  pointer-events: none;
}
.cl-hero > * { position: relative; z-index: 1; }
.cl-hero-tag .pulse {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--butter);
  animation: cl-pulse 1.5s infinite;
  box-shadow: 0 0 0 0 rgba(255,217,82,0.6);
}
@keyframes cl-pulse {
  0% { box-shadow: 0 0 0 0 rgba(255,217,82,0.7); }
  70% { box-shadow: 0 0 0 8px rgba(255,217,82,0); }
  100% { box-shadow: 0 0 0 0 rgba(255,217,82,0); }
}
.cl-hero-logo .dot { color: var(--accent); margin-left: 1px; }
.cl-hero-num .of {
  font-size: 13px;
  opacity: 0.7;
  font-weight: 600;
}
.cl-carousel-wrap {
  /* invisible wrapper · no bg / border / padding · structural only */
}
.cl-carousel {
  display: flex;
  gap: 10px;
  padding: 0 14px 4px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-padding-left: 14px;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.cl-carousel::-webkit-scrollbar { display: none; }

.cl-mini {
  flex: 0 0 165px;
  scroll-snap-align: start;
  background: var(--surface);
  border-radius: 18px;
  border: 1px solid var(--line);
  padding: 14px;
  position: relative;
  overflow: hidden;
  min-height: 158px;
  display: flex;
  flex-direction: column;
  text-decoration: none;
  color: inherit;
}
.cl-mini::before {
  content: '';
  position: absolute;
  right: -32px;
  top: -32px;
  width: 92px;
  height: 92px;
  border-radius: 50%;
  background: var(--shop-color, var(--accent));
  opacity: 0.10;
}
.cl-mini > * { position: relative; z-index: 1; }
.cl-mini .shop-avatar { margin-bottom: 10px; }
.cl-mini-name {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: var(--text-sm);
  color: var(--ink);
  margin-bottom: 2px;
  letter-spacing: -0.005em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cl-mini-reward {
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-2xs);
  color: var(--ink-soft);
  margin-bottom: 12px;
  line-height: 1.3;
  display: -webkit-box;
  -webkit-line-clamp: 1;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.cl-mini-foot { margin-top: auto; }
.cl-mini-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: 6px;
}
.cl-mini-num {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: 18px;
  color: var(--ink);
  letter-spacing: -0.02em;
  line-height: 1;
}
.cl-mini-num .of {
  font-size: 11px;
  color: var(--ink-soft);
  font-weight: 600;
}
.cl-mini-left {
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-2xs);
  color: var(--accent);
  font-weight: 600;
}
.cl-mini-bar {
  height: 4px;
  background: rgba(0,0,0,0.06);
  border-radius: 99px;
  overflow: hidden;
}
.cl-mini-fill {
  height: 100%;
  background: var(--shop-color, var(--accent));
  border-radius: 99px;
}

.cl-search {
  margin: 0 14px 10px;
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 10px 14px;
}
.cl-search svg {
  width: 16px;
  height: 16px;
  color: var(--ink-soft);
  stroke: currentColor;
  fill: none;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  flex-shrink: 0;
}
.cl-search input {
  flex: 1;
  border: none;
  background: transparent;
  outline: none;
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-sm);
  color: var(--ink);
  padding: 0;
  min-width: 0;
}
.cl-search input::placeholder { color: var(--ink-softer); }

.cl-other {
  margin: 0 14px;
  background: var(--surface);
  border-radius: 16px;
  border: 1px solid var(--line);
  overflow: hidden;
}
.cl-other-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  text-decoration: none;
  color: inherit;
}
.cl-other-row + .cl-other-row { border-top: 1px solid var(--line); }
.cl-other-info {
  flex: 1;
  min-width: 0;
}
.cl-other-name {
  font-family: 'Prompt', sans-serif;
  font-weight: 600;
  font-size: var(--text-sm);
  color: var(--ink);
  line-height: 1.2;
  margin-bottom: 2px;
}
.cl-other-reward {
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-2xs);
  color: var(--ink-soft);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cl-other-prog {
  flex-shrink: 0;
  text-align: right;
}
.cl-other-num {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 700;
  font-size: 13px;
  color: var(--ink);
  letter-spacing: -0.01em;
  margin-bottom: 4px;
  line-height: 1;
}
.cl-other-num .of { color: var(--ink-soft); font-weight: 500; }
.cl-other-bar {
  width: 50px;
  height: 3px;
  background: rgba(0,0,0,0.06);
  border-radius: 99px;
  overflow: hidden;
}
.cl-other-fill {
  height: 100%;
  background: var(--shop-color, var(--accent));
}

.cl-add {
  margin: 18px 14px 100px;
  padding: 18px;
  border-radius: 16px;
  border: 1.5px dashed rgba(17,17,17,0.18);
  text-align: center;
  background: transparent;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-decoration: none;
  color: inherit;
}
.cl-add-icon {
  width: 38px; height: 38px;
  border-radius: 50%;
  background: var(--accent-soft);
  color: var(--accent);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 8px;
}
.cl-add-icon svg {
  width: 18px; height: 18px;
  stroke: currentColor;
  fill: none;
  stroke-width: 2.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.cl-add-h {
  font-family: 'Prompt', sans-serif;
  font-weight: 600;
  font-size: var(--text-sm);
  color: var(--ink);
  margin-bottom: 2px;
}
.cl-add-s {
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-2xs);
  color: var(--ink-soft);
}

/* ==========================================================
   C6 — Account menu
   ========================================================== */

/* Toggle switch (used in c6) */
.c6-toggle {
  width: 38px;
  height: 22px;
  background: var(--line);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 999px;
  position: relative;
  transition: background 0.2s;
  cursor: pointer;
  flex-shrink: 0;
}
.c6-toggle .dot {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  left: 2px;
  width: 14px;
  height: 14px;
  background: #fff;
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 50%;
  transition: left 0.2s;
}
.c6-toggle.on { background: var(--accent); }
.c6-toggle.on .dot { left: 19px; background: var(--butter); }

/* Pill variants used in c6 rows */
.s10-row .pill.butter {
  background: var(--butter);
  color: var(--ink);
  border: 1px solid rgba(17, 17, 17, 0.18);
}

/* Version mark at bottom */
.c6-version .brand {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  color: var(--ink);
  letter-spacing: -0.01em;
}
.c6-version .brand .dot { color: var(--accent); }

/* ==========================================================
   Install pill + bottom sheet (persistent install affordance)
   Used in: C1, C2, C5, C7 (customer) + S3 (shop)
   ========================================================== */

/* Install bottom sheet — hidden by default; .open shows it. Ported from
   design 2564-2776 (Apr 29 home-mock variant + iOS step-by-step). */
/* Bottom-sheet overlay — used by both the install sheet and the
   nickname-collect sheet. Default state stays in the DOM at
   opacity 0 with pointer-events disabled so the inner sheet's
   translateY transition actually fires when .open is toggled.
   (Earlier `display:none → display:flex` toggle killed the
   transition because CSS can't animate through a display change.) */
.install-sheet-overlay {
  position: fixed;
  inset: 0;
  background: rgba(17, 17, 17, 0.45);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  z-index: 100;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding-bottom: 0;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s ease-out;
}
.install-sheet-overlay.open {
  opacity: 1;
  pointer-events: auto;
}
.install-sheet {
  background: var(--bg);
  border-top: 1px solid rgba(17, 17, 17, 0.18);
  border-top-left-radius: 22px;
  border-top-right-radius: 22px;
  padding: 18px 18px 16px;
  width: 100%;
  max-width: 440px;
  box-shadow: 0 -8px 24px -8px rgba(0, 0, 0, 0.25);
  position: relative;
  transform: translateY(100%);
  /* Slightly bouncy ease-out so the sheet feels like it's settling
     in, not just sliding to a stop. Same curve the design's
     signup-sheet uses. */
  transition: transform 0.32s cubic-bezier(0.32, 0.72, 0.18, 1);
}
.install-sheet-overlay.open .install-sheet {
  transform: translateY(0);
}
.install-sheet .sheet-handle {
  width: 36px;
  height: 4px;
  border-radius: 999px;
  background: var(--ink-softer);
  margin: 0 auto 12px;
  opacity: 0.4;
}

/* Home-screen mock-up · TaemDee icon spotlit (4 phone-app icons in a row) */
.install-sheet .home-mock {
  background: linear-gradient(180deg, #F7B65A 0%, #FF8E4F 100%);
  border-radius: 16px;
  padding: 16px 14px 14px;
  margin: 0 -2px 14px;
  position: relative;
  overflow: hidden;
}
.install-sheet .home-mock .icon-row {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 10px;
  align-items: end;
}
.install-sheet .home-mock .app-icon { text-align: center; }
.install-sheet .home-mock .app-icon.dim { opacity: 0.5; }
.install-sheet .home-mock .app-icon .tile {
  aspect-ratio: 1;
  border-radius: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.install-sheet .home-mock .app-icon .tile.t1 {
  background: linear-gradient(135deg, #34D058, #28A745);
}
.install-sheet .home-mock .app-icon .tile.t2 {
  background: linear-gradient(135deg, #6B6660, #3A3633);
}
.install-sheet .home-mock .app-icon .tile.t4 {
  background: #fff;
  color: #E91E63;
}
.install-sheet .home-mock .app-icon .tile svg { width: 56%; }
.install-sheet .home-mock .app-icon .label {
  font-size: 9px;
  color: #fff;
  margin-top: 4px;
  font-weight: 500;
  text-shadow: 0 1px 3px rgba(0,0,0,0.18);
}
.install-sheet .home-mock .app-icon.spotlight {
  transform: scale(1.18);
  z-index: 2;
  position: relative;
}
.install-sheet .home-mock .app-icon.spotlight::before {
  content: '';
  position: absolute;
  inset: -12px -8px 8px -8px;
  background: radial-gradient(circle, rgba(255,217,82,0.55) 0%, transparent 65%);
  border-radius: 50%;
  z-index: -1;
  animation: spot-pulse 2.4s ease-in-out infinite;
}
@keyframes spot-pulse {
  0%, 100% { opacity: 0.6; transform: scale(1); }
  50% { opacity: 0.9; transform: scale(1.08); }
}
.install-sheet .home-mock .app-icon.spotlight .tile {
  background: var(--accent);
  box-shadow: 0 8px 22px -6px rgba(0,0,0,0.45);
  border: 2px solid var(--butter);
}
.install-sheet .home-mock .app-icon.spotlight .tile svg { width: 64%; }
.install-sheet .home-mock .app-icon.spotlight .label {
  color: #fff;
  font-weight: 700;
}

.install-sheet .pitch-h {
  font-family: 'Prompt', sans-serif;
  font-weight: 800; font-size: var(--text-xl);
  letter-spacing: -0.025em;
  line-height: 1.15;
  margin-bottom: 6px;
  text-align: center;
}
.install-sheet .pitch-h em {
  font-style: italic; color: var(--accent);
}
.install-sheet .pitch-s {
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-xs); color: var(--ink-soft);
  line-height: 1.5;
  text-align: center;
  margin-bottom: 14px;
}

.install-sheet .sheet-cta {
  width: 100%;
  background: var(--accent);
  color: #fff;
  border: none;
  padding: 13px;
  border-radius: 99px;
  font-family: 'Prompt', sans-serif;
  font-weight: 700; font-size: var(--text-base);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}
.install-sheet .sheet-cta .arr {
  font-weight: 800; font-size: var(--text-base);
}
.install-sheet .sheet-cta.cta-dark {
  background: var(--ink);
  color: var(--bg);
}
.install-sheet .sheet-close {
  width: 100%;
  background: transparent; color: var(--ink-soft);
  border: none;
  padding: 8px;
  margin-top: 4px;
  font-family: 'Prompt', sans-serif;
  font-weight: 500; font-size: var(--text-xs);
  cursor: pointer;
}

/* Combined install instructions — both Android and iOS sets shown
   side by side because UA detection is unreliable (Chrome on iOS,
   Firefox on Android, etc). Each platform block has a small heading
   and the steps. Spacing is tighter than a standalone variant since
   they have to fit together in the sheet. */
.install-sheet .install-platforms {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin: 12px 0 6px;
}
.install-sheet .install-plat {
  background: rgba(17, 17, 17, 0.04);
  padding: 11px 12px;
  border-radius: 12px;
}
.install-sheet .install-plat .ip-h {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 11.5px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-bottom: 6px;
}
.install-sheet .install-plat .ip-step {
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-xs);
  color: var(--ink);
  line-height: 1.4;
}
.install-sheet .install-plat .ip-step strong { font-weight: 700; }
/* Inside the iOS block the existing .ios-steps rules already
   format the numbered rows; trim the wrapping margin and drop
   the inner row background so it doesn't double up against the
   .install-plat surface. */
.install-sheet .install-plat .ios-steps { margin-bottom: 0; }
.install-sheet .install-plat .ios-step {
  background: transparent;
  padding: 6px 0;
}

/* iOS step rows — used inside the .install-plat container above. */
.install-sheet .ios-steps {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 4px;
}
.install-sheet .ios-steps .ios-step {
  background: rgba(17,17,17,0.04);
  padding: 10px 12px;
  border-radius: 10px;
  display: flex;
  align-items: center;
  gap: 10px;
}
.install-sheet .ios-steps .ios-step .ios-num {
  width: 24px;
  height: 24px;
  background: var(--accent);
  color: #fff;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-xs);
  font-weight: 700;
  flex-shrink: 0;
}
.install-sheet .ios-steps .ios-step .ios-step-text {
  flex: 1;
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-xs);
  color: var(--ink);
  line-height: 1.4;
}
.install-sheet .ios-steps .ios-step .ios-step-text strong {
  font-weight: 700;
}
.install-sheet .ios-steps .ios-step .ios-step-icon {
  width: 18px;
  height: 18px;
  color: var(--accent);
  flex-shrink: 0;
}
.install-sheet .ios-steps .ios-step .ios-step-icon svg {
  width: 100%;
  height: 100%;
}

/* ==========================================================
   Shared — page-title (used in S11, S12)
   ========================================================== */

.page-title { padding: 22px 20px 0; }
.page-title .h {
  font-weight: 700;
  font-size: 26px;
  letter-spacing: -0.02em;
  line-height: 1.15;
  margin-bottom: 4px;
}
.page-title .h em {
  font-style: italic;
  font-weight: 700;
  color: var(--accent);
}
.page-title .sub {
  font-weight: 400;
  font-size: 15px;
  color: var(--ink-soft);
}
.app-bar .right-action {
  font-size: 14px;
  font-weight: 500;
  color: var(--ink-soft);
  text-decoration: none;
}

/* ==========================================================
   S10 — Settings home
   ========================================================== */

.s10-shop-card .logo {
  width: 42px;
  height: 42px;
  background: var(--accent);
  color: #fff;
  border-radius: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: 18px;
  letter-spacing: -0.03em;
  flex-shrink: 0;
  position: relative;
}
.s10-shop-card .info { flex: 1; line-height: 1.2; position: relative; min-width: 0; }
.s10-shop-card .name {
  font-weight: 700;
  font-size: 15px;
  letter-spacing: -0.02em;
  margin-bottom: 1px;
}
.s10-shop-card .name .dot { color: var(--butter); }
.s10-shop-card .meta {
  font-weight: 400;
  font-size: 12px;
  color: var(--ink-softer);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Settings list — small bold left-aligned label per section, then rows
   that are each their own rounded card with a tinted icon chip. Ported
   from design/taemdee-customer.html (settings / settings.notif). */
.s10-section {
  padding: 22px 20px 0;
}
.s10-section .label {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: var(--text-xs);
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-soft);
  margin: 0 0 8px;
  padding-left: 4px;
}

/* ============================================================
   .page-container — Settings split into labelled cards. Every
   direct child becomes its own surface (bg + border + radius)
   with a 16px / weight 700 label above the rows so the groups
   read as distinct sections instead of one flat list. Used by
   /shop/settings and /card/account. Selector targets > div so
   we don't have to name the legacy section class explicitly.
   (shop/settings.html still has the same rules duplicated in an
   inline <style> for now — kept there so an existing deployment
   doesn't visibly shift while this CSS rolls out; the inline copy
   can be removed in a follow-up once the cache settles.)
   ============================================================ */
.page-container > div {
  margin: 12px 0 0;
}
.page-container > div:first-of-type { margin: 0; }
/* Connect-status rows carry the provider's own brand-coloured icon
   (see .connect-icon-* below) — keep that chip round rather than the
   default rounded-square. */
.s10-row.connect-row .row-icon {
  border-radius: 50%;
}

/* Inline profile edit form at the top of /shop/settings and
   /card/account. The wrapper <div> picks up the .page-container
   > div card chrome (bg + border + radius + 14px padding), so
   the form lays out the avatar + input + button centred. */
.profile-edit-inline {
  padding: 0;
  text-align: center;
}
.profile-edit-inline .pe-avatar-wrap { margin: 0 0 14px; }
.profile-edit-inline .pe-avatar {
  width: 64px;
  height: 64px;
  font-size: 26px;
}
.profile-edit-inline .pe-avatar .pe-edit-badge {
  width: 22px;
  height: 22px;
}
.profile-edit-inline .pe-avatar .pe-edit-badge svg {
  width: 11px;
  height: 11px;
}
.profile-edit-inline input[type="text"] {
  max-width: 220px;
  margin: 0 auto;
  padding: 9px 12px;
  font-size: var(--text-sm);
  text-align: center;
}
.profile-edit-inline .pe-actions {
  grid-template-columns: 1fr;
  justify-items: center;
  margin-top: 12px;
}
.profile-edit-inline .pe-save {
  min-width: 180px;
  padding: 13px 28px;
  font-size: var(--text-md);
}
/* /card/account wraps the .profile-edit-inline form itself — that page
   isn't a .page-container, so the card chrome the shop side inherits
   has to be spelled out here. Margin matches the old .c6-profile-card. */
.c6-profile-card-wrap {
  margin: 22px 20px 0;
  padding: 18px 16px 16px;
  background: var(--surface);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 18px;
}
.c6-profile-card-wrap .pe-phone {
  margin-top: 8px;
  font-family: 'JetBrains Mono', monospace;
  font-size: var(--text-sm);
  color: var(--ink-soft);
  letter-spacing: 0.02em;
  text-align: center;
}

/* รายการแนะนำ todos — onboarding nudges on /card/account. Moved here
   verbatim from the retired profile_edit_sheet's inline <style>. */
.pe-todos {
  margin: 18px 20px 0;
}
.pe-todos-h {
  display: flex; align-items: center; gap: 8px;
  font-family: 'Prompt', sans-serif;
  font-size: 13px; font-weight: 700;
  color: var(--ink-soft);
  margin-bottom: 8px;
  letter-spacing: 0.02em;
}
.pe-todos-count {
  background: var(--accent-soft, #FFE6DF); color: var(--accent);
  padding: 1px 8px; border-radius: 999px;
  font-size: 11px; font-weight: 700;
}
.pe-todos-list { display: flex; flex-direction: column; gap: 8px; }
.pe-todo {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 12px; padding: 12px 14px;
}
.pe-todo-title {
  font-family: 'Prompt', sans-serif;
  font-size: 14px; font-weight: 600; color: var(--ink);
}
.pe-todo-desc {
  font-family: 'Prompt', sans-serif;
  font-size: 12px; color: var(--ink-soft);
  margin-top: 2px;
}
.pe-todo-actions {
  display: flex; align-items: center; gap: 8px;
  margin-top: 10px;
}
.pe-todo-cta {
  flex: 1 1 auto;
  appearance: none; -webkit-appearance: none;
  padding: 9px 14px; border: 0; border-radius: 12px;
  background: var(--accent); color: #fff;
  font-family: 'Prompt', sans-serif;
  font-size: 13px; font-weight: 700;
  text-align: center; text-decoration: none;
  cursor: pointer;
}
.pe-todo-skip {
  flex: 0 0 auto;
  appearance: none; -webkit-appearance: none;
  padding: 9px 12px; border: 1px solid var(--line);
  border-radius: 12px;
  background: transparent; color: var(--ink-soft);
  font-family: 'Prompt', sans-serif;
  font-size: 12px; font-weight: 600;
  cursor: pointer;
}
.pe-todo-form { margin: 0; display: contents; }

/* S2.1 / S10.location — province picker (text input styled with chevron). */
/* S10.location — multi-line address textarea. */
.s10-textarea {
  min-height: 60px;
  align-items: flex-start !important;
  line-height: 1.5;
}

/* S10.contact — opening-hours editor: 7 day rows in a single rounded card. */
.s10-hours {
  margin: 0 20px;
  background: var(--surface);
  border-radius: 14px;
  overflow: hidden;
  border: 1px solid rgba(17, 17, 17, 0.18);
}
.s10-hour-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  border-bottom: 1px solid rgba(17, 17, 17, 0.08);
  cursor: pointer;
  font-family: 'Prompt', sans-serif;
  font-size: 14px;
}
.s10-hour-row:last-child { border-bottom: none; }
.s10-hour-row .s10-day {
  flex: 0 0 70px;
  color: var(--ink);
  font-weight: 600;
}
.s10-hour-row .s10-time {
  flex: 1;
  color: var(--ink-soft);
  font-family: 'JetBrains Mono', monospace;
  font-size: 13px;
  display: flex;
  align-items: center;
}
.s10-hour-row .s10-time input[type="time"] {
  appearance: none;
  -webkit-appearance: none;
  background: transparent;
  border: none;
  font-family: 'JetBrains Mono', monospace;
  /* 16px minimum so iOS Safari / PWA doesn't auto-zoom on focus. */
  font-size: 16px;
  color: var(--ink-soft);
  padding: 0;
}
.s10-hour-row.closed .s10-time {
  color: var(--ink-softer);
  font-style: italic;
  font-family: 'Prompt', sans-serif;
}
.s10-hour-row .s10-edit {
  display: inline-flex;
  align-items: center;
  color: var(--ink-softer);
  font-size: 14px;
}

/* S10.location — flat map placeholder card (decorative; no real map yet). */
.s10-map-preview {
  display: block;
  margin: 14px 20px 0;
  height: 110px;
  border-radius: 14px;
  background: linear-gradient(135deg, #DCE6D8 0%, #C8D8C0 100%);
  position: relative;
  overflow: hidden;
  cursor: pointer;
  text-decoration: none;
}
.s10-map-bg {
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(rgba(17, 17, 17, 0.04) 1px, transparent 1px),
    linear-gradient(90deg, rgba(17, 17, 17, 0.04) 1px, transparent 1px);
  background-size: 16px 16px;
}
.s10-map-pin {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -100%);
  color: var(--accent);
  width: 26px; height: 26px;
  filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.15));
}
.s10-map-pin svg { width: 100%; height: 100%; }
.s10-map-label {
  position: absolute;
  bottom: 10px; left: 10px;
  padding: 5px 10px;
  background: var(--bg);
  border-radius: 999px;
  font-family: 'Prompt', sans-serif;
  font-size: 11px;
  font-weight: 600;
  color: var(--ink);
}
/* Row card — each settings row is its own rounded surface with a
   tinted icon chip on the left and (usually) a JetBrains-Mono chevron
   on the right. Ported from design/taemdee-customer.html. */
.s10-row {
  background: var(--surface);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 14px;
  box-shadow: none;
  padding: 12px 14px;
  margin: 0 0 8px;
  display: grid;
  grid-template-columns: 36px 1fr auto;
  gap: 12px;
  align-items: center;
  cursor: pointer;
  text-decoration: none;
  color: inherit;
}
.s10-row .row-icon {
  width: 36px;
  height: 36px;
  background: var(--accent-soft);
  color: var(--accent);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.s10-row .row-icon svg { width: 16px; height: 16px; }
/* Variant for rows that want no leading icon column — drops the
   icon slot so the row-info text starts flush left. Used on the
   topup history + credit log lists where the status / +N delta
   carries the visual cue instead. */
.s10-row.no-icon { grid-template-columns: 1fr auto; }
/* <button class="s10-row"> — rows that fire an action (open a sheet /
   doc overlay) rather than navigate. Strip the UA button chrome so
   they line up with the <a> rows. */
button.s10-row {
  appearance: none;
  -webkit-appearance: none;
  width: 100%;
  font: inherit;
  text-align: left;
}

/* Doc viewer — full-screen overlay that renders the /contact, /privacy
   bodies inline (data-doc triggers; see _partials/doc_viewer.html).
   Exists because a PWA in standalone display mode has no browser back,
   so navigating to those pages would strand the user; this slides up
   over the app and X-es back. */
.doc-viewer-overlay {
  /* Mounted in body_end — outside any .td — so it can't inherit the
     mobile-shell theme tokens. Re-declare the default .td palette here
     (the doc bodies + this chrome read --bg / --surface / --ink / …);
     without it the overlay paints transparent over the page. */
  --bg: #F6F1E5;
  --surface: #FDFAF2;
  --ink: #111111;
  --ink-soft: #6B6660;
  --ink-softer: #A39D92;
  --accent: #FF5E3A;
  --accent-soft: #FFE6DF;
  --line: rgba(17, 17, 17, 0.10);
  --text-2xs: 0.625rem;
  --text-xs: 0.75rem;
  --text-sm: 0.8125rem;
  --text-base: 0.875rem;
  --text-md: 1rem;
  --text-lg: 1.125rem;
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  transform: translateY(100%);
  transition: transform 0.26s ease;
  visibility: hidden;
}
.doc-viewer-overlay.open {
  transform: translateY(0);
  visibility: visible;
}
.doc-viewer-bar {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: calc(10px + env(safe-area-inset-top)) 14px 10px;
  background: var(--surface);
  border-bottom: 1px solid rgba(17, 17, 17, 0.12);
}
.doc-viewer-bar .dv-title {
  flex: 1;
  min-width: 0;
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: var(--text-md);
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.doc-viewer-bar .dv-close {
  appearance: none;
  -webkit-appearance: none;
  flex-shrink: 0;
  width: 34px;
  height: 34px;
  border: none;
  border-radius: 50%;
  background: rgba(17, 17, 17, 0.06);
  color: var(--ink);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.doc-viewer-bar .dv-close svg { width: 18px; height: 18px; }
.doc-viewer-body {
  flex: 1;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  background: var(--bg);
}
/* The contact / privacy bodies ship with marketing-page padding (80px
   top, sits below a fixed nav). Inside the overlay there's a bar
   instead — pull the top in. */
.doc-viewer-body .contact-page,
.doc-viewer-body .legal-page {
  padding-top: 24px;
  padding-bottom: 56px;
}
body.doc-viewer-locked { overflow: hidden; }
.s10-row .row-icon.butter { background: var(--butter); color: var(--ink); }
.s10-row .row-icon.mint { background: var(--mint); color: var(--mint-ink); }
.s10-row .row-info { line-height: 1.2; min-width: 0; }
.s10-row .row-name {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: var(--text-base);
  letter-spacing: -0.01em;
  margin-bottom: 1px;
}
.s10-row .row-meta {
  font-family: 'Prompt', sans-serif;
  font-style: italic;
  font-weight: 400;
  font-size: var(--text-sm);
  color: var(--ink-soft);
  line-height: 1.3;
}
.s10-row .arrow-r {
  font-family: 'JetBrains Mono', monospace;
  color: var(--ink-soft);
  font-size: var(--text-base);
  line-height: 1;
}

/* Disabled row — feature flagged off / coming soon. Drops the
   pointer + dims the icon and copy so it reads as informational
   rather than a tappable action. */
.s10-row.s10-row-soon {
  cursor: default;
  opacity: 0.7;
}
.s10-row.s10-row-soon .row-icon,
.s10-row.s10-row-soon .row-name { color: var(--ink-soft); }
.s10-row.s10-row-soon .row-meta { color: var(--ink-softer); }
.s10-soon-tag {
  font-family: 'Prompt', sans-serif;
  font-weight: 600;
  font-size: 10.5px;
  letter-spacing: 0.04em;
  background: rgba(17, 17, 17, 0.06);
  color: var(--ink-soft);
  padding: 4px 9px;
  border-radius: 999px;
  white-space: nowrap;
}

/* Connect-status rows — provider icon keeps its brand color, connected
   rows lose the cursor + pointer (read-only), and a small check chip
   replaces the arrow when linked. */
/* Scan-cooldown form — number + unit pair sits inline so it reads
   like a sentence ("1 คะแนนต่อ [2] [สัปดาห์]"). Preset buttons round
   out the unit options into common shop intervals. */
.s10-cooldown-row {
  display: flex;
  gap: 10px;
  margin: 10px 0 12px;
}
.s10-cooldown-num,
.s10-cooldown-unit {
  background: var(--surface);
  border: 1.5px solid rgba(17, 17, 17, 0.18);
  border-radius: 12px;
  padding: 12px 14px;
  font-family: 'Prompt', sans-serif;
  font-weight: 600;
  font-size: var(--text-md);
  color: var(--ink);
}
.s10-cooldown-num { width: 90px; text-align: center; -moz-appearance: textfield; }
.s10-cooldown-num::-webkit-outer-spin-button,
.s10-cooldown-num::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.s10-cooldown-unit { flex: 1; appearance: none; background-image: linear-gradient(45deg, transparent 50%, var(--ink-soft) 50%), linear-gradient(135deg, var(--ink-soft) 50%, transparent 50%); background-position: calc(100% - 16px) 18px, calc(100% - 11px) 18px; background-size: 5px 5px; background-repeat: no-repeat; padding-right: 30px; }
.s10-cooldown-num:disabled,
.s10-cooldown-unit:disabled { opacity: 0.4; cursor: not-allowed; }
.s10-cooldown-presets {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 8px;
}
.s10-cooldown-presets button {
  background: transparent;
  border: 1px dashed rgba(17, 17, 17, 0.3);
  border-radius: 99px;
  padding: 6px 12px;
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-sm);
  color: var(--ink-soft);
  cursor: pointer;
}
.s10-cooldown-presets button:hover { color: var(--ink); border-color: var(--ink); }

/* Revoke button on a connected row — looks like the .connect-check
   pill at rest, flips to an accent × when armed. The whole row is
   the form element, so click anywhere triggers the same arm/submit
   sequence. */
.s10-row.connect-row.connected { cursor: pointer; }
.connect-revoke {
  width: 22px;
  height: 22px;
  border: none;
  background: var(--mint);
  color: var(--mint-ink);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 800;
  font-size: 13px;
  cursor: pointer;
  padding: 0;
  transition: background 0.15s, color 0.15s;
}
/* Form is the row container in the revoke flow — strip browser
   default margin so it lays out the same as the <a>/div siblings. */
form.s10-row { margin: 0 0 4px; }

/* PWA OAuth pairing overlay — shown on the PWA while OAuth is in
   progress in the system browser. The PWA's SSE picks up the claim
   and redeems behind the scenes; the overlay just keeps the user
   informed and gives them a manual "ยกเลิก" out. */
@keyframes pair-spin { to { transform: rotate(360deg); } }
/* OAuth pair-complete landing page (rendered to the external browser
   after a PWA-initiated OAuth flow). Centered card + green/red icon,
   nothing fancy — the user's job is to flip back to the PWA. */
.pair-complete .pair-icon.ok { background: var(--mint, #C8E8D0); color: var(--mint-ink, #1A6B3A); }
.pair-complete .pair-icon.err { background: var(--accent-soft); color: var(--accent); }
/* Pair-complete CTAs — primary "ไปที่บัตรของฉัน" navigates to
   /my-cards (works whether this page is in the PWA or system
   browser; the cookie was just set on this response). Secondary
   "ปิดหน้านี้" tries window.close() for the popup-from-PWA case
   and falls through to /my-cards. */
.pair-complete .pair-cta-primary .arr {
  font-weight: 800;
  font-size: 14px;
}
.s10-row .row-icon.connect-icon-line { background: #06C755; color: #fff; border-color: #06C755; }
.s10-row .row-icon.connect-icon-google { background: #fff; color: var(--ink); }
.s10-row .row-icon.connect-icon-facebook { background: #fff; color: #1877F2; }
.s10-row .row-icon.connect-icon-phone { background: var(--accent-soft); color: var(--accent); }
.s10-row .row-icon.connect-icon-line svg,
.s10-row .row-icon.connect-icon-google svg,
.s10-row .row-icon.connect-icon-facebook svg { width: 18px; height: 18px; }
.s10-row .connect-check {
  width: 22px; height: 22px;
  border-radius: 50%;
  background: var(--mint);
  color: var(--mint-ink);
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 800;
  font-size: 13px;
}
.s10-logout {
  margin: 22px 16px 18px;
  padding: 10px 14px;
  background: transparent;
  border: none;
  border-radius: 12px;
  font-family: inherit;
  font-weight: 600;
  font-size: 13.5px;
  color: var(--ink-soft);
  width: calc(100% - 32px);
  cursor: pointer;
  text-align: center;
  text-decoration: none;
  display: block;
}
.s10-logout:hover { color: var(--ink); }
/* C6.notifications — channel preference radio list + muted-shop rows.
   Wrapped in a single rounded surface (.notif-radio-list) so the two
   options read as one control; .selected paints the accent dot. */
.notif-radio-list {
  display: flex;
  flex-direction: column;
  padding: 4px;
  background: var(--surface);
  border-radius: 14px;
  box-shadow: 0 1px 2px rgba(17, 17, 17, 0.04);
}
.notif-radio {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 11px 12px;
  border-radius: 11px;
  cursor: pointer;
}
.notif-radio.selected { background: var(--accent-soft); }
.notif-radio .nr-circle {
  width: 18px;
  height: 18px;
  border: 2px solid rgba(17, 17, 17, 0.25);
  border-radius: 50%;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
}
.notif-radio.selected .nr-circle { border-color: var(--accent); }
.notif-radio.selected .nr-circle::after {
  content: '';
  width: 9px;
  height: 9px;
  background: var(--accent);
  border-radius: 50%;
}
.notif-radio .nr-text { flex: 1; min-width: 0; }
.notif-radio .nr-name {
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-sm);
  font-weight: 500;
  color: var(--ink);
  display: flex;
  align-items: center;
  gap: 6px;
  line-height: 1.3;
}
.notif-radio.selected .nr-name { font-weight: 600; }
.notif-radio .nr-badge {
  font-family: 'Prompt', sans-serif;
  font-size: 9.5px;
  font-weight: 600;
  background: var(--accent);
  color: #fff;
  padding: 2px 6px;
  border-radius: 99px;
}
.notif-radio .nr-desc {
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-2xs);
  color: var(--ink-soft);
  margin-top: 2px;
  line-height: 1.45;
}
.notif-radio.disabled {
  opacity: 0.55;
  cursor: not-allowed;
}
.notif-radio.disabled .nr-circle {
  border-color: rgba(17, 17, 17, 0.18);
}
.notif-radio .nr-link {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
  font-weight: 600;
  cursor: pointer;
}
.notif-mute-row {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 12px 14px;
  background: var(--surface);
  border-radius: 14px;
  box-shadow: 0 1px 2px rgba(17, 17, 17, 0.04);
  margin-bottom: 6px;
}
.notif-mute-row .nm-name {
  flex: 1;
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-sm);
  color: var(--ink);
}
.notif-mute-row .nm-unmute {
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-xs);
  color: var(--accent);
  font-weight: 500;
}

/* DeeReach consent toggle — used in C3 phone signup + C3.line LINE
   confirm. Toggle ON = customer opts in for the shop they're signing
   up at (no mute row); OFF flips the .ct-switch grey + reveals the
   .consent-plea below explaining inbox-fallback so the owner doesn't
   feel like they lost the customer entirely. */
.consent-toggle {
  margin-top: 16px;
  margin-bottom: 14px;
  padding: 14px 16px;
  background: var(--surface);
  border: 1px solid rgba(17, 17, 17, 0.12);
  border-radius: 14px;
  display: flex;
  align-items: center;
  gap: 14px;
  cursor: pointer;
  user-select: none;
}
.consent-toggle .ct-info { flex: 1; min-width: 0; }
.consent-toggle .ct-title {
  font-family: 'Prompt', sans-serif;
  font-size: 14px;
  font-weight: 600;
  color: var(--ink);
  line-height: 1.3;
}
.consent-toggle .ct-sub {
  font-family: 'Prompt', sans-serif;
  font-size: 11.5px;
  color: var(--ink-soft);
  margin-top: 3px;
  line-height: 1.5;
}
.consent-toggle .ct-switch {
  flex-shrink: 0;
  width: 40px;
  height: 24px;
  background: var(--accent);
  border-radius: 99px;
  display: flex;
  align-items: center;
  padding: 0 3px;
  justify-content: flex-end;
  transition: background 0.15s ease, justify-content 0.15s ease;
}
.consent-toggle .ct-switch .ct-dot {
  width: 18px;
  height: 18px;
  background: #fff;
  border-radius: 50%;
  box-shadow: 0 1px 2px rgba(17, 17, 17, 0.18);
}
.consent-toggle.off .ct-switch {
  background: rgba(17, 17, 17, 0.18);
  justify-content: flex-start;
}
.consent-plea {
  display: none;
  margin-top: -6px;
  margin-bottom: 14px;
  padding: 12px 14px;
  background: var(--butter-soft);
  border-radius: 12px;
  font-family: 'Prompt', sans-serif;
  font-size: 12px;
  color: var(--ink);
  line-height: 1.55;
}
.consent-toggle.off + .consent-plea { display: block; }

/* C3.line — LINE account display card. Shown after the LINE OAuth
   callback so the customer can confirm the green-tick handle their
   stamps will live on, plus toggle DeeReach consent before the final
   redirect. Ports verbatim from design verbatim. */
.line-account {
  margin-top: 14px;
  background: var(--surface);
  border: 1px solid rgba(17,17,17,0.12);
  border-radius: 12px;
  padding: 12px;
  display: flex;
  align-items: center;
  gap: 12px;
}
.line-account .la-avatar {
  width: 40px;
  height: 40px;
  background: #06C755;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  color: #fff;
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: var(--text-md);
}
.line-account .la-avatar svg { width: 20px; height: 20px; }
.line-account .la-info { flex: 1; min-width: 0; }
.line-account .la-label {
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-2xs);
  color: var(--ink-softer);
  margin-bottom: 2px;
}
.line-account .la-name {
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-base);
  font-weight: 600;
  color: var(--ink);
  line-height: 1.3;
}

/* LINE-themed confirm button on C3.line. */
.btn-line {
  appearance: none; -webkit-appearance: none;
  width: 100%;
  background: #06C755;
  color: #fff;
  border: none;
  border-radius: 99px;
  padding: 12px;
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-base);
  font-weight: 600;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}
.btn-line .arr {
  font-size: var(--text-base);
  font-weight: 800;
}

/* PDPA delete-account link — quiet, below logout. .armed wears the
   accent so the second tap lands on a clearly-different visual state. */
.c6-delete-account {
  appearance: none;
  -webkit-appearance: none;
  display: block;
  width: calc(100% - 40px);
  margin: 0 20px 20px;
  padding: 8px 0;
  background: transparent;
  border: none;
  text-align: center;
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-xs);
  color: rgba(190, 60, 50, 0.85);
  text-decoration: none;
  cursor: pointer;
  letter-spacing: 0.01em;
}
.c6-delete-account.armed {
  color: #be3c32;
  font-weight: 700;
  text-decoration: underline;
}

/* ==========================================================
   S11 — Team
   ========================================================== */

.s11-invite .ic {
  width: 44px;
  height: 44px;
  background: var(--ink);
  color: var(--butter);
  border-radius: 14px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.s11-invite .ic svg { width: 20px; height: 20px; }
.s11-invite .meta { flex: 1; line-height: 1.25; }
.s11-invite .meta .h {
  font-weight: 700;
  font-size: 17px;
  letter-spacing: -0.015em;
}
.s11-invite .meta .s {
  font-size: 13px;
  color: var(--ink);
  opacity: 0.75;
  margin-top: 1px;
}

.s11-member .more {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  border: 1px solid rgba(17, 17, 17, 0.18);
  background: var(--surface);
  color: var(--ink);
  font-weight: 700;
  cursor: pointer;
  font-family: 'Prompt', sans-serif;
}
.s11-member .more.confirm-remove {
  width: auto;
  padding: 0 12px;
  background: var(--accent);
  color: #fff;
  font-size: 14px;
  letter-spacing: -0.01em;
}
.s11-member.owner-row { background: var(--mint); }
.s11-member .info { line-height: 1.2; }
.s11-member .name {
  font-weight: 700;
  font-size: 16px;
  letter-spacing: -0.015em;
  margin-bottom: 2px;
}
.s11-member .role {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-style: italic;
  font-size: 13px;
  color: var(--ink-soft);
}
.s11-member .role .dot {
  width: 4px;
  height: 4px;
  background: var(--accent);
  border-radius: 50%;
}
.s11-member.owner .role .dot { background: var(--mint-ink); }

/* Invite form (modal-ish placement on the same page) */
.s11-form {
  margin: 22px 20px 0;
  padding: 18px 16px;
  background: var(--surface);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 16px;
  box-shadow: none;
}
.s11-form label {
  display: block;
  font-weight: 600;
  font-size: 14px;
  color: var(--ink-soft);
  margin: 8px 0 4px;
}
.s11-form input[type="text"],
.s11-form input[type="tel"] {
  width: 100%;
  padding: 12px 14px;
  border-radius: 12px;
  border: 1px solid rgba(17, 17, 17, 0.18);
  background: var(--bg);
  font-family: inherit;
  font-size: 16px;
  font-weight: 600;
}
.s11-form .checks {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px;
  margin-top: 8px;
}
.s11-form .checks label {
  display: flex;
  align-items: center;
  gap: 6px;
  font-style: italic;
  font-size: 14px;
  color: var(--ink);
  background: var(--bg);
  padding: 8px 10px;
  border-radius: 10px;
  border: 1px solid var(--line);
}
.s11-form .submit-btn {
  width: 100%;
  margin-top: 12px;
  background: var(--ink);
  color: var(--bg);
  border: 1px solid rgba(17, 17, 17, 0.18);
  padding: 12px 14px;
  border-radius: 14px;
  font-family: inherit;
  font-weight: 700;
  font-size: 16px;
  cursor: pointer;
  box-shadow: none;
}

/* ==========================================================
   S12 — Branches
   ========================================================== */

.s12-mode {
  margin: 22px 20px 0;
  padding: 14px 16px;
  background: var(--surface);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 16px;
  box-shadow: none;
}
.s12-mode .top {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 4px;
}
.s12-mode .top .l {
  font-weight: 600;
  font-size: 13px;
  color: var(--ink-soft);
}
.s12-mode .top .pill {
  background: var(--accent);
  color: #fff;
  padding: 3px 9px;
  border-radius: 999px;
  font-weight: 700;
  font-size: 12px;
}
.s12-mode .name {
  font-weight: 700;
  font-size: 17px;
  letter-spacing: -0.015em;
  margin-bottom: 1px;
}
.s12-mode .desc {
  font-size: 13px;
  color: var(--ink-soft);
  line-height: 1.4;
}

.s12-add {
  margin: 14px 20px 0;
  padding: 14px 16px;
  background: var(--butter);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 16px;
  box-shadow: none;
  display: flex;
  align-items: center;
  gap: 12px;
  cursor: pointer;
  text-decoration: none;
  color: inherit;
}
.s12-add .ic {
  width: 36px;
  height: 36px;
  background: var(--ink);
  color: var(--butter);
  border-radius: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: 18px;
}
.s12-add .meta { flex: 1; line-height: 1.25; }
.s12-add .meta .h {
  font-weight: 700;
  font-size: 16px;
  letter-spacing: -0.015em;
}
.s12-add .meta .s {
  font-style: italic;
  font-weight: 400;
  font-size: 13px;
  color: var(--ink);
  opacity: 0.7;
  margin-top: 1px;
}
.s12-add .arrow { font-size: 16px; color: var(--ink); }

.s12-list-h {
  padding: 22px 20px 8px;
  font-style: italic;
  font-weight: 500;
  font-size: 15px;
  color: var(--ink);
}
.s12-branch {
  background: var(--surface);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 16px;
  box-shadow: none;
  padding: 12px 14px;
  margin: 0 20px 8px;
  display: grid;
  grid-template-columns: 36px 1fr auto;
  gap: 12px;
  align-items: center;
}
.s12-branch .num {
  width: 36px;
  height: 36px;
  background: var(--accent);
  color: #fff;
  border-radius: 10px;
  border: 1px solid rgba(17, 17, 17, 0.18);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: 15px;
}
.s12-branch.b2 .num { background: var(--butter); color: var(--ink); }
.s12-branch.b3 .num { background: var(--mint); color: var(--mint-ink); }
.s12-branch .info { line-height: 1.2; }
.s12-branch .name {
  font-weight: 700;
  font-size: 16px;
  letter-spacing: -0.015em;
  margin-bottom: 2px;
}
.s12-branch .addr {
  font-size: 13px;
  color: var(--ink-soft);
}
.s12-branch .qr-link {
  font-style: italic;
  font-weight: 500;
  font-size: 13px;
  color: var(--accent);
  text-decoration: underline;
  text-decoration-color: rgba(255, 94, 58, 0.4);
  text-underline-offset: 2px;
}

/* ==========================================================
   S5 — Issuance method toggles (multi-select per design 2026-04-26)
   ========================================================== */

.s5-toggles {
  padding: 22px 20px 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.s5-toggle-row {
  background: var(--surface);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 16px;
  padding: 12px 14px;
  display: grid;
  grid-template-columns: 40px 1fr 38px;
  gap: 12px;
  align-items: center;
  cursor: pointer;
}
.s5-toggle-row.primary {
  background: var(--bg);
  box-shadow: none;
}
.s5-toggle-row .t-icon {
  width: 40px;
  height: 40px;
  border-radius: 11px;
  background: var(--accent-soft);
  color: var(--accent);
  border: 1px solid rgba(17, 17, 17, 0.18);
  display: flex;
  align-items: center;
  justify-content: center;
}
.s5-toggle-row .t-icon svg { width: 18px; height: 18px; }
.s5-toggle-row .t-info { line-height: 1.25; min-width: 0; }
.s5-toggle-row .t-name-row {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 1px;
  flex-wrap: wrap;
}
.s5-toggle-row .t-name {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 16px;
  letter-spacing: -0.01em;
}
.s5-toggle-row .t-tag {
  font-family: 'Prompt', sans-serif;
  font-weight: 600;
  font-size: 11px;
  letter-spacing: 0.05em;
  background: var(--butter);
  color: var(--ink);
  padding: 2px 7px;
  border-radius: 999px;
  border: 1px solid rgba(17, 17, 17, 0.18);
}
.s5-toggle-row .t-sub {
  font-family: 'Prompt', sans-serif;
  font-size: 13px;
  color: var(--ink-soft);
  line-height: 1.3;
}
.s5-toggle {
  width: 38px;
  height: 22px;
  background: var(--ink-softer);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 999px;
  position: relative;
  flex-shrink: 0;
  cursor: pointer;
  transition: background 0.2s;
  justify-self: end;
}
.s5-toggle .dot {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  left: 2px;
  width: 14px;
  height: 14px;
  background: #fff;
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 50%;
  transition: left 0.2s;
}
.s5-toggle.on { background: var(--accent); }
.s5-toggle.on .dot { left: 19px; background: var(--butter); }
.s5-toggle.locked { cursor: not-allowed; opacity: 0.85; }
.s5-toggle.locked::after {
  content: '🔒';
  position: absolute;
  top: -6px;
  right: -6px;
  font-size: 11px;
  background: var(--ink);
  color: var(--butter);
  width: 14px;
  height: 14px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid rgba(17, 17, 17, 0.18);
}

/* Auto-save status pill — pinned to the bottom-right of the viewport
   so it doesn't fight the s5-toggles for space. Floats in only while
   a save is in flight or briefly after a successful one. */
.s5-autosave-status {
  position: fixed;
  bottom: 18px;
  right: 18px;
  background: var(--ink);
  color: var(--bg);
  font-family: 'Prompt', sans-serif;
  font-weight: 600;
  font-size: 12.5px;
  padding: 8px 14px;
  border-radius: 999px;
  box-shadow: 0 6px 18px -6px rgba(0, 0, 0, 0.4);
  z-index: 50;
  pointer-events: none;
}

/* Group row — drops the right toggle column so child chips can sit
   under the title. Used when one parent label gates two or more
   sub-options (ลูกค้าสแกน → Static / Dynamic). */
.s5-toggle-row.s5-group-row {
  grid-template-columns: 40px 1fr;
  align-items: start;
  cursor: default;
}
.s5-chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 8px;
}
.s5-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 12px;
  border-radius: 999px;
  background: rgba(17, 17, 17, 0.05);
  border: 1px solid rgba(17, 17, 17, 0.18);
  color: var(--ink-soft);
  font-family: 'Prompt', sans-serif;
  font-weight: 600;
  font-size: 12.5px;
  cursor: pointer;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.s5-chip:hover { color: var(--ink); }
.s5-chip.on {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
}
.s5-chip .chip-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  font-weight: 800;
  font-size: 11px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.85);
  color: var(--ink-soft);
}
.s5-chip.on .chip-mark {
  background: var(--butter);
  color: var(--ink);
}

/* ==========================================================
   S5 — Legacy issuance picker (kept for back-compat selectors)
   ========================================================== */

.s5-top .branch {
  display: flex;
  align-items: center;
  gap: 6px;
  background: var(--surface);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 999px;
  padding: 6px 12px 6px 8px;
  font-weight: 600;
  font-size: 13px;
  box-shadow: none;
}
.s5-top .branch::before {
  content: '';
  width: 6px;
  height: 6px;
  background: var(--accent);
  border-radius: 50%;
}

.s5-q {
  padding: 24px 20px 0;
  text-align: center;
}
.s5-q .ask {
  font-weight: 700;
  font-size: 26px;
  letter-spacing: -0.02em;
  line-height: 1.15;
  margin-bottom: 4px;
}
.s5-q .ask em {
  font-style: italic;
  font-weight: 700;
  color: var(--accent);
}
.s5-q .ask-th {
  font-weight: 500;
  font-size: 15px;
  color: var(--ink-soft);
}

.s5-option.primary { background: var(--ink); color: var(--bg); }
.s5-option.primary .ic-bg { background: var(--butter); color: var(--ink); }
.s5-option.primary .opt-arrow {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
}
.s5-option.primary .recommended-tag {
  position: absolute;
  top: -10px;
  right: 14px;
  transform: rotate(5deg);
  background: var(--butter);
  color: var(--ink);
  border: 1px solid rgba(17, 17, 17, 0.18);
  padding: 3px 10px;
  border-radius: 999px;
  font-weight: 700;
  font-size: 11px;
  letter-spacing: 0.06em;
}
.s5-option.primary .opt-name { color: var(--bg); }
.s5-option.primary .opt-sub { color: var(--ink-softer); }
/* "ไม่จำกัด" toggle on /shop/settings/cooldown dims the value+unit
   block while the override is on — visually communicates "this row
   is overridden" without removing the controls (so flipping unlimited
   off restores the previously chosen value). */
.s10-section.is-dim {
  opacity: 0.45;
  pointer-events: none;
}
.s10-section.is-dim button { cursor: not-allowed; }

.s5-tip {
  margin: 22px 20px 0;
  padding: 12px 14px;
  background: var(--butter-soft);
  border: 1.5px dashed var(--butter);
  border-radius: 12px;
  display: flex;
  align-items: center;
  gap: 10px;
  font-style: italic;
  font-size: 11.5px;
  color: var(--ink);
  line-height: 1.4;
}
.s5-tip .tip-bulb {
  flex-shrink: 0;
  width: 22px;
  height: 22px;
  background: var(--butter);
  color: var(--ink);
  border-radius: 50%;
  border: 1px solid rgba(17, 17, 17, 0.18);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  font-style: normal;
  font-weight: 700;
}

/* Inline phone-entry form on the issuance page */
.s5-phone-form .ok {
  background: var(--mint);
  color: var(--mint-ink);
  padding: 10px 12px;
  border-radius: 10px;
  font-size: 14px;
  text-align: center;
  margin-top: 10px;
}
.s5-phone-form .err {
  background: var(--accent-soft);
  color: var(--accent);
  padding: 10px 12px;
  border-radius: 10px;
  font-size: 14px;
  text-align: center;
  margin-top: 10px;
}

/* ==========================================================
   S2 wizard polish — back button + step counter skip
   ========================================================== */

.s2-counter .skip {
  font-weight: 500;
  font-size: 14px;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-soft);
  cursor: pointer;
  text-decoration: none;
}
.s2-foot .back {
  width: 50px;
  background: transparent;
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 14px;
  box-shadow: none;
  font-size: 16px;
  cursor: pointer;
  color: var(--ink);
  font-family: inherit;
  text-decoration: none;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* ==========================================================
   S2.1 — Branch toggle (single-branch hint, design 2026-04-26)
   ========================================================== */

.s2-branch-toggle .dot {
  position: absolute;
  top: 50%; transform: translateY(-50%);
  left: 2px;
  width: 14px; height: 14px;
  background: #fff;
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 50%;
  transition: left 0.2s;
}
.s2-branch-toggle.on { background: var(--accent); }
.s2-branch-toggle.on .dot { left: 19px; background: var(--butter); }

/* ==========================================================
   S2.2 — Reward image picker (CSS-drawn AI mockups)
   ========================================================== */

/* S2.2 reward picker — 4 inline-SVG illustrations from design (gift_box /
   card / star / coffee_cup). The old CSS-drawn brown gradients are gone. */
.s2-rewards {
  padding: 4px 20px 0;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 10px;
}
.s2-reward {
  aspect-ratio: 1;
  border-radius: 16px;
  border: 1px solid rgba(17, 17, 17, 0.18);
  background: var(--surface);
  box-shadow: none;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  padding: 0;
  appearance: none;
  -webkit-appearance: none;
}
.s2-reward.selected { transform: translateY(-2px); }
.s2-reward.selected::after {
  content: '✓';
  position: absolute;
  top: 6px;
  right: 6px;
  width: 20px;
  height: 20px;
  background: var(--accent);
  color: #fff;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  font-weight: 700;
  border: 1px solid rgba(17, 17, 17, 0.18);
  z-index: 2;
}
.s2-reward .reward-svg {
  display: block;
  width: 100%;
  height: 100%;
}

/* ==========================================================
   S2.2 — Logo picker (typography options + upload escape hatch)
   ========================================================== */

.s2-logos {
  padding: 22px 20px 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
}
.s2-logo {
  aspect-ratio: 1;
  border-radius: 16px;
  border: 1px solid rgba(17, 17, 17, 0.18);
  background: var(--surface);
  box-shadow: none;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  font-family: inherit;
}
.s2-logo.selected {
  background: var(--butter);
  transform: translateY(-2px);
}
.s2-logo.selected::after {
  content: '✓';
  position: absolute;
  top: 6px;
  right: 6px;
  width: 20px;
  height: 20px;
  background: var(--accent);
  color: #fff;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  font-weight: 700;
  border: 1px solid rgba(17, 17, 17, 0.18);
}
.s2-logo .edit-hint {
  display: none;
  position: absolute;
  bottom: 6px;
  left: 6px;
  width: 18px;
  height: 18px;
  background: rgba(17, 17, 17, 0.12);
  border-radius: 50%;
  align-items: center;
  justify-content: center;
  color: var(--ink);
  pointer-events: none;
}
.s2-logo.selected .edit-hint {
  display: flex;
}
.s2-logo .edit-hint svg {
  width: 10px;
  height: 10px;
}
/* Typography variants for the AI logo generator (PRD §6.E).
   Size-agnostic: container sets font-size, .lt-N controls family/weight/casing/colour
   so the same picked style renders consistently in the picker, on the customer
   DeeCard wordmark, and on dashboard/settings cards. */
.lt-1 { font-family: 'Host Grotesk', sans-serif; font-weight: 800; letter-spacing: -0.04em; }
.lt-1 .dot { color: var(--accent); }
.lt-2 { font-style: italic; font-weight: 700; letter-spacing: -0.02em; }
.lt-3 { font-weight: 800; letter-spacing: -0.03em; }
.lt-4 { font-family: 'Host Grotesk', sans-serif; font-weight: 700; letter-spacing: 0.18em; text-transform: uppercase; font-size: 0.7em; }
.lt-5 { font-family: 'JetBrains Mono', monospace; font-weight: 600; letter-spacing: -0.04em; color: var(--accent); }
.lt-6 { font-family: 'Host Grotesk', sans-serif; font-weight: 600; letter-spacing: -0.02em; font-size: 0.85em; }
.lt-7 { font-family: 'JetBrains Mono', monospace; font-weight: 500; letter-spacing: -0.02em; color: var(--ink-soft); font-size: 0.8em; }
.lt-8 { font-family: 'Host Grotesk', sans-serif; font-weight: 700; letter-spacing: -0.02em; color: var(--accent); }
.lt-9 { font-family: 'Host Grotesk', sans-serif; font-weight: 800; letter-spacing: -0.06em; text-transform: uppercase; }
.lt-9 .dot { color: var(--butter); }
.lt-10 { font-family: 'Host Grotesk', sans-serif; font-weight: 800; letter-spacing: -0.08em; font-style: italic; }
.lt-11 .dot { color: var(--butter); }
/* Picker tile sets the base font-size; the .lt-N classes inherit it. */
.s2-logo { font-size: 28px; }
.s2-helper {
  padding: 14px 20px 0;
  font-style: italic;
  font-weight: 500;
  font-size: 14px;
  color: var(--ink-soft);
  text-align: center;
}
.s2-helper em { color: var(--ink); font-weight: 600; }
.s2-helper .reroll {
  color: var(--accent);
  font-weight: 600;
  text-decoration: underline;
  text-decoration-color: rgba(255, 94, 58, 0.4);
  text-underline-offset: 2px;
  cursor: pointer;
}
.s2-upload {
  margin: 18px 20px 0;
  padding: 14px 16px;
  background: transparent;
  border: 1px dashed rgba(17, 17, 17, 0.3);
  border-radius: 14px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  font-size: 14px;
  font-weight: 500;
  color: var(--ink);
  cursor: pointer;
  font-family: inherit;
  text-decoration: none;
}
.s2-upload svg { width: 14px; height: 14px; }
.s2-upload.uploading {
  opacity: 0.7;
  pointer-events: none;
  border-style: solid;
  border-color: var(--accent);
  color: var(--accent);
}
.animate-spin {
  animation: s2-spin 1s linear infinite;
}
@keyframes s2-spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

/* ==========================================================
   S9 — settings/themes live preview frame.
   The preview is .s2-theme-preview with a t-{theme} modifier, so the
   four theme variants share one element but flip colors via class.
   ========================================================== */
.s9-preview-frame .s9-pf-label {
  margin: 0 18px 6px;
  font-family: 'Prompt', sans-serif;
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-softer);
}
.s2-theme-preview {
  margin: 14px 18px 0;
  border-radius: 22px;
  border: 1px solid rgba(17, 17, 17, 0.18);
  box-shadow: none;
  overflow: hidden;
  position: relative;
  transition: background 0.2s;
}
.s2-theme-preview .preview-shop {
  padding: 16px 18px 6px;
  text-align: center;
  border-bottom: 1px dashed currentColor;
  border-bottom-color: rgba(255, 255, 255, 0.15);
}
.s2-theme-preview .preview-shop-name {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 16px;
  letter-spacing: -0.02em;
  line-height: 1;
}
.s2-theme-preview .preview-shop-sub {
  font-family: 'Prompt', sans-serif;
  font-size: 9.5px;
  margin-top: 2px;
  opacity: 0.6;
}
.s2-theme-preview .preview-num {
  text-align: center;
  padding: 12px 0 4px;
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: 64px;
  letter-spacing: -0.045em;
  line-height: 1;
}
.s2-theme-preview .preview-meta {
  text-align: center;
  font-family: 'Prompt', sans-serif;
  font-style: italic;
  font-weight: 400;
  font-size: 10.5px;
  margin-bottom: 10px;
  opacity: 0.7;
}
.s2-theme-preview .preview-stamps {
  padding: 0 22px 12px;
  display: grid;
  grid-template-columns: repeat(10, 1fr);
  gap: 4px;
}
.s2-theme-preview .preview-stamps .ps {
  aspect-ratio: 1;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.1);
}
.s2-theme-preview .preview-reward {
  margin: 0 18px 14px;
  padding: 8px 12px;
  border-radius: 999px;
  text-align: center;
  font-family: 'Prompt', sans-serif;
  font-weight: 600;
  font-size: 11px;
  border: 1px dashed;
}
.s2-theme-preview.t-taemdee { background: #F6F1E5; color: #111; }
.s2-theme-preview.t-taemdee .preview-num { color: #FF5E3A; }
.s2-theme-preview.t-taemdee .preview-stamps .ps { background: rgba(17, 17, 17, 0.1); }
.s2-theme-preview.t-taemdee .preview-stamps .ps.on { background: #FF5E3A; }
.s2-theme-preview.t-taemdee .preview-stamps .ps.butter { background: #FFD952; }
.s2-theme-preview.t-taemdee .preview-reward { border-color: #FF5E3A; color: #FF5E3A; }

.s2-theme-preview.t-mono { background: #FFFFFF; color: #111; }
.s2-theme-preview.t-mono .preview-num { color: #111; }
.s2-theme-preview.t-mono .preview-stamps .ps { background: rgba(0, 0, 0, 0.08); }
.s2-theme-preview.t-mono .preview-stamps .ps.on { background: #111; }
.s2-theme-preview.t-mono .preview-stamps .ps.butter { background: #111; }
.s2-theme-preview.t-mono .preview-reward { border-color: #111; color: #111; }

.s2-theme-preview.t-night { background: #141414; color: #F6F1E5; }
.s2-theme-preview.t-night .preview-num { color: #FFD952; }
.s2-theme-preview.t-night .preview-stamps .ps { background: rgba(255, 255, 255, 0.12); }
.s2-theme-preview.t-night .preview-stamps .ps.on { background: #FFD952; }
.s2-theme-preview.t-night .preview-stamps .ps.butter { background: #FF5E3A; }
.s2-theme-preview.t-night .preview-reward { border-color: #FFD952; color: #FFD952; }

.s2-theme-preview.t-pastel { background: #FFEEE4; color: #5C2A1A; }
.s2-theme-preview.t-pastel .preview-num { color: #E87A6A; }
.s2-theme-preview.t-pastel .preview-stamps .ps { background: rgba(232, 122, 106, 0.18); }
.s2-theme-preview.t-pastel .preview-stamps .ps.on { background: #E87A6A; }
.s2-theme-preview.t-pastel .preview-stamps .ps.butter { background: #F4B583; }
.s2-theme-preview.t-pastel .preview-reward { border-color: #E87A6A; color: #E87A6A; }

.s2-theme-preview.t-sport { background: #F0FDF4; color: #052e16; }
.s2-theme-preview.t-sport .preview-num { color: #15803D; }
.s2-theme-preview.t-sport .preview-stamps .ps { background: rgba(21, 128, 61, 0.15); }
.s2-theme-preview.t-sport .preview-stamps .ps.on { background: #15803D; }
.s2-theme-preview.t-sport .preview-stamps .ps.butter { background: #BEF264; }
.s2-theme-preview.t-sport .preview-reward { border-color: #15803D; color: #15803D; }

/* ==========================================================
   S2.3 — Theme picker swatch row (lifted from the design's
   .s2-theme-swatches; the older .s2-themes / .s2-theme grid is
   gone, the new .s2-c1-preview owns the live preview)
   ========================================================== */

.s2-theme-swatches {
  margin: 16px 18px 0;
  display: flex;
  gap: 8px;
}
.s2-theme-swatch {
  flex: 1;
  cursor: pointer;
  border-radius: 12px;
  border: 1px solid rgba(17, 17, 17, 0.18);
  overflow: hidden;
  background: var(--surface);
  transition: transform 0.15s;
  appearance: none;
  -webkit-appearance: none;
  padding: 0;
  font-family: inherit;
  color: inherit;
}
.s2-theme-swatch.selected {
  transform: translateY(-3px);
  box-shadow: none;
}
.s2-theme-swatch .swatch-colors {
  height: 32px;
  display: flex;
}
.s2-theme-swatch .swatch-colors > div { flex: 1; }
.s2-theme-swatch .swatch-name {
  padding: 5px 4px 6px;
  text-align: center;
  font-family: 'Prompt', sans-serif;
  font-weight: 600;
  font-size: 12px;
  color: var(--ink);
  border-top: 1px solid var(--ink);
  background: var(--bg);
}
.s2-theme-swatch.selected .swatch-name { background: var(--butter); }


/* S2.4 — done-hero (confetti + check-mark celebration).
   Was deleted by mistake during the dead-CSS sweep — without these the
   confetti SVGs render at intrinsic size (huge) and break the page. */
.s2-done-hero {
  padding: 44px 22px 0;
  text-align: center;
  position: relative;
}
.s2-done-hero::before {
  content: '';
  position: absolute;
  top: 30px;
  left: 50%;
  transform: translateX(-50%);
  width: 240px;
  height: 240px;
  background: radial-gradient(circle, var(--butter) 0%, transparent 60%);
  opacity: 0.6;
  border-radius: 50%;
  z-index: 0;
}
.s2-done-hero > * { position: relative; z-index: 1; }
.s2-done-hero .confetti {
  position: absolute;
  color: var(--butter);
  stroke: var(--ink);
  stroke-width: 1.5;
  animation: twinkle-c 2s ease-in-out infinite;
}
.s2-done-hero .c1 { top: 50px; left: 18%;  width: 14px; height: 14px; }
.s2-done-hero .c2 { top: 80px; right: 14%; width: 12px; height: 12px; color: var(--accent); stroke: none; animation-delay: 0.6s; }
.s2-done-hero .c3 { top: 130px; left: 12%; width: 10px; height: 10px; animation-delay: 1.1s; }
.s2-done-hero .c4 { top: 60px; right: 22%; width: 10px; height: 10px; color: var(--accent); stroke: none; animation-delay: 1.6s; }
@keyframes twinkle-c {
  0%, 100% { transform: scale(1) rotate(0); }
  50% { transform: scale(1.2) rotate(20deg); }
}
.s2-done-mark {
  width: 76px;
  height: 76px;
  margin: 0 auto 20px;
  border-radius: 50%;
  background: var(--accent);
  color: #fff;
  border: 1px solid rgba(17, 17, 17, 0.18);
  box-shadow: 0 8px 20px -6px rgba(255, 94, 58, 0.5);
  display: flex;
  align-items: center;
  justify-content: center;
}
.s2-done-mark svg { width: 36px; height: 36px; }
.s2-done-title {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 28px;
  letter-spacing: -0.02em;
  line-height: 1.15;
  margin-bottom: 6px;
}
.s2-done-title em {
  font-style: italic;
  font-weight: 700;
  color: var(--accent);
}
.s2-done-sub {
  font-family: 'Prompt', sans-serif;
  font-size: 15px;
  color: var(--ink-soft);
  line-height: 1.5;
  margin-bottom: 24px;
}

/* S2 — shared real-input styling (looks like the design's faux .input.focused). */
.s2-input {
  width: 100%;
  padding: 14px 16px;
  background: var(--surface);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 14px;
  box-shadow: none;
  font-family: 'Prompt', sans-serif;
  font-size: 16px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--ink);
  -webkit-appearance: none;
  appearance: none;
  display: block;
}
.s2-input::placeholder { color: var(--ink-softer); font-weight: 400; }
.s2-input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: none;
}
/* S2.3 — Customer-view preview matching C1 (full card, not mini phone).
   Re-tinted via .theme-* class so the swatch row live-previews colors. */
.s2-c1-preview {
  margin: 8px 18px 16px;
  padding: 16px 16px 14px;
  background: var(--bg);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 22px;
  box-shadow: none;
  text-align: center;
  transition: background 0.2s, color 0.2s;
}
.s2-c1-preview .shop-head-mini {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  margin-bottom: 4px;
}
.s2-c1-preview .shop-name-mini {
  font-family: 'Prompt', sans-serif;
  font-weight: 800;
  font-size: 14px;
  color: var(--ink);
  letter-spacing: -0.01em;
  margin-top: 4px;
  line-height: 1.2;
}
.s2-c1-preview .shop-sub-mini {
  font-family: 'Prompt', sans-serif;
  font-size: 11px;
  color: var(--ink-soft);
  letter-spacing: 0.02em;
}
.s2-c1-preview .hero-num-wrap-mini { margin: 8px 0 4px; }
.s2-c1-preview .hero-label-mini {
  font-family: 'Prompt', sans-serif;
  font-size: 11px;
  color: var(--ink-soft);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  margin-bottom: 1px;
}
.s2-c1-preview .hero-num-mini {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: 56px;
  line-height: 1;
  letter-spacing: -0.04em;
  color: var(--accent);
  display: inline-flex;
  align-items: flex-start;
  gap: 4px;
}
.s2-c1-preview .mini-star-mini { width: 10px; height: 10px; color: var(--butter); margin-top: 4px; }
.s2-c1-preview .hero-num-sub-mini {
  font-family: 'Prompt', sans-serif;
  font-size: 12px;
  color: var(--ink);
  margin-top: 4px;
}
.s2-c1-preview .hero-num-sub-mini em { font-style: italic; font-weight: 700; color: var(--accent); }
.s2-c1-preview .hero-num-sub-mini .of { color: var(--ink-softer); }
.s2-c1-preview .stamps-mini {
  margin: 10px 0 12px;
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 5px;
}
.s2-c1-preview .stamps-mini .sm {
  aspect-ratio: 1;
  border: 1.5px dashed var(--ink-softer);
  border-radius: 50%;
  background: transparent;
}
.s2-c1-preview .stamps-mini .sm.on {
  background: var(--ink);
  border: 1px solid rgba(17, 17, 17, 0.18);
}
.s2-c1-preview .stamps-mini .sm.on.butter {
  background: var(--butter);
  border-color: var(--ink);
}
.s2-c1-preview .reward-pill-mini {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  background: var(--butter);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 999px;
  box-shadow: none;
  margin-top: 6px;
  text-align: left;
}
.s2-c1-preview .gift-mini {
  width: 22px;
  height: 22px;
  background: var(--ink);
  color: var(--butter);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.s2-c1-preview .gift-mini svg { width: 12px; height: 12px; }
.s2-c1-preview .rtxt-mini { flex: 1; line-height: 1.2; }
.s2-c1-preview .rlabel-mini {
  font-family: 'Prompt', sans-serif;
  font-size: 10px;
  color: var(--ink);
  opacity: 0.6;
  text-transform: uppercase;
  letter-spacing: 0.1em;
}
.s2-c1-preview .rname-mini {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 13px;
  color: var(--ink);
  margin-top: 1px;
}

/* ==========================================================
   S3.detail — Activity row detail bottom sheet (tap a feed row in
   the dock to open). CSS lifted from design/taemdee-shop.html.
   issue-modal-* uses position:fixed (design used absolute inside
   the phone-screen mockup; real app needs viewport positioning).
   ========================================================== */

.issue-modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(17, 17, 17, 0.6);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  z-index: 100;
  display: none;
}
.issue-modal-overlay.open { display: block; }
.issue-modal-sheet {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  margin: 0 auto;
  max-width: 480px;
  max-height: 90vh;
  max-height: 90dvh;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  background: var(--bg);
  border-top: 1px solid rgba(17, 17, 17, 0.18);
  border-top-left-radius: 24px;
  border-top-right-radius: 24px;
  padding: 12px 0 max(16px, env(safe-area-inset-bottom));
  z-index: 101;
  animation: issue-sheet-in 240ms cubic-bezier(.34, 1.56, .64, 1);
}
@keyframes issue-sheet-in {
  from { transform: translateY(20px); opacity: 0; }
  to { transform: translateY(0); opacity: 1; }
}
.issue-modal-handle {
  width: 38px;
  height: 4px;
  background: var(--ink-softer);
  border-radius: 999px;
  margin: 0 auto 14px;
  opacity: 0.5;
}
.issue-modal-head {
  padding: 0 20px 14px;
  border-bottom: 1px solid var(--line);
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.issue-modal-head .title {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 15px;
  letter-spacing: -0.015em;
}
.issue-modal-head .x-btn {
  width: 28px;
  height: 28px;
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 50%;
  background: var(--surface);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  cursor: pointer;
  text-decoration: none;
  color: var(--ink);
}

.detail-customer {
  margin: 14px 20px 12px;
  padding: 12px 14px;
  background: var(--surface);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 14px;
  display: flex;
  align-items: center;
  gap: 12px;
  box-shadow: none;
}
.detail-customer .dc-avatar {
  width: 40px;
  height: 40px;
  background: var(--accent);
  color: #fff;
  border-radius: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: 16px;
  flex-shrink: 0;
}
.detail-customer .dc-info { flex: 1; line-height: 1.3; }
.detail-customer .dc-name {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 14px;
  color: var(--ink);
}
.detail-customer .dc-name em {
  font-style: normal;
  color: var(--ink-soft);
  font-weight: 600;
}
.detail-customer .dc-meta {
  font-family: 'Prompt', sans-serif;
  font-size: 11px;
  color: var(--ink-soft);
  margin-top: 2px;
}
.detail-rows { margin: 0 20px 16px; }
.detail-rows .dr-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 9px 0;
  border-bottom: 1px solid var(--line);
  font-family: 'Prompt', sans-serif;
  font-size: 13px;
}
.detail-rows .dr-row:last-child { border-bottom: none; }
.detail-rows .dr-label {
  color: var(--ink-soft);
  font-size: 12px;
}
.detail-rows .dr-value {
  color: var(--ink);
  font-weight: 600;
  text-align: right;
}
.detail-rows .dr-value strong { font-weight: 700; }
.detail-rows .dr-icon {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  color: var(--accent);
}

.detail-void-row { margin: 4px 20px 0; }
.detail-void-btn {
  appearance: none;
  -webkit-appearance: none;
  width: 100%;
  padding: 12px 16px;
  background: var(--ink);
  color: var(--bg);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 14px;
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 13px;
  box-shadow: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
}
.detail-void-btn svg { width: 16px; height: 16px; }
.detail-void-btn[disabled] {
  opacity: 0.4;
  cursor: not-allowed;
  box-shadow: none;
}

/* S2.4 — final QR block + download (replaces the old customer-preview).
   The .s2-qr-svg wrapper sizes the inline segno SVG to a fixed cell. */
.s2-qr-block {
  margin: 8px 22px 20px;
}
.s2-qr-hint {
  margin-top: 10px;
  text-align: center;
  font-family: 'Prompt', sans-serif;
  font-style: italic;
  font-size: 11px;
  color: var(--ink-soft);
}

.s2-cta-final {
  margin: 0 22px 12px;
  background: var(--ink);
  color: var(--bg);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 16px;
  padding: 16px 18px;
  font-family: inherit;
  font-weight: 700;
  font-size: 17px;
  width: calc(100% - 44px);
  display: flex;
  align-items: center;
  justify-content: space-between;
  cursor: pointer;
  box-shadow: 0 10px 28px -8px rgba(17, 17, 17, 0.35);
}
.s2-cta-final .arrow {
  width: 28px;
  height: 28px;
  background: var(--accent);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-size: 16px;
}
/* ==========================================================
   S3 — Sticky bottom dock (live feed + 3 inline issuance actions)
   ========================================================== */

/* Spacer no longer needs flex: 1 — the dock is now position: fixed and
   doesn't take part in the .td flex flow, so content sits above it
   naturally with the page's padding-bottom reservation below. */
/* position:fixed (was sticky) — sticky inside .td was unreliable when
   the page scrolled (overflow-x: hidden on the parent makes .td its own
   scroll container in some browsers, so the dock would scroll out of
   view instead of pinning). Fixed always pins regardless of which
   ancestor scrolls. The dashboard reserves padding-bottom on .td-dashboard
   so content can scroll above the dock without ending up hidden under it. */
/* Sticky dock — rounded card hugging the bottom of the viewport, sits 44px
   above the .s3-footer-brand bar. Per design verbatim (taemdee-shop.html).
   Content scrolls beneath as user moves through the dashboard. */
/* Dock — design wants `position: sticky bottom: 60px` but `.td` has
   `overflow-x: hidden` which makes the browser treat it as a scroll
   container and pin the sticky element to .td's scroll instead of the
   viewport. The dashboard scrolls at the document level, so sticky-bottom
   then disappears as the page scrolls down. Use `position: fixed` — same
   visual outcome (rounded card pinned to viewport bottom) without the
   scroll-container quirk. .td-dashboard reserves space below so content
   doesn't end up hidden under the dock+brand stack. */
.td.td-dashboard { padding-bottom: 420px; }
.td.td-dashboard .s3-spacer { display: none; }
/* Footer brand bar — fixed full-width strip at the very bottom of the
   viewport. Sits below .s3-dock (which is fixed at bottom: 60px). */
.s3-footer-brand .brand {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: 15px;
  letter-spacing: -0.025em;
  color: var(--ink);
  line-height: 1;
}
.s3-footer-brand .brand .dot { color: var(--accent); }
.s3-footer-brand .fm-install {
  font-family: 'Prompt', sans-serif;
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-soft);
  display: flex;
  align-items: center;
  gap: 4px;
  text-decoration: none;
  cursor: pointer;
}
.s3-footer-brand .fm-install svg { width: 12px; height: 12px; }

/* ==========================================================
   S3.customers — Search bar + filter chips + customer list
   ========================================================== */
.s3-search-bar {
  margin: 8px 20px 12px;
  padding: 10px 14px;
  background: var(--surface);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 14px;
  display: flex;
  align-items: center;
  gap: 10px;
}
.s3-search-bar svg {
  width: 18px; height: 18px;
  color: var(--ink-softer);
  flex-shrink: 0;
}
.s3-search-bar input {
  flex: 1;
  border: none;
  background: transparent;
  outline: none;
  font-family: 'Prompt', sans-serif;
  /* 16px minimum so iOS Safari / PWA doesn't auto-zoom on focus. */
  font-size: 16px;
  color: var(--ink);
}
.s3-search-bar input::placeholder { color: var(--ink-softer); }

.s3-filter-chips {
  margin: 0 20px 16px;
  display: flex;
  gap: 6px;
  overflow-x: auto;
  overflow-y: hidden;
  padding: 4px 0;
  min-height: 42px;
  align-items: center;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.s3-filter-chips::-webkit-scrollbar { display: none; }
.s3-filter-chips .fc {
  flex-shrink: 0;
  padding: 7px 14px;
  background: var(--surface);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 999px;
  font-family: 'Prompt', sans-serif;
  font-size: 12.5px;
  font-weight: 500;
  color: var(--ink-soft);
  cursor: pointer;
  text-decoration: none;
  white-space: nowrap;
}
.s3-filter-chips .fc.active {
  background: var(--ink);
  color: var(--bg);
  border-color: var(--ink);
  font-weight: 600;
}
/* Bucket count appended to each chip label, e.g. "ลูกค้าประจำ 86" —
   smaller, dimmer than the label so it reads as metadata. */
.s3-filter-chips .fc .fc-count {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 700;
  font-size: 11px;
  color: var(--ink-softer);
  margin-left: 4px;
}
.s3-filter-chips .fc.active .fc-count { color: rgba(255,255,255,0.7); }

/* ==========================================================
   S3.customers — 4-up stats band (ทั้งหมด · ใกล้รับ · หายไป · ใหม่)
   ========================================================== */
.s3-cust-stats {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 8px;
  /* 8px top margin matches .s3-metrics on the dashboard so the
     first content block sits at the same y-coordinate across all
     dock tabs — no vertical jump when navigating between pages. */
  margin: 0px 20px 14px;
}
.s3-cust-stat {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 12px 8px 10px;
  text-align: center;
  text-decoration: none;
  color: inherit;
  display: block;
  transition: background 120ms ease, border-color 120ms ease;
}
.s3-cust-stat:active { background: var(--bg); }
.s3-cust-stat .num {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: 22px;
  line-height: 1;
  color: var(--ink);
  letter-spacing: -0.02em;
}
.s3-cust-stat .lab {
  font-family: 'Prompt', sans-serif;
  font-size: 11px;
  color: var(--ink-soft);
  margin-top: 4px;
}
.s3-cust-stat.accent .num { color: var(--accent); }
.s3-cust-stat.warn   .num { color: #B0341A; }
.s3-cust-stat.mint   .num { color: var(--mint-ink); }

/* น่าสนใจวันนี้ placeholder — keeps the layout slot reserved while
   the product angle for this section is still being figured out.
   When the real list ships, the .s3-cust-attn--coming variant goes
   away and the rows mount in the same wrapper. */
.s3-cust-attn {
  margin: 0 20px 14px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 12px 14px;
}
.s3-cust-attn-h {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.s3-cust-attn-h .lab {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 13px;
  color: var(--ink);
  letter-spacing: -0.01em;
}
/* Placeholder body shown until we have a product angle for this
   section (see git history for the recognition / outbound debate).
   Reserves a small block of vertical space so the layout stays
   stable when we swap in the real list. */
.s3-cust-attn-empty {
  margin-top: 8px;
  padding: 14px 0 4px;
  text-align: center;
  font-family: 'Prompt', sans-serif;
  font-size: 12px;
  color: var(--ink-softer);
  letter-spacing: 0.02em;
}

.s3-cust-list {
  margin: 0 20px 100px;
  /* Bordered white card per design spec — was a flat block before,
     now reads as its own surface and matches the dashboard's
     .s3-issue-feed visual treatment. */
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: 8px 14px;
}
.cust-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 0;
  border-bottom: 1px solid rgba(17, 17, 17, 0.06);
  cursor: pointer;
  text-decoration: none;
}
.cust-row:last-child { border-bottom: none; }
.cust-row .cust-avatar {
  flex-shrink: 0;
  width: 38px; height: 38px;
  border-radius: 50%;
  background: var(--accent);
  color: #FFF;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 14px;
}
.cust-row .cust-avatar.mint { background: var(--mint); color: var(--mint-ink); }
.cust-row .cust-info { flex: 1; line-height: 1.3; min-width: 0; }
.cust-row .cust-name {
  font-family: 'Prompt', sans-serif;
  font-weight: 600;
  font-size: 14.5px;
  color: var(--ink);
  margin-bottom: 2px;
  display: flex;
  align-items: center;
  gap: 8px;
}
.cust-row .cust-tag {
  font-family: 'Prompt', sans-serif;
  font-size: 10.5px;
  font-weight: 600;
  color: var(--accent);
  background: rgba(255, 94, 58, 0.1);
  padding: 2px 8px;
  border-radius: 999px;
  letter-spacing: 0;
}
.cust-row .cust-tag.soft {
  color: var(--ink-softer);
  background: rgba(17, 17, 17, 0.06);
}
/* DeeReach engagement chips — sit alongside the loyalty tag.
   "hot" = mint (replied / claimed offers), "warm" = butter
   (opened a few broadcasts). Cold customers render no chip so
   the row stays quiet. */
.cust-row .cust-tag.eng.hot {
  color: var(--mint-ink, #2a4f44);
  background: rgba(111, 168, 130, 0.18);
}
.cust-row .cust-tag.eng.warm {
  color: var(--ink);
  background: rgba(255, 217, 82, 0.45);
}
.cust-row .cust-meta {
  font-family: 'Prompt', sans-serif;
  font-size: 11.5px;
  color: var(--ink-soft);
}
.cust-row .cust-progress {
  flex-shrink: 0;
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 700;
  color: var(--ink-soft);
  text-align: right;
}
.cust-row .cust-progress .cp-num { font-size: 17px; color: var(--ink); }
.cust-row .cust-progress .cp-of { font-size: 12px; color: var(--ink-softer); }
.cust-row .cust-progress.accent .cp-num { color: var(--accent); }
.cust-row .cust-progress.claimed {
  font-family: 'Prompt', sans-serif;
  font-size: 12px;
  font-weight: 600;
  color: var(--mint-ink);
}
.cust-row .cust-arrow {
  color: var(--ink-softer);
  font-size: 22px;
  flex-shrink: 0;
}

/* ==========================================================
   S3.customers detail — /shop/customers/{id}
   Header card with avatar + progress bar, stat strip,
   activity timeline. Matches the bordered-surface treatment
   of .s3-cust-list and .s3-issue-feed elsewhere on shop side.
   ========================================================== */
.cd-card,
.cd-activity {
  margin: 8px 20px 14px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: 16px 16px 14px;
}
.cd-activity { padding: 14px 16px 8px; margin-bottom: 100px; }

.cd-head {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 16px;
}
.cd-avatar {
  flex-shrink: 0;
  width: 52px; height: 52px;
  border-radius: 50%;
  background: var(--accent);
  color: #FFF;
  display: flex; align-items: center; justify-content: center;
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 20px;
}
.cd-avatar.mint { background: var(--mint); color: var(--mint-ink); }
.cd-id { flex: 1; min-width: 0; }
.cd-name {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 17px;
  color: var(--ink);
  letter-spacing: -0.01em;
  margin-bottom: 2px;
}
.cd-meta {
  font-family: 'Prompt', sans-serif;
  font-size: 12px;
  color: var(--ink-soft);
}
.cd-pill {
  flex-shrink: 0;
  font-family: 'Prompt', sans-serif;
  font-weight: 600;
  font-size: 11.5px;
  padding: 5px 10px;
  border-radius: 99px;
}
.cd-pill.ready {
  color: var(--accent);
  background: var(--accent-soft);
}
.cd-pill.claimed {
  color: var(--mint-ink);
  background: var(--mint);
}

.cd-progress {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 18px;
}
.cd-progress-bar {
  flex: 1;
  height: 8px;
  background: rgba(17, 17, 17, 0.06);
  border-radius: 99px;
  overflow: hidden;
}
.cd-progress-fill {
  height: 100%;
  background: var(--accent);
  border-radius: 99px;
  transition: width 240ms ease;
}
.cd-progress-num {
  flex-shrink: 0;
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 700;
}
.cd-progress-num .cp-num { font-size: 18px; color: var(--ink); }
.cd-progress-num .cp-of { font-size: 12px; color: var(--ink-softer); }

.cd-stats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px;
}
.cd-stat {
  text-align: center;
  padding: 10px 4px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 12px;
}
.cd-stat .num {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: 18px;
  line-height: 1.1;
  color: var(--ink);
  letter-spacing: -0.02em;
}
.cd-stat .lab {
  font-family: 'Prompt', sans-serif;
  font-size: 10.5px;
  color: var(--ink-soft);
  margin-top: 4px;
}

/* Generic list-card wrapper for the customer detail page —
   reused by both รางวัลล่าสุด (gifts) and ออกแต้มล่าสุด (points).
   Same surface treatment as .s3-cust-list / .s3-issue-feed so all
   three list cards on the customer detail look uniform. */
.cd-list {
  margin: 0 20px 14px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: 8px 16px 12px;
}

/* Individual gift row inside .cd-list. Bordered between rows like
   .cust-row; last row drops the divider. */
.cd-gift {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 0;
  border-bottom: 1px solid rgba(17, 17, 17, 0.04);
}
.cd-gift:last-child { border-bottom: none; }
.cd-gift-icon {
  flex-shrink: 0;
  width: 40px; height: 40px;
  border-radius: 12px;
  background: var(--accent-soft);
  color: var(--accent);
  display: flex; align-items: center; justify-content: center;
}
.cd-gift-icon.served {
  background: var(--mint);
  color: var(--mint-ink);
}
.cd-gift-icon svg { width: 22px; height: 22px; }
.cd-gift-icon img { width: 28px; height: 28px; object-fit: cover; border-radius: 8px; }
.cd-gift-info { flex: 1; min-width: 0; line-height: 1.3; }
.cd-gift-reward {
  font-family: 'Prompt', sans-serif;
  font-weight: 600;
  font-size: 14px;
  color: var(--ink);
  letter-spacing: -0.01em;
  margin-bottom: 3px;
}
.cd-gift-meta {
  font-family: 'Prompt', sans-serif;
  font-size: 11.5px;
  color: var(--ink-soft);
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}
.cd-gift-status {
  font-weight: 700;
  font-size: 11px;
  padding: 2px 8px;
  border-radius: 99px;
}
.cd-gift-status.ready {
  color: var(--accent);
  background: var(--accent-soft);
}
.cd-gift-status.used {
  color: var(--mint-ink);
  background: var(--mint);
}

.cd-activity-h {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0 2px 8px;
  border-bottom: 1px solid var(--line);
  margin-bottom: 4px;
}
.cd-activity-h .lab {
  font-family: 'Prompt', sans-serif;
  font-style: italic;
  font-weight: 500;
  font-size: 13px;
  color: var(--ink);
}
.cd-activity-h .count {
  font-family: 'Prompt', sans-serif;
  font-size: 12px;
  color: var(--ink-softer);
}
.cd-act-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 0;
  border-bottom: 1px solid rgba(17, 17, 17, 0.04);
}
.cd-act-row:last-child { border-bottom: none; }
.cd-act-icon {
  flex-shrink: 0;
  width: 32px; height: 32px;
  border-radius: 10px;
  display: flex; align-items: center; justify-content: center;
}
.cd-act-icon.point { background: var(--accent-soft); color: var(--accent); }
.cd-act-icon.redemption { background: var(--mint); color: var(--mint-ink); }
.cd-act-icon svg { width: 16px; height: 16px; }
.cd-act-info { flex: 1; min-width: 0; }
.cd-act-label {
  font-family: 'Prompt', sans-serif;
  font-weight: 600;
  font-size: 13px;
  color: var(--ink);
}
.cd-act-time {
  font-family: 'Prompt', sans-serif;
  font-size: 11px;
  color: var(--ink-softer);
  margin-top: 1px;
}
.cd-empty {
  padding: 18px 12px;
  text-align: center;
  font-family: 'Prompt', sans-serif;
  font-size: 12px;
  color: var(--ink-softer);
}

/* Customer detail · broadcast-engagement timeline (phase 5).
   Mirrors .cd-act-row chrome so the engagement section reads as a
   sibling of "ออกแต้มล่าสุด" / "รางวัลล่าสุด". Per-kind icon tint
   matches the chip palette used on /shop/customers + the campaign
   stats page so a customer's engagement signal is the same colour
   wherever it surfaces. */
.cd-engagement {
  margin-top: 18px;
}
.cd-eng-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 0;
  border-bottom: 1px solid rgba(17, 17, 17, 0.04);
}
.cd-eng-row:last-child { border-bottom: none; }
.cd-eng-icon {
  flex-shrink: 0;
  width: 32px; height: 32px;
  border-radius: 10px;
  display: flex; align-items: center; justify-content: center;
  background: rgba(17,17,17,0.05);
  color: var(--ink-softer);
}
.cd-eng-icon.opened          { background: rgba(255, 217, 82, 0.45); color: var(--ink); }
.cd-eng-icon.replied         { background: rgba(111, 168, 130, 0.20); color: var(--mint-ink, #2a4f44); }
.cd-eng-icon.voucher_claimed { background: rgba(255, 94, 58, 0.12);  color: var(--accent); }
.cd-eng-icon svg { width: 16px; height: 16px; }
.cd-eng-info { flex: 1; min-width: 0; }
.cd-eng-label {
  font-family: 'Prompt', sans-serif;
  font-weight: 600;
  font-size: 13px;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cd-eng-time {
  font-family: 'Prompt', sans-serif;
  font-size: 11px;
  color: var(--ink-softer);
  margin-top: 1px;
}
.cd-eng-link {
  flex-shrink: 0;
  font-family: 'Prompt', sans-serif;
  font-size: 18px;
  color: var(--ink-softer);
  text-decoration: none;
  padding: 4px 6px;
}
/* Tier badge in the section header — same palette as the customers
   list chip so the operator pattern-matches the colour even before
   reading the label. */
.cd-eng-badge {
  display: inline-block;
  padding: 1px 7px;
  border-radius: 99px;
  font-family: 'Prompt', sans-serif;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.02em;
}
.cd-eng-badge.hot  { background: rgba(111, 168, 130, 0.18); color: var(--mint-ink, #2a4f44); }
.cd-eng-badge.warm { background: rgba(255, 217, 82, 0.45); color: var(--ink); }
.cd-eng-badge.cold { background: rgba(17,17,17,0.06); color: var(--ink-softer); }
/* Activity pager — sits below the activity rows. Disabled state
   (already on first/last page) keeps the same footprint so the
   pager doesn't reflow when toggling between pages. */
.cd-pager {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-top: 12px;
  padding: 10px 0 4px;
  border-top: 1px solid var(--line);
}
.cd-pager-btn {
  font-family: 'Prompt', sans-serif;
  font-weight: 600;
  font-size: 12px;
  color: var(--accent);
  text-decoration: none;
  padding: 6px 10px;
  border-radius: 8px;
  transition: background 120ms ease;
}
.cd-pager-btn:active { background: var(--accent-soft); }
.cd-pager-btn.disabled {
  color: var(--ink-softer);
  opacity: 0.5;
  pointer-events: none;
}
.cd-pager-info {
  font-family: 'Prompt', sans-serif;
  font-size: 11.5px;
  color: var(--ink-soft);
}

/* Tabbed layouts (customers / insights / etc.) reserve room at the bottom
   for the floating glass nav. */
.td.td-tabbed { padding-bottom: 112px; }

/* ==========================================================
   Pinned-page layout — opt-in via .td-pinned. Locks the page to
   the dynamic viewport so nothing scrolls at the document level,
   and the .page-scroll child becomes the only scroll container
   bounded above the floating glass-nav. iOS PWA safe-area is
   added on top of the standard 112px dock zone so the home
   indicator is also clear. Used on /shop/dashboard, /shop/messages
   and /shop/settings — pages where the dock and a pinned bottom
   element should both stay visible at all times.
   ========================================================== */
html:has(.td-pinned),
body:has(.td-pinned) {
  height: 100dvh;
  overflow: hidden;
  margin: 0;
}
.td.td-pinned {
  height: 100dvh;
  max-height: 100dvh;
  overflow: hidden;
}
.td.td-pinned.td-tabbed {
  padding-bottom: calc(env(safe-area-inset-bottom, 0px) + 112px);
}
/* Dashboard / issue page: the .s3-issue-actions card is fixed at
   bottom: 104px above the dock. On wide phones it's a single-row
   4-col grid (~99px tall, top at ~203px from viewport bottom). On
   narrow phones (<=380px) it falls back to 2x2 and grows to ~160px
   (top at ~264px). Reserve enough room for each width — too much
   padding eats the activity feed's scroll area. */
.td.td-pinned.td-tabbed.td-issue {
  padding-bottom: calc(env(safe-area-inset-bottom, 0px) + 215px);
}
@media (max-width: 380px) {
  .td.td-pinned.td-tabbed.td-issue {
    padding-bottom: calc(env(safe-area-inset-bottom, 0px) + 280px);
  }
}
.td.td-pinned .page-scroll {
  flex: 1 1 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  background: transparent;
  /* 12px each side mirrors the dock's max-width: calc(100% - 24px)
     + margin: 0 auto, so every direct child's outer edge lines up
     with the floating glass-nav below. */
  padding-left: 12px;
  padding-right: 12px;
}
/* Reset any per-card horizontal margin so the .page-scroll padding
   above is what defines the gutter — keeps every direct child's
   outer edge flush at 12px from the viewport. */
.td.td-pinned .page-scroll > * {
  margin-left: 0;
  margin-right: 0;
}
/* Top nav (s3_top) sits outside .page-scroll but should match the
   same 12px gutter so the header reads as part of the same column
   as the cards below + the dock at the bottom. */
.td.td-pinned .s3-top {
  padding-left: 12px;
  padding-right: 12px;
}

/* ==========================================================
   S3 — Home dashboard: merged metrics card (time pills + hero + trend
   + sub) per design rev — replaces 3 separate cards with one container.
   ========================================================== */
.s3-metrics {
  padding: 10px 20px 0px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 18px;
}
.s3-metrics .met-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 14px;
}
.s3-metrics .met-title {
  font-family: 'Prompt', sans-serif;
  font-size: 13px;
  font-weight: 500;
  color: var(--ink-soft);
}
.s3-metrics .met-pills, .met-pills.issue-feed-pills {
  display: flex;
  gap: 12px;
}
.s3-metrics .met-pills .mp, .met-pills.issue-feed-pills .mp {
  padding: 2px 0;
  font-family: 'Prompt', sans-serif;
  font-size: 12px;
  font-weight: 500;
  color: var(--ink-softer);
  cursor: pointer;
  text-decoration: none;
  transition: all 0.15s ease;
  position: relative;
}
.s3-metrics .met-pills .mp.active, .met-pills.issue-feed-pills .mp.active {
  color: var(--ink);
  font-weight: 700;
}
.s3-metrics .met-pills .mp.active::after, .met-pills.issue-feed-pills .mp.active::after {
  content: '';
  position: absolute;
  bottom: -2px; left: 0; right: 0;
  height: 2px;
  background: var(--accent);
  border-radius: 1px;
}
.s3-metrics .met-pills .mp[aria-disabled="true"], .met-pills.issue-feed-pills .mp[aria-disabled="true"] {
  opacity: 0.5;
  pointer-events: none;
}
.s3-metrics .met-num-row {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 16px;
}
.s3-metrics .met-num {
  display: flex;
  align-items: baseline;
  gap: 6px;
}
.s3-metrics .met-num .num-big {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: 56px;
  line-height: 1;
  color: var(--ink);
  letter-spacing: -0.04em;
}
.s3-metrics .met-num .num-unit {
  font-family: 'Prompt', sans-serif;
  font-size: 16px;
  font-weight: 500;
  color: var(--ink-soft);
}
.s3-metrics .met-delta {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  line-height: 1.3;
  padding-bottom: 1px;
}
/* delta == 0 → still occupies space (preserves .met-num-row height
   so the chart below doesn't shift between periods) but invisible. */
.s3-metrics .met-delta.met-delta--empty { visibility: hidden; }
.s3-metrics .met-delta .delta-arr,
.s3-metrics .met-delta .delta-num {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 700;
}
.s3-metrics .met-delta .delta-arr { font-size: 16px; }
.s3-metrics .met-delta .delta-num { font-size: 18px; }
.s3-metrics .met-delta.up .delta-arr,
.s3-metrics .met-delta.up .delta-num { color: #2D8050; }
.s3-metrics .met-delta.down .delta-arr,
.s3-metrics .met-delta.down .delta-num { color: var(--accent); }
.s3-metrics .met-delta .delta-from {
  font-family: 'Prompt', sans-serif;
  font-size: 11px;
  color: var(--ink-softer);
  margin-top: 2px;
}
/* Chart sits in its own bordered card so it reads as a distinct
   block from the headline number + delta above. The card's own
   padding gives the rotated tb-num labels (which extend up above
   row 1 of each bar's grid) clear space inside the card instead
   of bleeding past the edge. */
.s3-metrics .met-trend {
  margin-top: 14px;
  margin-bottom: 14px;
  padding: 16px 14px 12px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 12px;
}
.s3-metrics .met-trend .trend-legend {
  display: flex;
  gap: 14px;
  margin-bottom: 30px;
}
.s3-metrics .met-trend .trend-legend .lg-item {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-family: 'Prompt', sans-serif;
  font-size: 11px;
  color: var(--ink-soft);
}
.s3-metrics .met-trend .trend-legend .lg-dot {
  width: 10px;
  height: 10px;
  border-radius: 2px;
}
.s3-metrics .met-trend .trend-legend .lg-dot.scan { background: var(--accent); }
.s3-metrics .met-trend .trend-legend .lg-dot.redeem { background: var(--ink); }
.s3-metrics .met-trend .trend-bars {
  display: grid;
  /* Column count adapts to the active period: 7 (today/week) or 12
     (month). Template sets --cols inline so the grid spans the full
     card width regardless of bucket count. minmax(0, 1fr) lets the
     bars shrink below their content (number labels) without
     overflowing the row. */
  grid-template-columns: repeat(var(--cols, 7), minmax(0, 1fr));
  width: 100%;
  gap: 6px;
  align-items: end;
  /* Taller chart so the bars have visible delta even on slow days,
     and so the new "DD เดือน-abbrev" x-axis labels (today/week
     periods) get a comfortable line of breathing room under the
     bars. Total split: 16px label band on top (number) + ~ 100px
     bar zone + 12px x-axis label band at the bottom. */
  height: 132px;
}
/* When the chart compresses to 12 columns (month period), drop the
   gap and label font so the day-of-month numbers don't visually
   collide with each other. Same shrink for week period — its labels
   carry "DD เดือน" (e.g. 23 มี.ค.) which is wider than today's
   single-letter day abbrevs. */
.s3-metrics .met-trend .trend-bars[data-cols="12"] { gap: 3px; }
.s3-metrics .met-trend .trend-bars[data-cols="12"] .tb-num,
.s3-metrics .met-trend .trend-bars[data-cols="12"] .tb-day {
  /* 12-col month chart on phones is genuinely tight (~22px per
     column). Smaller font + tighter letter spacing so 4-char Thai
     month abbrevs ("ก.ย.") fit one line per cell. */
  font-size: 8.5px;
  letter-spacing: -0.04em;
}
.s3-metrics .met-trend .trend-bars[data-period="today"] .tb-day,
.s3-metrics .met-trend .trend-bars[data-period="week"] .tb-day {
  font-size: 9.5px;
}
.s3-metrics .met-trend .tb {
  /* 3-row grid with FIXED top/bottom row heights so the bar's top
     never slides — every column reserves the same band for the
     number above and the date below regardless of label content
     ("5" vs "5/2", "พ.ค." vs "23 มี.ค."). Row 2 (1fr) is the bar
     zone; the bar pins to the bottom via align-self: end. */
  display: grid;
  grid-template-rows: 14px 1fr 14px;
  justify-items: center;
  row-gap: 3px;
  height: 100%;
  min-width: 0;
}
.s3-metrics .met-trend .tb-num,
.s3-metrics .met-trend .tb-day {
  align-self: center;
  max-width: 100%;
  white-space: nowrap;
}
/* Day labels stay clipped to the column — they live in the bottom
   lane where there's no spare space, so a wide label would push
   the cell wider. */
.s3-metrics .met-trend .tb-day {
  overflow: hidden;
  text-overflow: clip;
}
/* Numbers above the bar are rotated and extend upward into empty
   space above the chart, so we deliberately allow overflow here —
   clipping would chop off the rotated digits. */
.s3-metrics .met-trend .tb-num { overflow: visible; }
.s3-metrics .met-trend .tb .tb-bar { align-self: end; }
.s3-metrics .met-trend .tb-num {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 700;
  font-size: 11px;
  letter-spacing: -0.02em;
  color: var(--accent);
  line-height: 1;
  /* Slight tilt so wider numbers ("127/3") extend diagonally instead
     of bleeding into the neighbouring column on dense 12-col charts.
     transform-origin: bottom-left pivots from the bar's top-left
     corner so the number reads upward-and-right from where the bar
     ends — and the .trend-bars row has no overflow clip so it can
     extend slightly above the chart's top edge. */
  transform: rotate(-25deg);
  transform-origin: bottom left;
  white-space: nowrap;
}
.s3-metrics .met-trend .tb-num.muted { color: var(--ink-softer); }
.s3-metrics .met-trend .tb-num-redeem {
  color: var(--ink);
  font-weight: 700;
  margin-left: 1px;
}
.s3-metrics .met-trend .tb .tb-bar {
  width: 100%;
  background: var(--accent);
  border-radius: 4px 4px 2px 2px;
  min-height: 8px;
  position: relative;
  overflow: hidden;
}
/* Redemption overlay sits at the bottom of the bar — its inline
   `height` is a percentage OF the parent .tb-bar (i.e. share of that
   day's stamps that were redemptions). Grows up from the floor. */
.s3-metrics .met-trend .tb .tb-bar .tb-redeem {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  background: var(--ink);
  border-radius: 0 0 2px 2px;
}
.s3-metrics .met-trend .tb .tb-day {
  font-family: 'Prompt', sans-serif;
  font-size: 10.5px;
  color: var(--ink-softer);
  line-height: 1;
}
.s3-metrics .met-sub {
  padding-top: 12px;
  font-family: 'Prompt', sans-serif;
  font-style: italic;
  font-size: 13px;
  color: var(--ink-soft);
}
.s3-metrics .met-sub strong {
  color: var(--ink);
  font-weight: 700;
}

/* Legacy s3-time-pills, s3-snapshot, s3-trend kept below for any caller
   that still uses them (none in the current dashboard, but the styles
   stay until we audit other pages). */
.s3-time-pills .tp.active {
  background: var(--ink);
  color: var(--bg);
  font-weight: 700;
}
.s3-snapshot .snap-num .num-big {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: 56px;
  line-height: 1;
  color: var(--ink);
  letter-spacing: -0.04em;
}
.s3-snapshot .snap-num .num-unit {
  font-family: 'Prompt', sans-serif;
  font-size: 16px;
  font-weight: 500;
  color: var(--ink-soft);
}
.s3-snapshot .snap-delta .delta-arr,
.s3-snapshot .snap-delta .delta-num {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 700;
  color: var(--mint-ink);
}
.s3-snapshot .snap-delta .delta-arr { font-size: 16px; }
.s3-snapshot .snap-delta .delta-num { font-size: 18px; }
.s3-snapshot .snap-delta.up .delta-arr,
.s3-snapshot .snap-delta.up .delta-num { color: #2D8050; }
.s3-snapshot .snap-delta.down .delta-arr,
.s3-snapshot .snap-delta.down .delta-num { color: var(--accent); }
.s3-snapshot .snap-delta .delta-from {
  font-family: 'Prompt', sans-serif;
  font-size: 11px;
  color: var(--ink-softer);
  margin-top: 2px;
}
.s3-trend .trend-bars {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 6px;
  align-items: end;
  height: 80px;
}
.s3-trend .tb {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  height: 100%;
  justify-content: flex-end;
}
.s3-trend .tb .tb-bar {
  width: 100%;
  background: linear-gradient(180deg, var(--accent) 0%, #FF8559 100%);
  border-radius: 6px 6px 2px 2px;
  min-height: 8px;
  transition: opacity 0.2s ease;
}
/* Last two bars (today, yesterday) get the dark gradient — visually anchors
   the "now" end of the chart. */
.s3-trend .tb:nth-last-child(-n+2) .tb-bar {
  background: linear-gradient(180deg, var(--ink) 0%, #333 100%);
}
.s3-trend .tb .tb-day {
  font-family: 'Prompt', sans-serif;
  font-size: 10.5px;
  color: var(--ink-softer);
  line-height: 1;
}

.s3-attn.warn .attn-icon { background: var(--accent); color: #FFF; }
.s3-attn.opp .attn-icon { background: var(--butter); color: var(--ink); }
.s3-attn.ai .attn-icon {
  background: linear-gradient(135deg, var(--accent) 0%, var(--butter) 100%);
  color: #FFF;
}
.s3-attn .attn-h {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 14px;
  color: var(--ink);
  margin-bottom: 2px;
}
/* Notification bell (top-right) — circular chrome that matches the
   customer-side .ph-icon-btn, so the two sides feel like the same
   product. Settings cog dropped in the 2026-05-04 dock rework. */
.s3-top .bell-btn {
  width: 44px;
  height: 44px;
  background: rgba(17, 17, 17, 0.05);
  color: var(--ink);
  border: none;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  text-decoration: none;
  flex-shrink: 0;
  position: relative;
}
.s3-top .bell-btn svg { width: 22px; height: 22px; }
.s3-top .bell-btn:active { transform: scale(0.92); }
.s3-top .bell-btn .bell-badge {
  position: absolute;
  top: 8px; right: 7px;
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 2px var(--bg);
}
/* Numeric variant — when the badge has a count to show, expand to a
   pill shape with the number centred. The dot styling above stays as
   a fallback for callers that just want unread-yes/no. */
.s3-top .bell-btn .bell-badge.has-count {
  top: 4px; right: 4px;
  min-width: 16px; height: 16px;
  width: auto;
  border-radius: 999px;
  padding: 0 4px;
  color: #fff;
  font-family: 'Prompt', sans-serif;
  font-size: 10px;
  font-weight: 700;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
}
/* Shop-side avatar in the s3-top action row — mirrors .page-head
   .ph-avatar from the customer side. Image variant of the shop logo
   if uploaded, otherwise the shop's first character on accent. Tap
   navigates to the full identity editor at /shop/settings/identity. */
.s3-top .s3-avatar {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 0;
  background: var(--accent);
  color: #fff;
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  text-decoration: none;
  overflow: hidden;
  flex-shrink: 0;
}
.s3-top .s3-avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.s3-top .s3-avatar:active { transform: scale(0.94); }

/* Day-caption row — moved out of .s3-top so the header line stays clean
   (greeting + actions only). The "วันศุกร์ · เริ่มต้นวันได้ดี" text plus
   branch pill live here on every S3.* page. */
.s3-day-caption {
  margin: 6px 20px 8px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}
.s3-day-caption .dc-text {
  font-family: 'Prompt', sans-serif;
  font-size: 13px;
  color: var(--ink-soft);
  font-style: italic;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.s3-day-caption .dc-text .smile-inline {
  width: 16px;
  height: 9px;
  color: var(--accent);
  font-style: normal;
}
.s3-day-caption .branch-pill {
  display: flex;
  align-items: center;
  gap: 6px;
  background: var(--surface);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 999px;
  padding: 6px 12px 6px 8px;
  font-family: 'Prompt', sans-serif;
  font-weight: 600;
  font-size: 11px;
  text-decoration: none;
  color: var(--ink);
}
.s3-day-caption .branch-pill::before {
  content: '';
  width: 6px;
  height: 6px;
  background: var(--accent);
  border-radius: 50%;
}
/* Back nav inside s3-day-caption (used on insights/history). */
.s3-day-caption .dc-back {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: 'Prompt', sans-serif;
  font-size: 13.5px;
  font-weight: 700;
  color: var(--ink);
  cursor: pointer;
  text-decoration: none;
}
.s3-day-caption .dc-back svg {
  width: 16px;
  height: 16px;
  color: var(--ink);
}

/* Dashboard "รายการที่ต้องทำ" tile — butter-soft surface, no leading
   icon, accent-orange pill CTA on the right. Title supports inline
   <strong> for the highlight ("รับ<strong>เครดิต 100</strong>
   เปิดบัญชี"). The whole card (main action + skip row) lives inside
   one .s3-todo-wrap so the dismissal feels like part of the same
   tile, not a footnote underneath it. */
.s3-todo-wrap {
  margin: 0 20px 12px;
  background: var(--butter-soft);
  border: 1px solid rgba(17, 17, 17, 0.10);
  border-radius: 16px;
  overflow: hidden;
  transition: opacity 220ms ease, max-height 260ms ease,
              margin 260ms ease, padding 260ms ease, border-width 260ms ease;
  max-height: 320px;
}
/* Click on the main action OR the skip button collapses the wrap so
   the owner sees immediate feedback while the underlying form POST
   or link navigation runs in parallel. */
.s3-todo-wrap.s3-todo-wrap--out {
  opacity: 0;
  max-height: 0;
  margin-top: 0;
  margin-bottom: 0;
  border-width: 0;
  pointer-events: none;
}
.s3-todo-wrap .s3-item-form { margin: 0; }
/* Skip row sits inside the box, separated from the main action by a
   dashed divider. The button is a small underlined affordance; the
   brief explainer beside it tells the owner what they're giving up
   so the dismissal feels informed. */
.s3-todo-skip {
  margin: 0;
  padding: 8px 14px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  flex-wrap: wrap;
  border-top: 1px dashed rgba(17, 17, 17, 0.12);
  background: var(--surface)
}
.s3-skip-btn {
  background: transparent;
  border: none;
  padding: 0;
  color: var(--ink-soft);
  font-family: 'Prompt', sans-serif;
  font-weight: 600;
  font-size: 12px;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 2px;
}
.s3-skip-btn:hover { color: var(--ink); }
.s3-skip-explain {
  color: var(--ink-softer);
  font-family: 'Prompt', sans-serif;
  font-style: italic;
  font-size: 11px;
  text-align: center;
}
.s3-todo {
  /* Inner button — no own background / border / radius now that the
     wrap supplies them. Keeps padding so the click target still feels
     comfortable. */
  margin: 0;
  padding: 14px 16px;
  background: transparent;
  border: none;
  border-radius: 0;
  display: flex;
  align-items: center;
  gap: 12px;
  cursor: pointer;
  text-decoration: none;
  color: var(--ink);
  appearance: none;
  -webkit-appearance: none;
  width: 100%;
  text-align: left;
  font-family: 'Prompt', sans-serif;
}
.s3-todo:active { transform: scale(0.99); }
.s3-todo .td-info { flex: 1; min-width: 0; line-height: 1.3; }
.s3-todo .td-info .td-h {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 13.5px;
  color: var(--ink);
}
.s3-todo .td-info .td-h strong {
  color: var(--accent);
  font-weight: 800;
}
.s3-todo .td-info .td-s {
  font-family: 'Prompt', sans-serif;
  font-size: 11.5px;
  color: var(--ink-soft);
  margin-top: 2px;
}
.s3-todo .td-cta {
  flex-shrink: 0;
  background: var(--accent);
  color: #fff;
  padding: 7px 14px;
  border-radius: 99px;
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 12px;
  border: none;
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

/* Section-header count badge — "รายการที่ต้องทำ N" pill. */
.ph-section-h .todo-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 20px;
  padding: 0 6px;
  background: var(--accent);
  color: #fff;
  border-radius: 99px;
  font-family: 'Prompt', sans-serif;
  font-style: normal;
  font-weight: 700;
  font-size: 11px;
  margin-left: 8px;
}

/* ==========================================================
   S3.issue — full-page ออกแต้ม hub: feed + 3 action buttons
   ========================================================== */
.s3-issue-feed {
  /* 8px top matches .s3-metrics + .s3-search-bar so the tab content
     starts at the same Y after the shared s3-day-caption. */
  margin: 8px 20px 16px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: 8px 14px;
}
/* Inline header inside the feed card — "ลูกค้าล่าสุด" label on the
   left, ทั้งหมด/สแกน/แลก pills on the right, hairline separator below.
   Replaces the older standalone .ph-section-h pattern that left the
   pills outside the card. */
/* if-head — list-card header with bucket label (left) + total count
   (right). Used by both the issue feed and the customers list. */
.s3-issue-feed .if-head,
.s3-cust-list .if-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 6px 2px 10px;
  border-bottom: 1px solid var(--line);
  margin-bottom: 4px;
}
.s3-issue-feed .if-head .if-label,
.s3-cust-list .if-head .if-label {
  font-family: 'Prompt', sans-serif;
  font-style: italic;
  font-weight: 500;
  font-size: 13px;
  color: var(--ink);
}
.s3-cust-list .if-head .if-count {
  font-family: 'Prompt', sans-serif;
  font-size: 12px;
  color: var(--ink-softer);
  letter-spacing: 0.02em;
}
.s3-issue-feed .sap-table {
  width: 100%;
  border-collapse: collapse;
}
.s3-issue-feed .sap-table thead th {
  text-align: left;
  font-family: 'Prompt', sans-serif;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--ink-softest);
  padding: 8px 0;
  border-bottom: 1px solid rgba(17, 17, 17, 0.08);
}
.s3-issue-feed .sap-table thead th.a {
  text-align: right;
}
.s3-issue-feed .sap-table td {
  padding: 8px 0;
  font-family: 'Prompt', sans-serif;
  font-size: 13px;
  border-bottom: 1px solid rgba(17, 17, 17, 0.06);
}
.s3-issue-feed .sap-table tr:last-child td { border-bottom: none; }
.s3-issue-feed .sap-table td.t {
  font-family: 'Prompt', sans-serif;
  font-size: 12px;
  color: var(--ink-softer);
  white-space: nowrap;
  padding-right: 10px;
}
.s3-issue-feed .sap-table td.n { font-weight: 600; color: var(--ink); }
.s3-issue-feed .sap-table td.m,
.s3-issue-feed .sap-table td.s {
  font-size: 12px;
  color: var(--ink-soft);
}
.s3-issue-feed .sap-table td.a {
  text-align: right;
  font-size: 12px;
  color: var(--ink-soft);
}
.s3-issue-feed .sap-table tr.latest td { color: var(--accent); }
.s3-issue-feed .sap-table tr.latest td.n {
  color: var(--accent);
  font-weight: 700;
}
.s3-issue-feed .sap-table .icon-mini {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: 14px;
}
.s3-issue-feed .sap-table tr.feed-row { cursor: pointer; }

/* Action buttons container — bottom of S3.issue page */
/* Sticky-bottom action card — stays above .s3-glass-nav so the shop owner
   can issue points without scrolling, even with a long ลูกค้าล่าสุด list.
   Per memory: .td has overflow-x:hidden so position:sticky breaks; ship
   position:fixed even though design uses margin-top:auto push. */
.s3-issue-actions {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 104px;
  z-index: 5;
  margin: 0 auto;
  max-width: calc(100% - 24px);
  padding: 12px 12px 12px;
  border-radius: 24px;
  /* Liquid glass — matches the dock chassis below it so the two
     floating layers read as a coherent stack of polished surfaces. */
  background: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.62) 0%,
    rgba(255, 245, 230, 0.48) 55%,
    rgba(246, 241, 229, 0.62) 100%
  );
  backdrop-filter: blur(28px) saturate(200%);
  -webkit-backdrop-filter: blur(28px) saturate(200%);
  border: 1px solid rgba(255, 255, 255, 0.65);
  box-shadow:
    inset 0 1.5px 0 rgba(255, 255, 255, 0.9),
    inset 0 -1px 0 rgba(17, 17, 17, 0.06),
    inset 0 0 22px rgba(255, 217, 82, 0.10),
    0 14px 40px -12px rgba(17, 17, 17, 0.24),
    0 4px 14px -4px rgba(17, 17, 17, 0.10);
  isolation: isolate;
}
/* Specular top highlight — same trick as the dock so the wet-glass
   illusion reads as a deliberate pair, not two unrelated panels. */
.s3-issue-actions::before {
  content: '';
  position: absolute;
  inset: 1px 1px auto 1px;
  height: 55%;
  border-radius: 23px 23px 60% 60% / 23px 23px 100% 100%;
  background: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.40) 0%,
    rgba(255, 255, 255, 0.05) 100%
  );
  pointer-events: none;
  z-index: 0;
}
.s3-issue-actions > * {
  position: relative;
  z-index: 1;
}
/* Padding-bottom on the page must clear the fixed action card +
   bottom nav. Tighter card → tighter clearance. */
.td.td-issue { padding-bottom: 210px; }
.s3-issue-actions .sap-actions-h {
  margin-bottom: 7px;
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-soft);
  padding: 0 4px;
}
.s3-issue-actions .sap-actions {
  /* 4-up row when there's space; falls back to 2×2 on narrow phones.
     Each tile keeps the icon-above-label stack but shrinks padding/
     typography to free vertical real estate. */
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 6px;
}
@media (max-width: 380px) {
  .s3-issue-actions .sap-actions { grid-template-columns: repeat(2, 1fr); gap: 8px; }
}
.s3-issue-actions .sap-action {
  appearance: none;
  -webkit-appearance: none;
  background: #fff;
  color: var(--ink);
  border: 1px solid rgba(17, 17, 17, 0.10);
  border-radius: 12px;
  padding: 10px 6px 9px;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  text-decoration: none;
  transition: transform 0.15s ease;
}
.s3-issue-actions .sap-action:active { transform: scale(0.98); }
.s3-issue-actions .sap-action svg { width: 18px; height: 18px; }
.s3-issue-actions .sap-action span {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 11.5px;
  line-height: 1.1;
  text-align: center;
}
/* First button highlight — "ลูกค้าสแกน" gets the primary accent
   so the recommended path stands out from the row of three other
   ink-colored options. */
.s3-issue-actions .sap-action.primary {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
  box-shadow: 0 4px 12px -4px rgba(255, 94, 58, 0.45);
}
.s3-issue-actions .sap-action.primary svg,
.s3-issue-actions .sap-action.primary span { color: #fff; }

/* ==========================================================
   S3.insights — Brief 30-day metrics card (suggestions view) +
   funnel/campaign cards (history view)
   ========================================================== */
.s3-ins-brief {
  display: block;
  /* 8px top matches the other tab roots so the insights first card
     lines up with dashboard/issue/customers. */
  margin: 0px 20px 16px;
  padding: 14px 16px;
  background: var(--surface);
  border: 1px solid rgba(17, 17, 17, 0.12);
  border-radius: 14px;
  text-decoration: none;
  cursor: pointer;
}
.s3-ins-brief .brief-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 8px;
}
.s3-ins-brief .brief-label {
  font-family: 'Prompt', sans-serif;
  font-size: 12px;
  font-weight: 500;
  color: var(--ink-soft);
}
.s3-ins-brief .brief-link {
  font-family: 'Prompt', sans-serif;
  font-size: 12px;
  font-weight: 600;
  color: var(--accent);
}
.s3-ins-brief .brief-stats {
  font-family: 'Prompt', sans-serif;
  font-size: 13px;
  color: var(--ink-soft);
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px;
}
.s3-ins-brief .brief-stats strong {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: 17px;
  color: var(--ink);
  letter-spacing: -0.02em;
}
.s3-ins-brief .brief-stats em {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 700;
  font-size: 11px;
  color: var(--ink-softer);
  font-style: normal;
}
.s3-ins-brief .brief-stats .accent strong { color: var(--accent); }
.s3-ins-brief .brief-stats .brief-sep {
  color: var(--ink-softer);
  margin: 0 2px;
}
.s3-ins-brief:active { transform: scale(0.99); }

.s3-ins-overview {
  margin: 0 20px 18px;
  padding: 16px 18px;
  background: var(--surface);
  border: 1px solid rgba(17, 17, 17, 0.12);
  border-radius: 18px;
}
.ins-ov-head {
  font-family: 'Prompt', sans-serif;
  font-size: 12px;
  font-weight: 500;
  color: var(--ink-soft);
  margin-bottom: 12px;
}
.ins-ov-funnel {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 4px;
}
.ins-ov-funnel .iov-cell { flex: 1; text-align: center; }
.ins-ov-funnel .iov-num {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: 26px;
  color: var(--ink);
  line-height: 1;
  letter-spacing: -0.02em;
}
.ins-ov-funnel .iov-num.accent { color: var(--accent); }
.ins-ov-funnel .iov-label {
  font-family: 'Prompt', sans-serif;
  font-size: 11.5px;
  color: var(--ink-soft);
  margin-top: 4px;
}
.ins-ov-funnel .iov-pct {
  font-family: 'Host Grotesk', sans-serif;
  font-size: 10.5px;
  font-weight: 700;
  color: var(--ink-softer);
  margin-top: 2px;
}
.ins-ov-funnel .iov-arrow {
  color: var(--ink-softer);
  font-size: 16px;
  flex-shrink: 0;
  padding-bottom: 28px;
}

.s3-camp {
  display: block;
  margin: 0 20px 10px;
  padding: 14px 16px;
  background: var(--surface);
  border: 1px solid rgba(17, 17, 17, 0.12);
  border-radius: 16px;
  text-decoration: none;
  cursor: pointer;
}
.s3-camp.active { border-left: 1px solid rgba(17, 17, 17, 0.12); }
.s3-camp.done { opacity: 0.92; }
.s3-camp:last-of-type { margin-bottom: 40px; }
.s3-camp .camp-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 6px;
}
.s3-camp .camp-status {
  font-family: 'Prompt', sans-serif;
  font-size: 11px;
  font-weight: 600;
  color: var(--accent);
}
.s3-camp .camp-status.done { color: var(--mint-ink); }
.s3-camp .camp-date {
  font-family: 'Prompt', sans-serif;
  font-size: 11px;
  color: var(--ink-softer);
}
.s3-camp .camp-name {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 14.5px;
  color: var(--ink);
  margin-bottom: 12px;
}
.s3-camp .camp-stats {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 0;
  padding: 10px 0;
  border-top: 1px solid rgba(17, 17, 17, 0.08);
  border-bottom: 1px solid rgba(17, 17, 17, 0.08);
  margin-bottom: 10px;
}
.s3-camp .cs-cell {
  text-align: center;
  border-right: 1px solid rgba(17, 17, 17, 0.08);
}
.s3-camp .cs-cell:last-child { border-right: none; }
.s3-camp .cs-num {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: 22px;
  color: var(--ink);
  line-height: 1;
  letter-spacing: -0.02em;
}
.s3-camp .cs-num.accent { color: var(--accent); }
.s3-camp .cs-label {
  font-family: 'Prompt', sans-serif;
  font-size: 11px;
  color: var(--ink-soft);
  margin-top: 4px;
}
.s3-camp .camp-roi {
  background: var(--butter);
  border-radius: 8px;
  padding: 8px 12px;
  margin-bottom: 10px;
  font-family: 'Prompt', sans-serif;
  font-size: 12px;
  color: var(--ink);
  display: flex;
  align-items: center;
  gap: 8px;
}
.s3-camp .roi-label {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: 11px;
  background: var(--ink);
  color: var(--butter);
  padding: 3px 8px;
  border-radius: 999px;
  letter-spacing: 0.05em;
}
.s3-camp .camp-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-family: 'Prompt', sans-serif;
  font-size: 12px;
  color: var(--ink-soft);
}
.s3-camp .camp-cta { color: var(--accent); font-weight: 600; }
.s3-camp .camp-arrow {
  color: var(--ink-softer);
  font-size: 18px;
}

/* ==========================================================
   S3 — Liquid-glass bottom navigation (4 tabs)
   Used across every S3.* full-page (home / issue / customers / insights).
   Position fixed because .td has overflow-x:hidden — same trick we use for
   .s3-dock and .s3-footer-brand (sticky behaves badly inside it).
   ========================================================== */
/* Liquid-glass dock — both shop (.s3-glass-nav) and customer
   (.c-glass-nav) share the same chassis. Heavier blur + saturation
   read as "wet glass"; the ::before pseudo paints a refractive
   highlight strip across the top so the surface looks like polished
   glass picking up ambient light. Bigger than the old version (more
   padding + larger icons + bolder labels) so taps land easier and the
   shape feels intentional rather than hidden. */
.s3-glass-nav,
.c-glass-nav {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 14px;
  z-index: 6;
  margin: 0 auto;
  max-width: calc(100% - 24px);
  padding: 10px;
  border-radius: 28px;
  background: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.55) 0%,
    rgba(255, 245, 230, 0.42) 55%,
    rgba(246, 241, 229, 0.55) 100%
  );
  backdrop-filter: blur(28px) saturate(200%);
  -webkit-backdrop-filter: blur(28px) saturate(200%);
  border: 1px solid rgba(255, 255, 255, 0.65);
  box-shadow:
    inset 0 1.5px 0 rgba(255, 255, 255, 0.9),
    inset 0 -1px 0 rgba(17, 17, 17, 0.06),
    inset 0 0 22px rgba(255, 217, 82, 0.10),
    0 14px 40px -12px rgba(17, 17, 17, 0.24),
    0 4px 14px -4px rgba(17, 17, 17, 0.10);
  display: grid;
  /* --tab-count is set inline by glass_nav.html (4 when staff lacks
     can_settings, 5 otherwise). Defaults to 5 for c-glass-nav and any
     caller that doesn't set it. */
  grid-template-columns: repeat(var(--tab-count, 5), 1fr);
  gap: 2px;
  isolation: isolate;
}
/* Top specular highlight — a curved sliver of brighter translucency
   that mimics light refracting off the dock's upper edge. */
.s3-glass-nav::before,
.c-glass-nav::before {
  content: '';
  position: absolute;
  inset: 1px 1px auto 1px;
  height: 55%;
  border-radius: 27px 27px 60% 60% / 27px 27px 100% 100%;
  background: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.40) 0%,
    rgba(255, 255, 255, 0.05) 100%
  );
  pointer-events: none;
  z-index: 0;
}
.s3-glass-nav .gn-tab,
.c-glass-nav .gn-tab {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  padding: 10px 4px 8px;
  border-radius: 20px;
  cursor: pointer;
  text-decoration: none;
  color: var(--ink-soft);
  transition: transform 0.15s ease, color 0.15s ease, background 0.18s ease;
  z-index: 1;
}
.s3-glass-nav .gn-tab .gn-icon,
.c-glass-nav .gn-tab .gn-icon {
  width: 24px;
  height: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
}
.s3-glass-nav .gn-tab .gn-icon svg,
.c-glass-nav .gn-tab .gn-icon svg {
  width: 100%;
  height: 100%;
  stroke-width: 2;
}
.s3-glass-nav .gn-tab .gn-label,
.c-glass-nav .gn-tab .gn-label {
  font-family: 'Prompt', sans-serif;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0;
  line-height: 1;
  white-space: nowrap;
}
.s3-glass-nav .gn-tab.active,
.c-glass-nav .gn-tab.active {
  background: linear-gradient(
    140deg,
    rgba(17, 17, 17, 0.96) 0%,
    rgba(34, 34, 34, 0.92) 100%
  );
  color: var(--butter);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.18),
    inset 0 -1px 0 rgba(0, 0, 0, 0.4),
    0 4px 14px -4px rgba(17, 17, 17, 0.45);
}
.s3-glass-nav .gn-tab.active .gn-icon svg,
.c-glass-nav .gn-tab.active .gn-icon svg {
  fill: rgba(255, 217, 82, 0.15);
}
.s3-glass-nav .gn-tab:active,
.c-glass-nav .gn-tab:active {
  transform: scale(0.96);
}
/* Pulsing badge on tabs with pending action (shop "ออกแต้ม", customer
   inbox / gifts). Same animation, single source of truth. */
.s3-glass-nav .gn-badge,
.c-glass-nav .gn-badge {
  position: absolute;
  top: -2px; right: -4px;
  min-width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 2px var(--bg);
  animation: gn-badge-pulse 1.6s ease-out infinite;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Prompt', sans-serif;
  font-size: 9px;
  font-weight: 700;
  color: #fff;
  line-height: 1;
}
.c-glass-nav .gn-badge.has-count,
.s3-glass-nav .gn-badge.has-count {
  min-width: 16px; height: 16px;
  padding: 0 4px;
  top: -4px; right: -8px;
  border-radius: 99px;
}
@keyframes gn-badge-pulse {
  0%   { box-shadow: 0 0 0 2px var(--bg), 0 0 0 0 rgba(255, 94, 58, 0.5); }
  70%  { box-shadow: 0 0 0 2px var(--bg), 0 0 0 8px rgba(255, 94, 58, 0); }
  100% { box-shadow: 0 0 0 2px var(--bg), 0 0 0 0 rgba(255, 94, 58, 0); }
}

/* Inline hint next to "ลูกค้าล่าสุด" — replaces the old pulsing live dot. */
.s3-dock .sap-table {
  width: 100%;
  border-collapse: collapse;
  font-family: 'Prompt', sans-serif;
  font-size: 14px;
  color: var(--ink);
}
.s3-dock .sap-table tr { border-bottom: 1px solid var(--line); }
.s3-dock .sap-table tr:last-child { border-bottom: none; }
.s3-dock .sap-table td { padding: 5px 0; vertical-align: middle; }
.s3-dock .sap-table td.t {
  font-family: 'Prompt', sans-serif;
  font-size: 12px;
  color: var(--ink-softer);
  width: auto;
  white-space: nowrap;
  padding-right: 10px;
}
.s3-dock .sap-table td.n { font-weight: 600; color: var(--ink); font-size: 13px; }
.s3-dock .sap-table td.a {
  text-align: right;
  font-size: 13px;
  color: var(--ink-soft);
}
.s3-dock .sap-table td.a strong { font-weight: 700; color: var(--ink); }
.s3-dock .sap-table td.a .icon-mini {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: 14px;
  color: var(--accent);
  margin-right: 2px;
}
.s3-dock .sap-table tr.latest { color: var(--accent); }
.s3-dock .sap-table tr.latest td { color: var(--accent); }
.s3-dock .sap-table tr.latest td.n {
  color: var(--accent);
  font-weight: 700;
}
.s3-dock .sap-table tr.latest td.a strong { color: var(--accent); }
.s3-dock .sap-table tr.voided td { opacity: 0.4; text-decoration: line-through; }
.s3-dock .sap-table tr.feed-row { cursor: pointer; }
/* Just-arrived row — fired by JS on each SSE feed-row event. Bright accent
   flash for the first 0.4s so the shop staff can't miss it (paired with
   a Web Audio "ding"), then fades through accent-soft to transparent. */
@keyframes feed-row-arrive-bg {
  0%   { background: var(--accent); }
  18%  { background: var(--accent); }
  60%  { background: var(--accent-soft); }
  100% { background: transparent; }
}
@keyframes feed-row-arrive-fg {
  0%, 18% { color: #fff; }
  100%    { color: var(--accent); }
}
.s3-dock .sap-table tr.feed-row.just-arrived td,
.s3-issue-feed .sap-table tr.feed-row.just-arrived td {
  animation: feed-row-arrive-bg 2.5s ease-out, feed-row-arrive-fg 2.5s ease-out;
}
.s3-dock .sap-table tr.feed-row.just-arrived td *,
.s3-issue-feed .sap-table tr.feed-row.just-arrived td * {
  animation: feed-row-arrive-fg 2.5s ease-out;
}
/* Voided rows fade out — same dim treatment used on the dock once the
   60-sec window button gets pressed. */
.s3-issue-feed .sap-table tr.feed-row.voided td {
  opacity: 0.4;
  text-decoration: line-through;
}
/* Armed state — first tap on a row primes it, the column flips to a
   confirming "ยกเลิก?" cell that shows tapping again will fire the void.
   3-second timeout (handled in JS) clears .armed if the owner taps away. */
.s3-dock .sap-table tr.feed-row.armed { background: var(--accent-soft); }
.s3-dock .sap-table tr.feed-row.armed td.t {
  color: var(--accent);
  font-weight: 700;
}
.s3-dock .sap-table tr.feed-row.armed td.t::after {
  content: ' · แตะอีกครั้ง';
  text-transform: none;
  letter-spacing: 0;
}
.s3-dock .sap-actions-h {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-bottom: 4px;
  padding: 0 4px;
}
.s3-dock .sap-actions {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
}
.s3-dock .sap-action {
  appearance: none;
  -webkit-appearance: none;
  background: var(--ink);
  color: var(--bg);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 12px;
  padding: 7px 4px;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  box-shadow: none;
  text-decoration: none;
}
.s3-dock .sap-action svg { width: 16px; height: 16px; }
.s3-dock .sap-action span {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 12px;
}


/* ==========================================================
   S3.search — Customer search + give points
   ========================================================== */

.search-box { margin: 14px 16px 10px; }
.search-input {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 14px;
  background: var(--surface);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 14px;
  font-family: 'Prompt', sans-serif;
  font-size: 17px;
}
.search-input svg {
  width: 16px;
  height: 16px;
  color: var(--ink-softer);
  flex-shrink: 0;
}
.search-input input {
  border: none;
  outline: none;
  background: transparent;
  flex: 1;
  font: inherit;
  color: var(--ink);
  width: 100%;
}
.search-results {
  margin: 0 16px 12px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.search-result {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  background: transparent;
  border: 1.5px solid var(--line);
  border-radius: 12px;
  cursor: pointer;
  text-decoration: none;
  color: var(--ink);
}
.search-result.selected {
  background: var(--surface);
  border-color: var(--ink);
  box-shadow: none;
}
.search-result .sr-avatar {
  width: 32px;
  height: 32px;
  background: var(--accent);
  color: #fff;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 15px;
  flex-shrink: 0;
}
.search-result .sr-info { flex: 1; line-height: 1.25; }
.search-result .sr-info .sr-name {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 15px;
  letter-spacing: -0.01em;
}
.search-result .sr-info .sr-name em {
  font-style: normal;
  color: var(--ink-soft);
  font-weight: 500;
}
.search-result .sr-info .sr-meta {
  font-family: 'JetBrains Mono', monospace;
  font-size: 12px;
  color: var(--ink-softer);
  margin-top: 1px;
}
.search-result .sr-check {
  color: var(--accent);
  font-size: 16px;
  font-weight: 700;
  flex-shrink: 0;
}
.search-empty {
  margin: 0 16px 12px;
  padding: 24px 16px;
  text-align: center;
  font-family: 'Prompt', sans-serif;
  font-size: 14px;
  color: var(--ink-softer);
}
.point-amount {
  margin: 4px 16px 14px;
  padding: 12px 14px;
  background: var(--bg);
  border: 1.5px dashed var(--ink-softer);
  border-radius: 14px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.point-amount .pa-label {
  font-family: 'Prompt', sans-serif;
  font-weight: 600;
  font-size: 15px;
  color: var(--ink);
}
.point-amount .pa-stepper {
  display: flex;
  align-items: center;
  gap: 14px;
}
.point-amount .pa-btn {
  width: 30px;
  height: 30px;
  background: var(--surface);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 50%;
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 700;
  font-size: 16px;
  color: var(--ink);
  box-shadow: none;
  cursor: pointer;
}
.point-amount .pa-num {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: 22px;
  letter-spacing: -0.02em;
  color: var(--ink);
  min-width: 28px;
  text-align: center;
}
.search-confirm {
  display: flex;
  width: calc(100% - 32px);
  margin: 16px;
  background: var(--ink);
  color: var(--bg);
  padding: 16px 20px;
  border-radius: 16px;
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 16px;
  align-items: center;
  justify-content: space-between;
  cursor: pointer;
  border: none;
  box-shadow: 4px 4px 0 rgba(17, 17, 17, 0.15);
  transition: transform 0.1s;
}
.search-confirm:active {
  transform: scale(0.98);
}
.search-confirm .arrow {
  width: 24px;
  height: 24px;
  background: var(--accent);
  color: #fff;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
}
.phone-display {
  margin: 18px 20px 12px;
  padding: 16px 14px;
  background: var(--surface);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 14px;
  text-align: center;
}
.phone-display .label {
  font-family: 'Prompt', sans-serif;
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-softer);
  margin-bottom: 4px;
}
.phone-display .number {
  font-family: 'JetBrains Mono', monospace;
  font-weight: 700;
  font-size: 22px;
  letter-spacing: 0.02em;
  color: var(--ink);
}
.phone-display .number .placeholder { color: var(--ink-softer); opacity: 0.4; }
.phone-display .number .cursor {
  display: inline-block;
  width: 2px;
  height: 22px;
  background: var(--accent);
  vertical-align: middle;
  margin-left: 1px;
  animation: blink 1.1s infinite;
}
@keyframes blink { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0; } }

.phone-numpad {
  margin: 0 20px 14px;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
}
.phone-numpad .key {
  aspect-ratio: 2 / 1.1;
  background: var(--surface);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 700;
  font-size: 18px;
  color: var(--ink);
  cursor: pointer;
  box-shadow: none;
  user-select: none;
}
.phone-numpad .key.del {
  background: var(--bg);
  color: var(--ink-soft);
  box-shadow: none;
}
.phone-numpad .key.del svg { width: 18px; height: 18px; }

.phone-confirm {
  margin: 0 20px;
  padding: 14px 16px;
  background: var(--accent);
  color: #fff;
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 14px;
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 16px;
  text-align: center;
  box-shadow: none;
  cursor: pointer;
  width: calc(100% - 40px);
  display: block;
}
.phone-confirm.disabled,
.phone-confirm:disabled {
  background: var(--surface);
  color: var(--ink-softer);
  box-shadow: none;
  border-color: var(--ink-softer);
  cursor: not-allowed;
}

/* ==========================================================
   shop_not_found.html — friendly Thai page when a customer scans
   a QR for a deleted/missing shop instead of a JSON 404.
   ========================================================== */

.not-found {
  margin: auto;
  padding: 18vh 28px 24px;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.not-found .nf-icon {
  width: 72px;
  height: 72px;
  border-radius: 50%;
  background: var(--accent-soft);
  border: 1px solid rgba(17, 17, 17, 0.18);
  color: var(--accent);
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 18px;
  box-shadow: none;
}
.not-found .nf-icon svg { width: 32px; height: 32px; }
.not-found .nf-title {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 26px;
  letter-spacing: -0.02em;
  margin-bottom: 8px;
}
.not-found .nf-title em { color: var(--accent); font-style: normal; }
.not-found .nf-sub {
  font-family: 'Prompt', sans-serif;
  font-size: 15px;
  color: var(--ink-soft);
  line-height: 1.55;
  max-width: 320px;
  margin-bottom: 24px;
}
.not-found .nf-actions {
  display: flex;
  flex-direction: column;
  gap: 10px;
  width: 100%;
  max-width: 280px;
  margin-bottom: 18px;
}
.not-found .nf-btn {
  padding: 13px 18px;
  border-radius: 14px;
  border: 1px solid rgba(17, 17, 17, 0.18);
  text-decoration: none;
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 16px;
  background: var(--surface);
  color: var(--ink);
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.not-found .nf-btn.primary {
  background: var(--ink);
  color: var(--bg);
  box-shadow: none;
}
.not-found .nf-btn .arrow {
  width: 26px;
  height: 26px;
  background: var(--accent);
  color: #fff;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
}
.not-found .nf-debug {
  font-family: 'JetBrains Mono', monospace;
  font-size: 9.5px;
  color: var(--ink-softer);
  letter-spacing: 0.04em;
  display: flex;
  flex-direction: column;
  gap: 2px;
  align-items: center;
  opacity: 0.55;
}
.not-found .nf-debug code {
  font-size: 11px;
  word-break: break-all;
  max-width: 320px;
}

/* ==========================================================
   Inline flash — replaces alert(); auto-dismisses on dashboard
   ========================================================== */

.dash-flash {
  position: fixed;
  left: 50%;
  bottom: max(140px, calc(env(safe-area-inset-bottom) + 130px));
  transform: translateX(-50%);
  z-index: 95;
  padding: 10px 16px;
  border-radius: 999px;
  border: 1px solid rgba(17, 17, 17, 0.18);
  font-family: 'Prompt', sans-serif;
  font-weight: 600;
  font-size: 15px;
  letter-spacing: -0.01em;
  box-shadow: 0 8px 24px -6px rgba(17, 17, 17, 0.4);
  max-width: calc(100vw - 36px);
  text-align: center;
}
.dash-flash[hidden] { display: none; }
.dash-flash.is-ok { background: var(--mint); color: var(--mint-ink); }
.dash-flash.is-error { background: var(--accent); color: #fff; }

/* S7c — verification error banner shown after a failed slip upload.
   Sits between the steps and the upload CTA so the owner sees what
   went wrong before they press the button again. */
.topup-error {
  margin: 12px 20px 0;
  padding: 11px 14px;
  background: var(--accent-soft);
  border: 1px solid rgba(255, 94, 58, 0.35);
  border-radius: 12px;
  font-family: 'Prompt', sans-serif;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--ink);
}

/* ==========================================================
   Manual-issue FAB — one-tap walk-in stamp on the shop dashboard
   ========================================================== */

.manual-fab .plus {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: 22px;
  line-height: 1;
}
.manual-fab .lbl {
  font-family: 'Prompt', sans-serif;
  font-size: 17px;
}

/* ==========================================================
   S7 — Top-up packages
   ========================================================== */

/* Hero balance — lives in the same light material as the package
   cards and PromptPay row below it, so the page reads as one
   stack of related rows instead of a dark badge floating on its
   own. The big credit number stays prominent in ink (not butter
   on dark) which is more cohesive with the rest of the app's
   recent lightening. */
.s7-balance {
  margin: 14px 20px 0;
  padding: 14px 16px;
  background: var(--surface);
  color: var(--ink);
  border-radius: 16px;
  border: 1px solid rgba(17, 17, 17, 0.10);
  box-shadow: none;
  position: relative;
}
.s7-balance .lbl {
  font-weight: 600;
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-softer);
  margin-bottom: 4px;
}
.s7-balance .num-row {
  display: flex;
  align-items: baseline;
  gap: 6px;
}
.s7-balance .num {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 700;
  font-size: 44px;
  letter-spacing: -0.04em;
  color: var(--ink);
  line-height: 0.95;
}
.s7-balance .unit {
  font-weight: 500;
  font-size: 13px;
  color: var(--ink-soft);
}
.s7-balance .est {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px dashed rgba(17, 17, 17, 0.10);
  font-size: 11.5px;
  color: var(--ink-soft);
}
.s7-balance .est strong { color: var(--accent); font-weight: 700; }

.s7-q { padding: 22px 20px 0; }
.s7-q .ask {
  font-weight: 700;
  font-size: 22px;
  letter-spacing: -0.025em;
  margin-bottom: 2px;
}
.s7-q .ask em {
  font-style: italic;
  font-weight: 700;
  color: var(--accent);
}
.s7-q .sub {
  font-weight: 500;
  font-size: 12px;
  color: var(--ink-soft);
}

.s7-packages {
  padding: 14px 20px 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.s7-pkg {
  background: var(--surface);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 16px;
  box-shadow: none;
  padding: 12px 14px;
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  cursor: pointer;
  position: relative;
  text-decoration: none;
  color: inherit;
  font-family: inherit;
}
.s7-pkg.popular { background: var(--butter); }
.s7-pkg.popular::before {
  content: 'แนะนำ';
  position: absolute;
  top: -10px;
  left: 14px;
  transform: rotate(-4deg);
  background: var(--accent);
  color: #fff;
  padding: 3px 10px;
  border-radius: 999px;
  border: 1px solid rgba(17, 17, 17, 0.18);
  font-weight: 700;
  font-size: 9px;
  letter-spacing: 0.04em;
}
.s7-pkg .left .credits {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 700;
  font-size: 22px;
  letter-spacing: -0.025em;
  line-height: 1;
  margin-bottom: 2px;
}
.s7-pkg .left .credits .unit {
  font-style: italic;
  font-weight: 500;
  font-size: 12px;
  color: var(--ink-soft);
  margin-left: 3px;
}
.s7-pkg.popular .left .credits .unit { color: var(--ink); opacity: 0.6; }
.s7-pkg .left .sub {
  font-size: 10px;
  color: var(--ink-soft);
}
.s7-pkg.popular .left .sub { color: var(--ink); opacity: 0.7; }
.s7-pkg .right { text-align: right; }
.s7-pkg .right .price {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 700;
  font-size: 18px;
  letter-spacing: -0.02em;
  color: var(--ink);
}
.s7-pkg .right .price .currency {
  font-style: italic;
  font-weight: 500;
  font-size: 12px;
  color: var(--ink-soft);
  margin-right: 2px;
}
.s7-pkg .right .bonus {
  display: inline-block;
  background: var(--accent);
  color: #fff;
  padding: 2px 8px;
  border-radius: 999px;
  font-weight: 700;
  font-size: 9px;
  letter-spacing: 0.04em;
  margin-top: 4px;
}

.s7-method .ic {
  width: 36px;
  height: 36px;
  background: #1546B7;
  color: #fff;
  border-radius: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: 9px;
  text-align: center;
}
.s7-method .meta { flex: 1; line-height: 1.2; }
.s7-method .meta .name {
  font-weight: 700;
  font-size: 13px;
}
.s7-method .meta .sub {
  font-style: italic;
  font-size: 11px;
  color: var(--ink-soft);
  margin-top: 1px;
}
.s7-method .check {
  width: 22px;
  height: 22px;
  background: var(--accent);
  color: #fff;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  font-weight: 700;
  border: 1px solid rgba(17, 17, 17, 0.18);
}

.s7-cta .arrow {
  width: 30px;
  height: 30px;
  background: var(--accent);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-size: 14px;
}

/* ==========================================================
   S7 confirm — PromptPay QR + step-by-step
   ========================================================== */

.s7c-meta .label {
  font-weight: 500;
  font-style: italic;
  font-size: 13px;
  color: var(--ink-soft);
  margin-bottom: 4px;
}
.s7c-meta .pkg {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 700;
  font-size: 26px;
  letter-spacing: -0.025em;
  margin-bottom: 2px;
}
.s7c-meta .pkg .accent { color: var(--accent); }
.s7c-meta .pkg .unit {
  font-weight: 600;
  font-size: 18px;
  margin-left: 4px;
}
.s7c-meta .price {
  font-weight: 600;
  font-size: 14px;
  color: var(--ink-soft);
}

.s7c-qr {
  margin: 22px 22px 0;
  background: var(--surface);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 22px;
  box-shadow: none;
  padding: 18px 16px 16px;
  text-align: center;
}
.s7c-qr .promptpay-logo {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: #1546B7;
  color: #fff;
  padding: 4px 10px;
  border-radius: 999px;
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: 12px;
  letter-spacing: 0.02em;
  margin-bottom: 14px;
}
.s7c-qr .qr-box {
  width: 160px;
  height: 160px;
  margin: 0 auto 14px;
  background: #fff;
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 12px;
  padding: 8px;
  box-shadow: none;
}
.s7c-qr .qr-box svg { width: 100%; height: 100%; }
.s7c-qr .recipient {
  font-weight: 600;
  font-size: 15px;
  margin-bottom: 2px;
}
.s7c-qr .recipient-id {
  font-family: 'JetBrains Mono', monospace;
  font-size: 13px;
  color: var(--ink-soft);
}

.s7c-step.active { background: var(--butter); }
.s7c-step .text {
  font-weight: 600;
  font-size: 15px;
  line-height: 1.3;
}
.s7c-step .text .sub {
  font-weight: 400;
  font-size: 13px;
  color: var(--ink-soft);
  display: block;
  margin-top: 1px;
}
.s7c-upload-cta {
  margin: 22px 22px 22px;
  padding: 16px;
  background: var(--ink);
  color: var(--bg);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 18px;
  font-family: inherit;
  font-weight: 700;
  font-size: 17px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  cursor: pointer;
  box-shadow: 0 10px 28px -8px rgba(17, 17, 17, 0.35);
  text-decoration: none;
}
.s7c-upload-cta svg { width: 18px; height: 18px; }
.s7c-upload-cta .l {
  display: flex;
  align-items: center;
  gap: 10px;
}
.s7c-upload-cta .arrow {
  width: 28px;
  height: 28px;
  background: var(--accent);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-size: 16px;
}

/* ==========================================================
   S9 — Theme picker (full-screen, larger previews)
   ========================================================== */

.theme-card {
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 18px;
  box-shadow: none;
  overflow: hidden;
  cursor: pointer;
  background: var(--surface);
  position: relative;
  text-decoration: none;
  color: inherit;
  display: block;
  font-family: inherit;
}
.theme-card.selected { transform: translateY(-2px); }
.theme-card.selected::after {
  content: '✓';
  position: absolute;
  top: 8px;
  right: 8px;
  width: 22px;
  height: 22px;
  background: var(--accent);
  color: #fff;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  font-weight: 700;
  border: 1px solid rgba(17, 17, 17, 0.18);
  z-index: 2;
}
.theme-preview {
  aspect-ratio: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  padding: 16px 10px;
  border-bottom: 1px solid rgba(17, 17, 17, 0.18);
  position: relative;
}
.theme-preview.taemdee { background: #F6F1E5; }
.theme-preview.mono { background: #fff; }
.theme-preview.night { background: #141414; }
.theme-preview.pastel { background: #FFEEE4; }
.theme-preview .num {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 700;
  font-size: 36px;
  letter-spacing: -0.04em;
  line-height: 1;
}
.theme-preview.taemdee .num { color: #FF5E3A; }
.theme-preview.mono .num { color: #111; }
.theme-preview.night .num { color: #FFD952; }
.theme-preview.pastel .num { color: #E87A6A; }
.theme-preview .stamps {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 2px;
  margin-top: 6px;
  width: 60%;
}
.theme-preview .stamps .s {
  height: 6px;
  border-radius: 2px;
  background: rgba(0, 0, 0, 0.1);
}
.theme-preview.night .stamps .s { background: #333; }
.theme-preview.taemdee .stamps .s.on { background: #FF5E3A; }
.theme-preview.taemdee .stamps .s.b { background: #FFD952; }
.theme-preview.mono .stamps .s.on { background: #111; }
.theme-preview.night .stamps .s.on { background: #FFD952; }
.theme-preview.pastel .stamps .s.on { background: #E87A6A; }
.theme-meta { padding: 10px 12px; }
.theme-meta .name {
  font-weight: 700;
  font-size: 15px;
  letter-spacing: -0.015em;
  margin-bottom: 1px;
}
.theme-meta .meta {
  font-style: italic;
  font-size: 13px;
  color: var(--ink-soft);
}
.theme-card.selected .theme-meta { background: var(--butter); }

/* ==========================================================
   S8 — tip strip (under the printable QR)
   ========================================================== */

.s8-tip .tip-bulb {
  flex-shrink: 0;
  width: 22px;
  height: 22px;
  background: var(--butter);
  color: var(--ink);
  border-radius: 50%;
  border: 1px solid rgba(17, 17, 17, 0.18);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  font-style: normal;
  font-weight: 700;
}

/* ==========================================================
   Customer DeeCard themes — overrides for the .td root
   (PRD §9: themes apply to customer DeeCard only, not shop UI)
   ========================================================== */

/* "taemdee" is the default; "default" is a legacy alias for backfilled rows.
   Applied to either the customer DeeCard root (.td) or the onboarding
   live preview (.s2-c1-preview) so the swatch picker repaints in place. */
.td.theme-taemdee, .td.theme-default,
.s2-c1-preview.theme-taemdee, .s2-c1-preview.theme-default {
  /* uses default tokens defined on .td above */
}

.td.theme-mono,
.s2-c1-preview.theme-mono {
  --bg: #ffffff;
  --surface: #f6f6f6;
  --ink: #111111;
  --ink-soft: #4a4a4a;
  --ink-softer: #999999;
  --accent: #111111;
  --accent-soft: rgba(17, 17, 17, 0.07);
  --butter: #d8d8d8;
  --butter-soft: #f0f0f0;
  --mint: #d8d8d8;
  --mint-ink: #444;
  --line: rgba(17, 17, 17, 0.1);
}
.td.theme-mono::before { display: none; }       /* no warm radial gradients */
.td.theme-mono::after { opacity: 0.2; }          /* dotted bg lighter */

.td.theme-night,
.s2-c1-preview.theme-night {
  --bg: #141414;
  --surface: #1d1d1d;
  --ink: #fafafa;
  --ink-soft: #a8a8a8;
  --ink-softer: #6a6a6a;
  --accent: #FFD952;
  --accent-soft: rgba(255, 217, 82, 0.15);
  --butter: #FFD952;
  --butter-soft: #3d3520;
  --mint: #2a4a3a;
  --mint-ink: #C8E8D0;
  --line-green: #06C755;
  --line: rgba(255, 255, 255, 0.12);
}
.td.theme-night::before {
  background-image:
    radial-gradient(circle at 85% 12%, rgba(255, 217, 82, 0.18) 0%, transparent 35%),
    radial-gradient(circle at 10% 85%, rgba(255, 217, 82, 0.06) 0%, transparent 45%);
}
.td.theme-night::after {
  background-image: radial-gradient(circle, rgba(255, 255, 255, 0.05) 1px, transparent 1.5px);
}
.td.theme-night .td-badge { background: #FFD952; color: #141414; }
.td.theme-night .td-badge .s { color: #141414; }
.td.theme-night .footer-mark .brand .dot { color: #FFD952; }
/* Mini-preview also needs its border darkened on night so the card edge stays visible */
.s2-c1-preview.theme-night { border-color: rgba(255, 255, 255, 0.18); }

.td.theme-pastel,
.s2-c1-preview.theme-pastel {
  --bg: #FFEEE4;
  --surface: #FFF6F0;
  --ink: #3a201c;
  --ink-soft: #7d564f;
  --ink-softer: #b08c83;
  --accent: #E87A6A;
  --accent-soft: rgba(232, 122, 106, 0.15);
  --butter: #FFD4A6;
  --butter-soft: #FFE8D4;
  --mint: #D6E5C7;
  --mint-ink: #4a6b3d;
  --line: rgba(58, 32, 28, 0.1);
}

.td.theme-sport,
.s2-c1-preview.theme-sport {
  --bg: #F0FDF4;
  --surface: #FFFFFF;
  --ink: #052e16;
  --ink-soft: #4d7c5d;
  --ink-softer: #94b59f;
  --accent: #15803D;
  --accent-soft: rgba(21, 128, 61, 0.13);
  --butter: #BEF264;
  --butter-soft: #E6F8B8;
  --mint: #BBE3C8;
  --mint-ink: #155f33;
  --line: rgba(5, 46, 22, 0.1);
}

/* ==========================================================
   S13 — DeeReach campaigns (list / detail / sent)
   ========================================================== */

.s13-intro {
  padding: 22px 22px 0;
  margin-bottom: 14px;
}
.s13-intro .ask {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: 28px;
  letter-spacing: -0.03em;
  color: var(--ink);
  line-height: 1;
}
.s13-intro .ask em {
  font-style: italic;
  color: var(--accent);
}
.s13-intro .ask-th {
  font-family: 'Prompt', sans-serif;
  font-size: 14px;
  color: var(--ink-soft);
  margin-top: 4px;
  line-height: 1.4;
}

.s13-list {
  padding: 0 18px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.s13-card {
  background: var(--surface);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 16px;
  padding: 12px 14px;
  box-shadow: none;
  text-decoration: none;
  color: inherit;
  position: relative;
  display: block;
}
.s13-card.primary {
  background: var(--ink);
  color: var(--bg);
  box-shadow: none;
}
.s13-card .sc-tag {
  position: absolute;
  top: -8px;
  right: 12px;
  background: var(--butter);
  color: var(--ink);
  border: 1px solid rgba(17, 17, 17, 0.18);
  padding: 2px 8px;
  border-radius: 999px;
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 11px;
  letter-spacing: 0.04em;
}
.s13-card .sc-row { display: flex; align-items: center; gap: 12px; }
.s13-card .sc-icon {
  width: 36px;
  height: 36px;
  background: var(--bg);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--ink);
  flex-shrink: 0;
}
.s13-card.primary .sc-icon {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}
.s13-card .sc-icon svg { width: 18px; height: 18px; }
.s13-card .sc-info { flex: 1; line-height: 1.25; min-width: 0; }
.s13-card .sc-name {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 14px;
  letter-spacing: -0.01em;
  margin-bottom: 1px;
}
.s13-card .sc-meta {
  font-family: 'Prompt', sans-serif;
  font-size: 12px;
  color: var(--ink-softer);
}
.s13-card.primary .sc-meta { color: var(--butter); opacity: 0.95; }
.s13-card .sc-cost {
  font-family: 'JetBrains Mono', monospace;
  font-size: 12px;
  background: var(--accent-soft);
  color: var(--accent);
  padding: 4px 8px;
  border-radius: 999px;
  border: 1px solid var(--accent);
  flex-shrink: 0;
  font-weight: 600;
}
.s13-card.primary .sc-cost {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
}

.s13-create {
  margin: 14px 18px 0;
  width: calc(100% - 36px);
  padding: 12px;
  background: transparent;
  border: 1.5px dashed var(--ink-softer);
  border-radius: 14px;
  font-family: 'Prompt', sans-serif;
  font-weight: 600;
  font-size: 14px;
  color: var(--ink-soft);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  text-decoration: none;
  box-sizing: border-box;
}
.s13-create[disabled] { cursor: not-allowed; opacity: 0.7; }
.s13-create .plus {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: 18px;
  color: var(--accent);
}
.s13-create .s13-create-hint {
  font-style: italic;
  font-size: 11px;
  color: var(--ink-softer);
  margin-left: 6px;
}

/* S13.detail */
.s13d-section { padding: 14px 20px 0; }
.s13d-h {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 8px;
}
.s13d-h .s13d-title {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 14px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink);
}
.s13d-h .s13d-count {
  font-family: 'JetBrains Mono', monospace;
  font-size: 13px;
  color: var(--ink-softer);
}
.s13d-h .s13d-edit {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 13px;
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}
.s13d-customers {
  background: var(--surface);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 14px;
  padding: 4px 8px;
  max-height: 340px;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}
/* Manual-only audience segment chips. Tap → bulk-select all
   customers in that bucket (ใกล้ครบ / หายไป / ใหม่). Active state
   tracks "selection exactly equals this segment". The count badge
   on the right reads as bucket size, dimmer when inactive. */
.s13d-segments {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 8px;
}
.s13d-seg-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 10px 5px 12px;
  background: rgba(17, 17, 17, 0.06);
  border: none;
  border-radius: 99px;
  font-family: 'Prompt', sans-serif;
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-soft);
  cursor: pointer;
  transition: background 120ms ease, color 120ms ease;
}
.s13d-seg-chip:active { background: rgba(17, 17, 17, 0.10); }
.s13d-seg-chip.active {
  background: var(--ink);
  color: #fff;
}
/* Empty bucket — chip stays visible so the owner sees the bucket
   exists, but is non-interactive. Lower opacity + disabled cursor
   read as "0 today, come back tomorrow". */
.s13d-seg-chip[disabled] {
  opacity: 0.45;
  cursor: not-allowed;
  pointer-events: none;
}
.s13d-seg-count {
  font-family: 'Host Grotesk', sans-serif;
  font-size: 11px;
  font-weight: 700;
  color: var(--ink-softer);
  background: rgba(17, 17, 17, 0.06);
  padding: 1px 6px;
  border-radius: 99px;
  min-width: 18px;
  text-align: center;
}
.s13d-seg-chip.active .s13d-seg-count {
  background: rgba(255, 255, 255, 0.15);
  color: rgba(255, 255, 255, 0.85);
}

.s13d-toolbar {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 8px;
}
/* .s13d-search is a wrapper holding the magnifying-glass SVG + the
   actual <input> — style it as a pill flex container, then size the
   icon and clear the input chrome inside. Previously this rule
   styled .s13d-search as if it were the input itself, leaving the
   SVG with no size constraint so it ballooned to fill the row. */
.s13d-search {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px;
  background: var(--bg);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 999px;
  min-width: 0;
}
.s13d-search:focus-within { border-color: var(--accent); }
.s13d-search svg {
  width: 16px;
  height: 16px;
  color: var(--ink-softer);
  flex-shrink: 0;
}
.s13d-search input {
  flex: 1;
  min-width: 0;
  background: transparent;
  border: none;
  outline: none;
  padding: 0;
  appearance: none;
  -webkit-appearance: none;
  font-family: 'Prompt', sans-serif;
  font-size: 13px;
  color: var(--ink);
}
.s13d-search input::placeholder { color: var(--ink-softer); }
.s13d-select-all {
  appearance: none;
  -webkit-appearance: none;
  padding: 6px 12px;
  background: var(--ink);
  color: var(--bg);
  border: none;
  border-radius: 999px;
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 12px;
  cursor: pointer;
  flex-shrink: 0;
  transition: transform 0.1s active;
}
.s13d-select-all:active { transform: scale(0.96); }

.customer-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 6px;
  border-bottom: 1px solid var(--line);
  cursor: pointer;
  transition: opacity 0.15s ease;
}
.customer-row:last-of-type { border-bottom: none; }
.customer-row.off { opacity: 0.45; }
.customer-row.off .cr-name { text-decoration: line-through; }
.customer-row .cr-check {
  width: 20px;
  height: 20px;
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 6px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  font-weight: 700;
  flex-shrink: 0;
  color: var(--ink-softer);
  background: var(--bg);
}
.customer-row .cr-check.on {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
}
.customer-row .cr-avatar {
  width: 28px;
  height: 28px;
  background: var(--bg);
  color: var(--ink);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 13px;
  flex-shrink: 0;
}
.customer-row .cr-info { flex: 1; line-height: 1.25; min-width: 0; }
.customer-row .cr-name {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 15px;
  color: var(--ink);
}
.customer-row .cr-meta {
  font-family: 'JetBrains Mono', monospace;
  font-size: 12px;
  color: var(--ink-softer);
  margin-top: 1px;
}
/* Channel badge strip — one tiny pill per channel, every customer
   row shows all four. .active = waterfall pick (filled accent),
   .available = subscribed but not the cheapest (outline ink),
   .unavailable = no subscription (dim + strikethrough). The trailing
   <em>N</em> is the per-message Cr cost, monospace. */
.customer-row .cr-channels {
  display: flex;
  gap: 4px;
  margin-top: 4px;
}
.customer-row .cr-channels .ch-badge {
  flex: 1 1 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  padding: 2px 6px;
  border-radius: 999px;
  font-family: 'Prompt', sans-serif;
  font-size: 10px;
  font-weight: 600;
  line-height: 1.4;
  border: 1px solid transparent;
  white-space: nowrap;
}
.customer-row .cr-channels .ch-badge em {
  font-family: 'Host Grotesk', sans-serif;
  font-style: normal;
  font-weight: 700;
  font-size: 9.5px;
  letter-spacing: -0.01em;
  opacity: 0.8;
}
.customer-row .cr-channels .ch-badge.active {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
}
.customer-row .cr-channels .ch-badge.available {
  background: transparent;
  color: var(--ink);
  border-color: rgba(17, 17, 17, 0.18);
}
.customer-row .cr-channels .ch-badge.unavailable {
  background: transparent;
  color: var(--ink-softer);
  border-color: rgba(17, 17, 17, 0.08);
  text-decoration: line-through;
  opacity: 0.5;
}
.s13d-empty {
  margin: 16px 4px;
  padding: 22px 14px;
  text-align: center;
  font-family: 'Prompt', sans-serif;
  font-style: italic;
  font-size: 13px;
  color: var(--ink-soft);
  background: var(--surface);
  border: 1px dashed rgba(17, 17, 17, 0.18);
  border-radius: 12px;
}
.customer-more {
  text-align: center;
  padding: 10px 6px 6px;
  font-family: 'Prompt', sans-serif;
  font-style: italic;
  font-size: 13px;
  color: var(--ink-soft);
  cursor: pointer;
}

.s13d-message {
  padding: 14px;
  background: var(--surface);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 14px;
  font-family: 'Prompt', sans-serif;
  font-size: 15px;
  color: var(--ink);
  line-height: 1.6;
}
/* Starter-template chip strip — sits above the message textarea on
   the deereach editor. Tap to load a seed body. Active state =
   message exactly matches the chip body. Mirrors design's
   reach.create .s13d-badges + .s13d-badge.tpl. */
.s13d-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 8px 0 12px;
}
.s13d-badge {
  padding: 4px 10px;
  border-radius: 99px;
  font-family: 'Prompt', sans-serif;
  font-size: 11px;
  font-weight: 600;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  cursor: pointer;
  transition: background 120ms ease, color 120ms ease;
}
.s13d-badge.tpl {
  background: rgba(17, 17, 17, 0.06);
  color: var(--ink-soft);
  font-weight: 500;
}
.s13d-badge.tpl:active { background: rgba(17, 17, 17, 0.10); }
.s13d-badge.tpl.active {
  background: var(--ink);
  color: #fff;
  font-weight: 700;
}

.s13d-vars {
  display: flex;
  gap: 6px;
  margin-top: 8px;
}
.var-chip {
  padding: 6px 12px;
  background: var(--bg);
  border: 1px solid rgba(17, 17, 17, 0.12);
  border-radius: 8px;
  font-family: 'Prompt', sans-serif;
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-soft);
  cursor: pointer;
}
.var-chip:hover { border-color: var(--accent); color: var(--accent); }
.s13d-message-edit {
  width: 100%;
  appearance: none;
  -webkit-appearance: none;
  resize: vertical;
  min-height: 96px;
  outline: none;
}
.s13d-message-edit:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(255, 94, 58, 0.15);
}
.s13d-preview {
  padding: 12px 14px;
  background: var(--mint);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 14px;
  font-family: 'Prompt', sans-serif;
  font-size: 14px;
  color: var(--mint-ink);
  line-height: 1.5;
}
.s13d-preview .prev-line { margin-bottom: 4px; }
.s13d-preview .prev-line:last-child { margin-bottom: 0; }

/* ------------------------------------------------------------------
   reach.create — แถมของฝาก (attached offer)
   Empty state = dashed "+ ของฝาก" tile. Filled state = inline row
   with icon + name + edit / remove actions. Mirrors design's
   .s13d-offer-add + .s13c-offer-attached.
------------------------------------------------------------------- */
.s13d-offer-add {
  width: 100%;
  margin-top: 4px;
  padding: 16px;
  background: transparent;
  border: 1.5px dashed rgba(17, 17, 17, 0.18);
  border-radius: 14px;
  font-family: 'Prompt', sans-serif;
  font-weight: 600;
  font-size: 13px;
  color: var(--ink-soft);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}
.s13d-offer-add:hover { border-color: var(--accent); color: var(--accent); }
.s13d-offer-add .plus {
  font-size: 18px;
  line-height: 1;
  font-weight: 400;
}

.s13d-offer-attached {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 4px;
  padding: 12px 14px;
  background: var(--accent-soft);
  border: 1px solid rgba(255, 94, 58, 0.30);
  border-radius: 14px;
}
.s13d-offer-attached .off-icon {
  flex-shrink: 0;
  width: 40px; height: 40px;
  border-radius: 12px;
  background: #fff;
  color: var(--accent);
  display: flex; align-items: center; justify-content: center;
}
.s13d-offer-attached .off-info { flex: 1; min-width: 0; line-height: 1.3; }
.s13d-offer-attached .off-name {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 13.5px;
  color: var(--ink);
  letter-spacing: -0.01em;
}
.s13d-offer-attached .off-meta {
  font-family: 'Prompt', sans-serif;
  font-size: 11.5px;
  color: var(--ink-soft);
  margin-top: 2px;
}
.s13d-offer-attached .off-edit,
.s13d-offer-attached .off-remove {
  font-family: 'Prompt', sans-serif;
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-soft);
  cursor: pointer;
  padding: 6px 8px;
  text-decoration: none;
}
.s13d-offer-attached .off-edit { color: var(--accent); }
.s13d-offer-attached .off-remove { font-size: 18px; line-height: 1; }
.s13d-opt {
  font-weight: 400;
  font-size: 11.5px;
  color: var(--ink-softer);
}

/* Inline preview offer card (mirrors customer-side inbox detail). */
.s13d-preview .prev-offer {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 10px;
  padding: 10px 12px;
  background: #fff;
  border-radius: 10px;
}
.s13d-preview .prev-offer .po-icon {
  flex-shrink: 0;
  width: 32px; height: 32px;
  border-radius: 9px;
  background: var(--accent-soft);
  color: var(--accent);
  display: flex; align-items: center; justify-content: center;
}
.s13d-preview .prev-offer .po-info { flex: 1; min-width: 0; line-height: 1.25; }
.s13d-preview .prev-offer .po-name {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 12.5px;
  color: var(--ink);
}
.s13d-preview .prev-offer .po-meta {
  font-family: 'Prompt', sans-serif;
  font-size: 10.5px;
  color: var(--ink-soft);
  margin-top: 1px;
}

/* Offer-edit sheet (S-offer.create) — fields and the icon picker. */
.off-field-label {
  display: block;
  font-family: 'Prompt', sans-serif;
  font-size: 12px;
  font-weight: 600;
  color: var(--ink);
  margin: 14px 0 6px;
}
.off-field-label .off-field-opt {
  font-weight: 400;
  color: var(--ink-softer);
  font-size: 11px;
  margin-left: 4px;
}
.off-field-input {
  width: 100%;
  padding: 11px 14px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 12px;
  font-family: 'Prompt', sans-serif;
  /* 16px minimum so iOS Safari / PWA doesn't auto-zoom on focus. */
  font-size: 16px;
  color: var(--ink);
  outline: none;
  box-sizing: border-box;
}
.off-field-input:focus { border-color: var(--accent); }
.off-icon-opt.active {
  border-color: var(--ink);
  box-shadow: 0 0 0 2px var(--ink);
}
/* Per-icon colour swatches — peach / butter / mint — match design's
   .sof-icon variants. Active state stamps the dark ink ring on top. */
/* Live offer preview inside the sheet — same layout as the
   customer-side inbox detail's offer card. */
.s-offer-preview {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  background: var(--accent-soft);
  border: 1px solid rgba(255, 94, 58, 0.30);
  border-radius: 14px;
}
.s-offer-preview .opv-icon {
  flex-shrink: 0;
  width: 38px; height: 38px;
  border-radius: 11px;
  background: #fff;
  color: var(--accent);
  display: flex; align-items: center; justify-content: center;
}
.s-offer-preview .opv-info { flex: 1; min-width: 0; line-height: 1.3; }
.s-offer-preview .opv-name {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 13.5px;
  color: var(--ink);
  letter-spacing: -0.01em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.s-offer-preview .opv-meta {
  font-family: 'Prompt', sans-serif;
  font-size: 11.5px;
  color: var(--ink-soft);
  margin-top: 2px;
}

/* Full-width "บันทึก · กลับไปส่ง" primary CTA — replaces the
   side-by-side cancel/save buttons inside the sheet. Cancel is
   demoted to a centred text link below. */
.s-offer-cta {
  width: 100%;
  margin-top: 20px;
  padding: 14px 18px;
  background: var(--ink);
  color: var(--bg);
  border: none;
  border-radius: 14px;
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 15px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.s-offer-cta:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}
.s-offer-cta .arrow {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px; height: 26px;
  border-radius: 50%;
  background: var(--accent);
  color: #fff;
}
.s-offer-cancel {
  display: block;
  width: 100%;
  margin-top: 8px;
  padding: 10px;
  background: transparent;
  border: none;
  font-family: 'Prompt', sans-serif;
  font-size: 13px;
  color: var(--ink-soft);
  cursor: pointer;
  text-align: center;
}

/* Offer type toggle (ของฟรี / ลดราคา) — segmented pill that swaps
   the field shape below. */
.off-type-tabs {
  display: flex;
  gap: 6px;
  padding: 4px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 12px;
}
.off-type-tab {
  flex: 1;
  padding: 8px 12px;
  background: transparent;
  border: none;
  border-radius: 8px;
  font-family: 'Prompt', sans-serif;
  font-weight: 600;
  font-size: 13px;
  color: var(--ink-soft);
  cursor: pointer;
  transition: background 120ms ease, color 120ms ease;
}
.off-type-tab.active {
  background: var(--ink);
  color: var(--bg);
}

/* Stage that wraps both ของฟรี / ลดราคา branches in the offer
   sheet. Both branches occupy the same grid cell, sized to whichever
   needs the most space. Toggling kinds flips visibility (not display)
   so the inactive branch still contributes its height to the cell —
   the date-range / preview / CTA below never shift when the type
   changes, regardless of which branch is taller in any future
   content tweak. */
.off-kind-stage { display: grid; }
.off-kind-stage > div { grid-area: 1 / 1; min-width: 0; }
.off-kind-stage > div.is-hidden {
  visibility: hidden;
  pointer-events: none;
}

/* Discount input row: "ลด [N] [บาท|%]" */
.off-discount-row {
  display: flex;
  align-items: center;
  gap: 8px;
}
.off-discount-prefix {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 14px;
  color: var(--ink);
}
.off-discount-input {
  flex: 1;
  text-align: center;
  font-weight: 700;
}
.off-unit-tabs {
  display: flex;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 3px;
  flex-shrink: 0;
}
.off-unit-tab {
  padding: 7px 14px;
  background: transparent;
  border: none;
  border-radius: 7px;
  font-family: 'Prompt', sans-serif;
  font-weight: 600;
  font-size: 13px;
  color: var(--ink-soft);
  cursor: pointer;
}
.off-unit-tab.active {
  background: var(--ink);
  color: var(--bg);
}
.off-discount-hint {
  margin-top: 6px;
  font-family: 'Prompt', sans-serif;
  font-size: 11.5px;
  color: var(--ink-soft);
}

/* Date range: "ตั้งแต่ → ถึง" */
.off-date-range {
  display: flex;
  align-items: center;
  gap: 8px;
}
.off-date-cell {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.off-date-cap {
  font-family: 'Prompt', sans-serif;
  font-size: 11px;
  color: var(--ink-softer);
  padding-left: 4px;
}
/* 16px font-size so iOS Safari / PWA doesn't auto-zoom on focus. */
.off-date-input { padding: 9px 10px; font-size: 16px; }
.off-date-arrow {
  color: var(--ink-softer);
  font-size: 14px;
  align-self: end;
  padding-bottom: 8px;
}

/* Bottom sheet primitive (rc-overlay + rc-sheet). Customer-side
   pages (my_cards / my_gifts) ship their own inline copies of these
   rules — those override here when active. The global rule covers
   shop-side surfaces (deereach offer sheet) where the markup exists
   but no inline CSS does.

   Animation pattern: overlay is always in the DOM with opacity:0 +
   pointer-events:none, sheet sits below the viewport via
   translateY(100%). Toggling .is-open on the overlay fades the
   backdrop in and slides the sheet up — proper modal feel,
   no display:none flash. */
.rc-overlay {
  position: fixed;
  inset: 0;
  background: rgba(17, 17, 17, 0.5);
  z-index: 9000;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity 200ms ease;
}
.rc-overlay.is-open {
  opacity: 1;
  pointer-events: auto;
}
.rc-sheet {
  background: var(--bg);
  border-top: 1px solid var(--line);
  border-top-left-radius: 24px;
  border-top-right-radius: 24px;
  padding: 14px 20px calc(20px + env(safe-area-inset-bottom));
  width: 100%;
  max-width: 480px;
  /* Cap at 90vh — sheets with rich content (offer create has type
     toggle + name + icons + dates + preview + CTAs) easily overflow
     a phone viewport. Inner overflow-y so the sheet itself stays
     pinned to the bottom while the content scrolls. */
  max-height: 90vh;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  box-shadow: 0 -8px 24px -8px rgba(0, 0, 0, 0.25);
  position: relative;
  transform: translateY(100%);
  transition: transform 280ms cubic-bezier(0.32, 0.72, 0, 1);
}
/* Onboarding-reward styles (.s2-field / .s2-rewards / etc.) carry
   page-level margins (~22px 20px). When reused inside a bottom
   sheet the outer margin makes the layout feel hollow — strip the
   horizontal margin and tighten the vertical so each field reads
   as its own block within the sheet. */
.rc-sheet .s2-field { margin: 16px 0 0; padding: 0; }
.rc-sheet .s2-rewards { margin: 8px 0 0; padding: 0; }
.rc-sheet .s2-upload { margin: 10px 0 0 !important; }
.rc-overlay.is-open .rc-sheet { transform: translateY(0); }
.rc-sheet .sheet-handle {
  width: 36px; height: 4px;
  border-radius: 999px;
  background: var(--ink-softer);
  margin: 0 auto 16px;
  opacity: 0.4;
}
.rc-sheet .vc-h {
  text-align: center;
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 17px;
  color: var(--ink);
  letter-spacing: -0.01em;
  margin: 4px 0 4px;
}
.rc-sheet .vc-sub {
  text-align: center;
  font-family: 'Prompt', sans-serif;
  font-size: 12px;
  color: var(--ink-soft);
  margin-bottom: 4px;
}
.rc-sheet .rc-actions {
  display: flex;
  gap: 10px;
  margin-top: 18px;
}
.rc-sheet .rc-actions .cancel,
.rc-sheet .rc-actions .send {
  flex: 1;
  padding: 12px 14px;
  border-radius: 12px;
  border: none;
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 14px;
  cursor: pointer;
}
.rc-sheet .rc-actions .cancel {
  background: var(--bg);
  border: 1px solid var(--line);
  color: var(--ink-soft);
}
.rc-sheet .rc-actions .send {
  background: var(--ink);
  color: var(--bg);
}
.rc-sheet .rc-actions .send:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
.s13d-preview strong {
  background: var(--ink);
  color: var(--butter);
  padding: 1px 6px;
  border-radius: 4px;
  font-weight: 700;
}
.s13d-send {
  margin: 18px 20px 12px;
  width: calc(100% - 40px);
  background: var(--accent);
  color: #fff;
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 16px;
  padding: 14px 16px;
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 16px;
  cursor: pointer;
  box-shadow: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.s13d-send .s13d-cost {
  background: var(--ink);
  color: var(--butter);
  padding: 4px 10px;
  border-radius: 999px;
  font-family: 'JetBrains Mono', monospace;
  font-size: 12px;
  letter-spacing: 0.04em;
}
.s13d-send[disabled] {
  opacity: 0.5;
  cursor: not-allowed;
}
.s13d-shortfall {
  margin: 14px 20px 0;
  padding: 12px 14px;
  background: var(--accent-soft);
  border: 1px solid rgba(255, 94, 58, 0.32);
  border-radius: 12px;
  font-family: 'Prompt', sans-serif;
  font-size: 13px;
  line-height: 1.5;
  color: var(--ink);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
}
.s13d-shortfall strong {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  color: var(--accent);
  letter-spacing: -0.02em;
}
.s13d-shortfall .s13d-shortfall-cta {
  margin-left: auto;
  background: var(--ink);
  color: var(--butter);
  padding: 5px 12px;
  border-radius: 999px;
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 12px;
  text-decoration: none;
}

/* S13.sent */
.s13s-stage {
  padding: 36px 24px 24px;
  text-align: center;
}
.s13s-mark {
  width: 60px;
  height: 60px;
  margin: 0 auto 18px;
  background: var(--accent);
  color: #fff;
  border: 2px solid var(--ink);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 4px 4px 0 var(--butter);
}
.s13s-mark svg { width: 28px; height: 28px; }
.s13s-title {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: 30px;
  line-height: 1.05;
  letter-spacing: -0.03em;
  color: var(--ink);
  margin-bottom: 6px;
}
.s13s-title em { font-style: italic; color: var(--accent); }
.s13s-sub {
  font-family: 'Prompt', sans-serif;
  font-size: 14px;
  color: var(--ink-soft);
  margin-bottom: 20px;
}
.s13s-card {
  background: var(--surface);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 16px;
  padding: 14px 16px;
  box-shadow: none;
  text-align: left;
}
.s13s-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 6px 0;
}
.s13s-row .s13s-label {
  font-family: 'Prompt', sans-serif;
  font-weight: 600;
  font-size: 14px;
  color: var(--ink-soft);
}
.s13s-row .s13s-val {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: 22px;
  letter-spacing: -0.02em;
  color: var(--ink);
}
.s13s-cta {
  margin: 18px 22px 12px;
  width: calc(100% - 44px);
  background: var(--ink);
  color: var(--bg);
  border: 1px solid rgba(17, 17, 17, 0.18);
  border-radius: 16px;
  padding: 14px 16px;
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 16px;
  cursor: pointer;
  box-shadow: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  text-decoration: none;
}
.s13s-cta .arrow {
  color: var(--butter);
  font-size: 18px;
  font-weight: 800;
}

/* C2.4 — Recovery code (post-skip path) */
.ob-recovery-avatar {
  width: 50px;
  height: 50px;
  margin: 0 auto 14px;
  position: relative;
  flex-shrink: 0;
}
.ob-recovery-avatar::before {
  content: '';
  position: absolute;
  inset: -10px;
  background: radial-gradient(circle, var(--butter) 0%, transparent 60%);
  opacity: 0.4;
  pointer-events: none;
  z-index: 0;
}
.ob-recovery-avatar svg {
  width: 100%;
  height: 100%;
  display: block;
  position: relative;
  z-index: 1;
}

.ob-recovery-h {
  text-align: center;
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-md);
  font-weight: 600;
  color: var(--ink);
  margin-bottom: 6px;
  line-height: 1.4;
}
.ob-recovery-s {
  text-align: center;
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-sm);
  color: var(--ink-soft);
  line-height: 1.55;
  margin-bottom: 22px;
  padding: 0 6px;
}

.ob-recovery-card {
  background: var(--surface);
  border: 1.5px dashed var(--accent);
  border-radius: 14px;
  padding: 14px 12px;
  text-align: center;
  margin-bottom: 10px;
}
.ob-recovery-code {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: var(--text-lg);
  font-weight: 700;
  color: var(--ink);
  letter-spacing: 0.04em;
}

.ob-recovery-copy {
  appearance: none; -webkit-appearance: none;
  background: var(--butter-soft);
  color: var(--ink);
  border: 1px solid rgba(17,17,17,0.18);
  border-radius: 99px;
  padding: 10px;
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-sm);
  font-weight: 600;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  margin-bottom: 14px;
  cursor: pointer;
  width: 100%;
}
.ob-recovery-copy svg {
  width: 14px;
  height: 14px;
}

.ob-recovery-hint {
  text-align: center;
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-xs);
  color: var(--ink-softer);
  font-style: italic;
  margin-bottom: 6px;
}

/* Inbox row · per-shop mute link. Sits to the right of the time row,
   small italic to avoid competing with the message body. */
/* Inbox.detail — single message view (port from design lines 1042-1246).
   Image hero + offer card omitted in v1 since the Inbox model doesn't
   yet carry image/offer fields; can be slotted in later. */
.inbox-detail-hero {
  padding: 4px 22px 16px;
  display: flex;
  gap: 12px;
  align-items: center;
  flex-shrink: 0;
}
.inbox-detail-hero .idh-logo {
  width: 48px;
  height: 48px;
  border-radius: 14px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: var(--text-md);
  color: #fff;
  letter-spacing: -0.025em;
  background: var(--ink);
  overflow: hidden;
}
.inbox-detail-hero .idh-logo .dot { color: var(--accent); }
.inbox-detail-hero .idh-logo .idh-logo-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.inbox-detail-hero .idh-text { flex: 1; min-width: 0; }
.inbox-detail-hero .idh-shop {
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-md);
  font-weight: 600;
  color: var(--ink);
  line-height: 1.3;
}
.inbox-detail-hero .idh-meta {
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-xs);
  color: var(--ink-soft);
  margin-top: 1px;
}

.inbox-detail-body {
  padding: 0 22px 16px;
  flex-shrink: 0;
}
.inbox-detail-body p {
  font-family: 'Prompt', sans-serif;
  font-size: 14px;
  color: var(--ink-soft);
  line-height: 1.65;
  margin: 0;
}

.inbox-detail-cta {
  padding: 0 22px 8px;
  flex-shrink: 0;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}
.inbox-detail-cta.single { grid-template-columns: 1fr; }
.inbox-detail-cta .idc-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  background: var(--surface);
  border: 1px solid rgba(17,17,17,0.18);
  border-radius: 12px;
  padding: 12px;
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--ink);
  text-decoration: none;
  cursor: pointer;
}
.inbox-detail-cta .idc-btn.primary {
  background: var(--ink);
  color: var(--butter);
  border-color: var(--ink);
}
.inbox-detail-cta .idc-btn svg {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
}

/* Push.prompt — auto-trigger bottom sheet on first PWA open. Hidden by
   default; push-prompt.js un-hides only when the conditions match. */
.pp-overlay {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  pointer-events: none;
}
.pp-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(17,17,17,0.4);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
  z-index: 1;
  pointer-events: auto;
}
.pp-sheet {
  position: relative;
  z-index: 2;
  background: var(--bg);
  border-radius: 24px 24px 0 0;
  padding: 12px 22px 28px;
  box-shadow: 0 -4px 30px -8px rgba(17,17,17,0.3);
  pointer-events: auto;
}
.pp-handle {
  width: 36px;
  height: 4px;
  background: rgba(17,17,17,0.18);
  border-radius: 999px;
  margin: 0 auto 16px;
}
.pp-avatar {
  position: relative;
  width: 64px;
  height: 64px;
  margin: 0 auto 14px;
}
.pp-avatar::before {
  content: '';
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: 110px; height: 110px;
  background: radial-gradient(circle, var(--butter) 0%, transparent 65%);
  opacity: 0.5;
  border-radius: 50%;
  z-index: 0;
}
.pp-avatar svg {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
  display: block;
}
.pp-headline {
  text-align: center;
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-md);
  font-weight: 600;
  color: var(--ink);
  line-height: 1.4;
  margin-bottom: 6px;
}
.pp-sub {
  text-align: center;
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-sm);
  color: var(--ink-soft);
  line-height: 1.55;
  margin-bottom: 16px;
}
.pp-bullet-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 18px;
}
.pp-bullet {
  display: flex;
  gap: 10px;
  align-items: center;
  padding: 9px 12px;
  background: var(--surface);
  border-radius: 11px;
}
.pp-bullet .pb-icon {
  width: 24px;
  height: 24px;
  border-radius: 7px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.pp-bullet .pb-icon.accent { background: var(--accent-soft); color: var(--accent); }
.pp-bullet .pb-icon.butter { background: var(--butter-soft); color: var(--ink); }
.pp-bullet .pb-icon svg { width: 12px; height: 12px; }
.pp-bullet span {
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-xs);
  color: var(--ink);
}
.pp-primary {
  appearance: none; -webkit-appearance: none;
  width: 100%;
  background: var(--ink);
  color: var(--surface);
  border: none;
  border-radius: 99px;
  padding: 13px;
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-base);
  font-weight: 600;
  cursor: pointer;
  margin-bottom: 6px;
}
.pp-secondary {
  display: block;
  text-align: center;
  padding: 10px;
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-sm);
  color: var(--ink-soft);
  text-decoration: underline;
  text-decoration-color: rgba(17,17,17,0.25);
  text-underline-offset: 3px;
  cursor: pointer;
}

/* C9 Shop Story — emotional layer reachable from C1 wordmark.
   Ported from design lines 5497-5599. Menu + reviews omitted in v1. */
/* ============================================================
   shop.story (.ss-*) — Robinhood-style "ทำความรู้จักร้าน" page.
   Cover hero with gradient + decorative coffee-cup + floating
   action buttons; .ss-shop-card overlaps the cover; below that
   a points highlight strip (links to /card/<shop>) and three
   sections: เรื่องราวร้าน / เมนูเด็ด / ติดต่อร้าน. Replaces the
   simple .c9-cover + .c9-thanks + .c9-section block from the
   prior design pass.
   ============================================================ */
.ss-cover {
  position: relative;
  height: 220px;
  background: linear-gradient(160deg, #FFE8B3 0%, #FFCB7A 50%, #E8965A 100%);
  overflow: hidden;
  z-index: 1;
}
.ss-cover::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image:
    radial-gradient(circle at 85% 70%, rgba(255,255,255,0.25) 0%, transparent 50%),
    radial-gradient(circle at 15% 30%, rgba(255,217,82,0.4) 0%, transparent 45%);
  pointer-events: none;
}
.ss-cover-deco {
  position: absolute;
  right: -30px;
  bottom: -30px;
  width: 220px;
  height: 220px;
  opacity: 0.22;
  transform: rotate(-12deg);
  pointer-events: none;
}
.ss-cover-deco svg { width: 100%; height: 100%; display: block; }

.ss-cover-actions {
  position: absolute;
  top: 14px; left: 14px; right: 14px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  z-index: 3;
}
.ss-fab {
  width: 38px; height: 38px;
  border-radius: 50%;
  background: rgba(255,255,255,0.92);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--ink);
  box-shadow: 0 2px 6px rgba(0,0,0,0.10);
  border: none;
  cursor: pointer;
  text-decoration: none;
}
.ss-fab svg {
  width: 18px; height: 18px;
  stroke: currentColor;
  fill: none;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.ss-fab-group { display: flex; gap: 8px; }

.ss-cover-text {
  position: absolute;
  left: 22px;
  bottom: 60px;
  z-index: 2;
  max-width: 65%;
}
.ss-cover-eyebrow {
  font-family: 'Host Grotesk', sans-serif;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(255,255,255,0.95);
  margin-bottom: 6px;
  text-shadow: 0 1px 2px rgba(0,0,0,0.10);
}
.ss-cover-headline {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 22px;
  line-height: 1.15;
  color: #fff;
  letter-spacing: -0.015em;
  text-shadow: 0 1px 4px rgba(0,0,0,0.15);
}

/* Shop card — overlaps cover by ~40px */
.ss-shop-card {
  position: relative;
  margin: -40px 14px 0;
  background: var(--surface);
  border-radius: 18px;
  box-shadow: 0 6px 18px rgba(0,0,0,0.08);
  padding: 14px;
  display: flex;
  align-items: center;
  gap: 12px;
  z-index: 2;
}
/* ============================================================
   Shared .shop-avatar — single visual treatment for shop logos
   used everywhere (chat, inbox, voucher card, /story, /card).
   Wraps {% include "_partials/_shop_avatar_compact" %} which
   renders inner content (image / lt-* wordmark / initial) for
   any of the three logo states. All sizes are rounded rectangles
   so a shop's identity reads the same shape everywhere — only
   the size and corner radius scale.
     .shop-avatar--xs   28px (chat bubble)
     .shop-avatar--sm   36px (chat header / small list rows)
     .shop-avatar--md   40px (inbox row / voucher / cards list)
     .shop-avatar--lg   56px (/story shop card)
     .shop-avatar--xl   96px (/card identity hero)
   ============================================================ */
.shop-avatar {
  /* Per-shop chip colors driven by the shop's chosen theme. The
     _shop_avatar_compact partial sets --shop-color (bg) and
     --shop-ink (text) inline via shop_theme_bg / shop_theme_ink so
     the same shop reads consistently across every surface — even
     pages not wrapped in .theme-X. Fallback #111 / #fff when no
     shop theme is available. */
  flex-shrink: 0;
  background: var(--shop-color, #111);
  color: var(--shop-ink, #fff);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  letter-spacing: -0.04em;
  line-height: 1;
  overflow: hidden;
  padding: 2px 4px;
  white-space: nowrap;
}
.shop-avatar > span,
.shop-avatar > span > span:not(.dot) { color: inherit; }
/* .dot keeps the theme accent — the trailing period reads as the
   shop's identity color regardless of bg, so `Coffee.` shows the
   period in #FF5E3A on taemdee, #FFD952 on night, etc. */
.shop-avatar .dot { color: var(--accent); }
.shop-avatar img,
.shop-avatar .shop-avatar-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.shop-avatar--xs {
  width: 28px; height: 28px; border-radius: 10px;
  font-size: 9px; padding: 2px 3px;
}
.shop-avatar--sm {
  width: 36px; height: 36px; border-radius: 12px;
  font-size: 10px;
}
.shop-avatar--md {
  width: 40px; height: 40px; border-radius: 11px;
  font-size: 11px; padding: 3px 4px;
}
.shop-avatar--lg {
  width: 56px; height: 56px; border-radius: 14px;
  font-size: 12px; padding: 4px 6px;
}
.shop-avatar--xl {
  width: 96px; height: 96px; border-radius: 22px;
  font-size: 18px; padding: 6px 10px;
  margin: 0 auto;
}

/* Standalone .shop-avatar-img rule for any future caller that drops
   the partial outside a .shop-avatar wrapper. */
.shop-avatar-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* ============================================================
   Voucher card — "ของขวัญพร้อมใช้" carousel section. Rendered by
   _partials/voucher_section.html and shared between /my-cards
   (multi-card carousel) and /my-gifts (single hero card via
   .cl-voucher-section.single → 100% width, no scroll snap).

   Two-section card: image strip on top (gradient + reward
   illustration + "พร้อมใช้" pulse pill) and a body below
   (shop chip + name, reward text, white pill CTA).
   ============================================================ */
.cl-voucher-section { margin-bottom: 14px; }
.cl-voucher-carousel {
  display: flex;
  gap: 10px;
  overflow-x: auto;
  overflow-y: hidden;
  padding: 0 14px 6px;
  scroll-snap-type: x mandatory;
  scroll-padding-left: 14px;
  scrollbar-width: none;
}
.cl-voucher-carousel::-webkit-scrollbar { display: none; }
.cl-voucher-section.single .cl-voucher-carousel {
  overflow: visible;
  scroll-snap-type: none;
  padding: 0 16px 6px;
}
/* flex: 0 0 70% on the base card pins it at 70% width even with
   max-width 100%. Override the flex-basis so the single card
   actually fills the row. */
.cl-voucher-section.single .cl-voucher-card {
  flex: 1 1 100%;
  width: 100%;
  max-width: 100%;
}

.cl-voucher-card {
  flex: 0 0 70%;
  max-width: 240px;
  scroll-snap-align: start;
  border-radius: 18px;
  overflow: hidden;
  text-decoration: none;
  color: inherit;
  /* Per-shop tint via --shop-color (set inline). Lighter at 0%,
     base at 55%, darker at 100% — the design's hand-picked
     gradient shape, driven by the shop's swatch. */
  background: linear-gradient(
    135deg,
    color-mix(in srgb, var(--shop-color, #FF5E3A) 75%, #fff) 0%,
    var(--shop-color, #FF5E3A) 55%,
    color-mix(in srgb, var(--shop-color, #FF5E3A) 70%, #000) 100%
  );
  color: #fff;
  position: relative;
  box-shadow: 0 10px 22px -10px color-mix(in srgb, var(--shop-color, #FF5E3A) 60%, transparent);
  cursor: pointer;
  display: flex;
  flex-direction: column;
  border: none;
  text-align: left;
  font: inherit;
  padding: 0;
}
.cl-voucher-card::before {
  content: '';
  position: absolute; inset: 0;
  background-image:
    radial-gradient(circle at 18% 30%, rgba(255,255,255,0.22) 0, transparent 8%),
    radial-gradient(circle at 82% 18%, rgba(255,255,255,0.18) 0, transparent 12%),
    radial-gradient(circle at 60% 85%, rgba(255,255,255,0.20) 0, transparent 9%),
    radial-gradient(circle at 30% 75%, rgba(255,255,255,0.15) 0, transparent 8%),
    radial-gradient(circle at 90% 60%, rgba(255,217,82,0.30) 0, transparent 14%);
  pointer-events: none;
  z-index: 0;
}
.cl-voucher-card > * { position: relative; z-index: 1; }
.cl-voucher-card:active { transform: scale(0.99); }

.cl-voucher-image {
  height: 110px;
  position: relative;
  overflow: hidden;
  background: rgba(0, 0, 0, 0.18);
}
.cl-voucher-image .reward-svg {
  width: 100%;
  height: 100%;
  display: block;
  opacity: 0.9;
}
.cl-voucher-image::after {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(180deg, transparent 50%, rgba(0,0,0,0.18) 100%);
  pointer-events: none;
}
.cl-voucher-image .v-tag {
  position: absolute;
  top: 12px; left: 12px;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  background: rgba(0,0,0,0.55);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  padding: 4px 9px;
  border-radius: 99px;
  color: #fff;
  font-family: 'Prompt', sans-serif;
  font-size: 10.5px;
  font-weight: 600;
  z-index: 2;
}
.cl-voucher-image .v-tag .pulse {
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--butter);
  animation: cl-pulse 1.5s infinite;
}
@keyframes cl-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(255,217,82,0.7); }
  70%  { box-shadow: 0 0 0 8px rgba(255,217,82,0); }
  100% { box-shadow: 0 0 0 0 rgba(255,217,82,0); }
}

.cl-voucher-body {
  padding: 12px 14px 14px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  /* Body grows to fill remaining card height so CTAs align at the
     bottom across cards with different reward-text lengths in the
     carousel (flex stretches all cards to the tallest height). */
  flex: 1;
}
.cl-voucher-shop {
  display: flex;
  align-items: center;
  gap: 8px;
}
.cl-voucher-shop .name {
  font-family: 'Prompt', sans-serif;
  font-weight: 600;
  font-size: 15px;
  color: rgba(255,255,255,0.95);
  flex: 1;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cl-voucher-reward {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 17px;
  line-height: 1.3;
  color: #fff;
  letter-spacing: -0.01em;
}
.cl-voucher-cta {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 11px 14px;
  background: rgba(255,255,255,0.96);
  color: var(--shop-color, var(--accent));
  border-radius: 10px;
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 14.5px;
  /* Pin to the bottom of .cl-voucher-body so CTAs align across
     cards in the carousel. */
  margin-top: auto;
}
.cl-voucher-cta svg {
  width: 14px; height: 14px;
  stroke: currentColor; fill: none;
  stroke-width: 2.4;
  stroke-linecap: round; stroke-linejoin: round;
}

.ss-shop-info {
  flex: 1;
  min-width: 0;
}
.ss-shop-name {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: var(--text-md);
  color: var(--ink);
  line-height: 1.2;
  letter-spacing: -0.01em;
  margin-bottom: 2px;
}
.ss-shop-sub {
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-2xs);
  color: var(--ink-soft);
  margin-bottom: 4px;
}
.ss-shop-meta {
  display: flex;
  align-items: center;
  gap: 4px;
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-2xs);
  color: var(--ink-soft);
}
.ss-shop-meta .open-dot {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: #06C755;
  display: inline-block;
}
.ss-shop-meta .closed-dot {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--ink-softer);
  display: inline-block;
}
.ss-shop-meta strong {
  color: var(--ink);
  font-weight: 600;
}

/* Points highlight — links to /card/<shop>. Shown only when the
   customer already has at least one stamp here. */
.ss-points {
  margin: 14px 14px 0;
  padding: 14px 16px;
  background: var(--butter-soft);
  border-radius: 16px;
  display: flex;
  align-items: center;
  gap: 12px;
  cursor: pointer;
  border: 1px solid rgba(255, 217, 82, 0.4);
  text-decoration: none;
  color: inherit;
}
.ss-points-body {
  flex: 1;
  min-width: 0;
}
.ss-points-row {
  display: flex;
  align-items: baseline;
  gap: 4px;
  margin-bottom: 6px;
}
.ss-points-num {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: 22px;
  color: var(--ink);
  line-height: 1;
  letter-spacing: -0.02em;
}
.ss-points-of {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 600;
  font-size: 13px;
  color: var(--ink-soft);
}
.ss-points-hint {
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--accent);
  margin-left: auto;
}
.ss-points-bar {
  height: 5px;
  background: rgba(17,17,17,0.08);
  border-radius: 99px;
  overflow: hidden;
}
.ss-points-fill {
  height: 100%;
  background: var(--accent);
  border-radius: 99px;
}
.ss-points-arrow {
  flex-shrink: 0;
  color: var(--ink-soft);
  margin-left: 4px;
}
.ss-points-arrow svg {
  width: 18px; height: 18px;
  stroke: currentColor;
  fill: none;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Section header (consistent across blocks) */
.ss-section-h {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: var(--text-lg);
  color: var(--ink);
  letter-spacing: -0.01em;
  margin: 28px 22px 12px;
}

/* Story — italic quote + signature */
.ss-story {
  margin: 0 14px;
  padding: 16px 18px;
  background: var(--surface);
  border-radius: 16px;
  border: 1px solid var(--line);
}
.ss-story-text {
  font-family: 'Prompt', sans-serif;
  font-style: italic;
  font-weight: 400;
  font-size: var(--text-sm);
  line-height: 1.65;
  color: var(--ink);
  letter-spacing: -0.005em;
  white-space: pre-line;
}
/* Menu — 2-col grid (Robinhood-style) of shop menu items. Each tile
   is a 1:1 aspect-ratio gradient image area + name + price below.
   `:nth-child` cycles four palette gradients so visiting a shop with
   ≥4 items reads as variety even though all images are emoji. */
.ss-menu-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  padding: 0 14px;
}
.ss-menu-item {
  background: var(--surface);
  border-radius: 16px;
  overflow: hidden;
  border: 1px solid var(--line);
  position: relative;
  display: flex;
  flex-direction: column;
}
.ss-menu-img {
  aspect-ratio: 1 / 1;
  background: linear-gradient(135deg, #FFF7DA 0%, #FFE8B3 100%);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 56px;
  line-height: 1;
  position: relative;
}
.ss-menu-item:nth-child(4n+2) .ss-menu-img {
  background: linear-gradient(135deg, #FFEDD8 0%, #FFD2A8 100%);
}
.ss-menu-item:nth-child(4n+3) .ss-menu-img {
  background: linear-gradient(135deg, #FFE0E0 0%, #FFC2C2 100%);
}
.ss-menu-item:nth-child(4n+4) .ss-menu-img {
  background: linear-gradient(135deg, #E8F5E0 0%, #C8E8B8 100%);
}
.ss-menu-tag {
  position: absolute;
  top: 8px;
  left: 8px;
  padding: 4px 10px;
  background: var(--mint-ink);
  color: #fff;
  font-family: 'Prompt', sans-serif;
  font-size: 9.5px;
  font-weight: 600;
  border-radius: 99px;
  letter-spacing: 0.01em;
  line-height: 1.2;
  z-index: 1;
}
.ss-menu-info {
  padding: 10px 12px 12px;
}
.ss-menu-name {
  font-family: 'Prompt', sans-serif;
  font-weight: 600;
  font-size: var(--text-sm);
  color: var(--ink);
  line-height: 1.25;
  margin-bottom: 4px;
}
.ss-menu-price {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 700;
  font-size: 13px;
  color: var(--ink);
  letter-spacing: -0.01em;
}
.ss-menu-price .baht {
  color: var(--ink-soft);
  font-weight: 500;
  margin-right: 1px;
}

/* Info — key/value rows with dashed dividers */
.ss-info {
  margin: 0 14px 24px;
  padding: 4px 18px;
  background: var(--surface);
  border-radius: 16px;
  border: 1px solid var(--line);
}
.ss-info-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: 12px 0;
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-sm);
}
.ss-info-row + .ss-info-row {
  border-top: 1px dashed rgba(17,17,17,0.10);
}
.ss-info-key {
  color: var(--ink-soft);
  font-weight: 500;
}
.ss-info-val {
  color: var(--ink);
  font-weight: 600;
}

/* Customer dock · liquid glass nav. Pinned to bottom on every C1/C5/C7/
   Inbox/C6/C9/C8 — mirrors shop-side .s3-glass-nav. Position FIXED, not
   sticky (design says sticky but .td overflow-x:hidden breaks sticky-
   bottom in prod — see memory feedback_dock_position_fixed). */
/* .c-glass-nav shares its full chassis with .s3-glass-nav above —
   the shared block handles the 5-column grid, tab padding, and label
   sizing for both docks. No customer-specific overrides needed since
   shop also moved to 5 tabs (cards/scan/inbox/gifts/settings vs
   home/issue/customers/insights/settings). */

/* When the dock is present, leave room at the bottom of `.td` so it doesn't
   sit on top of the last content row. Applied via .has-c-dock on the
   container so it's opt-in per page. */
.td.has-c-dock {
  padding-bottom: 102px;
}

/* C5 voucher · served state. After the shop scans the customer's QR
   within the served-window, the voucher swaps to a greyed "✓ ใช้แล้ว"
   label so the customer can see the redemption was fulfilled. */
.c5 .voucher.served {
  opacity: 0.62;
  filter: saturate(0.6);
}
.c5 .voucher.served .v-label .v-served {
  color: var(--mint-ink);
  font-weight: 700;
  letter-spacing: 0;
}
.c5 .voucher.served .v-title {
  text-decoration: line-through;
  text-decoration-thickness: 1.5px;
  text-decoration-color: rgba(17,17,17,0.45);
}

/* C7/Inbox · page-head — greeting + sub + ph-actions on the right.
   Replaces the .app-bar pattern for primary destinations from the dock. */
.page-head {
  padding: 14px 22px 14px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-shrink: 0;
}
.page-head .ph-text { flex: 1; min-width: 0; }
.page-head h1 {
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-xl);
  font-weight: 600;
  color: var(--ink);
  line-height: 1.25;
  margin: 0;
}
.page-head h1 .ph-name { color: var(--accent); }
.page-head .ph-sub {
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-xs);
  color: var(--ink-soft);
  margin-top: 3px;
}
.page-head .ph-actions {
  display: flex;
  gap: 8px;
  flex-shrink: 0;
}
.page-head .ph-icon-btn {
  width: 44px;
  height: 44px;
  background: rgba(17,17,17,0.05);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  color: var(--ink);
  text-decoration: none;
}
.page-head .ph-icon-btn svg { width: 22px; height: 22px; }

/* Profile avatar button in the page-head action row. Picture or
   initial-on-accent fallback. Tap opens the profile-edit sheet. */
.page-head .ph-avatar {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 0;
  /* Match .ph-icon-btn (search / QR) so the action row reads as one
     uniform chrome — three discs in a line. The accent fill we used
     to use stuck out as a fourth visual element. */
  background: rgba(17,17,17,0.05);
  color: var(--ink);
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  padding: 0;
  overflow: visible;       /* badge sticks out of the circle */
  flex-shrink: 0;
  position: relative;
}
.page-head .ph-avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  border-radius: 50%;
}
.page-head .ph-avatar:active { transform: scale(0.94); }
/* Gear overlay — the avatar is now the entry to ตั้งค่า (the dock
   dropped its settings tab), so a small gear disc on the lower-right
   flags that tapping it opens settings. Mirrors .ph-avatar-badge's
   disc + page-bg ring so the two corner chips read as one language. */
.page-head .ph-avatar-gear {
  position: absolute;
  bottom: -3px; right: -3px;
  width: 17px; height: 17px;
  border-radius: 50%;
  background: var(--ink);
  color: #fff;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 0 0 2px var(--bg);
  pointer-events: none;
}
.page-head .ph-avatar-gear svg { width: 11px; height: 11px; display: block; }
/* Pending-todos count chip — same shape + ring as the shop side's
   .gn-badge.has-count so both surfaces' "X notifications" chip
   reads with one visual language. Accent fill, ring punched out of
   the page bg, soft pulse. */
.page-head .ph-avatar-badge {
  position: absolute;
  top: -4px; right: -4px;
  min-width: 16px; height: 16px;
  padding: 0 4px;
  border-radius: 99px;
  background: var(--accent); color: #fff;
  font-family: 'Prompt', sans-serif;
  font-size: 9px; font-weight: 700;
  line-height: 1;
  display: flex; align-items: center; justify-content: center;
  pointer-events: none;
  box-shadow: 0 0 0 2px var(--bg);
  animation: gn-badge-pulse 1.6s ease-out infinite;
}

/* Profile-edit form — display name + picture uploader. Rendered
   inline on /card/account (.profile-edit-inline) and /shop/settings,
   and in the staff profile sheet. */
.profile-edit-form { padding: 0 8px; }
.pe-avatar-wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  margin: 8px 0 18px;
}
.pe-avatar {
  position: relative;
  width: 96px;
  height: 96px;
  border-radius: 50%;
  background: var(--accent);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Prompt', sans-serif;
  font-weight: 800;
  font-size: 38px;
  cursor: pointer;
  border: 0;
  /* No overflow:hidden here — the .pe-edit-badge needs to extend
     outside the avatar circle to look like a camera-corner stamp.
     The image gets its own border-radius below to stay round. */
}
.pe-avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 50%;
}
.pe-avatar .pe-edit-badge {
  position: absolute;
  bottom: -2px; right: -2px;
  width: 32px; height: 32px;
  border-radius: 50%;
  background: var(--ink);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 2px solid var(--surface);
}
.pe-avatar .pe-edit-badge svg { width: 16px; height: 16px; }
.pe-default-btn {
  background: transparent;
  border: 0;
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-sm);
  color: var(--ink-soft);
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
  padding: 4px 8px;
}
.pe-label {
  display: block;
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-xs);
  color: var(--ink-soft);
  margin-bottom: 6px;
  letter-spacing: 0.02em;
}
/* Single selector so customer + staff sheets both pick this up — was
   keyed on #profile-edit-name only, leaving the staff input with the
   browser-default border. */
.profile-edit-form input[type="text"] {
  width: 100%;
  padding: 13px 14px;
  border: 1.5px solid var(--ink);
  border-radius: 14px;
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-md);
  background: var(--surface);
  outline: none;
}
.pe-actions {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin-top: 18px;
}
.pe-cancel,
.pe-save {
  padding: 13px;
  border-radius: 14px;
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: var(--text-md);
  cursor: pointer;
  border: 0;
}
.pe-cancel {
  background: transparent;
  border: 1.5px solid rgba(17, 17, 17, 0.18);
  color: var(--ink);
}
.pe-save {
  background: var(--accent);
  color: #fff;
  box-shadow: 0 6px 16px -4px rgba(255, 94, 58, 0.45);
}
.pe-save:active,
.pe-cancel:active { transform: scale(0.98); }
/* /shop/no_permission — friendly 403 for staff who tap a gated link.
   Centered card with lock icon, message, and "back to dashboard" CTA. */
.no-perm {
  margin: 40px 24px 0;
  text-align: center;
}
.no-perm-icon {
  width: 64px;
  height: 64px;
  margin: 0 auto 18px;
  border-radius: 50%;
  background: rgba(255, 94, 58, 0.08);
  color: var(--accent);
  display: flex;
  align-items: center;
  justify-content: center;
}
.no-perm-icon svg { width: 30px; height: 30px; }
.no-perm h1 {
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-xl);
  font-weight: 700;
  margin: 0 0 8px;
  color: var(--ink);
}
.no-perm p {
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-sm);
  color: var(--ink-soft);
  line-height: 1.55;
  margin: 0 auto 18px;
  max-width: 320px;
}
.no-perm-detail {
  font-family: 'JetBrains Mono', monospace;
  font-size: var(--text-2xs);
  color: var(--ink-softer);
  margin-bottom: 18px;
}
.no-perm-cta {
  display: inline-block;
  padding: 12px 22px;
  border-radius: 14px;
  background: var(--accent);
  color: #fff;
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: var(--text-md);
  text-decoration: none;
  box-shadow: 0 6px 16px -4px rgba(255, 94, 58, 0.45);
}
.no-perm-cta:active { transform: scale(0.98); }

/* line.friend.prompt — soft inline banner asking the customer to add
   @taemdee as a friend on LINE so DeeReach `line` campaigns can
   actually deliver. Renders only when the customer has a line_id but
   no friend_status='friended' yet. Tap → opens LINE app to add the OA. */
.line-friend-prompt {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 8px 22px 14px;
  padding: 12px 14px;
  background: linear-gradient(135deg, #06C755 0%, #04a045 100%);
  color: #fff;
  border-radius: 14px;
  text-decoration: none;
  box-shadow: 0 6px 16px -6px rgba(6, 199, 85, 0.45);
  transition: transform .12s ease, opacity .15s ease;
}
.line-friend-prompt:active { transform: scale(0.985); opacity: 0.92; }
.line-friend-prompt .lfp-icon {
  width: 32px; height: 32px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.18);
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
.line-friend-prompt .lfp-icon svg { width: 18px; height: 18px; }
.line-friend-prompt .lfp-text {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.line-friend-prompt .lfp-h {
  font-family: 'Prompt', sans-serif;
  font-weight: 600;
  font-size: var(--text-sm);
  line-height: 1.25;
}
.line-friend-prompt .lfp-h strong { font-weight: 700; }
.line-friend-prompt .lfp-s {
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-xs);
  opacity: 0.85;
}
.line-friend-prompt .lfp-arrow {
  font-size: 24px;
  font-weight: 600;
  flex-shrink: 0;
  opacity: 0.85;
}

/* Shared tab-pill row — used on /my-inbox (customer) and
   /shop/messages (shop) to split content into kind tabs.
   Inactive pill is transparent with a soft rounded border so the
   page texture shows through; active flips to ink fill. flex:1
   so the pills share the row evenly. */
.tab-pills {
  display: flex;
  gap: 6px;
  margin: 0 0 12px;
  /* Left-align: pills size to their content (no flex:1 stretch),
     so the row hugs the start of the container instead of spanning
     the full width like a segmented control. */
  justify-content: flex-start;
}
.tab-pill {
  appearance: none; -webkit-appearance: none;
  flex: 0 0 auto;
  min-width: 96px;
  padding: 5px 22px;
  border-radius: 999px;
  font-family: 'Prompt', sans-serif;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink-soft);
  background: transparent;
  border: 1px solid rgba(17, 17, 17, 0.18);
  white-space: nowrap;
  cursor: pointer;
  text-align: center;
}
.tab-pill.active {
  color: var(--accent);
}

/* Inbox card list — replaces the old .inbox-row markup. */
/* ── Inbox filters + list ─────────────────────────────────────────
   Mirrors design/taemdee-customer.html → inbox.list. Filter pills
   above (ทั้งหมด · ยังไม่อ่าน · มีของฝาก) drive a JS filter.
   Cards use a 6px dot (top-left) for unread + butter-soft .ic-offer
   chip when a row carries an attached voucher. */
.inbox-filters {
  padding: 0 22px 14px;
  display: flex;
  gap: 6px;
  overflow-x: auto;
  scrollbar-width: none;
  flex-shrink: 0;
}
.inbox-filters::-webkit-scrollbar { display: none; }
.inbox-filter-pill {
  padding: 6px 12px;
  border-radius: 99px;
  font-family: 'Prompt', sans-serif;
  font-size: 11.5px;
  color: var(--ink-soft);
  background: var(--surface);
  border: 1px solid rgba(17,17,17,0.12);
  white-space: nowrap;
  cursor: pointer;
  flex-shrink: 0;
}
.inbox-filter-pill.active {
  background: var(--ink);
  color: var(--surface);
  border-color: var(--ink);
  font-weight: 500;
}

.inbox-list {
  margin: 0;
  padding: 0 14px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  flex: 1;
}
.inbox-card {
  background: var(--surface);
  border-radius: 14px;
  padding: 12px;
  display: flex;
  gap: 11px;
  position: relative;
  box-shadow: 0 1px 2px rgba(17,17,17,0.04);
  cursor: pointer;
  text-decoration: none;
  color: inherit;
  transition: transform 0.12s ease;
}
.inbox-card:active { transform: scale(0.99); }
.inbox-card.read {
  background: rgba(253,250,242,0.55);
  box-shadow: none;
}
.inbox-card.read .ic-body { opacity: 0.7; }
.inbox-card .ic-unread-dot {
  position: absolute;
  top: 14px;
  left: 4px;
  width: 6px;
  height: 6px;
  background: var(--accent);
  border-radius: 50%;
}

.inbox-card .ic-body { flex: 1; min-width: 0; }
.inbox-card .ic-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 6px;
}
.inbox-card .ic-shop {
  font-family: 'Prompt', sans-serif;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--ink);
  line-height: 1.3;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.inbox-card.read .ic-shop {
  font-weight: 500;
  color: var(--ink-soft);
}
.inbox-card .ic-time {
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-2xs);
  color: var(--ink-softer);
  flex-shrink: 0;
}
.inbox-card .ic-preview {
  font-family: 'Prompt', sans-serif;
  font-size: 12.5px;
  color: var(--ink);
  line-height: 1.45;
  margin-top: 2px;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 1;
  line-clamp: 1;
  -webkit-box-orient: vertical;
}
.inbox-card.read .ic-preview { color: var(--ink-soft); }

/* Offer pill — surfaces "ของฝาก: …" inline on the card so the
   customer can see at a glance that a row has an attached voucher
   without opening it. butter-soft tint pairs with the accent dot. */
.inbox-card .ic-offer {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  background: var(--butter-soft);
  padding: 3px 9px;
  border-radius: 99px;
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-2xs);
  font-weight: 500;
  color: var(--ink);
  margin-top: 6px;
}
.inbox-card .ic-offer svg {
  width: 11px;
  height: 11px;
  flex-shrink: 0;
}

/* Inline "แชท" tag — distinguishes a 2-way chat thread row from a
   1-way DeeReach broadcast in the mixed inbox feed. Squarish chip
   so it reads as a kind label, not a count badge. */
.inbox-card .ic-tag-chat {
  display: inline-flex;
  align-items: center;
  margin-left: 6px;
  padding: 1px 6px;
  border-radius: 4px;
  background: var(--accent);
  color: #fff;
  font-family: 'Host Grotesk', sans-serif;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  vertical-align: middle;
}
.inbox-card.read .ic-tag-chat {
  background: var(--ink-softer);
}

/* Inbox empty state — typography hero: a giant 0. (Host Grotesk +
   accent dot) reads as identity, not a placeholder illustration.
   Overrides the older .inbox-empty .h/.s rule earlier in the file —
   that markup is dead now. */
.inbox-empty {
  margin: 0;
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 60px 30px;
  text-align: center;
}
.inbox-empty .ie-mark {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: 96px;
  line-height: 0.9;
  letter-spacing: -0.06em;
  color: var(--ink);
  margin: 0 0 20px;
  display: inline-flex;
  align-items: baseline;
}
.inbox-empty .ie-mark-dot {
  color: var(--accent);
  margin-left: 2px;
}
.inbox-empty .ie-h {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: var(--text-md);
  color: var(--ink);
  letter-spacing: -0.01em;
  margin-bottom: 6px;
}
.inbox-empty .ie-msg {
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-sm);
  color: var(--ink-soft);
  line-height: 1.6;
  max-width: 260px;
}

/* C6 ขนาดตัวอักษร — sm/md/lg picker (ported from design 5800-5860). */
.s10-fontsize {
  background: var(--surface);
  border: none;
  border-radius: 12px;
  padding: 10px 14px;
  margin: 0 0 4px;
}
.s10-fontsize .fs-head {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 8px;
}
.s10-fontsize .fs-icon {
  width: 24px; height: 24px;
  background: transparent; color: var(--ink-soft);
  border: none; border-radius: 0;
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: var(--text-md);
  letter-spacing: -0.04em;
}
.s10-fontsize .fs-info { line-height: 1.2; }
.s10-fontsize .fs-name {
  font-family: 'Prompt', sans-serif;
  font-weight: 700; font-size: var(--text-base);
  letter-spacing: -0.01em;
  margin-bottom: 1px;
}
.s10-fontsize .fs-meta {
  font-family: 'Prompt', sans-serif;
  font-style: italic; font-weight: 400;
  font-size: var(--text-xs); color: var(--ink-soft);
}
.s10-fontsize .fs-options {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 6px;
}
.s10-fontsize .fs-opt {
  appearance: none; -webkit-appearance: none;
  background: var(--bg);
  border: 1px solid rgba(17,17,17,0.18);
  border-radius: 10px;
  padding: 10px 8px;
  cursor: pointer;
  text-align: center;
  font-family: 'Prompt', sans-serif;
  color: var(--ink);
  transition: none;
}
.s10-fontsize .fs-opt.sm { font-size: var(--text-xs); font-weight: 500; }
.s10-fontsize .fs-opt.md { font-size: var(--text-base); font-weight: 600; }
.s10-fontsize .fs-opt.lg { font-size: var(--text-md); font-weight: 600; }
.s10-fontsize .fs-opt.active {
  border: 2px solid var(--accent);
  padding: 9px 7px;
  font-weight: 700;
}

/* C6 ขนาดตัวอักษร — toggles root rem so any rule using --text-* (rem)
   tokens scales naturally. Per Apr 30 design refresh: rem-based, not
   zoom — accessibility-correct (Apple HIG, WCAG) and standard CSS.
   Existing px-based rules stay fixed; future ports of px → var(--text-*)
   widen the scope of what scales. */
html { font-size: 16px; }
html.fs-sm { font-size: 14px; }   /* −12.5% */
html.fs-md { font-size: 16px; }   /* default */
html.fs-lg { font-size: 18px; }   /* +12.5% */

/* C-gifts — list of vouchers/rewards (Apr 30 design refresh). The
   placeholder /my-gifts route renders an empty state for now; section/
   card markup is wired so step B can surface real Voucher rows
   without a template change. */
.c-gifts-section.last { padding-bottom: 100px; }
.c-gifts-label.muted { color: var(--ink-soft); }
.c-gifts-label .star {
  width: 12px; height: 12px;
  color: var(--butter);
}

.gift-card.used {
  background: rgba(17,17,17,0.04);
  opacity: 0.6;
  border-color: transparent;
}
.gift-card.used .gc-icon {
  background: rgba(17,17,17,0.06);
  border: none;
  width: 36px; height: 36px;
  border-radius: 10px;
  font-size: var(--text-md);
}
.gift-card .gc-icon.butter { background: var(--butter); border: 1px solid var(--ink); }
.gift-card .gc-icon.mint { background: var(--mint); border: 1px solid var(--mint-ink); }
.gift-card .gc-icon.accent { background: var(--accent-soft); border: 1px solid var(--accent); }
.gift-card.used .gc-name {
  text-decoration: line-through;
  font-weight: 600;
  font-size: var(--text-xs);
}
.gift-card.used .gc-meta {
  font-size: var(--text-2xs);
}
/* Mint check tag — replaces .gc-cta on used vouchers so the row
   reads "consumed" without a CTA the customer can re-tap. */
/* ============================================================
   voucher.use — fullscreen voucher screen reached from gifts.list.
   Trust-based: pressing "ใช้" stamps the redemption with served_at,
   then we render this page so the customer shows it to staff. QR is
   audit-trail (optional) — staff can verify by visual check.
   ============================================================ */
.voucher-screen {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 14px 22px 22px;
  text-align: center;
}
.voucher-screen .vs-shop {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 5px 14px 5px 5px;
  background: var(--surface);
  border-radius: 99px;
  border: 1px solid rgba(17,17,17,0.08);
  margin-bottom: 22px;
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-xs);
  color: var(--ink);
}
.voucher-screen .vs-shop .vss-logo {
  width: 22px;
  height: 22px;
  background: var(--ink);
  border-radius: 6px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: var(--text-2xs);
  color: #fff;
  letter-spacing: -0.025em;
  flex-shrink: 0;
}
.voucher-screen .vs-shop .vss-logo .dot { color: var(--accent); }
.voucher-screen .vs-headline {
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-base);
  color: var(--ink-soft);
  margin-bottom: 6px;
}
.voucher-screen .vs-offer {
  font-family: 'Prompt', sans-serif;
  font-size: 28px;
  font-weight: 700;
  color: var(--ink);
  line-height: 1.2;
  margin-bottom: 24px;
}
.voucher-screen .vs-qr-frame {
  width: 200px;
  height: 200px;
  background: var(--surface);
  border-radius: 20px;
  padding: 14px;
  box-sizing: border-box;
  margin: 0 auto 14px;
  box-shadow: 0 4px 24px -8px rgba(17,17,17,0.18);
}
.voucher-screen .vs-qr-frame svg {
  width: 100%;
  height: 100%;
  display: block;
}
.voucher-screen .vs-instruction {
  font-family: 'Prompt', sans-serif;
  font-size: 12.5px;
  color: var(--ink-soft);
  margin-bottom: 14px;
}
.voucher-screen .vs-countdown {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--accent-soft);
  color: var(--accent);
  padding: 7px 14px;
  border-radius: 99px;
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-sm);
  font-weight: 600;
  margin-bottom: 14px;
}
.voucher-screen .vs-countdown svg {
  width: 12px;
  height: 12px;
}

/* C-scan modal — fullscreen QR scanner reached from dock "สแกน" tab.
   Ported from design lines 3345-3479 (Apr 30 design refresh).
   Camera viewfinder with butter corner brackets + subtle scanning
   line, dark backdrop so the camera feed dominates. */
.c-scan-modal {
  background: #0a0a0a;
  color: #fff;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  padding-bottom: 0;
}
.c-scan-modal .csm-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 18px 16px;
}
.c-scan-modal .csm-title {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: var(--text-md);
  color: #fff;
}
.c-scan-modal .csm-x {
  width: 36px; height: 36px;
  background: rgba(255,255,255,0.12);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  cursor: pointer;
  text-decoration: none;
}
.c-scan-modal .csm-x svg { width: 18px; height: 18px; }
.c-scan-modal .csm-spacer { width: 36px; height: 36px; }

.c-scan-modal .csm-stage {
  flex: 1;
  padding: 8px 24px 0;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.c-scan-modal .csm-viewfinder {
  width: 100%;
  aspect-ratio: 1;
  background: #000;
  border-radius: 22px;
  position: relative;
  overflow: hidden;
  margin-bottom: 16px;
}
.c-scan-modal .csm-viewfinder video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.c-scan-modal .vf-corners {
  position: absolute;
  inset: 28px;
  pointer-events: none;
}
.c-scan-modal .vf-corners::before,
.c-scan-modal .vf-corners::after,
.c-scan-modal .vf-corners > .ct,
.c-scan-modal .vf-corners > .cb {
  content: '';
  position: absolute;
  width: 32px; height: 32px;
}
.c-scan-modal .vf-corners::before {
  top: 0; left: 0;
  border-top: 4px solid var(--butter);
  border-left: 4px solid var(--butter);
  border-radius: 8px 0 0 0;
}
.c-scan-modal .vf-corners::after {
  top: 0; right: 0;
  border-top: 4px solid var(--butter);
  border-right: 4px solid var(--butter);
  border-radius: 0 8px 0 0;
}
.c-scan-modal .vf-corners .ct {
  bottom: 0; left: 0;
  border-bottom: 4px solid var(--butter);
  border-left: 4px solid var(--butter);
  border-radius: 0 0 0 8px;
}
.c-scan-modal .vf-corners .cb {
  bottom: 0; right: 0;
  border-bottom: 4px solid var(--butter);
  border-right: 4px solid var(--butter);
  border-radius: 0 0 8px 0;
}
.c-scan-modal .vf-line {
  position: absolute;
  left: 28px; right: 28px;
  top: 50%;
  height: 2px;
  background: linear-gradient(90deg, transparent, var(--butter), transparent);
  box-shadow: 0 0 12px rgba(255,217,82,0.5);
  animation: csm-vf-line 2.2s ease-in-out infinite;
}
@keyframes csm-vf-line {
  0%, 100% { transform: translateY(-40%); opacity: 0.85; }
  50%      { transform: translateY(40%); opacity: 1; }
}

.c-scan-modal .csm-helper {
  text-align: center;
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-sm);
  color: rgba(255,255,255,0.7);
  line-height: 1.5;
  margin-bottom: 18px;
}
.c-scan-modal .csm-helper[data-kind="err"] { color: #ff8a78; }
.c-scan-modal .csm-helper[data-kind="ok"]  { color: var(--butter); }

/* C5 CTA "ดูในของขวัญของพี่" — pins the voucher to /my-gifts so the
   customer can keep browsing without losing the receipt of the redemption.
   Ported from design lines 3219-3242 (Apr 30 design refresh). */
.c5 .c5-cta-gifts {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  margin: 14px 20px 0;
  padding: 12px 16px;
  background: var(--ink);
  color: var(--butter);
  border-radius: 14px;
  text-decoration: none;
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: var(--text-md);
  cursor: pointer;
}
.c5 .c5-cta-gifts svg {
  width: 16px; height: 16px;
  color: var(--butter);
}
.c5 .c5-cta-gifts .arrow {
  margin-left: 2px;
  font-weight: 700;
}

/* Inbox.detail offer card — "ของฝาก" attached to a DeeReach message.
   Renders only when Inbox.offer_text is set. Ported from design lines
   1171-1220 (Apr 30 design refresh). Claim flow + Inbox.voucher
   full-screen QR are deferred until S13 editor can write these fields. */
.inbox-detail-offer {
  margin: 0 14px 14px;
  padding: 14px;
  background: var(--surface);
  border: 1.5px dashed var(--accent);
  border-radius: 16px;
  flex-shrink: 0;
}
.inbox-detail-offer .ido-row {
  display: flex;
  gap: 11px;
  align-items: center;
  margin-bottom: 12px;
}
.inbox-detail-offer .ido-icon {
  width: 38px;
  height: 38px;
  background: var(--accent);
  border-radius: 11px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.inbox-detail-offer .ido-icon svg {
  width: 18px;
  height: 18px;
  color: #fff;
}
.inbox-detail-offer .ido-text { flex: 1; }
.inbox-detail-offer .ido-label {
  font-family: 'Prompt', sans-serif;
  font-size: 10.5px;
  color: var(--mint-ink);
  font-weight: 600;
  letter-spacing: 0.02em;
  display: flex;
  align-items: center;
  gap: 4px;
}
.inbox-detail-offer .ido-check {
  width: 12px;
  height: 12px;
  color: var(--mint-ink);
}
.inbox-detail-offer .ido-name {
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-base);
  font-weight: 600;
  color: var(--ink);
  margin-top: 2px;
}
.inbox-detail-offer .ido-condition {
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-2xs);
  color: var(--ink-soft);
  margin-top: 2px;
}
/* "ดูใน ของขวัญของพี่ →" — full-width pill nudges the customer to
   gifts.list now that vouchers auto-receive. */
.inbox-detail-offer .ido-link {
  display: block;
  width: 100%;
  background: var(--ink);
  color: var(--butter);
  text-align: center;
  border-radius: 99px;
  padding: 12px;
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-sm);
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  margin-top: 4px;
  box-sizing: border-box;
}
.inbox-detail-offer .ido-link strong {
  font-weight: 700;
  color: var(--butter);
}

/* S-staff list — Settings → พนักงาน. Ported from design 4078-4163. */
.s-staff-page { padding-bottom: 100px; }
.s-staff-add-btn {
  margin: 14px 18px 0;
  padding: 12px 16px;
  background: var(--ink);
  color: var(--butter);
  border: none;
  border-radius: 14px;
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 14px;
  width: calc(100% - 36px);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  cursor: pointer;
  text-decoration: none;
}
.s-staff-add-btn .plus { font-size: 18px; line-height: 1; }
.s-staff-list {
  margin: 14px 18px 0;
  background: var(--surface);
  border: 1px solid rgba(17,17,17,0.10);
  border-radius: 14px;
  overflow: hidden;
}
.staff-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  border-bottom: 1px solid rgba(17,17,17,0.06);
  cursor: pointer;
  text-decoration: none;
  color: inherit;
}
.staff-row:last-child { border-bottom: none; }
.staff-row .sr-avatar {
  width: 38px; height: 38px;
  background: var(--accent-soft);
  color: var(--accent);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 14px;
  flex-shrink: 0;
}
.staff-row .sr-info { flex: 1; line-height: 1.3; min-width: 0; }
.staff-row .sr-name {
  font-family: 'Prompt', sans-serif;
  font-weight: 600;
  font-size: 14px;
  color: var(--ink);
}
.staff-row .sr-meta {
  font-family: 'Prompt', sans-serif;
  font-size: 11.5px;
  color: var(--ink-soft);
  margin-top: 1px;
}
.staff-row .sr-status {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  border-radius: 99px;
  font-family: 'Prompt', sans-serif;
  font-size: 10.5px;
  font-weight: 600;
  flex-shrink: 0;
  text-decoration: none;
}
.staff-row .sr-status.online {
  background: rgba(26,107,58,0.12);
  color: var(--mint-ink);
}
.staff-row .sr-status.online::before {
  content: '';
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--mint-ink);
}
.staff-row .sr-status.pending {
  background: var(--butter-soft);
  color: #6B5102;
}
.staff-row .sr-more {
  appearance: none; -webkit-appearance: none;
  background: transparent;
  border: none;
  font-size: 18px;
  color: var(--ink-soft);
  cursor: pointer;
  padding: 4px 8px;
  flex-shrink: 0;
}

/* S-staff.add — single nickname field form */
.s-staff-form { padding: 18px; }
.ssf-field { margin-bottom: 14px; }
.ssf-label {
  font-family: 'Prompt', sans-serif;
  font-weight: 600;
  font-size: 13px;
  color: var(--ink);
  margin-bottom: 6px;
}
.ssf-input {
  width: 100%;
  padding: 12px 14px;
  border: 1px solid rgba(17,17,17,0.18);
  border-radius: 12px;
  background: var(--surface);
  font-family: 'Prompt', sans-serif;
  /* 16px minimum so iOS Safari / PWA doesn't auto-zoom on focus. */
  font-size: 16px;
  color: var(--ink);
  outline: none;
  box-sizing: border-box;
}
.ssf-helper {
  font-family: 'Prompt', sans-serif;
  font-size: 11.5px;
  color: var(--ink-soft);
  margin-top: 4px;
  line-height: 1.5;
}

/* Per-staff permission section on S-staff.add — section header +
   stacked rows with icon + name/desc + on/off toggle (or 'เปิดเสมอ'
   pill on the locked "ออกแต้ม" row). */
.ssf-perm-section {
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px solid rgba(17,17,17,0.10);
}
.ssf-perm-h {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 14px;
  color: var(--ink);
  margin-bottom: 4px;
  letter-spacing: -0.005em;
}
.ssf-perm-sub {
  font-family: 'Prompt', sans-serif;
  font-size: 11.5px;
  color: var(--ink-soft);
  margin-bottom: 14px;
  line-height: 1.4;
}
.ssf-perm-list {
  background: var(--surface);
  border: 1px solid rgba(17,17,17,0.10);
  border-radius: 14px;
  overflow: hidden;
}
.ssf-perm-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 13px 14px;
}
.ssf-perm-row + .ssf-perm-row {
  border-top: 1px solid rgba(17,17,17,0.06);
}
.ssf-perm-row .icon {
  width: 32px; height: 32px;
  border-radius: 9px;
  background: var(--butter-soft, #FFF7DA);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--accent);
  flex-shrink: 0;
}
.ssf-perm-row .icon svg {
  width: 16px; height: 16px;
  stroke: currentColor;
  fill: none;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.ssf-perm-row .info {
  flex: 1;
  min-width: 0;
}
.ssf-perm-row .perm-name {
  font-family: 'Prompt', sans-serif;
  font-weight: 600;
  font-size: 13.5px;
  color: var(--ink);
  line-height: 1.2;
}
.ssf-perm-row .perm-desc {
  font-family: 'Prompt', sans-serif;
  font-size: 11px;
  color: var(--ink-soft);
  margin-top: 2px;
  line-height: 1.3;
}
.ssf-perm-row .perm-locked {
  font-family: 'Prompt', sans-serif;
  font-size: 10.5px;
  color: var(--ink-softer, rgba(17,17,17,0.45));
  flex-shrink: 0;
}
.ssf-toggle {
  flex-shrink: 0;
  width: 40px;
  height: 24px;
  background: rgba(17,17,17,0.18);
  border-radius: 99px;
  position: relative;
  cursor: pointer;
  transition: background 0.2s ease;
  border: 0;
  padding: 0;
}
.ssf-toggle::after {
  content: '';
  position: absolute;
  top: 2px; left: 2px;
  width: 20px; height: 20px;
  background: #fff;
  border-radius: 50%;
  transition: left 0.2s ease;
  box-shadow: 0 1px 3px rgba(0,0,0,0.2);
}
.ssf-toggle.on { background: var(--accent); }
.ssf-toggle.on::after { left: 18px; }
.ssf-toggle.locked {
  background: var(--accent);
  opacity: 0.5;
  cursor: not-allowed;
}
.ssf-toggle.locked::after { left: 18px; }

/* S-staff.invite — QR + share */
.ssi-stage { padding: 18px; text-align: center; }
.ssi-greet {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 16px;
  color: var(--ink);
  margin-bottom: 4px;
}
.ssi-greet em { color: var(--accent); font-style: normal; }
.ssi-helper {
  font-family: 'Prompt', sans-serif;
  font-size: 12.5px;
  color: var(--ink-soft);
  margin-bottom: 18px;
  line-height: 1.5;
}
.ssi-qr-card {
  background: var(--surface);
  border: 1px solid rgba(17,17,17,0.18);
  border-radius: 18px;
  padding: 24px;
  margin-bottom: 14px;
}
.ssi-qr-card .qr-svg {
  width: 100%;
  aspect-ratio: 1;
  max-width: 220px;
  margin: 0 auto;
  display: block;
}
.ssi-qr-card .qr-svg svg { width: 100%; height: 100%; display: block; }
.ssi-qr-card .ssi-expire {
  margin-top: 12px;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 11px;
  color: var(--ink-soft);
  letter-spacing: 0.05em;
}
.ssi-qr-card .ssi-expire strong { color: var(--accent); }
.ssi-share { display: flex; gap: 8px; margin-bottom: 8px; }
.ssi-share-btn {
  flex: 1;
  padding: 12px;
  background: var(--ink);
  color: var(--butter);
  border: none;
  border-radius: 12px;
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 13px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  cursor: pointer;
}
.ssi-share-btn.secondary {
  background: var(--surface);
  color: var(--ink);
  border: 1px solid rgba(17,17,17,0.18);
}
.ssi-share-btn svg { width: 16px; height: 16px; }

/* Staff.join — staff-side join confirm */
.staff-join { padding: 24px 20px 0; text-align: center; }
.staff-join .sj-shop-mark {
  width: 64px; height: 64px;
  background: var(--accent);
  color: #fff;
  border-radius: 18px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  /* Hero shop-letter inside the 64px tile — kept px so it stays
     dominant in the join confirmation card. */
  font-size: 28px;
  margin: 0 auto 12px;
}
.staff-join .sj-shop-name {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: var(--text-xl);
  letter-spacing: -0.03em;
  color: var(--ink);
  margin-bottom: 4px;
}
.staff-join .sj-shop-name .dot { color: var(--accent); }
.staff-join .sj-shop-sub {
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-xs);
  color: var(--ink-soft);
  margin-bottom: 18px;
}
.staff-join .sj-question {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: var(--text-lg);
  color: var(--ink);
  margin-bottom: 6px;
  line-height: 1.4;
}
.staff-join .sj-question em { color: var(--accent); font-style: normal; }
.staff-join .sj-helper {
  font-family: 'Prompt', sans-serif;
  font-size: var(--text-xs);
  color: var(--ink-soft);
  margin-bottom: 22px;
  line-height: 1.5;
}
.staff-join .sj-login-btn {
  width: 100%;
  padding: 14px;
  border: none;
  border-radius: 14px;
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: var(--text-base);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  cursor: pointer;
  margin-bottom: 8px;
  text-decoration: none;
}
.staff-join .sj-login-btn svg { width: 20px; height: 20px; flex-shrink: 0; }
.staff-join .sj-login-btn.line {
  background: #06C755;
  color: #fff;
}
.staff-join .sj-login-btn.phone {
  background: var(--surface);
  color: var(--ink);
  border: 1px solid rgba(17,17,17,0.18);
}
.staff-join .sj-cta-cancel {
  width: 100%;
  display: block;
  padding: 12px;
  background: transparent;
  color: var(--ink-soft);
  border: none;
  font-family: 'Prompt', sans-serif;
  font-weight: 500;
  font-size: var(--text-xs);
  cursor: pointer;
  margin-top: 6px;
  text-decoration: none;
  text-align: center;
}

/* S2.1.warn — inline collision warning under the shop-name field. */
.s2-input.warn {
  border-color: var(--accent);
}
.s2-warn {
  margin-top: 8px;
  padding: 10px 12px;
  background: var(--accent-soft);
  border-radius: 10px;
  display: flex;
  align-items: flex-start;
  gap: 8px;
}
.s2-warn svg {
  width: 16px; height: 16px;
  color: var(--accent);
  flex-shrink: 0;
  margin-top: 1px;
}
.s2-warn-text {
  font-family: 'Prompt', sans-serif;
  font-size: 12px;
  line-height: 1.45;
  flex: 1;
}
.s2-warn-text strong {
  font-weight: 700;
  color: var(--accent);
  display: block;
  margin-bottom: 2px;
}
.s2-warn-text .hint {
  color: var(--ink-soft);
  font-size: 11.5px;
}

/* S3.qr — fullscreen rotating-QR mode for "หันจอให้ลูกค้าสแกน". */
.s3-qr-stage {
  padding: 0 20px 20px;
  flex: 1;
  display: flex;
  flex-direction: column;
}
.s3-qr-helper {
  text-align: center;
  margin-bottom: 18px;
}
.s3-qr-helper .qh-title {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 17px;
  color: var(--ink);
  line-height: 1.4;
}
.s3-qr-helper .qh-sub {
  font-family: 'Prompt', sans-serif;
  font-size: 12px;
  color: var(--ink-soft);
  margin-top: 4px;
}
.s3-qr-card {
  background: var(--surface);
  border: 1.5px solid rgba(17,17,17,0.18);
  border-radius: 22px;
  padding: 24px 24px 18px;
  text-align: center;
}
.s3-qr-svg {
  width: 100%;
  aspect-ratio: 1;
  max-width: 240px;
  margin: 0 auto 14px;
  display: block;
  position: relative;
}
.s3-qr-svg svg { width: 100%; height: 100%; display: block; }
.s3-qr-shop-name {
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: 20px;
  letter-spacing: -0.03em;
  color: var(--ink);
}
.s3-qr-shop-name .dot { color: var(--accent); }
.s3-qr-countdown {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 11px;
  color: var(--ink-soft);
  letter-spacing: 0.05em;
  margin-top: 6px;
}
.s3-qr-countdown strong {
  color: var(--accent);
  font-weight: 700;
}
.s3-qr-foot {
  text-align: center;
  margin-top: 14px;
  padding: 0 20px;
  font-family: 'Prompt', sans-serif;
  font-size: 11.5px;
  color: var(--ink-soft);
  line-height: 1.5;
}

/* S2.1 district combobox — plain input (full-width, same as other
   .s2-input fields) + filtered dropdown of "<district> · <province>"
   rows. Ambiguous district names render one row per candidate so the
   picker resolves them in a single tap. */
.s2-district-input::placeholder { color: var(--ink-softer); font-weight: 400; }

.s2-combo-list {
  margin-top: 6px;
  background: var(--surface);
  border: 1px solid rgba(17,17,17,0.10);
  border-radius: 14px;
  padding: 4px;
  max-height: 280px;
  overflow-y: auto;
  box-shadow: 0 4px 14px -4px rgba(17,17,17,0.10);
}
.s2-combo-row {
  appearance: none; -webkit-appearance: none;
  width: 100%;
  background: transparent;
  border: 0;
  padding: 10px 12px;
  border-radius: 10px;
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  text-align: left;
  font-family: 'Prompt', sans-serif;
}
.s2-combo-row:hover,
.s2-combo-row:focus {
  background: rgba(17,17,17,0.04);
}
.s2-combo-row.selected {
  background: var(--accent-soft);
}
.s2-combo-check {
  color: var(--accent);
  font-weight: 700;
  flex-shrink: 0;
  width: 14px;
}
.s2-combo-name {
  flex: 1;
  font-weight: 600;
  font-size: 14px;
  color: var(--ink);
}
.s2-combo-prov {
  font-size: 12px;
  color: var(--ink-soft);
  flex-shrink: 0;
}

/* Input bar — fixed above the customer dock so the compose stays
   visible while the thread scrolls. */
.chat-input-bar {
  position: fixed;
  left: 0; right: 0;
  bottom: calc(env(safe-area-inset-bottom, 0px) + 100px);
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 14px 14px;
  background: var(--bg);
  border-top: 1px solid rgba(17,17,17,0.08);
  z-index: 10;
}
.chat-input {
  flex: 1;
  background: var(--surface);
  border: 1px solid rgba(17,17,17,0.12);
  border-radius: 99px;
  padding: 13px 20px;
  font-family: 'Prompt', sans-serif;
  font-size: 16px;
  color: var(--ink);
  outline: none;
  min-width: 0;
}
.chat-input::placeholder {
  color: var(--ink-softer);
}
.chat-send {
  flex-shrink: 0;
  width: 46px; height: 46px;
  background: var(--ink);
  color: var(--bg);
  border: none;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  padding: 0;
}
.chat-send svg {
  width: 18px; height: 18px;
  stroke: currentColor; fill: none;
  stroke-width: 2; stroke-linecap: round; stroke-linejoin: round;
}
.chat-send:disabled,
.chat-send.disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

/* "↓ ข้อความใหม่" pill — fixed above chat-input-bar so a new bubble
   that arrives while the customer is typing surfaces an explicit jump
   target. JS toggles `hidden`. */
.chat-new-pill {
  position: fixed;
  bottom: calc(env(safe-area-inset-bottom, 0px) + 168px);
  left: 50%; transform: translateX(-50%);
  padding: 6px 14px; border: 0; border-radius: 999px;
  background: var(--ink); color: #fff;
  font-family: 'Prompt', sans-serif; font-size: 12px; font-weight: 600;
  box-shadow: 0 6px 18px -6px rgba(0,0,0,0.45);
  z-index: 11;
  cursor: pointer;
}
.chat-locked {
  position: fixed;
  bottom: calc(env(safe-area-inset-bottom, 0px) + 100px);
  left: 0; right: 0;
  padding: 14px 16px;
  background: rgba(245,241,232,0.96);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  border-top: 1px solid rgba(17,17,17,0.08);
  text-align: center; color: var(--ink-soft);
  font-size: 13px;
  z-index: 10;
}

/* ============================================================
   Inbox detail chrome (ix-*) — broadcast post + replies. Used by
   /shop/messages/<inbox_id> (operator view) and /my-inbox/<id>
   (customer view). Replaces the old chat-bubble pattern: replies
   render as ix-comment rows with me/them sides instead of bubbles
   so the conversation reads as comments under a post (per
   design/taemdee-customer.html → inbox.message and
   design/taemdee-shop.html → inbox.message).

   Page-grouping list (.ib-*) for /shop/messages — sections per
   campaign with "ลูกค้าตอบกลับ" rows underneath.
   ============================================================ */

/* Customer side — shop strip atop the broadcast detail page.
   Mirrors design/taemdee-customer.html → inbox.message: shop logo
   + name + sent-time + a "ดูร้าน" CTA link. */
.ix-shop-strip {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  background: var(--surface);
  border-bottom: 1px solid rgba(17,17,17,0.08);
}
.ix-shop-strip .ix-logo {
  width: 38px; height: 38px;
  border-radius: 11px;
  background: var(--ink);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Host Grotesk', sans-serif;
  font-weight: 800;
  font-size: 15px;
  letter-spacing: -0.04em;
  flex-shrink: 0;
  overflow: hidden;
}
.ix-shop-strip .ix-logo .dot { color: var(--accent); }
.ix-shop-strip .ix-logo img,
.ix-shop-strip .ix-logo .shop-avatar-img {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
}
.ix-shop-strip .ix-info { flex: 1; min-width: 0; }
.ix-shop-strip .ix-name {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 14px;
  color: var(--ink);
  line-height: 1.2;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ix-shop-strip .ix-time {
  font-family: 'Prompt', sans-serif;
  font-size: 11px;
  color: var(--ink-soft);
  margin-top: 1px;
}
.ix-shop-strip .ix-contact {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 6px 11px;
  background: var(--bg);
  border: 1px solid rgba(17,17,17,0.12);
  border-radius: 99px;
  font-family: 'Prompt', sans-serif;
  font-size: 11px;
  font-weight: 600;
  color: var(--ink);
  text-decoration: none;
}
.ix-shop-strip .ix-contact svg {
  width: 11px; height: 11px;
  stroke: currentColor; fill: none;
  stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round;
}

/* Shop side — customer relationship strip atop the detail page. */
.ix-cust-strip {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  background: var(--surface);
  border-bottom: 1px solid rgba(17,17,17,0.08);
}
.ix-cust-strip .ix-avatar {
  width: 38px; height: 38px;
  border-radius: 50%;
  background: var(--accent-soft, #FFE3DA);
  color: var(--accent);
  display: flex; align-items: center; justify-content: center;
  font-family: 'Prompt', sans-serif;
  font-weight: 700; font-size: 14px;
  flex-shrink: 0;
}
.ix-cust-strip .ix-info { flex: 1; min-width: 0; }
.ix-cust-strip .ix-name {
  font-family: 'Prompt', sans-serif;
  font-weight: 700; font-size: 14px;
  color: var(--ink); line-height: 1.2;
}
.ix-cust-strip .ix-tag {
  font-family: 'Prompt', sans-serif;
  font-size: 11px; color: var(--ink-soft);
  margin-top: 1px;
}
.ix-cust-strip .ix-tag .dot-on {
  display: inline-block;
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--mint, #6FA882);
  margin-right: 4px;
  vertical-align: 1px;
}
.ix-cust-strip .ix-view-cust {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 6px 11px;
  background: var(--bg);
  border: 1px solid rgba(17,17,17,0.12);
  border-radius: 99px;
  font-family: 'Prompt', sans-serif;
  font-size: 11px;
  font-weight: 600;
  color: var(--ink);
  text-decoration: none;
}

.ix-body {
  padding: 16px;
}

/* DeeReach broadcast card embedded above the replies. */
.ix-deereach {
  background: var(--butter-soft, #FFF6D9);
  border: 1px solid rgba(255, 217, 82, 0.55);
  border-radius: 16px;
  padding: 18px 20px;
}
.ix-deereach .ixd-tag {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  background: var(--accent);
  color: #fff;
  padding: 3px 9px;
  border-radius: 99px;
  font-family: 'Prompt', sans-serif;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  margin-bottom: 12px;
}
.ix-deereach .ixd-tag svg {
  width: 10px; height: 10px;
  fill: currentColor;
}
.ix-deereach .ixd-headline {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 17px;
  color: var(--ink);
  line-height: 1.35;
  letter-spacing: -0.01em;
  margin-bottom: 6px;
}
.ix-deereach .ixd-text {
  font-family: 'Prompt', sans-serif;
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--ink-soft);
  white-space: pre-wrap;
}
.ix-deereach .ixd-voucher {
  margin-top: 12px;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  background: rgba(255,255,255,0.7);
  border-radius: 10px;
  border: 1px dashed rgba(176, 130, 30, 0.35);
}
.ix-deereach .ixd-voucher .ixv-icon {
  width: 32px; height: 32px;
  border-radius: 8px;
  background: var(--accent);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.ix-deereach .ixd-voucher .ixv-icon svg {
  width: 16px; height: 16px;
  stroke: currentColor; fill: none;
  stroke-width: 2; stroke-linecap: round; stroke-linejoin: round;
}
.ix-deereach .ixd-voucher .ixv-info { flex: 1; min-width: 0; }
.ix-deereach .ixd-voucher .ixv-name {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 13px;
  color: var(--ink);
  line-height: 1.2;
}
.ix-deereach .ixd-voucher .ixv-meta {
  font-family: 'Prompt', sans-serif;
  font-size: 10.5px;
  color: var(--ink-soft);
  margin-top: 2px;
}
.ix-deereach .ixd-stats {
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px dashed rgba(176, 130, 30, 0.35);
  display: flex;
  gap: 14px;
  flex-wrap: wrap;
  font-family: 'Prompt', sans-serif;
  font-size: 11px;
  color: var(--ink-soft);
}
.ix-deereach .ixd-stats strong {
  color: var(--ink);
  font-weight: 700;
}

/* Section header above the reply thread. */
.ix-comments-h {
  margin: 24px 4px 12px;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
}
.ix-comments-h .lab {
  font-family: 'Prompt', sans-serif;
  font-weight: 600;
  font-size: 13px;
  color: var(--ink);
  letter-spacing: -0.005em;
}
.ix-comments-h .count {
  font-family: 'Prompt', sans-serif;
  font-size: 11.5px;
  color: var(--ink-soft);
}

/* Reply rows — comment-under-a-post pattern from
   design/taemdee-shop.html → inbox.message. Avatar chip on the
   left, author + time row, body underneath. Border-top divider
   between rows so the thread reads as a list of comments rather
   than chat bubbles. .ix-comment.shop swaps the avatar to ink so
   the shop's voice is visually distinct from customer replies. */
.ix-thread {
  display: flex;
  flex-direction: column;
}
.ix-comment {
  display: flex;
  gap: 12px;
  padding: 10px 4px;
  border-top: 1px solid rgba(17,17,17,0.06);
}
.ix-comment:first-of-type {
  border-top: none;
  padding-top: 4px;
}
.ix-comment .ixc-avatar {
  width: 28px; height: 28px;
  border-radius: 50%;
  background: var(--accent-soft, #FFE3DA);
  color: var(--accent);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 11px;
  flex-shrink: 0;
}
.ix-comment.shop .ixc-avatar {
  background: var(--ink);
  color: #fff;
}
.ix-comment .ixc-body { flex: 1; min-width: 0; }
.ix-comment .ixc-head {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin-bottom: 2px;
}
.ix-comment .ixc-author {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 12.5px;
  color: var(--ink);
  letter-spacing: -0.005em;
}
.ix-comment .ixc-time {
  font-family: 'Prompt', sans-serif;
  font-size: 10.5px;
  color: var(--ink-softer);
  margin-left: auto;
}
/* "ผ่านไลน์" / future external-channel pill next to the author —
   only renders for replies that came in from outside the app (LINE
   webhook today, SMS / web_push later). The .line modifier uses
   LINE's green palette so it pattern-matches at a glance. */
.ix-comment .ixc-via {
  font-family: 'Prompt', sans-serif;
  font-size: 9.5px;
  font-weight: 700;
  padding: 1px 6px;
  border-radius: 99px;
  letter-spacing: 0.02em;
  background: rgba(17,17,17,0.06);
  color: var(--ink-softer);
}
.ix-comment .ixc-via.line {
  background: rgba(6, 199, 85, 0.12);
  color: #06c755;
}
.ix-comment .ixc-text {
  font-family: 'Prompt', sans-serif;
  font-size: 13px;
  line-height: 1.5;
  color: var(--ink);
  white-space: pre-wrap;
  word-wrap: break-word;
}

/* Shop /shop/messages — section title under the shared s3-top
   greeting. Keeps the inbox page consistent with the other dock
   pages (greeting + bell on top), then drops a slim section header
   below carrying the unread-reply count so the operator's queue
   load is the first specific thing they see. */
.ib-section-h {
  margin: 8px 20px 12px;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
}
.ib-section-h .ibsh-title {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 18px;
  color: var(--ink);
  letter-spacing: -0.01em;
}
.ib-section-h .ibsh-title .dot { color: var(--accent); }
.ib-section-h .ibsh-sub {
  font-family: 'Prompt', sans-serif;
  font-size: 12px;
  color: var(--ink-soft);
  flex-shrink: 0;
}

/* Shop /shop/messages — one .ib-broadcast card per campaign with the
   customers who replied listed underneath. Matches design's
   inbox.list (taemdee-shop.html L11999): butter-soft header strip
   carrying the broadcast tag/title/meta + "ดู →" deep link, then a
   flat .ib-replies list of customer rows beneath. */
.ib-broadcast {
  margin: 12px 16px;
  background: var(--surface);
  border: 1px solid rgba(17,17,17,0.08);
  border-radius: 16px;
  overflow: hidden;
}
.ib-broadcast .ib-bh {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 16px 10px;
  background: var(--butter-soft, #FFF6D9);
  border-bottom: 1px solid rgba(255, 217, 82, 0.55);
}
.ib-broadcast .ib-bh .ibh-text { flex: 1; min-width: 0; }
.ib-broadcast .ib-bh .ibh-tag {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-family: 'Prompt', sans-serif;
  font-size: 9.5px;
  font-weight: 700;
  color: var(--accent);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  margin-bottom: 3px;
}
.ib-broadcast .ib-bh .ibh-tag svg {
  width: 9px; height: 9px;
  fill: currentColor;
}
.ib-broadcast .ib-bh .ibh-title {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 13.5px;
  color: var(--ink);
  letter-spacing: -0.005em;
  line-height: 1.25;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ib-broadcast .ib-bh .ibh-meta {
  font-family: 'Prompt', sans-serif;
  font-size: 10.5px;
  color: var(--ink-soft);
  margin-top: 1px;
}
.ib-broadcast .ib-bh .ibh-link {
  flex-shrink: 0;
  font-family: 'Prompt', sans-serif;
  font-size: 11.5px;
  font-weight: 700;
  color: var(--accent);
  cursor: pointer;
  padding: 4px 8px;
  text-decoration: none;
}

.ib-replies {
  display: flex;
  flex-direction: column;
}
.ib-reply {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 11px 14px;
  border-top: 1px solid rgba(17,17,17,0.06);
  cursor: pointer;
  background: var(--surface);
  text-decoration: none;
  color: var(--ink);
  position: relative;
}
.ib-reply:first-child { border-top: none; }
.ib-reply.unread::before {
  content: '';
  position: absolute;
  left: 6px; top: 50%;
  transform: translateY(-50%);
  width: 6px; height: 6px;
  background: var(--accent);
  border-radius: 50%;
  box-shadow: 0 0 0 0 rgba(255, 94, 58, 0.5);
  animation: ib-dot-pulse 1.8s ease-out infinite;
}
.ib-reply.unread {
  padding-left: 20px;
}
.ib-reply .ibr-avatar {
  width: 32px; height: 32px;
  border-radius: 50%;
  background: var(--ink);
  color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 12.5px;
  flex-shrink: 0;
}
.ib-reply.unread .ibr-avatar {
  background: var(--accent);
}
.ib-reply .ibr-body { flex: 1; min-width: 0; }
.ib-reply .ibr-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 8px;
}
.ib-reply .ibr-name {
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 13px;
  color: var(--ink);
  letter-spacing: -0.005em;
}
.ib-reply .ibr-time {
  font-family: 'Prompt', sans-serif;
  font-size: 10.5px;
  color: var(--ink-soft);
  flex-shrink: 0;
}
.ib-reply .ibr-preview {
  font-family: 'Prompt', sans-serif;
  font-size: 12px;
  color: var(--ink-soft);
  line-height: 1.35;
  margin-top: 1px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  display: flex;
  align-items: center;
  gap: 4px;
}
.ib-reply.unread .ibr-preview {
  color: var(--ink);
  font-weight: 500;
}
@keyframes ib-dot-pulse {
  0% { box-shadow: 0 0 0 0 rgba(255, 94, 58, 0.5); }
  100% { box-shadow: 0 0 0 5px rgba(255, 94, 58, 0); }
}

.ib-empty {
  padding: 50px 24px;
  text-align: center;
  color: var(--ink-soft);
  font-size: 14px;
  line-height: 1.7;
}
.ib-empty a { color: var(--accent); font-weight: 600; }

/* Compose — two flavours per design.
   .ix-compose       = dashed CTA card (tap-to-open compose sheet).
                       Used by /shop/messages/<id> per design — keeps
                       the detail page tight; the actual textarea
                       lives in a bottom sheet that the page mounts.
   .ix-compose-active = always-visible inline textarea + quick-reply
                       chips + char counter. Used by /my-inbox/<id>
                       per design — customer reply is one-shot and
                       short, so the inline form is the lighter UX.
   Free pill is dropped per the project's spec — shop's broadcast cost
   already lives on the ix-deereach card, replies don't need a
   separate "ฟรี" label. */
.ix-compose {
  margin-top: 20px;
  padding: 14px 16px;
  background: var(--surface);
  border: 1.5px dashed rgba(17,17,17,0.18);
  border-radius: 14px;
  display: flex;
  align-items: center;
  gap: 12px;
  cursor: text;
}
.ix-compose .ixco-icon {
  width: 30px; height: 30px;
  border-radius: 50%;
  background: var(--ink);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.ix-compose .ixco-icon svg {
  width: 14px; height: 14px;
  stroke: currentColor; fill: none;
  stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round;
}
.ix-compose .ixco-text {
  flex: 1;
  font-family: 'Prompt', sans-serif;
  font-size: 13px;
  color: var(--ink-soft);
}
.ix-compose .ixco-text strong {
  color: var(--ink);
  font-weight: 700;
}

.ix-compose-active {
  margin-top: 20px;
  padding: 14px 16px 12px;
  background: var(--surface);
  border: 1.5px solid var(--ink);
  border-radius: 14px;
}
.ix-compose-active .ixca-head { margin-bottom: 10px; }
.ix-compose-active .ixca-label {
  font-family: 'Prompt', sans-serif;
  font-size: 11.5px;
  font-weight: 700;
  color: var(--ink);
  display: flex;
  align-items: center;
  gap: 6px;
}
/* "ฟรี · ไม่ใช้เครดิต" reassurance pill on the shop-side reply
   composer — broadcasts cost credits, replies don't, and the design
   surfaces that explicitly so operators don't hesitate to follow up. */
.ix-compose-active .ixca-label .free {
  background: rgba(111, 168, 130, 0.18);
  color: var(--mint-ink, #2a4f44);
  padding: 1px 7px;
  border-radius: 99px;
  font-size: 9.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.ix-compose-active .ixca-textarea {
  width: 100%;
  background: var(--bg);
  border: 1px solid rgba(17,17,17,0.12);
  border-radius: 10px;
  padding: 10px 12px;
  font-family: 'Prompt', sans-serif;
  font-size: 16px;
  color: var(--ink);
  line-height: 1.5;
  outline: none;
  resize: none;
  min-height: 70px;
  box-sizing: border-box;
}
.ix-compose-active .ixca-textarea::placeholder {
  color: var(--ink-softer);
}
.ix-compose-active .ixca-quicks {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 10px;
}
.ix-compose-active .ixca-quick {
  padding: 5px 10px;
  background: var(--butter-soft, #FFF6D9);
  border: 1px solid rgba(255, 217, 82, 0.45);
  border-radius: 99px;
  font-family: 'Prompt', sans-serif;
  font-size: 11px;
  color: var(--ink);
  cursor: pointer;
  appearance: none;
  -webkit-appearance: none;
}
.ix-compose-active .ixca-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 10px;
}
.ix-compose-active .ixca-count {
  font-family: 'Prompt', sans-serif;
  font-size: 10.5px;
  color: var(--ink-soft);
}
.ix-compose-active .ixca-send {
  background: var(--accent);
  color: #fff;
  border: none;
  border-radius: 99px;
  padding: 8px 18px;
  cursor: pointer;
  font-family: 'Prompt', sans-serif;
  font-weight: 700;
  font-size: 12.5px;
  letter-spacing: -0.005em;
}
.ix-compose-active .ixca-send:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

/* Per-broadcast engagement stats page — light wrapper for the
   ix-deereach card at the top + the per-customer drill-down list
   below. Reuses .s3-cust-stat for the 4-up grid + .ib-reply for
   the customer rows so the page reads as a sibling of /shop/messages. */
.bs-broadcast {
  margin: 4px 20px 18px;
  padding: 16px 18px;
  background: var(--butter-soft, #FFF6D9);
  border: 1px solid rgba(255, 217, 82, 0.55);
  border-radius: 16px;
  font-family: 'Prompt', sans-serif;
}
.bs-broadcast .ixd-tag {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 10px;
  font-weight: 700;
  color: var(--accent);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  margin-bottom: 8px;
}
.bs-broadcast .ixd-tag svg { width: 10px; height: 10px; fill: currentColor; }
.bs-broadcast .ixd-headline {
  font-size: 16px; font-weight: 700;
  color: var(--ink);
  letter-spacing: -0.005em;
  line-height: 1.3;
  margin-bottom: 4px;
}
.bs-broadcast .ixd-text {
  font-size: 13.5px;
  color: var(--ink);
  line-height: 1.5;
}
.bs-broadcast .ixd-stats {
  display: flex; flex-wrap: wrap; gap: 4px 14px;
  margin-top: 12px;
  font-size: 11.5px;
  color: var(--ink-soft);
}
.bs-broadcast .ixd-stats strong {
  color: var(--ink);
  font-weight: 700;
}

.bs-rows-h {
  margin: 18px 20px 8px;
  font-family: 'Prompt', sans-serif;
  font-size: 11.5px;
  font-weight: 700;
  color: var(--ink-soft);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.bs-rows {
  margin: 0 16px 24px;
  background: var(--surface);
  border: 1px solid rgba(17,17,17,0.08);
  border-radius: 16px;
  overflow: hidden;
}
.bs-marks {
  display: flex; flex-wrap: wrap; gap: 4px;
  margin-top: 4px;
}
.bs-mark {
  font-family: 'Prompt', sans-serif;
  font-size: 10px;
  font-weight: 600;
  padding: 1px 7px;
  border-radius: 99px;
  letter-spacing: 0.02em;
}
.bs-mark.replied { background: rgba(111, 168, 130, 0.18); color: var(--mint-ink, #2a4f44); }
.bs-mark.opened  { background: rgba(255, 217, 82, 0.45); color: var(--ink); }
.bs-mark.silent  { background: rgba(17,17,17,0.05); color: var(--ink-softer); }
.bs-mark.voucher { background: rgba(255, 94, 58, 0.12); color: var(--accent); }

.bs-empty {
  padding: 40px 20px;
  text-align: center;
  color: var(--ink-soft);
  font-family: 'Prompt', sans-serif;
  font-size: 13px;
}

/* "Ball in whose court" placeholder — replaces the active compose
   form when it's the other side's turn to reply. Quiet ink-soft
   text in a subtle pill so the thread doesn't end abruptly but
   nothing invites another send either. */
.ix-compose-waiting {
  margin-top: 20px;
  padding: 14px 16px;
  background: var(--bg);
  border: 1px solid rgba(17,17,17,0.08);
  border-radius: 14px;
  text-align: center;
  font-family: 'Prompt', sans-serif;
  font-size: 12.5px;
  color: var(--ink-soft);
  line-height: 1.45;
}
