feat: the deck studio is a deck being made, not three pictures of slides
Three improvements and one real bug. The bug: `.lp-sl-wash` is absolutely positioned and ends in an opaque white, so it painted *over* its static siblings — the title slide laid its rule, heading and picture out correctly and then covered them with its own background. An explicit z-index on the wash and its siblings fixes it. The improvements: the slide now sits inside editor chrome, with an export control that lights up as each slide lands, because three slides in a row are three pictures and the same three inside a window are a deck being made; a pointer moves across the canvas, places two things and presses export, which is what makes it read as being *built*; and the artwork is worth looking at — a figure on the title slide, a line chart with gridlines, a shaded band and plotted points, a two-segment ring and a legend. Each slide carries its own accent, so the three do not look like one slide shown three times. The warm accent was half theme and half amber, which against a blue primary is the colour of a wet pavement. It is mostly amber now. Also: "Pediatric clinical tools" is "Clinical tools", for the same reason the hero no longer says pediatric. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TqXevQJhxFrM7jJg82cgZN
This commit is contained in:
parent
831cb01650
commit
5670ebbdda
2 changed files with 236 additions and 98 deletions
|
|
@ -542,21 +542,22 @@
|
|||
|
||||
|
||||
/* ── 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.
|
||||
A slide building itself inside an editor, 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 is 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.
|
||||
of a slide. They are declared once, as local properties, and mixed out of
|
||||
--primary so the warm theme stays warm — with one accent per slide, so three
|
||||
slides in a row do not look like one slide shown three times.
|
||||
|
||||
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. */
|
||||
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 keyframe per
|
||||
part — is what staggers the build. */
|
||||
.lp-studio {
|
||||
--sl-ink: #1e293b;
|
||||
--sl-paper: #ffffff;
|
||||
|
|
@ -564,75 +565,132 @@
|
|||
--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);
|
||||
/* A little of the theme, mostly the hue itself. Half and half turned amber
|
||||
into mud against a blue primary, which is how the highlight bar came out
|
||||
the colour of a wet pavement. */
|
||||
--sl-warm: color-mix(in srgb, var(--primary) 12%, #f0a53d);
|
||||
--sl-cool: color-mix(in srgb, var(--primary) 35%, #14b8a6);
|
||||
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. */
|
||||
/* The editor around the slide. Three slides in a row are three pictures; the
|
||||
same three inside a window are a deck being made. */
|
||||
.lp-deck {
|
||||
position: relative; aspect-ratio: 16 / 9; overflow: hidden;
|
||||
position: relative; 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-chrome {
|
||||
display: flex; align-items: center; gap: 12px;
|
||||
padding: 8px 12px; border-bottom: 1px solid var(--border); background: var(--bg);
|
||||
}
|
||||
.lp-chrome-dots, .lp-chrome-tools { display: inline-flex; gap: 5px; }
|
||||
.lp-chrome-dots i { width: 8px; height: 8px; border-radius: 50%; background: var(--border); }
|
||||
.lp-chrome-tools i { width: 22px; height: 7px; border-radius: 3px; background: var(--sl-tint-2); }
|
||||
.lp-chrome-tools i:nth-child(2) { width: 14px; }
|
||||
.lp-chrome-tools i:nth-child(3) { width: 30px; }
|
||||
/* The export control, which flashes as each slide lands: a downward arrow, the
|
||||
one shape that means "out of here and onto your disk" without a word. */
|
||||
.lp-chrome-export {
|
||||
position: relative; margin-left: auto; width: 20px; height: 20px;
|
||||
border-radius: 6px; background: color-mix(in srgb, var(--primary) 12%, transparent);
|
||||
}
|
||||
.lp-chrome-export::before {
|
||||
content: ''; position: absolute; left: 9px; top: 4px;
|
||||
width: 2px; height: 9px; border-radius: 1px; background: var(--sl-accent);
|
||||
}
|
||||
.lp-chrome-export::after {
|
||||
content: ''; position: absolute; left: 6px; top: 8px;
|
||||
width: 7px; height: 7px; transform: rotate(45deg);
|
||||
border-right: 2px solid var(--sl-accent); border-bottom: 2px solid var(--sl-accent);
|
||||
}
|
||||
|
||||
/* 16:9, because that is the shape people recognise before they read anything. */
|
||||
.lp-canvas { position: relative; aspect-ratio: 16 / 9; overflow: hidden; }
|
||||
|
||||
.lp-slide {
|
||||
position: absolute; inset: 0; padding: 7% 8%;
|
||||
display: flex; flex-direction: column; gap: 2.4%;
|
||||
position: absolute; inset: 0; padding: 6% 7%;
|
||||
display: flex; flex-direction: column; gap: 2.2%;
|
||||
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; }
|
||||
/* One accent each, so the deck reads as three different slides. */
|
||||
.lp-slide.is-figure { --sl-accent: var(--sl-cool); }
|
||||
.lp-slide.is-data { --sl-accent: var(--primary); }
|
||||
|
||||
/* Calm motion: the three lie 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-canvas { 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; }
|
||||
.lp-studio.is-calm .lp-sl-cursor, .lp-studio.is-calm .lp-sl-sheen { display: none; }
|
||||
|
||||
/* Slide 1 — the opener. */
|
||||
.lp-slide.is-title { justify-content: center; padding-left: 11%; }
|
||||
.lp-slide.is-title { display: grid; grid-template-columns: 1.5fr 1fr; align-items: center; gap: 6%; }
|
||||
/* A fixed gap: the block is only as tall as its three bars, so a percentage
|
||||
gap resolves to three pixels and the title crowds its own rule. */
|
||||
.lp-sl-titleblock { display: flex; flex-direction: column; gap: 11px; }
|
||||
/* Behind the slide's content, explicitly. An absolutely positioned element
|
||||
paints above its static siblings, and this one ends in an opaque white — so
|
||||
the title, the rule and the picture were being laid out correctly and then
|
||||
covered by their own background. */
|
||||
.lp-slide > * { position: relative; z-index: 1; }
|
||||
.lp-sl-wash {
|
||||
position: absolute; inset: 0; opacity: 0;
|
||||
position: absolute; inset: 0; opacity: 0; z-index: 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%),
|
||||
radial-gradient(120% 90% at 6% 110%, var(--sl-tint-2), transparent 60%),
|
||||
radial-gradient(90% 80% at 100% 0%, color-mix(in srgb, var(--sl-warm) 30%, #ffffff), transparent 55%),
|
||||
var(--sl-paper);
|
||||
}
|
||||
.lp-sl-mark {
|
||||
position: absolute; top: 9%; right: 8%; width: 26px; height: 26px; border-radius: 50%;
|
||||
position: absolute; top: 7%; right: 6%; width: 22px; height: 22px; border-radius: 50%;
|
||||
background: var(--sl-accent); opacity: 0;
|
||||
box-shadow: 0 0 0 6px color-mix(in srgb, var(--sl-accent) 16%, transparent);
|
||||
box-shadow: 0 0 0 5px 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; }
|
||||
.lp-sl-rule { width: 46px; height: 5px; border-radius: 3px; background: var(--sl-accent); opacity: 0; }
|
||||
.lp-sl-h1 { width: 92%; height: 17px; border-radius: 5px; background: var(--sl-ink); opacity: 0; }
|
||||
.lp-sl-h2 { width: 58%; height: 9px; border-radius: 5px; background: var(--sl-quiet); opacity: 0; }
|
||||
.lp-sl-foot { position: absolute; left: 7%; bottom: 7%; width: 26%; height: 5px; border-radius: 3px; background: var(--sl-tint-2); opacity: 0; }
|
||||
/* The picture on a title slide. Abstract on purpose — a figure, not a diagram
|
||||
of anything in particular. */
|
||||
.lp-sl-hero {
|
||||
align-self: stretch; margin: 6% 0; border-radius: 10px; overflow: hidden; opacity: 0;
|
||||
background: linear-gradient(150deg, var(--sl-tint), color-mix(in srgb, var(--sl-warm) 22%, #ffffff));
|
||||
}
|
||||
.lp-sl-hero svg { display: block; width: 100%; height: 100%; }
|
||||
.lp-hero-a { fill: var(--sl-accent); opacity: .28; }
|
||||
.lp-hero-b { fill: var(--sl-accent); opacity: .18; }
|
||||
|
||||
/* 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; }
|
||||
.lp-sl-eyebrow { width: 14%; height: 5px; border-radius: 3px; background: var(--sl-accent); opacity: 0; }
|
||||
.lp-sl-title { width: 54%; height: 11px; border-radius: 5px; background: var(--sl-ink); opacity: 0; }
|
||||
.lp-sl-cite { margin-top: auto; width: 30%; 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-cols { display: grid; grid-template-columns: 1fr 1.2fr; gap: 5%; flex: 1; min-height: 0; margin-top: 2%; }
|
||||
.lp-sl-copy { display: flex; flex-direction: column; justify-content: center; gap: 10%; }
|
||||
.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(2) { width: 90%; }
|
||||
.lp-sl-copy span:nth-child(3) { width: 96%; }
|
||||
.lp-sl-copy span:nth-child(4) { width: 64%; }
|
||||
.lp-sl-copy span:nth-child(4) { width: 62%; }
|
||||
/* The line an author adds last, in the accent: the point of the slide. */
|
||||
.lp-sl-copy .lp-sl-bullet { width: 76%; height: 6px; background: var(--sl-accent); opacity: 0; }
|
||||
.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));
|
||||
background: linear-gradient(150deg, var(--sl-tint), color-mix(in srgb, var(--sl-cool) 14%, #ffffff));
|
||||
}
|
||||
.lp-sl-figure svg { display: block; width: 100%; height: 100%; }
|
||||
.lp-sl-band { fill: var(--sl-accent); opacity: .16; }
|
||||
.lp-sl-grid line { stroke: var(--sl-accent); stroke-width: .6; opacity: .18; }
|
||||
.lp-sl-band { fill: var(--sl-accent); opacity: .14; }
|
||||
.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; }
|
||||
.lp-sl-dot.is-last { fill: var(--sl-warm); }
|
||||
|
||||
/* 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-data { display: grid; grid-template-columns: 1fr 80px; 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 {
|
||||
|
|
@ -640,15 +698,30 @@
|
|||
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 { align-self: center; justify-self: end; width: 80px; 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 second segment, so the ring is a proportion of something rather than a
|
||||
progress bar bent into a circle. */
|
||||
.lp-sl-ring-second { fill: none; stroke: var(--sl-warm); stroke-width: 7; stroke-linecap: round;
|
||||
stroke-dasharray: 18 82; stroke-dashoffset: -62; opacity: 0; }
|
||||
.lp-sl-legend { list-style: none; margin: 3% 0 0; padding: 0; display: flex; gap: 10px; }
|
||||
.lp-sl-legend li { width: 34px; height: 5px; border-radius: 3px; background: var(--sl-tint-2); opacity: 0; }
|
||||
.lp-sl-legend li:nth-child(1) { background: var(--sl-accent); }
|
||||
.lp-sl-legend li:nth-child(3) { background: var(--sl-warm); }
|
||||
|
||||
/* 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. */
|
||||
/* The pointer that puts things where they go. It is what makes the panel read
|
||||
as a deck being *made* rather than three slides being shown. */
|
||||
.lp-sl-cursor {
|
||||
position: absolute; top: 0; left: 0; width: 11px; height: 11px; border-radius: 50%;
|
||||
background: var(--sl-ink); opacity: 0; pointer-events: none;
|
||||
box-shadow: 0 0 0 4px color-mix(in srgb, var(--sl-ink) 14%, transparent);
|
||||
}
|
||||
|
||||
/* A single pass of light once a slide is standing. The only purely decorative
|
||||
part, and the reason the thing reads as finished rather than 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%);
|
||||
|
|
@ -669,7 +742,7 @@
|
|||
.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-fig { border-radius: 4px; background: linear-gradient(150deg, var(--sl-cool), 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); }
|
||||
|
|
@ -682,10 +755,19 @@
|
|||
/* 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 {
|
||||
.lp-studio:not(.is-calm) .lp-sl-titleblock > *,
|
||||
.lp-studio:not(.is-calm) .lp-sl-copy span,
|
||||
.lp-studio:not(.is-calm) .lp-sl-legend li {
|
||||
animation: lp-sl-part 21s cubic-bezier(.2, .7, .3, 1) infinite;
|
||||
animation-delay: calc(var(--i) * -14s + var(--d, 0s));
|
||||
}
|
||||
/* The two wrappers are layout, not content: they must not fade as a block or
|
||||
the parts inside them build twice over. */
|
||||
.lp-studio:not(.is-calm) .lp-sl-titleblock,
|
||||
.lp-studio:not(.is-calm) .lp-sl-copy,
|
||||
.lp-studio:not(.is-calm) .lp-sl-cols,
|
||||
.lp-studio:not(.is-calm) .lp-sl-data,
|
||||
.lp-studio:not(.is-calm) .lp-sl-bars { animation: none; opacity: 1; }
|
||||
.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;
|
||||
|
|
@ -693,19 +775,23 @@
|
|||
}
|
||||
.lp-studio:not(.is-calm) .lp-sl-dot {
|
||||
animation: lp-sl-part 21s ease-out infinite;
|
||||
animation-delay: calc(var(--i) * -14s + 2.1s);
|
||||
animation-delay: calc(var(--i) * -14s + var(--d, 1.9s));
|
||||
}
|
||||
.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);
|
||||
animation-delay: calc(var(--i) * -14s + 1.1s);
|
||||
}
|
||||
.lp-studio:not(.is-calm) .lp-sl-ring-second {
|
||||
animation: lp-sl-part 21s ease-out infinite;
|
||||
animation-delay: calc(var(--i) * -14s + 1.8s);
|
||||
}
|
||||
.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-sl-sheen { animation: lp-sl-sheen 21s linear infinite; }
|
||||
.lp-studio:not(.is-calm) .lp-sl-cursor { animation: lp-sl-point 7s cubic-bezier(.5, 0, .3, 1) infinite; }
|
||||
.lp-studio:not(.is-calm) .lp-chrome-export { animation: lp-sl-export 7s ease-out infinite; }
|
||||
.lp-studio:not(.is-calm) .lp-thumb {
|
||||
animation: lp-sl-land 21s ease-in-out infinite;
|
||||
animation-delay: calc(var(--i) * -14s);
|
||||
|
|
@ -749,6 +835,27 @@
|
|||
28% { opacity: 0; transform: translate3d(70%, 0, 0); }
|
||||
29%, 100% { opacity: 0; transform: translate3d(-70%, 0, 0); }
|
||||
}
|
||||
/* The pointer runs on the per-slide beat rather than the whole loop: it places
|
||||
two things, presses the export, and gets out of the way. */
|
||||
@keyframes lp-sl-point {
|
||||
0% { opacity: 0; transform: translate3d(18%, 74%, 0) scale(1); }
|
||||
6% { opacity: .85; transform: translate3d(18%, 62%, 0) scale(1); }
|
||||
14% { opacity: .85; transform: translate3d(24%, 34%, 0) scale(.8); }
|
||||
18% { opacity: .85; transform: translate3d(24%, 34%, 0) scale(1); }
|
||||
30% { opacity: .85; transform: translate3d(66%, 52%, 0) scale(1); }
|
||||
34% { opacity: .85; transform: translate3d(66%, 52%, 0) scale(.8); }
|
||||
38% { opacity: .85; transform: translate3d(66%, 52%, 0) scale(1); }
|
||||
58% { opacity: .85; transform: translate3d(95%, 4%, 0) scale(1); }
|
||||
62% { opacity: .85; transform: translate3d(95%, 4%, 0) scale(.75); }
|
||||
70% { opacity: 0; transform: translate3d(95%, 4%, 0) scale(1); }
|
||||
100% { opacity: 0; transform: translate3d(18%, 74%, 0) scale(1); }
|
||||
}
|
||||
/* And the export lights up as the pointer reaches it. */
|
||||
@keyframes lp-sl-export {
|
||||
0%, 60% { background: color-mix(in srgb, var(--primary) 12%, transparent); transform: none; }
|
||||
64% { background: color-mix(in srgb, var(--primary) 34%, transparent); transform: scale(1.12); }
|
||||
74%, 100% { background: color-mix(in srgb, var(--primary) 12%, transparent); transform: none; }
|
||||
}
|
||||
/* 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); }
|
||||
|
|
|
|||
|
|
@ -621,66 +621,97 @@ function ModeShowcase({ calm }) {
|
|||
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">
|
||||
{/* aria-hidden throughout: this is a picture of a deck being made, 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 being built: a title, a figure with a growth curve, and a slide of results, then exported">
|
||||
<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' }} />
|
||||
{/* The app around the slide. Without it three slides in a row are
|
||||
three pictures; with it they are a deck being made. */}
|
||||
<div className="lp-chrome">
|
||||
<span className="lp-chrome-dots"><i /><i /><i /></span>
|
||||
<span className="lp-chrome-tools"><i /><i /><i /></span>
|
||||
<span className="lp-chrome-export" />
|
||||
</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 className="lp-canvas">
|
||||
{/* 1 — the opener. */}
|
||||
<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': '1.0s' }} />
|
||||
<div className="lp-sl-titleblock">
|
||||
<span className="lp-sl-rule" style={{ '--d': '0.45s' }} />
|
||||
<span className="lp-sl-h1" style={{ '--d': '0.65s' }} />
|
||||
<span className="lp-sl-h2" style={{ '--d': '0.85s' }} />
|
||||
</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" />
|
||||
<div className="lp-sl-hero" style={{ '--d': '0.55s' }}>
|
||||
<svg viewBox="0 0 60 80" preserveAspectRatio="none" role="presentation">
|
||||
<circle className="lp-hero-a" cx="30" cy="26" r="17" />
|
||||
<path className="lp-hero-b" d="M8 78 C 10 52, 22 44, 30 44 C 38 44, 50 52, 52 78 Z" />
|
||||
</svg>
|
||||
</div>
|
||||
<span className="lp-sl-foot" style={{ '--d': '1.25s' }} />
|
||||
</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' }} />
|
||||
{/* 2 — evidence and a figure that draws itself. */}
|
||||
<div className="lp-slide is-figure" style={{ '--i': 1 }}>
|
||||
<span className="lp-sl-eyebrow" style={{ '--d': '0.25s' }} />
|
||||
<span className="lp-sl-title" style={{ '--d': '0.4s' }} />
|
||||
<div className="lp-sl-cols">
|
||||
<div className="lp-sl-copy">
|
||||
<span style={{ '--d': '0.65s' }} />
|
||||
<span style={{ '--d': '0.78s' }} />
|
||||
<span style={{ '--d': '0.91s' }} />
|
||||
<span style={{ '--d': '1.04s' }} />
|
||||
<span className="lp-sl-bullet" style={{ '--d': '1.2s' }} />
|
||||
</div>
|
||||
<div className="lp-sl-figure" style={{ '--d': '0.7s' }}>
|
||||
<svg viewBox="0 0 120 84" preserveAspectRatio="none" role="presentation">
|
||||
<g className="lp-sl-grid">
|
||||
<line x1="6" y1="20" x2="114" y2="20" /><line x1="6" y1="42" x2="114" y2="42" />
|
||||
<line x1="6" y1="64" x2="114" y2="64" />
|
||||
</g>
|
||||
<path className="lp-sl-band" d="M6 62 C 34 54, 66 34, 114 12 L114 32 C 66 52, 34 66, 6 74 Z" />
|
||||
<path className="lp-sl-curve" d="M6 68 C 34 60, 66 40, 114 18" pathLength="100" />
|
||||
<circle className="lp-sl-dot" cx="42" cy="57" r="2.8" style={{ '--d': '1.9s' }} />
|
||||
<circle className="lp-sl-dot" cx="78" cy="39" r="2.8" style={{ '--d': '2.0s' }} />
|
||||
<circle className="lp-sl-dot is-last" cx="114" cy="18" r="3.6" style={{ '--d': '2.1s' }} />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<span className="lp-sl-cite" style={{ '--d': '1.35s' }} />
|
||||
</div>
|
||||
|
||||
{/* 3 — the numbers. */}
|
||||
<div className="lp-slide is-data" style={{ '--i': 2 }}>
|
||||
<span className="lp-sl-eyebrow" style={{ '--d': '0.25s' }} />
|
||||
<span className="lp-sl-title" style={{ '--d': '0.4s' }} />
|
||||
<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.85s' }}>
|
||||
<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" />
|
||||
<circle className="lp-sl-ring-second" cx="22" cy="22" r="18" pathLength="100" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<ul className="lp-sl-legend">
|
||||
<li style={{ '--d': '1.25s' }} /><li style={{ '--d': '1.33s' }} /><li style={{ '--d': '1.41s' }} />
|
||||
</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" />
|
||||
{/* The pointer that puts things where they go, and the sheen that
|
||||
crosses a slide once it is standing. */}
|
||||
<span className="lp-sl-cursor" aria-hidden="true" />
|
||||
<span className="lp-sl-sheen" aria-hidden="true" />
|
||||
</div>
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
|
|
@ -800,7 +831,7 @@ export default function LandingPage() {
|
|||
<div className="lp-inner lp-split">
|
||||
<div>
|
||||
<span className="lp-eyebrow">Also from PedsHub</span>
|
||||
<h2>Pediatric clinical tools</h2>
|
||||
<h2>Clinical tools</h2>
|
||||
<p>
|
||||
The same material, pointed at the ward instead of the exam: well visit
|
||||
planning from newborn to adolescence, developmental milestones, the full
|
||||
|
|
|
|||
Loading…
Reference in a new issue