mirror of
https://github.com/nexu-io/open-design.git
synced 2026-06-01 03:14:35 +07:00
- Introduced comprehensive design documentation and JSON configurations for multiple design systems, including Agentic, Airtable, Ant, Apple, Application, Arc, and Artistic. - Each design system includes detailed guidelines on visual themes, color palettes, typography, spacing, layout, components, and interaction principles. - Enhanced the overall design framework to support diverse user interfaces and improve consistency across applications. This update significantly enriches the design resources available for developers, enabling them to create visually cohesive and user-friendly applications.
1606 lines
59 KiB
HTML
1606 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>
|