feat: a deck building itself on the landing page, and no captions anywhere
Three things this site does, and the third had no picture. A talk built from the same evidence the bank is written from — a template, the figures dropped in, exported as PowerPoint — is hard to say in a sentence and easy to show, so this says nothing at all: a slide assembles itself, the deck beside it lights up as each one lands, and the eye works out what it is watching. The one link is navigation, not explanation. Three slides share a 21s loop, each a third of a turn behind the last by way of a negative delay, so there is no clock in JavaScript and nothing to unwind on unmount. Every part inside a slide rides the same loop and the same delay plus its own `--d`, and that is what staggers the build. Under calm motion the loop is not applied and the three lie side by side, finished. Also here, because it is the same argument: the study panel's caption is gone. The panel is a picture of a question marking itself, which is the whole of what the caption said, and a screen reader is told that by the figure's own label. And the hero no longer says "pediatric". The domain says whose site this is, more steps are coming, and a line naming one exam has to be rewritten the week the next one is added. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TqXevQJhxFrM7jJg82cgZN
This commit is contained in:
parent
532d613393
commit
177df84817
2 changed files with 363 additions and 13 deletions
|
|
@ -361,9 +361,6 @@
|
|||
gap: 28px; align-items: start;
|
||||
}
|
||||
.lp-mode { margin: 0; }
|
||||
.lp-mode figcaption { margin-bottom: 14px; }
|
||||
.lp-mode figcaption strong { display: block; font-size: 1.05rem; font-weight: 700; }
|
||||
.lp-mode figcaption span { display: block; margin-top: 4px; font-size: .88rem; line-height: 1.5; color: var(--text-muted); }
|
||||
|
||||
.lp-screen {
|
||||
border: 1px solid var(--border); border-radius: 12px; overflow: hidden;
|
||||
|
|
@ -542,3 +539,237 @@
|
|||
@media (min-width: 1100px) {
|
||||
.lp-modes { grid-template-columns: repeat(3, minmax(0, 1fr)); }
|
||||
}
|
||||
|
||||
|
||||
/* ── The deck studio ──────────────────────────────────────────────────
|
||||
A slide building itself, and the deck beside it filling up. No prose: the
|
||||
third thing this site does is make a talk out of the same evidence, and a
|
||||
picture of that lands before a sentence about it would have been read.
|
||||
|
||||
The colours here are a deliberate exception to the tokens-only rule at the
|
||||
top of this file, in the same way the mimed question screens are: these are
|
||||
pictures of slides, and a slide with no colour of its own is not a picture
|
||||
of a slide. They are declared once, as local properties, and every one of
|
||||
them is mixed out of --primary so the warm theme stays warm.
|
||||
|
||||
Timing. One 21s loop shared by everything. Each slide is a third of a turn
|
||||
behind the last, done with a negative delay (`--i * -14s`), so the three
|
||||
take the stage in order with no clock in JavaScript. Every part inside a
|
||||
slide carries the same delay plus its own `--d`, and that — not a separate
|
||||
keyframe per part — is what staggers the build. */
|
||||
.lp-studio {
|
||||
--sl-ink: #1e293b;
|
||||
--sl-paper: #ffffff;
|
||||
--sl-accent: var(--primary);
|
||||
--sl-tint: color-mix(in srgb, var(--primary) 12%, #ffffff);
|
||||
--sl-tint-2: color-mix(in srgb, var(--primary) 26%, #ffffff);
|
||||
--sl-quiet: color-mix(in srgb, var(--primary) 16%, #94a3b8);
|
||||
--sl-warm: color-mix(in srgb, var(--primary) 55%, #f0a04b);
|
||||
display: grid; grid-template-columns: minmax(0, 1fr) 168px; gap: 22px;
|
||||
align-items: stretch; max-width: 880px; margin: 0 auto;
|
||||
}
|
||||
|
||||
.lp-stage { margin: 0; min-width: 0; }
|
||||
|
||||
/* 16:9, because that is the shape people recognise before they read
|
||||
anything on it. */
|
||||
.lp-deck {
|
||||
position: relative; aspect-ratio: 16 / 9; overflow: hidden;
|
||||
border: 1px solid var(--border); border-radius: 14px; background: var(--sl-paper);
|
||||
box-shadow: 0 20px 48px rgba(15, 23, 42, .16);
|
||||
}
|
||||
|
||||
.lp-slide {
|
||||
position: absolute; inset: 0; padding: 7% 8%;
|
||||
display: flex; flex-direction: column; gap: 2.4%;
|
||||
background: var(--sl-paper); opacity: 0;
|
||||
}
|
||||
/* Calm motion, or no motion preference: the three sit side by side, finished.
|
||||
Nothing is lost — a deck is a thing you look at, not a thing you watch. */
|
||||
.lp-studio.is-calm .lp-deck { aspect-ratio: auto; display: grid; gap: 10px; padding: 10px; }
|
||||
.lp-studio.is-calm .lp-slide { position: static; opacity: 1; aspect-ratio: 16 / 9; border: 1px solid var(--border); border-radius: 8px; }
|
||||
|
||||
/* Slide 1 — the opener. */
|
||||
.lp-slide.is-title { justify-content: center; padding-left: 11%; }
|
||||
.lp-sl-wash {
|
||||
position: absolute; inset: 0; opacity: 0;
|
||||
background:
|
||||
radial-gradient(120% 90% at 8% 110%, var(--sl-tint-2), transparent 62%),
|
||||
radial-gradient(90% 80% at 100% 0%, color-mix(in srgb, var(--sl-warm) 34%, #ffffff), transparent 58%),
|
||||
var(--sl-paper);
|
||||
}
|
||||
.lp-sl-mark {
|
||||
position: absolute; top: 9%; right: 8%; width: 26px; height: 26px; border-radius: 50%;
|
||||
background: var(--sl-accent); opacity: 0;
|
||||
box-shadow: 0 0 0 6px color-mix(in srgb, var(--sl-accent) 16%, transparent);
|
||||
}
|
||||
.lp-sl-rule { width: 52px; height: 5px; border-radius: 3px; background: var(--sl-accent); opacity: 0; }
|
||||
.lp-sl-h1 { width: 74%; height: 15%; border-radius: 6px; background: var(--sl-ink); opacity: 0; }
|
||||
.lp-sl-h2 { width: 46%; height: 8%; border-radius: 5px; background: var(--sl-quiet); opacity: 0; }
|
||||
.lp-sl-foot { position: absolute; left: 11%; bottom: 8%; width: 30%; height: 5px; border-radius: 3px; background: var(--sl-tint-2); opacity: 0; }
|
||||
|
||||
/* Shared furniture on slides 2 and 3. */
|
||||
.lp-sl-eyebrow { width: 16%; height: 5px; border-radius: 3px; background: var(--sl-accent); opacity: 0; }
|
||||
.lp-sl-title { width: 58%; height: 9%; border-radius: 5px; background: var(--sl-ink); opacity: 0; }
|
||||
.lp-sl-cite { margin-top: auto; width: 34%; height: 4px; border-radius: 2px; background: var(--sl-tint-2); opacity: 0; }
|
||||
|
||||
/* Slide 2 — the figure. */
|
||||
.lp-sl-cols { display: grid; grid-template-columns: 1fr 1.15fr; gap: 5%; flex: 1; min-height: 0; margin-top: 2%; }
|
||||
.lp-sl-copy { display: flex; flex-direction: column; justify-content: center; gap: 11%; }
|
||||
.lp-sl-copy span { display: block; height: 5px; border-radius: 3px; background: var(--sl-quiet); opacity: 0; }
|
||||
.lp-sl-copy span:nth-child(1) { width: 100%; }
|
||||
.lp-sl-copy span:nth-child(2) { width: 92%; }
|
||||
.lp-sl-copy span:nth-child(3) { width: 96%; }
|
||||
.lp-sl-copy span:nth-child(4) { width: 64%; }
|
||||
.lp-sl-figure {
|
||||
border-radius: 8px; overflow: hidden; opacity: 0;
|
||||
background: linear-gradient(150deg, var(--sl-tint), color-mix(in srgb, var(--sl-warm) 20%, #ffffff));
|
||||
}
|
||||
.lp-sl-figure svg { display: block; width: 100%; height: 100%; }
|
||||
.lp-sl-band { fill: var(--sl-accent); opacity: .16; }
|
||||
.lp-sl-curve { fill: none; stroke: var(--sl-accent); stroke-width: 3; stroke-linecap: round;
|
||||
stroke-dasharray: 100; stroke-dashoffset: 100; }
|
||||
.lp-sl-dot { fill: var(--sl-accent); opacity: 0; }
|
||||
|
||||
/* Slide 3 — the numbers. */
|
||||
.lp-sl-data { display: grid; grid-template-columns: 1fr 86px; gap: 6%; align-items: end; flex: 1; min-height: 0; margin-top: 3%; }
|
||||
.lp-sl-bars { list-style: none; margin: 0; padding: 0 0 6px; height: 100%;
|
||||
display: flex; align-items: flex-end; gap: 7%; border-bottom: 2px solid var(--sl-tint-2); }
|
||||
.lp-sl-bars li {
|
||||
flex: 1; height: 0; border-radius: 5px 5px 0 0;
|
||||
background: linear-gradient(180deg, var(--sl-accent), color-mix(in srgb, var(--sl-accent) 55%, #ffffff));
|
||||
}
|
||||
.lp-sl-bars li:nth-child(4) { background: linear-gradient(180deg, var(--sl-warm), color-mix(in srgb, var(--sl-warm) 50%, #ffffff)); }
|
||||
.lp-sl-ring { align-self: center; justify-self: end; width: 86px; opacity: 0; }
|
||||
.lp-sl-ring svg { display: block; width: 100%; height: auto; transform: rotate(-90deg); }
|
||||
.lp-sl-ring-track { fill: none; stroke: var(--sl-tint); stroke-width: 7; }
|
||||
.lp-sl-ring-fill { fill: none; stroke: var(--sl-accent); stroke-width: 7; stroke-linecap: round;
|
||||
stroke-dasharray: 100; stroke-dashoffset: 100; }
|
||||
|
||||
/* A single pass of light once a slide is standing. It is the only part of
|
||||
this that is purely decorative, and it is why the thing reads as finished
|
||||
rather than as still loading. */
|
||||
.lp-sl-sheen {
|
||||
position: absolute; inset: -40% -60%; pointer-events: none; opacity: 0;
|
||||
background: linear-gradient(72deg, transparent 42%, rgba(255,255,255,.55) 50%, transparent 58%);
|
||||
}
|
||||
|
||||
/* The deck filling up beside the stage. */
|
||||
.lp-strip { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 12px; }
|
||||
.lp-thumb {
|
||||
position: relative; aspect-ratio: 16 / 9; overflow: hidden; padding: 11% 10%;
|
||||
display: flex; flex-direction: column; gap: 7%;
|
||||
border: 1px solid var(--border); border-radius: 8px; background: var(--sl-paper);
|
||||
box-shadow: 0 4px 12px rgba(15, 23, 42, .07);
|
||||
}
|
||||
.lp-th-wash { position: absolute; inset: 0;
|
||||
background: radial-gradient(120% 90% at 10% 110%, var(--sl-tint-2), transparent 62%); }
|
||||
.lp-th-bar { position: relative; height: 5px; border-radius: 3px; background: var(--sl-ink); }
|
||||
.lp-th-bar.w70 { width: 70%; } .lp-th-bar.w52 { width: 52%; } .lp-th-bar.w44 { width: 44%; background: var(--sl-quiet); }
|
||||
.lp-th-split { display: grid; grid-template-columns: 1fr 1fr; gap: 8%; flex: 1; }
|
||||
.lp-th-lines { border-radius: 3px;
|
||||
background: repeating-linear-gradient(180deg, var(--sl-quiet) 0 3px, transparent 3px 9px); }
|
||||
.lp-th-fig { border-radius: 4px; background: linear-gradient(150deg, var(--sl-tint-2), var(--sl-tint)); }
|
||||
.lp-th-cols { display: flex; align-items: flex-end; gap: 8%; flex: 1; }
|
||||
.lp-th-cols i { flex: 1; height: var(--h); border-radius: 2px 2px 0 0; background: var(--sl-accent); opacity: .75; }
|
||||
.lp-th-cols i:last-child { background: var(--sl-warm); }
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
.lp-studio:not(.is-calm) .lp-slide {
|
||||
animation: lp-sl-stand 21s linear infinite;
|
||||
animation-delay: calc(var(--i) * -14s);
|
||||
}
|
||||
/* Everything a slide is made of, on the one loop and the one delay, each
|
||||
part late by its own --d. */
|
||||
.lp-studio:not(.is-calm) .lp-slide > *,
|
||||
.lp-studio:not(.is-calm) .lp-sl-copy span {
|
||||
animation: lp-sl-part 21s cubic-bezier(.2, .7, .3, 1) infinite;
|
||||
animation-delay: calc(var(--i) * -14s + var(--d, 0s));
|
||||
}
|
||||
.lp-studio:not(.is-calm) .lp-sl-wash { animation-name: lp-sl-wash-in; }
|
||||
.lp-studio:not(.is-calm) .lp-sl-curve {
|
||||
animation: lp-sl-draw 21s cubic-bezier(.4, 0, .2, 1) infinite;
|
||||
animation-delay: calc(var(--i) * -14s + 1s);
|
||||
}
|
||||
.lp-studio:not(.is-calm) .lp-sl-dot {
|
||||
animation: lp-sl-part 21s ease-out infinite;
|
||||
animation-delay: calc(var(--i) * -14s + 2.1s);
|
||||
}
|
||||
.lp-studio:not(.is-calm) .lp-sl-ring-fill {
|
||||
animation: lp-sl-draw 21s cubic-bezier(.4, 0, .2, 1) infinite;
|
||||
animation-delay: calc(var(--i) * -14s + 1.2s);
|
||||
}
|
||||
.lp-studio:not(.is-calm) .lp-sl-bars li {
|
||||
animation: lp-sl-grow 21s cubic-bezier(.2, .8, .25, 1) infinite;
|
||||
animation-delay: calc(var(--i) * -14s + var(--d));
|
||||
}
|
||||
.lp-studio:not(.is-calm) .lp-sl-sheen {
|
||||
animation: lp-sl-sheen 21s linear infinite;
|
||||
}
|
||||
.lp-studio:not(.is-calm) .lp-thumb {
|
||||
animation: lp-sl-land 21s ease-in-out infinite;
|
||||
animation-delay: calc(var(--i) * -14s);
|
||||
}
|
||||
}
|
||||
|
||||
/* A slide holds the stage for a third of the loop and leaves before the next
|
||||
arrives, so two are never on it at once. */
|
||||
@keyframes lp-sl-stand {
|
||||
0% { opacity: 0; transform: translate3d(14px, 0, 0) scale(.985); }
|
||||
3% { opacity: 1; transform: none; }
|
||||
29% { opacity: 1; transform: none; }
|
||||
32%, 100% { opacity: 0; transform: translate3d(-14px, 0, 0) scale(.985); }
|
||||
}
|
||||
/* Parts clear out well before the slide does, so the next turn always starts
|
||||
on an empty sheet rather than on the last one's leftovers. */
|
||||
@keyframes lp-sl-part {
|
||||
0% { opacity: 0; transform: translate3d(0, 9px, 0); }
|
||||
4% { opacity: 1; transform: none; }
|
||||
26% { opacity: 1; transform: none; }
|
||||
27%, 100% { opacity: 0; transform: none; }
|
||||
}
|
||||
@keyframes lp-sl-wash-in {
|
||||
0% { opacity: 0; }
|
||||
5%, 26% { opacity: 1; }
|
||||
27%, 100% { opacity: 0; }
|
||||
}
|
||||
@keyframes lp-sl-draw {
|
||||
0%, 3% { stroke-dashoffset: 100; }
|
||||
14%, 26% { stroke-dashoffset: 0; }
|
||||
27%, 100% { stroke-dashoffset: 100; }
|
||||
}
|
||||
@keyframes lp-sl-grow {
|
||||
0%, 3% { height: 0; }
|
||||
13%, 26% { height: var(--h); }
|
||||
27%, 100% { height: 0; }
|
||||
}
|
||||
@keyframes lp-sl-sheen {
|
||||
0%, 20% { opacity: 0; transform: translate3d(-70%, 0, 0); }
|
||||
23% { opacity: 1; }
|
||||
28% { opacity: 0; transform: translate3d(70%, 0, 0); }
|
||||
29%, 100% { opacity: 0; transform: translate3d(-70%, 0, 0); }
|
||||
}
|
||||
/* The thumbnail lifts while its slide is the one on the stage. */
|
||||
@keyframes lp-sl-land {
|
||||
0%, 2% { transform: none; border-color: var(--border); box-shadow: 0 4px 12px rgba(15, 23, 42, .07); }
|
||||
6%, 28% { transform: translate3d(-6px, 0, 0);
|
||||
border-color: color-mix(in srgb, var(--primary) 60%, transparent);
|
||||
box-shadow: 0 8px 22px color-mix(in srgb, var(--primary) 22%, transparent); }
|
||||
33%, 100% { transform: none; border-color: var(--border); box-shadow: 0 4px 12px rgba(15, 23, 42, .07); }
|
||||
}
|
||||
|
||||
@media (max-width: 720px) {
|
||||
.lp-studio { grid-template-columns: minmax(0, 1fr); }
|
||||
.lp-strip { flex-direction: row; }
|
||||
.lp-thumb { flex: 1; }
|
||||
/* Sideways on a narrow screen, so the lift has to be sideways too. */
|
||||
@keyframes lp-sl-land {
|
||||
0%, 2% { transform: none; border-color: var(--border); }
|
||||
6%, 28% { transform: translate3d(0, -5px, 0);
|
||||
border-color: color-mix(in srgb, var(--primary) 60%, transparent);
|
||||
box-shadow: 0 8px 22px color-mix(in srgb, var(--primary) 22%, transparent); }
|
||||
33%, 100% { transform: none; border-color: var(--border); }
|
||||
}
|
||||
}
|
||||
|
||||
.lp-studio-cta { margin-top: 34px; text-align: center; }
|
||||
|
|
|
|||
|
|
@ -511,13 +511,11 @@ function ModeShowcase({ calm }) {
|
|||
const cls = `lp-modes${calm ? ' is-calm' : ''}`
|
||||
return (
|
||||
<div className={cls}>
|
||||
<figure className="lp-mode lp-mode-study">
|
||||
<figcaption>
|
||||
<strong>Study</strong>
|
||||
<span>Marked as you answer, with the reasoning underneath.</span>
|
||||
</figcaption>
|
||||
{/* aria-hidden throughout: this is a picture of the product, and a
|
||||
screen reader should hear the caption, not a mimed question. */}
|
||||
<figure className="lp-mode lp-mode-study" aria-label="A study question marking itself and opening its explanation">
|
||||
{/* No caption. The panel is a picture of a study question marking
|
||||
itself, which is the whole of what a caption would have said — and
|
||||
a screen reader is told that by the figure's own label rather than
|
||||
by a line of prose under a mimed screen. */}
|
||||
<div className="lp-screen" aria-hidden="true">
|
||||
<div className="lp-screen-bar">
|
||||
<span className="lp-pill is-study">Study</span>
|
||||
|
|
@ -600,6 +598,110 @@ function ModeShowcase({ calm }) {
|
|||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* The deck studio.
|
||||
*
|
||||
* The third thing PedsHub does is make slides — a talk built from the same
|
||||
* evidence the bank is written from, laid out on a template, with the figures
|
||||
* dropped in, exported as PowerPoint. That is a hard thing to say in a
|
||||
* sentence and an easy thing to show, so this says nothing: a slide assembles
|
||||
* itself, the deck beside it lights up as each one lands, and the eye works
|
||||
* out what it is watching before any caption could have told it.
|
||||
*
|
||||
* Three slides share one 21s loop, each phase-shifted by a third of it with a
|
||||
* negative delay, so there is no JavaScript clock and nothing to unwind on
|
||||
* unmount. Every part inside a slide is on the same loop and the same delay
|
||||
* plus its own small `--d`, which is what staggers the build: the panel, then
|
||||
* the heading, then the figure, then the numbers.
|
||||
*
|
||||
* Under calm motion the loop is not applied at all and the three slides are
|
||||
* laid out side by side, finished — which is the state a deck is meant to be
|
||||
* looked at in anyway.
|
||||
*/
|
||||
function SlideStudio({ calm }) {
|
||||
return (
|
||||
<div className={`lp-studio${calm ? ' is-calm' : ''}`}>
|
||||
{/* aria-hidden: this is a picture of a deck, not a deck. A screen reader
|
||||
is told what it is by the figure's label and skips the mime. */}
|
||||
<figure className="lp-stage" aria-label="A slide deck building itself: a title, a figure with a growth curve, and a slide of results">
|
||||
<div className="lp-deck" aria-hidden="true">
|
||||
|
||||
{/* 1 — the opener. A wash, a rule, a title. */}
|
||||
<div className="lp-slide is-title" style={{ '--i': 0 }}>
|
||||
<span className="lp-sl-wash" style={{ '--d': '0.15s' }} />
|
||||
<span className="lp-sl-mark" style={{ '--d': '0.9s' }} />
|
||||
<span className="lp-sl-rule" style={{ '--d': '0.5s' }} />
|
||||
<span className="lp-sl-h1" style={{ '--d': '0.7s' }} />
|
||||
<span className="lp-sl-h2" style={{ '--d': '0.9s' }} />
|
||||
<span className="lp-sl-foot" style={{ '--d': '1.2s' }} />
|
||||
</div>
|
||||
|
||||
{/* 2 — evidence and a figure. The curve draws itself. */}
|
||||
<div className="lp-slide is-figure" style={{ '--i': 1 }}>
|
||||
<span className="lp-sl-eyebrow" style={{ '--d': '0.3s' }} />
|
||||
<span className="lp-sl-title" style={{ '--d': '0.45s' }} />
|
||||
<div className="lp-sl-cols">
|
||||
<div className="lp-sl-copy">
|
||||
<span style={{ '--d': '0.7s' }} />
|
||||
<span style={{ '--d': '0.85s' }} />
|
||||
<span style={{ '--d': '1s' }} />
|
||||
<span style={{ '--d': '1.15s' }} />
|
||||
</div>
|
||||
<div className="lp-sl-figure" style={{ '--d': '0.75s' }}>
|
||||
<svg viewBox="0 0 120 84" preserveAspectRatio="none" role="presentation">
|
||||
<path className="lp-sl-band" d="M6 62 C 34 54, 66 34, 114 12 L114 30 C 66 50, 34 66, 6 72 Z" />
|
||||
<path className="lp-sl-curve" d="M6 68 C 34 60, 66 40, 114 18" pathLength="100" />
|
||||
<circle className="lp-sl-dot" cx="114" cy="18" r="3.6" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<span className="lp-sl-cite" style={{ '--d': '1.35s' }} />
|
||||
</div>
|
||||
|
||||
{/* 3 — the numbers. Bars grow, the ring closes. */}
|
||||
<div className="lp-slide is-data" style={{ '--i': 2 }}>
|
||||
<span className="lp-sl-eyebrow" style={{ '--d': '0.3s' }} />
|
||||
<span className="lp-sl-title" style={{ '--d': '0.45s' }} />
|
||||
<div className="lp-sl-data">
|
||||
<ul className="lp-sl-bars">
|
||||
<li style={{ '--h': '46%', '--d': '0.7s' }} />
|
||||
<li style={{ '--h': '72%', '--d': '0.82s' }} />
|
||||
<li style={{ '--h': '58%', '--d': '0.94s' }} />
|
||||
<li style={{ '--h': '92%', '--d': '1.06s' }} />
|
||||
</ul>
|
||||
<div className="lp-sl-ring" style={{ '--d': '0.9s' }}>
|
||||
<svg viewBox="0 0 44 44" role="presentation">
|
||||
<circle className="lp-sl-ring-track" cx="22" cy="22" r="18" />
|
||||
<circle className="lp-sl-ring-fill" cx="22" cy="22" r="18" pathLength="100" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<span className="lp-sl-cite" style={{ '--d': '1.35s' }} />
|
||||
</div>
|
||||
|
||||
{/* The sheen that crosses a slide once it is finished. */}
|
||||
<span className="lp-sl-sheen" aria-hidden="true" />
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
{/* The deck as it fills: three thumbnails, the one being built lit. */}
|
||||
<ul className="lp-strip" aria-hidden="true">
|
||||
<li className="lp-thumb is-title" style={{ '--i': 0 }}>
|
||||
<span className="lp-th-wash" /><span className="lp-th-bar w70" /><span className="lp-th-bar w44" />
|
||||
</li>
|
||||
<li className="lp-thumb is-figure" style={{ '--i': 1 }}>
|
||||
<span className="lp-th-bar w52" />
|
||||
<div className="lp-th-split"><span className="lp-th-lines" /><span className="lp-th-fig" /></div>
|
||||
</li>
|
||||
<li className="lp-thumb is-data" style={{ '--i': 2 }}>
|
||||
<span className="lp-th-bar w52" />
|
||||
<div className="lp-th-cols"><i style={{ '--h': '46%' }} /><i style={{ '--h': '72%' }} /><i style={{ '--h': '58%' }} /><i style={{ '--h': '92%' }} /></div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
// ── Main landing page ─────────────────────────────────────────────────────────
|
||||
|
||||
export default function LandingPage() {
|
||||
|
|
@ -623,11 +725,14 @@ export default function LandingPage() {
|
|||
{/* ── Hero ───────────────────────────────────────────────────────────── */}
|
||||
<section className="lp-hero">
|
||||
<div className="lp-hero-inner">
|
||||
<span className="lp-eyebrow">Pediatric board preparation</span>
|
||||
{/* Deliberately not "pediatric". The domain already says whose site
|
||||
this is, and the steps are coming — a line that names one exam
|
||||
would have to be rewritten the week the next one is added. */}
|
||||
<span className="lp-eyebrow">Clinical boards and exam preparation</span>
|
||||
<h1>Sit the paper<br /><em>before you sit the paper.</em></h1>
|
||||
<p className="lp-lead">
|
||||
A pediatric question bank you take as timed blocks or as study, an analysis
|
||||
that tells you where you actually stand, and an assistant that is only
|
||||
A question bank you take as timed blocks or as study, an analysis that
|
||||
tells you where you actually stand, and an assistant that is only
|
||||
permitted to answer out of your own library.
|
||||
</p>
|
||||
<Rotator calm={calm} />
|
||||
|
|
@ -653,6 +758,20 @@ export default function LandingPage() {
|
|||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── Slides ─────────────────────────────────────────────────────────
|
||||
Wordless on purpose. It is a deck being built out of the same
|
||||
evidence, and watching it land says more than a paragraph claiming
|
||||
it would. The one link is navigation, not explanation. */}
|
||||
<section className="lp-section lp-section-raised">
|
||||
<div className="lp-inner">
|
||||
<SlideStudio calm={calm} />
|
||||
<div className="lp-studio-cta">
|
||||
<a href="https://app.pedshub.com" target="_blank" rel="noopener noreferrer"
|
||||
className="btn lp-cta-ghost">Make a deck ↗</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── Where the AI is ────────────────────────────────────────────────── */}
|
||||
<section className="lp-section lp-section-dark">
|
||||
<div className="lp-inner">
|
||||
|
|
|
|||
Loading…
Reference in a new issue