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
gemini-3.6-flash @medium · api P-q slot 0 screenshot

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

within 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 total27,084html / css / js5,016 / 8,125 / 13,943
dom nodes77dom depth9
css rules48js presentyes
brightness25.6contrast15.6
colorfulness23.5whitespace87.9%

This slot's telemetry

prompt tokens348completion tokens10,305
total tokens10,653wall66.6 s
costrequest 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
    }
  }
}