{"version":3,"file":"element-BG0OnGub.cjs","names":["parseFuzzyDate","resolveInstant","utcTime","resolveInstant","utcTime","CSS","#handleDocumentClick","#closePopover","#handleWheel","#root","#container","#handleZoomKeydown","#handleMarkerKeydown","#state","#abortFetch","#ingest","#resizeObserver","#lastWidth","#resolveOrientation","#renderedOrientation","#render","#cancelZoomDraw","#fetchSrc","#zoom","#minZoom","#baseWidthCache","validateTimelineData","#dispatch","#abort","#viewport","#scale","#zoomControls","#pendingAnchor","#statusBox","#errorBox","#renderContext","#zoomEnabled","#onWheel","#drawPlot","#legendEnabled","#buildLegend","#buildZoomControls","#applyRovingTabindex","#syncZoomControls","#togglePopover","#markers","#viewportWidth","#baseWidth","#scheduleZoomDraw","#drawZoom","#zoomFrame","#renderPlot","#setZoom","#zoomLabel","#openEventId","#openAnchor","#onDocumentClick","#onDocumentKeydown"],"sources":["../src/model/normalize.ts","../src/render/format.ts","../src/render/url.ts","../src/render/event-card.ts","../src/layout/lanes.ts","../src/layout/scale.ts","../src/render/axis.ts","../src/render/render.ts","../src/render/styles.ts","../src/render/vertical.ts","../src/element.ts"],"sourcesContent":["import type { TimarroEvent, TimarroTimelineData } from '../schema/types';\nimport { parseFuzzyDate, resolveInstant, type DateParts, type ResolvedInstant } from './date';\n\n/** A validated event resolved onto the time axis — the renderer's working unit. */\nexport interface ResolvedEvent {\n  src: TimarroEvent;\n  start: ResolvedInstant;\n  end?: ResolvedInstant | undefined;\n  startParts: DateParts;\n  endParts?: DateParts | undefined;\n  /** True when the event carries visible uncertainty: year/month precision or `circa`. */\n  fuzzy: boolean;\n}\n\nexport interface NormalizedTimeline {\n  /** Chronologically sorted (start.mid, then order, then title, then id). */\n  events: ResolvedEvent[];\n  /** `[min earliest, max latest]` across all events; null for an empty timeline. */\n  domain: [number, number] | null;\n}\n\n/**\n * Resolve + sort validated data. Assumes `validateTimelineData` (or the Zod schema)\n * accepted the input — parse errors here indicate a bug, not bad user data.\n */\nexport function normalizeTimelineData(data: TimarroTimelineData): NormalizedTimeline {\n  const events = data.events\n    .map((src): ResolvedEvent => {\n      const startParts = parseFuzzyDate(src.date.start);\n      const endParts = src.date.end !== undefined ? parseFuzzyDate(src.date.end) : undefined;\n      const start = resolveInstant(startParts);\n      const end = endParts !== undefined ? resolveInstant(endParts) : undefined;\n      const fuzzy =\n        src.date.precision === 'year' || src.date.precision === 'month' || src.date.circa === true;\n      return { src, start, end, startParts, endParts, fuzzy };\n    })\n    .sort(compareResolvedEvents);\n\n  let domain: [number, number] | null = null;\n  if (events.length > 0) {\n    let min = Infinity;\n    let max = -Infinity;\n    for (const ev of events) {\n      min = Math.min(min, ev.start.earliest);\n      max = Math.max(max, (ev.end ?? ev.start).latest);\n    }\n    domain = [min, max];\n  }\n  return { events, domain };\n}\n\n/**\n * Total, deterministic order: start midpoint → `order` (default 0) → title → id.\n * Title/id compare by code points (not locale) so sorting is stable across environments.\n */\nexport function compareResolvedEvents(a: ResolvedEvent, b: ResolvedEvent): number {\n  if (a.start.mid !== b.start.mid) return a.start.mid - b.start.mid;\n  const orderA = a.src.order ?? 0;\n  const orderB = b.src.order ?? 0;\n  if (orderA !== orderB) return orderA - orderB;\n  if (a.src.title !== b.src.title) return a.src.title < b.src.title ? -1 : 1;\n  if (a.src.id !== b.src.id) return a.src.id < b.src.id ? -1 : 1;\n  return 0;\n}\n","import type { DateParts } from '../model/date';\nimport { resolveInstant, utcTime } from '../model/date';\nimport type { ResolvedEvent } from '../model/normalize';\nimport type { TickUnit } from '../layout/scale';\n\n/**\n * All formatting goes through Intl with an explicit `timeZone: 'UTC'` — resolved\n * instants are UTC, and letting the viewer's zone shift a date-only value by\n * ±1 day would be a correctness bug, not a localization feature.\n */\n\nexport function formatDateLabel(parts: DateParts, circa: boolean, locale?: string): string {\n  const prefix = circa ? '~' : '';\n  switch (parts.precision) {\n    case 'year':\n      return prefix + String(parts.year);\n    case 'month':\n      return (\n        prefix +\n        new Intl.DateTimeFormat(locale, { month: 'long', year: 'numeric', timeZone: 'UTC' }).format(\n          utcTime(parts.year, parts.month ?? 1),\n        )\n      );\n    case 'day':\n      return (\n        prefix +\n        new Intl.DateTimeFormat(locale, { dateStyle: 'medium', timeZone: 'UTC' }).format(\n          utcTime(parts.year, parts.month ?? 1, parts.day ?? 1),\n        )\n      );\n    case 'datetime':\n      return (\n        prefix +\n        new Intl.DateTimeFormat(locale, {\n          dateStyle: 'medium',\n          timeStyle: 'short',\n          timeZone: 'UTC',\n        }).format(resolveInstant(parts).mid)\n      );\n  }\n}\n\n/** \"May 12, 1943\" / \"May 1943\" / \"1943\" / \"~1943\" / \"1943 – May 1945\". */\nexport function formatEventDate(ev: ResolvedEvent, locale?: string): string {\n  const circa = ev.src.date.circa === true;\n  const startLabel = formatDateLabel(ev.startParts, circa, locale);\n  if (!ev.endParts) return startLabel;\n  return `${startLabel} – ${formatDateLabel(ev.endParts, false, locale)}`;\n}\n\n/** Accessible name for an event's marker button. */\nexport function formatEventAria(ev: ResolvedEvent, locale?: string): string {\n  const approx = ev.src.date.circa === true ? ', approximate' : '';\n  return `${ev.src.title}, ${formatEventDate(ev, locale)}${approx}`;\n}\n\nexport function formatTickLabel(t: number, unit: TickUnit, locale?: string): string {\n  const d = new Date(t);\n  switch (unit) {\n    case 'decade':\n    case 'year':\n      return String(d.getUTCFullYear());\n    case 'month': {\n      const month = new Intl.DateTimeFormat(locale, { month: 'short', timeZone: 'UTC' }).format(t);\n      return d.getUTCMonth() === 0 ? `${month} ${d.getUTCFullYear()}` : month;\n    }\n    case 'day':\n      return new Intl.DateTimeFormat(locale, {\n        month: 'short',\n        day: 'numeric',\n        timeZone: 'UTC',\n      }).format(t);\n  }\n}\n","/**\n * Accept http(s) URLs only — anything else (`javascript:`, `data:`, junk) is\n * dropped.\n *\n * Every URL that ends up in an `src` here arrived inside timeline JSON that the\n * host page fetched from somewhere; none of it is the element's to trust.\n * Resolved against `document.baseURI` so a relative path in the data still\n * points where its author meant it to.\n */\nexport function safeHttpUrl(url: string): string | null {\n  // `new URL('', base)` resolves to the host page itself, which as an image\n  // src is a guaranteed broken icon. An empty field means \"unset\", not \"here\".\n  if (url.trim().length === 0) return null;\n  try {\n    const parsed = new URL(url, document.baseURI);\n    return parsed.protocol === 'http:' || parsed.protocol === 'https:' ? parsed.href : null;\n  } catch {\n    return null;\n  }\n}\n","import type { ResolvedEvent } from '../model/normalize';\nimport { formatEventAria, formatEventDate } from './format';\nimport { safeHttpUrl } from './url';\n\n/** Point events: short label sits above the marker. */\nexport const LANE_HEIGHT = 52;\nexport const AXIS_HEIGHT = 42;\nexport const CANVAS_TOP_PAD = 14;\nexport const POPOVER_WIDTH = 320;\n\n/** Range layout: labeled bars live in their own region below the point events. */\nexport const RANGE_BAR_HEIGHT = 10;\n/**\n * Height of a single range row: title + date above the bar (never straddling it).\n * ~16 title + 2 gap + 12 date + 4 gap + 10 bar ≈ 44, plus breathing room.\n */\nexport const RANGE_ROW_HEIGHT = 56;\n/** Vertical stride between stacked range lanes (row + gap). */\nexport const RANGE_LANE_HEIGHT = 64;\n/** Gap between the point-events region and the ranges region below it. */\nexport const RANGES_TOP_GAP = 14;\n/** Soft cap for estimated / clamped range label width. */\nexport const MAX_LABEL_PX = 200;\n/** Short range bars still get a readable label overhang to the right. */\nexport const MIN_RANGE_LABEL_PX = 120;\n/**\n * Point-event on-canvas titles are shortened to this many letters; the full\n * title is exposed via the native `title` tooltip on hover.\n */\nexport const POINT_LABEL_CHARS = 12;\n\n/** CSS custom property carrying a per-event accent (see {@link safeCssColor}). */\nconst EV_COLOR_VAR = '--ev-color';\n/**\n * The resolved accent token. The stylesheet defines `--_accent` on each\n * color-bearing container as `var(--ev-color, var(--timarro-accent, …))`, so a\n * single-level `var()` here is enough — and stays parseable in non-browser DOMs\n * (happy-dom rejects nested `var()` in inline styles).\n */\nconst ACCENT = 'var(--_accent)';\n\nexport interface PositionedEvent {\n  ev: ResolvedEvent;\n  kind: 'point' | 'range';\n  /** Points: px of start.mid. Ranges: px of the bar's left edge (start.earliest). */\n  x: number;\n  /** Bar width for ranges (uncertainty envelope included); 0 for points. */\n  barWidth: number;\n  /** Left edge of the rendered flex row. */\n  left: number;\n  /** Canvas-px y of the rendered row (marker centre line region). */\n  top: number;\n  /** Horizontal extent (incl. estimated label and band) used for lane packing. */\n  extent: [number, number];\n  lane: number;\n  /** Fuzzy points: canvas-px span of the start uncertainty interval. */\n  band?: [number, number] | undefined;\n  /** Ranges: px width of the endpoint fade when that endpoint is fuzzy. */\n  fadeLeft?: number | undefined;\n  fadeRight?: number | undefined;\n  /**\n   * Ranges only: the full-height translucent band drawn behind the events the\n   * range spans. Height grows with overlap depth so stacked ranges stay legible.\n   */\n  rangeBand?: { left: number; width: number; top: number; height: number } | undefined;\n  /** Sanitized per-event accent, or undefined to inherit the host accent. */\n  color?: string | undefined;\n}\n\n/**\n * Accept a CSS color for use as an inline accent; reject anything else so an\n * untrusted `color` field can't smuggle extra declarations into the style\n * attribute. Uses `CSS.supports` where available (browser), with a conservative\n * literal-form fallback for non-DOM environments.\n */\nexport function safeCssColor(value: unknown): string | null {\n  if (typeof value !== 'string') return null;\n  const v = value.trim();\n  if (v.length === 0 || v.length > 64) return null;\n  // Never allow value-terminating / comment / url tokens regardless of engine.\n  if (/[;{}]/.test(v) || v.includes('/*') || /url\\s*\\(/i.test(v)) return null;\n  if (typeof CSS !== 'undefined' && typeof CSS.supports === 'function') {\n    return CSS.supports('color', v) ? v : null;\n  }\n  // Fallback: hex, a bare keyword, or a numeric color function.\n  return /^#[0-9a-f]{3,8}$/i.test(v) ||\n    /^[a-z]+$/i.test(v) ||\n    /^(rgb|rgba|hsl|hsla|hwb|lab|lch|oklab|oklch|color)\\([\\d\\s.,%/-]+\\)$/i.test(v)\n    ? v\n    : null;\n}\n\n/** Marker shape modifier per precision: ring for month, diamond for year (M5). */\nexport function markerShapeClass(precision: string): string {\n  if (precision === 'year') return ' marker--year';\n  if (precision === 'month') return ' marker--month';\n  return '';\n}\n\n/**\n * Shorten a point-event title for the canvas (~10–15 letters). Returns the\n * original when it already fits; otherwise truncates and appends an ellipsis.\n */\nexport function shortenPointTitle(title: string, maxChars = POINT_LABEL_CHARS): string {\n  const trimmed = title.trim();\n  if (trimmed.length <= maxChars) return trimmed;\n  // Leave room for the ellipsis character.\n  const keep = Math.max(1, maxChars - 1);\n  return `${trimmed.slice(0, keep).trimEnd()}…`;\n}\n\n/** Estimated label width for packing — mirrors CSS clamp without a measure pass. */\nexport function estimateLabelWidth(title: string, barWidth = 0): number {\n  if (barWidth > 0) {\n    const chars = Math.min(MAX_LABEL_PX, 24 + title.length * 6.5);\n    // Ranges: prefer the bar span; short bars still get a readable overhang.\n    return Math.max(barWidth, Math.min(MAX_LABEL_PX, Math.max(chars, MIN_RANGE_LABEL_PX)));\n  }\n  // Points: packing uses the shortened on-canvas label.\n  const short = shortenPointTitle(title);\n  return Math.min(MAX_LABEL_PX, 24 + short.length * 6.5);\n}\n\n/** All data strings go through textContent — never innerHTML. */\nexport function renderEvent(\n  positioned: PositionedEvent,\n  locale: string | undefined,\n  onSelect: (ev: ResolvedEvent, anchor: HTMLElement) => void,\n): HTMLElement {\n  const item = document.createElement('div');\n  item.className = positioned.kind === 'range' ? 'event event--range' : 'event event--point';\n  item.setAttribute('role', 'listitem');\n  item.setAttribute('part', 'event');\n  item.dataset['eventId'] = positioned.ev.src.id;\n  item.style.left = `${positioned.left}px`;\n  item.style.top = `${positioned.top}px`;\n  if (positioned.color) item.style.setProperty(EV_COLOR_VAR, positioned.color);\n\n  // Uncertainty band behind fuzzy point markers; dashed edges signal circa.\n  if (positioned.band) {\n    const band = document.createElement('span');\n    band.className = positioned.ev.src.date.circa === true ? 'band band--circa' : 'band';\n    band.setAttribute('aria-hidden', 'true');\n    band.style.left = `${positioned.band[0] - positioned.left}px`;\n    band.style.width = `${Math.max(positioned.band[1] - positioned.band[0], 2)}px`;\n    item.append(band);\n  }\n\n  const marker = document.createElement('button');\n  marker.type = 'button';\n  marker.className =\n    positioned.kind === 'range'\n      ? 'marker marker--range'\n      : `marker marker--point${markerShapeClass(positioned.ev.startParts.precision)}`;\n  if (positioned.kind === 'range') {\n    marker.style.width = `${positioned.barWidth}px`;\n    const fadeLeft = positioned.fadeLeft ?? 0;\n    const fadeRight = positioned.fadeRight ?? 0;\n    if (fadeLeft > 1 || fadeRight > 1) {\n      marker.style.background = `linear-gradient(to right, transparent 0, ${ACCENT} ${fadeLeft}px, ${ACCENT} calc(100% - ${fadeRight}px), transparent 100%)`;\n    }\n  }\n  marker.setAttribute('aria-label', formatEventAria(positioned.ev, locale));\n  marker.setAttribute('aria-haspopup', 'dialog');\n  marker.setAttribute('aria-expanded', 'false');\n  marker.addEventListener('click', () => {\n    onSelect(positioned.ev, marker);\n  });\n\n  const copy = document.createElement('span');\n  copy.className = 'event-copy';\n\n  const fullTitle = positioned.ev.src.title;\n  const isCirca = positioned.ev.src.date.circa === true;\n  if (positioned.kind === 'range') {\n    const label = document.createElement('span');\n    label.className = 'label';\n    // Ranges: single-line ellipsis sized to the bar; full title stays visible in popover.\n    label.style.maxWidth = `${estimateLabelWidth(fullTitle, positioned.barWidth)}px`;\n    label.textContent = isCirca ? `~ ${fullTitle}` : fullTitle;\n    copy.append(label);\n  } else {\n    copy.append(renderPointLabel(fullTitle, isCirca));\n  }\n\n  const date = document.createElement('span');\n  date.className = 'event-date';\n  date.textContent = formatEventDate(positioned.ev, locale);\n\n  copy.append(date);\n  // Copy above the accent (bar or marker) so text never sits through/below the stripe.\n  item.append(copy, marker);\n  return item;\n}\n\n/**\n * Point-event title: shortened on the canvas; click toggles the full title\n * (click again collapses). Titles that already fit stay as plain text.\n * The most recently expanded title is stacked on top of other expanded labels.\n */\nlet pointLabelStack = 1;\n\nfunction renderPointLabel(fullTitle: string, isCirca: boolean): HTMLElement {\n  const short = shortenPointTitle(fullTitle);\n  const displayShort = isCirca ? `~ ${short}` : short;\n  const displayFull = isCirca ? `~ ${fullTitle}` : fullTitle;\n\n  if (short === fullTitle) {\n    const label = document.createElement('span');\n    label.className = 'label';\n    label.textContent = displayFull;\n    return label;\n  }\n\n  const label = document.createElement('button');\n  label.type = 'button';\n  label.className = 'label label--toggle';\n  label.textContent = displayShort;\n  label.title = fullTitle;\n  label.setAttribute('aria-expanded', 'false');\n  label.setAttribute('aria-label', `Show full title: ${fullTitle}`);\n\n  let expanded = false;\n  label.addEventListener('click', (event) => {\n    // Don't bubble to any parent handlers; marker still owns the popover.\n    event.stopPropagation();\n    expanded = !expanded;\n    label.textContent = expanded ? displayFull : displayShort;\n    label.classList.toggle('label--expanded', expanded);\n    label.setAttribute('aria-expanded', String(expanded));\n    const item = label.closest<HTMLElement>('.event');\n    if (expanded) {\n      label.removeAttribute('title');\n      label.setAttribute('aria-label', `Collapse title: ${fullTitle}`);\n      // Bump above every previously expanded title in this timeline.\n      pointLabelStack += 1;\n      if (item) item.style.zIndex = String(pointLabelStack);\n    } else {\n      label.title = fullTitle;\n      label.setAttribute('aria-label', `Show full title: ${fullTitle}`);\n      if (item) item.style.zIndex = '';\n    }\n  });\n\n  return label;\n}\n\n/**\n * The full-height translucent band a range casts behind the events it spans.\n * Purely decorative (`pointer-events: none`) — the labeled bar from\n * {@link renderEvent} stays the interactive handle. Semi-transparent fill means\n * overlapping bands darken where they stack, reading as event density.\n */\nexport function renderRangeBand(positioned: PositionedEvent): HTMLElement | null {\n  const rb = positioned.rangeBand;\n  if (!rb) return null;\n  const band = document.createElement('span');\n  band.className = 'rband';\n  band.setAttribute('aria-hidden', 'true');\n  band.style.left = `${rb.left}px`;\n  band.style.width = `${rb.width}px`;\n  band.style.top = `${rb.top}px`;\n  band.style.height = `${rb.height}px`;\n  if (positioned.color) band.style.setProperty(EV_COLOR_VAR, positioned.color);\n  return band;\n}\n\nexport function renderPopover(\n  ev: ResolvedEvent,\n  locale: string | undefined,\n  onClose: () => void,\n): HTMLElement {\n  const { src } = ev;\n\n  const popover = document.createElement('article');\n  popover.className = 'popover';\n  popover.setAttribute('part', 'card');\n  popover.setAttribute('role', 'dialog');\n  popover.setAttribute('aria-label', src.title);\n\n  const close = document.createElement('button');\n  close.type = 'button';\n  close.className = 'popover-close';\n  close.setAttribute('aria-label', 'Close');\n  close.textContent = '✕';\n  close.addEventListener('click', onClose);\n\n  const title = document.createElement('h3');\n  title.className = 'popover-title';\n  title.textContent = src.title;\n\n  const date = document.createElement('p');\n  date.className = 'popover-date';\n  date.textContent = formatEventDate(ev, locale);\n\n  popover.append(close, title, date);\n\n  if (src.description) {\n    const desc = document.createElement('p');\n    desc.className = 'popover-desc';\n    desc.textContent = src.description;\n    popover.append(desc);\n  }\n\n  const safeMedia = (src.mediaUrls ?? [])\n    .map(safeHttpUrl)\n    .filter((url): url is string => url !== null);\n  const [thumbnail, ...restMedia] = safeMedia;\n  if (thumbnail) {\n    const img = document.createElement('img');\n    img.src = thumbnail;\n    img.loading = 'lazy';\n    img.alt = '';\n    popover.append(img);\n  }\n\n  if (src.entities && src.entities.length > 0) {\n    const entities = document.createElement('ul');\n    entities.className = 'entities';\n    for (const entity of src.entities) {\n      const li = document.createElement('li');\n      li.textContent = entity;\n      entities.append(li);\n    }\n    popover.append(entities);\n  }\n\n  if (restMedia.length > 0) {\n    const media = document.createElement('p');\n    media.className = 'popover-media';\n    media.textContent = `Media: ${restMedia.join(' · ')}`;\n    popover.append(media);\n  }\n\n  if (src.sourceRef) {\n    const source = document.createElement('p');\n    source.className = 'popover-source';\n    source.textContent = `Source: ${src.sourceRef}`;\n    popover.append(source);\n  }\n\n  return popover;\n}\n","export interface LaneAssignment {\n  /** Lane index per input extent (same order as the input array). */\n  lanes: number[];\n  laneCount: number;\n}\n\n/**\n * Greedy first-fit lane packing over px extents `[x0, x1]`. Input order is preserved\n * (callers pass chronologically sorted events); an extent lands in the first lane\n * whose last occupant ends at least `minGap` px before it, else opens a new lane.\n */\nexport function assignLanes(\n  extents: ReadonlyArray<readonly [number, number]>,\n  minGap = 8,\n): LaneAssignment {\n  const lastEnd: number[] = [];\n  const lanes: number[] = [];\n\n  for (const [x0, x1] of extents) {\n    let lane = lastEnd.findIndex((end) => x0 >= end + minGap);\n    if (lane === -1) {\n      lane = lastEnd.length;\n      lastEnd.push(x1);\n    } else {\n      lastEnd[lane] = x1;\n    }\n    lanes.push(lane);\n  }\n  return { lanes, laneCount: lastEnd.length };\n}\n","import { utcTime } from '../model/date';\n\nexport type TickUnit = 'decade' | 'year' | 'month' | 'day';\n\nexport interface Tick {\n  /** UTC epoch ms of the boundary. */\n  t: number;\n  level: 'major' | 'minor';\n}\n\nexport interface TimeScale {\n  /** Padded domain actually mapped onto the axis. */\n  domain: [number, number];\n  /** Canvas width in px the domain maps onto. */\n  width: number;\n  /** Unit of the major ticks (labels use this). */\n  unit: TickUnit;\n  toPx(t: number): number;\n  /** Inverse of {@link toPx}; extrapolates linearly outside the canvas. */\n  toTime(px: number): number;\n  ticks(): Tick[];\n}\n\nconst DAY_MS = 24 * 60 * 60 * 1000;\nconst HORIZONTAL_PAD_PX = 16;\nconst MAX_TICKS_PER_LEVEL = 500;\nconst MIN_MINOR_SPACING_PX = 8;\n\n/** Mean length of each unit, for estimating a tick count without generating one. */\nconst UNIT_MS: Record<TickUnit, number> = {\n  day: DAY_MS,\n  month: 30.44 * DAY_MS,\n  year: 365.25 * DAY_MS,\n  decade: 3652.5 * DAY_MS,\n};\n\n/**\n * Linear time→px scale over the (padded) domain, with calendar-aligned ticks.\n *\n * Major unit by span: > 40 y → decades, > 4 y → years, > 4 months → months, else\n * days. Those thresholds describe one screen-width of canvas, so a zoomed-in\n * canvas divides the span by `zoom` before choosing: 4× the pixels buys 4× the\n * tick detail, and the axis refines decade → year → month → day as the user\n * zooms in. The result is then coarsened while it would overrun the per-level\n * tick cap, so a long domain degrades to bigger units instead of a half-drawn\n * axis — up to the point where it can't. Decade is the coarsest unit there is,\n * so a domain past ~5,000 years exhausts the cap anyway and its ticks stop\n * part-way across the canvas; covering those spans needs a century unit.\n */\nexport function createTimeScale(rawDomain: [number, number], width: number, zoom = 1): TimeScale {\n  const rawSpan = Math.max(rawDomain[1] - rawDomain[0], 0);\n  const pad = Math.max(rawSpan * 0.05, 12 * 60 * 60 * 1000); // ≥ half a day of padding\n  const domain: [number, number] = [rawDomain[0] - pad, rawDomain[1] + pad];\n  const span = domain[1] - domain[0];\n\n  const spanDays = span / DAY_MS / (zoom > 0 ? zoom : 1);\n  let unit: TickUnit =\n    spanDays > 40 * 365 ? 'decade' : spanDays > 4 * 365 ? 'year' : spanDays > 120 ? 'month' : 'day';\n  while (tickCount(unit, span) > MAX_TICKS_PER_LEVEL) {\n    const coarser = coarserUnit(unit);\n    if (coarser === null) break;\n    unit = coarser;\n  }\n\n  const x0 = HORIZONTAL_PAD_PX;\n  const x1 = width - HORIZONTAL_PAD_PX;\n\n  function toPx(t: number): number {\n    return x0 + ((t - domain[0]) / span) * (x1 - x0);\n  }\n\n  function toTime(px: number): number {\n    const usable = x1 - x0;\n    if (usable <= 0) return domain[0];\n    return domain[0] + ((px - x0) / usable) * span;\n  }\n\n  function ticks(): Tick[] {\n    const majors = boundaries(unit, domain);\n    const result: Tick[] = majors.map((t) => ({ t, level: 'major' as const }));\n\n    // Minors are optional detail: skip them outright when there would be too\n    // many to generate, so a truncated run never covers only part of the axis.\n    const minorUnit = finerUnit(unit);\n    if (minorUnit && tickCount(minorUnit, span) <= MAX_TICKS_PER_LEVEL) {\n      const minors = boundaries(minorUnit, domain);\n      const spacing = minors.length > 1 ? toPx(minors[1]!) - toPx(minors[0]!) : Infinity;\n      if (spacing >= MIN_MINOR_SPACING_PX) {\n        const majorSet = new Set(majors);\n        for (const t of minors) {\n          if (!majorSet.has(t)) result.push({ t, level: 'minor' });\n        }\n      }\n    }\n    return result.sort((a, b) => a.t - b.t);\n  }\n\n  return { domain, width, unit, toPx, toTime, ticks };\n}\n\n/** Rough boundary count for `unit` across `span` ms — good enough to cap on. */\nfunction tickCount(unit: TickUnit, span: number): number {\n  return span / UNIT_MS[unit];\n}\n\nfunction finerUnit(unit: TickUnit): TickUnit | null {\n  switch (unit) {\n    case 'decade':\n      return 'year';\n    case 'year':\n      return 'month';\n    case 'month':\n      return 'day';\n    case 'day':\n      return null;\n  }\n}\n\nfunction coarserUnit(unit: TickUnit): TickUnit | null {\n  switch (unit) {\n    case 'day':\n      return 'month';\n    case 'month':\n      return 'year';\n    case 'year':\n      return 'decade';\n    case 'decade':\n      return null;\n  }\n}\n\n/** Calendar-aligned boundaries of `unit` inside `[d0, d1]`, capped for safety. */\nfunction boundaries(unit: TickUnit, [d0, d1]: [number, number]): number[] {\n  const out: number[] = [];\n  const push = (t: number): boolean => {\n    if (t >= d0 && t <= d1) out.push(t);\n    return out.length < MAX_TICKS_PER_LEVEL && t <= d1;\n  };\n\n  const startYear = new Date(d0).getUTCFullYear();\n  if (unit === 'decade' || unit === 'year') {\n    const step = unit === 'decade' ? 10 : 1;\n    let year = unit === 'decade' ? Math.floor(startYear / 10) * 10 : startYear;\n    while (push(utcTime(year))) year += step;\n  } else if (unit === 'month') {\n    let year = startYear;\n    let month = new Date(d0).getUTCMonth() + 1;\n    while (push(utcTime(year, month))) {\n      month += 1;\n      if (month > 12) {\n        month = 1;\n        year += 1;\n      }\n    }\n  } else {\n    let t = Math.floor(d0 / DAY_MS) * DAY_MS;\n    while (push(t)) t += DAY_MS;\n  }\n  return out;\n}\n","import type { TimeScale } from '../layout/scale';\nimport { formatTickLabel } from './format';\n\nconst MIN_LABEL_SPACING_PX = 56;\n\nexport function renderAxis(scale: TimeScale, locale?: string): HTMLElement {\n  const axis = document.createElement('div');\n  axis.className = 'axis';\n  axis.setAttribute('part', 'axis');\n  axis.setAttribute('aria-hidden', 'true');\n\n  const ticks = scale.ticks();\n  const majors = ticks.filter((tick) => tick.level === 'major');\n  const majorGap =\n    majors.length > 1 ? scale.toPx(majors[1]!.t) - scale.toPx(majors[0]!.t) : Infinity;\n  const labelStep = Math.max(1, Math.ceil(MIN_LABEL_SPACING_PX / majorGap));\n\n  let majorIndex = 0;\n  for (const tick of ticks) {\n    const el = document.createElement('div');\n    el.className = tick.level === 'major' ? 'tick tick--major' : 'tick tick--minor';\n    el.style.left = `${scale.toPx(tick.t)}px`;\n\n    const line = document.createElement('div');\n    line.className = 'tick-line';\n    el.append(line);\n\n    if (tick.level === 'major') {\n      if (majorIndex % labelStep === 0) {\n        const label = document.createElement('span');\n        label.className = 'tick-label';\n        label.textContent = formatTickLabel(tick.t, scale.unit, locale);\n        el.append(label);\n      }\n      majorIndex += 1;\n    }\n    axis.append(el);\n  }\n  return axis;\n}\n","import { assignLanes } from '../layout/lanes';\nimport { createTimeScale, type TimeScale } from '../layout/scale';\nimport type { NormalizedTimeline, ResolvedEvent } from '../model/normalize';\nimport { renderAxis } from './axis';\nimport {\n  AXIS_HEIGHT,\n  CANVAS_TOP_PAD,\n  estimateLabelWidth,\n  LANE_HEIGHT,\n  RANGE_LANE_HEIGHT,\n  RANGE_ROW_HEIGHT,\n  RANGES_TOP_GAP,\n  renderEvent,\n  renderRangeBand,\n  safeCssColor,\n  type PositionedEvent,\n} from './event-card';\n\nexport type { PositionedEvent } from './event-card';\n\nexport interface RenderContext {\n  locale?: string | undefined;\n  onSelect: (ev: ResolvedEvent, anchor: HTMLElement) => void;\n}\n\nconst MIN_RANGE_BAR_PX = 12;\n\n/**\n * Point events stack no deeper than this at the default zoom. A stack much taller\n * than this stops reading as a timeline and starts reading as a list — past it the\n * canvas is widened instead, trading vertical crowding for horizontal scrolling.\n * Ranges are exempt: they pack in their own region below, and a busy range stack\n * is legible in a way a deep column of point labels is not.\n */\nconst MAX_POINT_LANES = 5;\n/** Ceiling on that auto-spread, as a multiple of the viewport width. */\nconst MAX_SPREAD_FACTOR = 12;\n/** Geometric step while searching for a width inside the lane budget. */\nconst SPREAD_STEP = 1.4;\n\n/** Year/month precision spans a visible uncertainty interval; day/datetime doesn't. */\nfunction isFuzzyPrecision(precision: string): boolean {\n  return precision === 'year' || precision === 'month';\n}\n\n/**\n * The canvas width at zoom 1: the smallest width at or above `viewportWidth` that\n * packs point events into at most {@link MAX_POINT_LANES} lanes, giving up at\n * {@link MAX_SPREAD_FACTOR}×. It exceeds the viewport when the spread kicked in,\n * which is what makes zoom 1 mean \"readable\" rather than \"everything visible\".\n *\n * Label widths are fixed px while positions scale with the canvas, so widening\n * always separates events that collided — the search only has to find how much.\n * It starts at the viewport and steps up, so the common case (a timeline that was\n * never crowded) settles on the first try.\n *\n * Depends only on the data and the viewport width, never on zoom, and costs up to\n * {@link MAX_SPREAD_FACTOR}-worth of trial layouts of every event. Callers that\n * re-draw at many zoom levels should measure once and hand the result to\n * {@link renderTimeline} rather than let it re-measure per draw.\n */\nexport function measureBaseWidth(normalized: NormalizedTimeline, viewportWidth: number): number {\n  const domain = normalized.domain;\n  if (domain === null) return viewportWidth;\n  const maxWidth = viewportWidth * MAX_SPREAD_FACTOR;\n  let width = viewportWidth;\n  for (;;) {\n    const scale = createTimeScale(domain, width, width / viewportWidth);\n    const points = positionEvents(normalized.events, scale).filter((p) => p.kind === 'point');\n    if (assignLanes(points.map((p) => p.extent)).laneCount <= MAX_POINT_LANES) return width;\n    if (width >= maxWidth) return maxWidth;\n    width = Math.min(width * SPREAD_STEP, maxWidth);\n  }\n}\n\n/** Places every event on the canvas. Pure — no lanes assigned yet (`top` is 0). */\nfunction positionEvents(events: NormalizedTimeline['events'], scale: TimeScale): PositionedEvent[] {\n  return events.map((ev): PositionedEvent => {\n    const kind = ev.end ? 'range' : 'point';\n    const color = safeCssColor(ev.src.color) ?? undefined;\n\n    if (kind === 'range' && ev.end) {\n      // Bar spans the full uncertainty envelope; fuzzy endpoints fade out via a\n      // gradient across their interval instead of ending in a hard cap (M5).\n      const barStart = scale.toPx(ev.start.earliest);\n      const barEnd = Math.max(scale.toPx(ev.end.latest), barStart + MIN_RANGE_BAR_PX);\n      const barWidth = barEnd - barStart;\n      const half = barWidth / 2;\n      const fadeLeft = isFuzzyPrecision(ev.startParts.precision)\n        ? Math.min(scale.toPx(ev.start.latest) - barStart, half)\n        : 0;\n      const fadeRight =\n        ev.endParts && isFuzzyPrecision(ev.endParts.precision)\n          ? Math.min(barEnd - scale.toPx(ev.end.earliest), half)\n          : 0;\n      // Label sits above the bar; packing uses the wider of bar vs label overhang.\n      const labelWidth = estimateLabelWidth(ev.src.title, barWidth);\n      return {\n        ev,\n        kind,\n        x: barStart,\n        barWidth,\n        left: barStart,\n        top: 0,\n        fadeLeft,\n        fadeRight,\n        extent: [barStart, barStart + Math.max(barWidth, labelWidth)],\n        lane: 0,\n        color,\n      };\n    }\n\n    const x = scale.toPx(ev.start.mid);\n    // Point labels sit above the marker, left-aligned with the marker centre.\n    const left = x - 6;\n    const labelWidth = estimateLabelWidth(ev.src.title);\n    const band: [number, number] | undefined = isFuzzyPrecision(ev.startParts.precision)\n      ? [scale.toPx(ev.start.earliest), scale.toPx(ev.start.latest)]\n      : undefined;\n    const contentWidth = Math.max(12, labelWidth);\n    // The uncertainty band counts toward the packing extent so same-lane\n    // neighbours don't sit on top of it.\n    const extent: [number, number] = [\n      Math.min(left, band ? band[0] : left),\n      Math.max(left + contentWidth, band ? band[1] : 0),\n    ];\n    return { ev, kind, x, barWidth: 0, left, top: 0, band, extent, lane: 0, color };\n  });\n}\n\n/**\n * Builds the horizontal timeline into `viewport` (cleared first): an absolutely\n * positioned canvas with lane-packed point events on top, ranges as full-height\n * translucent bands behind them (labeled bars packed into a region below), and a\n * calendar axis. The canvas may be wider than the viewport — horizontal overflow\n * scrolls natively.\n *\n * Width is chosen in two stages. First {@link measureBaseWidth} widens the layout\n * until point events fit the {@link MAX_POINT_LANES} budget, which is what zoom 1\n * means; then `zoom` scales that. The domain never changes — zooming only buys\n * pixels per day, so packing re-runs at the new size and crowded labels spread\n * out. Pass `baseWidth` to reuse an earlier measurement; it is re-measured only\n * when omitted.\n *\n * Returns the scale, for mapping time ↔ canvas px so the caller can pin the\n * instant under the cursor while zooming.\n */\nexport function renderTimeline(\n  viewport: HTMLElement,\n  normalized: NormalizedTimeline,\n  viewportWidth: number,\n  ctx: RenderContext,\n  zoom = 1,\n  baseWidth = measureBaseWidth(normalized, viewportWidth),\n): TimeScale | null {\n  viewport.replaceChildren();\n  if (normalized.domain === null) return null;\n\n  const plotWidth = baseWidth * zoom;\n  // Tick density follows the total stretch, not just the user's share of it.\n  const scale = createTimeScale(normalized.domain, plotWidth, plotWidth / viewportWidth);\n  const positioned = positionEvents(normalized.events, scale);\n\n  // Points and ranges pack independently: points into lanes at the top, ranges\n  // into their own region below. Chronological order in `positioned` is kept for\n  // keyboard nav and DOM order.\n  const pointIdx = positioned.flatMap((p, i) => (p.kind === 'point' ? [i] : []));\n  const rangeIdx = positioned.flatMap((p, i) => (p.kind === 'range' ? [i] : []));\n\n  const pointLanes = assignLanes(pointIdx.map((i) => positioned[i]!.extent));\n  pointIdx.forEach((i, k) => {\n    const p = positioned[i]!;\n    p.lane = pointLanes.lanes[k] ?? 0;\n    p.top = CANVAS_TOP_PAD + p.lane * LANE_HEIGHT;\n  });\n\n  // Ranges stack by label+bar extent so overhanging titles on short bars don't collide.\n  const rangeLanes = assignLanes(\n    rangeIdx.map((i) => positioned[i]!.extent),\n    2,\n  );\n  const pointsHeight = pointLanes.laneCount * LANE_HEIGHT;\n  const rangesTop = CANVAS_TOP_PAD + pointsHeight + (rangeLanes.laneCount > 0 ? RANGES_TOP_GAP : 0);\n  rangeIdx.forEach((i, k) => {\n    const p = positioned[i]!;\n    p.lane = rangeLanes.lanes[k] ?? 0;\n    p.top = rangesTop + p.lane * RANGE_LANE_HEIGHT;\n    // Band reaches from the top of the events area down to this range's own bar;\n    // deeper (more-overlapped) lanes yield taller bands. Semi-transparent fill\n    // (CSS) makes overlaps darken so density reads at a glance.\n    p.rangeBand = {\n      left: p.x,\n      width: p.barWidth,\n      top: CANVAS_TOP_PAD,\n      height: p.top + RANGE_ROW_HEIGHT - CANVAS_TOP_PAD,\n    };\n  });\n\n  const plotBottom =\n    rangeLanes.laneCount > 0\n      ? rangesTop + rangeLanes.laneCount * RANGE_LANE_HEIGHT\n      : CANVAS_TOP_PAD + pointsHeight;\n\n  const canvasWidth = Math.max(\n    viewportWidth,\n    scale.width,\n    ...positioned.map((p) => p.extent[1] + 16),\n  );\n\n  const canvas = document.createElement('div');\n  canvas.className = 'canvas';\n  canvas.style.width = `${canvasWidth}px`;\n  canvas.style.height = `${plotBottom + AXIS_HEIGHT}px`;\n\n  // Background layer: range bands, painted below the events (pointer-transparent).\n  const ranges = document.createElement('div');\n  ranges.className = 'ranges';\n  ranges.setAttribute('aria-hidden', 'true');\n  for (const i of rangeIdx) {\n    const band = renderRangeBand(positioned[i]!);\n    if (band) ranges.append(band);\n  }\n\n  const list = document.createElement('div');\n  list.className = 'events';\n  list.setAttribute('role', 'list');\n  for (const p of positioned) {\n    list.append(renderEvent(p, ctx.locale, ctx.onSelect));\n  }\n\n  canvas.append(ranges, list, renderAxis(scale, ctx.locale));\n  viewport.append(canvas);\n  return scale;\n}\n","/**\n * One stylesheet for the whole shadow tree. Uses a shared constructable stylesheet\n * when available; falls back to a persistent <style> element (the element renders\n * into a separate container so re-renders never wipe the fallback).\n *\n * Theming: --timarro-accent / --timarro-bg / --timarro-fg / --timarro-muted /\n * --timarro-border / --timarro-font / --timarro-display-font /\n * --timarro-mono-font / --timarro-error / --timarro-card-bg /\n * --timarro-card-fg.\n * Parts: header | cover | controls | viewport | event | axis | card | brand.\n */\n\nconst CSS = /* css */ `\n  :host {\n    display: block;\n    --timarro-accent: #d6451b;\n    --timarro-muted: #6b6459;\n    --_accent: var(--timarro-accent, #d6451b);\n    --_fg: var(--timarro-fg, #1a1714);\n    --_muted: var(--timarro-muted, #6b6459);\n    --_border: var(--timarro-border, #e7e2d9);\n    font-family: var(--timarro-font, ui-sans-serif, system-ui, sans-serif);\n    color: var(--_fg);\n    background: var(--timarro-bg, transparent);\n    line-height: 1.5;\n    text-rendering: optimizeLegibility;\n    -webkit-font-smoothing: antialiased;\n  }\n  :host([hidden]) {\n    display: none;\n  }\n  *,\n  *::before,\n  *::after {\n    box-sizing: border-box;\n  }\n\n  .container {\n    position: relative;\n  }\n  .heading {\n    /* flow-root, so the floated cover is contained here instead of hanging\n       down over the viewport when the copy beside it is short. */\n    display: flow-root;\n    max-width: 100%;\n    margin: 0 0 1.5rem;\n  }\n  .header {\n    margin: 0;\n    color: var(--_fg);\n    font-family: var(--timarro-display-font, ui-serif, Georgia, serif);\n    font-size: clamp(1.45rem, 3vw, 2.15rem);\n    font-weight: 520;\n    line-height: 1.08;\n    letter-spacing: -0.025em;\n  }\n  /*\n   * Cover art floated right, with the title and description running up its\n   * left side and then continuing underneath once they clear it.\n   *\n   * Never cropped: covers on real timelines are overwhelmingly portrait (a\n   * painting of one person), and any object-fit: cover strip centres the crop\n   * straight through the subject's face. Width governs (30%); the height cap is\n   * only a backstop against a freakishly tall crop becoming a vertical strip.\n   */\n  .cover {\n    float: right;\n    width: auto;\n    max-width: 30%;\n    max-height: 28rem;\n    margin: 0.25rem 0 0.75rem 1.25rem;\n    border: 1px solid var(--_border);\n    border-radius: 10px;\n  }\n  .description {\n    max-width: 42rem;\n    margin: 0.65rem 0 0;\n    color: var(--_muted);\n    font-size: 0.925rem;\n    line-height: 1.65;\n  }\n\n  /*\n   * Footer strip below the plot and above the attribution: legend on the left,\n   * zoom pill on the right. Deliberately NOT floated over the canvas the way map\n   * controls are — lane 0 runs along the top edge, so an overlay would sit on\n   * top of the labels of whatever is latest in the timeline.\n   */\n  .toolbar {\n    display: flex;\n    align-items: center;\n    flex-wrap: wrap;\n    gap: 0.5rem 1rem;\n    margin-top: 0.75rem;\n  }\n  .zoom {\n    display: inline-flex;\n    align-items: center;\n    gap: 2px;\n    padding: 2px;\n    /* Holds the right edge whether or not a legend shares the row. */\n    margin-left: auto;\n    border: 1px solid var(--_border);\n    border-radius: 999px;\n    background: color-mix(in srgb, var(--timarro-card-bg, #fff) 92%, transparent);\n  }\n  .zoom-btn {\n    appearance: none;\n    display: inline-flex;\n    align-items: center;\n    justify-content: center;\n    min-width: 26px;\n    height: 24px;\n    padding: 0 6px;\n    border: 0;\n    border-radius: 999px;\n    background: transparent;\n    color: var(--_muted);\n    font: inherit;\n    font-size: 14px;\n    line-height: 1;\n    cursor: pointer;\n    transition: background-color 120ms ease;\n  }\n  .zoom-btn:hover:not(:disabled) {\n    background: color-mix(in srgb, var(--_accent) 12%, transparent);\n    color: var(--_fg);\n  }\n  .zoom-btn:focus-visible {\n    outline: 2px solid var(--_accent);\n    outline-offset: 2px;\n  }\n  .zoom-btn:disabled {\n    opacity: 0.4;\n    cursor: default;\n  }\n  .zoom-level {\n    /* Fixed width: the readout changes on every step and must not jog the\n       buttons either side of it. */\n    min-width: 46px;\n    font-family: var(--timarro-mono-font, ui-monospace, monospace);\n    font-size: 10.5px;\n    letter-spacing: 0.02em;\n  }\n  /* Announces the level to screen readers without taking up layout. */\n  .zoom-status {\n    position: absolute;\n    width: 1px;\n    height: 1px;\n    margin: -1px;\n    padding: 0;\n    border: 0;\n    overflow: hidden;\n    clip-path: inset(50%);\n    white-space: nowrap;\n  }\n\n  .viewport {\n    position: relative;\n    overflow-x: auto;\n    overflow-y: hidden;\n    border: 1px solid var(--_border);\n    border-radius: 14px;\n    background:\n      linear-gradient(90deg, color-mix(in srgb, var(--_border) 55%, transparent) 1px, transparent 1px)\n        0 0 / 80px 100%,\n      color-mix(in srgb, var(--timarro-card-bg, #fff) 92%, transparent);\n    box-shadow:\n      0 1px 1px color-mix(in srgb, var(--_fg) 4%, transparent),\n      0 12px 32px color-mix(in srgb, var(--_fg) 4%, transparent);\n    scrollbar-color: color-mix(in srgb, var(--_muted) 35%, transparent) transparent;\n  }\n  .viewport--vertical {\n    overflow: visible;\n    background: color-mix(in srgb, var(--timarro-card-bg, #fff) 94%, transparent);\n  }\n  .canvas {\n    position: relative;\n  }\n\n  /* Vertical (rail) layout — markers on a left rail, cards to the right. */\n  .vlist {\n    --_vlist-inline-pad: 1.25rem;\n    position: relative;\n    padding: 1.25rem var(--_vlist-inline-pad) 1rem;\n  }\n  .vlist::before {\n    content: '';\n    position: absolute;\n    left: calc(var(--_vlist-inline-pad) + 6px);\n    top: 2rem;\n    bottom: 2rem;\n    width: 1px;\n    background: color-mix(in srgb, var(--_accent) 38%, var(--_border));\n  }\n  .vevent {\n    --_accent: var(--ev-color, var(--timarro-accent, #d6451b));\n    position: relative;\n    display: grid;\n    grid-template-columns: 18px minmax(0, 1fr);\n    align-items: flex-start;\n    gap: 1rem;\n    padding: 0 0 1.4rem;\n  }\n  .vevent:last-child {\n    padding-bottom: 0;\n  }\n  .vevent .marker {\n    position: relative;\n    z-index: 1;\n    margin-top: 0.35rem;\n  }\n  .marker--vrange {\n    width: 12px;\n    height: 12px;\n    border-radius: 3px;\n  }\n  .vbody {\n    display: flex;\n    flex-direction: column;\n    gap: 0.25rem;\n    min-width: 0;\n    padding: 0 0 1.3rem;\n    border-bottom: 1px solid color-mix(in srgb, var(--_border) 72%, transparent);\n  }\n  .vevent:last-child .vbody {\n    padding-bottom: 0;\n    border-bottom: 0;\n  }\n  .vbody .label {\n    white-space: normal;\n    max-width: none;\n    overflow: visible;\n    color: var(--_fg);\n    font-family: var(--timarro-display-font, ui-serif, Georgia, serif);\n    font-size: 1.05rem;\n    font-weight: 580;\n    line-height: 1.28;\n  }\n  .vdate {\n    color: var(--_accent);\n    font-family: var(--timarro-mono-font, ui-monospace, monospace);\n    font-size: 0.7rem;\n    font-weight: 600;\n    letter-spacing: 0.055em;\n    line-height: 1.4;\n    text-transform: uppercase;\n  }\n  .vdesc {\n    display: -webkit-box;\n    max-width: 48rem;\n    overflow: hidden;\n    color: var(--_muted);\n    font-size: 0.85rem;\n    line-height: 1.55;\n    -webkit-box-orient: vertical;\n    -webkit-line-clamp: 2;\n  }\n\n  /* Range bands: a background layer painted below the event markers. */\n  .ranges {\n    position: absolute;\n    inset: 0;\n    z-index: 0;\n    pointer-events: none;\n  }\n  .rband {\n    /* Resolve the per-event accent once; children/inline styles read var(--_accent). */\n    --_accent: var(--ev-color, var(--timarro-accent, #d6451b));\n    position: absolute;\n    border-radius: 8px;\n    /* Semi-transparent so overlapping bands darken — the stack reads as density. */\n    background: color-mix(in srgb, var(--_accent) 8%, transparent);\n    box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--_accent) 16%, transparent);\n  }\n  .events {\n    position: absolute;\n    inset: 0;\n    z-index: 1;\n  }\n\n  .event {\n    /* Resolve the per-event accent once; .marker / .band read var(--_accent). */\n    --_accent: var(--ev-color, var(--timarro-accent, #d6451b));\n    position: absolute;\n    z-index: 0; /* stacking context so the band's z-index: -1 stays inside the item */\n    display: flex;\n    flex-direction: column;\n    align-items: flex-start;\n    gap: 4px;\n  }\n  /*\n   * Point events: short title + date stacked above the marker (classic pin).\n   * Full title is revealed via the native title tooltip on hover.\n   */\n  .event--point {\n    height: 48px;\n  }\n  /*\n   * Ranges: title + date ABOVE the bar — never straddling or below the stripe.\n   * Label width is set inline from the bar span (with a short-bar overhang).\n   */\n  .event--range {\n    height: 56px;\n    gap: 3px;\n  }\n  .marker {\n    appearance: none;\n    border: 0;\n    padding: 0;\n    cursor: pointer;\n    flex: none;\n    background: var(--_accent);\n    box-shadow: 0 0 0 3px color-mix(in srgb, var(--timarro-card-bg, #fff) 88%, transparent);\n    transition:\n      transform 150ms ease,\n      box-shadow 150ms ease;\n  }\n  .marker:hover {\n    transform: scale(1.14);\n    box-shadow:\n      0 0 0 3px var(--timarro-card-bg, #fff),\n      0 0 0 5px color-mix(in srgb, var(--_accent) 22%, transparent);\n  }\n  .marker--point {\n    width: 12px;\n    height: 12px;\n    border-radius: 50%;\n    /* Keep the pin visually under the start of the label. */\n    margin-left: 0;\n  }\n  .marker--month {\n    /* Keep the precision ring, but mask the rail/axis behind its center. */\n    background: var(--timarro-card-bg, #fff);\n    border: 3px solid var(--_accent);\n  }\n  .marker--year {\n    width: 11px;\n    height: 11px;\n    border-radius: 2px;\n    transform: rotate(45deg);\n  }\n  .marker--year:hover {\n    transform: rotate(45deg) scale(1.14);\n  }\n  .marker--range {\n    height: 10px;\n    border-radius: 5px;\n    box-shadow: none;\n  }\n  .marker--range:hover {\n    transform: translateY(-1px);\n    box-shadow: 0 3px 8px color-mix(in srgb, var(--_accent) 25%, transparent);\n  }\n\n  /* Uncertainty band behind fuzzy point markers (M5). */\n  .band {\n    position: absolute;\n    z-index: -1;\n    /* Align with the marker near the bottom of the stacked point row. */\n    bottom: 3px;\n    top: auto;\n    transform: none;\n    height: 8px;\n    border-radius: 4px;\n    background: color-mix(in srgb, var(--_accent) 18%, transparent);\n  }\n  .band--circa {\n    border-left: 1px dashed var(--_accent);\n    border-right: 1px dashed var(--_accent);\n  }\n  .marker:focus-visible {\n    outline: 2px solid var(--_accent);\n    outline-offset: 4px;\n  }\n  .event-copy {\n    display: flex;\n    min-width: 0;\n    flex-direction: column;\n    gap: 1px;\n  }\n  .label {\n    color: var(--_fg);\n    font-size: 12.5px;\n    font-weight: 560;\n    line-height: 1.25;\n    white-space: nowrap;\n    max-width: 200px;\n    overflow: hidden;\n    text-overflow: ellipsis;\n  }\n  .event--point .label {\n    /* Shortened in JS (~12 letters); keep a tight cap for packing/layout. */\n    max-width: 7.5rem;\n  }\n  /* Clickable short title — expands to full text on click, collapses on next click. */\n  .label--toggle {\n    appearance: none;\n    display: block;\n    margin: 0;\n    border: 0;\n    padding: 0;\n    background: transparent;\n    color: inherit;\n    font: inherit;\n    font-weight: 560;\n    line-height: 1.25;\n    text-align: left;\n    cursor: pointer;\n  }\n  .label--toggle:hover,\n  .label--toggle:focus-visible {\n    color: var(--_accent);\n  }\n  .label--toggle:focus-visible {\n    outline: 2px solid var(--_accent);\n    outline-offset: 2px;\n  }\n  .label--expanded {\n    max-width: none;\n    white-space: normal;\n    overflow: visible;\n    text-overflow: unset;\n    position: relative;\n    padding: 1px 4px;\n    margin: -1px -4px;\n    border-radius: 4px;\n    background: color-mix(in srgb, var(--timarro-card-bg, #fff) 92%, transparent);\n    box-shadow: 0 1px 4px color-mix(in srgb, var(--_fg) 10%, transparent);\n  }\n  /* Base lift for expanded items; JS raises z-index further on each expand. */\n  .event--point:has(.label--expanded) {\n    z-index: 3;\n  }\n  .event-date {\n    overflow: hidden;\n    color: var(--_muted);\n    font-family: var(--timarro-mono-font, ui-monospace, monospace);\n    font-size: 9.5px;\n    letter-spacing: 0.025em;\n    line-height: 1.3;\n    text-overflow: ellipsis;\n    white-space: nowrap;\n    max-width: 200px;\n  }\n  .event--point .event-date {\n    max-width: 7.5rem;\n  }\n  .event--range .event-date {\n    max-width: none;\n  }\n\n  .axis {\n    position: absolute;\n    left: 0;\n    right: 0;\n    bottom: 0;\n    z-index: 2;\n    height: 42px;\n    border-top: 1px solid var(--_border);\n    background: color-mix(in srgb, var(--timarro-card-bg, #fff) 78%, transparent);\n  }\n  .tick {\n    position: absolute;\n    top: 0;\n    bottom: 0;\n  }\n  .tick-line {\n    position: absolute;\n    top: 0;\n    left: 0;\n    width: 1px;\n    height: 7px;\n    background: var(--_muted);\n    opacity: 0.5;\n  }\n  .tick--minor .tick-line {\n    height: 4px;\n    opacity: 0.2;\n  }\n  .tick-label {\n    position: absolute;\n    top: 12px;\n    transform: translateX(-50%);\n    color: var(--_muted);\n    font-family: var(--timarro-mono-font, ui-monospace, monospace);\n    font-size: 9.5px;\n    letter-spacing: 0.04em;\n    white-space: nowrap;\n  }\n\n  .popover {\n    position: absolute;\n    z-index: 10;\n    width: min(320px, calc(100% - 16px));\n    background: var(--timarro-card-bg, #fff);\n    color: var(--timarro-card-fg, var(--_fg));\n    border: 1px solid var(--_border);\n    border-radius: 14px;\n    box-shadow:\n      0 18px 48px color-mix(in srgb, var(--_fg) 16%, transparent),\n      0 2px 8px color-mix(in srgb, var(--_fg) 7%, transparent);\n    padding: 1.15rem 1.2rem 1.2rem;\n  }\n  .popover-title {\n    margin: 0 24px 0.3rem 0;\n    font-family: var(--timarro-display-font, ui-serif, Georgia, serif);\n    font-size: 1.15rem;\n    font-weight: 600;\n    line-height: 1.25;\n  }\n  .popover-date {\n    margin: 0 0 0.85rem;\n    color: var(--_accent);\n    font-family: var(--timarro-mono-font, ui-monospace, monospace);\n    font-size: 0.68rem;\n    font-weight: 600;\n    letter-spacing: 0.045em;\n    text-transform: uppercase;\n  }\n  .popover-desc {\n    margin: 0 0 0.9rem;\n    color: var(--_muted);\n    font-size: 0.85rem;\n    line-height: 1.6;\n  }\n  .popover img {\n    display: block;\n    max-width: 100%;\n    border-radius: 8px;\n    margin: 0 0 0.9rem;\n  }\n  .entities {\n    display: flex;\n    flex-wrap: wrap;\n    gap: 6px;\n    margin: 0 0 0.9rem;\n    padding: 0;\n    list-style: none;\n  }\n  .entities li {\n    color: var(--_muted);\n    font-size: 10.5px;\n    padding: 3px 8px;\n    border-radius: 999px;\n    border: 1px solid var(--_border);\n    background: color-mix(in srgb, var(--_accent) 6%, transparent);\n  }\n  .popover-media,\n  .popover-source {\n    margin: 0 0 4px;\n    font-size: 11px;\n    color: var(--_muted);\n    overflow-wrap: break-word;\n  }\n  .popover-close {\n    position: absolute;\n    top: 8px;\n    right: 8px;\n    appearance: none;\n    border: 0;\n    background: transparent;\n    cursor: pointer;\n    font-size: 13px;\n    line-height: 1;\n    padding: 6px;\n    color: inherit;\n    opacity: 0.55;\n  }\n  .popover-close:hover,\n  .popover-close:focus-visible {\n    opacity: 1;\n  }\n\n  .legend {\n    display: flex;\n    flex-wrap: wrap;\n    gap: 0.35rem 1rem;\n    /* Spacing above belongs to .toolbar, which owns the whole row. */\n    margin: 0;\n    color: var(--_muted);\n    font-size: 10.5px;\n  }\n  .legend-item {\n    display: inline-flex;\n    align-items: center;\n    gap: 5px;\n  }\n  .legend-swatch {\n    flex: none;\n    width: 11px;\n    height: 11px;\n    border-radius: 50%;\n    background: var(--timarro-accent, #d6451b);\n  }\n  .legend-swatch--month {\n    background: transparent;\n    border: 3px solid var(--timarro-accent, #d6451b);\n  }\n  .legend-swatch--year {\n    border-radius: 2px;\n    transform: rotate(45deg);\n  }\n  .legend-tilde {\n    font-weight: 700;\n    line-height: 1;\n  }\n\n  .brand {\n    display: flex;\n    justify-content: flex-end;\n    margin-top: 0.55rem;\n  }\n  .brand a {\n    color: var(--_muted);\n    font-size: 9.5px;\n    letter-spacing: 0.025em;\n    text-decoration: none;\n  }\n  .brand a:hover,\n  .brand a:focus-visible {\n    opacity: 1;\n    text-decoration: underline;\n  }\n\n  .box {\n    color: var(--_muted);\n    border: 1px dashed var(--_border);\n    border-radius: 12px;\n    padding: 1rem;\n  }\n  .box--error {\n    border-color: var(--timarro-error, #b3261e);\n  }\n  .issues {\n    margin: 0.5rem 0 0;\n    padding-left: 1.25rem;\n  }\n\n  @media (max-width: 480px) {\n    .heading {\n      margin-bottom: 1rem;\n    }\n    .vlist {\n      --_vlist-inline-pad: 1rem;\n      padding: 1rem;\n    }\n    .vevent {\n      gap: 0.75rem;\n    }\n  }\n\n  @media (prefers-reduced-motion: reduce) {\n    *,\n    *::before,\n    *::after {\n      animation: none !important;\n      transition: none !important;\n      scroll-behavior: auto !important;\n    }\n  }\n`;\n\nlet sharedSheet: CSSStyleSheet | null = null;\n\nexport function applyStyles(root: ShadowRoot): void {\n  if (\n    typeof CSSStyleSheet !== 'undefined' &&\n    'replaceSync' in CSSStyleSheet.prototype &&\n    'adoptedStyleSheets' in root\n  ) {\n    if (!sharedSheet) {\n      sharedSheet = new CSSStyleSheet();\n      sharedSheet.replaceSync(CSS);\n    }\n    root.adoptedStyleSheets = [...root.adoptedStyleSheets, sharedSheet];\n  } else {\n    const style = document.createElement('style');\n    style.textContent = CSS;\n    root.append(style);\n  }\n}\n","import type { NormalizedTimeline, ResolvedEvent } from '../model/normalize';\nimport { markerShapeClass, safeCssColor } from './event-card';\nimport { formatEventAria, formatEventDate } from './format';\n\nexport interface VerticalRenderContext {\n  locale?: string | undefined;\n  onSelect: (ev: ResolvedEvent, anchor: HTMLElement) => void;\n}\n\n/**\n * Vertical (rail) layout for narrow containers: markers on a left rail, title +\n * date to the right, natural page-flow height. Chronological top → bottom; no\n * time scale — spacing is uniform, the dates carry the chronology.\n */\nexport function renderVerticalTimeline(\n  viewport: HTMLElement,\n  normalized: NormalizedTimeline,\n  ctx: VerticalRenderContext,\n): void {\n  viewport.replaceChildren();\n  if (normalized.domain === null) return;\n\n  const list = document.createElement('div');\n  list.className = 'vlist';\n  list.setAttribute('role', 'list');\n\n  for (const ev of normalized.events) {\n    const item = document.createElement('div');\n    item.className = 'vevent';\n    item.setAttribute('role', 'listitem');\n    item.setAttribute('part', 'event');\n    item.dataset['eventId'] = ev.src.id;\n    const color = safeCssColor(ev.src.color);\n    if (color) item.style.setProperty('--ev-color', color);\n\n    const marker = document.createElement('button');\n    marker.type = 'button';\n    marker.className =\n      ev.end !== undefined\n        ? 'marker marker--range marker--vrange'\n        : `marker marker--point${markerShapeClass(ev.startParts.precision)}`;\n    marker.setAttribute('aria-label', formatEventAria(ev, ctx.locale));\n    marker.setAttribute('aria-haspopup', 'dialog');\n    marker.setAttribute('aria-expanded', 'false');\n    marker.addEventListener('click', () => {\n      ctx.onSelect(ev, marker);\n    });\n\n    const body = document.createElement('div');\n    body.className = 'vbody';\n    const label = document.createElement('span');\n    label.className = 'label';\n    label.textContent = ev.src.title;\n    const date = document.createElement('span');\n    date.className = 'vdate';\n    date.textContent = formatEventDate(ev, ctx.locale);\n    body.append(date, label);\n    if (ev.src.description) {\n      const description = document.createElement('span');\n      description.className = 'vdesc';\n      description.textContent = ev.src.description;\n      body.append(description);\n    }\n\n    item.append(marker, body);\n    list.append(item);\n  }\n\n  viewport.append(list);\n}\n","import type { TimeScale } from './layout/scale';\nimport {\n  normalizeTimelineData,\n  type NormalizedTimeline,\n  type ResolvedEvent,\n} from './model/normalize';\nimport { renderPopover, POPOVER_WIDTH } from './render/event-card';\nimport { measureBaseWidth, renderTimeline, type RenderContext } from './render/render';\nimport { applyStyles } from './render/styles';\nimport { safeHttpUrl } from './render/url';\nimport { renderVerticalTimeline } from './render/vertical';\nimport type { TimarroTimelineData } from './schema/types';\nimport { validateTimelineData } from './schema/validate';\n\ntype State =\n  | { kind: 'empty' }\n  | { kind: 'error'; heading: string; details: string[] }\n  | { kind: 'ready'; data: TimarroTimelineData; normalized: NormalizedTimeline };\n\ntype Orientation = 'horizontal' | 'vertical';\n\ninterface ZoomControls {\n  zoomOut: HTMLButtonElement;\n  level: HTMLButtonElement;\n  zoomIn: HTMLButtonElement;\n  /** Off-screen live region; see `#buildZoomControls`. */\n  status: HTMLElement;\n}\n\n/** Memoized {@link measureBaseWidth}, keyed on the inputs it actually depends on. */\ninterface BaseWidthCache {\n  normalized: NormalizedTimeline;\n  viewportWidth: number;\n  value: number;\n}\n\n/** Container width (px) below which `orientation=\"auto\"` switches to vertical. */\nconst VERTICAL_BREAKPOINT = 800;\n\n/** Minimum canvas width the horizontal layout is laid out against. */\nconst MIN_PLOT_WIDTH = 480;\n\n/**\n * 1× is the layout's own default: wide enough that point events stay inside\n * their lane budget, which on a dense timeline is already wider than the\n * viewport. Zooming out below it (down to `#minZoom`, where the whole domain\n * fits on screen) is what gets you the overview.\n */\nconst DEFAULT_ZOOM = 1;\nconst MAX_ZOOM = 16;\n/** One button press / key press. ~1.7 presses per doubling. */\nconst ZOOM_STEP = 1.5;\n/** Zoom per px of wheel travel: one 100px notch ≈ 1.4×. */\nconst WHEEL_ZOOM_RATE = 0.0035;\n/** Coarse devices can report huge single deltas — cap one event's worth. */\nconst MAX_WHEEL_DELTA_PX = 200;\nconst WHEEL_LINE_PX = 16;\nconst WHEEL_PAGE_PX = 400;\n\nfunction clamp(value: number, min: number, max: number): number {\n  return Math.min(Math.max(value, min), max);\n}\n\n/** Wheel deltas arrive in px, lines, or pages — normalize to px. */\nfunction wheelDeltaPx(event: WheelEvent): number {\n  // 1 = DOM_DELTA_LINE, 2 = DOM_DELTA_PAGE (spelled out: the static members\n  // aren't present on every DOM implementation this runs in).\n  const scale = event.deltaMode === 1 ? WHEEL_LINE_PX : event.deltaMode === 2 ? WHEEL_PAGE_PX : 1;\n  return clamp(event.deltaY * scale, -MAX_WHEEL_DELTA_PX, MAX_WHEEL_DELTA_PX);\n}\n\n/**\n * SSR-safe base: importing this module in Node (e.g. to run the validator\n * server-side) must not crash on a missing HTMLElement. The stand-in class is\n * never instantiated — `define()` no-ops outside the browser.\n */\nconst BaseElement: typeof HTMLElement =\n  typeof HTMLElement !== 'undefined' ? HTMLElement : (class {} as unknown as typeof HTMLElement);\n\n/**\n * `<timarro-timeline>` — renders a timeline from §5-shaped JSON.\n *\n * Attributes: `src` (JSON URL) · `locale` (BCP-47, default browser) ·\n * `orientation` (auto | horizontal | vertical; auto switches on container\n * width < 800px) · `legend` (M5) · `zoom` (`off`/`false` disables the\n * horizontal zoom controls and gestures). Setting the `data` property wins\n * over `src`.\n *\n * Keyboard: arrow keys move focus chronologically between event markers\n * (roving tabindex), Home/End jump to the first/last event, Enter/Space\n * toggle the detail popover, Escape closes it and returns focus, `+`/`-`\n * zoom the horizontal plot and `0` fits it back.\n *\n * Zoom (horizontal only): the −/level/+ pill in the footer row beside the\n * legend, `Ctrl`/`⌘` + wheel or a trackpad pinch (anchored at the cursor).\n * A plain wheel is left to the host page.\n *\n * Events (bubbling, composed): `timarro:load` {timeline} · `timarro:error`\n * {message[, issues]} · `timarro:select` {event}.\n */\nexport class TimarroTimeline extends BaseElement {\n  static readonly observedAttributes: readonly string[] = [\n    'src',\n    'locale',\n    'orientation',\n    'legend',\n    'zoom',\n  ];\n\n  #root: ShadowRoot;\n  #container: HTMLDivElement;\n  #state: State = { kind: 'empty' };\n  #abort: AbortController | null = null;\n  #resizeObserver: ResizeObserver | null = null;\n  #lastWidth = 0;\n  #renderedOrientation: Orientation | null = null;\n  #openEventId: string | null = null;\n  #openAnchor: HTMLElement | null = null;\n  /** Horizontal only: the scroll container, its scale, and the zoom pill. */\n  #viewport: HTMLElement | null = null;\n  #scale: TimeScale | null = null;\n  #zoomControls: ZoomControls | null = null;\n  #zoom = DEFAULT_ZOOM;\n  /** Zoom at which the whole domain fits on screen; ≤ 1 once auto-spread bites. */\n  #minZoom = DEFAULT_ZOOM;\n  #baseWidthCache: BaseWidthCache | null = null;\n  /** In-flight coalesced zoom redraw, and the anchor it should restore. */\n  #zoomFrame: number | null = null;\n  #pendingAnchor: { time: number; offset: number } | null = null;\n  #onDocumentClick = (event: MouseEvent): void => {\n    this.#handleDocumentClick(event);\n  };\n  #onDocumentKeydown = (event: KeyboardEvent): void => {\n    if (event.key === 'Escape') this.#closePopover(true);\n  };\n  #onWheel = (event: WheelEvent): void => {\n    this.#handleWheel(event);\n  };\n\n  constructor() {\n    super();\n    this.#root = this.attachShadow({ mode: 'open' });\n    applyStyles(this.#root);\n    this.#container = document.createElement('div');\n    this.#container.className = 'container';\n    this.#container.addEventListener('keydown', (event) => {\n      if (this.#handleZoomKeydown(event)) return;\n      this.#handleMarkerKeydown(event);\n    });\n    this.#root.append(this.#container);\n  }\n\n  /** The last successfully validated data; null if unset or the last input was invalid. */\n  get data(): TimarroTimelineData | null {\n    return this.#state.kind === 'ready' ? this.#state.data : null;\n  }\n\n  /** Setting data aborts any in-flight `src` fetch — the property wins. */\n  set data(value: TimarroTimelineData | null) {\n    this.#abortFetch();\n    this.#ingest(value);\n  }\n\n  connectedCallback(): void {\n    if (typeof ResizeObserver !== 'undefined' && this.#resizeObserver === null) {\n      this.#resizeObserver = new ResizeObserver(() => {\n        const width = this.clientWidth;\n        if (width === this.#lastWidth) return;\n        this.#lastWidth = width;\n        // Vertical layout is flow-based — only re-render there when the\n        // orientation actually flips; horizontal re-scales on every change.\n        if (\n          this.#resolveOrientation() !== this.#renderedOrientation ||\n          this.#renderedOrientation === 'horizontal'\n        ) {\n          this.#render();\n        }\n      });\n      this.#resizeObserver.observe(this);\n    }\n    this.#render();\n  }\n\n  disconnectedCallback(): void {\n    this.#resizeObserver?.disconnect();\n    this.#resizeObserver = null;\n    this.#cancelZoomDraw();\n    this.#abortFetch();\n    this.#closePopover();\n  }\n\n  attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n    if (oldValue === newValue) return;\n    if (name === 'src') {\n      if (newValue !== null) void this.#fetchSrc(newValue);\n    } else {\n      this.#render();\n    }\n  }\n\n  #ingest(value: unknown): void {\n    // A new timeline starts at its own default — the old zoom described a\n    // domain that no longer exists, and the cached width measured it.\n    this.#zoom = DEFAULT_ZOOM;\n    this.#minZoom = DEFAULT_ZOOM;\n    this.#baseWidthCache = null;\n    if (value === null || value === undefined) {\n      this.#state = { kind: 'empty' };\n      this.#render();\n      return;\n    }\n    const result = validateTimelineData(value);\n    if (result.ok) {\n      this.#state = {\n        kind: 'ready',\n        data: result.data,\n        normalized: normalizeTimelineData(result.data),\n      };\n      this.#dispatch('timarro:load', { timeline: result.data.timeline });\n    } else {\n      const n = result.issues.length;\n      this.#state = {\n        kind: 'error',\n        heading: `timarro: invalid data (${n} issue${n === 1 ? '' : 's'})`,\n        details: result.issues.map((issue) => `${issue.path}: ${issue.message}`),\n      };\n      this.#dispatch('timarro:error', { message: 'invalid data', issues: result.issues });\n    }\n    this.#render();\n  }\n\n  async #fetchSrc(src: string): Promise<void> {\n    this.#abortFetch();\n    const controller = new AbortController();\n    this.#abort = controller;\n    try {\n      const response = await fetch(src, { signal: controller.signal });\n      if (!response.ok) throw new Error(`HTTP ${response.status} while loading ${src}`);\n      const json: unknown = await response.json();\n      if (controller.signal.aborted) return;\n      this.#ingest(json);\n    } catch (error) {\n      if (controller.signal.aborted) return;\n      const message = error instanceof Error ? error.message : String(error);\n      this.#state = { kind: 'error', heading: 'timarro: failed to load data', details: [message] };\n      this.#dispatch('timarro:error', { message });\n      this.#render();\n    } finally {\n      if (this.#abort === controller) this.#abort = null;\n    }\n  }\n\n  #abortFetch(): void {\n    this.#abort?.abort();\n    this.#abort = null;\n  }\n\n  #dispatch(type: string, detail: unknown): void {\n    this.dispatchEvent(new CustomEvent(type, { detail, bubbles: true, composed: true }));\n  }\n\n  #resolveOrientation(): Orientation {\n    const attr = this.getAttribute('orientation');\n    if (attr === 'horizontal' || attr === 'vertical') return attr;\n    const width = this.clientWidth || 0;\n    return width > 0 && width < VERTICAL_BREAKPOINT ? 'vertical' : 'horizontal';\n  }\n\n  #render(): void {\n    this.#closePopover();\n    const container = this.#container;\n    container.replaceChildren();\n    const state = this.#state;\n    this.#renderedOrientation = null;\n    // Everything below was just detached along with the container's children,\n    // including whatever a coalesced zoom draw was about to redraw into.\n    this.#viewport = null;\n    this.#scale = null;\n    this.#zoomControls = null;\n    this.#cancelZoomDraw();\n    this.#pendingAnchor = null;\n\n    if (state.kind === 'empty') {\n      container.append(this.#statusBox('timarro: no data'));\n      return;\n    }\n    if (state.kind === 'error') {\n      container.append(this.#errorBox(state.heading, state.details));\n      return;\n    }\n\n    const header = document.createElement('h2');\n    header.className = 'header';\n    header.setAttribute('part', 'header');\n    header.textContent = state.data.timeline.title;\n    const heading = document.createElement('header');\n    heading.className = 'heading';\n    // Cover art floats to the right of the title and description — the same\n    // layout timarro-platform gives it, so an embed and the page it came from\n    // agree. It is appended FIRST because a float is taken out of flow where it\n    // appears: the title and description only run up its left side if they come\n    // after it. Dropped silently when the URL isn't http(s): a broken image is\n    // worse than no image, and the field is whatever an author typed.\n    const coverUrl = state.data.timeline.coverImageUrl;\n    const cover = coverUrl === undefined ? null : safeHttpUrl(coverUrl);\n    if (cover !== null) {\n      const img = document.createElement('img');\n      img.className = 'cover';\n      img.setAttribute('part', 'cover');\n      img.src = cover;\n      img.loading = 'lazy';\n      // Decorative by position: the title beside it already names the subject,\n      // and there is no caption field to say anything more.\n      img.alt = '';\n      heading.append(img);\n    }\n    heading.append(header);\n    if (state.data.timeline.description) {\n      const description = document.createElement('p');\n      description.className = 'description';\n      description.textContent = state.data.timeline.description;\n      heading.append(description);\n    }\n    container.append(heading);\n\n    if (state.normalized.domain === null) {\n      container.append(this.#statusBox('timarro: timeline has no events'));\n      return;\n    }\n\n    const orientation = this.#resolveOrientation();\n    this.#renderedOrientation = orientation;\n    this.#lastWidth = this.clientWidth || 0;\n\n    const viewport = document.createElement('div');\n    viewport.className = orientation === 'vertical' ? 'viewport viewport--vertical' : 'viewport';\n    viewport.setAttribute('part', 'viewport');\n    const ctx = this.#renderContext();\n    if (orientation === 'vertical') {\n      // The rail layout is flow-based and never overflows, so there is nothing\n      // to zoom; drop back to the default so a flip back to horizontal is clean.\n      this.#zoom = DEFAULT_ZOOM;\n      this.#minZoom = DEFAULT_ZOOM;\n      renderVerticalTimeline(viewport, state.normalized, ctx);\n    } else if (this.#zoomEnabled()) {\n      // Non-passive: the zoom gesture has to cancel the browser's own.\n      viewport.addEventListener('wheel', this.#onWheel, { passive: false });\n      this.#viewport = viewport;\n      this.#drawPlot(viewport, state.normalized, ctx);\n    } else {\n      // Zoom turned off mid-session: drop back to the default rather than\n      // freeze at whatever level the user had reached, since the pill and the\n      // gestures that would take them back are both about to disappear.\n      this.#zoom = DEFAULT_ZOOM;\n      this.#minZoom = DEFAULT_ZOOM;\n      this.#viewport = viewport;\n      this.#drawPlot(viewport, state.normalized, ctx);\n    }\n    container.append(viewport);\n\n    // Footer strip under the plot, above the attribution: legend on the left,\n    // zoom pill pushed to the right. Either may be turned off on its own.\n    const showZoom = orientation === 'horizontal' && this.#zoomEnabled();\n    if (this.#legendEnabled() || showZoom) {\n      const toolbar = document.createElement('div');\n      toolbar.className = 'toolbar';\n      if (this.#legendEnabled()) toolbar.append(this.#buildLegend());\n      if (showZoom) toolbar.append(this.#buildZoomControls());\n      container.append(toolbar);\n    }\n\n    this.#applyRovingTabindex();\n    this.#syncZoomControls();\n\n    const brand = document.createElement('div');\n    brand.className = 'brand';\n    const link = document.createElement('a');\n    link.href = 'https://timarro.com';\n    link.target = '_blank';\n    link.rel = 'noopener';\n    link.setAttribute('part', 'brand');\n    link.textContent = 'Powered by Timarro';\n    brand.append(link);\n    container.append(brand);\n  }\n\n  #renderContext(): RenderContext {\n    return {\n      locale: this.getAttribute('locale') ?? undefined,\n      onSelect: (ev: ResolvedEvent, anchor: HTMLElement) => {\n        this.#togglePopover(ev, anchor);\n      },\n    };\n  }\n\n  /**\n   * Visible width the horizontal layout packs against, before the auto-spread\n   * and the zoom multiplier widen the canvas past it.\n   */\n  #viewportWidth(): number {\n    return Math.max(this.clientWidth || 0, MIN_PLOT_WIDTH);\n  }\n\n  /**\n   * Zoom-1 canvas width, measured at most once per (timeline, viewport width).\n   * The measurement is a search over as many as a dozen trial layouts of every\n   * event, and nothing it depends on changes while zooming — without the cache a\n   * wheel gesture would pay for it again on every event it emits.\n   */\n  #baseWidth(normalized: NormalizedTimeline, viewportWidth: number): number {\n    const cached = this.#baseWidthCache;\n    if (cached?.normalized === normalized && cached.viewportWidth === viewportWidth)\n      return cached.value;\n    const value = measureBaseWidth(normalized, viewportWidth);\n    this.#baseWidthCache = { normalized, viewportWidth, value };\n    return value;\n  }\n\n  /**\n   * Re-draws just the plot at the current zoom, leaving the heading, zoom pill,\n   * legend and brand in place — a full `#render()` would rebuild the very\n   * controls the click came from.\n   */\n  #renderPlot(): void {\n    const viewport = this.#viewport;\n    const state = this.#state;\n    if (viewport === null || state.kind !== 'ready') return;\n    // Every marker is about to move, and the popover is positioned from its\n    // anchor's rect — close it rather than leave it pointing at nothing.\n    this.#closePopover();\n    const focused = this.#markers().indexOf(this.#root.activeElement as HTMLButtonElement);\n    this.#drawPlot(viewport, state.normalized, this.#renderContext());\n    this.#applyRovingTabindex(focused);\n    this.#syncZoomControls();\n  }\n\n  /**\n   * One draw of the horizontal plot, plus the zoom bookkeeping that depends on\n   * it: the layout picks its own zoom-1 width, which is what sets how far out\n   * the user is allowed to zoom.\n   */\n  #drawPlot(viewport: HTMLElement, normalized: NormalizedTimeline, ctx: RenderContext): void {\n    const viewportWidth = this.#viewportWidth();\n    const baseWidth = this.#baseWidth(normalized, viewportWidth);\n    // Below this the domain is fully on screen, so there is nothing further to\n    // reveal. It is 1 unless the layout had to spread itself out to stay legible.\n    this.#minZoom = Math.min(DEFAULT_ZOOM, viewportWidth / baseWidth);\n    // A resize can raise the floor out from under the current zoom. Settle that\n    // before drawing — correcting afterwards would throw away a whole canvas.\n    this.#zoom = Math.max(this.#zoom, this.#minZoom);\n    this.#scale = renderTimeline(viewport, normalized, viewportWidth, ctx, this.#zoom, baseWidth);\n  }\n\n  /** Zoom defaults on; `zoom=\"false\"` / `zoom=\"off\"` removes it entirely. */\n  #zoomEnabled(): boolean {\n    const value = this.getAttribute('zoom');\n    return value !== 'false' && value !== 'off';\n  }\n\n  /**\n   * Applies a new zoom level and keeps the instant under `anchorClientX` (or the\n   * viewport centre, for button and keyboard zoom) pinned to the same spot on\n   * screen — without that, zooming in appears to fling the view sideways.\n   *\n   * `defer` coalesces the redraw onto the next frame; see `#scheduleZoomDraw`.\n   */\n  #setZoom(value: number, anchorClientX?: number, defer = false): void {\n    const next = clamp(value, this.#minZoom, MAX_ZOOM);\n    if (next === this.#zoom) return;\n\n    // Captured against the geometry currently on screen. With a deferred draw\n    // that is still the last-drawn geometry, so every event in a burst anchors\n    // against the same picture the user is looking at and the last one wins.\n    const viewport = this.#viewport;\n    const scale = this.#scale;\n    if (viewport !== null && scale !== null) {\n      const inner = viewport.clientWidth;\n      const offset =\n        anchorClientX === undefined\n          ? inner / 2\n          : clamp(anchorClientX - viewport.getBoundingClientRect().left, 0, inner);\n      this.#pendingAnchor = { time: scale.toTime(viewport.scrollLeft + offset), offset };\n    } else {\n      this.#pendingAnchor = null;\n    }\n\n    this.#zoom = next;\n    // The readout tracks the gesture even on a frame where the plot doesn't.\n    this.#syncZoomControls();\n    if (defer) this.#scheduleZoomDraw();\n    else this.#drawZoom();\n  }\n\n  /**\n   * Wheel events outrun the frame budget on a big timeline — laying out a\n   * 500-event plot costs ~35ms against a 16.7ms frame — so a gesture coalesces\n   * into one draw per frame instead of one per event. Buttons and keys draw\n   * immediately: they cannot arrive fast enough to matter.\n   */\n  #scheduleZoomDraw(): void {\n    if (this.#zoomFrame !== null) return;\n    this.#zoomFrame = requestAnimationFrame(() => {\n      this.#zoomFrame = null;\n      this.#drawZoom();\n    });\n  }\n\n  #cancelZoomDraw(): void {\n    if (this.#zoomFrame === null) return;\n    cancelAnimationFrame(this.#zoomFrame);\n    this.#zoomFrame = null;\n  }\n\n  #drawZoom(): void {\n    const anchor = this.#pendingAnchor;\n    this.#pendingAnchor = null;\n    this.#renderPlot();\n    const viewport = this.#viewport;\n    if (viewport !== null && anchor !== null && this.#scale !== null) {\n      viewport.scrollLeft = this.#scale.toPx(anchor.time) - anchor.offset;\n    }\n  }\n\n  /** Compact −/level/+ pill; the level readout doubles as reset-to-default. */\n  #buildZoomControls(): HTMLElement {\n    const group = document.createElement('div');\n    group.className = 'zoom';\n    group.setAttribute('part', 'controls');\n    group.setAttribute('role', 'group');\n    group.setAttribute('aria-label', 'Zoom');\n    // Names the gestures that have no visible affordance of their own.\n    group.title = 'Zoom: these buttons, the + / − keys, or Ctrl/⌘ + scroll (trackpad pinch)';\n\n    const button = (className: string, label: string, onClick: () => void): HTMLButtonElement => {\n      const el = document.createElement('button');\n      el.type = 'button';\n      el.className = className;\n      el.setAttribute('aria-label', label);\n      el.addEventListener('click', onClick);\n      return el;\n    };\n\n    const zoomOut = button('zoom-btn', 'Zoom out', () => {\n      this.#setZoom(this.#zoom / ZOOM_STEP);\n    });\n    zoomOut.textContent = '−';\n    const level = button('zoom-btn zoom-level', 'Reset zoom', () => {\n      this.#setZoom(DEFAULT_ZOOM);\n    });\n    const zoomIn = button('zoom-btn', 'Zoom in', () => {\n      this.#setZoom(this.#zoom * ZOOM_STEP);\n    });\n    zoomIn.textContent = '+';\n\n    // The level readout carries an aria-label (\"Reset zoom (currently 2.3×)\"),\n    // so its accessible name — not its text — is what a screen reader reads, and\n    // a silent relabel is not an announcement. This off-screen live region is\n    // what actually reports the new level. Seeded before insertion so mounting\n    // the widget doesn't announce anything.\n    const status = document.createElement('span');\n    status.className = 'zoom-status';\n    status.setAttribute('aria-live', 'polite');\n    status.textContent = this.#zoomLabel();\n\n    group.append(zoomOut, level, zoomIn, status);\n    this.#zoomControls = { zoomOut, level, zoomIn, status };\n    return group;\n  }\n\n  #zoomLabel(): string {\n    return `${this.#zoom.toFixed(1)}×`;\n  }\n\n  #syncZoomControls(): void {\n    const controls = this.#zoomControls;\n    if (controls === null) return;\n    const label = this.#zoomLabel();\n    controls.level.textContent = label;\n    controls.level.setAttribute('aria-label', `Reset zoom (currently ${label})`);\n    controls.level.disabled = this.#zoom === DEFAULT_ZOOM;\n    controls.zoomOut.disabled = this.#zoom <= this.#minZoom;\n    controls.zoomIn.disabled = this.#zoom >= MAX_ZOOM;\n    // Guarded: re-writing identical text still mutates the live region, and some\n    // screen readers announce that as a fresh change.\n    const spoken = `Zoom ${label}`;\n    if (controls.status.textContent !== spoken) controls.status.textContent = spoken;\n  }\n\n  #handleWheel(event: WheelEvent): void {\n    // Only the zoom gesture is intercepted. A plain wheel keeps scrolling the\n    // host page: an embed that swallows the page's scroll is a scroll trap.\n    if (!event.ctrlKey && !event.metaKey) return;\n    if (this.#renderedOrientation !== 'horizontal' || !this.#zoomEnabled()) return;\n    event.preventDefault();\n    this.#setZoom(\n      this.#zoom * Math.exp(-wheelDeltaPx(event) * WHEEL_ZOOM_RATE),\n      event.clientX,\n      true,\n    );\n  }\n\n  /** `+` / `-` / `0` on the plot. Returns true when the key was consumed. */\n  #handleZoomKeydown(event: KeyboardEvent): boolean {\n    // With a modifier these belong to the browser (page zoom); Shift is fair\n    // game because `+` needs it on most layouts.\n    if (event.ctrlKey || event.metaKey || event.altKey) return false;\n    if (this.#renderedOrientation !== 'horizontal' || !this.#zoomEnabled()) return false;\n    // An open card is a reading state, and re-drawing the plot would tear it\n    // down (its position is derived from a marker that is about to move). Arrow\n    // keys already leave it open, so a bare keystroke should not destroy it —\n    // Escape closes it. The pointer gestures still zoom: those aim at the plot.\n    if (this.#openEventId !== null) return false;\n\n    let next: number;\n    if (event.key === '+' || event.key === '=') next = this.#zoom * ZOOM_STEP;\n    else if (event.key === '-' || event.key === '_') next = this.#zoom / ZOOM_STEP;\n    else if (event.key === '0') next = DEFAULT_ZOOM;\n    else return false;\n\n    event.preventDefault();\n    this.#setZoom(next);\n    return true;\n  }\n\n  /** Legend defaults on; `legend=\"false\"` / `legend=\"off\"` hides it. */\n  #legendEnabled(): boolean {\n    const value = this.getAttribute('legend');\n    return value !== 'false' && value !== 'off';\n  }\n\n  /** Compact key for the precision marker shapes (M5). */\n  #buildLegend(): HTMLElement {\n    const legend = document.createElement('div');\n    legend.className = 'legend';\n    legend.setAttribute('part', 'legend');\n    const entries: [string, string][] = [\n      ['legend-swatch', 'Exact date'],\n      ['legend-swatch legend-swatch--month', 'Month'],\n      ['legend-swatch legend-swatch--year', 'Year'],\n      ['legend-tilde', 'Approximate'],\n    ];\n    for (const [className, text] of entries) {\n      const item = document.createElement('span');\n      item.className = 'legend-item';\n      const swatch = document.createElement('span');\n      swatch.className = className;\n      swatch.setAttribute('aria-hidden', 'true');\n      if (className === 'legend-tilde') swatch.textContent = '~';\n      const label = document.createElement('span');\n      label.textContent = text;\n      item.append(swatch, label);\n      legend.append(item);\n    }\n    return legend;\n  }\n\n  /**\n   * First marker is the single tab stop; arrow keys move focus from there.\n   * `focusIndex` re-homes focus after a zoom re-render replaced the focused\n   * marker with a fresh node — otherwise keyboard zooming drops to the body.\n   */\n  #applyRovingTabindex(focusIndex = -1): void {\n    const markers = this.#markers();\n    const active = focusIndex >= 0 && focusIndex < markers.length ? focusIndex : 0;\n    markers.forEach((marker, index) => {\n      marker.tabIndex = index === active ? 0 : -1;\n    });\n    // preventScroll: #setZoom restores the scroll position itself, from the\n    // zoom anchor rather than from whichever marker happened to hold focus.\n    if (focusIndex >= 0) markers[active]?.focus({ preventScroll: true });\n  }\n\n  #markers(): HTMLButtonElement[] {\n    return [...this.#container.querySelectorAll<HTMLButtonElement>('.marker')];\n  }\n\n  #handleMarkerKeydown(event: KeyboardEvent): void {\n    const key = event.key;\n    if (!['ArrowRight', 'ArrowLeft', 'ArrowUp', 'ArrowDown', 'Home', 'End'].includes(key)) return;\n    const markers = this.#markers();\n    if (markers.length === 0) return;\n    const current = markers.indexOf(this.#root.activeElement as HTMLButtonElement);\n    if (current === -1) return;\n\n    let next: number;\n    if (key === 'ArrowRight' || key === 'ArrowDown')\n      next = Math.min(current + 1, markers.length - 1);\n    else if (key === 'ArrowLeft' || key === 'ArrowUp') next = Math.max(current - 1, 0);\n    else if (key === 'Home') next = 0;\n    else next = markers.length - 1;\n\n    event.preventDefault();\n    if (next === current) return;\n    const from = markers[current];\n    const to = markers[next];\n    if (!from || !to) return;\n    from.tabIndex = -1;\n    to.tabIndex = 0;\n    to.focus();\n    to.scrollIntoView?.({ block: 'nearest', inline: 'nearest' });\n  }\n\n  #togglePopover(ev: ResolvedEvent, anchor: HTMLElement): void {\n    if (this.#openEventId === ev.src.id) {\n      this.#closePopover();\n      return;\n    }\n    this.#closePopover();\n\n    const popover = renderPopover(ev, this.getAttribute('locale') ?? undefined, () => {\n      this.#closePopover(true);\n    });\n    // Positioned from the anchor's rect relative to .container (works in both\n    // orientations, and rect math already accounts for the viewport's scroll).\n    // Appended to .container, not the canvas — the viewport's overflow clipping\n    // must not cut the popover off.\n    const containerRect = this.#container.getBoundingClientRect();\n    const anchorRect = anchor.getBoundingClientRect();\n    const containerWidth = this.#container.clientWidth || 480;\n    const left = Math.min(\n      Math.max(anchorRect.left - containerRect.left, 8),\n      Math.max(containerWidth - POPOVER_WIDTH - 8, 8),\n    );\n    popover.style.left = `${left}px`;\n    popover.style.top = `${anchorRect.bottom - containerRect.top + 8}px`;\n    this.#container.append(popover);\n    this.#openEventId = ev.src.id;\n    this.#openAnchor = anchor;\n    anchor.setAttribute('aria-expanded', 'true');\n\n    document.addEventListener('click', this.#onDocumentClick);\n    document.addEventListener('keydown', this.#onDocumentKeydown);\n\n    this.#dispatch('timarro:select', { event: ev.src });\n  }\n\n  #handleDocumentClick(event: MouseEvent): void {\n    const path = event.composedPath();\n    const popover = this.#container.querySelector('.popover');\n    const clickedPopover = popover !== null && path.includes(popover);\n    // The opening click also bubbles to this handler — the marker guard keeps it open.\n    const clickedOwnMarker =\n      path.includes(this.#root) &&\n      path.some((node) => node instanceof HTMLElement && node.classList.contains('marker'));\n    if (clickedPopover || clickedOwnMarker) return;\n    this.#closePopover();\n  }\n\n  #closePopover(refocusAnchor = false): void {\n    this.#container.querySelector('.popover')?.remove();\n    this.#openEventId = null;\n    const anchor = this.#openAnchor;\n    this.#openAnchor = null;\n    anchor?.setAttribute('aria-expanded', 'false');\n    if (refocusAnchor) anchor?.focus();\n    document.removeEventListener('click', this.#onDocumentClick);\n    document.removeEventListener('keydown', this.#onDocumentKeydown);\n  }\n\n  #statusBox(message: string): HTMLElement {\n    const box = document.createElement('div');\n    box.className = 'box';\n    box.textContent = message;\n    return box;\n  }\n\n  #errorBox(heading: string, details: string[]): HTMLElement {\n    const box = document.createElement('div');\n    box.className = 'box box--error';\n    const head = document.createElement('div');\n    head.textContent = heading;\n    box.append(head);\n    if (details.length > 0) {\n      const list = document.createElement('ul');\n      list.className = 'issues';\n      for (const detail of details.slice(0, 3)) {\n        const item = document.createElement('li');\n        item.textContent = detail;\n        list.append(item);\n      }\n      if (details.length > 3) {\n        const item = document.createElement('li');\n        item.textContent = `… and ${details.length - 3} more`;\n        list.append(item);\n      }\n      box.append(list);\n    }\n    return box;\n  }\n}\n\nexport function define(tagName = 'timarro-timeline'): void {\n  if (typeof customElements === 'undefined') return; // SSR / Node: no-op\n  if (!customElements.get(tagName)) {\n    customElements.define(tagName, TimarroTimeline);\n  }\n}\n"],"mappings":";;;;;;AAyBA,SAAgB,sBAAsB,MAA+C;CACnF,MAAM,SAAS,KAAK,OACjB,KAAK,QAAuB;EAC3B,MAAM,aAAaA,iBAAAA,eAAe,IAAI,KAAK,KAAK;EAChD,MAAM,WAAW,IAAI,KAAK,QAAQ,KAAA,IAAYA,iBAAAA,eAAe,IAAI,KAAK,GAAG,IAAI,KAAA;EAK7E,OAAO;GAAE;GAAK,OAJAC,iBAAAA,eAAe,UAIX;GAAG,KAHT,aAAa,KAAA,IAAYA,iBAAAA,eAAe,QAAQ,IAAI,KAAA;GAGtC;GAAY;GAAU,OAD9C,IAAI,KAAK,cAAc,UAAU,IAAI,KAAK,cAAc,WAAW,IAAI,KAAK,UAAU;EAClC;CACxD,CAAC,CAAC,CACD,KAAK,qBAAqB;CAE7B,IAAI,SAAkC;CACtC,IAAI,OAAO,SAAS,GAAG;EACrB,IAAI,MAAM;EACV,IAAI,MAAM;EACV,KAAK,MAAM,MAAM,QAAQ;GACvB,MAAM,KAAK,IAAI,KAAK,GAAG,MAAM,QAAQ;GACrC,MAAM,KAAK,IAAI,MAAM,GAAG,OAAO,GAAG,MAAA,CAAO,MAAM;EACjD;EACA,SAAS,CAAC,KAAK,GAAG;CACpB;CACA,OAAO;EAAE;EAAQ;CAAO;AAC1B;;;;;AAMA,SAAgB,sBAAsB,GAAkB,GAA0B;CAChF,IAAI,EAAE,MAAM,QAAQ,EAAE,MAAM,KAAK,OAAO,EAAE,MAAM,MAAM,EAAE,MAAM;CAC9D,MAAM,SAAS,EAAE,IAAI,SAAS;CAC9B,MAAM,SAAS,EAAE,IAAI,SAAS;CAC9B,IAAI,WAAW,QAAQ,OAAO,SAAS;CACvC,IAAI,EAAE,IAAI,UAAU,EAAE,IAAI,OAAO,OAAO,EAAE,IAAI,QAAQ,EAAE,IAAI,QAAQ,KAAK;CACzE,IAAI,EAAE,IAAI,OAAO,EAAE,IAAI,IAAI,OAAO,EAAE,IAAI,KAAK,EAAE,IAAI,KAAK,KAAK;CAC7D,OAAO;AACT;;;;;;;;ACpDA,SAAgB,gBAAgB,OAAkB,OAAgB,QAAyB;CACzF,MAAM,SAAS,QAAQ,MAAM;CAC7B,QAAQ,MAAM,WAAd;EACE,KAAK,QACH,OAAO,SAAS,OAAO,MAAM,IAAI;EACnC,KAAK,SACH,OACE,SACA,IAAI,KAAK,eAAe,QAAQ;GAAE,OAAO;GAAQ,MAAM;GAAW,UAAU;EAAM,CAAC,CAAC,CAAC,OACnFC,iBAAAA,QAAQ,MAAM,MAAM,MAAM,SAAS,CAAC,CACtC;EAEJ,KAAK,OACH,OACE,SACA,IAAI,KAAK,eAAe,QAAQ;GAAE,WAAW;GAAU,UAAU;EAAM,CAAC,CAAC,CAAC,OACxEA,iBAAAA,QAAQ,MAAM,MAAM,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,CACtD;EAEJ,KAAK,YACH,OACE,SACA,IAAI,KAAK,eAAe,QAAQ;GAC9B,WAAW;GACX,WAAW;GACX,UAAU;EACZ,CAAC,CAAC,CAAC,OAAOC,iBAAAA,eAAe,KAAK,CAAC,CAAC,GAAG;CAEzC;AACF;;AAGA,SAAgB,gBAAgB,IAAmB,QAAyB;CAC1E,MAAM,QAAQ,GAAG,IAAI,KAAK,UAAU;CACpC,MAAM,aAAa,gBAAgB,GAAG,YAAY,OAAO,MAAM;CAC/D,IAAI,CAAC,GAAG,UAAU,OAAO;CACzB,OAAO,GAAG,WAAW,KAAK,gBAAgB,GAAG,UAAU,OAAO,MAAM;AACtE;;AAGA,SAAgB,gBAAgB,IAAmB,QAAyB;CAC1E,MAAM,SAAS,GAAG,IAAI,KAAK,UAAU,OAAO,kBAAkB;CAC9D,OAAO,GAAG,GAAG,IAAI,MAAM,IAAI,gBAAgB,IAAI,MAAM,IAAI;AAC3D;AAEA,SAAgB,gBAAgB,GAAW,MAAgB,QAAyB;CAClF,MAAM,IAAI,IAAI,KAAK,CAAC;CACpB,QAAQ,MAAR;EACE,KAAK;EACL,KAAK,QACH,OAAO,OAAO,EAAE,eAAe,CAAC;EAClC,KAAK,SAAS;GACZ,MAAM,QAAQ,IAAI,KAAK,eAAe,QAAQ;IAAE,OAAO;IAAS,UAAU;GAAM,CAAC,CAAC,CAAC,OAAO,CAAC;GAC3F,OAAO,EAAE,YAAY,MAAM,IAAI,GAAG,MAAM,GAAG,EAAE,eAAe,MAAM;EACpE;EACA,KAAK,OACH,OAAO,IAAI,KAAK,eAAe,QAAQ;GACrC,OAAO;GACP,KAAK;GACL,UAAU;EACZ,CAAC,CAAC,CAAC,OAAO,CAAC;CACf;AACF;;;;;;;;;;;;AChEA,SAAgB,YAAY,KAA4B;CAGtD,IAAI,IAAI,KAAK,CAAC,CAAC,WAAW,GAAG,OAAO;CACpC,IAAI;EACF,MAAM,SAAS,IAAI,IAAI,KAAK,SAAS,OAAO;EAC5C,OAAO,OAAO,aAAa,WAAW,OAAO,aAAa,WAAW,OAAO,OAAO;CACrF,QAAQ;EACN,OAAO;CACT;AACF;;ACaA,MAAM,eAAe;;;;;;;AAOrB,MAAM,SAAS;;;;;;;AAoCf,SAAgB,aAAa,OAA+B;CAC1D,IAAI,OAAO,UAAU,UAAU,OAAO;CACtC,MAAM,IAAI,MAAM,KAAK;CACrB,IAAI,EAAE,WAAW,KAAK,EAAE,SAAS,IAAI,OAAO;CAE5C,IAAI,QAAQ,KAAK,CAAC,KAAK,EAAE,SAAS,IAAI,KAAK,YAAY,KAAK,CAAC,GAAG,OAAO;CACvE,IAAI,OAAO,QAAQ,eAAe,OAAO,IAAI,aAAa,YACxD,OAAO,IAAI,SAAS,SAAS,CAAC,IAAI,IAAI;CAGxC,OAAO,oBAAoB,KAAK,CAAC,KAC/B,YAAY,KAAK,CAAC,KAClB,uEAAuE,KAAK,CAAC,IAC3E,IACA;AACN;;AAGA,SAAgB,iBAAiB,WAA2B;CAC1D,IAAI,cAAc,QAAQ,OAAO;CACjC,IAAI,cAAc,SAAS,OAAO;CAClC,OAAO;AACT;;;;;AAMA,SAAgB,kBAAkB,OAAe,WAAA,IAAsC;CACrF,MAAM,UAAU,MAAM,KAAK;CAC3B,IAAI,QAAQ,UAAU,UAAU,OAAO;CAEvC,MAAM,OAAO,KAAK,IAAI,GAAG,WAAW,CAAC;CACrC,OAAO,GAAG,QAAQ,MAAM,GAAG,IAAI,CAAC,CAAC,QAAQ,EAAE;AAC7C;;AAGA,SAAgB,mBAAmB,OAAe,WAAW,GAAW;CACtE,IAAI,WAAW,GAAG;EAChB,MAAM,QAAQ,KAAK,IAAA,KAAkB,KAAK,MAAM,SAAS,GAAG;EAE5D,OAAO,KAAK,IAAI,UAAU,KAAK,IAAA,KAAkB,KAAK,IAAI,OAAA,GAAyB,CAAC,CAAC;CACvF;CAEA,MAAM,QAAQ,kBAAkB,KAAK;CACrC,OAAO,KAAK,IAAA,KAAkB,KAAK,MAAM,SAAS,GAAG;AACvD;;AAGA,SAAgB,YACd,YACA,QACA,UACa;CACb,MAAM,OAAO,SAAS,cAAc,KAAK;CACzC,KAAK,YAAY,WAAW,SAAS,UAAU,uBAAuB;CACtE,KAAK,aAAa,QAAQ,UAAU;CACpC,KAAK,aAAa,QAAQ,OAAO;CACjC,KAAK,QAAQ,aAAa,WAAW,GAAG,IAAI;CAC5C,KAAK,MAAM,OAAO,GAAG,WAAW,KAAK;CACrC,KAAK,MAAM,MAAM,GAAG,WAAW,IAAI;CACnC,IAAI,WAAW,OAAO,KAAK,MAAM,YAAY,cAAc,WAAW,KAAK;CAG3E,IAAI,WAAW,MAAM;EACnB,MAAM,OAAO,SAAS,cAAc,MAAM;EAC1C,KAAK,YAAY,WAAW,GAAG,IAAI,KAAK,UAAU,OAAO,qBAAqB;EAC9E,KAAK,aAAa,eAAe,MAAM;EACvC,KAAK,MAAM,OAAO,GAAG,WAAW,KAAK,KAAK,WAAW,KAAK;EAC1D,KAAK,MAAM,QAAQ,GAAG,KAAK,IAAI,WAAW,KAAK,KAAK,WAAW,KAAK,IAAI,CAAC,EAAE;EAC3E,KAAK,OAAO,IAAI;CAClB;CAEA,MAAM,SAAS,SAAS,cAAc,QAAQ;CAC9C,OAAO,OAAO;CACd,OAAO,YACL,WAAW,SAAS,UAChB,yBACA,uBAAuB,iBAAiB,WAAW,GAAG,WAAW,SAAS;CAChF,IAAI,WAAW,SAAS,SAAS;EAC/B,OAAO,MAAM,QAAQ,GAAG,WAAW,SAAS;EAC5C,MAAM,WAAW,WAAW,YAAY;EACxC,MAAM,YAAY,WAAW,aAAa;EAC1C,IAAI,WAAW,KAAK,YAAY,GAC9B,OAAO,MAAM,aAAa,4CAA4C,OAAO,GAAG,SAAS,MAAM,OAAO,eAAe,UAAU;CAEnI;CACA,OAAO,aAAa,cAAc,gBAAgB,WAAW,IAAI,MAAM,CAAC;CACxE,OAAO,aAAa,iBAAiB,QAAQ;CAC7C,OAAO,aAAa,iBAAiB,OAAO;CAC5C,OAAO,iBAAiB,eAAe;EACrC,SAAS,WAAW,IAAI,MAAM;CAChC,CAAC;CAED,MAAM,OAAO,SAAS,cAAc,MAAM;CAC1C,KAAK,YAAY;CAEjB,MAAM,YAAY,WAAW,GAAG,IAAI;CACpC,MAAM,UAAU,WAAW,GAAG,IAAI,KAAK,UAAU;CACjD,IAAI,WAAW,SAAS,SAAS;EAC/B,MAAM,QAAQ,SAAS,cAAc,MAAM;EAC3C,MAAM,YAAY;EAElB,MAAM,MAAM,WAAW,GAAG,mBAAmB,WAAW,WAAW,QAAQ,EAAE;EAC7E,MAAM,cAAc,UAAU,KAAK,cAAc;EACjD,KAAK,OAAO,KAAK;CACnB,OACE,KAAK,OAAO,iBAAiB,WAAW,OAAO,CAAC;CAGlD,MAAM,OAAO,SAAS,cAAc,MAAM;CAC1C,KAAK,YAAY;CACjB,KAAK,cAAc,gBAAgB,WAAW,IAAI,MAAM;CAExD,KAAK,OAAO,IAAI;CAEhB,KAAK,OAAO,MAAM,MAAM;CACxB,OAAO;AACT;;;;;;AAOA,IAAI,kBAAkB;AAEtB,SAAS,iBAAiB,WAAmB,SAA+B;CAC1E,MAAM,QAAQ,kBAAkB,SAAS;CACzC,MAAM,eAAe,UAAU,KAAK,UAAU;CAC9C,MAAM,cAAc,UAAU,KAAK,cAAc;CAEjD,IAAI,UAAU,WAAW;EACvB,MAAM,QAAQ,SAAS,cAAc,MAAM;EAC3C,MAAM,YAAY;EAClB,MAAM,cAAc;EACpB,OAAO;CACT;CAEA,MAAM,QAAQ,SAAS,cAAc,QAAQ;CAC7C,MAAM,OAAO;CACb,MAAM,YAAY;CAClB,MAAM,cAAc;CACpB,MAAM,QAAQ;CACd,MAAM,aAAa,iBAAiB,OAAO;CAC3C,MAAM,aAAa,cAAc,oBAAoB,WAAW;CAEhE,IAAI,WAAW;CACf,MAAM,iBAAiB,UAAU,UAAU;EAEzC,MAAM,gBAAgB;EACtB,WAAW,CAAC;EACZ,MAAM,cAAc,WAAW,cAAc;EAC7C,MAAM,UAAU,OAAO,mBAAmB,QAAQ;EAClD,MAAM,aAAa,iBAAiB,OAAO,QAAQ,CAAC;EACpD,MAAM,OAAO,MAAM,QAAqB,QAAQ;EAChD,IAAI,UAAU;GACZ,MAAM,gBAAgB,OAAO;GAC7B,MAAM,aAAa,cAAc,mBAAmB,WAAW;GAE/D,mBAAmB;GACnB,IAAI,MAAM,KAAK,MAAM,SAAS,OAAO,eAAe;EACtD,OAAO;GACL,MAAM,QAAQ;GACd,MAAM,aAAa,cAAc,oBAAoB,WAAW;GAChE,IAAI,MAAM,KAAK,MAAM,SAAS;EAChC;CACF,CAAC;CAED,OAAO;AACT;;;;;;;AAQA,SAAgB,gBAAgB,YAAiD;CAC/E,MAAM,KAAK,WAAW;CACtB,IAAI,CAAC,IAAI,OAAO;CAChB,MAAM,OAAO,SAAS,cAAc,MAAM;CAC1C,KAAK,YAAY;CACjB,KAAK,aAAa,eAAe,MAAM;CACvC,KAAK,MAAM,OAAO,GAAG,GAAG,KAAK;CAC7B,KAAK,MAAM,QAAQ,GAAG,GAAG,MAAM;CAC/B,KAAK,MAAM,MAAM,GAAG,GAAG,IAAI;CAC3B,KAAK,MAAM,SAAS,GAAG,GAAG,OAAO;CACjC,IAAI,WAAW,OAAO,KAAK,MAAM,YAAY,cAAc,WAAW,KAAK;CAC3E,OAAO;AACT;AAEA,SAAgB,cACd,IACA,QACA,SACa;CACb,MAAM,EAAE,QAAQ;CAEhB,MAAM,UAAU,SAAS,cAAc,SAAS;CAChD,QAAQ,YAAY;CACpB,QAAQ,aAAa,QAAQ,MAAM;CACnC,QAAQ,aAAa,QAAQ,QAAQ;CACrC,QAAQ,aAAa,cAAc,IAAI,KAAK;CAE5C,MAAM,QAAQ,SAAS,cAAc,QAAQ;CAC7C,MAAM,OAAO;CACb,MAAM,YAAY;CAClB,MAAM,aAAa,cAAc,OAAO;CACxC,MAAM,cAAc;CACpB,MAAM,iBAAiB,SAAS,OAAO;CAEvC,MAAM,QAAQ,SAAS,cAAc,IAAI;CACzC,MAAM,YAAY;CAClB,MAAM,cAAc,IAAI;CAExB,MAAM,OAAO,SAAS,cAAc,GAAG;CACvC,KAAK,YAAY;CACjB,KAAK,cAAc,gBAAgB,IAAI,MAAM;CAE7C,QAAQ,OAAO,OAAO,OAAO,IAAI;CAEjC,IAAI,IAAI,aAAa;EACnB,MAAM,OAAO,SAAS,cAAc,GAAG;EACvC,KAAK,YAAY;EACjB,KAAK,cAAc,IAAI;EACvB,QAAQ,OAAO,IAAI;CACrB;CAKA,MAAM,CAAC,WAAW,GAAG,cAHF,IAAI,aAAa,CAAC,EAAA,CAClC,IAAI,WAAW,CAAC,CAChB,QAAQ,QAAuB,QAAQ,IACA;CAC1C,IAAI,WAAW;EACb,MAAM,MAAM,SAAS,cAAc,KAAK;EACxC,IAAI,MAAM;EACV,IAAI,UAAU;EACd,IAAI,MAAM;EACV,QAAQ,OAAO,GAAG;CACpB;CAEA,IAAI,IAAI,YAAY,IAAI,SAAS,SAAS,GAAG;EAC3C,MAAM,WAAW,SAAS,cAAc,IAAI;EAC5C,SAAS,YAAY;EACrB,KAAK,MAAM,UAAU,IAAI,UAAU;GACjC,MAAM,KAAK,SAAS,cAAc,IAAI;GACtC,GAAG,cAAc;GACjB,SAAS,OAAO,EAAE;EACpB;EACA,QAAQ,OAAO,QAAQ;CACzB;CAEA,IAAI,UAAU,SAAS,GAAG;EACxB,MAAM,QAAQ,SAAS,cAAc,GAAG;EACxC,MAAM,YAAY;EAClB,MAAM,cAAc,UAAU,UAAU,KAAK,KAAK;EAClD,QAAQ,OAAO,KAAK;CACtB;CAEA,IAAI,IAAI,WAAW;EACjB,MAAM,SAAS,SAAS,cAAc,GAAG;EACzC,OAAO,YAAY;EACnB,OAAO,cAAc,WAAW,IAAI;EACpC,QAAQ,OAAO,MAAM;CACvB;CAEA,OAAO;AACT;;;;;;;;AC3UA,SAAgB,YACd,SACA,SAAS,GACO;CAChB,MAAM,UAAoB,CAAC;CAC3B,MAAM,QAAkB,CAAC;CAEzB,KAAK,MAAM,CAAC,IAAI,OAAO,SAAS;EAC9B,IAAI,OAAO,QAAQ,WAAW,QAAQ,MAAM,MAAM,MAAM;EACxD,IAAI,SAAS,IAAI;GACf,OAAO,QAAQ;GACf,QAAQ,KAAK,EAAE;EACjB,OACE,QAAQ,QAAQ;EAElB,MAAM,KAAK,IAAI;CACjB;CACA,OAAO;EAAE;EAAO,WAAW,QAAQ;CAAO;AAC5C;;;ACNA,MAAM,SAAS,OAAU,KAAK;AAC9B,MAAM,oBAAoB;AAC1B,MAAM,sBAAsB;AAC5B,MAAM,uBAAuB;;AAG7B,MAAM,UAAoC;CACxC,KAAK;CACL,OAAO,QAAQ;CACf,MAAM,SAAS;CACf,QAAQ,SAAS;AACnB;;;;;;;;;;;;;;AAeA,SAAgB,gBAAgB,WAA6B,OAAe,OAAO,GAAc;CAC/F,MAAM,UAAU,KAAK,IAAI,UAAU,KAAK,UAAU,IAAI,CAAC;CACvD,MAAM,MAAM,KAAK,IAAI,UAAU,KAAM,MAAU,KAAK,GAAI;CACxD,MAAM,SAA2B,CAAC,UAAU,KAAK,KAAK,UAAU,KAAK,GAAG;CACxE,MAAM,OAAO,OAAO,KAAK,OAAO;CAEhC,MAAM,WAAW,OAAO,UAAU,OAAO,IAAI,OAAO;CACpD,IAAI,OACF,WAAW,KAAK,MAAM,WAAW,WAAW,IAAI,MAAM,SAAS,WAAW,MAAM,UAAU;CAC5F,OAAO,UAAU,MAAM,IAAI,IAAI,qBAAqB;EAClD,MAAM,UAAU,YAAY,IAAI;EAChC,IAAI,YAAY,MAAM;EACtB,OAAO;CACT;CAEA,MAAM,KAAK;CACX,MAAM,KAAK,QAAQ;CAEnB,SAAS,KAAK,GAAmB;EAC/B,OAAO,MAAO,IAAI,OAAO,MAAM,QAAS,KAAK;CAC/C;CAEA,SAAS,OAAO,IAAoB;EAClC,MAAM,SAAS,KAAK;EACpB,IAAI,UAAU,GAAG,OAAO,OAAO;EAC/B,OAAO,OAAO,MAAO,KAAK,MAAM,SAAU;CAC5C;CAEA,SAAS,QAAgB;EACvB,MAAM,SAAS,WAAW,MAAM,MAAM;EACtC,MAAM,SAAiB,OAAO,KAAK,OAAO;GAAE;GAAG,OAAO;EAAiB,EAAE;EAIzE,MAAM,YAAY,UAAU,IAAI;EAChC,IAAI,aAAa,UAAU,WAAW,IAAI,KAAK,qBAAqB;GAClE,MAAM,SAAS,WAAW,WAAW,MAAM;GAE3C,KADgB,OAAO,SAAS,IAAI,KAAK,OAAO,EAAG,IAAI,KAAK,OAAO,EAAG,IAAI,aAC3D,sBAAsB;IACnC,MAAM,WAAW,IAAI,IAAI,MAAM;IAC/B,KAAK,MAAM,KAAK,QACd,IAAI,CAAC,SAAS,IAAI,CAAC,GAAG,OAAO,KAAK;KAAE;KAAG,OAAO;IAAQ,CAAC;GAE3D;EACF;EACA,OAAO,OAAO,MAAM,GAAG,MAAM,EAAE,IAAI,EAAE,CAAC;CACxC;CAEA,OAAO;EAAE;EAAQ;EAAO;EAAM;EAAM;EAAQ;CAAM;AACpD;;AAGA,SAAS,UAAU,MAAgB,MAAsB;CACvD,OAAO,OAAO,QAAQ;AACxB;AAEA,SAAS,UAAU,MAAiC;CAClD,QAAQ,MAAR;EACE,KAAK,UACH,OAAO;EACT,KAAK,QACH,OAAO;EACT,KAAK,SACH,OAAO;EACT,KAAK,OACH,OAAO;CACX;AACF;AAEA,SAAS,YAAY,MAAiC;CACpD,QAAQ,MAAR;EACE,KAAK,OACH,OAAO;EACT,KAAK,SACH,OAAO;EACT,KAAK,QACH,OAAO;EACT,KAAK,UACH,OAAO;CACX;AACF;;AAGA,SAAS,WAAW,MAAgB,CAAC,IAAI,KAAiC;CACxE,MAAM,MAAgB,CAAC;CACvB,MAAM,QAAQ,MAAuB;EACnC,IAAI,KAAK,MAAM,KAAK,IAAI,IAAI,KAAK,CAAC;EAClC,OAAO,IAAI,SAAS,uBAAuB,KAAK;CAClD;CAEA,MAAM,YAAY,IAAI,KAAK,EAAE,CAAC,CAAC,eAAe;CAC9C,IAAI,SAAS,YAAY,SAAS,QAAQ;EACxC,MAAM,OAAO,SAAS,WAAW,KAAK;EACtC,IAAI,OAAO,SAAS,WAAW,KAAK,MAAM,YAAY,EAAE,IAAI,KAAK;EACjE,OAAO,KAAKC,iBAAAA,QAAQ,IAAI,CAAC,GAAG,QAAQ;CACtC,OAAO,IAAI,SAAS,SAAS;EAC3B,IAAI,OAAO;EACX,IAAI,QAAQ,IAAI,KAAK,EAAE,CAAC,CAAC,YAAY,IAAI;EACzC,OAAO,KAAKA,iBAAAA,QAAQ,MAAM,KAAK,CAAC,GAAG;GACjC,SAAS;GACT,IAAI,QAAQ,IAAI;IACd,QAAQ;IACR,QAAQ;GACV;EACF;CACF,OAAO;EACL,IAAI,IAAI,KAAK,MAAM,KAAK,MAAM,IAAI;EAClC,OAAO,KAAK,CAAC,GAAG,KAAK;CACvB;CACA,OAAO;AACT;;;AC5JA,MAAM,uBAAuB;AAE7B,SAAgB,WAAW,OAAkB,QAA8B;CACzE,MAAM,OAAO,SAAS,cAAc,KAAK;CACzC,KAAK,YAAY;CACjB,KAAK,aAAa,QAAQ,MAAM;CAChC,KAAK,aAAa,eAAe,MAAM;CAEvC,MAAM,QAAQ,MAAM,MAAM;CAC1B,MAAM,SAAS,MAAM,QAAQ,SAAS,KAAK,UAAU,OAAO;CAC5D,MAAM,WACJ,OAAO,SAAS,IAAI,MAAM,KAAK,OAAO,EAAE,CAAE,CAAC,IAAI,MAAM,KAAK,OAAO,EAAE,CAAE,CAAC,IAAI;CAC5E,MAAM,YAAY,KAAK,IAAI,GAAG,KAAK,KAAK,uBAAuB,QAAQ,CAAC;CAExE,IAAI,aAAa;CACjB,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,KAAK,SAAS,cAAc,KAAK;EACvC,GAAG,YAAY,KAAK,UAAU,UAAU,qBAAqB;EAC7D,GAAG,MAAM,OAAO,GAAG,MAAM,KAAK,KAAK,CAAC,EAAE;EAEtC,MAAM,OAAO,SAAS,cAAc,KAAK;EACzC,KAAK,YAAY;EACjB,GAAG,OAAO,IAAI;EAEd,IAAI,KAAK,UAAU,SAAS;GAC1B,IAAI,aAAa,cAAc,GAAG;IAChC,MAAM,QAAQ,SAAS,cAAc,MAAM;IAC3C,MAAM,YAAY;IAClB,MAAM,cAAc,gBAAgB,KAAK,GAAG,MAAM,MAAM,MAAM;IAC9D,GAAG,OAAO,KAAK;GACjB;GACA,cAAc;EAChB;EACA,KAAK,OAAO,EAAE;CAChB;CACA,OAAO;AACT;;;ACdA,MAAM,mBAAmB;;;;;;;;AASzB,MAAM,kBAAkB;;AAExB,MAAM,oBAAoB;;AAE1B,MAAM,cAAc;;AAGpB,SAAS,iBAAiB,WAA4B;CACpD,OAAO,cAAc,UAAU,cAAc;AAC/C;;;;;;;;;;;;;;;;;AAkBA,SAAgB,iBAAiB,YAAgC,eAA+B;CAC9F,MAAM,SAAS,WAAW;CAC1B,IAAI,WAAW,MAAM,OAAO;CAC5B,MAAM,WAAW,gBAAgB;CACjC,IAAI,QAAQ;CACZ,SAAS;EACP,MAAM,QAAQ,gBAAgB,QAAQ,OAAO,QAAQ,aAAa;EAElE,IAAI,YADW,eAAe,WAAW,QAAQ,KAAK,CAAC,CAAC,QAAQ,MAAM,EAAE,SAAS,OAC5D,CAAC,CAAC,KAAK,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,aAAa,iBAAiB,OAAO;EAClF,IAAI,SAAS,UAAU,OAAO;EAC9B,QAAQ,KAAK,IAAI,QAAQ,aAAa,QAAQ;CAChD;AACF;;AAGA,SAAS,eAAe,QAAsC,OAAqC;CACjG,OAAO,OAAO,KAAK,OAAwB;EACzC,MAAM,OAAO,GAAG,MAAM,UAAU;EAChC,MAAM,QAAQ,aAAa,GAAG,IAAI,KAAK,KAAK,KAAA;EAE5C,IAAI,SAAS,WAAW,GAAG,KAAK;GAG9B,MAAM,WAAW,MAAM,KAAK,GAAG,MAAM,QAAQ;GAC7C,MAAM,SAAS,KAAK,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,GAAG,WAAW,gBAAgB;GAC9E,MAAM,WAAW,SAAS;GAC1B,MAAM,OAAO,WAAW;GACxB,MAAM,WAAW,iBAAiB,GAAG,WAAW,SAAS,IACrD,KAAK,IAAI,MAAM,KAAK,GAAG,MAAM,MAAM,IAAI,UAAU,IAAI,IACrD;GACJ,MAAM,YACJ,GAAG,YAAY,iBAAiB,GAAG,SAAS,SAAS,IACjD,KAAK,IAAI,SAAS,MAAM,KAAK,GAAG,IAAI,QAAQ,GAAG,IAAI,IACnD;GAEN,MAAM,aAAa,mBAAmB,GAAG,IAAI,OAAO,QAAQ;GAC5D,OAAO;IACL;IACA;IACA,GAAG;IACH;IACA,MAAM;IACN,KAAK;IACL;IACA;IACA,QAAQ,CAAC,UAAU,WAAW,KAAK,IAAI,UAAU,UAAU,CAAC;IAC5D,MAAM;IACN;GACF;EACF;EAEA,MAAM,IAAI,MAAM,KAAK,GAAG,MAAM,GAAG;EAEjC,MAAM,OAAO,IAAI;EACjB,MAAM,aAAa,mBAAmB,GAAG,IAAI,KAAK;EAClD,MAAM,OAAqC,iBAAiB,GAAG,WAAW,SAAS,IAC/E,CAAC,MAAM,KAAK,GAAG,MAAM,QAAQ,GAAG,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,IAC3D,KAAA;EACJ,MAAM,eAAe,KAAK,IAAI,IAAI,UAAU;EAO5C,OAAO;GAAE;GAAI;GAAM;GAAG,UAAU;GAAG;GAAM,KAAK;GAAG;GAAM,QAAA,CAHrD,KAAK,IAAI,MAAM,OAAO,KAAK,KAAK,IAAI,GACpC,KAAK,IAAI,OAAO,cAAc,OAAO,KAAK,KAAK,CAAC,CAEU;GAAG,MAAM;GAAG;EAAM;CAChF,CAAC;AACH;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,eACd,UACA,YACA,eACA,KACA,OAAO,GACP,YAAY,iBAAiB,YAAY,aAAa,GACpC;CAClB,SAAS,gBAAgB;CACzB,IAAI,WAAW,WAAW,MAAM,OAAO;CAEvC,MAAM,YAAY,YAAY;CAE9B,MAAM,QAAQ,gBAAgB,WAAW,QAAQ,WAAW,YAAY,aAAa;CACrF,MAAM,aAAa,eAAe,WAAW,QAAQ,KAAK;CAK1D,MAAM,WAAW,WAAW,SAAS,GAAG,MAAO,EAAE,SAAS,UAAU,CAAC,CAAC,IAAI,CAAC,CAAE;CAC7E,MAAM,WAAW,WAAW,SAAS,GAAG,MAAO,EAAE,SAAS,UAAU,CAAC,CAAC,IAAI,CAAC,CAAE;CAE7E,MAAM,aAAa,YAAY,SAAS,KAAK,MAAM,WAAW,EAAE,CAAE,MAAM,CAAC;CACzE,SAAS,SAAS,GAAG,MAAM;EACzB,MAAM,IAAI,WAAW;EACrB,EAAE,OAAO,WAAW,MAAM,MAAM;EAChC,EAAE,MAAA,KAAuB,EAAE,OAAA;CAC7B,CAAC;CAGD,MAAM,aAAa,YACjB,SAAS,KAAK,MAAM,WAAW,EAAE,CAAE,MAAM,GACzC,CACF;CACA,MAAM,eAAe,WAAW,YAAA;CAChC,MAAM,YAAA,KAA6B,gBAAgB,WAAW,YAAY,IAAA,KAAqB;CAC/F,SAAS,SAAS,GAAG,MAAM;EACzB,MAAM,IAAI,WAAW;EACrB,EAAE,OAAO,WAAW,MAAM,MAAM;EAChC,EAAE,MAAM,YAAY,EAAE,OAAA;EAItB,EAAE,YAAY;GACZ,MAAM,EAAE;GACR,OAAO,EAAE;GACT,KAAA;GACA,QAAQ,EAAE,MAAA,KAAA;EACZ;CACF,CAAC;CAED,MAAM,aACJ,WAAW,YAAY,IACnB,YAAY,WAAW,YAAA,KAAA,KACN;CAEvB,MAAM,cAAc,KAAK,IACvB,eACA,MAAM,OACN,GAAG,WAAW,KAAK,MAAM,EAAE,OAAO,KAAK,EAAE,CAC3C;CAEA,MAAM,SAAS,SAAS,cAAc,KAAK;CAC3C,OAAO,YAAY;CACnB,OAAO,MAAM,QAAQ,GAAG,YAAY;CACpC,OAAO,MAAM,SAAS,GAAG,aAAA,GAAyB;CAGlD,MAAM,SAAS,SAAS,cAAc,KAAK;CAC3C,OAAO,YAAY;CACnB,OAAO,aAAa,eAAe,MAAM;CACzC,KAAK,MAAM,KAAK,UAAU;EACxB,MAAM,OAAO,gBAAgB,WAAW,EAAG;EAC3C,IAAI,MAAM,OAAO,OAAO,IAAI;CAC9B;CAEA,MAAM,OAAO,SAAS,cAAc,KAAK;CACzC,KAAK,YAAY;CACjB,KAAK,aAAa,QAAQ,MAAM;CAChC,KAAK,MAAM,KAAK,YACd,KAAK,OAAO,YAAY,GAAG,IAAI,QAAQ,IAAI,QAAQ,CAAC;CAGtD,OAAO,OAAO,QAAQ,MAAM,WAAW,OAAO,IAAI,MAAM,CAAC;CACzD,SAAS,OAAO,MAAM;CACtB,OAAO;AACT;;;;;;;;;;;;;;AC7NA,MAAMC,QAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2oBtB,IAAI,cAAoC;AAExC,SAAgB,YAAY,MAAwB;CAClD,IACE,OAAO,kBAAkB,eACzB,iBAAiB,cAAc,aAC/B,wBAAwB,MACxB;EACA,IAAI,CAAC,aAAa;GAChB,cAAc,IAAI,cAAc;GAChC,YAAY,YAAYA,KAAG;EAC7B;EACA,KAAK,qBAAqB,CAAC,GAAG,KAAK,oBAAoB,WAAW;CACpE,OAAO;EACL,MAAM,QAAQ,SAAS,cAAc,OAAO;EAC5C,MAAM,cAAcA;EACpB,KAAK,OAAO,KAAK;CACnB;AACF;;;;;;;;AC3pBA,SAAgB,uBACd,UACA,YACA,KACM;CACN,SAAS,gBAAgB;CACzB,IAAI,WAAW,WAAW,MAAM;CAEhC,MAAM,OAAO,SAAS,cAAc,KAAK;CACzC,KAAK,YAAY;CACjB,KAAK,aAAa,QAAQ,MAAM;CAEhC,KAAK,MAAM,MAAM,WAAW,QAAQ;EAClC,MAAM,OAAO,SAAS,cAAc,KAAK;EACzC,KAAK,YAAY;EACjB,KAAK,aAAa,QAAQ,UAAU;EACpC,KAAK,aAAa,QAAQ,OAAO;EACjC,KAAK,QAAQ,aAAa,GAAG,IAAI;EACjC,MAAM,QAAQ,aAAa,GAAG,IAAI,KAAK;EACvC,IAAI,OAAO,KAAK,MAAM,YAAY,cAAc,KAAK;EAErD,MAAM,SAAS,SAAS,cAAc,QAAQ;EAC9C,OAAO,OAAO;EACd,OAAO,YACL,GAAG,QAAQ,KAAA,IACP,wCACA,uBAAuB,iBAAiB,GAAG,WAAW,SAAS;EACrE,OAAO,aAAa,cAAc,gBAAgB,IAAI,IAAI,MAAM,CAAC;EACjE,OAAO,aAAa,iBAAiB,QAAQ;EAC7C,OAAO,aAAa,iBAAiB,OAAO;EAC5C,OAAO,iBAAiB,eAAe;GACrC,IAAI,SAAS,IAAI,MAAM;EACzB,CAAC;EAED,MAAM,OAAO,SAAS,cAAc,KAAK;EACzC,KAAK,YAAY;EACjB,MAAM,QAAQ,SAAS,cAAc,MAAM;EAC3C,MAAM,YAAY;EAClB,MAAM,cAAc,GAAG,IAAI;EAC3B,MAAM,OAAO,SAAS,cAAc,MAAM;EAC1C,KAAK,YAAY;EACjB,KAAK,cAAc,gBAAgB,IAAI,IAAI,MAAM;EACjD,KAAK,OAAO,MAAM,KAAK;EACvB,IAAI,GAAG,IAAI,aAAa;GACtB,MAAM,cAAc,SAAS,cAAc,MAAM;GACjD,YAAY,YAAY;GACxB,YAAY,cAAc,GAAG,IAAI;GACjC,KAAK,OAAO,WAAW;EACzB;EAEA,KAAK,OAAO,QAAQ,IAAI;EACxB,KAAK,OAAO,IAAI;CAClB;CAEA,SAAS,OAAO,IAAI;AACtB;;;;AChCA,MAAM,sBAAsB;;AAG5B,MAAM,iBAAiB;;;;;;;AAQvB,MAAM,eAAe;AACrB,MAAM,WAAW;;AAEjB,MAAM,YAAY;;AAElB,MAAM,kBAAkB;;AAExB,MAAM,qBAAqB;AAC3B,MAAM,gBAAgB;AACtB,MAAM,gBAAgB;AAEtB,SAAS,MAAM,OAAe,KAAa,KAAqB;CAC9D,OAAO,KAAK,IAAI,KAAK,IAAI,OAAO,GAAG,GAAG,GAAG;AAC3C;;AAGA,SAAS,aAAa,OAA2B;CAG/C,MAAM,QAAQ,MAAM,cAAc,IAAI,gBAAgB,MAAM,cAAc,IAAI,gBAAgB;CAC9F,OAAO,MAAM,MAAM,SAAS,OAAO,MAAqB,kBAAkB;AAC5E;;;;;;AAOA,MAAM,cACJ,OAAO,gBAAgB,cAAc,cAAe,MAAM,CAAC;;;;;;;;;;;;;;;;;;;;;;AAuB7D,IAAa,kBAAb,cAAqC,YAAY;CAC/C,OAAgB,qBAAwC;EACtD;EACA;EACA;EACA;EACA;CACF;CAEA;CACA;CACA,SAAgB,EAAE,MAAM,QAAQ;CAChC,SAAiC;CACjC,kBAAyC;CACzC,aAAa;CACb,uBAA2C;CAC3C,eAA8B;CAC9B,cAAkC;;CAElC,YAAgC;CAChC,SAA2B;CAC3B,gBAAqC;CACrC,QAAQ;;CAER,WAAW;CACX,kBAAyC;;CAEzC,aAA4B;CAC5B,iBAA0D;CAC1D,oBAAoB,UAA4B;EAC9C,KAAKC,qBAAqB,KAAK;CACjC;CACA,sBAAsB,UAA+B;EACnD,IAAI,MAAM,QAAQ,UAAU,KAAKC,cAAc,IAAI;CACrD;CACA,YAAY,UAA4B;EACtC,KAAKC,aAAa,KAAK;CACzB;CAEA,cAAc;EACZ,MAAM;EACN,KAAKC,QAAQ,KAAK,aAAa,EAAE,MAAM,OAAO,CAAC;EAC/C,YAAY,KAAKA,KAAK;EACtB,KAAKC,aAAa,SAAS,cAAc,KAAK;EAC9C,KAAKA,WAAW,YAAY;EAC5B,KAAKA,WAAW,iBAAiB,YAAY,UAAU;GACrD,IAAI,KAAKC,mBAAmB,KAAK,GAAG;GACpC,KAAKC,qBAAqB,KAAK;EACjC,CAAC;EACD,KAAKH,MAAM,OAAO,KAAKC,UAAU;CACnC;;CAGA,IAAI,OAAmC;EACrC,OAAO,KAAKG,OAAO,SAAS,UAAU,KAAKA,OAAO,OAAO;CAC3D;;CAGA,IAAI,KAAK,OAAmC;EAC1C,KAAKC,YAAY;EACjB,KAAKC,QAAQ,KAAK;CACpB;CAEA,oBAA0B;EACxB,IAAI,OAAO,mBAAmB,eAAe,KAAKC,oBAAoB,MAAM;GAC1E,KAAKA,kBAAkB,IAAI,qBAAqB;IAC9C,MAAM,QAAQ,KAAK;IACnB,IAAI,UAAU,KAAKC,YAAY;IAC/B,KAAKA,aAAa;IAGlB,IACE,KAAKC,oBAAoB,MAAM,KAAKC,wBACpC,KAAKA,yBAAyB,cAE9B,KAAKC,QAAQ;GAEjB,CAAC;GACD,KAAKJ,gBAAgB,QAAQ,IAAI;EACnC;EACA,KAAKI,QAAQ;CACf;CAEA,uBAA6B;EAC3B,KAAKJ,iBAAiB,WAAW;EACjC,KAAKA,kBAAkB;EACvB,KAAKK,gBAAgB;EACrB,KAAKP,YAAY;EACjB,KAAKP,cAAc;CACrB;CAEA,yBAAyB,MAAc,UAAyB,UAA+B;EAC7F,IAAI,aAAa,UAAU;EAC3B,IAAI,SAAS,OACP;OAAA,aAAa,MAAM,KAAUe,UAAU,QAAQ;EAAA,OAEnD,KAAKF,QAAQ;CAEjB;CAEA,QAAQ,OAAsB;EAG5B,KAAKG,QAAQ;EACb,KAAKC,WAAW;EAChB,KAAKC,kBAAkB;EACvB,IAAI,UAAU,QAAQ,UAAU,KAAA,GAAW;GACzC,KAAKZ,SAAS,EAAE,MAAM,QAAQ;GAC9B,KAAKO,QAAQ;GACb;EACF;EACA,MAAM,SAASM,iBAAAA,qBAAqB,KAAK;EACzC,IAAI,OAAO,IAAI;GACb,KAAKb,SAAS;IACZ,MAAM;IACN,MAAM,OAAO;IACb,YAAY,sBAAsB,OAAO,IAAI;GAC/C;GACA,KAAKc,UAAU,gBAAgB,EAAE,UAAU,OAAO,KAAK,SAAS,CAAC;EACnE,OAAO;GACL,MAAM,IAAI,OAAO,OAAO;GACxB,KAAKd,SAAS;IACZ,MAAM;IACN,SAAS,0BAA0B,EAAE,QAAQ,MAAM,IAAI,KAAK,IAAI;IAChE,SAAS,OAAO,OAAO,KAAK,UAAU,GAAG,MAAM,KAAK,IAAI,MAAM,SAAS;GACzE;GACA,KAAKc,UAAU,iBAAiB;IAAE,SAAS;IAAgB,QAAQ,OAAO;GAAO,CAAC;EACpF;EACA,KAAKP,QAAQ;CACf;CAEA,MAAME,UAAU,KAA4B;EAC1C,KAAKR,YAAY;EACjB,MAAM,aAAa,IAAI,gBAAgB;EACvC,KAAKc,SAAS;EACd,IAAI;GACF,MAAM,WAAW,MAAM,MAAM,KAAK,EAAE,QAAQ,WAAW,OAAO,CAAC;GAC/D,IAAI,CAAC,SAAS,IAAI,MAAM,IAAI,MAAM,QAAQ,SAAS,OAAO,iBAAiB,KAAK;GAChF,MAAM,OAAgB,MAAM,SAAS,KAAK;GAC1C,IAAI,WAAW,OAAO,SAAS;GAC/B,KAAKb,QAAQ,IAAI;EACnB,SAAS,OAAO;GACd,IAAI,WAAW,OAAO,SAAS;GAC/B,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;GACrE,KAAKF,SAAS;IAAE,MAAM;IAAS,SAAS;IAAgC,SAAS,CAAC,OAAO;GAAE;GAC3F,KAAKc,UAAU,iBAAiB,EAAE,QAAQ,CAAC;GAC3C,KAAKP,QAAQ;EACf,UAAU;GACR,IAAI,KAAKQ,WAAW,YAAY,KAAKA,SAAS;EAChD;CACF;CAEA,cAAoB;EAClB,KAAKA,QAAQ,MAAM;EACnB,KAAKA,SAAS;CAChB;CAEA,UAAU,MAAc,QAAuB;EAC7C,KAAK,cAAc,IAAI,YAAY,MAAM;GAAE;GAAQ,SAAS;GAAM,UAAU;EAAK,CAAC,CAAC;CACrF;CAEA,sBAAmC;EACjC,MAAM,OAAO,KAAK,aAAa,aAAa;EAC5C,IAAI,SAAS,gBAAgB,SAAS,YAAY,OAAO;EACzD,MAAM,QAAQ,KAAK,eAAe;EAClC,OAAO,QAAQ,KAAK,QAAQ,sBAAsB,aAAa;CACjE;CAEA,UAAgB;EACd,KAAKrB,cAAc;EACnB,MAAM,YAAY,KAAKG;EACvB,UAAU,gBAAgB;EAC1B,MAAM,QAAQ,KAAKG;EACnB,KAAKM,uBAAuB;EAG5B,KAAKU,YAAY;EACjB,KAAKC,SAAS;EACd,KAAKC,gBAAgB;EACrB,KAAKV,gBAAgB;EACrB,KAAKW,iBAAiB;EAEtB,IAAI,MAAM,SAAS,SAAS;GAC1B,UAAU,OAAO,KAAKC,WAAW,kBAAkB,CAAC;GACpD;EACF;EACA,IAAI,MAAM,SAAS,SAAS;GAC1B,UAAU,OAAO,KAAKC,UAAU,MAAM,SAAS,MAAM,OAAO,CAAC;GAC7D;EACF;EAEA,MAAM,SAAS,SAAS,cAAc,IAAI;EAC1C,OAAO,YAAY;EACnB,OAAO,aAAa,QAAQ,QAAQ;EACpC,OAAO,cAAc,MAAM,KAAK,SAAS;EACzC,MAAM,UAAU,SAAS,cAAc,QAAQ;EAC/C,QAAQ,YAAY;EAOpB,MAAM,WAAW,MAAM,KAAK,SAAS;EACrC,MAAM,QAAQ,aAAa,KAAA,IAAY,OAAO,YAAY,QAAQ;EAClE,IAAI,UAAU,MAAM;GAClB,MAAM,MAAM,SAAS,cAAc,KAAK;GACxC,IAAI,YAAY;GAChB,IAAI,aAAa,QAAQ,OAAO;GAChC,IAAI,MAAM;GACV,IAAI,UAAU;GAGd,IAAI,MAAM;GACV,QAAQ,OAAO,GAAG;EACpB;EACA,QAAQ,OAAO,MAAM;EACrB,IAAI,MAAM,KAAK,SAAS,aAAa;GACnC,MAAM,cAAc,SAAS,cAAc,GAAG;GAC9C,YAAY,YAAY;GACxB,YAAY,cAAc,MAAM,KAAK,SAAS;GAC9C,QAAQ,OAAO,WAAW;EAC5B;EACA,UAAU,OAAO,OAAO;EAExB,IAAI,MAAM,WAAW,WAAW,MAAM;GACpC,UAAU,OAAO,KAAKD,WAAW,iCAAiC,CAAC;GACnE;EACF;EAEA,MAAM,cAAc,KAAKf,oBAAoB;EAC7C,KAAKC,uBAAuB;EAC5B,KAAKF,aAAa,KAAK,eAAe;EAEtC,MAAM,WAAW,SAAS,cAAc,KAAK;EAC7C,SAAS,YAAY,gBAAgB,aAAa,gCAAgC;EAClF,SAAS,aAAa,QAAQ,UAAU;EACxC,MAAM,MAAM,KAAKkB,eAAe;EAChC,IAAI,gBAAgB,YAAY;GAG9B,KAAKZ,QAAQ;GACb,KAAKC,WAAW;GAChB,uBAAuB,UAAU,MAAM,YAAY,GAAG;EACxD,OAAO,IAAI,KAAKY,aAAa,GAAG;GAE9B,SAAS,iBAAiB,SAAS,KAAKC,UAAU,EAAE,SAAS,MAAM,CAAC;GACpE,KAAKR,YAAY;GACjB,KAAKS,UAAU,UAAU,MAAM,YAAY,GAAG;EAChD,OAAO;GAIL,KAAKf,QAAQ;GACb,KAAKC,WAAW;GAChB,KAAKK,YAAY;GACjB,KAAKS,UAAU,UAAU,MAAM,YAAY,GAAG;EAChD;EACA,UAAU,OAAO,QAAQ;EAIzB,MAAM,WAAW,gBAAgB,gBAAgB,KAAKF,aAAa;EACnE,IAAI,KAAKG,eAAe,KAAK,UAAU;GACrC,MAAM,UAAU,SAAS,cAAc,KAAK;GAC5C,QAAQ,YAAY;GACpB,IAAI,KAAKA,eAAe,GAAG,QAAQ,OAAO,KAAKC,aAAa,CAAC;GAC7D,IAAI,UAAU,QAAQ,OAAO,KAAKC,mBAAmB,CAAC;GACtD,UAAU,OAAO,OAAO;EAC1B;EAEA,KAAKC,qBAAqB;EAC1B,KAAKC,kBAAkB;EAEvB,MAAM,QAAQ,SAAS,cAAc,KAAK;EAC1C,MAAM,YAAY;EAClB,MAAM,OAAO,SAAS,cAAc,GAAG;EACvC,KAAK,OAAO;EACZ,KAAK,SAAS;EACd,KAAK,MAAM;EACX,KAAK,aAAa,QAAQ,OAAO;EACjC,KAAK,cAAc;EACnB,MAAM,OAAO,IAAI;EACjB,UAAU,OAAO,KAAK;CACxB;CAEA,iBAAgC;EAC9B,OAAO;GACL,QAAQ,KAAK,aAAa,QAAQ,KAAK,KAAA;GACvC,WAAW,IAAmB,WAAwB;IACpD,KAAKC,eAAe,IAAI,MAAM;GAChC;EACF;CACF;;;;;CAMA,iBAAyB;EACvB,OAAO,KAAK,IAAI,KAAK,eAAe,GAAG,cAAc;CACvD;;;;;;;CAQA,WAAW,YAAgC,eAA+B;EACxE,MAAM,SAAS,KAAKnB;EACpB,IAAI,QAAQ,eAAe,cAAc,OAAO,kBAAkB,eAChE,OAAO,OAAO;EAChB,MAAM,QAAQ,iBAAiB,YAAY,aAAa;EACxD,KAAKA,kBAAkB;GAAE;GAAY;GAAe;EAAM;EAC1D,OAAO;CACT;;;;;;CAOA,cAAoB;EAClB,MAAM,WAAW,KAAKI;EACtB,MAAM,QAAQ,KAAKhB;EACnB,IAAI,aAAa,QAAQ,MAAM,SAAS,SAAS;EAGjD,KAAKN,cAAc;EACnB,MAAM,UAAU,KAAKsC,SAAS,CAAC,CAAC,QAAQ,KAAKpC,MAAM,aAAkC;EACrF,KAAK6B,UAAU,UAAU,MAAM,YAAY,KAAKH,eAAe,CAAC;EAChE,KAAKO,qBAAqB,OAAO;EACjC,KAAKC,kBAAkB;CACzB;;;;;;CAOA,UAAU,UAAuB,YAAgC,KAA0B;EACzF,MAAM,gBAAgB,KAAKG,eAAe;EAC1C,MAAM,YAAY,KAAKC,WAAW,YAAY,aAAa;EAG3D,KAAKvB,WAAW,KAAK,IAAI,cAAc,gBAAgB,SAAS;EAGhE,KAAKD,QAAQ,KAAK,IAAI,KAAKA,OAAO,KAAKC,QAAQ;EAC/C,KAAKM,SAAS,eAAe,UAAU,YAAY,eAAe,KAAK,KAAKP,OAAO,SAAS;CAC9F;;CAGA,eAAwB;EACtB,MAAM,QAAQ,KAAK,aAAa,MAAM;EACtC,OAAO,UAAU,WAAW,UAAU;CACxC;;;;;;;;CASA,SAAS,OAAe,eAAwB,QAAQ,OAAa;EACnE,MAAM,OAAO,MAAM,OAAO,KAAKC,UAAU,QAAQ;EACjD,IAAI,SAAS,KAAKD,OAAO;EAKzB,MAAM,WAAW,KAAKM;EACtB,MAAM,QAAQ,KAAKC;EACnB,IAAI,aAAa,QAAQ,UAAU,MAAM;GACvC,MAAM,QAAQ,SAAS;GACvB,MAAM,SACJ,kBAAkB,KAAA,IACd,QAAQ,IACR,MAAM,gBAAgB,SAAS,sBAAsB,CAAC,CAAC,MAAM,GAAG,KAAK;GAC3E,KAAKE,iBAAiB;IAAE,MAAM,MAAM,OAAO,SAAS,aAAa,MAAM;IAAG;GAAO;EACnF,OACE,KAAKA,iBAAiB;EAGxB,KAAKT,QAAQ;EAEb,KAAKoB,kBAAkB;EACvB,IAAI,OAAO,KAAKK,kBAAkB;OAC7B,KAAKC,UAAU;CACtB;;;;;;;CAQA,oBAA0B;EACxB,IAAI,KAAKC,eAAe,MAAM;EAC9B,KAAKA,aAAa,4BAA4B;GAC5C,KAAKA,aAAa;GAClB,KAAKD,UAAU;EACjB,CAAC;CACH;CAEA,kBAAwB;EACtB,IAAI,KAAKC,eAAe,MAAM;EAC9B,qBAAqB,KAAKA,UAAU;EACpC,KAAKA,aAAa;CACpB;CAEA,YAAkB;EAChB,MAAM,SAAS,KAAKlB;EACpB,KAAKA,iBAAiB;EACtB,KAAKmB,YAAY;EACjB,MAAM,WAAW,KAAKtB;EACtB,IAAI,aAAa,QAAQ,WAAW,QAAQ,KAAKC,WAAW,MAC1D,SAAS,aAAa,KAAKA,OAAO,KAAK,OAAO,IAAI,IAAI,OAAO;CAEjE;;CAGA,qBAAkC;EAChC,MAAM,QAAQ,SAAS,cAAc,KAAK;EAC1C,MAAM,YAAY;EAClB,MAAM,aAAa,QAAQ,UAAU;EACrC,MAAM,aAAa,QAAQ,OAAO;EAClC,MAAM,aAAa,cAAc,MAAM;EAEvC,MAAM,QAAQ;EAEd,MAAM,UAAU,WAAmB,OAAe,YAA2C;GAC3F,MAAM,KAAK,SAAS,cAAc,QAAQ;GAC1C,GAAG,OAAO;GACV,GAAG,YAAY;GACf,GAAG,aAAa,cAAc,KAAK;GACnC,GAAG,iBAAiB,SAAS,OAAO;GACpC,OAAO;EACT;EAEA,MAAM,UAAU,OAAO,YAAY,kBAAkB;GACnD,KAAKsB,SAAS,KAAK7B,QAAQ,SAAS;EACtC,CAAC;EACD,QAAQ,cAAc;EACtB,MAAM,QAAQ,OAAO,uBAAuB,oBAAoB;GAC9D,KAAK6B,SAAS,YAAY;EAC5B,CAAC;EACD,MAAM,SAAS,OAAO,YAAY,iBAAiB;GACjD,KAAKA,SAAS,KAAK7B,QAAQ,SAAS;EACtC,CAAC;EACD,OAAO,cAAc;EAOrB,MAAM,SAAS,SAAS,cAAc,MAAM;EAC5C,OAAO,YAAY;EACnB,OAAO,aAAa,aAAa,QAAQ;EACzC,OAAO,cAAc,KAAK8B,WAAW;EAErC,MAAM,OAAO,SAAS,OAAO,QAAQ,MAAM;EAC3C,KAAKtB,gBAAgB;GAAE;GAAS;GAAO;GAAQ;EAAO;EACtD,OAAO;CACT;CAEA,aAAqB;EACnB,OAAO,GAAG,KAAKR,MAAM,QAAQ,CAAC,EAAE;CAClC;CAEA,oBAA0B;EACxB,MAAM,WAAW,KAAKQ;EACtB,IAAI,aAAa,MAAM;EACvB,MAAM,QAAQ,KAAKsB,WAAW;EAC9B,SAAS,MAAM,cAAc;EAC7B,SAAS,MAAM,aAAa,cAAc,yBAAyB,MAAM,EAAE;EAC3E,SAAS,MAAM,WAAW,KAAK9B,UAAU;EACzC,SAAS,QAAQ,WAAW,KAAKA,SAAS,KAAKC;EAC/C,SAAS,OAAO,WAAW,KAAKD,SAAS;EAGzC,MAAM,SAAS,QAAQ;EACvB,IAAI,SAAS,OAAO,gBAAgB,QAAQ,SAAS,OAAO,cAAc;CAC5E;CAEA,aAAa,OAAyB;EAGpC,IAAI,CAAC,MAAM,WAAW,CAAC,MAAM,SAAS;EACtC,IAAI,KAAKJ,yBAAyB,gBAAgB,CAAC,KAAKiB,aAAa,GAAG;EACxE,MAAM,eAAe;EACrB,KAAKgB,SACH,KAAK7B,QAAQ,KAAK,IAAI,CAAC,aAAa,KAAK,IAAI,eAAe,GAC5D,MAAM,SACN,IACF;CACF;;CAGA,mBAAmB,OAA+B;EAGhD,IAAI,MAAM,WAAW,MAAM,WAAW,MAAM,QAAQ,OAAO;EAC3D,IAAI,KAAKJ,yBAAyB,gBAAgB,CAAC,KAAKiB,aAAa,GAAG,OAAO;EAK/E,IAAI,KAAKkB,iBAAiB,MAAM,OAAO;EAEvC,IAAI;EACJ,IAAI,MAAM,QAAQ,OAAO,MAAM,QAAQ,KAAK,OAAO,KAAK/B,QAAQ;OAC3D,IAAI,MAAM,QAAQ,OAAO,MAAM,QAAQ,KAAK,OAAO,KAAKA,QAAQ;OAChE,IAAI,MAAM,QAAQ,KAAK,OAAO;OAC9B,OAAO;EAEZ,MAAM,eAAe;EACrB,KAAK6B,SAAS,IAAI;EAClB,OAAO;CACT;;CAGA,iBAA0B;EACxB,MAAM,QAAQ,KAAK,aAAa,QAAQ;EACxC,OAAO,UAAU,WAAW,UAAU;CACxC;;CAGA,eAA4B;EAC1B,MAAM,SAAS,SAAS,cAAc,KAAK;EAC3C,OAAO,YAAY;EACnB,OAAO,aAAa,QAAQ,QAAQ;EAOpC,KAAK,MAAM,CAAC,WAAW,SAAS;GAL9B,CAAC,iBAAiB,YAAY;GAC9B,CAAC,sCAAsC,OAAO;GAC9C,CAAC,qCAAqC,MAAM;GAC5C,CAAC,gBAAgB,aAAa;EAEM,GAAG;GACvC,MAAM,OAAO,SAAS,cAAc,MAAM;GAC1C,KAAK,YAAY;GACjB,MAAM,SAAS,SAAS,cAAc,MAAM;GAC5C,OAAO,YAAY;GACnB,OAAO,aAAa,eAAe,MAAM;GACzC,IAAI,cAAc,gBAAgB,OAAO,cAAc;GACvD,MAAM,QAAQ,SAAS,cAAc,MAAM;GAC3C,MAAM,cAAc;GACpB,KAAK,OAAO,QAAQ,KAAK;GACzB,OAAO,OAAO,IAAI;EACpB;EACA,OAAO;CACT;;;;;;CAOA,qBAAqB,aAAa,IAAU;EAC1C,MAAM,UAAU,KAAKP,SAAS;EAC9B,MAAM,SAAS,cAAc,KAAK,aAAa,QAAQ,SAAS,aAAa;EAC7E,QAAQ,SAAS,QAAQ,UAAU;GACjC,OAAO,WAAW,UAAU,SAAS,IAAI;EAC3C,CAAC;EAGD,IAAI,cAAc,GAAG,QAAQ,OAAO,EAAE,MAAM,EAAE,eAAe,KAAK,CAAC;CACrE;CAEA,WAAgC;EAC9B,OAAO,CAAC,GAAG,KAAKnC,WAAW,iBAAoC,SAAS,CAAC;CAC3E;CAEA,qBAAqB,OAA4B;EAC/C,MAAM,MAAM,MAAM;EAClB,IAAI,CAAC;GAAC;GAAc;GAAa;GAAW;GAAa;GAAQ;EAAK,CAAC,CAAC,SAAS,GAAG,GAAG;EACvF,MAAM,UAAU,KAAKmC,SAAS;EAC9B,IAAI,QAAQ,WAAW,GAAG;EAC1B,MAAM,UAAU,QAAQ,QAAQ,KAAKpC,MAAM,aAAkC;EAC7E,IAAI,YAAY,IAAI;EAEpB,IAAI;EACJ,IAAI,QAAQ,gBAAgB,QAAQ,aAClC,OAAO,KAAK,IAAI,UAAU,GAAG,QAAQ,SAAS,CAAC;OAC5C,IAAI,QAAQ,eAAe,QAAQ,WAAW,OAAO,KAAK,IAAI,UAAU,GAAG,CAAC;OAC5E,IAAI,QAAQ,QAAQ,OAAO;OAC3B,OAAO,QAAQ,SAAS;EAE7B,MAAM,eAAe;EACrB,IAAI,SAAS,SAAS;EACtB,MAAM,OAAO,QAAQ;EACrB,MAAM,KAAK,QAAQ;EACnB,IAAI,CAAC,QAAQ,CAAC,IAAI;EAClB,KAAK,WAAW;EAChB,GAAG,WAAW;EACd,GAAG,MAAM;EACT,GAAG,iBAAiB;GAAE,OAAO;GAAW,QAAQ;EAAU,CAAC;CAC7D;CAEA,eAAe,IAAmB,QAA2B;EAC3D,IAAI,KAAK6C,iBAAiB,GAAG,IAAI,IAAI;GACnC,KAAK/C,cAAc;GACnB;EACF;EACA,KAAKA,cAAc;EAEnB,MAAM,UAAU,cAAc,IAAI,KAAK,aAAa,QAAQ,KAAK,KAAA,SAAiB;GAChF,KAAKA,cAAc,IAAI;EACzB,CAAC;EAKD,MAAM,gBAAgB,KAAKG,WAAW,sBAAsB;EAC5D,MAAM,aAAa,OAAO,sBAAsB;EAChD,MAAM,iBAAiB,KAAKA,WAAW,eAAe;EACtD,MAAM,OAAO,KAAK,IAChB,KAAK,IAAI,WAAW,OAAO,cAAc,MAAM,CAAC,GAChD,KAAK,IAAI,iBAAA,MAAiC,GAAG,CAAC,CAChD;EACA,QAAQ,MAAM,OAAO,GAAG,KAAK;EAC7B,QAAQ,MAAM,MAAM,GAAG,WAAW,SAAS,cAAc,MAAM,EAAE;EACjE,KAAKA,WAAW,OAAO,OAAO;EAC9B,KAAK4C,eAAe,GAAG,IAAI;EAC3B,KAAKC,cAAc;EACnB,OAAO,aAAa,iBAAiB,MAAM;EAE3C,SAAS,iBAAiB,SAAS,KAAKC,gBAAgB;EACxD,SAAS,iBAAiB,WAAW,KAAKC,kBAAkB;EAE5D,KAAK9B,UAAU,kBAAkB,EAAE,OAAO,GAAG,IAAI,CAAC;CACpD;CAEA,qBAAqB,OAAyB;EAC5C,MAAM,OAAO,MAAM,aAAa;EAChC,MAAM,UAAU,KAAKjB,WAAW,cAAc,UAAU;EACxD,MAAM,iBAAiB,YAAY,QAAQ,KAAK,SAAS,OAAO;EAEhE,MAAM,mBACJ,KAAK,SAAS,KAAKD,KAAK,KACxB,KAAK,MAAM,SAAS,gBAAgB,eAAe,KAAK,UAAU,SAAS,QAAQ,CAAC;EACtF,IAAI,kBAAkB,kBAAkB;EACxC,KAAKF,cAAc;CACrB;CAEA,cAAc,gBAAgB,OAAa;EACzC,KAAKG,WAAW,cAAc,UAAU,CAAC,EAAE,OAAO;EAClD,KAAK4C,eAAe;EACpB,MAAM,SAAS,KAAKC;EACpB,KAAKA,cAAc;EACnB,QAAQ,aAAa,iBAAiB,OAAO;EAC7C,IAAI,eAAe,QAAQ,MAAM;EACjC,SAAS,oBAAoB,SAAS,KAAKC,gBAAgB;EAC3D,SAAS,oBAAoB,WAAW,KAAKC,kBAAkB;CACjE;CAEA,WAAW,SAA8B;EACvC,MAAM,MAAM,SAAS,cAAc,KAAK;EACxC,IAAI,YAAY;EAChB,IAAI,cAAc;EAClB,OAAO;CACT;CAEA,UAAU,SAAiB,SAAgC;EACzD,MAAM,MAAM,SAAS,cAAc,KAAK;EACxC,IAAI,YAAY;EAChB,MAAM,OAAO,SAAS,cAAc,KAAK;EACzC,KAAK,cAAc;EACnB,IAAI,OAAO,IAAI;EACf,IAAI,QAAQ,SAAS,GAAG;GACtB,MAAM,OAAO,SAAS,cAAc,IAAI;GACxC,KAAK,YAAY;GACjB,KAAK,MAAM,UAAU,QAAQ,MAAM,GAAG,CAAC,GAAG;IACxC,MAAM,OAAO,SAAS,cAAc,IAAI;IACxC,KAAK,cAAc;IACnB,KAAK,OAAO,IAAI;GAClB;GACA,IAAI,QAAQ,SAAS,GAAG;IACtB,MAAM,OAAO,SAAS,cAAc,IAAI;IACxC,KAAK,cAAc,SAAS,QAAQ,SAAS,EAAE;IAC/C,KAAK,OAAO,IAAI;GAClB;GACA,IAAI,OAAO,IAAI;EACjB;EACA,OAAO;CACT;AACF;AAEA,SAAgB,OAAO,UAAU,oBAA0B;CACzD,IAAI,OAAO,mBAAmB,aAAa;CAC3C,IAAI,CAAC,eAAe,IAAI,OAAO,GAC7B,eAAe,OAAO,SAAS,eAAe;AAElD"}