Login
+Sign in to Document Processor.
+ + {% if error %} +diff --git a/app/static/app.css b/app/static/app.css index 3683068..95b2f06 100644 --- a/app/static/app.css +++ b/app/static/app.css @@ -68,8 +68,8 @@ a:hover { .main { margin-left: var(--rail-closed); + padding: calc(var(--topbar-height) + 1.25rem) 1.25rem 1.25rem 1.25rem; min-height: 100vh; - padding: 1.25rem; transition: margin-left 0.18s ease; } @@ -173,13 +173,6 @@ a:hover { justify-content: center; } -.topbar { - display: flex; - justify-content: space-between; - align-items: flex-start; - gap: 1rem; - margin-bottom: 1rem; -} .page-title { margin: 0; @@ -575,3 +568,1098 @@ pre.codeblock { color: var(--text-muted); font-size: 0.9rem; } + +/* GLOBAL TOP BAR */ +.global-topbar { + width: 100%; + min-height: 56px; + display: flex; + align-items: center; + justify-content: space-between; + background: #06153d; + color: #f8fafc; + border-radius: 12px; + padding: 0.75rem 1rem; + margin: 0 0 1rem 0; + box-sizing: border-box; +} + +.global-topbar-left { + flex: 1 1 auto; +} + +.global-topbar-right { + margin-left: auto; + display: flex; + align-items: center; + justify-content: flex-end; + gap: 0.65rem; + flex-wrap: nowrap; +} + +.global-topbar-user { + display: flex; + flex-direction: column; + align-items: flex-end; + line-height: 1.1; +} + +.global-topbar-name { + font-weight: 700; + font-size: 0.95rem; + color: #f8fafc; +} + +.global-topbar-username { + font-size: 0.8rem; + color: #cbd5e1; +} + +.global-topbar-logout { + height: 34px; + padding: 0 0.75rem; + border-radius: 10px; + white-space: nowrap; +} + +@media (max-width: 700px) { + .global-topbar { + min-height: 48px; + padding: 0.6rem 0.75rem; + } + + .global-topbar-right { + gap: 0.5rem; + } + + .global-topbar-name { + font-size: 0.88rem; + } + + .global-topbar-username { + font-size: 0.75rem; + } + + .global-topbar-logout { + height: 32px; + padding: 0 0.6rem; + } +} + + +/* CONNECT SIDEBAR + HEADER */ +.app-shell { + display: grid; + grid-template-columns: 240px 1fr; +} + +.sidebar { + border-top-left-radius: 12px; +} + +.global-topbar { + border-top-right-radius: 12px; + border-top-left-radius: 0; + margin: 0; +} + +/* inline brand */ +.brand-inline { + font-weight: 700; + font-size: 1rem; +} + + +/* MAKE HEADER PART OF FRAME */ +.main { + display: flex; + flex-direction: column; +} + +.global-topbar { + margin: 0; + border-radius: 0 12px 0 0; +} + +/* remove extra top spacing from pages */ +.main > *:first-child:not(.global-topbar) { + margin-top: 1rem; +} + +/* APP FRAME */ +.app-shell { + display: grid; + grid-template-columns: 190px 1fr; + min-height: 100vh; +} + +.sidebar { + background: #06153d; + color: #f8fafc; + border-radius: 0 !important; + margin: 0 !important; + min-height: 100vh; +} + +.main { + padding: 0 !important; + margin: 0 !important; + display: flex; + flex-direction: column; +} + +.main-content { + padding: 1rem; +} + +.global-topbar { + height: 52px; + display: flex; + align-items: center; + justify-content: space-between; + background: #06153d; + color: #f8fafc; + border-radius: 0 !important; + margin: 0 !important; + padding: 0 1rem; + box-sizing: border-box; + border-left: 1px solid rgba(255,255,255,0.08); +} + +.global-topbar-left, +.global-topbar-right { + display: flex; + align-items: center; + gap: 0.6rem; +} + +.global-topbar-right { + margin-left: auto; +} + +.global-topbar-user { + text-align: right; + line-height: 1.1; +} + +.global-topbar-name { + font-weight: 700; + font-size: 0.9rem; + color: #f8fafc; +} + +.global-topbar-username { + font-size: 0.75rem; + color: #cbd5e1; +} + +.global-topbar-logout { + height: 30px; + padding: 0 0.6rem; + border-radius: 8px; +} + +.sidebar-top { + min-height: 52px; + display: flex; + align-items: center; + padding: 0 0.75rem; + box-sizing: border-box; + border-bottom: 1px solid rgba(255,255,255,0.08); +} + +.brand { + font-weight: 700; + font-size: 0.95rem; +} + + +.page-header { + margin-bottom: 1rem; +} + +.page-title { + margin: 0; + font-size: 1.7rem; +} + +.page-subtitle { + margin: 0.25rem 0 0 0; + color: var(--text-muted); + font-size: 0.95rem; +} + +:root { + --topbar-height: 72px; +} + +.global-topbar { + position: fixed; + top: 0; + right: 0; + left: var(--rail-closed); + height: var(--topbar-height); + display: flex; + align-items: center; + justify-content: space-between; + gap: 1rem; + padding: 0 1.25rem; + background: var(--panel); + border-bottom: 1px solid var(--border); + z-index: 90; + transition: left 0.18s ease; +} + +.app-shell.nav-open .global-topbar { + left: var(--rail-open); +} + +.global-topbar-left { + display: flex; + align-items: center; + min-width: 0; +} + +.global-app-title { + font-size: 1.05rem; + font-weight: 700; + color: var(--text); + white-space: nowrap; +} + +.global-topbar-right { + display: flex; + align-items: center; + justify-content: flex-end; + gap: 0.75rem; + flex-wrap: wrap; +} + +.global-topbar-user { + display: flex; + flex-direction: column; + align-items: flex-end; + line-height: 1.2; +} + +.global-topbar-name { + font-weight: 600; + color: var(--text); +} + +.global-topbar-username { + font-size: 0.88rem; + color: var(--text-muted); +} + +.global-topbar-logout { + appearance: none; + border: 1px solid var(--border); + background: var(--panel); + color: var(--text); + border-radius: 10px; + padding: 0.55rem 0.9rem; + cursor: pointer; + font: inherit; +} + +.global-topbar-logout:hover { + background: #f3f4f6; +} + +.main { + margin-left: var(--rail-closed); + min-height: 100vh; + padding: calc(var(--topbar-height) + 1.25rem) 1.25rem 1.25rem 1.25rem; + transition: margin-left 0.18s ease; +} + +.app-shell.nav-open .main { + margin-left: var(--rail-open); +} + +.main-content { + padding-top: 0; +} + +.page-header { + margin-bottom: 1rem; +} + +/* ==== final shell override ==== */ +:root { + --topbar-height: 72px; +} + +.sidebar { + position: fixed !important; + inset: 0 auto 0 0 !important; + width: var(--rail-closed) !important; + z-index: 100 !important; +} + +.app-shell.nav-open .sidebar { + width: var(--rail-open) !important; +} + +.global-topbar { + position: fixed !important; + top: 0 !important; + right: 0 !important; + left: var(--rail-closed) !important; + height: var(--topbar-height) !important; + display: flex !important; + align-items: center !important; + justify-content: space-between !important; + gap: 1rem !important; + padding: 0 1.25rem !important; + background: var(--panel) !important; + border-bottom: 1px solid var(--border) !important; + z-index: 90 !important; + transition: left 0.18s ease !important; +} + +.app-shell.nav-open .global-topbar { + left: var(--rail-open) !important; +} + +.main { + margin-left: var(--rail-closed) !important; + min-height: 100vh !important; + padding: calc(var(--topbar-height) + 1.25rem) 1.25rem 1.25rem 1.25rem !important; + transition: margin-left 0.18s ease !important; +} + +.app-shell.nav-open .main { + margin-left: var(--rail-open) !important; +} + +.main-content { + padding-top: 0 !important; +} + +.page-header { + display: block !important; + margin-bottom: 1rem !important; +} + +.global-topbar-left { + display: flex !important; + align-items: center !important; + min-width: 0 !important; +} + +.global-app-title { + font-size: 1.05rem !important; + font-weight: 700 !important; + color: var(--text) !important; + white-space: nowrap !important; +} + +.global-topbar-right { + display: flex !important; + align-items: center !important; + justify-content: flex-end !important; + gap: 0.75rem !important; + flex-wrap: wrap !important; +} + +.global-topbar-user { + display: flex !important; + flex-direction: column !important; + align-items: flex-end !important; + line-height: 1.2 !important; +} + +.global-topbar-name { + font-weight: 600 !important; +} + +.global-topbar-username { + font-size: 0.88rem !important; + color: var(--text-muted) !important; +} + +.global-topbar-logout { + border: 1px solid var(--border) !important; + background: var(--panel) !important; + color: var(--text) !important; + border-radius: 10px !important; + padding: 0.55rem 0.9rem !important; +} + +.global-topbar-logout:hover { + background: #f3f4f6 !important; +} +/* ==== end final shell override ==== */ + +/* ===== shell final enforced layout ===== */ +body { + background: var(--bg); +} + +.app-shell { + min-height: 100vh; +} + +.sidebar { + position: fixed !important; + top: 0 !important; + left: 0 !important; + bottom: 0 !important; + width: var(--rail-closed) !important; + z-index: 1000 !important; +} + +.app-shell.nav-open .sidebar { + width: var(--rail-open) !important; +} + +.global-topbar { + position: fixed !important; + top: 0 !important; + left: var(--rail-closed) !important; + right: 0 !important; + height: 72px !important; + display: flex !important; + align-items: center !important; + justify-content: space-between !important; + padding: 0 1.25rem !important; + background: var(--panel) !important; + border-bottom: 1px solid var(--border) !important; + z-index: 900 !important; +} + +.app-shell.nav-open .global-topbar { + left: var(--rail-open) !important; +} + +.main { + margin-left: var(--rail-closed) !important; + min-height: 100vh !important; + padding: 96px 1.25rem 1.25rem 1.25rem !important; + background: var(--bg) !important; +} + +.app-shell.nav-open .main { + margin-left: var(--rail-open) !important; +} + +.main-content { + padding-top: 0 !important; +} + +.page-header { + margin-bottom: 1rem !important; +} + +.page-title { + margin: 0 !important; + font-size: 1.7rem !important; +} + +.page-subtitle { + margin: 0.25rem 0 0 0 !important; + color: var(--text-muted) !important; + font-size: 0.95rem !important; +} +/* ===== end shell final enforced layout ===== */ + +/* ===== clean final shell layout ===== */ +:root { + --topbar-height: 72px; +} + +body { + background: var(--bg); +} + +.app-shell { + min-height: 100vh; +} + +/* left rail */ +.sidebar { + position: fixed !important; + top: 0 !important; + left: 0 !important; + bottom: 0 !important; + width: var(--rail-closed) !important; + background: #08142f !important; + color: #e5e7eb !important; + z-index: 1000 !important; + overflow-x: hidden !important; + overflow-y: auto !important; + padding: 0.75rem 0.45rem 1rem 0.45rem !important; +} + +.app-shell.nav-open .sidebar { + width: var(--rail-open) !important; +} + +/* top bar */ +.global-topbar { + position: fixed !important; + top: 0 !important; + left: var(--rail-closed) !important; + right: 0 !important; + min-height: var(--topbar-height) !important; + display: flex !important; + align-items: center !important; + justify-content: space-between !important; + gap: 1rem !important; + padding: 0.75rem 1rem !important; + background: #ffffff !important; + border-bottom: 1px solid var(--border) !important; + box-shadow: 0 1px 3px rgba(0,0,0,0.06) !important; + z-index: 900 !important; +} + +.app-shell.nav-open .global-topbar { + left: var(--rail-open) !important; +} + +/* content region */ +.main { + margin-left: var(--rail-closed) !important; + min-height: 100vh !important; + padding: calc(var(--topbar-height) + 1.25rem) 1rem 1rem 1rem !important; + background: var(--bg) !important; +} + +.app-shell.nav-open .main { + margin-left: var(--rail-open) !important; +} + +.main-content { + padding-top: 0 !important; +} + +/* top bar content */ +.global-topbar-left { + display: flex !important; + align-items: center !important; + min-width: 0 !important; +} + +.global-app-title { + font-size: 1rem !important; + font-weight: 700 !important; + color: var(--text) !important; + white-space: nowrap !important; + overflow: hidden !important; + text-overflow: ellipsis !important; +} + +.global-topbar-right { + display: flex !important; + align-items: center !important; + justify-content: flex-end !important; + gap: 0.6rem !important; + flex-wrap: nowrap !important; + min-width: 0 !important; +} + +.global-topbar-user { + display: flex !important; + flex-direction: column !important; + align-items: flex-end !important; + line-height: 1.15 !important; +} + +.global-topbar-name { + font-weight: 600 !important; + color: var(--text) !important; + font-size: 0.95rem !important; +} + +.global-topbar-username { + color: var(--text-muted) !important; + font-size: 0.8rem !important; +} + +.global-topbar-logout { + appearance: none !important; + border: 1px solid var(--border) !important; + background: var(--panel) !important; + color: var(--text) !important; + border-radius: 10px !important; + padding: 0.5rem 0.85rem !important; + cursor: pointer !important; + font: inherit !important; +} + +.global-topbar-logout:hover { + background: #f3f4f6 !important; +} + +/* page header under global top bar */ +.page-header { + margin-bottom: 1rem !important; +} + +.page-title { + margin: 0 !important; + font-size: 1.7rem !important; + line-height: 1.1 !important; +} + +.page-subtitle { + margin: 0.3rem 0 0 0 !important; + color: var(--text-muted) !important; + font-size: 0.95rem !important; + line-height: 1.35 !important; +} + +/* sidebar label behavior */ +.brand, +.sidebar-section-title, +.nav-link-text { + display: none !important; +} + +.app-shell.nav-open .brand, +.app-shell.nav-open .sidebar-section-title, +.app-shell.nav-open .nav-link-text { + display: initial !important; +} + +.app-shell:not(.nav-open) .nav-link { + justify-content: center !important; +} + +/* mobile */ +@media (max-width: 700px) { + .global-topbar { + padding: 0.65rem 0.75rem !important; + } + + .global-app-title { + font-size: 0.92rem !important; + max-width: 120px !important; + } + + .global-topbar-user { + display: none !important; + } + + .badge.reviewed { + display: none !important; + } + + .global-topbar-logout { + padding: 0.42rem 0.7rem !important; + font-size: 0.88rem !important; + } + + .main { + padding: calc(var(--topbar-height) + 1rem) 0.75rem 0.75rem 0.75rem !important; + } + + .page-title { + font-size: 1.25rem !important; + } + + .page-subtitle { + font-size: 0.88rem !important; + } +} +/* ===== end clean final shell layout ===== */ + + +/* ===== width + blue topbar fix ===== */ +.global-topbar { + background: #0b3b91 !important; + color: #ffffff !important; + border-bottom: 1px solid rgba(255,255,255,0.12) !important; +} + +.global-app-title, +.global-topbar-name, +.global-topbar-username { + color: #ffffff !important; +} + +.global-topbar-logout { + background: rgba(255,255,255,0.12) !important; + color: #ffffff !important; + border: 1px solid rgba(255,255,255,0.18) !important; +} + +.global-topbar-logout:hover { + background: rgba(255,255,255,0.18) !important; +} + +/* force the main region to use full width */ +.main, +.main-content, +.page-header, +.card, +.table-wrap, +.right-pane-tabs, +.tab-panel, +form, +.form-grid, +.form-field, +input, +textarea, +select { + max-width: none !important; +} + +.main { + width: auto !important; +} + +.main-content { + width: 100% !important; +} + +.card, +.tab-panel, +.table-wrap, +form { + width: 100% !important; +} + +.tab-panel { + display: block !important; +} + +/* prevent tiny wrapped buttons/labels */ +.button-row { + display: flex !important; + flex-wrap: wrap !important; + gap: 0.65rem !important; +} + +.button-link, +button, +.tab-button { + white-space: nowrap !important; +} + +/* forms should fill horizontally */ +.form-grid { + display: grid !important; + grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)) !important; + gap: 1rem !important; + width: 100% !important; +} + +.form-field.full { + grid-column: 1 / -1 !important; +} + +input, +textarea, +select { + width: 100% !important; +} + +/* tables should occupy full width */ +table { + width: 100% !important; +} + +/* document page tabs/buttons */ +.right-pane-tabs { + display: flex !important; + flex-wrap: wrap !important; + gap: 0.65rem !important; + margin-bottom: 1rem !important; +} +/* ===== end width + blue topbar fix ===== */ + +/* ===== top bar color sync ===== */ +.global-topbar { + background: #08142f !important; + color: #ffffff !important; + border-bottom: 1px solid rgba(255,255,255,0.10) !important; +} + +.global-topbar-name, +.global-topbar-username { + color: #ffffff !important; +} + +.global-topbar-logout { + background: rgba(255,255,255,0.10) !important; + color: #ffffff !important; + border: 1px solid rgba(255,255,255,0.16) !important; +} + +.global-topbar-logout:hover { + background: rgba(255,255,255,0.16) !important; +} + +.global-topbar-left { + flex: 1 1 auto !important; +} + +.global-topbar-right { + flex: 0 0 auto !important; +} +/* ===== end top bar color sync ===== */ + +/* ===== documents/page width fix ===== */ + +/* top bar: same color as side pane, no title text needed there */ +.global-topbar { + background: #08142f !important; + color: #fff !important; + border-bottom: 1px solid rgba(255,255,255,0.08) !important; +} + +.global-topbar-left { + display: none !important; +} + +.global-topbar-name, +.global-topbar-username { + color: #fff !important; +} + +.global-topbar-logout { + background: rgba(255,255,255,0.10) !important; + color: #fff !important; + border: 1px solid rgba(255,255,255,0.14) !important; +} + +/* restore sidebar branding */ +.sidebar .brand { + display: block !important; +} + +/* main region must consume available width */ +.main { + margin-left: var(--rail-closed) !important; + width: calc(100vw - var(--rail-closed)) !important; + max-width: none !important; + min-width: 0 !important; + box-sizing: border-box !important; +} + +.app-shell.nav-open .main { + margin-left: var(--rail-open) !important; + width: calc(100vw - var(--rail-open)) !important; +} + +.main-content { + display: block !important; + width: 100% !important; + max-width: none !important; + min-width: 0 !important; +} + +/* all normal content containers should stretch */ +.page-header, +.card, +.table-wrap, +form, +.form-grid, +.form-field, +.button-row, +.right-pane-tabs, +.tab-panel { + width: 100% !important; + max-width: none !important; + min-width: 0 !important; + box-sizing: border-box !important; +} + +/* cards should stack normally */ +.card { + display: block !important; +} + +/* tab strip */ +.right-pane-tabs { + display: flex !important; + flex-wrap: wrap !important; + gap: 0.65rem !important; + margin-bottom: 1rem !important; +} + +/* IMPORTANT: only active tab panel should show */ +.tab-panel { + display: none !important; +} + +.tab-panel.active { + display: block !important; +} + +/* forms */ +.form-grid { + display: grid !important; + grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)) !important; + gap: 1rem !important; +} + +.form-field.full { + grid-column: 1 / -1 !important; +} + +input, +textarea, +select { + display: block !important; + width: 100% !important; + max-width: none !important; + min-width: 0 !important; + box-sizing: border-box !important; +} + +/* buttons should not collapse into vertical word wrapping */ +.button-link, +button, +.tab-button { + white-space: nowrap !important; +} + +/* text should wrap normally, not per-character */ +.page-title, +.page-subtitle, +.card-title, +label, +p, +td, +th, +a, +span, +div { + word-break: normal !important; + overflow-wrap: break-word !important; +} + +/* tables */ +table { + width: 100% !important; +} + +/* mobile */ +@media (max-width: 700px) { + .main { + width: calc(100vw - var(--rail-closed)) !important; + padding: 96px 0.75rem 0.75rem 0.75rem !important; + } + + .app-shell.nav-open .main { + width: calc(100vw - var(--rail-open)) !important; + } +} + +/* ===== end documents/page width fix ===== */ + +/* ===== topbar locked-right behavior ===== */ +.global-topbar { + left: 0 !important; + right: 0 !important; + padding-left: 56px !important; /* leave room for collapsed rail + toggle */ + justify-content: flex-end !important; +} + +.app-shell.nav-open .global-topbar { + left: 0 !important; + right: 0 !important; +} + +.global-topbar-left { + display: none !important; +} + +.global-topbar-right { + margin-left: auto !important; + padding-right: 0.25rem !important; + justify-content: flex-end !important; + max-width: calc(100vw - 70px) !important; + overflow: hidden !important; +} + +.global-topbar-user { + min-width: 0 !important; +} + +.global-topbar-name, +.global-topbar-username { + white-space: nowrap !important; + overflow: hidden !important; + text-overflow: ellipsis !important; +} + +/* sidebar should sit above the top bar when opened */ +.sidebar { + z-index: 1000 !important; +} + +.global-topbar { + z-index: 900 !important; +} + +/* keep main sizing tied to rail, not top bar */ +.main { + width: calc(100vw - var(--rail-closed)) !important; +} + +.app-shell.nav-open .main { + width: calc(100vw - var(--rail-open)) !important; +} + +/* mobile trim */ +@media (max-width: 700px) { + .global-topbar { + padding-left: 52px !important; + padding-right: 0.4rem !important; + } + + .global-topbar-right { + max-width: calc(100vw - 60px) !important; + gap: 0.4rem !important; + } + + .global-topbar-name { + font-size: 0.9rem !important; + } + + .global-topbar-username { + font-size: 0.75rem !important; + } +} +/* ===== end topbar locked-right behavior ===== */ + +/* ===== topbar username visibility fix ===== */ +.global-topbar { + left: 0 !important; + right: 0 !important; + padding-left: 0.5rem !important; + padding-right: 0.75rem !important; + justify-content: flex-end !important; +} + +.global-topbar-right { + margin-left: auto !important; + max-width: calc(100vw - 3.5rem) !important; + overflow: visible !important; +} + +.global-topbar-user { + display: flex !important; + flex-direction: column !important; + align-items: flex-end !important; + white-space: nowrap !important; +} + +.global-topbar-name, +.global-topbar-username { + white-space: nowrap !important; + overflow: visible !important; + text-overflow: clip !important; +} + +@media (max-width: 700px) { + .global-topbar-username { + display: none !important; + } +} +/* ===== end topbar username visibility fix ===== */ diff --git a/app/templates/auth/login.html b/app/templates/auth/login.html new file mode 100644 index 0000000..581fe33 --- /dev/null +++ b/app/templates/auth/login.html @@ -0,0 +1,38 @@ + + +
+ +Sign in to Document Processor.
+ + {% if error %} +