diff --git a/design/watching/build-watching-osd.py b/design/watching/build-watching-osd.py
new file mode 100644
index 0000000..ad20dfe
--- /dev/null
+++ b/design/watching/build-watching-osd.py
@@ -0,0 +1,89 @@
+#!/usr/bin/env python3
+"""
+The watching screen's programme bar and subtitles/sound panel, redesigned (Paul, 6 November 2026): the panel used to sit
+halfway down the right and hang over the bar, the bar hid itself while the panel was open, and the bar's white and dark
+blue ignored the theme. Here both are one family drawn only from each look's tokens (Themes.kt), the panel docked above
+the bar on the right, the bar staying while the panel is open. Drawn as SVG, converted and exported with FigCraft.
+"""
+import subprocess
+from html import escape
+from pathlib import Path
+
+HERE = Path(__file__).resolve().parent
+LOOKS = {
+ 'Orbit Night': dict(background='#071632', surface='#12356B', raised='#194C91', accent='#FFDE59', ink='#FFFFFF', muted='#B7CBE8', deep='#0C2148', onAccent='#071632'),
+ 'Daybreak': dict(background='#E8F1FB', surface='#FFFFFF', raised='#D2E2F6', accent='#1E66D0', ink='#0E1E3C', muted='#4A5D7A', deep='#DCE8F6', onAccent='#FFFFFF'),
+ 'Nebula': dict(background='#170B2E', surface='#3A1D6B', raised='#522D8F', accent='#FF7AC6', ink='#FFFFFF', muted='#C8B4E6', deep='#22113F', onAccent='#170B2E'),
+ 'Retro Tube': dict(background='#1A120B', surface='#3B2A1A', raised='#574029', accent='#FFB347', ink='#FFECD2', muted='#D2B48C', deep='#241911', onAccent='#1A120B'),
+ 'Deep Sea': dict(background='#04212B', surface='#0B4A5C', raised='#126378', accent='#6EF0D8', ink='#F0FFFC', muted='#A0D2D2', deep='#072C38', onAccent='#04212B'),
+ 'High Contrast': dict(background='#000000', surface='#1A1A1A', raised='#333333', accent='#FFFF00', ink='#FFFFFF', muted='#DCDCDC', deep='#0D0D0D', onAccent='#000000'),
+}
+FONT = 'Barlow, DejaVu Sans, sans-serif'
+
+
+def t(x, y, s, size, fill, weight=400, anchor='start', extra=''):
+ return f'{escape(s)}'
+
+
+def frame(c, panel=True):
+ """One 1920x1080 frame: a programme stand-in, the bar along the bottom, and the panel docked above it on the right."""
+ o = ['',
+ '',
+ '',
+ '',
+ # Subtitles on the picture, kept above the bar.
+ t(960, 742, 'I said we\'d be home by Christmas.', 44, '#FFFFFF', 600, 'middle', 'stroke="#000" stroke-width="3" paint-order="stroke"')]
+ # The bar: one card, deep at 94%, a hairline of raised, rounded 16.
+ x, y, w, h = 134, 800, 1652, 236
+ o.append(f'')
+ o.append(t(x + 32, y + 50, '308', 34, c['accent'], 700) + t(x + 104, y + 50, 'BritX', 34, c['ink'], 700) + t(x + w - 32, y + 50, '21:30 Fri 6 Nov', 28, c['muted'], 400, 'end'))
+ o.append(f'' + t(x + 78, y + 106, 'NOW', 26, c['onAccent'], 700, 'middle'))
+ o.append(t(x + 144, y + 108, 'Hot Fuzz', 42, c['ink'], 700) + t(x + w - 32, y + 108, '21:00 to 23:05', 28, c['muted'], 400, 'end'))
+ o.append(f'')
+ o.append(t(x + 32, y + 178, 'NEXT 23:05 The World\'s End', 28, c['muted'], 600))
+ # Hints, on the surface along the bottom of the card.
+ o.append(f'')
+ hints = [('▲▼', 'Channel'), ('◄', 'TV guide'), ('►', 'Subtitles and sound'), ('OK', 'Hide')] if not panel else [('▲▼', 'Move'), ('OK', 'Choose'), ('◄', 'Back'), ('►', 'Close')]
+ hx = x + 32
+ for key, label in hints:
+ kw = 22 * len(key) + 28
+ o.append(f'' + t(hx + kw / 2, y + 225, key, 20, c['ink'], 700, 'middle') + t(hx + kw + 12, y + 225, label, 24, c['ink'], 600))
+ hx += kw + 30 + 14 * len(label)
+ if panel:
+ # The panel, docked above the bar's right end: never over it, never taller than the space above.
+ px, pw, ph = x + w - 520, 520, 600
+ py = y - 24 - ph
+ o.append(f'')
+ o.append(t(px + 28, py + 52, 'SUBTITLES', 24, c['muted'], 700, extra='letter-spacing="3"'))
+ rows = [('Off', False, False), ('English', True, True), ('English (SDH)', False, False), ('French', False, False)]
+ ry = py + 72
+ for label, selected, cursor in rows:
+ if cursor: o.append(f'')
+ o.append(t(px + 44, ry + 36, ('✓ ' if selected else '') + label, 30, c['onAccent'] if cursor else c['ink'], 700 if (cursor or selected) else 400))
+ ry += 58
+ o.append(f'')
+ o.append(t(px + 28, ry + 56, 'SOUND', 24, c['muted'], 700, extra='letter-spacing="3"'))
+ ry += 74
+ for label, selected in [('English 5.1', True), ('English stereo', False), ('Commentary', False)]:
+ o.append(t(px + 44, ry + 36, ('✓ ' if selected else '') + label, 30, c['ink'], 700 if selected else 400)); ry += 58
+ return o
+
+
+def board():
+ cells = []
+ for i, (name, c) in enumerate(LOOKS.items()):
+ gx, gy = (i % 2) * 980, (i // 2) * 600 + 140
+ cells.append(f'' + ''.join(frame(c)) + '')
+ cells.append(t(gx + 20, gy + 568, name, 30, '#FFFFFF', 600))
+ head = t(40, 70, 'Watching: programme bar and subtitles panel', 46, '#FFDE59', 700) + t(40, 112, 'The panel docks above the bar and the bar stays while it is open. Every colour comes from the look.', 26, '#B7CBE8')
+ svg = f''
+ (HERE / 'watching-osd-themes.svg').write_text(svg)
+ big = f''
+ (HERE / 'watching-osd-night.svg').write_text(big)
+ for name in ('watching-osd-themes', 'watching-osd-night'):
+ subprocess.run(['figcraft-cli', 'convert', str(HERE / f'{name}.svg'), str(HERE / f'{name}.figcraft')], check=True, stdout=subprocess.DEVNULL)
+ subprocess.run(['figcraft-cli', 'export', str(HERE / f'{name}.figcraft'), '--out', str(HERE / f'{name}.png')], check=True, stdout=subprocess.DEVNULL)
+
+
+if __name__ == '__main__':
+ board()
diff --git a/design/watching/watching-osd-night.figcraft b/design/watching/watching-osd-night.figcraft
new file mode 100644
index 0000000..8cfb9c9
Binary files /dev/null and b/design/watching/watching-osd-night.figcraft differ
diff --git a/design/watching/watching-osd-night.png b/design/watching/watching-osd-night.png
new file mode 100644
index 0000000..cc8120c
Binary files /dev/null and b/design/watching/watching-osd-night.png differ
diff --git a/design/watching/watching-osd-night.svg b/design/watching/watching-osd-night.svg
new file mode 100644
index 0000000..d6d0df2
--- /dev/null
+++ b/design/watching/watching-osd-night.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/design/watching/watching-osd-themes.figcraft b/design/watching/watching-osd-themes.figcraft
new file mode 100644
index 0000000..feed281
Binary files /dev/null and b/design/watching/watching-osd-themes.figcraft differ
diff --git a/design/watching/watching-osd-themes.png b/design/watching/watching-osd-themes.png
new file mode 100644
index 0000000..c7b1561
Binary files /dev/null and b/design/watching/watching-osd-themes.png differ
diff --git a/design/watching/watching-osd-themes.svg b/design/watching/watching-osd-themes.svg
new file mode 100644
index 0000000..d50c856
--- /dev/null
+++ b/design/watching/watching-osd-themes.svg
@@ -0,0 +1 @@
+
\ No newline at end of file