2089 lines
103 KiB
HTML
2089 lines
103 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 — Classical — 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=Playfair+Display:ital,wght@0,600;0,700;1,500;1,600&family=Source+Serif+4:wght@400;500;600&family=IBM+Plex+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
|
|
|
<style>
|
|
/* ============================================================
|
|
SKIN 05 : CLASSICAL
|
|
Warm cream paper, gold/bronze accent, serif display, vintage print plate.
|
|
============================================================ */
|
|
|
|
:root {
|
|
--font-display: "Playfair Display", ui-serif, Georgia, serif;
|
|
--font-sans: "Source Serif 4", ui-serif, Georgia, serif;
|
|
--font-mono: "IBM Plex Mono", ui-monospace, Consolas, monospace;
|
|
|
|
--ease-out: cubic-bezier(0.16, 1, 0.3, 1);
|
|
--dur-micro: 180ms;
|
|
--dur-ui: 350ms;
|
|
|
|
--r: 6px;
|
|
--r-sm: 3px;
|
|
--r-pill: 999px;
|
|
--container: 1240px;
|
|
}
|
|
|
|
html[data-theme="light"] {
|
|
color-scheme: light;
|
|
--paper: #F5F1E6;
|
|
--paper-2: #EDE6D3;
|
|
--panel: #FFFDF7;
|
|
--ink: #1A1611;
|
|
--ink-2: #4A4335;
|
|
--muted: #8C8268;
|
|
--line: #E3DBC8;
|
|
--line-strong: #CBBFA0;
|
|
--accent: #A6752C;
|
|
--accent-hover: #8A5F20;
|
|
--accent-text: #7A541E;
|
|
--accent-soft: rgba(166, 117, 44, 0.10);
|
|
--cyan-accent: #A6752C;
|
|
--mark-band: rgba(166, 117, 44, 0.2);
|
|
--danger: #EF4444;
|
|
--success: #10B981;
|
|
--cta: #A6752C;
|
|
--cta-hover: #8A5F20;
|
|
--inv-bg: #1A1611;
|
|
--inv-fg: #F5F1E6;
|
|
--deep: #141008;
|
|
--deep-text: #F3ECDD;
|
|
--deep-muted: #A79A7D;
|
|
--deep-accent: #D8B45C;
|
|
--shadow-ink: rgba(26, 22, 17, 0.8);
|
|
--hard-shadow: 6px 6px 0 var(--shadow-ink);
|
|
--nav-bg: rgba(245, 241, 230, 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='%231A1611' fill-opacity='0.08'/%3E%3C/svg%3E");
|
|
}
|
|
|
|
html[data-theme="dark"] {
|
|
color-scheme: dark;
|
|
--paper: #141008;
|
|
--paper-2: #1C1710;
|
|
--panel: #211B12;
|
|
--ink: #F3ECDD;
|
|
--ink-2: #B8AC8E;
|
|
--muted: #8C8268;
|
|
--line: #33291A;
|
|
--line-strong: #4A3C24;
|
|
--accent: #D8B45C;
|
|
--accent-hover: #E8C877;
|
|
--accent-text: #F0D699;
|
|
--accent-soft: rgba(216, 180, 92, 0.14);
|
|
--cyan-accent: #D8B45C;
|
|
--mark-band: rgba(216, 180, 92, 0.25);
|
|
--danger: #F87171;
|
|
--success: #34D399;
|
|
--cta: #D8B45C;
|
|
--cta-hover: #E8C877;
|
|
--inv-bg: #F3ECDD;
|
|
--inv-fg: #141008;
|
|
--deep: #0C0906;
|
|
--deep-text: #F3ECDD;
|
|
--deep-muted: #A79A7D;
|
|
--deep-accent: #D8B45C;
|
|
--shadow-ink: rgba(0, 0, 0, 0.85);
|
|
--hard-shadow: 6px 6px 0 var(--shadow-ink);
|
|
--nav-bg: rgba(20, 16, 8, 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='%23F3ECDD' fill-opacity='0.05'/%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; }
|
|
}
|
|
|
|
/* Classical flourishes */
|
|
mark { font-style: italic; font-weight: 500; }
|
|
.hero h1, .final-cta h2, .section-head h2 { font-weight: 600; }
|
|
.qr-frame, .price-card.popular, .roi-card { border-color: var(--line-strong); }
|
|
.eyebrow { border-style: dashed; }
|
|
|
|
|
|
/* Classical hero layout */
|
|
.hero--classic { padding:150px 0 90px; }
|
|
.hero-classic { max-width:720px; margin:0 auto; text-align:center; display:flex; flex-direction:column; align-items:center; gap:16px; }
|
|
.classic-rule-top { width:1px; height:52px; background:var(--line-strong); margin-bottom:6px; }
|
|
.hero-classic h1 { font-size:clamp(2.3rem,5.2vw,4rem); }
|
|
.classic-plate { position:relative; width:210px; height:210px; margin:22px auto 0; padding:20px; background:var(--panel); border:1px solid var(--line-strong); box-shadow:var(--hard-shadow); }
|
|
.classic-plate canvas { width:100%; height:100%; }
|
|
.classic-caption { display:flex; gap:16px; font-family:var(--font-mono); font-size:10.5px; color:var(--muted); text-transform:uppercase; letter-spacing:0.08em; }
|
|
.classic-caption .live { color:var(--accent-text); font-weight:600; }
|
|
.classic-types { display:flex; flex-wrap:wrap; justify-content:center; gap:8px; margin-top:10px; }
|
|
.classic-types .lbl { width:100%; font-family:var(--font-mono); font-size:10px; letter-spacing:0.1em; text-transform:uppercase; color:var(--muted); margin-bottom:2px; }
|
|
.classic-bullets { display:flex; flex-wrap:wrap; justify-content:center; gap:8px 20px; list-style:none; font-family:var(--font-mono); font-size:11px; color:var(--muted); text-transform:uppercase; letter-spacing:0.03em; }
|
|
.classic-bullets .tick { color:var(--accent); }
|
|
|
|
</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 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 hero--classic" id="top">
|
|
<div class="container hero-classic">
|
|
<div class="classic-rule-top" aria-hidden="true"></div>
|
|
<span class="eyebrow" data-hero="0"><span class="no">EST. 2026 · PLATE I</span> Free Dynamic QR Code Generator</span>
|
|
<h1 data-hero="1">Free <mark>Dynamic QR Code</mark><br>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>
|
|
<div class="classic-plate" data-hero="3">
|
|
<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>
|
|
</div>
|
|
<div class="classic-caption" data-hero="4">
|
|
<span id="heroQrEcho">https://www.qrmaster.net</span>
|
|
<span class="live">Live Specimen</span>
|
|
</div>
|
|
<div class="hero-ctas" data-hero="5">
|
|
<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="classic-types" data-hero="6">
|
|
<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>
|
|
<ul class="classic-bullets" data-hero="7">
|
|
<li><span class="tick">+</span> No credit card required</li>
|
|
<li><span class="tick">+</span> Free forever static codes</li>
|
|
<li><span class="tick">+</span> Real-time scan analytics</li>
|
|
<li><span class="tick">+</span> Custom colors & branding</li>
|
|
</ul>
|
|
</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 & 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 & 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 & 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 & 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 & 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 & 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 & 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 & 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 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>“' + t.title + '”</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>
|