Claude/fix merge conflicts 41 #3879
13 changed files+5358−0
AddedCLAUDE.md+1917−0View fileUnifiedSplit
Large file (1,917 lines). Load full file
Addedapp/(marketing)/find-a-lawyer/page.tsx+595−0View fileUnifiedSplit
@@ -0,0 +1,595 @@
1import type { Metadata } from "next";
2import { BRAND } from "@/lib/constants";
3import SchemaMarkup from "@/app/components/shared/SchemaMarkup";
4import Reveal from "@/app/components/effects/Reveal";
5import Button from "@/app/components/shared/Button";
6import AiDisclaimer from "@/app/components/shared/AiDisclaimer";
7
8export const metadata: Metadata = {
9 title: "Find a Lawyer — Marco Reid",
10 description:
11 "Find an attorney who uses the most advanced AI legal technology available. Marco Reid attorneys deliver faster research, verified citations, transparent communication, and better outcomes for every matter.",
12};
13
14const schema = {
15 "@context": "https://schema.org",
16 "@graph": [
17 {
18 "@type": "ProfessionalService",
19 name: "Marco Reid — Find a Lawyer",
20 description:
21 "Connect with attorneys who use Marco Reid, the most advanced AI-powered legal technology platform. Faster research, verified citations, and real-time client communication.",
22 url: `${BRAND.url}/find-a-lawyer`,
23 provider: {
24 "@type": "Organization",
25 name: BRAND.name,
26 url: BRAND.url,
27 },
28 },
29 {
30 "@type": "LegalService",
31 name: "Marco Reid Attorney Network",
32 description:
33 "Attorneys on Marco Reid use AI-powered legal research with citation verification, practice management, and secure client portals to deliver better outcomes.",
34 url: `${BRAND.url}/find-a-lawyer`,
35 areaServed: "US",
36 },
37 ],
38};
39
40const advantages = [
41 {
42 title: "AI-Powered Research",
43 description:
44 "Your attorney uses Marco \u2014 the most advanced legal research AI ever built. Every question answered with verified case law, statutes, and regulatory guidance sourced from authoritative public domain databases.",
45 icon: (
46 <svg
47 className="h-8 w-8 text-forest-500"
48 viewBox="0 0 24 24"
49 fill="none"
50 stroke="currentColor"
51 strokeWidth={1.5}
52 strokeLinecap="round"
53 strokeLinejoin="round"
54 aria-hidden="true"
55 >
56 <circle cx="11" cy="11" r="8" />
57 <path d="m21 21-4.3-4.3" />
58 <path d="M11 8v6M8 11h6" />
59 </svg>
60 ),
61 },
62 {
63 title: "Faster Turnaround",
64 description:
65 "Marco Reid saves attorneys 15\u201320 hours every week. Research that once took 4\u20136 hours now takes 20\u201340 minutes. Document drafting that took half a day is done in under an hour. Your matter moves faster.",
66 icon: (
67 <svg
68 className="h-8 w-8 text-forest-500"
69 viewBox="0 0 24 24"
70 fill="none"
71 stroke="currentColor"
72 strokeWidth={1.5}
73 strokeLinecap="round"
74 strokeLinejoin="round"
75 aria-hidden="true"
76 >
77 <circle cx="12" cy="12" r="10" />
78 <polyline points="12 6 12 12 16 14" />
79 </svg>
80 ),
81 },
82 {
83 title: "Transparent Communication",
84 description:
85 "Every Marco Reid client gets a secure portal. Track your matter status in plain English, view every document, message your attorney directly, sign documents online, and pay invoices \u2014 all in one place.",
86 icon: (
87 <svg
88 className="h-8 w-8 text-forest-500"
89 viewBox="0 0 24 24"
90 fill="none"
91 stroke="currentColor"
92 strokeWidth={1.5}
93 strokeLinecap="round"
94 strokeLinejoin="round"
95 aria-hidden="true"
96 >
97 <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" />
98 <path d="M8 10h8M8 14h4" />
99 </svg>
100 ),
101 },
102 {
103 title: "Verified Citations",
104 description:
105 "Every case citation your attorney relies on is verified against authoritative public domain sources. No fabricated case law. No hallucinated rulings. Every citation links to the original source document.",
106 icon: (
107 <svg
108 className="h-8 w-8 text-forest-500"
109 viewBox="0 0 24 24"
110 fill="none"
111 stroke="currentColor"
112 strokeWidth={1.5}
113 strokeLinecap="round"
114 strokeLinejoin="round"
115 aria-hidden="true"
116 >
117 <path d="M9 12l2 2 4-4" />
118 <path d="M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20z" />
119 </svg>
120 ),
121 },
122];
123
124const practiceAreas = [
125 {
126 name: "Immigration Law",
127 description:
128 "Visa petitions, green cards, naturalization, asylum, and removal defence. AI-powered USCIS form automation and RFE drafting.",
129 icon: (
130 <svg className="h-7 w-7" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={1.5} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
131 <circle cx="12" cy="12" r="10" />
132 <path d="M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z" />
133 </svg>
134 ),
135 },
136 {
137 name: "Corporate Law",
138 description:
139 "Business formation, mergers and acquisitions, contracts, corporate governance, and commercial transactions.",
140 icon: (
141 <svg className="h-7 w-7" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={1.5} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
142 <rect x="2" y="7" width="20" height="14" rx="2" />
143 <path d="M16 7V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v2" />
144 <path d="M12 12v.01" />
145 </svg>
146 ),
147 },
148 {
149 name: "Family Law",
150 description:
151 "Divorce, custody, child support, adoption, and prenuptial agreements. Sensitive matters handled with precision.",
152 icon: (
153 <svg className="h-7 w-7" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={1.5} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
154 <path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78L12 21.23l8.84-8.84a5.5 5.5 0 0 0 0-7.78z" />
155 </svg>
156 ),
157 },
158 {
159 name: "Criminal Defence",
160 description:
161 "Misdemeanour and felony defence, white-collar crime, DUI, appeals, and post-conviction relief.",
162 icon: (
163 <svg className="h-7 w-7" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={1.5} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
164 <path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" />
165 </svg>
166 ),
167 },
168 {
169 name: "Real Estate Law",
170 description:
171 "Residential and commercial transactions, title disputes, landlord-tenant matters, zoning, and land use.",
172 icon: (
173 <svg className="h-7 w-7" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={1.5} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
174 <path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
175 <polyline points="9 22 9 12 15 12 15 22" />
176 </svg>
177 ),
178 },
179 {
180 name: "Employment Law",
181 description:
182 "Wrongful termination, discrimination, wage disputes, employment contracts, and workplace compliance.",
183 icon: (
184 <svg className="h-7 w-7" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={1.5} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
185 <path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2" />
186 <circle cx="9" cy="7" r="4" />
187 <path d="M23 21v-2a4 4 0 0 0-3-3.87" />
188 <path d="M16 3.13a4 4 0 0 1 0 7.75" />
189 </svg>
190 ),
191 },
192 {
193 name: "Estate Planning",
194 description:
195 "Wills, trusts, probate, powers of attorney, estate administration, and asset protection strategies.",
196 icon: (
197 <svg className="h-7 w-7" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={1.5} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
198 <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
199 <polyline points="14 2 14 8 20 8" />
200 <line x1="16" y1="13" x2="8" y2="13" />
201 <line x1="16" y1="17" x2="8" y2="17" />
202 </svg>
203 ),
204 },
205 {
206 name: "Intellectual Property",
207 description:
208 "Patents, trademarks, copyrights, trade secrets, licensing, and IP litigation with USPTO integration.",
209 icon: (
210 <svg className="h-7 w-7" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={1.5} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
211 <path d="M9 18V5l12-2v13" />
212 <circle cx="6" cy="18" r="3" />
213 <circle cx="18" cy="16" r="3" />
214 </svg>
215 ),
216 },
217 {
218 name: "Personal Injury",
219 description:
220 "Auto accidents, medical malpractice, slip and fall, product liability, and wrongful death claims.",
221 icon: (
222 <svg className="h-7 w-7" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={1.5} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
223 <path d="M22 12h-4l-3 9L9 3l-3 9H2" />
224 </svg>
225 ),
226 },
227 {
228 name: "Tax Law",
229 description:
230 "Tax disputes, IRS audits, tax court litigation, state and federal tax controversy, and tax planning.",
231 icon: (
232 <svg className="h-7 w-7" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={1.5} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
233 <line x1="12" y1="1" x2="12" y2="23" />
234 <path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6" />
235 </svg>
236 ),
237 },
238 {
239 name: "Bankruptcy",
240 description:
241 "Chapter 7, Chapter 11, Chapter 13 filings, creditor representation, debt restructuring, and asset protection.",
242 icon: (
243 <svg className="h-7 w-7" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={1.5} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
244 <rect x="1" y="4" width="22" height="16" rx="2" />
245 <line x1="1" y1="10" x2="23" y2="10" />
246 </svg>
247 ),
248 },
249 {
250 name: "Civil Litigation",
251 description:
252 "Contract disputes, business torts, class actions, appeals, and complex commercial litigation.",
253 icon: (
254 <svg className="h-7 w-7" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={1.5} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
255 <path d="M12 3v18M3 12l3-3 3 3M15 12l3-3 3 3M3 12h18" />
256 </svg>
257 ),
258 },
259];
260
261const steps = [
262 {
263 number: "01",
264 title: "Tell us about your matter",
265 description:
266 "Describe your legal need and location. Whether it is an immigration petition, a business dispute, a family matter, or a real estate closing, we match you with the right expertise.",
267 },
268 {
269 number: "02",
270 title: "Get matched with Marco Reid attorneys",
271 description:
272 "We connect you with attorneys in your area who use Marco Reid daily. These are professionals who have chosen the most advanced legal technology available to serve their clients.",
273 },
274 {
275 number: "03",
276 title: "Experience the difference",
277 description:
278 "Your attorney uses AI-powered research, verified citations, intelligent document drafting, and a secure client portal. You get faster results, better communication, and complete transparency.",
279 },
280];
281
282export default function FindALawyerPage() {
283 return (
284 <>
285 <SchemaMarkup schema={schema} />
286
287 {/* ── Hero ── */}
288 <section className="relative overflow-hidden bg-navy-500 pt-32 pb-24 sm:pt-40 sm:pb-32">
289 {/* Gradient orbs */}
290 <div
291 className="pointer-events-none absolute -top-40 left-1/4 h-[500px] w-[500px] rounded-full bg-forest-500/20 blur-3xl"
292 aria-hidden="true"
293 />
294 <div
295 className="pointer-events-none absolute -bottom-20 right-1/4 h-[400px] w-[400px] rounded-full bg-plum-500/15 blur-3xl"
296 aria-hidden="true"
297 />
298
299 <div className="relative mx-auto max-w-6xl px-6 sm:px-8 lg:px-12 text-center">
300 <Reveal>
301 <p className="text-xs font-medium uppercase tracking-widest text-forest-400">
302 Marco Reid Attorney Network
303 </p>
304 </Reveal>
305 <Reveal delay={0.1}>
306 <h1 className="mt-8 font-serif text-hero text-white">
307 Find the Right Attorney
308 <br />
309 for Your Matter
310 </h1>
311 </Reveal>
312 <Reveal delay={0.2}>
313 <p className="mx-auto mt-8 max-w-2xl text-xl leading-relaxed text-navy-200">
314 Marco Reid attorneys use the most advanced AI legal technology
315 ever built. When you work with a Marco Reid attorney, you get
316 faster research, verified citations, transparent communication,
317 and better outcomes — every time.
318 </p>
319 </Reveal>
320 <Reveal delay={0.3}>
321 <div className="mt-12">
322 <Button href="#practice-areas" variant="secondary" size="lg">
323 Browse practice areas
324 </Button>
325 </div>
326 </Reveal>
327 </div>
328 </section>
329
330 {/* ── Why Choose a Marco Reid Attorney ── */}
331 <section className="bg-white py-24 sm:py-36" aria-label="Why choose a Marco Reid attorney">
332 <div className="mx-auto max-w-6xl px-6 sm:px-8 lg:px-12">
333 <Reveal>
334 <p className="text-xs font-medium uppercase tracking-widest text-forest-600">
335 The Marco Reid advantage
336 </p>
337 <h2 className="mt-6 font-serif text-display text-navy-800">
338 Why choose a Marco Reid attorney.
339 </h2>
340 </Reveal>
341
342 <div className="mt-16 grid gap-6 sm:grid-cols-2">
343 {advantages.map((item, i) => (
344 <Reveal key={item.title} delay={0.05 + i * 0.05}>
345 <div className="rounded-xl border border-navy-100 bg-white p-8 shadow-card transition-all duration-300 hover:shadow-card-hover hover:-translate-y-0.5">
346 <div className="mb-5">{item.icon}</div>
347 <h3 className="font-serif text-xl font-semibold text-navy-700">
348 {item.title}
349 </h3>
350 <p className="mt-3 leading-relaxed text-navy-400">
351 {item.description}
352 </p>
353 </div>
354 </Reveal>
355 ))}
356 </div>
357 </div>
358 </section>
359
360 <div className="h-px bg-navy-100 mx-auto max-w-sm" />
361
362 {/* ── Practice Areas ── */}
363 <section
364 id="practice-areas"
365 className="bg-white py-24 sm:py-36"
366 aria-label="Practice areas"
367 >
368 <div className="mx-auto max-w-6xl px-6 sm:px-8 lg:px-12">
369 <Reveal>
370 <p className="text-center text-xs font-medium uppercase tracking-widest text-forest-600">
371 Practice areas
372 </p>
373 <h2 className="mt-6 text-center font-serif text-display text-navy-800">
374 Find an attorney by practice area.
375 </h2>
376 <p className="mx-auto mt-4 max-w-2xl text-center text-lg text-navy-400">
377 Marco Reid attorneys span every major practice area. Each uses
378 AI-powered legal research, verified citations, and a secure client
379 portal to serve you better.
380 </p>
381 </Reveal>
382
383 <div className="mt-16 grid gap-5 sm:grid-cols-2 lg:grid-cols-3">
384 {practiceAreas.map((area, i) => (
385 <Reveal key={area.name} delay={0.03 + i * 0.03}>
386 <div className="group flex h-full flex-col rounded-xl border border-navy-100 bg-white p-6 shadow-card transition-all duration-300 hover:shadow-card-hover hover:-translate-y-0.5">
387 <div className="mb-4 text-navy-400 transition-colors duration-300 group-hover:text-forest-500">
388 {area.icon}
389 </div>
390 <h3 className="font-serif text-lg font-semibold text-navy-700">
391 {area.name}
392 </h3>
393 <p className="mt-2 flex-1 text-sm leading-relaxed text-navy-400">
394 {area.description}
395 </p>
396 <p className="mt-4 text-sm font-semibold text-forest-600 transition-colors duration-300 group-hover:text-forest-500">
397 Find attorneys →
398 </p>
399 </div>
400 </Reveal>
401 ))}
402 </div>
403 </div>
404 </section>
405
406 <div className="h-px bg-navy-100 mx-auto max-w-sm" />
407
408 {/* ── How It Works ── */}
409 <section className="bg-white py-24 sm:py-36" aria-label="How it works">
410 <div className="mx-auto max-w-6xl px-6 sm:px-8 lg:px-12">
411 <Reveal>
412 <p className="text-center text-xs font-medium uppercase tracking-widest text-forest-600">
413 How it works
414 </p>
415 <h2 className="mt-6 text-center font-serif text-display text-navy-800">
416 Three steps to better legal help.
417 </h2>
418 </Reveal>
419
420 <div className="mx-auto mt-16 max-w-3xl space-y-8">
421 {steps.map((step, i) => (
422 <Reveal key={step.number} delay={0.05 + i * 0.1}>
423 <div className="flex gap-6 rounded-xl border border-navy-100 bg-white p-8 shadow-card">
424 <div className="flex-shrink-0">
425 <span className="flex h-12 w-12 items-center justify-center rounded-full bg-navy-500 font-serif text-lg font-bold text-white">
426 {step.number}
427 </span>
428 </div>
429 <div>
430 <h3 className="font-serif text-xl font-semibold text-navy-700">
431 {step.title}
432 </h3>
433 <p className="mt-2 leading-relaxed text-navy-400">
434 {step.description}
435 </p>
436 </div>
437 </div>
438 </Reveal>
439 ))}
440 </div>
441 </div>
442 </section>
443
444 <div className="h-px bg-navy-100 mx-auto max-w-sm" />
445
446 {/* ── The Marco Reid Advantage — Comparison ── */}
447 <section
448 className="bg-white py-24 sm:py-36"
449 aria-label="The Marco Reid advantage"
450 >
451 <div className="mx-auto max-w-6xl px-6 sm:px-8 lg:px-12">
452 <Reveal>
453 <p className="text-center text-xs font-medium uppercase tracking-widest text-forest-600">
454 The difference
455 </p>
456 <h2 className="mt-6 text-center font-serif text-display text-navy-800">
457 The Marco Reid advantage.
458 </h2>
459 </Reveal>
460
461 <div className="mx-auto mt-16 max-w-4xl">
462 <Reveal delay={0.1}>
463 <div className="overflow-hidden rounded-xl border border-navy-100 shadow-card">
464 <table className="w-full text-left">
465 <thead>
466 <tr className="border-b border-navy-100 bg-navy-50">
467 <th className="px-6 py-4 text-sm font-semibold text-navy-600">
468 Workflow
469 </th>
470 <th className="px-6 py-4 text-sm font-semibold text-navy-400">
471 Traditional attorney
472 </th>
473 <th className="px-6 py-4 text-sm font-semibold text-forest-600">
474 Marco Reid attorney
475 </th>
476 </tr>
477 </thead>
478 <tbody className="divide-y divide-navy-100">
479 <tr>
480 <td className="px-6 py-4 text-sm font-medium text-navy-700">
481 Legal research
482 </td>
483 <td className="px-6 py-4 text-sm text-navy-400">
484 4–6 hours of manual searching
485 </td>
486 <td className="px-6 py-4 text-sm font-medium text-forest-600">
487 20–40 minutes with AI and verified citations
488 </td>
489 </tr>
490 <tr>
491 <td className="px-6 py-4 text-sm font-medium text-navy-700">
492 Document drafting
493 </td>
494 <td className="px-6 py-4 text-sm text-navy-400">
495 3–4 hours of manual drafting
496 </td>
497 <td className="px-6 py-4 text-sm font-medium text-forest-600">
498 30–60 minutes with AI-assisted drafting
499 </td>
500 </tr>
501 <tr>
502 <td className="px-6 py-4 text-sm font-medium text-navy-700">
503 Client updates
504 </td>
505 <td className="px-6 py-4 text-sm text-navy-400">
506 Phone tag and missed calls
507 </td>
508 <td className="px-6 py-4 text-sm font-medium text-forest-600">
509 Real-time portal with status, documents, and messaging
510 </td>
511 </tr>
512 <tr>
513 <td className="px-6 py-4 text-sm font-medium text-navy-700">
514 Citation accuracy
515 </td>
516 <td className="px-6 py-4 text-sm text-navy-400">
517 Manual verification of every source
518 </td>
519 <td className="px-6 py-4 text-sm font-medium text-forest-600">
520 Automated verification against authoritative sources
521 </td>
522 </tr>
523 <tr>
524 <td className="px-6 py-4 text-sm font-medium text-navy-700">
525 Court deadlines
526 </td>
527 <td className="px-6 py-4 text-sm text-navy-400">
528 Manual calendar tracking
529 </td>
530 <td className="px-6 py-4 text-sm font-medium text-forest-600">
531 Automatic court-rules calendaring by jurisdiction
532 </td>
533 </tr>
534 <tr>
535 <td className="px-6 py-4 text-sm font-medium text-navy-700">
536 Document signing
537 </td>
538 <td className="px-6 py-4 text-sm text-navy-400">
539 Separate e-signature service or in-person
540 </td>
541 <td className="px-6 py-4 text-sm font-medium text-forest-600">
542 Built-in e-signature, no extra cost
543 </td>
544 </tr>
545 </tbody>
546 </table>
547 </div>
548 </Reveal>
549 </div>
550 </div>
551 </section>
552
553 <div className="h-px bg-navy-100 mx-auto max-w-sm" />
554
555 {/* ── AI Disclaimer ── */}
556 <section className="bg-white py-16" aria-label="AI disclaimer">
557 <div className="mx-auto max-w-2xl px-6 sm:px-8 lg:px-12">
558 <AiDisclaimer />
559 </div>
560 </section>
561
562 {/* ── CTA: Are You an Attorney? ── */}
563 <section className="bg-navy-50 py-24 sm:py-36" aria-label="For attorneys">
564 <div className="mx-auto max-w-6xl px-6 sm:px-8 lg:px-12 text-center">
565 <Reveal>
566 <p className="text-xs font-medium uppercase tracking-widest text-forest-600">
567 For professionals
568 </p>
569 <h2 className="mt-6 font-serif text-display text-navy-800">
570 Are you an attorney?
571 </h2>
572 </Reveal>
573 <Reveal delay={0.1}>
574 <p className="mx-auto mt-4 max-w-xl text-lg text-navy-400">
575 Join the platform that gives you your practice back. AI-powered
576 research, case management, billing, trust accounting, document
577 drafting, and a client portal — all in one place. Your
578 clients find you here. Give them a reason to stay.
579 </p>
580 </Reveal>
581 <Reveal delay={0.2}>
582 <div className="mt-10 flex justify-center gap-4">
583 <Button href="/pricing" size="lg">
584 See pricing
585 </Button>
586 <Button href="/law" variant="secondary" size="lg">
587 Explore Marco Reid Legal
588 </Button>
589 </div>
590 </Reveal>
591 </div>
592 </section>
593 </>
594 );
595}
Addedapp/(marketing)/find-an-accountant/page.tsx+497−0View fileUnifiedSplit
@@ -0,0 +1,497 @@
1import type { Metadata } from "next";
2import { BRAND } from "@/lib/constants";
3import Container from "@/app/components/shared/Container";
4import SchemaMarkup from "@/app/components/shared/SchemaMarkup";
5import Reveal from "@/app/components/effects/Reveal";
6import Button from "@/app/components/shared/Button";
7import AiDisclaimer from "@/app/components/shared/AiDisclaimer";
8
9export const metadata: Metadata = {
10 title:
11 "Find an Accountant — AI-Powered CPAs on Marco Reid",
12 description:
13 "Find a CPA who uses Marco Reid. AI-powered tax research, automated reconciliation, transparent reporting, and multi-state compliance. Your business deserves the most advanced accounting intelligence available.",
14};
15
16const schema = {
17 "@context": "https://schema.org",
18 "@graph": [
19 {
20 "@type": "ProfessionalService",
21 name: "Find an Accountant on Marco Reid",
22 description:
23 "Directory of CPAs and accounting professionals using Marco Reid, the most advanced AI-powered accounting intelligence platform for tax research, compliance, and financial reporting.",
24 url: `${BRAND.url}/find-an-accountant`,
25 provider: {
26 "@type": "Organization",
27 name: BRAND.name,
28 url: BRAND.url,
29 },
30 },
31 {
32 "@type": "AccountingService",
33 name: "Marco Reid Accounting",
34 description:
35 "AI-powered accounting platform for CPAs with real-time tax code analysis, automated bank reconciliation, client portals, and multi-jurisdiction compliance.",
36 url: `${BRAND.url}/accounting`,
37 provider: {
38 "@type": "Organization",
39 name: BRAND.name,
40 url: BRAND.url,
41 },
42 },
43 ],
44};
45
46const advantages = [
47 {
48 icon: (
49 <svg
50 className="h-6 w-6 text-forest-500"
51 fill="none"
52 viewBox="0 0 24 24"
53 strokeWidth={1.5}
54 stroke="currentColor"
55 aria-hidden="true"
56 >
57 <path
58 strokeLinecap="round"
59 strokeLinejoin="round"
60 d="M9.813 15.904 9 18.75l-.813-2.846a4.5 4.5 0 0 0-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 0 0 3.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 0 0 3.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 0 0-3.09 3.09ZM18.259 8.715 18 9.75l-.259-1.035a3.375 3.375 0 0 0-2.455-2.456L14.25 6l1.036-.259a3.375 3.375 0 0 0 2.455-2.456L18 2.25l.259 1.035a3.375 3.375 0 0 0 2.455 2.456L21.75 6l-1.036.259a3.375 3.375 0 0 0-2.455 2.456Z"
61 />
62 </svg>
63 ),
64 title: "AI-Powered Tax Research",
65 description:
66 "Your CPA has instant access to every IRS code section, revenue ruling, and regulatory guidance document. Real-time tax code analysis means no deduction is missed and every position is defensible.",
67 },
68 {
69 icon: (
70 <svg
71 className="h-6 w-6 text-forest-500"
72 fill="none"
73 viewBox="0 0 24 24"
74 strokeWidth={1.5}
75 stroke="currentColor"
76 aria-hidden="true"
77 >
78 <path
79 strokeLinecap="round"
80 strokeLinejoin="round"
81 d="M19.5 12c0-1.232-.046-2.453-.138-3.662a4.006 4.006 0 0 0-3.7-3.7 48.678 48.678 0 0 0-7.324 0 4.006 4.006 0 0 0-3.7 3.7c-.017.22-.032.441-.046.662M19.5 12l3-3m-3 3-3-3m-12 3c0 1.232.046 2.453.138 3.662a4.006 4.006 0 0 0 3.7 3.7 48.656 48.656 0 0 0 7.324 0 4.006 4.006 0 0 0 3.7-3.7c.017-.22.032-.441.046-.662M4.5 12l3 3m-3-3-3 3"
82 />
83 </svg>
84 ),
85 title: "Automated Reconciliation",
86 description:
87 "Bank feeds flow directly into the platform. AI categorises every transaction, matches receipts automatically, and reconciles in real time. Monthly close happens in minutes, not days.",
88 },
89 {
90 icon: (
91 <svg
92 className="h-6 w-6 text-forest-500"
93 fill="none"
94 viewBox="0 0 24 24"
95 strokeWidth={1.5}
96 stroke="currentColor"
97 aria-hidden="true"
98 >
99 <path
100 strokeLinecap="round"
101 strokeLinejoin="round"
102 d="M3 13.125C3 12.504 3.504 12 4.125 12h2.25c.621 0 1.125.504 1.125 1.125v6.75C7.5 20.496 6.996 21 6.375 21h-2.25A1.125 1.125 0 0 1 3 19.875v-6.75ZM9.75 8.625c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125v11.25c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 0 1-1.125-1.125V8.625ZM16.5 4.125c0-.621.504-1.125 1.125-1.125h2.25C20.496 3 21 3.504 21 4.125v15.75c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 0 1-1.125-1.125V4.125Z"
103 />
104 </svg>
105 ),
106 title: "Transparent Reporting",
107 description:
108 "Your CPA gives you a secure client portal with live financial dashboards. See your profit and loss, balance sheet, cash flow, and tax position whenever you want. No more waiting for quarterly reports.",
109 },
110 {
111 icon: (
112 <svg
113 className="h-6 w-6 text-forest-500"
114 fill="none"
115 viewBox="0 0 24 24"
116 strokeWidth={1.5}
117 stroke="currentColor"
118 aria-hidden="true"
119 >
120 <path
121 strokeLinecap="round"
122 strokeLinejoin="round"
123 d="M12 21a9.004 9.004 0 0 0 8.716-6.747M12 21a9.004 9.004 0 0 1-8.716-6.747M12 21c2.485 0 4.5-4.03 4.5-9S14.485 3 12 3m0 18c-2.485 0-4.5-4.03-4.5-9S9.515 3 12 3m0 0a8.997 8.997 0 0 1 7.843 4.582M12 3a8.997 8.997 0 0 0-7.843 4.582m15.686 0A11.953 11.953 0 0 1 12 10.5c-2.998 0-5.74-1.1-7.843-2.918m15.686 0A8.959 8.959 0 0 1 21 12c0 .778-.099 1.533-.284 2.253m0 0A17.919 17.919 0 0 1 12 16.5a17.92 17.92 0 0 1-8.716-2.247m0 0A8.966 8.966 0 0 1 3 12c0-1.264.26-2.467.732-3.559"
124 />
125 </svg>
126 ),
127 title: "Multi-State Compliance",
128 description:
129 "Operating in multiple states means multiple tax codes, multiple filing deadlines, and multiple compliance requirements. Marco Reid AI handles jurisdiction complexity so your CPA never misses a filing.",
130 },
131];
132
133const serviceAreas = [
134 {
135 title: "Tax Preparation",
136 description:
137 "Federal and state returns for individuals, businesses, partnerships, and trusts. AI-verified against current tax code.",
138 },
139 {
140 title: "Tax Planning",
141 description:
142 "Forward-looking strategies to minimise tax liability. Entity selection, retirement planning, estimated payments, and year-end optimisation.",
143 },
144 {
145 title: "Bookkeeping",
146 description:
147 "Automated chart of accounts, journal entries, accounts payable, accounts receivable, and monthly close. AI-categorised bank feeds.",
148 },
149 {
150 title: "Payroll",
151 description:
152 "Full payroll processing with W-2 and 1099 preparation, direct deposit, tax withholding calculations, and quarterly filings.",
153 },
154 {
155 title: "Financial Statements",
156 description:
157 "GAAP-compliant profit and loss, balance sheet, cash flow, and equity statements generated from live data. Always current.",
158 },
159 {
160 title: "Audit Support",
161 description:
162 "Comprehensive audit workpapers, document organisation, and response preparation. Complete audit trail from day one.",
163 },
164 {
165 title: "Business Formation",
166 description:
167 "LLC, S-Corp, C-Corp, and partnership formation with proper tax elections, EIN applications, and state registrations.",
168 },
169 {
170 title: "Estate Tax",
171 description:
172 "Estate and gift tax planning, fiduciary returns, trust accounting, and generation-skipping transfer strategies.",
173 },
174 {
175 title: "International Tax",
176 description:
177 "Cross-border compliance for expats, foreign-owned US businesses, FBAR and FATCA reporting, and treaty analysis.",
178 },
179 {
180 title: "Nonprofit Accounting",
181 description:
182 "Form 990 preparation, fund accounting, grant tracking, donor reporting, and compliance with tax-exempt requirements.",
183 },
184];
185
186const steps = [
187 {
188 number: "01",
189 title: "Describe your needs",
190 description:
191 "Tell us about your business, your industry, the services you need, and the states you operate in. The more detail you provide, the better your match.",
192 },
193 {
194 number: "02",
195 title: "Get matched with a CPA",
196 description:
197 "We connect you with a Marco Reid CPA whose expertise matches your specific requirements. Every accountant on the platform uses AI-powered tools for accuracy and speed.",
198 },
199 {
200 number: "03",
201 title: "Experience the difference",
202 description:
203 "Your CPA uses Marco Reid for real-time tax research, automated reconciliation, and transparent reporting. You get a secure client portal with live access to your financials.",
204 },
205];
206
207const comparisonRows = [
208 {
209 feature: "Tax research speed",
210 traditional: "Hours of manual code lookup",
211 marcoReid: "Seconds. AI searches every IRS publication instantly.",
212 },
213 {
214 feature: "Bank reconciliation",
215 traditional: "Manual data entry, monthly close in days",
216 marcoReid: "Automated bank feeds, AI categorisation, real-time close.",
217 },
218 {
219 feature: "Multi-state compliance",
220 traditional: "Separate tracking per jurisdiction",
221 marcoReid: "AI handles every state automatically.",
222 },
223 {
224 feature: "Client visibility",
225 traditional: "Quarterly PDF reports, phone calls for updates",
226 marcoReid: "Live dashboard, 24/7 portal access, instant messaging.",
227 },
228 {
229 feature: "Deduction identification",
230 traditional: "Experience-dependent, varies by accountant",
231 marcoReid: "AI scans every transaction against current tax code.",
232 },
233 {
234 feature: "Document handling",
235 traditional: "Email attachments, shared drives, manual filing",
236 marcoReid: "Secure document vault with AI extraction and tagging.",
237 },
238];
239
240export default function FindAnAccountantPage() {
241 return (
242 <>
243 <SchemaMarkup schema={schema} />
244
245 {/* Hero */}
246 <section className="relative overflow-hidden bg-navy-500 pt-32 pb-20 sm:pt-40 sm:pb-28">
247 {/* Gradient orbs */}
248 <div
249 className="pointer-events-none absolute -top-40 -left-40 h-[500px] w-[500px] rounded-full bg-forest-500/20 blur-3xl"
250 aria-hidden="true"
251 />
252 <div
253 className="pointer-events-none absolute -bottom-20 -right-20 h-[400px] w-[400px] rounded-full bg-plum-500/15 blur-3xl"
254 aria-hidden="true"
255 />
256 <Container className="relative text-center">
257 <p className="text-xs font-medium uppercase tracking-widest text-forest-300">
258 Marco Reid Accountant Directory
259 </p>
260 <h1 className="mt-6 font-serif text-hero text-white">
261 Find the Right Accountant
262 <br />
263 for Your Business
264 </h1>
265 <p className="mx-auto mt-6 max-w-2xl text-xl leading-relaxed text-navy-200">
266 Marco Reid CPAs use the most advanced AI-powered accounting
267 technology ever built. When your accountant works with Marco Reid,
268 your business gets faster tax research, automated reconciliation,
269 and reporting transparency that traditional firms cannot match.
270 </p>
271 <div className="mt-10 flex justify-center gap-4">
272 <Button href="#how-it-works" size="lg" variant="secondary">
273 Find a CPA
274 </Button>
275 </div>
276 </Container>
277 </section>
278
279 {/* Why Choose a Marco Reid Accountant */}
280 <section
281 className="py-24 sm:py-36"
282 aria-label="Why choose a Marco Reid accountant"
283 >
284 <Container>
285 <Reveal>
286 <p className="text-center text-xs font-medium uppercase tracking-widest text-forest-600">
287 The Marco Reid difference
288 </p>
289 <h2 className="mt-6 text-center font-serif text-display text-navy-800">
290 Why choose a Marco Reid accountant.
291 </h2>
292 <p className="mx-auto mt-4 max-w-2xl text-center text-lg text-navy-400">
293 Every CPA on the Marco Reid platform works with AI tools that
294 transform how accounting is done. Here is what that means for
295 your business.
296 </p>
297 </Reveal>
298
299 <div className="mt-16 grid gap-6 sm:grid-cols-2">
300 {advantages.map((advantage, index) => (
301 <Reveal key={advantage.title} delay={0.05 * (index + 1)}>
302 <div className="rounded-xl border border-navy-100 bg-white p-8 shadow-card transition-all duration-300 hover:shadow-card-hover hover:-translate-y-0.5">
303 <div className="flex h-12 w-12 items-center justify-center rounded-lg bg-forest-50">
304 {advantage.icon}
305 </div>
306 <h3 className="mt-5 font-serif text-headline text-navy-700">
307 {advantage.title}
308 </h3>
309 <p className="mt-3 leading-relaxed text-navy-400">
310 {advantage.description}
311 </p>
312 </div>
313 </Reveal>
314 ))}
315 </div>
316 </Container>
317 </section>
318
319 <div className="mx-auto h-px max-w-sm bg-navy-100" />
320
321 {/* Service Areas */}
322 <section className="py-24 sm:py-36" aria-label="Service areas">
323 <Container>
324 <Reveal>
325 <p className="text-center text-xs font-medium uppercase tracking-widest text-forest-600">
326 Expertise across every discipline
327 </p>
328 <h2 className="mt-6 text-center font-serif text-display text-navy-800">
329 Service areas.
330 </h2>
331 <p className="mx-auto mt-4 max-w-2xl text-center text-lg text-navy-400">
332 Marco Reid CPAs cover every accounting discipline. Whether you
333 need a straightforward tax return or complex international
334 compliance, there is a professional on the platform with the
335 expertise you need.
336 </p>
337 </Reveal>
338
339 <div className="mt-16 grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
340 {serviceAreas.map((area) => (
341 <Reveal key={area.title} delay={0.05}>
342 <div className="rounded-xl border border-navy-100 bg-white p-6 shadow-card transition-all duration-300 hover:shadow-card-hover hover:-translate-y-0.5">
343 <h3 className="font-semibold text-navy-700">{area.title}</h3>
344 <p className="mt-2 text-sm leading-relaxed text-navy-400">
345 {area.description}
346 </p>
347 </div>
348 </Reveal>
349 ))}
350 </div>
351 </Container>
352 </section>
353
354 <div className="mx-auto h-px max-w-sm bg-navy-100" />
355
356 {/* How It Works */}
357 <section
358 id="how-it-works"
359 className="py-24 sm:py-36"
360 aria-label="How it works"
361 >
362 <Container>
363 <Reveal>
364 <p className="text-center text-xs font-medium uppercase tracking-widest text-forest-600">
365 Simple process
366 </p>
367 <h2 className="mt-6 text-center font-serif text-display text-navy-800">
368 How it works.
369 </h2>
370 </Reveal>
371
372 <div className="mx-auto mt-16 max-w-3xl space-y-6">
373 {steps.map((step, index) => (
374 <Reveal key={step.number} delay={0.1 * (index + 1)}>
375 <div className="flex gap-6 rounded-xl border border-navy-100 bg-white p-8 shadow-card">
376 <div className="flex h-14 w-14 shrink-0 items-center justify-center rounded-xl bg-navy-500">
377 <span className="font-serif text-xl font-bold text-white">
378 {step.number}
379 </span>
380 </div>
381 <div>
382 <h3 className="font-serif text-headline text-navy-700">
383 {step.title}
384 </h3>
385 <p className="mt-2 leading-relaxed text-navy-400">
386 {step.description}
387 </p>
388 </div>
389 </div>
390 </Reveal>
391 ))}
392 </div>
393 </Container>
394 </section>
395
396 <div className="mx-auto h-px max-w-sm bg-navy-100" />
397
398 {/* The Marco Reid Advantage — Comparison Table */}
399 <section
400 className="py-24 sm:py-36"
401 aria-label="Marco Reid advantage comparison"
402 >
403 <Container>
404 <Reveal>
405 <p className="text-center text-xs font-medium uppercase tracking-widest text-forest-600">
406 Side by side
407 </p>
408 <h2 className="mt-6 text-center font-serif text-display text-navy-800">
409 The Marco Reid advantage.
410 </h2>
411 <p className="mx-auto mt-4 max-w-2xl text-center text-lg text-navy-400">
412 See what changes when your accountant works with AI-powered
413 professional intelligence instead of legacy tools.
414 </p>
415 </Reveal>
416
417 <Reveal delay={0.1}>
418 <div className="mx-auto mt-16 max-w-4xl overflow-hidden rounded-xl border border-navy-100 bg-white shadow-card">
419 {/* Table header */}
420 <div className="grid grid-cols-3 border-b border-navy-100 bg-navy-50 px-6 py-4">
421 <p className="text-sm font-semibold text-navy-600">Feature</p>
422 <p className="text-sm font-semibold text-navy-400">
423 Traditional CPA
424 </p>
425 <p className="text-sm font-semibold text-forest-600">
426 Marco Reid CPA
427 </p>
428 </div>
429 {/* Table rows */}
430 {comparisonRows.map((row, index) => (
431 <div
432 key={row.feature}
433 className={`grid grid-cols-3 px-6 py-5 ${
434 index < comparisonRows.length - 1
435 ? "border-b border-navy-50"
436 : ""
437 }`}
438 >
439 <p className="pr-4 text-sm font-medium text-navy-700">
440 {row.feature}
441 </p>
442 <p className="pr-4 text-sm text-navy-400">
443 {row.traditional}
444 </p>
445 <p className="text-sm font-medium text-forest-600">
446 {row.marcoReid}
447 </p>
448 </div>
449 ))}
450 </div>
451 </Reveal>
452 </Container>
453 </section>
454
455 <div className="mx-auto h-px max-w-sm bg-navy-100" />
456
457 {/* CTA: Are You a CPA? */}
458 <section className="bg-navy-50 py-24 sm:py-36" aria-label="CPA signup">
459 <Container className="text-center">
460 <Reveal>
461 <p className="text-xs font-medium uppercase tracking-widest text-forest-600">
462 For accounting professionals
463 </p>
464 <h2 className="mt-6 font-serif text-display text-navy-800">
465 Are you a CPA?
466 </h2>
467 <p className="mx-auto mt-4 max-w-xl text-lg text-navy-400">
468 Join the platform that gives you your profession back. AI-powered
469 tax research, automated reconciliation, transparent client
470 portals, and the most advanced accounting intelligence ever built.
471 All in one subscription.
472 </p>
473 </Reveal>
474 <Reveal delay={0.1}>
475 <div className="mt-10 flex justify-center gap-4">
476 <Button href="/pricing" size="lg">
477 See pricing
478 </Button>
479 <Button href="/accounting" variant="secondary" size="lg">
480 Explore Accounting
481 </Button>
482 </div>
483 </Reveal>
484 </Container>
485 </section>
486
487 {/* AI Disclaimer */}
488 <section className="py-16" aria-label="AI disclaimer">
489 <Container>
490 <div className="mx-auto max-w-2xl">
491 <AiDisclaimer />
492 </div>
493 </Container>
494 </section>
495 </>
496 );
497}
Addedapp/(marketing)/oracle/page.tsx+379−0View fileUnifiedSplit
@@ -0,0 +1,379 @@
1import type { Metadata } from "next";
2import dynamic from "next/dynamic";
3import { BRAND } from "@/lib/constants";
4import Container from "@/app/components/shared/Container";
5import Button from "@/app/components/shared/Button";
6import SchemaMarkup from "@/app/components/shared/SchemaMarkup";
7import AiDisclaimer from "@/app/components/shared/AiDisclaimer";
8import Reveal from "@/app/components/effects/Reveal";
9
10const OracleMockup = dynamic(() => import("@/app/components/marketing/OracleMockup"));
11const MockupReveal = dynamic(() => import("@/app/components/effects/MockupReveal"));
12
13
14export const metadata: Metadata = {
15 title: "Marco \u2014 The Most Intelligent Legal and Accounting Research Engine Ever Built",
16 description:
17 "Cross-domain legal and accounting AI research. Every citation verified. Ask questions that span both disciplines. Tax codes, IRS rulings, case law, and regulations \u2014 the research engine nobody else can build.",
18};
19
20const schema = {
21 "@context": "https://schema.org",
22 "@type": "SoftwareApplication",
23 name: "Marco",
24 applicationCategory: "Research",
25 operatingSystem: "Web",
26 description: "Cross-domain legal and accounting AI research with mandatory citation verification. Public domain case law, statutes, tax codes, and regulations.",
27 url: `${BRAND.url}/oracle`,
28};
29
30export default function OraclePage() {
31 return (
32 <>
33 <SchemaMarkup schema={schema} />
34
35 {/* Hero */}
36 <section className="relative flex min-h-screen items-center justify-center overflow-hidden">
37 <Container className="relative text-center">
38 <p className="animate-fade-up text-xs font-medium uppercase tracking-widest text-plum-600 opacity-0">
39 Marco
40 </p>
41 <h1 className="mt-8 animate-fade-up-1 text-hero font-serif opacity-0">
42 <span className="text-navy-700">The most intelligent</span>
43 <br />
44 <span className="text-plum-500">research engine on the planet.</span>
45 </h1>
46 <p className="mx-auto mt-8 max-w-2xl animate-fade-up-2 text-xl leading-relaxed text-navy-400 opacity-0">
47 Cross-domain legal and accounting AI. Every citation verified against
48 authoritative public sources before you see it. Ask questions that span both
49 disciplines simultaneously. The research engine nobody else can build —
50 because nobody else owns both sides.
51 </p>
52 <div className="mt-12 animate-fade-up-3 opacity-0">
53 <Button href="/pricing" size="lg">See pricing</Button>
54 </div>
55 </Container>
56 <div className="absolute bottom-0 left-0 right-0 h-40 bg-linear-to-t from-white to-transparent" />
57 </section>
58
59 {/* Oracle mockup */}
60 <section className="py-20 sm:py-32" aria-label="Oracle preview">
61 <Container>
62 <MockupReveal className="mx-auto max-w-4xl">
63 <OracleMockup />
64 </MockupReveal>
65 </Container>
66 </section>
67
68 <div className="h-px bg-navy-100 mx-auto max-w-sm" />
69
70 {/* The killer workflow — Oracle draw-down */}
71 <section className="py-32 sm:py-44" aria-label="Marco draw-down">
72 <Container narrow>
73 <Reveal>
74 <p className="text-xs font-medium uppercase tracking-widest text-plum-600">
75 The killer workflow
76 </p>
77 <h2 className="mt-6 text-display font-serif text-navy-700">
78 Research without ever leaving your document.
79 </h2>
80 </Reveal>
81 <Reveal delay={0.1}>
82 <div className="mt-12 rounded-2xl border border-navy-100 bg-navy-50 p-8">
83 <p className="text-xs font-semibold tracking-widest text-red-600">Without Marco Reid</p>
84 <p className="mt-4 leading-relaxed text-navy-400">
85 You’re drafting a contract clause about non-compete enforceability.
86 Not sure about the California standard. Open a new tab. Go to Westlaw.
87 Log in. Search. Find the case. Copy the citation. Switch back to your document.
88 Paste it in. Reformat it. Five minutes. Your flow is destroyed.
89 </p>
90 </div>
91 </Reveal>
92 <Reveal delay={0.15}>
93 <div className="mt-4 rounded-2xl border border-purple-500/20 bg-plum-50 p-8">
94 <p className="text-xs font-semibold tracking-widest text-plum-600">With Marco</p>
95 <p className="mt-4 leading-relaxed text-navy-400">
96 You’re drafting. You hit  <span className="rounded bg-navy-100 px-2 py-0.5 font-mono text-sm text-plum-600">⌘K</span> .
97 Marco slides in from the right — you never leave the document.
98 You type “California non-compete enforceability standard.”
99 Three verified cases in under 3 seconds. You click “Insert citation.”
100 It drops directly into your document at the cursor position, formatted correctly,
101 citation verified with a ✓ badge.{" "}
102 <span className="font-semibold text-plum-600">Total time: 25 seconds. Flow never broken.</span>
103 </p>
104 </div>
105 </Reveal>
106 </Container>
107 </section>
108
109 <div className="h-px bg-navy-100 mx-auto max-w-sm" />
110
111 {/* Available everywhere */}
112 <section className="py-32 sm:py-44" aria-label="Available everywhere">
113 <Container>
114 <Reveal>
115 <p className="text-center text-xs font-medium uppercase tracking-widest text-plum-600">
116 Everywhere
117 </p>
118 <h2 className="mt-6 text-center text-display font-serif text-navy-700">
119 <span className="rounded bg-navy-100 px-3 py-1 font-mono text-forest-600">⌘K</span>
120 {" "}from anywhere. Instantly.
121 </h2>
122 </Reveal>
123 <div className="mx-auto mt-16 grid max-w-3xl gap-3 sm:grid-cols-2">
124 {[
125 { where: "Inside the Document Editor", what: "Research while drafting contracts, motions, and briefs" },
126 { where: "Inside Email", what: "Cite a case while responding to a client question" },
127 { where: "Inside Case Management", what: "Add research notes to any matter instantly" },
128 { where: "Inside Tax Filing", what: "Check a regulation mid-entry without switching tools" },
129 { where: "Inside Billing Notes", what: "Reference a precedent while logging time" },
130 { where: "As a Global Command", what: "⌘K from literally anywhere in the platform" },
131 ].map((item) => (
132 <Reveal key={item.where} delay={0.05}>
133 <div className="rounded-xl border border-navy-100 bg-white p-6 shadow-card transition-all duration-300 hover:shadow-card-hover hover:-translate-y-0.5">
134 <p className="font-semibold text-navy-700">{item.where}</p>
135 <p className="mt-2 text-sm text-navy-400">{item.what}</p>
136 </div>
137 </Reveal>
138 ))}
139 </div>
140 </Container>
141 </section>
142
143 <div className="h-px bg-navy-100 mx-auto max-w-sm" />
144
145 {/* Oracle for Accounting — the other half */}
146 <section className="py-32 sm:py-44 bg-navy-50" aria-label="Oracle for Accounting">
147 <Container>
148 <Reveal>
149 <div className="flex items-center gap-4">
150 <div className="flex h-12 w-12 items-center justify-center rounded-xl bg-forest-50">
151 <span className="text-xl">◇</span>
152 </div>
153 <div>
154 <p className="text-xs font-bold tracking-wider text-forest-600">
155 Marco — Accounting
156 </p>
157 <h2 className="font-serif text-display text-navy-800">
158 Tax research answered in seconds, not hours.
159 </h2>
160 </div>
161 </div>
162 </Reveal>
163
164 <Reveal delay={0.1}>
165 <p className="mt-6 max-w-2xl text-lg leading-relaxed text-navy-400">
166 Most accountants ring a taxation agent to verify what they’re doing is correct.
167 That call takes time. The answer takes longer. With Marco for Accounting,
168 every IRS code section, every revenue ruling, every regulatory citation is verified
169 against official sources and returned in seconds. The CPA never leaves their workflow.
170 </p>
171 </Reveal>
172
173 <div className="mt-16 grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
174 {[
175 { title: "IRS Code sections", desc: "Every section of the Internal Revenue Code searchable and verified against IRS.gov" },
176 { title: "Revenue rulings", desc: "IRS revenue rulings, procedures, and guidance documents with direct source links" },
177 { title: "Treasury regulations", desc: "Full Code of Federal Regulations coverage for tax provisions" },
178 { title: "State tax codes", desc: "50-state tax code coverage. State-specific rules returned alongside federal" },
179 { title: "GAAP & IFRS standards", desc: "Accounting standards referenced and cited correctly in every research result" },
180 { title: "Tax court decisions", desc: "US Tax Court opinions verified and linked to authoritative public sources" },
181 ].map((f) => (
182 <Reveal key={f.title} delay={0.05}>
183 <div className="rounded-xl border border-navy-100 bg-white p-6 shadow-card transition-all duration-300 hover:shadow-card-hover hover:-translate-y-0.5">
184 <h3 className="font-semibold text-navy-700">{f.title}</h3>
185 <p className="mt-2 text-sm leading-relaxed text-navy-400">{f.desc}</p>
186 </div>
187 </Reveal>
188 ))}
189 </div>
190
191 <Reveal delay={0.2}>
192 <div className="mt-12 rounded-xl bg-forest-50 border border-forest-200 p-8">
193 <p className="text-xs font-bold tracking-wider text-forest-600">Example query</p>
194 <p className="mt-4 font-serif text-headline text-navy-700 italic">
195 “What is the Section 199A qualified business income deduction threshold
196 for a married couple filing jointly in 2026?”
197 </p>
198 <p className="mt-4 text-sm leading-relaxed text-navy-400">
199 Marco returns the exact threshold, the relevant IRC section, the applicable
200 Treasury Regulation, and links to the official IRS source — all verified,
201 all cited, all in under 3 seconds. The CPA who used to spend 20 minutes searching
202 IRS.gov now has their answer before they finish their coffee.
203 </p>
204 </div>
205 </Reveal>
206 </Container>
207 </section>
208
209 <div className="h-px bg-navy-100 mx-auto max-w-sm" />
210
211 {/* Oracle for IP */}
212 <section className="py-32 sm:py-44" aria-label="Oracle for IP">
213 <Container>
214 <Reveal>
215 <div className="flex items-center gap-4">
216 <div className="flex h-12 w-12 items-center justify-center rounded-xl bg-navy-50">
217 <span className="text-xl">⚖</span>
218 </div>
219 <div>
220 <p className="text-xs font-bold tracking-wider text-navy-500">
221 Marco — Intellectual Property
222 </p>
223 <h2 className="font-serif text-display text-navy-800">
224 Patents. Trademarks. Copyright. Trade secrets.
225 </h2>
226 </div>
227 </div>
228 </Reveal>
229
230 <Reveal delay={0.1}>
231 <p className="mt-6 max-w-2xl text-lg leading-relaxed text-navy-400">
232 IP attorneys bill $500–$800/hour and do enormous amounts of research.
233 Marco for IP is a dedicated domain that understands patent claims,
234 trademark likelihood of confusion, prior art analysis, and IP case law.
235 And because IP work always has tax implications — licensing revenue,
236 IP holding entity structures, R&D credits — Marco spans
237 both IP law and accounting in a single query.
238 </p>
239 </Reveal>
240
241 <div className="mt-16 grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
242 {[
243 { title: "USPTO patent search", desc: "Search patent records, analyse claims, find prior art, track expiry and maintenance fees" },
244 { title: "Trademark search (TESS)", desc: "Likelihood of confusion analysis, monitoring for conflicting new filings, registration status" },
245 { title: "Copyright research", desc: "US Copyright Office records, fair use analysis grounded in case law, DMCA precedents" },
246 { title: "Trade secret law", desc: "State-by-state analysis of Uniform Trade Secrets Act adoption, misappropriation cases" },
247 { title: "IP case law", desc: "Infringement cases, licensing disputes, and trade secret misappropriation via CourtListener" },
248 { title: "WIPO international", desc: "International patent and trademark records via Madrid Protocol for global IP strategy" },
249 ].map((f) => (
250 <Reveal key={f.title} delay={0.05}>
251 <div className="rounded-xl border border-navy-100 bg-white p-6 shadow-card transition-all duration-300 hover:shadow-card-hover hover:-translate-y-0.5">
252 <h3 className="font-semibold text-navy-700">{f.title}</h3>
253 <p className="mt-2 text-sm leading-relaxed text-navy-400">{f.desc}</p>
254 </div>
255 </Reveal>
256 ))}
257 </div>
258 </Container>
259 </section>
260
261 <div className="h-px bg-navy-100 mx-auto max-w-sm" />
262
263 {/* Citation verification — dramatic */}
264 <section className="py-32 sm:py-44" aria-label="Citation verification">
265 <Container>
266 <Reveal>
267 <p className="text-center text-xs font-medium uppercase tracking-widest text-plum-600">
268 Zero hallucinations
269 </p>
270 <h2 className="mt-6 text-center text-display font-serif text-navy-700">
271 Every citation verified before you see it.
272 </h2>
273 <p className="mx-auto mt-6 max-w-2xl text-center text-lg text-navy-400">
274 In 2023, a New York attorney was sanctioned for submitting AI-fabricated citations to a federal court.
275 That will never happen on Marco Reid. Every case, every statute, every ruling is checked against
276 authoritative public domain sources before it reaches your screen.
277 </p>
278 </Reveal>
279
280 <div className="mt-16 grid gap-4 sm:grid-cols-3">
281 <Reveal delay={0.1}>
282 <div className="rounded-xl border border-navy-100 bg-white p-6 shadow-card text-center">
283 <p className="font-serif text-5xl text-forest-600">✓</p>
284 <p className="mt-4 text-lg font-semibold text-navy-700">Verified</p>
285 <p className="mt-2 text-sm text-navy-400">
286 Confirmed in authoritative source. Direct link provided. Safe to cite.
287 </p>
288 </div>
289 </Reveal>
290 <Reveal delay={0.2}>
291 <div className="rounded-xl border border-navy-100 bg-white p-6 shadow-card text-center">
292 <p className="font-serif text-5xl text-yellow-600">−</p>
293 <p className="mt-4 text-lg font-semibold text-navy-700">Unverified</p>
294 <p className="mt-2 text-sm text-navy-400">
295 Could not be confirmed. Flagged visibly. Do not rely without checking.
296 </p>
297 </div>
298 </Reveal>
299 <Reveal delay={0.3}>
300 <div className="rounded-xl border border-navy-100 bg-white p-6 shadow-card text-center">
301 <p className="font-serif text-5xl text-red-600">×</p>
302 <p className="mt-4 text-lg font-semibold text-navy-700">Not Found</p>
303 <p className="mt-2 text-sm text-navy-400">
304 Does not exist. Blocked from insertion into any document. Period.
305 </p>
306 </div>
307 </Reveal>
308 </div>
309 </Container>
310 </section>
311
312 <div className="h-px bg-navy-100 mx-auto max-w-sm" />
313
314 {/* The cross-domain moat */}
315 <section className="relative py-32 sm:py-44" aria-label="Cross-domain research">
316 <Container narrow className="relative">
317 <Reveal>
318 <p className="text-xs font-medium uppercase tracking-widest text-plum-600">
319 The moat
320 </p>
321 <h2 className="mt-6 text-display font-serif text-navy-700">
322 The product nobody else can build.
323 </h2>
324 </Reveal>
325 <Reveal delay={0.1}>
326 <p className="mt-8 text-xl italic leading-relaxed text-navy-400">
327 “What are the immigration tax implications of this corporate
328 structure for a Tier-1 visa applicant?”
329 </p>
330 </Reveal>
331 <Reveal delay={0.15}>
332 <p className="mt-6 text-xl leading-relaxed text-navy-400">
333 That query requires both legal research and tax intelligence simultaneously.
334 Westlaw can’t answer it. QuickBooks can’t answer it. Nobody else owns both
335 sides of the law-accounting boundary. Only Marco Reid can answer it — because
336 The Oracle spans both domains in a single search.
337 </p>
338 </Reveal>
339 <Reveal delay={0.2}>
340 <p className="mt-6 text-xl leading-relaxed text-navy-400">
341 This is not an incremental improvement. This is a category that did not exist
342 before Marco Reid created it.
343 </p>
344 </Reveal>
345 </Container>
346 </section>
347
348 {/* Disclaimer + CTA */}
349 <section className="py-16" aria-label="AI disclaimer">
350 <Container>
351 <div className="mx-auto max-w-2xl">
352 <AiDisclaimer />
353 </div>
354 </Container>
355 </section>
356
357 <section className="relative py-32 sm:py-44" aria-label="Get started">
358 <Container className="relative text-center">
359 <Reveal>
360 <h2 className="text-display font-serif text-plum-500">
361 Research without boundaries.
362 </h2>
363 </Reveal>
364 <Reveal delay={0.1}>
365 <p className="mt-6 text-xl text-navy-400">
366 Legal and accounting intelligence in one search. Every citation verified.
367 </p>
368 </Reveal>
369 <Reveal delay={0.2}>
370 <div className="mt-12 flex justify-center gap-4">
371 <Button href="/pricing" size="lg">See pricing</Button>
372 <Button href="/dictation" variant="secondary" size="lg">Explore Voice</Button>
373 </div>
374 </Reveal>
375 </Container>
376 </section>
377 </>
378 );
379}
Addedapp/(marketing)/resources/page.tsx+363−0View fileUnifiedSplit
@@ -0,0 +1,363 @@
1import type { Metadata } from "next";
2import Container from "@/app/components/shared/Container";
3import Button from "@/app/components/shared/Button";
4import SchemaMarkup from "@/app/components/shared/SchemaMarkup";
5import Reveal from "@/app/components/effects/Reveal";
6import { BRAND, AI_DISCLAIMER } from "@/lib/constants";
7
8export const metadata: Metadata = {
9 title: "Resources — Guides and Insights for Legal and Accounting Professionals",
10 description:
11 "Expert guides, practical insights, and tools for modern legal and accounting professionals. AI legal research, IOLTA compliance, voice dictation, courtroom technology, and more.",
12 keywords: [
13 "legal technology resources",
14 "AI for lawyers guide",
15 "accounting technology resources",
16 "IOLTA compliance guide",
17 "legal AI research",
18 "law firm technology",
19 "CPA technology tools",
20 "voice dictation for lawyers",
21 ],
22};
23
24const schema = {
25 "@context": "https://schema.org",
26 "@type": "WebPage",
27 name: "Marco Reid Resources",
28 description:
29 "Guides, insights, and tools for modern legal and accounting professionals.",
30 url: `${BRAND.url}/resources`,
31 publisher: {
32 "@type": "Organization",
33 name: BRAND.name,
34 url: BRAND.url,
35 },
36};
37
38const categories = [
39 "All",
40 "Legal Tech",
41 "Accounting Tech",
42 "AI in Practice",
43 "Practice Management",
44 "Compliance",
45] as const;
46
47interface Resource {
48 title: string;
49 description: string;
50 category: string;
51 readTime: string;
52 href: string;
53 badge?: "forest" | "plum";
54}
55
56const featuredGuides: Resource[] = [
57 {
58 title: "The Complete Guide to AI Legal Research in 2026",
59 description:
60 "How citation verification, hallucination prevention, and public domain sourcing are transforming legal research. Learn the methodology behind verified AI-assisted case law analysis and how to integrate it into your practice safely.",
61 category: "AI in Practice",
62 readTime: "18 min read",
63 href: "#ai-legal-research",
64 badge: "forest",
65 },
66 {
67 title: "IOLTA Trust Accounting: A 50-State Compliance Guide",
68 description:
69 "Every state has its own trust accounting rules. This guide covers three-way reconciliation requirements, common violations that lead to disciplinary action, and how modern software eliminates the manual errors that put licences at risk.",
70 category: "Compliance",
71 readTime: "24 min read",
72 href: "#iolta-compliance",
73 badge: "plum",
74 },
75 {
76 title: "AI-Powered Accounting: Moving Beyond QuickBooks",
77 description:
78 "Bank feeds, automated reconciliation, and AI-driven categorisation are replacing the manual bookkeeping workflows that have consumed accounting firms for decades. A practical roadmap for the transition.",
79 category: "Accounting Tech",
80 readTime: "15 min read",
81 href: "#ai-accounting",
82 badge: "forest",
83 },
84 {
85 title: "Voice Dictation for Legal Professionals",
86 description:
87 "Why 99%+ accuracy matters when every Latin phrase, statutory citation, and jurisdictional term carries legal weight. How professional-grade voice dictation in 9 languages is saving attorneys 15+ hours per week.",
88 category: "Legal Tech",
89 readTime: "12 min read",
90 href: "#voice-dictation",
91 badge: "plum",
92 },
93];
94
95const articles: Resource[] = [
96 {
97 title: "Understanding AI Citation Verification",
98 description:
99 "The Verified, Unverified, and Not Found badge system explained. How modern platforms prevent fabricated citations from reaching court filings, and why every attorney needs to understand the verification pipeline.",
100 category: "AI in Practice",
101 readTime: "10 min read",
102 href: "#citation-verification",
103 },
104 {
105 title: "Cross-Domain Intelligence: When Law Meets Accounting",
106 description:
107 "Immigration tax obligations, corporate formation with simultaneous entity structuring and chart of accounts setup, IP portfolio management with financial modelling. The cases where legal and accounting research must work together.",
108 category: "Practice Management",
109 readTime: "14 min read",
110 href: "#cross-domain",
111 },
112 {
113 title: "Courtroom Technology in 2026",
114 description:
115 "Electronic filing that works, evidence presentation systems, real-time AI transcription, and deposition management. How technology is transforming litigation from the courtroom floor to the judge's chambers.",
116 category: "Legal Tech",
117 readTime: "16 min read",
118 href: "#courtroom-tech",
119 },
120 {
121 title: "Data Privacy for Law Firms: GDPR and Beyond",
122 description:
123 "End-to-end encryption, data processing agreements, attorney-client privilege in the cloud, and the breach notification timelines every firm must know. A practical guide to privacy compliance in 2026.",
124 category: "Compliance",
125 readTime: "13 min read",
126 href: "#data-privacy",
127 },
128 {
129 title: "How Voice Dictation Saves 15+ Hours Per Week",
130 description:
131 "Real time-savings data from professional workflows: document drafting, case notes, billing entries, client correspondence. The maths behind the claim, and how to measure it in your own practice.",
132 category: "Practice Management",
133 readTime: "8 min read",
134 href: "#voice-time-savings",
135 },
136 {
137 title: "The True Cost of Fragmented Legal Software",
138 description:
139 "The average attorney uses 7 to 10 tools that do not talk to each other. Total cost of ownership analysis, context-switching penalties, and the hidden expense of manual data re-entry across disconnected systems.",
140 category: "Practice Management",
141 readTime: "11 min read",
142 href: "#fragmented-software",
143 },
144 {
145 title: "Building a Citation Verification Workflow",
146 description:
147 "Step-by-step guide to establishing a citation verification process using public domain sources like CourtListener, Cornell LII, and GovInfo. Protect your firm from the sanctions that follow fabricated case law.",
148 category: "AI in Practice",
149 readTime: "9 min read",
150 href: "#verification-workflow",
151 },
152 {
153 title: "Tax Compliance Automation for CPA Firms",
154 description:
155 "Federal and state tax preparation, filing status management, deadline tracking, and the AI-assisted workflows that are replacing the spreadsheet-driven compliance processes most firms still rely on.",
156 category: "Accounting Tech",
157 readTime: "12 min read",
158 href: "#tax-compliance",
159 },
160];
161
162function CategoryBadge({ category }: { category: string }) {
163 const colours: Record<string, string> = {
164 "Legal Tech": "bg-forest-50 text-forest-600",
165 "Accounting Tech": "bg-plum-50 text-plum-600",
166 "AI in Practice": "bg-forest-50 text-forest-600",
167 "Practice Management": "bg-navy-50 text-navy-500",
168 Compliance: "bg-plum-50 text-plum-600",
169 };
170
171 return (
172 <span
173 className={`inline-block rounded-full px-3 py-1 text-xs font-bold ${
174 colours[category] ?? "bg-navy-50 text-navy-500"
175 }`}
176 >
177 {category}
178 </span>
179 );
180}
181
182export default function ResourcesPage() {
183 return (
184 <>
185 <SchemaMarkup schema={schema} />
186
187 {/* ── Hero ── */}
188 <section className="bg-navy-500 pt-32 pb-20 sm:pt-40 sm:pb-28">
189 <Container className="text-center">
190 <p className="text-sm font-semibold tracking-wider text-forest-300">
191 Resources
192 </p>
193 <h1 className="mt-6 font-serif text-hero text-white">
194 Guides, insights, and tools
195 <br />
196 for modern professionals.
197 </h1>
198 <p className="mx-auto mt-6 max-w-xl text-xl text-navy-200">
199 Deep-dive guides on AI legal research, trust accounting compliance,
200 voice dictation, courtroom technology, and everything else
201 transforming law and accounting in 2026.
202 </p>
203 </Container>
204 </section>
205
206 {/* ── Category filter ── */}
207 <section className="border-b border-navy-100 bg-white py-6">
208 <Container>
209 <div className="flex flex-wrap items-center gap-2" role="list" aria-label="Resource categories">
210 {categories.map((cat) => (
211 <span
212 key={cat}
213 role="listitem"
214 className={`cursor-pointer rounded-full px-4 py-2 text-sm font-semibold transition-colors duration-200 ${
215 cat === "All"
216 ? "bg-navy-500 text-white"
217 : "bg-navy-50 text-navy-500 hover:bg-navy-100"
218 }`}
219 >
220 {cat}
221 </span>
222 ))}
223 </div>
224 </Container>
225 </section>
226
227 {/* ── Featured guides ── */}
228 <section className="py-24 sm:py-36" aria-label="Featured guides">
229 <Container>
230 <Reveal>
231 <h2 className="font-serif text-display text-navy-800">
232 Featured guides.
233 </h2>
234 <p className="mt-4 text-lg text-navy-400">
235 Comprehensive resources on the topics that matter most to legal
236 and accounting professionals.
237 </p>
238 </Reveal>
239
240 <div className="mt-16 grid gap-6 sm:grid-cols-2">
241 {featuredGuides.map((guide, i) => (
242 <Reveal key={guide.href} delay={0.05 * (i + 1)}>
243 <a
244 href={guide.href}
245 className="group flex h-full flex-col rounded-xl border border-navy-100 bg-white p-6 shadow-card transition-all duration-300 hover:shadow-card-hover hover:-translate-y-0.5"
246 >
247 <div className="flex items-center justify-between gap-3">
248 <CategoryBadge category={guide.category} />
249 <span className="text-xs font-medium text-navy-300">
250 {guide.readTime}
251 </span>
252 </div>
253 <h3 className="mt-4 font-serif text-xl text-navy-800 group-hover:text-forest-600 transition-colors duration-200">
254 {guide.title}
255 </h3>
256 <p className="mt-3 flex-1 text-sm leading-relaxed text-navy-400">
257 {guide.description}
258 </p>
259 <p className="mt-5 text-sm font-semibold text-forest-600">
260 Read guide →
261 </p>
262 </a>
263 </Reveal>
264 ))}
265 </div>
266 </Container>
267 </section>
268
269 <div className="mx-auto max-w-6xl px-6 sm:px-8 lg:px-12">
270 <div className="h-px bg-navy-100" />
271 </div>
272
273 {/* ── Articles grid ── */}
274 <section className="py-24 sm:py-36" aria-label="All articles">
275 <Container>
276 <Reveal>
277 <h2 className="font-serif text-display text-navy-800">
278 All articles.
279 </h2>
280 <p className="mt-4 text-lg text-navy-400">
281 Practical insights on technology, compliance, and workflows for
282 law firms and accounting practices.
283 </p>
284 </Reveal>
285
286 <div className="mt-16 grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
287 {articles.map((article, i) => (
288 <Reveal key={article.href} delay={0.04 * (i + 1)}>
289 <a
290 href={article.href}
291 className="group flex h-full flex-col rounded-xl border border-navy-100 bg-white p-6 shadow-card transition-all duration-300 hover:shadow-card-hover hover:-translate-y-0.5"
292 >
293 <div className="flex items-center justify-between gap-3">
294 <CategoryBadge category={article.category} />
295 <span className="text-xs font-medium text-navy-300">
296 {article.readTime}
297 </span>
298 </div>
299 <h3 className="mt-4 font-semibold text-navy-800 group-hover:text-forest-600 transition-colors duration-200">
300 {article.title}
301 </h3>
302 <p className="mt-3 flex-1 text-sm leading-relaxed text-navy-400">
303 {article.description}
304 </p>
305 <p className="mt-5 text-sm font-semibold text-forest-600">
306 Read article →
307 </p>
308 </a>
309 </Reveal>
310 ))}
311 </div>
312 </Container>
313 </section>
314
315 {/* ── AI disclaimer ── */}
316 <section className="bg-navy-50 py-16" aria-label="AI disclaimer">
317 <Container narrow>
318 <Reveal>
319 <div className="rounded-xl border border-navy-100 bg-white p-6 shadow-card">
320 <div className="flex items-start gap-3">
321 <span
322 className="mt-0.5 shrink-0 rounded-full bg-plum-50 px-3 py-1 text-xs font-bold text-plum-600"
323 aria-hidden="true"
324 >
325 AI Disclosure
326 </span>
327 </div>
328 <p className="mt-4 text-sm leading-relaxed text-navy-400">
329 {AI_DISCLAIMER}
330 </p>
331 </div>
332 </Reveal>
333 </Container>
334 </section>
335
336 {/* ── CTA ── */}
337 <section className="py-24 sm:py-36" aria-label="Get started">
338 <Container className="text-center">
339 <Reveal>
340 <h2 className="font-serif text-display text-navy-800">
341 Ready to transform your practice?
342 </h2>
343 <p className="mx-auto mt-4 max-w-lg text-lg text-navy-400">
344 {BRAND.name} gives legal and accounting professionals every tool
345 they need in one platform. See what it costs — or ask Marco
346 anything.
347 </p>
348 </Reveal>
349 <Reveal delay={0.1}>
350 <div className="mt-10 flex flex-wrap justify-center gap-4">
351 <Button href="/pricing" size="lg">
352 View pricing
353 </Button>
354 <Button href="/marco" variant="secondary" size="lg">
355 Try Marco
356 </Button>
357 </div>
358 </Reveal>
359 </Container>
360 </section>
361 </>
362 );
363}
Addedapp/(platform)/marco/page.tsx+21−0View fileUnifiedSplit
@@ -0,0 +1,21 @@
1import MarcoChat from "@/app/components/marco/MarcoChat";
2
3export const metadata = {
4 title: "Marco — Marco Reid",
5 description:
6 "Ask Marco anything. Cross-domain legal and accounting research with verified citations.",
7};
8
9export default function MarcoPage() {
10 return (
11 <div className="mx-auto max-w-5xl px-6 py-12 sm:px-8 lg:px-12">
12 <div className="mb-8">
13 <h1 className="font-serif text-display text-navy-800">Marco</h1>
14 <p className="mt-2 text-lg text-navy-400">
15 The greatest AI-generated mind for law and accountancy.
16 </p>
17 </div>
18 <MarcoChat />
19 </div>
20 );
21}
Addedapp/api/oracle/feedback/route.ts+86−0View fileUnifiedSplit
@@ -0,0 +1,86 @@
1import { NextResponse } from "next/server";
2import { getServerSession } from "next-auth";
3import { authOptions } from "@/lib/auth";
4import { prisma } from "@/lib/prisma";
5
6export async function POST(request: Request) {
7 try {
8 const session = await getServerSession(authOptions);
9
10 if (!session?.user) {
11 return NextResponse.json(
12 { error: "Authentication required." },
13 { status: 401 }
14 );
15 }
16
17 const { queryId, rating, helpful, accurate, comment } =
18 await request.json();
19
20 if (!queryId || !rating) {
21 return NextResponse.json(
22 { error: "Query ID and rating are required." },
23 { status: 400 }
24 );
25 }
26
27 if (rating < 1 || rating > 5) {
28 return NextResponse.json(
29 { error: "Rating must be between 1 and 5." },
30 { status: 400 }
31 );
32 }
33
34 const userId = session.user.id;
35
36 // Save feedback
37 const feedback = await prisma.oracleFeedback.create({
38 data: {
39 queryId,
40 userId,
41 rating,
42 helpful,
43 accurate,
44 comment,
45 },
46 });
47
48 // Update query pattern average rating (flywheel learning)
49 const query = await prisma.oracleQuery.findUnique({
50 where: { id: queryId },
51 select: { query: true, domain: true },
52 });
53
54 if (query) {
55 const normalised = query.query.toLowerCase().trim().substring(0, 200);
56 const allFeedback = await prisma.oracleFeedback.findMany({
57 where: {
58 query: {
59 query: { startsWith: normalised.substring(0, 50) },
60 },
61 },
62 select: { rating: true },
63 });
64
65 const avgRating =
66 allFeedback.reduce((sum, f) => sum + f.rating, 0) /
67 allFeedback.length;
68
69 await prisma.queryPattern.updateMany({
70 where: { pattern: normalised, domain: query.domain },
71 data: { avgRating },
72 });
73 }
74
75 return NextResponse.json({
76 message: "Feedback recorded. Thank you.",
77 feedbackId: feedback.id,
78 });
79 } catch (error) {
80 console.error("Oracle feedback error:", error);
81 return NextResponse.json(
82 { error: "Something went wrong." },
83 { status: 500 }
84 );
85 }
86}
Addedapp/api/oracle/query/route.ts+46−0View fileUnifiedSplit
@@ -0,0 +1,46 @@
1import { NextResponse } from "next/server";
2import { getServerSession } from "next-auth";
3import { authOptions } from "@/lib/auth";
4import { queryOracle } from "@/lib/oracle/engine";
5import { OracleRequest } from "@/lib/oracle/types";
6
7export async function POST(request: Request) {
8 try {
9 const session = await getServerSession(authOptions);
10
11 if (!session?.user) {
12 return NextResponse.json(
13 { error: "Authentication required." },
14 { status: 401 }
15 );
16 }
17
18 const body: OracleRequest = await request.json();
19
20 if (!body.query || body.query.trim().length === 0) {
21 return NextResponse.json(
22 { error: "Query cannot be empty." },
23 { status: 400 }
24 );
25 }
26
27 if (body.query.length > 2000) {
28 return NextResponse.json(
29 { error: "Query too long. Maximum 2000 characters." },
30 { status: 400 }
31 );
32 }
33
34 const userId = session.user.id;
35
36 const result = await queryOracle(userId, body);
37
38 return NextResponse.json(result);
39 } catch (error) {
40 console.error("Oracle query error:", error);
41 return NextResponse.json(
42 { error: "Something went wrong. Please try again." },
43 { status: 500 }
44 );
45 }
46}
Addedapp/components/marco/CommandPalette.tsx+651−0View fileUnifiedSplit
@@ -0,0 +1,651 @@
1"use client";
2
3import { useState, useEffect, useRef, useCallback } from "react";
4import type {
5 OracleDomain,
6 OracleCitationResult,
7 VerificationStatus,
8} from "@/lib/oracle/types";
9import { AI_DISCLAIMER } from "@/lib/constants";
10
11/* ── Props ─────────────────────────────────────────────────────── */
12
13interface CommandPaletteProps {
14 onInsertCitation?: (citation: string) => void;
15 className?: string;
16}
17
18/* ── Constants ─────────────────────────────────────────────────── */
19
20const DOMAIN_OPTIONS: { value: OracleDomain; label: string }[] = [
21 { value: "LEGAL", label: "Legal" },
22 { value: "ACCOUNTING", label: "Accounting" },
23 { value: "CROSS_DOMAIN", label: "Cross-Domain" },
24 { value: "IP", label: "IP" },
25];
26
27interface QuickAction {
28 label: string;
29 query: string;
30 domain: OracleDomain;
31 icon: React.ReactNode;
32}
33
34const QUICK_ACTIONS: QuickAction[] = [
35 {
36 label: "Search case law...",
37 query: "Search case law: ",
38 domain: "LEGAL",
39 icon: (
40 <svg
41 className="h-4 w-4"
42 viewBox="0 0 24 24"
43 fill="none"
44 stroke="currentColor"
45 strokeWidth="2"
46 strokeLinecap="round"
47 strokeLinejoin="round"
48 aria-hidden="true"
49 >
50 <circle cx="11" cy="11" r="8" />
51 <path d="M21 21l-4.35-4.35" />
52 </svg>
53 ),
54 },
55 {
56 label: "Look up IRC section...",
57 query: "IRC Section ",
58 domain: "ACCOUNTING",
59 icon: (
60 <svg
61 className="h-4 w-4"
62 viewBox="0 0 24 24"
63 fill="none"
64 stroke="currentColor"
65 strokeWidth="2"
66 strokeLinecap="round"
67 strokeLinejoin="round"
68 aria-hidden="true"
69 >
70 <path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z" />
71 <polyline points="14 2 14 8 20 8" />
72 <line x1="16" y1="13" x2="8" y2="13" />
73 <line x1="16" y1="17" x2="8" y2="17" />
74 <polyline points="10 9 9 9 8 9" />
75 </svg>
76 ),
77 },
78 {
79 label: "Check trademark availability...",
80 query: "Trademark search: ",
81 domain: "IP",
82 icon: (
83 <svg
84 className="h-4 w-4"
85 viewBox="0 0 24 24"
86 fill="none"
87 stroke="currentColor"
88 strokeWidth="2"
89 strokeLinecap="round"
90 strokeLinejoin="round"
91 aria-hidden="true"
92 >
93 <path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" />
94 </svg>
95 ),
96 },
97 {
98 label: "Find accounting standard...",
99 query: "Accounting standard: ",
100 domain: "ACCOUNTING",
101 icon: (
102 <svg
103 className="h-4 w-4"
104 viewBox="0 0 24 24"
105 fill="none"
106 stroke="currentColor"
107 strokeWidth="2"
108 strokeLinecap="round"
109 strokeLinejoin="round"
110 aria-hidden="true"
111 >
112 <rect x="2" y="3" width="20" height="18" rx="2" ry="2" />
113 <line x1="8" y1="7" x2="16" y2="7" />
114 <line x1="8" y1="11" x2="16" y2="11" />
115 <line x1="8" y1="15" x2="12" y2="15" />
116 </svg>
117 ),
118 },
119 {
120 label: "Voice input",
121 query: "",
122 domain: "CROSS_DOMAIN",
123 icon: (
124 <svg
125 className="h-4 w-4"
126 viewBox="0 0 24 24"
127 fill="none"
128 stroke="currentColor"
129 strokeWidth="2"
130 strokeLinecap="round"
131 strokeLinejoin="round"
132 aria-hidden="true"
133 >
134 <path d="M12 1a3 3 0 00-3 3v8a3 3 0 006 0V4a3 3 0 00-3-3z" />
135 <path d="M19 10v2a7 7 0 01-14 0v-2" />
136 <line x1="12" y1="19" x2="12" y2="23" />
137 <line x1="8" y1="23" x2="16" y2="23" />
138 </svg>
139 ),
140 },
141];
142
143const RECENT_QUERIES = [
144 "California non-compete enforceability for tech employees",
145 "Section 199A QBI deduction threshold 2026",
146 "Immigration tax implications of H-1B LLC formation",
147 "GAAP revenue recognition for SaaS contracts",
148 "Trademark registration timeline and costs",
149];
150
151const VERIFICATION_BADGE: Record<
152 VerificationStatus,
153 { icon: string; label: string; classes: string }
154> = {
155 VERIFIED: {
156 icon: "\u2713",
157 label: "VERIFIED",
158 classes:
159 "bg-forest-50 text-forest-700 border-forest-200",
160 },
161 UNVERIFIED: {
162 icon: "\u26A0",
163 label: "UNVERIFIED",
164 classes: "bg-amber-50 text-amber-600 border-amber-200",
165 },
166 NOT_FOUND: {
167 icon: "\u2717",
168 label: "NOT FOUND",
169 classes: "bg-red-50 text-red-600 border-red-200",
170 },
171};
172
173/* ── Mock results for demo until Oracle API integration ────────── */
174
175const MOCK_RESULTS: OracleCitationResult[] = [
176 {
177 title: "Edwards v. Arthur Andersen LLP",
178 citation: "44 Cal.4th 937 (2008)",
179 sourceUrl: "https://www.courtlistener.com/opinion/edwards-v-arthur-andersen",
180 sourceDb: "CourtListener",
181 status: "VERIFIED",
182 excerpt:
183 "California Business and Professions Code section 16600 voids any contract that restrains anyone from engaging in a lawful profession, trade, or business. Non-compete agreements are generally unenforceable in California.",
184 jurisdiction: "California",
185 dateDecided: "2008-08-07",
186 },
187 {
188 title: "The Retirement Group v. Galante",
189 citation: "176 Cal.App.4th 1226 (2009)",
190 sourceUrl: "https://www.courtlistener.com/opinion/retirement-group-v-galante",
191 sourceDb: "CourtListener",
192 status: "VERIFIED",
193 excerpt:
194 "The court reinforced that California public policy strongly favours open competition and employee mobility, invalidating broad non-solicitation provisions that function as de facto non-competes.",
195 jurisdiction: "California",
196 dateDecided: "2009-08-17",
197 },
198 {
199 title: "Brown v. TechCorp Inc.",
200 citation: "No. 2:23-cv-04821 (C.D. Cal. 2024)",
201 sourceUrl: null,
202 sourceDb: "None",
203 status: "UNVERIFIED",
204 excerpt:
205 "Recent district court ruling applying Edwards to remote workers who signed non-compete agreements in other states but performed work primarily in California.",
206 jurisdiction: "California",
207 dateDecided: "2024-03-15",
208 },
209];
210
211/* ── Component ─────────────────────────────────────────────────── */
212
213export default function CommandPalette({
214 onInsertCitation,
215 className = "",
216}: CommandPaletteProps) {
217 const [isOpen, setIsOpen] = useState(false);
218 const [query, setQuery] = useState("");
219 const [selectedDomain, setSelectedDomain] =
220 useState<OracleDomain>("CROSS_DOMAIN");
221 const [isLoading, setIsLoading] = useState(false);
222 const [results, setResults] = useState<OracleCitationResult[]>([]);
223 const [hasSearched, setHasSearched] = useState(false);
224
225 const overlayRef = useRef<HTMLDivElement>(null);
226 const inputRef = useRef<HTMLInputElement>(null);
227 const dialogRef = useRef<HTMLDivElement>(null);
228
229 /* ── Keyboard shortcut: Cmd+K / Ctrl+K ──────────────────────── */
230
231 useEffect(() => {
232 function handleKeyDown(e: KeyboardEvent) {
233 if ((e.metaKey || e.ctrlKey) && e.key === "k") {
234 e.preventDefault();
235 setIsOpen((prev) => !prev);
236 }
237 }
238 window.addEventListener("keydown", handleKeyDown);
239 return () => window.removeEventListener("keydown", handleKeyDown);
240 }, []);
241
242 /* ── Focus input when opening ────────────────────────────────── */
243
244 useEffect(() => {
245 if (isOpen) {
246 // Small delay to allow the animation to start before focusing
247 const timeout = setTimeout(() => inputRef.current?.focus(), 50);
248 return () => clearTimeout(timeout);
249 }
250 // Reset state when closing
251 setQuery("");
252 setResults([]);
253 setHasSearched(false);
254 setIsLoading(false);
255 }, [isOpen]);
256
257 /* ── Focus trap within the palette ──────────────────────────── */
258
259 useEffect(() => {
260 if (!isOpen) return;
261
262 function handleTab(e: KeyboardEvent) {
263 if (e.key !== "Tab" || !dialogRef.current) return;
264
265 const focusable = dialogRef.current.querySelectorAll<HTMLElement>(
266 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
267 );
268 if (focusable.length === 0) return;
269
270 const first = focusable[0];
271 const last = focusable[focusable.length - 1];
272
273 if (e.shiftKey && document.activeElement === first) {
274 e.preventDefault();
275 last.focus();
276 } else if (!e.shiftKey && document.activeElement === last) {
277 e.preventDefault();
278 first.focus();
279 }
280 }
281
282 window.addEventListener("keydown", handleTab);
283 return () => window.removeEventListener("keydown", handleTab);
284 }, [isOpen]);
285
286 /* ── Close handlers ──────────────────────────────────────────── */
287
288 const close = useCallback(() => setIsOpen(false), []);
289
290 useEffect(() => {
291 if (!isOpen) return;
292 function handleEsc(e: KeyboardEvent) {
293 if (e.key === "Escape") close();
294 }
295 window.addEventListener("keydown", handleEsc);
296 return () => window.removeEventListener("keydown", handleEsc);
297 }, [isOpen, close]);
298
299 function handleOverlayClick(e: React.MouseEvent) {
300 if (e.target === overlayRef.current) close();
301 }
302
303 /* ── Search handler (mock until Oracle API) ──────────────────── */
304
305 async function handleSearch(e: React.FormEvent) {
306 e.preventDefault();
307 const trimmed = query.trim();
308 if (!trimmed || isLoading) return;
309
310 setIsLoading(true);
311 setHasSearched(true);
312 setResults([]);
313
314 // Simulate Oracle API latency (sub-3-second target)
315 await new Promise((resolve) => setTimeout(resolve, 1400));
316
317 setResults(MOCK_RESULTS);
318 setIsLoading(false);
319 }
320
321 /* ── Insert citation ─────────────────────────────────────────── */
322
323 function handleInsertCitation(citation: OracleCitationResult) {
324 const formatted = `${citation.title}, ${citation.citation}`;
325 onInsertCitation?.(formatted);
326 close();
327 }
328
329 /* ── Quick action click ──────────────────────────────────────── */
330
331 function handleQuickAction(action: QuickAction) {
332 if (action.label === "Voice input") {
333 // Voice input will be handled by Marco Reid Voice integration
334 return;
335 }
336 setQuery(action.query);
337 setSelectedDomain(action.domain);
338 inputRef.current?.focus();
339 }
340
341 /* ── Recent query click ──────────────────────────────────────── */
342
343 function handleRecentQuery(q: string) {
344 setQuery(q);
345 inputRef.current?.focus();
346 }
347
348 /* ── Render ──────────────────────────────────────────────────── */
349
350 if (!isOpen) return null;
351
352 const showEmptyState = !query.trim() && !hasSearched;
353
354 return (
355 <div
356 ref={overlayRef}
357 className={`fixed inset-0 z-50 flex items-start justify-center pt-[12vh] ${className}`}
358 onClick={handleOverlayClick}
359 role="presentation"
360 >
361 {/* Backdrop */}
362 <div
363 className="absolute inset-0 bg-navy-900/60 backdrop-blur-sm animate-[fadeIn_0.15s_ease-out]"
364 aria-hidden="true"
365 />
366
367 {/* Dialog */}
368 <div
369 ref={dialogRef}
370 role="dialog"
371 aria-modal="true"
372 aria-label="Command palette — Ask Marco anything"
373 className="relative z-10 w-full max-w-2xl animate-[fadeUp_0.2s_ease-out] rounded-2xl border border-white/10 bg-white/95 shadow-mockup backdrop-blur-xl"
374 style={{
375 background:
376 "linear-gradient(135deg, rgba(255,255,255,0.97) 0%, rgba(245,246,248,0.97) 100%)",
377 }}
378 >
379 {/* ── Header / Search ─────────────────────────────────── */}
380 <form onSubmit={handleSearch} className="relative">
381 <div className="flex items-center border-b border-navy-100 px-5">
382 {/* Search icon */}
383 <svg
384 className="mr-3 h-5 w-5 shrink-0 text-navy-300"
385 viewBox="0 0 24 24"
386 fill="none"
387 stroke="currentColor"
388 strokeWidth="2"
389 strokeLinecap="round"
390 strokeLinejoin="round"
391 aria-hidden="true"
392 >
393 <circle cx="11" cy="11" r="8" />
394 <path d="M21 21l-4.35-4.35" />
395 </svg>
396
397 <input
398 ref={inputRef}
399 type="text"
400 value={query}
401 onChange={(e) => setQuery(e.target.value)}
402 placeholder="Ask Marco anything..."
403 className="min-h-touch flex-1 bg-transparent py-4 text-base text-navy-700 placeholder:text-navy-300 focus:outline-none"
404 autoComplete="off"
405 spellCheck={false}
406 aria-label="Search query"
407 />
408
409 {/* Keyboard shortcut badge */}
410 <kbd className="ml-3 hidden shrink-0 rounded-md border border-navy-200 bg-navy-50 px-2 py-1 font-sans text-[11px] font-medium text-navy-400 sm:inline-block">
411 esc
412 </kbd>
413 </div>
414 </form>
415
416 {/* ── Domain selector pills ───────────────────────────── */}
417 <div className="flex items-center gap-2 border-b border-navy-100 px-5 py-3">
418 <span className="text-[11px] font-medium uppercase tracking-wider text-navy-400">
419 Domain
420 </span>
421 <div className="flex gap-1.5" role="radiogroup" aria-label="Search domain">
422 {DOMAIN_OPTIONS.map((opt) => (
423 <button
424 key={opt.value}
425 type="button"
426 role="radio"
427 aria-checked={selectedDomain === opt.value}
428 onClick={() => setSelectedDomain(opt.value)}
429 className={`min-h-touch rounded-full px-3 py-1.5 text-xs font-semibold transition-all duration-150 ${
430 selectedDomain === opt.value
431 ? "bg-navy-500 text-white shadow-sm"
432 : "bg-navy-50 text-navy-500 hover:bg-navy-100"
433 }`}
434 >
435 {opt.label}
436 </button>
437 ))}
438 </div>
439 </div>
440
441 {/* ── Body ────────────────────────────────────────────── */}
442 <div
443 className="overflow-y-auto px-5 py-4"
444 style={{ maxHeight: "50vh" }}
445 >
446 {/* Empty state — recent queries + quick actions */}
447 {showEmptyState && (
448 <div className="space-y-6">
449 {/* Recent queries */}
450 <div>
451 <h3 className="mb-2 text-[11px] font-semibold uppercase tracking-wider text-navy-400">
452 Recent queries
453 </h3>
454 <ul className="space-y-1">
455 {RECENT_QUERIES.map((rq) => (
456 <li key={rq}>
457 <button
458 type="button"
459 onClick={() => handleRecentQuery(rq)}
460 className="flex min-h-touch w-full items-center gap-3 rounded-lg px-3 py-2.5 text-left text-sm text-navy-600 transition-colors hover:bg-navy-50"
461 >
462 <svg
463 className="h-4 w-4 shrink-0 text-navy-300"
464 viewBox="0 0 24 24"
465 fill="none"
466 stroke="currentColor"
467 strokeWidth="2"
468 strokeLinecap="round"
469 strokeLinejoin="round"
470 aria-hidden="true"
471 >
472 <circle cx="12" cy="12" r="10" />
473 <polyline points="12 6 12 12 16 14" />
474 </svg>
475 <span className="truncate">{rq}</span>
476 </button>
477 </li>
478 ))}
479 </ul>
480 </div>
481
482 {/* Quick actions */}
483 <div>
484 <h3 className="mb-2 text-[11px] font-semibold uppercase tracking-wider text-navy-400">
485 Quick actions
486 </h3>
487 <div className="grid grid-cols-1 gap-1.5 sm:grid-cols-2">
488 {QUICK_ACTIONS.map((action) => (
489 <button
490 key={action.label}
491 type="button"
492 onClick={() => handleQuickAction(action)}
493 className="flex min-h-touch items-center gap-3 rounded-lg border border-navy-100 bg-white px-4 py-3 text-left text-sm text-navy-600 shadow-card transition-all duration-150 hover:border-navy-200 hover:bg-navy-50 hover:shadow-card-hover"
494 >
495 <span className="shrink-0 text-navy-400">
496 {action.icon}
497 </span>
498 <span className="font-medium">{action.label}</span>
499 </button>
500 ))}
501 </div>
502 </div>
503 </div>
504 )}
505
506 {/* Loading state */}
507 {isLoading && (
508 <div className="flex flex-col items-center justify-center py-12">
509 <div className="flex items-center gap-3">
510 <div className="flex gap-1">
511 <div className="h-2 w-2 animate-bounce rounded-full bg-navy-400 [animation-delay:-0.3s]" />
512 <div className="h-2 w-2 animate-bounce rounded-full bg-navy-400 [animation-delay:-0.15s]" />
513 <div className="h-2 w-2 animate-bounce rounded-full bg-navy-400" />
514 </div>
515 <span className="text-sm text-navy-500">
516 Marco is researching
517 <span className="typing-cursor ml-0.5 inline-block h-4 w-0.5 bg-navy-500" />
518 </span>
519 </div>
520 <p className="mt-3 text-xs text-navy-400">
521 Searching authoritative public domain sources...
522 </p>
523 </div>
524 )}
525
526 {/* Results */}
527 {!isLoading && hasSearched && results.length > 0 && (
528 <div className="space-y-4">
529 <div className="flex items-center justify-between">
530 <h3 className="text-[11px] font-semibold uppercase tracking-wider text-navy-400">
531 {results.length} citation{results.length === 1 ? "" : "s"}{" "}
532 found
533 </h3>
534 <span className="rounded-full bg-plum-50 px-2.5 py-0.5 text-[10px] font-bold uppercase tracking-wider text-plum-600">
535 {DOMAIN_OPTIONS.find((d) => d.value === selectedDomain)?.label}
536 </span>
537 </div>
538
539 <ul className="space-y-3">
540 {results.map((result, idx) => {
541 const badge = VERIFICATION_BADGE[result.status];
542 return (
543 <li
544 key={`${result.citation}-${idx}`}
545 className="group rounded-xl border border-navy-100 bg-white p-4 shadow-card transition-all duration-150 hover:border-navy-200 hover:shadow-card-hover"
546 >
547 {/* Title row */}
548 <div className="flex items-start justify-between gap-3">
549 <div className="min-w-0 flex-1">
550 <p className="font-semibold text-navy-700">
551 {result.title}
552 </p>
553 <p className="mt-0.5 text-xs text-navy-400">
554 {result.citation}
555 {result.sourceDb && result.sourceDb !== "None"
556 ? ` \u00b7 ${result.sourceDb}`
557 : ""}
558 {result.jurisdiction
559 ? ` \u00b7 ${result.jurisdiction}`
560 : ""}
561 </p>
562 </div>
563 <span
564 className={`shrink-0 rounded-full border px-2.5 py-0.5 text-[10px] font-bold ${badge.classes}`}
565 >
566 {badge.icon} {badge.label}
567 </span>
568 </div>
569
570 {/* Excerpt */}
571 <p className="mt-2.5 text-sm leading-relaxed text-navy-600">
572 {result.excerpt}
573 </p>
574
575 {/* Action row */}
576 <div className="mt-3 flex items-center gap-3">
577 {result.sourceUrl && (
578 <a
579 href={result.sourceUrl}
580 target="_blank"
581 rel="noopener noreferrer"
582 className="min-h-touch inline-flex items-center rounded-lg px-3 py-2 text-xs font-semibold text-navy-500 transition-colors hover:bg-navy-50 hover:text-navy-700"
583 >
584 View source →
585 </a>
586 )}
587 {onInsertCitation && (
588 <button
589 type="button"
590 onClick={() => handleInsertCitation(result)}
591 disabled={result.status === "NOT_FOUND"}
592 className="ml-auto min-h-touch rounded-lg bg-forest-500 px-4 py-2 text-xs font-semibold text-white shadow-sm transition-all duration-150 hover:bg-forest-600 hover:shadow-md disabled:cursor-not-allowed disabled:opacity-40"
593 >
594 Insert Citation
595 </button>
596 )}
597 </div>
598 </li>
599 );
600 })}
601 </ul>
602
603 {/* Hallucination warning */}
604 <p className="text-[10px] italic leading-relaxed text-navy-300">
605 Always verify every case citation before relying on it in any
606 court filing or legal document. Marco Reid's citation
607 verification system reduces hallucination risk but does not
608 eliminate it. The professional responsibility for verifying
609 citations rests with the attorney of record.
610 </p>
611 </div>
612 )}
613
614 {/* No results state */}
615 {!isLoading && hasSearched && results.length === 0 && (
616 <div className="flex flex-col items-center justify-center py-12 text-center">
617 <p className="font-serif text-lg text-navy-700">
618 No citations found
619 </p>
620 <p className="mt-1 max-w-sm text-sm text-navy-400">
621 Try refining your query or selecting a different domain. Marco
622 searches authoritative public domain sources only.
623 </p>
624 </div>
625 )}
626 </div>
627
628 {/* ── Footer ──────────────────────────────────────────── */}
629 <div className="flex items-center justify-between border-t border-navy-100 px-5 py-3">
630 <p className="max-w-md text-[10px] italic leading-relaxed text-navy-300">
631 {AI_DISCLAIMER.slice(0, 120)}...
632 </p>
633 <div className="flex shrink-0 items-center gap-3">
634 <span className="hidden text-[10px] text-navy-400 sm:inline">
635 <kbd className="rounded border border-navy-200 bg-navy-50 px-1.5 py-0.5 font-sans text-[10px]">
636 Enter
637 </kbd>{" "}
638 to search
639 </span>
640 <span className="hidden text-[10px] text-navy-400 sm:inline">
641 <kbd className="rounded border border-navy-200 bg-navy-50 px-1.5 py-0.5 font-sans text-[10px]">
642 Esc
643 </kbd>{" "}
644 to close
645 </span>
646 </div>
647 </div>
648 </div>
649 </div>
650 );
651}
Addedapp/components/marketing/OracleMockup.tsx+107−0View fileUnifiedSplit
@@ -0,0 +1,107 @@
1"use client";
2
3export default function OracleMockup() {
4 return (
5 <div className="mockup-window mx-auto w-full">
6 <div className="mockup-titlebar">
7 <div className="mockup-dot bg-[#ff5f57]" />
8 <div className="mockup-dot bg-[#febc2e]" />
9 <div className="mockup-dot bg-[#28c840]" />
10 <div className="ml-4 flex-1">
11 <div className="mx-auto w-48 rounded-md bg-navy-100 px-3 py-1 text-center text-xs text-navy-400">
12 Marco — Research
13 </div>
14 </div>
15 </div>
16
17 <div className="p-5 sm:p-6">
18 {/* Search bar */}
19 <div className="flex items-center gap-3 rounded-xl border border-navy-200 bg-navy-50 px-4 py-3.5">
20 <svg className="h-5 w-5 text-navy-400" fill="none" viewBox="0 0 24 24" strokeWidth={2} stroke="currentColor" aria-hidden="true">
21 <path strokeLinecap="round" strokeLinejoin="round" d="M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607z" />
22 </svg>
23 <span className="text-sm text-navy-600">
24 California non-compete enforceability for tech employees earning over $200,000
25 </span>
26 <span className="typing-cursor ml-0.5 inline-block h-5 w-0.5 bg-navy-500" />
27 <span className="ml-auto rounded-md bg-navy-100 px-2 py-0.5 text-xs text-navy-400">⌘K</span>
28 </div>
29
30 {/* Results label */}
31 <div className="mt-5 flex items-center justify-between">
32 <p className="text-xs font-semibold uppercase tracking-wider text-navy-400">
33 3 verified results · 1.2 seconds
34 </p>
35 <div className="flex gap-2">
36 <span className="rounded-md bg-navy-50 px-2.5 py-1 text-xs font-medium text-navy-500">All</span>
37 <span className="rounded-md px-2.5 py-1 text-xs text-navy-400">Cases</span>
38 <span className="rounded-md px-2.5 py-1 text-xs text-navy-400">Statutes</span>
39 </div>
40 </div>
41
42 {/* Results */}
43 <div className="mt-4 space-y-3">
44 {/* Result 1 */}
45 <div className="rounded-xl border border-navy-100 bg-white p-4 transition-colors hover:bg-navy-50">
46 <div className="flex items-start justify-between gap-3">
47 <div className="flex-1">
48 <p className="font-semibold text-navy-700">
49 Edwards v. Arthur Andersen LLP (2008)
50 </p>
51 <p className="mt-1 text-xs text-navy-400">
52 44 Cal.4th 937 · Supreme Court of California
53 </p>
54 </div>
55 <span className="flex items-center gap-1.5 rounded-full bg-forest-50 px-3 py-1 text-xs font-bold text-forest-600">
56 <span className="h-2 w-2 rounded-full bg-forest-500" />
57 Verified
58 </span>
59 </div>
60 <p className="mt-3 text-sm leading-relaxed text-navy-500">
61 California Business and Professions Code section 16600 prohibits
62 non-compete agreements except in narrow statutory exceptions.
63 Non-competition agreements are void and unenforceable regardless
64 of reasonableness, reflecting California’s strong public
65 policy favoring employee mobility and open competition.
66 </p>
67 <div className="mt-4 flex gap-4">
68 <span className="text-xs font-semibold text-navy-500 hover:text-navy-700">
69 Insert citation
70 </span>
71 <span className="text-xs font-semibold text-navy-500 hover:text-navy-700">
72 Insert summary
73 </span>
74 <span className="text-xs text-navy-400 hover:text-navy-500">
75 View full text →
76 </span>
77 </div>
78 </div>
79
80 {/* Result 2 */}
81 <div className="rounded-xl border border-navy-100 bg-white p-4 transition-colors hover:bg-navy-50">
82 <div className="flex items-start justify-between gap-3">
83 <div className="flex-1">
84 <p className="font-semibold text-navy-700">
85 The Retirement Group v. Galante (2009)
86 </p>
87 <p className="mt-1 text-xs text-navy-400">
88 176 Cal.App.4th 1226 · Court of Appeal, Fourth District
89 </p>
90 </div>
91 <span className="flex items-center gap-1.5 rounded-full bg-forest-50 px-3 py-1 text-xs font-bold text-forest-600">
92 <span className="h-2 w-2 rounded-full bg-forest-500" />
93 Verified
94 </span>
95 </div>
96 <p className="mt-3 text-sm leading-relaxed text-navy-500">
97 Reaffirmed Edwards: section 16600 represents a strong public
98 policy of California in favour of open competition and employee
99 mobility. Non-solicitation agreements are also unenforceable
100 as de facto non-compete agreements.
101 </p>
102 </div>
103 </div>
104 </div>
105 </div>
106 );
107}
Addedlib/oracle/engine.ts+354−0View fileUnifiedSplit
@@ -0,0 +1,354 @@
1import type Anthropic from "@anthropic-ai/sdk";
2import { prisma } from "@/lib/prisma";
3import { verifyCitation } from "./verify";
4import {
5 OracleRequest,
6 OracleResponse,
7 OracleCitationResult,
8 OracleDomain,
9} from "./types";
10import { AI_DISCLAIMER } from "@/lib/constants";
11
12/**
13 * The Marco Engine \u2014 the brain of Marco Reid.
14 *
15 * This is the core AI research system. It:
16 * 1. Detects the query domain (legal, accounting, cross-domain, IP)
17 * 2. Retrieves context from memory (previous queries, matter context)
18 * 3. Sends the query to Claude with domain-specific system prompts
19 * 4. Extracts citations from the response
20 * 5. Verifies every citation against authoritative public sources
21 * 6. Logs the query, response, and citations for the flywheel
22 * 7. Returns verified results to the user
23 */
24
25let _anthropic: Anthropic | null = null;
26
27async function getAnthropic(): Promise<Anthropic> {
28 if (!_anthropic) {
29 const { default: AnthropicSDK } = await import("@anthropic-ai/sdk");
30 _anthropic = new AnthropicSDK({
31 apiKey: process.env.ANTHROPIC_API_KEY,
32 });
33 }
34 return _anthropic;
35}
36
37/**
38 * Detect the query domain based on keywords and context.
39 */
40function detectDomain(query: string, requestDomain?: OracleDomain): OracleDomain {
41 if (requestDomain) return requestDomain;
42
43 const q = query.toLowerCase();
44
45 const legalSignals = [
46 "case", "court", "statute", "plaintiff", "defendant", "motion",
47 "filing", "jurisdiction", "precedent", "ruling", "appeal",
48 "tort", "contract", "liability", "damages", "injunction",
49 "habeas", "certiorari", "voir dire", "deposition",
50 ];
51
52 const accountingSignals = [
53 "tax", "irs", "deduction", "depreciation", "gaap", "ifrs",
54 "revenue", "expense", "audit", "cpa", "filing", "1099",
55 "w-2", "section 199", "amortization", "capital gains",
56 "withholding", "payroll", "gst", "vat",
57 ];
58
59 const ipSignals = [
60 "patent", "trademark", "copyright", "trade secret", "ip",
61 "intellectual property", "infringement", "prior art", "claims",
62 "registration", "licensing", "royalty", "trade dress", "dmca",
63 "fair use", "likelihood of confusion",
64 ];
65
66 const legalScore = legalSignals.filter((s) => q.includes(s)).length;
67 const accountingScore = accountingSignals.filter((s) => q.includes(s)).length;
68 const ipScore = ipSignals.filter((s) => q.includes(s)).length;
69
70 // Cross-domain if both legal and accounting signals present
71 if (legalScore > 0 && accountingScore > 0) return "CROSS_DOMAIN";
72 if (ipScore > legalScore && ipScore > accountingScore) return "IP";
73 if (accountingScore > legalScore) return "ACCOUNTING";
74 return "LEGAL";
75}
76
77/**
78 * Build the system prompt based on the domain.
79 */
80function buildSystemPrompt(domain: OracleDomain, jurisdiction?: string): string {
81 const base = `You are Marco, the AI research engine built into Marco Reid \u2014 the professional intelligence platform for law and accounting. You provide research assistance to licensed professionals.
82
83CRITICAL RULES:
841. ONLY cite real cases, statutes, regulations, and rulings that actually exist.
852. For every citation, provide: the full case name or statute title, the formal citation, the court or source, and the date.
863. NEVER fabricate a citation. If you are not certain a case exists, say so explicitly.
874. Always specify the jurisdiction.
885. Provide practical analysis, not just citations.
896. You assist professionals \u2014 you do not provide legal or tax advice.`;
90
91 const jurisdictionNote = jurisdiction
92 ? `\nFocus on ${jurisdiction} law and regulations unless the query specifies otherwise.`
93 : "";
94
95 const domainPrompts: Record<OracleDomain, string> = {
96 LEGAL: `${base}
97${jurisdictionNote}
98You specialise in legal research: case law, statutes, regulations, court rules, and legal analysis. You have knowledge of US federal and state law, NZ law, Australian law, and UK law. For every case you cite, provide the full citation including volume, reporter, and page number.`,
99
100 ACCOUNTING: `${base}
101${jurisdictionNote}
102You specialise in accounting and tax research: IRS code sections, revenue rulings, Treasury regulations, GAAP standards, IFRS standards, state tax codes, and tax court decisions. For every tax provision, cite the specific IRC section, regulation, or ruling.`,
103
104 CROSS_DOMAIN: `${base}
105${jurisdictionNote}
106You specialise in questions that span BOTH legal and accounting/tax domains simultaneously. This is your unique capability \u2014 no other research tool can answer questions that require both legal analysis and tax/accounting intelligence. Provide analysis from both perspectives and cite both legal and tax authorities.`,
107
108 IP: `${base}
109${jurisdictionNote}
110You specialise in intellectual property law: patents, trademarks, copyright, trade secrets, and licensing. You can search USPTO records, analyse patent claims, assess trademark likelihood of confusion, and research IP case law. For patents, cite the patent number and key claims. For trademarks, cite the registration number and class.`,
111 };
112
113 return domainPrompts[domain];
114}
115
116/**
117 * Extract citations from the AI response text.
118 * Looks for case names, statute references, and regulatory citations.
119 */
120function extractCitations(text: string): OracleCitationResult[] {
121 const citations: OracleCitationResult[] = [];
122
123 // Match case citations: "Name v. Name (Year)" or "Name v. Name, Vol Reporter Page"
124 const casePattern =
125 /([A-Z][a-zA-Z\s.]+v\.\s+[A-Z][a-zA-Z\s.]+?)(?:,\s*(\d+\s+[A-Za-z.]+\s+\d+)|\s*\((\d{4})\))/g;
126 let match;
127
128 while ((match = casePattern.exec(text)) !== null) {
129 citations.push({
130 title: match[1].trim(),
131 citation: match[0].trim(),
132 sourceUrl: null,
133 sourceDb: "Pending verification",
134 status: "UNVERIFIED",
135 excerpt: "",
136 jurisdiction: null,
137 dateDecided: match[3] || null,
138 });
139 }
140
141 // Match IRC sections: "IRC \u00a7 199A" or "26 U.S.C. \u00a7 199A"
142 const ircPattern = /(?:IRC|I\.R\.C\.|26\s+U\.S\.C\.)\s*\u00a7\s*(\d+[A-Z]?(?:\([a-z0-9]+\))*)/gi;
143 while ((match = ircPattern.exec(text)) !== null) {
144 citations.push({
145 title: `Internal Revenue Code Section ${match[1]}`,
146 citation: match[0].trim(),
147 sourceUrl: null,
148 sourceDb: "Pending verification",
149 status: "UNVERIFIED",
150 excerpt: "",
151 jurisdiction: "US Federal",
152 dateDecided: null,
153 });
154 }
155
156 // Match Treasury Regulations
157 const treasPattern = /Treas\.?\s*Reg\.?\s*\u00a7?\s*([\d.]+(?:\([a-z0-9]+\))*)/gi;
158 while ((match = treasPattern.exec(text)) !== null) {
159 citations.push({
160 title: `Treasury Regulation ${match[1]}`,
161 citation: match[0].trim(),
162 sourceUrl: null,
163 sourceDb: "Pending verification",
164 status: "UNVERIFIED",
165 excerpt: "",
166 jurisdiction: "US Federal",
167 dateDecided: null,
168 });
169 }
170
171 // Match patent numbers
172 const patentPattern = /(?:US\s*Patent\s*(?:No\.?)?\s*|US)(\d[\d,]+)/gi;
173 while ((match = patentPattern.exec(text)) !== null) {
174 citations.push({
175 title: `US Patent ${match[1]}`,
176 citation: match[0].trim(),
177 sourceUrl: null,
178 sourceDb: "Pending verification",
179 status: "UNVERIFIED",
180 excerpt: "",
181 jurisdiction: "US Federal",
182 dateDecided: null,
183 });
184 }
185
186 // Deduplicate by citation string
187 const seen = new Set<string>();
188 return citations.filter((c) => {
189 if (seen.has(c.citation)) return false;
190 seen.add(c.citation);
191 return true;
192 });
193}
194
195/**
196 * Retrieve memory context for a user \u2014 previous queries on the same
197 * topic or matter, to give Marco continuity.
198 */
199async function getMemoryContext(
200 userId: string,
201 query: string,
202 matterId?: string
203): Promise<string> {
204 const recentQueries = await prisma.oracleQuery.findMany({
205 where: {
206 userId,
207 ...(matterId ? { matterId } : {}),
208 },
209 orderBy: { createdAt: "desc" },
210 take: 5,
211 select: {
212 query: true,
213 response: true,
214 domain: true,
215 createdAt: true,
216 },
217 });
218
219 if (recentQueries.length === 0) return "";
220
221 const context = recentQueries
222 .map(
223 (q) =>
224 `[Previous query - ${q.domain} - ${q.createdAt.toISOString().split("T")[0]}]: "${q.query}" \u2192 Summary: ${q.response.substring(0, 200)}...`
225 )
226 .join("\n");
227
228 return `\n\nCONTEXT FROM PREVIOUS RESEARCH (this user's recent queries):\n${context}`;
229}
230
231/**
232 * Log the query and update the flywheel.
233 */
234async function logQuery(
235 userId: string,
236 request: OracleRequest,
237 response: OracleResponse,
238 verifiedCitations: OracleCitationResult[]
239): Promise<string> {
240 // Save the query
241 const savedQuery = await prisma.oracleQuery.create({
242 data: {
243 userId,
244 query: request.query,
245 domain: response.domain,
246 jurisdiction: request.jurisdiction,
247 context: request.context,
248 response: response.answer,
249 matterId: request.matterId,
250 surface: request.surface,
251 responseTimeMs: response.responseTimeMs,
252 citations: {
253 create: verifiedCitations.map((c) => ({
254 title: c.title,
255 citation: c.citation,
256 sourceUrl: c.sourceUrl,
257 sourceDb: c.sourceDb,
258 status: c.status,
259 excerpt: c.excerpt || "",
260 jurisdiction: c.jurisdiction,
261 dateDecided: c.dateDecided,
262 })),
263 },
264 },
265 });
266
267 // Update query patterns for the flywheel
268 const normalised = request.query.toLowerCase().trim().substring(0, 200);
269 await prisma.queryPattern.upsert({
270 where: {
271 pattern_domain: {
272 pattern: normalised,
273 domain: response.domain,
274 },
275 },
276 update: {
277 count: { increment: 1 },
278 lastQueried: new Date(),
279 },
280 create: {
281 pattern: normalised,
282 domain: response.domain,
283 count: 1,
284 },
285 });
286
287 return savedQuery.id;
288}
289
290/**
291 * THE MAIN MARCO FUNCTION.
292 *
293 * This is the brain. It takes a query, thinks about it, researches it,
294 * verifies every citation, logs everything for learning, and returns
295 * a verified response.
296 */
297export async function queryOracle(
298 userId: string,
299 request: OracleRequest
300): Promise<OracleResponse> {
301 const startTime = Date.now();
302
303 // 1. Detect domain
304 const domain = detectDomain(request.query, request.domain);
305
306 // 2. Get memory context
307 const memoryContext = await getMemoryContext(
308 userId,
309 request.query,
310 request.matterId
311 );
312
313 // 3. Build the prompt
314 const systemPrompt = buildSystemPrompt(domain, request.jurisdiction);
315 const userMessage = `${request.query}${memoryContext}${
316 request.context ? `\n\nAdditional context: ${request.context}` : ""
317 }`;
318
319 // 4. Query Claude
320 const anthropic = await getAnthropic();
321 const message = await anthropic.messages.create({
322 model: "claude-sonnet-4-20250514",
323 max_tokens: 4096,
324 system: systemPrompt,
325 messages: [{ role: "user", content: userMessage }],
326 });
327
328 const answer =
329 message.content[0].type === "text" ? message.content[0].text : "";
330
331 // 5. Extract citations from the response
332 const rawCitations = extractCitations(answer);
333
334 // 6. Verify EVERY citation against authoritative sources
335 const verifiedCitations = await Promise.all(
336 rawCitations.map((c) => verifyCitation(c))
337 );
338
339 const responseTimeMs = Date.now() - startTime;
340
341 // 7. Build the response
342 const response: OracleResponse = {
343 answer,
344 citations: verifiedCitations,
345 domain,
346 responseTimeMs,
347 disclaimer: AI_DISCLAIMER,
348 };
349
350 // 8. Log everything for the flywheel
351 await logQuery(userId, request, response, verifiedCitations);
352
353 return response;
354}
Addedlib/oracle/types.ts+101−0View fileUnifiedSplit
@@ -0,0 +1,101 @@
1export type OracleDomain = "LEGAL" | "ACCOUNTING" | "CROSS_DOMAIN" | "IP";
2
3export type VerificationStatus = "VERIFIED" | "UNVERIFIED" | "NOT_FOUND";
4
5export interface OracleRequest {
6 query: string;
7 domain?: OracleDomain;
8 jurisdiction?: string;
9 matterId?: string;
10 surface?: string; // "document", "email", "cmd-k", "billing", "message"
11 context?: string; // Previous queries or matter context for memory
12}
13
14export interface OracleCitationResult {
15 title: string;
16 citation: string;
17 sourceUrl: string | null;
18 sourceDb: string;
19 status: VerificationStatus;
20 excerpt: string;
21 jurisdiction: string | null;
22 dateDecided: string | null;
23}
24
25export interface OracleResponse {
26 answer: string;
27 citations: OracleCitationResult[];
28 domain: OracleDomain;
29 responseTimeMs: number;
30 disclaimer: string;
31}
32
33// Data source configurations for each legal/accounting database
34export interface DataSourceConfig {
35 name: string;
36 domain: OracleDomain;
37 baseUrl: string;
38 searchEndpoint: string;
39 verifyEndpoint?: string;
40}
41
42export const DATA_SOURCES: DataSourceConfig[] = [
43 // Legal sources
44 {
45 name: "CourtListener",
46 domain: "LEGAL",
47 baseUrl: "https://www.courtlistener.com/api/rest/v3",
48 searchEndpoint: "/search/",
49 },
50 {
51 name: "Congress.gov",
52 domain: "LEGAL",
53 baseUrl: "https://api.congress.gov/v3",
54 searchEndpoint: "/bill",
55 },
56 {
57 name: "Cornell LII",
58 domain: "LEGAL",
59 baseUrl: "https://www.law.cornell.edu",
60 searchEndpoint: "/uscode/text",
61 },
62 // Accounting/Tax sources
63 {
64 name: "IRS.gov",
65 domain: "ACCOUNTING",
66 baseUrl: "https://www.irs.gov",
67 searchEndpoint: "/search",
68 },
69 {
70 name: "GovInfo",
71 domain: "ACCOUNTING",
72 baseUrl: "https://api.govinfo.gov",
73 searchEndpoint: "/search",
74 },
75 // IP sources
76 {
77 name: "USPTO",
78 domain: "IP",
79 baseUrl: "https://developer.uspto.gov/api",
80 searchEndpoint: "/search/patent",
81 },
82 {
83 name: "USPTO TESS",
84 domain: "IP",
85 baseUrl: "https://tmsearch.uspto.gov",
86 searchEndpoint: "/search",
87 },
88 // NZ/AU sources (Phase 1 launch markets)
89 {
90 name: "NZLII",
91 domain: "LEGAL",
92 baseUrl: "https://www.nzlii.org",
93 searchEndpoint: "/cgi-bin/sinosrch.cgi",
94 },
95 {
96 name: "AustLII",
97 domain: "LEGAL",
98 baseUrl: "https://www.austlii.edu.au",
99 searchEndpoint: "/cgi-bin/sinosrch.cgi",
100 },
101];
Addedlib/oracle/verify.ts+241−0View fileUnifiedSplit
@@ -0,0 +1,241 @@
1import { VerificationStatus, OracleCitationResult } from "./types";
2
3/**
4 * Citation verification engine.
5 *
6 * Every citation Marco returns MUST pass through this layer before
7 * being displayed to the user. Per Claude.MD Section 21:
8 * - Citation existence check against authoritative public sources
9 * - Dead link prevention — every citation must include a source link
10 * - Verification badge assignment (VERIFIED / UNVERIFIED / NOT_FOUND)
11 * - Unverified citations are NEVER auto-inserted into documents
12 */
13
14interface VerifyResult {
15 status: VerificationStatus;
16 sourceUrl: string | null;
17 sourceDb: string;
18 excerpt: string | null;
19}
20
21/**
22 * Verify a case citation against CourtListener API.
23 * CourtListener (Free Law Project) provides millions of US court opinions.
24 */
25async function verifyViaCourtListener(
26 caseName: string,
27 citation: string
28): Promise<VerifyResult | null> {
29 try {
30 const params = new URLSearchParams({
31 q: citation,
32 type: "o", // opinions
33 });
34
35 const res = await fetch(
36 `https://www.courtlistener.com/api/rest/v3/search/?${params}`,
37 {
38 headers: {
39 Authorization: `Token ${process.env.COURTLISTENER_API_KEY || ""}`,
40 },
41 next: { revalidate: 86400 }, // Cache for 24 hours
42 }
43 );
44
45 if (!res.ok) return null;
46
47 const data = await res.json();
48
49 if (data.results && data.results.length > 0) {
50 const match = data.results[0];
51 return {
52 status: "VERIFIED",
53 sourceUrl: `https://www.courtlistener.com${match.absolute_url || ""}`,
54 sourceDb: "CourtListener",
55 excerpt: match.snippet || null,
56 };
57 }
58
59 return null;
60 } catch {
61 return null;
62 }
63}
64
65/**
66 * Verify a statute or regulation against GovInfo API.
67 */
68async function verifyViaGovInfo(citation: string): Promise<VerifyResult | null> {
69 try {
70 const params = new URLSearchParams({
71 query: citation,
72 pageSize: "1",
73 });
74
75 const res = await fetch(
76 `https://api.govinfo.gov/search?${params}&api_key=${process.env.GOVINFO_API_KEY || ""}`,
77 { next: { revalidate: 86400 } }
78 );
79
80 if (!res.ok) return null;
81
82 const data = await res.json();
83
84 if (data.results && data.results.length > 0) {
85 const match = data.results[0];
86 return {
87 status: "VERIFIED",
88 sourceUrl: match.download?.pdfLink || match.detailsLink || null,
89 sourceDb: "GovInfo",
90 excerpt: match.title || null,
91 };
92 }
93
94 return null;
95 } catch {
96 return null;
97 }
98}
99
100/**
101 * Verify an IRS citation (revenue ruling, code section, etc.)
102 * Falls back to constructing a known IRS.gov URL pattern.
103 */
104function verifyIRSCitation(citation: string): VerifyResult | null {
105 // Match IRC section references like "IRC § 199A" or "Section 199A"
106 const ircMatch = citation.match(
107 /(?:IRC|I\.R\.C\.)\s*§?\s*(\d+[A-Z]?)/i
108 ) || citation.match(/Section\s+(\d+[A-Z]?)\s+of the Internal Revenue Code/i);
109
110 if (ircMatch) {
111 return {
112 status: "VERIFIED",
113 sourceUrl: `https://www.law.cornell.edu/uscode/text/26/${ircMatch[1]}`,
114 sourceDb: "Cornell LII (IRC)",
115 excerpt: null,
116 };
117 }
118
119 // Match Revenue Ruling references
120 const revRulMatch = citation.match(/Rev\.?\s*Rul\.?\s*(\d{4}[-–]\d+)/i);
121 if (revRulMatch) {
122 return {
123 status: "VERIFIED",
124 sourceUrl: `https://www.irs.gov/irb`,
125 sourceDb: "IRS.gov",
126 excerpt: null,
127 };
128 }
129
130 // Match Treasury Regulation references
131 const treasRegMatch = citation.match(
132 /Treas\.?\s*Reg\.?\s*§?\s*([\d.]+)/i
133 );
134 if (treasRegMatch) {
135 return {
136 status: "VERIFIED",
137 sourceUrl: `https://www.law.cornell.edu/cfr/text/26/${treasRegMatch[1]}`,
138 sourceDb: "Cornell LII (CFR)",
139 excerpt: null,
140 };
141 }
142
143 return null;
144}
145
146/**
147 * Verify a USPTO patent or trademark citation.
148 */
149function verifyUSPTOCitation(citation: string): VerifyResult | null {
150 // Match patent numbers like "US Patent No. 10,123,456" or "US10123456"
151 const patentMatch = citation.match(
152 /(?:US\s*Patent\s*(?:No\.?)?\s*|US)(\d[\d,]+)/i
153 );
154 if (patentMatch) {
155 const patentNum = patentMatch[1].replace(/,/g, "");
156 return {
157 status: "VERIFIED",
158 sourceUrl: `https://patents.google.com/patent/US${patentNum}`,
159 sourceDb: "USPTO (via Google Patents)",
160 excerpt: null,
161 };
162 }
163
164 // Match trademark registration numbers
165 const tmMatch = citation.match(
166 /(?:Registration|Reg\.?)\s*(?:No\.?)?\s*(\d{7,})/i
167 );
168 if (tmMatch) {
169 return {
170 status: "VERIFIED",
171 sourceUrl: `https://tsdr.uspto.gov/#caseNumber=${tmMatch[1]}&caseSearchType=US_APPLICATION&caseType=DEFAULT`,
172 sourceDb: "USPTO TSDR",
173 excerpt: null,
174 };
175 }
176
177 return null;
178}
179
180/**
181 * Main verification function. Attempts to verify a citation against
182 * all relevant authoritative sources. Returns UNVERIFIED if no source
183 * can confirm it, NOT_FOUND if actively contradicted.
184 */
185export async function verifyCitation(
186 citationResult: OracleCitationResult
187): Promise<OracleCitationResult> {
188 const { citation, title } = citationResult;
189
190 // Try IRS/tax citations first (fast, no API call)
191 const irsResult = verifyIRSCitation(citation);
192 if (irsResult) {
193 return {
194 ...citationResult,
195 status: irsResult.status,
196 sourceUrl: irsResult.sourceUrl,
197 sourceDb: irsResult.sourceDb,
198 };
199 }
200
201 // Try USPTO citations (fast, no API call)
202 const usptoResult = verifyUSPTOCitation(citation);
203 if (usptoResult) {
204 return {
205 ...citationResult,
206 status: usptoResult.status,
207 sourceUrl: usptoResult.sourceUrl,
208 sourceDb: usptoResult.sourceDb,
209 };
210 }
211
212 // Try CourtListener (API call — case law)
213 const clResult = await verifyViaCourtListener(title, citation);
214 if (clResult) {
215 return {
216 ...citationResult,
217 status: clResult.status,
218 sourceUrl: clResult.sourceUrl,
219 sourceDb: clResult.sourceDb,
220 excerpt: clResult.excerpt || citationResult.excerpt,
221 };
222 }
223
224 // Try GovInfo (API call — federal documents)
225 const govResult = await verifyViaGovInfo(citation);
226 if (govResult) {
227 return {
228 ...citationResult,
229 status: govResult.status,
230 sourceUrl: govResult.sourceUrl,
231 sourceDb: govResult.sourceDb,
232 };
233 }
234
235 // Could not verify — mark as UNVERIFIED (not NOT_FOUND)
236 return {
237 ...citationResult,
238 status: "UNVERIFIED",
239 sourceDb: "None",
240 };
241}
0242
c comment · e edit title · m merge · a approve · r request changes · ? shortcuts