/* CouponRelay — custom bits on top of Tailwind CDN for the public site.
   Design tokens mirror the Tailwind config in public/base.html:
     paper #FAF8F4 · line #E9E3D9 · ink #141322 · relay-600 #0D8F6A          */

:root {
    --paper: #FAF8F4;
    --line: #E9E3D9;
    --line-strong: #DED6C8;
    --relay-50: #EEFBF6;
}

.no-scrollbar::-webkit-scrollbar { display: none; }
.no-scrollbar { -ms-overflow-style: none; scrollbar-width: none; }

/* Dashed reveal ticket edges in the code modal */
.code-ticket {
    background-image: radial-gradient(circle at 0 50%, transparent 8px, var(--relay-50) 8px),
                      radial-gradient(circle at 100% 50%, transparent 8px, var(--relay-50) 8px);
    background-position: left, right;
    background-size: 51% 100%;
    background-repeat: no-repeat;
}

.policy-body a { word-break: break-word; }

/* ── Coupon card as a real tear-off ticket ─────────────────────────────────
   The card itself has NO background. Two pieces stack flush: `.ticket-body`
   (band + content) and `.ticket-stub`. Each is cut with a radial mask at the
   flush edge, so together they leave a genuine hole the page shows straight
   through — at any card height, no magic offsets. Elevation is a drop-shadow
   filter so the shadow follows the punched silhouette, not a rectangle. */
.coupon-card {
    --notch-r: 11px;
    background: transparent;
    filter: drop-shadow(0 1px 1px rgba(20, 19, 34, .05))
            drop-shadow(0 12px 24px -6px rgba(20, 19, 34, .17));
    transition: transform .2s ease, filter .2s ease;
}

.coupon-card:hover {
    /* A crisp green rim that hugs the whole ticket outline (notches included,
       because drop-shadow follows the punched silhouette), plus a lifted
       ambient shadow — the entire ticket lights up, not just its underside. */
    filter: drop-shadow(0 0 1.5px rgba(13, 143, 106, .65))
            drop-shadow(0 10px 16px -6px rgba(20, 19, 34, .12))
            drop-shadow(0 24px 46px -10px rgba(13, 143, 106, .32));
}

.ticket-body {
    -webkit-mask:
        radial-gradient(circle var(--notch-r) at left  bottom, #0000 var(--notch-r), #000 calc(var(--notch-r) + .5px)),
        radial-gradient(circle var(--notch-r) at right bottom, #0000 var(--notch-r), #000 calc(var(--notch-r) + .5px));
    -webkit-mask-composite: source-in;
    mask:
        radial-gradient(circle var(--notch-r) at left  bottom, #0000 var(--notch-r), #000 calc(var(--notch-r) + .5px)),
        radial-gradient(circle var(--notch-r) at right bottom, #0000 var(--notch-r), #000 calc(var(--notch-r) + .5px));
    mask-composite: intersect;
}

.ticket-stub {
    position: relative;
    background: #fff;
    -webkit-mask:
        radial-gradient(circle var(--notch-r) at left  top, #0000 var(--notch-r), #000 calc(var(--notch-r) + .5px)),
        radial-gradient(circle var(--notch-r) at right top, #0000 var(--notch-r), #000 calc(var(--notch-r) + .5px));
    -webkit-mask-composite: source-in;
    mask:
        radial-gradient(circle var(--notch-r) at left  top, #0000 var(--notch-r), #000 calc(var(--notch-r) + .5px)),
        radial-gradient(circle var(--notch-r) at right top, #0000 var(--notch-r), #000 calc(var(--notch-r) + .5px));
    mask-composite: intersect;
}

/* dashed tear line, held clear of the two holes */
.ticket-stub::before {
    content: "";
    position: absolute;
    top: -1px;
    left: 16px;
    right: 16px;
    border-top: 2px dashed var(--line-strong);
}

/* ── Ambient grain ─────────────────────────────────────────────────────────
   A fixed, non-interactive noise film that keeps large flat areas from
   reading as sterile digital vector. Very low opacity on purpose. */
.grain {
    position: fixed;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    opacity: .5;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='3'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='.035'/%3E%3C/svg%3E");
}

/* Ambient wash behind the hero — a soft radial, not a 45° linear gradient. */
.hero-wash::before {
    content: "";
    position: absolute;
    inset: -20% -10% auto -10%;
    height: 520px;
    z-index: -1;
    pointer-events: none;
    background:
        radial-gradient(58% 62% at 18% 28%, rgba(13, 143, 106, .13), transparent 68%),
        radial-gradient(46% 58% at 88% 8%, rgba(245, 185, 59, .16), transparent 70%);
}

/* Card entrance */
@keyframes floatUp { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
.floaty { animation: floatUp .45s cubic-bezier(.16, 1, .3, 1) both; }
@media (prefers-reduced-motion: reduce) { .floaty { animation: none; } }

/* ── Horizontal scroll-snap rail ───────────────────────────────────────── */
.snap-rail { scroll-snap-type: x proximity; }
.snap-rail > .snap-start { scroll-snap-align: start; }

/* ── Scroll reveal (progressive enhancement) ───────────────────────────────
   Content is fully visible by default. public.js adds `.has-reveal` to <body>
   only when JS runs AND the user hasn't requested reduced motion; the reveal
   never gates content visibility on its own. */
.has-reveal .reveal { opacity: 0; transform: translateY(18px); }
.has-reveal .reveal.in {
    opacity: 1;
    transform: none;
    transition: opacity .6s cubic-bezier(.16, 1, .3, 1),
                transform .6s cubic-bezier(.16, 1, .3, 1);
}
@media (prefers-reduced-motion: reduce) {
    .has-reveal .reveal,
    .has-reveal .reveal.in { opacity: 1; transform: none; transition: none; }
}
