diff --git a/LOGISDATA/.env.example b/LOGISDATA/.env.example index d8e1af3..19f63bb 100644 --- a/LOGISDATA/.env.example +++ b/LOGISDATA/.env.example @@ -9,7 +9,8 @@ NEXT_PUBLIC_SITE_URL=http://localhost:3000 # Version string reported by GET /api/health. -NEXT_PUBLIC_APP_VERSION=3.0.0 +# Optional deployment build identifier; defaults to package.json version. +NEXT_PUBLIC_APP_VERSION=3.1.0 # --------------------------------------------------------------------- # Database (optional). Only needed if you add database-backed features. diff --git a/LOGISDATA/next.config.ts b/LOGISDATA/next.config.ts index 6fa6fe3..5d214d0 100644 --- a/LOGISDATA/next.config.ts +++ b/LOGISDATA/next.config.ts @@ -72,11 +72,8 @@ const nextConfig: NextConfig = { return [ { source: "/(.*)", headers: securityHeaders }, { - // Immutable hashed build assets. - source: "/_next/static/:path*", - headers: [{ key: "Cache-Control", value: "public, max-age=31536000, immutable" }], - }, - { + // Next.js owns the immutable cache policy for hashed `/_next/static` + // assets. Overriding it here is redundant and triggers a build warning. source: "/api/:path*", headers: [{ key: "Cache-Control", value: "no-store, max-age=0" }], }, diff --git a/LOGISDATA/src/app/api/health/route.ts b/LOGISDATA/src/app/api/health/route.ts index 935bbe0..7ddc29c 100644 --- a/LOGISDATA/src/app/api/health/route.ts +++ b/LOGISDATA/src/app/api/health/route.ts @@ -1,4 +1,5 @@ import { sql } from "drizzle-orm"; +import packageMetadata from "../../../../package.json"; import { getDb, isDatabaseConfigured } from "@/db"; export const dynamic = "force-dynamic"; @@ -51,7 +52,9 @@ export async function GET(): Promise { const payload: HealthPayload = { ok: database !== "unavailable", service: "logisdata-control-room", - version: process.env.NEXT_PUBLIC_APP_VERSION ?? "3.0.0", + // Package metadata is the release source of truth. Deployments may + // override it with an immutable build identifier when required. + version: process.env.NEXT_PUBLIC_APP_VERSION?.trim() || packageMetadata.version, database, uptimeSeconds: Math.round(process.uptime()), timestamp: new Date().toISOString(), diff --git a/LOGISDATA/src/app/globals.css b/LOGISDATA/src/app/globals.css index 3edb0ac..9534532 100644 --- a/LOGISDATA/src/app/globals.css +++ b/LOGISDATA/src/app/globals.css @@ -871,6 +871,12 @@ button:focus-visible { .verdict-red { color: var(--red); background: rgba(251, 91, 91, 0.06); } .verdict-green { color: var(--emerald); background: rgba(77, 225, 193, 0.06); } +.table-empty-state { + padding: 28px 16px !important; + color: var(--text-muted); + text-align: center; +} + .table-footnote { padding: 11px 17px; border-top: 1px solid var(--line); @@ -1395,9 +1401,20 @@ button:focus-visible { unicode-bidi: isolate; } -@media (max-width: 1180px) { - .brand-lockup, - .navigation-actions { min-width: 160px; } +@media (max-width: 2100px) { + .navigation-actions { min-width: auto; } + .navigation-actions .control-button { + flex: 0 0 32px; + justify-content: center; + width: 32px; + padding: 0; + } + .navigation-actions .control-button > span { display: none; } +} + +@media (max-width: 1700px) { + .top-navigation { padding-right: 20px; padding-left: 20px; } + .brand-lockup { min-width: 160px; } .section-nav { gap: 7px; } .section-nav-button { font-size: 0.55rem; } .section-nav-button span:last-child { display: none; } @@ -1425,6 +1442,13 @@ button:focus-visible { } @media (max-width: 600px) { + .brand-text { display: none; } + .navigation-actions { gap: 3px; } + .navigation-actions .control-button { + flex-basis: 30px; + width: 30px; + min-height: 30px; + } .presentation-section { min-height: 690px; } .section-inner { padding: 91px 38px 30px 16px; } [dir="rtl"] .section-inner { padding-right: 16px; padding-left: 38px; } @@ -2570,6 +2594,15 @@ html[data-theme="light"] { font-size: 0.68rem; } +.telemetry-disclosure { + margin: 0; + padding: 8px 14px; + border-bottom: 1px solid var(--line); + color: var(--text-muted); + font-size: 0.62rem; + line-height: 1.5; +} + .telemetry-filters { display: flex; align-items: center; @@ -2685,17 +2718,33 @@ html[data-theme="light"] { .inspector-overlay { position: fixed; inset: 0; + width: 100%; + max-width: none; + height: 100dvh; + max-height: none; + margin: 0; + border: 0; background: rgba(4, 12, 20, 0.75); + color: inherit; backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); - display: flex; + display: none; align-items: center; justify-content: center; - z-index: 100; padding: 18px; animation: overlay-fade 200ms ease both; } +.calculator-overlay[open], +.inspector-overlay[open] { + display: flex; +} + +.calculator-overlay::backdrop, +.inspector-overlay::backdrop { + background: transparent; +} + @keyframes overlay-fade { from { opacity: 0; } to { opacity: 1; } @@ -2761,6 +2810,16 @@ html[data-theme="light"] { gap: 20px; } +.calculator-disclosure { + margin: 0; + padding: 10px 12px; + border-inline-start: 2px solid var(--amber); + background: var(--surface-soft); + color: var(--text-muted); + font-size: 0.68rem; + line-height: 1.6; +} + .calculator-inputs { display: flex; flex-direction: column; diff --git a/LOGISDATA/src/components/HandoutView.tsx b/LOGISDATA/src/components/HandoutView.tsx index 115d1be..376a68d 100644 --- a/LOGISDATA/src/components/HandoutView.tsx +++ b/LOGISDATA/src/components/HandoutView.tsx @@ -80,7 +80,7 @@ function Handout() { aria-pressed={theme === "light"} > {theme === "dark" ?