diff --git a/tl/resources/public/css/app.css b/tl/resources/public/css/app.css
new file mode 100644
index 0000000..74b4bf5
--- /dev/null
+++ b/tl/resources/public/css/app.css
@@ -0,0 +1,119 @@
+/* tl — app styles. Dynamic geometry (positions/sizes derived from zoom/frames
+ or the resizable panes) stays inline in the views; everything static is here. */
+
+html, body, #app { height: 100%; margin: 0; }
+body { overflow: hidden; }
+
+.app {
+ height: 100vh;
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+ font-family: sans-serif;
+ background: #0c0c0c;
+ color: #ddd;
+}
+
+/* --- top region: video | annotation ------------------------------------ */
+.top { display: flex; min-height: 0; }
+
+.video-pane {
+ flex-shrink: 0;
+ display: flex; align-items: center; justify-content: center;
+ background: #000; overflow: hidden; min-width: 0;
+}
+.video-pane video { max-width: 100%; max-height: 100%; display: block; background: #000; }
+
+.annot-pane { flex: 1; min-width: 0; display: flex; }
+
+/* --- draggable dividers ------------------------------------------------- */
+.divider-v { flex-shrink: 0; width: 6px; cursor: col-resize; background: #222; }
+.divider-h { flex-shrink: 0; height: 6px; cursor: row-resize; background: #222; }
+.divider-v:hover, .divider-h:hover { background: #3a6ea5; }
+
+/* --- commentary --------------------------------------------------------- */
+.commentary {
+ position: relative; flex: 1; overflow-y: auto;
+ background: #111; padding: 8px 12px; box-sizing: border-box;
+}
+.ann {
+ position: relative;
+ padding: 8px 10px; margin-bottom: 8px; border-radius: 4px;
+ border: 1px solid transparent; background: #161616;
+}
+.ann.active { border-color: #3a6ea5; background: #152333; }
+.ann-head { display: flex; align-items: center; justify-content: space-between;
+ gap: 8px; margin-bottom: 4px; }
+.ann-title { font-size: 10px; text-transform: uppercase; letter-spacing: 1px;
+ color: #7aa6d6; }
+.ann-empty { color: #666; font-size: 12px; }
+
+.jump-btn {
+ flex-shrink: 0; background: #1c2a38; color: #cfe3f5;
+ border: 1px solid #3a6ea5; border-radius: 4px;
+ padding: 1px 7px; cursor: pointer; font-size: 10px; white-space: nowrap;
+}
+/* native popover in the top layer; top/right set by JS (place-popover!) in
+ viewport coords so it tracks the commentary scroll. */
+.jump-pop:popover-open {
+ position: fixed;
+ margin: 0; inset: auto;
+ min-width: 150px; max-height: 180px; overflow-y: auto;
+ background: #1b1b1b; border: 1px solid #3a6ea5; border-radius: 4px;
+ box-shadow: 0 4px 14px rgba(0,0,0,0.5); padding: 4px;
+}
+.jump-pop button {
+ display: block; width: 100%; text-align: left; background: none;
+ color: #cde; border: none; border-radius: 3px; padding: 4px 6px;
+ cursor: pointer; font-size: 11px; white-space: nowrap;
+}
+.jump-pop button:hover { background: #2a4a6a; }
+
+/* --- markdown (tl.md output is wrapped in .md) -------------------------- */
+.md h1 { font-size: 16px; margin: 0 0 6px; line-height: 1.25; }
+.md h2 { font-size: 14px; margin: 0 0 6px; line-height: 1.25; }
+.md h3 { font-size: 13px; margin: 0 0 6px; line-height: 1.25; }
+.md h4, .md h5, .md h6 { font-size: 12px; margin: 0 0 6px; }
+.md p { margin: 0 0 8px; }
+.md ul { margin: 0 0 8px 18px; padding: 0; }
+.md code { background: #222; padding: 0 3px; border-radius: 3px; font-size: 12px; }
+
+/* --- timeline region ---------------------------------------------------- */
+.timeline-pane { flex: 1; display: flex; flex-direction: column; min-height: 0; }
+
+.toolbar { display: flex; gap: 20px; align-items: center; padding: 6px 8px;
+ background: #0c0c0c; border-bottom: 1px solid #222; flex-shrink: 0; }
+.slider { display: flex; align-items: center; gap: 6px; font-size: 11px; color: #9ab; }
+.slider input { width: 150px; }
+
+.timeline-scroll { flex: 1; overflow-y: auto; overflow-x: hidden; min-height: 0; }
+.timeline { display: flex; align-items: flex-start; background: #111; }
+
+.gutter { flex-shrink: 0; width: 150px; user-select: none; }
+.gutter-label {
+ box-sizing: border-box;
+ border-bottom: 1px solid #2a2a2a; border-right: 1px solid #2a2a2a;
+ padding: 0 6px; font-size: 10px; color: #9ab; background: #141414;
+ white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
+}
+.hscroll { overflow-x: auto; flex: 1; }
+.content { position: relative; cursor: ew-resize; }
+
+.track-row { position: relative; background: #1c1c1c; border-bottom: 1px solid #2a2a2a; }
+.clip {
+ position: absolute; top: 1px; box-sizing: border-box; overflow: hidden;
+ background: #3a6ea5; border: 1px solid #16324f; border-radius: 2px;
+ font-size: 10px; color: #cfe3f5; white-space: nowrap; padding-left: 3px;
+}
+
+.playhead { position: absolute; top: 0; bottom: 0; width: 2px; background: #e33;
+ z-index: 10; pointer-events: none; }
+.playhead-handle { position: absolute; top: 0; left: -5px; width: 12px; height: 10px;
+ background: #e33; border-radius: 2px; }
+
+/* --- annotation lane ---------------------------------------------------- */
+.ann-lane-row { position: relative; height: 18px; }
+.ann-bar { position: absolute; top: 2px; height: 14px; border-radius: 2px; }
+.ann-bar-label { position: absolute; top: 1px; font-size: 9px; line-height: 16px;
+ color: #eee; white-space: nowrap; pointer-events: none;
+ text-shadow: 0 1px 2px #000; }
diff --git a/tl/resources/public/index.html b/tl/resources/public/index.html
index f75fb21..a9a0f93 100644
--- a/tl/resources/public/index.html
+++ b/tl/resources/public/index.html
@@ -4,6 +4,7 @@
tl
+