# Import Window Responsive Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Make the floating import window recompute a viewport-appropriate size and position every time it opens, and stack collection/item panes vertically on narrower viewports. **Architecture:** Keep the existing floating-window shell and collection importer flow, but replace reopen-time geometry reuse with viewport-derived geometry helpers. Add a narrow-layout breakpoint in the template CSS and a resize handler that constrains normal-mode geometry without overriding minimized or maximized state. **Tech Stack:** FastAPI template rendering, inline HTML/CSS/JavaScript, pytest, Node syntax checking --- ### Task 1: Update UI Contract Tests For Responsive Window Behavior **Files:** - Modify: `tests/test_ui.py` - Test: `tests/test_ui.py` - [ ] **Step 1: Write the failing test** ```python def test_index_has_responsive_import_window_geometry_helpers(tmp_path) -> None: html = _get_index_html(tmp_path) assert "function computeResponsiveWindowRect()" in html assert "function applyResponsiveWindowRect()" in html assert "function syncWindowToViewport()" in html assert "window.addEventListener(\"resize\"" in html ``` ```python def test_index_has_responsive_import_window_layout_rules(tmp_path) -> None: html = _get_index_html(tmp_path) assert ".window-pane.items" in html assert "@media (max-width: 980px)" in html assert ".window-body {" in html assert "grid-template-columns: 1fr;" in html assert "border-bottom: 1px solid var(--line);" in html ``` - [ ] **Step 2: Run test to verify it fails** Run: `UV_CACHE_DIR=/tmp/uv-cache uv run pytest tests/test_ui.py -q` Expected: FAIL because the new responsive geometry helper names are not present yet. - [ ] **Step 3: Keep the existing syntax guard test** Do not remove `test_index_inline_script_is_valid_javascript`; it remains the regression guard for the inline script. - [ ] **Step 4: Run test to verify the contract file still parses** Run: `UV_CACHE_DIR=/tmp/uv-cache uv run pytest tests/test_ui.py::test_index_inline_script_is_valid_javascript -q` Expected: PASS - [ ] **Step 5: Commit** ```bash git add tests/test_ui.py git commit -m "test: define responsive import window contract" ``` ### Task 2: Implement Viewport-Derived Window Geometry **Files:** - Modify: `src/zotero_kb/templates/index.html` - Test: `tests/test_ui.py` - [ ] **Step 1: Write the failing test** Use the Task 1 tests as the failing contract. Do not add production code first. - [ ] **Step 2: Run the failing test** Run: `UV_CACHE_DIR=/tmp/uv-cache uv run pytest tests/test_ui.py -q` Expected: FAIL with missing responsive helper function names or missing layout assertions. - [ ] **Step 3: Write minimal implementation** Add responsive geometry helpers to the inline script in `src/zotero_kb/templates/index.html`: ```javascript function computeResponsiveWindowRect() { const viewportWidth = window.innerWidth; const viewportHeight = window.innerHeight; const margin = viewportWidth <= 980 ? 8 : 24; const minWidth = viewportWidth <= 980 ? 320 : 640; const minHeight = viewportHeight <= 980 ? 420 : 480; const maxWidth = Math.max(minWidth, viewportWidth - margin * 2); const maxHeight = Math.max(minHeight, viewportHeight - margin * 2); const width = Math.min(maxWidth, Math.max(minWidth, Math.round(viewportWidth * 0.88))); const height = Math.min(maxHeight, Math.max(minHeight, Math.round(viewportHeight * 0.82))); const left = Math.max(margin, Math.round((viewportWidth - width) / 2)); const top = Math.max(margin, Math.round((viewportHeight - height) / 2)); return { width, height, left, top }; } function applyResponsiveWindowRect() { const fw = elements.importWindow; if (!fw || state.isWindowMinimized || state.isWindowMaximized) return; const rect = computeResponsiveWindowRect(); fw.style.width = `${rect.width}px`; fw.style.height = `${rect.height}px`; fw.style.left = `${rect.left}px`; fw.style.top = `${rect.top}px`; state.windowWidth = rect.width; state.windowHeight = rect.height; state.windowX = rect.left; state.windowY = rect.top; } function syncWindowToViewport() { const fw = elements.importWindow; if (!fw || state.isWindowMinimized || state.isWindowMaximized) return; const margin = window.innerWidth <= 980 ? 8 : 24; const rect = computeResponsiveWindowRect(); const currentWidth = parseFloat(fw.style.width) || rect.width; const currentHeight = parseFloat(fw.style.height) || rect.height; const width = Math.min(currentWidth, rect.width); const height = Math.min(currentHeight, rect.height); const maxLeft = Math.max(margin, window.innerWidth - width - margin); const maxTop = Math.max(margin, window.innerHeight - height - margin); const left = Math.min(Math.max(parseFloat(fw.style.left) || rect.left, margin), maxLeft); const top = Math.min(Math.max(parseFloat(fw.style.top) || rect.top, margin), maxTop); fw.style.width = `${width}px`; fw.style.height = `${height}px`; fw.style.left = `${left}px`; fw.style.top = `${top}px`; state.windowWidth = width; state.windowHeight = height; state.windowX = left; state.windowY = top; } ``` Update `openImportWindow()` to call `applyResponsiveWindowRect()` after `initWindowFromSession()` when the window is not minimized or maximized. - [ ] **Step 4: Run the focused tests** Run: `UV_CACHE_DIR=/tmp/uv-cache uv run pytest tests/test_ui.py -q` Expected: PASS - [ ] **Step 5: Commit** ```bash git add src/zotero_kb/templates/index.html tests/test_ui.py git commit -m "feat: derive import window geometry from viewport" ``` ### Task 3: Add Responsive Layout Switching And Resize Wiring **Files:** - Modify: `src/zotero_kb/templates/index.html` - Test: `tests/test_ui.py` - [ ] **Step 1: Write the failing test** Use the layout assertions from Task 1 as the failing contract. No new production code before running them. - [ ] **Step 2: Run the failing test** Run: `UV_CACHE_DIR=/tmp/uv-cache uv run pytest tests/test_ui.py -q` Expected: FAIL if the resize listener or stacked layout rules are still missing. - [ ] **Step 3: Write minimal implementation** Extend the existing media query and event wiring in `src/zotero_kb/templates/index.html`: ```css @media (max-width: 980px) { .window-frame { min-width: 0; width: calc(100vw - 1rem); height: calc(100vh - 1rem); left: 0.5rem; top: 0.5rem; } .window-toolbar, .window-toolbar-actions { align-items: stretch; } .window-body { grid-template-columns: 1fr; } .window-pane.collections { border-right: 0; border-bottom: 1px solid var(--line); } } ``` Wire the resize handler: ```javascript window.addEventListener("resize", () => { syncWindowToViewport(); }); ``` - [ ] **Step 4: Run the focused tests** Run: `UV_CACHE_DIR=/tmp/uv-cache uv run pytest tests/test_ui.py -q` Expected: PASS - [ ] **Step 5: Commit** ```bash git add src/zotero_kb/templates/index.html tests/test_ui.py git commit -m "feat: make import window layout responsive" ``` ### Task 4: End-To-End Verification **Files:** - Modify: none - Test: `tests/test_ui.py`, `tests/test_api.py` - [ ] **Step 1: Run the UI test suite** Run: `UV_CACHE_DIR=/tmp/uv-cache uv run pytest tests/test_ui.py -q` Expected: PASS with all UI contract tests green. - [ ] **Step 2: Run the API regression suite** Run: `UV_CACHE_DIR=/tmp/uv-cache uv run pytest tests/test_api.py -q` Expected: PASS with all API tests green. - [ ] **Step 3: Run fresh JS syntax verification through pytest** Run: `UV_CACHE_DIR=/tmp/uv-cache uv run pytest tests/test_ui.py::test_index_inline_script_is_valid_javascript -q` Expected: PASS - [ ] **Step 4: Manual verification** Run the app: ```bash UV_CACHE_DIR=/tmp/uv-cache uv run python main.py ``` Manual checks: - open the import window at one browser zoom level and note the size - close it, change browser zoom, reopen it, confirm it recenters and resizes - shrink the viewport below the narrow breakpoint, reopen it, confirm the panes stack vertically - maximize and minimize the window, confirm those modes still behave correctly - [ ] **Step 5: Commit** ```bash git add src/zotero_kb/templates/index.html tests/test_ui.py docs/superpowers/specs/2026-04-16-import-window-responsive-design.md docs/superpowers/plans/2026-04-16-import-window-responsive.md git commit -m "feat: make import window adapt to viewport changes" ```