:root {
  /* Matches rewards.yogurtland.co.za and the transactional email templates exactly. */
  --bg: #F0F4FF;
  --card: #ffffff;
  --input-bg: #F8FAFF;
  --ink: #1a2340;
  --ink-soft: #4a5578;
  --ink-faint: #9aa3b8;
  --line: #dde5f7;

  --brand: #3978F6;       /* hero blue, brand identity, links, topbar */
  --brand-dark: #2857C4;
  --brand-soft: #F5F8FF;

  --accent: #E8A020;      /* CTA gold, matches their "Join Now!" button */
  --accent-dark: #C6841A;
  --accent-soft: #FBF0DC;

  --mint: #2E9E5B;
  --mint-soft: #DEF3E6;
  --crit: #e24b4a;
  --crit-soft: #fff8f8;
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  background: var(--bg);
  color: var(--ink);
  font-family: "Nunito Sans", -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  font-size: 16px;
  line-height: 1.5;
}
a { color: var(--brand); }
h1, h2, .btn, .pill, .store-btn, .form-grid label, .login-card label, .redeem-card label, .chart-card-title, .stat-value {
  font-family: "Nunito", "Nunito Sans", -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 20px;
  background: var(--card);
  border-bottom: 1px solid var(--line);
  flex-wrap: wrap;
  gap: 10px;
  position: relative; /* anchors the mobile dropdown below, see .topnav in the breakpoint below */
}
.brand { display: flex; align-items: center; text-decoration: none; }
.brand img { height: 26px; display: block; }
.topnav { display: flex; align-items: center; gap: 16px; font-size: 14px; }
.topnav a { text-decoration: none; color: var(--ink); font-weight: 700; }
.topnav .who { color: var(--ink-soft); font-weight: 400; }

.burger-btn {
  display: none;
  align-items: center; justify-content: center;
  width: 40px; height: 40px;
  border: none; background: transparent; color: var(--ink);
  cursor: pointer; border-radius: 10px; flex-shrink: 0;
}
.burger-btn:hover { background: var(--brand-soft); }

/* Below this width the nav links collapse behind the burger button instead of
   wrapping onto their own crowded row, matches the .data-table stacking breakpoint. */
@media (max-width: 720px) {
  .burger-btn { display: inline-flex; }
  .topnav {
    display: none;
    position: absolute;
    top: 100%;
    right: 20px;
    margin-top: 8px;
    flex-direction: column;
    align-items: flex-end;
    gap: 14px;
    padding: 16px 20px;
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: 14px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
    min-width: 200px;
    z-index: 30;
  }
  .topnav.open { display: flex; }
}

.wrap { max-width: 880px; margin: 0 auto; padding: 24px 20px 80px; }
/* Data-table pages (Vouchers history) get real room to breathe on a wide desktop
   window instead of being squeezed into the same width as a simple form. */
.wrap.wrap-wide { max-width: 1400px; }

h1 { font-size: 26px; font-weight: 800; margin: 0 0 16px; color: var(--ink); }
h2 { font-size: 18px; font-weight: 800; margin: 28px 0 12px; color: var(--ink); }
.lead { color: var(--ink-soft); margin: 0 0 16px; }
.muted { color: var(--ink-faint); font-size: 13px; }
.optional { font-weight: 400; color: var(--ink-faint); font-size: 12px; }
.mono { font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace; }

.card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 20px;
  padding: 20px;
  margin-bottom: 20px;
}

.two-col { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
@media (max-width: 800px) { .two-col { grid-template-columns: 1fr; } }

.form-grid { display: flex; flex-direction: column; gap: 14px; }
.form-grid label { display: flex; flex-direction: column; gap: 6px; font-size: 14px; font-weight: 700; color: var(--ink); }
input, select, button, textarea { font: inherit; }
input[type=text], input[type=email], input[type=password], input[type=date], input[type=tel], input[type=number], select, textarea {
  padding: 10px 14px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--input-bg);
  color: var(--ink);
  resize: vertical;
}
input:focus, select:focus, button:focus, textarea:focus { outline: 2px solid var(--brand); outline-offset: 1px; }

.radio-fieldset { border: 1px solid var(--line); border-radius: 12px; padding: 12px 14px; display: flex; flex-direction: column; gap: 10px; }
.radio-fieldset legend { font-size: 14px; font-weight: 700; color: var(--ink); padding: 0 4px; }
.radio-label { display: flex; align-items: flex-start; gap: 8px; font-size: 13.5px; font-weight: 400; color: var(--ink-soft); cursor: pointer; }
.radio-label input[type=radio] { margin-top: 3px; accent-color: var(--brand); flex-shrink: 0; }

.btn {
  display: inline-block;
  padding: 11px 20px;
  border-radius: 50px;
  border: 1px solid var(--line);
  background: var(--card);
  color: var(--ink);
  text-decoration: none;
  cursor: pointer;
  font-weight: 800;
  font-size: 15px;
}
.btn-primary { background: var(--accent); border-color: var(--accent); color: #ffffff; }
.btn-primary:hover { background: var(--accent-dark); border-color: var(--accent-dark); }
.btn-big { display: block; width: 100%; padding: 16px; font-size: 17px; margin-top: 10px; text-align: center; }
.btn-link { background: none; border: none; color: var(--brand); text-decoration: underline; cursor: pointer; padding: 0; font-size: 13px; font-weight: 700; }

.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }
.icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px;
  border-radius: 10px;
  border: none;
  background: transparent;
  color: var(--brand);
  cursor: pointer;
  padding: 0;
  text-decoration: none;
  transition: background 0.15s;
}
.icon-btn:hover { background: var(--brand-soft); }
.icon-btn.icon-btn-warn { color: var(--accent-dark); }
.icon-btn.icon-btn-warn:hover { background: var(--accent-soft); }
.icon-btn.icon-btn-danger { color: var(--crit); }
.icon-btn.icon-btn-danger:hover { background: var(--crit-soft); }
.icon-btn .icon { display: block; width: 18px; height: 18px; flex-shrink: 0; }

.flash { padding: 12px 18px; border-radius: 14px; margin-bottom: 16px; font-size: 14px; font-weight: 600; }
.flash-success { background: var(--mint-soft); color: var(--mint); }
.flash-error { background: var(--crit-soft); color: var(--crit); }

.pill { display: inline-block; font-size: 12px; font-weight: 800; padding: 3px 12px; border-radius: 100px; }
.pill-issued { background: var(--accent-soft); color: var(--accent-dark); }
.pill-partial { background: var(--brand-soft); color: var(--brand-dark); }
.pill-redeemed { background: var(--mint-soft); color: var(--mint); }
.pill-void { background: var(--crit-soft); color: var(--crit); }
.pill-expired { background: var(--line); color: var(--ink-soft); }

.filter-bar {
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: 12px;
  margin-bottom: 16px;
}
.filter-bar .field { display: flex; flex-direction: column; gap: 6px; font-size: 13px; font-weight: 700; color: var(--ink); }
.filter-bar input[type=text], .filter-bar input[type=date], .filter-bar select { min-width: 160px; }
.filter-bar .field-search { flex: 1 1 220px; }
.filter-bar .field-search input { width: 100%; }

.pagination { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 10px; margin-top: 16px; }
.pagination .btn { padding: 8px 16px; font-size: 14px; }
.pagination .btn[aria-disabled="true"] { opacity: 0.4; pointer-events: none; }

.table-scroll { overflow-x: auto; }
.data-table { width: 100%; border-collapse: collapse; font-size: 13.5px; background: var(--card); border: 1px solid var(--line); border-radius: 20px; overflow: hidden; }
.data-table th, .data-table td { text-align: left; padding: 8px 10px; border-bottom: 1px solid var(--line); }
.data-table th { background: var(--brand-soft); color: var(--brand-dark); font-size: 11px; text-transform: uppercase; letter-spacing: .04em; font-weight: 800; }
.data-table th a.sort-link { color: inherit; text-decoration: none; white-space: nowrap; }
.data-table th a.sort-link:hover { text-decoration: underline; }
.data-table tr:last-child td { border-bottom: none; }
.row-actions { display: flex; align-items: center; gap: 0; white-space: nowrap; }
.row-actions form { display: inline-flex; }
.row-actions .icon-btn { width: 30px; height: 30px; }

.text-actions { display: flex; align-items: center; gap: 14px; white-space: nowrap; }
.text-actions form { display: inline-flex; }

/* Below phone/small-tablet width, each row becomes its own card instead of forcing
   sideways scrolling. Tightened padding above handles wider windows that are still snug. */
@media (max-width: 720px) {
  .table-scroll { overflow-x: visible; }
  .data-table { border: none; background: none; border-radius: 0; }
  .data-table thead { display: none; }
  .data-table, .data-table tbody, .data-table tr, .data-table td { display: block; width: 100%; }
  .data-table tr {
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: 16px;
    padding: 14px 16px;
    margin-bottom: 12px;
  }
  .data-table td { border: none; padding: 3px 0; }
  .data-table td.mono { font-size: 15px; font-weight: 800; }
  .data-table td[data-label]::before {
    content: attr(data-label) ": ";
    color: var(--ink-faint);
    font-weight: 700;
  }
  .row-actions { padding-top: 10px; margin-top: 8px; border-top: 1px solid var(--line); }
}

.detail-table { width: 100%; border-collapse: collapse; margin: 16px 0; }
.detail-table th { text-align: left; color: var(--ink-soft); font-weight: 700; padding: 6px 12px 6px 0; vertical-align: top; width: 110px; }
.detail-table td { padding: 6px 0; }

.login-card, .redeem-card { max-width: 400px; margin: 40px auto; background: var(--card); border: 1px solid var(--line); border-radius: 24px; padding: 32px 28px; text-align: center; }
.login-card form, .redeem-card form { display: flex; flex-direction: column; gap: 14px; text-align: left; }
.login-card label, .redeem-card label { font-weight: 700; font-size: 14px; }
.switch { margin-top: 16px; font-size: 14px; }

.store-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin: 16px 0; }
.store-btn { display: block; padding: 18px; border-radius: 16px; border: 1px solid var(--line); background: var(--input-bg); text-decoration: none; color: var(--ink); font-weight: 800; }
.store-btn:hover { background: var(--brand-soft); border-color: var(--brand); }

.tile-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 14px; margin: 16px 0; }
.tile {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px;
  padding: 28px 16px; border-radius: 20px; border: 1px solid var(--line); background: var(--card);
  text-decoration: none; color: var(--ink); font-weight: 800; text-align: center;
  transition: background 0.15s, border-color 0.15s, transform 0.1s;
}
.tile:hover { background: var(--brand-soft); border-color: var(--brand); transform: translateY(-2px); }
.tile .icon { color: var(--brand); }

.activity-feed { display: flex; flex-direction: column; gap: 8px; }
.activity-item { display: flex; gap: 12px; align-items: flex-start; padding: 14px 16px; background: var(--card); border: 1px solid var(--line); border-radius: 14px; }
.activity-icon { width: 34px; height: 34px; border-radius: 10px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.activity-issued { background: var(--accent-soft); color: var(--accent-dark); }
.activity-redeemed { background: var(--mint-soft); color: var(--mint); }
.activity-failed_attempt { background: var(--crit-soft); color: var(--crit); }
.activity-voided { background: var(--line); color: var(--ink-soft); }
.activity-deleted { background: var(--crit-soft); color: var(--crit); }
.activity-resent { background: var(--brand-soft); color: var(--brand-dark); }
.activity-edited { background: var(--accent-soft); color: var(--accent-dark); }
.activity-body { flex: 1; font-size: 14px; }
.activity-time { font-size: 12px; color: var(--ink-faint); margin-top: 3px; }

.stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; margin: 0 0 8px; }
.stat-tile { background: var(--card); border: 1px solid var(--line); border-radius: 16px; padding: 16px 18px; }
.stat-tile .stat-label { font-size: 11px; font-weight: 800; color: var(--ink-faint); text-transform: uppercase; letter-spacing: .05em; margin-bottom: 6px; }
.stat-tile .stat-value { font-size: 24px; font-weight: 800; color: var(--ink); line-height: 1.2; }
.stat-tile .stat-sub { font-size: 12px; color: var(--ink-soft); margin-top: 4px; }
.stat-tile.stat-accent-brand .stat-value { color: var(--brand-dark); }
.stat-tile.stat-accent-mint .stat-value { color: var(--mint); }
.stat-tile.stat-accent-gold .stat-value { color: var(--accent-dark); }
.stat-tile.stat-accent-crit .stat-value { color: var(--crit); }
.stat-tile.stat-accent-faint .stat-value { color: var(--ink-soft); }

.chart-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin: 0 0 8px; }
@media (max-width: 800px) { .chart-grid { grid-template-columns: 1fr; } }
.chart-card { background: var(--card); border: 1px solid var(--line); border-radius: 20px; padding: 20px; }
.chart-card-title { font-size: 15px; font-weight: 800; color: var(--ink); margin: 0 0 2px; }
.chart-card svg rect { transition: opacity 0.1s; }
.chart-card svg rect:hover { opacity: 0.7; }

.pin-input {
  width: 100%; text-align: center; font-size: 32px; letter-spacing: 12px;
  padding: 16px; border-radius: 16px; border: 1px solid var(--line); background: var(--input-bg);
}

.status-good { color: var(--mint); }
.status-bad { color: var(--crit); }

.qr-reader { max-width: 320px; margin: 16px auto; }
.manual-code-form { display: flex; gap: 10px; }
.manual-code-form input { flex: 1; text-transform: uppercase; }

/* ── On-screen keypad (see assets/keypad.js) ──────────────────────────────────
   Built for the docked till iPad, which often won't raise a software keyboard.
   Keys are deliberately large: they're pressed with a thumb, mid-service, and a
   mis-tap on the redeem amount costs real money. */
.keypad {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
  margin: 14px 0 4px;
}
.keypad-key {
  padding: 18px 0;
  font-family: "Nunito", "Nunito Sans", sans-serif;
  font-size: 22px;
  font-weight: 800;
  color: var(--ink);
  background: var(--input-bg);
  border: 1px solid var(--line);
  border-radius: 14px;
  cursor: pointer;
  /* Tells iOS there's no pan or double-tap-zoom gesture to wait for on these keys,
     so it dispatches the press immediately instead of holding it back. Without
     this, taps on the pad can go nowhere on an iPhone. */
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  user-select: none;
  transition: background 0.12s, border-color 0.12s;
}
.keypad-key:active {
  background: var(--brand-soft);
  border-color: var(--brand);
}
.keypad-key-alt {
  font-size: 19px;
  color: var(--muted);
}

/* ── Redeem screen: keypad beside the card on a wide display ─────────────────
   Stacked by default (phone, portrait iPad). From 900px the card widens and the
   pad moves into a right-hand column that starts level with the voucher title,
   with Cancel beneath it - so the amount, the note and both buttons stay on one
   screen instead of the pad pushing them below the fold.

   Scoped with :has() so only the redeem-form state widens: the same .redeem-card
   also renders "already redeemed", "not found" and "expired", which should stay
   narrow. Browsers without :has() keep the stacked layout, which is the old
   behaviour, so nothing breaks. */
.redeem-layout { display: grid; grid-template-columns: 1fr; gap: 14px; }
.redeem-main { display: flex; flex-direction: column; gap: 14px; }
.redeem-side { display: flex; flex-direction: column; gap: 14px; }

/* The label stacked its text above the box only because the 400px card forced a
   wrap. At 740px there is room for them to sit side by side, which left the
   amount box comically small - so make the stacking explicit, matching the
   .form-grid label rule the rest of the app uses. */
.redeem-card label, .login-card label { display: flex; flex-direction: column; gap: 6px; }
.redeem-card label input, .login-card label input { width: 100%; }

@media (min-width: 900px) {
  .redeem-card:has(.redeem-side .keypad) { max-width: 760px; text-align: left; }
  .redeem-card:has(.redeem-side .keypad) .redeem-layout {
    grid-template-columns: 1fr 260px;
    gap: 32px;
    align-items: start;
  }
  .redeem-card:has(.redeem-side .keypad) .redeem-side .keypad { margin: 0; }
}

/* ── Redeem: in-flight feedback ───────────────────────────────────────────────
   The response is fast now that the recon webhook and confirmation email run
   after it, but a queue at the till still needs an unmistakable acknowledgement,
   and a second tap on Confirm must be impossible. */
.btn-spinner {
  display: inline-block;
  width: 15px; height: 15px;
  margin-right: 9px;
  vertical-align: -2px;
  border: 2px solid rgba(255,255,255,0.45);
  border-top-color: #fff;
  border-radius: 50%;
  animation: btn-spin 0.7s linear infinite;
}
@keyframes btn-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .btn-spinner { animation: none; } }

.redeem-card.is-submitting .keypad { opacity: 0.45; pointer-events: none; }
.redeem-card.is-submitting input { pointer-events: none; }
