export function mount({ root, state, host }) {
  state = state || {};
  const __cleanup = [];
  const __setInterval = (...args) => {
    const id = window.setInterval(...args);
    __cleanup.push(() => window.clearInterval(id));
    return id;
  };
  const __setTimeout = (...args) => {
    const id = window.setTimeout(...args);
    __cleanup.push(() => window.clearTimeout(id));
    return id;
  };
  if (!(root instanceof HTMLElement)) return;

  const headlineEl = root.querySelector('[data-calendar-headline]');
  const detailEl = root.querySelector('[data-calendar-detail]');
  const allDayWrapEl = root.querySelector('[data-calendar-all-day-wrap]');
  const allDayEl = root.querySelector('[data-calendar-all-day]');
  const emptyEl = root.querySelector('[data-calendar-empty]');
  const timelineShellEl = root.querySelector('[data-calendar-timeline-shell]');
  const weatherScaleEl = root.querySelector('[data-calendar-weather-scale]');
  const weatherLowEl = root.querySelector('[data-calendar-weather-low]');
  const weatherHighEl = root.querySelector('[data-calendar-weather-high]');
  const timelineEl = root.querySelector('[data-calendar-timeline]');

  if (!(headlineEl instanceof HTMLElement) ||
      !(detailEl instanceof HTMLElement) ||
      !(allDayWrapEl instanceof HTMLElement) ||
      !(allDayEl instanceof HTMLElement) ||
      !(emptyEl instanceof HTMLElement) ||
      !(timelineShellEl instanceof HTMLElement) ||
      !(weatherScaleEl instanceof HTMLElement) ||
      !(weatherLowEl instanceof HTMLElement) ||
      !(weatherHighEl instanceof HTMLElement) ||
      !(timelineEl instanceof HTMLElement)) {
    return;
  }

  const subtitle = typeof state.subtitle === 'string' ? state.subtitle.trim() : '';
  const configuredToolName = typeof state.tool_name === 'string' ? state.tool_name.trim() : '';
  const calendarNames = Array.isArray(state.calendar_names)
    ? state.calendar_names.map((value) => String(value || '').trim()).filter(Boolean)
    : [];
  const refreshMsRaw = Number(state.refresh_ms);
  const refreshMs = Number.isFinite(refreshMsRaw) && refreshMsRaw >= 60000 ? refreshMsRaw : 15 * 60 * 1000;
  const configuredWeatherToolName = typeof state.weather_tool_name === 'string' ? state.weather_tool_name.trim() : 'exec';
  const weatherCommand = typeof state.weather_command === 'string' ? state.weather_command.trim() : '';
  const minStartHourRaw = Number(state.min_start_hour);
  const maxEndHourRaw = Number(state.max_end_hour);
  const minWindowHoursRaw = Number(state.min_window_hours);
  const slotHeightRaw = Number(state.slot_height);
  const minStartHour = Number.isFinite(minStartHourRaw) ? Math.max(0, Math.min(23, Math.round(minStartHourRaw))) : 6;
  const maxEndHour = Number.isFinite(maxEndHourRaw) ? Math.max(minStartHour + 1, Math.min(24, Math.round(maxEndHourRaw))) : 22;
  const minWindowMinutes = (Number.isFinite(minWindowHoursRaw) ? Math.max(3, Math.min(18, minWindowHoursRaw)) : 6) * 60;
  const slotHeight = Number.isFinite(slotHeightRaw) ? Math.max(14, Math.min(24, Math.round(slotHeightRaw))) : 18;
  const emptyText = typeof state.empty_text === 'string' && state.empty_text.trim()
    ? state.empty_text.trim()
    : 'No events for today.';

  const LABEL_WIDTH = 42;
  const TRACK_TOP_PAD = 6;
  const TOOL_FALLBACK = configuredToolName || 'mcp_home_assistant_calendar_get_events';

  let latestEvents = [];
  let latestSelectedCalendars = [];
  let latestUpdatedAt = '';
  let latestWeatherPoints = [];
  let latestWeatherRange = null;
  let clockIntervalId = null;

  emptyEl.textContent = emptyText;

  const updateLiveContent = (snapshot) => {
    host.setLiveContent(snapshot);
  };

  const normalizeDateValue = (value) => {
    if (typeof value === 'string') return value;
    if (value && typeof value === 'object') {
      if (typeof value.dateTime === 'string') return value.dateTime;
      if (typeof value.date === 'string') return value.date;
    }
    return '';
  };

  const isAllDay = (start, end) =>
    /^\d{4}-\d{2}-\d{2}$/.test(normalizeDateValue(start)) ||
    /^\d{4}-\d{2}-\d{2}$/.test(normalizeDateValue(end));

  const parseDate = (value, allDay, endOfDay = false) => {
    const raw = normalizeDateValue(value);
    if (!raw) return null;
    const normalized = /^\d{4}-\d{2}-\d{2}$/.test(raw)
      ? `${raw}T${endOfDay ? '23:59:59' : '00:00:00'}`
      : raw;
    const date = new Date(normalized);
    return Number.isNaN(date.getTime()) ? null : date;
  };

  const eventBounds = (event) => {
    const allDay = isAllDay(event?.start, event?.end);
    const startDate = parseDate(event?.start, allDay, false);
    const endDate = parseDate(event?.end, allDay, allDay);
    if (!startDate) return null;
    const start = startDate.getTime();
    let end = endDate ? endDate.getTime() : start + 30 * 60 * 1000;
    if (!Number.isFinite(end) || end <= start) end = start + 30 * 60 * 1000;
    return { start, end, allDay };
  };

  const formatClock = (date) => {
    const hours = String(date.getHours()).padStart(2, '0');
    const minutes = String(date.getMinutes()).padStart(2, '0');
    return `${hours}:${minutes}`;
  };
  const formatShortDate = (date) => date.toLocaleDateString([], { weekday: 'short', month: 'short', day: 'numeric' });

  const formatDistance = (ms) => {
    const totalMinutes = Math.max(0, Math.round(ms / 60000));
    const hours = Math.floor(totalMinutes / 60);
    const minutes = totalMinutes % 60;
    if (hours <= 0) return `${minutes}m`;
    if (minutes === 0) return `${hours}h`;
    return `${hours}h ${minutes}m`;
  };

  const formatTimeRange = (event) => {
    const bounds = eventBounds(event);
    if (!bounds) return '--';
    if (bounds.allDay) return 'All day';
    return `${formatClock(new Date(bounds.start))}–${formatClock(new Date(bounds.end))}`;
  };

  const hourLabel = (minutes) => String(Math.floor(minutes / 60)).padStart(2, '0');

  const minutesIntoDay = (time) => {
    const date = new Date(time);
    return date.getHours() * 60 + date.getMinutes();
  };

  const roundDownToHalfHour = (minutes) => Math.floor(minutes / 30) * 30;
  const roundUpToHalfHour = (minutes) => Math.ceil(minutes / 30) * 30;

  const computeWeatherWindow = () => {
    if (!Array.isArray(latestWeatherPoints) || latestWeatherPoints.length < 2) return null;
    const sorted = latestWeatherPoints
      .map((point) => minutesIntoDay(point.time))
      .filter((minutes) => Number.isFinite(minutes))
      .sort((left, right) => left - right);
    if (sorted.length < 2) return null;
    const start = roundDownToHalfHour(sorted[0]);
    const end = roundUpToHalfHour(sorted[sorted.length - 1]);
    if (end <= start) return null;
    return { start, end };
  };

  const computeVisibleWindow = (events) => {
    const now = new Date();
    const nowMinutes = now.getHours() * 60 + now.getMinutes();
    const timedEvents = events.filter((event) => !event._allDay);
    const weatherWindow = computeWeatherWindow();

    if (timedEvents.length === 0) {
      let start = roundDownToHalfHour(nowMinutes - 120);
      let end = start + minWindowMinutes;
      const minBound = minStartHour * 60;
      const maxBound = maxEndHour * 60;
      if (start < minBound) {
        start = minBound;
        end = start + minWindowMinutes;
      }
      if (end > maxBound) {
        end = maxBound;
        start = Math.max(minBound, end - minWindowMinutes);
      }
      if (weatherWindow) {
        start = Math.max(start, weatherWindow.start);
        end = Math.min(end, weatherWindow.end);
        if (end <= start) return { start: weatherWindow.start, end: weatherWindow.end };
      }
      return { start, end };
    }

    const earliest = Math.min(nowMinutes, ...timedEvents.map((event) => minutesIntoDay(event._start)));
    const latest = Math.max(nowMinutes + 30, ...timedEvents.map((event) => minutesIntoDay(event._end)));

    let start = roundDownToHalfHour(earliest - 60);
    let end = roundUpToHalfHour(latest + 90);
    if (end - start < minWindowMinutes) {
      const center = roundDownToHalfHour((earliest + latest) / 2);
      start = center - Math.floor(minWindowMinutes / 2);
      end = start + minWindowMinutes;
    }

    const minBound = minStartHour * 60;
    const maxBound = maxEndHour * 60;

    if (start < minBound) {
      const shift = minBound - start;
      start += shift;
      end += shift;
    }
    if (end > maxBound) {
      const shift = end - maxBound;
      start -= shift;
      end -= shift;
    }
    start = Math.max(minBound, start);
    end = Math.min(maxBound, end);
    if (end - start < 120) {
      end = Math.min(maxBound, start + 120);
    }
    if (weatherWindow) {
      start = Math.max(start, weatherWindow.start);
      end = Math.min(end, weatherWindow.end);
      if (end <= start) return { start: weatherWindow.start, end: weatherWindow.end };
    }
    return { start, end };
  };

  const assignColumns = (events) => {
    const timed = events.filter((event) => !event._allDay).sort((left, right) => left._start - right._start);
    let active = [];
    let cluster = [];
    let clusterEnd = -Infinity;
    let clusterMax = 1;

    const finalizeCluster = () => {
      for (const item of cluster) item._columns = clusterMax;
    };

    for (const event of timed) {
      if (cluster.length > 0 && event._start >= clusterEnd) {
        finalizeCluster();
        active = [];
        cluster = [];
        clusterEnd = -Infinity;
        clusterMax = 1;
      }
      active = active.filter((item) => item.end > event._start);
      const used = new Set(active.map((item) => item.column));
      let column = 0;
      while (used.has(column)) column += 1;
      event._column = column;
      active.push({ end: event._end, column });
      cluster.push(event);
      clusterEnd = Math.max(clusterEnd, event._end);
      clusterMax = Math.max(clusterMax, active.length, column + 1);
    }

    if (cluster.length > 0) finalizeCluster();
    return timed;
  };

  const extractEvents = (toolResult) => {
    if (toolResult && toolResult.parsed && typeof toolResult.parsed === 'object' && Array.isArray(toolResult.parsed.result)) {
      return toolResult.parsed.result;
    }
    if (typeof toolResult?.content === 'string') {
      try {
        const parsed = JSON.parse(toolResult.content);
        if (parsed && typeof parsed === 'object' && Array.isArray(parsed.result)) return parsed.result;
      } catch {}
    }
    return [];
  };

  const stripExecFooter = (value) => String(value || '').replace(/\n+\s*Exit code:\s*\d+\s*$/i, '').trim();

  const extractExecJson = (toolResult) => {
    const text = stripExecFooter(toolResult?.content);
    if (!text) return null;
    try {
      return JSON.parse(text);
    } catch {
      return null;
    }
  };

  const forecastTime = (entry) => {
    const time = new Date(String(entry?.datetime || '')).getTime();
    return Number.isFinite(time) ? time : Number.NaN;
  };

  const extractWeatherPoints = (payload) => {
    const rows = Array.isArray(payload?.nws?.forecast) ? payload.nws.forecast : [];
    const today = new Date();
    const dayStart = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 0, 0, 0, 0).getTime();
    const dayEnd = dayStart + 24 * 60 * 60 * 1000;
    return rows
      .map((entry) => {
        const time = forecastTime(entry);
        const temp = Number(entry?.temperature);
        if (!Number.isFinite(time) || !Number.isFinite(temp)) return null;
        if (time < dayStart || time >= dayEnd) return null;
        return {
          time,
          temp,
        };
      })
      .filter(Boolean);
  };

  const resolveWeatherForecast = async () => {
    if (!weatherCommand) return [];
    const toolResult = await host.callTool(configuredWeatherToolName || 'exec', {
      command: weatherCommand,
      max_output_chars: 200000,
    });
    const payload = extractExecJson(toolResult);
    if (!payload || typeof payload !== 'object') return [];
    return extractWeatherPoints(payload);
  };

  const resolveToolConfig = async () => {
    if (!host.listTools) {
      return { name: TOOL_FALLBACK, availableCalendars: calendarNames };
    }
    try {
      const tools = await host.listTools();
      const tool = Array.isArray(tools)
        ? tools.find((item) => /(^|_)calendar_get_events$/i.test(String(item?.name || '')))
        : null;
      const enumValues = Array.isArray(tool?.parameters?.properties?.calendar?.enum)
        ? tool.parameters.properties.calendar.enum.map((value) => String(value || '').trim()).filter(Boolean)
        : [];
      return {
        name: tool?.name || TOOL_FALLBACK,
        availableCalendars: enumValues,
      };
    } catch {
      return { name: TOOL_FALLBACK, availableCalendars: calendarNames };
    }
  };

  const computeScore = (events, nowTime) => {
    const current = events.find((event) => !event._allDay && event._start <= nowTime && event._end > nowTime);
    if (current) return 99;
    const next = events.find((event) => !event._allDay && event._start > nowTime);
    if (!next) {
      if (events.some((event) => event._allDay)) return 74;
      return 18;
    }
    const minutesAway = Math.max(0, Math.round((next._start - nowTime) / 60000));
    let score = 70;
    if (minutesAway <= 15) score = 98;
    else if (minutesAway <= 30) score = 95;
    else if (minutesAway <= 60) score = 92;
    else if (minutesAway <= 180) score = 88;
    else if (minutesAway <= 360) score = 82;
    else score = 76;
    score += Math.min(events.length, 3);
    return Math.min(100, score);
  };

  const createAllDayChip = (event) => {
    const chip = document.createElement('div');
    chip.style.padding = '3px 6px';
    chip.style.border = '1px solid rgba(161, 118, 84, 0.28)';
    chip.style.background = 'rgba(255, 249, 241, 0.94)';
    chip.style.color = '#5e412d';
    chip.style.fontSize = '0.62rem';
    chip.style.lineHeight = '1.2';
    chip.style.fontWeight = '700';
    chip.style.minWidth = '0';
    chip.style.maxWidth = '100%';
    chip.style.overflow = 'hidden';
    chip.style.textOverflow = 'ellipsis';
    chip.style.whiteSpace = 'nowrap';
    chip.textContent = String(event.summary || '(No title)');
    return chip;
  };

  const computeWeatherRange = (points) => {
    if (!Array.isArray(points) || points.length === 0) return null;
    let low = Number.POSITIVE_INFINITY;
    let high = Number.NEGATIVE_INFINITY;
    for (const point of points) {
      low = Math.min(low, point.temp);
      high = Math.max(high, point.temp);
    }
    if (!Number.isFinite(low) || !Number.isFinite(high)) return null;
    if (low === high) high = low + 1;
    return { low, high };
  };

  const renderWeatherGraph = (windowRange, timelineHeight) => {
    weatherScaleEl.style.display = 'none';
    weatherLowEl.textContent = '--';
    weatherHighEl.textContent = '--';

    if (!Array.isArray(latestWeatherPoints) || latestWeatherPoints.length === 0 || !latestWeatherRange) return;

    const visiblePoints = latestWeatherPoints.filter((point) => {
      const minutes = minutesIntoDay(point.time);
      return minutes >= windowRange.start && minutes <= windowRange.end;
    });
    if (visiblePoints.length < 2) return;

    weatherScaleEl.style.display = 'flex';
    weatherLowEl.textContent = `${Math.round(latestWeatherRange.low)}°`;
    weatherHighEl.textContent = `${Math.round(latestWeatherRange.high)}°`;

    const timelineWidth = timelineEl.getBoundingClientRect().width;
    const overlayWidth = Math.max(1, timelineWidth - (LABEL_WIDTH + 6));

    const overlay = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
    overlay.setAttribute('viewBox', `0 0 ${overlayWidth} ${timelineHeight}`);
    overlay.style.position = 'absolute';
    overlay.style.left = `${LABEL_WIDTH + 6}px`;
    overlay.style.top = '0';
    overlay.style.height = `${timelineHeight}px`;
    overlay.style.width = `${overlayWidth}px`;
    overlay.style.pointerEvents = 'none';
    overlay.style.opacity = '0.85';

    const toPoint = (point) => {
      const minutes = minutesIntoDay(point.time);
      const y = TRACK_TOP_PAD + ((minutes - windowRange.start) / 30) * slotHeight;
      const x = ((point.temp - latestWeatherRange.low) / (latestWeatherRange.high - latestWeatherRange.low)) * overlayWidth;
      return { x, y };
    };

    const coords = visiblePoints.map(toPoint);
    const buildSmoothPath = (points) => {
      if (points.length === 0) return '';
      if (points.length === 1) return `M ${points[0].x.toFixed(2)} ${points[0].y.toFixed(2)}`;
      let d = `M ${points[0].x.toFixed(2)} ${points[0].y.toFixed(2)}`;
      for (let index = 1; index < points.length - 1; index += 1) {
        const point = points[index];
        const next = points[index + 1];
        const midX = (point.x + next.x) / 2;
        const midY = (point.y + next.y) / 2;
        d += ` Q ${point.x.toFixed(2)} ${point.y.toFixed(2)} ${midX.toFixed(2)} ${midY.toFixed(2)}`;
      }
      const penultimate = points[points.length - 2];
      const last = points[points.length - 1];
      d += ` Q ${penultimate.x.toFixed(2)} ${penultimate.y.toFixed(2)} ${last.x.toFixed(2)} ${last.y.toFixed(2)}`;
      return d;
    };

    const line = document.createElementNS('http://www.w3.org/2000/svg', 'path');
    line.setAttribute('d', buildSmoothPath(coords));
    line.setAttribute('fill', 'none');
    line.setAttribute('stroke', 'rgba(184, 110, 58, 0.34)');
    line.setAttribute('stroke-width', '1.8');
    line.setAttribute('stroke-linecap', 'round');
    line.setAttribute('stroke-linejoin', 'round');
    line.setAttribute('vector-effect', 'non-scaling-stroke');
    overlay.appendChild(line);

    for (const point of coords) {
      const dot = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
      dot.setAttribute('cx', point.x.toFixed(2));
      dot.setAttribute('cy', point.y.toFixed(2));
      dot.setAttribute('r', '1.9');
      dot.setAttribute('fill', 'rgba(184, 110, 58, 0.34)');
      dot.setAttribute('stroke', 'rgba(226, 188, 156, 0.62)');
      dot.setAttribute('stroke-width', '0.55');
      overlay.appendChild(dot);
    }

    timelineEl.appendChild(overlay);
  };

  const renderState = () => {
    const now = new Date();
    const nowTime = now.getTime();
    const todayLabel = formatShortDate(now);
    if (!Array.isArray(latestEvents) || latestEvents.length === 0) {
      headlineEl.textContent = todayLabel;
      detailEl.textContent = emptyText;
      allDayWrapEl.style.display = 'none';
      timelineShellEl.style.display = 'none';
      emptyEl.style.display = 'block';
      updateLiveContent({
        kind: 'calendar_timeline',
        subtitle: subtitle || null,
        tool_name: TOOL_FALLBACK,
        calendar_names: latestSelectedCalendars,
        updated_at: latestUpdatedAt || null,
        now_label: formatClock(now),
        headline: headlineEl.textContent || null,
        detail: detailEl.textContent || null,
        weather_temperature_range: latestWeatherRange ? {
          low: latestWeatherRange.low,
          high: latestWeatherRange.high,
        } : null,
        event_count: 0,
        all_day_count: 0,
        score: 18,
        events: [],
      });
      return;
    }

    const allDayEvents = latestEvents.filter((event) => event._allDay);
    const timedEvents = latestEvents.filter((event) => !event._allDay);
    const currentEvent = timedEvents.find((event) => event._start <= nowTime && event._end > nowTime) || null;
    const nextEvent = timedEvents.find((event) => event._start > nowTime) || null;

    headlineEl.textContent = todayLabel;

    if (currentEvent) {
      detailEl.textContent = '';
    } else if (nextEvent) {
      detailEl.textContent = '';
    } else if (allDayEvents.length > 0) {
      detailEl.textContent = 'All-day events on your calendar.';
    } else {
      detailEl.textContent = 'Your calendar is clear for the rest of the day.';
    }

    const windowRange = computeVisibleWindow(latestEvents);
    allDayEl.innerHTML = '';
    allDayWrapEl.style.display = allDayEvents.length > 0 ? 'block' : 'none';
    for (const event of allDayEvents) allDayEl.appendChild(createAllDayChip(event));

    emptyEl.style.display = 'none';
    timelineShellEl.style.display = timedEvents.length > 0 ? 'block' : 'none';
    timelineEl.innerHTML = '';

    if (timedEvents.length > 0) {
      const slotCount = Math.max(1, Math.round((windowRange.end - windowRange.start) / 30));
      const timelineHeight = TRACK_TOP_PAD + slotCount * slotHeight;
      timelineEl.style.height = `${timelineHeight}px`;

      const gridLayer = document.createElement('div');
      gridLayer.style.position = 'absolute';
      gridLayer.style.inset = '0';
      timelineEl.appendChild(gridLayer);

      for (let index = 0; index <= slotCount; index += 1) {
        const minutes = windowRange.start + index * 30;
        const top = TRACK_TOP_PAD + index * slotHeight;

        const line = document.createElement('div');
        line.style.position = 'absolute';
        line.style.left = `${LABEL_WIDTH}px`;
        line.style.right = '0';
        line.style.top = `${top}px`;
        line.style.borderTop = minutes % 60 === 0
          ? '1px solid rgba(143, 101, 69, 0.24)'
          : '1px dashed rgba(181, 145, 116, 0.18)';
        gridLayer.appendChild(line);

        if (minutes % 60 === 0 && minutes < windowRange.end) {
          const label = document.createElement('div');
          label.style.position = 'absolute';
          label.style.left = '0';
          label.style.top = `${Math.max(0, top - 7)}px`;
          label.style.width = `${LABEL_WIDTH - 8}px`;
          label.style.fontFamily = "'M-1m Code', ui-monospace, Menlo, Consolas, monospace";
          label.style.fontSize = '0.54rem';
          label.style.lineHeight = '1';
          label.style.color = '#8a6248';
          label.style.textAlign = 'right';
          label.style.textTransform = 'uppercase';
          label.style.letterSpacing = '0.05em';
          label.textContent = hourLabel(minutes);
          gridLayer.appendChild(label);
        }
      }

      renderWeatherGraph(windowRange, timelineHeight);

      const eventsLayer = document.createElement('div');
      eventsLayer.style.position = 'absolute';
      eventsLayer.style.left = `${LABEL_WIDTH + 6}px`;
      eventsLayer.style.right = '0';
      eventsLayer.style.top = `${TRACK_TOP_PAD}px`;
      eventsLayer.style.bottom = '0';
      timelineEl.appendChild(eventsLayer);

      const layoutEvents = assignColumns(timedEvents.map((event) => ({ ...event })));
      for (const event of layoutEvents) {
        const offsetStart = Math.max(windowRange.start, minutesIntoDay(event._start)) - windowRange.start;
        const offsetEnd = Math.min(windowRange.end, minutesIntoDay(event._end)) - windowRange.start;
        const top = Math.max(0, (offsetStart / 30) * slotHeight);
        const height = Math.max(16, ((offsetEnd - offsetStart) / 30) * slotHeight - 3);

        const block = document.createElement('div');
        block.style.position = 'absolute';
        block.style.top = `${top}px`;
        block.style.height = `${height}px`;
        block.style.left = `calc(${(100 / event._columns) * event._column}% + ${event._column * 4}px)`;
        block.style.width = `calc(${100 / event._columns}% - 4px)`;
        block.style.padding = '5px 6px';
        block.style.border = currentEvent && currentEvent._start === event._start && currentEvent._end === event._end
          ? '1px solid rgba(169, 39, 29, 0.38)'
          : '1px solid rgba(162, 105, 62, 0.26)';
        block.style.background = currentEvent && currentEvent._start === event._start && currentEvent._end === event._end
          ? 'linear-gradient(180deg, rgba(255, 228, 224, 0.98) 0%, rgba(248, 205, 198, 0.94) 100%)'
          : 'linear-gradient(180deg, rgba(244, 220, 196, 0.98) 0%, rgba(230, 197, 165, 0.98) 100%)';
        block.style.boxShadow = '0 4px 10px rgba(84, 51, 29, 0.08)';
        block.style.overflow = 'hidden';

        const title = document.createElement('div');
        title.style.fontFamily = "'IBM Plex Sans Condensed', 'Arial Narrow', sans-serif";
        title.style.fontSize = '0.74rem';
        title.style.lineHeight = '0.98';
        title.style.letterSpacing = '-0.01em';
        title.style.color = '#22140c';
        title.style.fontWeight = '700';
        title.style.whiteSpace = 'nowrap';
        title.style.textOverflow = 'ellipsis';
        title.style.overflow = 'hidden';
        title.textContent = String(event.summary || '(No title)');
        block.appendChild(title);

        eventsLayer.appendChild(block);
      }

      if (nowTime >= new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, windowRange.start, 0, 0).getTime() &&
          nowTime <= new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, windowRange.end, 0, 0).getTime()) {
        const nowMinutes = now.getHours() * 60 + now.getMinutes();
        const nowTop = TRACK_TOP_PAD + ((nowMinutes - windowRange.start) / 30) * slotHeight;

        const line = document.createElement('div');
        line.style.position = 'absolute';
        line.style.left = `${LABEL_WIDTH + 6}px`;
        line.style.right = '0';
        line.style.top = `${nowTop}px`;
        line.style.borderTop = '1.5px solid #cf2f21';
        line.style.transition = 'top 28s linear';
        timelineEl.appendChild(line);

        const dot = document.createElement('div');
        dot.style.position = 'absolute';
        dot.style.left = `${LABEL_WIDTH + 1}px`;
        dot.style.top = `${nowTop - 4}px`;
        dot.style.width = '8px';
        dot.style.height = '8px';
        dot.style.borderRadius = '999px';
        dot.style.background = '#cf2f21';
        dot.style.boxShadow = '0 0 0 2px rgba(255, 255, 255, 0.95)';
        dot.style.transition = 'top 28s linear';
        timelineEl.appendChild(dot);

      }
    }

    updateLiveContent({
      kind: 'calendar_timeline',
      subtitle: subtitle || null,
      tool_name: TOOL_FALLBACK,
      calendar_names: latestSelectedCalendars,
      updated_at: latestUpdatedAt || null,
      now_label: formatClock(now),
      headline: headlineEl.textContent || null,
      detail: detailEl.textContent || null,
      weather_temperature_range: latestWeatherRange ? {
        low: latestWeatherRange.low,
        high: latestWeatherRange.high,
      } : null,
      current_event: currentEvent ? {
        summary: String(currentEvent.summary || '(No title)'),
        start: normalizeDateValue(currentEvent.start) || null,
        end: normalizeDateValue(currentEvent.end) || null,
      } : null,
      next_event: nextEvent ? {
        summary: String(nextEvent.summary || '(No title)'),
        start: normalizeDateValue(nextEvent.start) || null,
        end: normalizeDateValue(nextEvent.end) || null,
        starts_in: formatDistance(nextEvent._start - nowTime),
      } : null,
      event_count: latestEvents.length,
      all_day_count: allDayEvents.length,
      score: computeScore(latestEvents, nowTime),
      events: latestEvents.map((event) => ({
        summary: String(event.summary || '(No title)'),
        start: normalizeDateValue(event.start) || null,
        end: normalizeDateValue(event.end) || null,
        all_day: Boolean(event._allDay),
      })),
    });
  };

  const refresh = async () => {
    headlineEl.textContent = 'Loading today…';
    detailEl.textContent = 'Checking your calendar.';

    try {
      const toolConfig = await resolveToolConfig();
      const selectedCalendars = calendarNames.length > 0 ? calendarNames : toolConfig.availableCalendars;
      if (!toolConfig.name) throw new Error('Calendar tool unavailable');
      if (!Array.isArray(selectedCalendars) || selectedCalendars.length === 0) {
        throw new Error('No calendars configured');
      }

      const [weatherPoints, allEvents] = await Promise.all([
        resolveWeatherForecast().catch(() => []),
        (async () => {
          const allEvents = [];
          for (const calendarName of selectedCalendars) {
            const toolResult = await host.callTool(toolConfig.name, {
              calendar: calendarName,
              range: 'today',
            });
            const events = extractEvents(toolResult);
            for (const event of events) {
              const bounds = eventBounds(event);
              if (!bounds) continue;
              allEvents.push({
                ...event,
                _calendarName: calendarName,
                _start: bounds.start,
                _end: bounds.end,
                _allDay: bounds.allDay,
              });
            }
          }
          return allEvents;
        })(),
      ]);

      allEvents.sort((left, right) => left._start - right._start);
      latestWeatherPoints = weatherPoints;
      latestWeatherRange = computeWeatherRange(weatherPoints);
      latestEvents = allEvents;
      latestSelectedCalendars = selectedCalendars;
      latestUpdatedAt = new Date().toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' });
      renderState();
    } catch (error) {
      const errorText = String(error);
      latestWeatherPoints = [];
      latestWeatherRange = null;
      latestEvents = [];
      latestSelectedCalendars = calendarNames;
      latestUpdatedAt = errorText;
      headlineEl.textContent = formatShortDate(new Date());
      detailEl.textContent = errorText;
      allDayWrapEl.style.display = 'none';
      timelineShellEl.style.display = 'none';
      emptyEl.style.display = 'block';
      updateLiveContent({
        kind: 'calendar_timeline',
        subtitle: subtitle || null,
        tool_name: TOOL_FALLBACK,
        calendar_names: latestSelectedCalendars,
        updated_at: errorText,
        now_label: formatClock(new Date()),
        headline: headlineEl.textContent || null,
        detail: detailEl.textContent || null,
        weather_temperature_range: null,
        event_count: 0,
        all_day_count: 0,
        score: 0,
        events: [],
        error: errorText,
      });
    }
  };

  host.setRefreshHandler(() => {
    void refresh();
  });

  if (clockIntervalId) window.clearInterval(clockIntervalId);
  clockIntervalId = __setInterval(() => {
    renderState();
  }, 30000);

  void refresh();
  __setInterval(() => {
    void refresh();
  }, refreshMs);

  return {
    destroy() {
      host.setRefreshHandler(null);
      host.setLiveContent(null);
      host.clearSelection();
      for (const cleanup of __cleanup.splice(0)) cleanup();
    },
  };
}
