gemini-3.6-flash @ medium · api
apimedium
- config
- gemini-3.6-flash-eff-medium--api--official--dev
- batch
- 2026-07-19--unified
- transport
- google-gemini-developer-api-openai-compat
- protocol
- api · metered
- served model
- gemini-3.6-flash
- captured
- Jul 18, 2026, 11:54 AM · N=4
variant
live
slot 0 · P-q · sandboxed iframe

The screenshot is the exact frozen pixels the similarity channels measured. Run live re-executes the raw output in a sandboxed iframe; its rendering depends on your browser and fonts and is not guaranteed to match the measured pixels.
similarity neighbors
nearest
claude-opus-4-7 @low · kiro0.66claude-sonnet-5 @low · CC0.66gpt-5.6-sol @low · kiro0.66gpt-5.6-terra @low · codex-oauth0.66gpt-5.6-terra @low · kiro0.66farthest
gpt-5.6-luna @high · kiro0.41gpt-5.6-luna @medium · codex-oauth0.42north-mini-code-free · api0.45minimax-m2.7 · go0.45gpt-5.5 @medium · codex-oauth0.45within session 2026-07-19--unified
similarity measures convergence within this session — not quality.
Fidelity — does the card show the right data?
- namematch
- conditionmatch
- datematch
- max tempmatchshown: 25
- min tempmatchshown: 16
- hourlymismatchcoverage 12/24 · 12 match · 1 mismatch · 11 not shown
- request sidematch0 violation(s)
extractor fidelity-extractor-v1+Berlin-2026-07-15
Source — raw model output, one byte unchanged
download card.html<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=1280, height=800, initial-scale=1.0">
<title>Weather Dashboard</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
width: 1280px;
height: 800px;
overflow: hidden;
background-color: #0b0f19;
color: #f8fafc;
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
display: flex;
align-items: center;
justify-content: center;
position: relative;
user-select: none;
}
/* Ambient Dynamic Background Glows */
.bg-glow {
position: absolute;
border-radius: 50%;
filter: blur(120px);
opacity: 0.45;
transition: all 1.2s cubic-bezier(0.16, 1, 0.3, 1);
z-index: 1;
}
.glow-1 {
width: 550px;
height: 550px;
top: -100px;
left: -50px;
background: radial-gradient(circle, #38bdf8, #0284c7);
}
.glow-2 {
width: 600px;
height: 600px;
bottom: -150px;
right: -50px;
background: radial-gradient(circle, #6366f1, #4338ca);
}
/* Main Card Shell */
.weather-card {
position: relative;
z-index: 10;
width: 1120px;
height: 680px;
background: rgba(15, 23, 42, 0.65);
backdrop-filter: blur(32px) saturate(180%);
-webkit-backdrop-filter: blur(32px) saturate(180%);
border: 1px solid rgba(255, 255, 255, 0.12);
border-radius: 36px;
box-shadow:
0 30px 60px -12px rgba(0, 0, 0, 0.5),
inset 0 1px 0 rgba(255, 255, 255, 0.15);
padding: 44px;
display: flex;
flex-direction: column;
justify-content: space-between;
box-sizing: border-box;
}
/* Header Section */
.card-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
}
.location-info h1 {
font-size: 42px;
font-weight: 700;
letter-spacing: -0.02em;
color: #ffffff;
line-height: 1.1;
display: flex;
align-items: center;
gap: 12px;
}
.location-info .coords {
margin-top: 6px;
font-size: 14px;
font-weight: 500;
color: #94a3b8;
letter-spacing: 0.03em;
text-transform: uppercase;
display: flex;
align-items: center;
gap: 8px;
}
.date-badge {
background: rgba(255, 255, 255, 0.07);
border: 1px solid rgba(255, 255, 255, 0.1);
padding: 10px 20px;
border-radius: 20px;
font-size: 15px;
font-weight: 600;
color: #e2e8f0;
backdrop-filter: blur(10px);
display: flex;
align-items: center;
gap: 10px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
.source-tag {
font-size: 11px;
padding: 3px 8px;
border-radius: 6px;
background: rgba(56, 189, 248, 0.15);
color: #38bdf8;
font-weight: 700;
letter-spacing: 0.05em;
text-transform: uppercase;
}
/* Main Hero Weather Row */
.hero-row {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 10px;
}
.hero-left {
display: flex;
align-items: center;
gap: 32px;
}
.weather-icon-wrapper {
width: 120px;
height: 120px;
display: flex;
align-items: center;
justify-content: center;
background: rgba(255, 255, 255, 0.04);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 28px;
box-shadow: inset 0 2px 4px rgba(255, 255, 255, 0.05);
}
.weather-icon-wrapper svg {
width: 80px;
height: 80px;
filter: drop-shadow(0 8px 16px rgba(0, 0, 0, 0.3));
}
.hero-temp-block {
display: flex;
flex-direction: column;
}
.condition-text {
font-size: 26px;
font-weight: 600;
color: #f1f5f9;
margin-bottom: 4px;
}
.temp-range-pills {
display: flex;
align-items: center;
gap: 16px;
}
.temp-pill {
display: flex;
align-items: baseline;
gap: 6px;
}
.temp-pill .label {
font-size: 13px;
font-weight: 600;
color: #64748b;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.temp-pill .val {
font-size: 36px;
font-weight: 800;
letter-spacing: -0.03em;
}
.temp-pill.max .val {
color: #f43f5e;
text-shadow: 0 0 20px rgba(244, 63, 94, 0.3);
}
.temp-pill.min .val {
color: #38bdf8;
text-shadow: 0 0 20px rgba(56, 189, 248, 0.3);
}
.pill-divider {
width: 1px;
height: 28px;
background: rgba(255, 255, 255, 0.12);
}
/* Key Metrics Highlights */
.metrics-group {
display: flex;
gap: 16px;
}
.metric-card {
background: rgba(255, 255, 255, 0.03);
border: 1px solid rgba(255, 255, 255, 0.06);
padding: 16px 22px;
border-radius: 20px;
min-width: 140px;
display: flex;
flex-direction: column;
gap: 6px;
}
.metric-card .title {
font-size: 12px;
font-weight: 600;
color: #94a3b8;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.metric-card .value {
font-size: 20px;
font-weight: 700;
color: #f8fafc;
}
/* Hourly Section */
.hourly-section {
background: rgba(0, 0, 0, 0.2);
border: 1px solid rgba(255, 255, 255, 0.06);
border-radius: 24px;
padding: 20px 24px 16px;
display: flex;
flex-direction: column;
gap: 12px;
}
.hourly-title-row {
display: flex;
justify-content: space-between;
align-items: center;
}
.hourly-title {
font-size: 13px;
font-weight: 700;
color: #94a3b8;
text-transform: uppercase;
letter-spacing: 0.08em;
}
/* Chart Canvas */
.chart-container {
position: relative;
width: 100%;
height: 140px;
}
.chart-svg {
width: 100%;
height: 100%;
overflow: visible;
}
/* Time Axis Scroll / Grid */
.timeline-row {
display: flex;
justify-content: space-between;
padding-top: 4px;
border-top: 1px solid rgba(255, 255, 255, 0.06);
}
.time-slot {
display: flex;
flex-direction: column;
align-items: center;
gap: 4px;
flex: 1;
}
.time-slot .time {
font-size: 11px;
font-weight: 600;
color: #64748b;
}
.time-slot .temp {
font-size: 13px;
font-weight: 700;
color: #cbd5e1;
}
.time-slot.is-peak .temp {
color: #f43f5e;
}
.time-slot.is-low .temp {
color: #38bdf8;
}
/* Error & Loading States */
.state-overlay {
position: absolute;
inset: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
padding: 40px;
z-index: 20;
background: rgba(15, 23, 42, 0.85);
backdrop-filter: blur(16px);
border-radius: 36px;
transition: opacity 0.4s ease;
}
.loader-spinner {
width: 48px;
height: 48px;
border: 4px solid rgba(255, 255, 255, 0.1);
border-left-color: #38bdf8;
border-radius: 50%;
animation: spin 1s linear infinite;
margin-bottom: 20px;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
.error-icon {
width: 64px;
height: 64px;
color: #f43f5e;
margin-bottom: 16px;
}
.error-title {
font-size: 24px;
font-weight: 700;
color: #ffffff;
margin-bottom: 8px;
}
.error-msg {
font-size: 15px;
color: #94a3b8;
max-width: 480px;
line-height: 1.5;
margin-bottom: 24px;
}
.error-details {
background: rgba(0, 0, 0, 0.3);
border: 1px solid rgba(255, 255, 255, 0.08);
padding: 12px 18px;
border-radius: 12px;
font-family: monospace;
font-size: 12px;
color: #cbd5e1;
max-width: 600px;
word-break: break-all;
}
.hidden {
display: none !important;
}
</style>
</head>
<body>
<!-- Background Ambient Glows -->
<div class="bg-glow glow-1" id="glow1"></div>
<div class="bg-glow glow-2" id="glow2"></div>
<!-- Main Card Container -->
<div class="weather-card">
<!-- State Overlays -->
<div id="loadingState" class="state-overlay">
<div class="loader-spinner"></div>
<div style="font-size: 18px; font-weight: 600; color: #e2e8f0;">Fetching Weather Insights...</div>
<div style="font-size: 13px; color: #64748b; margin-top: 6px;">Connecting to Open-Meteo endpoint</div>
</div>
<div id="errorState" class="state-overlay hidden">
<svg class="error-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z"/>
</svg>
<div class="error-title">Unable to Load Weather Data</div>
<div class="error-msg" id="errorMessage">We encountered an issue retrieving data for the requested location or date.</div>
<div class="error-details" id="errorDetails">API Request Failed</div>
</div>
<!-- Main Content Layout -->
<div class="card-header">
<div class="location-info">
<h1 id="locName">
<span>---</span>
</h1>
<div class="coords" id="locCoords">
<svg width="14" height="14" fill="currentColor" viewBox="0 0 24 24"><path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"/></svg>
<span id="coordsText">0.00° N, 0.00° E</span>
</div>
</div>
<div class="date-badge">
<svg width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>
<span id="dateDisplay">---</span>
<span class="source-tag" id="sourceTag">FORECAST</span>
</div>
</div>
<div class="hero-row">
<div class="hero-left">
<div class="weather-icon-wrapper" id="weatherIcon">
<!-- Dynamic SVG Icon inserted here -->
</div>
<div class="hero-temp-block">
<div class="condition-text" id="conditionText">Loading...</div>
<div class="temp-range-pills">
<div class="temp-pill max">
<span class="label">High</span>
<span class="val" id="maxTemp">--°</span>
</div>
<div class="pill-divider"></div>
<div class="temp-pill min">
<span class="label">Low</span>
<span class="val" id="minTemp">--°</span>
</div>
</div>
</div>
</div>
<div class="metrics-group">
<div class="metric-card">
<span class="title">24h Mean</span>
<span class="value" id="meanTemp">--°C</span>
</div>
<div class="metric-card">
<span class="title">Amplitude</span>
<span class="value" id="tempSpread">--°C</span>
</div>
<div class="metric-card">
<span class="title">Peak Temp At</span>
<span class="value" id="peakHour">--:--</span>
</div>
</div>
</div>
<div class="hourly-section">
<div class="hourly-title-row">
<span class="hourly-title">24-Hour Temperature Trajectory (°C)</span>
</div>
<!-- SVG Temperature Spline Chart -->
<div class="chart-container">
<svg class="chart-svg" id="chartSvg" viewBox="0 0 1000 140" preserveAspectRatio="none">
<!-- Definitions for chart gradients -->
<defs>
<linearGradient id="chartGradient" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="#38bdf8" stop-opacity="0.4"/>
<stop offset="100%" stop-color="#38bdf8" stop-opacity="0.0"/>
</linearGradient>
<linearGradient id="lineGradient" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stop-color="#38bdf8"/>
<stop offset="50%" stop-color="#f43f5e"/>
<stop offset="100%" stop-color="#6366f1"/>
</linearGradient>
</defs>
<path id="chartArea" fill="url(#chartGradient)" d="" />
<path id="chartLine" fill="none" stroke="url(#lineGradient)" stroke-width="3.5" stroke-linecap="round" d="" />
<g id="chartPoints"></g>
</svg>
</div>
<!-- Time Axis Bar -->
<div class="timeline-row" id="timelineRow">
<!-- Time slots dynamically generated -->
</div>
</div>
</div>
<script>
// --- Weather Codes Definition & Icons ---
const WMO_CODES = {
0: { name: 'Clear Sky', icon: 'sun', theme: ['#f59e0b', '#ef4444'] },
1: { name: 'Mainly Clear', icon: 'sun-cloud', theme: ['#38bdf8', '#f59e0b'] },
2: { name: 'Partly Cloudy', icon: 'sun-cloud', theme: ['#38bdf8', '#6366f1'] },
3: { name: 'Overcast', icon: 'cloud', theme: ['#64748b', '#475569'] },
45: { name: 'Foggy', icon: 'fog', theme: ['0x475569', '#334155'] },
48: { name: 'Depositing Rime Fog', icon: 'fog', theme: ['#475569', '#334155'] },
51: { name: 'Light Drizzle', icon: 'rain', theme: ['#0284c7', '#2563eb'] },
53: { name: 'Moderate Drizzle', icon: 'rain', theme: ['#0284c7', '#2563eb'] },
55: { name: 'Dense Drizzle', icon: 'rain', theme: ['#0284c7', '#1d4ed8'] },
56: { name: 'Freezing Drizzle', icon: 'rain-snow', theme: ['#0284c7', '#9333ea'] },
57: { name: 'Freezing Drizzle', icon: 'rain-snow', theme: ['#0284c7', '#9333ea'] },
61: { name: 'Slight Rain', icon: 'rain', theme: ['#0284c7', '#2563eb'] },
63: { name: 'Moderate Rain', icon: 'rain', theme: ['#0284c7', '#1d4ed8'] },
65: { name: 'Heavy Rain', icon: 'rain', theme: ['#0369a1', '#1e40af'] },
66: { name: 'Freezing Rain', icon: 'rain-snow', theme: ['#0284c7', '#9333ea'] },
67: { name: 'Heavy Freezing Rain', icon: 'rain-snow', theme: ['#0284c7', '#9333ea'] },
71: { name: 'Slight Snow', icon: 'snow', theme: ['#38bdf8', '#a855f7'] },
73: { name: 'Moderate Snow', icon: 'snow', theme: ['#38bdf8', '#a855f7'] },
75: { name: 'Heavy Snow', icon: 'snow', theme: ['#0284c7', '#7e22ce'] },
77: { name: 'Snow Grains', icon: 'snow', theme: ['#38bdf8', '#a855f7'] },
80: { name: 'Light Rain Showers', icon: 'rain', theme: ['#0284c7', '#2563eb'] },
81: { name: 'Moderate Rain Showers', icon: 'rain', theme: ['#0284c7', '#1d4ed8'] },
82: { name: 'Violent Rain Showers', icon: 'rain', theme: ['#0369a1', '#1e40af'] },
85: { name: 'Slight Snow Showers', icon: 'snow', theme: ['#38bdf8', '#a855f7'] },
86: { name: 'Heavy Snow Showers', icon: 'snow', theme: ['#0284c7', '#7e22ce'] },
95: { name: 'Thunderstorm', icon: 'thunder', theme: ['#7c3aed', '#db2777'] },
96: { name: 'Thunderstorm with Hail', icon: 'thunder', theme: ['#7c3aed', '#db2777'] },
99: { name: 'Heavy Thunderstorm', icon: 'thunder', theme: ['#5b21b6', '#9f1239'] }
};
function getSVGIcon(type) {
switch (type) {
case 'sun':
return `<svg viewBox="0 0 24 24" fill="none" stroke="#f59e0b" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="5" fill="#f59e0b" fill-opacity="0.2"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg>`;
case 'sun-cloud':
return `<svg viewBox="0 0 24 24" fill="none" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2v2M4.93 4.93l1.41 1.41M20 12h2M19.07 4.93l-1.41 1.41" stroke="#f59e0b"/><circle cx="12" cy="9" r="4" stroke="#f59e0b" fill="#f59e0b" fill-opacity="0.2"/><path d="M17 18a4 4 0 00-2-7.5 5 5 0 00-9.5 1.8A3.5 3.5 0 005 19h12z" stroke="#38bdf8" fill="#38bdf8" fill-opacity="0.2"/></svg>`;
case 'cloud':
return `<svg viewBox="0 0 24 24" fill="none" stroke="#94a3b8" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M17.5 19c2.5 0 4.5-2 4.5-4.5 0-2.3-1.7-4.1-3.9-4.5-.4-3.4-3.3-6-6.8-6-3 0-5.6 1.9-6.5 4.6-.4-.1-.8-.1-1.3-.1-3 0-5.5 2.5-5.5 5.5s2.5 5.5 5.5 5.5h14z" fill="#94a3b8" fill-opacity="0.15"/></svg>`;
case 'rain':
return `<svg viewBox="0 0 24 24" fill="none" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M16 13a4 4 0 00-1.8-7.5 5 5 0 00-9.5 1.8A3.5 3.5 0 004 14h12z" stroke="#38bdf8" fill="#38bdf8" fill-opacity="0.2"/><line x1="8" y1="16" x2="7" y2="20" stroke="#0284c7" stroke-width="2"/><line x1="12" y1="16" x2="11" y2="20" stroke="#0284c7" stroke-width="2"/><line x1="16" y1="16" x2="15" y2="20" stroke="#0284c7" stroke-width="2"/></svg>`;
case 'snow':
return `<svg viewBox="0 0 24 24" fill="none" stroke="#38bdf8" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M20 17.58A5 5 0 0018 8h-1.26A8 8 0 103 16.3"/><path d="M8 16h.01M8 20h.01M12 18h.01M12 22h.01M16 16h.01M16 20h.01" stroke-width="3"/></svg>`;
case 'thunder':
return `<svg viewBox="0 0 24 24" fill="none" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M19 15a4 4 0 00-2-7.5 5 5 0 00-9.5 1.8A3.5 3.5 0 004 16h12z" stroke="#94a3b8" fill="#94a3b8" fill-opacity="0.2"/><path d="M13 11l-4 6h4l-2 5 7-7h-4l2-4z" stroke="#f59e0b" fill="#f59e0b" fill-opacity="0.3" stroke-width="2"/></svg>`;
default:
return `<svg viewBox="0 0 24 24" fill="none" stroke="#94a3b8" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M17.5 19c2.5 0 4.5-2 4.5-4.5 0-2.3-1.7-4.1-3.9-4.5-.4-3.4-3.3-6-6.8-6-3 0-5.6 1.9-6.5 4.6-.4-.1-.8-.1-1.3-.1-3 0-5.5 2.5-5.5 5.5s2.5 5.5 5.5 5.5h14z"/></svg>`;
}
}
// --- Main Application Logic ---
async function init() {
const urlParams = new URLSearchParams(window.location.search);
// Default Parameters
const todayStr = new Date().toISOString().split('T')[0];
const lat = urlParams.get('lat') || '52.52';
const lon = urlParams.get('lon') || '13.405';
const name = urlParams.get('name') || 'Berlin';
const date = urlParams.get('date') || todayStr;
// Determine API Endpoint (Forecast vs Archive based on date)
const isPast = date < todayStr;
const endpoint = isPast ? '/api/om/archive' : '/api/om/forecast';
const apiParams = new URLSearchParams({
latitude: lat,
longitude: lon,
daily: 'temperature_2m_max,temperature_2m_min,weather_code',
hourly: 'temperature_2m',
timezone: 'UTC',
temperature_unit: 'celsius',
start_date: date,
end_date: date
});
const fullUrl = `${endpoint}?${apiParams.toString()}`;
try {
const response = await fetch(fullUrl);
if (!response.ok) {
throw new Error(`HTTP Error ${response.status}: ${response.statusText}`);
}
const data = await response.json();
if (data.error) {
throw new Error(data.reason || 'Open-Meteo API returned an error response.');
}
renderWeather(data, { lat, lon, name, date, isPast });
document.getElementById('loadingState').classList.add('hidden');
} catch (err) {
showError(err.message, fullUrl);
}
}
function renderWeather(data, meta) {
const daily = data.daily || {};
const hourly = data.hourly || {};
const maxTemp = daily.temperature_2m_max ? Math.round(daily.temperature_2m_max[0]) : null;
const minTemp = daily.temperature_2m_min ? Math.round(daily.temperature_2m_min[0]) : null;
const code = daily.weather_code ? daily.weather_code[0] : 0;
const hourlyTemps = hourly.temperature_2m || [];
// Validate required data
if (maxTemp === null || minTemp === null || hourlyTemps.length === 0) {
showError('Incomplete weather payload returned for this date.', 'Required daily/hourly records are missing.');
return;
}
// Location & Date UI
document.getElementById('locName').querySelector('span').textContent = meta.name;
const latNum = parseFloat(meta.lat).toFixed(2);
const lonNum = parseFloat(meta.lon).toFixed(2);
const latDir = latNum >= 0 ? 'N' : 'S';
const lonDir = lonNum >= 0 ? 'E' : 'W';
document.getElementById('coordsText').textContent = `${Math.abs(latNum)}° ${latDir}, ${Math.abs(lonNum)}° ${lonDir}`;
// Date Formatting
const dateObj = new Date(`${meta.date}T00:00:00Z`);
const dateFormatted = dateObj.toLocaleDateString('en-US', {
weekday: 'short',
month: 'short',
day: 'numeric',
year: 'numeric',
timeZone: 'UTC'
});
document.getElementById('dateDisplay').textContent = dateFormatted;
const tagEl = document.getElementById('sourceTag');
tagEl.textContent = meta.isPast ? 'ARCHIVE' : 'FORECAST';
if (meta.isPast) {
tagEl.style.background = 'rgba(168, 85, 247, 0.15)';
tagEl.style.color = '#c084fc';
}
// Condition Meta
const condition = WMO_CODES[code] || { name: 'Unknown', icon: 'cloud', theme: ['#38bdf8', '#6366f1'] };
document.getElementById('conditionText').textContent = condition.name;
document.getElementById('weatherIcon').innerHTML = getSVGIcon(condition.icon);
// Temperature Display
document.getElementById('maxTemp').textContent = `${maxTemp}°`;
document.getElementById('minTemp').textContent = `${minTemp}°`;
// Theme Colors update
if (condition.theme) {
document.getElementById('glow1').style.background = `radial-gradient(circle, ${condition.theme[0]}, transparent)`;
document.getElementById('glow2').style.background = `radial-gradient(circle, ${condition.theme[1]}, transparent)`;
}
// Derived Hourly Metrics
const sum = hourlyTemps.reduce((a, b) => a + b, 0);
const mean = (sum / hourlyTemps.length).toFixed(1);
const spread = (Math.max(...hourlyTemps) - Math.min(...hourlyTemps)).toFixed(1);
let maxVal = -Infinity;
let peakIdx = 0;
hourlyTemps.forEach((t, i) => {
if (t > maxVal) {
maxVal = t;
peakIdx = i;
}
});
const peakTimeStr = `${String(peakIdx).padStart(2, '0')}:00`;
document.getElementById('meanTemp').textContent = `${mean}°C`;
document.getElementById('tempSpread').textContent = `${spread}°C`;
document.getElementById('peakHour').textContent = peakTimeStr;
// Render Hourly Chart & Timeline
renderHourlyChart(hourlyTemps);
}
function renderHourlyChart(temps) {
const svgWidth = 1000;
const svgHeight = 140;
const paddingY = 24;
const minT = Math.min(...temps);
const maxT = Math.max(...temps);
const range = (maxT - minT) || 1;
// Coordinate mapper
const points = temps.map((t, i) => {
const x = (i / (temps.length - 1)) * svgWidth;
const y = svgHeight - paddingY - ((t - minT) / range) * (svgHeight - 2 * paddingY);
return { x, y, temp: t, hour: i };
});
// Smooth Cubic Bezier Path Generator
function buildBezierPath(pts) {
if (pts.length === 0) return '';
let path = `M ${pts[0].x.toFixed(1)},${pts[0].y.toFixed(1)}`;
for (let i = 0; i < pts.length - 1; i++) {
const p0 = pts[i === 0 ? i : i - 1];
const p1 = pts[i];
const p2 = pts[i + 1];
const p3 = pts[i + 2 < pts.length ? i + 2 : i + 1];
const cp1x = p1.x + (p2.x - p0.x) / 6;
const cp1y = p1.y + (p2.y - p0.y) / 6;
const cp2x = p2.x - (p3.x - p1.x) / 6;
const cp2y = p2.y - (p3.y - p1.y) / 6;
path += ` C ${cp1x.toFixed(1)},${cp1y.toFixed(1)} ${cp2x.toFixed(1)},${cp2y.toFixed(1)} ${p2.x.toFixed(1)},${p2.y.toFixed(1)}`;
}
return path;
}
const linePath = buildBezierPath(points);
const areaPath = `${linePath} L ${svgWidth},${svgHeight} L 0,${svgHeight} Z`;
document.getElementById('chartLine').setAttribute('d', linePath);
document.getElementById('chartArea').setAttribute('d', areaPath);
// Chart Points & Highlights
const pointsGroup = document.getElementById('chartPoints');
pointsGroup.innerHTML = '';
points.forEach((p) => {
if (p.temp === maxT || p.temp === minT || p.hour % 3 === 0) {
const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
circle.setAttribute('cx', p.x.toFixed(1));
circle.setAttribute('cy', p.y.toFixed(1));
circle.setAttribute('r', p.temp === maxT || p.temp === minT ? '5' : '3');
circle.setAttribute('fill', p.temp === maxT ? '#f43f5e' : p.temp === minT ? '#38bdf8' : '#ffffff');
circle.setAttribute('stroke', '#0f172a');
circle.setAttribute('stroke-width', '2');
pointsGroup.appendChild(circle);
}
});
// Render Timeline Axis Items
const timelineRow = document.getElementById('timelineRow');
timelineRow.innerHTML = '';
// Sample 12 columns for cleaner display (every 2 hours)
for (let i = 0; i < 24; i += 2) {
const t = temps[i];
const rounded = Math.round(t);
const isPeak = t === maxT;
const isLow = t === minT;
const timeSlot = document.createElement('div');
timeSlot.className = `time-slot ${isPeak ? 'is-peak' : ''} ${isLow ? 'is-low' : ''}`;
timeSlot.innerHTML = `
<span class="time">${String(i).padStart(2, '0')}:00</span>
<span class="temp">${rounded}°</span>
`;
timelineRow.appendChild(timeSlot);
}
}
function showError(message, details) {
document.getElementById('loadingState').classList.add('hidden');
const errOverlay = document.getElementById('errorState');
errOverlay.classList.remove('hidden');
document.getElementById('errorMessage').textContent = message;
document.getElementById('errorDetails').textContent = details || 'Please check your parameters and endpoint availability.';
}
// Initialize on load
window.addEventListener('DOMContentLoaded', init);
</script>
</body>
</html>L1 — cheap deterministic descriptors
| bytes total | 27,084 | html / css / js | 5,016 / 8,125 / 13,943 |
|---|---|---|---|
| dom nodes | 77 | dom depth | 9 |
| css rules | 48 | js present | yes |
| brightness | 25.6 | contrast | 15.6 |
| colorfulness | 23.5 | whitespace | 87.9% |
This slot's telemetry
| prompt tokens | 348 | completion tokens | 10,305 |
|---|---|---|---|
| total tokens | 10,653 | wall | 66.6 s |
| cost | — | request id | — |
config.json602 B
{
"N": 4,
"auth": {
"credential_ref": "WCB_GEMINI_KEY",
"method": "api-key"
},
"billing": "metered",
"config_id": "gemini-3.6-flash-eff-medium--api--official--dev",
"effort": "medium",
"family": "gemini",
"m": {
"min": 4,
"q": 4
},
"model_id": "gemini-3.6-flash",
"protocol": "api",
"served_model": "gemini-3.6-flash",
"telemetry": {
"completion_tokens": 62084,
"cost_usd": null,
"prompt_tokens": 2748,
"total_tokens": 64832,
"wall_ms": 387879
},
"transport": "google-gemini-developer-api-openai-compat",
"vendor_sanction_ref": null
}send-log4.7 KB
{
"N": 4,
"batch_id": "2026-07-22--gemini-36flash",
"config_id": "gemini-3.6-flash-eff-medium--api--official--dev",
"positions": [
{
"attempts": [
{
"attempt_index": 0,
"backoff_ms": null,
"charged": true,
"ended_at": "2026-07-22T07:44:07.452999+00:00",
"http_status": 200,
"outcome": "valid",
"reached_model": true,
"reason": "ok",
"request_id": null,
"started_at": "2026-07-22T07:43:29.928172+00:00"
}
],
"block_index": 0,
"model_reaching_attempt_index": 0,
"slot_index": 0,
"terminal_state": "valid",
"variant": "P-min"
},
{
"attempts": [
{
"attempt_index": 0,
"backoff_ms": null,
"charged": true,
"ended_at": "2026-07-22T07:45:17.425766+00:00",
"http_status": 200,
"outcome": "valid",
"reached_model": true,
"reason": "ok",
"request_id": null,
"started_at": "2026-07-22T07:44:10.822706+00:00"
}
],
"block_index": 0,
"model_reaching_attempt_index": 0,
"slot_index": 0,
"terminal_state": "valid",
"variant": "P-q"
},
{
"attempts": [
{
"attempt_index": 0,
"backoff_ms": null,
"charged": true,
"ended_at": "2026-07-22T07:46:21.704469+00:00",
"http_status": 200,
"outcome": "valid",
"reached_model": true,
"reason": "ok",
"request_id": null,
"started_at": "2026-07-22T07:45:20.735511+00:00"
}
],
"block_index": 1,
"model_reaching_attempt_index": 0,
"slot_index": 1,
"terminal_state": "valid",
"variant": "P-q"
},
{
"attempts": [
{
"attempt_index": 0,
"backoff_ms": null,
"charged": true,
"ended_at": "2026-07-22T07:46:59.225892+00:00",
"http_status": 200,
"outcome": "valid",
"reached_model": true,
"reason": "ok",
"request_id": null,
"started_at": "2026-07-22T07:46:25.154624+00:00"
}
],
"block_index": 1,
"model_reaching_attempt_index": 0,
"slot_index": 1,
"terminal_state": "valid",
"variant": "P-min"
},
{
"attempts": [
{
"attempt_index": 0,
"backoff_ms": null,
"charged": true,
"ended_at": "2026-07-22T07:48:08.298516+00:00",
"http_status": 200,
"outcome": "valid",
"reached_model": true,
"reason": "ok",
"request_id": null,
"started_at": "2026-07-22T07:47:02.364841+00:00"
}
],
"block_index": 2,
"model_reaching_attempt_index": 0,
"slot_index": 2,
"terminal_state": "valid",
"variant": "P-q"
},
{
"attempts": [
{
"attempt_index": 0,
"backoff_ms": null,
"charged": true,
"ended_at": "2026-07-22T07:48:39.042901+00:00",
"http_status": 200,
"outcome": "valid",
"reached_model": true,
"reason": "ok",
"request_id": null,
"started_at": "2026-07-22T07:48:12.983884+00:00"
}
],
"block_index": 2,
"model_reaching_attempt_index": 0,
"slot_index": 2,
"terminal_state": "valid",
"variant": "P-min"
},
{
"attempts": [
{
"attempt_index": 0,
"backoff_ms": null,
"charged": true,
"ended_at": "2026-07-22T07:49:26.460851+00:00",
"http_status": 200,
"outcome": "valid",
"reached_model": true,
"reason": "ok",
"request_id": null,
"started_at": "2026-07-22T07:48:42.384956+00:00"
}
],
"block_index": 3,
"model_reaching_attempt_index": 0,
"slot_index": 3,
"terminal_state": "valid",
"variant": "P-min"
},
{
"attempts": [
{
"attempt_index": 0,
"backoff_ms": null,
"charged": true,
"ended_at": "2026-07-22T07:50:22.358389+00:00",
"http_status": 200,
"outcome": "valid",
"reached_model": true,
"reason": "ok",
"request_id": null,
"started_at": "2026-07-22T07:49:29.709862+00:00"
}
],
"block_index": 3,
"model_reaching_attempt_index": 0,
"slot_index": 3,
"terminal_state": "valid",
"variant": "P-q"
}
],
"retry_policy": {
"max_unreachable_retries": 5,
"rate_limit_backoff": {
"max_attempts": 4,
"max_total_ms": 60000
}
}
}