/* Variation CTO — 10-question peer review for the technical director.
Same warm-dark editorial language but framed as engineer-to-engineer.
Uses ?role=cto to pull the technical question set + interactive widgets. */
// Inline ladder for {v, label} levels.
function CTOLadder({ levels, value, onChange }) {
return (
{levels.map(lv => (
onChange(value === lv.v ? undefined : lv.v)}
>
{String(lv.v).padStart(2, '0')}
{lv.label}
))}
);
}
function makeCTOQuestions(t) {
const c = t.cq;
const slider = (key) => ({ key, kicker: c[key].kicker, title: c[key].title, lead: c[key].lead,
render: (a, set, onAuto) => (
set(key, v)} lowLabel={c[key].low} highLabel={c[key].high} leftWord={c[key].low} rightWord={c[key].high} />
),
});
const ladder = (key) => ({ key, kicker: c[key].kicker, title: c[key].title, lead: c[key].lead,
render: (a, set) => set(key, v)} />,
});
return [
slider('summary'),
{ key: 'mood', kicker: c.mood.kicker, title: c.mood.title, lead: c.mood.lead,
render: (a, set, onAuto) => set('mood', v)} onAutoAdvance={onAuto} t={{ ...t, q: { ...t.q, mood: { moods: c.mood.moods } } }} /> },
{ key: 'skills', kicker: c.skills.kicker, title: c.skills.title, lead: c.skills.lead,
render: (a, set) => set('skills', v)} /> },
{ key: 'stack', kicker: c.stack.kicker, title: c.stack.title, lead: c.stack.lead,
render: (a, set) => set('stack', v)} /> },
{ key: 'diff', kicker: c.diff.kicker, title: c.diff.title, lead: c.diff.lead,
render: (a, set) => set('diff', v)} t={t} /> },
{ key: 'pairs', kicker: c.pairs.kicker, title: c.pairs.title, lead: c.pairs.lead,
render: (a, set) => set('pairs', v)} /> },
{ key: 'pr', kicker: c.pr.kicker, title: c.pr.title, lead: c.pr.lead,
render: (a, set) => set('pr', v)} /> },
slider('share'),
ladder('grit'),
{ key: 'trust', kicker: c.trust.kicker, title: c.trust.title, lead: c.trust.lead,
render: (a, set) => ({ ...it, levels: c.trust.levels }))} value={a.trust || {}} onChange={v => set('trust', v)} /> },
{ key: 'ship', kicker: c.ship.kicker, title: c.ship.title, lead: c.ship.lead,
render: (a, set) => set('ship', v)} yesLabel={c.ship.yes} noLabel={c.ship.no} reasonPlaceholder={c.ship.reasonPlaceholder} /> },
{ key: 'rhythm', kicker: c.rhythm.kicker, title: c.rhythm.title, lead: c.rhythm.lead,
render: (a, set) => set('rhythm', v)} weeks={8} /> },
{ key: 'points', kicker: c.points.kicker, title: c.points.title, lead: c.points.lead,
render: (a, set) => set('points', v)} total={100} /> },
{ key: 'flow', kicker: c.flow.kicker, title: c.flow.title, lead: c.flow.lead,
render: (a, set) => set('flow', v)} /> },
slider('hire'),
{ key: 'steal', kicker: c.steal.kicker, title: c.steal.title, lead: c.steal.lead,
render: (a, set) => set('steal', v)} max={3} /> },
{ key: 'sort', kicker: c.sort.kicker, title: c.sort.title, lead: c.sort.lead,
render: (a, set) => set('sort', v)} /> },
{ key: 'risk', kicker: c.risk.kicker, title: c.risk.title, lead: c.risk.lead,
render: (a, set) => set('risk', v)} placeholder={c.risk.placeholder} severityLow={c.risk.sevLow} severityHigh={c.risk.sevHigh} /> },
ladder('readiness'),
{ key: 'open', kicker: c.open.kicker, title: c.open.title, lead: c.open.lead,
render: (a, set) => set('open', v)} t={{ ...t, q: { ...t.q, open: c.open } }} /> },
];
}
function VariationCTO({ frameW = 1280, frameH = 820 }) {
const { lang, id, setLang } = useRoute();
const t = useT(lang, 'cto');
const client = useClient(id);
const questions = useMemo(() => makeCTOQuestions(t), [t]);
const total = questions.length;
const wiz = useWizard(id, total, 'vcto');
const { state, setAnswer, next, back, start, finish } = wiz;
const stepIdx = state.step;
const isStart = !state.started;
const isDone = state.done;
const onLast = stepIdx === total - 1;
return (
{`{ }`}
{t.brand} · CTO TRACK
{t.pill} · /{lang}/{id}?role=cto
{state.started && !isDone && (
)}
{isStart ? (
{t.greetingKicker}
{t.greetingTitle(client.contact || client.name)}
{t.greetingLead}
{t.cta} →
{t.greetingMeta}
{questions.map((q, i) => (
{String(i + 1).padStart(2, '0')} {q.kicker.split('·')[1]?.trim() || ''}
))}
// peer review
{`function review(me) {
return {
strengths: [...],
sloppiness: [...],
nextLevel: '???',
};
}`}
10 questions
· 1 slider
· 1 mood
· skill matrix
· stack tags
· code diff
· ship gate
· rhythm grid
· 100-point split
· drag to rank
· open feedback
) : isDone ? (
{t.done.kicker}
{t.done.title}
{t.done.lead}
) : (
{questions[stepIdx].kicker}
{t.progress(stepIdx + 1, total)}
{questions[stepIdx].title}
{questions[stepIdx].lead}
{questions[stepIdx].render(state.answers, setAnswer, onLast ? finish : next)}
{stepIdx > 0 && ← {t.back} }
{onLast ? t.submit : t.next} →
)}
);
}
const vctoStyles = {
frame: (w, h) => ({
width: w, height: h, background: 'var(--ink-bg)', color: 'var(--text)',
fontFamily: "'Geist', system-ui, sans-serif",
display: 'flex', flexDirection: 'column', overflow: 'hidden', position: 'relative',
}),
header: {
display: 'flex', justifyContent: 'space-between', alignItems: 'center',
padding: '24px 56px', borderBottom: '1px solid var(--ink-line)',
flexShrink: 0,
},
mark: {
width: 36, height: 36, borderRadius: 8,
background: 'var(--accent-2)', color: 'var(--accent-ink)',
display: 'flex', alignItems: 'center', justifyContent: 'center',
fontFamily: 'JetBrains Mono, monospace', fontWeight: 600, fontSize: 14,
},
main: { flex: 1, padding: '48px 56px', display: 'flex', alignItems: 'flex-start', justifyContent: 'center', overflowY: 'auto', minHeight: 0 },
grid: { display: 'grid', gridTemplateColumns: '1.5fr 1fr', gap: 60, width: '100%', maxWidth: 1100, alignItems: 'center' },
h1: { fontSize: 56, lineHeight: 1.05, fontWeight: 400, letterSpacing: '-0.02em' },
h2: { fontSize: 38, lineHeight: 1.1, fontWeight: 400, letterSpacing: '-0.015em' },
lead: { fontSize: 17, lineHeight: 1.55, color: 'var(--text-2)', marginTop: 16, maxWidth: 640 },
aside: { borderLeft: '1px solid var(--ink-line)', paddingLeft: 36, display: 'flex', flexDirection: 'column' },
code: {
fontFamily: 'JetBrains Mono, monospace', fontSize: 13, lineHeight: 1.6,
color: 'var(--text-2)', marginTop: 18, whiteSpace: 'pre',
background: 'rgba(255,255,255,0.03)', padding: 18, borderRadius: 12,
border: '1px solid var(--ink-line)',
},
stepGrid: { display: 'grid', gridTemplateColumns: '160px 1fr', gap: 56, width: '100%', maxWidth: 1100 },
stepLeft: { display: 'flex', flexDirection: 'column', paddingTop: 8, minHeight: 280 },
stepRight: { borderLeft: '1px solid var(--ink-line)', paddingLeft: 56 },
};
window.VariationCTO = VariationCTO;
window.makeCTOQuestions = makeCTOQuestions;