diff --git a/next.config.ts b/next.config.ts
index 7ad9f31bd..262feb75f 100644
--- a/next.config.ts
+++ b/next.config.ts
@@ -2,6 +2,7 @@ import type { NextConfig } from "next";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { buildSecurityHeaders, resolveRuntimeFlags } from "./src/lib/security-headers";
+import { expectedSupabaseProject } from "./src/lib/supabase/project";
const projectRoot = path.dirname(fileURLToPath(import.meta.url));
const requestedDistDir = process.env.NEXT_DIST_DIR?.trim();
@@ -47,6 +48,26 @@ const nextConfig: NextConfig = {
proxyClientMaxBodySize: "151mb",
},
poweredByHeader: false,
+ images: {
+ // Prefer AVIF (~20-30% smaller than WebP), falling back to WebP, for any
+ // next/image output.
+ formats: ["image/avif", "image/webp"],
+ // Permit optimizing Supabase Storage signed URLs (private document/image
+ // previews) through next/image. Scoped to this app's exact production and
+ // (when configured) staging project hostnames, not the wildcard *.supabase.co.
+ remotePatterns: (() => {
+ const allowedHostnames = [expectedSupabaseProject.ref + ".supabase.co"];
+ const stagingRef = process.env.SUPABASE_STAGING_PROJECT_REF?.trim();
+ if (stagingRef) {
+ allowedHostnames.push(stagingRef + ".supabase.co");
+ }
+ return allowedHostnames.map((hostname) => ({
+ protocol: "https" as const,
+ hostname,
+ pathname: "/storage/v1/object/**",
+ }));
+ })(),
+ },
turbopack: {
root: projectRoot,
},
diff --git a/src/app/forms/[slug]/page.tsx b/src/app/forms/[slug]/page.tsx
index 3e8ddd973..8aef1678c 100644
--- a/src/app/forms/[slug]/page.tsx
+++ b/src/app/forms/[slug]/page.tsx
@@ -19,5 +19,9 @@ export async function generateMetadata({ params }: FormRouteProps): Promise;
+ // Hand the public fixture record to the client so the detail view paints real
+ // content on first load instead of a centered spinner; the owner-aware record
+ // refreshes in place. Absent from the fixtures (owner-only slug) → null.
+ const fallbackRecord = getFormRecord(slug);
+ return ;
}
diff --git a/src/app/globals.css b/src/app/globals.css
index 241f1bf60..36c28d12b 100644
--- a/src/app/globals.css
+++ b/src/app/globals.css
@@ -525,8 +525,9 @@ summary {
transition-timing-function: var(--ease-out-soft);
}
+/* Tactile press only on button-like controls. Applying it to every `a` nudged
+ inline body/citation links down 1px on tap, which reads oddly for text links. */
button:active,
-a:active,
summary:active {
transform: translateY(1px);
}
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index 7d9a185a0..809791d96 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -17,6 +17,11 @@ const geistSans = Geist({
const geistMono = Geist_Mono({
variable: "--font-geist-mono",
subsets: ["latin"],
+ // The mono face is only used deep in the UI (tabular figures, `kbd`, code) and
+ // never in initial/LCP text, so don't preload it on every route — it competes
+ // for the critical-path connection. It still loads on-demand via `swap` when
+ // first painted. The sans face keeps the default preload.
+ preload: false,
});
const baseMetadata: Metadata = {
diff --git a/src/app/medications/[slug]/page.tsx b/src/app/medications/[slug]/page.tsx
index 4ee491c9a..e52cdbe36 100644
--- a/src/app/medications/[slug]/page.tsx
+++ b/src/app/medications/[slug]/page.tsx
@@ -1,6 +1,7 @@
import type { Metadata } from "next";
import { MedicationRecordPage } from "@/components/clinical-dashboard/medication-record-page";
+import { deriveGovernanceFromSections } from "@/lib/medication-records";
import { getMedicationRecord, loadMedicationSnapshot } from "@/lib/medication-snapshot";
type MedicationPageProps = {
@@ -31,5 +32,21 @@ export async function generateMetadata({ params }: MedicationPageProps): Promise
export default async function MedicationPage({ params }: MedicationPageProps) {
const { slug } = await params;
- return ;
+ // The public snapshot record is already in hand server-side. Pass it (plus the
+ // governance derived exactly as the public API does) so the page paints real
+ // clinical content on first load instead of a skeleton, while the client hook
+ // refreshes in place for authenticated owner records. Slugs absent from the
+ // snapshot (owner-only medications) pass `undefined` and keep the loading path.
+ const record = getMedicationRecord(slug);
+ const fallbackGovernance = record
+ ? (() => {
+ const derived = deriveGovernanceFromSections(record);
+ // Validation/review status is a governance decision that must come from
+ // the live/authoritative response, not a hard-coded guess used only for
+ // the pre-fetch content-first paint.
+ return { sourceStatus: derived.source_status, validationStatus: "unverified" as const };
+ })()
+ : undefined;
+
+ return ;
}
diff --git a/src/app/services/[slug]/page.tsx b/src/app/services/[slug]/page.tsx
index 4c1986d41..0b17109fe 100644
--- a/src/app/services/[slug]/page.tsx
+++ b/src/app/services/[slug]/page.tsx
@@ -19,5 +19,9 @@ export async function generateMetadata({ params }: ServiceRouteProps): Promise;
+ // Hand the public fixture record to the client so the detail view paints real
+ // content on first load instead of a centered spinner; the owner-aware record
+ // refreshes in place. Absent from the fixtures (owner-only slug) → null.
+ const fallbackRecord = getServiceRecord(slug);
+ return ;
}
diff --git a/src/components/clinical-dashboard/DocumentManagerPanel.tsx b/src/components/clinical-dashboard/DocumentManagerPanel.tsx
index 030e5e9aa..7927cb14d 100644
--- a/src/components/clinical-dashboard/DocumentManagerPanel.tsx
+++ b/src/components/clinical-dashboard/DocumentManagerPanel.tsx
@@ -429,8 +429,8 @@ export function UploadPanel({
className="h-1.5 w-full overflow-hidden rounded-full bg-[color:var(--surface-inset)]"
>
diff --git a/src/components/clinical-dashboard/medication-record-page.tsx b/src/components/clinical-dashboard/medication-record-page.tsx
index 1b4f02e85..e159a07df 100644
--- a/src/components/clinical-dashboard/medication-record-page.tsx
+++ b/src/components/clinical-dashboard/medication-record-page.tsx
@@ -475,8 +475,25 @@ function MedicationRecordDetail({
);
}
-export function MedicationRecordPage({ slug }: { slug: string }) {
+export function MedicationRecordPage({
+ slug,
+ fallbackRecord,
+ fallbackGovernance,
+}: {
+ slug: string;
+ fallbackRecord?: MedicationRecord;
+ fallbackGovernance?: MedicationGovernance;
+}) {
const { data, loading, error } = useMedicationDetail(slug);
+ // Content-first: render the SSR fallback immediately, then swap in the live
+ // (owner-aware) record once the hook resolves. Only fall back to the skeleton
+ // when there is no server record to show (owner-only slugs) and the fetch is
+ // still in flight; the error state applies only when nothing renderable exists.
+ const record = data?.record ?? fallbackRecord ?? null;
+ // Only trust the SSR fallback governance while the live fetch is still in
+ // flight. A failed request means the authoritative status is unknown, so
+ // don't keep presenting the fixture-derived guess as if it were confirmed.
+ const governance = data?.governance ?? (error ? undefined : fallbackGovernance);
return (
@@ -491,19 +508,19 @@ export function MedicationRecordPage({ slug }: { slug: string }) {