/* ==========================================================================
   loyalty.css — Public rewards landing / check-in page (/loyalty)
   ==========================================================================

   DESIGN TOKEN NOTE
   The build spec proposed its own palette (--bg-base #1A1512, --bg-panel
   #221B16, --brass #C9A227, --olive #8B9A6C, --text #EDE3D3, --text-muted
   #9C9184) plus Fraunces / Inter / IBM Plex Mono. Those were chosen without
   sight of this codebase, and base.css already defines near-identical values
   for every one of them — the site's own --gold-accent (#c5a059) is the same
   idea as --brass, and --color-on-surface (#ede0dc) differs from the spec's
   --text by three hex digits.

   So the spec's token NAMES are kept below as local aliases (the vocabulary in
   the spec still resolves), but they point at the site's real tokens. That way
   a future palette change in base.css flows through here instead of leaving
   this page stranded on a hardcoded near-match.

   Type: --font-headline (Noto Serif) and --font-body (Manrope) are already
   loaded on every page. Adding Fraunces and Inter would mean two more Google
   Font round trips for two pages, against the explicit font-loading work
   documented at the top of base.css. IBM Plex Mono is replaced by a system
   mono stack with tabular figures — the ledger feel with no network cost.
   ========================================================================== */

.loyalty-page {
  /* ─ Spec token aliases → real site tokens ─ */
  --bg-base:    var(--color-surface);
  --bg-panel:   var(--color-surface-container);
  --bg-raised:  var(--color-surface-container-high);
  --brass:      var(--gold-accent);
  --olive:      var(--color-tertiary);
  --text:       var(--color-on-surface);
  --text-muted: var(--color-outline);
  --hairline:   var(--border-glow);

  --font-display: var(--font-headline);
  --font-ui:      var(--font-body);
  --font-data:    ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  background-color: var(--bg-base);
}

.loyalty-main {
  position: relative;
  z-index: 20;
  max-width: 46rem;
  margin: 0 auto;
  padding: 0 1.5rem 8rem;
}

@media (min-width: 768px) {
  .loyalty-main { padding-bottom: 5.5rem; }
}

/* ── HERO ─────────────────────────────────────────────────────────────────
   The customer-facing counterpart to the admin dashboard's restraint: same
   palette, much louder. ─────────────────────────────────────────────────── */
.loyalty-hero {
  position: relative;
  text-align: center;
  padding: 3rem 0 2.75rem;
}

/* Brass bloom behind the title. Sits under the text and never intercepts a
   tap — this is the page's one decorative flourish. */
.loyalty-hero-glow {
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  width: min(34rem, 120%);
  height: 18rem;
  pointer-events: none;
  background: radial-gradient(
    ellipse at 50% 32%,
    rgba(197, 160, 89, 0.20) 0%,
    rgba(197, 160, 89, 0.07) 42%,
    transparent 72%
  );
  filter: blur(6px);
}

.loyalty-eyebrow {
  position: relative;
  font-family: var(--font-ui);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--brass);
  margin-bottom: 1rem;
}

.loyalty-hero-title {
  position: relative;
  font-family: var(--font-display);
  font-size: clamp(2.6rem, 11vw, 4.25rem);
  font-weight: 700;
  line-height: 1.02;
  letter-spacing: -0.015em;
  color: var(--text);
  margin-bottom: 1.15rem;
  background: linear-gradient(180deg, #f4e9d6 0%, var(--brass) 165%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

.loyalty-hero-copy {
  position: relative;
  max-width: 30rem;
  margin: 0 auto;
  font-family: var(--font-ui);
  font-size: 1.0625rem;
  line-height: 1.62;
  color: var(--text-muted);
}

/* ── SECTION HEADINGS ─────────────────────────────────────────────────── */
.loyalty-section-heading {
  font-family: var(--font-ui);
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--text-muted);
  text-align: center;
  margin-bottom: 1.1rem;
}

/* ── CHECK-IN CARD ────────────────────────────────────────────────────── */
.loyalty-checkin { scroll-margin-top: 6rem; }

.loyalty-card {
  position: relative;
  background: linear-gradient(165deg, var(--bg-panel) 0%, var(--bg-base) 100%);
  border: 1px solid var(--hairline);
  border-radius: 1.15rem;
  padding: 2.25rem 1.75rem;
  text-align: center;
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.03) inset,
    0 18px 40px -24px rgba(0, 0, 0, 0.9);
}

/* The one state that earns a brighter frame. */
.loyalty-card[data-state="success"],
.loyalty-card[data-state="ready"] {
  border-color: rgba(197, 160, 89, 0.42);
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.04) inset,
    0 0 44px -14px rgba(197, 160, 89, 0.36),
    0 18px 40px -24px rgba(0, 0, 0, 0.9);
}

.loyalty-state-title {
  font-family: var(--font-display);
  font-size: 1.4rem;
  font-weight: 700;
  color: var(--text);
  margin-bottom: 0.5rem;
}

.loyalty-state-copy {
  font-family: var(--font-ui);
  font-size: 0.95rem;
  line-height: 1.6;
  color: var(--text-muted);
  max-width: 26rem;
  margin: 0 auto;
}

.loyalty-state-copy + .loyalty-state-copy { margin-top: 0.6rem; }

.loyalty-state-icon {
  font-size: 2.25rem;
  color: var(--brass);
  margin-bottom: 0.75rem;
  display: block;
}

/* ── POINTS READOUT ───────────────────────────────────────────────────────
   Deliberately shows the balance and nothing else: no "N points to go", no
   progress bar toward a threshold. Reward mechanics are undecided (Phase 2),
   and a progress meter is a promise about a number that does not exist yet.
   ───────────────────────────────────────────────────────────────────────── */
.loyalty-points {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.15rem;
  margin-bottom: 1.5rem;
}

.loyalty-points-value {
  font-family: var(--font-display);
  font-size: clamp(3.5rem, 18vw, 5rem);
  font-weight: 700;
  line-height: 1;
  color: var(--brass);
  font-variant-numeric: tabular-nums;
  text-shadow: 0 0 34px rgba(197, 160, 89, 0.28);
}

.loyalty-points-label {
  font-family: var(--font-ui);
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* ── COUNTDOWN DIAL ───────────────────────────────────────────────────── */
/* Drawn for the cooldown between points, and for the daily cap. The SVG and
   the digits are aria-hidden (see js/loyalty.js) -- #loyalty-cta is an
   aria-live region, so a per-second update would otherwise be announced every
   second. The absolute unlock time in the body copy is the accessible
   equivalent. */
.loyalty-dial {
  position: relative;
  width: 128px;
  height: 128px;
  margin: 0 auto 0.25rem;
}

.loyalty-dial-svg {
  width: 100%;
  height: 100%;
  display: block;
}

.loyalty-dial-track {
  stroke: var(--hairline);
  stroke-width: 7;
  opacity: 0.5;
}

.loyalty-dial-arc {
  stroke-width: 7;
  /* Matches the 1s tick: the arc glides between values instead of stepping.
     Only the offset is animated -- transitioning `all` here would also animate
     the dasharray and make the ring visibly redraw itself on first paint. */
  transition: stroke-dashoffset 0.95s linear;
}

.loyalty-dial-readout {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.15rem;
  text-align: center;
}

.loyalty-dial-digits {
  font-family: var(--font-data);
  /* Tabular figures so the countdown does not jitter as digits change width. */
  font-variant-numeric: tabular-nums;
  font-size: 1.55rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  color: var(--text);
  line-height: 1;
}

.loyalty-dial-caption {
  font-family: var(--font-ui);
  font-size: 0.58rem;
  font-weight: 600;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--text-muted);
  max-width: 92px;
  line-height: 1.25;
}

.loyalty-state-note {
  font-family: var(--font-ui);
  font-size: 0.85rem;
  color: var(--text-muted);
  margin-top: 0.15rem;
}

/* Respect a reduced-motion preference: the dial still updates every second,
   it just stops easing between positions. */
@media (prefers-reduced-motion: reduce) {
  .loyalty-dial-arc { transition: none; }
}

/* ── FORM ─────────────────────────────────────────────────────────────── */
.loyalty-form {
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
  margin-top: 1.4rem;
  text-align: left;
}

/* One label + input + error. The form's gap separates fields; this tighter gap
   binds a label to the input it names. */
.loyalty-field {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.loyalty-label {
  font-family: var(--font-ui);
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.loyalty-input {
  width: 100%;
  padding: 0.95rem 1.1rem;
  background: var(--color-surface-container-lowest);
  border: 1px solid var(--hairline);
  border-radius: 0.7rem;
  color: var(--text);
  /* Tabular figures so a phone number does not shimmy as it is typed. */
  font-family: var(--font-data);
  font-size: 1.05rem;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
  caret-color: var(--brass);
  transition: border-color 0.18s ease, box-shadow 0.18s ease;
}

.loyalty-input::placeholder { color: var(--text-muted); opacity: 0.55; }

.loyalty-input:focus-visible {
  outline: none;
  border-color: rgba(197, 160, 89, 0.6);
  box-shadow: 0 0 0 3px rgba(197, 160, 89, 0.14);
}

.loyalty-input[aria-invalid="true"] {
  border-color: var(--color-error);
  box-shadow: 0 0 0 3px rgba(255, 180, 171, 0.12);
}

.loyalty-error {
  font-family: var(--font-ui);
  font-size: 0.85rem;
  color: var(--color-error);
  min-height: 1.2em;
}

/* Collapse the reserved error row while it is empty. A single-field form could
   afford to hold 1.2em open permanently to avoid a jump on validation; three
   fields would hold ~3.6em of dead space above the button on every render,
   which pushes the primary action off a phone screen. */
.loyalty-field .loyalty-error {
  min-height: 0;
}

.loyalty-field .loyalty-error:empty {
  display: none;
}

/* ── PRIMARY BUTTON ───────────────────────────────────────────────────── */
.loyalty-btn {
  width: 100%;
  padding: 1.05rem 1.5rem;
  border: none;
  border-radius: 0.7rem;
  background: linear-gradient(150deg, #d8b877 0%, var(--brass) 52%, #a8853f 100%);
  color: #1a1208;
  font-family: var(--font-ui);
  font-size: 0.85rem;
  font-weight: 800;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  cursor: pointer;
  transition: transform 0.16s ease, box-shadow 0.16s ease, filter 0.16s ease;
  box-shadow: 0 10px 26px -14px rgba(197, 160, 89, 0.85);
}

.loyalty-btn:hover:not(:disabled) {
  filter: brightness(1.07);
  transform: translateY(-1px);
  box-shadow: 0 14px 30px -14px rgba(197, 160, 89, 0.95);
}

.loyalty-btn:active:not(:disabled) { transform: translateY(0); }

.loyalty-btn:focus-visible {
  outline: 2px solid var(--brass);
  outline-offset: 3px;
}

.loyalty-btn:disabled {
  opacity: 0.55;
  cursor: not-allowed;
  box-shadow: none;
}

.loyalty-btn--ghost {
  background: transparent;
  border: 1px solid var(--hairline);
  color: var(--text);
  box-shadow: none;
  margin-top: 0.85rem;
}

.loyalty-btn--ghost:hover:not(:disabled) {
  border-color: rgba(197, 160, 89, 0.5);
  filter: none;
}

/* ── SPINNER ──────────────────────────────────────────────────────────── */
.loyalty-spinner {
  display: block;
  width: 1.75rem;
  height: 1.75rem;
  margin: 0 auto 0.9rem;
  border: 2px solid var(--hairline);
  border-top-color: var(--brass);
  border-radius: 50%;
  animation: loyalty-spin 0.75s linear infinite;
}

@keyframes loyalty-spin { to { transform: rotate(360deg); } }

/* ── STATUS PILL (daily cap / reset) ──────────────────────────────────── */
.loyalty-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  margin-top: 1.15rem;
  padding: 0.42rem 0.85rem;
  border: 1px solid rgba(164, 211, 147, 0.28);
  border-radius: 999px;
  background: rgba(164, 211, 147, 0.08);
  font-family: var(--font-data);
  font-size: 0.76rem;
  letter-spacing: 0.04em;
  color: var(--olive);
  font-variant-numeric: tabular-nums;
}

/* ── HOW IT WORKS ─────────────────────────────────────────────────────── */
.loyalty-how { margin-top: 3.5rem; }

.loyalty-steps {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
  margin-top: 1.75rem;
}

.loyalty-step {
  display: flex;
  align-items: flex-start;
  gap: 1.15rem;
}

.loyalty-step-num {
  flex-shrink: 0;
  font-family: var(--font-data);
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--brass);
  font-variant-numeric: tabular-nums;
  padding-top: 0.2rem;
  opacity: 0.8;
}

.loyalty-step-title {
  font-family: var(--font-display);
  font-size: 1.1rem;
  font-weight: 700;
  color: var(--text);
  margin-bottom: 0.3rem;
}

.loyalty-step-copy {
  font-family: var(--font-ui);
  font-size: 0.94rem;
  line-height: 1.6;
  color: var(--text-muted);
}

.loyalty-fineprint {
  margin-top: 2.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--hairline);
  font-family: var(--font-ui);
  font-size: 0.78rem;
  line-height: 1.65;
  color: var(--text-muted);
  opacity: 0.85;
  text-align: center;
}

/* ── MOTION PREFERENCES ───────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  .loyalty-spinner { animation-duration: 2.4s; }
  .loyalty-btn { transition: none; }
  .loyalty-btn:hover:not(:disabled) { transform: none; }
}
