"""Phase 128 task 03 E2E (Playwright, mock-only): the RUNNING sync label is fully visible at a phone viewport — the file path ellipsizes to fit and the ``(n/m)`` count span sits in its own non-shrinking part that is NEVER clipped — in BOTH long spans (import + summaries), while desktop keeps the pre-phase strings and the ``min(16rem, 40vw)`` cap. 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 splits 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. 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 rendered ``#sync-label``'s bounding box is INSIDE the viewport (left ≥ 0, right ≤ 390 — the bug's direct negation), and the ``.sync-label-count`` part is VISIBLE (non-null box) and NOT clipped — its right edge sits at or inside the label's right edge and the button's right edge, with text matching ``\\(\\d+/\\d+\\)`` once a file is in flight; ``.sync-label-main`` carries ``Syncing… `` — the FULL source/relative/path (visually ellipsized, but the DOM text and the button ``title`` are untruncated, A4). Phase 129: the label's THIRD pinned part — ``.sync-label-chunk``, "· chunk n/m" (the in-flight file's embed-batch position, batch granularity) — renders while a file's embed batch is in flight (``chunks_total > 0``) and rides the untruncated ``title`` too; the snapshot accepts it (optional — the pre-first-batch frame has no chunk part yet; the phase-129 dedicated suite pins it strictly). 2. ``test_mobile_label_shows_summaries_count`` — same mobile viewport; through to the summaries phase: ``.sync-label-main`` matches ``Summarizing folders…`` (the folder part optional — the phase's first poll may precede the first hook), the ``.sync-label-count`` part matches ``\\(\\d+/3\\)`` and stays visible (same clip pins as test 1); on settle the button leaves the running label (the phase-32 terminal ``Synced HH:MM``) and the count span is hidden + empty. 3. ``test_desktop_label_unchanged`` — viewport 1280×800; the same sync: during import the full rendered label text (main + count + optional phase-129 chunk concatenation) matches ``Syncing… (n/m)`` (the pre-phase byte-identical string, the chunk part appended while a batch is in flight) and the label's width respects the ``min(16rem, 40vw)`` cap (bounding box width ≤ 256 px + slack — the shrinkable main part absorbs the extra pinned part); the ``title`` carries 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 ``