Files
QR-master/design-variants/landing-blueprint.html

2081 lines
102 KiB
HTML

<!DOCTYPE html>
<html lang="en" data-theme="light">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>QR Master — Blueprint / Print-Tech — Design Variant</title>
<meta name="description" content="QR Master is a free dynamic QR code generator with tracking, editable destinations, custom branding, interactive ROI calculator, and bulk QR creation.">
<meta name="color-scheme" content="light dark">
<script>if (location.hash === "#dark") document.documentElement.setAttribute("data-theme","dark");</script>
<!-- Typography: Plus Jakarta Sans + Inter + JetBrains Mono -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Plus+Jakarta+Sans:wght@500;600;700;800;900&family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>
/* ============================================================
SKIN 01 : BLUEPRINT / PRINT-TECH
Royal Blue technical palette, hard flat shadows, registration marks.
============================================================ */
:root {
--font-display: "Plus Jakarta Sans", ui-sans-serif, system-ui, sans-serif;
--font-sans: "Inter", ui-sans-serif, system-ui, sans-serif;
--font-mono: "JetBrains Mono", ui-monospace, "SF Mono", Consolas, monospace;
--ease-out: cubic-bezier(0.16, 1, 0.3, 1);
--dur-micro: 180ms;
--dur-ui: 350ms;
--r: 8px;
--r-sm: 4px;
--r-pill: 999px;
--container: 1240px;
}
html[data-theme="light"] {
color-scheme: light;
--paper: #F8FAFC;
--paper-2: #EDF2F7;
--panel: #FFFFFF;
--ink: #0B132B;
--ink-2: #334155;
--muted: #64748B;
--line: #E2E8F0;
--line-strong: #CBD5E1;
--accent: #2563EB;
--accent-hover: #1D4ED8;
--accent-text: #1E40AF;
--accent-soft: rgba(37, 99, 235, 0.08);
--cyan-accent: #06B6D4;
--mark-band: rgba(37, 99, 235, 0.15);
--danger: #EF4444;
--success: #10B981;
--cta: #2563EB;
--cta-hover: #1D4ED8;
--inv-bg: #0B132B;
--inv-fg: #F8FAFC;
--deep: #0F172A;
--deep-text: #F8FAFC;
--deep-muted: #94A3B8;
--deep-accent: #60A5FA;
--shadow-ink: rgba(11, 19, 43, 0.85);
--hard-shadow: 6px 6px 0 var(--shadow-ink);
--nav-bg: rgba(248, 250, 252, 0.92);
--dots: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='28'%3E%3Ccircle cx='1.5' cy='1.5' r='1.3' fill='%230B132B' fill-opacity='0.08'/%3E%3C/svg%3E");
}
html[data-theme="dark"] {
color-scheme: dark;
--paper: #090D16;
--paper-2: #0F172A;
--panel: #131C31;
--ink: #F1F5F9;
--ink-2: #94A3B8;
--muted: #64748B;
--line: #1E293B;
--line-strong: #334155;
--accent: #3B82F6;
--accent-hover: #60A5FA;
--accent-text: #93C5FD;
--accent-soft: rgba(59, 130, 246, 0.12);
--cyan-accent: #22D3EE;
--mark-band: rgba(59, 130, 246, 0.25);
--danger: #F87171;
--success: #34D399;
--cta: #2563EB;
--cta-hover: #3B82F6;
--inv-bg: #F1F5F9;
--inv-fg: #090D16;
--deep: #0B132B;
--deep-text: #F8FAFC;
--deep-muted: #94A3B8;
--deep-accent: #60A5FA;
--shadow-ink: rgba(0, 0, 0, 0.75);
--hard-shadow: 6px 6px 0 var(--shadow-ink);
--nav-bg: rgba(9, 13, 22, 0.9);
--dots: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='28'%3E%3Ccircle cx='1.5' cy='1.5' r='1.3' fill='%23F1F5F9' fill-opacity='0.06'/%3E%3C/svg%3E");
}
* { margin: 0; padding: 0; box-sizing: border-box; }
html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }
body {
font-family: var(--font-sans);
background: var(--paper);
color: var(--ink);
line-height: 1.55;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
overflow-x: hidden;
transition: background-color var(--dur-ui) var(--ease-out), color var(--dur-ui) var(--ease-out);
}
::selection { background: var(--accent); color: #ffffff; }
::-webkit-scrollbar { width: 9px; }
::-webkit-scrollbar-track { background: var(--paper); }
::-webkit-scrollbar-thumb { background: var(--line-strong); border-radius: 0; }
::-webkit-scrollbar-thumb:hover { background: var(--accent); }
a { color: inherit; text-decoration: none; }
a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible {
outline: 2px solid var(--accent); outline-offset: 2px;
}
.skip-link {
position: absolute; top: -100px; left: 12px; z-index: 999;
background: var(--accent); color: #ffffff; font-weight: 600; font-size: 0.875rem;
padding: 12px 18px; border-radius: var(--r-sm);
transition: top var(--dur-micro) var(--ease-out);
}
.skip-link:focus { top: 12px; }
button { font: inherit; color: inherit; background: none; border: none; cursor: pointer; }
img, svg, canvas { display: block; max-width: 100%; }
ul { list-style: none; }
.container { max-width: var(--container); margin: 0 auto; padding: 0 24px; }
h1, h2, h3, h4 { font-family: var(--font-display); letter-spacing: -0.03em; text-wrap: balance; }
.section { padding: 104px 0; position: relative; }
.section--tight { padding: 76px 0; }
.mono {
font-family: var(--font-mono); font-size: 11px; font-weight: 600;
letter-spacing: 0.14em; text-transform: uppercase;
}
.eyebrow {
display: inline-flex; align-items: center; gap: 10px;
font-family: var(--font-mono); font-size: 11px; font-weight: 600;
letter-spacing: 0.14em; text-transform: uppercase; color: var(--accent-text);
background: var(--accent-soft); padding: 4px 12px; border-radius: var(--r-pill);
border: 1px solid rgba(37, 99, 235, 0.2);
}
.eyebrow .no { color: var(--muted); font-weight: 500; }
.section-head { max-width: 720px; margin-bottom: 52px; }
.section-head--split {
max-width: none; display: flex; align-items: flex-end; justify-content: space-between;
gap: 32px; flex-wrap: wrap;
}
.section-head h2 {
font-size: clamp(2.1rem, 4.2vw, 3.2rem); font-weight: 800; line-height: 1.05;
letter-spacing: -0.035em; margin: 16px 0 14px;
}
.section-head p { color: var(--ink-2); font-size: 1.0625rem; line-height: 1.6; max-width: 56ch; }
.section-head .side-note {
font-family: var(--font-mono); font-size: 11px; color: var(--muted);
letter-spacing: 0.08em; text-align: right; padding-bottom: 8px;
}
mark {
background: none; color: var(--accent-text);
box-shadow: inset 0 -0.16em 0 var(--mark-band);
-webkit-box-decoration-break: clone; box-decoration-break: clone;
}
.btn {
display: inline-flex; align-items: center; justify-content: center; gap: 10px;
font-weight: 600; font-size: 0.95rem; border-radius: var(--r); letter-spacing: -0.01em;
padding: 14px 28px; position: relative; border: 1px solid transparent;
transition: transform var(--dur-micro) var(--ease-out), box-shadow var(--dur-micro) var(--ease-out),
background var(--dur-micro) var(--ease-out), border-color var(--dur-micro) var(--ease-out),
color var(--dur-micro) var(--ease-out);
}
.btn:active { transform: translate(2px, 2px); box-shadow: none; }
.btn-primary { background: var(--cta); color: #ffffff; }
.btn-primary:hover { background: var(--cta-hover); transform: translate(-2px, -2px); box-shadow: 4px 4px 0 var(--shadow-ink); }
.btn-ghost { background: transparent; color: var(--ink); border-color: var(--line-strong); }
.btn-ghost:hover { border-color: var(--ink); transform: translate(-2px, -2px); box-shadow: 4px 4px 0 var(--line-strong); }
.btn-sm { padding: 9px 18px; font-size: 0.875rem; }
.panel {
background: var(--panel); border: 1px solid var(--line); border-radius: var(--r);
transition: border-color var(--dur-ui) var(--ease-out), transform var(--dur-ui) var(--ease-out),
box-shadow var(--dur-ui) var(--ease-out), background var(--dur-ui) var(--ease-out);
}
.panel-hover:hover {
border-color: var(--ink); transform: translate(-3px, -3px);
box-shadow: 5px 5px 0 var(--ink);
}
html[data-theme="dark"] .panel-hover:hover { box-shadow: 5px 5px 0 rgba(0,0,0,0.65); border-color: var(--line-strong); }
.tag {
display: inline-flex; align-items: center; gap: 8px;
font-family: var(--font-mono); font-size: 10px; font-weight: 600;
letter-spacing: 0.12em; text-transform: uppercase;
padding: 5px 11px; border-radius: var(--r-pill);
background: var(--accent-soft); color: var(--accent-text);
border: 1px solid var(--accent-text);
}
.tag .pulse { width: 6px; height: 6px; border-radius: 50%; background: var(--accent); animation: blink 1.6s steps(2, start) infinite; }
@keyframes blink { to { visibility: hidden; } }
/* Scroll progress */
.progress { position: fixed; top: 0; left: 0; right: 0; height: 3px; z-index: 300; pointer-events: none; }
.progress span { display: block; height: 100%; width: 100%; background: var(--accent); transform-origin: 0 50%; transform: scaleX(0); }
/* Navigation */
.nav {
position: fixed; top: 0; left: 0; right: 0; z-index: 200;
background: var(--nav-bg); -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
border-bottom: 1px solid transparent;
transition: border-color var(--dur-ui) var(--ease-out), background var(--dur-ui) var(--ease-out);
}
.nav.scrolled { border-bottom-color: var(--line); }
.nav-inner {
max-width: var(--container); margin: 0 auto; padding: 0 24px;
height: 68px; display: flex; align-items: center; justify-content: space-between; gap: 24px;
}
.logo { display: inline-flex; align-items: center; gap: 10px; font-family: var(--font-display); font-weight: 800; font-size: 1.125rem; letter-spacing: -0.02em; }
.logo-mark {
width: 32px; height: 32px; background: var(--cta); color: #ffffff;
display: grid; place-items: center; border-radius: var(--r-sm);
box-shadow: 2px 2px 0 var(--shadow-ink);
}
.nav-links { display: flex; align-items: center; gap: 4px; }
.nav-links a {
font-family: var(--font-mono); font-size: 11px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase;
color: var(--ink-2); padding: 8px 12px; border-radius: var(--r-sm);
transition: color var(--dur-micro) var(--ease-out), background var(--dur-micro) var(--ease-out);
}
.nav-links a:hover { color: var(--ink); background: var(--paper-2); }
.nav-links a.active { color: var(--accent); background: var(--accent-soft); }
.nav-actions { display: flex; align-items: center; gap: 12px; }
.nav-burger {
display: none; width: 38px; height: 38px; border-radius: var(--r-sm);
border: 1px solid var(--line-strong); align-items: center; justify-content: center;
color: var(--ink); background: transparent; flex-direction: column; gap: 4px;
}
.nav-burger span { display: block; width: 16px; height: 2px; background: currentColor; transition: transform var(--dur-micro) var(--ease-out), opacity var(--dur-micro) var(--ease-out); }
.nav-burger[aria-expanded="true"] span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.nav-burger[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav-burger[aria-expanded="true"] span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }
.nav-mobile-panel {
display: none; position: fixed; top: 68px; left: 0; right: 0; z-index: 199;
background: var(--panel); border-bottom: 1px solid var(--line);
padding: 8px 24px 20px; flex-direction: column; gap: 2px;
box-shadow: 0 12px 24px -8px rgba(11,19,43,0.18);
}
.nav-mobile-panel.open { display: flex; }
.nav-mobile-panel a {
font-family: var(--font-mono); font-size: 13px; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase;
color: var(--ink-2); padding: 14px 4px; border-bottom: 1px solid var(--line);
}
.nav-mobile-panel a:last-of-type { border-bottom: none; }
.nav-mobile-panel a:active { color: var(--accent); }
.theme-toggle {
width: 38px; height: 38px; border-radius: var(--r-sm); border: 1px solid var(--line-strong);
display: grid; place-items: center; color: var(--ink-2); background: transparent;
transition: color var(--dur-micro) var(--ease-out), border-color var(--dur-micro) var(--ease-out);
}
.theme-toggle:hover { color: var(--accent); border-color: var(--accent); }
.theme-toggle .icon-sun { display: none; }
html[data-theme="dark"] .theme-toggle .icon-sun { display: block; }
html[data-theme="dark"] .theme-toggle .icon-moon { display: none; }
/* 21st.dev Ambient Grid Spotlight Hero Background */
.hero {
position: relative; min-height: 94vh;
display: flex; align-items: center;
padding: 140px 0 80px; overflow: hidden;
}
.hero-spotlight {
position: absolute; inset: 0; pointer-events: none; z-index: 1;
background-image: var(--dots); background-size: 28px 28px;
mask-image: radial-gradient(circle 420px at var(--mouse-x, 50%) var(--mouse-y, 40%), black 0%, transparent 80%);
-webkit-mask-image: radial-gradient(circle 420px at var(--mouse-x, 50%) var(--mouse-y, 40%), black 0%, transparent 80%);
transition: opacity 0.3s ease;
}
.hero-canvas {
position: absolute; inset: 0; pointer-events: none; z-index: 0;
width: 100%; height: 100%; opacity: 0.9;
}
.hero::before {
content: ""; position: absolute; inset: 0; pointer-events: none; z-index: 0;
background-image: var(--dots); background-size: 28px 28px; opacity: 0.35;
mask-image: linear-gradient(to bottom, black 70%, transparent);
-webkit-mask-image: linear-gradient(to bottom, black 70%, transparent);
}
.hero-grid {
position: relative; z-index: 2;
display: grid; grid-template-columns: 1.05fr 0.95fr; gap: 56px; align-items: center;
}
.hero h1 {
font-size: clamp(2.6rem, 5.2vw, 4.6rem); font-weight: 900; line-height: 0.98;
letter-spacing: -0.04em; margin: 20px 0 20px;
}
.hero-sub { color: var(--ink-2); font-size: 1.125rem; line-height: 1.6; max-width: 48ch; }
.hero-bullets { margin: 28px 0 34px; display: grid; grid-template-columns: 1fr 1fr; gap: 12px 20px; max-width: 540px; }
.hero-bullets li {
display: flex; align-items: center; gap: 10px;
font-family: var(--font-mono); font-size: 12px; font-weight: 500; letter-spacing: 0.01em; color: var(--ink-2);
}
.hero-bullets .tick { color: var(--accent); flex-shrink: 0; font-weight: 700; }
.hero-ctas { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
.hero-meta {
margin-top: 36px; padding-top: 18px; border-top: 1px solid var(--line);
display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
}
.hero-meta .lbl { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--muted); margin-right: 2px; }
.type-chip {
font-family: var(--font-mono); font-size: 10px; font-weight: 600; letter-spacing: 0.04em;
color: var(--ink-2); border: 1px solid var(--line); border-radius: var(--r-sm);
padding: 4px 9px; background: var(--panel); cursor: pointer;
transition: border-color var(--dur-micro) var(--ease-out), color var(--dur-micro) var(--ease-out), background var(--dur-micro), transform var(--dur-micro);
}
.type-chip:hover { transform: translateY(-1px); border-color: var(--accent); }
.type-chip.active { border-color: var(--accent); color: var(--accent-text); background: var(--accent-soft); }
/* Hero Right: Product Spec Card */
.hero-qr { position: relative; justify-self: center; width: 100%; max-width: 440px; }
.qr-frame {
position: relative; background: #ffffff; border: 1px solid var(--line-strong);
border-radius: var(--r); padding: 28px; box-shadow: var(--hard-shadow);
transition: transform var(--dur-ui) var(--ease-out), box-shadow var(--dur-ui) var(--ease-out);
}
.qr-frame:hover {
transform: translateY(-2px); box-shadow: 8px 8px 0 var(--shadow-ink);
}
.qr-frame canvas { width: 100%; height: auto; display: block; border-radius: 4px; }
.qr-frame .laser {
position: absolute; left: 16px; right: 16px; top: 28px; height: 2px;
background: var(--accent); box-shadow: 0 0 16px 3px var(--accent-soft), 0 0 8px var(--accent);
animation: laser 3.2s var(--ease-out) infinite alternate; pointer-events: none;
}
@keyframes laser {
0% { transform: translateY(0); opacity: 0.95; }
100% { transform: translateY(320px); opacity: 0.95; }
}
.reg { position: absolute; width: 14px; height: 14px; color: var(--muted); }
.reg::before, .reg::after { content: ""; position: absolute; background: currentColor; }
.reg::before { left: 50%; top: 0; width: 1px; height: 100%; }
.reg::after { top: 50%; left: 0; width: 100%; height: 1px; }
.reg-tl { top: -20px; left: -20px; }
.reg-tr { top: -20px; right: -20px; }
.reg-bl { bottom: -20px; left: -20px; }
.reg-br { bottom: -20px; right: -20px; }
.frame-tag {
position: absolute; top: -30px; z-index: 3;
font-family: var(--font-mono); font-size: 10px; font-weight: 500;
letter-spacing: 0.16em; text-transform: uppercase; color: var(--muted);
}
.frame-tag.ft-left { left: 0; }
.frame-tag.ft-right { right: 0; color: var(--accent-text); }
.qr-meta {
margin-top: 22px; display: flex; justify-content: space-between; gap: 12px;
font-family: var(--font-mono); font-size: 10.5px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted);
}
.qr-meta .live { color: var(--accent-text); font-weight: 600; display: inline-flex; align-items: center; gap: 6px; }
.qr-meta .live::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--accent); animation: blink 1.4s infinite; }
/* Stats Strip */
.stats { border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); background: var(--paper-2); }
.stats-grid { display: grid; grid-template-columns: repeat(4, 1fr); }
.stat { padding: 32px 24px; border-left: 1px solid var(--line); }
.stat:first-child { border-left: none; }
.stat-num {
font-family: var(--font-display); font-size: clamp(1.8rem, 2.8vw, 2.4rem); font-weight: 900;
letter-spacing: -0.03em; font-variant-numeric: tabular-nums; line-height: 1;
}
.stat-num em { font-style: normal; color: var(--accent); }
.stat-label { margin-top: 8px; font-family: var(--font-mono); font-size: 10.5px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted); }
/* Generator Studio */
.gen-wrap { display: grid; grid-template-columns: 1.05fr 0.95fr; gap: 32px; align-items: stretch; }
.gen-panel { padding: 34px; display: flex; flex-direction: column; gap: 20px; }
.field label {
display: block; font-family: var(--font-mono); font-size: 10.5px; font-weight: 600;
letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-2); margin-bottom: 8px;
}
.input, .select {
width: 100%; padding: 12px 14px; border-radius: var(--r-sm);
background: var(--paper); border: 1px solid var(--line-strong); color: var(--ink);
font: inherit; font-size: 0.9375rem;
transition: border-color var(--dur-micro) var(--ease-out);
}
.input:focus, .select:focus { outline: none; border-color: var(--accent); }
.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.swatch-group { display: flex; gap: 8px; align-items: center; margin-top: 6px; flex-wrap: wrap; }
.swatch-btn {
width: 28px; height: 28px; border-radius: 50%; border: 2px solid var(--line-strong);
cursor: pointer; transition: transform var(--dur-micro), border-color var(--dur-micro), box-shadow var(--dur-micro);
position: relative;
}
.swatch-btn:hover { transform: scale(1.15); border-color: var(--accent); }
.swatch-btn.active { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.swatch-btn.active::after {
content: ""; position: absolute; inset: 0; border-radius: 50%;
box-shadow: 0 0 0 2px var(--panel) inset;
}
.color-row { display: flex; gap: 10px; align-items: stretch; }
.color-row input[type="color"] {
width: 44px; height: 44px; padding: 2px; border-radius: var(--r-sm);
background: var(--paper); border: 1px solid var(--line-strong); cursor: pointer; flex-shrink: 0;
}
.range { width: 100%; accent-color: var(--accent); height: 30px; cursor: pointer; }
.range-val { font-family: var(--font-mono); font-size: 11px; color: var(--muted); text-align: center; }
.contrast-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; border-top: 1px dashed var(--line-strong); padding-top: 16px; }
.contrast-badge { font-family: var(--font-mono); font-size: 10.5px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; padding: 5px 10px; border-radius: var(--r-sm); }
.contrast-badge.ok { background: var(--accent-soft); color: var(--accent-text); border: 1px solid var(--accent-text); }
.contrast-badge.bad { background: rgba(239, 68, 68, 0.15); color: var(--danger); border: 1px solid var(--danger); }
.contrast-val { font-family: var(--font-mono); font-size: 11px; color: var(--muted); font-variant-numeric: tabular-nums; }
.gen-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.gen-actions .btn { padding: 12px 14px; font-size: 0.875rem; }
.gen-preview {
position: relative; border-radius: var(--r); overflow: hidden;
border: 1px solid var(--line); background: var(--paper-2);
display: flex; flex-direction: column; align-items: center; justify-content: center;
padding: 40px 24px; gap: 20px; min-height: 500px;
}
.gen-preview::before {
content: ""; position: absolute; inset: 0; pointer-events: none;
background-image: var(--dots); background-size: 28px 28px;
}
.gen-preview-title {
position: relative; z-index: 2; display: flex; align-items: center; gap: 8px;
font-family: var(--font-mono); font-size: 10.5px; font-weight: 600;
letter-spacing: 0.18em; text-transform: uppercase; color: var(--muted);
}
.gen-preview-title::before { content: ""; width: 7px; height: 7px; background: var(--accent); border-radius: 50%; }
.qr-stage { position: relative; z-index: 2; padding: 20px; background: #ffffff; border: 1px solid var(--line-strong); border-radius: var(--r); box-shadow: 6px 6px 0 rgba(11,19,43,0.85); }
html[data-theme="dark"] .qr-stage { box-shadow: 6px 6px 0 rgba(0,0,0,0.6); }
.qr-stage .corner { position: absolute; width: 12px; height: 12px; border: 2px solid var(--accent); pointer-events: none; }
.qr-stage .corner.tl { top: -6px; left: -6px; border-right: 0; border-bottom: 0; }
.qr-stage .corner.tr { top: -6px; right: -6px; border-left: 0; border-bottom: 0; }
.qr-stage .corner.bl { bottom: -6px; left: -6px; border-right: 0; border-top: 0; }
.qr-stage .corner.br { bottom: -6px; right: -6px; border-left: 0; border-top: 0; }
.qr-stage .qr-holder { line-height: 0; }
.qr-url {
position: relative; z-index: 2; max-width: 100%;
font-family: var(--font-mono); font-size: 11.5px; color: var(--ink-2);
background: var(--panel); border: 1px solid var(--line);
padding: 8px 16px; border-radius: var(--r-sm);
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.qr-note { position: relative; z-index: 2; font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--muted); }
/* AI Section */
.ai { background: var(--paper-2); border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.ai-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0; border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; background: var(--panel); margin-bottom: 44px; }
.ai-cell { padding: 26px 24px; border-left: 1px solid var(--line); transition: background var(--dur-micro) var(--ease-out); }
.ai-cell:first-child { border-left: none; }
.ai-cell:hover { background: var(--paper-2); }
.ai-cell .idx { font-family: var(--font-mono); font-size: 11px; font-weight: 700; color: var(--accent-text); letter-spacing: 0.1em; }
.ai-cell h3 { font-size: 1.0625rem; font-weight: 700; margin: 12px 0 12px; letter-spacing: -0.02em; }
.ai-cell li { font-size: 0.875rem; color: var(--ink-2); padding: 4px 0 4px 16px; position: relative; }
.ai-cell li::before { content: "+"; position: absolute; left: 0; color: var(--accent); font-family: var(--font-mono); font-size: 12px; }
.ai-capture {
max-width: 640px; margin: 0 auto; padding: 30px;
background: var(--panel); border: 1px solid var(--line); border-radius: var(--r); box-shadow: var(--hard-shadow);
}
.ai-capture .cap-title { font-family: var(--font-mono); font-size: 11px; font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-2); margin-bottom: 16px; text-align: center; }
.ai-form { display: flex; gap: 10px; }
.ai-form .input { flex: 1; }
.ai-hint { margin-top: 12px; font-family: var(--font-mono); font-size: 10.5px; letter-spacing: 0.06em; color: var(--muted); text-align: center; text-transform: uppercase; }
.ai-success { display: none; align-items: center; justify-content: center; gap: 10px; color: var(--accent-text); font-weight: 600; padding: 12px 0; font-family: var(--font-mono); font-size: 13px; }
.ai-capture.done form, .ai-capture.done .ai-hint { display: none; }
.ai-capture.done .ai-success { display: flex; }
/* Tools Index with Search Filter */
.tools-filter { margin-bottom: 24px; display: flex; gap: 16px; align-items: center; }
.tools-filter .input { max-width: 420px; }
.tools-index { border-top: 1px solid var(--line-strong); }
.tool-row {
display: grid; grid-template-columns: 50px 180px 1fr 32px; align-items: center; gap: 20px;
padding: 16px 8px; border-bottom: 1px solid var(--line);
transition: background var(--dur-micro) var(--ease-out), padding-left var(--dur-micro) var(--ease-out);
}
.tool-row:hover { background: var(--panel); padding-left: 16px; box-shadow: inset 3px 0 0 var(--accent); }
.tool-row .idx { font-family: var(--font-mono); font-size: 11px; color: var(--muted); font-variant-numeric: tabular-nums; }
.tool-row:hover .idx { color: var(--accent-text); }
.tool-row h3 { font-size: 1.0625rem; font-weight: 700; letter-spacing: -0.015em; }
.tool-row p { font-size: 0.875rem; color: var(--ink-2); }
.tool-row .arr { color: var(--muted); transition: color var(--dur-micro) var(--ease-out), transform var(--dur-micro) var(--ease-out); justify-self: end; }
.tool-row:hover .arr { color: var(--accent); transform: translate(2px, -2px); }
/* Link cards */
.link-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; }
.link-card { padding: 24px 22px; position: relative; display: block; }
.link-card .idx {
font-family: var(--font-mono); font-size: 11px; font-weight: 600; color: var(--muted);
letter-spacing: 0.1em; display: block; margin-bottom: 14px; font-variant-numeric: tabular-nums;
transition: color var(--dur-micro) var(--ease-out);
}
.link-card:hover .idx { color: var(--accent-text); }
.link-card h3 { font-size: 1rem; font-weight: 700; line-height: 1.3; margin-bottom: 8px; letter-spacing: -0.015em; }
.link-card p { font-size: 0.8125rem; color: var(--ink-2); line-height: 1.55; }
.link-card .go {
position: absolute; top: 18px; right: 18px; color: var(--muted);
transition: color var(--dur-micro) var(--ease-out), transform var(--dur-micro) var(--ease-out);
}
.link-card:hover .go { color: var(--accent); transform: translate(2px, -2px); }
.center-cta { text-align: center; margin-top: 40px; }
.alt-bg { background: var(--paper-2); border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
/* Testimonials Marquee */
.testi { overflow: hidden; }
.marquee-mask {
overflow: hidden; position: relative;
mask-image: linear-gradient(90deg, transparent, black 5%, black 95%, transparent);
-webkit-mask-image: linear-gradient(90deg, transparent, black 5%, black 95%, transparent);
}
.marquee-track { display: flex; gap: 16px; width: max-content; padding: 8px 0 16px; }
.testi-card {
width: 380px; flex-shrink: 0; padding: 24px;
display: flex; flex-direction: column; gap: 12px;
}
.testi-top { display: flex; align-items: center; justify-content: space-between; }
.stars { display: flex; gap: 2px; color: var(--accent); font-size: 13px; letter-spacing: 2px; font-family: var(--font-mono); }
.stars .off { color: var(--line-strong); }
.verified {
font-family: var(--font-mono); font-size: 10px; font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase;
color: var(--accent-text); background: var(--accent-soft); border: 1px solid var(--accent-text); padding: 2px 8px; border-radius: var(--r-pill);
}
.testi-card h3 { font-size: 0.975rem; font-weight: 700; letter-spacing: -0.015em; }
.testi-card > p { font-size: 0.85rem; color: var(--ink-2); line-height: 1.6; flex-grow: 1; }
.testi-author { border-top: 1px solid var(--line); padding-top: 12px; font-family: var(--font-mono); }
.testi-author b { display: block; font-size: 11.5px; letter-spacing: 0.02em; }
.testi-author span { display: block; font-size: 10px; color: var(--muted); letter-spacing: 0.05em; text-transform: uppercase; margin-top: 2px; }
/* Compare Table */
.cmp { max-width: 960px; margin: 0 auto; border: 1px solid var(--line-strong); border-radius: var(--r); overflow: hidden; background: var(--panel); box-shadow: var(--hard-shadow); }
.cmp-row { display: grid; grid-template-columns: 1.4fr 1fr 1fr; align-items: center; }
.cmp-row + .cmp-row { border-top: 1px solid var(--line); }
.cmp-row > div { padding: 18px 24px; }
.cmp-head { background: var(--paper-2); }
.cmp-head > div { padding: 24px; }
.cmp-head .ttl { font-family: var(--font-display); font-size: 1.3rem; font-weight: 800; letter-spacing: -0.02em; }
.cmp-head .sub { font-family: var(--font-mono); font-size: 10px; font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted); margin-top: 4px; }
.cmp-head .dyn .ttl { color: var(--accent); }
.cmp-head .dyn { box-shadow: inset 0 3px 0 var(--accent); }
.cmp-cap { font-weight: 600; font-size: 0.9375rem; }
.cmp-yes, .cmp-no { font-family: var(--font-mono); font-size: 12.5px; font-weight: 700; display: inline-flex; align-items: center; gap: 8px; }
.cmp-yes { color: var(--accent); }
.cmp-no { color: var(--muted); }
.cmp-note { font-size: 0.75rem; color: var(--muted); font-weight: 400; display: block; margin-top: 2px; font-family: var(--font-sans); }
.cmp-row .dyn-cell { background: var(--accent-soft); border-left: 1px solid var(--line); }
.cmp-row.cmp-head .dyn-cell { border-left: none; }
/* Interactive ROI Calculator */
.roi-card {
border: 1px solid var(--line-strong); border-radius: var(--r); background: var(--panel);
display: grid; grid-template-columns: 1.2fr 0.8fr; overflow: hidden; box-shadow: var(--hard-shadow);
}
.roi-left { padding: 48px 40px; display: flex; flex-direction: column; gap: 20px; }
.roi-left h2 { font-size: clamp(1.6rem, 3vw, 2.4rem); font-weight: 800; line-height: 1.05; }
.roi-right {
border-left: 1px solid var(--line); background: var(--deep); color: var(--deep-text);
display: flex; flex-direction: column; justify-content: center; padding: 48px 36px; gap: 12px;
}
.roi-right .big-savings { font-family: var(--font-display); font-size: clamp(2.4rem, 4vw, 3.6rem); font-weight: 900; letter-spacing: -0.04em; color: var(--deep-accent); font-variant-numeric: tabular-nums; line-height: 1; }
.roi-right .lbl { font-family: var(--font-mono); font-size: 10.5px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--deep-muted); }
/* Features */
.feat-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0; border-top: 1px solid var(--line-strong); }
.feat { padding: 32px 32px 10px 0; border-bottom: 1px solid var(--line); }
.feat:not(:last-child) { border-right: 1px solid var(--line); padding-right: 32px; }
.feat:not(:first-child) { padding-left: 32px; }
.feat .no { font-family: var(--font-mono); font-size: 12px; font-weight: 700; color: var(--accent); letter-spacing: 0.1em; }
.feat h3 { font-size: 1.3rem; font-weight: 800; margin: 14px 0 10px; letter-spacing: -0.02em; line-height: 1.15; }
.feat p { font-size: 0.9375rem; color: var(--ink-2); padding-bottom: 24px; }
/* Pricing */
.billing-toggle {
display: inline-flex; align-items: center; gap: 16px; margin: 0 auto 48px;
font-family: var(--font-mono); font-size: 11px; font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase; color: var(--muted);
}
.billing-toggle .opt.active { color: var(--ink); }
.switch {
width: 52px; height: 28px; border-radius: 999px; background: var(--paper-2);
border: 1px solid var(--line-strong); position: relative; cursor: pointer;
transition: border-color var(--dur-micro) var(--ease-out);
}
.switch:hover { border-color: var(--accent); }
.switch::after {
content: ""; position: absolute; top: 3px; left: 3px; width: 20px; height: 20px;
border-radius: 50%; background: var(--accent);
transition: transform var(--dur-micro) var(--ease-out);
}
.switch[aria-checked="true"]::after { transform: translateX(24px); }
.save-tag {
font-family: var(--font-mono); font-size: 10px; font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase;
color: var(--accent-text); background: var(--accent-soft); border: 1px solid var(--accent-text); padding: 3px 8px; border-radius: var(--r-pill);
opacity: 0; transform: translateY(3px); transition: opacity var(--dur-micro), transform var(--dur-micro);
}
.save-tag.show { opacity: 1; transform: none; }
.price-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; align-items: stretch; }
.price-card { padding: 30px 24px; display: flex; flex-direction: column; position: relative; }
.price-card.popular {
background: var(--deep); color: var(--deep-text); border-color: var(--deep);
transform: translate(-3px, -3px); box-shadow: 6px 6px 0 var(--accent);
}
.price-card.popular:hover { transform: translate(-5px, -5px); box-shadow: 8px 8px 0 var(--accent); }
.pop-tag {
position: absolute; top: -12px; left: 20px;
background: var(--accent); color: #ffffff;
font-family: var(--font-mono); font-size: 9.5px; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase;
padding: 4px 11px; border-radius: var(--r-pill);
}
.price-name { font-family: var(--font-mono); font-size: 11px; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase; color: var(--muted); }
.price-card.popular .price-name { color: var(--deep-muted); }
.price-row { display: flex; align-items: baseline; gap: 6px; margin: 14px 0 4px; min-height: 54px; }
.price-val { font-family: var(--font-display); font-size: 2.8rem; font-weight: 900; letter-spacing: -0.04em; font-variant-numeric: tabular-nums; line-height: 1; }
.price-per { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); }
.price-card.popular .price-per { color: var(--deep-muted); }
.price-feats { margin: 20px 0 24px; display: grid; gap: 10px; flex-grow: 1; }
.price-feats li { display: flex; align-items: flex-start; gap: 8px; font-size: 0.85rem; color: var(--ink-2); }
.price-card.popular .price-feats li { color: rgba(248, 250, 252, 0.82); }
.price-feats li::before { content: "+"; font-family: var(--font-mono); color: var(--accent); font-weight: 700; flex-shrink: 0; }
.price-card.popular .price-feats li::before { color: var(--deep-accent); }
.price-card .btn { width: 100%; }
.price-card.popular .btn-primary { background: var(--accent); color: #ffffff; }
/* FAQ */
.faq-list { max-width: 800px; margin: 0 auto; border-top: 1px solid var(--line-strong); }
.faq-item { border-bottom: 1px solid var(--line); }
.faq-q {
width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 20px;
padding: 22px 4px; text-align: left; background: transparent;
font-family: var(--font-display); font-size: 1.15rem; font-weight: 700; letter-spacing: -0.015em;
transition: color var(--dur-micro) var(--ease-out);
}
.faq-q:hover { color: var(--accent); }
.faq-q .pm { font-family: var(--font-mono); font-size: 18px; font-weight: 500; color: var(--muted); transition: transform var(--dur-ui) var(--ease-out), color var(--dur-micro); flex-shrink: 0; }
.faq-item.open .faq-q .pm { transform: rotate(45deg); color: var(--accent); }
.faq-a { display: grid; grid-template-rows: 0fr; transition: grid-template-rows var(--dur-ui) var(--ease-out); }
.faq-item.open .faq-a { grid-template-rows: 1fr; }
.faq-a > div { overflow: hidden; }
.faq-a p { padding: 0 4px 24px; color: var(--ink-2); font-size: 0.9375rem; line-height: 1.65; max-width: 68ch; }
/* Final CTA */
.final-cta { text-align: center; background: var(--deep); color: var(--deep-text); }
.final-cta h2 { font-size: clamp(2.2rem, 5vw, 4rem); font-weight: 900; line-height: 0.98; margin: 18px 0 18px; }
.final-cta p { color: var(--deep-muted); font-size: 1.0625rem; max-width: 48ch; margin: 0 auto 36px; }
.final-cta .eyebrow { color: var(--deep-accent); background: rgba(96, 165, 250, 0.12); border-color: rgba(96, 165, 250, 0.3); }
/* Footer */
.footer { border-top: 1px solid var(--line-strong); background: var(--paper-2); padding: 60px 0 32px; }
.footer-grid { display: grid; grid-template-columns: 1.6fr 1fr 1fr 1fr 1fr; gap: 36px; margin-bottom: 44px; }
.footer-brand p { margin-top: 14px; font-size: 0.85rem; color: var(--muted); max-width: 30ch; }
.footer h4 { font-family: var(--font-mono); font-size: 10.5px; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase; color: var(--muted); margin-bottom: 14px; }
.footer li { margin-bottom: 9px; }
.footer-col a { font-size: 0.85rem; color: var(--ink-2); transition: color var(--dur-micro) var(--ease-out); }
.footer-col a:hover { color: var(--accent); }
.footer-bottom {
border-top: 1px solid var(--line); padding-top: 22px;
display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap;
font-family: var(--font-mono); font-size: 10.5px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted);
}
/* Responsive Breakpoints */
@media (max-width: 1080px) {
.link-grid { grid-template-columns: repeat(2, 1fr); }
.ai-grid { grid-template-columns: repeat(2, 1fr); }
.ai-cell:nth-child(3) { border-left: none; }
.ai-cell:nth-child(n+3) { border-top: 1px solid var(--line); }
.price-grid { grid-template-columns: repeat(2, 1fr); }
.footer-grid { grid-template-columns: 1fr 1fr 1fr; }
.feat-grid { grid-template-columns: 1fr; }
.feat:not(:last-child) { border-right: none; padding-right: 0; }
.feat:not(:first-child) { padding-left: 0; }
}
@media (max-width: 900px) {
.section { padding: 76px 0; }
.hero { padding: 110px 0 70px; min-height: 0; }
.hero-grid { grid-template-columns: 1fr; gap: 48px; }
.hero-qr { order: 2; }
.gen-wrap, .roi-card { grid-template-columns: 1fr; }
.roi-right { border-left: none; border-top: 1px solid var(--line); }
.roi-left { padding: 36px 24px; }
.stats-grid { grid-template-columns: repeat(2, 1fr); }
.stat { padding-left: 0; }
.stat:nth-child(3) { border-left: none; }
.nav-links { display: none; }
.nav-burger { display: inline-flex; }
.tool-row { grid-template-columns: 40px 1fr 28px; }
.tool-row p { display: none; }
.cmp-row > div { padding: 14px 16px; }
.type-chip { padding: 8px 12px; }
.swatch-btn { width: 34px; height: 34px; }
}
@media (max-width: 600px) {
.link-grid, .ai-grid, .price-grid { grid-template-columns: 1fr; }
.ai-cell { border-left: none; border-top: 1px solid var(--line); }
.ai-cell:first-child { border-top: none; }
.testi-card { width: 300px; }
.gen-actions { grid-template-columns: 1fr; }
.ai-form { flex-direction: column; }
.field-row { grid-template-columns: 1fr; }
.footer-grid { grid-template-columns: 1fr 1fr; }
.hero-bullets { grid-template-columns: 1fr; }
}
</style>
</head>
<body>
<a class="skip-link" href="#top">Skip to content</a>
<!-- Scroll Progress Bar -->
<div class="progress" aria-hidden="true"><span id="progressBar"></span></div>
<!-- ==================== NAVIGATION ==================== -->
<nav class="nav" id="nav">
<div class="nav-inner">
<a class="logo" href="#top" data-scroll>
<span class="logo-mark" aria-hidden="true">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round">
<rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/>
<rect x="3" y="14" width="7" height="7" rx="1"/><path d="M14 14h3v3h-3zM21 14v.01M14 21v.01M21 21v.01M18 18h3"/>
</svg>
</span>
QR&nbsp;Master
</a>
<div class="nav-links" id="navLinks">
<a href="#generator" data-scroll data-nav="generator">Generator</a>
<a href="#tools" data-scroll data-nav="tools">Tools</a>
<a href="#use-cases" data-scroll data-nav="use-cases">Use Cases</a>
<a href="#roi" data-scroll data-nav="roi">ROI Calculator</a>
<a href="#pricing" data-scroll data-nav="pricing">Pricing</a>
<a href="#faq" data-scroll data-nav="faq">FAQ</a>
</div>
<div class="nav-actions">
<button class="theme-toggle" id="themeToggle" aria-label="Toggle color theme">
<svg class="icon-moon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>
<svg class="icon-sun" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M4.93 4.93l1.41 1.41m11.32 11.32 1.41 1.41M2 12h2m16 0h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41"/></svg>
</button>
<a class="btn btn-primary btn-sm" href="https://www.qrmaster.net/signup">Sign up free</a>
<button class="nav-burger" id="navBurger" aria-expanded="false" aria-controls="navMobilePanel" aria-label="Toggle navigation menu">
<span></span><span></span><span></span>
</button>
</div>
</div>
<div class="nav-mobile-panel" id="navMobilePanel">
<a href="#generator" data-scroll data-mobile-nav>Generator</a>
<a href="#tools" data-scroll data-mobile-nav>Tools</a>
<a href="#use-cases" data-scroll data-mobile-nav>Use Cases</a>
<a href="#roi" data-scroll data-mobile-nav>ROI Calculator</a>
<a href="#pricing" data-scroll data-mobile-nav>Pricing</a>
<a href="#faq" data-scroll data-mobile-nav>FAQ</a>
</div>
</nav>
<!-- ==================== HERO SECTION ==================== -->
<header class="hero" id="top">
<!-- 21st.dev Ambient Canvas & Radial Spotlight Glow -->
<canvas class="hero-canvas" id="heroBgCanvas" aria-hidden="true"></canvas>
<div class="hero-spotlight" id="heroSpotlight" aria-hidden="true"></div>
<div class="container hero-grid">
<div>
<span class="eyebrow" data-hero="0"><span class="no">BLUEPRINT 3.0</span> Free Dynamic QR Code Generator</span>
<h1 data-hero="1">Free <mark>Dynamic QR Code</mark> Generator with Tracking</h1>
<p class="hero-sub" data-hero="2">
Create static and dynamic QR codes with editable destinations, scan analytics, custom branding, and bulk creation.
</p>
<ul class="hero-bullets">
<li data-hero="3"><span class="tick">+</span> No credit card required</li>
<li data-hero="4"><span class="tick">+</span> Free forever static codes</li>
<li data-hero="5"><span class="tick">+</span> Real-time scan analytics</li>
<li data-hero="6"><span class="tick">+</span> Custom colors &amp; branding</li>
</ul>
<div class="hero-ctas" data-hero="7">
<a class="btn btn-primary" href="#generator" data-scroll data-magnetic>Make a QR Code Free
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14m-7-7 7 7-7 7"/></svg>
</a>
<a class="btn btn-ghost" href="#pricing" data-scroll>View Pricing</a>
</div>
<div class="hero-meta" data-hero="8">
<span class="lbl">Select type:</span>
<span class="type-chip active" data-type="url">URL</span>
<span class="type-chip" data-type="vcard">vCard</span>
<span class="type-chip" data-type="wifi">WiFi</span>
<span class="type-chip" data-type="pdf">PDF</span>
<span class="type-chip" data-type="event">Event</span>
<span class="type-chip" data-type="coupon">Coupon</span>
<span class="type-chip" data-type="app">App Store</span>
<span class="type-chip" data-type="call">Call</span>
</div>
</div>
<!-- Product as Hero Poster -->
<div class="hero-qr" data-hero="9">
<span class="frame-tag ft-left" aria-hidden="true">Fig. 01: Specimen Preview</span>
<span class="frame-tag ft-right" aria-hidden="true">QRM/2026: Rev C</span>
<div class="qr-frame">
<span class="reg reg-tl" aria-hidden="true"></span>
<span class="reg reg-tr" aria-hidden="true"></span>
<span class="reg reg-bl" aria-hidden="true"></span>
<span class="reg reg-br" aria-hidden="true"></span>
<canvas id="heroQr" width="640" height="640" aria-label="Scannable QR code pointing to qrmaster.net"></canvas>
<span class="laser" aria-hidden="true"></span>
</div>
<div class="qr-meta">
<span id="heroQrEcho">https://www.qrmaster.net</span>
<span class="live">Live Specimen</span>
</div>
</div>
</div>
</header>
<!-- ==================== STATS STRIP ==================== -->
<section class="stats" aria-label="Key numbers">
<div class="container">
<div class="stats-grid">
<div class="stat"><div class="stat-num"><em data-count="4.9" data-decimals="1">0</em>/5</div><div class="stat-label">Customer Rating</div></div>
<div class="stat"><div class="stat-num"><span data-count="12">0</span>+</div><div class="stat-label">Verified Reviews</div></div>
<div class="stat"><div class="stat-num"><span data-count="18">0</span></div><div class="stat-label">Free Specialized Tools</div></div>
<div class="stat"><div class="stat-num"><span data-count="0">0</span></div><div class="stat-label">To Start Forever</div></div>
</div>
</div>
</section>
<!-- ==================== GENERATOR STUDIO ==================== -->
<section class="section" id="generator">
<div class="container">
<div class="section-head section-head--split" data-reveal>
<div>
<span class="eyebrow"><span class="no">01</span> Instant Studio</span>
<h2>Interactive QR Code Generator Studio</h2>
<p>Type a URL or destination, pick colors, test WCAG contrast, and download SVG or PNG instantly without signup.</p>
</div>
<div class="side-note">SVG + PNG : High-Res 300 DPI : 100% Free</div>
</div>
<div class="gen-wrap">
<!-- Controls Panel -->
<div class="panel gen-panel" data-reveal>
<div class="field">
<label for="qrUrl">URL or Destination Content</label>
<input class="input" id="qrUrl" type="url" value="https://www.qrmaster.net" placeholder="Enter URL, text, or destination..." spellcheck="false">
</div>
<div class="field">
<label>Color Theme Swatches</label>
<div class="swatch-group" role="group" aria-label="Color theme presets">
<button class="swatch-btn active" style="background:#0B132B" data-fg="#0B132B" data-bg="#ffffff" title="Navy Blueprint" aria-label="Navy Blueprint theme" aria-pressed="true"></button>
<button class="swatch-btn" style="background:#2563EB" data-fg="#2563EB" data-bg="#ffffff" title="Royal Blue" aria-label="Royal Blue theme" aria-pressed="false"></button>
<button class="swatch-btn" style="background:#10B981" data-fg="#10B981" data-bg="#0F172A" title="Emerald Dark" aria-label="Emerald Dark theme" aria-pressed="false"></button>
<button class="swatch-btn" style="background:#000000" data-fg="#000000" data-bg="#ffffff" title="Classic Monochrome" aria-label="Classic Monochrome theme" aria-pressed="false"></button>
<button class="swatch-btn" style="background:#7C3AED" data-fg="#7C3AED" data-bg="#F3E8FF" title="Purple Subtle" aria-label="Purple Subtle theme" aria-pressed="false"></button>
<button class="swatch-btn" style="background:#D97706" data-fg="#D97706" data-bg="#FEF3C7" title="Amber Accent" aria-label="Amber Accent theme" aria-pressed="false"></button>
</div>
</div>
<div class="field-row">
<div class="field">
<label for="fgColor">Foreground Color</label>
<div class="color-row">
<input type="color" id="fgColor" value="#0B132B" aria-label="Foreground color picker">
<input class="input" id="fgHex" value="#0B132B" aria-label="Foreground color hex value" spellcheck="false">
</div>
</div>
<div class="field">
<label for="bgColor">Background Color</label>
<div class="color-row">
<input type="color" id="bgColor" value="#ffffff" aria-label="Background color picker">
<input class="input" id="bgHex" value="#ffffff" aria-label="Background color hex value" spellcheck="false">
</div>
</div>
</div>
<div class="field-row">
<div class="field">
<label for="cornerStyle">Corner Style</label>
<select class="select" id="cornerStyle">
<option value="square">Square Corners</option>
<option value="rounded">Rounded Corners</option>
</select>
</div>
<div class="field">
<label for="qrSize">Render Size</label>
<input class="range" id="qrSize" type="range" min="120" max="400" value="230" aria-label="QR code size in pixels">
<div class="range-val"><span id="sizeVal">230</span>px</div>
</div>
</div>
<div class="contrast-row">
<span class="contrast-badge ok" id="contrastBadge">Good contrast</span>
<span class="contrast-val">WCAG Ratio: <span id="contrastVal">16.2:1</span></span>
</div>
<div class="gen-actions">
<button class="btn btn-ghost" id="dlSvg" type="button">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M7 10l5 5 5-5M12 15V3"/></svg>
Download SVG
</button>
<button class="btn btn-ghost" id="dlPng" type="button">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M7 10l5 5 5-5M12 15V3"/></svg>
Download PNG
</button>
</div>
<a class="btn btn-primary" href="https://www.qrmaster.net/login">Save &amp; Track Analytics
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14m-7-7 7 7-7 7"/></svg>
</a>
</div>
<!-- Preview Stage -->
<div class="gen-preview" data-reveal>
<span class="gen-preview-title">Real-Time Studio Canvas</span>
<div class="qr-stage">
<span class="corner tl" aria-hidden="true"></span>
<span class="corner tr" aria-hidden="true"></span>
<span class="corner bl" aria-hidden="true"></span>
<span class="corner br" aria-hidden="true"></span>
<div class="qr-holder" id="qrHolder">
<canvas id="qrCanvas" width="460" height="460" aria-label="QR code preview canvas"></canvas>
</div>
</div>
<div class="qr-url" id="qrUrlEcho">https://www.qrmaster.net</div>
<div class="qr-note">Scan with any smartphone camera</div>
</div>
</div>
</div>
</section>
<!-- ==================== AI FEATURES SPOTLIGHT ==================== -->
<section class="section ai" id="ai">
<div class="container">
<div class="section-head section-head--split" data-reveal>
<div>
<span class="eyebrow"><span class="no">02</span> AI Innovation</span>
<h2>The future of QR codes is <mark>AI-powered</mark></h2>
<p>Next-generation intelligence for QR code generation, design optimization, and scan prediction.</p>
</div>
<div class="side-note"><span class="tag"><span class="pulse"></span>In Active Development</span></div>
</div>
<div class="ai-grid" data-reveal>
<div class="ai-cell">
<span class="idx">A1</span>
<h3>Smart QR Generation</h3>
<ul>
<li>AI-powered content optimization</li>
<li>Intelligent design &amp; color matching</li>
<li>Auto vCard creation from LinkedIn</li>
<li>SEO-optimized short URLs</li>
</ul>
</div>
<div class="ai-cell">
<span class="idx">A2</span>
<h3>Predictive Analytics</h3>
<ul>
<li>AI scan rate forecasting</li>
<li>Anomaly &amp; fraud detection</li>
<li>Natural language analytics queries</li>
<li>Automated performance alerts</li>
</ul>
</div>
<div class="ai-cell">
<span class="idx">A3</span>
<h3>Smart Content Hub</h3>
<ul>
<li>Automated campaign tagging</li>
<li>Smart bulk CSV generation</li>
<li>AI fallback destination routing</li>
<li>Dynamic content personalization</li>
</ul>
</div>
<div class="ai-cell">
<span class="idx">A4</span>
<h3>Creative Studio AI</h3>
<ul>
<li>AI custom artistic QR designs</li>
<li>Auto-generated marketing copy</li>
<li>Automated A/B split testing</li>
<li>Print-ready layout checks</li>
</ul>
</div>
</div>
<div class="ai-capture" id="aiCapture" data-reveal>
<div class="cap-title">Get early access when AI features launch</div>
<form class="ai-form" id="aiForm" novalidate>
<input class="input" type="email" placeholder="enter your email address..." required aria-label="Email address" id="aiEmail">
<button class="btn btn-primary" type="submit">Notify Me
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14m-7-7 7 7-7 7"/></svg>
</button>
</form>
<p class="ai-hint">Join 1,400+ creators on the VIP access list</p>
<div class="ai-success">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><path d="m9 11 3 3L22 4"/></svg>
You are on the list. We will notify you first!
</div>
</div>
</div>
</section>
<!-- ==================== FREE TOOLS INDEX ==================== -->
<section class="section" id="tools">
<div class="container">
<div class="section-head section-head--split" data-reveal>
<div>
<span class="eyebrow"><span class="no">03</span> Tool Index</span>
<h2>18 Specialized Free QR Code Tools</h2>
<p>Create dedicated QR codes for every use case. 100% free with no registration required.</p>
</div>
<div class="side-note">18 Tools : No Account Needed</div>
</div>
<div class="tools-filter" data-reveal>
<input class="input" id="toolSearch" type="search" placeholder="🔍 Search tools (e.g. WiFi, vCard, Barcode, Instagram)..." aria-label="Search tools">
</div>
<div class="tools-index" id="toolsGrid"></div>
</div>
</section>
<!-- ==================== WORKFLOWS ==================== -->
<section class="section alt-bg" id="workflows">
<div class="container">
<div class="section-head" data-reveal>
<span class="eyebrow"><span class="no">04</span> Workflows</span>
<h2>Popular QR Master Workflows</h2>
<p>High-intent solutions for editable QR codes, spreadsheet batches, barcodes, meeting links, and local business campaigns.</p>
</div>
<div class="link-grid" id="workflowGrid"></div>
</div>
</section>
<!-- ==================== USE CASES ==================== -->
<section class="section" id="use-cases">
<div class="container">
<div class="section-head" data-reveal>
<span class="eyebrow"><span class="no">05</span> Industry Guides</span>
<h2>QR Codes by Industry</h2>
<p>Explore how modern teams use dynamic QR codes to track offline engagement and convert physical traffic.</p>
</div>
<div class="link-grid" id="useCaseGrid"></div>
<div class="center-cta" data-reveal>
<a class="btn btn-ghost" href="https://www.qrmaster.net/use-cases">View All Industry Guides
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14m-7-7 7 7-7 7"/></svg>
</a>
</div>
</div>
</section>
<!-- ==================== TESTIMONIALS MARQUEE ==================== -->
<section class="section alt-bg testi" id="testimonials">
<div class="container">
<div class="section-head section-head--split" data-reveal>
<div>
<span class="eyebrow"><span class="no">06</span> Social Proof</span>
<h2>Trusted by Businesses Worldwide</h2>
<p>Real stories from restaurant owners, marketers, and designers using QR Master.</p>
</div>
<div class="side-note">4.9/5 Rating : 12 Verified Reviews</div>
</div>
</div>
<div class="marquee-mask">
<div class="marquee-track" id="marqueeTrack"></div>
</div>
<div class="center-cta" style="margin-top:20px" data-reveal>
<a class="btn btn-ghost btn-sm" href="https://www.qrmaster.net/testimonials">Read All 12 Customer Stories
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14m-7-7 7 7-7 7"/></svg>
</a>
</div>
</section>
<!-- ==================== STATIC VS DYNAMIC MATRIX ==================== -->
<section class="section" id="compare">
<div class="container">
<div class="section-head section-head--split" data-reveal>
<div>
<span class="eyebrow"><span class="no">07</span> Feature Comparison</span>
<h2>Why Dynamic QR Codes Save You Money</h2>
<p>Stop re-printing physical materials every time a URL changes. Update destination links instantly and track every scan.</p>
</div>
<div class="side-note">Static = Fixed Forever : Dynamic = Editable Forever</div>
</div>
<div class="cmp" data-reveal>
<div class="cmp-row cmp-head">
<div></div>
<div class="ttl-cell"><div class="ttl">Static QR</div><div class="sub">Always Free</div></div>
<div class="dyn"><div class="ttl">Dynamic QR</div><div class="sub">Recommended</div></div>
</div>
<div class="cmp-row">
<div class="cmp-cap">Edit Destination URL Anytime</div>
<div><span class="cmp-no">Fixed Forever</span></div>
<div class="dyn-cell"><span class="cmp-yes">YES (Instant)</span></div>
</div>
<div class="cmp-row">
<div class="cmp-cap">Real-Time Scan Analytics<span class="cmp-note">Time, device type, location</span></div>
<div><span class="cmp-no">Not Available</span></div>
<div class="dyn-cell"><span class="cmp-yes">YES</span></div>
</div>
<div class="cmp-row">
<div class="cmp-cap">Custom Branding &amp; Logo Overlay</div>
<div><span class="cmp-no">Basic Only</span></div>
<div class="dyn-cell"><span class="cmp-yes">YES</span></div>
</div>
<div class="cmp-row">
<div class="cmp-cap">Bulk Creation from Excel/CSV</div>
<div><span class="cmp-no">Manual Only</span></div>
<div class="dyn-cell"><span class="cmp-yes">YES</span></div>
</div>
<div class="cmp-row">
<div class="cmp-cap">No Account Required to Create<span class="cmp-note">Dynamic account signup takes under 60 seconds</span></div>
<div><span class="cmp-yes">YES</span></div>
<div class="dyn-cell"><span class="cmp-no">Free Account</span></div>
</div>
</div>
</div>
</section>
<!-- ==================== INTERACTIVE ROI CALCULATOR ==================== -->
<section class="section section--tight" id="roi">
<div class="container">
<div class="roi-card" data-reveal>
<div class="roi-left">
<span class="eyebrow"><span class="no">08</span> Interactive ROI Calculator</span>
<h2>Are you burning budget on <mark>static reprints?</mark></h2>
<p>Estimate your annual print savings by switching from static printed codes to dynamic QR codes.</p>
<div class="field">
<label for="roiPrints">Total Print Items (e.g. Menus, Flyers, Cards): <strong id="roiPrintsVal">2,500</strong></label>
<input class="range" id="roiPrints" type="range" min="200" max="25000" step="100" value="2500">
</div>
<div class="field">
<label for="roiUpdates">Annual URL/Destination Updates: <strong id="roiUpdatesVal">3x per year</strong></label>
<input class="range" id="roiUpdates" type="range" min="1" max="12" step="1" value="3">
</div>
<a class="btn btn-primary" href="https://www.qrmaster.net/reprint-calculator" data-magnetic>Calculate Custom Campaign ROI
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14m-7-7 7 7-7 7"/></svg>
</a>
</div>
<div class="roi-right">
<span class="lbl">Estimated Annual Savings</span>
<span class="big-savings" id="roiSavingsVal">€1,125</span>
<span class="lbl">*Based on average €0.15 print cost per unit, industry estimate</span>
</div>
</div>
</div>
</section>
<!-- ==================== FEATURES GRID ==================== -->
<section class="section alt-bg" id="features">
<div class="container">
<div class="section-head" data-reveal>
<span class="eyebrow"><span class="no">09</span> Platform Highlights</span>
<h2>Everything You Need for Professional QR Campaigns</h2>
</div>
<div class="feat-grid">
<div class="feat" data-reveal>
<span class="no">F/01</span>
<h3>Real-Time Scan Analytics</h3>
<p>Track total scans, device breakdown, geographic locations, and time trends in an intuitive dashboard.</p>
</div>
<div class="feat" data-reveal>
<span class="no">F/02</span>
<h3>Full Brand Customization</h3>
<p>Customize colors, corner styles, and add your company logo for seamless visual brand alignment.</p>
</div>
<div class="feat" data-reveal>
<span class="no">F/03</span>
<h3>Unlimited Static QR Codes</h3>
<p>Generate as many static QR codes as your project needs. Free forever with zero limits or expiration.</p>
</div>
</div>
</div>
</section>
<!-- ==================== PRICING MATRIX ==================== -->
<section class="section" id="pricing">
<div class="container">
<div class="section-head section-head--split" data-reveal>
<div>
<span class="eyebrow"><span class="no">10</span> Transparent Pricing</span>
<h2>Choose the Perfect Plan</h2>
<p>Simple pricing with no hidden fees. Upgrade or downgrade anytime.</p>
</div>
<div class="side-note">All Plans Include Unlimited Static Codes</div>
</div>
<div style="text-align:center" data-reveal>
<div class="billing-toggle">
<span class="opt active" id="optMonthly">Monthly Billing</span>
<button class="switch" id="billingSwitch" role="switch" aria-checked="false" aria-label="Toggle yearly billing"></button>
<span class="opt" id="optYearly">Yearly Billing</span>
<span class="save-tag" id="saveTag">Save 16%</span>
</div>
</div>
<div class="price-grid">
<div class="panel price-card" data-reveal>
<div class="price-name">Free Plan</div>
<div class="price-row"><span class="price-val">€0</span><span class="price-per">Forever</span></div>
<ul class="price-feats">
<li>3 active dynamic QR codes (8 types)</li>
<li>Unlimited static QR codes</li>
<li>Basic scan tracking</li>
<li>Standard styling presets</li>
<li>High-res SVG &amp; PNG export</li>
</ul>
<a class="btn btn-ghost" href="https://www.qrmaster.net/signup">Get Started Free</a>
<p style="text-align:center;margin-top:10px;font-family:var(--font-mono);font-size:10.5px;color:var(--muted);text-transform:uppercase;letter-spacing:0.06em;">No credit card required</p>
</div>
<div class="panel price-card popular" data-reveal>
<span class="pop-tag">Most Popular</span>
<div class="price-name">Pro Plan</div>
<div class="price-row"><span class="price-val" data-monthly="€9" data-yearly="€90">€9</span><span class="price-per" data-monthly="per month" data-yearly="per year">per month</span></div>
<ul class="price-feats">
<li>50 dynamic QR codes</li>
<li>Unlimited static QR codes</li>
<li>Advanced scan analytics</li>
<li>Custom branding &amp; logo overlay</li>
<li>CSV scan reports export</li>
</ul>
<a class="btn btn-primary" href="https://www.qrmaster.net/signup">Start 14-Day Free Trial</a>
<p style="text-align:center;margin-top:10px;font-family:var(--font-mono);font-size:10.5px;color:var(--deep-muted);text-transform:uppercase;letter-spacing:0.06em;">No credit card required</p>
</div>
<div class="panel price-card" data-reveal>
<div class="price-name">Business Plan</div>
<div class="price-row"><span class="price-val" data-monthly="€29" data-yearly="€290">€29</span><span class="price-per" data-monthly="per month" data-yearly="per year">per month</span></div>
<ul class="price-feats">
<li>500 dynamic QR codes</li>
<li>Unlimited static QR codes</li>
<li>Everything in Pro</li>
<li>Bulk QR Generator (up to 1,000)</li>
<li>Priority support</li>
</ul>
<a class="btn btn-ghost" href="https://www.qrmaster.net/signup">Get Started</a>
</div>
<div class="panel price-card" data-reveal>
<div class="price-name">Enterprise</div>
<div class="price-row"><span class="price-val" style="font-size:2rem">Custom</span></div>
<ul class="price-feats">
<li>Unlimited dynamic QR codes</li>
<li>Unlimited static QR codes</li>
<li>Custom API integration</li>
<li>Dedicated Account Manager</li>
<li>SLA &amp; custom contract</li>
</ul>
<a class="btn btn-ghost" href="mailto:timo@qrmaster.net">Contact Sales</a>
</div>
</div>
<p style="text-align:center;margin-top:32px;font-family:var(--font-mono);font-size:11px;color:var(--muted);text-transform:uppercase;" data-reveal>All plans include high-resolution vector export and full privacy compliance.</p>
</div>
</section>
<!-- ==================== FAQ ==================== -->
<section class="section alt-bg" id="faq">
<div class="container">
<div class="section-head" data-reveal>
<span class="eyebrow"><span class="no">11</span> FAQ</span>
<h2>Frequently Asked Questions</h2>
</div>
<div class="faq-list">
<div class="faq-item" data-reveal>
<button class="faq-q" aria-expanded="false">
Do I need an account to create QR codes?
<span class="pm" aria-hidden="true">+</span>
</button>
<div class="faq-a"><div><p>No account is required to generate static QR codes. Dynamic QR codes with scan tracking and editing capabilities require a free account.</p></div></div>
</div>
<div class="faq-item" data-reveal>
<button class="faq-q" aria-expanded="false">
What is the difference between static and dynamic QR codes?
<span class="pm" aria-hidden="true">+</span>
</button>
<div class="faq-a"><div><p>Static QR codes hold fixed data embedded directly in the code matrix. Dynamic QR codes route through a short URL so you can edit the destination anytime without reprinting.</p></div></div>
</div>
<div class="faq-item" data-reveal>
<button class="faq-q" aria-expanded="false">
Will static QR codes work forever?
<span class="pm" aria-hidden="true">+</span>
</button>
<div class="faq-a"><div><p>Yes. Static QR codes contain raw data (like plain text or URLs) and never expire as long as the destination URL remains active.</p></div></div>
</div>
<div class="faq-item" data-reveal>
<button class="faq-q" aria-expanded="false">
Which format should I download for printing?
<span class="pm" aria-hidden="true">+</span>
</button>
<div class="faq-a"><div><p>For commercial print (flyers, signs, packaging), SVG is recommended because vector graphics scale losslessly to any size.</p></div></div>
</div>
<div class="faq-item" data-reveal>
<button class="faq-q" aria-expanded="false">
Is QR Master GDPR compliant?
<span class="pm" aria-hidden="true">+</span>
</button>
<div class="faq-a"><div><p>Yes. Scan analytics process aggregated technical metadata (country, device type) without storing personally identifiable user data.</p></div></div>
</div>
</div>
<div class="center-cta" style="margin-top:32px" data-reveal>
<a class="btn btn-ghost btn-sm" href="https://www.qrmaster.net/faq">View Full Help Center &amp; FAQ
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14m-7-7 7 7-7 7"/></svg>
</a>
</div>
</div>
</section>
<!-- ==================== FINAL CTA ==================== -->
<section class="section final-cta">
<div class="container">
<span class="eyebrow" data-reveal><span class="no">12</span> GET STARTED</span>
<h2 data-reveal>Your next QR code is <mark>30 seconds away.</mark></h2>
<p data-reveal>Static codes free forever. Dynamic codes with analytics starting at €0.</p>
<a class="btn btn-primary" data-reveal data-magnetic href="https://www.qrmaster.net/signup" style="font-size:1.0625rem;padding:18px 40px">Create a QR Code Free
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14m-7-7 7 7-7 7"/></svg>
</a>
</div>
</section>
<!-- ==================== FOOTER ==================== -->
<footer class="footer">
<div class="container">
<div class="footer-grid">
<div class="footer-brand">
<a class="logo" href="#top" data-scroll>
<span class="logo-mark" aria-hidden="true">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round">
<rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/>
<rect x="3" y="14" width="7" height="7" rx="1"/><path d="M14 14h3v3h-3zM21 14v.01M14 21v.01M21 21v.01M18 18h3"/>
</svg>
</span>
QR&nbsp;Master
</a>
<p>Free dynamic QR code generator with tracking, editable destinations, custom branding, and bulk creation.</p>
</div>
<div class="footer-col">
<h4>Product</h4>
<ul>
<li><a href="https://www.qrmaster.net/dynamic-qr-code-generator">Dynamic Generator</a></li>
<li><a href="https://www.qrmaster.net/bulk-qr-code-generator">Bulk Generator</a></li>
<li><a href="https://www.qrmaster.net/pricing">Pricing</a></li>
<li><a href="https://www.qrmaster.net/alternatives">Alternatives</a></li>
</ul>
</div>
<div class="footer-col">
<h4>Free Tools</h4>
<ul>
<li><a href="https://www.qrmaster.net/tools/barcode-generator">Barcode Generator</a></li>
<li><a href="https://www.qrmaster.net/tools/wifi-qr-code">WiFi QR Code</a></li>
<li><a href="https://www.qrmaster.net/tools/vcard-qr-code">vCard QR Code</a></li>
<li><a href="https://www.qrmaster.net/tools/google-review-qr-code">Google Review QR</a></li>
</ul>
</div>
<div class="footer-col">
<h4>Company</h4>
<ul>
<li><a href="https://www.qrmaster.net/about">About</a></li>
<li><a href="https://www.qrmaster.net/blog">Blog</a></li>
<li><a href="https://www.qrmaster.net/contact">Contact</a></li>
<li><a href="https://www.qrmaster.net/testimonials">Testimonials</a></li>
</ul>
</div>
<div class="footer-col">
<h4>Legal</h4>
<ul>
<li><a href="https://www.qrmaster.net/privacy">Privacy Policy</a></li>
<li><a href="https://www.qrmaster.net/terms">Terms of Service</a></li>
<li><a href="https://www.qrmaster.net/cookie-policy">Cookie Policy</a></li>
</ul>
</div>
</div>
<div class="footer-bottom">
<span>© 2026 QR Master. All rights reserved.</span>
<span>GDPR Compliant : SSL Secured : 4.9/5 Customer Rating</span>
</div>
</div>
</footer>
<!-- ==================== LIBRARIES & INTERACTIVE APP JS ==================== -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/qrcode-generator/1.4.4/qrcode.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/ScrollTrigger.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/ScrollToPlugin.min.js"></script>
<script>
(function () {
'use strict';
var REDUCED = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
var FINE_POINTER = window.matchMedia('(pointer: fine)').matches;
var HAS_GSAP = typeof window.gsap !== 'undefined';
var HAS_ST = HAS_GSAP && typeof window.ScrollTrigger !== 'undefined';
if (HAS_ST) gsap.registerPlugin(ScrollTrigger, ScrollToPlugin);
var root = document.documentElement;
/* Mouse Follow Ambient Spotlight (21st.dev Hero Effect) */
var spotlight = document.getElementById('heroSpotlight');
if (spotlight && FINE_POINTER && !REDUCED) {
window.addEventListener('mousemove', function (e) {
spotlight.style.setProperty('--mouse-x', e.clientX + 'px');
spotlight.style.setProperty('--mouse-y', e.clientY + 'px');
}, { passive: true });
}
/* Mobile Nav Toggle */
var navBurger = document.getElementById('navBurger');
var navMobilePanel = document.getElementById('navMobilePanel');
if (navBurger && navMobilePanel) {
function closeMobileNav() {
navBurger.setAttribute('aria-expanded', 'false');
navMobilePanel.classList.remove('open');
}
navBurger.addEventListener('click', function () {
var open = navBurger.getAttribute('aria-expanded') === 'true';
navBurger.setAttribute('aria-expanded', String(!open));
navMobilePanel.classList.toggle('open', !open);
});
navMobilePanel.querySelectorAll('[data-mobile-nav]').forEach(function (a) {
a.addEventListener('click', closeMobileNav);
});
document.addEventListener('keydown', function (e) {
if (e.key === 'Escape') closeMobileNav();
});
window.addEventListener('resize', function () {
if (window.innerWidth > 900) closeMobileNav();
}, { passive: true });
}
/* Animated Blueprint Particle Canvas Background (skipped on narrow/mobile viewports for perf) */
var bgCanvas = document.getElementById('heroBgCanvas');
if (bgCanvas && !REDUCED && window.innerWidth > 900) {
var ctx = bgCanvas.getContext('2d');
var pts = [];
var numPts = 42;
var mouse = { x: -1000, y: -1000 };
function initPts() {
bgCanvas.width = bgCanvas.offsetWidth || window.innerWidth;
bgCanvas.height = bgCanvas.offsetHeight || window.innerHeight;
pts = [];
for (var i = 0; i < numPts; i++) {
pts.push({
x: Math.random() * bgCanvas.width,
y: Math.random() * bgCanvas.height,
vx: (Math.random() - 0.5) * 0.35,
vy: (Math.random() - 0.5) * 0.35,
r: Math.random() * 1.6 + 1
});
}
}
initPts();
window.addEventListener('resize', initPts, { passive: true });
if (FINE_POINTER) {
window.addEventListener('mousemove', function (e) {
var rect = bgCanvas.getBoundingClientRect();
mouse.x = e.clientX - rect.left;
mouse.y = e.clientY - rect.top;
}, { passive: true });
}
function animateBg() {
if (!ctx || bgCanvas.width === 0) return;
ctx.clearRect(0, 0, bgCanvas.width, bgCanvas.height);
var isDark = root.getAttribute('data-theme') === 'dark';
var dotColor = isDark ? 'rgba(96, 165, 250, 0.4)' : 'rgba(37, 99, 235, 0.25)';
var lineColor = isDark ? 'rgba(96, 165, 250, 0.08)' : 'rgba(37, 99, 235, 0.06)';
for (var i = 0; i < pts.length; i++) {
var p = pts[i];
p.x += p.vx;
p.y += p.vy;
if (p.x < 0 || p.x > bgCanvas.width) p.vx *= -1;
if (p.y < 0 || p.y > bgCanvas.height) p.vy *= -1;
if (FINE_POINTER) {
var dx = mouse.x - p.x, dy = mouse.y - p.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 160) {
p.x += (dx / dist) * 0.15;
p.y += (dy / dist) * 0.15;
}
}
ctx.beginPath();
ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2);
ctx.fillStyle = dotColor;
ctx.fill();
for (var j = i + 1; j < pts.length; j++) {
var p2 = pts[j];
var d = Math.hypot(p.x - p2.x, p.y - p2.y);
if (d < 115) {
ctx.beginPath();
ctx.moveTo(p.x, p.y);
ctx.lineTo(p2.x, p2.y);
ctx.strokeStyle = lineColor;
ctx.lineWidth = 0.75;
ctx.stroke();
}
}
}
requestAnimationFrame(animateBg);
}
animateBg();
}
/* Theme Switcher */
var storedTheme = null;
try { storedTheme = localStorage.getItem('qm-theme'); } catch (e) {}
if (storedTheme === 'light' || storedTheme === 'dark') root.setAttribute('data-theme', storedTheme);
document.getElementById('themeToggle').addEventListener('click', function () {
var next = root.getAttribute('data-theme') === 'dark' ? 'light' : 'dark';
root.setAttribute('data-theme', next);
try { localStorage.setItem('qm-theme', next); } catch (e) {}
});
/* Nav & Progress Indicator */
var nav = document.getElementById('nav');
var progressBar = document.getElementById('progressBar');
function onScroll() {
nav.classList.toggle('scrolled', window.scrollY > 20);
var h = document.documentElement.scrollHeight - window.innerHeight;
progressBar.style.transform = 'scaleX(' + (h > 0 ? window.scrollY / h : 0) + ')';
}
window.addEventListener('scroll', onScroll, { passive: true });
onScroll();
/* Smooth Scrolling */
document.querySelectorAll('[data-scroll]').forEach(function (a) {
a.addEventListener('click', function (e) {
var id = a.getAttribute('href');
if (!id || id.charAt(0) !== '#') return;
var target = document.querySelector(id);
if (!target) return;
e.preventDefault();
if (HAS_ST && !REDUCED) {
gsap.to(window, { duration: 0.8, ease: 'power3.inOut', scrollTo: { y: target, offsetY: 68 } });
} else {
target.scrollIntoView({ behavior: REDUCED ? 'auto' : 'smooth', block: 'start' });
}
});
});
/* QR Core Rendering helper */
var HAS_QR = typeof window.qrcode !== 'undefined';
function makeQr(text) {
if (!HAS_QR) return null;
try {
var qr = window.qrcode(0, 'M');
qr.addData(text);
qr.make();
return qr;
} catch (e) { return null; }
}
function paintQr(canvas, qr, fg, bg, marginModules) {
var ctx = canvas.getContext('2d');
var n = qr.getModuleCount(), m = marginModules || 4;
var cell = canvas.width / (n + m * 2);
ctx.fillStyle = bg;
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = fg;
for (var row = 0; row < n; row++) {
for (var col = 0; col < n; col++) {
if (qr.isDark(row, col)) {
ctx.fillRect(Math.floor((col + m) * cell), Math.floor((row + m) * cell), Math.ceil(cell), Math.ceil(cell));
}
}
}
}
/* Render Hero Specimen Poster */
var heroCanvas = document.getElementById('heroQr');
var heroQrEcho = document.getElementById('heroQrEcho');
function updateHeroQr(text) {
if (!heroCanvas) return;
var qr = makeQr(text);
if (qr) paintQr(heroCanvas, qr, '#0B132B', '#ffffff', 4);
if (heroQrEcho) heroQrEcho.textContent = text;
}
updateHeroQr('https://www.qrmaster.net');
/* Hero Type Selector Chips */
document.querySelectorAll('.type-chip').forEach(function (chip) {
chip.addEventListener('click', function () {
document.querySelectorAll('.type-chip').forEach(function (c) { c.classList.remove('active'); });
chip.classList.add('active');
var type = chip.getAttribute('data-type');
var sampleUrls = {
url: 'https://www.qrmaster.net',
vcard: 'BEGIN:VCARD\nFN:Timo Master\nTEL:+49123456789\nEND:VCARD',
wifi: 'WIFI:S:MyNetwork;T:WPA;P:SecretPassword;;',
pdf: 'https://www.qrmaster.net/sample-document.pdf',
event: 'https://www.qrmaster.net/event-registration',
coupon: 'https://www.qrmaster.net/claim-discount-20',
app: 'https://apps.apple.com/app/qrmaster',
call: 'tel:+49123456789'
};
var target = sampleUrls[type] || 'https://www.qrmaster.net';
updateHeroQr(target);
});
});
/* Data lists */
var ARROW = '<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M7 17 17 7M8 7h9v9"/></svg>';
var TOOLS = [
{ name: 'URL Generator', desc: 'Open any web destination', href: 'https://www.qrmaster.net/tools/url-qr-code' },
{ name: 'vCard Contact', desc: 'Share contact details instantly',href: 'https://www.qrmaster.net/tools/vcard-qr-code' },
{ name: 'WiFi Connect', desc: 'Join WiFi network without password', href: 'https://www.qrmaster.net/tools/wifi-qr-code' },
{ name: 'Plain Text', desc: 'Display unformatted text', href: 'https://www.qrmaster.net/tools/text-qr-code' },
{ name: 'Email Dispatch', desc: 'Pre-fill email recipient & subject', href: 'https://www.qrmaster.net/tools/email-qr-code' },
{ name: 'SMS Text', desc: 'Send a pre-written text message', href: 'https://www.qrmaster.net/tools/sms-qr-code' },
{ name: 'Crypto Wallet', desc: 'Receive crypto payments', href: 'https://www.qrmaster.net/tools/crypto-qr-code' },
{ name: 'Calendar Event', desc: 'Save event to calendar', href: 'https://www.qrmaster.net/tools/event-qr-code' },
{ name: 'Facebook Page', desc: 'Direct scans to Facebook page', href: 'https://www.qrmaster.net/tools/facebook-qr-code' },
{ name: 'Instagram', desc: 'Open Instagram profile', href: 'https://www.qrmaster.net/tools/instagram-qr-code' },
{ name: 'YouTube Channel', desc: 'Open YouTube video or channel', href: 'https://www.qrmaster.net/tools/youtube-qr-code' },
{ name: 'WhatsApp Message', desc: 'Start a WhatsApp chat', href: 'https://www.qrmaster.net/tools/whatsapp-qr-code' },
{ name: 'TikTok Link', desc: 'Open TikTok profile', href: 'https://www.qrmaster.net/tools/tiktok-qr-code' },
{ name: 'Geolocation GPS', desc: 'Share map coordinates', href: 'https://www.qrmaster.net/tools/geolocation-qr-code' },
{ name: 'Phone Call', desc: 'Initiate a direct phone call', href: 'https://www.qrmaster.net/tools/call-qr-code-generator' },
{ name: 'Google Review', desc: 'Collect customer reviews', href: 'https://www.qrmaster.net/tools/google-review-qr-code' },
{ name: 'Barcode Generator', desc: 'Online EAN & UPC barcodes', href: 'https://www.qrmaster.net/tools/barcode-generator' },
{ name: 'Teams Meeting', desc: 'Join MS Teams call', href: 'https://www.qrmaster.net/tools/teams-qr-code' }
];
var WORKFLOWS = [
{ title: 'Dynamic QR Code Generator', desc: 'Create editable QR codes with tracking and zero reprint workflow.', href: 'https://www.qrmaster.net/dynamic-qr-code-generator' },
{ title: 'Bulk QR Code Generator', desc: 'Generate thousands of unique QR codes from Excel/CSV rows.', href: 'https://www.qrmaster.net/bulk-qr-code-generator' },
{ title: 'Barcode Generator Studio', desc: 'Create EAN-13, UPC-A, and Code 128 barcodes online.', href: 'https://www.qrmaster.net/tools/barcode-generator' },
{ title: 'QR Code Platform Comparison', desc: 'Compare QR Master features with Bitly, Beaconstac, and Flowcode.', href: 'https://www.qrmaster.net/alternatives' },
{ title: 'Teams Meeting QR Generator', desc: 'Create instant access QR codes for Microsoft Teams meetings.', href: 'https://www.qrmaster.net/tools/teams-qr-code' },
{ title: 'WiFi Guest QR Code', desc: 'Let restaurant & hotel guests scan once to join WiFi.', href: 'https://www.qrmaster.net/tools/wifi-qr-code' },
{ title: 'QR Code Erstellen', desc: 'German language QR code generator page.', href: 'https://www.qrmaster.net/qr-code-erstellen' },
{ title: 'Scan Analytics & Tracking', desc: 'Track QR scan counts by time, device, and location context.', href: 'https://www.qrmaster.net/qr-code-tracking' }
];
var USE_CASES = [
{ title: 'Hotels & Hospitality', desc: 'Route guests to current room-service menus and check-in flows.', href: 'https://www.qrmaster.net/use-cases/qr-codes-for-hotel' },
{ title: 'Barbershops & Salons', desc: 'Keep booking routes current on windows without reprinting cards.', href: 'https://www.qrmaster.net/use-cases/qr-codes-for-barbershops' },
{ title: 'Business Cards', desc: 'Direct contacts to an up-to-date vCard or booking page.', href: 'https://www.qrmaster.net/use-cases/business-card-qr-codes' },
{ title: 'Events & Conferences', desc: 'Manage schedules and venue maps live on event day.', href: 'https://www.qrmaster.net/use-cases/event-qr-codes' },
{ title: 'Print Flyers & Posters', desc: 'Compare flyer placements and rotate promotional offers.', href: 'https://www.qrmaster.net/use-cases/flyer-qr-codes' },
{ title: 'Product Packaging', desc: 'Connect packaging inserts to manuals and support chat.', href: 'https://www.qrmaster.net/use-cases/packaging-qr-codes' },
{ title: 'Real Estate Signs', desc: 'Update listing info instantly on outdoor yard signs.', href: 'https://www.qrmaster.net/use-cases/real-estate-sign-qr-codes' },
{ title: 'Customer Feedback', desc: 'Capture in-store reviews and measure location responses.', href: 'https://www.qrmaster.net/use-cases/feedback-qr-codes' }
];
var TESTIMONIALS = [
{ rating: 5, title: 'Perfect for my pottery shop', content: 'I place QR Master codes directly on my pottery pieces so customers can instantly view my website and contact details. Extremely practical solution!', name: 'Claudia', role: 'Studio Owner', location: 'Texas, USA' },
{ rating: 5, title: 'No more reprinting menus', content: 'We used to reprint paper menus every time prices changed. With QR Master, I update the PDF link online and table codes update instantly. Saved us hundreds of Euros!', name: 'Thomas B.', role: 'Restaurant Owner', location: 'Hamburg, Germany' },
{ rating: 5, title: 'Measurable ROI on print campaigns', content: 'Print used to be a black box for our marketing team. QR Master scan analytics let us see exactly which flyer and location generated traffic.', name: 'Sarah M.', role: 'Head of Marketing', location: 'Berlin, Germany' },
{ rating: 5, title: '800 unique codes in 3 minutes', content: 'We needed individual QR codes for product packaging. I uploaded a CSV spreadsheet and generated all 800 codes instantly.', name: 'Jennifer K.', role: 'Operations Manager', location: 'London, UK' },
{ rating: 5, title: 'Essential for event management', content: 'We run 20+ corporate events per year. When venue schedules change last minute, we update the destination URL without reprinting posters.', name: 'Marco F.', role: 'Event Director', location: 'Munich, Germany' },
{ rating: 5, title: 'Strict GDPR compliance', content: 'Our legal team approved QR Master because it hashes IP addresses and respects user privacy. Highly recommended for European companies.', name: 'Stefan W.', role: 'Data Protection Officer', location: 'Frankfurt, Germany' }
];
function el(htmlStr) {
var t = document.createElement('template');
t.innerHTML = htmlStr.trim();
return t.content.firstChild;
}
/* Render Tools List with Filter */
var toolsGrid = document.getElementById('toolsGrid');
function renderTools(filterText) {
if (!toolsGrid) return;
toolsGrid.innerHTML = '';
var q = (filterText || '').toLowerCase().trim();
var count = 0;
TOOLS.forEach(function (t, i) {
if (q && t.name.toLowerCase().indexOf(q) === -1 && t.desc.toLowerCase().indexOf(q) === -1) return;
count++;
toolsGrid.appendChild(el(
'<a class="tool-row" href="' + t.href + '" data-reveal>' +
'<span class="idx">' + ('0' + count).slice(-2) + '</span>' +
'<h3>' + t.name + '</h3><p>' + t.desc + '</p>' +
'<span class="arr">' + ARROW + '</span>' +
'</a>'
));
});
if (count === 0) {
toolsGrid.innerHTML = '<div style="padding:32px;text-align:center;color:var(--muted);font-family:var(--font-mono);font-size:12px;">No matching tools found. Try searching "WiFi", "vCard", or "URL".</div>';
}
}
renderTools('');
var toolSearch = document.getElementById('toolSearch');
if (toolSearch) {
toolSearch.addEventListener('input', function () { renderTools(toolSearch.value); });
}
/* Render Link Cards */
function renderLinkCards(targetId, items) {
var grid = document.getElementById(targetId);
if (!grid) return;
items.forEach(function (item, i) {
grid.appendChild(el(
'<a class="panel panel-hover link-card" href="' + item.href + '" data-reveal>' +
'<span class="go">' + ARROW + '</span>' +
'<span class="idx">' + ('0' + (i + 1)).slice(-2) + '</span>' +
'<h3>' + item.title + '</h3><p>' + item.desc + '</p>' +
'</a>'
));
});
}
renderLinkCards('workflowGrid', WORKFLOWS);
renderLinkCards('useCaseGrid', USE_CASES);
/* Render Testimonials Marquee */
function stars(rating) {
var s = '<div class="stars" role="img" aria-label="' + rating + ' out of 5 stars">';
for (var i = 0; i < 5; i++) s += i < rating ? '★' : '<span class="off">★</span>';
return s + '</div>';
}
var track = document.getElementById('marqueeTrack');
if (track) {
TESTIMONIALS.concat(TESTIMONIALS).forEach(function (t) {
track.appendChild(el(
'<div class="panel testi-card">' +
'<div class="testi-top">' + stars(t.rating) + '<span class="verified">Verified</span></div>' +
'<h3>&ldquo;' + t.title + '&rdquo;</h3>' +
'<p>' + t.content + '</p>' +
'<div class="testi-author"><b>' + t.name + '</b><span>' + t.role + ' : ' + t.location + '</span></div>' +
'</div>'
));
});
}
/* Interactive Generator Studio */
(function generator() {
var urlInput = document.getElementById('qrUrl');
var fgColor = document.getElementById('fgColor'), fgHex = document.getElementById('fgHex');
var bgColor = document.getElementById('bgColor'), bgHex = document.getElementById('bgHex');
var corners = document.getElementById('cornerStyle');
var sizeInput = document.getElementById('qrSize'), sizeVal = document.getElementById('sizeVal');
var holder = document.getElementById('qrHolder');
var canvas = document.getElementById('qrCanvas');
var echo = document.getElementById('qrUrlEcho');
var badge = document.getElementById('contrastBadge');
var contrastVal = document.getElementById('contrastVal');
var debounce = null;
function normHex(v) {
v = (v || '').trim();
if (v.charAt(0) !== '#') v = '#' + v;
return /^#[0-9a-fA-F]{6}$/.test(v) ? v.toLowerCase() : null;
}
function luminance(hex) {
var r = parseInt(hex.slice(1, 3), 16) / 255;
var g = parseInt(hex.slice(3, 5), 16) / 255;
var b = parseInt(hex.slice(5, 7), 16) / 255;
function ch(v) { return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4); }
return 0.2126 * ch(r) + 0.7152 * ch(g) + 0.0722 * ch(b);
}
function contrast(a, b) {
var l1 = luminance(a), l2 = luminance(b);
return (Math.max(l1, l2) + 0.05) / (Math.min(l1, l2) + 0.05);
}
function state() {
return {
url: urlInput ? urlInput.value.trim() : 'https://www.qrmaster.net',
fg: normHex(fgHex.value) || '#0B132B',
bg: normHex(bgHex.value) || '#ffffff',
size: parseInt(sizeInput.value, 10) || 230
};
}
function render() {
if (!canvas) return;
var s = state();
if (sizeVal) sizeVal.textContent = s.size;
if (echo) echo.textContent = s.url || 'https://www.qrmaster.net';
if (holder) holder.style.borderRadius = corners.value === 'rounded' ? '12px' : '0px';
var c = contrast(s.fg, s.bg);
var ok = c >= 4.5;
if (badge) {
badge.textContent = ok ? 'Good contrast' : 'Low contrast';
badge.className = 'contrast-badge ' + (ok ? 'ok' : 'bad');
}
if (contrastVal) contrastVal.textContent = c.toFixed(1) + ':1';
var scale = 2;
canvas.style.width = s.size + 'px';
canvas.style.height = s.size + 'px';
canvas.width = s.size * scale;
canvas.height = s.size * scale;
var qr = makeQr(s.url || 'https://www.qrmaster.net');
if (!qr) return;
paintQr(canvas, qr, s.fg, s.bg, 4);
}
function queue() {
clearTimeout(debounce);
debounce = setTimeout(render, 120);
}
function bindColor(picker, hex) {
if (!picker || !hex) return;
picker.addEventListener('input', function () { hex.value = picker.value; queue(); });
hex.addEventListener('input', function () {
var v = normHex(hex.value);
if (v) picker.value = v;
queue();
});
}
bindColor(fgColor, fgHex);
bindColor(bgColor, bgHex);
var swatchBtns = document.querySelectorAll('.swatch-btn');
swatchBtns.forEach(function (btn) {
btn.addEventListener('click', function () {
var fg = btn.getAttribute('data-fg');
var bg = btn.getAttribute('data-bg');
if (fg && fgColor && fgHex) { fgColor.value = fg; fgHex.value = fg; }
if (bg && bgColor && bgHex) { bgColor.value = bg; bgHex.value = bg; }
swatchBtns.forEach(function (b) { b.classList.remove('active'); b.setAttribute('aria-pressed', 'false'); });
btn.classList.add('active');
btn.setAttribute('aria-pressed', 'true');
render();
});
});
if (fgHex) {
fgHex.addEventListener('input', function () {
swatchBtns.forEach(function (b) { b.classList.remove('active'); b.setAttribute('aria-pressed', 'false'); });
});
}
if (urlInput) urlInput.addEventListener('input', queue);
if (corners) corners.addEventListener('change', queue);
if (sizeInput) sizeInput.addEventListener('input', queue);
function triggerDownload(href, name) {
var a = document.createElement('a');
a.href = href; a.download = name;
document.body.appendChild(a); a.click(); document.body.removeChild(a);
setTimeout(function () { URL.revokeObjectURL(href); }, 1000);
}
var dlSvg = document.getElementById('dlSvg');
if (dlSvg) {
dlSvg.addEventListener('click', function () {
var s = state();
var qr = makeQr(s.url || 'https://www.qrmaster.net');
if (!qr) return;
var n = qr.getModuleCount(), margin = 4, cell = 10;
var dim = (n + margin * 2) * cell;
var rects = '';
for (var row = 0; row < n; row++) {
for (var col = 0; col < n; col++) {
if (qr.isDark(row, col)) {
rects += '<rect x="' + ((col + margin) * cell) + '" y="' + ((row + margin) * cell) + '" width="' + cell + '" height="' + cell + '"/>';
}
}
}
var svg = '<?xml version="1.0" encoding="UTF-8"?>\n' +
'<svg xmlns="http://www.w3.org/2000/svg" width="' + dim + '" height="' + dim + '" viewBox="0 0 ' + dim + ' ' + dim + '">' +
'<rect width="' + dim + '" height="' + dim + '" fill="' + s.bg + '"/>' +
'<g fill="' + s.fg + '">' + rects + '</g></svg>';
triggerDownload(URL.createObjectURL(new Blob([svg], { type: 'image/svg+xml' })), 'qrcode.svg');
});
}
var dlPng = document.getElementById('dlPng');
if (dlPng) {
dlPng.addEventListener('click', function () {
var s = state();
var qr = makeQr(s.url || 'https://www.qrmaster.net');
if (!qr) return;
var out = document.createElement('canvas');
var px = Math.max(s.size, 512);
out.width = px; out.height = px;
paintQr(out, qr, s.fg, s.bg, 4);
out.toBlob(function (blob) {
if (blob) triggerDownload(URL.createObjectURL(blob), 'qrcode.png');
});
});
}
render();
})();
/* Interactive ROI Calculator */
(function roiCalculator() {
var printsInput = document.getElementById('roiPrints');
var updatesInput = document.getElementById('roiUpdates');
var printsVal = document.getElementById('roiPrintsVal');
var updatesVal = document.getElementById('roiUpdatesVal');
var savingsVal = document.getElementById('roiSavingsVal');
function updateRoi() {
if (!printsInput || !updatesInput) return;
var prints = parseInt(printsInput.value, 10);
var updates = parseInt(updatesInput.value, 10);
if (printsVal) printsVal.textContent = prints.toLocaleString();
if (updatesVal) updatesVal.textContent = updates + 'x per year';
var annualSavings = Math.round(prints * updates * 0.15);
if (savingsVal) savingsVal.textContent = '€' + annualSavings.toLocaleString();
}
if (printsInput) printsInput.addEventListener('input', updateRoi);
if (updatesInput) updatesInput.addEventListener('input', updateRoi);
updateRoi();
})();
/* Widgets: AI Form, Pricing Toggle, FAQ Accordion */
(function widgets() {
var aiForm = document.getElementById('aiForm');
var aiCapture = document.getElementById('aiCapture');
if (aiForm && aiCapture) {
aiForm.addEventListener('submit', function (e) {
e.preventDefault();
var email = document.getElementById('aiEmail').value.trim();
if (/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(email)) {
aiCapture.classList.add('done');
}
});
}
var sw = document.getElementById('billingSwitch');
var saveTag = document.getElementById('saveTag');
var optM = document.getElementById('optMonthly');
var optY = document.getElementById('optYearly');
if (sw) {
sw.addEventListener('click', function () {
var yearly = sw.getAttribute('aria-checked') !== 'true';
sw.setAttribute('aria-checked', String(yearly));
if (saveTag) saveTag.classList.toggle('show', yearly);
if (optM) optM.classList.toggle('active', !yearly);
if (optY) optY.classList.toggle('active', yearly);
document.querySelectorAll('.price-val[data-monthly]').forEach(function (el2) {
el2.textContent = yearly ? el2.getAttribute('data-yearly') : el2.getAttribute('data-monthly');
});
document.querySelectorAll('.price-per[data-monthly]').forEach(function (el2) {
el2.textContent = yearly ? el2.getAttribute('data-yearly') : el2.getAttribute('data-monthly');
});
});
}
document.querySelectorAll('.faq-item').forEach(function (item) {
var btn = item.querySelector('.faq-q');
if (btn) {
btn.addEventListener('click', function () {
var open = item.classList.toggle('open');
btn.setAttribute('aria-expanded', String(open));
});
}
});
})();
/* GSAP Animations & Interactions */
(function animations() {
if (!HAS_GSAP || REDUCED) {
document.querySelectorAll('[data-count]').forEach(function (el3) {
el3.textContent = el3.getAttribute('data-count');
});
return;
}
/* Hero entrance timeline */
var heroEls = document.querySelectorAll('[data-hero]');
gsap.set(heroEls, { opacity: 0, y: 22 });
var tl = gsap.timeline({ defaults: { ease: 'power3.out' } });
heroEls.forEach(function (el4) {
var idx = parseInt(el4.getAttribute('data-hero'), 10);
tl.to(el4, { opacity: 1, y: 0, duration: 0.75 }, idx * 0.06 + 0.1);
});
/* Hero QR frame stamp animation */
var frame = document.querySelector('.qr-frame');
if (frame) {
gsap.from(frame, { rotation: -2, scale: 0.95, opacity: 0, duration: 1, ease: 'back.out(1.3)' }, 0.4);
}
/* ScrollTrigger reveals */
if (HAS_ST) {
gsap.utils.toArray('[data-reveal]').forEach(function (el5) {
gsap.from(el5, {
opacity: 0, y: 26, duration: 0.75, ease: 'power3.out',
scrollTrigger: { trigger: el5, start: 'top 88%', once: true }
});
});
/* Counters */
document.querySelectorAll('[data-count]').forEach(function (el8) {
var end = parseFloat(el8.getAttribute('data-count'));
var decimals = parseInt(el8.getAttribute('data-decimals') || '0', 10);
var obj = { v: 0 };
ScrollTrigger.create({
trigger: el8, start: 'top 92%', once: true,
onEnter: function () {
gsap.to(obj, {
v: end, duration: 1.4, ease: 'power2.out',
onUpdate: function () { el8.textContent = obj.v.toFixed(decimals); }
});
}
});
});
/* Active nav highlighting */
['generator', 'tools', 'use-cases', 'roi', 'pricing', 'faq'].forEach(function (id) {
var section = document.getElementById(id);
var link = document.querySelector('[data-nav="' + id + '"]');
if (!section || !link) return;
ScrollTrigger.create({
trigger: section, start: 'top 45%', end: 'bottom 45%',
onToggle: function (self) { link.classList.toggle('active', self.isActive); }
});
});
}
/* Marquee Track */
var marquee = document.getElementById('marqueeTrack');
if (marquee) {
var tween = gsap.to(marquee, { xPercent: -50, ease: 'none', duration: 110, repeat: -1 });
marquee.addEventListener('mouseenter', function () { gsap.to(tween, { timeScale: 0.08, duration: 0.4 }); });
marquee.addEventListener('mouseleave', function () { gsap.to(tween, { timeScale: 1, duration: 0.4 }); });
marquee.addEventListener('focusin', function () { gsap.to(tween, { timeScale: 0.08, duration: 0.4 }); });
marquee.addEventListener('focusout', function () { gsap.to(tween, { timeScale: 1, duration: 0.4 }); });
}
/* Magnetic Buttons */
if (FINE_POINTER) {
document.querySelectorAll('[data-magnetic]').forEach(function (btn) {
btn.addEventListener('mousemove', function (e) {
var r = btn.getBoundingClientRect();
gsap.to(btn, {
x: (e.clientX - r.left - r.width / 2) * 0.16,
y: (e.clientY - r.top - r.height / 2) * 0.16,
duration: 0.3, ease: 'power3.out'
});
});
btn.addEventListener('mouseleave', function () {
gsap.to(btn, { x: 0, y: 0, duration: 0.4, ease: 'elastic.out(1, 0.4)' });
});
});
}
})();
})();
</script>
</body>
</html>