diff --git a/src/index.css b/src/index.css index 72af2fb..c94b163 100644 --- a/src/index.css +++ b/src/index.css @@ -427,143 +427,152 @@ html, body { mix-blend-mode: screen; } +/* ── Force background graphics to print on all card themes ── + Browsers suppress backgrounds by default. -webkit-print-color-adjust: exact + overrides this for Chrome/Safari. color-adjust: exact covers Firefox/Edge. */ +.rider-card, +.rider-card *, +[class^="card-theme-"], +[class^="card-theme-"] * { + -webkit-print-color-adjust: exact !important; + print-color-adjust: exact !important; + color-adjust: exact !important; +} + /* ── Theme: THUG (default — black + neon red) ── */ .card-theme-thug { - background: linear-gradient(135deg, #0a0a0a 0%, #1a0008 60%, #0d0d0d 100%); + background: linear-gradient(135deg, #0a0a0a 0%, #1a0008 60%, #0d0d0d 100%) !important; border: 1.5px solid rgba(255,0,64,0.5); box-shadow: 0 0 30px rgba(255,0,64,0.2), inset 0 1px 0 rgba(255,255,255,0.05); - color: #fff; + color: #fff !important; } -.card-theme-thug .card-accent { color: #ff0040; } -.card-theme-thug .card-accent2 { color: #ccff00; } -.card-theme-thug .card-stripe { background: linear-gradient(90deg, #ff0040, #ff6600); } -.card-theme-thug .card-muted { color: rgba(255,255,255,0.45); } -.card-theme-thug .card-bg-chip { background: rgba(255,0,64,0.12); border: 1px solid rgba(255,0,64,0.3); } +.card-theme-thug .card-accent { color: #ff0040 !important; } +.card-theme-thug .card-accent2 { color: #ccff00 !important; } +.card-theme-thug .card-stripe { background: linear-gradient(90deg, #ff0040, #ff6600) !important; } +.card-theme-thug .card-muted { color: rgba(255,255,255,0.6) !important; } +.card-theme-thug .card-bg-chip { background: rgba(255,0,64,0.25) !important; border: 1px solid rgba(255,0,64,0.5) !important; } /* ── Theme: NEON LIME ── */ .card-theme-lime { - background: linear-gradient(135deg, #050f00 0%, #0a1a00 60%, #050f00 100%); + background: linear-gradient(135deg, #050f00 0%, #0a1a00 60%, #050f00 100%) !important; border: 1.5px solid rgba(204,255,0,0.5); box-shadow: 0 0 30px rgba(204,255,0,0.15), inset 0 1px 0 rgba(255,255,255,0.05); - color: #fff; + color: #fff !important; } -.card-theme-lime .card-accent { color: #ccff00; } -.card-theme-lime .card-accent2 { color: #ff6600; } -.card-theme-lime .card-stripe { background: linear-gradient(90deg, #ccff00, #88ff00); } -.card-theme-lime .card-muted { color: rgba(255,255,255,0.45); } -.card-theme-lime .card-bg-chip { background: rgba(204,255,0,0.10); border: 1px solid rgba(204,255,0,0.3); } +.card-theme-lime .card-accent { color: #ccff00 !important; } +.card-theme-lime .card-accent2 { color: #ff6600 !important; } +.card-theme-lime .card-stripe { background: linear-gradient(90deg, #ccff00, #88ff00) !important; } +.card-theme-lime .card-muted { color: rgba(255,255,255,0.6) !important; } +.card-theme-lime .card-bg-chip { background: rgba(204,255,0,0.2) !important; border: 1px solid rgba(204,255,0,0.5) !important; } /* ── Theme: CHROME (silver/steel) ── */ .card-theme-chrome { - background: linear-gradient(135deg, #1a1a1a 0%, #2e2e2e 40%, #111 100%); + background: linear-gradient(135deg, #1a1a1a 0%, #2e2e2e 40%, #111 100%) !important; border: 1.5px solid rgba(200,200,200,0.4); box-shadow: 0 0 20px rgba(180,180,180,0.1), inset 0 1px 0 rgba(255,255,255,0.15); - color: #e8e8e8; + color: #e8e8e8 !important; } -.card-theme-chrome .card-accent { color: #c8c8c8; } -.card-theme-chrome .card-accent2 { color: #ff6600; } -.card-theme-chrome .card-stripe { background: linear-gradient(90deg, #888, #ccc, #888); } -.card-theme-chrome .card-muted { color: rgba(232,232,232,0.45); } -.card-theme-chrome .card-bg-chip { background: rgba(200,200,200,0.08); border: 1px solid rgba(200,200,200,0.2); } +.card-theme-chrome .card-accent { color: #c8c8c8 !important; } +.card-theme-chrome .card-accent2 { color: #ff6600 !important; } +.card-theme-chrome .card-stripe { background: linear-gradient(90deg, #888, #ccc, #888) !important; } +.card-theme-chrome .card-muted { color: rgba(232,232,232,0.6) !important; } +.card-theme-chrome .card-bg-chip { background: rgba(200,200,200,0.15) !important; border: 1px solid rgba(200,200,200,0.3) !important; } /* ── Theme: WOODGRAIN ── */ .card-theme-wood { - background: - repeating-linear-gradient( - 90deg, - transparent, - transparent 2px, - rgba(0,0,0,0.03) 2px, - rgba(0,0,0,0.03) 4px - ), - linear-gradient(160deg, #3d2008 0%, #5c3210 30%, #2e1804 60%, #4a2a0e 100%); + background: linear-gradient(160deg, #3d2008 0%, #5c3210 30%, #2e1804 60%, #4a2a0e 100%) !important; border: 1.5px solid rgba(160,100,40,0.6); box-shadow: 0 0 20px rgba(120,70,20,0.2), inset 0 1px 0 rgba(255,200,100,0.1); - color: #f5e6c8; + color: #f5e6c8 !important; } -.card-theme-wood .card-accent { color: #f5c842; } -.card-theme-wood .card-accent2 { color: #ff6600; } -.card-theme-wood .card-stripe { background: linear-gradient(90deg, #8b5e3c, #d4a05a, #8b5e3c); } -.card-theme-wood .card-muted { color: rgba(245,230,200,0.5); } -.card-theme-wood .card-bg-chip { background: rgba(160,100,40,0.15); border: 1px solid rgba(160,100,40,0.4); } +.card-theme-wood .card-accent { color: #f5c842 !important; } +.card-theme-wood .card-accent2 { color: #ff6600 !important; } +.card-theme-wood .card-stripe { background: linear-gradient(90deg, #8b5e3c, #d4a05a, #8b5e3c) !important; } +.card-theme-wood .card-muted { color: rgba(245,230,200,0.65) !important; } +.card-theme-wood .card-bg-chip { background: rgba(160,100,40,0.3) !important; border: 1px solid rgba(160,100,40,0.6) !important; } /* ── Theme: MIDNIGHT BLUE ── */ .card-theme-midnight { - background: linear-gradient(135deg, #020818 0%, #050e2a 60%, #030b1a 100%); + background: linear-gradient(135deg, #020818 0%, #050e2a 60%, #030b1a 100%) !important; border: 1.5px solid rgba(100,160,255,0.4); box-shadow: 0 0 30px rgba(60,120,255,0.15), inset 0 1px 0 rgba(100,160,255,0.08); - color: #d0e4ff; + color: #d0e4ff !important; } -.card-theme-midnight .card-accent { color: #64a0ff; } -.card-theme-midnight .card-accent2 { color: #ccff00; } -.card-theme-midnight .card-stripe { background: linear-gradient(90deg, #3060cc, #64a0ff); } -.card-theme-midnight .card-muted { color: rgba(208,228,255,0.45); } -.card-theme-midnight .card-bg-chip { background: rgba(100,160,255,0.08); border: 1px solid rgba(100,160,255,0.25); } +.card-theme-midnight .card-accent { color: #64a0ff !important; } +.card-theme-midnight .card-accent2 { color: #ccff00 !important; } +.card-theme-midnight .card-stripe { background: linear-gradient(90deg, #3060cc, #64a0ff) !important; } +.card-theme-midnight .card-muted { color: rgba(208,228,255,0.6) !important; } +.card-theme-midnight .card-bg-chip { background: rgba(100,160,255,0.15) !important; border: 1px solid rgba(100,160,255,0.4) !important; } /* ── Theme: SUNSET (orange/pink) ── */ .card-theme-sunset { - background: linear-gradient(135deg, #120006 0%, #1a0808 40%, #0e0810 100%); + background: linear-gradient(135deg, #120006 0%, #1a0808 40%, #0e0810 100%) !important; border: 1.5px solid rgba(255,80,0,0.5); box-shadow: 0 0 30px rgba(255,60,0,0.2), inset 0 1px 0 rgba(255,150,50,0.08); - color: #ffd0a0; + color: #ffd0a0 !important; } -.card-theme-sunset .card-accent { color: #ff6020; } -.card-theme-sunset .card-accent2 { color: #ff0080; } -.card-theme-sunset .card-stripe { background: linear-gradient(90deg, #ff0040, #ff6020, #ffaa00); } -.card-theme-sunset .card-muted { color: rgba(255,208,160,0.5); } -.card-theme-sunset .card-bg-chip { background: rgba(255,80,0,0.10); border: 1px solid rgba(255,80,0,0.3); } +.card-theme-sunset .card-accent { color: #ff6020 !important; } +.card-theme-sunset .card-accent2 { color: #ff0080 !important; } +.card-theme-sunset .card-stripe { background: linear-gradient(90deg, #ff0040, #ff6020, #ffaa00) !important; } +.card-theme-sunset .card-muted { color: rgba(255,208,160,0.65) !important; } +.card-theme-sunset .card-bg-chip { background: rgba(255,80,0,0.2) !important; border: 1px solid rgba(255,80,0,0.5) !important; } -/* ── Print-only card: invisible on screen, appears on print ── */ +/* ── Print-only card: hidden on screen, shown only when printing ── */ .print-only-card { - display: none; + display: none !important; + position: fixed; + top: 0; + left: 0; + z-index: -1; } /* ── Print styles ── */ @media print { - /* Hide absolutely everything */ - * { - visibility: hidden !important; + /* Step 1: hide the entire page */ + html, body { + background: white !important; } - /* Show only the print-only card and all its children */ - .print-only-card, - .print-only-card * { - visibility: visible !important; + body > * { + display: none !important; } - /* Position the card at top-left of the page */ + /* Step 2: show only the print-only-card container */ .print-only-card { display: block !important; position: fixed !important; top: 0 !important; left: 0 !important; + width: 85.6mm !important; + height: 54mm !important; margin: 0 !important; padding: 0 !important; z-index: 99999 !important; + overflow: hidden !important; } - /* Reset page to card size */ - @page { - size: 85.6mm 54mm; - margin: 0; - } - - /* Card at exact print dimensions */ + /* Step 3: size the card to exact credit-card dimensions */ .print-only-card .rider-card { width: 85.6mm !important; height: 54mm !important; border-radius: 4mm !important; page-break-inside: avoid; box-shadow: none !important; + overflow: hidden !important; + } + + /* Reset page margins to zero */ + @page { + size: 85.6mm 54mm; + margin: 0; } /* Kill holographic overlay on print */ .rider-card-holo::after { display: none !important; - visibility: hidden !important; } - /* Kill all animations */ + /* Kill animations */ *, *::before, *::after { animation: none !important; transition: none !important; diff --git a/src/pages/RiderCardPage.tsx b/src/pages/RiderCardPage.tsx index ccbb362..37827fd 100644 --- a/src/pages/RiderCardPage.tsx +++ b/src/pages/RiderCardPage.tsx @@ -875,10 +875,21 @@ export default function RiderCardPage() { {cardType === 'park' && (
-
- Park owners only.{' '} - Park Access Cards should only be issued by the park's Nostr key. - For private parks this is enforced on-chain — anyone can verify the issuer matches the park owner. +
+
+ Park owners only.{' '} + Park Access Cards should only be issued by the park's own Nostr key — the same key that published the park listing on SkateSpots. +
+
+ How verification works:{' '} + The card is a signed message on the Nostr network (like a public post only you could have written). + Anyone can scan the QR, look up the event on any Nostr relay, and see which key signed it — + if that key matches the park's registered identity, the card is genuine. + No central authority needed. +
+
+ Self-issued cards for private parks will show a mismatch warning — the park owner's key won't match. +
)} @@ -1058,11 +1069,21 @@ export default function RiderCardPage() { placeholder="e.g. 2026-12-31" className="bg-black/50 border-gray-700" />
-
-
🔐 Nostr-verified access
- This card is published as a signed Nostr event from your key. - Anyone scanning the QR code can verify the card is genuine and was issued by - the park's Nostr identity. +
+
🔐 How the park verifies it's real
+
+ When you publish this card, it's signed with your Nostr private key and broadcast to relays. + The park's staff can scan the QR on any printed card and instantly see: +
+ +
+ A rider can't fake this card — they'd need your private key to forge your signature. +
)}