intro updates
This commit is contained in:
1
public/icons/cloud-lightning-icon.svg
Normal file
1
public/icons/cloud-lightning-icon.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 122.88 116.82" style="enable-background:new 0 0 122.88 116.82" xml:space="preserve"><style type="text/css">.st0{fill-rule:evenodd;clip-rule:evenodd;}</style><g><path class="st0" d="M59.63,61.55h22.58l-7.87,15.24l13.4,0.24l-32.64,39.8l6.28-26.18H50.81L59.63,61.55L59.63,61.55z M44.2,71.76 c2.03,0,3.68,1.65,3.68,3.68c0,2.03-1.65,3.68-3.68,3.68H23.38l-0.46-0.04c-2.67-0.34-5.09-0.97-7.29-1.88 c-2.25-0.93-4.26-2.14-6.04-3.63H9.58c-1.68-1.4-3.15-2.99-4.4-4.72C1.84,64.25,0.04,58.63,0,53.03 c-0.04-5.66,1.72-11.29,5.52-15.85c1.23-1.48,2.68-2.84,4.34-4.04c1.93-1.4,4.14-2.58,6.64-3.55c1.72-0.67,3.56-1.23,5.5-1.68 c2.2-8.74,6.89-15.47,12.92-20.14c5.64-4.37,12.43-6.92,19.42-7.59c6.96-0.67,14.12,0.51,20.55,3.6 c7.37,3.54,13.43,9.56,17.11,16.87c1.6-0.25,3.2-0.38,4.79-0.36c6.72,0.05,13.2,2.45,18.3,7.95c5.31,5.72,7.88,14.14,7.79,21.82 c-0.07,6.31-1.77,12.59-5.25,17.22c-2.27,3.02-5.18,5.47-8.67,7.42c-3.36,1.88-7.28,3.31-11.68,4.33c-1.98,0.45-3.95-0.78-4.4-2.76 c-0.45-1.98,0.78-3.95,2.76-4.4c3.71-0.86,6.97-2.04,9.72-3.58c2.63-1.47,4.78-3.26,6.39-5.41c2.5-3.33,3.73-8.04,3.78-12.87 c0.06-5.07-1.18-10.16-3.59-13.86c-0.69-1.07-1.44-2.03-2.25-2.89c-3.61-3.89-8.19-5.59-12.95-5.62 c-3.46-0.02-7.02,0.81-10.41,2.31c-0.75,0.37-1.51,0.78-2.25,1.21c-2.25,1.32-4.48,2.93-6.74,4.78l-4.84-5.54 c1.67-1.55,3.48-2.96,5.4-4.21c1.53-1,3.13-1.88,4.77-2.65c0.66-0.33,1.33-0.64,2-0.93c-3.19-5.65-7.78-9.7-12.98-12.2 c-5.2-2.49-11.02-3.45-16.69-2.9c-5.63,0.54-11.1,2.59-15.62,6.1c-5.23,4.06-9.2,10.11-10.73,18.14l-0.48,2.51l-2.5,0.44 c-2.45,0.43-4.64,1.02-6.56,1.77c-1.86,0.72-3.52,1.61-4.97,2.66c-1.16,0.84-2.16,1.78-3.01,2.8c-2.63,3.15-3.85,7.1-3.82,11.1 c0.03,4.06,1.35,8.16,3.79,11.53c0.91,1.25,1.96,2.4,3.16,3.4l-0.01,0.01c1.2,1,2.58,1.83,4.13,2.47c1.53,0.63,3.22,1.08,5.09,1.34 H44.2L44.2,71.76z M57.07,85.6l6.59-18.76h10.23l-5.32,14.28l8.03,0.14l-13.51,20.22l4.03-15.88H57.07L57.07,85.6z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
1
public/icons/hand-watch-icon.svg
Normal file
1
public/icons/hand-watch-icon.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 98.47 122.88" style="enable-background:new 0 0 98.47 122.88" xml:space="preserve"><style type="text/css">.st0{fill-rule:evenodd;clip-rule:evenodd;}</style><g><path class="st0" d="M71.93,23.88c9.62,6.8,16.5,17.23,18.63,29.29h5.68c1.23,0,2.23,1.01,2.23,2.23v10.67 c0,1.22-1.01,2.23-2.23,2.23h-5.53c-1.95,12.43-8.93,23.2-18.78,30.16v18.77c0,3.11-2.54,5.65-5.64,5.65l-41.3,0 c-3.1,0-5.64-2.54-5.64-5.65V98.47C7.64,90.2,0,76.58,0,61.18c0-15.4,7.64-29.03,19.33-37.29V5.65c0-3.11,2.54-5.65,5.64-5.65h41.3 c3.1,0,5.64,2.54,5.64,5.65V23.88L71.93,23.88z M44.01,60.23c3.48,0,6.3,2.82,6.3,6.3c0,3.48-2.82,6.3-6.3,6.3 c-3.48,0-6.3-2.82-6.3-6.3C37.71,63.05,40.53,60.23,44.01,60.23L44.01,60.23z M52.85,68.01v-2.97c0-0.33,0.27-0.62,0.6-0.6 l22.36,1.52l-22.36,2.65C53.13,68.65,52.85,68.34,52.85,68.01L52.85,68.01L52.85,68.01z M41.35,56.31h5.31c0.33,0,0.6-0.27,0.6-0.6 l-3.08-22.35l-3.43,22.35C40.76,56.04,41.02,56.31,41.35,56.31L41.35,56.31L41.35,56.31z M45.03,24.38c0.31,0,0.62,0,0.93,0.01 h0.01c0.31,0.01,0.61,0.02,0.92,0.04h0.01c0.27,0.01,0.55,0.03,0.82,0.05l0.24,0.02c0.24,0.02,0.48,0.04,0.72,0.06l0.04,0l0.01,0 l0.06,0.01c0.26,0.03,0.52,0.06,0.78,0.09l0.12,0.02c0.26,0.03,0.52,0.07,0.78,0.11l0.14,0.02c0.26,0.04,0.52,0.08,0.78,0.13 l0.12,0.02c0.27,0.05,0.53,0.1,0.8,0.15l0.02,0.01c0.26,0.05,0.52,0.11,0.78,0.17l0.17,0.04c0.24,0.06,0.48,0.12,0.72,0.18 l0.16,0.04c0.24,0.06,0.48,0.13,0.72,0.2L55,25.77c0.26,0.07,0.51,0.15,0.76,0.23L55.79,26l0.06,0.02 c0.25,0.07,0.49,0.15,0.74,0.24l0.05,0.02l0.06,0.02c0.24,0.08,0.47,0.16,0.7,0.25l0.23,0.09c13.78,5.12,23.61,18.39,23.61,33.94 c0,16.22-10.68,29.95-25.38,34.55l-0.06,0.02l-0.02,0.01l-0.17,0.05l-0.33,0.1l-0.16,0.05l-0.04,0.01l-0.22,0.07l-0.57,0.15 l-0.17,0.04l-0.22,0.05l-0.55,0.14l-0.4,0.09l-0.17,0.04l-0.08,0.02l-0.54,0.11l-0.56,0.1l-0.2,0.04 c-0.26,0.05-0.53,0.09-0.79,0.13l-0.17,0.03c-0.2,0.03-0.4,0.06-0.6,0.08l-0.17,0.02l-0.02,0l-0.16,0.02l-0.54,0.06l-0.34,0.04 l-0.18,0.02h-0.01l-0.58,0.05l-0.03,0l-0.1,0.01l-0.66,0.04l-0.28,0.01c-0.25,0.01-0.5,0.02-0.76,0.03l-0.13,0 c-0.29,0.01-0.57,0.01-0.86,0.01c-0.29,0-0.58,0-0.86-0.01l-0.13,0c-0.25-0.01-0.51-0.02-0.76-0.03l-0.27-0.01l-0.66-0.04 l-0.1-0.01l-0.02,0c-0.2-0.01-0.39-0.03-0.59-0.05l-0.18-0.02l-0.33-0.04c-0.22-0.02-0.45-0.05-0.67-0.08l-0.04,0l-0.02,0 l-0.17-0.02l-0.62-0.09l-0.13-0.02c-0.26-0.04-0.55-0.09-0.81-0.13l-0.04-0.01l-0.13-0.02l-0.61-0.11l-0.25-0.05l-0.17-0.04 l-0.03-0.01l-0.28-0.06l-0.03-0.01l-0.17-0.04l-0.2-0.05l-0.64-0.16l-0.13-0.03l-0.04-0.01c-0.27-0.07-0.54-0.15-0.8-0.22 l-0.03-0.01l-0.01,0l-0.03-0.01C20.53,91.66,9.43,77.71,9.43,61.18c0-16.53,11.09-30.47,26.23-34.81l0.07-0.02l0.02,0 c0.27-0.08,0.54-0.15,0.81-0.22l0.03-0.01l0.03-0.01l0,0c0.26-0.06,0.53-0.13,0.79-0.19l0.12-0.03c0.54-0.12,1.08-0.24,1.62-0.33 l0.08-0.02l0.03,0c0.27-0.05,0.54-0.09,0.82-0.14l0.05-0.01l0.02,0l0.03,0c0.26-0.04,0.51-0.07,0.77-0.11l0.09-0.01l0.12-0.01 c0.25-0.03,0.5-0.06,0.75-0.08l0.05,0l0.01,0l0.03,0c0.25-0.02,0.5-0.05,0.75-0.07l0.22-0.02c0.28-0.02,0.55-0.04,0.83-0.05h0.01 c0.3-0.02,0.61-0.03,0.92-0.04h0.01c0.31-0.01,0.62-0.01,0.93-0.01L45.03,24.38L45.03,24.38z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 3.2 KiB |
1
public/icons/secure-icon.svg
Normal file
1
public/icons/secure-icon.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 106.11 122.88"><defs><style>.cls-1{fill-rule:evenodd;}</style></defs><title>secure</title><path class="cls-1" d="M56.36,2.44A104.34,104.34,0,0,0,79.77,13.9a48.25,48.25,0,0,0,19.08,2.57l6.71-.61.33,6.74c1.23,24.79-2.77,46.33-11.16,63.32C86,103.6,72.58,116.37,55.35,122.85l-4.48,0c-16.84-6.15-30.16-18.57-39-36.47C3.62,69.58-.61,47.88.07,22l.18-6.65,6.61.34A64.65,64.65,0,0,0,28.23,13.5,60.59,60.59,0,0,0,48.92,2.79L52.51,0l3.85,2.44ZM52.93,19.3C66.46,27.88,78.68,31.94,89.17,31,91,68,77.32,96.28,53.07,105.41c-23.43-8.55-37.28-35.85-36.25-75,12.31.65,24.4-2,36.11-11.11ZM45.51,61.61a28.89,28.89,0,0,1,2.64,2.56,104.48,104.48,0,0,1,8.27-11.51c8.24-9.95,5.78-9.3,17.21-9.3L72,45.12a135.91,135.91,0,0,0-11.8,15.3,163.85,163.85,0,0,0-10.76,17.9l-1,1.91-.91-1.94a47.17,47.17,0,0,0-6.09-9.87,33.4,33.4,0,0,0-7.75-7.12c1.49-4.89,8.59-2.38,11.77.31Zm7.38-53.7c17.38,11,33.07,16.22,46.55,15,2.35,47.59-15.23,82.17-46.37,93.9C23,105.82,5.21,72.45,6.53,22.18,22.34,23,37.86,19.59,52.89,7.91Z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
69
src/App.vue
69
src/App.vue
@@ -228,13 +228,44 @@
|
||||
loads in the same tab via sessionStorage. -->
|
||||
<div class="intro-overlay" id="intro-overlay" aria-hidden="true">
|
||||
<div class="intro-stage stage-1" data-stage="1">
|
||||
<svg class="stage-icon icon-shield" viewBox="0 0 96 96" aria-hidden="true">
|
||||
<circle class="badge" cx="48" cy="48" r="42"/>
|
||||
<path class="glyph-stroke i-shield-outline" d="M48 20 C42.8 23.4 36 25.8 29.2 25.6 C28.5 48.2 35.4 67.2 48 75.6 C60.6 67.2 67.5 48.2 66.8 25.6 C60 25.8 53.2 23.4 48 20 Z"/>
|
||||
<path class="glyph-fill i-secure-tick" d="M44.8 56.1 L38.9 50.1 L42 47 L45.1 50.2 L55.6 39.5 L58.8 42.6 Z"/>
|
||||
</svg>
|
||||
<span class="intro-text" data-i18n="intro_l1">Wisdom is to prepare</span>
|
||||
</div>
|
||||
<div class="intro-stage stage-2" data-stage="2">
|
||||
<svg class="stage-icon icon-storm" viewBox="0 0 96 96" aria-hidden="true">
|
||||
<circle class="badge" cx="48" cy="48" r="42"/>
|
||||
<g class="glyph filled-icon" transform="translate(19.75 21.15) scale(0.46)">
|
||||
<path class="i-cloud" d="M44.2,71.76 c2.03,0,3.68,1.65,3.68,3.68c0,2.03-1.65,3.68-3.68,3.68H23.38l-0.46-0.04c-2.67-0.34-5.09-0.97-7.29-1.88 c-2.25-0.93-4.26-2.14-6.04-3.63H9.58c-1.68-1.4-3.15-2.99-4.4-4.72C1.84,64.25,0.04,58.63,0,53.03 c-0.04-5.66,1.72-11.29,5.52-15.85c1.23-1.48,2.68-2.84,4.34-4.04c1.93-1.4,4.14-2.58,6.64-3.55c1.72-0.67,3.56-1.23,5.5-1.68 c2.2-8.74,6.89-15.47,12.92-20.14c5.64-4.37,12.43-6.92,19.42-7.59c6.96-0.67,14.12,0.51,20.55,3.6 c7.37,3.54,13.43,9.56,17.11,16.87c1.6-0.25,3.2-0.38,4.79-0.36c6.72,0.05,13.2,2.45,18.3,7.95c5.31,5.72,7.88,14.14,7.79,21.82 c-0.07,6.31-1.77,12.59-5.25,17.22c-2.27,3.02-5.18,5.47-8.67,7.42c-3.36,1.88-7.28,3.31-11.68,4.33c-1.98,0.45-3.95-0.78-4.4-2.76 c-0.45-1.98,0.78-3.95,2.76-4.4c3.71-0.86,6.97-2.04,9.72-3.58c2.63-1.47,4.78-3.26,6.39-5.41c2.5-3.33,3.73-8.04,3.78-12.87 c0.06-5.07-1.18-10.16-3.59-13.86c-0.69-1.07-1.44-2.03-2.25-2.89c-3.61-3.89-8.19-5.59-12.95-5.62 c-3.46-0.02-7.02,0.81-10.41,2.31c-0.75,0.37-1.51,0.78-2.25,1.21c-2.25,1.32-4.48,2.93-6.74,4.78l-4.84-5.54 c1.67-1.55,3.48-2.96,5.4-4.21c1.53-1,3.13-1.88,4.77-2.65c0.66-0.33,1.33-0.64,2-0.93c-3.19-5.65-7.78-9.7-12.98-12.2 c-5.2-2.49-11.02-3.45-16.69-2.9c-5.63,0.54-11.1,2.59-15.62,6.1c-5.23,4.06-9.2,10.11-10.73,18.14l-0.48,2.51l-2.5,0.44 c-2.45,0.43-4.64,1.02-6.56,1.77c-1.86,0.72-3.52,1.61-4.97,2.66c-1.16,0.84-2.16,1.78-3.01,2.8c-2.63,3.15-3.85,7.1-3.82,11.1 c0.03,4.06,1.35,8.16,3.79,11.53c0.91,1.25,1.96,2.4,3.16,3.4l-0.01,0.01c1.2,1,2.58,1.83,4.13,2.47c1.53,0.63,3.22,1.08,5.09,1.34 H44.2L44.2,71.76z"/>
|
||||
</g>
|
||||
<path class="glyph-fill i-lightning-flash" d="M47.2 49.5 L57.6 49.5 L54 56.5 L60.2 56.6 L45.2 74.9 L48.1 62.9 L43.2 62.9 Z"/>
|
||||
</svg>
|
||||
<span class="intro-text" data-i18n="intro_l2">Even if crisis is not here yet</span>
|
||||
</div>
|
||||
<div class="intro-stage stage-3" data-stage="3">
|
||||
<span class="intro-text" data-i18n="intro_l3">Figure out your Plan B in less than two minutes.</span>
|
||||
<!-- Clock — face centred in the badge with no crown above it.
|
||||
The minute hand sweeps 720° (two full revolutions) during
|
||||
the second half of the sentence, ending back at the top. -->
|
||||
<svg class="stage-icon icon-clock" viewBox="0 0 96 96" aria-hidden="true">
|
||||
<circle class="badge" cx="48" cy="48" r="42"/>
|
||||
<g class="glyph">
|
||||
<!-- Face circle, centred in the badge. -->
|
||||
<circle class="i-face" cx="48" cy="48" r="22"/>
|
||||
<!-- Cardinal hour ticks. -->
|
||||
<line class="i-tick" x1="48" y1="30" x2="48" y2="34"/>
|
||||
<line class="i-tick" x1="66" y1="48" x2="62" y2="48"/>
|
||||
<line class="i-tick" x1="48" y1="66" x2="48" y2="62"/>
|
||||
<line class="i-tick" x1="30" y1="48" x2="34" y2="48"/>
|
||||
<!-- Minute hand pointing to 12 — rotates 720° over the line. -->
|
||||
<line class="i-hand" x1="48" y1="48" x2="48" y2="32"/>
|
||||
<!-- Center pin. -->
|
||||
<circle class="i-pin" cx="48" cy="48" r="2.2"/>
|
||||
</g>
|
||||
</svg>
|
||||
<span class="intro-text" data-i18n="intro_l3">Figure out your Plan B in less than 2 Minutes.</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -613,8 +644,8 @@ const T = {
|
||||
hero_sub: "Preparedness, refined.",
|
||||
hero_cta: "Begin",
|
||||
intro_l1: "Wisdom is to prepare",
|
||||
intro_l2: "Even if crisis is not here yet",
|
||||
intro_l3: "Figure out your Plan B in less than two minutes.",
|
||||
intro_l2: "Even if\ncrisis is not here yet",
|
||||
intro_l3: "Figure out your Plan B in less than 2 Minutes.",
|
||||
stat_scenarios: "Scenarios",
|
||||
stat_questions: "Questions",
|
||||
stat_free: "Free Forever",
|
||||
@@ -733,8 +764,8 @@ const T = {
|
||||
hero_sub: "Vorsorge, verfeinert.",
|
||||
hero_cta: "Beginnen",
|
||||
intro_l1: "Weise ist, wer vorsorgt.",
|
||||
intro_l2: "Auch wenn noch keine Krise da ist.",
|
||||
intro_l3: "Finden Sie Ihren Plan B in weniger als zwei Minuten.",
|
||||
intro_l2: "Auch wenn\nnoch keine Krise da ist.",
|
||||
intro_l3: "Finden Sie Ihren Plan B in weniger als 2 Minuten.",
|
||||
stat_scenarios: "Szenarien",
|
||||
stat_questions: "Fragen",
|
||||
stat_free: "Kostenlos",
|
||||
@@ -1861,17 +1892,39 @@ async function playIntro() {
|
||||
const text = textEl.textContent.trim()
|
||||
textEl.innerHTML = ''
|
||||
words = text.split(/\s+/)
|
||||
// Per-stage emphasis. Stage 1 bolds "prepare" / "vorsorgt"; stage
|
||||
// 2 bolds "crisis" / "krise"; stage 3 bolds the final two words
|
||||
// ("2 Minutes." / "2 Minuten.") — both EN and DE land at the
|
||||
// same word index. Word matching is case-insensitive and trailing
|
||||
// punctuation is stripped before testing.
|
||||
const emphasisRe = {
|
||||
1: /^(prepare|vorsorgt)$/i,
|
||||
2: /^(crisis|krise)$/i,
|
||||
}[n] || null
|
||||
const stripPunct = w => w.replace(/[.,;:!?]+$/, '')
|
||||
// Stage 3 — bold "less than 2 Minutes." (last four words).
|
||||
const boldFromIdx = (n === 3) ? 6 : Infinity
|
||||
words.forEach((word, i) => {
|
||||
const span = document.createElement('span')
|
||||
span.className = 'word'
|
||||
const isBold = i >= boldFromIdx || (emphasisRe && emphasisRe.test(stripPunct(word)))
|
||||
span.className = 'word' + (isBold ? ' bold' : '')
|
||||
span.style.animationDelay = (BASE + i * STAGGER) + 's'
|
||||
span.textContent = word
|
||||
textEl.appendChild(span)
|
||||
// Stage 2 — insert a mobile-only line break after the leading
|
||||
// conjunction so "crisis is not here yet" / "noch keine Krise
|
||||
// da ist." sits on its own row on small viewports. Hidden on
|
||||
// desktop via CSS.
|
||||
if (n === 2 && /^(if|wenn)$/i.test(stripPunct(word))) {
|
||||
textEl.appendChild(document.createElement('br'))
|
||||
.className = 'mobile-break'
|
||||
}
|
||||
})
|
||||
}
|
||||
const entryMs = Math.round((BASE + (Math.max(0, words.length - 1)) * STAGGER + PER_WORD) * 1000)
|
||||
// Stage 3 holds longest because it's the longest line.
|
||||
const hold = n === 3 ? 1500 : 700
|
||||
// Bigger hold on stage 1 so the opening line lingers; stage 3 (the
|
||||
// longest sentence) holds the longest.
|
||||
const hold = n === 3 ? 1500 : (n === 1 ? 1200 : 900)
|
||||
stages.push({ sel: '.stage-' + n, enter: entryMs, hold })
|
||||
}
|
||||
const exit = 800 // matches the introOut (smoke out) duration
|
||||
|
||||
298
src/styles.css
298
src/styles.css
@@ -90,7 +90,11 @@ body { background: #FAFAFA; color: var(--text); font-family: var(--font-body); f
|
||||
.lang-btn.active { background: var(--red); color: #FFFFFF; }
|
||||
|
||||
/* ── APP ── */
|
||||
.app { padding-top: 0; height: 100vh; height: 100dvh; display: flex; flex-direction: column; overflow: hidden; }
|
||||
.app { padding-top: 0; height: 100vh; height: 100dvh; display: flex; flex-direction: column; overflow: hidden; position: relative; isolation: isolate; }
|
||||
.app > :not(.page-bg-pattern) {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* ── HERO ── */
|
||||
.hero {
|
||||
@@ -117,21 +121,13 @@ body { background: #FAFAFA; color: var(--text); font-family: var(--font-body); f
|
||||
.page-bg-pattern {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
/* z-index:-1 keeps the pattern below normal-flow content (hero / quiz
|
||||
/ results) without forcing those sections into their own stacking
|
||||
context. That matters because creating a context on .results-section
|
||||
would trap the capture-modal (a position:fixed descendant) inside
|
||||
it, and its z-index:200 wouldn't escape that context to sit above
|
||||
the body-level site-header. Body bg is the canvas; the pattern
|
||||
paints above the canvas and below positioned content. */
|
||||
z-index: -1;
|
||||
z-index: 0;
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
overflow: hidden;
|
||||
background: #FAFAFA;
|
||||
/* Parent is always visible — the intro overlay covers it during the
|
||||
intro, and the per-row animations handle the staggered reveal once
|
||||
intro-done lands. Nothing to fade on the wrapper. */
|
||||
/* Parent is always visible. The intro overlay is translucent, so the
|
||||
animated emboss pattern is already present behind the first line. */
|
||||
opacity: 1;
|
||||
}
|
||||
.page-bg-pattern .bg-tilt {
|
||||
@@ -178,28 +174,59 @@ body { background: #FAFAFA; color: var(--text); font-family: var(--font-body); f
|
||||
sits inside the rotated .bg-tilt, so the slide is slightly off-axis
|
||||
in screen space (matches the diagonal tilt). */
|
||||
.page-bg-pattern .bg-row {
|
||||
--row-delay: 0s;
|
||||
opacity: 0;
|
||||
will-change: opacity, transform;
|
||||
}
|
||||
.page-bg-pattern .bg-row:nth-child(odd) { transform: translateX(-160px); }
|
||||
.page-bg-pattern .bg-row:nth-child(even) { transform: translateX( 160px); }
|
||||
.page-bg-pattern .bg-row:nth-child(odd) {
|
||||
transform: translateX(-160px);
|
||||
animation:
|
||||
bgRowSlideLeft 1.1s var(--row-delay) cubic-bezier(0.22, 0.61, 0.36, 1) forwards,
|
||||
bgRowDriftLeft 14s calc(var(--row-delay) + 2.1s) ease-in-out infinite;
|
||||
}
|
||||
.page-bg-pattern .bg-row:nth-child(even) {
|
||||
transform: translateX(160px);
|
||||
animation:
|
||||
bgRowSlideRight 1.1s var(--row-delay) cubic-bezier(0.22, 0.61, 0.36, 1) forwards,
|
||||
bgRowDriftRight 14s calc(var(--row-delay) + 2.1s) ease-in-out infinite;
|
||||
}
|
||||
body:not(.intro-done) .page-bg-pattern .bg-row {
|
||||
opacity: 1;
|
||||
}
|
||||
body:not(.intro-done) .page-bg-pattern .bg-row:nth-child(odd) {
|
||||
animation: bgRowDriftLeft 14s ease-in-out infinite;
|
||||
}
|
||||
body:not(.intro-done) .page-bg-pattern .bg-row:nth-child(even) {
|
||||
animation: bgRowDriftRight 14s ease-in-out infinite;
|
||||
}
|
||||
body:not(.intro-done) .page-bg-pattern .bg-row {
|
||||
text-shadow:
|
||||
-1px -1px 0 rgba(0, 0, 0, 0.075),
|
||||
-2px -2px 1px rgba(0, 0, 0, 0.035),
|
||||
1px 1px 0 rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
|
||||
body.intro-done .page-bg-pattern .bg-row:nth-child(odd) {
|
||||
animation: bgRowSlideLeft 1.1s cubic-bezier(0.22, 0.61, 0.36, 1) forwards;
|
||||
/* Simple slide-in per row, alternating direction, followed by a perpetual
|
||||
alternating drift. This starts immediately so the pattern is visible
|
||||
underneath the intro overlay from the first sentence onward. */
|
||||
@keyframes bgRowDriftLeft {
|
||||
0%, 100% { transform: translateX(0); }
|
||||
50% { transform: translateX(-60px); }
|
||||
}
|
||||
body.intro-done .page-bg-pattern .bg-row:nth-child(even) {
|
||||
animation: bgRowSlideRight 1.1s cubic-bezier(0.22, 0.61, 0.36, 1) forwards;
|
||||
@keyframes bgRowDriftRight {
|
||||
0%, 100% { transform: translateX(0); }
|
||||
50% { transform: translateX(60px); }
|
||||
}
|
||||
body.intro-done .page-bg-pattern .bg-row:nth-child(1) { animation-delay: 0.00s; }
|
||||
body.intro-done .page-bg-pattern .bg-row:nth-child(2) { animation-delay: 0.10s; }
|
||||
body.intro-done .page-bg-pattern .bg-row:nth-child(3) { animation-delay: 0.20s; }
|
||||
body.intro-done .page-bg-pattern .bg-row:nth-child(4) { animation-delay: 0.30s; }
|
||||
body.intro-done .page-bg-pattern .bg-row:nth-child(5) { animation-delay: 0.40s; }
|
||||
body.intro-done .page-bg-pattern .bg-row:nth-child(6) { animation-delay: 0.50s; }
|
||||
body.intro-done .page-bg-pattern .bg-row:nth-child(7) { animation-delay: 0.60s; }
|
||||
body.intro-done .page-bg-pattern .bg-row:nth-child(8) { animation-delay: 0.70s; }
|
||||
body.intro-done .page-bg-pattern .bg-row:nth-child(9) { animation-delay: 0.80s; }
|
||||
body.intro-done .page-bg-pattern .bg-row:nth-child(10) { animation-delay: 0.90s; }
|
||||
.page-bg-pattern .bg-row:nth-child(1) { --row-delay: 0.00s; }
|
||||
.page-bg-pattern .bg-row:nth-child(2) { --row-delay: 0.10s; }
|
||||
.page-bg-pattern .bg-row:nth-child(3) { --row-delay: 0.20s; }
|
||||
.page-bg-pattern .bg-row:nth-child(4) { --row-delay: 0.30s; }
|
||||
.page-bg-pattern .bg-row:nth-child(5) { --row-delay: 0.40s; }
|
||||
.page-bg-pattern .bg-row:nth-child(6) { --row-delay: 0.50s; }
|
||||
.page-bg-pattern .bg-row:nth-child(7) { --row-delay: 0.60s; }
|
||||
.page-bg-pattern .bg-row:nth-child(8) { --row-delay: 0.70s; }
|
||||
.page-bg-pattern .bg-row:nth-child(9) { --row-delay: 0.80s; }
|
||||
.page-bg-pattern .bg-row:nth-child(10) { --row-delay: 0.90s; }
|
||||
@keyframes bgRowSlideLeft {
|
||||
from { opacity: 0; transform: translateX(-160px); }
|
||||
to { opacity: 1; transform: translateX(0); }
|
||||
@@ -211,10 +238,7 @@ body.intro-done .page-bg-pattern .bg-row:nth-child(10) { animation-delay: 0.90s;
|
||||
|
||||
/* (Per-page bg override removed — every page now uses #FAFAFA.) */
|
||||
|
||||
/* No section-level stacking context needed — the pattern lives at
|
||||
z-index:-1 so normal-flow sections paint above it automatically.
|
||||
Avoiding a stacking context on .results-section also lets the
|
||||
capture-modal (z-index:200) reach above the site-header. */
|
||||
/* Hero copy sits above the fixed pattern layer. */
|
||||
.hero-eyebrow {
|
||||
position: relative; z-index: 1;
|
||||
font-family: var(--font-body);
|
||||
@@ -345,7 +369,7 @@ html[lang="en"] .hero h1 { font-size: calc((100vw - 32px) / 5.2); }
|
||||
max-width: 520px;
|
||||
margin: 0 auto 40px;
|
||||
line-height: 1.6;
|
||||
animation: fadeUp 1s 1.3s ease both;
|
||||
animation: fadeUp 1s 2.0s ease both;
|
||||
}
|
||||
.cta-btn {
|
||||
display: inline-flex;
|
||||
@@ -360,7 +384,7 @@ html[lang="en"] .hero h1 { font-size: calc((100vw - 32px) / 5.2); }
|
||||
border-radius: 0;
|
||||
cursor: pointer;
|
||||
transition: color 0.3s ease, var(--trans);
|
||||
animation: fadeUp 1s 1.45s ease both;
|
||||
animation: fadeUp 1s 2.45s ease both;
|
||||
/* Lift above .hero::after radial fade so the button isn't washed out */
|
||||
z-index: 2;
|
||||
}
|
||||
@@ -782,14 +806,26 @@ input[type=range]::-moz-range-thumb {
|
||||
to dark for legibility on the light background. */
|
||||
.rec-cards { animation: fadeUp 0.4s 0.15s ease both; }
|
||||
.rec-card {
|
||||
background: #F0F0F0;
|
||||
/* Lighter card body — was #F0F0F0 (read as grey on the page); now
|
||||
#FAFAFA so the product info sits on a near-white surface. The
|
||||
header above takes the light sage tone as a visual section break. */
|
||||
background: #FAFAFA;
|
||||
border: 1px solid rgba(0,0,0,0.06);
|
||||
border-radius: var(--radius);
|
||||
margin-bottom: 12px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 3px 6px rgba(0,0,0,0.06), inset 0 1px 0 rgba(255,255,255,0.7);
|
||||
}
|
||||
.rec-header { padding: 14px 16px; display: flex; align-items: center; gap: 12px; border-bottom: 1px solid rgba(0,0,0,0.06); }
|
||||
/* Header strip wears the same light sage as the .rp-hint banner so
|
||||
the rec-card sections read as a coordinated family. */
|
||||
.rec-header {
|
||||
padding: 14px 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
background: #E5F0E0;
|
||||
border-bottom: 1px solid rgba(90,154,120,0.22);
|
||||
}
|
||||
/* Green-paint icon chip — matches the painted CTA buttons. ::before
|
||||
carries the dark-green fill with the gloss filter; the icon SVG inside
|
||||
inherits the warm-cream stroke colour via currentColor. */
|
||||
@@ -1143,7 +1179,7 @@ input[type=range]::-moz-range-thumb {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 1000;
|
||||
background: #FAFAFA;
|
||||
background: transparent;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -1157,12 +1193,177 @@ input[type=range]::-moz-range-thumb {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 28px;
|
||||
text-align: center;
|
||||
padding: 0 32px;
|
||||
white-space: pre-line;
|
||||
}
|
||||
|
||||
/* Stage icons — paint-style badge that visually persists across all
|
||||
three stages (same circle, same paint filter, same position) so the
|
||||
inner glyph appears to morph through it as stages crossfade. The
|
||||
glyph itself draws in stroke-by-stroke per stage. Cream stroke on
|
||||
dark green paint matches the CTA buttons. */
|
||||
.stage-icon {
|
||||
display: block;
|
||||
width: clamp(72px, 13vw, 100px);
|
||||
height: clamp(72px, 13vw, 100px);
|
||||
fill: none;
|
||||
opacity: 0;
|
||||
transform: scale(0.78);
|
||||
transform-origin: center;
|
||||
}
|
||||
.stage-icon .badge {
|
||||
fill: #2a3010;
|
||||
stroke: none;
|
||||
filter: url(#paintGlossBtn);
|
||||
-webkit-filter: url(#paintGlossBtn);
|
||||
}
|
||||
.stage-icon .glyph {
|
||||
color: #f4ecd8;
|
||||
stroke: currentColor;
|
||||
/* Slightly thicker strokes so the cream icons read with confidence
|
||||
against the dark green paint chip. */
|
||||
stroke-width: 3.2;
|
||||
fill: none;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
/* Per-element overrides — accent strokes (ridge, hour hand, side
|
||||
buttons) are thinner so they read as detail rather than primary. */
|
||||
.stage-icon .glyph .i-ridge { stroke-width: 1.4; opacity: 0.55; }
|
||||
.stage-icon .glyph .i-side { stroke-width: 2.2; }
|
||||
.stage-icon .glyph .i-hour { stroke-width: 2.6; }
|
||||
.stage-icon .glyph .i-tick { stroke-width: 2.4; }
|
||||
.stage-icon .glyph .i-pin { fill: currentColor; stroke: none; }
|
||||
/* Bolder mark / bolt — the punctuation strokes inside each icon. */
|
||||
.stage-icon .glyph .i-mark { stroke-width: 4.2; }
|
||||
.stage-icon .glyph .i-bolt { stroke-width: 4.0; }
|
||||
/* Glyph paths/lines/circles draw in stroke-by-stroke. pathLength: 1
|
||||
normalises the dashoffset so each piece draws over the same time. */
|
||||
.stage-icon .glyph path,
|
||||
.stage-icon .glyph line,
|
||||
.stage-icon .glyph circle {
|
||||
stroke-dasharray: 1;
|
||||
stroke-dashoffset: 1;
|
||||
pathLength: 1;
|
||||
}
|
||||
.intro-stage.active .stage-icon {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
transition:
|
||||
opacity 0.25s ease 0.05s,
|
||||
transform 0.55s cubic-bezier(0.18, 0.89, 0.32, 1.18) 0.05s;
|
||||
}
|
||||
.intro-stage.active .stage-icon .glyph path,
|
||||
.intro-stage.active .stage-icon .glyph line,
|
||||
.intro-stage.active .stage-icon .glyph circle {
|
||||
animation: introDraw 0.9s 0.1s cubic-bezier(0.22, 0.61, 0.36, 1) forwards;
|
||||
}
|
||||
@keyframes introDraw {
|
||||
to { stroke-dashoffset: 0; }
|
||||
}
|
||||
.stage-icon .filled-icon path {
|
||||
fill: currentColor;
|
||||
stroke: none;
|
||||
opacity: 0;
|
||||
transform: scale(0.84);
|
||||
transform-box: fill-box;
|
||||
transform-origin: center;
|
||||
}
|
||||
.intro-stage.active .stage-icon .filled-icon path {
|
||||
animation: introGlyphPop 0.65s 0.18s cubic-bezier(0.18, 0.89, 0.32, 1.18) forwards;
|
||||
}
|
||||
@keyframes introGlyphPop {
|
||||
to { opacity: 1; transform: scale(1); }
|
||||
}
|
||||
.stage-icon .glyph-stroke {
|
||||
fill: none;
|
||||
stroke: #fff8dc;
|
||||
stroke-width: 4.2;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
stroke-dasharray: 1;
|
||||
stroke-dashoffset: 1;
|
||||
pathLength: 1;
|
||||
opacity: 0;
|
||||
filter: drop-shadow(0 0 5px rgba(255, 248, 220, 0.55));
|
||||
}
|
||||
.stage-icon .i-shield-outline {
|
||||
stroke-width: 3.8;
|
||||
}
|
||||
.stage-icon .glyph-fill {
|
||||
fill: #fff8dc;
|
||||
stroke: none;
|
||||
opacity: 0;
|
||||
filter:
|
||||
drop-shadow(0 0 5px rgba(255, 248, 220, 0.95))
|
||||
drop-shadow(0 0 14px rgba(244, 236, 216, 0.7));
|
||||
}
|
||||
|
||||
/* Stage 1 — the shield border appears first; the filled check ticks in
|
||||
near the end of the sentence, after "prepare" has landed. */
|
||||
.intro-stage.stage-1.active .i-shield-outline {
|
||||
animation: introDraw 0.78s 0.18s cubic-bezier(0.22, 0.61, 0.36, 1) forwards;
|
||||
opacity: 1;
|
||||
}
|
||||
.intro-stage.stage-1.active .i-secure-tick {
|
||||
animation: tickFillIn 0.48s 2.35s cubic-bezier(0.18, 0.89, 0.32, 1.18) forwards;
|
||||
transform-box: fill-box;
|
||||
transform-origin: center;
|
||||
}
|
||||
@keyframes tickFillIn {
|
||||
0% { opacity: 0; transform: scale(0.55) rotate(-8deg); }
|
||||
65% { opacity: 1; transform: scale(1.13) rotate(0deg); }
|
||||
100% { opacity: 1; transform: scale(1) rotate(0deg); }
|
||||
}
|
||||
|
||||
/* Stage 2 — the supplied cloud icon appears first; the bolt flashes like
|
||||
lightning once the crisis sentence is readable. */
|
||||
.intro-stage.stage-2.active .i-lightning-flash {
|
||||
animation: lightningStrike 1.08s 0.45s steps(1, end) infinite;
|
||||
}
|
||||
@keyframes lightningStrike {
|
||||
0% { opacity: 0; }
|
||||
7% { opacity: 1; }
|
||||
12% { opacity: 0.16; }
|
||||
18% { opacity: 1; }
|
||||
25% { opacity: 0; }
|
||||
42% { opacity: 0.92; }
|
||||
50% { opacity: 0.18; }
|
||||
64% { opacity: 1; }
|
||||
72% { opacity: 0; }
|
||||
100% { opacity: 0; }
|
||||
}
|
||||
|
||||
/* Stage 3 — face + ticks draw, then the minute hand takes the sentence
|
||||
timing to sweep two full rotations and land back at 12. */
|
||||
.icon-clock .i-crown { animation-delay: 0.10s !important; }
|
||||
.icon-clock .i-face { animation-delay: 0.20s !important; animation-duration: 0.7s !important; }
|
||||
.icon-clock .i-tick { animation-delay: 0.70s !important; animation-duration: 0.3s !important; }
|
||||
.icon-clock .i-hand {
|
||||
transform-origin: 48px 48px;
|
||||
animation-delay: 0.70s !important;
|
||||
animation-duration: 0.35s !important;
|
||||
}
|
||||
.intro-stage.stage-3.active .icon-clock .i-hand {
|
||||
animation: introDraw 0.35s 0.70s cubic-bezier(0.22, 0.61, 0.36, 1) forwards,
|
||||
clockSweep 2.2s 1.35s linear forwards;
|
||||
}
|
||||
@keyframes clockSweep {
|
||||
from { transform: rotate(0deg); }
|
||||
to { transform: rotate(720deg); }
|
||||
}
|
||||
|
||||
/* Stage exit — keep the badge/icon present while text dissolves, so the
|
||||
circle feels continuous instead of outroing between sentences. */
|
||||
.intro-stage.leaving .stage-icon {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
/* Intro text — uppercase Barlow at heading scale with wide tracking,
|
||||
matching the "Preparedness. Refined." sub-line typeface. No paint
|
||||
filter / no gradient text-fill (those tanked render performance during
|
||||
@@ -1201,6 +1402,29 @@ input[type=range]::-moz-range-thumb {
|
||||
was the lag source. */
|
||||
will-change: opacity, transform;
|
||||
}
|
||||
/* Per-stage emphasis — JS adds .bold to specific words per intro line
|
||||
("prepare" / "vorsorgt", "crisis" / "krise", and the closing clause
|
||||
on stage 3). */
|
||||
.intro-stage .intro-text > .word.bold {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
/* Stage 2 mobile line break — JS inserts <br class="mobile-break">
|
||||
after the leading conjunction ("if" / "wenn") so the second clause
|
||||
("crisis is not here yet" / "noch keine Krise da ist.") wraps onto
|
||||
its own line on small viewports. Hidden on desktop via display:none
|
||||
so the sentence renders on a single line. */
|
||||
.intro-stage br.mobile-break { display: inline; }
|
||||
@media (min-width: 768px) {
|
||||
.intro-stage br.mobile-break { display: none; }
|
||||
}
|
||||
/* Mobile-only line break — JS inserts a <br class="mobile-break">
|
||||
after "if" / "wenn" on stage 2. Display:none on wider viewports so
|
||||
the line stays one row on desktop / tablet. */
|
||||
.intro-stage .intro-text .mobile-break { display: inline; }
|
||||
@media (min-width: 768px) {
|
||||
.intro-stage .intro-text .mobile-break { display: none; }
|
||||
}
|
||||
.intro-stage.active .intro-text > .word {
|
||||
animation: introWord 1.05s cubic-bezier(0.22, 0.61, 0.36, 1) forwards;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user