index.html's inline <style> hid the cursor on any viewport >= 1024px:
@media (min-width: 1024px) { html, body { overflow: hidden; cursor: none; } }
which is every desktop browser opening the public demo. Descendants inherit
it, so the pointer vanished everywhere except over buttons — those carry
Tailwind's .cursor-pointer, which overrode the inherited value and made the
bug look stranger than it was.
This is the rule the earlier .kiosk scoping missed: src/style.css got gated,
this one did not, so the two disagreed.
Delete it rather than gate it. src/style.css's `.kiosk, .kiosk *` rule already
covers <html> and every descendant with !important, and main.ts applies that
class unless VITE_DEMO_TAG is set — so real machines are unaffected and cursor
hiding now has exactly one owner, the one that knows whether this is a kiosk.
The block here cannot make that call: it is static HTML, and the page CSP
(script-src 'self') forbids an inline script that could read the env.
overflow: hidden stays as it was — untouched on both.
Verified by building both ways: without the tag the built HTML has no cursor
rule, the JS still adds .kiosk and the CSS still carries the !important
hide; with the tag the .kiosk branch is dead-code-eliminated and no
cursor: none survives anywhere.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013A6683cCHnQxFUosx1krY4
55 lines
2.1 KiB
HTML
55 lines
2.1 KiB
HTML
<!doctype html>
|
|
<html lang="en" class="dark">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<link rel="icon" type="image/png" href="/logo.png" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
|
|
<!--
|
|
Content Security Policy:
|
|
- script-src 'self': only our own bundled scripts, no inline/eval (XSS protection)
|
|
- style-src 'self' 'unsafe-inline': Vue injects styles inline
|
|
- connect-src: WebSocket for Nostr relay, HTTPS for Lightning.Pub and exchange rate APIs
|
|
- img-src 'self' data: blob:: QR codes use data URIs
|
|
- default-src 'self': deny everything not explicitly allowed
|
|
- frame-src 'none': no iframes
|
|
- object-src 'none': no plugins
|
|
-->
|
|
<meta
|
|
http-equiv="Content-Security-Policy"
|
|
content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; connect-src 'self' ws: wss: http: https:; img-src 'self' data: blob:; font-src 'self'; frame-src 'none'; object-src 'none'"
|
|
/>
|
|
<title>bitSpire ATM</title>
|
|
<style>
|
|
/* Prevent text selection and context menu on kiosk */
|
|
* {
|
|
user-select: none;
|
|
-webkit-user-select: none;
|
|
touch-action: manipulation;
|
|
-webkit-tap-highlight-color: transparent;
|
|
}
|
|
html,
|
|
body {
|
|
margin: 0;
|
|
padding: 0;
|
|
background: #000;
|
|
}
|
|
/* Kiosk-only: lock overflow. The cursor is NOT hidden here — that is
|
|
src/style.css's `.kiosk` rule, which main.ts applies at runtime unless
|
|
VITE_DEMO_TAG is set. This block can't make that distinction (static
|
|
HTML, and the CSP forbids an inline script to read the env), so a
|
|
`cursor: none` here would also blank the pointer on the public web
|
|
demo, where people drive the kiosk with a mouse. One owner for cursor
|
|
hiding, and it is the one that knows whether this is a real machine. */
|
|
@media (min-width: 1024px) {
|
|
html,
|
|
body {
|
|
overflow: hidden;
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div id="app"></div>
|
|
<script type="module" src="/src/main.ts"></script>
|
|
</body>
|
|
</html>
|