1101 lines
37 KiB
HTML
1101 lines
37 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=1440, height=2560, initial-scale=1">
|
|
<title>Private QR Scanner 7-inch Tablet Screenshots</title>
|
|
<style>
|
|
:root {
|
|
--bg: #f6fbfa;
|
|
--surface: #ffffff;
|
|
--soft: #f2f7ff;
|
|
--ink: #0b1220;
|
|
--muted: #607080;
|
|
--line: #dce8e6;
|
|
--deep: #07111f;
|
|
--navy: #0b1220;
|
|
--teal-900: #123b3f;
|
|
--teal-700: #0f766e;
|
|
--teal-300: #2dd4bf;
|
|
--mint: #dff7f2;
|
|
--success: #10b981;
|
|
--danger: #be123c;
|
|
--warning: #ffc857;
|
|
--white: #f8fafc;
|
|
}
|
|
|
|
* { box-sizing: border-box; }
|
|
|
|
html,
|
|
body {
|
|
width: 1440px;
|
|
height: 2560px;
|
|
margin: 0;
|
|
overflow: hidden;
|
|
font-family: Inter, "DejaVu Sans", Arial, sans-serif;
|
|
background: var(--bg);
|
|
color: var(--ink);
|
|
}
|
|
|
|
.shot {
|
|
position: relative;
|
|
width: 1440px;
|
|
height: 2560px;
|
|
overflow: hidden;
|
|
background:
|
|
radial-gradient(circle at 90% -2%, rgba(45, 212, 191, 0.22), transparent 30%),
|
|
linear-gradient(180deg, #f7fcfb 0%, #eef8f6 100%);
|
|
}
|
|
|
|
.shot.dark {
|
|
background:
|
|
radial-gradient(circle at 74% 16%, rgba(45, 212, 191, 0.22), transparent 28%),
|
|
linear-gradient(180deg, #07111f 0%, #103840 52%, #07111f 100%);
|
|
color: var(--white);
|
|
}
|
|
|
|
.status {
|
|
position: absolute;
|
|
z-index: 20;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
height: 112px;
|
|
padding: 30px 64px 0;
|
|
font-size: 30px;
|
|
font-weight: 800;
|
|
color: inherit;
|
|
}
|
|
|
|
.system-icons {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 14px;
|
|
}
|
|
|
|
.signal {
|
|
display: flex;
|
|
align-items: end;
|
|
gap: 5px;
|
|
height: 28px;
|
|
}
|
|
|
|
.signal span {
|
|
width: 7px;
|
|
border-radius: 999px;
|
|
background: currentColor;
|
|
}
|
|
|
|
.signal span:nth-child(1) { height: 10px; opacity: .68; }
|
|
.signal span:nth-child(2) { height: 15px; opacity: .78; }
|
|
.signal span:nth-child(3) { height: 21px; opacity: .9; }
|
|
.signal span:nth-child(4) { height: 28px; }
|
|
|
|
.battery {
|
|
width: 54px;
|
|
height: 26px;
|
|
border: 3px solid currentColor;
|
|
border-radius: 8px;
|
|
padding: 4px;
|
|
}
|
|
|
|
.battery::after {
|
|
content: "";
|
|
display: block;
|
|
width: 34px;
|
|
height: 12px;
|
|
border-radius: 4px;
|
|
background: var(--teal-300);
|
|
}
|
|
|
|
.content {
|
|
position: relative;
|
|
z-index: 2;
|
|
padding: 138px 72px 172px;
|
|
}
|
|
|
|
.app-head {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 24px;
|
|
margin-bottom: 34px;
|
|
}
|
|
|
|
.app-icon {
|
|
width: 104px;
|
|
height: 104px;
|
|
border-radius: 26px;
|
|
box-shadow: 0 18px 36px rgba(15, 118, 110, .18);
|
|
}
|
|
|
|
.app-title {
|
|
margin: 0;
|
|
color: var(--ink);
|
|
font-size: 46px;
|
|
line-height: 1.06;
|
|
font-weight: 900;
|
|
letter-spacing: 0;
|
|
}
|
|
|
|
.dark .app-title { color: var(--white); }
|
|
|
|
.app-subtitle {
|
|
margin-top: 7px;
|
|
color: var(--muted);
|
|
font-size: 26px;
|
|
font-weight: 750;
|
|
}
|
|
|
|
.dark .app-subtitle { color: var(--mint); }
|
|
|
|
.hero {
|
|
margin-bottom: 34px;
|
|
padding: 38px;
|
|
border-radius: 42px;
|
|
background:
|
|
radial-gradient(circle at 88% 22%, rgba(45, 212, 191, .18), transparent 34%),
|
|
linear-gradient(145deg, #0b1220, #123b3f);
|
|
color: var(--white);
|
|
box-shadow: 0 28px 58px rgba(7, 17, 31, .18);
|
|
overflow: hidden;
|
|
}
|
|
|
|
.hero h1 {
|
|
margin: 0;
|
|
max-width: 930px;
|
|
font-size: 64px;
|
|
line-height: 1.04;
|
|
font-weight: 900;
|
|
letter-spacing: 0;
|
|
}
|
|
|
|
.hero p {
|
|
margin: 20px 0 0;
|
|
max-width: 1000px;
|
|
color: #cbe7e3;
|
|
font-size: 33px;
|
|
line-height: 1.25;
|
|
font-weight: 650;
|
|
}
|
|
|
|
.chips {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 16px;
|
|
margin-top: 30px;
|
|
}
|
|
|
|
.chip {
|
|
min-height: 66px;
|
|
padding: 17px 24px;
|
|
border-radius: 22px;
|
|
background: rgba(223, 247, 242, .12);
|
|
color: var(--mint);
|
|
font-size: 26px;
|
|
font-weight: 900;
|
|
}
|
|
|
|
.panel {
|
|
padding: 32px;
|
|
border-radius: 36px;
|
|
background: var(--surface);
|
|
box-shadow: 0 20px 42px rgba(15, 23, 42, .08);
|
|
}
|
|
|
|
.two-col {
|
|
display: grid;
|
|
grid-template-columns: minmax(0, 1.08fr) minmax(0, .92fr);
|
|
gap: 24px;
|
|
align-items: stretch;
|
|
}
|
|
|
|
.section-title {
|
|
margin: 0 0 22px;
|
|
color: #132032;
|
|
font-size: 42px;
|
|
line-height: 1.08;
|
|
font-weight: 900;
|
|
}
|
|
|
|
.screen-grid {
|
|
display: grid;
|
|
gap: 18px;
|
|
}
|
|
|
|
.row-card {
|
|
display: grid;
|
|
grid-template-columns: 76px 1fr;
|
|
gap: 20px;
|
|
align-items: center;
|
|
padding: 24px;
|
|
border-radius: 30px;
|
|
background: var(--surface);
|
|
box-shadow: 0 18px 36px rgba(15, 23, 42, .06);
|
|
}
|
|
|
|
.row-icon {
|
|
display: grid;
|
|
place-items: center;
|
|
width: 76px;
|
|
height: 76px;
|
|
border-radius: 22px;
|
|
background: rgba(223, 247, 242, .72);
|
|
color: var(--teal-700);
|
|
}
|
|
|
|
.row-icon svg { width: 38px; height: 38px; }
|
|
|
|
.row-card strong {
|
|
display: block;
|
|
color: #132032;
|
|
font-size: 31px;
|
|
line-height: 1.12;
|
|
font-weight: 900;
|
|
}
|
|
|
|
.row-card span {
|
|
display: block;
|
|
margin-top: 7px;
|
|
color: var(--muted);
|
|
font-size: 25px;
|
|
line-height: 1.25;
|
|
font-weight: 680;
|
|
}
|
|
|
|
.nav {
|
|
position: absolute;
|
|
z-index: 30;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
display: grid;
|
|
grid-template-columns: repeat(3, 1fr);
|
|
height: 138px;
|
|
padding: 14px 124px 22px;
|
|
background: #fcfffe;
|
|
color: #607080;
|
|
border-top: 1px solid rgba(15, 23, 42, .08);
|
|
}
|
|
|
|
.nav-item {
|
|
display: grid;
|
|
place-items: center;
|
|
align-content: center;
|
|
gap: 8px;
|
|
font-size: 25px;
|
|
font-weight: 780;
|
|
}
|
|
|
|
.nav-item svg {
|
|
width: 34px;
|
|
height: 34px;
|
|
}
|
|
|
|
.nav-item.active { color: var(--teal-700); }
|
|
|
|
.camera-bg {
|
|
position: absolute;
|
|
inset: 0;
|
|
background:
|
|
linear-gradient(90deg, rgba(45, 212, 191, .09) 1px, transparent 1px) 0 0 / 84px 84px,
|
|
linear-gradient(0deg, rgba(45, 212, 191, .08) 1px, transparent 1px) 0 0 / 84px 84px,
|
|
radial-gradient(circle at 52% 38%, rgba(45, 212, 191, .18), transparent 24%),
|
|
linear-gradient(150deg, rgba(8, 17, 31, .16), rgba(8, 17, 31, .82));
|
|
}
|
|
|
|
.camera-bg::before,
|
|
.camera-bg::after {
|
|
content: "";
|
|
position: absolute;
|
|
left: -160px;
|
|
right: -160px;
|
|
pointer-events: none;
|
|
}
|
|
|
|
.camera-bg::before {
|
|
top: 460px;
|
|
height: 520px;
|
|
background: rgba(223, 247, 242, .10);
|
|
clip-path: polygon(0 60%, 18% 35%, 38% 47%, 60% 30%, 80% 42%, 100% 18%, 100% 100%, 0 100%);
|
|
}
|
|
|
|
.camera-bg::after {
|
|
top: 820px;
|
|
height: 620px;
|
|
background: rgba(2, 6, 23, .60);
|
|
clip-path: polygon(0 19%, 19% 8%, 38% 27%, 56% 17%, 75% 33%, 100% 14%, 100% 100%, 0 100%);
|
|
}
|
|
|
|
.top-chip {
|
|
position: absolute;
|
|
z-index: 5;
|
|
top: 146px;
|
|
left: 358px;
|
|
right: 358px;
|
|
min-height: 68px;
|
|
padding: 15px 24px;
|
|
border-radius: 24px;
|
|
background: rgba(0, 0, 0, .52);
|
|
text-align: center;
|
|
color: var(--white);
|
|
font-size: 30px;
|
|
font-weight: 900;
|
|
}
|
|
|
|
.gallery {
|
|
position: absolute;
|
|
z-index: 5;
|
|
right: 72px;
|
|
top: 142px;
|
|
display: grid;
|
|
place-items: center;
|
|
width: 78px;
|
|
height: 78px;
|
|
border-radius: 22px;
|
|
border: 1px solid rgba(248, 250, 252, .22);
|
|
background: rgba(0, 0, 0, .38);
|
|
}
|
|
|
|
.gallery svg { width: 40px; height: 40px; }
|
|
|
|
.aim {
|
|
position: absolute;
|
|
z-index: 2;
|
|
top: 520px;
|
|
left: 202px;
|
|
width: 1036px;
|
|
height: 620px;
|
|
border-radius: 68px;
|
|
background: rgba(45, 212, 191, .06);
|
|
border: 9px solid rgba(45, 212, 191, .95);
|
|
box-shadow: 0 0 92px rgba(45, 212, 191, .30), inset 0 0 0 2px rgba(223, 247, 242, .20);
|
|
}
|
|
|
|
.scan-line {
|
|
position: absolute;
|
|
z-index: 7;
|
|
top: 820px;
|
|
left: 288px;
|
|
right: 288px;
|
|
height: 9px;
|
|
border-radius: 999px;
|
|
background: linear-gradient(90deg, transparent, var(--teal-300), transparent);
|
|
box-shadow: 0 0 42px rgba(45, 212, 191, .92);
|
|
}
|
|
|
|
.hint {
|
|
position: absolute;
|
|
z-index: 7;
|
|
left: 382px;
|
|
right: 382px;
|
|
bottom: 790px;
|
|
padding: 18px 26px;
|
|
border-radius: 28px;
|
|
background: rgba(0, 0, 0, .45);
|
|
color: var(--white);
|
|
font-size: 31px;
|
|
font-weight: 850;
|
|
text-align: center;
|
|
}
|
|
|
|
.qr-target {
|
|
position: absolute;
|
|
z-index: 4;
|
|
top: 640px;
|
|
left: 482px;
|
|
width: 476px;
|
|
height: 344px;
|
|
border-radius: 32px;
|
|
padding: 32px;
|
|
background: rgba(248, 250, 252, .97);
|
|
box-shadow: 0 34px 80px rgba(2, 6, 23, .36);
|
|
display: grid;
|
|
grid-template-columns: repeat(7, 1fr);
|
|
grid-template-rows: repeat(5, 1fr);
|
|
gap: 15px;
|
|
}
|
|
|
|
.qr-target span,
|
|
.mini-qr span {
|
|
border-radius: 6px;
|
|
background: var(--deep);
|
|
}
|
|
|
|
.qr-target span:nth-child(4),
|
|
.qr-target span:nth-child(10),
|
|
.qr-target span:nth-child(18),
|
|
.qr-target span:nth-child(25),
|
|
.qr-target span:nth-child(32),
|
|
.mini-qr span:nth-child(5n+3),
|
|
.mini-qr span:nth-child(7),
|
|
.mini-qr span:nth-child(18) {
|
|
background: var(--teal-300);
|
|
}
|
|
|
|
.detect-box {
|
|
position: absolute;
|
|
z-index: 5;
|
|
top: 622px;
|
|
left: 456px;
|
|
width: 528px;
|
|
height: 386px;
|
|
border: 6px solid #4ae3a3;
|
|
border-radius: 42px;
|
|
}
|
|
|
|
.sheet {
|
|
position: absolute;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 138px;
|
|
z-index: 8;
|
|
min-height: 690px;
|
|
padding: 28px 74px 48px;
|
|
border-radius: 52px 52px 0 0;
|
|
background: var(--white);
|
|
color: var(--ink);
|
|
box-shadow: 0 -42px 92px rgba(2, 6, 23, .35);
|
|
}
|
|
|
|
.handle {
|
|
width: 116px;
|
|
height: 10px;
|
|
margin: 0 auto 32px;
|
|
border-radius: 999px;
|
|
background: #cbd5e1;
|
|
}
|
|
|
|
.result-card {
|
|
padding: 34px;
|
|
border-radius: 34px;
|
|
background: var(--soft);
|
|
}
|
|
|
|
.result-title {
|
|
display: flex;
|
|
gap: 16px;
|
|
align-items: center;
|
|
margin: 0 0 28px;
|
|
color: var(--ink);
|
|
font-size: 40px;
|
|
font-weight: 900;
|
|
}
|
|
|
|
.badge {
|
|
padding: 10px 17px;
|
|
border-radius: 999px;
|
|
background: var(--mint);
|
|
color: var(--teal-700);
|
|
font-size: 22px;
|
|
font-weight: 900;
|
|
}
|
|
|
|
.field-label {
|
|
margin-top: 22px;
|
|
color: #526879;
|
|
font-size: 23px;
|
|
font-weight: 850;
|
|
}
|
|
|
|
.field-value {
|
|
margin-top: 8px;
|
|
color: #1d4ed8;
|
|
font-size: 30px;
|
|
line-height: 1.28;
|
|
font-weight: 760;
|
|
text-decoration: underline;
|
|
}
|
|
|
|
.safe-pill {
|
|
display: flex;
|
|
gap: 14px;
|
|
align-items: center;
|
|
margin-top: 26px;
|
|
padding: 20px 22px;
|
|
border-radius: 24px;
|
|
background: #ecfdf5;
|
|
color: #065f46;
|
|
font-size: 27px;
|
|
font-weight: 850;
|
|
}
|
|
|
|
.safe-pill svg { width: 34px; height: 34px; flex: 0 0 auto; }
|
|
|
|
.actions {
|
|
display: flex;
|
|
gap: 18px;
|
|
margin-top: 30px;
|
|
}
|
|
|
|
.action {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 12px;
|
|
min-height: 78px;
|
|
padding: 0 28px;
|
|
border-radius: 24px;
|
|
background: var(--surface);
|
|
color: var(--ink);
|
|
font-size: 27px;
|
|
font-weight: 900;
|
|
box-shadow: 0 16px 32px rgba(15, 23, 42, .08);
|
|
}
|
|
|
|
.action.primary {
|
|
margin-left: auto;
|
|
min-width: 300px;
|
|
background: var(--teal-700);
|
|
color: var(--white);
|
|
}
|
|
|
|
.action svg { width: 30px; height: 30px; }
|
|
|
|
.batch-panel {
|
|
position: absolute;
|
|
z-index: 8;
|
|
left: 44px;
|
|
right: 44px;
|
|
bottom: 158px;
|
|
padding: 28px;
|
|
border-radius: 36px;
|
|
background: rgba(2, 6, 23, .62);
|
|
color: var(--white);
|
|
box-shadow: 0 -22px 70px rgba(2, 6, 23, .38);
|
|
}
|
|
|
|
.batch-title {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 18px;
|
|
font-size: 34px;
|
|
font-weight: 900;
|
|
}
|
|
|
|
.share-batch {
|
|
padding: 12px 18px;
|
|
border-radius: 999px;
|
|
background: var(--mint);
|
|
color: var(--teal-700);
|
|
font-size: 22px;
|
|
font-weight: 900;
|
|
}
|
|
|
|
.capture {
|
|
display: grid;
|
|
grid-template-columns: 1fr auto;
|
|
gap: 18px;
|
|
align-items: center;
|
|
padding: 18px 0;
|
|
border-top: 1px solid rgba(223, 247, 242, .15);
|
|
}
|
|
|
|
.capture:first-of-type { border-top: 0; }
|
|
.capture strong { display: block; font-size: 27px; line-height: 1.2; }
|
|
.capture span { display: block; margin-top: 5px; color: rgba(223, 247, 242, .72); font-size: 22px; font-weight: 750; }
|
|
|
|
.copy-btn {
|
|
display: grid;
|
|
place-items: center;
|
|
width: 58px;
|
|
height: 58px;
|
|
border-radius: 18px;
|
|
background: rgba(223, 247, 242, .12);
|
|
color: var(--white);
|
|
}
|
|
|
|
.copy-btn svg { width: 29px; height: 29px; }
|
|
|
|
.ticket {
|
|
position: absolute;
|
|
z-index: 4;
|
|
top: 660px;
|
|
left: 344px;
|
|
width: 752px;
|
|
height: 314px;
|
|
border-radius: 38px;
|
|
padding: 38px;
|
|
background:
|
|
radial-gradient(circle at 0 50%, transparent 34px, var(--white) 35px),
|
|
radial-gradient(circle at 100% 50%, transparent 34px, var(--white) 35px),
|
|
linear-gradient(90deg, var(--white), #e9fffb);
|
|
box-shadow: 0 34px 80px rgba(2, 6, 23, .36);
|
|
color: var(--navy);
|
|
}
|
|
|
|
.ticket-top {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 28px;
|
|
font-size: 38px;
|
|
font-weight: 900;
|
|
}
|
|
|
|
.valid {
|
|
padding: 10px 15px;
|
|
border-radius: 999px;
|
|
background: var(--mint);
|
|
color: var(--teal-700);
|
|
font-size: 20px;
|
|
font-weight: 900;
|
|
}
|
|
|
|
.barcode {
|
|
display: grid;
|
|
grid-template-columns: repeat(18, 1fr);
|
|
gap: 9px;
|
|
height: 98px;
|
|
margin-bottom: 24px;
|
|
}
|
|
|
|
.barcode span {
|
|
border-radius: 4px;
|
|
background: var(--navy);
|
|
}
|
|
|
|
.barcode span:nth-child(3n),
|
|
.barcode span:nth-child(7),
|
|
.barcode span:nth-child(16) {
|
|
background: var(--teal-300);
|
|
}
|
|
|
|
.ticket-id {
|
|
color: #526879;
|
|
font-size: 25px;
|
|
font-weight: 850;
|
|
}
|
|
|
|
.contact-card {
|
|
padding: 34px;
|
|
border-radius: 38px;
|
|
background: linear-gradient(135deg, #081c3b, #0f2e58, #134b73);
|
|
color: var(--white);
|
|
box-shadow: 0 22px 44px rgba(15, 23, 42, .16);
|
|
}
|
|
|
|
.contact-top {
|
|
display: flex;
|
|
gap: 22px;
|
|
align-items: center;
|
|
margin-bottom: 28px;
|
|
}
|
|
|
|
.initials {
|
|
display: grid;
|
|
place-items: center;
|
|
width: 92px;
|
|
height: 92px;
|
|
border-radius: 26px;
|
|
background: rgba(122, 247, 207, .18);
|
|
color: #7af7cf;
|
|
font-size: 38px;
|
|
font-weight: 900;
|
|
}
|
|
|
|
.person h2 {
|
|
margin: 0;
|
|
font-size: 43px;
|
|
line-height: 1.05;
|
|
font-weight: 900;
|
|
}
|
|
|
|
.person p {
|
|
margin: 9px 0 0;
|
|
color: #c7d6e8;
|
|
font-size: 27px;
|
|
font-weight: 720;
|
|
}
|
|
|
|
.contact-lines {
|
|
display: grid;
|
|
gap: 17px;
|
|
}
|
|
|
|
.contact-line {
|
|
display: grid;
|
|
grid-template-columns: 128px 1fr;
|
|
gap: 22px;
|
|
font-size: 28px;
|
|
line-height: 1.25;
|
|
font-weight: 760;
|
|
}
|
|
|
|
.contact-line span:first-child {
|
|
color: #c7d6e8;
|
|
font-size: 21px;
|
|
font-weight: 850;
|
|
}
|
|
|
|
.wifi-card {
|
|
padding: 38px;
|
|
border-radius: 38px;
|
|
background: var(--surface);
|
|
box-shadow: 0 20px 42px rgba(15, 23, 42, .08);
|
|
}
|
|
|
|
.wifi-head {
|
|
display: flex;
|
|
gap: 24px;
|
|
align-items: center;
|
|
margin-bottom: 30px;
|
|
}
|
|
|
|
.wifi-icon {
|
|
display: grid;
|
|
place-items: center;
|
|
width: 96px;
|
|
height: 96px;
|
|
border-radius: 28px;
|
|
background: var(--mint);
|
|
color: var(--teal-700);
|
|
}
|
|
|
|
.wifi-icon svg { width: 54px; height: 54px; }
|
|
.wifi-head h2 { margin: 0; font-size: 48px; font-weight: 900; }
|
|
.wifi-head p { margin: 6px 0 0; color: var(--muted); font-size: 27px; font-weight: 750; }
|
|
|
|
.wifi-field {
|
|
padding: 24px 0;
|
|
border-top: 1px solid var(--line);
|
|
}
|
|
|
|
.wifi-field label {
|
|
display: block;
|
|
color: var(--muted);
|
|
font-size: 22px;
|
|
font-weight: 850;
|
|
}
|
|
|
|
.wifi-field div {
|
|
margin-top: 8px;
|
|
color: var(--ink);
|
|
font-size: 34px;
|
|
font-weight: 900;
|
|
}
|
|
|
|
.dialog-shade {
|
|
position: absolute;
|
|
inset: 0;
|
|
z-index: 35;
|
|
background: rgba(2, 6, 23, .44);
|
|
}
|
|
|
|
.dialog {
|
|
position: absolute;
|
|
z-index: 36;
|
|
left: 110px;
|
|
right: 110px;
|
|
top: 900px;
|
|
padding: 38px;
|
|
border-radius: 36px;
|
|
background: var(--surface);
|
|
color: var(--ink);
|
|
box-shadow: 0 34px 90px rgba(2, 6, 23, .42);
|
|
}
|
|
|
|
.dialog h2 {
|
|
margin: 0 0 18px;
|
|
font-size: 42px;
|
|
font-weight: 900;
|
|
}
|
|
|
|
.dialog p {
|
|
margin: 0;
|
|
color: var(--muted);
|
|
font-size: 30px;
|
|
line-height: 1.32;
|
|
font-weight: 680;
|
|
}
|
|
|
|
.dialog-actions {
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
gap: 18px;
|
|
margin-top: 34px;
|
|
}
|
|
|
|
.dialog-btn {
|
|
padding: 18px 26px;
|
|
border-radius: 22px;
|
|
color: var(--teal-700);
|
|
font-size: 28px;
|
|
font-weight: 900;
|
|
}
|
|
|
|
.dialog-btn.primary {
|
|
background: var(--teal-700);
|
|
color: var(--white);
|
|
}
|
|
|
|
.photo-preview {
|
|
position: relative;
|
|
height: 780px;
|
|
border-radius: 44px;
|
|
background: linear-gradient(150deg, #0b1220, #155e63);
|
|
box-shadow: 0 34px 80px rgba(2, 6, 23, .30);
|
|
overflow: hidden;
|
|
}
|
|
|
|
.paper {
|
|
position: absolute;
|
|
left: 220px;
|
|
top: 185px;
|
|
width: 700px;
|
|
height: 440px;
|
|
border-radius: 38px;
|
|
background: var(--white);
|
|
transform: rotate(-4deg);
|
|
box-shadow: 0 30px 72px rgba(2, 6, 23, .38);
|
|
}
|
|
|
|
.paper h2 {
|
|
margin: 46px 46px 20px;
|
|
color: var(--ink);
|
|
font-size: 42px;
|
|
font-weight: 900;
|
|
}
|
|
|
|
.paper-bars {
|
|
position: absolute;
|
|
left: 52px;
|
|
right: 52px;
|
|
bottom: 70px;
|
|
display: grid;
|
|
gap: 18px;
|
|
}
|
|
|
|
.paper-bars span {
|
|
height: 22px;
|
|
border-radius: 999px;
|
|
background: #cbd5e1;
|
|
}
|
|
|
|
.paper-bars span:nth-child(2) { width: 72%; }
|
|
|
|
.mini-qr {
|
|
position: absolute;
|
|
display: grid;
|
|
grid-template-columns: repeat(5, 1fr);
|
|
gap: 8px;
|
|
width: 200px;
|
|
height: 164px;
|
|
padding: 18px;
|
|
border-radius: 20px;
|
|
background: #edf8f6;
|
|
}
|
|
|
|
.paper .mini-qr {
|
|
left: 410px;
|
|
top: 128px;
|
|
transform: rotate(-3deg);
|
|
}
|
|
|
|
.image-dialog {
|
|
position: absolute;
|
|
z-index: 9;
|
|
left: 72px;
|
|
right: 72px;
|
|
bottom: 160px;
|
|
padding: 36px;
|
|
border-radius: 42px;
|
|
background: var(--surface);
|
|
color: var(--ink);
|
|
box-shadow: 0 -24px 82px rgba(2, 6, 23, .35);
|
|
}
|
|
|
|
.candidate {
|
|
display: grid;
|
|
grid-template-columns: 68px 1fr;
|
|
gap: 18px;
|
|
align-items: center;
|
|
padding: 22px;
|
|
border-radius: 28px;
|
|
background: var(--bg);
|
|
margin-top: 16px;
|
|
border: 2px solid transparent;
|
|
}
|
|
|
|
.candidate.active {
|
|
border-color: var(--teal-300);
|
|
background: #ecfdf5;
|
|
}
|
|
|
|
.candidate-icon {
|
|
display: grid;
|
|
place-items: center;
|
|
width: 68px;
|
|
height: 68px;
|
|
border-radius: 20px;
|
|
background: var(--mint);
|
|
color: var(--teal-700);
|
|
}
|
|
|
|
.candidate-icon svg { width: 36px; height: 36px; }
|
|
.candidate strong { display: block; font-size: 30px; font-weight: 900; }
|
|
.candidate span { display: block; margin-top: 5px; color: var(--muted); font-size: 25px; font-weight: 700; }
|
|
|
|
.setting {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
min-height: 106px;
|
|
border-top: 1px solid var(--line);
|
|
font-size: 32px;
|
|
font-weight: 900;
|
|
}
|
|
|
|
.setting:first-child { border-top: 0; }
|
|
|
|
.switch {
|
|
position: relative;
|
|
width: 88px;
|
|
height: 50px;
|
|
border-radius: 999px;
|
|
background: var(--teal-700);
|
|
}
|
|
|
|
.switch::after {
|
|
content: "";
|
|
position: absolute;
|
|
right: 6px;
|
|
top: 6px;
|
|
width: 38px;
|
|
height: 38px;
|
|
border-radius: 50%;
|
|
background: var(--surface);
|
|
box-shadow: 0 5px 10px rgba(15, 23, 42, .22);
|
|
}
|
|
|
|
.option {
|
|
display: grid;
|
|
grid-template-columns: 76px 1fr;
|
|
gap: 20px;
|
|
align-items: center;
|
|
padding: 24px;
|
|
border-radius: 30px;
|
|
background: var(--bg);
|
|
margin-top: 16px;
|
|
border: 2px solid transparent;
|
|
}
|
|
|
|
.option.active {
|
|
border-color: var(--teal-300);
|
|
background: #ecfdf5;
|
|
}
|
|
|
|
.check {
|
|
display: grid;
|
|
place-items: center;
|
|
width: 76px;
|
|
height: 76px;
|
|
border-radius: 22px;
|
|
background: var(--mint);
|
|
color: var(--teal-700);
|
|
font-size: 38px;
|
|
font-weight: 900;
|
|
}
|
|
|
|
.option strong { display: block; font-size: 30px; font-weight: 900; }
|
|
.option span { display: block; margin-top: 6px; color: var(--muted); font-size: 24px; line-height: 1.23; font-weight: 700; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<main id="shot" class="shot"></main>
|
|
<script>
|
|
const icon = "./private-qr-scanner-icon.svg";
|
|
const params = new URLSearchParams(location.search);
|
|
const screen = Number(params.get("screen") || "1");
|
|
const shot = document.getElementById("shot");
|
|
|
|
const svg = {
|
|
scan: '<svg viewBox="0 0 24 24" fill="none"><path d="M5 7V5H9M15 5H19V9M19 15V19H15M9 19H5V15" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"/><path d="M8 12H16" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"/></svg>',
|
|
history: '<svg viewBox="0 0 24 24" fill="none"><path d="M5 5H19V19H5V5Z" stroke="currentColor" stroke-width="2"/><path d="M8 9H16M8 13H16M8 17H13" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>',
|
|
settings: '<svg viewBox="0 0 24 24" fill="none"><path d="M12 15.5C13.9 15.5 15.5 13.9 15.5 12C15.5 10.1 13.9 8.5 12 8.5C10.1 8.5 8.5 10.1 8.5 12C8.5 13.9 10.1 15.5 12 15.5Z" stroke="currentColor" stroke-width="2"/><path d="M19 12H21M3 12H5M12 3V5M12 19V21M17 7L18.4 5.6M5.6 18.4L7 17M17 17L18.4 18.4M5.6 5.6L7 7" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>',
|
|
gallery: '<svg viewBox="0 0 24 24" fill="none"><path d="M4 5H20V19H4V5Z" stroke="white" stroke-width="2"/><path d="M7 16L10.6 12.4L13 14.8L15 12.8L19 16.8" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>',
|
|
copy: '<svg viewBox="0 0 24 24" fill="none"><path d="M8 8H6C5.4 8 5 8.4 5 9V19C5 19.6 5.4 20 6 20H16C16.6 20 17 19.6 17 19V17" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><path d="M8 4H18C18.6 4 19 4.4 19 5V15C19 15.6 18.6 16 18 16H8C7.4 16 7 15.6 7 15V5C7 4.4 7.4 4 8 4Z" stroke="currentColor" stroke-width="2"/></svg>',
|
|
share: '<svg viewBox="0 0 24 24" fill="none"><path d="M18 8C19.7 8 21 6.7 21 5C21 3.3 19.7 2 18 2C16.3 2 15 3.3 15 5C15 5.2 15 5.4 15.1 5.6L8.6 9.2C8.1 8.5 7.1 8 6 8C4.3 8 3 9.3 3 11C3 12.7 4.3 14 6 14C7.1 14 8.1 13.5 8.6 12.8L15.1 16.4C15 16.6 15 16.8 15 17C15 18.7 16.3 20 18 20C19.7 20 21 18.7 21 17C21 15.3 19.7 14 18 14C16.9 14 15.9 14.5 15.4 15.2L8.9 11.6C9 11.4 9 11.2 9 11C9 10.8 9 10.6 8.9 10.4L15.4 6.8C15.9 7.5 16.9 8 18 8Z" stroke="currentColor" stroke-width="2"/></svg>',
|
|
shield: '<svg viewBox="0 0 24 24" fill="none"><path d="M12 3L19 6V11C19 15.7 16.1 19.9 12 21.8C7.9 19.9 5 15.7 5 11V6L12 3Z" fill="#10B981"/><path d="M9 12L11.1 14.1L15.5 9.7" stroke="white" stroke-width="2.2" stroke-linecap="round"/></svg>',
|
|
wifi: '<svg viewBox="0 0 24 24" fill="none"><path d="M5 12.5C8.9 8.7 15.1 8.7 19 12.5M8.2 15.4C10.3 13.4 13.7 13.4 15.8 15.4" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"/><path d="M12 19H12.02" stroke="currentColor" stroke-width="3.2" stroke-linecap="round"/></svg>',
|
|
mail: '<svg viewBox="0 0 24 24" fill="none"><path d="M4 8L12 13L20 8" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/><path d="M5 6H19C19.6 6 20 6.4 20 7V17C20 17.6 19.6 18 19 18H5C4.4 18 4 17.6 4 17V7C4 6.4 4.4 6 5 6Z" stroke="currentColor" stroke-width="2.2"/></svg>',
|
|
link: '<svg viewBox="0 0 24 24" fill="none"><path d="M10 13A5 5 0 0 0 17.1 13L20 10.1A5 5 0 0 0 12.9 3L11.8 4.1" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><path d="M14 11A5 5 0 0 0 6.9 11L4 13.9A5 5 0 0 0 11.1 21L12.2 19.9" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>',
|
|
calendar: '<svg viewBox="0 0 24 24" fill="none"><path d="M7 4V7M17 4V7M5 9H19M6 6H18C18.6 6 19 6.4 19 7V19C19 19.6 18.6 20 18 20H6C5.4 20 5 19.6 5 19V7C5 6.4 5.4 6 6 6Z" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>',
|
|
contact: '<svg viewBox="0 0 24 24" fill="none"><path d="M12 12C14.2 12 16 10.2 16 8C16 5.8 14.2 4 12 4C9.8 4 8 5.8 8 8C8 10.2 9.8 12 12 12Z" stroke="currentColor" stroke-width="2"/><path d="M4 21C4.7 17.6 7.8 15 12 15C16.2 15 19.3 17.6 20 21" stroke="currentColor" stroke-width="2" stroke-linecap="round"/><path d="M19 5V11M16 8H22" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>',
|
|
warn: '<svg viewBox="0 0 24 24" fill="none"><path d="M12 3L22 20H2L12 3Z" fill="#F43F5E"/><path d="M12 9V13M12 17H12.02" stroke="white" stroke-width="2.3" stroke-linecap="round"/></svg>'
|
|
};
|
|
|
|
function status() {
|
|
return '<div class="status"><div>9:41</div><div class="system-icons"><div class="signal"><span></span><span></span><span></span><span></span></div><div class="battery"></div></div></div>';
|
|
}
|
|
|
|
function nav(active = "scan") {
|
|
return `<nav class="nav">
|
|
<div class="nav-item ${active === "scan" ? "active" : ""}">${svg.scan}Scan</div>
|
|
<div class="nav-item ${active === "history" ? "active" : ""}">${svg.history}History</div>
|
|
<div class="nav-item ${active === "settings" ? "active" : ""}">${svg.settings}Settings</div>
|
|
</nav>`;
|
|
}
|
|
|
|
function header(subtitle) {
|
|
return `<header class="app-head"><img class="app-icon" src="${icon}" alt=""><div><h1 class="app-title">Private QR Scanner</h1><div class="app-subtitle">${subtitle}</div></div></header>`;
|
|
}
|
|
|
|
function qrCells(count = 35) {
|
|
return Array.from({ length: count }, () => "<span></span>").join("");
|
|
}
|
|
|
|
function row(icon, title, body) {
|
|
return `<article class="row-card"><div class="row-icon">${icon}</div><div><strong>${title}</strong><span>${body}</span></div></article>`;
|
|
}
|
|
|
|
function scanScreen() {
|
|
shot.className = "shot dark";
|
|
return `${status()}<div class="camera-bg"></div><div class="top-chip">Everyday personal use</div><div class="gallery">${svg.gallery}</div><div class="aim"></div><div class="qr-target">${qrCells()}</div><div class="detect-box"></div><div class="scan-line"></div><div class="hint">Readable code detected.</div>
|
|
<section class="sheet"><div class="handle"></div><div class="result-card"><h1 class="result-title">URL <span class="badge">Local check</span></h1><div class="field-label">Link</div><div class="field-value">https://example.org/menu</div><div class="field-label">Risk score</div><div class="field-value" style="color:#0b1220;text-decoration:none">0</div><div class="safe-pill">${svg.shield}Checked on device before opening</div></div><div class="actions"><div class="action">${svg.copy}Copy</div><div class="action">${svg.share}Share</div><div class="action primary">Open</div></div></section>${nav("scan")}`;
|
|
}
|
|
|
|
function historyScreen() {
|
|
shot.className = "shot";
|
|
return `${status()}<section class="content">${header("Optional history stays on your device")}<section class="hero"><h1>Review past scans locally</h1><p>Search, export, or delete saved scans whenever you choose.</p><div class="chips"><div class="chip">No ads</div><div class="chip">No tracking</div><div class="chip">No account</div></div></section><div class="two-col"><section><h2 class="section-title">History</h2><div class="screen-grid">${row(svg.link, "URL", "https://example.org/menu")}${row(svg.mail, "Email", "support@example.org")}${row(svg.wifi, "Wi-Fi", "SSID: Guest Network")}</div></section><section><h2 class="section-title">Local controls</h2><div class="panel"><div class="setting"><span>Save history (local)</span><span class="switch"></span></div><div class="setting"><span>Security warnings</span><span class="switch"></span></div><div class="setting"><span>Scan feedback</span><span class="switch"></span></div></div><div style="height:20px"></div><div class="actions"><div class="action">TXT</div><div class="action">CSV</div><div class="action">JSON</div></div></section></div></section>${nav("history")}`;
|
|
}
|
|
|
|
function eventScreen() {
|
|
shot.className = "shot dark";
|
|
return `${status()}<div class="camera-bg"></div><div class="top-chip">Event & ticketing</div><div class="gallery" style="right:172px">${svg.gallery}</div><div class="gallery">${svg.scan}</div><div class="aim"></div><section class="ticket"><div class="ticket-top"><div>Entry Pass</div><div class="valid">VALID</div></div><div class="barcode">${qrCells(18)}</div><div class="ticket-id">ID: EVT-24-0187</div></section><div class="detect-box" style="left:318px;top:638px;width:804px;height:354px"></div><div class="scan-line"></div><div class="hint">Readable code detected.</div><section class="batch-panel"><div class="batch-title"><div>Batch captures: 3</div><div class="share-batch">Share batch</div></div><div class="capture"><div><strong>Barcode: EVT-24-0187</strong><span>9:41 AM</span></div><div class="copy-btn">${svg.copy}</div></div><div class="capture"><div><strong>QR Code: EVT-24-0186</strong><span>9:40 AM</span></div><div class="copy-btn">${svg.copy}</div></div><div class="capture"><div><strong>QR Code: EVT-24-0185</strong><span>9:39 AM</span></div><div class="copy-btn">${svg.copy}</div></div><div class="safe-pill" style="background:rgba(244,63,94,.16);color:#ffe4e6">${svg.warn}Duplicate and unregistered ticket alerts stay on device.</div></section>${nav("scan")}`;
|
|
}
|
|
|
|
function contactScreen() {
|
|
shot.className = "shot";
|
|
return `${status()}<section class="content">${header("Structured results, practical actions")}<section class="hero"><h1>Scan from camera or image</h1><p>Recognize contacts, email, Wi-Fi, calendar events, links, and more.</p><div class="chips"><div class="chip">Copy</div><div class="chip">Share</div><div class="chip">Add contact</div></div></section><div class="two-col"><section><h2 class="section-title">Contact result</h2><div class="contact-card"><div class="contact-top"><div class="initials">AR</div><div class="person"><h2>Avery Reed</h2><p>Operations Lead • North Hall Events</p></div></div><div class="contact-lines"><div class="contact-line"><span>Phone</span><span>+1 555 0134</span></div><div class="contact-line"><span>Email</span><span>avery@example.org</span></div><div class="contact-line"><span>Address</span><span>240 Market Street, Suite 8</span></div></div></div><div class="actions"><div class="action primary" style="margin-left:0">${svg.contact}Add contact</div><div class="action">${svg.copy}Copy</div><div class="action">${svg.share}Share</div></div></section><section><h2 class="section-title">Other results</h2><div class="screen-grid">${row(svg.wifi, "Wi-Fi QR codes", "Open Wi-Fi settings after inspecting network details.")}${row(svg.calendar, "Calendar events", "Review title, location, and time before adding.")}${row(svg.mail, "Email and SMS", "Send only after checking the scanned content.")}</div></section></div></section>${nav("scan")}`;
|
|
}
|
|
|
|
function warningScreen() {
|
|
shot.className = "shot dark";
|
|
return `${status()}<div class="camera-bg"></div><div class="top-chip">Everyday personal use</div><div class="gallery">${svg.gallery}</div><div class="aim"></div><div class="qr-target">${qrCells()}</div><div class="detect-box"></div><div class="scan-line"></div><section class="sheet" style="opacity:.55"><div class="handle"></div><div class="result-card"><h1 class="result-title">URL <span class="badge" style="background:#fff1f2;color:#be123c">Unusual link</span></h1><div class="field-label">Link</div><div class="field-value">https://login.example-secure.co/session</div><div class="field-label">Risk score</div><div class="field-value" style="color:#be123c;text-decoration:none">4</div></div></section><div class="dialog-shade"></div><section class="dialog"><h2>This URL looks unusual</h2><p>Check the link before opening. The warning is calculated on your device, without sending the scan anywhere.</p><div class="dialog-actions"><div class="dialog-btn">Cancel</div><div class="dialog-btn primary">Open anyway</div></div></section>${nav("scan")}`;
|
|
}
|
|
|
|
function wifiScreen() {
|
|
shot.className = "shot";
|
|
return `${status()}<section class="content">${header("Structured QR details before acting")}<section class="hero"><h1>Wi-Fi codes stay readable</h1><p>Inspect network name and security type before opening Android Wi-Fi settings.</p><div class="chips"><div class="chip">Local parsing</div><div class="chip">No tracking</div><div class="chip">No account</div></div></section><div class="two-col"><section class="wifi-card"><div class="wifi-head"><div class="wifi-icon">${svg.wifi}</div><div><h2>Wi-Fi</h2><p>Scanned result</p></div></div><div class="wifi-field"><label>SSID</label><div>Guest Network</div></div><div class="wifi-field"><label>Security</label><div>WPA/WPA2</div></div><div class="wifi-field"><label>Password</label><div style="letter-spacing:5px">••••••••••</div></div><div class="action primary" style="margin:28px 0 0;min-width:100%">${svg.wifi}Open Wi-Fi settings</div></section><section><div class="safe-pill">${svg.shield}Parsing happens on the device. Data leaves only when you choose an external action.</div><div style="height:24px"></div><div class="screen-grid">${row(svg.copy, "Copy result", "Save the raw QR payload when needed.")}${row(svg.share, "Share deliberately", "Send scanned content only when you choose.")}</div></section></div></section>${nav("scan")}`;
|
|
}
|
|
|
|
function imagePickerScreen() {
|
|
shot.className = "shot dark";
|
|
return `${status()}<div class="camera-bg"></div><div class="top-chip">Scan from image</div><div class="gallery">${svg.gallery}</div><section class="content" style="padding-top:300px"><div class="photo-preview"><div class="paper"><h2>Meeting flyer</h2><div class="mini-qr">${qrCells(25)}</div><div class="paper-bars"><span></span><span></span><span></span></div><div style="position:absolute;left:390px;top:95px;width:270px;height:250px;border:7px solid #2dd4bf;border-radius:34px"></div><div style="position:absolute;left:98px;top:260px;width:330px;height:150px;border:7px solid #ffc857;border-radius:34px"></div></div></div></section><section class="image-dialog"><h2 class="section-title">Found 2 codes in image</h2><p style="margin:0 0 20px;color:#607080;font-size:30px;font-weight:700">Choose the result you want to use. Detection and parsing happen locally.</p><div class="candidate active"><div class="candidate-icon">${svg.link}</div><div><strong>URL</strong><span>https://example.org/register</span></div></div><div class="candidate"><div class="candidate-icon">${svg.mail}</div><div><strong>Email</strong><span>hello@example.org</span></div></div><div class="dialog-actions"><div class="dialog-btn">Cancel</div><div class="dialog-btn primary">Use selected</div></div></section>${nav("scan")}`;
|
|
}
|
|
|
|
function settingsScreen() {
|
|
shot.className = "shot";
|
|
return `${status()}<section class="content">${header("Settings that keep you in control")}<section class="hero"><h1>Privacy settings are yours</h1><p>Choose local history, security warnings, feedback, and the scanner view that fits your workflow.</p></section><div class="two-col"><section><div class="panel"><div class="setting"><span>Save history (local)</span><span class="switch"></span></div><div class="setting"><span>Security warnings</span><span class="switch"></span></div><div class="setting"><span>Scan feedback</span><span class="switch"></span></div></div><div style="height:28px"></div><div class="panel"><h2 class="section-title">About</h2><p style="color:#607080;font-size:27px;font-weight:700">Version 1.0.0</p><p style="color:#607080;font-size:27px;font-weight:700">Contact: softwareapp.hb@gmail.com</p><div class="actions"><div class="action">Privacy Policy</div><div class="action">Review</div></div></div></section><section><h2 class="section-title">Select use-case view</h2><div class="option active"><div class="check">✓</div><div><strong>Everyday personal use</strong><span>Full personal scanner with local history and common result actions.</span></div></div><div class="option"><div class="check">◎</div><div><strong>Event & ticketing</strong><span>Batch scanning, duplicate detection, whitelist import, and batch sharing.</span></div></div></section></div></section>${nav("settings")}`;
|
|
}
|
|
|
|
const renderers = [scanScreen, historyScreen, eventScreen, contactScreen, warningScreen, wifiScreen, imagePickerScreen, settingsScreen];
|
|
shot.innerHTML = (renderers[screen - 1] || renderers[0])();
|
|
</script>
|
|
</body>
|
|
</html>
|