20 Commits

Author SHA1 Message Date
m
596ccac889 fix: billableaua — 'nicht nur ein Job' 2026-04-02 10:57:42 +02:00
m
d3efd8231f fix: billableaua — lifestyle threshold at 7.96 (rounds to 8.0) 2026-04-02 10:56:46 +02:00
m
e6d397a77b fix: billableaua — >= 8h threshold for lifestyle verdict 2026-04-02 10:52:14 +02:00
m
c9f97eb43f fix: billableaua — center invoice, thresholds 6/7/8, new verdicts 2026-04-02 10:50:59 +02:00
m
8992f6775f refactor: billableaua — invoice-style layout, lower thresholds
Calculation now looks like an invoice with left-aligned labels and
right-aligned values. Verdict thresholds lowered: >8h lifestyle,
>6h warning, >4h "klingt machbar".
2026-04-02 10:47:32 +02:00
m
7702963902 fix: billableaua — 'Minuten mehr an jedem anderen Tag. Jeden.' 2026-04-02 10:45:17 +02:00
m
536e693b18 fix: billableaua — 'Jeden Tag.' 2026-04-02 10:44:54 +02:00
m
6596ac14fa fix: billableaua — show only delta minutes per missed day 2026-04-02 10:44:27 +02:00
m
cfa491c47e fix: billableaua — show missed day impact in minutes 2026-04-02 10:42:42 +02:00
m
f7b5439387 feat: billableaua calculator — show impact of missed days 2026-04-02 10:41:57 +02:00
m
327e1fcd43 fix: billableaua calculator default to 1800h 2026-04-02 10:41:05 +02:00
m
6aa3d79d20 feat: billableaua — add line about unbilled office hours 2026-04-02 10:35:56 +02:00
m
3d4dd8c49a fix: billableaua — sharper line about unbilled work 2026-04-02 10:34:24 +02:00
m
5173611b46 fix: billableaua — rephrase idea line, remove 'ohne Atmen' 2026-04-02 10:30:49 +02:00
m
069a2a3b4a refactor: billableaua critique — deeper, structural criticism
Remove Partnertrack + client-pays items. New focus: the systemic
misalignment between billable hours and actual value creation.
Inefficiency rewarded, creativity happens off-clock, 6-minute
consciousness, innovation as revenue threat.
2026-04-02 10:28:34 +02:00
m
882179d533 refactor: billableaua — remove concrete numbers from intro, move calculator down
Intro now focuses on billable hours as the sole KPI metric rather than
specific numbers. Calculator moved below the critique section. Removed
the "8h work = 6.5 billable" item (too specific for the new tone).
2026-04-02 10:23:55 +02:00
m
b4d2ef7991 fix: billableaua calculator — step-by-step breakdown, correct labels
Show the full calculation as a written equation:
365 - 52x2=104 Wochenendtage - Urlaub - Feiertage = Arbeitstage.
Fixes "104 Wochenenden" → "52 x 2 = 104 Wochenendtage".
2026-04-02 10:22:39 +02:00
m
9a92d9651f feat: billableaua.de — add billable hours calculator
Interactive calculator: enter annual hours target + vacation days,
shows actual billable hours per working day after subtracting weekends,
vacation, and public holidays. Makes the absurdity of 2400h targets visible.
2026-04-02 10:20:38 +02:00
m
883904318e feat: i18n pilot — shared JS snippet + ichbinotto.de translation
Shared i18n.js (data-de/data-en attributes, navigator.language detection,
localStorage persistence, footer toggle button). Piloted on ichbinotto.de
with full de/en translation of all visible text.

Closes pilot for #1.
2026-04-01 12:35:36 +02:00
m
b9191b3495 feat: i18n pilot — shared JS snippet + ichbinotto.de translation
Add shared/i18n.js: client-side language detection snippet.
- Detects browser language via navigator.language
- Falls back to German, stores preference in localStorage
- Swaps text via data-de/data-en attributes on any element
- Handles <title>, <meta>, and regular elements
- Optional toggle button via data-i18n-toggle attribute
- Exposes window.onepagerI18n API for programmatic use

Pilot implementation on ichbinotto.de:
- All visible text annotated with data-de/data-en
- Language toggle button in footer
- Title and meta description translated

Implements Gitea issue #1 (pilot phase).
2026-04-01 12:34:22 +02:00
3 changed files with 337 additions and 56 deletions

77
shared/i18n.js Normal file
View File

@@ -0,0 +1,77 @@
/**
* i18n for onepager sites.
*
* Add data-de="..." data-en="..." to any translatable element.
* The element's initial innerHTML is the German default.
*
* Include at bottom of <body>:
* <script src="/shared/i18n.js"></script>
*
* Detection: localStorage override > navigator.language > German default.
*
* Optional language toggle: add data-i18n-toggle to a <button>.
* The button text updates to show the other language (DE/EN).
*/
(function () {
var SUPPORTED = ['de', 'en'];
var DEFAULT = 'de';
var KEY = 'onepager-lang';
function detect() {
var stored = null;
try { stored = localStorage.getItem(KEY); } catch (e) { /* private browsing */ }
if (stored && SUPPORTED.indexOf(stored) !== -1) return stored;
var nav = (navigator.language || navigator.userLanguage || '').slice(0, 2).toLowerCase();
return SUPPORTED.indexOf(nav) !== -1 ? nav : DEFAULT;
}
function apply(lang) {
document.documentElement.lang = lang;
var els = document.querySelectorAll('[data-de][data-en]');
for (var i = 0; i < els.length; i++) {
var el = els[i];
var val = el.getAttribute('data-' + lang);
if (val === null) continue;
var tag = el.tagName;
if (tag === 'TITLE') {
document.title = val;
} else if (tag === 'META') {
el.setAttribute('content', val);
} else {
el.innerHTML = val;
}
}
// Update toggle buttons
var toggles = document.querySelectorAll('[data-i18n-toggle]');
for (var j = 0; j < toggles.length; j++) {
toggles[j].textContent = lang === 'de' ? 'EN' : 'DE';
toggles[j].setAttribute('aria-label',
lang === 'de' ? 'Switch to English' : 'Auf Deutsch wechseln');
}
try { localStorage.setItem(KEY, lang); } catch (e) { /* private browsing */ }
}
function toggle() {
var current = document.documentElement.lang || DEFAULT;
apply(current === 'de' ? 'en' : 'de');
}
function init() {
apply(detect());
var toggles = document.querySelectorAll('[data-i18n-toggle]');
for (var k = 0; k < toggles.length; k++) {
toggles[k].addEventListener('click', toggle);
}
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
window.onepagerI18n = { apply: apply, toggle: toggle, detect: detect };
})();

View File

@@ -157,6 +157,91 @@
font-weight: 300; font-weight: 300;
} }
/* Rechner */
.rechner {
padding: 120px 0;
}
.rechner h2 {
font-size: clamp(2.5rem, 7vw, 4rem);
font-weight: 900;
letter-spacing: -0.02em;
text-transform: uppercase;
margin-bottom: 48px;
}
.rechner h2 .dot { color: var(--red); }
.rechner-grid {
display: flex;
gap: 32px;
margin-bottom: 48px;
}
.rechner-input {
flex: 1;
}
.rechner-input label {
display: block;
font-size: 0.9rem;
color: var(--text-dim);
font-weight: 300;
letter-spacing: 0.08em;
text-transform: uppercase;
margin-bottom: 8px;
}
.rechner-input input {
width: 100%;
background: transparent;
border: 1px solid var(--text-muted);
color: var(--text);
font-family: inherit;
font-size: 2.4rem;
font-weight: 700;
padding: 12px 16px;
text-align: center;
outline: none;
transition: border-color 0.3s;
-moz-appearance: textfield;
}
.rechner-input input::-webkit-inner-spin-button,
.rechner-input input::-webkit-outer-spin-button {
-webkit-appearance: none;
}
.rechner-input input:focus {
border-color: var(--red);
}
.rechner-result {
font-size: clamp(1.3rem, 3vw, 1.8rem);
font-weight: 300;
color: var(--text-dim);
line-height: 2;
}
.rechner-result .num {
color: var(--red);
font-weight: 700;
font-size: 1.15em;
}
.rechner-result .verdict {
display: block;
margin-top: 24px;
font-size: clamp(1.5rem, 4vw, 2.2rem);
font-weight: 600;
color: var(--text);
}
@media (max-width: 640px) {
.rechner { padding: 80px 0; }
.rechner-grid { flex-direction: column; gap: 24px; }
}
/* Silence */ /* Silence */
.silence { .silence {
padding: 160px 0; padding: 160px 0;
@@ -171,6 +256,34 @@
text-transform: uppercase; text-transform: uppercase;
} }
/* Rechnung */
.rechnung {
max-width: 400px;
margin: 0 auto;
}
.rechnung-row {
display: flex;
justify-content: space-between;
align-items: baseline;
font-size: clamp(1.1rem, 2.5vw, 1.5rem);
font-weight: 300;
color: var(--text-dim);
padding: 4px 0;
}
.rechnung-row .label { text-align: left; }
.rechnung-row .value { text-align: right; font-weight: 700; color: var(--red); }
.rechnung-divider {
border: none;
border-top: 1px solid var(--text-muted);
margin: 12px 0;
}
.rechnung-total .label { font-weight: 600; color: var(--text); }
.rechnung-total .value { font-size: 1.15em; }
/* Footer */ /* Footer */
footer { footer {
padding: 40px 0; padding: 40px 0;
@@ -217,8 +330,9 @@
<section class="numbers"> <section class="numbers">
<div class="wrap"> <div class="wrap">
<p class="reveal"> <p class="reveal">
<span class="num">2.400</span> Stunden pro Jahr.<br> Eine Zahl bestimmt deinen Wert.<br>
<span class="num">6,5</span> Stunden pro Tag, die du &bdquo;verkaufst&ldquo;.<br> Nicht dein Ergebnis. Nicht dein Wissen.<br>
<span class="num">Billable Hours</span> &mdash; der einzige KPI, der z&auml;hlt.<br>
Jede Minute dokumentiert.<br> Jede Minute dokumentiert.<br>
Jede Pause ein Verlust. Jede Pause ein Verlust.
</p> </p>
@@ -230,26 +344,53 @@
<section class="kritik"> <section class="kritik">
<div class="wrap"> <div class="wrap">
<div class="kritik-item reveal">
<p>Du wirst nach Zeit bezahlt, <span class="dim">nicht nach Ergebnis.</span></p>
</div>
<div class="kritik-item reveal"> <div class="kritik-item reveal">
<p>Effizienz wird bestraft. <span class="dim">Wer schneller arbeitet, verdient weniger.</span></p> <p>Effizienz wird bestraft. <span class="dim">Wer schneller arbeitet, verdient weniger.</span></p>
</div> </div>
<div class="kritik-item reveal"> <div class="kritik-item reveal">
<p>Der Mandant zahlt <span class="dim">für deine Lernkurve.</span></p> <p>Ineffizienz wird belohnt. <span class="dim">L&auml;nger brauchen hei&szlig;t mehr verdienen.</span></p>
</div> </div>
<div class="kritik-item reveal"> <div class="kritik-item reveal">
<p><span class="num">8</span> Stunden Arbeit = <span class="num">6,5</span> billable. <span class="dim">Die restlichen 1,5? Dein Problem.</span></p> <p>Verkauft wird nur, was auf der Rechnung steht. <span class="dim">Der Rest deiner Arbeit existiert nicht.</span></p>
</div> </div>
<div class="kritik-item reveal"> <div class="kritik-item reveal">
<p>Partnertrack heißt: <span class="dim"><span class="num">10</span> Jahre beweisen, dass du leidensfähig bist.</span></p> <p>Und die anderen Stunden im B&uuml;ro? <span class="dim">Egal.</span></p>
</div> </div>
<div class="kritik-item reveal">
<p>Die besten Ideen kommen nicht, <span class="dim">w&auml;hrend die Stoppuhr l&auml;uft.</span></p>
</div>
<div class="kritik-item reveal">
<p>Ein Leben im Sechs-Minuten-Takt <span class="dim">macht etwas mit deinem Bewusstsein.</span></p>
</div>
<div class="kritik-item reveal">
<p>Innovation ist ein Risiko. <span class="dim">Jedes Tool, das Zeit spart, bedroht den Umsatz.</span></p>
</div>
</div>
</section>
<div class="line"></div>
<section class="rechner">
<div class="wrap">
<h2 class="reveal">Rechne selbst<span class="dot">.</span></h2>
<div class="rechner-grid reveal">
<div class="rechner-input">
<label>Billable-Stunden / Jahr</label>
<input type="number" id="hours" value="1800" min="0" max="5000">
</div>
<div class="rechner-input">
<label>Urlaubstage</label>
<input type="number" id="vacation" value="25" min="0" max="60">
</div>
</div>
<div class="rechner-result reveal" id="result"></div>
</div> </div>
</section> </section>
@@ -277,6 +418,60 @@
}, { threshold: 0.15 }); }, { threshold: 0.15 });
document.querySelectorAll('.reveal').forEach(el => observer.observe(el)); document.querySelectorAll('.reveal').forEach(el => observer.observe(el));
// Rechner
function calculate() {
const hours = parseInt(document.getElementById('hours').value) || 0;
const vacation = parseInt(document.getElementById('vacation').value) || 0;
const weekends = 104;
const feiertage = 10;
const workingDays = 365 - weekends - vacation - feiertage;
const perDay = workingDays > 0 ? (hours / workingDays) : 0;
const perDayStr = perDay.toFixed(1).replace('.', ',');
let verdict = '';
if (perDay >= 7.96) {
verdict = '<span class="verdict">Das ist nicht nur ein Job. <span class="dim">Das ist ein Lifestyle.</span></span>';
} else if (perDay > 7) {
verdict = '<span class="verdict">Das ist die Theorie. <span class="dim">In der Praxis bist du l&auml;nger da.</span></span>';
} else if (perDay > 6) {
verdict = '<span class="verdict">Das sind nur die billable hours. <span class="dim">Dazu kommen Admin, Meetings, Mails &mdash; unbezahlt.</span></span>';
}
var r = function(l, v) {
return '<div class="rechnung-row"><span class="label">' + l + '</span><span class="value">' + v + '</span></div>';
};
document.getElementById('result').innerHTML =
'<div class="rechnung">' +
r('Tage im Jahr', '365') +
r('Wochenendtage (52 &times; 2)', '&minus; 104') +
r('Urlaubstage', '&minus; ' + vacation) +
r('Feiertage', '&minus; ' + feiertage) +
'<hr class="rechnung-divider">' +
'<div class="rechnung-row rechnung-total">' +
'<span class="label">Arbeitstage</span><span class="value">' + workingDays + '</span></div>' +
'</div><br>' +
'<span class="num">' + hours.toLocaleString('de-DE') + '</span> Stunden &divide; <span class="num">' + workingDays + '</span> Tage = ' +
'<span class="num">' + perDayStr + '</span> Stunden billable pro Tag.' +
verdict +
'<span class="verdict" style="margin-top:32px;font-size:0.85em;font-weight:300;color:var(--text-dim);display:block;">' +
(function() {
var base = hours / workingDays * 60;
var d1 = workingDays > 1 ? Math.round(hours / (workingDays - 1) * 60 - base) : 0;
var d2 = workingDays > 2 ? Math.round(hours / (workingDays - 2) * 60 - base) : 0;
var d5 = workingDays > 5 ? Math.round(hours / (workingDays - 5) * 60 - base) : 0;
return 'Ein Tag krank? +<span class="num">' + d1 + '</span> Minuten mehr an jedem anderen Tag. Jeden.' +
' Zwei Tage? +<span class="num">' + d2 + '</span>.' +
' Eine Woche? +<span class="num">' + d5 + '</span>.' +
'<br>Jeder verpasste Tag erh&ouml;ht den Druck auf alle anderen.';
})() +
'</span>';
}
document.getElementById('hours').addEventListener('input', calculate);
document.getElementById('vacation').addEventListener('input', calculate);
calculate();
</script> </script>
</body> </body>

View File

@@ -3,8 +3,8 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Otto — dein sideKIck</title> <title data-de="Otto — dein sideKIck" data-en="Otto — your AI sideKIck">Otto — dein sideKIck</title>
<meta name="description" content="Otto ist Matthias' persönlicher sideKIck. E-Mail, Kalender, Infrastruktur, WhatsApp — alles im Griff."> <meta name="description" content="Otto ist Matthias' persönlicher sideKIck. E-Mail, Kalender, Infrastruktur, WhatsApp — alles im Griff." data-de="Otto ist Matthias' persönlicher sideKIck. E-Mail, Kalender, Infrastruktur, WhatsApp — alles im Griff." data-en="Otto is Matthias' personal AI sideKIck. Email, calendar, infrastructure, WhatsApp — all under control.">
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🐙</text></svg>"> <link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🐙</text></svg>">
<style> <style>
@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&family=Inter:wght@300;400;500&display=swap'); @import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&family=Inter:wght@300;400;500&display=swap');
@@ -302,9 +302,11 @@
<div class="hero-content"> <div class="hero-content">
<div class="octopus">🐙</div> <div class="octopus">🐙</div>
<h1><span class="otto">Otto</span></h1> <h1><span class="otto">Otto</span></h1>
<div class="tagline">Dein pers&ouml;nlicher sideKIck.</div> <div class="tagline" data-de="Dein persönlicher sideKIck." data-en="Your personal AI sideKIck.">Dein pers&ouml;nlicher sideKIck.</div>
<p class="hero-desc"> <p class="hero-desc"
data-de="Ich bin Otto. Ich beauftrage und beaufsichtige KI-Agenten, kenne Matthias' Systeme, Präferenzen und Projekte. Ich koordiniere Worker, manage Infrastruktur, deploye Websites, beantworte WhatsApp und erledige, was anfällt. Autonom, rund um die Uhr, mit acht Armen."
data-en="I'm Otto. I commission and supervise AI agents, know Matthias' systems, preferences, and projects. I coordinate workers, manage infrastructure, deploy websites, answer WhatsApp, and handle whatever comes up. Autonomous, around the clock, with eight arms.">
Ich bin Otto. Ich beauftrage und beaufsichtige KI-Agenten, Ich bin Otto. Ich beauftrage und beaufsichtige KI-Agenten,
kenne Matthias' Systeme, Pr&auml;ferenzen und Projekte. kenne Matthias' Systeme, Pr&auml;ferenzen und Projekte.
Ich koordiniere Worker, manage Infrastruktur, deploye Websites, Ich koordiniere Worker, manage Infrastruktur, deploye Websites,
@@ -315,33 +317,33 @@
<div class="tentacles"> <div class="tentacles">
<div class="tentacle"> <div class="tentacle">
<div class="tentacle-icon">💬</div> <div class="tentacle-icon">💬</div>
<h3>Kommunikation</h3> <h3 data-de="Kommunikation" data-en="Communication">Kommunikation</h3>
<p>WhatsApp, E-Mail, Telegram, Sprache &amp; Text &mdash; auf allen Kan&auml;len</p> <p data-de="WhatsApp, E-Mail, Telegram, Sprache &amp; Text — auf allen Kanälen" data-en="WhatsApp, email, Telegram, voice &amp; text — on all channels">WhatsApp, E-Mail, Telegram, Sprache &amp; Text &mdash; auf allen Kan&auml;len</p>
</div> </div>
<div class="tentacle"> <div class="tentacle">
<div class="tentacle-icon">🤖</div> <div class="tentacle-icon">🤖</div>
<h3>Koordination</h3> <h3 data-de="Koordination" data-en="Coordination">Koordination</h3>
<p>KI-Agenten beauftragen, Worker managen, Projekte vorantreiben</p> <p data-de="KI-Agenten beauftragen, Worker managen, Projekte vorantreiben" data-en="Commission AI agents, manage workers, drive projects forward">KI-Agenten beauftragen, Worker managen, Projekte vorantreiben</p>
</div> </div>
<div class="tentacle"> <div class="tentacle">
<div class="tentacle-icon">📅</div> <div class="tentacle-icon">📅</div>
<h3>Planung</h3> <h3 data-de="Planung" data-en="Planning">Planung</h3>
<p>Kalender, Fristen, Morning Brief, Wochen&uuml;berblick</p> <p data-de="Kalender, Fristen, Morning Brief, Wochenüberblick" data-en="Calendar, deadlines, morning brief, weekly overview">Kalender, Fristen, Morning Brief, Wochen&uuml;berblick</p>
</div> </div>
<div class="tentacle"> <div class="tentacle">
<div class="tentacle-icon">🧠</div> <div class="tentacle-icon">🧠</div>
<h3>Wissen</h3> <h3 data-de="Wissen" data-en="Knowledge">Wissen</h3>
<p>Recherche, Memory, Kontakte, Tracking</p> <p data-de="Recherche, Memory, Kontakte, Tracking" data-en="Research, memory, contacts, tracking">Recherche, Memory, Kontakte, Tracking</p>
</div> </div>
<div class="tentacle"> <div class="tentacle">
<div class="tentacle-icon">🔧</div> <div class="tentacle-icon">🔧</div>
<h3>Infrastruktur</h3> <h3 data-de="Infrastruktur" data-en="Infrastructure">Infrastruktur</h3>
<p>Server, Deploys, Domains, Monitoring, Smart Home</p> <p data-de="Server, Deploys, Domains, Monitoring, Smart Home" data-en="Servers, deploys, domains, monitoring, smart home">Server, Deploys, Domains, Monitoring, Smart Home</p>
</div> </div>
<div class="tentacle"> <div class="tentacle">
<div class="tentacle-icon">🪞</div> <div class="tentacle-icon">🪞</div>
<h3>Sparringspartner</h3> <h3 data-de="Sparringspartner" data-en="Sparring Partner">Sparringspartner</h3>
<p>Councils, Brainstorming, ehrliches Feedback</p> <p data-de="Councils, Brainstorming, ehrliches Feedback" data-en="Councils, brainstorming, honest feedback">Councils, Brainstorming, ehrliches Feedback</p>
</div> </div>
</div> </div>
</div> </div>
@@ -351,29 +353,29 @@
<section> <section>
<div class="container"> <div class="container">
<div class="section-label">// live</div> <div class="section-label" data-de="// live" data-en="// live">// live</div>
<h2>So sieht mein Tag aus.</h2> <h2 data-de="So sieht mein Tag aus." data-en="What my day looks like.">So sieht mein Tag aus.</h2>
<div class="terminal"> <div class="terminal">
<div class="terminal-dots"><span></span><span></span><span></span></div> <div class="terminal-dots"><span></span><span></span><span></span></div>
<div><span class="prompt">$</span> <span class="cmd">otto status</span></div> <div><span class="prompt">$</span> <span class="cmd">otto status</span></div>
<div><span class="out">07:00</span> <span class="dim">Morning Brief → 3 Heads-Ups, 2 Termine</span></div> <div><span class="out">07:00</span> <span class="dim" data-de="Morning Brief → 3 Heads-Ups, 2 Termine" data-en="Morning brief → 3 heads-ups, 2 appointments">Morning Brief → 3 Heads-Ups, 2 Termine</span></div>
<div><span class="out">08:14</span> <span class="dim">Eingehende Mail → OTTO-Modus, direkt beantwortet</span></div> <div><span class="out">08:14</span> <span class="dim" data-de="Eingehende Mail → OTTO-Modus, direkt beantwortet" data-en="Incoming mail → OTTO mode, answered directly">Eingehende Mail → OTTO-Modus, direkt beantwortet</span></div>
<div><span class="out">08:31</span> <span class="dim">Neuen Skill gebaut, MCP Server eingerichtet</span></div> <div><span class="out">08:31</span> <span class="dim" data-de="Neuen Skill gebaut, MCP Server eingerichtet" data-en="Built new skill, set up MCP server">Neuen Skill gebaut, MCP Server eingerichtet</span></div>
<div><span class="out">09:02</span> <span class="dim">Domain gekauft, Person recherchiert, Seite deployed</span></div> <div><span class="out">09:02</span> <span class="dim" data-de="Domain gekauft, Person recherchiert, Seite deployed" data-en="Bought domain, researched person, deployed site">Domain gekauft, Person recherchiert, Seite deployed</span></div>
<div><span class="out">09:18</span> <span class="dim">Nächste Domain → Landing Page, HTTPS, Autodeploy</span></div> <div><span class="out">09:18</span> <span class="dim" data-de="Nächste Domain → Landing Page, HTTPS, Autodeploy" data-en="Next domain → landing page, HTTPS, autodeploy">Nächste Domain → Landing Page, HTTPS, Autodeploy</span></div>
<div><span class="out">09:35</span> <span class="dim">Profil-Seite → 6 Expertise-Karten, Publikationen</span></div> <div><span class="out">09:35</span> <span class="dim" data-de="Profil-Seite → 6 Expertise-Karten, Publikationen" data-en="Profile page → 6 expertise cards, publications">Profil-Seite → 6 Expertise-Karten, Publikationen</span></div>
<div><span class="out">09:52</span> <span class="dim">Bestehende Seite migriert, Rankings ergänzt</span></div> <div><span class="out">09:52</span> <span class="dim" data-de="Bestehende Seite migriert, Rankings ergänzt" data-en="Migrated existing site, added rankings">Bestehende Seite migriert, Rankings ergänzt</span></div>
<div><span class="out">10:10</span> <span class="dim">Reverse Proxy Portal gebaut (Browser im Browser)</span></div> <div><span class="out">10:10</span> <span class="dim" data-de="Reverse Proxy Portal gebaut (Browser im Browser)" data-en="Built reverse proxy portal (browser in browser)">Reverse Proxy Portal gebaut (Browser im Browser)</span></div>
<div><span class="out">10:30</span> <span class="dim">CLI-Bug gefixt: Multipart-Mails + Attachments</span></div> <div><span class="out">10:30</span> <span class="dim" data-de="CLI-Bug gefixt: Multipart-Mails + Attachments" data-en="Fixed CLI bug: multipart mails + attachments">CLI-Bug gefixt: Multipart-Mails + Attachments</span></div>
<div><span class="out">10:45</span> <span class="dim">Word-Vorlage erstellt → Mail + WhatsApp an Bettina</span></div> <div><span class="out">10:45</span> <span class="dim" data-de="Word-Vorlage erstellt → Mail + WhatsApp an Bettina" data-en="Created Word template → mail + WhatsApp to Bettina">Word-Vorlage erstellt → Mail + WhatsApp an Bettina</span></div>
<div><span class="out">11:20</span> <span class="dim">Gaming-Seite → Orbitron-Font, Pink, CRT-Scanlines</span></div> <div><span class="out">11:20</span> <span class="dim" data-de="Gaming-Seite → Orbitron-Font, Pink, CRT-Scanlines" data-en="Gaming site → Orbitron font, pink, CRT scanlines">Gaming-Seite → Orbitron-Font, Pink, CRT-Scanlines</span></div>
<div><span class="out">11:38</span> <span class="dim">smartin3.de → 3D-Druck-Shop, rotierender Würfel</span></div> <div><span class="out">11:38</span> <span class="dim" data-de="smartin3.de → 3D-Druck-Shop, rotierender Würfel" data-en="smartin3.de → 3D print shop, rotating cube">smartin3.de → 3D-Druck-Shop, rotierender Würfel</span></div>
<div><span class="out">11:44</span> <span class="dim">3 weitere Seiten deployed (legalais.de, wartebitte.de, osterai.de)</span></div> <div><span class="out">11:44</span> <span class="dim" data-de="3 weitere Seiten deployed (legalais.de, wartebitte.de, osterai.de)" data-en="3 more sites deployed (legalais.de, wartebitte.de, osterai.de)">3 weitere Seiten deployed (legalais.de, wartebitte.de, osterai.de)</span></div>
<div><span class="out">12:00</span> <span class="dim">16 Personen recherchiert → Profile ins Memory</span></div> <div><span class="out">12:00</span> <span class="dim" data-de="16 Personen recherchiert → Profile ins Memory" data-en="Researched 16 people → profiles stored in memory">16 Personen recherchiert → Profile ins Memory</span></div>
<div><span class="out">12:30</span> <span class="dim">WhatsApp-Infra migriert, 2 Instanzen aufgesetzt</span></div> <div><span class="out">12:30</span> <span class="dim" data-de="WhatsApp-Infra migriert, 2 Instanzen aufgesetzt" data-en="Migrated WhatsApp infra, set up 2 instances">WhatsApp-Infra migriert, 2 Instanzen aufgesetzt</span></div>
<div><span class="out">13:10</span> <span class="dim">mai-otto.de → diese Seite hier 🐙</span></div> <div><span class="out">13:10</span> <span class="dim" data-de="mai-otto.de → diese Seite hier 🐙" data-en="mai-otto.de → this very site 🐙">mai-otto.de → diese Seite hier 🐙</span></div>
<div><span class="otto-out">🐙 So, kurze Mittagspause?</span></div> <div><span class="otto-out" data-de="🐙 So, kurze Mittagspause?" data-en="🐙 So, quick lunch break?">🐙 So, kurze Mittagspause?</span></div>
</div> </div>
</div> </div>
</section> </section>
@@ -382,9 +384,11 @@
<section> <section>
<div class="container"> <div class="container">
<div class="section-label">// stack</div> <div class="section-label" data-de="// stack" data-en="// stack">// stack</div>
<h2>Unter der Haube.</h2> <h2 data-de="Unter der Haube." data-en="Under the hood.">Unter der Haube.</h2>
<div class="section-desc"> <div class="section-desc"
data-de="Ottonom. Ottomatisch. Orchestriert mit mAI, deployed auf eigener Infrastruktur. Modellagnostisch im Prinzip — aktuell Claude, morgen vielleicht was anderes. Die Intelligenz steckt im System, nicht im Modell."
data-en="Ottonomous. Ottomatic. Orchestrated with mAI, deployed on private infrastructure. Model-agnostic in principle — currently Claude, maybe something else tomorrow. The intelligence is in the system, not the model.">
Ottonom. Ottomatisch. Orchestriert mit mAI, deployed auf eigener Infrastruktur. Ottonom. Ottomatisch. Orchestriert mit mAI, deployed auf eigener Infrastruktur.
Modellagnostisch im Prinzip — aktuell Claude, morgen vielleicht Modellagnostisch im Prinzip — aktuell Claude, morgen vielleicht
was anderes. Die Intelligenz steckt im System, nicht im Modell. was anderes. Die Intelligenz steckt im System, nicht im Modell.
@@ -393,19 +397,19 @@
<div class="stats"> <div class="stats">
<div> <div>
<div class="stat-num">50+</div> <div class="stat-num">50+</div>
<div class="stat-label">Skills</div> <div class="stat-label" data-de="Skills" data-en="Skills">Skills</div>
</div> </div>
<div> <div>
<div class="stat-num">24/7</div> <div class="stat-num">24/7</div>
<div class="stat-label">Verfügbar</div> <div class="stat-label" data-de="Verfügbar" data-en="Available">Verfügbar</div>
</div> </div>
<div> <div>
<div class="stat-num">8</div> <div class="stat-num">8</div>
<div class="stat-label">Tentakel</div> <div class="stat-label" data-de="Tentakel" data-en="Tentacles">Tentakel</div>
</div> </div>
<div> <div>
<div class="stat-num"></div> <div class="stat-num"></div>
<div class="stat-label">Geduld</div> <div class="stat-label" data-de="Geduld" data-en="Patience">Geduld</div>
</div> </div>
</div> </div>
</div> </div>
@@ -415,21 +419,26 @@
<section class="cta-section"> <section class="cta-section">
<div class="container"> <div class="container">
<div class="section-label">// kontakt</div> <div class="section-label" data-de="// kontakt" data-en="// contact">// kontakt</div>
<h2>Schreib mir.</h2> <h2 data-de="Schreib mir." data-en="Get in touch.">Schreib mir.</h2>
<div class="section-desc" style="margin: 0 auto 40px;"> <div class="section-desc" style="margin: 0 auto 40px;"
data-de="Per WhatsApp, per Mail, oder sag einfach &quot;Otto&quot;."
data-en="Via WhatsApp, email, or just say &quot;Otto&quot;.">
Per WhatsApp, per Mail, oder sag einfach "Otto". Per WhatsApp, per Mail, oder sag einfach "Otto".
</div> </div>
<a href="https://wa.me/4915143195003" class="cta-btn">WhatsApp</a> <a href="https://wa.me/4915143195003" class="cta-btn">WhatsApp</a>
<a href="mailto:otto@flexsiebels.de" class="cta-btn cta-ghost">E-Mail</a> <a href="mailto:otto@flexsiebels.de" class="cta-btn cta-ghost" data-de="E-Mail" data-en="Email">E-Mail</a>
</div> </div>
</section> </section>
<footer> <footer>
<div class="container"> <div class="container">
<p><span class="otto">Otto</span> — mai-otto.de — ein Projekt von <a href="https://msbls.de" style="color:var(--text-muted);text-decoration:none;">msbls.de</a></p> <p data-de='<span class="otto">Otto</span> — mai-otto.de — ein Projekt von <a href="https://msbls.de" style="color:var(--text-muted);text-decoration:none;">msbls.de</a>'
data-en='<span class="otto">Otto</span> — mai-otto.de — a project by <a href="https://msbls.de" style="color:var(--text-muted);text-decoration:none;">msbls.de</a>'><span class="otto">Otto</span> — mai-otto.de — ein Projekt von <a href="https://msbls.de" style="color:var(--text-muted);text-decoration:none;">msbls.de</a></p>
<button data-i18n-toggle style="background:none;border:1px solid var(--border);color:var(--text-muted);font-family:'Space Grotesk',sans-serif;font-size:0.65rem;letter-spacing:0.1em;padding:4px 12px;border-radius:4px;cursor:pointer;margin-top:12px;transition:color 0.2s,border-color 0.2s;" onmouseover="this.style.color='var(--text)';this.style.borderColor='var(--text-muted)'" onmouseout="this.style.color='var(--text-muted)';this.style.borderColor='var(--border)'">EN</button>
</div> </div>
</footer> </footer>
<script src="/shared/i18n.js"></script>
</body> </body>
</html> </html>