1607 lines
59 KiB
HTML
1607 lines
59 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>Studio Presentation</title>
|
||
|
||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||
<!--
|
||
Studio style uses three font families:
|
||
1. Barlow 900 — the entire display and heading system; becomes graphic at scale
|
||
2. Barlow 400/500 — body, lead paragraphs
|
||
3. IBM Plex Mono — footer metadata, slide counters, caption labels
|
||
4. Noto Sans SC — Chinese fallback for all roles
|
||
-->
|
||
<link
|
||
href="https://fonts.googleapis.com/css2?family=Barlow:wght@400;500;700;800;900&family=IBM+Plex+Mono:wght@300;400;500&family=Noto+Sans+SC:wght@400;500;700;900&display=swap"
|
||
rel="stylesheet"
|
||
/>
|
||
|
||
<style>
|
||
/* ╔══════════════════════════════════════════════════════════════════════╗
|
||
║ ZONE A · TOKENS — STUDIO STYLE ║
|
||
║ ║
|
||
║ Replace this block to change the visual style entirely. ║
|
||
║ Every color, font, and size in this file reads from these vars. ║
|
||
║ Never write raw hex values, font names, or px sizes outside here. ║
|
||
╚══════════════════════════════════════════════════════════════════════╝ */
|
||
:root {
|
||
/* ── Palette ──────────────────────────────────────────────────────── */
|
||
/* Near-black: the dark slide background — warm dark, not cold neutral */
|
||
--c-bg: #1c1c1c;
|
||
/* Slightly lighter near-black for secondary dark surfaces */
|
||
--c-bg-alt: #242422;
|
||
/* Acid yellow: THE light slide background — yellow is the environment, not an accent */
|
||
--c-bg-light: #f5d200;
|
||
/* Slightly cooler yellow for secondary light surfaces */
|
||
--c-bg-light-alt: #f0cc00;
|
||
|
||
/* Primary text on dark: acid yellow — the only colour on dark slides */
|
||
--c-fg: #f5d200;
|
||
/* Secondary text on dark: yellow at 58% opacity — muted but still warm */
|
||
--c-fg-2: rgba(245, 210, 0, 0.58);
|
||
/* Tertiary / hint text on dark: yellow at 32% */
|
||
--c-fg-3: rgba(245, 210, 0, 0.32);
|
||
/* Primary text on light: near-black on yellow */
|
||
--c-fg-light: #1c1c1c;
|
||
/* Secondary text on light: near-black at 62% */
|
||
--c-fg-light-2: rgba(28, 28, 28, 0.62);
|
||
/* Tertiary text on light */
|
||
--c-fg-light-3: rgba(28, 28, 28, 0.35);
|
||
|
||
/* Accent: yellow on dark / same yellow (var reused by engine) */
|
||
--c-accent: #f5d200;
|
||
/* Dividers on dark: very dark warm border */
|
||
--c-border: #2e2e2c;
|
||
/* Dividers on light: near-black at 18% opacity on yellow */
|
||
--c-border-light: rgba(28, 28, 28, 0.18);
|
||
|
||
/* ── Typography ──────────────────────────────────────────────────── */
|
||
/* Display + Heading: Barlow 900 — grotesque at max weight becomes a graphic object */
|
||
--f-display: "Barlow", "Noto Sans SC", sans-serif;
|
||
--f-heading: "Barlow", "Noto Sans SC", sans-serif;
|
||
/* Body: Barlow 400/500 — same family, steps back as weight drops */
|
||
--f-body: "Barlow", "Noto Sans SC", system-ui, sans-serif;
|
||
/* Mono: IBM Plex Mono — metadata, counters, footer columns */
|
||
--f-mono: "IBM Plex Mono", monospace;
|
||
|
||
/* ── Type Scale ───────────────────────────────────────────────────── */
|
||
/* Studio runs type LARGER than Signal — the headline IS the layout */
|
||
--sz-display: 12vw; /* cover hero — type at maximum scale */
|
||
--sz-h1: 7.5vw; /* chapter titles, statement headlines */
|
||
--sz-h2: 4.8vw; /* section headers */
|
||
--sz-h3: 2.8vw; /* sub-headlines */
|
||
--sz-lead: 1.6vw; /* intro paragraphs */
|
||
--sz-body: 1.15vw; /* body text, bullets */
|
||
--sz-caption: 0.85vw; /* captions, footnotes */
|
||
--sz-label: 0.72vw; /* mono metadata, chrome */
|
||
|
||
/* ── Spacing ─────────────────────────────────────────────────────── */
|
||
/* Studio pads tighter than Signal — type runs to near-edge */
|
||
--pad-x: 5vw;
|
||
--pad-y: 5vh;
|
||
--gap-lg: 3.5vh;
|
||
--gap-md: 2vh;
|
||
--gap-sm: 1vh;
|
||
|
||
/* ── Motion ──────────────────────────────────────────────────────── */
|
||
/* Harder, sharper transitions — agency urgency, not editorial grace */
|
||
--ease-slide: cubic-bezier(0.77, 0, 0.175, 1);
|
||
--dur-slide: 0.75s;
|
||
--ease-enter: cubic-bezier(0.16, 1, 0.3, 1);
|
||
--dur-enter: 0.5s;
|
||
}
|
||
|
||
/* ╔══════════════════════════════════════════════════════════════════════╗
|
||
║ ZONE B · ENGINE — DO NOT MODIFY ║
|
||
║ ║
|
||
║ Layout engine, transitions, animation system, navigation. ║
|
||
║ Touching this breaks the mechanics. ║
|
||
╚══════════════════════════════════════════════════════════════════════╝ */
|
||
|
||
*,
|
||
*::before,
|
||
*::after {
|
||
box-sizing: border-box;
|
||
margin: 0;
|
||
padding: 0;
|
||
}
|
||
html,
|
||
body {
|
||
width: 100%;
|
||
height: 100%;
|
||
overflow: hidden;
|
||
background: var(--c-bg);
|
||
-webkit-font-smoothing: antialiased;
|
||
}
|
||
|
||
/* Deck container — all slides sit side by side in one horizontal strip */
|
||
#deck {
|
||
display: flex;
|
||
height: 100vh;
|
||
transition: transform var(--dur-slide) var(--ease-slide);
|
||
will-change: transform;
|
||
}
|
||
|
||
/* Slide base — each slide occupies exactly one full viewport */
|
||
.slide {
|
||
flex: 0 0 100vw;
|
||
width: 100vw;
|
||
height: 100vh;
|
||
position: relative;
|
||
padding: var(--pad-y) var(--pad-x);
|
||
display: grid;
|
||
grid-template-rows: auto 1fr auto;
|
||
overflow: hidden;
|
||
}
|
||
.slide-body {
|
||
min-height: 0;
|
||
}
|
||
|
||
/* Slide themes */
|
||
.slide.dark {
|
||
background: var(--c-bg);
|
||
color: var(--c-fg);
|
||
}
|
||
.slide.light {
|
||
background: var(--c-bg-light);
|
||
color: var(--c-fg-light);
|
||
}
|
||
|
||
/* ── Animation system ─────────────────────────────────────────────── */
|
||
/* Elements start invisible; become visible only when slide is active */
|
||
[data-anim] {
|
||
opacity: 0;
|
||
}
|
||
.slide.is-active [data-anim] {
|
||
animation-duration: var(--dur-enter);
|
||
animation-timing-function: var(--ease-enter);
|
||
animation-fill-mode: forwards;
|
||
}
|
||
.slide.is-active [data-anim="fade-up"] {
|
||
animation-name: kFadeUp;
|
||
}
|
||
.slide.is-active [data-anim="fade-in"] {
|
||
animation-name: kFadeIn;
|
||
}
|
||
.slide.is-active [data-anim="reveal-right"] {
|
||
animation-name: kRevealRight;
|
||
}
|
||
.slide.is-active [data-anim="reveal-left"] {
|
||
animation-name: kRevealLeft;
|
||
}
|
||
.slide.is-active [data-anim="scale-in"] {
|
||
animation-name: kScaleIn;
|
||
}
|
||
|
||
/* Staggered delays via data-delay attribute (0–6) */
|
||
[data-delay="0"] {
|
||
animation-delay: 0s;
|
||
}
|
||
[data-delay="1"] {
|
||
animation-delay: 0.08s;
|
||
}
|
||
[data-delay="2"] {
|
||
animation-delay: 0.18s;
|
||
}
|
||
[data-delay="3"] {
|
||
animation-delay: 0.3s;
|
||
}
|
||
[data-delay="4"] {
|
||
animation-delay: 0.44s;
|
||
}
|
||
[data-delay="5"] {
|
||
animation-delay: 0.6s;
|
||
}
|
||
[data-delay="6"] {
|
||
animation-delay: 0.78s;
|
||
}
|
||
|
||
@keyframes kFadeUp {
|
||
from {
|
||
opacity: 0;
|
||
transform: translateY(28px);
|
||
}
|
||
to {
|
||
opacity: 1;
|
||
transform: none;
|
||
}
|
||
}
|
||
@keyframes kFadeIn {
|
||
from {
|
||
opacity: 0;
|
||
}
|
||
to {
|
||
opacity: 1;
|
||
}
|
||
}
|
||
@keyframes kRevealRight {
|
||
from {
|
||
clip-path: inset(0 100% 0 0);
|
||
opacity: 1;
|
||
}
|
||
to {
|
||
clip-path: inset(0 0% 0 0);
|
||
opacity: 1;
|
||
}
|
||
}
|
||
@keyframes kRevealLeft {
|
||
from {
|
||
clip-path: inset(0 0 0 100%);
|
||
opacity: 1;
|
||
}
|
||
to {
|
||
clip-path: inset(0 0 0 0%);
|
||
opacity: 1;
|
||
}
|
||
}
|
||
@keyframes kScaleIn {
|
||
from {
|
||
opacity: 0;
|
||
transform: scale(0.94);
|
||
}
|
||
to {
|
||
opacity: 1;
|
||
transform: none;
|
||
}
|
||
}
|
||
|
||
/* ── Navigation UI ───────────────────────────────────────────────── */
|
||
#nav-dots {
|
||
position: fixed;
|
||
bottom: 24px;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
display: flex;
|
||
gap: 7px;
|
||
z-index: 100;
|
||
}
|
||
.nav-dot {
|
||
width: 5px;
|
||
height: 5px;
|
||
border-radius: 50%;
|
||
border: none;
|
||
background: rgba(255, 255, 255, 0.22);
|
||
cursor: pointer;
|
||
transition:
|
||
background 0.3s,
|
||
transform 0.3s;
|
||
padding: 0;
|
||
}
|
||
.nav-dot.is-active {
|
||
background: rgba(255, 255, 255, 0.8);
|
||
transform: scale(1.4);
|
||
}
|
||
|
||
#slide-counter {
|
||
position: fixed;
|
||
bottom: 20px;
|
||
right: 28px;
|
||
font-family: var(--f-mono);
|
||
font-size: 10px;
|
||
letter-spacing: 0.12em;
|
||
color: rgba(255, 255, 255, 0.25);
|
||
z-index: 100;
|
||
user-select: none;
|
||
}
|
||
|
||
/* ╔══════════════════════════════════════════════════════════════════════╗
|
||
║ ZONE C · TYPOGRAPHY — STUDIO OVERRIDES ║
|
||
║ ║
|
||
║ All headings: weight 900, uppercase, tight tracking. ║
|
||
║ The headline is not decoration — it IS the design. ║
|
||
╚══════════════════════════════════════════════════════════════════════╝ */
|
||
|
||
/* Display: maximum weight, maximum scale, uppercase — type as visual mass */
|
||
.display {
|
||
font-size: var(--sz-display);
|
||
font-weight: 900;
|
||
line-height: 0.9;
|
||
letter-spacing: -0.02em;
|
||
text-transform: uppercase;
|
||
font-family: var(--f-display);
|
||
}
|
||
.h1 {
|
||
font-size: var(--sz-h1);
|
||
font-weight: 900;
|
||
line-height: 0.92;
|
||
letter-spacing: -0.02em;
|
||
text-transform: uppercase;
|
||
font-family: var(--f-heading);
|
||
}
|
||
.h2 {
|
||
font-size: var(--sz-h2);
|
||
font-weight: 900;
|
||
line-height: 0.95;
|
||
letter-spacing: -0.01em;
|
||
text-transform: uppercase;
|
||
font-family: var(--f-heading);
|
||
}
|
||
.h3 {
|
||
font-size: var(--sz-h3);
|
||
font-weight: 700;
|
||
line-height: 1.1;
|
||
text-transform: uppercase;
|
||
font-family: var(--f-heading);
|
||
}
|
||
.lead {
|
||
font-size: var(--sz-lead);
|
||
font-weight: 500;
|
||
line-height: 1.45;
|
||
font-family: var(--f-body);
|
||
}
|
||
.body {
|
||
font-size: var(--sz-body);
|
||
font-weight: 400;
|
||
line-height: 1.6;
|
||
font-family: var(--f-body);
|
||
}
|
||
.caption {
|
||
font-size: var(--sz-caption);
|
||
font-weight: 400;
|
||
line-height: 1.5;
|
||
font-family: var(--f-body);
|
||
}
|
||
/* Label: mono metadata — the only non-bold text that gets prominence */
|
||
.label {
|
||
font-size: var(--sz-label);
|
||
font-weight: 500;
|
||
letter-spacing: 0.06em;
|
||
font-family: var(--f-mono);
|
||
}
|
||
|
||
/* Muted variants — context-aware opacity */
|
||
.muted {
|
||
color: var(--c-fg-2);
|
||
}
|
||
.light .muted {
|
||
color: var(--c-fg-light-2);
|
||
}
|
||
|
||
/* Accent colour class */
|
||
.accent {
|
||
color: var(--c-accent);
|
||
}
|
||
/* On light slides, accent is the dark foreground */
|
||
.light .accent {
|
||
color: var(--c-fg-light);
|
||
}
|
||
|
||
/* Bullet list — Studio signature: dash bullet in accent, tight spacing */
|
||
.bullet-list {
|
||
list-style: none;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: var(--gap-sm);
|
||
font-family: var(--f-body);
|
||
font-size: var(--sz-body);
|
||
font-weight: 400;
|
||
line-height: 1.5;
|
||
padding-left: 1em;
|
||
}
|
||
.bullet-list li::before {
|
||
content: "\2014"; /* em dash used as bullet marker */
|
||
margin-left: -1em;
|
||
margin-right: 0.5em;
|
||
color: var(--c-accent);
|
||
}
|
||
.light .bullet-list li::before {
|
||
color: var(--c-fg-light);
|
||
}
|
||
|
||
/* ── Studio cover footer: three-column metadata bar ──────────────────── */
|
||
/* The signature Boring Studios three-column foot: studio × client, title, name */
|
||
.cover-footer {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr 1fr;
|
||
gap: 0;
|
||
padding-top: var(--gap-md);
|
||
border-top: 1px solid var(--c-fg-3);
|
||
margin-top: auto;
|
||
}
|
||
.cover-footer-col {
|
||
font-family: var(--f-mono);
|
||
font-size: var(--sz-caption);
|
||
font-weight: 400;
|
||
line-height: 1.5;
|
||
}
|
||
.cover-footer-col:last-child {
|
||
text-align: right;
|
||
}
|
||
|
||
/* Image placeholder box — dark warm grey rectangle, mono label centered */
|
||
.img-placeholder {
|
||
background: var(--c-bg-alt);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-family: var(--f-mono);
|
||
font-size: var(--sz-label);
|
||
letter-spacing: 0.1em;
|
||
color: var(--c-fg-3);
|
||
width: 100%;
|
||
flex: 1;
|
||
}
|
||
.light .img-placeholder {
|
||
background: var(--c-bg-light-alt);
|
||
color: var(--c-fg-light-3);
|
||
border: 1px solid var(--c-border-light);
|
||
}
|
||
|
||
/* ╔══════════════════════════════════════════════════════════════════════╗
|
||
║ ZONE D · CHROME ║
|
||
╚══════════════════════════════════════════════════════════════════════╝ */
|
||
|
||
/* Chrome (top bar) and footer */
|
||
.slide-chrome,
|
||
.slide-foot {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
}
|
||
.slide-chrome {
|
||
padding-bottom: var(--gap-sm);
|
||
border-bottom: 1px solid var(--c-border);
|
||
margin-bottom: var(--gap-md);
|
||
}
|
||
.slide-foot {
|
||
padding-top: var(--gap-sm);
|
||
border-top: 1px solid var(--c-border);
|
||
margin-top: var(--gap-md);
|
||
}
|
||
.light .slide-chrome,
|
||
.light .slide-foot {
|
||
border-color: var(--c-border-light);
|
||
}
|
||
|
||
/* Special layouts that don't use chrome/foot */
|
||
.slide--cover .slide-chrome,
|
||
.slide--cover .slide-foot,
|
||
.slide--chapter .slide-chrome,
|
||
.slide--chapter .slide-foot,
|
||
.slide--quote .slide-chrome,
|
||
.slide--quote .slide-foot,
|
||
.slide--statement .slide-chrome,
|
||
.slide--statement .slide-foot,
|
||
.slide--end .slide-chrome,
|
||
.slide--end .slide-foot {
|
||
display: none;
|
||
}
|
||
|
||
/* ╔══════════════════════════════════════════════════════════════════════╗
|
||
║ ZONE E · LAYOUT PATTERNS — STUDIO-SPECIFIC ║
|
||
╚══════════════════════════════════════════════════════════════════════╝ */
|
||
|
||
/* 1. COVER ─────────────────────────────────────────────────────────── */
|
||
/* Full dark slide, image placeholder fills the background, type overlaid */
|
||
.slide--cover {
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: space-between;
|
||
padding: 0;
|
||
position: relative;
|
||
}
|
||
/* Image placeholder sits absolute behind everything */
|
||
.cover-img-area {
|
||
position: absolute;
|
||
inset: 0;
|
||
background: var(
|
||
--c-bg-alt
|
||
); /* warm dark placeholder — replace with real image */
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-family: var(--f-mono);
|
||
font-size: var(--sz-label);
|
||
letter-spacing: 0.1em;
|
||
color: var(--c-fg-3);
|
||
}
|
||
/* Type area: z-index above the image, padded normally */
|
||
.cover-type {
|
||
position: relative;
|
||
z-index: 1;
|
||
padding: var(--pad-y) var(--pad-x) 0;
|
||
flex: 1;
|
||
display: flex;
|
||
align-items: flex-start;
|
||
}
|
||
/* Three-column meta footer over the image */
|
||
.cover-meta {
|
||
position: relative;
|
||
z-index: 1;
|
||
padding: var(--gap-md) var(--pad-x) var(--pad-y);
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr 1fr;
|
||
gap: 0;
|
||
border-top: 1px solid rgba(245, 210, 0, 0.25);
|
||
}
|
||
.cover-meta-col {
|
||
font-family: var(--f-mono);
|
||
font-size: var(--sz-caption);
|
||
font-weight: 400;
|
||
line-height: 1.6;
|
||
color: var(--c-fg-2);
|
||
}
|
||
.cover-meta-col:last-child {
|
||
text-align: right;
|
||
}
|
||
|
||
/* 2. CHAPTER ───────────────────────────────────────────────────────── */
|
||
/* Yellow or dark chapter divider — huge uppercase section number + title */
|
||
.slide--chapter {
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: flex-end;
|
||
padding-bottom: calc(var(--pad-y) * 1.5);
|
||
}
|
||
.chapter-num {
|
||
font-family: var(--f-mono);
|
||
font-size: var(--sz-label);
|
||
letter-spacing: 0.22em;
|
||
text-transform: uppercase;
|
||
color: var(--c-fg-2);
|
||
margin-bottom: var(--gap-lg);
|
||
}
|
||
.light .chapter-num {
|
||
color: var(--c-fg-light-2);
|
||
}
|
||
|
||
/* 3. STATEMENT ─────────────────────────────────────────────────────── */
|
||
/* Full-slide statement — huge uppercase type, zero decoration */
|
||
.slide--statement {
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: flex-end;
|
||
padding-bottom: calc(var(--pad-y) * 1.5);
|
||
}
|
||
.statement-body {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: var(--gap-md);
|
||
}
|
||
|
||
/* 4. SPLIT ─────────────────────────────────────────────────────────── */
|
||
.slide--split .slide-body {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: calc(var(--pad-x) * 0.8);
|
||
align-items: center;
|
||
}
|
||
.split-text {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: var(--gap-md);
|
||
}
|
||
.split-image {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: var(--gap-sm);
|
||
height: 100%;
|
||
}
|
||
|
||
/* 5. STATS ─────────────────────────────────────────────────────────── */
|
||
.slide--stats {
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
}
|
||
.slide--stats .slide-body {
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
gap: var(--gap-lg);
|
||
}
|
||
/* Stats numbers: huge weight-900 display, near-black on yellow */
|
||
.stats-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, 1fr);
|
||
gap: 0;
|
||
}
|
||
.stat-card {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: var(--gap-sm);
|
||
padding: var(--gap-md) var(--gap-md) var(--gap-md) 0;
|
||
border-top: 2px solid var(--c-fg-light);
|
||
}
|
||
.dark .stat-card {
|
||
border-top-color: var(--c-fg-3);
|
||
}
|
||
/* Value: weight-900 display type — the number IS the stat */
|
||
.stat-value {
|
||
font-family: var(--f-display);
|
||
font-size: 5.5vw;
|
||
font-weight: 900;
|
||
line-height: 0.9;
|
||
color: var(--c-fg-light);
|
||
letter-spacing: -0.03em;
|
||
text-transform: uppercase;
|
||
}
|
||
.dark .stat-value {
|
||
color: var(--c-fg);
|
||
}
|
||
.stat-label {
|
||
font-family: var(--f-body);
|
||
font-size: var(--sz-body);
|
||
font-weight: 500;
|
||
line-height: 1.4;
|
||
}
|
||
.stat-note {
|
||
font-family: var(--f-mono);
|
||
font-size: var(--sz-caption);
|
||
letter-spacing: 0.05em;
|
||
color: var(--c-fg-light-3);
|
||
}
|
||
.dark .stat-note {
|
||
color: var(--c-fg-3);
|
||
}
|
||
|
||
/* 6. LIST ─────────────────────────────────────────────────────────── */
|
||
.slide--list {
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
}
|
||
.slide--list .slide-body {
|
||
display: grid;
|
||
grid-template-columns: 2fr 3fr;
|
||
gap: calc(var(--pad-x) * 0.8);
|
||
align-items: center;
|
||
}
|
||
.list-head {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: var(--gap-md);
|
||
}
|
||
|
||
/* 7. QUOTE ─────────────────────────────────────────────────────────── */
|
||
/* Dark slide — large quote with no quote mark, just raw type */
|
||
.slide--quote {
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
}
|
||
.quote-text {
|
||
font-family: var(--f-heading);
|
||
font-size: 3.8vw;
|
||
font-weight: 900;
|
||
line-height: 1.05;
|
||
letter-spacing: -0.02em;
|
||
text-transform: uppercase;
|
||
max-width: 82%;
|
||
margin-bottom: var(--gap-lg);
|
||
}
|
||
.quote-attr {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 0.4vh;
|
||
}
|
||
|
||
/* 8. COMPARE ─────────────────────────────────────────────────────────── */
|
||
.slide--compare .slide-body {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
height: 100%;
|
||
}
|
||
.compare-panel {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: var(--gap-md);
|
||
padding: var(--gap-md) 0;
|
||
}
|
||
.compare-panel.left {
|
||
padding-right: calc(var(--pad-x) * 0.55);
|
||
border-right: 2px solid var(--c-fg-light);
|
||
}
|
||
.compare-panel.right {
|
||
padding-left: calc(var(--pad-x) * 0.55);
|
||
}
|
||
.dark .compare-panel.left {
|
||
border-right-color: var(--c-fg-3);
|
||
}
|
||
.compare-label {
|
||
font-family: var(--f-mono);
|
||
font-size: var(--sz-label);
|
||
letter-spacing: 0.16em;
|
||
text-transform: uppercase;
|
||
padding-bottom: var(--gap-sm);
|
||
border-bottom: 1px solid var(--c-border-light);
|
||
}
|
||
.dark .compare-label {
|
||
border-bottom-color: var(--c-border);
|
||
}
|
||
.compare-label.after {
|
||
color: var(--c-accent);
|
||
}
|
||
.light .compare-label.after {
|
||
color: var(--c-fg-light);
|
||
font-weight: 700;
|
||
}
|
||
|
||
/* 9. CHART ─────────────────────────────────────────────────────────── */
|
||
.slide--chart .slide-body {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: var(--gap-md);
|
||
min-height: 0;
|
||
}
|
||
.chart-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: baseline;
|
||
flex-shrink: 0;
|
||
}
|
||
.chart-wrapper {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: flex-end;
|
||
min-height: 0;
|
||
}
|
||
/* Bar chart track: bars sit in a horizontal row along a baseline */
|
||
.bar-track {
|
||
height: 30vh;
|
||
display: flex;
|
||
align-items: flex-end;
|
||
gap: 4vw;
|
||
border-left: 2px solid var(--c-fg-3);
|
||
padding-left: 0.5vw;
|
||
}
|
||
.light .bar-track {
|
||
border-left-color: var(--c-border-light);
|
||
}
|
||
.bar-col {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: flex-start;
|
||
justify-content: flex-end;
|
||
gap: 1vh;
|
||
height: 100%;
|
||
}
|
||
/* Bar fill: default is dark muted, accent is full yellow */
|
||
.bar-fill {
|
||
width: 100%;
|
||
background: var(--c-fg-3);
|
||
}
|
||
.bar-fill.accent {
|
||
background: var(--c-accent);
|
||
}
|
||
.light .bar-fill {
|
||
background: var(--c-fg-light-3);
|
||
}
|
||
.light .bar-fill.accent {
|
||
background: var(--c-fg-light);
|
||
}
|
||
.bar-x-label {
|
||
font-family: var(--f-mono);
|
||
font-size: var(--sz-caption);
|
||
letter-spacing: 0.1em;
|
||
color: var(--c-fg-3);
|
||
white-space: nowrap;
|
||
text-transform: uppercase;
|
||
}
|
||
.light .bar-x-label {
|
||
color: var(--c-fg-light-3);
|
||
}
|
||
.bar-val {
|
||
font-family: var(--f-body);
|
||
font-size: var(--sz-body);
|
||
font-weight: 700;
|
||
color: var(--c-fg-2);
|
||
}
|
||
.bar-val.hi {
|
||
color: var(--c-accent);
|
||
font-weight: 900;
|
||
}
|
||
.light .bar-val {
|
||
color: var(--c-fg-light-2);
|
||
}
|
||
.light .bar-val.hi {
|
||
color: var(--c-fg-light);
|
||
}
|
||
.chart-baseline {
|
||
height: 2px;
|
||
background: var(--c-fg-3);
|
||
flex-shrink: 0;
|
||
margin-top: 1px;
|
||
}
|
||
.light .chart-baseline {
|
||
background: var(--c-border-light);
|
||
}
|
||
.chart-source {
|
||
flex-shrink: 0;
|
||
font-family: var(--f-mono);
|
||
font-size: var(--sz-caption);
|
||
color: var(--c-fg-3);
|
||
letter-spacing: 0.06em;
|
||
margin-top: var(--gap-sm);
|
||
}
|
||
.light .chart-source {
|
||
color: var(--c-fg-light-3);
|
||
}
|
||
|
||
/* 10. END ─────────────────────────────────────────────────────────── */
|
||
/* Yellow slide — huge question fills top 60%, two-column contact below */
|
||
.slide--end {
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: space-between;
|
||
}
|
||
</style>
|
||
</head>
|
||
|
||
<body>
|
||
<!-- NAV DOTS: generated by JS -->
|
||
<nav id="nav-dots"></nav>
|
||
<!-- SLIDE COUNTER: generated by JS -->
|
||
<div id="slide-counter"></div>
|
||
|
||
<!-- ═══════════════════════════════════════════════════════════════════════
|
||
DECK — all 12 slides live here, side by side
|
||
═══════════════════════════════════════════════════════════════════════ -->
|
||
<div id="deck">
|
||
<!-- ═══════ SLIDE 1 · COVER dark ══════════════════════════════════════
|
||
Image placeholder fills the background.
|
||
"PROPOSAL" in huge yellow display type across the top.
|
||
Three-column meta footer at bottom edge.
|
||
═══════════════════════════════════════════════════════════════════ -->
|
||
<section class="slide dark slide--cover">
|
||
<!-- Full-bleed image placeholder: sits behind all content -->
|
||
<div class="cover-img-area" data-anim="fade-in" data-delay="0">
|
||
IMAGE PLACEHOLDER
|
||
</div>
|
||
|
||
<!-- Type block: "PROPOSAL" at display scale — type over image -->
|
||
<div class="cover-type">
|
||
<h1
|
||
class="display"
|
||
style="color: var(--c-fg)"
|
||
data-anim="fade-up"
|
||
data-delay="1"
|
||
>
|
||
PROPOSAL
|
||
</h1>
|
||
</div>
|
||
|
||
<!-- Three-column footer: studio × client · presentation title · studio name -->
|
||
<div class="cover-meta" data-anim="fade-in" data-delay="3">
|
||
<div class="cover-meta-col">
|
||
[Studio Name] × [Client Name]<br />
|
||
[Date]
|
||
</div>
|
||
<div class="cover-meta-col" style="text-align: center">
|
||
[Presentation Title]
|
||
</div>
|
||
<div class="cover-meta-col" style="text-align: right">
|
||
[Studio Name]
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ═══════ SLIDE 2 · CHAPTER light (yellow bg) ═══════════════════════
|
||
Section divider: mono section number + huge black title.
|
||
Yellow background — no decoration, type IS the design.
|
||
═══════════════════════════════════════════════════════════════════ -->
|
||
<section class="slide light slide--chapter">
|
||
<!-- Section number: mono label in muted near-black -->
|
||
<div class="chapter-num" data-anim="fade-in" data-delay="0">
|
||
01 / WHO WE ARE
|
||
</div>
|
||
|
||
<!-- Chapter title: maximum weight, runs wide -->
|
||
<h1
|
||
class="h1"
|
||
style="max-width: 90%; color: var(--c-fg-light)"
|
||
data-anim="fade-up"
|
||
data-delay="1"
|
||
>
|
||
WHO WE ARE
|
||
</h1>
|
||
</section>
|
||
|
||
<!-- ═══════ SLIDE 3 · STATEMENT dark ══════════════════════════════════
|
||
Single huge statement on near-black.
|
||
Yellow type, no decoration, no chrome.
|
||
═══════════════════════════════════════════════════════════════════ -->
|
||
<section class="slide dark slide--statement">
|
||
<div
|
||
class="statement-body"
|
||
style="
|
||
justify-content: flex-end;
|
||
height: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
padding-bottom: calc(var(--pad-y) * 0.5);
|
||
"
|
||
>
|
||
<h1
|
||
class="h1"
|
||
style="max-width: 90%"
|
||
data-anim="fade-up"
|
||
data-delay="0"
|
||
>
|
||
GREAT WORK DOESN'T HAPPEN BY ACCIDENT
|
||
</h1>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ═══════ SLIDE 4 · SPLIT light (yellow bg) ════════════════════════
|
||
Text left + image placeholder right.
|
||
Black on yellow — tight, structured, zero ornament.
|
||
═══════════════════════════════════════════════════════════════════ -->
|
||
<section class="slide light slide--split">
|
||
<!-- Chrome bar -->
|
||
<div class="slide-chrome">
|
||
<span
|
||
class="label"
|
||
style="color: var(--c-fg-light-2)"
|
||
data-anim="fade-in"
|
||
data-delay="0"
|
||
>Our Work</span
|
||
>
|
||
<span
|
||
class="label"
|
||
style="color: var(--c-fg-light-2)"
|
||
data-anim="fade-in"
|
||
data-delay="0"
|
||
>04 / 12</span
|
||
>
|
||
</div>
|
||
|
||
<div class="slide-body">
|
||
<!-- Left: text content -->
|
||
<div class="split-text" data-anim="fade-up" data-delay="1">
|
||
<p
|
||
class="label"
|
||
style="color: var(--c-fg-light-2); letter-spacing: 0.12em"
|
||
>
|
||
APPROACH
|
||
</p>
|
||
<h2 class="h2" style="color: var(--c-fg-light)">
|
||
WE BUILD WHAT OTHERS PLAN
|
||
</h2>
|
||
<p
|
||
class="lead"
|
||
style="
|
||
color: var(--c-fg-light-2);
|
||
font-weight: 400;
|
||
text-transform: none;
|
||
"
|
||
>
|
||
Our studio pairs strategic thinking with craft-level execution.
|
||
Every project begins with a question: what needs to be true for
|
||
this to work? We answer it in the work itself.
|
||
</p>
|
||
<ul class="bullet-list">
|
||
<li>Strategy before aesthetics</li>
|
||
<li>Constraints as creative fuel</li>
|
||
<li>Delivery on schedule, not on someday</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<!-- Right: image placeholder -->
|
||
<div
|
||
data-anim="fade-in"
|
||
data-delay="3"
|
||
style="
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: var(--gap-sm);
|
||
height: 100%;
|
||
"
|
||
>
|
||
<div class="img-placeholder" style="min-height: 40vh">
|
||
IMAGE PLACEHOLDER
|
||
</div>
|
||
<p
|
||
class="caption"
|
||
style="color: var(--c-fg-light-3); font-family: var(--f-mono)"
|
||
>
|
||
[Caption — project name, year]
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="slide-foot">
|
||
<span class="label" style="color: var(--c-fg-light-3)"
|
||
>[Studio Name] · [Date]</span
|
||
>
|
||
<span class="label" style="color: var(--c-fg-light-2)">04 / 12</span>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ═══════ SLIDE 5 · STATS light (yellow bg) ════════════════════════
|
||
3 huge stats with weight-900 display numbers.
|
||
Numbers at near-display scale — the numbers are the layout.
|
||
═══════════════════════════════════════════════════════════════════ -->
|
||
<section class="slide light slide--stats">
|
||
<!-- Chrome bar -->
|
||
<div class="slide-chrome">
|
||
<span
|
||
class="label"
|
||
style="color: var(--c-fg-light-2)"
|
||
data-anim="fade-in"
|
||
data-delay="0"
|
||
>By the Numbers</span
|
||
>
|
||
<span
|
||
class="label"
|
||
style="color: var(--c-fg-light-2)"
|
||
data-anim="fade-in"
|
||
data-delay="0"
|
||
>05 / 12</span
|
||
>
|
||
</div>
|
||
|
||
<div class="slide-body">
|
||
<!-- Section label above stats -->
|
||
<h2
|
||
class="h2"
|
||
style="color: var(--c-fg-light)"
|
||
data-anim="fade-up"
|
||
data-delay="1"
|
||
>
|
||
THE STUDIO
|
||
</h2>
|
||
|
||
<!-- 3-column stat grid: numbers at display scale -->
|
||
<div class="stats-grid" data-anim="fade-up" data-delay="2">
|
||
<div class="stat-card">
|
||
<div class="stat-value">12</div>
|
||
<div class="stat-label" style="color: var(--c-fg-light)">
|
||
Years of practice
|
||
</div>
|
||
<div class="stat-note">[Studio Name] founded [Year]</div>
|
||
</div>
|
||
<div class="stat-card">
|
||
<div class="stat-value">200+</div>
|
||
<div class="stat-label" style="color: var(--c-fg-light)">
|
||
Projects delivered
|
||
</div>
|
||
<div class="stat-note">Across [N] industries</div>
|
||
</div>
|
||
<div class="stat-card">
|
||
<div class="stat-value">3</div>
|
||
<div class="stat-label" style="color: var(--c-fg-light)">
|
||
Continents active
|
||
</div>
|
||
<div class="stat-note">[City A], [City B], [City C]</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="slide-foot">
|
||
<span class="label" style="color: var(--c-fg-light-3)"
|
||
>[Studio Name] · [Date]</span
|
||
>
|
||
<span class="label" style="color: var(--c-fg-light-2)">05 / 12</span>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ═══════ SLIDE 6 · LIST dark ═══════════════════════════════════════
|
||
"WHAT WE OFFER" heading left, 5 yellow bullets right.
|
||
Dark background, yellow type throughout.
|
||
═══════════════════════════════════════════════════════════════════ -->
|
||
<section class="slide dark slide--list">
|
||
<!-- Chrome bar -->
|
||
<div class="slide-chrome">
|
||
<span class="label muted" data-anim="fade-in" data-delay="0"
|
||
>Services</span
|
||
>
|
||
<span class="label muted" data-anim="fade-in" data-delay="0"
|
||
>06 / 12</span
|
||
>
|
||
</div>
|
||
|
||
<div class="slide-body">
|
||
<!-- Left: heading -->
|
||
<div class="list-head" data-anim="fade-up" data-delay="1">
|
||
<h2 class="h2" style="color: var(--c-fg)">WHAT WE OFFER</h2>
|
||
<p
|
||
class="lead muted"
|
||
style="text-transform: none; font-weight: 400; max-width: 90%"
|
||
>
|
||
A focused set of services built for ambitious creative and
|
||
commercial challenges.
|
||
</p>
|
||
</div>
|
||
|
||
<!-- Right: bullet list -->
|
||
<ul
|
||
class="bullet-list"
|
||
style="font-size: var(--sz-lead); font-weight: 500"
|
||
data-anim="fade-up"
|
||
data-delay="2"
|
||
>
|
||
<li>Brand strategy and identity systems</li>
|
||
<li>Campaign and content direction</li>
|
||
<li>Digital experience design and build</li>
|
||
<li>Motion and video production</li>
|
||
<li>Ongoing creative partnership and retainer</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="slide-foot">
|
||
<span class="label muted">[Studio Name] · [Date]</span>
|
||
<span class="label muted">06 / 12</span>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ═══════ SLIDE 7 · QUOTE dark ══════════════════════════════════════
|
||
Large client quote, no quote mark, just raw uppercase weight-900 type.
|
||
Attribution below in mono label.
|
||
═══════════════════════════════════════════════════════════════════ -->
|
||
<section class="slide dark slide--quote">
|
||
<!-- Quote body: uppercase grotesque, no quote marks needed -->
|
||
<p
|
||
class="quote-text"
|
||
style="color: var(--c-fg)"
|
||
data-anim="fade-up"
|
||
data-delay="0"
|
||
>
|
||
THEY DON'T JUST MAKE THINGS LOOK GOOD. THEY MAKE THINGS WORK.
|
||
</p>
|
||
|
||
<!-- Attribution: mono label -->
|
||
<div class="quote-attr" data-anim="fade-in" data-delay="2">
|
||
<span class="label" style="color: var(--c-fg); letter-spacing: 0.1em"
|
||
>[CLIENT NAME]</span
|
||
>
|
||
<span class="label muted">CMO · [Company] · [Year]</span>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ═══════ SLIDE 8 · COMPARE light (yellow bg) ══════════════════════
|
||
Before/after on yellow background.
|
||
Two panels divided by a heavy vertical rule.
|
||
═══════════════════════════════════════════════════════════════════ -->
|
||
<section class="slide light slide--compare">
|
||
<!-- Chrome bar -->
|
||
<div class="slide-chrome">
|
||
<span
|
||
class="label"
|
||
style="color: var(--c-fg-light-2)"
|
||
data-anim="fade-in"
|
||
data-delay="0"
|
||
>Before / After</span
|
||
>
|
||
<span
|
||
class="label"
|
||
style="color: var(--c-fg-light-2)"
|
||
data-anim="fade-in"
|
||
data-delay="0"
|
||
>08 / 12</span
|
||
>
|
||
</div>
|
||
|
||
<div class="slide-body">
|
||
<!-- Left panel: Before -->
|
||
<div class="compare-panel left" data-anim="fade-up" data-delay="1">
|
||
<div class="compare-label" style="color: var(--c-fg-light-2)">
|
||
BEFORE
|
||
</div>
|
||
<h3 class="h3" style="color: var(--c-fg-light)">
|
||
GENERIC IDENTITY, FORGETTABLE CAMPAIGNS
|
||
</h3>
|
||
<p
|
||
class="lead"
|
||
style="
|
||
color: var(--c-fg-light-2);
|
||
text-transform: none;
|
||
font-weight: 400;
|
||
"
|
||
>
|
||
A brand built by committee, refined to inoffensiveness. Nothing
|
||
wrong. Nothing memorable. Indistinguishable from category norms.
|
||
</p>
|
||
<ul class="bullet-list">
|
||
<li>No clear point of view</li>
|
||
<li>Inconsistent execution across touchpoints</li>
|
||
<li>Campaigns that launched and disappeared</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<!-- Right panel: After -->
|
||
<div class="compare-panel right" data-anim="fade-up" data-delay="2">
|
||
<div class="compare-label after" style="font-weight: 700">
|
||
AFTER
|
||
</div>
|
||
<h3 class="h3" style="color: var(--c-fg-light)">
|
||
A DISTINCTIVE VOICE PEOPLE RECOGNIZE
|
||
</h3>
|
||
<p
|
||
class="lead"
|
||
style="
|
||
color: var(--c-fg-light-2);
|
||
text-transform: none;
|
||
font-weight: 400;
|
||
"
|
||
>
|
||
A brand with a defined perspective. Work that accumulates — each
|
||
campaign reinforces the one before, building memory and trust.
|
||
</p>
|
||
<ul class="bullet-list">
|
||
<li>Ownable visual and verbal territory</li>
|
||
<li>System that scales without diluting</li>
|
||
<li>Campaigns that created lasting recall</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="slide-foot">
|
||
<span class="label" style="color: var(--c-fg-light-3)"
|
||
>[Studio Name] · [Date]</span
|
||
>
|
||
<span class="label" style="color: var(--c-fg-light-2)">08 / 12</span>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ═══════ SLIDE 9 · CHAPTER dark ════════════════════════════════════
|
||
Dark chapter divider — "THE WORK" in huge yellow type.
|
||
═══════════════════════════════════════════════════════════════════ -->
|
||
<section class="slide dark slide--chapter">
|
||
<!-- Section number -->
|
||
<div class="chapter-num" data-anim="fade-in" data-delay="0">
|
||
02 / THE WORK
|
||
</div>
|
||
|
||
<!-- Chapter title: yellow on dark at h1 scale -->
|
||
<h1
|
||
class="h1"
|
||
style="max-width: 90%; color: var(--c-fg)"
|
||
data-anim="fade-up"
|
||
data-delay="1"
|
||
>
|
||
THE WORK
|
||
</h1>
|
||
</section>
|
||
|
||
<!-- ═══════ SLIDE 10 · STATEMENT light (yellow bg) ════════════════════
|
||
Huge statement on yellow — black type filling most of the slide.
|
||
═══════════════════════════════════════════════════════════════════ -->
|
||
<section class="slide light slide--statement">
|
||
<div
|
||
class="statement-body"
|
||
style="
|
||
justify-content: flex-end;
|
||
height: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
padding-bottom: calc(var(--pad-y) * 0.5);
|
||
"
|
||
>
|
||
<h1
|
||
class="h1"
|
||
style="max-width: 95%; color: var(--c-fg-light)"
|
||
data-anim="fade-up"
|
||
data-delay="0"
|
||
>
|
||
BOLD IDEAS DESERVE BOLD EXECUTION
|
||
</h1>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ═══════ SLIDE 11 · CHART dark ════════════════════════════════════
|
||
Bar chart with yellow accent on the highlight bar.
|
||
Near-black background, yellow accent bar, muted bars for others.
|
||
═══════════════════════════════════════════════════════════════════ -->
|
||
<section class="slide dark slide--chart">
|
||
<!-- Chrome bar -->
|
||
<div class="slide-chrome">
|
||
<span class="label muted" data-anim="fade-in" data-delay="0"
|
||
>Project Output</span
|
||
>
|
||
<span class="label muted" data-anim="fade-in" data-delay="0"
|
||
>11 / 12</span
|
||
>
|
||
</div>
|
||
|
||
<div class="slide-body">
|
||
<div class="chart-header">
|
||
<h2
|
||
class="h2"
|
||
style="color: var(--c-fg)"
|
||
data-anim="fade-up"
|
||
data-delay="0"
|
||
>
|
||
PROJECTS BY YEAR
|
||
</h2>
|
||
<span
|
||
class="caption muted"
|
||
style="
|
||
font-family: var(--f-mono);
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.08em;
|
||
"
|
||
data-anim="fade-in"
|
||
data-delay="1"
|
||
>
|
||
Count · [Studio Name] Portfolio
|
||
</span>
|
||
</div>
|
||
|
||
<div class="chart-wrapper" data-anim="fade-up" data-delay="2">
|
||
<div class="bar-track">
|
||
<div class="bar-col">
|
||
<span class="bar-val">14</span>
|
||
<div class="bar-fill" style="height: 8vh"></div>
|
||
<span class="bar-x-label">[Y-4]</span>
|
||
</div>
|
||
<div class="bar-col">
|
||
<span class="bar-val">21</span>
|
||
<div class="bar-fill" style="height: 12vh"></div>
|
||
<span class="bar-x-label">[Y-3]</span>
|
||
</div>
|
||
<div class="bar-col">
|
||
<span class="bar-val">28</span>
|
||
<div class="bar-fill" style="height: 17vh"></div>
|
||
<span class="bar-x-label">[Y-2]</span>
|
||
</div>
|
||
<div class="bar-col">
|
||
<span class="bar-val">35</span>
|
||
<div class="bar-fill" style="height: 22vh"></div>
|
||
<span class="bar-x-label">[Y-1]</span>
|
||
</div>
|
||
<div class="bar-col">
|
||
<!-- Accent bar: the highlighted year -->
|
||
<span class="bar-val hi">47</span>
|
||
<div class="bar-fill accent" style="height: 30vh"></div>
|
||
<span class="bar-x-label">[Year]</span>
|
||
</div>
|
||
</div>
|
||
<div class="chart-baseline"></div>
|
||
</div>
|
||
|
||
<p class="chart-source" data-anim="fade-in" data-delay="3">
|
||
Source: [Studio Name] internal tracking · [Year]
|
||
</p>
|
||
</div>
|
||
|
||
<div class="slide-foot">
|
||
<span class="label muted">[Studio Name] · [Date]</span>
|
||
<span class="label muted">11 / 12</span>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ═══════ SLIDE 12 · END light (yellow bg) ══════════════════════════
|
||
Huge closing question fills top portion, two-column contact info below.
|
||
Studio signature ending layout from the Boring Studios reference.
|
||
═══════════════════════════════════════════════════════════════════ -->
|
||
<section class="slide light slide--end">
|
||
<!-- Main closing statement: display scale, fills the top of the slide -->
|
||
<h1
|
||
class="h1"
|
||
style="
|
||
max-width: 85%;
|
||
line-height: 0.9;
|
||
font-size: var(--sz-display);
|
||
color: var(--c-fg-light);
|
||
"
|
||
data-anim="fade-up"
|
||
data-delay="0"
|
||
>
|
||
ANY QUESTIONS OR THOUGHTS?
|
||
</h1>
|
||
|
||
<!-- Two-column contact info below the statement -->
|
||
<div
|
||
style="
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: var(--gap-lg);
|
||
margin-top: var(--gap-lg);
|
||
"
|
||
data-anim="fade-up"
|
||
data-delay="2"
|
||
>
|
||
<div>
|
||
<p class="body" style="color: var(--c-fg-light-2)">
|
||
Contact [Name A] via email on [name@studio.com]<br />
|
||
or via phone on [+00 000 000 000]
|
||
</p>
|
||
</div>
|
||
<div>
|
||
<p class="body" style="color: var(--c-fg-light-2)">
|
||
Contact [Name B] via email on [name@studio.com]<br />
|
||
or via phone on [+00 000 000 000]
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Three-column footer: the Studio signature cover footer pattern -->
|
||
<div
|
||
class="cover-footer"
|
||
style="border-top-color: var(--c-border-light)"
|
||
data-anim="fade-in"
|
||
data-delay="4"
|
||
>
|
||
<span class="cover-footer-col" style="color: var(--c-fg-light-2)">
|
||
Page 12<br />[Studio Name] × [Client Name]
|
||
</span>
|
||
<span
|
||
class="cover-footer-col"
|
||
style="text-align: center; color: var(--c-fg-light-2)"
|
||
>
|
||
[Presentation title]
|
||
</span>
|
||
<span class="cover-footer-col" style="color: var(--c-fg-light-2)">
|
||
[Studio Name]
|
||
</span>
|
||
</div>
|
||
</section>
|
||
</div>
|
||
<!-- /deck -->
|
||
|
||
<script>
|
||
/* ══════════════════════════════════════════════════════════════════════
|
||
STUDIO PRESENTATION ENGINE
|
||
Self-contained navigation: keyboard, touch, mouse-wheel, nav-dots.
|
||
No external dependencies.
|
||
══════════════════════════════════════════════════════════════════════ */
|
||
(function () {
|
||
"use strict";
|
||
|
||
/* ── State ─────────────────────────────────────────────────────────── */
|
||
const deck = document.getElementById("deck");
|
||
const slides = Array.from(document.querySelectorAll(".slide"));
|
||
const dotsEl = document.getElementById("nav-dots");
|
||
const counter = document.getElementById("slide-counter");
|
||
const total = slides.length;
|
||
let current = 0;
|
||
let animating = false;
|
||
|
||
/* ── Bootstrap: set deck width, build nav dots ─────────────────────── */
|
||
function init() {
|
||
// The deck is one wide strip — width equals N full viewports
|
||
deck.style.width = total + "00vw";
|
||
|
||
// Build one dot per slide
|
||
slides.forEach(function (_, i) {
|
||
const btn = document.createElement("button");
|
||
btn.className = "nav-dot";
|
||
btn.setAttribute("aria-label", "Go to slide " + (i + 1));
|
||
btn.addEventListener("click", function () {
|
||
goTo(i);
|
||
});
|
||
dotsEl.appendChild(btn);
|
||
});
|
||
|
||
// Activate the first slide immediately
|
||
goTo(0, true); // true = skip transition on load
|
||
}
|
||
|
||
/* ── goTo: the single source of truth for navigation ───────────────── */
|
||
function goTo(index, instant) {
|
||
// Clamp to valid range
|
||
index = Math.max(0, Math.min(total - 1, index));
|
||
if (index === current && !instant) return;
|
||
|
||
// Mark animating to block rapid key/swipe spam
|
||
animating = true;
|
||
|
||
// Deactivate current slide: reset animations by toggling is-active
|
||
const prev = slides[current];
|
||
prev.classList.remove("is-active");
|
||
// Force a reflow so removing then re-adding is-active (on same slide)
|
||
// actually re-triggers the keyframe animations
|
||
void prev.offsetWidth; // eslint-disable-line no-void
|
||
|
||
// Translate the deck
|
||
if (instant) {
|
||
// Remove transition temporarily for the initial load snap
|
||
deck.style.transition = "none";
|
||
deck.style.transform = "translateX(-" + index + "00vw)";
|
||
void deck.offsetWidth; // force reflow
|
||
deck.style.transition = "";
|
||
} else {
|
||
deck.style.transform = "translateX(-" + index + "00vw)";
|
||
}
|
||
|
||
// Activate new slide
|
||
current = index;
|
||
const next = slides[current];
|
||
next.classList.add("is-active");
|
||
|
||
// Update nav dots
|
||
Array.from(dotsEl.children).forEach(function (dot, i) {
|
||
dot.classList.toggle("is-active", i === current);
|
||
});
|
||
|
||
// Update counter: "3 / 12"
|
||
counter.textContent = current + 1 + " / " + total;
|
||
|
||
// Unlock after transition completes
|
||
const delay = instant
|
||
? 0
|
||
: parseFloat(getComputedStyle(deck).transitionDuration) * 1000;
|
||
setTimeout(function () {
|
||
animating = false;
|
||
}, delay);
|
||
}
|
||
|
||
/* ── Keyboard navigation ──────────────────────────────────────────── */
|
||
document.addEventListener("keydown", function (e) {
|
||
if (animating) return;
|
||
if (
|
||
e.key === "ArrowRight" ||
|
||
e.key === "ArrowDown" ||
|
||
e.key === " "
|
||
) {
|
||
e.preventDefault();
|
||
goTo(current + 1);
|
||
} else if (e.key === "ArrowLeft" || e.key === "ArrowUp") {
|
||
e.preventDefault();
|
||
goTo(current - 1);
|
||
} else if (e.key === "Home") {
|
||
e.preventDefault();
|
||
goTo(0);
|
||
} else if (e.key === "End") {
|
||
e.preventDefault();
|
||
goTo(total - 1);
|
||
}
|
||
});
|
||
|
||
/* ── Mouse-wheel navigation ───────────────────────────────────────── */
|
||
let wheelCooldown = false;
|
||
document.addEventListener(
|
||
"wheel",
|
||
function (e) {
|
||
e.preventDefault();
|
||
if (animating || wheelCooldown) return;
|
||
wheelCooldown = true;
|
||
setTimeout(function () {
|
||
wheelCooldown = false;
|
||
}, 900);
|
||
if (e.deltaY > 0 || e.deltaX > 0) {
|
||
goTo(current + 1);
|
||
} else {
|
||
goTo(current - 1);
|
||
}
|
||
},
|
||
{ passive: false },
|
||
);
|
||
|
||
/* ── Touch swipe navigation ───────────────────────────────────────── */
|
||
let touchStartX = null;
|
||
let touchStartY = null;
|
||
|
||
document.addEventListener(
|
||
"touchstart",
|
||
function (e) {
|
||
touchStartX = e.touches[0].clientX;
|
||
touchStartY = e.touches[0].clientY;
|
||
},
|
||
{ passive: true },
|
||
);
|
||
|
||
document.addEventListener(
|
||
"touchend",
|
||
function (e) {
|
||
if (touchStartX === null) return;
|
||
const dx = touchStartX - e.changedTouches[0].clientX;
|
||
const dy = touchStartY - e.changedTouches[0].clientY;
|
||
// Only respond if horizontal swipe is dominant
|
||
if (Math.abs(dx) > Math.abs(dy) && Math.abs(dx) > 40) {
|
||
if (animating) return;
|
||
if (dx > 0) {
|
||
goTo(current + 1); // swipe left: next
|
||
} else {
|
||
goTo(current - 1); // swipe right: prev
|
||
}
|
||
}
|
||
touchStartX = null;
|
||
touchStartY = null;
|
||
},
|
||
{ passive: true },
|
||
);
|
||
|
||
/* ── Boot ─────────────────────────────────────────────────────────── */
|
||
init();
|
||
})();
|
||
</script>
|
||
</body>
|
||
</html>
|