142 lines
7.3 KiB
HTML
142 lines
7.3 KiB
HTML
<!doctype html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||
<title>Filebase · Investor deck — Q2 2026</title>
|
||
<style>
|
||
:root {
|
||
--bg: #fafaf9; --fg: #1c1b1a; --muted: #6b6964; --accent: #c96442; --surface: #ffffff;
|
||
}
|
||
* { box-sizing: border-box; }
|
||
html, body { margin: 0; height: 100%; }
|
||
body {
|
||
background: var(--bg);
|
||
color: var(--fg);
|
||
font: 18px/1.5 -apple-system, system-ui, sans-serif;
|
||
display: flex;
|
||
overflow-x: auto;
|
||
overflow-y: hidden;
|
||
scroll-snap-type: x mandatory;
|
||
scroll-behavior: smooth;
|
||
}
|
||
body::-webkit-scrollbar { display: none; }
|
||
.slide {
|
||
flex: 0 0 100vw;
|
||
height: 100vh;
|
||
scroll-snap-align: start;
|
||
padding: 80px 96px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
position: relative;
|
||
}
|
||
.slide.title { background: var(--fg); color: var(--bg); }
|
||
.eyebrow { font-size: 12px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--accent); margin-bottom: 28px; }
|
||
.slide h1 { font-size: clamp(48px, 7vw, 96px); line-height: 1.05; letter-spacing: -0.025em; margin: 0 0 20px; max-width: 16ch; }
|
||
.slide h2 { font-size: clamp(32px, 4vw, 48px); letter-spacing: -0.015em; margin: 0 0 20px; max-width: 20ch; }
|
||
.slide .body { font-size: 22px; color: var(--muted); max-width: 56ch; }
|
||
.slide.title .body { color: rgba(250,250,249,0.7); }
|
||
.slide.big-stat .number { font-size: clamp(120px, 22vw, 280px); line-height: 0.9; letter-spacing: -0.04em; color: var(--accent); margin-bottom: 16px; font-weight: 600; }
|
||
.slide.big-stat .caption { font-size: 24px; color: var(--muted); max-width: 24ch; }
|
||
.quote-mark { font-family: Georgia, serif; font-size: 200px; line-height: 0.7; color: var(--accent); opacity: 0.18; margin-bottom: -40px; }
|
||
.quote-text { font-family: Georgia, serif; font-size: 36px; line-height: 1.3; max-width: 26ch; margin: 0 0 28px; }
|
||
.quote-author { font-size: 14px; color: var(--muted); }
|
||
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 32px; margin-top: 40px; }
|
||
.grid-3 .pt { border-top: 2px solid var(--accent); padding-top: 16px; }
|
||
.grid-3 .pt .h { font-size: 18px; font-weight: 500; margin: 0 0 8px; }
|
||
.grid-3 .pt .p { color: var(--muted); margin: 0; font-size: 16px; }
|
||
.counter { position: fixed; bottom: 24px; right: 32px; font-family: ui-monospace, monospace; font-size: 12px; color: var(--muted); background: var(--surface); padding: 4px 10px; border-radius: 999px; border: 1px solid #e6e4e0; }
|
||
.hint { position: fixed; bottom: 24px; left: 32px; font-size: 11px; color: var(--muted); }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<section class="slide title" data-od-id="slide-1">
|
||
<div class="eyebrow" style="color:#c96442;">Filebase · Series B · Q2 2026</div>
|
||
<h1>The bandwidth bill is the bug.</h1>
|
||
<p class="body">A sync engine that ships only what changed. Backed by 3,184 paying teams.</p>
|
||
</section>
|
||
<section class="slide" data-od-id="slide-2">
|
||
<div class="eyebrow">Problem</div>
|
||
<h2>Every other tool re-uploads the whole file.</h2>
|
||
<p class="body">Edit one frame in a 4 GB Final Cut project; today's tools sync all 4 GB. The video, post-production, and design industries are eating multi-thousand-dollar bandwidth bills they shouldn't be.</p>
|
||
</section>
|
||
<section class="slide big-stat" data-od-id="slide-3">
|
||
<div class="number">38×</div>
|
||
<div class="caption">less data moved over the wire vs. naive sync, on real customer workloads.</div>
|
||
</section>
|
||
<section class="slide" data-od-id="slide-4">
|
||
<div class="eyebrow">Why now</div>
|
||
<h2>Three shifts make this market real.</h2>
|
||
<div class="grid-3">
|
||
<div class="pt"><h3 class="h">Remote post-production</h3><p class="p">Editors don't sit in one room any more. Cloud sync went from convenient to load-bearing.</p></div>
|
||
<div class="pt"><h3 class="h">AI workflows</h3><p class="p">Diffusion checkpoints are 7 GB. Engineers iterate on them daily. Existing tools choke.</p></div>
|
||
<div class="pt"><h3 class="h">Bandwidth pricing</h3><p class="p">Egress costs 4× what it did in 2022. Storage is cheap; movement is expensive.</p></div>
|
||
</div>
|
||
</section>
|
||
<section class="slide" data-od-id="slide-5">
|
||
<div class="quote-mark">"</div>
|
||
<p class="quote-text">Filebase pays for itself in the first month. We were going to hire a dedicated DevOps person to babysit our sync — instead we just switched.</p>
|
||
<p class="quote-author">— Mira Hassan, CTO at Northwind Studios</p>
|
||
</section>
|
||
<section class="slide title" data-od-id="slide-6">
|
||
<div class="eyebrow" style="color:#c96442;">Ask</div>
|
||
<h1>$22M to ship the next sync engine.</h1>
|
||
<p class="body">18-month runway, hire 14, expand to enterprise on-prem.</p>
|
||
</section>
|
||
|
||
<div class="counter" id="counter">1 / 6</div>
|
||
<div class="hint">← / → to navigate</div>
|
||
|
||
<script>
|
||
const slides = document.querySelectorAll('.slide');
|
||
const counter = document.getElementById('counter');
|
||
let active = 0;
|
||
|
||
// Detect the real scroller — when body has `display: flex` + `overflow-x: auto`
|
||
// the scroller can be body OR documentElement depending on the host (in
|
||
// particular, the OD srcdoc iframe). Pick whichever actually overflows.
|
||
function scroller() {
|
||
if (document.body.scrollWidth > document.body.clientWidth + 1) return document.body;
|
||
return document.scrollingElement || document.documentElement;
|
||
}
|
||
|
||
function go(i) {
|
||
const next = Math.max(0, Math.min(slides.length - 1, i));
|
||
active = next;
|
||
counter.textContent = (next + 1) + ' / ' + slides.length;
|
||
scroller().scrollTo({ left: next * window.innerWidth, behavior: 'smooth' });
|
||
}
|
||
function syncFromScroll() {
|
||
const i = Math.round(scroller().scrollLeft / window.innerWidth);
|
||
if (i !== active && i >= 0 && i < slides.length) {
|
||
active = i;
|
||
counter.textContent = (i + 1) + ' / ' + slides.length;
|
||
}
|
||
}
|
||
function onKey(e) {
|
||
if (e.target && (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA')) return;
|
||
if (e.key === 'ArrowRight' || e.key === ' ' || e.key === 'PageDown') { e.preventDefault(); go(active + 1); }
|
||
else if (e.key === 'ArrowLeft' || e.key === 'PageUp') { e.preventDefault(); go(active - 1); }
|
||
else if (e.key === 'Home') { e.preventDefault(); go(0); }
|
||
else if (e.key === 'End') { e.preventDefault(); go(slides.length - 1); }
|
||
}
|
||
// Listen on both window and document in capture phase so the handler
|
||
// fires regardless of which element holds focus inside the iframe.
|
||
window.addEventListener('keydown', onKey, true);
|
||
document.addEventListener('keydown', onKey, true);
|
||
// And listen for scroll on both surfaces — same reason.
|
||
document.addEventListener('scroll', syncFromScroll, { passive: true, capture: true });
|
||
window.addEventListener('scroll', syncFromScroll, { passive: true });
|
||
|
||
// Auto-focus body so arrow keys work without a click.
|
||
document.body.setAttribute('tabindex', '-1');
|
||
document.body.style.outline = 'none';
|
||
function focusDeck() { try { window.focus(); document.body.focus({ preventScroll: true }); } catch (_) {} }
|
||
document.addEventListener('mousedown', focusDeck);
|
||
window.addEventListener('load', focusDeck);
|
||
focusDeck();
|
||
</script>
|
||
</body>
|
||
</html>
|