Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d3c30859b2 | ||
|
|
2f8dcd66ad |
@@ -1,6 +1,7 @@
|
|||||||
import type { CSSProperties } from "react";
|
import type { CSSProperties } from "react";
|
||||||
|
|
||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
|
import { redirect } from "next/navigation";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
|
|
||||||
import { MedscribeLogo } from "~/components/medscribe-logo";
|
import { MedscribeLogo } from "~/components/medscribe-logo";
|
||||||
@@ -131,6 +132,11 @@ const printLightTokens = {
|
|||||||
} as CSSProperties;
|
} as CSSProperties;
|
||||||
|
|
||||||
export default function ExecutiveSummaryPage() {
|
export default function ExecutiveSummaryPage() {
|
||||||
|
// The home page is now the executive summary (single-page site). This deep
|
||||||
|
// page is retired but kept in place — its content (incl. the print one-pager)
|
||||||
|
// is a one-line revert away if we want a longer version back.
|
||||||
|
redirect("/");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{/* ===================== SCREEN ===================== */}
|
{/* ===================== SCREEN ===================== */}
|
||||||
|
|||||||
+188
-291
@@ -1,332 +1,229 @@
|
|||||||
import {
|
import { HeartPulse, Layers, ShieldCheck, Users } from "lucide-react";
|
||||||
AlertTriangle,
|
|
||||||
ChevronRight,
|
|
||||||
ClipboardList,
|
|
||||||
HeartPulse,
|
|
||||||
Lock,
|
|
||||||
Mic,
|
|
||||||
Pill,
|
|
||||||
Shield,
|
|
||||||
Users,
|
|
||||||
} from "lucide-react";
|
|
||||||
|
|
||||||
import { FeatureShowcase } from "~/components/feature-showcase";
|
|
||||||
import { PhoneMockup } from "~/components/phone-mockup";
|
import { PhoneMockup } from "~/components/phone-mockup";
|
||||||
import { SectionLabel } from "~/components/section-label";
|
import { SectionLabel } from "~/components/section-label";
|
||||||
import {
|
import { BETA_INVITE_MAILTO } from "~/lib/beta";
|
||||||
BETA_CTA_BODY,
|
|
||||||
BETA_CTA_TITLE,
|
|
||||||
BETA_INVITE_MAILTO,
|
|
||||||
} from "~/lib/beta";
|
|
||||||
import { Badge } from "~/components/ui/badge";
|
import { Badge } from "~/components/ui/badge";
|
||||||
import { Button } from "~/components/ui/button";
|
import { Button } from "~/components/ui/button";
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
CardContent,
|
|
||||||
CardDescription,
|
CardDescription,
|
||||||
CardHeader,
|
CardHeader,
|
||||||
CardTitle,
|
CardTitle,
|
||||||
} from "~/components/ui/card";
|
} from "~/components/ui/card";
|
||||||
|
|
||||||
const quickActions = [
|
const fit = [
|
||||||
{
|
{
|
||||||
icon: HeartPulse,
|
icon: Layers,
|
||||||
title: "Know Me card",
|
title: "Complements Epic, doesn't compete",
|
||||||
meta: "Baseline, conditions, allergies",
|
body: "Different job. Epic is the record of care inside Northwell. Medscribe is the patient-owned layer beside it, holding what Epic can't reach: the non-Epic care, the between-visit context, the emergency handoff. With the patient's consent, that context flows back into the workflows Northwell already runs, raising the value of the Epic investment rather than competing for it.",
|
||||||
featured: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: Pill,
|
|
||||||
title: "Time-critical meds",
|
|
||||||
meta: "Schedules caregivers can trust",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: Mic,
|
|
||||||
title: "Visit capture",
|
|
||||||
meta: "Consent-gated, on-device",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: Users,
|
icon: Users,
|
||||||
title: "Caregiver handoff",
|
title: "Keeps patients active in their own care",
|
||||||
meta: "One current shared truth",
|
body: "Reminders and refills the app sets for them, dose tracking, and, between visits, questions routed back to their own care team rather than out to a search engine. Low-friction by design, because a tool the patient actually uses is what turns into adherence, engagement, and in-network follow-through, the things Northwell is measured on.",
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const pillars = [
|
|
||||||
{
|
|
||||||
icon: ClipboardList,
|
|
||||||
title: "Keep the record current",
|
|
||||||
body: "Capture visits, scan labels, and keep conditions, medications, allergies, contacts, and caregiver notes in one portable record.",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: AlertTriangle,
|
icon: HeartPulse,
|
||||||
title: "Make the critical context obvious",
|
title: "Patient-centered where it counts",
|
||||||
body: "The emergency view prioritizes the facts clinicians need fast: baseline, time-critical meds, active conditions, allergies, and who to call.",
|
body: "The emergency handoff, the family caregiver covering a shift, the newly-diagnosed patient who half-remembers the plan. Fewer blank handoffs, safer medication moments, patients who stay engaged instead of going dark.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: Shield,
|
icon: ShieldCheck,
|
||||||
title: "Stay private by architecture",
|
title: "Private by architecture",
|
||||||
body: "Transcription, OCR, and medication chat run locally. No cloud AI processing. Sharing should be explicit, revocable, and encrypted.",
|
body: "The sensitive work (summarizing visits, answering medication questions, building the record) runs entirely on the device, not the cloud. No health data sent to a server for AI processing, no new inbox to breach, no BAA to negotiate.",
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const impact = [
|
|
||||||
{
|
|
||||||
title: "Fewer blank handoffs",
|
|
||||||
body: "When a caregiver is overwhelmed, the important facts are already assembled: conditions, medications, allergies, baseline, contacts, and recent changes.",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Safer medication moments",
|
|
||||||
body: "Time-critical schedules and dose history stay visible, so a missed or delayed medication is easier to catch before it becomes a crisis.",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "More confident families",
|
|
||||||
body: "Caregivers can see what changed, where it came from, and what still needs a clinician or pharmacist instead of guessing from memory.",
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export default function HomePage() {
|
export default function HomePage() {
|
||||||
const today = new Date().toLocaleDateString("en-US", {
|
|
||||||
weekday: "long",
|
|
||||||
month: "long",
|
|
||||||
day: "numeric",
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mx-auto max-w-6xl space-y-14 px-4 py-8 sm:px-6 sm:py-12 lg:space-y-20 lg:py-14">
|
<div className="mx-auto max-w-5xl px-4 py-10 sm:px-6 lg:py-14">
|
||||||
|
{/* Phone floats right on sm+; prose sections wrap around it like a newspaper column */}
|
||||||
|
<div className="animate-fade-in-up-delay-1 mx-auto mb-8 flex justify-center sm:float-right sm:mx-0 sm:mb-4 sm:ml-8 lg:ml-10">
|
||||||
|
<PhoneMockup
|
||||||
|
src="/screenshots/home.png"
|
||||||
|
alt="Medscribe home screen"
|
||||||
|
width={200}
|
||||||
|
priority
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Hero */}
|
<div className="space-y-10 lg:space-y-12">
|
||||||
<section className="grid items-center gap-8 lg:grid-cols-[minmax(0,1fr)_minmax(230px,280px)] lg:gap-14">
|
{/* Origin */}
|
||||||
<div className="space-y-6">
|
<section className="animate-fade-in-up space-y-5">
|
||||||
<div className="animate-fade-in-up space-y-5">
|
<SectionLabel>Executive summary · Northwell Health</SectionLabel>
|
||||||
<SectionLabel>Medscribe · Private complex-care context</SectionLabel>
|
<h1 className="text-foreground font-serif text-4xl leading-[1.05] font-semibold tracking-tight sm:text-5xl lg:text-6xl">
|
||||||
<h1 className="max-w-2xl font-serif text-4xl leading-[1.05] font-semibold tracking-tight text-foreground sm:text-5xl lg:text-6xl">
|
Be known when care gets complicated
|
||||||
Be known when care gets complicated
|
</h1>
|
||||||
</h1>
|
<div className="text-muted-foreground space-y-4 text-base leading-relaxed sm:text-lg">
|
||||||
<p className="max-w-xl text-base leading-relaxed text-muted-foreground sm:text-lg">
|
<p>
|
||||||
A private medical context app for families managing complex care.
|
A grandfather with three adult children, each living twenty to
|
||||||
It keeps visits, medications, baseline, contacts, allergies, and
|
fifty minutes away. None able to be at every appointment. No
|
||||||
emergency facts ready before the chart catches up.
|
shared, current view of his medications, his visits, or what had
|
||||||
|
changed.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Then came the emergency. A fall. A hospital that did not
|
||||||
|
understand his condition. Some of his medications were
|
||||||
|
time-critical. They were administered incorrectly, his decline was
|
||||||
|
misread, the wrong path was taken, and he passed six weeks later.
|
||||||
|
The clinicians were not negligent. The system was blind to who he
|
||||||
|
was, and no trustworthy picture of him existed to hand over.
|
||||||
|
</p>
|
||||||
|
<p className="text-foreground font-medium">
|
||||||
|
Medscribe is the private, patient-owned record built for that gap:
|
||||||
|
the whole picture, held by the patient, ready to hand over the
|
||||||
|
moment the chart in front of you doesn't have it.
|
||||||
</p>
|
</p>
|
||||||
<p className="text-sm text-muted-foreground">{today}</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div className="flex flex-wrap gap-2">
|
||||||
<div className="animate-fade-in-up-delay-1 flex flex-wrap gap-3">
|
<Badge variant="success">On-device · no cloud AI</Badge>
|
||||||
<Button asChild size="lg">
|
|
||||||
<a href="/executive-summary">
|
|
||||||
Read executive summary
|
|
||||||
<ChevronRight className="size-4" />
|
|
||||||
</a>
|
|
||||||
</Button>
|
|
||||||
<Button asChild variant="outline" size="lg">
|
|
||||||
<a href="#features">See how it works</a>
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="animate-fade-in-up-delay-2 flex flex-wrap gap-2">
|
|
||||||
<Badge variant="success">Beta available</Badge>
|
|
||||||
<Badge variant="outline">iOS · TestFlight</Badge>
|
|
||||||
<Badge variant="outline">Android · Play internal</Badge>
|
|
||||||
<Badge variant="outline">Emergency-ready</Badge>
|
<Badge variant="outline">Emergency-ready</Badge>
|
||||||
<Badge variant="outline">No cloud AI</Badge>
|
<Badge variant="outline">Complements Epic</Badge>
|
||||||
|
<Badge variant="outline">iOS · Android beta</Badge>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</section>
|
||||||
|
|
||||||
<div className="animate-fade-in-up-delay-3 flex justify-center lg:justify-end">
|
{/* What it is */}
|
||||||
<div className="flex w-fit items-start justify-center">
|
<section className="animate-fade-in-up space-y-3">
|
||||||
<PhoneMockup
|
<SectionLabel>What it is</SectionLabel>
|
||||||
src="/screenshots/home.png"
|
<h2 className="font-serif text-3xl font-semibold tracking-tight sm:text-4xl">
|
||||||
alt="Medscribe home dashboard"
|
A medical record the patient owns and carries
|
||||||
priority
|
</h2>
|
||||||
width={190}
|
<p className="text-muted-foreground leading-relaxed">
|
||||||
/>
|
Current medications, allergies, baseline, visit summaries, and an
|
||||||
|
emergency “know-me” record, kept current through
|
||||||
|
everyday use, and ready to hand to a caregiver, a new doctor, or an
|
||||||
|
ER in seconds. Everything runs on the device. Nothing is uploaded.
|
||||||
|
</p>
|
||||||
|
<div className="border-primary/30 space-y-2 border-l-2 pl-4">
|
||||||
|
<p className="text-foreground text-sm font-medium">
|
||||||
|
How the record stays current (live in beta today)
|
||||||
|
</p>
|
||||||
|
<ul className="text-muted-foreground space-y-1.5 text-sm leading-relaxed">
|
||||||
|
<li>
|
||||||
|
<span className="text-foreground">Visit summaries: </span>type
|
||||||
|
or paste notes, import MyChart and portal after-visit summaries
|
||||||
|
from a screenshot, or attach photos and documents; optional
|
||||||
|
consent-gated audio recording for patients who want it. Any path
|
||||||
|
feeds the same on-device summary.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<span className="text-foreground">Medication management: </span>
|
||||||
|
pill-bottle label recognition, reminders, and on-device Q&A
|
||||||
|
grounded in FDA drug facts
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<span className="text-foreground">Emergency handoff: </span>a
|
||||||
|
know-me card and encrypted caregiver sharing, patient-controlled
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<p className="text-muted-foreground text-sm leading-relaxed">
|
||||||
|
Structured MyChart / FHIR export import is on the roadmap:
|
||||||
|
import-and-own, not write-back.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</section>
|
||||||
</section>
|
|
||||||
|
|
||||||
{/* Strategic spine */}
|
{/* The gap Epic's own tools can't close */}
|
||||||
<section className="animate-fade-in-up space-y-5">
|
<section className="animate-fade-in-up space-y-3">
|
||||||
<SectionLabel>The story</SectionLabel>
|
<SectionLabel>Where the picture breaks</SectionLabel>
|
||||||
<div className="grid gap-6 lg:grid-cols-[minmax(0,0.9fr)_minmax(0,1.1fr)] lg:items-start">
|
<h2 className="font-serif text-3xl font-semibold tracking-tight sm:text-4xl">
|
||||||
<div className="space-y-3">
|
Epic knows what Epic sees
|
||||||
|
</h2>
|
||||||
|
<p className="text-muted-foreground leading-relaxed">
|
||||||
|
MyChart is excellent inside the Epic walls. It puts the chart on the
|
||||||
|
patient's phone, links their Epic portals through MyChart
|
||||||
|
Central, and lets them share with a caregiver or a provider. What no
|
||||||
|
institutional record can be is the whole picture: the urgent care,
|
||||||
|
the community specialist, the facility that isn't on Epic; the
|
||||||
|
changes between visits; the context a patient keeps themselves. Epic
|
||||||
|
aggregates Epic. And when it matters most, at an out-of-network ER,
|
||||||
|
or when the patient can't generate a share code, the record
|
||||||
|
that's actually there is the one they already carry.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* What makes it different */}
|
||||||
|
<section className="animate-fade-in-up space-y-3">
|
||||||
|
<SectionLabel>What makes it different</SectionLabel>
|
||||||
|
<h2 className="font-serif text-3xl font-semibold tracking-tight sm:text-4xl">
|
||||||
|
No one else owns the whole job
|
||||||
|
</h2>
|
||||||
|
<p className="text-muted-foreground leading-relaxed">
|
||||||
|
Existing Electronic Health Record (EHR) systems owns the
|
||||||
|
institutional view, and every institutional tool stops at its own
|
||||||
|
walls. Around them, the market is full of single-purpose apps: visit
|
||||||
|
notetakers, medication trackers, record vaults, emergency-ID cards.
|
||||||
|
Each owns one slice. None holds a private, patient-owned record that
|
||||||
|
spans every system, Epic and non-Epic alike, stays current through
|
||||||
|
daily use, and is ready to hand over in a crisis, all on the
|
||||||
|
patient's own device. Medscribe is that combination, beside
|
||||||
|
Epic, not instead of it.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Why it fits Northwell: clear float so the card grid spans full width */}
|
||||||
|
<section className="animate-fade-in-up clear-both space-y-6">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<SectionLabel>Why it fits Northwell</SectionLabel>
|
||||||
<h2 className="font-serif text-3xl font-semibold tracking-tight sm:text-4xl">
|
<h2 className="font-serif text-3xl font-semibold tracking-tight sm:text-4xl">
|
||||||
The story scatters right when it matters
|
Built to strengthen the Epic investment, not compete with it
|
||||||
</h2>
|
</h2>
|
||||||
<p className="max-w-xl leading-relaxed text-muted-foreground">
|
|
||||||
A daughter remembers the medication schedule. A spouse knows what
|
|
||||||
normal looks like. A specialist mentioned a change three visits ago.
|
|
||||||
In a crisis, those details are scattered across people, portals, and
|
|
||||||
memory.
|
|
||||||
</p>
|
|
||||||
<p className="max-w-xl text-sm leading-relaxed text-muted-foreground/80 italic">
|
|
||||||
I built the first version of Medscribe after watching my own family
|
|
||||||
try to hold this together for my grandfather. The record scattered
|
|
||||||
right when we needed it most.
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="rounded-lg border border-border-soft bg-surface p-5 shadow-[0_1px_4px_rgba(0,0,0,0.05)]">
|
<div className="grid gap-4 md:grid-cols-2">
|
||||||
<div className="flex items-start gap-3">
|
{fit.map((item) => {
|
||||||
<HeartPulse className="mt-0.5 size-5 shrink-0 text-primary" />
|
const Icon = item.icon;
|
||||||
<div className="space-y-2">
|
|
||||||
<h3 className="font-serif text-xl font-semibold tracking-tight">
|
return (
|
||||||
One current story
|
<Card key={item.title} className="card-hover">
|
||||||
</h3>
|
<CardHeader>
|
||||||
<p className="text-sm leading-relaxed text-muted-foreground">
|
<div className="bg-primary-light flex size-10 items-center justify-center rounded-[10px]">
|
||||||
Medscribe gives the family a private place to keep that context
|
<Icon className="text-primary size-5" />
|
||||||
alive: current meds, timing, baseline, allergies, recent visit
|
</div>
|
||||||
summaries, emergency contacts, and the source trail behind each
|
<CardTitle className="text-lg">{item.title}</CardTitle>
|
||||||
fact.
|
<CardDescription>{item.body}</CardDescription>
|
||||||
</p>
|
</CardHeader>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Who's behind it + the ask */}
|
||||||
|
<section className="animate-fade-in-up">
|
||||||
|
<Card className="border-primary-button/20 bg-primary-button overflow-hidden text-white">
|
||||||
|
<CardHeader className="gap-4">
|
||||||
|
<div className="space-y-3">
|
||||||
|
<CardTitle className="text-white">
|
||||||
|
Who's behind it
|
||||||
|
</CardTitle>
|
||||||
|
<CardDescription className="leading-relaxed text-white/80">
|
||||||
|
Sean O'Connor, a Bucknell computer science and engineering
|
||||||
|
graduate, built Medscribe after watching his own family try to
|
||||||
|
hold this together for his grandfather, when the record
|
||||||
|
scattered exactly at the moment it mattered most. It is live in
|
||||||
|
beta on iOS and Android today.
|
||||||
|
</CardDescription>
|
||||||
|
<CardDescription className="leading-relaxed text-white/80">
|
||||||
|
The ask is a short conversation about whether a patient-owned
|
||||||
|
record that spans the systems Epic can't reach, and feeds
|
||||||
|
that context back into Northwell's Epic, is worth
|
||||||
|
exploring together.
|
||||||
|
</CardDescription>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<Button
|
||||||
</div>
|
asChild
|
||||||
</div>
|
size="lg"
|
||||||
|
variant="outline"
|
||||||
<div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-4">
|
className="text-primary-button w-fit border-white/30 bg-white hover:bg-white/90"
|
||||||
{quickActions.map((action) => {
|
|
||||||
const Icon = action.icon;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Card
|
|
||||||
key={action.title}
|
|
||||||
className={`card-hover ${action.featured ? "border-primary-button/20 bg-primary-button text-white" : ""}`}
|
|
||||||
>
|
>
|
||||||
<CardHeader className="gap-3">
|
<a href={BETA_INVITE_MAILTO}>Start the conversation</a>
|
||||||
<div
|
</Button>
|
||||||
className={`flex size-10 items-center justify-center rounded-[10px] ${
|
</CardHeader>
|
||||||
action.featured ? "bg-white/18" : "bg-primary-light"
|
</Card>
|
||||||
}`}
|
</section>
|
||||||
>
|
</div>
|
||||||
<Icon
|
|
||||||
className={`size-5 ${action.featured ? "text-white" : "text-primary"}`}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<CardTitle className={action.featured ? "text-white" : ""}>
|
|
||||||
{action.title}
|
|
||||||
</CardTitle>
|
|
||||||
<CardDescription
|
|
||||||
className={action.featured ? "text-white/72" : ""}
|
|
||||||
>
|
|
||||||
{action.meta}
|
|
||||||
</CardDescription>
|
|
||||||
</div>
|
|
||||||
</CardHeader>
|
|
||||||
</Card>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
{/* Interactive feature showcase */}
|
|
||||||
<section id="features" className="animate-fade-in-up scroll-mt-24 space-y-5">
|
|
||||||
<div className="space-y-2">
|
|
||||||
<SectionLabel>The record</SectionLabel>
|
|
||||||
<h2 className="font-serif text-3xl font-semibold tracking-tight sm:text-4xl">
|
|
||||||
The pieces that keep the story current
|
|
||||||
</h2>
|
|
||||||
<p className="max-w-2xl text-muted-foreground">
|
|
||||||
Visits, medications, reminders, search, and questions all point toward
|
|
||||||
the same outcome: a record the family can trust when the stakes rise.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<FeatureShowcase />
|
|
||||||
</section>
|
|
||||||
|
|
||||||
{/* Privacy */}
|
|
||||||
<section id="privacy" className="animate-fade-in-up scroll-mt-24 space-y-6">
|
|
||||||
<div className="space-y-3">
|
|
||||||
<SectionLabel>Why this is different</SectionLabel>
|
|
||||||
<h2 className="font-serif text-3xl font-semibold tracking-tight sm:text-4xl">
|
|
||||||
Built for the family record, not another cloud inbox
|
|
||||||
</h2>
|
|
||||||
<p className="max-w-2xl text-muted-foreground">
|
|
||||||
The crowded space already has visit recorders, medication apps, and
|
|
||||||
caregiver portals. Medscribe's wedge is the private, portable
|
|
||||||
context layer families control before an institution is ready — and
|
|
||||||
it works alongside the systems a care team already uses, not instead
|
|
||||||
of them.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="grid gap-4 md:grid-cols-3">
|
|
||||||
{pillars.map((pillar) => {
|
|
||||||
const Icon = pillar.icon;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Card key={pillar.title} className="card-hover">
|
|
||||||
<CardHeader>
|
|
||||||
<div className="flex size-10 items-center justify-center rounded-[10px] bg-primary-light">
|
|
||||||
<Icon className="size-5 text-primary" />
|
|
||||||
</div>
|
|
||||||
<CardTitle>{pillar.title}</CardTitle>
|
|
||||||
<CardDescription>{pillar.body}</CardDescription>
|
|
||||||
</CardHeader>
|
|
||||||
</Card>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Card className="border-primary/15 bg-primary-light/40">
|
|
||||||
<CardContent className="flex items-start gap-4 pt-5">
|
|
||||||
<Lock className="mt-0.5 size-5 shrink-0 text-primary" />
|
|
||||||
<p className="text-sm leading-relaxed text-foreground">
|
|
||||||
All AI models run on your device. No health data is uploaded for
|
|
||||||
processing. The medication chatbot stays in drug-information
|
|
||||||
territory. It defers dosing and diagnosis questions to your
|
|
||||||
clinician or pharmacist.
|
|
||||||
</p>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
{/* Impact */}
|
|
||||||
<section id="impact" className="animate-fade-in-up scroll-mt-24 space-y-6">
|
|
||||||
<div className="space-y-3">
|
|
||||||
<SectionLabel>Potential impact</SectionLabel>
|
|
||||||
<h2 className="font-serif text-3xl font-semibold tracking-tight sm:text-4xl">
|
|
||||||
Less panic, more context, better handoffs
|
|
||||||
</h2>
|
|
||||||
<p className="max-w-2xl text-muted-foreground">
|
|
||||||
The goal is simple: make the person easier to understand at the exact
|
|
||||||
moment their care team has the least context.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="grid gap-4 md:grid-cols-3">
|
|
||||||
{impact.map((item) => (
|
|
||||||
<Card key={item.title} className="card-hover">
|
|
||||||
<CardHeader>
|
|
||||||
<CardTitle>{item.title}</CardTitle>
|
|
||||||
<CardDescription>{item.body}</CardDescription>
|
|
||||||
</CardHeader>
|
|
||||||
</Card>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
{/* CTA */}
|
|
||||||
<section className="animate-fade-in-up">
|
|
||||||
<Card className="overflow-hidden border-primary-button/20 bg-primary-button text-white">
|
|
||||||
<CardHeader className="gap-4 sm:flex-row sm:items-center sm:justify-between">
|
|
||||||
<div className="space-y-2">
|
|
||||||
<CardTitle className="text-white">{BETA_CTA_TITLE}</CardTitle>
|
|
||||||
<CardDescription className="text-white/75">
|
|
||||||
{BETA_CTA_BODY}
|
|
||||||
</CardDescription>
|
|
||||||
</div>
|
|
||||||
<Button
|
|
||||||
asChild
|
|
||||||
size="lg"
|
|
||||||
variant="outline"
|
|
||||||
className="border-white/30 bg-white text-primary-button hover:bg-white/90"
|
|
||||||
>
|
|
||||||
<a href={BETA_INVITE_MAILTO}>Request an invite</a>
|
|
||||||
</Button>
|
|
||||||
</CardHeader>
|
|
||||||
</Card>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
export function SiteFooter() {
|
export function SiteFooter() {
|
||||||
return (
|
return (
|
||||||
<footer className="print-hidden border-t border-border-soft bg-surface/70">
|
<footer className="print-hidden border-t border-border-soft bg-surface/70">
|
||||||
<div className="mx-auto flex max-w-6xl flex-col gap-4 px-4 py-10 text-sm text-muted-foreground sm:px-6 sm:flex-row sm:items-center sm:justify-between">
|
<div className="mx-auto flex max-w-5xl flex-col gap-4 px-4 py-10 text-sm text-muted-foreground sm:px-6 sm:flex-row sm:items-center sm:justify-between">
|
||||||
<div>
|
<div>
|
||||||
<p className="font-serif text-base font-semibold text-foreground">Medscribe</p>
|
<p className="font-serif text-base font-semibold text-foreground">Medscribe</p>
|
||||||
<p className="mt-1 max-w-md leading-relaxed">
|
<p className="mt-1 max-w-md leading-relaxed">
|
||||||
Be known when care gets complicated.
|
Be known when care gets complicated.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="sm:text-right">
|
||||||
<p>
|
<p>
|
||||||
Built by{" "}
|
Built by{" "}
|
||||||
<a
|
<a
|
||||||
@@ -18,6 +18,9 @@ export function SiteFooter() {
|
|||||||
Sean O'Connor
|
Sean O'Connor
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
<p className="mt-1 text-xs text-muted-foreground/80">
|
||||||
|
© {new Date().getFullYear()} Hadlock Holdings LLC
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|||||||
@@ -1,133 +1,27 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import { useState } from "react";
|
|
||||||
import { FileText, Home, Menu, X } from "lucide-react";
|
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { usePathname } from "next/navigation";
|
|
||||||
|
|
||||||
import { MedscribeLogo } from "~/components/medscribe-logo";
|
import { MedscribeLogo } from "~/components/medscribe-logo";
|
||||||
import { cn } from "~/lib/utils";
|
|
||||||
|
|
||||||
const navLinks = [
|
|
||||||
{ href: "/", label: "About", icon: Home },
|
|
||||||
{ href: "/executive-summary", label: "Summary", icon: FileText },
|
|
||||||
];
|
|
||||||
|
|
||||||
export function SiteHeader() {
|
export function SiteHeader() {
|
||||||
const pathname = usePathname();
|
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className="print-hidden sticky top-3 z-50 px-3 sm:px-6">
|
<header className="print-hidden sticky top-3 z-50 px-3 sm:px-6">
|
||||||
<div className="relative mx-auto max-w-5xl">
|
<div className="relative mx-auto max-w-5xl">
|
||||||
<div className="flex h-14 items-center justify-between gap-4 rounded-full border border-border-soft/80 bg-canvas/82 px-4 shadow-[0_10px_30px_rgba(15,23,42,0.08)] backdrop-blur-md sm:px-5">
|
<div className="relative flex h-14 items-center rounded-full border border-border-soft/80 bg-canvas/82 px-4 shadow-[0_10px_30px_rgba(15,23,42,0.08)] backdrop-blur-md sm:px-5">
|
||||||
<Link
|
<Link
|
||||||
href="/"
|
href="/"
|
||||||
className="flex items-center text-foreground transition-opacity hover:opacity-80"
|
className="relative z-10 flex items-center text-foreground transition-opacity hover:opacity-80"
|
||||||
aria-label="Medscribe home"
|
aria-label="Medscribe home"
|
||||||
onClick={() => setIsOpen(false)}
|
|
||||||
>
|
>
|
||||||
<MedscribeLogo className="h-7 w-[88px]" />
|
<MedscribeLogo className="h-7 w-auto" />
|
||||||
</Link>
|
</Link>
|
||||||
|
<p className="pointer-events-none absolute inset-x-0 text-center font-serif text-lg font-semibold tracking-tight text-foreground">
|
||||||
{/* Desktop nav */}
|
Medscribe
|
||||||
<nav className="hidden items-center gap-6 text-sm sm:flex">
|
</p>
|
||||||
{navLinks.map((link) => {
|
<span className="relative z-10 ml-auto hidden text-xs font-medium tracking-[0.14em] text-muted-foreground uppercase sm:inline">
|
||||||
const isActive = link.href === pathname;
|
Executive summary
|
||||||
|
</span>
|
||||||
return (
|
|
||||||
<Link
|
|
||||||
key={link.href}
|
|
||||||
href={link.href}
|
|
||||||
aria-current={isActive ? "page" : undefined}
|
|
||||||
className={cn(
|
|
||||||
"relative py-1 transition-colors",
|
|
||||||
isActive
|
|
||||||
? "text-foreground"
|
|
||||||
: "text-muted-foreground hover:text-foreground",
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{link.label}
|
|
||||||
<span
|
|
||||||
className={cn(
|
|
||||||
"absolute inset-x-0 -bottom-0.5 h-0.5 origin-center rounded-full bg-primary transition-transform duration-200",
|
|
||||||
isActive ? "scale-x-100" : "scale-x-0",
|
|
||||||
)}
|
|
||||||
aria-hidden
|
|
||||||
/>
|
|
||||||
</Link>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
{/* Mobile menu toggle */}
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() => setIsOpen((v) => !v)}
|
|
||||||
className="relative size-6 text-muted-foreground transition-colors hover:text-foreground focus:outline-none sm:hidden"
|
|
||||||
aria-label={isOpen ? "Close menu" : "Open menu"}
|
|
||||||
aria-expanded={isOpen}
|
|
||||||
>
|
|
||||||
<Menu
|
|
||||||
className={cn(
|
|
||||||
"absolute inset-0 transition-opacity duration-200",
|
|
||||||
isOpen ? "opacity-0" : "opacity-100",
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<X
|
|
||||||
className={cn(
|
|
||||||
"absolute inset-0 transition-opacity duration-200",
|
|
||||||
isOpen ? "opacity-100" : "opacity-0",
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Mobile dropdown */}
|
|
||||||
<div
|
|
||||||
className={cn(
|
|
||||||
"absolute inset-x-0 top-16 overflow-hidden rounded-2xl border border-border-soft/80 bg-canvas/95 shadow-[0_10px_30px_rgba(15,23,42,0.12)] backdrop-blur-md transition-all duration-200 sm:hidden",
|
|
||||||
isOpen
|
|
||||||
? "pointer-events-auto opacity-100"
|
|
||||||
: "pointer-events-none -translate-y-1 opacity-0",
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<nav className="flex flex-col p-2">
|
|
||||||
{navLinks.map((link) => {
|
|
||||||
const isActive = link.href === pathname;
|
|
||||||
const Icon = link.icon;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Link
|
|
||||||
key={link.href}
|
|
||||||
href={link.href}
|
|
||||||
aria-current={isActive ? "page" : undefined}
|
|
||||||
onClick={() => setIsOpen(false)}
|
|
||||||
className={cn(
|
|
||||||
"flex items-center gap-3 rounded-xl px-3 py-2.5 text-sm font-medium transition-colors",
|
|
||||||
isActive
|
|
||||||
? "bg-primary-light/60 text-foreground"
|
|
||||||
: "text-muted-foreground hover:bg-surface-soft hover:text-foreground",
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<Icon className="size-4" />
|
|
||||||
{link.label}
|
|
||||||
</Link>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</nav>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Backdrop */}
|
|
||||||
<div
|
|
||||||
className={cn(
|
|
||||||
"fixed inset-0 -z-10 bg-canvas/30 backdrop-blur-sm transition-opacity duration-200 sm:hidden",
|
|
||||||
isOpen ? "opacity-100" : "pointer-events-none opacity-0",
|
|
||||||
)}
|
|
||||||
onClick={() => setIsOpen(false)}
|
|
||||||
aria-hidden
|
|
||||||
/>
|
|
||||||
</header>
|
</header>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user