diff --git a/docs/release-control/v6/internal/subsystems/frontend-primitives.md b/docs/release-control/v6/internal/subsystems/frontend-primitives.md
index 6ac37f5e92..700a8fd417 100644
--- a/docs/release-control/v6/internal/subsystems/frontend-primitives.md
+++ b/docs/release-control/v6/internal/subsystems/frontend-primitives.md
@@ -2314,6 +2314,10 @@ not a replacement status card, CTA band, or page-local nested card.
`platformTableBandWidthStyle` or the sortable header's `bandWidth`, which
sets `--platform-table-band-width`; the shell applies it only inside the band,
after the name anchor, so md widths and phone widths are unchanged.
+ A column whose content must read in full (a status badge) is sized for its
+ widest label at the narrowest table in each range: a 34rem container for the
+ band, and the table a 768px viewport leaves (about 695px) for md widths. The
+ Docker Images Update check column needs 23 percent and 19 percent for that.
Below a 360-pixel content width, the shared narrow layout promotes identity to
40 percent and may remove one additional lowest-priority context column via
`platform-table-narrow-hidden` rather than shrinking names and metric values
diff --git a/docs/release-control/v6/internal/subsystems/unified-resources.md b/docs/release-control/v6/internal/subsystems/unified-resources.md
index 8713af1120..fc0d77b8dc 100644
--- a/docs/release-control/v6/internal/subsystems/unified-resources.md
+++ b/docs/release-control/v6/internal/subsystems/unified-resources.md
@@ -882,7 +882,12 @@ failed and server-denied observations alongside a no-invented-grant control.
The Docker phone container projection keeps identity, state when applicable,
CPU, memory and update; restart counts remain in the existing detail expansion
and return at mobile width. Images retain image, size and update verdict on
-phones; host and consumers stay reachable in detail. Hidden header/body columns
+phones; host and consumers stay reachable in detail. The update verdict reads
+in full at every width: the Update check column keeps the ~122px its longest
+badge ("Update available", "Managed by Pulse") needs with cell padding, through
+a 23 percent tablet-band width taken from Size and a 19 percent md width taken
+from Host, Used by and Size. An equal band share and the old 16 percent md width cut
+the badge off between 600 and 800px. Hidden header/body columns
are symmetric. Swarm rollout tokens render as words with raw state retained in
the title; task starts use the shared relative-time primitive with their exact
timestamp retained. Native table/model/guardrail tests and the production
diff --git a/frontend-modern/browser-verification/7db5e194a586019d.json b/frontend-modern/browser-verification/7db5e194a586019d.json
new file mode 100644
index 0000000000..200a52b266
--- /dev/null
+++ b/frontend-modern/browser-verification/7db5e194a586019d.json
@@ -0,0 +1,99 @@
+{
+ "version": 1,
+ "base_sha": "8e68bab55a68d80c7fa234a89216daa5e3af8f29",
+ "verified_at": "2026-10-05T13:41:29Z",
+ "result": "passed",
+ "changed_paths": [
+ "frontend-modern/src/features/docker/DockerImagesTable.tsx"
+ ],
+ "content_sha256": {
+ "frontend-modern/src/features/docker/DockerImagesTable.tsx": "a4b95eaae2c0b67cc8195b3b5f5812cee3499bd583da195f809bf8ff1c4e81f0"
+ },
+ "routes": [
+ "/docker/images"
+ ],
+ "viewports": [
+ {
+ "width": 390,
+ "height": 900
+ },
+ {
+ "width": 430,
+ "height": 900
+ },
+ {
+ "width": 480,
+ "height": 900
+ },
+ {
+ "width": 540,
+ "height": 900
+ },
+ {
+ "width": 573,
+ "height": 900
+ },
+ {
+ "width": 600,
+ "height": 900
+ },
+ {
+ "width": 640,
+ "height": 900
+ },
+ {
+ "width": 700,
+ "height": 900
+ },
+ {
+ "width": 740,
+ "height": 900
+ },
+ {
+ "width": 767,
+ "height": 900
+ },
+ {
+ "width": 768,
+ "height": 900
+ },
+ {
+ "width": 800,
+ "height": 900
+ },
+ {
+ "width": 900,
+ "height": 900
+ },
+ {
+ "width": 1024,
+ "height": 900
+ },
+ {
+ "width": 1100,
+ "height": 900
+ },
+ {
+ "width": 1280,
+ "height": 900
+ },
+ {
+ "width": 1440,
+ "height": 900
+ }
+ ],
+ "states": [
+ "Private mock stack (PULSE_MOCK_MODE, random metrics off) serving this tree on main 8e68bab55a, which already carries the Used by block-truncate span from #2514; before = main, after = main plus this change",
+ "Clip sweep (scrollWidth over clientWidth + 1 on every td and its overflow-hidden or ellipsis descendants, .sr-only excluded) at 15 widths from 390 to 1440: the Update check badge clipped at 600, 640, 700 and 768 on main and nowhere patched; total clipped elements 65 on main, 61 patched; Image, Host, Used by and Size clip counts identical at every width (Used by 1/2/2/1 at 600/640/700/740 both ways, 0 from 768)",
+ "Label probe: each of the six update labels (Update available 97.9px, Managed by Pulse 105.8px, Check failed, Not checked, Current, Pinned) cloned into the narrowest Update check cell: on main Update available and Managed by Pulse overflow at 600, 640, 700 and 768, and Managed by Pulse alone at 740 and 800; patched every label fits at every width (Update check content box 113px at the 573px band edge, 116px at 768, 108px at 390)",
+ "Column widths patched: band at 600 Image 171 / Host 100 / Used by 100 / Size 69 / Update check 131 (Host and Used by unchanged from main); md at 768 Image 209 / Host 118 / Used by 160 / Size 76 / Update check 132 (main 209 / 125 / 167 / 83 / 111)",
+ "Size probe: the widest byte strings (1023 MB, 9.99 GB, 99.9 MB, 1023 KB) fit the narrower Size cell at 573, 640, 767, 768, 800 and 900 (worst 49.6px in a 53 to 74px content box)",
+ "The UPDATE CHECK header clipped at 600 on main, including with a sort indicator; patched no header clips at any width, sorted or not",
+ "Before and after element screenshots of the table at 600, 700, 768 and 1440 show the postgres:16.4 Update available badge cut at the cell edge with a stray ellipsis dot on main and whole patched; the phone projection at 390 keeps Image, Size and Update check unchanged"
+ ],
+ "interactions": [
+ "Loaded /docker/images fresh, waited for the row count to settle, then resized through every viewport before measuring",
+ "Sorted by Size and by Update check at the 573px band edge and re-measured header clipping",
+ "Expanded and collapsed the Update available row's detail at 390, 600, 768 and 1440 (aria-expanded true then false, detail row visible); no console errors"
+ ]
+}
diff --git a/frontend-modern/src/features/docker/DockerImagesTable.tsx b/frontend-modern/src/features/docker/DockerImagesTable.tsx
index 454a028d53..b470bbbbb0 100644
--- a/frontend-modern/src/features/docker/DockerImagesTable.tsx
+++ b/frontend-modern/src/features/docker/DockerImagesTable.tsx
@@ -140,11 +140,21 @@ export const DockerImagesTable: Component<
tableClass="min-w-full table-fixed text-xs md:min-w-[880px]"
header={
<>
+ {/*
+ The Update check badge needs about 122px with its cell
+ padding ("Update available", "Managed by Pulse"). An
+ equal tablet-band share gave it 100px at 600px, and 16%
+ at md gave it 111px at 768px, so the label was cut off.
+ Size values are short, so the band takes the extra room
+ from Size, and md takes a point each from Host, Used by
+ and Size, which had room to spare there.
+ */}
Image
@@ -152,7 +162,8 @@ export const DockerImagesTable: Component<
kind="text"
sort={sort}
sortKey="host"
- class="platform-table-phone-hidden md:w-[18%]"
+ class="platform-table-phone-hidden md:w-[17%]"
+ bandWidth={17.5}
>
Host
@@ -160,7 +171,8 @@ export const DockerImagesTable: Component<
kind="text"
sort={sort}
sortKey="usedBy"
- class="platform-table-phone-hidden md:w-[24%]"
+ class="platform-table-phone-hidden md:w-[23%]"
+ bandWidth={17.5}
>
Used by
@@ -168,7 +180,8 @@ export const DockerImagesTable: Component<
kind="numeric-value"
sort={sort}
sortKey="size"
- class="platform-table-mobile-w-20 md:w-[12%]"
+ class="platform-table-mobile-w-20 md:w-[11%]"
+ bandWidth={12}
>
Size
@@ -176,7 +189,8 @@ export const DockerImagesTable: Component<
kind="badge"
sort={sort}
sortKey="update"
- class="platform-table-mobile-w-25 md:w-[16%]"
+ class="platform-table-mobile-w-25 md:w-[19%]"
+ bandWidth={23}
>
diff --git a/frontend-modern/src/features/platformPage/__tests__/platformOverviewLayout.guardrails.test.ts b/frontend-modern/src/features/platformPage/__tests__/platformOverviewLayout.guardrails.test.ts
index f55f91896a..61a4dd9678 100644
--- a/frontend-modern/src/features/platformPage/__tests__/platformOverviewLayout.guardrails.test.ts
+++ b/frontend-modern/src/features/platformPage/__tests__/platformOverviewLayout.guardrails.test.ts
@@ -322,18 +322,24 @@ describe('platform overview layout guardrails', () => {
expect(source).toContain('platform-table-mobile-w-30');
}
// The images phone row keeps image, size and the update verdict; host and
- // consumers move to the row expansion so the verdict is not clipped.
+ // consumers move to the row expansion so the verdict is not clipped. In
+ // the tablet band and at md the Update check column keeps the ~122px its
+ // longest badge needs ("Update available", "Managed by Pulse"), taken
+ // from Size in the band and from Host, Used by and Size at md.
expect(dockerImagesTableSource).toMatch(
- /sortKey="size"[\s\S]{0,120}?class="platform-table-mobile-w-20 md:w-\[12%\]"/,
+ /sortKey="image"[\s\S]{0,120}?class="platform-table-mobile-w-30 md:w-\[30%\]"\s*bandWidth=\{30\}/,
);
expect(dockerImagesTableSource).toMatch(
- /sortKey="host"[\s\S]{0,120}?class="platform-table-phone-hidden md:w-\[18%\]"/,
+ /sortKey="size"[\s\S]{0,120}?class="platform-table-mobile-w-20 md:w-\[11%\]"\s*bandWidth=\{12\}/,
);
expect(dockerImagesTableSource).toMatch(
- /sortKey="usedBy"[\s\S]{0,120}?class="platform-table-phone-hidden md:w-\[24%\]"/,
+ /sortKey="host"[\s\S]{0,120}?class="platform-table-phone-hidden md:w-\[17%\]"\s*bandWidth=\{17\.5\}/,
);
expect(dockerImagesTableSource).toMatch(
- /sortKey="update"[\s\S]{0,120}?class="platform-table-mobile-w-25 md:w-\[16%\]"/,
+ /sortKey="usedBy"[\s\S]{0,120}?class="platform-table-phone-hidden md:w-\[23%\]"\s*bandWidth=\{17\.5\}/,
+ );
+ expect(dockerImagesTableSource).toMatch(
+ /sortKey="update"[\s\S]{0,120}?class="platform-table-mobile-w-25 md:w-\[19%\]"\s*bandWidth=\{23\}/,
);
expect(dockerServicesTableSource).toMatch(
/sortKey="mode"[\s\S]{0,120}?class="platform-table-phone-hidden md:w-\[8%\]"/,