458 lines
13 KiB
HTML
458 lines
13 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>{{PRODUCT_NAME}} — 即将推出</title>
|
|
<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={{DISPLAY_FONT_URL}}:wght@700;800&family={{BODY_FONT_URL}}:wght@400;500;600&display=swap" rel="stylesheet">
|
|
<style>
|
|
:root {
|
|
--bg: {{BG_EXPRESSION}};
|
|
--fg: {{FG_EXPRESSION}};
|
|
--accent: {{ACCENT_EXPRESSION}};
|
|
--deco: {{DECO_EXPRESSION}};
|
|
--deco-stripe: {{STRIPE_EXPRESSION}};
|
|
--input-border: {{BORDER_EXPRESSION}};
|
|
--success: {{SUCCESS_EXPRESSION}};
|
|
--btn-label: {{BTN_LABEL_EXPRESSION}};
|
|
--ticker-bg: {{TICKER_BG_EXPRESSION}};
|
|
--ticker-fg: {{TICKER_FG_EXPRESSION}};
|
|
--deco-stroke: {{DECO_STROKE_EXPRESSION}};
|
|
--logo-shadow: {{LOGO_SHADOW_EXPRESSION}};
|
|
--logo-fg: {{LOGO_FG_EXPRESSION}};
|
|
--font-body: {{BODY_FONT_CSS}}, sans-serif;
|
|
--font-display: {{DISPLAY_FONT_CSS}}, serif;
|
|
}
|
|
|
|
*, *::before, *::after {
|
|
box-sizing: border-box;
|
|
margin: 0;
|
|
padding: 0;
|
|
}
|
|
|
|
html, body {
|
|
height: 100%;
|
|
overflow-x: hidden;
|
|
}
|
|
|
|
body {
|
|
font-family: var(--font-body);
|
|
background-color: var(--bg);
|
|
color: var(--fg);
|
|
display: flex;
|
|
flex-direction: column;
|
|
min-height: 100svh;
|
|
overflow-x: hidden;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
/* Logo — reusable component */
|
|
.logo {
|
|
position: absolute;
|
|
top: 20px;
|
|
left: 24px;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
z-index: 10;
|
|
}
|
|
|
|
.logo-container {
|
|
width: 48px;
|
|
height: 48px;
|
|
flex-shrink: 0;
|
|
border-radius: 50%;
|
|
background: var(--accent);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
overflow: hidden;
|
|
color: var(--logo-fg);
|
|
font-family: var(--font-display);
|
|
font-size: 20px;
|
|
font-weight: 700;
|
|
letter-spacing: -0.02em;
|
|
}
|
|
|
|
.logo-container svg {
|
|
width: 100%;
|
|
height: 100%;
|
|
object-fit: contain;
|
|
}
|
|
|
|
.logo-text {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.logo-name {
|
|
font-family: var(--font-display);
|
|
font-weight: 700;
|
|
font-size: 16px;
|
|
color: var(--fg);
|
|
}
|
|
|
|
.logo-dot {
|
|
font-size: 8px;
|
|
color: var(--accent);
|
|
opacity: 0.6;
|
|
}
|
|
|
|
/* Upper section — hero */
|
|
.upper {
|
|
flex: 0 0 auto;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
text-align: center;
|
|
padding: 60px 24px 40px;
|
|
position: relative;
|
|
z-index: 2;
|
|
}
|
|
|
|
.headline {
|
|
font-family: var(--font-display);
|
|
font-weight: 800;
|
|
font-size: clamp(48px, 7vw, 80px);
|
|
letter-spacing: -0.02em;
|
|
line-height: 1.1;
|
|
color: var(--fg);
|
|
max-width: 900px;
|
|
margin: 0 auto 18px;
|
|
}
|
|
|
|
.subtext {
|
|
font-size: clamp(14px, 1.3vw, 16px);
|
|
font-weight: 400;
|
|
line-height: 1.5;
|
|
color: var(--fg);
|
|
opacity: 0.75;
|
|
max-width: 480px;
|
|
margin-bottom: 40px;
|
|
}
|
|
|
|
/* Form */
|
|
.form-row {
|
|
display: flex;
|
|
gap: 8px;
|
|
width: 100%;
|
|
max-width: 560px;
|
|
justify-content: center;
|
|
}
|
|
|
|
.form-row input {
|
|
flex: 1;
|
|
min-width: 0;
|
|
padding: 14px 16px;
|
|
font-family: var(--font-body);
|
|
font-size: 14px;
|
|
color: var(--fg);
|
|
background: transparent;
|
|
border: 1.5px solid var(--input-border);
|
|
border-radius: 3px;
|
|
outline: none;
|
|
transition: border-color 0.2s;
|
|
}
|
|
|
|
.form-row input::placeholder {
|
|
color: var(--input-border);
|
|
opacity: 0.7;
|
|
}
|
|
|
|
.form-row input:focus {
|
|
border-color: var(--fg);
|
|
outline: 2px solid var(--fg);
|
|
outline-offset: 2px;
|
|
}
|
|
|
|
.form-row button {
|
|
flex-shrink: 0;
|
|
padding: 14px 24px;
|
|
font-family: var(--font-body);
|
|
font-size: 14px;
|
|
font-weight: 600;
|
|
color: var(--btn-label);
|
|
background: var(--fg);
|
|
border: none;
|
|
border-radius: 2px;
|
|
cursor: pointer;
|
|
white-space: nowrap;
|
|
transition: opacity 0.15s;
|
|
}
|
|
|
|
.form-row button:hover {
|
|
opacity: 0.85;
|
|
}
|
|
|
|
.success-msg {
|
|
display: none;
|
|
margin-top: 16px;
|
|
font-size: 14px;
|
|
font-weight: 500;
|
|
color: var(--success);
|
|
}
|
|
|
|
.success-msg.visible {
|
|
display: block;
|
|
}
|
|
|
|
/* Decoration section */
|
|
.deco-section {
|
|
flex: 1;
|
|
position: relative;
|
|
overflow: hidden;
|
|
min-height: 25vh;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
/* Coil pattern */
|
|
.coil-row {
|
|
display: block;
|
|
width: 100%;
|
|
height: 60px;
|
|
flex-shrink: 0;
|
|
background: var(--bg);
|
|
}
|
|
|
|
/* Accent stripe */
|
|
.stripe {
|
|
width: 100%;
|
|
height: 12px;
|
|
background: var(--deco-stripe);
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
/* Floor with grid */
|
|
.grid-floor {
|
|
flex: 1;
|
|
position: relative;
|
|
background-color: var(--deco);
|
|
min-height: 80px;
|
|
}
|
|
|
|
.grid-svg {
|
|
position: absolute;
|
|
inset: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
|
|
/* Ticker ribbon */
|
|
.ticker-wrap {
|
|
width: 100%;
|
|
overflow: hidden;
|
|
background: var(--ticker-bg);
|
|
padding: 10px 0;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.ticker-track {
|
|
display: flex;
|
|
gap: 24px;
|
|
white-space: nowrap;
|
|
animation: ticker-scroll 20s linear infinite;
|
|
}
|
|
|
|
.ticker-unit {
|
|
font-family: var(--font-body);
|
|
font-size: 11px;
|
|
font-weight: 600;
|
|
letter-spacing: 0.12em;
|
|
text-transform: uppercase;
|
|
color: var(--ticker-fg);
|
|
flex-shrink: 0;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
margin-right: -12px;
|
|
}
|
|
|
|
.ticker-star {
|
|
color: var(--deco-stripe);
|
|
margin-right: 4px;
|
|
}
|
|
|
|
@keyframes ticker-scroll {
|
|
from { transform: translateX(0); }
|
|
to { transform: translateX(-50%); }
|
|
}
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.ticker-track {
|
|
animation: none;
|
|
}
|
|
}
|
|
|
|
/* Responsive */
|
|
@media (max-width: 600px) {
|
|
.logo {
|
|
left: 16px;
|
|
top: 16px;
|
|
}
|
|
|
|
.logo-container {
|
|
width: 40px;
|
|
height: 40px;
|
|
}
|
|
|
|
.logo-name {
|
|
font-size: 13px;
|
|
}
|
|
|
|
.upper {
|
|
padding: 50px 20px 30px;
|
|
}
|
|
|
|
.headline {
|
|
margin: 0 auto 12px;
|
|
}
|
|
|
|
.subtext {
|
|
margin-bottom: 30px;
|
|
}
|
|
|
|
.form-row {
|
|
flex-direction: column;
|
|
align-items: stretch;
|
|
}
|
|
|
|
.form-row input,
|
|
.form-row button {
|
|
width: 100%;
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<!-- Logo placeholder — replace or customize -->
|
|
<div class="logo">
|
|
<div class="logo-container" data-od-id="logo-mark">
|
|
{{LOGO_MARK}}
|
|
</div>
|
|
<div class="logo-text">
|
|
<span class="logo-name" data-od-id="logo-name">{{PRODUCT_NAME}}</span>
|
|
<span class="logo-dot">·</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Hero section -->
|
|
<section class="upper">
|
|
<h1 class="headline" data-od-id="headline">{{PRODUCT_NAME}}<br>即将上线</h1>
|
|
<p class="subtext" data-od-id="tagline">{{TAGLINE}}</p>
|
|
|
|
<form class="form-row" id="waitlist-form" data-od-id="form">
|
|
<input type="text" name="firstname" placeholder="名字">
|
|
<input type="email" name="email" placeholder="工作邮箱" required>
|
|
<button type="submit">加入候补名单</button>
|
|
</form>
|
|
<p class="success-msg" id="success-msg" role="status">您已加入名单,我们会与您联系。</p>
|
|
</section>
|
|
|
|
<!-- Decorative section -->
|
|
<div class="deco-section">
|
|
|
|
<!-- Coil pattern (optional) -->
|
|
<svg class="coil-row" viewBox="0 0 1440 60" preserveAspectRatio="none" xmlns="http://www.w3.org/2000/svg" data-od-id="coil">
|
|
<g fill="none" style="stroke: var(--deco-stroke);" stroke-width="1.5">
|
|
<path d="M 9,60 A 41,30 0 0 1 91,60"/>
|
|
<path d="M 94,60 A 41,30 0 0 1 176,60"/>
|
|
<path d="M 179,60 A 41,30 0 0 1 261,60"/>
|
|
<path d="M 264,60 A 41,30 0 0 1 346,60"/>
|
|
<path d="M 349,60 A 41,30 0 0 1 431,60"/>
|
|
<path d="M 434,60 A 41,30 0 0 1 516,60"/>
|
|
<path d="M 519,60 A 41,30 0 0 1 601,60"/>
|
|
<path d="M 604,60 A 41,30 0 0 1 686,60"/>
|
|
<path d="M 689,60 A 41,30 0 0 1 771,60"/>
|
|
<path d="M 774,60 A 41,30 0 0 1 856,60"/>
|
|
<path d="M 859,60 A 41,30 0 0 1 941,60"/>
|
|
<path d="M 944,60 A 41,30 0 0 1 1026,60"/>
|
|
<path d="M 1029,60 A 41,30 0 0 1 1111,60"/>
|
|
<path d="M 1114,60 A 41,30 0 0 1 1196,60"/>
|
|
<path d="M 1199,60 A 41,30 0 0 1 1281,60"/>
|
|
<path d="M 1284,60 A 41,30 0 0 1 1366,60"/>
|
|
<path d="M 1369,60 A 41,30 0 0 1 1451,60"/>
|
|
</g>
|
|
</svg>
|
|
|
|
<!-- Accent stripe -->
|
|
<div class="stripe" data-od-id="stripe"></div>
|
|
|
|
<!-- Floor with perspective grid -->
|
|
<div class="grid-floor">
|
|
<svg class="grid-svg" viewBox="0 0 1280 400" preserveAspectRatio="none" xmlns="http://www.w3.org/2000/svg" data-od-id="grid">
|
|
<g style="stroke: var(--deco-stroke);" stroke-width="1" fill="none">
|
|
<!-- Radiating lines from center top -->
|
|
<line x1="640" y1="0" x2="0" y2="400"/>
|
|
<line x1="640" y1="0" x2="128" y2="400"/>
|
|
<line x1="640" y1="0" x2="256" y2="400"/>
|
|
<line x1="640" y1="0" x2="384" y2="400"/>
|
|
<line x1="640" y1="0" x2="512" y2="400"/>
|
|
<line x1="640" y1="0" x2="640" y2="400"/>
|
|
<line x1="640" y1="0" x2="768" y2="400"/>
|
|
<line x1="640" y1="0" x2="896" y2="400"/>
|
|
<line x1="640" y1="0" x2="1024" y2="400"/>
|
|
<line x1="640" y1="0" x2="1152" y2="400"/>
|
|
<line x1="640" y1="0" x2="1280" y2="400"/>
|
|
<!-- Horizontal grid lines -->
|
|
<line x1="0" y1="80" x2="1280" y2="80"/>
|
|
<line x1="0" y1="160" x2="1280" y2="160"/>
|
|
<line x1="0" y1="240" x2="1280" y2="240"/>
|
|
<line x1="0" y1="320" x2="1280" y2="320"/>
|
|
</g>
|
|
</svg>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Ticker ribbon -->
|
|
<div class="ticker-wrap" aria-hidden="true" data-od-id="ticker">
|
|
<div class="ticker-track">
|
|
<span class="ticker-unit">即将推出 <span class="ticker-star">✦</span></span>
|
|
<span class="ticker-unit">即将推出 <span class="ticker-star">✦</span></span>
|
|
<span class="ticker-unit">即将推出 <span class="ticker-star">✦</span></span>
|
|
<span class="ticker-unit">即将推出 <span class="ticker-star">✦</span></span>
|
|
<span class="ticker-unit">即将推出 <span class="ticker-star">✦</span></span>
|
|
<span class="ticker-unit">即将推出 <span class="ticker-star">✦</span></span>
|
|
<span class="ticker-unit">即将推出 <span class="ticker-star">✦</span></span>
|
|
<span class="ticker-unit">即将推出 <span class="ticker-star">✦</span></span>
|
|
<span class="ticker-unit">即将推出 <span class="ticker-star">✦</span></span>
|
|
<span class="ticker-unit">即将推出 <span class="ticker-star">✦</span></span>
|
|
<span class="ticker-unit">即将推出 <span class="ticker-star">✦</span></span>
|
|
<span class="ticker-unit">即将推出 <span class="ticker-star">✦</span></span>
|
|
<!-- Duplicate for seamless loop -->
|
|
<span class="ticker-unit">即将推出 <span class="ticker-star">✦</span></span>
|
|
<span class="ticker-unit">即将推出 <span class="ticker-star">✦</span></span>
|
|
<span class="ticker-unit">即将推出 <span class="ticker-star">✦</span></span>
|
|
<span class="ticker-unit">即将推出 <span class="ticker-star">✦</span></span>
|
|
<span class="ticker-unit">即将推出 <span class="ticker-star">✦</span></span>
|
|
<span class="ticker-unit">即将推出 <span class="ticker-star">✦</span></span>
|
|
<span class="ticker-unit">即将推出 <span class="ticker-star">✦</span></span>
|
|
<span class="ticker-unit">即将推出 <span class="ticker-star">✦</span></span>
|
|
<span class="ticker-unit">即将推出 <span class="ticker-star">✦</span></span>
|
|
<span class="ticker-unit">即将推出 <span class="ticker-star">✦</span></span>
|
|
<span class="ticker-unit">即将推出 <span class="ticker-star">✦</span></span>
|
|
<span class="ticker-unit">即将推出 <span class="ticker-star">✦</span></span>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
document.getElementById('waitlist-form').addEventListener('submit', function(e) {
|
|
e.preventDefault();
|
|
if (!this.checkValidity()) {
|
|
this.reportValidity();
|
|
return;
|
|
}
|
|
this.style.display = 'none';
|
|
document.getElementById('success-msg').classList.add('visible');
|
|
});
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|