mirror of
https://github.com/AmanTahiliani/box-box.git
synced 2026-08-07 11:54:59 -04:00
848 lines
38 KiB
HTML
848 lines
38 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>box-box — Race Hub · Monaco GP 2025</title>
|
||
<link rel="stylesheet" href="styles.css">
|
||
<style>
|
||
/* ── Race Hub sub-header ── */
|
||
.rh-header {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--s4);
|
||
padding: var(--s3) var(--s5);
|
||
background: var(--c-surface);
|
||
border-bottom: 1px solid var(--c-border);
|
||
flex-wrap: wrap;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.rh-breadcrumb {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--s2);
|
||
font-size: 12px;
|
||
}
|
||
|
||
.rh-breadcrumb a { color: var(--c-text-3); }
|
||
.rh-breadcrumb a:hover { color: var(--c-text-2); }
|
||
.rh-breadcrumb .sep { color: var(--c-text-3); }
|
||
.rh-breadcrumb .cur { font-weight: 600; color: var(--c-text); }
|
||
|
||
.rh-session-btns {
|
||
display: flex;
|
||
gap: 2px;
|
||
margin-left: auto;
|
||
}
|
||
|
||
.rh-session-btn {
|
||
padding: 3px 8px;
|
||
background: none;
|
||
border: 1px solid var(--c-border);
|
||
border-radius: 2px;
|
||
font-size: 10px;
|
||
font-weight: 600;
|
||
letter-spacing: 0.05em;
|
||
color: var(--c-text-3);
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
.rh-session-btn.active {
|
||
background: var(--c-surface-2);
|
||
border-color: var(--c-border-2);
|
||
color: var(--c-text);
|
||
}
|
||
|
||
/* ── Section tabs (in rh-main) ── */
|
||
.rh-section-tabs {
|
||
display: flex;
|
||
gap: 2px;
|
||
padding: var(--s3) var(--s5);
|
||
border-bottom: 1px solid var(--c-border);
|
||
overflow-x: auto;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
/* ── Main content area ── */
|
||
.rh-content {
|
||
padding: var(--s5);
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: var(--sec-gap);
|
||
max-width: 860px;
|
||
}
|
||
|
||
/* ── Classification ── */
|
||
.result-pos { font-family: var(--f-mono); font-size: 14px; font-weight: 700; text-align: center; width: 28px; }
|
||
|
||
/* ── Strategy ── */
|
||
#strategy-chart { width: 100%; min-height: 320px; }
|
||
|
||
.compound-legend {
|
||
display: flex;
|
||
gap: var(--s4);
|
||
margin-top: var(--s3);
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.legend-item { display: flex; align-items: center; gap: 6px; font-size: 11px; color: var(--c-text-3); }
|
||
.legend-dot { width: 12px; height: 12px; border-radius: 50%; flex-shrink: 0; }
|
||
|
||
/* ── Position Evolution ── */
|
||
#position-chart { width: 100%; }
|
||
|
||
/* ── Race Control ── */
|
||
.rc-event {
|
||
display: grid;
|
||
grid-template-columns: 52px 90px 1fr;
|
||
gap: var(--s3);
|
||
padding: 7px 0;
|
||
border-bottom: 1px solid var(--c-border);
|
||
font-size: 11px;
|
||
align-items: baseline;
|
||
}
|
||
|
||
.rc-event:last-child { border-bottom: none; }
|
||
|
||
.rc-event-lap { font-family: var(--f-mono); font-weight: 600; color: var(--c-text-3); }
|
||
.rc-event-type { font-size: 10px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; }
|
||
.rc-event-msg { color: var(--c-text-2); line-height: 1.4; }
|
||
|
||
.rc-event.sc .rc-event-type { color: var(--c-yellow); }
|
||
.rc-event.vsc .rc-event-type { color: var(--c-yellow); }
|
||
.rc-event.drs .rc-event-type { color: var(--c-green); }
|
||
.rc-event.flag .rc-event-type { color: var(--c-red); }
|
||
.rc-event.fl .rc-event-type { color: var(--c-purple); }
|
||
.rc-event.info .rc-event-type { color: var(--c-text-3); }
|
||
|
||
/* ── Weather ── */
|
||
.wx-row {
|
||
display: grid;
|
||
grid-template-columns: 50px repeat(6, 1fr);
|
||
gap: var(--s3);
|
||
padding: 5px 0;
|
||
border-bottom: 1px solid var(--c-border);
|
||
font-size: 11px;
|
||
font-family: var(--f-mono);
|
||
align-items: center;
|
||
}
|
||
|
||
.wx-row:last-child { border-bottom: none; }
|
||
|
||
.wx-hdr {
|
||
font-family: var(--f-ui);
|
||
font-size: 10px;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.07em;
|
||
color: var(--c-text-3);
|
||
}
|
||
|
||
/* ── Dataset ── */
|
||
.ds-grid-main {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
|
||
gap: 1px;
|
||
border: 1px solid var(--c-border);
|
||
margin-bottom: var(--s4);
|
||
}
|
||
|
||
.ds-cell {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--s2);
|
||
padding: var(--s3) var(--s4);
|
||
background: var(--c-surface);
|
||
font-size: 11px;
|
||
}
|
||
|
||
.ds-cell-name { flex: 1; color: var(--c-text-2); }
|
||
.ds-cell-time { font-family: var(--f-mono); font-size: 10px; color: var(--c-text-3); }
|
||
|
||
/* ── Aside: condensed RC ── */
|
||
.rc-condensed { display: flex; flex-direction: column; }
|
||
|
||
.rc-cond-row {
|
||
display: grid;
|
||
grid-template-columns: 44px 1fr;
|
||
gap: var(--s2);
|
||
padding: 5px 0;
|
||
border-bottom: 1px solid var(--c-border);
|
||
font-size: 11px;
|
||
}
|
||
|
||
.rc-cond-row:last-child { border-bottom: none; }
|
||
|
||
.rc-cond-lap { font-family: var(--f-mono); color: var(--c-text-3); font-size: 10px; }
|
||
.rc-cond-msg { color: var(--c-text-2); line-height: 1.4; }
|
||
.rc-cond-row.sc .rc-cond-msg { color: var(--c-yellow); }
|
||
.rc-cond-row.vsc .rc-cond-msg { color: var(--c-yellow); }
|
||
.rc-cond-row.drs .rc-cond-msg { color: var(--c-green); }
|
||
.rc-cond-row.fl .rc-cond-msg { color: var(--c-purple); }
|
||
.rc-cond-row.flag .rc-cond-msg { color: var(--c-red); }
|
||
|
||
/* ── Aside: dataset mini ── */
|
||
.ds-mini { display: flex; flex-direction: column; gap: 3px; }
|
||
|
||
.ds-mini-row {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--s2);
|
||
font-size: 10px;
|
||
font-family: var(--f-mono);
|
||
color: var(--c-text-3);
|
||
}
|
||
|
||
.ds-mini-row .dot { flex-shrink: 0; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<nav class="app-nav">
|
||
<a href="index.html" class="nav-logo">box<em>-</em>box</a>
|
||
<div class="nav-links">
|
||
<a href="command-center.html">Command Center</a>
|
||
<a href="live-timing.html">Live</a>
|
||
<a href="race-hub.html" class="active">Race Hub</a>
|
||
<a href="data-library.html">Data Library</a>
|
||
</div>
|
||
<div class="nav-right">
|
||
<div class="density-toggle">
|
||
<button class="active" onclick="setDensity('default',this)">D</button>
|
||
<button onclick="setDensity('compact',this)">C</button>
|
||
</div>
|
||
</div>
|
||
</nav>
|
||
|
||
<!-- Sub-header -->
|
||
<div class="rh-header">
|
||
<div class="rh-breadcrumb">
|
||
<a href="command-center.html">2025</a>
|
||
<span class="sep">›</span>
|
||
<a href="#">Monaco GP</a>
|
||
<span class="sep">›</span>
|
||
<span class="cur">Race</span>
|
||
</div>
|
||
<div style="display:flex;align-items:center;gap:var(--s3);font-size:12px">
|
||
<span class="t3 mono">78 Laps · 260.286 km · 25 May 2025</span>
|
||
<span class="badge local">Local data</span>
|
||
</div>
|
||
<div class="rh-session-btns">
|
||
<button class="rh-session-btn">FP1</button>
|
||
<button class="rh-session-btn">FP2</button>
|
||
<button class="rh-session-btn">FP3</button>
|
||
<button class="rh-session-btn">Qual</button>
|
||
<button class="rh-session-btn active">Race</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── 2-column body ── -->
|
||
<div class="rh-body">
|
||
|
||
<!-- Left: tabbed content -->
|
||
<div style="display:flex;flex-direction:column;overflow:hidden">
|
||
|
||
<!-- Section tabs -->
|
||
<div class="rh-section-tabs">
|
||
<button class="tab-btn active" onclick="showTab('classification',this)">Classification</button>
|
||
<button class="tab-btn" onclick="showTab('strategy',this)">Strategy</button>
|
||
<button class="tab-btn" onclick="showTab('positions',this)">Positions</button>
|
||
<button class="tab-btn" onclick="showTab('racecontrol',this)">Race Control</button>
|
||
<button class="tab-btn" onclick="showTab('weather',this)">Weather</button>
|
||
<button class="tab-btn" onclick="showTab('dataset',this)">Dataset</button>
|
||
</div>
|
||
|
||
<!-- Tab panels -->
|
||
<div class="rh-content">
|
||
|
||
<!-- CLASSIFICATION -->
|
||
<div id="tab-classification" class="tab-panel active">
|
||
<div class="sec-header">
|
||
<span class="sec-title">Final Classification</span>
|
||
<span class="sec-meta">78 laps · 1:32:14.456</span>
|
||
</div>
|
||
<div class="scroll-x">
|
||
<table class="data-table" style="min-width:620px">
|
||
<thead>
|
||
<tr>
|
||
<th class="center" style="width:28px">P</th>
|
||
<th>Driver</th>
|
||
<th>Team</th>
|
||
<th class="center">Grid</th>
|
||
<th class="center">Δ</th>
|
||
<th class="num">Time / Gap</th>
|
||
<th class="num">Fastest Lap</th>
|
||
<th class="num">Pts</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td class="center"><span class="pos-p1">1</span></td>
|
||
<td>
|
||
<div class="drv-cell">
|
||
<div class="drv-bar" style="background:var(--t-fer)"></div>
|
||
<span class="drv-code">LEC</span><span class="drv-num">16</span>
|
||
</div>
|
||
</td>
|
||
<td class="t2">Ferrari</td>
|
||
<td class="center t3 mono">3</td>
|
||
<td class="center"><span class="pos-gain">↑2</span></td>
|
||
<td class="num mono">1:32:14.456</td>
|
||
<td class="num mono t3">1:14.892</td>
|
||
<td class="num" style="font-weight:700">25</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="center"><span class="pos-p2">2</span></td>
|
||
<td>
|
||
<div class="drv-cell">
|
||
<div class="drv-bar" style="background:var(--t-rb)"></div>
|
||
<span class="drv-code">VER</span><span class="drv-num">1</span>
|
||
</div>
|
||
</td>
|
||
<td class="t2">Red Bull</td>
|
||
<td class="center t3 mono">1</td>
|
||
<td class="center"><span class="pos-loss">↓1</span></td>
|
||
<td class="num mono t2">+3.456</td>
|
||
<td class="num mono t3">1:15.023</td>
|
||
<td class="num" style="font-weight:700">18</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="center"><span class="pos-p3">3</span></td>
|
||
<td>
|
||
<div class="drv-cell">
|
||
<div class="drv-bar" style="background:var(--t-mcl)"></div>
|
||
<span class="drv-code">NOR</span><span class="drv-num">4</span>
|
||
</div>
|
||
</td>
|
||
<td class="t2">McLaren</td>
|
||
<td class="center t3 mono">4</td>
|
||
<td class="center"><span class="pos-gain">↑1</span></td>
|
||
<td class="num mono t2">+8.123</td>
|
||
<td class="num mono" style="color:var(--c-purple)">1:14.756 ●</td>
|
||
<td class="num" style="font-weight:700">15</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="center t3 mono">4</td>
|
||
<td>
|
||
<div class="drv-cell">
|
||
<div class="drv-bar" style="background:var(--t-mcl)"></div>
|
||
<span class="drv-code">PIA</span><span class="drv-num">81</span>
|
||
</div>
|
||
</td>
|
||
<td class="t2">McLaren</td>
|
||
<td class="center t3 mono">6</td>
|
||
<td class="center"><span class="pos-gain">↑2</span></td>
|
||
<td class="num mono t2">+12.345</td>
|
||
<td class="num mono t3">1:15.234</td>
|
||
<td class="num t2">12</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="center t3 mono">5</td>
|
||
<td>
|
||
<div class="drv-cell">
|
||
<div class="drv-bar" style="background:var(--t-mer)"></div>
|
||
<span class="drv-code">RUS</span><span class="drv-num">63</span>
|
||
</div>
|
||
</td>
|
||
<td class="t2">Mercedes</td>
|
||
<td class="center t3 mono">2</td>
|
||
<td class="center"><span class="pos-loss">↓3</span></td>
|
||
<td class="num mono t2">+15.678</td>
|
||
<td class="num mono t3">1:15.456</td>
|
||
<td class="num t2">10</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="center t3 mono">6</td>
|
||
<td>
|
||
<div class="drv-cell">
|
||
<div class="drv-bar" style="background:var(--t-fer)"></div>
|
||
<span class="drv-code">HAM</span><span class="drv-num">44</span>
|
||
</div>
|
||
</td>
|
||
<td class="t2">Ferrari</td>
|
||
<td class="center t3 mono">5</td>
|
||
<td class="center"><span class="pos-loss">↓1</span></td>
|
||
<td class="num mono t2">+21.234</td>
|
||
<td class="num mono t3">1:15.890</td>
|
||
<td class="num t2">8</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="center t3 mono">7</td>
|
||
<td>
|
||
<div class="drv-cell">
|
||
<div class="drv-bar" style="background:var(--t-am)"></div>
|
||
<span class="drv-code">ALO</span><span class="drv-num">14</span>
|
||
</div>
|
||
</td>
|
||
<td class="t2">Aston Martin</td>
|
||
<td class="center t3 mono">8</td>
|
||
<td class="center"><span class="pos-gain">↑1</span></td>
|
||
<td class="num mono t2">+28.456</td>
|
||
<td class="num mono t3">1:16.234</td>
|
||
<td class="num t2">6</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="center t3 mono">8</td>
|
||
<td>
|
||
<div class="drv-cell">
|
||
<div class="drv-bar" style="background:var(--t-wil)"></div>
|
||
<span class="drv-code">SAI</span><span class="drv-num">55</span>
|
||
</div>
|
||
</td>
|
||
<td class="t2">Williams</td>
|
||
<td class="center t3 mono">7</td>
|
||
<td class="center"><span class="pos-loss">↓1</span></td>
|
||
<td class="num mono t2">+35.789</td>
|
||
<td class="num mono t3">1:16.567</td>
|
||
<td class="num t2">4</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="center t3 mono">9</td>
|
||
<td>
|
||
<div class="drv-cell">
|
||
<div class="drv-bar" style="background:var(--t-alp)"></div>
|
||
<span class="drv-code t3">GAS</span><span class="drv-num">10</span>
|
||
</div>
|
||
</td>
|
||
<td class="t3">Alpine</td>
|
||
<td class="center t3 mono">9</td>
|
||
<td class="center"><span class="pos-same">—</span></td>
|
||
<td class="num mono t3">+42.123</td>
|
||
<td class="num mono t3">1:16.890</td>
|
||
<td class="num t3">2</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="center t3 mono">10</td>
|
||
<td>
|
||
<div class="drv-cell">
|
||
<div class="drv-bar" style="background:var(--t-haas)"></div>
|
||
<span class="drv-code t3">OCO</span><span class="drv-num">31</span>
|
||
</div>
|
||
</td>
|
||
<td class="t3">Haas</td>
|
||
<td class="center t3 mono">10</td>
|
||
<td class="center"><span class="pos-same">—</span></td>
|
||
<td class="num mono t3">+48.456</td>
|
||
<td class="num mono t3">1:17.012</td>
|
||
<td class="num t3">1</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- STRATEGY -->
|
||
<div id="tab-strategy" class="tab-panel">
|
||
<div class="sec-header">
|
||
<span class="sec-title">Tyre Strategy</span>
|
||
<span class="sec-meta">78 laps · SC L23–26 · VSC L58–60</span>
|
||
</div>
|
||
<div id="strategy-chart"></div>
|
||
<div class="compound-legend">
|
||
<div class="legend-item"><div class="legend-dot" style="background:var(--tyre-s)"></div>Soft</div>
|
||
<div class="legend-item"><div class="legend-dot" style="background:var(--tyre-m)"></div>Medium</div>
|
||
<div class="legend-item"><div class="legend-dot" style="background:var(--tyre-h)"></div>Hard</div>
|
||
<div class="legend-item" style="margin-left:var(--s4)">
|
||
<div style="width:14px;height:2px;background:rgba(255,214,0,0.45);border-radius:1px"></div>
|
||
<span>SC / VSC period</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- POSITIONS -->
|
||
<div id="tab-positions" class="tab-panel">
|
||
<div class="sec-header">
|
||
<span class="sec-title">Position Evolution</span>
|
||
<span class="sec-meta">Top 6 · SC L23–26 · VSC L58–60</span>
|
||
</div>
|
||
<div id="position-chart"></div>
|
||
<div class="compound-legend" style="margin-top:var(--s3)">
|
||
<div class="legend-item"><div class="legend-dot" style="background:var(--t-fer)"></div>LEC</div>
|
||
<div class="legend-item"><div class="legend-dot" style="background:var(--t-rb)"></div>VER</div>
|
||
<div class="legend-item"><div class="legend-dot" style="background:var(--t-mcl)"></div>NOR</div>
|
||
<div class="legend-item"><div class="legend-dot" style="background:var(--t-mcl);opacity:.55"></div>PIA</div>
|
||
<div class="legend-item"><div class="legend-dot" style="background:var(--t-mer)"></div>RUS</div>
|
||
<div class="legend-item"><div class="legend-dot" style="background:var(--t-mer);opacity:.55"></div>HAM</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- RACE CONTROL -->
|
||
<div id="tab-racecontrol" class="tab-panel">
|
||
<div class="sec-header">
|
||
<span class="sec-title">Race Control</span>
|
||
<span class="sec-meta">14 messages</span>
|
||
</div>
|
||
<div>
|
||
<div class="rc-event info">
|
||
<span class="rc-event-lap">L1</span>
|
||
<span class="rc-event-type">Start</span>
|
||
<span class="rc-event-msg">RACE START — Track Clear</span>
|
||
</div>
|
||
<div class="rc-event drs">
|
||
<span class="rc-event-lap">L3</span>
|
||
<span class="rc-event-type">DRS</span>
|
||
<span class="rc-event-msg">DRS ENABLED</span>
|
||
</div>
|
||
<div class="rc-event info">
|
||
<span class="rc-event-lap">L18</span>
|
||
<span class="rc-event-type">Incident</span>
|
||
<span class="rc-event-msg">ALB/STR at T10 under investigation</span>
|
||
</div>
|
||
<div class="rc-event sc">
|
||
<span class="rc-event-lap">L23</span>
|
||
<span class="rc-event-type">Safety Car</span>
|
||
<span class="rc-event-msg">SAFETY CAR DEPLOYED — Incident T10 (ALB retirement)</span>
|
||
</div>
|
||
<div class="rc-event sc">
|
||
<span class="rc-event-lap">L26</span>
|
||
<span class="rc-event-type">Safety Car</span>
|
||
<span class="rc-event-msg">SAFETY CAR IN THIS LAP</span>
|
||
</div>
|
||
<div class="rc-event drs">
|
||
<span class="rc-event-lap">L27</span>
|
||
<span class="rc-event-type">DRS</span>
|
||
<span class="rc-event-msg">DRS ENABLED — Lap 27</span>
|
||
</div>
|
||
<div class="rc-event info">
|
||
<span class="rc-event-lap">L35</span>
|
||
<span class="rc-event-type">Penalty</span>
|
||
<span class="rc-event-msg">5-SECOND PENALTY — RUS · Unsafe release pit lane</span>
|
||
</div>
|
||
<div class="rc-event fl">
|
||
<span class="rc-event-lap">L38</span>
|
||
<span class="rc-event-type">Fastest Lap</span>
|
||
<span class="rc-event-msg">NOR · 1:14.756</span>
|
||
</div>
|
||
<div class="rc-event vsc">
|
||
<span class="rc-event-lap">L58</span>
|
||
<span class="rc-event-type">VSC</span>
|
||
<span class="rc-event-msg">VIRTUAL SAFETY CAR DEPLOYED — Debris T6</span>
|
||
</div>
|
||
<div class="rc-event vsc">
|
||
<span class="rc-event-lap">L60</span>
|
||
<span class="rc-event-type">VSC</span>
|
||
<span class="rc-event-msg">VIRTUAL SAFETY CAR ENDING</span>
|
||
</div>
|
||
<div class="rc-event drs">
|
||
<span class="rc-event-lap">L61</span>
|
||
<span class="rc-event-type">DRS</span>
|
||
<span class="rc-event-msg">DRS ENABLED — Lap 61</span>
|
||
</div>
|
||
<div class="rc-event flag">
|
||
<span class="rc-event-lap">L78</span>
|
||
<span class="rc-event-type">Finish</span>
|
||
<span class="rc-event-msg">CHEQUERED FLAG — Race complete</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- WEATHER -->
|
||
<div id="tab-weather" class="tab-panel">
|
||
<div class="sec-header">
|
||
<span class="sec-title">Weather</span>
|
||
<span class="sec-meta">Race · sampled every 5 laps · highlighted = SC/VSC</span>
|
||
</div>
|
||
<div class="scroll-x">
|
||
<div class="wx-row"><span class="wx-hdr">Lap</span><span class="wx-hdr">Air °C</span><span class="wx-hdr">Track °C</span><span class="wx-hdr">Humid %</span><span class="wx-hdr">Wind km/h</span><span class="wx-hdr">Dir</span><span class="wx-hdr">Rain</span></div>
|
||
<div class="wx-row"><span class="t3">1</span><span>22.4</span><span>32.1</span><span>65</span><span>6</span><span class="t3">NW</span><span class="t-green">0%</span></div>
|
||
<div class="wx-row"><span class="t3">10</span><span>23.1</span><span>34.2</span><span>63</span><span>7</span><span class="t3">NW</span><span class="t-green">0%</span></div>
|
||
<div class="wx-row"><span class="t3">20</span><span>23.8</span><span>35.6</span><span>62</span><span>6</span><span class="t3">N</span><span class="t-green">1%</span></div>
|
||
<div class="wx-row" style="background:rgba(255,214,0,0.05)"><span class="t-yellow">23</span><span>24.0</span><span>36.0</span><span>62</span><span>7</span><span class="t3">N</span><span class="t-green">1%</span></div>
|
||
<div class="wx-row"><span class="t3">30</span><span>24.3</span><span>36.8</span><span>61</span><span>8</span><span class="t3">NW</span><span class="t-green">2%</span></div>
|
||
<div class="wx-row"><span class="t3">40</span><span>24.9</span><span>37.4</span><span>60</span><span>8</span><span class="t3">NW</span><span class="t-green">2%</span></div>
|
||
<div class="wx-row"><span class="t3">50</span><span>25.2</span><span>38.1</span><span>59</span><span>9</span><span class="t3">W</span><span class="t-green">3%</span></div>
|
||
<div class="wx-row" style="background:rgba(255,214,0,0.05)"><span class="t-yellow">58</span><span>25.5</span><span>38.3</span><span>59</span><span>8</span><span class="t3">W</span><span class="t-green">3%</span></div>
|
||
<div class="wx-row"><span class="t3">70</span><span>25.8</span><span>38.6</span><span>58</span><span>7</span><span class="t3">W</span><span class="t-green">4%</span></div>
|
||
<div class="wx-row"><span class="t3">78</span><span>26.1</span><span>38.8</span><span>57</span><span>7</span><span class="t3">NW</span><span class="t-green">4%</span></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- DATASET -->
|
||
<div id="tab-dataset" class="tab-panel">
|
||
<div class="sec-header">
|
||
<span class="sec-title">Dataset Status</span>
|
||
<span class="sec-meta">session_key 9158 · Monaco GP Race</span>
|
||
</div>
|
||
<div class="ds-grid-main">
|
||
<div class="ds-cell"><span class="dot local"></span><span class="ds-cell-name">session_results</span><span class="ds-cell-time">3h ago</span></div>
|
||
<div class="ds-cell"><span class="dot local"></span><span class="ds-cell-name">starting_grid</span><span class="ds-cell-time">3h ago</span></div>
|
||
<div class="ds-cell"><span class="dot local"></span><span class="ds-cell-name">laps</span><span class="ds-cell-time">3h ago</span></div>
|
||
<div class="ds-cell"><span class="dot local"></span><span class="ds-cell-name">stints</span><span class="ds-cell-time">3h ago</span></div>
|
||
<div class="ds-cell"><span class="dot local"></span><span class="ds-cell-name">pit_stops</span><span class="ds-cell-time">3h ago</span></div>
|
||
<div class="ds-cell"><span class="dot local"></span><span class="ds-cell-name">positions</span><span class="ds-cell-time">3h ago</span></div>
|
||
<div class="ds-cell"><span class="dot local"></span><span class="ds-cell-name">race_control</span><span class="ds-cell-time">3h ago</span></div>
|
||
<div class="ds-cell"><span class="dot local"></span><span class="ds-cell-name">weather</span><span class="ds-cell-time">3h ago</span></div>
|
||
<div class="ds-cell"><span class="dot local"></span><span class="ds-cell-name">overtakes</span><span class="ds-cell-time">3h ago</span></div>
|
||
<div class="ds-cell"><span class="dot local"></span><span class="ds-cell-name">track_outline</span><span class="ds-cell-time">cached</span></div>
|
||
<div class="ds-cell"><span class="dot missing"></span><span class="ds-cell-name">car_data_samples</span><span class="ds-cell-time t3">not ingested</span></div>
|
||
<div class="ds-cell"><span class="dot missing"></span><span class="ds-cell-name">location_samples</span><span class="ds-cell-time t3">not ingested</span></div>
|
||
<div class="ds-cell"><span class="dot missing"></span><span class="ds-cell-name">team_radio</span><span class="ds-cell-time t3">not ingested</span></div>
|
||
</div>
|
||
<div class="cli-block">
|
||
<div class="comment"># Ingest telemetry (high-volume, explicit only)</div>
|
||
<div class="cmd">box-box --ingest-session 9158 --datasets car_data,location</div>
|
||
<br>
|
||
<div class="comment"># Refresh all datasets for this session</div>
|
||
<div class="cmd">box-box --ingest-session 9158 --refresh</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div><!-- /rh-content -->
|
||
</div><!-- /rh-main -->
|
||
|
||
<!-- ── Persistent right aside ── -->
|
||
<aside class="rh-aside">
|
||
|
||
<!-- Podium -->
|
||
<div>
|
||
<div class="sec-header">
|
||
<span class="sec-title">Podium</span>
|
||
</div>
|
||
<div class="podium-list">
|
||
<div class="podium-item">
|
||
<span class="podium-p pos-p1">P1</span>
|
||
<div class="drv-cell" style="gap:var(--s2)">
|
||
<div class="drv-bar" style="background:var(--t-fer);height:16px"></div>
|
||
<span class="drv-code" style="font-size:13px">LEC</span>
|
||
</div>
|
||
<span class="podium-gap-val">1:32:14.456</span>
|
||
</div>
|
||
<div class="podium-item">
|
||
<span class="podium-p pos-p2">P2</span>
|
||
<div class="drv-cell" style="gap:var(--s2)">
|
||
<div class="drv-bar" style="background:var(--t-rb);height:16px"></div>
|
||
<span class="drv-code" style="font-size:13px">VER</span>
|
||
</div>
|
||
<span class="podium-gap-val">+3.456</span>
|
||
</div>
|
||
<div class="podium-item">
|
||
<span class="podium-p pos-p3">P3</span>
|
||
<div class="drv-cell" style="gap:var(--s2)">
|
||
<div class="drv-bar" style="background:var(--t-mcl);height:16px"></div>
|
||
<span class="drv-code" style="font-size:13px">NOR</span>
|
||
</div>
|
||
<span class="podium-gap-val">+8.123</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Race Stats -->
|
||
<div>
|
||
<div class="sec-header">
|
||
<span class="sec-title">Race Stats</span>
|
||
</div>
|
||
<div>
|
||
<div class="summary-stat-row">
|
||
<span class="sstat-label">Fastest Lap</span>
|
||
<span class="sstat-val" style="color:var(--c-purple)">NOR 1:14.756 L38</span>
|
||
</div>
|
||
<div class="summary-stat-row">
|
||
<span class="sstat-label">Pole Position</span>
|
||
<span class="sstat-val">VER</span>
|
||
</div>
|
||
<div class="summary-stat-row">
|
||
<span class="sstat-label">Safety Car</span>
|
||
<span class="sstat-val t-yellow">L23–26 (4 laps)</span>
|
||
</div>
|
||
<div class="summary-stat-row">
|
||
<span class="sstat-label">VSC</span>
|
||
<span class="sstat-val t-yellow">L58–60 (3 laps)</span>
|
||
</div>
|
||
<div class="summary-stat-row">
|
||
<span class="sstat-label">Total Pit Stops</span>
|
||
<span class="sstat-val">22</span>
|
||
</div>
|
||
<div class="summary-stat-row">
|
||
<span class="sstat-label">DNF</span>
|
||
<span class="sstat-val">ALB (T10 crash)</span>
|
||
</div>
|
||
<div class="summary-stat-row">
|
||
<span class="sstat-label">Penalties</span>
|
||
<span class="sstat-val">RUS +5s</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Condensed RC -->
|
||
<div>
|
||
<div class="sec-header">
|
||
<span class="sec-title">Key Events</span>
|
||
</div>
|
||
<div class="rc-condensed">
|
||
<div class="rc-cond-row flag">
|
||
<span class="rc-cond-lap">L78</span>
|
||
<span class="rc-cond-msg">Chequered flag</span>
|
||
</div>
|
||
<div class="rc-cond-row drs">
|
||
<span class="rc-cond-lap">L61</span>
|
||
<span class="rc-cond-msg">DRS enabled</span>
|
||
</div>
|
||
<div class="rc-cond-row vsc">
|
||
<span class="rc-cond-lap">L58–60</span>
|
||
<span class="rc-cond-msg">VSC — debris T6</span>
|
||
</div>
|
||
<div class="rc-cond-row fl">
|
||
<span class="rc-cond-lap">L38</span>
|
||
<span class="rc-cond-msg">FL: NOR 1:14.756</span>
|
||
</div>
|
||
<div class="rc-cond-row drs">
|
||
<span class="rc-cond-lap">L27</span>
|
||
<span class="rc-cond-msg">DRS enabled</span>
|
||
</div>
|
||
<div class="rc-cond-row sc">
|
||
<span class="rc-cond-lap">L23–26</span>
|
||
<span class="rc-cond-msg">SC — ALB retirement T10</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Dataset mini -->
|
||
<div>
|
||
<div class="sec-header">
|
||
<span class="sec-title">Data</span>
|
||
<span class="t3" style="font-size:10px;margin-left:auto">10/13 datasets</span>
|
||
</div>
|
||
<div class="ds-mini">
|
||
<div class="ds-mini-row"><span class="dot local"></span>session_results · laps · stints</div>
|
||
<div class="ds-mini-row"><span class="dot local"></span>pit_stops · positions · race_control</div>
|
||
<div class="ds-mini-row"><span class="dot local"></span>weather · overtakes · track_outline</div>
|
||
<div class="ds-mini-row"><span class="dot missing"></span>car_data · location · team_radio</div>
|
||
</div>
|
||
</div>
|
||
|
||
</aside><!-- /rh-aside -->
|
||
|
||
</div><!-- /rh-body -->
|
||
|
||
<script>
|
||
function setDensity(mode, btn) {
|
||
document.querySelectorAll('.density-toggle button').forEach(b => b.classList.remove('active'));
|
||
btn.classList.add('active');
|
||
document.documentElement.classList.toggle('compact', mode === 'compact');
|
||
renderCharts();
|
||
}
|
||
|
||
function showTab(id, btn) {
|
||
document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
|
||
document.querySelectorAll('.tab-panel').forEach(p => p.classList.remove('active'));
|
||
btn.classList.add('active');
|
||
document.getElementById('tab-' + id).classList.add('active');
|
||
if (id === 'strategy' || id === 'positions') renderCharts();
|
||
}
|
||
|
||
/* ── Strategy Chart ── */
|
||
function renderStrategyChart() {
|
||
const el = document.getElementById('strategy-chart');
|
||
if (!el) return;
|
||
|
||
const TOTAL = 78;
|
||
const compounds = {
|
||
S: { fill: '#e8002d', text: '#fff' },
|
||
M: { fill: '#c8b400', text: '#000' },
|
||
H: { fill: '#909090', text: '#fff' }
|
||
};
|
||
|
||
const drivers = [
|
||
{ code: 'LEC', color: '#e8002d', stints: [{c:'S',s:1,e:20},{c:'M',s:21,e:55},{c:'H',s:56,e:78}] },
|
||
{ code: 'VER', color: '#3671c6', stints: [{c:'M',s:1,e:28},{c:'H',s:29,e:60},{c:'M',s:61,e:78}] },
|
||
{ code: 'NOR', color: '#ff8000', stints: [{c:'S',s:1,e:18},{c:'M',s:19,e:52},{c:'H',s:53,e:78}] },
|
||
{ code: 'PIA', color: '#cc6600', stints: [{c:'S',s:1,e:22},{c:'M',s:23,e:50},{c:'H',s:51,e:78}] },
|
||
{ code: 'RUS', color: '#27f4d2', stints: [{c:'M',s:1,e:30},{c:'H',s:31,e:62},{c:'S',s:63,e:78}] },
|
||
{ code: 'HAM', color: '#1abfa8', stints: [{c:'S',s:1,e:15},{c:'M',s:16,e:55},{c:'H',s:56,e:78}] },
|
||
{ code: 'ALO', color: '#229971', stints: [{c:'M',s:1,e:35},{c:'H',s:36,e:78}] },
|
||
{ code: 'SAI', color: '#64c4ff', stints: [{c:'S',s:1,e:20},{c:'M',s:21,e:58},{c:'S',s:59,e:78}] },
|
||
{ code: 'GAS', color: '#cc6699', stints: [{c:'M',s:1,e:28},{c:'H',s:29,e:65},{c:'S',s:66,e:78}] },
|
||
{ code: 'OCO', color: '#909090', stints: [{c:'S',s:1,e:20},{c:'M',s:21,e:55},{c:'H',s:56,e:78}] },
|
||
];
|
||
|
||
const ROW_H = 26, ROW_GAP = 7, LBL = 48, PAD = 8;
|
||
const W = el.clientWidth || 720;
|
||
const CHART_W = W - LBL - PAD;
|
||
const H = drivers.length * (ROW_H + ROW_GAP) + 24;
|
||
const lx = l => LBL + ((l - 1) / TOTAL) * CHART_W;
|
||
|
||
let svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${W} ${H}" width="${W}" height="${H}">`;
|
||
|
||
svg += `<rect x="${lx(23)}" y="0" width="${lx(27)-lx(23)}" height="${drivers.length*(ROW_H+ROW_GAP)}" fill="rgba(255,214,0,0.07)"/>`;
|
||
svg += `<rect x="${lx(58)}" y="0" width="${lx(61)-lx(58)}" height="${drivers.length*(ROW_H+ROW_GAP)}" fill="rgba(255,214,0,0.05)"/>`;
|
||
|
||
[1,10,20,30,40,50,60,70,78].forEach(l => {
|
||
svg += `<text x="${lx(l)}" y="${H-4}" text-anchor="middle" font-size="9" fill="#4a4a4a" font-family="monospace">L${l}</text>`;
|
||
});
|
||
|
||
drivers.forEach((d, i) => {
|
||
const y = i * (ROW_H + ROW_GAP);
|
||
svg += `<text x="${LBL-5}" y="${y+ROW_H/2+4}" text-anchor="end" font-size="11" font-weight="700" fill="${d.color}" font-family="monospace">${d.code}</text>`;
|
||
d.stints.forEach(st => {
|
||
const x1 = lx(st.s), x2 = lx(st.e+1), w = x2 - x1 - 1;
|
||
const laps = st.e - st.s + 1, c = compounds[st.c];
|
||
svg += `<rect x="${x1}" y="${y}" width="${w}" height="${ROW_H}" fill="${c.fill}" rx="1"/>`;
|
||
if (w > 28) svg += `<text x="${x1+w/2}" y="${y+ROW_H/2+4}" text-anchor="middle" font-size="10" font-weight="700" fill="${c.text}" font-family="monospace">${st.c} ${laps}</text>`;
|
||
else if (w > 10) svg += `<text x="${x1+w/2}" y="${y+ROW_H/2+4}" text-anchor="middle" font-size="9" font-weight="700" fill="${c.text}" font-family="monospace">${st.c}</text>`;
|
||
});
|
||
});
|
||
|
||
svg += '</svg>';
|
||
el.innerHTML = svg;
|
||
}
|
||
|
||
/* ── Position Evolution ── */
|
||
function renderPositionChart() {
|
||
const el = document.getElementById('position-chart');
|
||
if (!el) return;
|
||
|
||
const W = el.clientWidth || 720, H = 200;
|
||
const PAD = { t: 12, r: 40, b: 28, l: 28 };
|
||
const CW = W - PAD.l - PAD.r, CH = H - PAD.t - PAD.b;
|
||
const LAPS = 78, POSITIONS = 8;
|
||
|
||
const xp = l => PAD.l + (l / LAPS) * CW;
|
||
const yp = p => PAD.t + ((p - 1) / (POSITIONS - 1)) * CH;
|
||
|
||
const drivers = [
|
||
{ code: 'LEC', color: '#e8002d', dash: false, pts: [{l:0,p:3},{l:2,p:1},{l:78,p:1}] },
|
||
{ code: 'VER', color: '#3671c6', dash: false, pts: [{l:0,p:1},{l:2,p:2},{l:78,p:2}] },
|
||
{ code: 'NOR', color: '#ff8000', dash: false, pts: [{l:0,p:4},{l:6,p:3},{l:78,p:3}] },
|
||
{ code: 'PIA', color: '#ff8000', dash: true, pts: [{l:0,p:6},{l:10,p:4},{l:78,p:4}] },
|
||
{ code: 'RUS', color: '#27f4d2', dash: false, pts: [{l:0,p:2},{l:2,p:5},{l:78,p:5}] },
|
||
{ code: 'HAM', color: '#27f4d2', dash: true, pts: [{l:0,p:5},{l:78,p:6}] },
|
||
];
|
||
|
||
let svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${W} ${H}" width="${W}" height="${H}">`;
|
||
|
||
svg += `<rect x="${xp(23)}" y="${PAD.t}" width="${xp(26)-xp(23)}" height="${CH}" fill="rgba(255,214,0,0.08)"/>`;
|
||
svg += `<rect x="${xp(58)}" y="${PAD.t}" width="${xp(60)-xp(58)}" height="${CH}" fill="rgba(255,214,0,0.05)"/>`;
|
||
svg += `<text x="${xp(24.5)}" y="${PAD.t+10}" text-anchor="middle" font-size="8" fill="#6a5800" font-family="sans-serif" font-weight="700">SC</text>`;
|
||
svg += `<text x="${xp(59)}" y="${PAD.t+10}" text-anchor="middle" font-size="8" fill="#6a5800" font-family="sans-serif" font-weight="700">VSC</text>`;
|
||
|
||
for (let p = 1; p <= POSITIONS; p++) {
|
||
svg += `<line x1="${PAD.l}" y1="${yp(p)}" x2="${W-PAD.r}" y2="${yp(p)}" stroke="#1e1e1e" stroke-width="1"/>`;
|
||
svg += `<text x="${PAD.l-4}" y="${yp(p)+3}" text-anchor="end" font-size="9" fill="#4a4a4a" font-family="monospace">P${p}</text>`;
|
||
}
|
||
|
||
[0,10,20,30,40,50,60,70,78].forEach(l => {
|
||
svg += `<text x="${xp(l)}" y="${H-4}" text-anchor="middle" font-size="9" fill="#4a4a4a" font-family="monospace">L${l||1}</text>`;
|
||
});
|
||
|
||
drivers.forEach(d => {
|
||
const pts = d.pts.map(p => `${xp(p.l)},${yp(p.p)}`).join(' ');
|
||
const dash = d.dash ? 'stroke-dasharray="5,3"' : '';
|
||
svg += `<polyline points="${pts}" stroke="${d.color}" stroke-width="1.5" fill="none" ${dash} stroke-opacity="0.9"/>`;
|
||
const last = d.pts[d.pts.length - 1];
|
||
svg += `<text x="${xp(last.l)+4}" y="${yp(last.p)+4}" font-size="9" fill="${d.color}" font-family="monospace" font-weight="700">${d.code}</text>`;
|
||
});
|
||
|
||
svg += '</svg>';
|
||
el.innerHTML = svg;
|
||
}
|
||
|
||
function renderCharts() {
|
||
renderStrategyChart();
|
||
renderPositionChart();
|
||
}
|
||
|
||
document.addEventListener('DOMContentLoaded', renderCharts);
|
||
window.addEventListener('resize', renderCharts);
|
||
</script>
|
||
</body>
|
||
</html>
|