diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index 29900fb..1f0dffd 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -6,6 +6,7 @@ import { TopBar } from './components/layout/TopBar'
import { ScanProgress } from './components/ScanProgress'
import { ToastContainer } from './components/ToastContainer'
import { KeyboardHints } from './components/KeyboardHints'
+import { AppFooter } from './components/AppFooter'
import { PreviewView } from './components/preview/PreviewView'
import { FilterBar } from './components/filter/FilterBar'
import { DiscardActionBar } from './components/discard/DiscardActionBar'
@@ -66,13 +67,19 @@ function App() {
{/* Main column — filter bar, discard bar, timeline. Lives to the
* right of the left sidebar so the filter row doesn't bleed
- * across the sidebar. */}
-
+ * across the sidebar. relative so the KeyboardHints overlay
+ * centers against this column, not the viewport. */}
+
+ {/* Floating keyboard hints — bottom-center of the main column,
+ * glassy. Mounted here so it's centered against the timeline,
+ * not the viewport (which would be offset by the sidebars). */}
+
+
{/* Right Sidebar */}
@@ -85,10 +92,6 @@ function App() {
- {/* Floating keyboard hints — pinned bottom-center, glassy. Sits
- * above the timeline and below the toast layer. */}
-
-
{/* Scan Progress Indicator */}
diff --git a/frontend/src/components/AppFooter.tsx b/frontend/src/components/AppFooter.tsx
new file mode 100644
index 0000000..a13204a
--- /dev/null
+++ b/frontend/src/components/AppFooter.tsx
@@ -0,0 +1,43 @@
+/**
+ * Tiny corner footer pinned to the bottom-right of the main column.
+ * Renders "Built with hubris • ", refreshed
+ * once per page load.
+ */
+
+const ROMAN_PAIRS: [number, string][] = [
+ [1000, 'M'],
+ [900, 'CM'],
+ [500, 'D'],
+ [400, 'CD'],
+ [100, 'C'],
+ [90, 'XC'],
+ [50, 'L'],
+ [40, 'XL'],
+ [10, 'X'],
+ [9, 'IX'],
+ [5, 'V'],
+ [4, 'IV'],
+ [1, 'I'],
+]
+
+function toRoman(n: number): string {
+ let result = ''
+ for (const [value, symbol] of ROMAN_PAIRS) {
+ while (n >= value) {
+ result += symbol
+ n -= value
+ }
+ }
+ return result
+}
+
+export function AppFooter() {
+ const year = new Date().getFullYear()
+ return (
+
+
+ Built with hubris • {toRoman(year)}
+
+
+ )
+}
diff --git a/frontend/src/components/KeyboardHints.tsx b/frontend/src/components/KeyboardHints.tsx
index e011ca0..084b72c 100644
--- a/frontend/src/components/KeyboardHints.tsx
+++ b/frontend/src/components/KeyboardHints.tsx
@@ -25,7 +25,11 @@ export function KeyboardHints() {
]
return (
-
+ // Absolute (not fixed) so the parent's flex/position context can
+ // center it relative to the timeline area, not the viewport. Mount
+ // inside the main column in App.tsx so it isn't offset by the
+ // sidebar widths.
+
{hints.map((hint, i) => (