From ea27873dce72f51fb95a03a4397cd535c6a4678b Mon Sep 17 00:00:00 2001 From: Codex Date: Sun, 19 Jul 2026 12:59:25 +0200 Subject: [PATCH] Polish map-first workbench visuals --- CHANGELOG.md | 4 + frontend/README.md | 6 + frontend/src/App.tsx | 1 + frontend/src/styles/visual-polish.css | 515 ++++++++++++++++++++++++++ 4 files changed, 526 insertions(+) create mode 100644 frontend/src/styles/visual-polish.css diff --git a/CHANGELOG.md b/CHANGELOG.md index 95191fff..b4c7804f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ - Promoted the nationally federated, map-first GeoIntel workbench from the release candidate to the final `1.0.0` version. +- Added a restrained final visual polish pass for the map-first workbench: + clearer step hierarchy, an in-row results rail on wide screens, improved + widescreen use and explicit mobile header/navigation behavior. No workflow, + API, database or GIS behavior changed. - Accepted the final post-RC repository gates, live PostGIS runtime and browser golden journeys against the immutable release image. - Accepted live SPW waterbed elevation analysis in EPSG:3812/mDNG for the diff --git a/frontend/README.md b/frontend/README.md index fdb752f2..a112f538 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -113,6 +113,12 @@ The workbench uses a task-based shell instead of a single long panel stack. `App The premium V1 presentation layer lives in `src/styles/premium.css`. It groups navigation by Workspace, Analyze and Deliver, removes the permanent inspector column, gives desktop/ultrawide workspaces stable readable widths and switches narrow screens to full-width content with a horizontally scrollable navigation rail. API calls and workflow state remain owned by the existing hooks. +The final visual polish layer lives in `src/styles/visual-polish.css`. It keeps +the map dominant, places the results rail beside the map when the viewport is +wide enough, preserves a readable two-column map flow on smaller desktops and +stacks the context header and navigation explicitly on mobile. It contains no +workflow or API logic. + ## Current component boundaries `App.tsx` remains the shared workspace orchestrator, while focused surfaces diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 27afc7fd..6ba8d633 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,6 +1,7 @@ import { useEffect, useMemo, useRef, useState } from 'react' import './styles/app.css' import './styles/premium.css' +import './styles/visual-polish.css' import { ChangeDetectionPanel } from './components/analysis/ChangeDetectionPanel' import { GeoAssistantPanel } from './components/assistant/GeoAssistantPanel' import { DatasetPanel } from './components/datasets/DatasetPanel' diff --git a/frontend/src/styles/visual-polish.css b/frontend/src/styles/visual-polish.css new file mode 100644 index 00000000..dc3c4b4b --- /dev/null +++ b/frontend/src/styles/visual-polish.css @@ -0,0 +1,515 @@ +/* GeoIntel visual polish: a restrained map-first presentation layer. */ + +:root { + --visual-canvas: #eef2f1; + --visual-surface: #ffffff; + --visual-surface-soft: #f7f9f8; + --visual-ink: #172a2d; + --visual-muted: #657477; + --visual-line: #d7e1df; + --visual-line-strong: #b8c8c4; + --visual-teal: #087d73; + --visual-teal-deep: #056057; + --visual-teal-soft: #e7f4f1; + --visual-amber: #a76616; + --visual-amber-soft: #fff7e9; +} + +.workbench-shell { + background: var(--visual-canvas); + color: var(--visual-ink); +} + +.app-shell > header.workbench-topbar { + min-height: 4.35rem; + grid-template-columns: minmax(14rem, 17rem) minmax(0, 1fr); + gap: 1.15rem; + padding-inline: clamp(1rem, 1.5vw, 1.75rem); + background: rgba(255, 255, 255, 0.985); +} + +.brand-block { + gap: 0.8rem; +} + +.brand-mark { + width: 2.35rem; + height: 2.35rem; + flex-basis: 2.35rem; + border: 1px solid #20464a; + border-radius: 8px; + background: #153b40; + box-shadow: 0 2px 5px rgba(21, 59, 64, 0.14); +} + +.brand-block h1 { + color: var(--visual-ink); + font-size: 1.08rem; + letter-spacing: 0; +} + +.app-shell > header.workbench-topbar .brand-block p { + color: #718083; + font-size: 0.71rem; +} + +.context-bar { + border-color: var(--visual-line); + border-radius: 8px; + background: var(--visual-surface-soft); +} + +.context-bar > div { + min-height: 2.8rem; + padding-inline: 0.8rem; +} + +.context-bar span { + color: #708082; + font-size: 0.6rem; + letter-spacing: 0.03em; +} + +.context-bar strong { + color: var(--visual-ink); + font-size: 0.79rem; +} + +.workbench-layout { + grid-template-columns: 13.25rem minmax(0, 1fr); + height: calc(100dvh - 4.35rem); +} + +.workbench-sidebar { + padding: 1rem 0.8rem; + border-right-color: var(--visual-line); + background: #f6f8f7; +} + +.workbench-sidebar nav { + gap: 1.15rem; +} + +.nav-group { + gap: 0.28rem; +} + +.nav-section-label { + padding-inline: 0.62rem; + color: #7c898a; + font-size: 0.6rem; + letter-spacing: 0.07em; +} + +.workbench-sidebar .nav-item { + min-height: 2.55rem; + border-radius: 7px; + padding: 0.48rem 0.7rem; + color: #3e5153; +} + +.workbench-sidebar .nav-item span { + font-size: 0.82rem; + font-weight: 750; +} + +.workbench-sidebar .nav-item-active { + border-color: #b8d9d2; + background: var(--visual-teal-soft); + color: var(--visual-teal-deep); + box-shadow: inset 3px 0 0 var(--visual-teal); +} + +.workbench-main { + padding: 1.25rem clamp(1rem, 1.8vw, 2rem) 2rem; +} + +.workbench-main > * { + width: min(100%, 118rem); +} + +.workspace-heading { + margin-bottom: 1rem; + padding-bottom: 0.82rem; + border-bottom-color: var(--visual-line); +} + +.workspace-heading h2 { + color: var(--visual-ink); + font-size: 1.48rem; +} + +.workspace-heading-actions > p { + color: var(--visual-muted); +} + +/* Normal desktop keeps the three map steps in one purposeful working row. */ +@media (min-width: 1181px) { + .geo-explorer-layout { + grid-template-columns: minmax(15rem, 16.5rem) minmax(0, 1fr) minmax(17rem, 19rem); + gap: 0.85rem; + height: clamp(36rem, calc(100dvh - 9.8rem), 68rem); + min-height: 36rem; + } + + .geo-theme-panel, + .geo-results-panel, + .geo-map-stage { + border-color: var(--visual-line); + border-radius: 8px; + box-shadow: 0 1px 2px rgba(23, 42, 45, 0.035); + } + + .geo-results-panel { + grid-column: auto; + display: flex; + overflow-y: auto; + } + + .geo-map-toolbar { + align-items: flex-start; + } + + .geo-map-actions { + flex-wrap: wrap; + justify-content: flex-end; + } +} + +@media (min-width: 1800px) { + .workbench-layout { + grid-template-columns: 14rem minmax(0, 1fr); + } + + .workbench-main { + padding-inline: clamp(1.5rem, 2.2vw, 3rem); + } + + .geo-explorer-layout { + grid-template-columns: minmax(17rem, 19rem) minmax(42rem, 1fr) minmax(21rem, 24rem); + } +} + +.geo-explorer { + gap: 0.9rem; +} + +.geo-explorer-header { + gap: 1.25rem; + border-bottom-color: var(--visual-line); + padding-bottom: 0.95rem; +} + +.geo-explorer-header h2 { + color: var(--visual-ink); + font-size: clamp(1.45rem, 1.8vw, 1.9rem); + font-weight: 760; +} + +.geo-explorer-header p:last-child { + color: var(--visual-muted); + font-size: 0.86rem; +} + +.geo-analysis-mode { + border-color: var(--visual-line-strong); + background: #f3f7f6; +} + +.geo-analysis-mode button { + color: #687879; +} + +.geo-analysis-mode button.active { + color: var(--visual-teal-deep); + box-shadow: 0 1px 4px rgba(23, 42, 45, 0.11); +} + +.geo-panel-heading > span { + background: var(--visual-ink); +} + +.geo-panel-heading h3, +.geo-results-title-row h4 { + color: var(--visual-ink); +} + +.geo-panel-heading p, +.geo-results-empty p { + color: var(--visual-muted); +} + +.geo-theme-panel, +.geo-results-panel, +.geo-map-stage { + background: var(--visual-surface); +} + +.geo-theme-panel, +.geo-results-panel { + padding: 0.85rem; +} + +.geo-theme-list { + gap: 0.42rem; + scrollbar-gutter: stable; +} + +.geo-theme-option { + min-height: 3.35rem; + border-color: #dce6e3; + border-radius: 7px; + padding: 0.52rem 0.56rem; +} + +.geo-theme-option:not(:disabled):hover { + border-color: #98c5ba; + background: #f5faf8; +} + +.geo-theme-option-active { + border-color: #6da99b; + background: var(--visual-teal-soft); + box-shadow: inset 3px 0 0 var(--visual-teal); +} + +.geo-theme-option strong { + color: #233639; + font-size: 0.8rem; +} + +.geo-theme-option small { + color: #6e7d7f; + font-size: 0.66rem; +} + +.geo-theme-option i { + color: var(--visual-teal-deep); + font-size: 0.57rem; + letter-spacing: 0.02em; +} + +.geo-loaded-scope { + border-color: #d6e5e1; + border-radius: 7px; + background: #f6faf9; +} + +.geo-source-summary { + border-top-color: var(--visual-line); +} + +.geo-source-summary strong { + color: #223639; +} + +.geo-map-stage { + border-color: var(--visual-line-strong); + box-shadow: 0 3px 14px rgba(23, 42, 45, 0.08); +} + +.geo-map-toolbar { + border-bottom-color: var(--visual-line); + background: #fbfcfc; +} + +.geo-map-actions .primary-action, +.geo-result-next-actions .primary-action { + border-color: var(--visual-teal); + background: var(--visual-teal); +} + +.geo-map-actions .primary-action:hover:not(:disabled), +.geo-result-next-actions .primary-action:hover:not(:disabled) { + border-color: var(--visual-teal-deep); + background: var(--visual-teal-deep); +} + +.geo-map-canvas { + background: #dce9e6; +} + +.geo-map-legend { + border-color: rgba(23, 42, 45, 0.18); + border-radius: 6px; + background: rgba(255, 255, 255, 0.96); + box-shadow: 0 3px 12px rgba(23, 42, 45, 0.12); +} + +.geo-results-panel { + scrollbar-gutter: stable; +} + +.geo-results-empty, +.geo-results-loading { + border-color: #cbdad6; + background: #fafcfb; +} + +.geo-primary-metrics > div { + border-color: #dbe6e3; + border-radius: 6px; + background: #f7faf9; +} + +.geo-primary-metrics > div:first-child { + border-top: 2px solid var(--visual-teal); +} + +.geo-primary-metrics strong { + color: #183c3b; +} + +.geo-theme-result-row { + border-color: #e0e9e7; + background: #fbfcfc; +} + +.geo-theme-result-row:hover { + border-color: #b9d4cc; + background: #f4faf8; +} + +.geo-result-next-actions { + border-color: #c4ddd7; + border-radius: 7px; + background: #f2faf7; +} + +.geo-result-next-actions strong { + color: #174a42; +} + +.geo-result-next-actions small { + color: #607773; +} + +@media (max-width: 1180px) and (min-width: 921px) { + .geo-explorer-layout { + grid-template-columns: minmax(15rem, 17rem) minmax(0, 1fr); + grid-template-rows: auto auto; + height: auto; + min-height: 0; + } + + .geo-results-panel { + grid-column: 1 / -1; + display: grid; + grid-template-columns: minmax(13rem, 0.7fr) minmax(0, 1.3fr); + align-items: start; + } +} + +@media (max-width: 1359px) and (min-width: 921px) { + /* Keep the map readable until the viewport can support a result rail. */ + .geo-explorer-layout { + grid-template-columns: minmax(15rem, 17rem) minmax(28rem, 1fr); + grid-template-rows: clamp(34rem, calc(100dvh - 10rem), 54rem) auto; + height: auto; + min-height: 0; + } + + .geo-results-panel { + grid-column: 1 / -1; + display: grid; + grid-template-columns: minmax(13rem, 0.7fr) minmax(0, 1.3fr); + align-items: start; + } +} + +@media (max-width: 1799px) and (min-width: 1360px) { + /* A two-column work row keeps the selection step wide at standard desktop sizes. */ + .geo-explorer-layout { + grid-template-columns: minmax(16rem, 18rem) minmax(34rem, 1fr); + grid-template-rows: clamp(36rem, calc(100dvh - 10rem), 58rem) auto; + height: auto; + min-height: 0; + } + + .geo-results-panel { + grid-column: 1 / -1; + display: grid; + grid-template-columns: minmax(14rem, 0.7fr) minmax(0, 1.3fr); + align-items: start; + overflow: visible; + } +} + +@media (max-width: 920px) { + .app-shell > header.workbench-topbar { + position: relative; + display: grid; + grid-template-columns: 1fr; + gap: 0.65rem; + min-height: auto; + } + + .app-shell > header.workbench-topbar { + padding-block: 0.7rem; + } + + .workbench-sidebar { + background: #ffffff; + scrollbar-color: #a9bfba transparent; + scrollbar-width: thin; + } + + .workbench-sidebar::-webkit-scrollbar { + height: 4px; + } + + .workbench-sidebar::-webkit-scrollbar-thumb { + border-radius: 4px; + background: #a9bfba; + } + + .workbench-sidebar::-webkit-scrollbar-track { + background: transparent; + } + + .workbench-sidebar .nav-item { + border-color: transparent; + } + + .workbench-sidebar .nav-item-active { + border-color: #b8d9d2; + box-shadow: inset 0 -3px 0 var(--visual-teal); + } + + .geo-explorer-layout { + gap: 0.75rem; + } +} + +@media (max-width: 620px) { + .workbench-main { + padding-inline: 0.75rem; + } + + .geo-explorer-header { + gap: 0.8rem; + } + + .geo-explorer-header h2 { + font-size: 1.4rem; + } + + .geo-theme-panel, + .geo-results-panel { + padding: 0.75rem; + } + + .geo-map-stage { + box-shadow: none; + } + + .geo-map-canvas .map-container { + min-height: 25rem; + } +} + +@media (prefers-reduced-motion: reduce) { + .workbench-shell button { + transition: none; + } +}