claude-sonnet-5 @ max · CC

CCmax
config
claude-sonnet-5-eff-max--cli--claude-code--dev
batch
2026-07-19--unified
transport
claude-code-cli-headless
protocol
cli · plan
served model
claude-haiku-4-5-20251001
captured
Jul 18, 2026, 11:54 AM · N=2
variant
live
slot 0 · P-q · sandboxed iframe
claude-sonnet-5 @max · CC 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 0/24 · 0 match · 4 mismatch · 20 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, initial-scale=1">
<link rel="icon" href="data:,">
<title>Weather Card</title>
<style>
  :root { color-scheme: dark; }
  * { box-sizing: border-box; }
  html, body {
    margin: 0; padding: 0;
    width: 1280px; height: 800px;
    overflow: hidden;
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
  }
  body {
    display: flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(160deg, #4a5b7a 0%, #6f85a8 55%, #a9bdd4 100%);
  }
  body.theme-default        { background: linear-gradient(160deg, #4a5b7a 0%, #6f85a8 55%, #a9bdd4 100%); }
  body.theme-clear          { background: linear-gradient(160deg, #2d6fb0 0%, #5aa8e0 55%, #ffe2a8 100%); }
  body.theme-partly-cloudy  { background: linear-gradient(160deg, #4c6c8f 0%, #86a9c9 55%, #dbe8f2 100%); }
  body.theme-cloudy         { background: linear-gradient(160deg, #5b6675 0%, #8b96a3 55%, #c4ccd4 100%); }
  body.theme-fog            { background: linear-gradient(160deg, #6d7a86 0%, #a2aeb8 55%, #d6dee3 100%); }
  body.theme-drizzle        { background: linear-gradient(160deg, #435669 0%, #6c8497 55%, #a2b7c4 100%); }
  body.theme-rain           { background: linear-gradient(160deg, #24344a 0%, #3f5872 55%, #6c869a 100%); }
  body.theme-snow           { background: linear-gradient(160deg, #5f7ea0 0%, #a7cbe3 55%, #eef7fc 100%); }
  body.theme-thunderstorm   { background: linear-gradient(160deg, #181d2b 0%, #323a52 55%, #4c5468 100%); }

  #app { width: 1280px; height: 800px; display: flex; align-items: center; justify-content: center; }

  .card {
    position: relative;
    width: 1120px;
    border-radius: 32px;
    padding: 48px 60px 40px;
    background: linear-gradient(165deg, rgba(6,14,26,0.46), rgba(6,14,26,0.22));
    backdrop-filter: blur(30px) saturate(160%);
    -webkit-backdrop-filter: blur(30px) saturate(160%);
    border: 1px solid rgba(255,255,255,0.22);
    box-shadow: 0 30px 80px -20px rgba(0,0,0,0.55), inset 0 1px 0 rgba(255,255,255,0.22);
    color: #fff;
    text-shadow: 0 1px 3px rgba(0,0,0,0.2);
    overflow: hidden;
    display: flex;
    flex-direction: column;
    animation: cardIn 0.5s ease;
  }
  @keyframes cardIn { from { opacity: 0; transform: translateY(14px) scale(0.99); } to { opacity: 1; transform: translateY(0) scale(1); } }

  .card::before, .card::after { content: ''; position: absolute; border-radius: 50%; filter: blur(70px); pointer-events: none; z-index: 0; }
  .card::before { width: 380px; height: 380px; background: var(--accent, #ffb648); opacity: 0.30; top: -140px; right: -100px; }
  .card::after  { width: 300px; height: 300px; background: var(--accent2, #4a90e2); opacity: 0.22; bottom: -120px; left: -80px; }
  .card > * { position: relative; z-index: 1; }

  .card__header { display: flex; align-items: flex-start; justify-content: space-between; }
  .card__header > div:first-child { min-width: 0; flex: 1 1 auto; }
  .location-name { margin: 0; font-size: 38px; font-weight: 800; letter-spacing: -0.02em; line-height: 1.15; overflow-wrap: anywhere; }
  .date-label { margin: 8px 0 0; font-size: 16.5px; font-weight: 500; opacity: 0.8; }
  .badge { flex: 0 0 auto; font-size: 12px; font-weight: 700; letter-spacing: 0.09em; text-transform: uppercase; padding: 8px 16px; border-radius: 999px; background: rgba(255,255,255,0.14); border: 1px solid rgba(255,255,255,0.28); white-space: nowrap; }

  .hero-row { display: flex; align-items: center; gap: 36px; margin-top: 30px; }
  .hero-icon { width: 132px; height: 132px; flex: 0 0 auto; filter: drop-shadow(0 10px 18px rgba(0,0,0,0.28)); }
  .hero-icon svg, .error-icon svg { width: 100%; height: 100%; display: block; }
  .hero-condition { flex: 1 1 auto; min-width: 0; }
  .condition-label { margin: 0; font-size: 29px; font-weight: 700; letter-spacing: -0.01em; }
  .coords-label { margin: 8px 0 0; font-size: 14px; opacity: 0.68; font-variant-numeric: tabular-nums; }

  .hero-stats { display: flex; align-items: center; gap: 26px; flex: 0 0 auto; }
  .stat { display: flex; flex-direction: column; align-items: flex-end; }
  .stat-label { font-size: 12.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.09em; opacity: 0.68; margin-bottom: 6px; }
  .stat-value { font-size: 52px; font-weight: 800; line-height: 1; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }
  .stat--low .stat-value { opacity: 0.85; }
  .stat-divider { width: 1px; height: 56px; background: rgba(255,255,255,0.25); }

  .hourly-section { margin-top: 32px; padding-top: 24px; border-top: 1px solid rgba(255,255,255,0.16); }
  .section-heading { margin: 0 0 6px; font-size: 12.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.12em; opacity: 0.65; }
  .chart-wrap { position: relative; margin-top: 6px; }
  .chart-svg { display: block; overflow: visible; }
  .chart-axis-label { fill: rgba(255,255,255,0.62); font-size: 12px; font-weight: 600; font-variant-numeric: tabular-nums; }
  .chart-callout { fill: #fff; font-size: 13.5px; font-weight: 700; font-variant-numeric: tabular-nums; }
  #chartOverlay { cursor: crosshair; }
  .chart-tooltip { position: absolute; transform: translate(-50%, -100%); pointer-events: none; opacity: 0; transition: opacity 0.12s ease; background: rgba(6,12,22,0.92); color: #fff; font-size: 12.5px; font-weight: 600; padding: 6px 11px; border-radius: 8px; white-space: nowrap; box-shadow: 0 8px 20px rgba(0,0,0,0.35); }

  .card__footer { margin-top: 20px; font-size: 12.5px; opacity: 0.55; }

  .skeleton { background: rgba(255,255,255,0.16); border-radius: 10px; animation: pulse 1.4s ease-in-out infinite; }
  @keyframes pulse { 0%, 100% { opacity: 0.5; } 50% { opacity: 1; } }
  .card--loading { min-height: 620px; }
  .sk-badge { width: 90px; height: 26px; border-radius: 999px; position: absolute; top: 48px; right: 60px; }
  .sk-title { width: 320px; height: 38px; }
  .sk-subtitle { width: 220px; height: 18px; margin-top: 12px; }
  .hero-row .sk-icon { width: 132px; height: 132px; border-radius: 26px; }
  .hero-row .sk-condition { flex: 1; height: 29px; margin: 0 24px; align-self: center; }
  .hero-row .sk-stats { width: 220px; height: 56px; align-self: center; }
  .sk-chart { height: 220px; margin-top: 48px; border-radius: 16px; }
  .loading-caption { text-align: center; margin-top: 24px; font-size: 14px; opacity: 0.7; }

  .card--error { min-height: 620px; justify-content: center; align-items: center; text-align: center; padding: 60px 100px; }
  .error-icon { width: 72px; height: 72px; margin-bottom: 20px; opacity: 0.92; }
  .error-title { margin: 0 0 10px; font-size: 28px; font-weight: 800; }
  .error-message { margin: 0; font-size: 16px; opacity: 0.85; max-width: 560px; line-height: 1.5; }
  .error-meta { margin: 14px 0 0; font-size: 13px; opacity: 0.55; text-transform: uppercase; letter-spacing: 0.08em; }
  .retry-btn { margin-top: 28px; padding: 12px 28px; border-radius: 999px; border: 1px solid rgba(255,255,255,0.35); background: rgba(255,255,255,0.14); color: #fff; font-size: 14px; font-weight: 700; cursor: pointer; transition: background 0.15s ease, transform 0.15s ease; font-family: inherit; }
  .retry-btn:hover { background: rgba(255,255,255,0.24); transform: translateY(-1px); }
  .retry-btn:active { transform: translateY(0); }
  .retry-btn:focus-visible { outline: 2px solid #fff; outline-offset: 3px; }
</style>
</head>
<body class="theme-default">
<div id="app"></div>
<script>
(function () {
  'use strict';

  const DEFAULTS = { lat: 52.52, lon: 13.405, name: 'Berlin' };

  const WMO = {
    0: ['Clear sky', 'clear'], 1: ['Mainly clear', 'clear'],
    2: ['Partly cloudy', 'partlyCloudy'], 3: ['Overcast', 'cloudy'],
    45: ['Fog', 'fog'], 48: ['Depositing rime fog', 'fog'],
    51: ['Light drizzle', 'drizzle'], 53: ['Moderate drizzle', 'drizzle'], 55: ['Dense drizzle', 'drizzle'],
    56: ['Light freezing drizzle', 'drizzle'], 57: ['Dense freezing drizzle', 'drizzle'],
    61: ['Slight rain', 'rain'], 63: ['Moderate rain', 'rain'], 65: ['Heavy rain', 'rain'],
    66: ['Light freezing rain', 'rain'], 67: ['Heavy freezing rain', 'rain'],
    71: ['Slight snow fall', 'snow'], 73: ['Moderate snow fall', 'snow'], 75: ['Heavy snow fall', 'snow'],
    77: ['Snow grains', 'snow'],
    80: ['Slight rain showers', 'rain'], 81: ['Moderate rain showers', 'rain'], 82: ['Violent rain showers', 'rain'],
    85: ['Slight snow showers', 'snow'], 86: ['Heavy snow showers', 'snow'],
    95: ['Thunderstorm', 'thunderstorm'], 96: ['Thunderstorm, slight hail', 'thunderstorm'], 99: ['Thunderstorm, heavy hail', 'thunderstorm']
  };

  const CATEGORY_META = {
    clear:        { theme: 'clear',         accent: '#ffb648', accent2: '#3d7dc0' },
    partlyCloudy: { theme: 'partly-cloudy', accent: '#ffcf7a', accent2: '#5f8fc4' },
    cloudy:       { theme: 'cloudy',        accent: '#dbe2ea', accent2: '#8b98a8' },
    fog:          { theme: 'fog',           accent: '#dbe6ee', accent2: '#93a4b2' },
    drizzle:      { theme: 'drizzle',       accent: '#a9d6ff', accent2: '#5b7ea6' },
    rain:         { theme: 'rain',          accent: '#7ab8ff', accent2: '#2c4a66' },
    snow:         { theme: 'snow',          accent: '#eaf6ff', accent2: '#8fb6d6' },
    thunderstorm: { theme: 'thunderstorm',  accent: '#ffe066', accent2: '#4a5470' }
  };

  const WARNING_SVG = '<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">' +
    '<path d="M50 10 L94 86 L6 86 Z" fill="rgba(255,255,255,0.12)" stroke="#fff" stroke-width="5" stroke-linejoin="round" stroke-linecap="round"/>' +
    '<line x1="50" y1="40" x2="50" y2="62" stroke="#fff" stroke-width="6" stroke-linecap="round"/>' +
    '<circle cx="50" cy="74" r="4.5" fill="#fff"/>' +
    '</svg>';

  function iconDefs() {
    return '<defs>' +
      '<linearGradient id="gSun" x1="0" y1="0" x2="1" y2="1"><stop offset="0%" stop-color="#ffe6a7"/><stop offset="100%" stop-color="#ff9f43"/></linearGradient>' +
      '<linearGradient id="gCloud" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#ffffff"/><stop offset="100%" stop-color="#c7d3e0"/></linearGradient>' +
      '<linearGradient id="gCloudDark" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#bdc9d6"/><stop offset="100%" stop-color="#8898ab"/></linearGradient>' +
      '<linearGradient id="gRain" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#a9d6ff"/><stop offset="100%" stop-color="#4a90e2"/></linearGradient>' +
      '<linearGradient id="gSnow" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#ffffff"/><stop offset="100%" stop-color="#cfe7fb"/></linearGradient>' +
      '<linearGradient id="gBolt" x1="0" y1="0" x2="1" y2="1"><stop offset="0%" stop-color="#ffe066"/><stop offset="100%" stop-color="#ffb703"/></linearGradient>' +
      '</defs>';
  }

  const ICON_BODIES = {
    clear:
      '<circle cx="50" cy="50" r="24" fill="url(#gSun)"/>' +
      '<g stroke="url(#gSun)" stroke-width="6" stroke-linecap="round">' +
      '<line x1="50" y1="6" x2="50" y2="18"/><line x1="50" y1="82" x2="50" y2="94"/>' +
      '<line x1="6" y1="50" x2="18" y2="50"/><line x1="82" y1="50" x2="94" y2="50"/>' +
      '<line x1="19.3" y1="19.3" x2="27.6" y2="27.6"/><line x1="72.4" y1="72.4" x2="80.7" y2="80.7"/>' +
      '<line x1="19.3" y1="80.7" x2="27.6" y2="72.4"/><line x1="72.4" y1="27.6" x2="80.7" y2="19.3"/>' +
      '</g>',
    partlyCloudy:
      '<circle cx="35" cy="35" r="17" fill="url(#gSun)"/>' +
      '<g stroke="url(#gSun)" stroke-width="5" stroke-linecap="round">' +
      '<line x1="35" y1="7" x2="35" y2="16"/><line x1="8" y1="35" x2="17" y2="35"/>' +
      '<line x1="14" y1="14" x2="20.4" y2="20.4"/><line x1="56" y1="14" x2="49.6" y2="20.4"/>' +
      '</g>' +
      '<g fill="url(#gCloud)">' +
      '<ellipse cx="42" cy="66" rx="20" ry="15.5"/><ellipse cx="62" cy="56" rx="25" ry="20.5"/>' +
      '<ellipse cx="80" cy="64" rx="15" ry="12.5"/><rect x="33" y="62" width="56" height="19" rx="9.5"/>' +
      '</g>',
    cloudy:
      '<g fill="url(#gCloudDark)" opacity="0.6">' +
      '<ellipse cx="28" cy="38" rx="15" ry="11"/><ellipse cx="44" cy="32" rx="19" ry="15"/>' +
      '<rect x="22" y="36" width="42" height="14" rx="7"/>' +
      '</g>' +
      '<g fill="url(#gCloud)">' +
      '<ellipse cx="40" cy="63" rx="21" ry="16"/><ellipse cx="62" cy="53" rx="26" ry="21"/>' +
      '<ellipse cx="81" cy="62" rx="16" ry="13"/><rect x="31" y="59" width="58" height="20" rx="10"/>' +
      '</g>',
    fog:
      '<g fill="url(#gCloud)" opacity="0.85"><ellipse cx="46" cy="32" rx="22" ry="14"/></g>' +
      '<g stroke="#dbe6ee" stroke-width="6" stroke-linecap="round" opacity="0.92">' +
      '<line x1="10" y1="54" x2="90" y2="54"/><line x1="18" y1="68" x2="82" y2="68"/><line x1="14" y1="82" x2="86" y2="82"/>' +
      '</g>',
    drizzle:
      '<g fill="url(#gCloud)">' +
      '<ellipse cx="38" cy="44" rx="19" ry="14.5"/><ellipse cx="58" cy="35" rx="23" ry="18.5"/>' +
      '<ellipse cx="76" cy="43" rx="14" ry="11.5"/><rect x="29" y="40" width="54" height="18" rx="9"/>' +
      '</g>' +
      '<g stroke="url(#gRain)" stroke-width="4.5" stroke-linecap="round">' +
      '<line x1="38" y1="70" x2="35" y2="78"/><line x1="52" y1="72" x2="49" y2="80"/><line x1="66" y1="70" x2="63" y2="78"/>' +
      '</g>',
    rain:
      '<g fill="url(#gCloud)">' +
      '<ellipse cx="38" cy="40" rx="20" ry="15"/><ellipse cx="58" cy="31" rx="24" ry="19"/>' +
      '<ellipse cx="77" cy="39" rx="15" ry="12"/><rect x="29" y="36" width="55" height="18" rx="9"/>' +
      '</g>' +
      '<g stroke="url(#gRain)" stroke-width="5.5" stroke-linecap="round">' +
      '<line x1="34" y1="66" x2="28" y2="86"/><line x1="52" y1="68" x2="46" y2="90"/><line x1="70" y1="66" x2="64" y2="86"/>' +
      '</g>',
    snow:
      '<g fill="url(#gCloud)">' +
      '<ellipse cx="38" cy="40" rx="20" ry="15"/><ellipse cx="58" cy="31" rx="24" ry="19"/>' +
      '<ellipse cx="77" cy="39" rx="15" ry="12"/><rect x="29" y="36" width="55" height="18" rx="9"/>' +
      '</g>' +
      '<g fill="url(#gSnow)">' +
      '<circle cx="34" cy="72" r="4"/><circle cx="52" cy="79" r="4"/><circle cx="70" cy="72" r="4"/>' +
      '<circle cx="43" cy="87" r="3.2"/><circle cx="61" cy="87" r="3.2"/>' +
      '</g>',
    thunderstorm:
      '<g fill="url(#gCloudDark)">' +
      '<ellipse cx="38" cy="38" rx="20" ry="15"/><ellipse cx="58" cy="29" rx="24" ry="19"/>' +
      '<ellipse cx="77" cy="37" rx="15" ry="12"/><rect x="29" y="34" width="55" height="18" rx="9"/>' +
      '</g>' +
      '<polygon points="56,56 42,80 52,80 46,97 73,66 60,66 66,56" fill="url(#gBolt)"/>'
  };

  function getWeatherIconSVG(category) {
    const body = ICON_BODIES[category] || ICON_BODIES.cloudy;
    return '<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">' + iconDefs() + body + '</svg>';
  }

  function describeWeatherCode(code) {
    const entry = WMO[code];
    if (!entry) return { label: 'Unknown conditions', category: 'cloudy' };
    return { label: entry[0], category: entry[1] };
  }

  function pad2(n) { return n < 10 ? '0' + n : '' + n; }

  function todayUTCString() {
    const now = new Date();
    return now.getUTCFullYear() + '-' + pad2(now.getUTCMonth() + 1) + '-' + pad2(now.getUTCDate());
  }

  function isValidDateStr(s) {
    if (!/^\d{4}-\d{2}-\d{2}$/.test(s)) return false;
    const parts = s.split('-').map(Number);
    const y = parts[0], m = parts[1], d = parts[2];
    const dt = new Date(Date.UTC(y, m - 1, d));
    return dt.getUTCFullYear() === y && dt.getUTCMonth() === m - 1 && dt.getUTCDate() === d;
  }

  function formatFullDate(dateStr) {
    const parts = dateStr.split('-').map(Number);
    const dt = new Date(Date.UTC(parts[0], parts[1] - 1, parts[2]));
    return dt.toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric', timeZone: 'UTC' });
  }

  function hourFromIso(iso) { return parseInt(iso.slice(11, 13), 10); }

  function formatHourLabel(h) {
    const hour12 = (h % 12 === 0) ? 12 : (h % 12);
    return hour12 + ' ' + (h < 12 ? 'AM' : 'PM');
  }

  function formatCoords(lat, lon) {
    const latDir = lat >= 0 ? 'N' : 'S';
    const lonDir = lon >= 0 ? 'E' : 'W';
    return Math.abs(lat).toFixed(2) + '°' + latDir + ', ' + Math.abs(lon).toFixed(2) + '°' + lonDir;
  }

  // ---- Query param parsing ----
  const qs = new URLSearchParams(window.location.search);

  let lat = parseFloat(qs.get('lat'));
  if (!isFinite(lat) || lat < -90 || lat > 90) lat = DEFAULTS.lat;

  let lon = parseFloat(qs.get('lon'));
  if (!isFinite(lon) || lon < -180 || lon > 180) lon = DEFAULTS.lon;

  let name = qs.get('name');
  if (!name || !name.trim()) name = DEFAULTS.name;

  const today = todayUTCString();
  let dateParam = qs.get('date');
  if (!dateParam || !isValidDateStr(dateParam)) dateParam = today;

  const endpoint = (dateParam < today) ? '/api/om/archive' : '/api/om/forecast';

  const apiUrl = endpoint + '?' + new URLSearchParams({
    latitude: String(lat),
    longitude: String(lon),
    daily: 'temperature_2m_max,temperature_2m_min,weather_code',
    hourly: 'temperature_2m',
    timezone: 'UTC',
    temperature_unit: 'celsius',
    start_date: dateParam,
    end_date: dateParam
  }).toString();

  // ---- Chart ----
  function buildChart(times, temps, accent, accent2) {
    const n = temps.length;
    const W = 992, H = 190, TOP = 34, BOTTOM = 30;
    const svgH = TOP + H + BOTTOM;

    let tMin = Math.min.apply(null, temps);
    let tMax = Math.max.apply(null, temps);
    if (tMin === tMax) { tMin -= 1; tMax += 1; }
    const range = tMax - tMin;
    const padAmt = Math.max(range * 0.25, 2);
    const domainMin = tMin - padAmt;
    const domainMax = tMax + padAmt;

    function xAt(i) { return n > 1 ? (i / (n - 1)) * W : W / 2; }
    function yAt(t) { return TOP + H - ((t - domainMin) / (domainMax - domainMin)) * H; }

    const pts = [];
    for (let i = 0; i < n; i++) pts.push({ x: xAt(i), y: yAt(temps[i]), t: temps[i] });

    let linePath = 'M ' + pts[0].x.toFixed(1) + ' ' + pts[0].y.toFixed(1);
    for (let i = 0; i < pts.length - 1; i++) {
      const p0 = pts[i], p1 = pts[i + 1];
      const mx = ((p0.x + p1.x) / 2).toFixed(1);
      const my = ((p0.y + p1.y) / 2).toFixed(1);
      linePath += ' Q ' + p0.x.toFixed(1) + ' ' + p0.y.toFixed(1) + ' ' + mx + ' ' + my;
    }
    const lastPt = pts[pts.length - 1];
    linePath += ' L ' + lastPt.x.toFixed(1) + ' ' + lastPt.y.toFixed(1);

    const baseline = (TOP + H).toFixed(1);
    const areaPath = linePath + ' L ' + lastPt.x.toFixed(1) + ' ' + baseline + ' L ' + pts[0].x.toFixed(1) + ' ' + baseline + ' Z';

    let maxIdx = 0, minIdx = 0;
    for (let i = 0; i < temps.length; i++) {
      if (temps[i] > temps[maxIdx]) maxIdx = i;
      if (temps[i] < temps[minIdx]) minIdx = i;
    }

    const gridLines = [0.25, 0.5, 0.75].map(function (f) {
      const gy = (TOP + H * f).toFixed(1);
      return '<line x1="0" y1="' + gy + '" x2="' + W + '" y2="' + gy + '" stroke="rgba(255,255,255,0.14)" stroke-width="1" stroke-dasharray="4 6"/>';
    }).join('');

    const hourTicks = [0, 3, 6, 9, 12, 15, 18, 21].filter(function (h) { return h < n; }).map(function (h) {
      const px = xAt(h).toFixed(1);
      return '<text x="' + px + '" y="' + (svgH - 8) + '" text-anchor="middle" class="chart-axis-label">' + formatHourLabel(hourFromIso(times[h])) + '</text>';
    }).join('');

    const dots = pts.map(function (p) {
      return '<circle cx="' + p.x.toFixed(1) + '" cy="' + p.y.toFixed(1) + '" r="2.4" fill="#ffffff" opacity="0.5"/>';
    }).join('');

    const maxCallout = '<circle cx="' + pts[maxIdx].x.toFixed(1) + '" cy="' + pts[maxIdx].y.toFixed(1) + '" r="5" fill="#fff" stroke="' + accent + '" stroke-width="3"/>' +
      '<text x="' + pts[maxIdx].x.toFixed(1) + '" y="' + (pts[maxIdx].y - 14).toFixed(1) + '" text-anchor="middle" class="chart-callout">' + Math.round(temps[maxIdx]) + '°</text>';

    const minCallout = '<circle cx="' + pts[minIdx].x.toFixed(1) + '" cy="' + pts[minIdx].y.toFixed(1) + '" r="5" fill="#fff" stroke="' + accent2 + '" stroke-width="3"/>' +
      '<text x="' + pts[minIdx].x.toFixed(1) + '" y="' + (pts[minIdx].y + 22).toFixed(1) + '" text-anchor="middle" class="chart-callout">' + Math.round(temps[minIdx]) + '°</text>';

    const svg = '<svg width="' + W + '" height="' + svgH + '" viewBox="0 0 ' + W + ' ' + svgH + '" class="chart-svg">' +
      '<defs><linearGradient id="areaGrad" x1="0" y1="0" x2="0" y2="1">' +
      '<stop offset="0%" stop-color="' + accent + '" stop-opacity="0.5"/>' +
      '<stop offset="100%" stop-color="' + accent + '" stop-opacity="0"/>' +
      '</linearGradient></defs>' +
      gridLines +
      '<path d="' + areaPath + '" fill="url(#areaGrad)"/>' +
      '<path d="' + linePath + '" fill="none" stroke="#ffffff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>' +
      dots + maxCallout + minCallout + hourTicks +
      '<line id="hoverLine" x1="0" y1="' + TOP + '" x2="0" y2="' + (TOP + H) + '" stroke="#ffffff" stroke-width="1.5" opacity="0"/>' +
      '<circle id="hoverDot" cx="0" cy="0" r="5.5" fill="#ffffff" stroke="' + accent + '" stroke-width="3" opacity="0"/>' +
      '<rect id="chartOverlay" x="0" y="0" width="' + W + '" height="' + svgH + '" fill="transparent"/>' +
      '</svg>';

    return { svg: svg, W: W, svgH: svgH, pts: pts, times: times, temps: temps };
  }

  function attachChartInteractivity(chart) {
    const overlay = document.getElementById('chartOverlay');
    const hoverLine = document.getElementById('hoverLine');
    const hoverDot = document.getElementById('hoverDot');
    const tooltip = document.getElementById('chartTooltip');
    if (!overlay) return;
    const svgEl = overlay.closest('svg');

    overlay.addEventListener('mousemove', function (e) {
      const rect = svgEl.getBoundingClientRect();
      const relX = (e.clientX - rect.left) / rect.width * chart.W;
      let idx = Math.round((relX / chart.W) * (chart.pts.length - 1));
      idx = Math.max(0, Math.min(chart.pts.length - 1, idx));
      const p = chart.pts[idx];
      hoverLine.setAttribute('x1', p.x); hoverLine.setAttribute('x2', p.x); hoverLine.setAttribute('opacity', '1');
      hoverDot.setAttribute('cx', p.x); hoverDot.setAttribute('cy', p.y); hoverDot.setAttribute('opacity', '1');
      tooltip.style.opacity = '1';
      tooltip.style.left = ((p.x / chart.W) * 100) + '%';
      tooltip.style.top = Math.max(p.y - 46, 0) + 'px';
      tooltip.textContent = formatHourLabel(hourFromIso(chart.times[idx])) + ' · ' + Math.round(chart.temps[idx]) + '°C';
    });

    overlay.addEventListener('mouseleave', function () {
      hoverLine.setAttribute('opacity', '0');
      hoverDot.setAttribute('opacity', '0');
      tooltip.style.opacity = '0';
    });
  }

  // ---- Rendering ----
  const app = document.getElementById('app');

  function renderLoading() {
    document.body.className = 'theme-default';
    app.innerHTML =
      '<div class="card card--loading" role="status" aria-live="polite">' +
      '<div class="skeleton sk-badge"></div>' +
      '<div class="skeleton sk-title"></div>' +
      '<div class="skeleton sk-subtitle"></div>' +
      '<div class="hero-row">' +
      '<div class="skeleton sk-icon"></div>' +
      '<div class="skeleton sk-condition"></div>' +
      '<div class="skeleton sk-stats"></div>' +
      '</div>' +
      '<div class="skeleton sk-chart"></div>' +
      '<p class="loading-caption">Loading weather…</p>' +
      '</div>';
  }

  function renderError(message) {
    document.body.className = 'theme-default';
    app.innerHTML =
      '<div class="card card--error" role="alert">' +
      '<div class="error-icon">' + WARNING_SVG + '</div>' +
      '<h1 class="error-title">Weather unavailable</h1>' +
      '<p class="error-message" id="errorMessage"></p>' +
      '<p class="error-meta" id="errorMeta"></p>' +
      '<button class="retry-btn" id="retryBtn" type="button">Try again</button>' +
      '</div>';
    document.getElementById('errorMessage').textContent = message;
    document.getElementById('errorMeta').textContent = name + ' · ' + dateParam;
    document.getElementById('retryBtn').addEventListener('click', loadWeather);
  }

  function renderCard(info) {
    const desc = describeWeatherCode(info.code);
    const meta = CATEGORY_META[desc.category] || CATEGORY_META.cloudy;
    document.body.className = 'theme-' + meta.theme;

    const relLabel = (dateParam === today) ? 'Today' : (dateParam > today ? 'Forecast' : 'Historical');
    const dateLabel = formatFullDate(dateParam);
    const maxT = Math.round(info.max);
    const minT = Math.round(info.min);
    const chart = buildChart(info.hourlyTimes, info.hourlyTemps, meta.accent, meta.accent2);
    const rangeLabel = 'Hourly temperature chart ranging from ' + Math.round(Math.min.apply(null, info.hourlyTemps)) + ' to ' + Math.round(Math.max.apply(null, info.hourlyTemps)) + ' degrees Celsius';

    app.innerHTML =
      '<div class="card" style="--accent:' + meta.accent + ';--accent2:' + meta.accent2 + ';">' +
      '<div class="card__header">' +
      '<div><h1 class="location-name" id="locationName"></h1><p class="date-label" id="dateLabel"></p></div>' +
      '<div class="badge" id="badgeLabel"></div>' +
      '</div>' +
      '<div class="hero-row">' +
      '<div class="hero-icon" aria-hidden="true">' + getWeatherIconSVG(desc.category) + '</div>' +
      '<div class="hero-condition">' +
      '<p class="condition-label" id="conditionLabel"></p>' +
      '<p class="coords-label" id="coordsLabel"></p>' +
      '</div>' +
      '<div class="hero-stats">' +
      '<div class="stat stat--high"><span class="stat-label">↑ High</span><span class="stat-value" id="statHigh"></span></div>' +
      '<div class="stat-divider"></div>' +
      '<div class="stat stat--low"><span class="stat-label">↓ Low</span><span class="stat-value" id="statLow"></span></div>' +
      '</div>' +
      '</div>' +
      '<div class="hourly-section">' +
      '<h2 class="section-heading">Hourly Temperature · °C</h2>' +
      '<div class="chart-wrap" id="chartWrap" style="width:' + chart.W + 'px;height:' + chart.svgH + 'px;" role="img" aria-label="' + rangeLabel + '">' +
      chart.svg +
      '<div class="chart-tooltip" id="chartTooltip"></div>' +
      '</div>' +
      '</div>' +
      '<p class="card__footer" id="footerText"></p>' +
      '</div>';

    document.getElementById('locationName').textContent = name;
    document.getElementById('dateLabel').textContent = dateLabel;
    document.getElementById('badgeLabel').textContent = relLabel;
    document.getElementById('conditionLabel').textContent = desc.label;
    document.getElementById('coordsLabel').textContent = formatCoords(lat, lon);
    document.getElementById('statHigh').textContent = maxT + '°C';
    document.getElementById('statLow').textContent = minT + '°C';
    document.getElementById('footerText').textContent = 'Source: Open-Meteo · ' + (endpoint === '/api/om/archive' ? 'Historical Archive API' : 'Forecast API');
    document.title = name + ' · Weather';

    attachChartInteractivity(chart);
  }

  function validateAndRender(data) {
    const daily = data && data.daily;
    const hourly = data && data.hourly;
    const ok = daily && Array.isArray(daily.temperature_2m_max) && daily.temperature_2m_max.length &&
      Array.isArray(daily.temperature_2m_min) && daily.temperature_2m_min.length &&
      Array.isArray(daily.weather_code) && daily.weather_code.length &&
      hourly && Array.isArray(hourly.time) && Array.isArray(hourly.temperature_2m) &&
      hourly.time.length && hourly.time.length === hourly.temperature_2m.length;
    if (!ok) {
      renderError('Weather data for this location and date is unavailable.');
      return;
    }
    renderCard({
      max: daily.temperature_2m_max[0],
      min: daily.temperature_2m_min[0],
      code: daily.weather_code[0],
      hourlyTimes: hourly.time,
      hourlyTemps: hourly.temperature_2m
    });
  }

  async function loadWeather() {
    renderLoading();
    try {
      const res = await fetch(apiUrl);
      let data;
      try {
        data = await res.json();
      } catch (parseErr) {
        throw new Error('The server returned an unreadable response.');
      }
      if (!res.ok) {
        const reason = (data && data.reason) ? data.reason : ('Request failed with status ' + res.status + '.');
        throw new Error(reason);
      }
      if (data && data.error) {
        throw new Error(data.reason || 'The weather service returned an error.');
      }
      validateAndRender(data);
    } catch (err) {
      renderError((err && err.message) ? err.message : 'Something went wrong while loading weather data.');
    }
  }

  loadWeather();
})();
</script>
</body>
</html>

L1 — cheap deterministic descriptors

bytes total29,003html / css / js291 / 7,375 / 21,337
dom nodes10dom depth3
css rules70js presentyes
brightness101.1contrast26.3
colorfulness20.8whitespace31.5%

This slot's telemetry

prompt tokens48completion tokens120,348
total tokens120,396wall1,380.5 s
cost—request id—
config.json585 B
{
  "N": 2,
  "auth": {
    "credential_ref": "WCB_NONE",
    "method": "oauth-login"
  },
  "billing": "plan",
  "config_id": "claude-sonnet-5-eff-max--cli--claude-code--dev",
  "effort": "max",
  "family": "claude",
  "m": {
    "min": 2,
    "q": 2
  },
  "model_id": "claude-sonnet-5",
  "protocol": "cli",
  "served_model": "claude-haiku-4-5-20251001",
  "telemetry": {
    "completion_tokens": 338250,
    "cost_usd": null,
    "prompt_tokens": 92,
    "total_tokens": 338342,
    "wall_ms": 3794199
  },
  "transport": "claude-code-cli-headless",
  "vendor_sanction_ref": null
}
send-log2.5 KB
{
  "N": 2,
  "batch_id": "2026-07-20--refill4-cc-sonnet5-max",
  "config_id": "claude-sonnet-5-eff-max--cli--claude-code--dev",
  "positions": [
    {
      "attempts": [
        {
          "attempt_index": 0,
          "backoff_ms": null,
          "charged": true,
          "ended_at": "2026-07-20T11:35:38.122160+00:00",
          "http_status": null,
          "outcome": "valid",
          "reached_model": true,
          "reason": "ok",
          "request_id": null,
          "started_at": "2026-07-20T11:25:05.181904+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-20T11:58:43.086041+00:00",
          "http_status": null,
          "outcome": "valid",
          "reached_model": true,
          "reason": "ok",
          "request_id": null,
          "started_at": "2026-07-20T11:35:42.572651+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-20T12:23:34.901949+00:00",
          "http_status": null,
          "outcome": "valid",
          "reached_model": true,
          "reason": "ok",
          "request_id": null,
          "started_at": "2026-07-20T11:58:47.059152+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-20T12:28:32.176241+00:00",
          "http_status": null,
          "outcome": "valid",
          "reached_model": true,
          "reason": "ok",
          "request_id": null,
          "started_at": "2026-07-20T12:23:39.224864+00:00"
        }
      ],
      "block_index": 1,
      "model_reaching_attempt_index": 0,
      "slot_index": 1,
      "terminal_state": "valid",
      "variant": "P-min"
    }
  ],
  "retry_policy": {
    "max_unreachable_retries": 5,
    "rate_limit_backoff": {
      "max_attempts": 4,
      "max_total_ms": 60000
    }
  }
}