/* Self-hosted so that no request — and no visitor IP — reaches Google. One variable file per
   family and subset covers every weight the app uses. */
@font-face { font-family:'DM Sans'; font-style:normal; font-weight:100 1000; font-display:swap; src:url('fonts/dm-sans-latin-ext.woff2') format('woff2'); unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family:'DM Sans'; font-style:normal; font-weight:100 1000; font-display:swap; src:url('fonts/dm-sans-latin.woff2') format('woff2'); unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family:'Space Grotesk'; font-style:normal; font-weight:300 700; font-display:swap; src:url('fonts/space-grotesk-latin-ext.woff2') format('woff2'); unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family:'Space Grotesk'; font-style:normal; font-weight:300 700; font-display:swap; src:url('fonts/space-grotesk-latin.woff2') format('woff2'); unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
/* SPAR's red, sampled from its logo, and a green a shade darker than SPAR's own so that amounts in
   it stay readable as small text on white — Libri is the bound book at night,
   Tracktivity the cool green, TicketWatch the plum, Gustus the tomato and Horizon the dawn. --red is
   the colour anything interactive is drawn in. --green is money left on a voucher and is used for
   nothing else, so a figure in green is always something that can still be spent; --amber marks a
   balance nobody has checked yet, which is the face value and may well be out of date. */
:root { --ink:#24201f; --muted:#7a716d; --paper:#f8f5f3; --card:#fffefd; --line:#ebe3df; --red:#e40613; --red-soft:#fbe4e2; --green:#0b7a3a; --green-soft:#def2e6; --alert:#b3261e; --alert-soft:#fbe3e1; --amber:#a86412; --amber-soft:#fbefd9; --gold:#f5c64a; }
* { box-sizing:border-box; }
/* Defensive: user-select inherits, so any future none on an ancestor would silently take away the
   long-press "paste" menu inside text fields. */
input,textarea { user-select:text; -webkit-user-select:text; }
/* Beats any display rule below: .login-shell sets display:flex, which otherwise outranks the
   browser's own [hidden] { display:none } and leaves the signed-out panel showing under every tab. */
[hidden] { display:none !important; }
/* Android browsers "boost" text they take for body copy, which silently overrides small sizes. */
html { -webkit-text-size-adjust:100%; text-size-adjust:100%; }
/* A sideways drag would otherwise engage the browser's own swipe-to-go-back gesture, which nudges the
   whole page and drops fixed elements like the tab bar for a few frames. */
html,body { overscroll-behavior-x:none; }
/* The document does not scroll; the body inside it does. Browsers hang their own furniture — Samsung
   Internet's floating "scroll to top" button among it — off whatever the root scroller is, and in an
   installed app that button lands on top of the tab bar. See Libri's commit of the same name. */
html { height:100%; overflow:hidden; }
body { height:100%; overflow-x:hidden; overflow-y:auto; }
.shell { overflow-x:clip; }
/* Only transform and opacity are animated: those two the compositor handles on its own. */
@keyframes card-in-right { from { opacity:0; transform:translate3d(22%,0,0); } to { opacity:1; transform:none; } }
@keyframes card-in-left { from { opacity:0; transform:translate3d(-22%,0,0); } to { opacity:1; transform:none; } }
.view.card-right,.view.card-left { backface-visibility:hidden; will-change:transform, opacity; }
.view.card-right { animation:card-in-right .24s cubic-bezier(.16,.84,.36,1); }
.view.card-left { animation:card-in-left .24s cubic-bezier(.16,.84,.36,1); }
@media (prefers-reduced-motion: reduce) { .view.card-right,.view.card-left { animation:none !important; } }
body { margin:0; background:radial-gradient(circle at 100% 0%, #fbdcd9 0, transparent 38%), radial-gradient(circle at 0% 100%, #dcefe3 0, transparent 34%), var(--paper); background-attachment:fixed; color:var(--ink); font-family:'DM Sans', sans-serif; }
button,input,select,textarea { font:inherit; }
button { cursor:pointer; }
.shell,.login-shell { width:min(100% - 32px, 720px); margin:0 auto; }
.topbar { display:flex; align-items:center; justify-content:space-between; padding:26px 0 14px; gap:10px; }
.brand { align-items:center; display:flex; gap:12px; }
.brand img { border-radius:10px; box-shadow:0 4px 14px rgba(120,20,24,.22); flex:none; }
h1,h2 { font-family:'Space Grotesk', sans-serif; margin:0; letter-spacing:0; }
h1 { font-size:clamp(1.6rem, 6vw, 2.2rem); line-height:1.05; }
h2 { font-size:1.45rem; }
.kicker,.eyebrow { color:var(--red); font-size:.68rem; font-weight:700; letter-spacing:.14em; margin:0 0 5px; text-transform:uppercase; }
.muted { color:var(--muted); }
.icon-button { border:0; background:transparent; color:var(--muted); font-size:1.35rem; padding:8px; }
.topbar-actions { align-items:center; display:flex; gap:2px; position:relative; }
.menu { background:var(--card); border:1px solid var(--line); border-radius:6px; box-shadow:0 12px 28px rgba(36,32,31,.16); display:flex; flex-direction:column; overflow:hidden; padding:5px; position:absolute; right:0; top:calc(100% + 6px); width:max-content; min-width:190px; z-index:40; }
/* nowrap plus a max-content menu keeps every label on one line, whatever the phone's width.
   Absolute px, not rem: immune to a scaled root font size on the phone. */
.menu-item { background:transparent; border:0; border-radius:4px; color:var(--ink); font-size:11px; letter-spacing:.02em; padding:8px 11px; text-align:left; white-space:nowrap; width:100%; }
.menu-item:hover { background:var(--paper); }
.menu-item.danger { color:var(--alert); }
.menu-caption { color:var(--muted); display:block; font-size:.85em; letter-spacing:.08em; text-transform:uppercase; }
.menu-value { display:block; font-weight:600; margin-top:2px; }
.menu-value:after { content:' ▸'; color:var(--muted); }
.menu-divider { background:var(--line); height:1px; margin:4px 6px; }
.view { padding-bottom:100px; }
.view-title { align-items:end; display:flex; gap:12px; justify-content:space-between; margin:2px 0 16px; }
#view-legal { padding-bottom:40px; }
.section-heading { align-items:end; display:flex; gap:12px; justify-content:space-between; margin:24px 0 10px; }
.section-heading h3 { font-family:'Space Grotesk', sans-serif; font-size:1.02rem; margin:0; }
.section-heading span { color:var(--muted); font-size:.78rem; }

/* ---- panels and figures ---- */
.panel { background:var(--card); border:1px solid var(--line); border-radius:12px; padding:16px; }
.panel + .panel { margin-top:12px; }
.panel h3 { font-family:'Space Grotesk', sans-serif; font-size:1rem; margin:0 0 10px; }
.figure-label { color:var(--muted); font-size:.68rem; font-weight:700; letter-spacing:.12em; text-transform:uppercase; }
.amount { font-family:'Space Grotesk', sans-serif; font-variant-numeric:tabular-nums; font-weight:700; white-space:nowrap; }


/* ---- imprint and privacy ---- */
.back-button { background:transparent; border:0; color:inherit; font:inherit; letter-spacing:inherit; margin:0; padding:0; text-transform:inherit; }
.imprint-button { background:transparent; border:0; color:var(--muted); font-size:.78rem; padding:8px 4px; white-space:nowrap; }
.legal-block { background:var(--card); border:1px solid var(--line); border-radius:8px; padding:16px 18px; }
.legal-facts { display:grid; gap:2px 16px; grid-template-columns:auto 1fr; margin:0 0 14px; }
.legal-facts dt { color:var(--muted); font-size:.76rem; letter-spacing:.06em; text-transform:uppercase; }
.legal-facts dd { margin:0 0 8px; }
.legal-block a,.legal-body a { color:var(--red); }
.legal-details { background:var(--card); border:1px solid var(--line); border-radius:8px; margin-top:12px; }
.legal-details summary { cursor:pointer; font-family:'Space Grotesk', sans-serif; font-size:1.05rem; font-weight:600; list-style:none; padding:15px 18px; }
.legal-details summary::-webkit-details-marker { display:none; }
.legal-details summary:after { color:var(--muted); content:'▾'; float:right; transition:transform .2s; }
.legal-details[open] summary:after { transform:rotate(180deg); }
.legal-body { border-top:1px solid var(--line); padding:4px 18px 18px; }
.legal-body h3 { font-family:'Space Grotesk', sans-serif; font-size:.95rem; margin:18px 0 6px; }
.legal-body p,.legal-body li { color:#4a4442; font-size:.88rem; line-height:1.55; margin:6px 0; }
.legal-body ul { margin:6px 0; padding-left:20px; }

/* ---- tab bar ----
   Opaque, not translucent: translate3d and will-change keep it on its own compositor layer, so it is
   not repainted — and briefly dropped — while a card animates past. */
.tabbar { background:var(--paper); border-top:1px solid var(--line); bottom:0; display:flex; justify-content:space-around; left:50%; max-width:720px; padding:11px 0 max(11px, env(safe-area-inset-bottom)); position:fixed; transform:translate3d(-50%,0,0); width:100%; will-change:transform; z-index:3; }
.tabbar button { background:none; border:0; color:var(--muted); display:flex; flex-direction:column; font-size:.72rem; gap:4px; padding:3px 18px; }
.tabbar button span { font-size:1.25rem; line-height:1; }
.tabbar button.active { color:var(--red); font-weight:700; }
.tabbar button em { font-style:normal; }

/* ---- buttons, dialogs, the rest of the furniture ---- */
.primary-button { background:var(--red); border:0; border-radius:5px; color:#fff; font-weight:700; padding:10px 18px; white-space:nowrap; }
.primary-button:disabled,.update-button:disabled { opacity:.55; cursor:default; }
.ghost-button { background:var(--card); border:1px solid var(--line); border-radius:5px; color:var(--ink); font-weight:500; padding:9px 14px; }
.ghost-button.on { background:var(--green-soft); border-color:var(--green); color:var(--green); font-weight:700; }
.danger-button { background:var(--alert); }
.ghost-button.danger { color:var(--alert); }
.link-button { background:none; border:0; color:var(--red); font-weight:700; padding:0; text-decoration:underline; }
.empty-state { color:var(--muted); padding:30px 10px; text-align:center; }
.empty-state .primary-button { margin-top:14px; }
.loading { color:var(--muted); font-size:.88rem; padding:24px 4px; text-align:center; }
.offline-note { background:var(--amber-soft); border-radius:6px; color:var(--ink); font-size:.82rem; margin:0 0 12px; padding:8px 12px; }
.storage-status { border-left:3px solid var(--amber); color:var(--ink); font-size:.86rem; line-height:1.45; margin:0 0 12px; padding:2px 0 2px 10px; }
.storage-status.kept { border-left-color:var(--green); }
.segmented { background:var(--card); border:1px solid var(--line); border-radius:6px; display:flex; overflow:hidden; }
.segmented button { background:transparent; border:0; color:var(--muted); flex:1; font-size:.84rem; padding:10px 6px; }
.segmented button.active { background:var(--green); color:#fff; font-weight:700; }
.modal-overlay { align-items:center; background:rgba(36,32,31,.46); bottom:0; display:flex; justify-content:center; left:0; opacity:0; padding:20px; position:fixed; right:0; top:0; transition:opacity .16s; z-index:10; }
.modal-overlay.open { opacity:1; }
.modal { background:var(--paper); border-radius:12px; box-shadow:0 18px 44px rgba(36,32,31,.26); max-height:calc(100vh - 40px); max-width:480px; overflow-y:auto; padding:22px; transform:translateY(8px); transition:transform .16s; width:100%; }
/* vh on a phone is measured with the browser's toolbars hidden, so a dialog sized in it is taller
   than what can be seen and its last row — the buttons — sits under the address bar. dvh is the
   height there really is. */
@supports (max-height: 100dvh) { .modal { max-height:calc(100dvh - 40px); } }
.modal-overlay.open .modal { transform:none; }
.modal h3 { font-family:'Space Grotesk', sans-serif; font-size:1.2rem; margin:0 0 10px; }
.modal-copy { color:var(--muted); font-size:.9rem; line-height:1.45; margin:0 0 18px; }
/* Wrapping is not cosmetic: a flex row that justifies to the end overflows towards the start, and
   overflow in that direction cannot be scrolled to — on a narrow phone the leftmost button, which is
   Delete, would simply be gone. */
.modal-actions { display:flex; flex-wrap:wrap; gap:9px; justify-content:flex-end; margin-top:20px; }
.modal-actions .spacer { flex:1 1 0; min-width:0; }
.modal-error { background:var(--alert-soft); border-radius:6px; color:#8c1c17; font-size:.86rem; margin:4px 0 0; padding:9px 11px; }
@media (max-width: 460px) {
  .modal-overlay { padding:12px; }
  .modal { padding:18px; }
  .modal-actions { flex-direction:column-reverse; }
  .modal-actions .spacer { display:none; }
  .modal-actions > button { padding:12px 14px; width:100%; }
}
.field { display:flex; flex-direction:column; gap:8px; margin-bottom:16px; }
.field > span { color:var(--muted); font-size:.72rem; font-weight:700; letter-spacing:.09em; text-transform:uppercase; }
.field input,.field select { background:var(--card); border:1px solid var(--line); border-radius:5px; color:var(--ink); min-width:0; padding:11px; width:100%; }
.field input:disabled { background:#f0ebe8; color:var(--muted); }
.field select { appearance:none; background-image:linear-gradient(45deg, transparent 50%, var(--muted) 50%), linear-gradient(135deg, var(--muted) 50%, transparent 50%); background-position:calc(100% - 17px) 50%, calc(100% - 12px) 50%; background-repeat:no-repeat; background-size:5px 5px, 5px 5px; padding-right:34px; }
.field small { color:var(--muted); font-size:.74rem; }
.field-row { display:flex; gap:9px; }
.field-row > .field { flex:1; min-width:0; }
@media (max-width: 360px) { .field-row { flex-direction:column; gap:0; } }
.row-list { display:flex; flex-direction:column; gap:8px; }
.row { align-items:center; background:var(--card); border:1px solid var(--line); border-radius:8px; color:var(--ink); display:flex; gap:12px; padding:10px 12px; text-align:left; width:100%; }
.row-copy { display:flex; flex:1; flex-direction:column; gap:3px; min-width:0; }
.row-copy small { color:var(--muted); font-size:.77rem; }
.row .arrow { color:var(--muted); margin-left:auto; }

/* ---- signed out, and the two banners ---- */
.login-shell { align-items:flex-start; display:flex; flex-direction:column; justify-content:center; min-height:100vh; padding:30px 0; }
.login-mark { border-radius:16px; box-shadow:0 8px 24px rgba(120,20,24,.25); margin-bottom:26px; }
.login-shell h1 { font-size:clamp(2.2rem, 11vw, 4.3rem); max-width:560px; }
.login-shell > .muted { margin:10px 0 30px; }
.login-actions { display:flex; gap:9px; margin-top:4px; width:100%; max-width:420px; }
.login-actions .primary-button { align-items:center; display:flex; flex:1; justify-content:center; min-height:48px; text-decoration:none; }
.login-switch { color:var(--muted); font-size:.85rem; margin:14px 0 0; }
.build-badge { color:var(--muted); font-size:.6rem; letter-spacing:.04em; margin:0; opacity:.7; pointer-events:none; position:fixed; right:12px; top:max(calc(env(safe-area-inset-top) + 6px), 6px); z-index:2; }
.update-banner { align-items:center; background:var(--ink); border-radius:6px; color:var(--paper); display:flex; font-size:.85rem; gap:12px; left:50%; max-width:calc(100% - 32px); padding:10px 12px; position:fixed; top:12px; transform:translateX(-50%); width:720px; z-index:6; }
.update-banner span { flex:1; }
.update-button { background:var(--gold); border:0; border-radius:5px; color:var(--ink); font-weight:700; padding:8px 14px; }
#toast { background:var(--ink); border-radius:5px; bottom:85px; color:#fff; left:50%; max-width:calc(100% - 32px); opacity:0; padding:12px 16px; pointer-events:none; position:fixed; transform:translate(-50%, 15px); transition:.2s; z-index:20; }
#toast.show { opacity:1; transform:translate(-50%,0); }

@media (max-width:520px) {
  .shell,.login-shell { width:min(100% - 24px, 720px); }
  .primary-button { min-height:46px; }
  .brand img { height:36px; width:36px; }
  .tabbar button { padding:3px 12px; }
}

/* ---- the active voucher ----
   The screen that is held up at the till. The barcode sits on white whatever the page does around it,
   with the quiet zone Code 128 needs on either side, and is as wide as the screen allows: a scanner
   reads wide bars from further away and at a worse angle than narrow ones. */
.active-card { background:var(--card); border:1px solid var(--line); border-radius:14px; box-shadow:0 10px 30px rgba(120,20,24,.10); overflow:hidden; }
.active-head { align-items:center; background:var(--red); color:#fff; display:flex; gap:10px; justify-content:space-between; padding:12px 16px; }
.active-head .kicker { color:rgba(255,255,255,.85); margin:0; }
.active-head strong { font-family:'Space Grotesk', sans-serif; font-size:1.05rem; letter-spacing:.06em; }
.active-body { padding:18px 16px 16px; }
.barcode { background:#fff; border-radius:6px; display:block; padding:14px 0 6px; }
.barcode svg { display:block; height:110px; width:100%; }
.barcode-text { color:var(--ink); font-family:'Space Grotesk', sans-serif; font-size:1.02rem; font-variant-numeric:tabular-nums; letter-spacing:.12em; margin:8px 0 0; overflow-wrap:anywhere; text-align:center; }
.balance-line { align-items:baseline; display:flex; flex-wrap:wrap; gap:4px 12px; justify-content:space-between; margin-top:18px; }
.balance-big { color:var(--green); display:block; font-family:'Space Grotesk', sans-serif; font-size:clamp(2rem, 9vw, 2.7rem); font-variant-numeric:tabular-nums; font-weight:700; line-height:1.05; }
.balance-big.empty { color:var(--muted); }
.balance-note { color:var(--muted); font-size:.8rem; }
.balance-note.unchecked { color:var(--amber); }
.active-actions { display:flex; gap:9px; margin-top:16px; }
.active-actions > * { flex:1; }
.hint { background:var(--amber-soft); border-radius:8px; color:#7a4a0e; font-size:.84rem; line-height:1.45; margin:14px 0 0; padding:10px 12px; }
.queue-note { color:var(--muted); font-size:.82rem; margin:14px 2px 0; text-align:center; }

/* ---- lists of vouchers ---- */
.toolbar { align-items:center; display:flex; flex-wrap:wrap; gap:8px; justify-content:space-between; margin-bottom:12px; }
.toolbar small { color:var(--muted); font-size:.8rem; }
.voucher-list { display:flex; flex-direction:column; gap:8px; }
/* The row is the target: tapping a voucher opens it. The stripe on its left says at a glance which is
   the active one and which have nothing left. */
.voucher { align-items:center; background:var(--card); border:1px solid var(--line); border-left:4px solid var(--line); border-radius:9px; color:var(--ink); display:flex; gap:12px; padding:12px 13px; text-align:left; width:100%; }
.voucher.active { border-left-color:var(--red); }
.voucher.spent { opacity:.7; }
.voucher-copy { display:flex; flex:1; flex-direction:column; gap:4px; min-width:0; }
.voucher-copy strong { font-family:'Space Grotesk', sans-serif; font-size:.98rem; font-variant-numeric:tabular-nums; letter-spacing:.06em; }
.voucher-copy small { color:var(--muted); font-size:.76rem; }
.voucher-side { align-items:flex-end; display:flex; flex:none; flex-direction:column; gap:3px; }
.voucher-side .amount { color:var(--green); font-size:1.02rem; }
.voucher-side .amount.empty { color:var(--muted); }
.voucher-side small { color:var(--muted); font-size:.72rem; }
.voucher-side small.unchecked { color:var(--amber); }
.pill-row { display:flex; flex-wrap:wrap; gap:5px; }
.pill { background:var(--green-soft); border-radius:999px; color:var(--green); display:inline-block; font-size:.64rem; font-weight:700; letter-spacing:.05em; padding:3px 8px; text-transform:uppercase; white-space:nowrap; }
.pill.active { background:var(--red-soft); color:var(--red); }
.pill.muted { background:var(--paper); border:1px solid var(--line); color:var(--muted); padding:2px 7px; }
.add-tile { align-items:center; background:transparent; border:1.5px dashed var(--line); border-radius:9px; color:var(--red); display:flex; font-weight:700; gap:8px; justify-content:center; margin-top:10px; padding:14px; width:100%; }

/* ---- the voucher dialog ---- */
.modal.voucher-modal { max-width:520px; }
.secret-grid { display:grid; gap:10px; grid-template-columns:1fr auto; margin:16px 0 4px; }
.secret { background:var(--card); border:1px solid var(--line); border-radius:8px; padding:9px 12px; }
.secret small { color:var(--muted); display:block; font-size:.66rem; font-weight:700; letter-spacing:.1em; text-transform:uppercase; }
.secret span { display:block; font-family:'Space Grotesk', sans-serif; font-size:1.02rem; font-variant-numeric:tabular-nums; letter-spacing:.08em; margin-top:2px; overflow-wrap:anywhere; }
.secret button { background:none; border:0; color:var(--red); font-size:.74rem; font-weight:700; padding:0; }
.balance-box { align-items:center; background:var(--card); border:1px solid var(--line); border-radius:8px; display:flex; gap:10px; justify-content:space-between; margin-top:10px; padding:10px 12px; }
.balance-box .amount { color:var(--green); display:block; font-size:1.3rem; }
.balance-box .amount.empty { color:var(--muted); }
.balance-box small { color:var(--muted); display:block; font-size:.74rem; }
.balance-box small.unchecked { color:var(--amber); }
.balance-edit { display:flex; gap:8px; margin-top:10px; }
.balance-edit input { background:var(--card); border:1px solid var(--line); border-radius:5px; color:var(--ink); flex:1; font-size:1.05rem; min-width:0; padding:10px 11px; }
.small-button { background:var(--card); border:1px solid var(--line); border-radius:5px; color:var(--ink); flex:none; font-size:.8rem; font-weight:600; padding:7px 11px; white-space:nowrap; }
.small-button.red { border-color:var(--red); color:var(--red); }
a.small-button { text-decoration:none; }
.spar-links { display:flex; flex-wrap:wrap; gap:9px; margin-top:12px; }
.app-link { background:var(--card); border:1px solid var(--line); border-radius:8px; color:var(--red); display:block; font-weight:700; margin:12px 0 0; padding:12px 14px; text-align:center; text-decoration:none; }
.upload-results { display:flex; flex-direction:column; gap:6px; margin:4px 0 0; }
.upload-results div { background:var(--card); border:1px solid var(--line); border-left:4px solid var(--green); border-radius:7px; font-size:.84rem; padding:8px 11px; }
.upload-results div.duplicate { border-left-color:var(--amber); }
.upload-results div.unreadable { border-left-color:var(--alert); }
.upload-results small { color:var(--muted); display:block; font-size:.74rem; margin-top:2px; overflow-wrap:anywhere; }
.bookmarklet { background:var(--red); border-radius:6px; color:#fff; display:inline-block; font-weight:700; padding:9px 14px; text-decoration:none; }
.code-box { background:var(--card); border:1px solid var(--line); border-radius:6px; color:var(--muted); font-family:ui-monospace, monospace; font-size:.68rem; line-height:1.4; margin:10px 0 0; max-height:90px; overflow:auto; overflow-wrap:anywhere; padding:8px 10px; user-select:all; -webkit-user-select:all; }
.steps { color:var(--ink); font-size:.88rem; line-height:1.5; margin:0 0 14px; padding-left:20px; }
.steps li { margin:4px 0; }

/* ---- slide to archive ----
   A track the width of the card with a round thumb at its left end. The red fill follows the thumb,
   and the label fades as it goes, so how far is left is visible without reading anything. Only a
   release at the far end counts; anywhere short and the thumb springs back. touch-action:none keeps
   the drag from being taken for a scroll. */
.slide-track { background:var(--red-soft); border-radius:999px; height:56px; margin-top:14px; overflow:hidden; position:relative; touch-action:none; user-select:none; -webkit-user-select:none; }
.slide-track:focus-visible { outline:2px solid var(--red); outline-offset:3px; }
.slide-fill { background:var(--red); border-radius:999px; bottom:0; left:0; position:absolute; top:0; width:56px; }
.slide-label { align-items:center; color:var(--red); display:flex; font-size:.86rem; font-weight:700; inset:0; justify-content:center; letter-spacing:.04em; opacity:calc(1 - var(--slid, 0) * 1.4); padding-left:40px; pointer-events:none; position:absolute; }
.slide-thumb { align-items:center; background:#fff; border-radius:50%; box-shadow:0 2px 8px rgba(120,20,24,.28); color:var(--red); cursor:grab; display:flex; font-size:1.3rem; font-weight:700; height:48px; justify-content:center; left:4px; position:absolute; top:4px; touch-action:none; width:48px; }
.slide-track.dragging .slide-thumb { cursor:grabbing; }
.slide-track.springing .slide-thumb { transition:transform .25s cubic-bezier(.2,.9,.3,1.2); }
.slide-track.springing .slide-fill { transition:width .25s cubic-bezier(.2,.9,.3,1.2); }
.slide-track.confirmed .slide-label { color:#fff; opacity:1; padding-left:0; padding-right:44px; }
.slide-track.confirmed .slide-thumb:after { content:'✓'; }
.slide-track.confirmed .slide-thumb { font-size:0; }
.slide-track.confirmed .slide-thumb:after { font-size:1.3rem; }

/* ---- the archived stamp and notice ----
   When the slide completes, a stamp comes down across the card that is still showing — so there is
   no doubt which one went — and the card greys under it. Then the next voucher takes its place, with
   the notice above it saying what happened and offering to undo it. */
.active-card { position:relative; }
.archived-stamp { align-items:center; display:flex; inset:0; justify-content:center; opacity:0; pointer-events:none; position:absolute; }
.archived-stamp span { border:4px solid var(--red); border-radius:10px; color:var(--red); font-family:'Space Grotesk', sans-serif; font-size:clamp(1.8rem, 9vw, 2.6rem); font-weight:700; letter-spacing:.14em; padding:6px 18px; text-transform:uppercase; transform:rotate(-12deg) scale(2.2); }
.active-card.stamped .active-body { filter:grayscale(1); opacity:.35; transition:opacity .35s, filter .35s; }
.active-card.stamped .archived-stamp { animation:stamp-fade .2s ease-out forwards; }
.active-card.stamped .archived-stamp span { animation:stamp-down .32s cubic-bezier(.2,1.4,.4,1) forwards; background:rgba(255,255,255,.85); }
@keyframes stamp-fade { to { opacity:1; } }
@keyframes stamp-down { to { transform:rotate(-12deg) scale(1); } }
.archived-notice { align-items:center; animation:notice-in .3s ease-out; background:var(--green-soft); border:1px solid #b7dfc6; border-radius:12px; display:flex; gap:12px; margin-bottom:14px; padding:12px 14px; }
.archived-notice .tick { align-items:center; background:var(--green); border-radius:50%; color:#fff; display:flex; flex:none; font-weight:700; height:32px; justify-content:center; width:32px; }
.archived-notice div { display:flex; flex:1; flex-direction:column; gap:2px; min-width:0; }
.archived-notice strong { font-size:.95rem; }
.archived-notice small { color:#2f5c41; font-size:.8rem; }
@keyframes notice-in { from { opacity:0; transform:translateY(-8px); } to { opacity:1; transform:none; } }
@media (prefers-reduced-motion: reduce) {
  .active-card.stamped .archived-stamp,.active-card.stamped .archived-stamp span,.archived-notice { animation:none; opacity:1; }
  .archived-stamp span { transform:rotate(-12deg); }
  .slide-track.springing .slide-thumb,.slide-track.springing .slide-fill { transition:none; }
}
