U of I × MindRouter App Gallery

Two-Time-Zone Meeting Finder

Administration Built with ForgeCode v2.13.21 Critic status: shipped

Two-Time-Zone Meeting Finder

Schedule across Moscow, Boise, Idaho Falls and beyond

Idaho spans two time zones — Moscow and Coeur d'Alene run on Pacific time while Boise and Idaho Falls run on Mountain. Paste everyone's availability and find the meeting slots that work for the most people, shown in each person's local time.

Two-Time-Zone Meeting Finder running on a desktop screen, schedule across moscow, boise, idaho falls and beyond Desktop · click to enlarge
Two-Time-Zone Meeting Finder running on a phone, schedule across moscow, boise, idaho falls and beyond
Phone · click to enlarge

What it is ✎ blurb written by the AI critic

Plan a meeting for people split between Idaho's Pacific-time north (Moscow, Coeur d'Alene) and Mountain-time south (Boise, Idaho Falls, Twin Falls), or anywhere else. Add participants, paint each person's free hours in their own local time or paste busy blocks from a calendar .ics file. The app then shows a heatmap of who is free when and ranks the best slots. Every suggestion is shown in each person's local time, with daylight saving handled, and the chosen slot can be downloaded as a calendar invite or copied as a text summary.

Try this

  1. Click 'Load a sample team (illustrative data)', then hover the heatmap cells to see who is free at each half hour in Pacific and Mountain time.
  2. Set the meeting length to 2 hours and click a heatmap cell in the early afternoon. The Chosen slot panel shows who can't attend and why, then you can export the .ics invite.
  3. Jump to the week of Oct 26, 2026 with the date picker, add a participant in America/Phoenix, and pick a slot. Then go to the next week and see Phoenix's one-hour gap to Boise close after the clocks change.

Highlights ✎ written by the AI critic

  • All time math uses the browser's built-in time-zone data, so meetings in the week clocks change (e.g. Nov 1, 2026) show correct local times for Moscow, Boise and Phoenix
  • Heatmap of combined availability: hover or tab to a cell to see who is free and who is busy
  • Paint availability by click-dragging, or import busy blocks from .ics text, including weekly repeating events
  • Best slots are ranked all-required-first, then by most optional people, and each is shown in every person's local time
  • One click exports a calendar invite (.ics) or copies a plain-text summary of the chosen slot

Who it's for

Committee chairs, statewide Extension teams, multi-campus research groups

Features

  • Participant list with name, location/time zone (quick picks for U of I centers: Moscow, Coeur d'Alene, Boise, Idaho Falls, Twin Falls, plus any IANA zone) and required/optional flag
  • Paint-your-availability weekly grid per person (click-drag), or paste busy blocks from an .ics file
  • Heatmap of combined availability with best-slot ranking (all required present, most optional)
  • Every suggested slot shown simultaneously in each participant's local time, with DST-aware dates
  • Working-hours constraints and meeting length / buffer settings
  • Export the chosen slot as an .ics invite and a copyable plain-text summary

Data & sources

  • data.iana.org — IANA Time Zone Database zone1970.tab (tzdb 2026d)
  • data.iana.org — IANA tzdb version file
  • www.uidaho.edu — University of Idaho location pages, cited as links only:
  • www.rfc-editor.org — RFC 5545 iCalendar (IETF)
  • MDN Intl.DateTimeFormat and Intl.supportedValuesOf, reference; all time-zone math uses the browser's Intl support
Full data provenance ✎ written by the AI reviewer

Data & sources — Two-Time-Zone Meeting Finder

Retrieved 2026-09-13. The app does no network requests: all time-zone math uses the browser's built-in IANA time-zone support (Intl.DateTimeFormat with timeZone: 'America/Los_Angeles' etc.), which already knows every daylight-saving transition. The only raw file is a small zone list used to build a friendly, searchable "any IANA zone" picker. No participant, availability or calendar data ships with the app — any example participants the app offers must be clearly labelled as illustrative/sample data.


1. zone1970.tab — IANA Time Zone Database zone descriptions

  • URL: https://data.iana.org/time-zones/tzdb/zone1970.tab

  • Publisher: Internet Assigned Numbers Authority (IANA) — Time Zone Database (tzdb), maintained by Paul Eggert et al. Project page: https://www.iana.org/time-zones

  • Version: tzdb 2026d (see tzdb-version.txt, from https://data.iana.org/time-zones/tzdb/version)

  • Retrieved: 2026-09-13

  • License: public domain (stated in the file header)

  • Size: 17.6 KB, 312 data rows

  • Format notes (for parsing): UTF-8 text. Lines starting with # are comments — skip them and blank lines.

  • Each data row has 3 or 4 columns separated by a single TAB:

    1. comma-separated ISO 3166 country codes (first = most populous), e.g. US or US,CA

    2. coordinates in ISO 6709 (±DDMM±DDDMM or ±DDMMSS±DDDMMSS), e.g. +433649-1161209

    3. IANA zone name — the value to pass to Intl.DateTimeFormat({timeZone}), e.g. America/Boise

    4. optional comment, present only when a country has several zones, e.g. Mountain - ID (south), OR (east)

  • Useful US rows (verbatim):

    • America/Los_Angeles — Pacific

    • America/Boise — Mountain - ID (south), OR (east)

    • America/Denver — Mountain (most areas)

    • America/Phoenix — MST - AZ (most areas), Creston BC (no DST)

    • America/Chicago — Central (most areas), America/New_York — Eastern (most areas)

    • America/Anchorage — Alaska (most areas), Pacific/Honolulu — Hawaii

  • Suggested use: parse into a compact list of {zone, countries, comment} for a searchable picker. Current UTC offsets and abbreviations should be computed live in the browser (they change with DST), not stored. Intl.supportedValuesOf('timeZone') is a good cross-check/fallback in the browser.

2. U of I locations → time zones (quick picks)

These are facts about where University of Idaho locations are and which IANA zone governs them (Idaho's northern panhandle observes Pacific time; southern Idaho observes Mountain time, zone America/Boise). Link each center in the app's "Data & sources" section:

Quick pickIANA zoneOfficial page
Moscow (main campus)America/Los_Angeles (Pacific)https://www.uidaho.edu/
Coeur d'AleneAmerica/Los_Angeles (Pacific)https://www.uidaho.edu/coeur-d-alene
BoiseAmerica/Boise (Mountain)https://www.uidaho.edu/boise
Idaho FallsAmerica/Boise (Mountain)https://www.uidaho.edu/idaho-falls
Twin Falls (Research and Extension Center)America/Boise (Mountain)https://www.uidaho.edu/idaho-ag-experiment-station/centers/twin-falls

Publisher: University of Idaho (uidaho.edu). Page titles checked 2026-09-13. Zone assignments per the IANA tzdb comments above. Use these pages as links only — nothing is copied from them.

3. Standards and browser references (cite in the app; nothing downloaded)

  • iCalendar, RFC 5545 — Internet Engineering Task Force, https://www.rfc-editor.org/rfc/rfc5545 (retrieved 2026-09-13). Governs both .ics import (busy blocks) and .ics export (the invite). Parsing notes: lines end in CRLF; long lines are folded (a line starting with a space or tab continues the previous line — unfold first). Events are BEGIN:VEVENT … END:VEVENT. DTSTART/DTEND appear as DTSTART:20260914T160000Z (UTC, trailing Z), DTSTART;TZID=America/Boise:20260914T100000 (local time in a named zone) or DTSTART;VALUE=DATE:20260914 (all-day). DURATION:PT1H may replace DTEND. TRANSP:TRANSPARENT or STATUS:CANCELLED events are not busy. Recurring events use RRULE (weekly FREQ=WEEKLY;BYDAY=MO,WE is the common case). An exported invite needs VERSION:2.0, PRODID, UID, DTSTAMP, DTSTART, DTEND, SUMMARY; writing DTSTART/DTEND in UTC (Z) avoids needing a VTIMEZONE block.

  • Intl.DateTimeFormat — MDN Web Docs (Mozilla), https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat (retrieved 2026-09-13). formatToParts with timeZone gives the wall-clock date/time of any instant in any zone; timeZoneName: 'short' gives PDT/MST/MDT etc.

  • Intl.supportedValuesOf() — MDN Web Docs, https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/supportedValuesOf (retrieved 2026-09-13). Lists every IANA zone the browser supports.

License of references: RFC text © IETF Trust (cite, do not copy); MDN content CC-BY-SA 2.5 (cite only).

DST facts worth handling (for correctness checks)

  • US DST 2026 ends Sunday 2026-11-01 at 02:00 local; DST 2027 starts Sunday 2027-03-14 at 02:00 local.

  • Pacific (Moscow/CdA) and Mountain (Boise/Idaho Falls) are always 1 hour apart; America/Phoenix does not observe DST, so its gap to Mountain changes across the transition. A weekly grid that spans a transition week must compute each day's slot times separately in each zone.

How it was built

Written by ForgeCode 2.13.21 (forgecode.dev) on qwen/qwen3.8-27b, served by MindRouter, the University of Idaho's on-premises AI platform.

12harness rounds
107.2minutes of harness work (1.8 h)
2,719lines of code
174KB, single-file app

Rounds by kind

build1
feedback8
critic3

Lines of code per file

body html213
app css468
app js2,001
scripts37

Critic scores ✎ scored by the independent AI critic, 1–10

visual 8 out of 10
usefulness 8 out of 10
correctness 8 out of 10
interactivity 8 out of 10

Independent audits ✎ by the AI critic

Data honesty: checked against raw data Authorship audit: every app-code commit is a harness round

Automated checks

Console no console errors No network 0 external requests Phone layout 0 px overflow Canvases no empty canvases Brand header header present No key leak no key in source

Checked by critic-verify.

Data spot checks ✎ written by the AI critic

  • Chosen slot 'Mon, Sep 14 10:15-10:45 AM PDT' is displayed as UTC 17:15Z and 11:15 AM MDT for the Boise and Idaho Falls people. Python zoneinfo gives 2026-09-14 10:15 America/Los_Angeles = 17:15Z = 11:15 AM MDT in America/Boise. Match.
  • DST: for Nov 2 2026, 1:00 PM PST the app shows 21:00Z, Boise 2:00 PM MST and Phoenix 2:00 PM MST. For Oct 26, 1:00 PM PDT it shows Boise 2:00 PM MDT and Phoenix 1:00 PM MST. zoneinfo gives the same offsets (PST UTC-8, PDT UTC-7, MST UTC-7, MDT UTC-6; Phoenix is UTC-7 all year). Match.
  • The DST notice 'DST changes this week in: America/Los_Angeles, America/Boise' appears for Oct 26-Nov 1 and not for Nov 2-8. zoneinfo puts the transitions at 2026-11-01 09:00Z (LA) and 08:00Z (Boise). Match.
  • Exporting Mon Sep 14 11:00-11:30 AM PDT gives DTSTART:20260914T180000Z and DTEND:20260914T183000Z. zoneinfo: 11:00 PDT = 18:00Z. Match.
  • .ics import: an event with TZID=America/Los_Angeles, Wed 13:00-15:00, marks slots 52-59 (1-3 PM). A weekly MO-FR RRULE at 16:00Z for 30 min marks 9:00-9:30 AM PDT on Mon-Fri. 16:00Z = 9:00 AM PDT. Match.
Show all 8 spot checks
  • The heatmap shows 2 people free at Mon 8:00 AM PDT (Alex Morgan, Jordan Lee). By hand: 8:00 PDT = 9:00 MDT, which is inside 9-5 for the Boise people and outside 9-5 for the Pacific people. Match.
  • Zone list: data/raw/zone1970.tab has 312 data rows, data/embed/zones.json has 312 entries, and the UI says '312 zones'. The America/Boise label 'Mountain - ID (south), OR (east)' matches the raw row word for word.
  • Sample people are all tagged '(sample)', the load button and toast say 'illustrative data', and the Data & sources section links IANA tzdb 2026d, the U of I location pages, RFC 5545 and MDN. No invented U of I figures appear.
Build notes ✎ written by the AI reviewer

ForgeCode 2.13.21 on MindRouter default-agent (qwen/qwen3.8-27b) wrote all app code across 9 rounds: 1 build plus all 8 allowed feedback rounds, 5,988 s in total. No 'continue' or kill rounds were needed, and TAMPER GUARD never triggered.

The only project files I wrote were data/raw/zone1970.tab, data/raw/tzdb-version.txt, data/raw/SOURCES.md and FEEDBACK.md (removed in commit 830025c).

  • How the build went: Round 1 (7 min) produced a clean-looking app whose core logic was wrong. Grid slots were compared by index with no time-zone conversion, so '9:15 PDT' and '9:15 MDT' were shown as the same meeting. Drag painting marked only one cell, the week was fixed to the past week, and one all-day .ics event blocked all seven days.

  • Round 2 added real-instant conversion and many features, but introduced an off-by-one day (Sunday labelled Monday). Round 3 fixed it.

  • Weekly RRULE import took four reports to get right (wrong days, then nothing drawn, then 7 hours late). It was fixed in round 6 after I passed on the harness's own debug output (22:00Z instead of 15:00Z).

  • The ranked-card choose button needed three reports.

  • Rounds 3, 4 and 5 ended on ForgeCode's 'Maximum request (100) per turn achieved' with items unfinished; later rounds picked them up.

  • The phone heatmap tooltip went through three broken states (clipped, a one-letter-wide strip, then a 20 px strip caused by position:fixed inside a scaled cell) before round 8 fixed it.

  • The last defect, clipped times in phone person rows, got one fix attempt in round 9 (min-width:0) that did not work in the browser. No feedback rounds were left, so it stays open.

Status: everything works on desktop and phone except the clipped phone row times, so this is needs-work rather than shipped.

Verification: 38 feature checks and 14 probe checks via Playwright (drag paint, paste and file .ics, export download, clipboard, DST weeks, three browser zones, phone tooltip and overflow measurements). Every remaining failure is either the real phone-row issue or a documented test artifact.

Round-by-round timeline

Every harness round, in order. The prompts and FEEDBACK.md were written by the AI reviewer; the app code was written by the harness. Expand a round to see the exact prompt and the FEEDBACK.md the harness received.

    1 build 7.2 min · 6 files changed, 3209 insertions(+), 3 deletions(-) Show prompt

    Prompt given to the harness:

    Read AGENTS.md, SPEC.md and BRAND.md in this directory. Then build the complete app they describe, step by step: first write a small script in scripts/ that turns the IANA zone list in data/raw/zone1970.tab (see data/raw/SOURCES.md for its format and for the U of I center time zones and references) into compact JSON in data/embed/ for a searchable "any IANA zone" picker, and run it; then write src/body.html, src/app.css and src/app.js; run python3 build.py --check and fix any error it reports. All time-zone and daylight-saving math must use the browser's Intl.DateTimeFormat (no network requests). Credit every source listed in data/raw/SOURCES.md, with links, in a visible "Data & sources" section, and clearly label any example participants as sample data. Implement every required feature in SPEC.md with a polished, modern, responsive University of Idaho design. Do not stop until python3 build.py --check succeeds and every feature is implemented.
    

    No feedback file was sent in this round.

    10 critic 4.2 min · 4 files changed, 331 insertions(+), 92 deletions(-) Show prompt

    Prompt given to the harness:

    Read FEEDBACK.md in this directory — it lists problems a reviewer found when testing index.html in a real browser. Fix every item, keeping everything that already works, then run python3 build.py --check.
    

    FEEDBACK.md the harness received ✎ written by the AI reviewer:

    Reviewer feedback (tested index.html in Chromium at 1440×900 and 390×844)

    Fix every item, keep everything that already works, then run python3 build.py --check. Items are in priority order. Items 1–4 are wrong behavior; please fix those first.

    1. The heatmap tooltip always describes the wrong cell. Hovering or keyboard-focusing ANY heatmap cell (Mon 8:00 AM, Tue 12:00 PM, Fri 3:00 PM, Thu 10:00 AM…) always shows "Sun, Sep 20 · 5:00 PM–5:30 PM (PDT) · Free: —". This happens on desktop and on phone. Cause: in renderHeat() the listener IIFE is (function (dd, ss) { … showHeatTip(cell) … })(d1, s0). It captures dd/ss, but cell is the function-scoped var cell, which after the loop is the LAST cell built. Pass the element in, e.g. (function (dd, ss, cellEl) { … })(d1, s0, cell), and use cellEl in every handler: mouseenter, focus, click and keydown. With "Include weekends" unchecked, the last cell is an empty weekend cell, so an empty black box appears on hover. showHeatTip should also do nothing when dataset.tip is empty.

    2. The sample team loads out of date. Right after clicking "Load a sample team", the heatmap tops out at 3, but it should be 4. The Chosen panel says "Jordan Lee (sample) (optional) — Not available (not painted free)", and the ranked cards say "0/1 optional · Missing: Jordan Lee (sample)". Everything only corrects itself after the user changes a setting. Cause: loadSample() calls addPerson() (which renders) BEFORE filling that person's free slots, and never renders at the end. Fix: set state.chosen = null and call renderAll() once after all sample people are filled.

    3. The heatmap does not outline the chosen slot on first render. After loading the sample there are 0 .heat-cell.is-chosen cells. renderAll() runs renderHeat() before renderResults() pre-selects the #1 slot. Pre-select the best slot before drawing the heatmap, or redraw the heatmap after pre-selecting, so the chosen cell is outlined immediately.

    4. "Can attend" contradicts the score for longer meetings. Set the meeting length to 2 hours, then click heatmap Wed Sep 16, 12:30 PM (Pacific). The header says "2/3 required", but all four rows say "Can attend". Alex Morgan is busy 2–3 PM MDT, inside the meeting. The row status only checks the start instant (isFreeInstant(p, ps)). Use the same full-duration test as the score for each row's status, reason and red background. The test is: every 15-minute step of [start, end) is inside working hours and free. Also list people who are outside working hours under "Missing:". Right now they are silently left out.

    5. Phone (390 px): person rows overflow their cards, so the times are cut off. In the Chosen panel and in every Best-slots card, each .slot__time row is 385 px wide inside a 324 px card. The card has overflow:hidden, so the time reads "10:15 AM–10:" and the zone abbreviation is missing. The last attempt (min-width:0 on .slot__times) did not change the measurement. Cause: at ≤560 px the grid uses grid-template-columns: 1fr, and a 1fr track's minimum is the row's min-content width: the nowrap name plus the nowrap time. Fix both parts. First, use grid-template-columns: minmax(0, 1fr) and give .slot__time itself min-width: 0. Second, on phones stack each row as two lines (name + avatar on line 1, the full time "10:15 AM–10:45 AM PDT" on line 2) instead of one squeezed line. Check in a 390 px viewport that each row's right edge is inside its card and that the whole time string is visible.

    6. Phone: the "=====" divider in the plain-text summary box still wraps onto a second line. The box is about 296 px wide, about 40 monospace characters at .7rem. Cap the divider at 28 characters.

    7. Desktop: availability-grid day headers read "MON9/14", "TUE9/15" (day and date run together). The heatmap stacks them correctly. Give .avail-grid .gh the same display:flex; flex-direction:column; line-height:1.2 at ALL widths, not only in the phone media query.

    8. Phone: hour labels wrap in the 44 px label column. "10:00 AM", "11:00 AM" and "12:00 PM" break onto two lines in both the availability grid and the heatmap. Those rows grow taller, which leaves visibly uneven gaps between rows. On phones use compact labels ("9a", "10a", "12p", "1p") with white-space: nowrap.

    9. Desktop layout: large empty area. In the two-column section the Participants card (≈820 px) sits next to the Weekly availability card (≈1400 px), leaving ~580 px of blank page under Participants. Make the availability card more compact. Suggestions: 14 px cells on desktop, and hide the .ics paste textarea until "Import busy blocks from .ics…" / a "Paste .ics text" toggle is clicked. Or rebalance the columns so neither side has a big hole.

    10. Wording. Change "Times shown in Dr. Rivera (sample)'s local time" to "Times shown in local time for Dr. Rivera (sample)". "Jordan Lee (sample) (optional)" has doubled parentheses. In slot rows, cards and the summary, show optional as "· optional" or a small pill instead.

    11. Painting feedback for zones ahead of the reference zone. Add a participant in Asia/Tokyo and drag over Monday 9–11 AM on their grid. No cells turn green during the drag, although the slots are saved and appear after a re-render. applyPaint() colors the cell with isFreeInstant(...), which returns false when the instant falls before the reference week start. Color the painted cell from p.free / p.ics directly, the same way renderAvail() does.

    12. Phone page is very long (~9,500 px with the sample team). Show the top 3 Best-slot cards on phones with a "Show more slots" button. Keep the .ics paste textarea hidden until requested (see item 9).

    11 critic 2.2 min · 4 files changed, 73 insertions(+), 95 deletions(-) Show prompt

    Prompt given to the harness:

    Read FEEDBACK.md in this directory — it lists problems a reviewer found when testing index.html in a real browser. Fix every item, keeping everything that already works, then run python3 build.py --check.
    

    FEEDBACK.md the harness received ✎ written by the AI reviewer:

    Reviewer feedback, round 2 (tested index.html in Chromium at 1440×900 and 390×844)

    The last round fixed a lot: tooltips now describe the right cell, the sample team loads correctly, the chosen cell is outlined, desktop day headers are stacked, and painting works for Tokyo. But it introduced two JavaScript crashes that break the app. Please fix these first, keep everything else that now works, then run python3 build.py --check.

    1. CRITICAL: the Chosen slot panel is blank on every device. Every render throws ReferenceError: lenMs is not defined. In renderChosen() the new lines personFreeFor(p, ps, lenMs) and unavailReasonFor(p, ps, lenMs) use lenMs, but lenMs is only declared inside chosenInfo(), findSlots() and renderResults(), never in renderChosen(). As a result the panel shows only its heading. The slot, the per-person local times, Export .ics invite, Copy summary and the summary box are all missing. Fix: declare var lenMs = info.endMs - info.startMs; (or state.settings.length * 60000) at the top of renderChosen().

    2. CRITICAL, phone ≤560 px: the heatmap, Best slots and Chosen panel never render. It throws ReferenceError: compactHourLabel is not defined. compactHourLabel() is defined INSIDE renderAvail() but is also called from renderHeat(), where it is not in scope. Move compactHourLabel() out to the shared time-helper section (next to fmtHM()) so both grids can use it.

    3. After fixing 1 and 2, make sure these round-10 changes actually work. The crashes hid them from testing:

      • Phone: every person row in the Chosen panel and in each Best-slots card is two lines (name, then the full time such as "10:15 AM–10:45 AM PDT"), and no row is wider than its card.

      • Phone: the "=====" divider in the plain-text summary box fits on one line.

      • Set the meeting length to 2 hours and click heatmap Wed Sep 16, 12:30 PM (Pacific). Alex Morgan (sample) must show "Not available (busy …)" and the header must show 2/3 required.

      • Phone: Best slots shows 3 cards plus a working "Show more slots" button.

    4. Minor: the new "optional" pill sits right against the name, so the text reads "Jordan Lee (sample)optional". Put a space text node before the pill and give the pill a small left margin.

    Before finishing, check every function you changed. Each variable and helper it uses must be declared in that function or at the top level of the IIFE, not inside a different function.

    12 critic 1.0 min · 4 files changed, 83 insertions(+), 35 deletions(-) Show prompt

    Prompt given to the harness:

    Read FEEDBACK.md in this directory — it lists problems a reviewer found when testing index.html in a real browser. Fix every item, keeping everything that already works, then run python3 build.py --check.
    

    FEEDBACK.md the harness received ✎ written by the AI reviewer:

    Reviewer feedback, round 3 (tested index.html in Chromium at 1440×900 and 390×844)

    Everything now works correctly: no JavaScript errors, correct tooltips, correct sample team, correct DST times, and working export and copy. Please do not change any time-zone, slot-finding, ranking, .ics or tooltip logic. These are small visual-polish items only. When you finish, check that every variable and helper each changed function uses is declared in that function or at the IIFE top level, then run python3 build.py --check.

    1. The .ics paste area is still visible by default. renderAvail() sets pasteWrap.hidden = true, but the CSS rule .ics-paste { display: flex; … } overrides the browser's [hidden] style, so the textarea and the "Apply pasted .ics" button always show. The "Paste .ics text" toggle therefore appears to do nothing on the first click. Add .ics-paste[hidden] { display: none !important; } to app.css. This is the same pattern .loc-custom[hidden] already uses.

    2. Blank bands in the Weekly availability grid. visibleRange() shows working hours ±1 hour, but the out-of-hours cells are transparent. The result is two empty ~90 px bands at the top ("8:00 AM" row) and bottom ("5:00 PM" row) of the grid on desktop and phone. Give .cell.is-out a faint visible style instead of transparent, e.g. repeating-linear-gradient(45deg, var(--surface-2) 0 4px, transparent 4px 8px), plus the legend entry "Outside working hours". Make the rows look intentional.

    3. Desktop: the availability card is much taller than the Participants card beside it (≈1,410 px vs ≈820 px), leaving a big blank area under Participants. On desktop (min-width 561 px) set .cell { height: 12px; } and tighten the grid gap to 1 px so the card is roughly the height of the Participants card. Keep the phone cell height as it is.

    4. Desktop: participant names are cut off in the Chosen panel and Best-slots cards ("Jordan Lee (sample) …"). The white-space: nowrap; text-overflow: ellipsis rule on .slot__time .who applies at every width. Let names wrap normally above 560 px, keeping only the phone rule inside the ≤560 px media query.

    5. Phone: the plain-text summary box adds ~600 px to an already long page. On phones only, put the summary box inside a <details> element with the summary "Show plain-text summary". Keep it always visible on desktop. Copy summary must keep working in both cases.

What the agent was asked

The full specification the harness received, rendered from the original Markdown.

Read the specification

Two-Time-Zone Meeting Finder — Schedule across Moscow, Boise, Idaho Falls and beyond

Category: Administration Who it is for: Committee chairs, statewide Extension teams, multi-campus research groups

What it should do

Idaho spans two time zones — Moscow and Coeur d'Alene run on Pacific time while Boise and Idaho Falls run on Mountain. Paste everyone's availability and find the meeting slots that work for the most people, shown in each person's local time.

Data

No external data; use the browser's IANA time-zone support (Intl.DateTimeFormat, America/Los_Angeles, America/Boise, America/Denver, etc.) including daylight-saving transitions.

Raw downloads (if any) are in data/raw/ with data/raw/SOURCES.md describing where each file came from. Transform what the app needs into compact JSON in data/embed/ (write a small script in scripts/ to do it, so the transformation is reproducible). Every dataset the app shows must be credited in a visible "Data & sources" section of the app, with links. If a dataset is illustrative/synthetic, label it clearly as such in the UI — never present made-up numbers as real University of Idaho figures.

Required features

  • Participant list with name, location/time zone (quick picks for U of I centers: Moscow, Coeur d'Alene, Boise, Idaho Falls, Twin Falls, plus any IANA zone) and required/optional flag

  • Paint-your-availability weekly grid per person (click-drag), or paste busy blocks from an .ics file

  • Heatmap of combined availability with best-slot ranking (all required present, most optional)

  • Every suggested slot shown simultaneously in each participant's local time, with DST-aware dates

  • Working-hours constraints and meeting length / buffer settings

  • Export the chosen slot as an .ics invite and a copyable plain-text summary

Quality bar

This app is going into a University of Idaho gallery that shows faculty, staff and students what they can build with AI coding agents. It must look polished and modern (think a well-designed data product, not a homework demo), feel alive (smooth transitions, responsive hover/selection states, animated where it helps understanding), and do real, useful work — every control should change something meaningful. It must work well on a laptop and on a phone. Include a short "How to use" hint for first-time visitors and a helpful empty state wherever the user must supply data.

Known limitations

Reported by the independent critic. ✎ written by the AI critic

  • If a required person's working hours never overlap with the others (e.g. Asia/Tokyo 9-5 alongside Pacific 9-5), Best slots only says 'No slots satisfy the current constraints' instead of ranking the best partial matches.
  • The phone page is still long with the sample team, about 8,500 px (down from 9,500).
  • The exported .ics uses METHOD:REQUEST without ORGANIZER or ATTENDEE, and the long DESCRIPTION line is not folded at 75 octets as RFC 5545 requires. Common calendar apps import it, but strict clients may complain.
  • Edge case: during the fall-back week, the last hour of Sunday Nov 1 falls outside the grid week.
  • Desktop: the availability card is still about 200 px taller than the Participants card next to it. The heatmap's gold best-slot and green all-required outlines look heavy when most cells qualify.