# Visual redesign — Topaz Cinema Slate + Drawer layout **Date:** 2026-05-01 **Status:** Draft, awaiting user review **Related:** `2026-04-30-ltx23-aio-generator-design.md` (original spec) --- ## Goal Replace the current `gr.themes.Soft()` cream + purple palette with a dark slate-and-amber palette (**Topaz Cinema Slate**), and replace the always-visible left sidebar with a **hamburger drawer** that opens by default on desktop and is hidden by default on tablet/phone. Both changes are surface-level — no logic or backend changes. ## Why The current palette reads as a hobby AI demo, not a creative-pro tool. Slate-on-slate is gentlest on the eye when judging color-graded video output, and an amber CTA reads "render," not "alert." The drawer pattern gives the form panel full screen real estate on phones (the sidebar currently stacks above the form on `<700px`, eating half the viewport for nav), while still keeping the sidebar always-visible at desktop widths where it costs nothing. ## Theme tokens Applied via `gr.themes.Base().set(...)` overrides on the Blocks theme: | Token | Value | Used for | |---|---|---| | `body_background_fill` | `#12161B` | App background | | `background_fill_primary` | `#12161B` | Form/page background | | `background_fill_secondary` | `#1A1F26` | Card / panel surface | | `block_background_fill` | `#1A1F26` | Component (input, slider) surface | | `body_text_color` | `#E6E8EB` | Primary text | | `body_text_color_subdued` | `#7C8693` | Secondary / hint text | | `border_color_primary` | `#262C35` | Card / input border | | `border_color_accent` | `#E0A458` | Focused input ring | | `button_primary_background_fill` | `#E0A458` | Generate button | | `button_primary_text_color` | `#12161B` | Generate button label | | `error_background_fill` | `#3A1E20` | Error banner background | | `error_text_color` | `#F4A6A8` | Error banner text | Fonts: `IBM Plex Sans` (UI 14 px) + `IBM Plex Mono` (mono 13 px), loaded from Google Fonts in the page `
` (Gradio's `head` parameter on `Blocks`, or via `_CUSTOM_CSS` `@import`). ## Layout: hamburger drawer ### Markup structure (logical, Gradio components) ``` gr.Row() # header ├── HamburgerButton (gr.Button, ≡ icon) # toggles drawer ├── gr.Markdown("LTX 2.3 Studio") # title └── ActiveModeTag (gr.Markdown, amber pill) # shows current mode gr.Row(elem_classes="layer") ├── gr.Column(elem_classes="drawer", visible=...) # 220 px wide │ └── 6 mode buttons (existing) └── gr.Column(elem_classes="body-pane") └── gr.Tabs(elem_classes="hidden-tabs") # current 6 mode tabs ``` ### Open / closed behavior - **Desktop (≥1024 px):** drawer open by default, occupies the left 220 px of the viewport. Hamburger still works as a toggle but most users leave it open. - **Tablet (700–1023 px):** drawer closed by default; opening it slides over content with a translucent overlay (`background: rgba(0,0,0,0.5)`). Tapping outside closes. - **Phone (<700 px):** same as tablet, but drawer takes 80 % of viewport width when open. State persists in `localStorage` (`ltx-drawer-open` key) so a user who closes the drawer on desktop stays closed across reloads. ### Active mode header tag A small amber-bordered pill in the header (e.g., `T2V`, `A2V`, `LIPSYNC`) showing the currently selected mode. Updates whenever a mode button is clicked. Uses `IBM Plex Mono` 11 px so it reads as a label, not a button. ### CSS approach Pure CSS, no JS framework. Use `:has()` and `` hidden control for drawer toggle, OR a tiny inline `