ML/AI engineer portfolio website, built by Claude Opus 5.5
Hostedvia Claude CodeOpenRouter
Show the code the model wroteHide the code
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Mira Kovač — Machine Learning Engineer</title>
<meta name="description" content="Mira Kovač, Senior Machine Learning Engineer in Berlin. Ranking, forecasting and fraud models in production since 2017.">
<meta name="color-scheme" content="dark">
<meta name="theme-color" content="#0a0c0b">
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Crect width='16' height='16' fill='%230a0c0b'/%3E%3Crect x='5' y='3' width='6' height='10' fill='%234cf08f'/%3E%3C/svg%3E">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500&display=swap">
<style>
/* One green, one family, one 8px rhythm. Every vertical gap is a multiple of --u. */
:root {
--bg: #0a0c0b;
--fg-strong: #e9eee9;
--fg: #bcc5be;
--muted: #7f8981;
--rule: #1d221f;
--rule-strong: #2c3430;
--green: #4cf08f;
--u: 8px;
--lh: 24px;
--gutter: 32px;
--key: 112px; /* left key column: years, project names */
--gap: 48px; /* key column → content column */
--section: calc(var(--u) * 10);
--font: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
color-scheme: dark;
}
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
body {
margin: 0;
background: var(--bg);
color: var(--fg);
font: 400 15px/var(--lh) var(--font);
font-variant-ligatures: none;
-webkit-font-smoothing: antialiased;
}
h1, h2, h3, p, ul, ol { margin: 0; padding: 0; }
ul, ol { list-style: none; }
::selection { background: var(--green); color: var(--bg); }
a {
color: var(--fg-strong);
text-decoration: underline;
text-decoration-color: var(--rule-strong);
text-decoration-thickness: 1px;
text-underline-offset: 4px;
transition: color .15s, text-decoration-color .15s;
}
a:hover { color: var(--green); text-decoration-color: currentColor; }
a:focus-visible, button:focus-visible { outline: 1px solid var(--green); outline-offset: 4px; }
.page {
max-width: calc(736px + 2 * var(--gutter));
margin: 0 auto;
padding: calc(var(--u) * 12) var(--gutter) calc(var(--u) * 6);
}
.small { font-size: 13px; }
.muted { color: var(--muted); }
.accent { color: var(--green); }
/* ---- intro ---- */
.prompt { font-size: 13px; color: var(--muted); }
h1 {
margin-top: var(--u);
font-size: 32px;
line-height: 40px;
font-weight: 500;
letter-spacing: -0.01em;
color: var(--fg-strong);
}
.cursor {
display: inline-block;
width: 0.5em;
height: 0.8em;
margin-left: 0.15em;
vertical-align: -0.04em;
background: var(--green);
animation: blink 1.1s steps(1) infinite;
}
@keyframes blink { 50% { opacity: 0; } }
.headline { margin-top: var(--u); color: var(--fg-strong); }
.summary { margin-top: calc(var(--u) * 3); max-width: 62ch; }
.contact {
margin-top: calc(var(--u) * 4);
display: flex;
flex-wrap: wrap;
gap: var(--u) calc(var(--u) * 4);
font-size: 13px;
}
.contact .k { color: var(--muted); margin-right: var(--u); }
/* ---- sections ---- */
section { margin-top: var(--section); }
.section-title {
display: flex;
align-items: center;
gap: calc(var(--u) * 2);
margin-bottom: calc(var(--u) * 4);
font-size: 13px;
font-weight: 400;
color: var(--muted);
}
.section-title .accent { font-weight: 500; }
.section-title::after {
content: "";
flex: 1;
height: 1px;
background: var(--rule);
}
.indent { padding-left: calc(var(--key) + var(--gap)); }
/* ---- timeline ---- */
.role {
position: relative;
display: grid;
grid-template-columns: var(--key) 1fr;
column-gap: var(--gap);
padding-bottom: calc(var(--u) * 6);
--rail: calc(var(--key) + var(--gap) / 2);
}
.role::before { /* rail */
content: "";
position: absolute;
left: var(--rail);
top: 0;
bottom: 0;
width: 1px;
background: var(--rule-strong);
}
.role:first-child::before { top: 12px; }
.role:last-child { padding-bottom: 0; }
.role:last-child::before { background: linear-gradient(var(--rule-strong) 60%, transparent); }
.role::after { /* node */
content: "";
position: absolute;
left: calc(var(--rail) - 4px);
top: 8px;
width: 9px;
height: 9px;
border: 1px solid var(--green);
background: var(--bg);
}
.role.is-current::after { background: var(--green); }
.when {
display: flex;
flex-direction: column;
align-items: flex-end;
}
.when .start { color: var(--green); font-weight: 500; }
.when .end { font-size: 13px; color: var(--muted); }
.role h3 { font-size: 15px; font-weight: 500; color: var(--fg-strong); }
.org { font-size: 13px; color: var(--muted); }
.org .co { color: var(--fg); }
.bullets { margin-top: calc(var(--u) * 2); display: grid; gap: var(--u); }
.bullets li { position: relative; padding-left: calc(var(--u) * 3); }
.bullets li::before { content: "–"; position: absolute; left: 0; color: var(--muted); }
/* ---- skills ---- */
.chips { display: flex; flex-wrap: wrap; gap: var(--u); }
.chips li {
padding: 3px calc(var(--u) * 1.5);
border: 1px solid var(--rule-strong);
font-size: 13px;
color: var(--fg);
}
/* ---- key / value entries (projects, publication) ---- */
.entries { display: grid; gap: calc(var(--u) * 3); }
.entry {
display: grid;
grid-template-columns: var(--key) 1fr;
column-gap: var(--gap);
}
.entry .key { text-align: right; }
.entry .title { color: var(--fg-strong); }
.entry .meta { font-size: 13px; color: var(--muted); }
.entry .meta b { font-weight: 500; color: var(--fg); }
/* ---- footer ---- */
footer {
margin-top: var(--section);
padding-top: calc(var(--u) * 3);
border-top: 1px solid var(--rule);
display: flex;
flex-wrap: wrap;
justify-content: space-between;
gap: var(--u) calc(var(--u) * 4);
font-size: 13px;
color: var(--muted);
}
.linkish {
font: inherit;
color: var(--muted);
background: none;
border: 0;
padding: 0;
cursor: pointer;
transition: color .15s;
}
.linkish:hover { color: var(--green); }
/* ---- phone ---- */
@media (max-width: 720px) {
:root { --gutter: 16px; --section: calc(var(--u) * 7); }
.page { padding-top: calc(var(--u) * 6); }
.indent { padding-left: 0; }
.headline .sep { display: none; }
.headline .loc { display: block; color: var(--muted); }
.role { grid-template-columns: 1fr; padding-left: calc(var(--u) * 3); --rail: 0px; }
.when { flex-direction: row; align-items: baseline; gap: var(--u); }
.entry { grid-template-columns: 1fr; }
.entry .key { text-align: left; }
}
@media (prefers-reduced-motion: reduce) {
.cursor { animation: none; }
a, .linkish { transition: none; }
}
@media print {
:root {
--bg: #fff; --fg: #222; --fg-strong: #000; --muted: #555;
--rule: #ccc; --rule-strong: #bbb; --green: #0b7a3e;
--section: calc(var(--u) * 4);
}
@page { margin: 16mm; }
.page { max-width: none; padding: 0; }
.cursor, .no-print { display: none; }
a { text-decoration: none; }
.role, .entry { break-inside: avoid; }
}
</style>
</head>
<body>
<div class="page">
<header>
<p class="prompt"><span class="accent">$</span> whoami</p>
<h1>Mira Kovač<span class="cursor" aria-hidden="true"></span></h1>
<p class="headline">Senior Machine Learning Engineer<span class="sep"> · </span><span class="loc">Berlin</span></p>
<p class="summary">
Nine years taking ranking, forecasting and fraud models from notebook to production.
I care most about the unglamorous middle: offline evaluation you can trust,
latency budgets, and monitoring that pages the right person.
</p>
<ul class="contact" aria-label="Contact">
<li><span class="k">mail</span><a href="mailto:hello@mirakovac.dev">hello@mirakovac.dev</a></li>
<li><span class="k">github</span><a href="https://github.com/mirakovac">mirakovac</a></li>
<li><span class="k">linkedin</span><a href="https://www.linkedin.com/in/mirakovac">in/mirakovac</a></li>
<li><span class="k">tz</span>CET (UTC+1)</li>
</ul>
</header>
<main>
<section aria-labelledby="experience">
<h2 class="section-title" id="experience"><span class="accent">01</span>experience</h2>
<ol class="timeline">
<li class="role is-current">
<p class="when"><span class="start">2022</span><span class="end">→ now</span></p>
<div>
<h3>Senior Machine Learning Engineer</h3>
<p class="org"><span class="co">Zalando</span> · Search & Browse Ranking</p>
<ul class="bullets">
<li>Tech lead for catalog browse ranking: replaced a GBDT ranker with two-tower retrieval and a transformer re-ranker, +2.8% CTR and +1.1% revenue per session in a six-week A/B test across six markets.</li>
<li>Distilled the re-ranker into a 4-layer student served on CPU via ONNX Runtime — p99 latency from 140 ms to 38 ms and roughly €400k a year less GPU spend.</li>
<li>Built an IPS-weighted counterfactual replay harness on logged impressions; it now gates ranking releases for five teams.</li>
</ul>
</div>
</li>
<li class="role">
<p class="when"><span class="start">2019</span><span class="end">→ 2022</span></p>
<div>
<h3>Machine Learning Engineer</h3>
<p class="org"><span class="co">Delivery Hero</span> · Logistics</p>
<ul class="bullets">
<li>Owned delivery-time (ETA) prediction for 11 markets — quantile LightGBM over ~40M orders a month; cut MAE by 17% and late-delivery complaints by 9%.</li>
<li>Stood up a Feast + Redis feature store with point-in-time joins, taking feature-to-production time from about three weeks to four days.</li>
<li>Added PSI-based drift monitoring with retraining triggers; it caught a rider-app logging regression before it reached live forecasts.</li>
</ul>
</div>
</li>
<li class="role">
<p class="when"><span class="start">2017</span><span class="end">→ 2019</span></p>
<div>
<h3>Data Scientist</h3>
<p class="org"><span class="co">N26</span> · Financial Crime</p>
<ul class="bullets">
<li>Built the real-time card-fraud scorer — XGBoost on Kafka streaming features, p99 under 50 ms — lifting recall at a fixed 0.1% false-positive rate from 61% to 74%.</li>
<li>Wrote the model documentation and validation pack for BaFin review; it became the template for every risk model that followed.</li>
</ul>
</div>
</li>
</ol>
</section>
<section aria-labelledby="skills">
<h2 class="section-title" id="skills"><span class="accent">02</span>skills</h2>
<ul class="chips indent">
<li>Python</li>
<li>PyTorch</li>
<li>LightGBM / XGBoost</li>
<li>Learning to rank</li>
<li>Spark</li>
<li>Kubernetes</li>
<li>ONNX Runtime</li>
<li>Experimentation</li>
</ul>
</section>
<section aria-labelledby="projects">
<h2 class="section-title" id="projects"><span class="accent">03</span>projects</h2>
<ul class="entries">
<li class="entry">
<a class="key" href="https://github.com/mirakovac/tinyrank">tinyrank</a>
<p>Learning-to-rank losses (LambdaRank, ListNet, ApproxNDCG) in ~600 lines of PyTorch, tested against reference NDCG@k.</p>
</li>
<li class="entry">
<a class="key" href="https://github.com/mirakovac/driftwatch">driftwatch</a>
<p>CLI that diffs two Parquet snapshots and flags feature drift (PSI, KS) — drops into any CI pipeline.</p>
</li>
<li class="entry">
<a class="key" href="https://github.com/mirakovac/ubahn-eta">ubahn-eta</a>
<p>Quantile forecasts of Berlin U-Bahn delays from the VBB GTFS-realtime feed, with a live calibration plot.</p>
</li>
</ul>
</section>
<section aria-labelledby="publication">
<h2 class="section-title" id="publication"><span class="accent">04</span>publication</h2>
<ul class="entries">
<li class="entry">
<p class="key accent">2023</p>
<div>
<p class="title">Counterfactual Evaluation of Neural Re-rankers under Position Bias at Catalog Scale</p>
<p class="meta"><b>M. Kovač</b>, J. Brandt, T. Okafor · RecSys ’23, Industry Track · Singapore</p>
</div>
</li>
</ul>
</section>
</main>
<footer>
<p>© 2026 Mira Kovač</p>
<button class="linkish no-print" type="button" onclick="window.print()">$ print --pdf</button>
</footer>
</div>
</body>
</html>Same prompt, other models
One email when a new model lands on the board or in the showcase. Unsubscribe anytime.