/* =============================================================================
   AURORA STUB — user-facing design system for codesafka
   One stylesheet. No framework. RTL-native (logical properties only).
   Powers: templates/test_code.html (coupon page) + templates/user_main_temp.html
   -----------------------------------------------------------------------------
   Contents
     01 reset
     02 tokens (light / dark / toggle)
     03 base + typography
     04 utilities
     05 aurora ground
     06 sky bar
     07 the ticket
     08 the stub (money element)
     09 void / fallback state
     10 sticky mini CTA
     11 continue sheet (dialog)
     12 offers
     13 footer + toast
     14 landing page
     15 motion, reduced-motion, forced-colors, print
   ========================================================================== */

/* == 01 reset ============================================================== */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
html {
  -webkit-text-size-adjust: 100%; text-size-adjust: 100%; overflow-x: clip;
  scroll-padding-block-start: 72px;   /* clears the sticky sky bar */
}
body { min-block-size: 100svb; -webkit-font-smoothing: antialiased; }
img, svg, video, canvas { display: block; max-inline-size: 100%; }
/* author `svg{display:block}` would otherwise beat the UA sheet's [hidden] rule */
[hidden] { display: none !important; }
img { block-size: auto; }
input, button, textarea, select { font: inherit; color: inherit; }
button { background: none; border: 0; cursor: pointer; }
p, h1, h2, h3, h4 { overflow-wrap: break-word; }
ul { list-style: none; padding: 0; }
a { color: inherit; text-decoration: none; }
summary::-webkit-details-marker { display: none; }
:where(dialog) { border: 0; padding: 0; color: inherit; }

/* == 02 tokens ============================================================= */
/* The COMPLETE light palette lives on bare :root. Dark redefines only what
   changes, twice: once for the OS preference, once for the explicit toggle. */
:root {
  color-scheme: light;

  /* grounds */
  --bg:          #EFE8DC;   /* warm kraft ground - the ticket floats on it    */
  --surface:     #FFFFFF;   /* ticket upper half, dialog, sky bar            */
  --surface-2:   #FBF6ED;   /* the stub below the perforation — other stock  */
  --surface-3:   #F1EADD;   /* inset chips, meta cells, offer cards          */

  /* ink — every ratio below verified against the ground it sits on */
  --ink:         #14161C;   /* 15.00:1 on --bg                               */
  --ink-2:       #4A5262;   /*  6.45:1 on --bg                               */
  --ink-3:       #5C6473;   /*  5.85:1 on --surface / 4.81:1 on --bg         */

  /* boundaries */
  --edge:        #E2D9C8;   /* decorative hairlines only, never load-bearing */
  --edge-strong: #8F7F62;   /* perforation, notch rims — meets 3:1           */

  /* status */
  --ok:          #12B886;
  --ok-ink:      #06301F;   /* 5.67:1 on --ok                                */
  --ok-text:     #0E7A55;   /* 4.83:1 on cream                               */
  --warn:        #8A5A00;
  --danger:      #C42B31;
  --focus:       #1B62F5;

  /* the foil quartet — decorative fills and gradient stops, never text on a
     neutral ground. Ink allowed on each is fixed (see .chip--* below). */
  --foil-1:      #FF3D8B;
  --foil-2:      #7C4DFF;
  --foil-3:      #00D1FF;
  --foil-4:      #FFD400;
  --wash-teal:   #00BFA5;
  --wash-amber:  #FF7A1A;
  --ink-on-pop:  #0B0B12;

  /* brand — real defaults so the page is complete with JS disabled.
     stub.js overwrites these after validating [data-brand]. */
  --brand:       #6C3BF4;
  --brand-rgb:   108 59 244;
  --brand-ink:   #FFFFFF;
  --brand-text:  #5B2FD6;

  /* atmosphere */
  --aurora-a:    .16;
  --shadow-rgb:  20 22 28;
  --shadow-card: 0 18px 40px -18px rgb(var(--shadow-rgb) / .32);
  --shadow-soft: 0 6px 18px -10px rgb(var(--shadow-rgb) / .28);
  --glow-brand:  0 12px 34px -12px rgb(var(--brand-rgb) / .48);
  --media-filter: none;

  /* geometry */
  --notch: 18px;
  --r-card: 24px;
  --r-stub: 18px;
  --r-chip: 999px;
  --gutter: 16px;
  --page: 1080px;

  /* type */
  --font: 'Cairo', 'Segoe UI', Tahoma, 'Noto Sans Arabic', 'Hiragino Sans',
          'Yu Gothic UI', 'Noto Sans JP', system-ui, sans-serif;
  --font-code: ui-monospace, 'SF Mono', 'Cascadia Mono', 'Segoe UI Mono',
               Consolas, monospace;
  --lh: 1.6;
  --fs-code:  clamp(28px, 8.5vw, 44px);
  --fs-h1:    clamp(21px, 5.2vw, 30px);
  --fs-h2:    clamp(17px, 3.6vw, 21px);
  --fs-h3:    17px;
  --fs-body:  clamp(15px, 3.4vw, 17px);
  --fs-cta:   17px;
  --fs-meta:  13px;
  --fs-micro: 11px;

  --ease: cubic-bezier(.16, 1, .3, 1);
  --ease-back: cubic-bezier(.34, 1.56, .64, 1);
}

/* Arabic needs more leading; Latin/Japanese less. */
:root:lang(ar) { --lh: 1.78; }

@media (min-width: 768px) {
  :root { --notch: 22px; --gutter: 24px; --fs-meta: 14px; }
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --bg:          #0A0D16;
    --surface:     #141A26;
    --surface-2:   #1B2231;
    --surface-3:   #232B3B;
    --ink:         #F2F5FA;
    --ink-2:       #A9B4C6;
    --ink-3:       #7E8A9C;
    --edge:        #2B3444;
    --edge-strong: #63728D;
    --ok-text:     #35DDA0;
    --warn:        #FFC53D;
    --danger:      #FF8A8E;
    --focus:       #7FB0FF;
    --foil-1:      #FF5C9E;
    --foil-2:      #9A78FF;
    --foil-3:      #35DDFF;
    --foil-4:      #FFDE47;
    --aurora-a:    .24;
    --shadow-rgb:  0 0 0;
    --shadow-card: 0 10px 30px -14px rgb(0 0 0 / .75);
    --shadow-soft: 0 6px 16px -10px rgb(0 0 0 / .7);
    --media-filter: brightness(.92) saturate(1.05);
    --grain: .018;
    --brand-text: #B9A2FF;   /* 6.6:1 on --surface - the light value is ~2.3:1 here */
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --bg:          #0A0D16;
  --surface:     #141A26;
  --surface-2:   #1B2231;
  --surface-3:   #232B3B;
  --ink:         #F2F5FA;
  --ink-2:       #A9B4C6;
  --ink-3:       #7E8A9C;
  --edge:        #2B3444;
  --edge-strong: #63728D;
  --ok-text:     #35DDA0;
  --warn:        #FFC53D;
  --danger:      #FF8A8E;
  --focus:       #7FB0FF;
  --foil-1:      #FF5C9E;
  --foil-2:      #9A78FF;
  --foil-3:      #35DDFF;
  --foil-4:      #FFDE47;
  --aurora-a:    .24;
  --shadow-rgb:  0 0 0;
  --shadow-card: 0 10px 30px -14px rgb(0 0 0 / .75);
  --shadow-soft: 0 6px 16px -10px rgb(0 0 0 / .7);
  --media-filter: brightness(.92) saturate(1.05);
  --grain: .018;
  --brand-text: #B9A2FF;
}

/* == 03 base + typography ================================================== */
body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font);
  font-size: var(--fs-body);
  line-height: var(--lh);
  font-synthesis: none;             /* no smeared faux-bold if Cairo 800 misses */
  /* MUST be `clip`, not `hidden`: `hidden` makes body a scroll container, which
     silently breaks position:sticky on the sky bar. */
  overflow-x: clip;
}

h1, h2, h3 { line-height: 1.32; font-weight: 800; text-wrap: balance; }
:lang(ar) h1, :lang(ar) h2, :lang(ar) h3 { line-height: 1.48; }
h1 { font-size: var(--fs-h1); }
h2 { font-size: var(--fs-h2); }
h3 { font-size: var(--fs-h3); font-weight: 600; }

/* letter-spacing breaks Arabic cursive joins — scope it to Latin only. */
.u-track { letter-spacing: .14em; }
:lang(ar) .u-track,
:lang(ar) [class*="u-track"] { letter-spacing: normal; }

::selection { background: rgb(var(--brand-rgb) / .28); color: var(--ink); }

:where(a, button, summary, [tabindex]):focus-visible {
  outline: 0;
  box-shadow: 0 0 0 2px var(--surface), 0 0 0 5px var(--focus);
  border-radius: 10px;
}

/* == 04 utilities ========================================================== */
.vh {
  position: absolute; inline-size: 1px; block-size: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap; border: 0;
}
.skip {
  position: absolute; inset-block-start: -100px; inset-inline-start: 12px;
  z-index: 100; background: var(--surface); color: var(--ink);
  padding: 10px 16px; border-radius: 0 0 12px 12px; box-shadow: var(--shadow-card);
}
.skip:focus { inset-block-start: 0; }

.wrap {
  inline-size: min(100% - (var(--gutter) * 2), var(--page));
  margin-inline: auto;
}
.stack > * + * { margin-block-start: var(--s, 16px); }

/* Directional glyphs mirror with the document, never with a media query. */
[dir="rtl"] .u-flip { transform: scaleX(-1); }

.icon { inline-size: 1em; block-size: 1em; fill: none; stroke: currentColor;
        stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round;
        flex: none; }

.chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 11px; border-radius: var(--r-chip);
  font-size: var(--fs-meta); font-weight: 600; line-height: 1.4;
  background: var(--surface-3); color: var(--ink-2);
  border: 1px solid var(--edge);
}
.chip .icon { font-size: 15px; }
/* Fixed inks for the foil quartet — the only legible pairings. */
.chip--pink   { background: var(--foil-1); color: var(--ink-on-pop); border-color: transparent; }
.chip--violet { background: var(--foil-2); color: #fff;              border-color: transparent; }
.chip--cyan   { background: var(--foil-3); color: var(--ink-on-pop); border-color: transparent; }
.chip--yellow { background: var(--foil-4); color: var(--ink-on-pop); border-color: transparent; }
.chip--ok     { background: var(--ok);     color: var(--ok-ink);     border-color: transparent; }
.chip--brand  { background: rgb(var(--brand-rgb) / .14); color: var(--brand-text);
                border-color: rgb(var(--brand-rgb) / .28); }
.chip--warn   { color: var(--warn); border-color: color-mix(in srgb, var(--warn) 40%, transparent); }
.chip--danger { color: var(--danger); border-color: color-mix(in srgb, var(--danger) 40%, transparent); }

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  min-block-size: 48px; padding-inline: 22px; border-radius: 14px;
  font-size: var(--fs-cta); font-weight: 600;
  transition: transform .12s var(--ease), background-color .2s, box-shadow .2s;
}
.btn:active { transform: scale(.985); }
.btn--brand { background: var(--brand); color: var(--brand-ink); box-shadow: var(--glow-brand); }
.btn--ghost { background: var(--surface-3); color: var(--ink); border: 1px solid var(--edge); }
.btn--quiet { color: var(--ink-3); font-weight: 500; min-block-size: 40px; padding-inline: 12px; }
.btn--block { inline-size: 100%; }

.iconbtn {
  display: grid; place-items: center;
  inline-size: 44px; block-size: 44px; border-radius: 12px;
  color: var(--ink-2); font-size: 20px;
  transition: background-color .18s, color .18s, transform .12s var(--ease);
}
.iconbtn:active { transform: scale(.94); }
@media (hover: hover) and (pointer: fine) {
  .iconbtn:hover { background: var(--surface-3); color: var(--ink); }
}

/* Media that may 404: an explicit box kills layout shift either way. */
.media { position: relative; overflow: hidden; background: var(--surface-3); }
.media > img { inline-size: 100%; block-size: 100%; object-fit: cover; filter: var(--media-filter); }
.media::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(90deg, transparent, rgb(255 255 255 / .28), transparent);
  transform: translateX(-100%); animation: shimmer 1.4s linear infinite;
}
.media.is-loaded::after, .media.is-fallback::after { display: none; }
@keyframes shimmer { to { transform: translateX(100%); } }

/* == 05 aurora ground ====================================================== */
body::before {
  content: ""; position: fixed; inset: -20%; z-index: -2; pointer-events: none;
  opacity: var(--aurora-a); filter: blur(60px);
  background:
    radial-gradient(38vmax 38vmax at 78% 8%,  rgb(var(--brand-rgb) / .95), transparent 70%),
    radial-gradient(32vmax 32vmax at 12% 0%,  var(--foil-2), transparent 70%),
    radial-gradient(40vmax 34vmax at 50% 100%, var(--wash-teal), transparent 70%),
    radial-gradient(26vmax 26vmax at 95% 62%, var(--wash-amber), transparent 70%);
}
/* Paper grain — 3% guilloche, static, costs nothing. */
body::after {
  content: ""; position: fixed; inset: 0; z-index: -1; pointer-events: none;
  opacity: var(--grain, .035);
  background: repeating-linear-gradient(45deg, currentColor 0 1px, transparent 1px 3px);
}

/* == 06 sky bar ============================================================ */
.sky {
  position: sticky; inset-block-start: 0; z-index: 40;
  block-size: 56px; display: flex; align-items: center; gap: 10px;
  padding-inline: var(--gutter);
  background: color-mix(in srgb, var(--surface) 82%, transparent);
  border-block-end: 1px solid transparent;
  transition: border-color .2s, background-color .2s;
}
@supports (backdrop-filter: blur(1px)) {
  .sky { backdrop-filter: saturate(180%) blur(14px); -webkit-backdrop-filter: saturate(180%) blur(14px); }
}
@supports not (backdrop-filter: blur(1px)) { .sky { background: var(--surface); } }
.sky.is-stuck { border-block-end-color: var(--edge); }
@media (min-width: 768px) { .sky { block-size: 60px; } }

.sky__brand { display: flex; align-items: center; gap: 10px; min-inline-size: 0; flex: 1; }
.sky__name {
  font-weight: 700; font-size: 15px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.sky__tools { display: flex; align-items: center; gap: 2px; }

/* Logo medallions: a padded disc contains transparent PNGs and white-box JPEGs
   alike, in both themes. */
.medal {
  --size: 28px;
  inline-size: var(--size); block-size: var(--size); flex: none;
  display: grid; place-items: center; overflow: hidden;
  border-radius: 50%; background: var(--surface);
  border: 1px solid var(--edge);
}
.medal > img { inline-size: 100%; block-size: 100%; object-fit: contain; padding: 12%;
               filter: var(--media-filter); }
.medal__initial {
  display: grid; place-items: center; inline-size: 100%; block-size: 100%;
  background: var(--brand); color: var(--brand-ink);
  font-weight: 800; font-size: calc(var(--size) * .42);
}

/* == 07 the ticket ========================================================= */
.page { padding-block: 20px 40px; }
@media (min-width: 1200px) {
  /* the rail track only exists when there is something to put in it */
  .page__grid.has-rail {
    display: grid; grid-template-columns: minmax(0, 1fr) 340px;
    gap: 32px; align-items: start;
  }
  .page__rail .offers { margin-block-start: 0; }
}

.stripe {
  block-size: 6px; border-radius: 6px 6px 0 0;
  background: repeating-linear-gradient(90deg,
    var(--brand) 0 10px, rgb(var(--brand-rgb) / .55) 10px 16px);
}

.ticket {
  --perf: 260px;
  position: relative;
  background: var(--surface);
  border-radius: var(--r-card);
  box-shadow: var(--shadow-card);
  overflow: hidden;
}
@media (min-width: 768px) { .ticket { max-inline-size: 620px; margin-inline: auto; } }
@media (min-width: 1200px) { .ticket { max-inline-size: none; margin-inline: 0; } }

/* The die-cut notches. Guarded: without mask support the card is simply round,
   and the dashed perforation still reads. */
@supports (mask-image: radial-gradient(#000, #000)) {
  .ticket {
    --hole: radial-gradient(circle var(--notch) at left var(--perf), #0000 98%, #000) left / 51% 100% no-repeat,
            radial-gradient(circle var(--notch) at right var(--perf), #0000 98%, #000) right / 51% 100% no-repeat;
    -webkit-mask: var(--hole);
    mask: var(--hole);
  }
}

.ticket__banner { aspect-ratio: 16 / 7; }
@media (min-width: 768px) { .ticket__banner { aspect-ratio: 16 / 6; } }
.ticket__banner::before {
  content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: linear-gradient(var(--grad-angle, 160deg),
    rgb(var(--brand-rgb) / .86), rgb(var(--brand-rgb) / .38));
  mix-blend-mode: multiply;
}
[dir="rtl"] .ticket__banner { --grad-angle: 200deg; }
/* No banner? A brand mesh plus the store initial carries the space. */
.ticket__banner.is-fallback {
  background:
    radial-gradient(60% 90% at 20% 0%, rgb(var(--brand-rgb) / .9), transparent 70%),
    radial-gradient(70% 90% at 90% 100%, var(--foil-2), transparent 70%),
    var(--brand);
}
.ticket__banner.is-fallback > img { display: none; }
.ticket__banner .banner__initial {
  position: absolute; inset: 0; display: none; place-items: center;
  font-size: clamp(80px, 26vw, 160px); font-weight: 800;
  color: var(--brand-ink); opacity: .14; z-index: 1;
}
.ticket__banner.is-fallback .banner__initial { display: grid; }

.ticket__head { padding: 0 var(--gutter) 18px; }
.ticket__route {
  display: flex; align-items: center; gap: 12px;
  margin-block-start: -34px; margin-block-end: 14px; position: relative; z-index: 2;
}
@media (min-width: 768px) { .ticket__route { margin-block-start: -42px; } }
.ticket__route .medal { --size: 72px; border: 4px solid var(--surface); box-shadow: var(--shadow-soft); }
@media (min-width: 768px) { .ticket__route .medal { --size: 88px; } }

.route__line { flex: 1; display: flex; align-items: center; gap: 8px; min-inline-size: 0;
               padding-block-start: 30px; }
.route__dots {
  flex: 1; block-size: 2px; min-inline-size: 20px;
  background: repeating-linear-gradient(90deg, var(--edge-strong) 0 3px, transparent 3px 8px);
  opacity: .7;
}
.route__label {
  font-size: var(--fs-micro); font-weight: 700; color: var(--ink-3);
  white-space: nowrap;
}
.route__plane { color: var(--brand-text); font-size: 18px; }

.ticket__title { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.ticket__desc {
  color: var(--ink-2); margin-block-start: 10px; max-inline-size: 68ch;
}
@media (max-width: 480px) {
  .ticket__desc.is-clamped {
    display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
    overflow: hidden;
  }
}
.desc-more { margin-block-start: 6px; font-size: var(--fs-meta); color: var(--brand-text);
             font-weight: 600; display: none; }
.desc-more.is-on { display: inline-flex; align-items: center; gap: 4px; }

.badge--ok {
  position: relative; overflow: hidden;
  background: var(--ok); color: var(--ok-ink);
  border-color: transparent; font-weight: 700;
}
.badge--ok::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(110deg, transparent 34%, rgb(255 255 255 / .34) 50%, transparent 66%);
  transform: translateX(-120%); animation: sheen 3s ease-in-out infinite;
}
@keyframes sheen { 40%, 100% { transform: translateX(120%); } }

/* trust strip */
.trust {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
  border-block-start: 1px solid var(--edge);
  background: var(--surface);
}
.trust__cell {
  padding: 14px 10px; text-align: center;
  display: grid; gap: 4px; justify-items: center;
  font-size: var(--fs-meta); color: var(--ink-3);
  border-inline-start: 1px solid var(--edge);   /* mirrors automatically */
}
.trust__cell:first-child { border-inline-start: 0; }
.trust__cell .icon { font-size: 18px; color: var(--brand-text); }
.trust__val { color: var(--ink); font-weight: 700; line-height: 1.3; }

/* == the perforation ======================================================= */
.perf {
  position: relative; block-size: 34px;
  display: grid; place-items: center;
  background: linear-gradient(var(--surface) 0 50%, var(--surface-2) 50% 100%);
}
.perf__line {
  position: absolute; inset-inline: calc(var(--notch) + 6px); inset-block-start: 50%;
  block-size: 2px; transform: translateY(-50%);
  background: repeating-linear-gradient(90deg, var(--edge-strong) 0 6px, transparent 6px 12px);
}
.perf__dots {
  position: absolute; inset-inline: 18%; inset-block-start: 50%;
  transform: translateY(-50%);
  display: flex; justify-content: space-between; pointer-events: none;
}
.perf__dots i { inline-size: 5px; block-size: 5px; border-radius: 50%; background: var(--brand); opacity: .55; }
.perf__cut {
  position: relative; z-index: 2;
  inline-size: 26px; block-size: 26px; border-radius: 50%;
  background: var(--surface-2); color: var(--edge-strong);
  display: grid; place-items: center; font-size: 14px;
}

/* == 08 the stub =========================================================== */
.stub {
  position: relative; padding: 16px var(--gutter) 22px;
  background: var(--surface-2);
}
.stub::before {
  content: ""; position: absolute; inset: 0; pointer-events: none; opacity: .04;
  background: repeating-linear-gradient(45deg, currentColor 0 2px, transparent 2px 9px);
}
.stub__label {
  font-size: var(--fs-micro); font-weight: 700; color: var(--ink-3);
  display: block; margin-block-end: 10px; text-align: center;
}

/* The code IS the button: one target, one focus stop, one decision. */
.reveal {
  position: relative; overflow: hidden; isolation: isolate;
  inline-size: 100%; min-block-size: 68px;
  display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: 12px;
  padding: 12px 18px; border-radius: var(--r-stub);
  background: var(--brand); color: var(--brand-ink);
  box-shadow: var(--glow-brand);
  transition: transform .12s var(--ease), box-shadow .2s;
}
.reveal::before {                      /* depth */
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: linear-gradient(135deg, transparent, rgb(0 0 0 / .22));
}
.reveal:active { transform: scale(.985); }
.reveal > * { position: relative; z-index: 2; }
.reveal__icon { font-size: 22px; opacity: .9; }
/* Capped so a long localised label (e.g. the Japanese "click to copy") cannot
   squeeze the code, which is the element the visitor actually came for. */
.reveal__label {
  font-size: var(--fs-meta); font-weight: 700; opacity: .92; text-align: end;
  max-inline-size: 9ch;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}

/* Coupon codes are Latin/numeric even on an Arabic page. Without isolation a
   code containing digits reorders visually and the user reads a different
   string from the one they copied. */
.code, .sheet__code, .minibar__code, .stub__repeat, .variant {
  direction: ltr; unicode-bidi: isolate;
}
.code {
  font-family: var(--font-code); font-weight: 700;
  font-size: var(--fs-code); line-height: 1.1;
  font-variant-numeric: tabular-nums slashed-zero;
  text-align: center; min-inline-size: 0;
  overflow-wrap: anywhere; word-break: break-word; hyphens: none;
  transition: filter .4s var(--ease), transform .4s var(--ease);
}
:where([lang="en"], [lang="ja"]) .code, .code { letter-spacing: .06em; }
/* A long code must shrink rather than wrap the button to three lines. The cell
   is a fixed 1fr track, so its width says nothing about the code's LENGTH —
   the template stamps a length class instead. */
.code-cell { min-inline-size: 0; }
.code.len-m  { font-size: clamp(20px, 5.6vw, 28px); }
.code.len-l  { font-size: clamp(16px, 4.4vw, 22px); }
.code.len-xl { font-size: clamp(13px, 3.6vw, 18px); letter-spacing: .02em; }
@media (max-width: 340px) { :root { --fs-code: clamp(24px, 7.4vw, 34px); } }

/* The foil seal. Applied only when JS is running (html.js) so a no-JS visitor
   sees a plain, selectable code. */
.js-ready .reveal:not(.is-revealed) .code { filter: blur(6px); opacity: .92; transform: scale(.96); }
.js-ready .reveal:not(.is-revealed) .foil { opacity: 1; }
.foil {
  position: absolute; inset: 0; z-index: 3; opacity: 0; pointer-events: none;
  mix-blend-mode: overlay;
  background: linear-gradient(100deg,
    var(--foil-1) 0%, var(--foil-2) 26%, var(--foil-3) 52%, var(--foil-4) 78%, var(--foil-1) 100%);
  background-size: 220% 100%;
  animation: foil 5.5s linear infinite;
  transition: clip-path .4s var(--ease), opacity .4s var(--ease);
}
@keyframes foil { to { background-position: 220% 0; } }
.reveal.is-revealed .foil { clip-path: inset(0 0 0 100%); opacity: 0; animation: none; }
[dir="rtl"] .reveal.is-revealed .foil { clip-path: inset(0 100% 0 0); }
.is-paused .foil { animation-play-state: paused; }

.scan {
  position: absolute; inset-block: 0; inline-size: 2px; z-index: 4;
  background: var(--foil-3); box-shadow: 0 0 18px 4px var(--foil-3);
  opacity: 0; pointer-events: none;
}
.reveal.is-revealed .scan { animation: scan .5s var(--ease) 1; }
@keyframes scan {
  0%   { opacity: 0;  inset-inline-start: 0; }
  20%  { opacity: .9; }
  100% { opacity: 0;  inset-inline-start: 100%; }
}

.stamp {
  position: absolute; inset-block-start: 50%; inset-inline-start: 50%; z-index: 5;
  inline-size: 90px; block-size: 90px;
  margin-block-start: -48px; margin-inline-start: -48px;   /* 3px border => 96px box */
  border: 3px solid var(--brand-ink); border-radius: 50%;
  opacity: 0; pointer-events: none;
}
.reveal.is-stamped .stamp { animation: stamp .26s ease-out 1; }
@keyframes stamp {
  from { opacity: .85; transform: scale(.6); }
  to   { opacity: 0;   transform: scale(1.4); }
}

/* revealed extras */
.barcode {
  display: none; gap: 2px; align-items: end; block-size: 26px;
  margin-block-start: 12px; opacity: .5;
}
.reveal.is-revealed ~ .stub__after .barcode { display: flex; }
.barcode i { flex: 1; background: var(--ink-3); border-radius: 1px; }
.stub__after { text-align: center; }
.stub__repeat {
  display: none; margin-block-start: 10px;
  font-family: var(--font-code); font-size: var(--fs-micro);
  color: var(--ink-3); font-weight: 700;
}
.reveal.is-revealed ~ .stub__after .stub__repeat { display: block; }

/* "code didn't work?" — the honest failure path */
.helper { margin-block-start: 14px; }
.helper > summary {
  list-style: none; cursor: pointer;
  display: inline-flex; align-items: center; gap: 6px;
  font-size: var(--fs-meta); font-weight: 600; color: var(--ink-3);
}
.helper > summary .icon { transition: transform .2s var(--ease); }
.helper[open] > summary .icon { transform: rotate(180deg); }
.helper__body {
  margin-block-start: 10px; padding: 14px; border-radius: 14px;
  background: var(--surface-3); border: 1px solid var(--edge);
  display: grid; gap: 8px; text-align: start;
}
.variant {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 8px 12px; border-radius: 10px; background: var(--surface);
  border: 1px solid var(--edge); inline-size: 100%;
  font-family: var(--font-code); font-size: 14px; font-weight: 700;
  direction: ltr;
}
.variant span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.variant .icon { color: var(--brand-text); font-size: 17px; }

/* manual-copy last resort */
.reveal.is-manual { background: var(--surface); color: var(--ink);
                    border: 2px dashed var(--danger); box-shadow: none; }
.reveal.is-manual .code { user-select: all; -webkit-user-select: all; filter: none; }
.reveal.is-manual::before { display: none; }
.copy-note { display: none; margin-block-start: 8px; color: var(--danger);
             font-size: var(--fs-meta); font-weight: 600; }
.copy-note.is-on { display: block; }

/* == 09 void / fallback ==================================================== */
.void {
  position: relative; text-align: center; padding-block: 8px 4px;
}
.void__stamp {
  display: inline-block; transform: rotate(-8deg);
  border: 3px solid var(--danger); color: var(--danger);
  border-radius: 10px; padding: 4px 18px; opacity: .85;
  font-size: 20px; font-weight: 800; letter-spacing: .18em;
}
.void__msg {
  margin-block-start: 14px; color: var(--ink-2); font-weight: 600;
  max-inline-size: 46ch; margin-inline: auto;
}
.void__actions { margin-block-start: 18px; display: grid; gap: 10px; }
@media (min-width: 480px) { .void__actions { grid-auto-flow: column; justify-content: center; } }

/* == 10 sticky mini CTA ==================================================== */
.minibar {
  position: fixed; inset-inline: 0; inset-block-end: 0; z-index: 45;
  padding: 12px var(--gutter) max(12px, env(safe-area-inset-bottom));
  background: linear-gradient(transparent, var(--bg) 38%);
  transform: translateY(115%); transition: transform .18s var(--ease), visibility .18s;
  pointer-events: none;
  visibility: hidden;          /* also removes it from the tab order and a11y tree */
}
.minibar.is-on { transform: translateY(0); pointer-events: auto; visibility: visible; }
.minibar__inner {
  display: flex; align-items: center; gap: 10px;
  padding-block: 8px; padding-inline: 14px 8px; border-radius: 16px;
  background: var(--surface); border: 1px solid var(--edge);
  box-shadow: var(--shadow-card);
}
.minibar__code {
  flex: 1; min-inline-size: 0; direction: ltr; text-align: start;
  font-family: var(--font-code); font-weight: 700; font-size: 16px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.minibar .btn { min-block-size: 44px; padding-inline: 18px; border-radius: 12px; }
@media (min-width: 768px) { .minibar { display: none; } }

/* == 11 continue sheet ===================================================== */
.sheet {
  inline-size: min(100%, 420px); max-inline-size: 100%;
  margin: auto auto 0; padding: 0;
  background: var(--surface); color: var(--ink);
  border-radius: 24px 24px 0 0;
  box-shadow: var(--shadow-card);
  transform: translateY(100%); opacity: 0;
  transition: transform .28s var(--ease), opacity .28s var(--ease),
              display .28s allow-discrete, overlay .28s allow-discrete;
}
.sheet[open] { transform: translateY(0); opacity: 1; }
@starting-style { .sheet[open] { transform: translateY(100%); opacity: 0; } }
.sheet::backdrop { background: rgb(4 7 14 / 0); transition: background-color .28s; }
.sheet[open]::backdrop { background: rgb(4 7 14 / .72); backdrop-filter: blur(6px);
                         -webkit-backdrop-filter: blur(6px); }
@media (min-width: 768px) {
  .sheet { margin: auto; border-radius: 24px; transform: scale(.94); }
  .sheet[open] { transform: scale(1); }
  @starting-style { .sheet[open] { transform: scale(.94); opacity: 0; } }
}
.sheet__body { padding: 26px 22px max(22px, env(safe-area-inset-bottom)); text-align: center; }
.sheet__ring {
  inline-size: 56px; block-size: 56px; margin-inline: auto; margin-block-end: 14px;
  border-radius: 50%; display: grid; place-items: center;
  background: color-mix(in srgb, var(--ok) 18%, transparent);
  color: var(--ok-text); font-size: 28px;
}
.sheet__ring.is-fail { background: color-mix(in srgb, var(--danger) 18%, transparent);
                       color: var(--danger); }
.sheet__ring .icon { stroke-dasharray: 30; stroke-dashoffset: 30; animation: draw .45s .12s var(--ease) forwards; }
@keyframes draw { to { stroke-dashoffset: 0; } }
.sheet__well {
  display: flex; align-items: center; gap: 10px; justify-content: space-between;
  margin-block: 16px; padding: 12px 14px; border-radius: 14px;
  background: var(--surface-3); border: 1px dashed var(--edge-strong);
}
.sheet__code {
  flex: 1; min-inline-size: 0; direction: ltr; unicode-bidi: isolate;
  font-family: var(--font-code); font-weight: 700; font-size: 20px;
  overflow-wrap: anywhere;
}
.sheet__note { color: var(--ink-2); font-size: var(--fs-meta); }
.sheet__go { margin-block-start: 18px; }
/* The auto-redirect indicator lives INSIDE the button, so it can never drift
   out of alignment the way an absolutely-positioned overlay can. */
#redirectBtn { position: relative; overflow: hidden; isolation: isolate; }
.go__label, .go__count { position: relative; z-index: 1; }
.go__count {
  min-inline-size: 2ch; text-align: center;
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-meta); font-weight: 700; opacity: .85;
}
.go__count:empty { display: none; }
.go__fill {
  position: absolute; inset: 0; z-index: 0;
  background: rgb(0 0 0 / .26);
  transform: scaleX(1); transform-origin: left center;
}
[dir="rtl"] .go__fill { transform-origin: right center; }
.sheet__go.is-counting .go__fill { animation: deplete var(--dur, 6s) linear forwards; }
.sheet__go.is-paused .go__fill { animation-play-state: paused; }
@keyframes deplete { to { transform: scaleX(0); } }
.sheet__cancel { margin-block-start: 6px; }

/* == 12 offers ============================================================= */
.offers { margin-block-start: 34px; }
.offers__head { display: flex; align-items: center; gap: 10px; margin-block-end: 14px; }
.offers__head h2 { flex: 1; }
.offers__grid { display: grid; gap: 14px; }
@media (min-width: 768px) { .offers__grid { grid-template-columns: 1fr 1fr; } }
@media (min-width: 1200px) { .offers__grid { grid-template-columns: 1fr; } }

.offer {
  --notch: 10px;
  position: relative; display: grid; gap: 12px;
  padding: 16px; border-radius: 18px;
  background: var(--surface); border: 1px solid var(--edge);
  box-shadow: var(--shadow-soft);
}
.offer__top { display: flex; align-items: flex-start; gap: 12px; }
.offer__no {
  flex: none; inline-size: 48px; block-size: 48px; border-radius: 14px;
  display: grid; place-items: center;
  background: rgb(var(--brand-rgb) / .14); color: var(--brand-text);
  font-family: var(--font-code); font-weight: 700; font-size: 18px;
}
.offer__body { min-inline-size: 0; }
.offer__desc {
  color: var(--ink-2); font-size: var(--fs-body); margin-block-start: 4px;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.offer__tear {
  block-size: 1px; margin-block: 2px;
  background: repeating-linear-gradient(90deg, var(--edge-strong) 0 5px, transparent 5px 10px);
  opacity: .6;
}
.offer__foot { display: flex; align-items: center; justify-content: space-between; gap: 10px;
               flex-wrap: wrap; }

/* == 13 footer + toast ===================================================== */
.foot {
  margin-block-start: 40px; padding-block: 26px;
  padding-block-end: calc(26px + env(safe-area-inset-bottom) + 72px);
  border-block-start: 1px solid var(--edge);
  display: grid; gap: 12px; justify-items: center; text-align: center;
  color: var(--ink-3); font-size: var(--fs-meta);
}
@media (min-width: 768px) { .foot { padding-block-end: 40px; } }
.wordmark { display: inline-flex; align-items: center; gap: 8px; font-weight: 800;
            color: var(--ink); font-size: 16px; }
.wordmark .icon { font-size: 22px; color: var(--brand-text); }
.foot__legal { max-inline-size: 58ch; }

.toasts {
  position: fixed; z-index: 60; pointer-events: none;
  inset-inline: var(--gutter); inset-block-end: 84px;
  display: grid; gap: 8px; justify-items: center;
}
@media (min-width: 768px) {
  .toasts { inset-inline: auto var(--gutter); inset-block-end: var(--gutter); justify-items: end; }
}
.toast {
  padding: 11px 16px; border-radius: 12px;
  background: var(--surface); border: 1px solid var(--edge);
  box-shadow: var(--shadow-card); font-size: var(--fs-meta); font-weight: 600;
  animation: toast-in .24s var(--ease);
}
.toast--bad { color: var(--danger); }
@keyframes toast-in { from { opacity: 0; transform: translateY(10px); } }

/* == 14 landing page ======================================================= */
.hero { padding-block: 26px 8px; }
@media (min-width: 1024px) {
  .hero__grid { display: grid; grid-template-columns: 1fr 340px; gap: 32px; align-items: center; }
}
.hero h1 { font-size: clamp(26px, 6.4vw, 44px); }
.hero__sub { color: var(--ink-2); margin-block-start: 12px; max-inline-size: 52ch; }
.hero__stats { display: flex; flex-wrap: wrap; gap: 10px; margin-block-start: 18px; }
.stat {
  display: grid; gap: 2px; padding: 10px 16px; border-radius: 14px;
  background: var(--surface); border: 1px solid var(--edge); box-shadow: var(--shadow-soft);
}
.stat__n { font-size: 22px; font-weight: 800; font-variant-numeric: tabular-nums;
           color: var(--brand-text); line-height: 1.1; }
.stat__l { font-size: var(--fs-meta); color: var(--ink-3); }

/* the static fan of stubs — desktop ornament */
.fan { display: none; position: relative; block-size: 240px; }
@media (min-width: 1024px) { .fan { display: block; } }
.fan__card {
  position: absolute; inset-block-start: 20px; inset-inline-start: 50%;
  inline-size: 190px; block-size: 118px; margin-inline-start: -95px;
  border-radius: 16px; box-shadow: var(--shadow-card);
  display: grid; place-items: center; color: var(--ink-on-pop);
  font-weight: 800; font-size: 15px;
}
.fan__card:nth-child(1) { transform: rotate(-14deg) translate(-46px, 26px); background: var(--foil-3); }
.fan__card:nth-child(2) { transform: rotate(4deg)   translate(0, 0);        background: var(--foil-4); }
.fan__card:nth-child(3) { transform: rotate(16deg)  translate(46px, 34px);  background: var(--foil-1); }

.marquee {
  overflow: hidden; margin-block: 26px;
  background: var(--foil-4); color: var(--ink-on-pop);
  /* scaleX widens it past the page edges without adding layout width */
  transform: rotate(-2deg) scaleX(1.08);
  padding-block: 10px; box-shadow: var(--shadow-soft);
  /* LTR in both directions: an RTL parent would right-align the over-wide
     track, parking it off-screen. The ribbon is aria-hidden decoration, and
     the Arabic runs inside it still shape correctly. */
  direction: ltr;
}
.marquee__track {
  display: flex; gap: 28px; inline-size: max-content;
  font-weight: 800; font-size: 15px; white-space: nowrap;
  animation: marquee 40s linear infinite;
}
@keyframes marquee { to { transform: translateX(-50%); } }

.searchbar { position: relative; flex: 1; min-inline-size: 0; max-inline-size: 320px; }
.searchbar input {
  inline-size: 100%; min-block-size: 44px;
  padding-inline: 40px 36px; border-radius: var(--r-chip);
  background: var(--surface-3); border: 1px solid var(--edge); color: var(--ink);
  font-size: 16px;                 /* 16px minimum stops iOS focus-zoom */
}
.searchbar input::placeholder { color: var(--ink-2); }   /* --ink-3 is 4.06:1 on --surface-3 in dark */
.searchbar__ico {
  position: absolute; inset-inline-start: 13px; inset-block-start: 50%;
  transform: translateY(-50%); color: var(--ink-3); font-size: 18px; pointer-events: none;
}
.searchbar__clear {
  position: absolute; inset-inline-end: 4px; inset-block-start: 50%;
  transform: translateY(-50%); inline-size: 36px; block-size: 36px;
  display: none; place-items: center; border-radius: 50%; color: var(--ink-3);
}
.searchbar.is-filled .searchbar__clear { display: grid; }

.rail {
  display: flex; gap: 8px; overflow-x: auto; padding-block: 4px 12px;
  scroll-snap-type: inline mandatory; overscroll-behavior-inline: contain;
  scrollbar-width: none;
}
.rail::-webkit-scrollbar { display: none; }
.rail > * { scroll-snap-align: start; flex: none; }
.rail .chip { cursor: pointer; min-block-size: 44px; }
.rail .chip[aria-pressed="true"] { background: var(--brand); color: var(--brand-ink);
                                   border-color: transparent; }

.stores { display: grid; gap: 12px; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
@media (min-width: 768px)  { .stores { gap: 16px; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); } }
@media (min-width: 1200px) { .stores { grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); } }

.store {
  --notch: 10px;
  position: relative; display: grid; overflow: hidden;
  border-radius: 18px; background: var(--surface);
  border: 1px solid var(--edge); box-shadow: var(--shadow-soft);
  transition: transform .2s var(--ease), box-shadow .2s;
}
@media (hover: hover) and (pointer: fine) {
  .store:hover { transform: translateY(-2px); box-shadow: var(--shadow-card); }
}
.store__head {
  block-size: 74px; position: relative;
  background: var(--tint, rgb(var(--brand-rgb) / .16));
}
.store__head::after {
  content: ""; position: absolute; inset: 0; opacity: .18;
  background: repeating-linear-gradient(45deg, #fff 0 2px, transparent 2px 8px);
}
.store .medal {
  --size: 56px; position: absolute; inset-block-end: -22px;
  inset-inline-start: 16px; border: 3px solid var(--surface); z-index: 2;
}
.store__body { padding: 30px 14px 12px; display: grid; gap: 2px; }
.store__ar { font-weight: 700; font-size: var(--fs-h3); line-height: 1.35;
             overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.store__en { font-size: var(--fs-meta); color: var(--ink-3); }
.store__tear {
  block-size: 1px; margin-inline: 14px;
  background: repeating-linear-gradient(90deg, var(--edge-strong) 0 5px, transparent 5px 10px);
  opacity: .55;
}
.store__foot {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 10px 14px 14px; font-size: var(--fs-meta); color: var(--ink-3);
}
.store__go { color: var(--brand-text); font-size: 20px; }
/* A store with no live code is shown as such rather than sending the visitor
   to the "no coupons for your country" page to find out. */
.store__soon { color: var(--ink-3); font-style: italic; }
.store[data-codes="0"] .store__head { filter: saturate(.35); }
.store[data-codes="0"] .medal > img { opacity: .75; }

.steps { display: grid; gap: 14px; }
@media (min-width: 768px) { .steps { grid-template-columns: repeat(3, 1fr); } }
.step {
  --notch: 10px;
  padding: 20px 16px; border-radius: 18px; text-align: center;
  background: var(--surface-3); border: 1px solid var(--edge);
  display: grid; gap: 8px; justify-items: center;
}
.step__n {
  inline-size: 44px; block-size: 44px; border-radius: 50%; display: grid; place-items: center;
  background: var(--brand); color: var(--brand-ink); font-weight: 800;
}
.step p { color: var(--ink-2); font-size: var(--fs-meta); }

.faq { display: grid; gap: 10px; }
.faq details {
  border-radius: 14px; background: var(--surface);
  border: 1px solid var(--edge); overflow: hidden;
}
.faq summary {
  list-style: none; cursor: pointer; padding: 15px 16px;
  display: flex; align-items: center; gap: 12px; font-weight: 600;
}
.faq summary .icon { margin-inline-start: auto; color: var(--ink-3);
                     transition: transform .2s var(--ease); }
.faq details[open] summary .icon { transform: rotate(180deg); }
.faq__a { padding: 0 16px 16px; color: var(--ink-2); font-size: var(--fs-body); }

.section { margin-block-start: 38px; }
.section__head { margin-block-end: 14px; display: flex; align-items: center; gap: 10px; }
.section__head h2 { flex: 1; }
.recent[hidden] { display: none; }

/* == 15 motion ============================================================= */
.rise { animation: rise .42s var(--ease) both; }
.rise:nth-child(2) { animation-delay: .06s; }
.rise:nth-child(3) { animation-delay: .12s; }
.rise:nth-child(4) { animation-delay: .18s; }
@keyframes rise { from { opacity: 0; transform: translateY(12px); } }

.reveal-in { opacity: 0; transform: translateY(10px); }
.reveal-in.is-in { opacity: 1; transform: none; transition: opacity .28s var(--ease), transform .28s var(--ease); }

.pulse { animation: pulse .6s var(--ease) 2; }
@keyframes pulse { 50% { box-shadow: 0 0 0 10px rgb(var(--brand-rgb) / 0), var(--glow-brand); } }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  .marquee__track { animation: none; justify-content: center; inline-size: 100%; }
  .reveal-in { opacity: 1; transform: none; }
}

@media (prefers-contrast: more) {
  body::before, body::after { display: none; }
  /* must match the specificity of the dark blocks or it is a no-op in dark mode */
  :root,
  :root:not([data-theme="light"]),
  :root[data-theme="dark"] { --edge: var(--edge-strong); --ink-3: var(--ink-2); }
  .offer, .store, .chip { border-width: 2px; }
  .ticket { border: 2px solid var(--edge-strong); }   /* .ticket has no border-style otherwise */
  .foil { display: none; }
}
@media (prefers-reduced-transparency: reduce) {
  .sky { background: var(--surface); backdrop-filter: none; -webkit-backdrop-filter: none; }
  body::before { display: none; }
}

@media (forced-colors: active) {
  /* Punched holes read as rendering errors in high contrast — drop the mask. */
  .ticket { -webkit-mask: none; mask: none; border: 2px solid CanvasText; }
  .foil, .scan, .stamp, body::before, body::after { display: none; }
  .js-ready .reveal:not(.is-revealed) .code { filter: none; opacity: 1; transform: none; }
  .reveal, .btn { border: 2px solid ButtonText; }
}

@media print {
  .sky, .minibar, .toasts, .foot, .helper, .offers, body::before, body::after { display: none !important; }
  .js-ready .reveal:not(.is-revealed) .code { filter: none; opacity: 1; transform: none; }
  .ticket { box-shadow: none; border: 1px solid #000; }
}
