"""Phase 128 task 03 E2E (Playwright, mock-only): the RUNNING sync detail is fully visible at a phone viewport — in BOTH long spans (import + summaries) — while desktop keeps the pre-phase full strings. The dedicated story suite for ``128_sync_label_mobile`` (A16 — one Playwright file per phase, run in isolation): the owner's report was that ``Syncing… name/of/file/here (2/3)`` "doesn't show up on mobile" — pre-phase, ``#sync-label`` was ONE inline-block span (whole label string, one ellipsis) whose mobile media query LIFTED the ``min(16rem, 40vw)`` cap (``max-width: none``), so the ellipsized tail — where ``(n/m)`` lives — was clipped away on a phone. Phase 128 split the label into two parts (``.sync-label-main`, the shrinkable prefix + file/folder, + ``.sync-label-count`, the pinned position) so the count is never the ellipsis's sacrifice. Phase 149 (task 01) RE-POINTED the running-state pins: the owner's follow-up was that the full live label (a long ``source/relative/path`` + the counts + the chunk part) is clipped in the pill even on desktop, and the fix moves the running detail out of the pill entirely — while a run is in flight the button is the spinner (the ``is-running`` class; task 02's CSS hides the label parts), and a detail box under the button row (``#sync-progress``) carries the SAME full untruncated label — wrapping, never clipped, ``#sync-result`` staying the sole aria-live announcer. Tests 1–3 therefore pin the BOX: visible while the run is in flight, its text the pre-phase byte-identical full string ("Syncing… (n/4)" / "Summarizing folders… (n/3)" + the phase-129 "· chunk n/m" while a batch is in flight), inside the viewport at 390 px and 1280 px, the button in its running state, and the ``title`` carrying the same full string (A4 — one source, two surfaces). The SETTLED pins (the phase-32 "Synced HH:MM" label, the count span hidden + empty, the box hidden) are UNCHANGED. Test 4 (the pre-phase-128 rules' clip reproduction) pins the old markup/CSS counterfactually — the label parts still receive their text under any CSS (the writer is unchanged), so it holds on the DOM text + injected rules regardless of the phase-149 box. The injected set ALSO neutralizes the phase-149 hide rule (``.sync-btn.is-running .sync-label { display: none }`` — task 02's specificity (0,2,0) would beat the injected (0,1,0) ``.sync-label`` rule and leave the parts display:none, making the geometry vacuous); pre-phase, that rule simply did not exist, so the faithful pre-phase counterfactual restores the parts' inline-block display at matching specificity, last in the cascade. Run in isolation (DB must be up: ``podman compose up -d db``): uv run pytest tests/e2e/test_sync_label_mobile.py -v --no-cov MOCK-ONLY suite: ``E2E_REAL_LLM=1`` is not supported — the gate is the deterministic mock plus the phase-64 ``tests/e2e/slow_llm.py`` delay proxy that stretches the run past the UI's 2 s status poll, so the rendered-label assertions are deterministic, not races. Timing fixture (the phase-98 sizing rationale, re-sized for this suite): ``SLOW_DELAY_S = 1.5`` — the import span (4 file embeds ≈ 6 s) and the summaries span (3 folder summaries ≈ 4.5 s) each outlive the UI's 2 s poll by ≥ 2×, so the page's OWN 2 s poll renders each running label and holds it in the DOM for at least one full poll period (any window ≥ the period catches it). The whole changed sync is ≈ 10 LLM calls (2 model probes + 4 file embeds + 1 overview + 3 folder summaries) ≈ 15–18 s — well inside the generous settle budgets. The suite runs ONE module app (the phase-79 full-inventory pattern — it binds its own port) over the shared E2E Postgres: the SLOW app (``BOR_LLM_BASE_URL`` = the slow proxy in front of the mock). KB fixture — a host temp dir (``tmp_path_factory``; the app runs on the same host) registered as a ``kind=local`` source (the ``test_local_directory_sources.py`` / phase-94 API-registration pattern; no git anywhere): ``synclabel/`` with TWO files in ``alpha/`` and TWO in ``bravo/`` — the summaries phase then has 3 candidate folders (the source root + the two folders — the recursive-subtree ≥ 1 rule), a non-trivial ``(n/m)``. Autouse cleanup (the phase-96 pattern): before each test wait for no running sync on the app, then truncate the shared registry + KB tables (documents/chunks/query_log/steering_notes/kb_overview/ git_sources/folder_summaries) — each test seeds its own source and runs its own sync; after each test the same truncate. Test → observable mapping (Playwright Mapping Rule): 1. ``test_mobile_label_fits_viewport_with_count_in_import`` — admin page on the sources view at viewport **390×844** (mobile); click **Sync sources**; while the import phase is running (the page's own 2 s poll): the detail box (``#sync-progress``) is VISIBLE and an atomic snapshot of: its text the FULL untruncated label ``Syncing… (n/4)`` (+ the phase-129 "· chunk n/m" part while a batch is in flight — optional, the pre-first-batch frame has none) with the ``(n/4)`` count IN the text (never clipped — nothing is ellipsized away), the box's bounding box INSIDE the viewport (left ≥ 0, right ≤ 390 — the bug's direct negation), the button in its running state (``is-running`` — the spinner), and the button ``title`` carrying the SAME full string (A4 — one source, two surfaces). The run then settles (the phase-32 terminal shape; the box hides). 2. ``test_mobile_label_shows_summaries_count`` — same mobile viewport; through to the summaries phase: the box text matches ``Summarizing folders… [source/folder] (n/3)`` (the folder part optional — the phase's first poll may precede the first hook — the ``(n/3)`` count always present, IN the text) with the same box-geometry pins as test 1 (inside the viewport), the ``title`` carrying the same full string (A4); on settle the button leaves the running label (the phase-32 terminal ``Synced HH:MM``), the count span is hidden + empty, and the box hides. 3. ``test_desktop_label_unchanged`` — viewport 1280×800; the same sync: during import the box text matches ``Syncing… (n/m)`` (+ the phase-129 chunk part while a batch is in flight) — the pre-phase byte-identical FULL string (phase 149 moved it from the pill's parts to the box — the text is unchanged), the box inside the viewport, the button in its running state (``is-running``), and the ``title`` carrying the same untruncated string (A4). 4. ``test_pre_phase_css_reproduces_the_clip`` — the pin check: the SAME mobile run with the pre-phase-128 ``.sync-label`` rules re-injected (CSSOM ``insertRule`` into the origin's own linked stylesheet — the A20 CSP ``default-src 'self'`` blocks inline ``