diff --git a/docker/frontend/src/Landing.tsx b/docker/frontend/src/Landing.tsx index 00ba051..bf5dca7 100644 --- a/docker/frontend/src/Landing.tsx +++ b/docker/frontend/src/Landing.tsx @@ -720,6 +720,17 @@ export function Landing() { ))} + {/* The trial notice: the last shelf of the bar, under the menu line. It + scrolls because it is one long sentence that would otherwise wrap on + a phone and stand as a paragraph. The sentence is rendered twice — + the second copy is the one that walks in as the first walks out, and + is hidden from screen readers so the news is announced once. */} +
+
+ {t('notice.trial')} + +
+
{menu ? (
{nav.map((entry) => setMenu(false)}>{c(entry.label)})} diff --git a/docker/frontend/src/styles/landing.css b/docker/frontend/src/styles/landing.css index 8bbc3cf..c60b87b 100644 --- a/docker/frontend/src/styles/landing.css +++ b/docker/frontend/src/styles/landing.css @@ -63,7 +63,9 @@ [data-theme="light"] .lp-plan.vip { background: linear-gradient(180deg, var(--accent-soft), rgba(255, 255, 255, 0.92)); } [data-theme="light"] .lp-toast { background: rgba(255, 255, 255, 0.98); box-shadow: 0 20px 50px rgba(20, 22, 28, 0.22); } -html { scroll-behavior: smooth; scroll-padding-top: 116px; } +/* The jump target has to clear the fixed bar: 62px of nav + 43px of subnav + + 32px of notice, plus a little air. */ +html { scroll-behavior: smooth; scroll-padding-top: 148px; } .lp ::selection { background: var(--lp-amber); color: #10121a; } .lp-wrap { max-width: 1180px; margin: 0 auto; padding: 0 22px; } .lp h1, .lp h2, .lp h3 { font-family: var(--lp-display); font-weight: 800; line-height: 1.1; margin: 0; } @@ -139,6 +141,29 @@ html { scroll-behavior: smooth; scroll-padding-top: 116px; } white-space: nowrap; } .lp-subnav-link:hover { color: var(--lp-text); border-color: var(--accent-line); } +/* The trial notice: the bar's third shelf, under the menu line. One line, so it + never wraps and the bar keeps a fixed height the hero's padding can match. + The sentence is printed twice and the track slides exactly half its own width + — the second copy arrives where the first left, so the loop has no seam and + the gap lives in each copy's right padding rather than between them. */ +.lp-notice { border-top: 1px solid var(--lp-line); overflow: hidden; padding: 6px 0; } +.lp-notice-track { display: flex; width: max-content; animation: lp-notice-roll 40s linear infinite; } +.lp-notice-track span { + padding-right: 72px; + white-space: nowrap; + font-size: 12px; + /* The theme's own ink, not the page's amber: on the light theme the plain + accent is too bright to read on paper. Pulled a fifth of the way toward the + page's text colour, because the bare accent lands at 4.0:1 on the violet + dark theme, which a 12px line may not wear — the mix keeps the hue and + walks toward whichever extreme the page already uses. */ + color: color-mix(in srgb, var(--lp-ink-amber) 78%, var(--lp-text)); + letter-spacing: 0.02em; +} +@keyframes lp-notice-roll { to { transform: translateX(-50%); } } +@media (prefers-reduced-motion: reduce) { + .lp-notice-track { animation: none; } +} .lp-nav .lp-spacer { flex: 1 1 auto; } .lp-tools { display: flex; gap: 6px; } .lp-tool { @@ -205,7 +230,7 @@ html { scroll-behavior: smooth; scroll-padding-top: 116px; } @media (min-width: 1161px) { .lp-sheet { display: none; } } /* --- 2. hero ------------------------------------------------------------ */ -.lp-hero { position: relative; padding: 184px 0 74px; overflow: hidden; } +.lp-hero { position: relative; padding: 216px 0 74px; overflow: hidden; } .lp-glow { position: absolute; inset: -30% -10% auto -10%; @@ -577,7 +602,8 @@ html { scroll-behavior: smooth; scroll-padding-top: 116px; } .lp-tool { width: 30px; height: 30px; font-size: 11px; } .lp-burger { padding: 6px; } .lp-sec { padding: 64px 0; } - .lp-hero { padding: 112px 0 52px; } + /* The subnav is gone under 1160px, so only the notice has to be paid for. */ + .lp-hero { padding: 144px 0 52px; } .lp-grid, .lp-quotes, .lp-price, .lp-stats { grid-template-columns: minmax(0, 1fr); } .lp-stat { display: flex; align-items: baseline; gap: 10px; } .lp-social { margin-left: 0; }