Public role lookup - guided rail
public-role-guided-rail.tsx
componentskill: emil-design-eng + design-taste-frontendsearchpublic-recordscomplianceguided-flow
Variants of public-role-lookup-2026-q3: public-role-compact-ledger, public-role-evidence-workspace
Brief
The prompt that produced this. Re-run it to generate more in the same taste.
- Aesthetic
- institutional utility - sober, exact, trust-first, compact, evidence-led, accessible
- Reference
- FLAIR public-person role lookup, verified desktop and 390px screenshots
- Intent
- make public-role research efficient and auditable without turning the interface into an identity profile
- Guardrails
- always keep source and retrieval context beside every record, use native labels and controls, make public-record scope explicit, collapse cleanly at 375pxnever resolve identity automatically, surface private contact data, use ornamental motion, imply that a public record is a current fact
Install
pnpm dlx shadcn@latest add http://localhost:3040/r/public-role-guided-rail.json
Source
Meta block and library type import stripped - this is what pastes cleanly elsewhere.
'use client'
import { Check, ChevronRight, Search, ShieldCheck } from 'lucide-react'
import { useState } from 'react'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
const steps = ['Choose scope', 'Enter subject', 'Review evidence']
export default function PublicRoleGuidedRail() {
const [scope, setScope] = useState('mandate')
return (
<main className="min-h-[100dvh] bg-zinc-100 text-zinc-950 dark:bg-zinc-950 dark:text-zinc-100">
<div className="mx-auto grid min-h-[100dvh] max-w-7xl lg:grid-cols-[18rem_minmax(0,1fr)]">
<aside className="border-zinc-300 border-b bg-zinc-950 p-6 text-zinc-100 lg:border-r lg:border-b-0 dark:border-zinc-800">
<div className="flex items-center gap-3">
<ShieldCheck aria-hidden className="size-6 text-blue-400" />
<p className="font-semibold tracking-[-0.02em]">Public role lookup</p>
</div>
<p className="mt-3 max-w-[28rem] text-sm leading-6 text-zinc-400">
A constrained search for roles already disclosed by an official publisher.
</p>
<ol className="mt-8 grid grid-cols-3 gap-2 lg:grid-cols-1 lg:gap-0">
{steps.map((step, index) => (
<li
key={step}
className="flex min-w-0 items-center gap-3 border-zinc-800 border-t py-3 text-sm first:border-t-0 lg:first:border-t"
>
<span
className={`flex size-6 shrink-0 items-center justify-center border text-xs ${
index < 2
? 'border-blue-400 bg-blue-400 text-zinc-950'
: 'border-zinc-600 text-zinc-400'
}`}
>
{index < 2 ? <Check aria-hidden className="size-3.5" /> : index + 1}
</span>
<span className="hidden truncate sm:inline">{step}</span>
</li>
))}
</ol>
</aside>
<div className="min-w-0 px-4 py-8 sm:px-8 lg:px-12 lg:py-12">
<header className="max-w-2xl">
<p className="text-sm text-[#000091] dark:text-blue-400">Subject and scope</p>
<h1 className="mt-2 font-semibold text-3xl tracking-[-0.03em]">
Define what may be searched
</h1>
<p className="mt-3 text-sm leading-6 text-zinc-600 dark:text-zinc-300">
A narrow scope produces evidence that is easier to verify and less likely to be
misapplied.
</p>
</header>
<form
className="mt-8 max-w-3xl border-zinc-300 border bg-white dark:border-zinc-800 dark:bg-zinc-900"
onSubmit={(event) => event.preventDefault()}
>
<fieldset className="p-5 sm:p-7">
<legend className="px-1 font-semibold text-base">Published role type</legend>
<div className="mt-3 grid gap-0 border-zinc-300 border dark:border-zinc-700">
{[
['mandate', 'Public mandate', 'Elected or appointed public responsibilities'],
['company', 'Company office', 'Director or officer disclosed in a register'],
[
'appointment',
'Public appointment',
'Membership of a public body or commission',
],
].map(([value, label, description]) => (
<label
key={value}
className={`flex cursor-pointer gap-3 border-zinc-300 border-b p-4 last:border-b-0 dark:border-zinc-700 ${
scope === value
? 'bg-blue-50 dark:bg-blue-950/60'
: 'hover:bg-zinc-50 dark:hover:bg-zinc-800'
}`}
>
<input
type="radio"
name="scope"
value={value}
checked={scope === value}
onChange={() => setScope(value)}
className="mt-0.5 size-4 accent-[#000091]"
/>
<span>
<span className="block font-medium text-sm">{label}</span>
<span className="mt-1 block text-xs leading-5 text-zinc-600 dark:text-zinc-400">
{description}
</span>
</span>
</label>
))}
</div>
</fieldset>
<div className="grid gap-5 border-zinc-300 border-t p-5 sm:grid-cols-2 sm:p-7 dark:border-zinc-700">
<label htmlFor="guided-family-name" className="grid gap-2 font-medium text-sm">
Family name
<Input
id="guided-family-name"
defaultValue="Valcour"
autoComplete="family-name"
className="h-11 rounded-none border-zinc-400 bg-white shadow-none focus-visible:border-[#000091] focus-visible:ring-[#000091]/20 dark:border-zinc-700 dark:bg-zinc-950"
/>
</label>
<label htmlFor="guided-given-name" className="grid gap-2 font-medium text-sm">
Given name
<Input
id="guided-given-name"
defaultValue="NoƩmie"
autoComplete="given-name"
className="h-11 rounded-none border-zinc-400 bg-white shadow-none focus-visible:border-[#000091] focus-visible:ring-[#000091]/20 dark:border-zinc-700 dark:bg-zinc-950"
/>
</label>
</div>
<div className="flex flex-col gap-4 border-zinc-300 border-t bg-zinc-50 p-5 sm:flex-row sm:items-center sm:justify-between sm:p-7 dark:border-zinc-700 dark:bg-zinc-950">
<p className="max-w-md text-xs leading-5 text-zinc-600 dark:text-zinc-400">
Results remain unlinked until a reviewer confirms the subject.
</p>
<Button
type="submit"
className="h-11 rounded-none bg-[#000091] px-5 text-white transition-[transform,background-color] duration-[160ms] ease-[cubic-bezier(0.23,1,0.32,1)] hover:bg-[#1212a8] active:scale-[0.97] motion-reduce:transform-none motion-reduce:transition-none"
>
Continue to evidence
<ChevronRight aria-hidden className="size-4" />
</Button>
</div>
</form>
<section className="mt-8 max-w-3xl border-[#000091] border-l-4 bg-white p-5 dark:bg-zinc-900">
<div className="flex gap-3">
<Search
aria-hidden
className="mt-0.5 size-5 shrink-0 text-[#000091] dark:text-blue-400"
/>
<div>
<h2 className="font-semibold text-sm">What happens next</h2>
<p className="mt-1 text-sm leading-6 text-zinc-600 dark:text-zinc-300">
The tool checks official publishers, records the query, and returns source links
for manual review.
</p>
</div>
</div>
</section>
</div>
</div>
</main>
)
}