/* ══════════════════════════════════════════════════════════════
   KUDOS — View-specific styles
   ══════════════════════════════════════════════════════════════ */

/* ══ AUTH ══════════════════════════════════════════════════════ */
.auth {
  display: grid;
  grid-template-columns: 1.05fr .95fr;
  min-height: 100dvh;
}

.auth-art {
  position: relative;
  overflow: hidden;
  background: linear-gradient(155deg, #2A1F19 0%, #4A2E20 40%, #8B4229 78%, #BF5B3C 100%);
  color: #F6EFE4;
  display: flex; flex-direction: column;
  padding: clamp(2rem, 4vw, 3.5rem);
}
/* Two blob layers on deliberately mismatched clocks — 21s and 29s, which
   share no common multiple worth noticing, so the warm light never repeats
   the same arrangement twice in a sitting. Both drift and breathe rather
   than sliding a background-position: transform and opacity are handed to
   the compositor, and background-position repaints the whole panel every
   frame. That matters on the one screen where somebody is typing. */
.auth-art::before {
  content: "";
  position: absolute; inset: -30%;
  background:
    radial-gradient(45% 40% at 20% 25%, rgba(224,172,83,.4), transparent 65%),
    radial-gradient(40% 35% at 85% 70%, rgba(191,91,60,.55), transparent 65%);
  filter: blur(20px);
  animation: drift 21s var(--ease) infinite alternate,
             blob-breathe 13s var(--ease) infinite alternate;
}
/* The counter-current. Runs the other way and carries the plum out of the
   token set, so the two crossing each other shift the hue as well as the
   brightness. */
.auth-art::after {
  content: "";
  position: absolute; inset: -30%;
  background:
    radial-gradient(38% 34% at 75% 20%, rgba(224,172,83,.30), transparent 66%),
    radial-gradient(44% 38% at 15% 80%, rgba(122,78,99,.42), transparent 68%);
  filter: blur(26px);
  animation: drift-back 29s var(--ease) infinite alternate,
             blob-breathe 17s var(--ease) 2s infinite alternate;
}
/* Travel stays inside the -30% inset, so an edge can never slide into view. */
@keyframes drift { to { transform: translate3d(7%, -8%, 0) scale(1.16) rotate(8deg); } }
@keyframes drift-back { to { transform: translate3d(-8%, 6%, 0) scale(1.2) rotate(-10deg); } }
@keyframes blob-breathe { from { opacity: .72 } to { opacity: 1 } }

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

.auth-quote { margin-top: auto; }
.auth-quote blockquote {
  font-family: var(--font-display);
  font-size: clamp(1.7rem, 1rem + 2.1vw, 3rem);
  font-weight: 400; font-style: italic;
  line-height: 1.14; letter-spacing: -.022em;
  text-wrap: balance;
}
/* Fluid rather than --t-sm. At .875rem this line was fine on a phone, where
   it sits right under the quote, and lost on a laptop, where it has a whole
   column to itself and is the only thing moving on the page. */
.auth-quote cite {
  display: block; margin-top: 1.25rem;
  font-style: normal;
  font-size: clamp(.875rem, .72rem + .45vw, 1.25rem);
  line-height: 1.45;
  opacity: .82;
}

/* Only the ending of the line is typed. The row is held at one line height
   whatever the ending currently is, so the stats below cannot jog upward
   each time it empties. */
.auth-tail { display: inline-block; white-space: nowrap; }
.auth-tail i { font-style: normal; }
.auth-caret {
  display: inline-block;
  width: 1.5px; height: 1.05em;
  margin-left: 2px;
  vertical-align: -.16em;
  background: currentColor;
  opacity: .85;
}
/* Blinks only while it is sitting still. A cursor that blinks mid-word looks
   like two animations arguing. */
.auth-caret.resting { animation: caret-blink 1.05s steps(1, end) infinite; }
@keyframes caret-blink { 0%, 50% { opacity: .85 } 50.01%, 100% { opacity: 0 } }

.auth-forgot {
  align-self: center;
  font-size: var(--t-sm); color: var(--ink-3);
  padding: .35rem .5rem; border-radius: var(--r-sm);
  text-decoration: underline; text-underline-offset: 3px;
  text-decoration-color: var(--rule-strong);
}
.auth-forgot:hover { color: var(--ink); text-decoration-color: currentColor; }

.auth-stats { display: flex; gap: 2.2rem; margin-top: 2.5rem; padding-top: 1.6rem; border-top: 1px solid rgba(255,255,255,.2); flex-wrap: wrap; }
.auth-stat b { display: block; font-family: var(--font-display); font-size: 1.9rem; font-weight: 600; line-height: 1; }
.auth-stat span { font-size: var(--t-micro); letter-spacing: .13em; text-transform: uppercase; opacity: .75; }

/* NOT justify-content: center. This is a scroll container, and a centred flex
   child that outgrows it overflows equally in both directions — the top half
   ends up above the scrollable area, where no amount of scrolling will reach
   it. That is what put the Sign in / Register tabs off the top of a phone on
   the register form: the fields below could be scrolled to, the tabs could
   not. `margin-block: auto` centres exactly the same way when there is room
   and simply stops centring when there is not. */
.auth-panel {
  display: flex; flex-direction: column; justify-content: flex-start;
  padding: clamp(2rem, 4vw, 3.5rem);
  overflow-y: auto;
  max-height: 100dvh;
}
.auth-form { width: min(400px, 100%); margin-inline: auto; margin-block: auto; }
.auth-form h1 { font-size: var(--t-h1); margin: .5rem 0 .5rem; }
.auth-tabs { display: flex; gap: .25rem; padding: 4px; background: var(--paper-3); border-radius: var(--r-pill); margin-bottom: 1.75rem; }
.auth-tabs button {
  flex: 1; padding: .5rem; border-radius: var(--r-pill);
  font-size: var(--t-sm); font-weight: 600; color: var(--ink-3);
  transition: all .25s var(--ease);
}
.auth-tabs button.active { background: var(--surface); color: var(--ink); box-shadow: var(--shadow-sm); }

.demo-box {
  margin-top: 1.5rem; padding: .85rem 1rem;
  border: 1px dashed var(--rule-strong); border-radius: var(--r-md);
  background: var(--surface-sunk);
  font-size: var(--t-xs); color: var(--ink-3);
}
.demo-box b { color: var(--ink-2); }
.demo-box code {
  font-family: var(--font-mono); font-size: .95em;
  background: var(--paper-3); padding: 1px 5px; border-radius: 4px; color: var(--ink);
}
.demo-pick { display: flex; gap: .4rem; flex-wrap: wrap; margin-top: .6rem; }

@media (max-width: 900px) {
  .auth { grid-template-columns: 1fr; }
  .auth-art { min-height: 34dvh; padding: 1.6rem; }
  /* Same guard as .topbar in components.css — inert while viewport-fit=cover
     stays out of index.html, and there to catch it if that changes. */
  @media (display-mode: standalone) {
    .auth-art { padding-top: calc(1.6rem + env(safe-area-inset-top, 0px)); }
  }
  .auth-stats { display: none; }
  .auth-panel { padding: 2rem 1.25rem 3rem; }
}

/* ══ DASHBOARD ═════════════════════════════════════════════════ */
.hero {
  position: relative;
  border-radius: var(--r-xl);
  padding: clamp(1.8rem, 3.4vw, 3rem);
  background: linear-gradient(140deg, var(--paper-2), var(--paper-3));
  border: 1px solid var(--rule);
  overflow: hidden;
  margin-bottom: 2rem;
  isolation: isolate;
}
/* Two drifting light sources give the panel depth without an image. */
.hero::before {
  content: ""; position: absolute; inset: -40%; z-index: -1;
  background:
    radial-gradient(34% 40% at 78% 16%, rgba(201,138,43,.42), transparent 64%),
    radial-gradient(30% 38% at 20% 84%, rgba(191,91,60,.30), transparent 66%);
  filter: blur(24px);
  animation: aurora 26s var(--ease) infinite alternate;
}
.hero::after {
  content: "";
  position: absolute; top: -55%; right: -12%; z-index: -1;
  width: 460px; height: 460px; border-radius: 50%;
  background: radial-gradient(circle, var(--clay-soft), transparent 68%);
  opacity: .7; pointer-events: none;
}
:root[data-theme="dark"] .hero::after { opacity: .4; }
.hero > * { position: relative; z-index: 1; }
.hero h1 { font-size: var(--t-hero); font-weight: 400; letter-spacing: -.035em; }
.hero h1 em { font-style: italic; }
.hero p { color: var(--ink-2); max-width: 46ch; margin-top: .9rem; font-size: 1.02rem; }
.hero-actions { display: flex; gap: .6rem; margin-top: 1.6rem; flex-wrap: wrap; }

/* Decorative sparkle cluster in the hero corner. */
.hero-deco {
  position: absolute; top: 8%; right: 6%; z-index: 0;
  width: clamp(90px, 12vw, 160px); height: auto;
  opacity: .5;
  animation: float-y 6s var(--ease) infinite alternate;
}
.hero-deco .s1 { animation: spin-slow 26s linear infinite; transform-origin: center; }
@media (max-width: 720px) { .hero-deco { display: none; } }

/* Stat strip */
.stat-strip {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 1px; background: var(--rule);
  border: 1px solid var(--rule); border-radius: var(--r-lg);
  overflow: hidden; margin-bottom: 2.5rem;
}
.stat {
  background: var(--surface);
  padding: 1.15rem 1.25rem;
  position: relative;
  overflow: hidden;
  transition: background .35s var(--ease);
}
.stat::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 2px;
  background: var(--grad-warm);
  transform: scaleX(0); transform-origin: left;
  transition: transform .5s var(--ease-out);
}
.stat:hover::after { transform: scaleX(1); }
.stat:hover { background: var(--surface-sunk); }
.stat b {
  display: block; font-family: var(--font-display);
  font-size: 2rem; font-weight: 600; line-height: 1; letter-spacing: -.02em;
  margin-bottom: .3rem;
  font-variant-numeric: tabular-nums;
}
.stat span { font-size: var(--t-xs); color: var(--ink-3); font-weight: 500; }
.stat-trend { font-size: var(--t-micro); color: var(--olive); font-weight: 700; margin-left: .35rem; }

/* Layout: feed + rail */
/* minmax(0,1fr) in BOTH rules, not just the desktop one. A grid item's
   default min-width is auto, meaning it refuses to shrink below its content's
   min-content width — so a plain `1fr` column is only as narrow as its widest
   child allows, and one wide child pushes the whole grid past the viewport.
   The desktop rule always had the guard; the mobile override did not, which
   left the single-column phone layout as the one that could blow out. */
.dash-grid { display: grid; grid-template-columns: minmax(0,1fr) 320px; gap: 2rem; align-items: start; }
@media (max-width: 1040px) { .dash-grid { grid-template-columns: minmax(0,1fr); } }
/* Same reasoning one level down: the column's own children must be allowed
   to shrink, or the guard above buys nothing. */
.dash-grid > * { min-width: 0; }

.rail { display: flex; flex-direction: column; gap: 1.25rem; position: sticky; top: 88px; }
@media (max-width: 1040px) { .rail { position: static; } }

/* ── Appreciation feed ─────────────────────────────────────── */
.feed { display: flex; flex-direction: column; gap: 1rem; }

/* Text somebody typed can hold a token with no break opportunity in it — a
   file name, a case reference, a pasted link. Nothing in the app wrapped
   those except .detail-row .v, so one long word in a shoutout could widen the
   column it sits in and take the page sideways with it. */
.kudo p, .kudo blockquote, .kudo-msg,
.pf-bio, .pf-name, .mini-name, .who { overflow-wrap: anywhere; }

.kudo {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--r-lg);
  padding: 1.3rem 1.4rem 1rem;
  box-shadow: var(--shadow-xs);
  transition: box-shadow .3s var(--ease), transform .3s var(--ease-out);
}
.kudo:hover { box-shadow: var(--shadow-md); transform: translateY(-2px); }
.kudo::before {
  content: ""; position: absolute; left: 0; top: 1.5rem; bottom: 1.5rem;
  width: 3px; border-radius: 0 3px 3px 0;
  background: var(--accent, var(--clay));
  opacity: .9;
}

/* Both rows wrap. This header holds two names side by side with an arrow
   between them, and neither name has a length limit — a nowrap row put the
   card off the side of a phone the moment the pair got long. Wrapping keeps
   the names whole, which matters more here than keeping them on one line. */
.kudo-top { display: flex; align-items: center; gap: .7rem; margin-bottom: .9rem; flex-wrap: wrap; }
.kudo-people { display: flex; align-items: center; gap: .5rem; min-width: 0; flex-wrap: wrap; }
.kudo-people > *, .kudo-people a { min-width: 0; }
.kudo-arrow { color: var(--ink-4); flex: none; }
.kudo-arrow svg { width: 15px; height: 15px; }
.kudo-name { font-weight: 600; font-size: .9rem; overflow-wrap: anywhere; }
.kudo-name:hover { color: var(--clay); }
.kudo-time { margin-left: auto; font-size: var(--t-xs); color: var(--ink-4); white-space: nowrap; }

/* The remark is the product — set it large, quiet and modern.
   The old decorative curly quotes are gone: the size and the coloured
   accent bar already mark this out as someone's words. */
/* Poppins is a geometric sans with a big x-height, so it needs a smaller
   size and a taller leading than the serif it replaced to read as calmly. */
.kudo-remark {
  font-family: var(--font-quote);
  font-size: 1.06rem; font-weight: 500; line-height: 1.62;
  letter-spacing: -.011em;
  color: var(--ink-2);
  margin-bottom: 1.05rem;
  text-wrap: pretty;
}
@media (max-width: 620px) { .kudo-remark { font-size: 1rem; line-height: 1.58; } }

.kudo-foot { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; padding-top: .75rem; border-top: 1px solid var(--rule); }
.kudo-points {
  display: inline-flex; align-items: center; gap: .3rem;
  padding: .25rem .65rem; border-radius: var(--r-pill);
  background: var(--clay-soft); color: var(--clay-deep);
  font-family: var(--font-display); font-weight: 700; font-size: .88rem;
}
:root[data-theme="dark"] .kudo-points { color: var(--clay); }
.kudo-points svg { width: 13px; height: 13px; }

.react {
  display: inline-flex; align-items: center; gap: .3rem;
  padding: .25rem .6rem; border-radius: var(--r-pill);
  font-size: var(--t-xs); font-weight: 600; color: var(--ink-3);
  border: 1px solid transparent;
  transition: all .2s var(--ease-back);
}
.react:hover { background: var(--paper-3); transform: translateY(-1px); }
.react.on { background: var(--clay-soft); color: var(--clay-deep); border-color: color-mix(in srgb, var(--clay) 30%, transparent); }
:root[data-theme="dark"] .react.on { color: var(--clay); }
.react em { font-style: normal; font-size: .95rem; line-height: 1; }

/* ── Rail widgets ──────────────────────────────────────────── */
.mini-list { display: flex; flex-direction: column; }
.mini-row {
  display: flex; align-items: center; gap: .7rem;
  padding: .6rem 0;
  border-bottom: 1px solid var(--rule);
}
.mini-row:last-child { border-bottom: 0; padding-bottom: 0; }
.mini-row:first-child { padding-top: 0; }
.mini-name { font-size: .87rem; font-weight: 600; line-height: 1.25; }
.mini-meta { font-size: var(--t-xs); color: var(--ink-3); }
.mini-val { margin-left: auto; font-family: var(--font-display); font-weight: 700; font-size: .95rem; color: var(--clay); white-space: nowrap; }

.rank-no {
  width: 22px; flex: none; text-align: center;
  font-family: var(--font-display); font-weight: 700; font-size: .95rem; color: var(--ink-4);
}
.rank-no.top { color: var(--clay); }

/* Spotlight card */
.spotlight {
  position: relative; overflow: hidden;
  border-radius: var(--r-lg);
  padding: 1.5rem 1.35rem;
  background: linear-gradient(150deg, #2A1F19, #6B3521 70%, #A94F30);
  color: #F6EFE4;
  text-align: center;
  box-shadow: var(--shadow-md);
}
.spotlight::before {
  content: ""; position: absolute; inset: -40%;
  background: radial-gradient(38% 34% at 50% 12%, rgba(224,172,83,.5), transparent 62%);
}
.spotlight > * { position: relative; }
.spotlight .avatar { margin: .85rem auto .7rem; box-shadow: 0 0 0 3px rgba(255,255,255,.22); }
.spotlight h3 { font-size: 1.3rem; }
.spotlight .eyebrow { color: rgba(246,239,228,.72); }
.spotlight p { font-size: var(--t-xs); opacity: .8; margin-top: .3rem; }
.spotlight .points { color: #F0C078; font-size: 1.5rem; margin-top: .7rem; display: block; }

/* ══ DIRECTORY ═════════════════════════════════════════════════ */
.people-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 1rem; }

.person {
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--r-lg);
  padding: 1.5rem 1.1rem 1.2rem;
  text-align: center;
  position: relative; overflow: hidden;
  /* Column layout so .person-stats can be pinned to the bottom with
     margin-top:auto — otherwise a two-line name pushes the stats row
     down and cards in the same row stop lining up. */
  display: flex; flex-direction: column; align-items: center;
  transition: transform .35s var(--ease-out), box-shadow .35s var(--ease), border-color .3s;
}
.person::before {
  content: ""; position: absolute; inset: 0 0 auto; height: 62px;
  background: linear-gradient(160deg, var(--tint, var(--clay-soft)), transparent);
  opacity: .8;
}
.person > * { position: relative; }
.person:hover { transform: translateY(-4px); box-shadow: var(--shadow-md); border-color: var(--rule-strong); }
.person .avatar { margin: 0 auto .8rem; box-shadow: 0 0 0 3px var(--surface), var(--shadow-sm); }
.person-name { font-family: var(--font-display); font-size: 1.05rem; font-weight: 600; line-height: 1.2; }
.person-role { font-size: var(--t-xs); color: var(--ink-3); margin-top: .2rem; min-height: 2.2em; }
/* The team chip needs guaranteed clearance: `margin-top:auto` on the stats
   row collapses to zero once the card content fills the height, which left
   the chip sitting flush on the divider line. */
.person > .chip {
  margin-top: .5rem; margin-bottom: 1rem;
  /* Long team names ("Non Banca Partnership & Special Projects") are wider
     than the card. `.chip` is nowrap by default, so the pill burst out of
     both edges and got clipped. Here it wraps instead. */
  max-width: 100%;
  white-space: normal;
  text-align: center;
  line-height: 1.35;
  border-radius: var(--r-md);
  padding: .3rem .7rem;
}
.person-stats {
  display: flex; justify-content: center; gap: 1.1rem;
  width: 100%; margin-top: auto; padding-top: .8rem;
  border-top: 1px solid var(--rule);
}
.person-stat b { display: block; font-family: var(--font-display); font-size: 1.05rem; font-weight: 700; line-height: 1; }
.person-stat span { font-size: var(--t-micro); color: var(--ink-4); letter-spacing: .06em; text-transform: uppercase; }
.person-cake { position: absolute; top: .7rem; right: .8rem; font-size: 1rem; }

/* ══ PROFILE ═══════════════════════════════════════════════════
   Every profile is tinted with that person's own hue, passed in as
   --pf, so no two look identical.
   ═════════════════════════════════════════════════════════════ */
.pf-hero {
  position: relative;
  border-radius: var(--r-xl);
  overflow: hidden;
  border: 1px solid var(--rule);
  background: var(--surface);
  box-shadow: var(--shadow-md);
  margin-bottom: 1.1rem;
}

.pf-cover {
  position: relative;
  height: 152px;
  overflow: hidden;
  background:
    radial-gradient(80% 150% at 6% 0%, rgba(255,255,255,.28), transparent 58%),
    linear-gradient(122deg,
      var(--pf, var(--clay)) 0%,
      color-mix(in srgb, var(--pf, var(--clay)) 42%, #C98A2B) 100%);
}
.pf-cover::after {
  content: ""; position: absolute; inset: -45%;
  background:
    radial-gradient(30% 40% at 74% 22%, rgba(255,255,255,.30), transparent 62%),
    radial-gradient(26% 34% at 22% 88%, rgba(0,0,0,.24), transparent 66%);
  filter: blur(18px);
  animation: aurora 30s var(--ease) infinite alternate;
  pointer-events: none;
}
/* Oversized initials, clipped by the cover — gives each header a mark. */
.pf-watermark {
  position: absolute; right: 1.8rem; bottom: -1.1rem;
  font-family: var(--font-display);
  font-size: 7.5rem; font-weight: 700; line-height: .82;
  letter-spacing: -.07em;
  color: rgba(255,255,255,.18);
  user-select: none; pointer-events: none;
}
@media (max-width: 620px) { .pf-watermark { font-size: 5rem; right: .9rem; } }

.pf-body { padding: 0 clamp(1.25rem, 3vw, 2.2rem) 1.6rem; }

/* Only the avatar overlaps the cover. Pulling the whole row up put the
   name on the gradient, where contrast depends on the person's hue. */
.pf-id {
  position: relative; z-index: 1;
  display: flex; align-items: flex-start; gap: 1.3rem;
  padding-top: 1rem; flex-wrap: wrap;
}
.pf-avatar { margin-top: -78px; }
/* A ring in the person's own colour, sitting on a surface-coloured pad. */
.pf-avatar {
  flex: none; border-radius: 50%; padding: 5px;
  background: var(--surface);
  box-shadow: var(--shadow-md);
}
.pf-avatar .avatar {
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--pf, var(--clay)) 60%, transparent);
}
.pf-meta { flex: 1; min-width: 210px; padding-top: .1rem; }
.pf-name { font-size: clamp(1.55rem, 1.1rem + 1.7vw, 2.35rem); line-height: 1.06; }
.pf-role { color: var(--ink-2); font-size: .97rem; font-weight: 500; margin-top: .28rem; }
.pf-tags { display: flex; gap: .4rem; flex-wrap: wrap; margin-top: .8rem; }
.pf-actions { display: flex; gap: .5rem; flex-wrap: wrap; margin-left: auto; padding-top: .25rem; }

@media (max-width: 620px) {
  .pf-cover { height: 118px; }
  .pf-avatar { margin-top: -62px; }
  .pf-avatar .avatar.xl { width: 82px; height: 82px; font-size: 1.7rem; }
  /* Once the row wraps, margin-left:auto would strand the button mid-row. */
  .pf-actions { margin-left: 0; width: 100%; }
  .pf-actions .btn { flex: 1; }
}

.pf-bio {
  margin-top: 1.5rem;
  padding-left: 1.05rem;
  border-left: 3px solid color-mix(in srgb, var(--pf, var(--clay)) 65%, transparent);
  font-family: var(--font-display);
  font-size: 1.14rem; font-style: italic; line-height: 1.5;
  color: var(--ink-2);
  max-width: 62ch;
}

/* ── Stat tiles ────────────────────────────────────────────── */
.stat-tiles {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(146px, 1fr));
  gap: .8rem; margin-bottom: 2rem;
}
.stat-tile {
  position: relative; overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--r-lg);
  padding: 1.05rem 1.15rem;
  transition: transform .35s var(--ease-out), box-shadow .35s var(--ease), border-color .3s;
}
.stat-tile:hover { transform: translateY(-3px); box-shadow: var(--shadow-md); border-color: var(--rule-strong); }
.stat-tile .ico {
  width: 30px; height: 30px; border-radius: 9px;
  display: grid; place-items: center; margin-bottom: .75rem;
  background: var(--paper-3); color: var(--ink-3);
}
.stat-tile.t-clay  .ico { background: var(--clay-soft);  color: var(--clay-deep); }
.stat-tile.t-amber .ico { background: var(--amber-soft); color: #8A5D12; }
.stat-tile.t-olive .ico { background: var(--olive-soft); color: #4C5A38; }
.stat-tile.t-plum  .ico { background: var(--plum-soft);  color: #5E3A4B; }
.stat-tile.t-teal  .ico { background: var(--teal-soft);  color: #2C5253; }
:root[data-theme="dark"] .stat-tile.t-clay  .ico { color: var(--clay); }
:root[data-theme="dark"] .stat-tile.t-amber .ico { color: var(--amber); }
:root[data-theme="dark"] .stat-tile.t-olive .ico { color: var(--olive); }
:root[data-theme="dark"] .stat-tile.t-plum  .ico { color: var(--plum); }
:root[data-theme="dark"] .stat-tile.t-teal  .ico { color: var(--teal); }
.stat-tile b {
  display: block; font-family: var(--font-display);
  font-size: 1.8rem; font-weight: 600; line-height: 1; letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
}
.stat-tile span { display: block; font-size: var(--t-xs); color: var(--ink-3); margin-top: .32rem; }

/* ── Recognition over time ─────────────────────────────────── */
.spark { display: flex; align-items: flex-end; gap: 5px; height: 88px; margin-top: 1.1rem; }
.spark-col {
  flex: 1; height: 100%;
  display: flex; flex-direction: column; justify-content: flex-end;
  border-radius: 6px;
  transition: background .2s var(--ease);
}
.spark-col:hover { background: var(--surface-sunk); }
.spark-bar {
  width: 100%; min-height: 4px; border-radius: 5px;
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--pf, var(--clay)) 90%, white),
    var(--pf, var(--clay)));
  transition: height .9s var(--ease-out);
}
.spark-col.empty .spark-bar { background: var(--paper-3); min-height: 4px; }
.spark-axis {
  display: flex; justify-content: space-between;
  font-size: var(--t-micro); color: var(--ink-4);
  margin-top: .55rem; letter-spacing: .06em; text-transform: uppercase;
}

/* ── Value breakdown ───────────────────────────────────────── */
/* Two rows per value instead of one — a fixed-width label column made
   "Customer First" and "Above & Beyond" wrap and knocked the bars out
   of alignment. */
.vrow { padding: .6rem 0; }
.vrow + .vrow { border-top: 1px solid var(--rule); }
.vrow-top { display: flex; align-items: center; gap: .45rem; margin-bottom: .45rem; }
.vrow-name { font-size: var(--t-xs); font-weight: 600; color: var(--ink-2); }
.vrow-num {
  margin-left: auto; font-size: var(--t-xs); font-weight: 700;
  color: var(--ink-3); font-variant-numeric: tabular-nums;
}
.vrow-track { height: 6px; border-radius: 99px; background: var(--paper-3); overflow: hidden; }
.vrow-track i { display: block; height: 100%; border-radius: 99px; transition: width .9s var(--ease-out); }

/* ── Details ───────────────────────────────────────────────── */
.detail-list { display: flex; flex-direction: column; }
.detail-row { display: flex; gap: .75rem; align-items: flex-start; padding: .7rem 0; min-width: 0; }
.detail-row + .detail-row { border-top: 1px solid var(--rule); }
.detail-row > div { min-width: 0; }
.detail-row .ico {
  width: 28px; height: 28px; flex: none; border-radius: 8px;
  display: grid; place-items: center;
  background: var(--paper-3); color: var(--ink-3);
}
.detail-row .k { font-size: var(--t-micro); letter-spacing: .1em; text-transform: uppercase; color: var(--ink-4); }
/* Long addresses like ahmad.syahmizamir@retaildev.com.my overflowed the card. */
.detail-row .v { font-size: .92rem; font-weight: 500; overflow-wrap: anywhere; margin-top: 1px; }

/* ══ BIRTHDAYS ═════════════════════════════════════════════════ */
.bday-hero {
  border-radius: var(--r-xl);
  padding: clamp(1.5rem, 3vw, 2.4rem);
  background: linear-gradient(140deg, var(--plum-soft), var(--amber-soft));
  border: 1px solid var(--rule);
  display: flex; align-items: center; gap: 1.6rem; flex-wrap: wrap;
  margin-bottom: 2.5rem;
}
.bday-hero .avatar { box-shadow: 0 0 0 4px var(--surface), var(--shadow-md); }
.bday-hero h2 { font-size: var(--t-h2); }
.bday-hero p { color: var(--ink-2); margin-top: .4rem; }

/* 300px, not 250px — Malaysian full names need the room. */
.month-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 1.1rem; }
.month-card { background: var(--surface); border: 1px solid var(--rule); border-radius: var(--r-lg); padding: 1.15rem 1.2rem; }
.month-card.now { border-color: var(--clay); box-shadow: 0 0 0 3px var(--clay-soft); }
.month-head { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: .8rem; padding-bottom: .6rem; border-bottom: 1px solid var(--rule); }
.month-head h3 { font-size: 1.12rem; }
.month-head span { font-size: var(--t-micro); color: var(--ink-4); letter-spacing: .1em; text-transform: uppercase; }

.bday-row { display: flex; align-items: center; gap: .65rem; padding: .5rem 0; }
.bday-date {
  width: 38px; flex: none; text-align: center;
  font-family: var(--font-display); font-weight: 700; font-size: 1.05rem;
  color: var(--ink-3); line-height: 1;
}
.bday-date small { display: block; font-size: .55rem; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-4); font-family: var(--font-body); margin-top: 2px; }
/* flex:1 + min-width:0 keeps the name column elastic; without it a long
   name wrapped one word per line and collided with the "in N days" chip. */
.bday-info { flex: 1; min-width: 0; }
.bday-info b {
  display: block; font-size: .87rem; font-weight: 600; line-height: 1.25;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
.bday-info span {
  display: block; font-size: var(--t-xs); color: var(--ink-4);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.bday-soon { flex: none; margin-left: auto; align-self: center; }

/* ══ TIMELINE ══════════════════════════════════════════════════ */
.tl { position: relative; padding-left: 2.4rem; }
.tl::before {
  content: ""; position: absolute; left: 9px; top: 8px; bottom: 8px;
  width: 2px; background: linear-gradient(180deg, var(--clay), var(--rule) 22%, var(--rule));
  border-radius: 2px;
}
.tl-item { position: relative; margin-bottom: 2rem; }
.tl-dot {
  position: absolute; left: -2.4rem; top: 6px;
  width: 20px; height: 20px; border-radius: 50%;
  background: var(--surface); border: 2px solid var(--rule-strong);
  display: grid; place-items: center;
  font-size: .6rem;
}
.tl-item.upcoming .tl-dot { border-color: var(--clay); background: var(--clay); color: #fff; box-shadow: 0 0 0 4px var(--clay-soft); }

.tl-date { font-size: var(--t-xs); font-weight: 600; letter-spacing: .06em; color: var(--ink-3); text-transform: uppercase; }
.event {
  margin-top: .5rem;
  background: var(--surface); border: 1px solid var(--rule);
  border-radius: var(--r-lg); overflow: hidden;
  box-shadow: var(--shadow-xs);
  transition: box-shadow .3s var(--ease), transform .3s var(--ease-out);
}
.event:hover { box-shadow: var(--shadow-md); transform: translateY(-2px); }
.event-body { padding: 1.25rem 1.35rem; }
.event h3 { font-size: 1.3rem; margin-bottom: .4rem; }
.event p { color: var(--ink-2); font-size: .93rem; }
.event-meta { display: flex; gap: 1rem; flex-wrap: wrap; margin-top: .9rem; font-size: var(--t-xs); color: var(--ink-3); }
.event-meta span { display: inline-flex; align-items: center; gap: .3rem; }
.event-meta svg { width: 13px; height: 13px; }

/* auto-fit (not auto-fill) so a short album stretches to fill the row
   instead of leaving empty grid tracks showing the gap colour. */
.gallery { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 3px; background: var(--rule); }
.gallery figure {
  aspect-ratio: 4/3; position: relative; overflow: hidden;
  background: var(--paper-3); cursor: pointer;
}
.gallery img { width: 100%; height: 100%; object-fit: cover; transition: transform .6s var(--ease-out); }
.gallery figure:hover img { transform: scale(1.07); }
.gallery .ph {
  width: 100%; height: 100%;
  display: grid; place-items: center;
  font-family: var(--font-display); font-size: .78rem; font-weight: 600;
  color: rgba(255,255,255,.9);
  letter-spacing: .04em;
  padding: .5rem; text-align: center;
  transition: transform .6s var(--ease-out);
}
.gallery figure:hover .ph { transform: scale(1.06); }
.gallery .more {
  position: absolute; inset: 0; display: grid; place-items: center;
  background: rgba(28,24,21,.62); color: #fff;
  font-family: var(--font-display); font-size: 1.2rem; font-weight: 600;
}

.countdown {
  display: inline-flex; align-items: baseline; gap: .35rem;
  padding: .3rem .75rem; border-radius: var(--r-pill);
  background: var(--clay); color: #fff;
  font-size: var(--t-xs); font-weight: 700;
}
.countdown b { font-family: var(--font-display); font-size: .95rem; }

/* ══ LEADERBOARD ═══════════════════════════════════════════════ */
.podium { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; align-items: end; margin-bottom: 2.5rem; }
.pod { text-align: center; position: relative; }
.pod .avatar { margin: 0 auto .7rem; }
.pod-name { font-family: var(--font-display); font-size: 1.02rem; font-weight: 600; line-height: 1.2; }
.pod-role { font-size: var(--t-micro); color: var(--ink-3); margin-top: .15rem; }
.pod-block {
  margin-top: .8rem; border-radius: var(--r-md) var(--r-md) 0 0;
  background: linear-gradient(180deg, var(--paper-3), var(--paper-2));
  border: 1px solid var(--rule); border-bottom: 0;
  padding: .9rem .5rem 1.1rem;
}
.pod-1 .pod-block { height: 118px; background: linear-gradient(180deg, var(--clay), var(--clay-deep)); border-color: transparent; color: #fff; box-shadow: var(--shadow-md); }
.pod-2 .pod-block { height: 88px; }
.pod-3 .pod-block { height: 70px; }
.pod-pts { font-family: var(--font-display); font-size: 1.5rem; font-weight: 700; line-height: 1; }
.pod-lbl { font-size: var(--t-micro); letter-spacing: .1em; text-transform: uppercase; opacity: .75; }
.pod-medal { font-size: 1.3rem; margin-bottom: .3rem; }

.lb-table { background: var(--surface); border: 1px solid var(--rule); border-radius: var(--r-lg); overflow: hidden; }
.lb-row {
  display: flex; align-items: center; gap: .85rem;
  padding: .85rem 1.15rem;
  border-bottom: 1px solid var(--rule);
  transition: background .2s;
}
.lb-row:last-child { border-bottom: 0; }
.lb-row:hover { background: var(--surface-sunk); }
.lb-row.me { background: var(--clay-soft); }
.lb-rank { width: 30px; flex: none; font-family: var(--font-display); font-weight: 700; font-size: 1rem; color: var(--ink-4); }
.lb-name { font-weight: 600; font-size: .92rem; line-height: 1.25; }
.lb-sub { font-size: var(--t-xs); color: var(--ink-3); }
.lb-bar { flex: 1; max-width: 180px; height: 6px; border-radius: 99px; background: var(--paper-3); overflow: hidden; }
.lb-bar i { display: block; height: 100%; background: linear-gradient(90deg, var(--amber), var(--clay)); border-radius: 99px; transition: width 1s var(--ease-out); }
.lb-pts { font-family: var(--font-display); font-weight: 700; font-size: 1.05rem; width: 62px; text-align: right; flex: none; }
@media (max-width: 640px) { .lb-bar { display: none; } }

/* At 390px the three podium columns squeezed names onto three lines each
   and knocked the medals out of line. Below 620px it becomes a plain
   ranked strip — the table underneath already tells the same story. */
@media (max-width: 620px) {
  .podium { grid-template-columns: 1fr; gap: 0; margin-bottom: 1.5rem; }
  .pod {
    display: flex; align-items: center; gap: .75rem; text-align: left;
    padding: .7rem .9rem;
    background: var(--surface);
    border: 1px solid var(--rule);
    border-radius: var(--r-md);
    margin-bottom: .5rem;
  }
  .pod .avatar { margin: 0; }
  .pod-medal { font-size: 1.15rem; margin: 0; order: -1; }
  .pod-name { flex: 1; font-size: .95rem; }
  .pod-role { display: none; }
  .pod-block {
    height: auto !important; margin: 0; padding: .3rem .7rem;
    border: 0; border-radius: var(--r-pill);
    background: var(--clay-soft); color: var(--clay-deep);
    display: flex; align-items: baseline; gap: .3rem;
  }
  :root[data-theme="dark"] .pod-block { color: var(--clay); }
  .pod-1 .pod-block { background: var(--grad-warm); color: #fff; box-shadow: none; }
  .pod-pts { font-size: 1.05rem; }
  .pod-lbl { font-size: var(--t-micro); }
}

/* ── Redacted leaderboard rows (below the top 15) ──────────── */
.lb-row.locked { cursor: default; }
.lb-row.locked:hover { background: none; }
.lb-mask {
  background: var(--paper-3) !important;
  border: 1px dashed var(--rule-strong);
  box-shadow: none;
  color: var(--ink-4);
  font-family: var(--font-body); font-weight: 700;
}
/* Placeholder bars. No real text is rendered, so there is nothing to
   read in the DOM — the blur is decoration, not the privacy mechanism. */
.skel {
  display: block;
  height: .62em;
  margin: .28em 0;
  border-radius: 99px;
  background: var(--ink-4);
  opacity: .3;
  filter: blur(2.5px);
  user-select: none;
}
.skel-sm { height: .48em; opacity: .2; }

.privacy-note {
  display: flex; align-items: flex-start; gap: .7rem;
  margin-top: 1.25rem; padding: .9rem 1.1rem;
  border: 1px dashed var(--rule-strong);
  border-radius: var(--r-md);
  background: var(--surface-sunk);
  font-size: var(--t-xs); color: var(--ink-3); line-height: 1.55;
}
.privacy-note svg { color: var(--ink-4); margin-top: 2px; flex: none; }

/* ══ GIVE RECOGNITION MODAL ════════════════════════════════════ */
.picker { max-height: 240px; overflow-y: auto; border: 1px solid var(--rule); border-radius: var(--r-md); }
.picker-row {
  display: flex; align-items: center; gap: .7rem;
  padding: .55rem .8rem; width: 100%; text-align: left;
  border-bottom: 1px solid var(--rule);
  transition: background .15s;
}
.picker-row:last-child { border-bottom: 0; }
.picker-row:hover { background: var(--surface-sunk); }
.picker-row.sel { background: var(--clay-soft); }
.picker-row b { font-size: .88rem; font-weight: 600; display: block; line-height: 1.2; }
/* Scoped to the text column only — a bare `.picker-row span` would also
   match the avatar and repaint its initials in body-text colour. */
.picker-row .picker-sub { font-size: var(--t-xs); color: var(--ink-3); }
.picker-row .tick { margin-left: auto; color: var(--clay); }

.value-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(105px, 1fr)); gap: .5rem; }
.value-opt {
  padding: .7rem .5rem; border-radius: var(--r-md);
  border: 1.5px solid var(--rule); background: var(--surface);
  text-align: center; transition: all .22s var(--ease-back);
}
.value-opt em { display: block; font-style: normal; font-size: 1.15rem; margin-bottom: .25rem; }
.value-opt b { font-size: var(--t-xs); font-weight: 600; color: var(--ink-2); }
.value-opt:hover { transform: translateY(-2px); border-color: var(--ink-4); }
.value-opt.sel { border-color: var(--clay); background: var(--clay-soft); box-shadow: var(--shadow-sm); }
.value-opt.sel b { color: var(--clay-deep); }
:root[data-theme="dark"] .value-opt.sel b { color: var(--clay); }

.pts-preview {
  display: flex; align-items: baseline; justify-content: center; gap: .3rem;
  font-family: var(--font-display); font-weight: 700;
  font-size: 2.6rem; color: var(--clay); line-height: 1;
}
.pts-preview small { font-size: .9rem; font-weight: 600; color: var(--ink-3); }
.pts-quick { display: flex; gap: .4rem; justify-content: center; margin-top: .7rem; }

/* ══ REWARDS SHOP ══════════════════════════════════════════════ */
.wallet-hero {
  position: relative;
  border-radius: var(--r-xl);
  padding: clamp(1.6rem, 3vw, 2.4rem);
  background: var(--grad-dusk);
  color: #F6EFE4;
  overflow: hidden;
  margin-bottom: 2.5rem;
  box-shadow: var(--shadow-lg);
  isolation: isolate;
}
.wallet-hero::before {
  content: ""; position: absolute; inset: -45%; z-index: -1;
  background:
    radial-gradient(32% 40% at 76% 18%, rgba(224,172,83,.55), transparent 62%),
    radial-gradient(30% 36% at 18% 82%, rgba(191,91,60,.5), transparent 66%);
  filter: blur(26px);
  animation: aurora 22s var(--ease) infinite alternate;
}
.wallet-hero .eyebrow { color: rgba(246,239,228,.72); }
.wallet-hero-grid { display: flex; gap: 2.5rem; align-items: flex-end; flex-wrap: wrap; }
.wallet-big {
  font-family: var(--font-display);
  font-size: clamp(3rem, 2rem + 4vw, 5rem);
  font-weight: 600; line-height: .95; letter-spacing: -.03em;
  font-variant-numeric: tabular-nums;
  margin-top: .4rem;
}
.wallet-big small { font-size: .28em; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; opacity: .7; margin-left: .4rem; }
.wallet-side { display: flex; gap: 2rem; flex-wrap: wrap; padding-bottom: .5rem; }
.wallet-side div b { display: block; font-family: var(--font-display); font-size: 1.5rem; font-weight: 600; line-height: 1; }
.wallet-side div span { font-size: var(--t-micro); letter-spacing: .12em; text-transform: uppercase; opacity: .72; }

/* ── Colour-block header with a card floating over its lower edge ── */
.rw-hero {
  position: relative;
  margin: calc(clamp(1.5rem, 3.5vw, 3rem) * -1) calc(clamp(1rem, 3vw, 2.5rem) * -1) 0;
  padding: clamp(1.6rem, 3.5vw, 2.6rem) clamp(1rem, 3vw, 2.5rem) 5.5rem;
  background: var(--grad-dusk);
  color: #F6EFE4;
  border-radius: 0 0 var(--r-xl) var(--r-xl);
  overflow: hidden;
  isolation: isolate;
}
.rw-hero::before {
  content: ""; position: absolute; inset: -45%; z-index: -1;
  background:
    radial-gradient(30% 38% at 78% 16%, rgba(224,172,83,.5), transparent 62%),
    radial-gradient(28% 34% at 16% 88%, rgba(191,91,60,.5), transparent 66%);
  filter: blur(26px);
  animation: aurora 24s var(--ease) infinite alternate;
}
.rw-hero-top { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
.rw-hero .eyebrow { color: rgba(246,239,228,.72); }
.rw-hero h1 {
  font-size: clamp(1.9rem, 1.2rem + 2.6vw, 3.1rem);
  line-height: 1.06; margin-top: .7rem; max-width: 16ch;
}
.rw-hero h1 em { font-style: italic; color: var(--amber); }
.rw-balance {
  display: inline-flex; align-items: center; gap: .4rem;
  padding: .4rem .8rem; border-radius: var(--r-pill);
  background: rgba(255,255,255,.16);
  border: 1px solid rgba(255,255,255,.22);
  font-weight: 700; font-size: .9rem;
  backdrop-filter: blur(6px);
}
.rw-balance svg { width: 15px; height: 15px; opacity: .9; }

/* The floating wallet card, pulled up over the header */
.rw-wallet {
  position: relative; z-index: 2;
  margin: -4.2rem 0 2.25rem;
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-lg);
  padding: 1.4rem clamp(1.1rem, 2.5vw, 1.75rem);
  display: flex; align-items: center; gap: 1.5rem; flex-wrap: wrap;
}
.rw-wallet-main { flex: 1; min-width: 190px; }
.rw-wallet-num {
  font-family: var(--font-display); font-weight: 600;
  font-size: clamp(2.4rem, 1.8rem + 2.4vw, 3.4rem); line-height: 1;
  letter-spacing: -.03em; font-variant-numeric: tabular-nums;
  color: var(--clay);
}
.rw-wallet-num small { font-size: .28em; font-weight: 600; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3); margin-left: .45rem; }
.rw-wallet-sub { font-size: var(--t-xs); color: var(--ink-3); margin-top: .4rem; }
.rw-wallet-next { flex: 1; min-width: 200px; }
.rw-wallet-next b { font-size: var(--t-xs); font-weight: 600; color: var(--ink-2); }

/* ── Category rows ────────────────────────────────────────── */
.rw-cat { margin-bottom: 2.25rem; }
.rw-cat-head { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; margin-bottom: .9rem; }
.rw-cat-head h3 { font-size: var(--t-h3); }
.rw-see {
  font-size: var(--t-xs); font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink-3);
  display: inline-flex; align-items: center; gap: .25rem;
  transition: color .2s var(--ease), gap .2s var(--ease);
}
.rw-see:hover { color: var(--clay); gap: .45rem; }
.rw-see svg { width: 13px; height: 13px; }

/* Horizontal scroller, like the reference. Falls back to a grid when a
   category is opened via "see all". */
.rw-row {
  display: flex; gap: 1rem;
  overflow-x: auto; scroll-snap-type: x proximity;
  scrollbar-width: none; padding: 4px 4px 8px;
  margin: -4px -4px -8px;
}
.rw-row::-webkit-scrollbar { display: none; }
.rw-row > * { flex: 0 0 190px; scroll-snap-align: start; }

.reward-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 1rem; }

.reward {
  position: relative;
  display: block; width: 100%; text-align: left;
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--r-lg);
  padding: .75rem .75rem 1rem;
  transition: transform .4s var(--ease-out), box-shadow .4s var(--ease), border-color .3s;
}
.reward:hover { transform: translateY(-5px); box-shadow: var(--shadow-lg); border-color: var(--rule-strong); }

/* Cost badge sits on the art, top-left, as in the reference */
.reward-cost {
  position: absolute; top: 1.35rem; left: 1.35rem; z-index: 2;
  display: inline-flex; align-items: center; gap: .28rem;
  padding: .26rem .6rem; border-radius: var(--r-pill);
  background: color-mix(in srgb, var(--surface) 88%, transparent);
  backdrop-filter: blur(6px);
  border: 1px solid var(--rule);
  font-weight: 800; font-size: var(--t-xs);
  color: var(--clay-deep);
  box-shadow: var(--shadow-xs);
}
:root[data-theme="dark"] .reward-cost { color: var(--clay); }
.reward-cost svg { width: 12px; height: 12px; }

.reward-art {
  position: relative;
  height: 132px; border-radius: var(--r-md);
  display: grid; place-items: center;
  overflow: hidden;
  background:
    radial-gradient(70% 70% at 50% 40%, var(--tint, var(--clay-soft)), transparent 72%),
    var(--surface-sunk);
}
.reward-art span {
  font-size: 3.1rem; line-height: 1;
  filter: drop-shadow(0 6px 14px rgba(60,45,30,.25));
  transition: transform .45s var(--ease-back);
}
.reward:hover .reward-art span { transform: scale(1.14) rotate(-6deg); }

/* Uploaded reward photo — fills the tile, replaces the emoji.
   Both tiles are `display:grid; place-items:center`, so their single row is
   auto-sized: a tall photo made the row grow and `height:100%` resolved
   against the *content*, not the fixed container height. Absolute
   positioning pins the photo to the box regardless of its natural size. */
.reward-art, .rd-art { position: relative; overflow: hidden; }
.reward-art .rw-img,
.rd-art .rw-img {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover;
  transition: transform .55s var(--ease-out);
}
.reward:hover .rw-img { transform: scale(1.07); }
.voucher .rw-img {
  width: 74px; height: 74px; border-radius: 50%;
  object-fit: cover; margin: 0 auto;
  box-shadow: 0 6px 18px rgba(0,0,0,.28);
}

/* The card is a <button>, so its children are spans — they need to be
   made block or the vendor, name and detail all run together on one line. */
.reward-vendor {
  display: block;
  font-size: var(--t-micro); letter-spacing: .09em; text-transform: uppercase;
  color: var(--ink-4); margin: .85rem .35rem 0;
}
.reward-name {
  display: block;
  font-family: var(--font-display); font-size: 1.02rem; font-weight: 600;
  line-height: 1.25; margin: .2rem .35rem 0;
}
.reward-detail { display: block; font-size: var(--t-xs); color: var(--ink-3); margin: .2rem .35rem 0; }

.reward.locked { opacity: .55; }
.reward.locked:hover { transform: none; box-shadow: var(--shadow-xs); }
.reward-tag {
  display: inline-block; margin: .55rem .35rem 0;
  font-size: var(--t-micro); font-weight: 700;
  color: var(--ink-4);
}
.reward-tag.low { color: var(--clay); }

/* ── Detail sheet ─────────────────────────────────────────── */
.rd-art {
  height: 190px; border-radius: var(--r-lg);
  display: grid; place-items: center; margin-bottom: 1.4rem;
  background:
    radial-gradient(66% 66% at 50% 42%, var(--tint, var(--clay-soft)), transparent 72%),
    var(--surface-sunk);
}
.rd-art span { font-size: 5rem; line-height: 1; filter: drop-shadow(0 10px 22px rgba(60,45,30,.3)); }
.rd-vendor { font-size: var(--t-micro); letter-spacing: .1em; text-transform: uppercase; color: var(--ink-4); }
.rd-name { font-size: var(--t-h2); margin: .3rem 0 .5rem; }
.rd-desc { color: var(--ink-2); font-size: .95rem; line-height: 1.6; }

.rd-qty {
  display: flex; align-items: center; gap: 1rem; flex-wrap: wrap;
  margin-top: 1.4rem; padding: 1rem 1.15rem;
  background: var(--surface-sunk);
  border: 1px solid var(--rule);
  border-radius: var(--r-lg);
}
.rd-qty-info { flex: 1; min-width: 150px; }
.rd-qty-cost {
  display: flex; align-items: center; gap: .4rem;
  font-weight: 700; font-size: 1.05rem;
}
.rd-qty-cost svg { width: 16px; height: 16px; color: var(--clay); }
.rd-qty-left { font-size: var(--t-xs); color: var(--ink-3); margin-top: .25rem; }
.rd-qty-left.short { color: #C0392B; font-weight: 600; }

.stepper { display: flex; align-items: center; gap: .35rem; }
.stepper button {
  width: 38px; height: 38px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--surface);
  border: 1px solid var(--rule-strong);
  font-size: 1.15rem; font-weight: 700; line-height: 1;
  color: var(--ink-2);
  transition: all .2s var(--ease-back);
}
.stepper button:hover:not(:disabled) { border-color: var(--clay); color: var(--clay); }
.stepper button:active:not(:disabled) { transform: scale(.9); }
.stepper button:disabled { opacity: .35; cursor: not-allowed; }
.stepper output {
  min-width: 42px; text-align: center;
  font-family: var(--font-display); font-size: 1.35rem; font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* Shorter art on a phone so the stepper and CTA sit above the fold. */
@media (max-width: 620px) {
  .rd-art { height: 148px; margin-bottom: 1.1rem; }
  .rd-art span { font-size: 3.8rem; }
  .rd-name { font-size: var(--t-h3); }
  .rd-qty { margin-top: 1.1rem; padding: .85rem 1rem; }
  .rw-wallet { margin-bottom: 1.75rem; padding: 1.15rem 1.1rem; }
}

/* Progress toward the cheapest thing you cannot afford yet */
.afford-bar { height: 5px; border-radius: 99px; background: var(--paper-3); overflow: hidden; margin-top: .7rem; }
.afford-bar i { display: block; height: 100%; border-radius: 99px; background: var(--grad-warm); transition: width 1s var(--ease-out); }

.redemption-row {
  display: flex; align-items: center; gap: .85rem;
  padding: .85rem 0; border-bottom: 1px solid var(--rule);
}
.redemption-row:last-child { border-bottom: 0; }
.redemption-row .em { font-size: 1.5rem; flex: none; }
.redemption-row b { display: block; font-size: .9rem; }
.redemption-row .meta { font-size: var(--t-xs); color: var(--ink-3); }
.code {
  font-family: var(--font-mono); font-size: var(--t-xs); font-weight: 600;
  background: var(--paper-3); padding: 2px 7px; border-radius: 5px;
  letter-spacing: .04em;
}

/* Big celebratory voucher shown after redeeming.
   It sits inside an even frame of the modal's own surface colour. The
   original had side gaps but no top gap, which read as a mistake; bleeding
   it to the edges instead lost the frame altogether. Even on all sides. */
.voucher-note { margin-top: 1.15rem; }

.voucher {
  position: relative;
  border-radius: var(--r-lg);
  padding: 2.2rem 1.5rem;
  background: var(--grad-sunset);
  color: #fff; text-align: center;
  overflow: hidden;
  box-shadow: var(--shadow-lg);
}
.voucher::before {
  content: ""; position: absolute; inset: -50%;
  background: radial-gradient(36% 34% at 50% 10%, rgba(255,255,255,.4), transparent 62%);
}
.voucher > * { position: relative; }
.voucher .em { font-size: 3rem; line-height: 1; }
.voucher h3 { font-size: 1.5rem; margin: .6rem 0 .2rem; }
.voucher .code {
  display: inline-block; margin-top: 1rem;
  background: rgba(255,255,255,.2); color: #fff;
  font-size: 1.05rem; letter-spacing: .16em; padding: .5rem 1.1rem;
  border: 1px dashed rgba(255,255,255,.55); border-radius: var(--r-sm);
}

/* ══ MONTHLY QUIZ ══════════════════════════════════════════════ */
.quiz-card {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--r-xl);
  padding: clamp(1.4rem, 3vw, 2.1rem);
  box-shadow: var(--shadow-md);
  margin-bottom: 2rem;
  overflow: hidden;
}
.quiz-card.live { border-color: color-mix(in srgb, var(--clay) 45%, transparent); }
.quiz-card.live::before {
  content: ""; position: absolute; inset: 0 0 auto; height: 4px;
  background: var(--grad-warm);
}
.quiz-card.idle, .quiz-card.won, .quiz-card.lost { text-align: center; }

.quiz-top { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap; margin-bottom: 1.1rem; }
.quiz-live {
  display: inline-flex; align-items: center; gap: .35rem;
  padding: .3rem .75rem; border-radius: var(--r-pill);
  background: var(--clay-soft); color: var(--clay-deep);
  font-size: var(--t-xs); font-weight: 700;
  animation: pulse-ring 2.6s var(--ease) infinite;
}
:root[data-theme="dark"] .quiz-live { color: var(--clay); }
.quiz-spots { font-size: var(--t-xs); font-weight: 600; color: var(--ink-3); }
.quiz-spots.low { color: var(--clay); }

.quiz-q {
  font-size: clamp(1.25rem, 1rem + 1.1vw, 1.7rem);
  line-height: 1.28; margin-bottom: 1.25rem;
}

.quiz-options { display: grid; gap: .6rem; }
.quiz-opt {
  display: flex; align-items: center; gap: .85rem;
  width: 100%; text-align: left;
  padding: .9rem 1rem;
  border: 1.5px solid var(--rule); border-radius: var(--r-md);
  background: var(--surface);
  transition: border-color .2s var(--ease), background .2s var(--ease), transform .2s var(--ease-back);
}
.quiz-opt:hover:not(.static) { border-color: var(--ink-4); transform: translateX(3px); }
.quiz-opt.sel { border-color: var(--clay); background: var(--clay-soft); }
.quiz-letter {
  width: 30px; height: 30px; flex: none;
  display: grid; place-items: center; border-radius: 50%;
  background: var(--paper-3); color: var(--ink-2);
  font-weight: 800; font-size: .82rem;
}
.quiz-opt.sel .quiz-letter { background: var(--clay); color: #fff; }
.quiz-text { font-size: .95rem; font-weight: 500; }
.quiz-tick { margin-left: auto; display: grid; place-items: center; }

.quiz-opt.static { cursor: default; }
.quiz-opt.right { border-color: var(--olive); background: var(--olive-soft); }
.quiz-opt.right .quiz-letter { background: var(--olive); color: #fff; }
.quiz-opt.right .quiz-tick { color: var(--olive); }
.quiz-opt.wrong { border-color: #C0392B; background: color-mix(in srgb, #C0392B 12%, transparent); }
.quiz-opt.wrong .quiz-letter { background: #C0392B; color: #fff; }
.quiz-opt.wrong .quiz-tick { color: #C0392B; }

.quiz-foot {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem; flex-wrap: wrap;
  margin-top: 1.4rem; padding-top: 1.1rem;
  border-top: 1px solid var(--rule);
}
.quiz-foot .muted { font-size: var(--t-xs); max-width: 40ch; }

.quiz-result-mark { font-size: 2.8rem; line-height: 1; margin-bottom: .5rem; }
.quiz-result h2 { font-size: var(--t-h2); }
.quiz-result p { margin-top: .4rem; }
.quiz-recap { margin-top: 1.5rem; text-align: left; display: grid; gap: .5rem; }
.quiz-recap-q { font-size: var(--t-xs); color: var(--ink-3); margin-bottom: .3rem; }

/* ══ ADMIN ═════════════════════════════════════════════════════ */
.admin-tabs { display: flex; gap: .3rem; border-bottom: 1px solid var(--rule); margin-bottom: 1.75rem; overflow-x: auto; }
.admin-tab {
  padding: .65rem 1rem; font-size: .88rem; font-weight: 600; color: var(--ink-3);
  border-bottom: 2px solid transparent; margin-bottom: -1px; white-space: nowrap;
  transition: color .2s, border-color .2s;
}
.admin-tab:hover { color: var(--ink); }
.admin-tab.active { color: var(--clay); border-bottom-color: var(--clay); }

.approve-card {
  display: flex; align-items: center; gap: 1rem; flex-wrap: wrap;
  padding: 1.1rem 1.25rem;
  background: var(--surface); border: 1px solid var(--rule);
  border-radius: var(--r-lg); margin-bottom: .75rem;
}
.approve-card .grow { min-width: 180px; }
/* Scoped to the name only — a bare `.approve-card b` also matched the <b>
   inside .meta and forced "200 pts" onto its own oversized line. */
.approve-card .who { display: block; font-size: .95rem; font-weight: 700; }
.approve-card .meta { font-size: var(--t-xs); color: var(--ink-3); margin-top: .2rem; }
.approve-card .meta b { font-weight: 700; color: var(--ink-2); }

.table { width: 100%; border-collapse: collapse; font-size: .875rem; }
.table th {
  text-align: left; padding: .65rem .8rem;
  font-size: var(--t-micro); letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink-4); font-weight: 600;
  border-bottom: 1px solid var(--rule-strong);
}
.table td { padding: .7rem .8rem; border-bottom: 1px solid var(--rule); vertical-align: middle; }
.table tr:last-child td { border-bottom: 0; }
.table tbody tr:hover { background: var(--surface-sunk); }
.table-wrap { overflow-x: auto; background: var(--surface); border: 1px solid var(--rule); border-radius: var(--r-lg); }

/* Quiz option rows in the admin editor */
.qz-opt { display: flex; align-items: center; gap: .6rem; cursor: pointer; }
.qz-opt input[type="radio"] { width: 18px; height: 18px; flex: none; accent-color: var(--clay); cursor: pointer; }
.qz-letter {
  width: 28px; height: 28px; flex: none;
  display: grid; place-items: center; border-radius: 50%;
  background: var(--paper-3); color: var(--ink-2);
  font-weight: 800; font-size: .78rem;
}
.qz-opt input[type="radio"]:checked ~ .qz-letter { background: var(--clay); color: #fff; }

/* Reward photo preview in the admin editor */
.rw-thumb {
  width: 96px; height: 96px; flex: none;
  border-radius: var(--r-md);
  border: 1px solid var(--rule);
  background: var(--surface-sunk);
  display: grid; place-items: center;
  overflow: hidden;
}
.rw-thumb img { width: 100%; height: 100%; object-fit: cover; }
.rw-thumb span { font-size: 2.4rem; line-height: 1; }
.rw-thumb-sm {
  width: 40px; height: 40px; border-radius: var(--r-sm);
  object-fit: cover; border: 1px solid var(--rule);
}

/* Photo upload dropzone */
.dropzone {
  border: 2px dashed var(--rule-strong);
  border-radius: var(--r-lg);
  padding: 1.6rem 1rem; text-align: center;
  background: var(--surface-sunk);
  transition: border-color .2s, background .2s;
  cursor: pointer;
}
.dropzone:hover, .dropzone.over { border-color: var(--clay); background: var(--clay-soft); }
.dropzone p { font-size: var(--t-sm); color: var(--ink-3); }
.dropzone b { font-size: .92rem; color: var(--ink); display: block; margin-bottom: .2rem; }

.thumb-row { display: flex; gap: .5rem; flex-wrap: wrap; margin-top: .75rem; }
.thumb { position: relative; width: 74px; height: 74px; border-radius: var(--r-sm); overflow: hidden; border: 1px solid var(--rule); }
.thumb img { width: 100%; height: 100%; object-fit: cover; }
.thumb button {
  position: absolute; top: 3px; right: 3px;
  width: 19px; height: 19px; border-radius: 50%;
  background: rgba(28,24,21,.72); color: #fff;
  display: grid; place-items: center; font-size: .7rem; line-height: 1;
}

/* ══ Lightbox ══════════════════════════════════════════════════ */
.lightbox {
  position: fixed; inset: 0; z-index: 250;
  background: rgba(18,15,12,.93);
  display: grid; place-items: center; padding: 2rem;
  animation: fade .25s var(--ease) both;
}
.lightbox img { max-width: 92vw; max-height: 86vh; border-radius: var(--r-md); box-shadow: var(--shadow-lg); }
.lightbox .cap { color: rgba(246,239,228,.8); font-size: var(--t-sm); text-align: center; margin-top: 1rem; }
.lightbox .close { position: absolute; top: 1.2rem; right: 1.4rem; color: #fff; }

/* ══ GET THE APP (install + notifications) ═════════════════════ */

.pwa-grid {
  display: grid; gap: 1.25rem;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  align-items: start;
}

.pwa-card { padding: 1.6rem; }
.pwa-card-head { display: flex; gap: 1rem; align-items: flex-start; margin-bottom: 1.25rem; }
.pwa-card-head .card-title { margin-bottom: .35rem; }
.pwa-card-head .muted { font-size: var(--t-sm); line-height: 1.55; }

.pwa-ico {
  flex: none; width: 42px; height: 42px;
  border-radius: var(--r-md);
  display: grid; place-items: center;
}
.pwa-ico svg { width: 20px; height: 20px; }
.pwa-ico.t-clay  { background: var(--clay-soft);  color: var(--clay-deep); }
.pwa-ico.t-amber { background: var(--amber-soft); color: #8A5D12; }
.pwa-ico.t-olive { background: var(--olive-soft); color: #4C5A38; }
:root[data-theme="dark"] .pwa-ico.t-clay  { color: var(--clay); }
:root[data-theme="dark"] .pwa-ico.t-amber { color: var(--amber); }
:root[data-theme="dark"] .pwa-ico.t-olive { color: var(--olive); }

/* Already installed — the card is a receipt, not an offer. */
.pwa-done { background: var(--olive-soft); border-color: transparent; }
:root[data-theme="dark"] .pwa-done { background: color-mix(in srgb, var(--olive) 16%, var(--surface)); }
.pwa-done .pwa-card-head { margin-bottom: 0; }

/* ── The manual steps (iOS, and desktop browsers with no prompt) ── */
.pwa-steps { list-style: none; display: grid; gap: .8rem; margin: 0 0 .25rem; }
.pwa-step {
  display: flex; gap: .75rem; align-items: flex-start;
  font-size: var(--t-sm); line-height: 1.5; color: var(--ink-2);
}
.pwa-step b { color: var(--ink); font-weight: 600; }
/* The Share glyph sits inline in a sentence, so it has to ride the baseline
   rather than sit on it. */
.pwa-step svg { width: 15px; height: 15px; vertical-align: -3px; margin: 0 .1em; }
.pwa-step-n {
  flex: none; width: 22px; height: 22px; margin-top: -1px;
  border-radius: 50%;
  background: var(--paper-3); color: var(--ink-2);
  display: grid; place-items: center;
  font-size: var(--t-micro); font-weight: 700; font-variant-numeric: tabular-nums;
}

.pwa-note {
  display: flex; gap: .5rem; align-items: flex-start;
  margin-top: 1.1rem; padding-top: 1.1rem;
  border-top: 1px solid var(--rule);
  font-size: var(--t-xs); line-height: 1.55; color: var(--ink-3);
}
.pwa-note svg { width: 14px; height: 14px; flex: none; margin-top: 2px; }
.pwa-note b { color: var(--ink-2); }

/* The PDPA note. Quieter than a warning — it is reassurance, not a caveat. */
.pwa-privacy { color: var(--ink-3); }

.pwa-state { display: flex; align-items: center; gap: .75rem; flex-wrap: wrap; }

/* Install prompt on the sign-in screen — install, then register, then open
   from the icon. Quiet: it must not compete with the sign-in button. */
.auth-install {
  margin-top: .25rem;
  color: var(--ink-3);
  border: 1px dashed var(--rule-strong);
}
.auth-install:hover { color: var(--ink); border-style: solid; }
.auth-install svg { width: 15px; height: 15px; }

/* The same install card, reused inside a modal. It is already inside the
   modal's own panel, so it drops its border and padding to avoid a card
   sitting in a card. */
.pwa-modal-body .pwa-card {
  border: 0; padding: 0; background: none; box-shadow: none;
}
.pwa-modal-body .pwa-card-head { margin-bottom: 1rem; }


/* Second-level filter bar: units under the selected team. Quieter than the
   team row above it so the hierarchy reads at a glance. */
.filter-sub { margin-top: -.35rem; }
.filter-sub .filter { font-size: var(--t-micro); padding: .3rem .7rem; opacity: .9; }
.filter-sub .filter.active { opacity: 1; }


/* ── Quiz standings ────────────────────────────────────────────
   Who has answered the most correctly this year, plus what the top three
   collect before the points reset. */
.qz-standings { margin-top: 1.5rem; }

.qz-board { list-style: none; display: flex; flex-direction: column; gap: .2rem; }
.qz-row {
  display: flex; align-items: center; gap: .7rem;
  padding: .5rem .6rem;
  border-radius: var(--r-sm);
}
.qz-row.is-self { background: var(--clay-soft); }
:root[data-theme="dark"] .qz-row.is-self { background: color-mix(in srgb, var(--clay) 18%, transparent); }
.qz-place {
  flex: none; width: 26px; text-align: center;
  font-size: .95rem; font-weight: 700; color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.qz-who { display: flex; flex-direction: column; min-width: 0; line-height: 1.25; }
.qz-who b { font-size: .9rem; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.qz-who .muted { font-size: var(--t-micro); }
.qz-won {
  margin-left: auto; flex: none;
  font-size: var(--t-xs); font-weight: 700; color: var(--clay);
  font-variant-numeric: tabular-nums;
}

.qz-prizes {
  margin-top: 1.1rem; padding-top: 1rem;
  border-top: 1px solid var(--rule);
}
.qz-prizes-head {
  display: flex; align-items: center; gap: .45rem;
  font-size: var(--t-xs); font-weight: 600; color: var(--ink-3);
  margin-bottom: .6rem;
}
.qz-prizes-head svg { width: 14px; height: 14px; }
.qz-prize-row {
  display: flex; align-items: center; gap: .6rem;
  padding: .3rem 0;
  font-size: var(--t-sm); color: var(--ink-2);
}
.qz-prize-row b { margin-left: auto; color: var(--clay); font-variant-numeric: tabular-nums; }
.qz-medal { font-size: 1rem; }


/* ── Profile standing badges ───────────────────────────────────
   Top three on each board. The medal carries the placing so the label can
   stay short enough to wrap sensibly on a phone. */
.pf-badges {
  display: flex; flex-wrap: wrap; gap: .4rem;
  margin: .6rem 0 .2rem;
}
.pf-badge {
  display: inline-flex; align-items: center; gap: .35rem;
  padding: .28rem .65rem .28rem .45rem;
  border-radius: var(--r-pill);
  font-size: var(--t-xs); font-weight: 600;
  background: var(--paper-3); color: var(--ink-2);
  border: 1px solid transparent;
  white-space: nowrap;
}
.pf-badge-medal { font-size: .95rem; line-height: 1; }
/* Gold gets the strongest treatment, then silver, then bronze — otherwise
   three badges in a row read as equal. */
.pf-badge-1 {
  background: linear-gradient(135deg, var(--amber-soft), var(--clay-soft));
  border-color: color-mix(in srgb, var(--amber) 45%, transparent);
  color: var(--clay-deep);
}
.pf-badge-2 { background: var(--paper-3); border-color: var(--rule-strong); }
.pf-badge-3 { background: var(--surface-sunk); border-color: var(--rule); }
:root[data-theme="dark"] .pf-badge-1 { color: var(--amber); }


/* ══ ABOUT ═════════════════════════════════════════════════════ */
/* No width cap of its own. It had one at 780px, which made the hero and the
   cards visibly narrower than every other page — .page is already capped at
   --page-max. Prose is constrained per-element instead, so the line length
   stays readable without shrinking the whole page. */

.ab-hero {
  position: relative; overflow: hidden;
  border-radius: var(--r-xl);
  padding: clamp(1.75rem, 4vw, 3rem);
  margin-bottom: 2.5rem;
  background: linear-gradient(150deg, #2A1F19 0%, #4A2E20 42%, #8B4229 78%, #BF5B3C 100%);
  color: #F6EFE4;
  box-shadow: var(--shadow-lg);
}
.ab-hero::before {
  content: ""; position: absolute; inset: -40%;
  background:
    radial-gradient(42% 38% at 18% 22%, rgba(224,172,83,.42), transparent 65%),
    radial-gradient(38% 34% at 84% 74%, rgba(191,91,60,.5), transparent 65%);
  filter: blur(24px);
  animation: grad-shift 11s var(--ease) infinite alternate;
}
.ab-hero > * { position: relative; }
.ab-hero .eyebrow { color: rgba(246,239,228,.72); }
.ab-hero-mark {
  width: 44px; height: 44px; border-radius: var(--r-md);
  display: grid; place-items: center;
  background: rgba(255,255,255,.14);
  border: 1px solid rgba(255,255,255,.22);
  margin-bottom: 1.1rem;
}
.ab-hero-mark svg { width: 22px; height: 22px; }
.ab-title {
  font-family: var(--font-display);
  font-size: clamp(1.7rem, 1rem + 2.2vw, 3.1rem);
  max-width: 20ch;
  font-weight: 600; line-height: 1.12; letter-spacing: -.02em;
  margin: .4rem 0 .9rem;
}
.ab-title em { font-style: italic; color: #F0C67F; }
.ab-lede { font-size: clamp(.95rem, .9rem + .2vw, 1.05rem); line-height: 1.65; max-width: 58ch; opacity: .92; }

.ab-stats { display: flex; flex-wrap: wrap; gap: 2rem; margin-top: 1.9rem; padding-top: 1.4rem; border-top: 1px solid rgba(255,255,255,.2); }
.ab-stats b { display: block; font-family: var(--font-display); font-size: 1.8rem; font-weight: 600; line-height: 1; }
.ab-stats span { font-size: var(--t-micro); letter-spacing: .13em; text-transform: uppercase; opacity: .75; }

.ab-quote {
  display: flex; gap: 1rem; align-items: flex-start;
  padding: 1.25rem 1.4rem;
  border-radius: var(--r-lg);
  background: var(--clay-soft);
  border-left: 3px solid var(--clay);
  margin-bottom: 1.5rem;
}
:root[data-theme="dark"] .ab-quote { background: color-mix(in srgb, var(--clay) 15%, transparent); }
.ab-quote-mark { flex: none; color: var(--clay); opacity: .8; }
.ab-quote-mark svg { width: 22px; height: 22px; }
.ab-quote p { font-size: 1rem; line-height: 1.6; color: var(--ink); font-family: var(--font-quote); max-width: 68ch; }

.ab-body { font-size: .95rem; line-height: 1.75; color: var(--ink-2); max-width: 62ch; margin-bottom: 1rem; }

.ab-grid {
  display: grid; gap: 1rem; margin-top: 1.75rem;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
}
.ab-card {
  padding: 1.25rem;
  border: 1px solid var(--rule); border-radius: var(--r-lg);
  background: var(--surface);
  transition: transform .3s var(--ease-out), box-shadow .3s;
}
.ab-card:hover { transform: translateY(-3px); box-shadow: var(--shadow-md); }
.ab-emoji { font-size: 1.5rem; display: block; margin-bottom: .5rem; }
.ab-card h3 { font-family: var(--font-display); font-size: 1.02rem; font-weight: 600; margin-bottom: .35rem; }
.ab-card p { font-size: var(--t-sm); line-height: 1.6; color: var(--ink-3); }

.ab-dev {
  display: flex; gap: 1.5rem; flex-wrap: wrap; align-items: flex-start;
  padding: 1.5rem;
  border: 1px solid var(--rule); border-radius: var(--r-lg);
  background: linear-gradient(150deg, var(--surface), var(--surface-sunk));
}
.ab-dev-face { flex: none; }
.ab-dev-body { flex: 1; min-width: 240px; }
.ab-dev-body h3 { font-family: var(--font-display); font-size: 1.25rem; font-weight: 600; margin-bottom: .5rem; }
.ab-dev-body p { font-size: var(--t-sm); line-height: 1.7; color: var(--ink-2); margin-bottom: .7rem; max-width: 56ch; }
.ab-dev-actions { display: flex; flex-wrap: wrap; gap: .6rem; margin-top: 1rem; }

/* Full width, like every other card on the page. It had a narrower cap on the
   theory that a very wide textarea is unpleasant — but a card that stops
   short of all its neighbours is more obviously wrong than a wide textarea. */
.ab-feedback { padding: 1.5rem; }
.ab-feedback .textarea { min-height: 120px; }

.ab-install { margin-top: 1.25rem; }

.ab-foot {
  margin-top: 2.5rem; padding-top: 1.25rem;
  border-top: 1px solid var(--rule);
  font-size: var(--t-xs); color: var(--ink-4); text-align: center;
}

@media (max-width: 640px) {
  .ab-stats { gap: 1.25rem; }
  .ab-stats b { font-size: 1.45rem; }
  .ab-dev { gap: 1rem; }
}

/* Handled feedback recedes rather than disappearing — the history is
   sometimes the useful part. */
.fb-done { opacity: .55; }
.fb-done:hover { opacity: 1; }

/* ══ QUESTS ═══════════════════════════════════════════════════
   A quest is a note with a value on it, so it is drawn as one
   rather than as a dashboard tile: paper ground, a points seal
   stuck in the corner, and a perforated tear line above the
   footer. Same palette and the same two typefaces as everywhere
   else — the difference is the object being imitated. */

.q-grid {
  display: grid; gap: 1.4rem 1.15rem;
  grid-template-columns: repeat(auto-fill, minmax(310px, 1fr));
  padding-top: .6rem;           /* the seals overhang the top edge */
}

.q-card {
  position: relative;
  display: flex; flex-direction: column; gap: .5rem;
  padding: 1.3rem 1.35rem 1.05rem 1.35rem;
  border-radius: var(--r-lg);
  border: 1px solid var(--rule);
  background: linear-gradient(158deg, var(--surface), var(--paper-2) 140%);
  box-shadow: var(--shadow-sm);
  cursor: pointer;
  transition: transform .3s var(--ease-out), box-shadow .3s var(--ease),
              border-color .3s var(--ease);
}
/* Paper. The same turbulence the app uses for .grain, kept faint and
   clipped to the card rather than laid over the whole screen. */
.q-card::before {
  content: ""; position: absolute; inset: 0; border-radius: inherit;
  pointer-events: none; opacity: .05; mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
}
:root[data-theme="dark"] .q-card::before { mix-blend-mode: screen; opacity: .055; }

/* These used to be tilted a few hundredths of a turn each, so a grid of them
   would read as notes somebody put down rather than boxes a stylesheet drew.
   Gone with the tilt on the seal: at three cards across, the top edges not
   lining up reads as a bug, not as a hand. The paper grain and the tear rules
   carry the idea without anything sitting crooked. */
.q-card:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow-md); border-color: var(--rule-strong);
}
.q-card:hover .q-seal { transform: scale(1.05); }

/* ── The seal ─────────────────────────────────────────────────
   The one loud thing on the card, and the only place the wallet
   gradient appears outside the wallet itself — because it is the
   same substance: points, waiting to be given.

   IT SITS SQUARE. It was tilted -5deg to read as a stamp pressed on
   by hand; senget was the word that came back. Straight, the number
   is easier to read and the card looks less like a mistake. Keep it
   square — the tilt is not coming back. */
.q-seal {
  position: absolute; top: -.55rem; right: 1rem;
  width: 58px; height: 58px;
  display: grid; place-items: center; align-content: center;
  border-radius: 16px;
  background: linear-gradient(150deg, var(--clay-deep), var(--clay) 55%, var(--amber));
  color: #fff; text-align: center;
  box-shadow: 0 10px 22px -10px rgba(191,91,60,.75);
  transition: transform .3s var(--ease-back);
}
.q-seal::after {           /* the ring, like a stamp edge */
  content: ""; position: absolute; inset: 4px; border-radius: 11px;
  border: 1px dashed rgba(255,255,255,.35);
}
.q-seal b {
  font-family: var(--font-display); font-size: 1.45rem; font-weight: 600;
  line-height: 1; letter-spacing: -.02em;
}
.q-seal em {
  font-style: normal; font-size: .5rem; font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase; opacity: .9; margin-top: 2px;
}
.q-solo .q-seal { background: linear-gradient(150deg, #5E3A4C, var(--plum) 55%, var(--clay)); }
.q-solo .q-seal { box-shadow: 0 10px 22px -10px rgba(122,78,99,.75); }

/* ── Type ─────────────────────────────────────────────────────── */
/* Only the eyebrow and the title need to keep clear of the seal; the brief
   and the footer run the full width underneath it. */
.q-brow {
  font-size: var(--t-micro); font-weight: 700; letter-spacing: .13em;
  text-transform: uppercase; color: var(--clay);
  padding-right: 3.6rem;
}
.q-solo .q-brow { color: var(--plum); }
.q-card.is-settled .q-brow { color: var(--ink-4); }

.q-title {
  font-family: var(--font-display); font-size: 1.28rem; font-weight: 600;
  line-height: 1.16; letter-spacing: -.02em; overflow-wrap: anywhere;
  padding-right: 3.4rem;
}
/* Poppins, the same face the wall sets remarks in — a quest brief and a
   shoutout are both somebody talking. */
.q-detail {
  font-family: var(--font-quote);
  font-size: .86rem; line-height: 1.6; color: var(--ink-2);
  overflow-wrap: anywhere;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
  overflow: hidden;
}
.q-detail.full {
  display: block; overflow: visible; font-size: .95rem; margin-bottom: 1.1rem;
}

/* The perforation. A real tear-off notice, and it does the job a border
   would do without looking like a table. */
.q-tear {
  height: 1px; margin: .5rem 0 .1rem;
  background-image: linear-gradient(90deg, var(--rule-strong) 0 4px, transparent 4px 9px);
  background-size: 9px 1px;
}

/* The numbers, given their own line so the eyebrow can stay short. */
.q-take {
  font-size: var(--t-xs); color: var(--ink-3);
  margin: .15rem 0 .1rem;
}
.q-take b { color: var(--clay); font-weight: 700; }
.q-solo .q-take b { color: var(--plum); }

.q-foot { display: flex; align-items: center; gap: .55rem; flex-wrap: wrap; }
.q-owner { display: inline-flex; align-items: center; gap: .4rem; font-size: var(--t-xs); font-weight: 600; }
.q-owner:hover { color: var(--clay); }
.q-meta { display: inline-flex; align-items: center; gap: .28rem; font-size: var(--t-xs); color: var(--ink-3); }
.q-meta svg { width: 13px; height: 13px; }

/* Settled notes have been taken down: flatter, quieter, no lift. */
.q-card.is-settled {
  background: var(--surface-sunk); box-shadow: none; opacity: .9;
}
.q-card.is-settled .q-seal { filter: saturate(.45); box-shadow: none; }
.q-card.is-settled:hover { transform: none; box-shadow: var(--shadow-sm); }

/* ── Faces ────────────────────────────────────────────────────── */
.q-faces { display: inline-flex; align-items: center; }
.q-face { display: inline-flex; margin-right: -7px; }
.q-face:last-child { margin-right: 0; }
.q-face .avatar { box-shadow: 0 0 0 2px var(--surface); }
.q-card.is-settled .q-face .avatar { box-shadow: 0 0 0 2px var(--surface-sunk); }
.q-more {
  display: grid; place-items: center;
  min-width: 24px; height: 24px; padding: 0 5px;
  border-radius: 999px; background: var(--paper-3); color: var(--ink-2);
  font-size: var(--t-micro); font-weight: 700;
  box-shadow: 0 0 0 2px var(--surface);
}

/* ── The detail sheet ─────────────────────────────────────────
   The same note, opened up: paper ground, the seal moved to the
   top-right, and the tear lines carried over so the sheet and the
   card are recognisably the same object. */
.q-sheet { position: relative; }
.q-sheet::before {
  content: ""; position: absolute; inset: -1.6rem -1.6rem 0; pointer-events: none;
  opacity: .045; mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
}
:root[data-theme="dark"] .q-sheet::before { mix-blend-mode: screen; opacity: .05; }

/* Sits at the top-right of the sheet, tilted like the one on the card.
   NOT overhanging into the modal head: .modal-body is the scroll container,
   so anything poking out of it gets clipped — the first attempt had the seal
   sliced in half along the top edge. */
.q-seal.big {
  position: absolute; top: .2rem; right: 0;
  width: 66px; height: 66px; border-radius: 18px;
  z-index: 2;
}
.q-seal.big b { font-size: 1.75rem; }
.q-seal.big em { font-size: .53rem; }
.q-sheet.is-settled .q-seal { filter: saturate(.45); box-shadow: none; }

.q-byline {
  display: flex; align-items: center; gap: .45rem; flex-wrap: wrap;
  font-size: var(--t-xs); color: var(--ink-3);
  min-height: 34px;                   /* the seal is taller than one line */
  padding-right: 5.2rem;              /* clears the seal */
}
.q-byline b { color: var(--ink-2); font-weight: 600; }
.q-dot { width: 3px; height: 3px; border-radius: 50%; background: var(--ink-4); flex: none; }

.q-brief {
  font-family: var(--font-quote);
  font-size: .97rem; line-height: 1.65; color: var(--ink-2);
  margin-top: .85rem; overflow-wrap: anywhere;
  /* The seal hangs into the top-right corner and is out of flow, so the
     brief is inset to the same gutter — otherwise the first two lines run
     underneath it. Reads as a measure column rather than a dodge. */
  padding-right: 5.4rem;
}

/* The outcome, stamped on rather than boxed. */
.q-stamp {
  position: relative; margin-top: 1.1rem; padding: .85rem 1rem .9rem 1.1rem;
  border-radius: var(--r-md);
  background: var(--olive-soft);
  border-left: 3px solid var(--olive);
}
.q-stamp b {
  display: block; font-size: var(--t-micro); font-weight: 800;
  letter-spacing: .18em; text-transform: uppercase; color: var(--olive);
}
.q-stamp p {
  font-family: var(--font-quote); font-size: var(--t-sm);
  color: var(--ink-2); margin-top: .3rem;
}
.q-stamp.is-off { background: var(--paper-3); border-left-color: var(--ink-4); }
.q-stamp.is-off b { color: var(--ink-3); }

.q-block { padding-top: 1.1rem; }
.q-block-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 1rem; margin-bottom: .6rem;
}
.q-block-head h4 {
  font-size: var(--t-micro); font-weight: 700; letter-spacing: .13em;
  text-transform: uppercase; color: var(--ink-3);
}
.q-note-right { font-size: var(--t-xs); color: var(--clay); font-weight: 600; }
.q-solo .q-note-right { color: var(--plum); }
.q-hollow { font-family: var(--font-quote); font-size: var(--t-sm); color: var(--ink-4); }

/* ── Roster ───────────────────────────────────────────────────
   Each row carries the share that person would actually be paid. The
   arithmetic is the point of a group quest, so it sits next to the face
   rather than in a sentence somewhere above. */
.q-roster { display: flex; flex-direction: column; }
.q-roster-row {
  display: flex; align-items: center; gap: .65rem; padding: .55rem 0;
}
.q-roster-row + .q-roster-row {
  background-image: linear-gradient(90deg, var(--rule) 0 4px, transparent 4px 9px);
  background-size: 9px 1px; background-repeat: repeat-x; background-position: top;
}
.q-roster-row b { display: block; font-size: var(--t-sm); }
.q-roster-row span { display: block; font-size: var(--t-micro); color: var(--ink-4); }

.q-share {
  flex: none; min-width: 38px; padding: .2rem .5rem;
  border-radius: var(--r-pill); text-align: center;
  font-family: var(--font-display); font-size: .92rem; font-weight: 600;
  background: var(--clay-soft); color: var(--clay-deep);
}
:root[data-theme="dark"] .q-share { color: var(--clay); }

/* Paid, not pending — olive says settled everywhere else in the app, and the
   tick stops it reading as a number still waiting to happen. */
/* There is no --olive-deep token; --olive itself is too light to read on
   --olive-soft at this size. */
.q-share.is-paid { background: var(--olive-soft); color: #4E5B3B; }
.q-share.is-paid::before { content: "\2713"; margin-right: .22em; font-size: .78em; opacity: .7; }
:root[data-theme="dark"] .q-share.is-paid { color: var(--olive); }

/* Only appears when the owner is looking, and stays quiet until reached for. */
.q-drop {
  flex: none; width: 26px; height: 26px; display: grid; place-items: center;
  border-radius: 50%; color: var(--ink-4); background: transparent;
  opacity: .5; transition: opacity .18s, background .18s, color .18s;
}
.q-drop svg { width: 14px; height: 14px; }
.q-roster-row:hover .q-drop { opacity: 1; }
.q-drop:hover { background: var(--clay-soft); color: var(--clay-deep); }

/* ── Thread ───────────────────────────────────────────────────── */
.q-thread { display: flex; flex-direction: column; gap: .9rem; max-height: 250px; overflow-y: auto; }
.q-comment { display: flex; gap: .6rem; align-items: flex-start; }
.q-comment-who { font-size: var(--t-xs); font-weight: 700; color: var(--ink-2); }
.q-comment-who time { font-weight: 500; color: var(--ink-4); margin-left: .4rem; }
.q-comment p {
  font-family: var(--font-quote); font-size: var(--t-sm);
  margin-top: .15rem; overflow-wrap: anywhere;
}
.q-say { display: flex; gap: .5rem; margin-top: .95rem; }
.q-say .input { flex: 1; }
.q-say .btn { flex: none; padding-inline: .8rem; }

/* ── Settling ───────────────────────────────────────────────── */
.q-payout { display: flex; gap: 1rem; align-items: center; }
/* The seal, grown up: same gradient and same dashed stamp edge as the one on
   the card and the sheet, so the number you are about to send is recognisably
   the number that has been sitting on the note all along. Untilted — this one
   is being read carefully, not glanced at. */
.q-payout-sum {
  position: relative;
  flex: none; width: 92px; padding: .85rem .5rem; text-align: center;
  border-radius: var(--r-md); color: #fff;
  background: linear-gradient(150deg, var(--clay-deep), var(--clay) 55%, var(--amber));
  box-shadow: var(--shadow-md);
}
.q-payout-sum::after {
  content: ""; position: absolute; inset: 5px; border-radius: calc(var(--r-md) - 4px);
  border: 1px dashed rgba(255,255,255,.35); pointer-events: none;
}
.q-payout-sum b { display: block; font-family: var(--font-display); font-size: 1.9rem; line-height: 1; }
.q-payout-sum span { font-size: var(--t-micro); letter-spacing: .1em; text-transform: uppercase; opacity: .88; }
.q-payout p { font-family: var(--font-quote); font-size: var(--t-sm); color: var(--ink-2); }
.q-payout-faces { margin-top: .6rem; }

/* ── Choosing a kind ────────────────────────────────────────── */
.q-kind { display: grid; grid-template-columns: 1fr 1fr; gap: .6rem; }
.q-kind-opt {
  text-align: left; padding: .9rem;
  border: 1px solid var(--rule-strong); border-radius: var(--r-md);
  background: var(--surface); cursor: pointer;
  transition: border-color .2s var(--ease), background .2s var(--ease);
}
.q-kind-opt svg { width: 18px; height: 18px; color: var(--ink-3); }
.q-kind-opt b { display: block; margin-top: .35rem; font-size: var(--t-sm); }
.q-kind-opt span { display: block; font-size: var(--t-xs); color: var(--ink-3); line-height: 1.45; margin-top: .15rem; }
.q-kind-opt:hover { border-color: var(--ink-4); }
.q-kind-opt.active { border-color: var(--clay); background: var(--clay-soft); }
.q-kind-opt.active svg { color: var(--clay-deep); }
:root[data-theme="dark"] .q-kind-opt.active svg { color: var(--clay); }

/* ── On the wall ────────────────────────────────────────────── */
.q-chip { cursor: pointer; border: 0; font: inherit; font-size: var(--t-xs); font-weight: 600; }
.q-chip:hover { background: var(--teal); color: #fff; }
.q-chip svg { width: 13px; height: 13px; }

/* Ten names will not fit in a card header, so the card shows the count and
   hands over the list on hover. There is no hover on a phone — tapping the
   quest chip opens the sheet, which lists everyone properly. */
.kudo-crowd { position: relative; display: inline-flex; align-items: center; gap: .45rem; }
.kudo-roster {
  position: absolute; left: 0; top: calc(100% + 8px); z-index: 20;
  display: none; flex-direction: column; gap: .2rem;
  min-width: 160px; max-height: 220px; overflow-y: auto;
  padding: .6rem .75rem;
  border-radius: var(--r-md); border: 1px solid var(--rule);
  background: var(--surface); box-shadow: var(--shadow-lg);
  font-size: var(--t-xs); font-weight: 500; color: var(--ink-2);
  white-space: nowrap;
}
.kudo-crowd:hover .kudo-roster,
.kudo-crowd:focus-visible .kudo-roster { display: flex; }

@media (max-width: 620px) {
  .q-grid { grid-template-columns: 1fr; }
  .q-kind { grid-template-columns: 1fr; }
  .q-payout { flex-direction: column; align-items: stretch; }
  .q-payout-sum { width: auto; }
}
@media (prefers-reduced-motion: reduce) {
  .q-card, .q-card:hover { transform: none; }
}
