2026-05-12 15:18:16 +08:00
<!doctype html>
< html lang = "en" >
< head >
< meta charset = "utf-8" />
< meta name = "viewport" content = "width=device-width, initial-scale=1" />
2026-07-10 17:41:47 +08:00
< title > Write an Operating Review like a Disciplined COO - Corporate strategy</ title >
2026-05-12 15:18:16 +08:00
< style >
2026-06-16 16:41:04 +08:00
@ import url ( 'https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,400;0,9..144,500;0,9..144,600;1,9..144,400&family=Geist+Mono:wght@400;500&display=swap' ) ;
/* warm editorial: Fraunces display serif, paper ground, burnt-orange accent */
2026-05-12 15:18:16 +08:00
: root {
2026-06-16 16:41:04 +08:00
--bg : #faf7f2 ;
--fg : #211d18 ;
--muted : #5d564c ;
--faint : #6f6859 ;
--accent : #b3431b ;
--accent-bright : #e8703d ;
--line : rgba ( 33 , 29 , 24 , 0.14 );
--line-strong : rgba ( 33 , 29 , 24 , 0.32 );
--surface : #fffdfa ;
--serif : 'Fraunces' , Georgia , 'Times New Roman' , serif ;
--sans : - apple-system , BlinkMacSystemFont , 'Segoe UI' , system-ui , sans-serif ;
--mono : 'Geist Mono' , ui-monospace , SFMono-Regular , Menlo , monospace ;
--ease : cubic-bezier ( .16 , 1 , .3 , 1 );
2026-05-12 15:18:16 +08:00
}
* { box-sizing : border-box ; }
html , body { margin : 0 ; height : 100 % ; }
body {
background : var ( -- bg );
color : var ( -- fg );
2026-06-16 16:41:04 +08:00
font : 18 px / 1.55 var ( -- sans );
-webkit- font-smoothing : antialiased ;
2026-05-12 15:18:16 +08:00
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 100 vw ;
height : 100 vh ;
scroll-snap-align : start ;
2026-06-16 16:41:04 +08:00
padding : 88 px 104 px ;
2026-05-12 15:18:16 +08:00
display : flex ;
flex-direction : column ;
justify-content : center ;
position : relative ;
}
2026-06-16 16:41:04 +08:00
. slide + . slide { border-left : 1 px solid var ( -- line ); }
/* entrance: transform + opacity only, staggered, ease-out */
@ keyframes rise { from { opacity : 0 ; transform : translateY ( 22 px ); } to { opacity : 1 ; transform : none ; } }
. slide > * { animation : rise .7 s var ( -- ease ) both ; }
. slide > * : nth-child ( 2 ) { animation-delay : .07 s ; }
. slide > * : nth-child ( 3 ) { animation-delay : .14 s ; }
@ media ( prefers-reduced-motion : reduce ) { . slide > * { animation : none ; } }
. eyebrow {
font-family : var ( -- mono );
font-size : 11.5 px ;
font-weight : 500 ;
letter-spacing : 0.16 em ;
text-transform : uppercase ;
color : var ( -- accent );
margin-bottom : 30 px ;
}
. slide h1 {
font-family : var ( -- serif );
font-weight : 500 ;
font-size : clamp ( 56 px , 8.5 vw , 124 px );
line-height : 1.0 ;
letter-spacing : -0.015 em ;
margin : 0 0 26 px ;
max-width : 16 ch ;
text-wrap : balance ;
}
. slide h2 {
font-family : var ( -- serif );
font-weight : 500 ;
font-size : clamp ( 36 px , 4.4 vw , 58 px );
line-height : 1.08 ;
letter-spacing : -0.01 em ;
margin : 0 0 24 px ;
max-width : 22 ch ;
text-wrap : balance ;
}
. slide . body { font-size : 20 px ; line-height : 1.6 ; color : var ( -- muted ); max-width : 56 ch ; }
/* cover stays on paper; a thick accent rule is its signature */
. slide . cover :: before {
content : '' ;
position : absolute ;
top : 88 px ;
left : 104 px ;
width : 72 px ;
height : 6 px ;
background : var ( -- accent );
}
. slide . cover h1 { font-size : clamp ( 64 px , 10 vw , 148 px ); }
/* single deliberate inversion: the closing CTA slide */
2026-05-12 15:18:16 +08:00
. slide . title { background : var ( -- fg ); color : var ( -- bg ); }
2026-06-16 16:41:04 +08:00
. slide . title . eyebrow { color : var ( -- accent - bright ); }
. slide . title . body { color : rgba ( 250 , 247 , 242 , 0.72 ); }
/* the closing line is a full sentence, not a wordmark: step the scale down so it can't clip at 720p */
. slide . title h1 { font-size : clamp ( 46 px , 6.8 vw , 100 px ); max-width : 18 ch ; }
. slide . big-stat . number {
font-family : var ( -- serif );
font-weight : 500 ;
font-size : clamp ( 140 px , 24 vw , 300 px );
line-height : 0.85 ;
letter-spacing : -0.02 em ;
color : var ( -- accent );
margin-bottom : 28 px ;
}
. slide . big-stat . caption {
font-size : 22 px ;
color : var ( -- muted );
max-width : 26 ch ;
border-top : 1 px solid var ( -- line - strong );
padding-top : 18 px ;
}
. quote-mark {
font-family : var ( -- serif );
font-weight : 500 ;
font-size : 96 px ;
line-height : 0.6 ;
color : var ( -- accent );
margin-bottom : 18 px ;
}
. quote-text {
font-family : var ( -- serif );
font-style : italic ;
font-weight : 400 ;
font-size : clamp ( 30 px , 3.6 vw , 46 px );
line-height : 1.25 ;
letter-spacing : -0.005 em ;
max-width : 26 ch ;
margin : 0 0 34 px ;
}
. quote-author { font-family : var ( -- mono ); font-size : 13 px ; letter-spacing : 0.03 em ; color : var ( -- faint ); }
. grid-3 { display : grid ; grid-template-columns : repeat ( 3 , 1 fr ); gap : 40 px ; margin-top : 48 px ; }
. grid-3 . pt { border-top : 1 px solid var ( -- line - strong ); padding-top : 18 px ; }
. grid-3 . pt . h { font-family : var ( -- serif ); font-size : 20 px ; font-weight : 600 ; letter-spacing : -0.005 em ; margin : 0 0 10 px ; }
. grid-3 . pt . p { color : var ( -- muted ); margin : 0 ; font-size : 15.5 px ; line-height : 1.55 ; }
. counter {
position : fixed ;
bottom : 26 px ;
right : 32 px ;
font-family : var ( -- mono );
font-size : 11.5 px ;
letter-spacing : 0.05 em ;
font-variant-numeric : tabular-nums ;
color : var ( -- muted );
background : var ( -- surface );
padding : 5 px 12 px ;
border : 1 px solid var ( -- line );
}
/* chip ground matches .counter so the hint stays legible on the inverted CTA slide */
. hint {
position : fixed ;
bottom : 26 px ;
left : 32 px ;
font-family : var ( -- mono );
font-size : 11 px ;
letter-spacing : 0.04 em ;
color : var ( -- muted );
background : var ( -- surface );
padding : 5 px 12 px ;
border : 1 px solid var ( -- line );
}
@ media print { . slide { page-break-after : always ; border-left : none ; } }
2026-05-12 15:18:16 +08:00
</ style >
</ head >
< body >
2026-06-16 16:41:04 +08:00
< section class = "slide cover" data-od-id = "slide-1" >
2026-07-10 17:41:47 +08:00
< div class = "eyebrow" > Corporate Strategy · Operating Review · Board Pre-Read</ div >
< h1 > Approve the plan: cut burn 35%, protect the open core.</ h1 >
2026-08-18 07:09:45 +00:00
< p class = "body" > OpenDesign's Q2 operating review — growth, burn, and the concrete path to sustainability, without gating the Apache-2.0 project that got us here.</ p >
2026-05-12 15:18:16 +08:00
</ section >
< section class = "slide" data-od-id = "slide-2" >
2026-07-10 17:41:47 +08:00
< div class = "eyebrow" > Recommendation</ div >
< h2 > Extend runway to 22 months without touching the open core.</ h2 >
< p class = "body" > Growth is not the problem — 76K GitHub stars and 200+ community plugins prove demand. The gap is cost structure: we're subsidizing every user's model calls. The fix is to make BYOK the default, license self-hosted enterprise deployments, and leave the open-source desktop app untouched.</ p >
2026-05-12 15:18:16 +08:00
</ section >
< section class = "slide big-stat" data-od-id = "slide-3" >
2026-07-10 17:41:47 +08:00
< div class = "number" > 42%</ div >
< div class = "caption" > Cloud inference spend cut, from $187K to $109K/month, since local-first agent routing shipped in Q1.</ div >
2026-05-12 15:18:16 +08:00
</ section >
< section class = "slide" data-od-id = "slide-4" >
2026-07-10 17:41:47 +08:00
< div class = "eyebrow" > Options considered</ div >
< h2 > Three paths to sustainability.</ h2 >
2026-05-12 15:18:16 +08:00
< div class = "grid-3" >
2026-07-10 17:41:47 +08:00
< div class = "pt" >< h3 class = "h" > A — Hold course</ h3 >< p class = "p" > Keep subsidizing hosted inference. Burn stays flat at $187K/mo; runway closes to 9 months by Q4.</ p ></ div >
< div class = "pt" >< h3 class = "h" > B — BYOK default (recommended)</ h3 >< p class = "p" > Users bring their own model keys by default. Cuts hosted inference cost ~40% with zero change to the open-source app.</ p ></ div >
< div class = "pt" >< h3 class = "h" > C — Enterprise self-host license</ h3 >< p class = "p" > Charge for managed self-hosted deployments and support, on top of B, without paywalling any existing feature.</ p ></ div >
2026-05-12 15:18:16 +08:00
</ div >
</ section >
< section class = "slide" data-od-id = "slide-5" >
< div class = "quote-mark" > "</ div >
2026-07-10 17:41:47 +08:00
< p class = "quote-text" > If we gate any existing plugin or feature behind a paywall to hit these numbers, we break the open-source flywheel that built the 200+ plugin ecosystem — that risk isn't worth the savings.</ p >
< p class = "quote-author" > — Risk flagged jointly by Engineering and Community leads</ p >
2026-05-12 15:18:16 +08:00
</ section >
< section class = "slide title" data-od-id = "slide-6" >
2026-07-10 17:41:47 +08:00
< div class = "eyebrow" > Decision needed by July 23 board meeting</ div >
< h1 > Approve BYOK-default plus the enterprise self-host license.</ h1 >
< p class = "body" > Owners: Maria Chen (CFO) runs the burn-down plan · Alex Osei (Head of Platform) ships BYOK-default in Q3 · Community leads keep plugin governance fully open throughout.</ p >
2026-05-12 15:18:16 +08:00
</ 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 >
2026-07-10 17:41:47 +08:00
2026-05-12 15:18:16 +08:00
</ body >
</ html >