11import { useMemo , useState } from "react" ;
2+ import { Plus , Minus } from "lucide-react" ;
23import { cases , getDisplayCompany , type Jurisdiction } from "@/data/cases" ;
34import { JURISDICTION_INFO } from "@/data/jurisdictionInfo" ;
45import { JurisdictionLogo } from "./JurisdictionLogos" ;
@@ -58,10 +59,16 @@ export default function JurisdictionDetail({ jurisdiction }: JurisdictionDetailP
5859 . sort ( ( [ , a ] , [ , b ] ) => b - a )
5960 . slice ( 0 , 5 ) ;
6061
62+ // Top companies by fine — include outcome
6163 const topCompanies = [ ...jCases ]
6264 . sort ( ( a , b ) => b . fineAmount - a . fineAmount )
6365 . slice ( 0 , 5 )
64- . map ( ( c ) => ( { name : getDisplayCompany ( c ) , fine : c . fineAmount , year : c . year } ) ) ;
66+ . map ( ( c ) => ( {
67+ name : getDisplayCompany ( c ) ,
68+ fine : c . fineAmount ,
69+ year : c . year ,
70+ outcome : c . outcomeSummary || "—" ,
71+ } ) ) ;
6572
6673 return {
6774 totalCases, minYear, maxYear,
@@ -88,180 +95,173 @@ export default function JurisdictionDetail({ jurisdiction }: JurisdictionDetailP
8895 </ div >
8996 </ div >
9097
91- < div className = "p-6 space-y-8 " >
98+ < div className = "p-6 space-y-10 " >
9299 { /* Overview */ }
93- < div >
94- < SectionLabel > Overview</ SectionLabel >
95- < p className = "text-sm leading-relaxed" > { info . overview } </ p >
96- </ div >
100+ < section >
101+ < h2 className = "text-2xl font-bold tracking-tight mb-4" > \ OVERVIEW</ h2 >
102+ < div className = "h-[3px] bg-border mb-4" />
103+ < p className = "text-[15px] leading-relaxed" > { info . overview } </ p >
104+ </ section >
97105
98- { /* Main Privacy Laws — entire section is collapsible */ }
99- < div >
106+ { /* Severity Snapshot — yellow detail boxes matching CaseDetail */ }
107+ < section >
108+ < h2 className = "text-2xl font-bold tracking-tight mb-4" > \ SEVERITY SNAPSHOT</ h2 >
109+ < div className = "h-[3px] bg-border mb-4" />
110+ < div className = "grid grid-cols-2 md:grid-cols-4 gap-4" >
111+ < div className = "detail-yellow-box p-4" >
112+ < p className = "text-[10px] font-mono font-bold uppercase tracking-wider text-muted-foreground" > Total Fines</ p >
113+ < p className = "text-lg font-bold mt-1" > { formatCurrency ( stats . totalFines ) } </ p >
114+ </ div >
115+ < div className = "detail-yellow-box p-4" >
116+ < p className = "text-[10px] font-mono font-bold uppercase tracking-wider text-muted-foreground" > Largest Fine</ p >
117+ < p className = "text-lg font-bold mt-1" > { formatCurrency ( stats . maxFine ) } </ p >
118+ </ div >
119+ < div className = "detail-yellow-box p-4" >
120+ < p className = "text-[10px] font-mono font-bold uppercase tracking-wider text-muted-foreground" > Avg Fine</ p >
121+ < p className = "text-lg font-bold mt-1" > { formatCurrency ( stats . avgFine ) } </ p >
122+ </ div >
123+ < div className = "detail-yellow-box p-4" >
124+ < p className = "text-[10px] font-mono font-bold uppercase tracking-wider text-muted-foreground" > % Monetary</ p >
125+ < p className = "text-lg font-bold mt-1" > { stats . pctMonetary } %</ p >
126+ </ div >
127+ </ div >
128+ < p className = "text-[10px] font-mono font-bold uppercase tracking-widest text-muted-foreground mt-3" >
129+ { stats . totalCases } cases · { stats . minYear } –{ stats . maxYear }
130+ </ p >
131+ </ section >
132+
133+ { /* Enforcement Style */ }
134+ < section >
135+ < h2 className = "text-2xl font-bold tracking-tight mb-4" > \ ENFORCEMENT STYLE</ h2 >
136+ < div className = "h-[3px] bg-border mb-4" />
137+ < div className = "brutalist-border info-box p-6" >
138+ < p className = "text-[15px] leading-relaxed" > { info . enforcementStyle } </ p >
139+ </ div >
140+ </ section >
141+
142+ { /* Main Privacy Laws — loot-drop accordion */ }
143+ < section >
100144 < button
101145 type = "button"
102- onClick = { ( ) => setLawsOpen ( ! lawsOpen ) }
103- className = "w-full flex items-center justify-between gap-2 cursor-pointer group"
146+ className = "loot-drop-accordion-header"
147+ onClick = { ( ) => setLawsOpen ( ( o ) => ! o ) }
104148 >
105- < SectionLabel > Main Privacy Laws</ SectionLabel >
106- < span
107- className = "text-[10px] font-mono font-bold shrink-0 transition-transform duration-200 text-muted-foreground"
108- style = { { transform : lawsOpen ? "rotate(180deg)" : "rotate(0deg)" } }
109- >
110- ▼
149+ < span className = "loot-drop-circle" >
150+ { lawsOpen ? < Minus className = "w-5 h-5" /> : < Plus className = "w-5 h-5" /> }
111151 </ span >
152+ < span className = "loot-drop-accordion-title" > Main Privacy Laws</ span >
153+ { lawsOpen ? < Minus className = "w-6 h-6 shrink-0" /> : < Plus className = "w-6 h-6 shrink-0" /> }
112154 </ button >
113155 { lawsOpen && (
114- < div className = "mt-3 space-y-3 animate-in fade-in slide-in-from-top-1 duration-200 " >
156+ < div className = "loot-drop-accordion-content space-y-4 " >
115157 { info . laws . map ( ( law ) => (
116- < div key = { law . name } className = "border-l-4 border-black pl -4" >
158+ < div key = { law . name } className = "brutalist- border info-box p -4" style = { { borderLeftWidth : "4px" , borderLeftColor : "#FFD700" } } >
117159 < p className = "text-sm font-bold" >
118160 { law . name } < span className = "font-normal opacity-60" > ({ law . year } )</ span >
119161 </ p >
120- < p className = "text-xs leading-relaxed mt-1 opacity-80" > { law . description } </ p >
162+ < p className = "text-sm leading-relaxed mt-2 opacity-80" > { law . description } </ p >
121163 </ div >
122164 ) ) }
123165 </ div >
124166 ) }
125- </ div >
126-
127- { /* Enforcement Authority */ }
128- < div >
129- < SectionLabel > Enforcement Authority</ SectionLabel >
130- < div className = "border-l-4 border-black pl-4 mt-1" >
131- < p className = "text-sm font-bold" >
132- { info . authority . name } { " " }
133- < span className = "font-normal opacity-60" > ({ info . authority . acronym } )</ span >
134- </ p >
135- < p className = "text-xs leading-relaxed mt-1 opacity-80" > { info . authority . role } </ p >
136- </ div >
137- </ div >
138-
139- { /* Enforcement Style */ }
140- < div >
141- < SectionLabel > Enforcement Style</ SectionLabel >
142- < p className = "text-sm leading-relaxed" > { info . enforcementStyle } </ p >
143- </ div >
144-
145- < div className = "border-t-2 border-dashed border-border" />
146-
147- { /* Dataset Stats Header */ }
148- < div >
149- < h3 className = "hero-title text-2xl uppercase tracking-tight mb-1" > From Our Dataset</ h3 >
150- < p className = "text-[10px] font-mono font-bold uppercase tracking-widest text-muted-foreground" >
151- { stats . totalCases } cases · { stats . minYear } –{ stats . maxYear }
152- </ p >
153- </ div >
167+ </ section >
154168
155169 { /* Stats Grid */ }
156- < div className = "grid grid-cols-1 md:grid-cols-2 gap-6" >
157- { /* Severity Snapshot */ }
158- < div >
159- < SectionLabel > Severity Snapshot</ SectionLabel >
160- < div className = "grid grid-cols-2 gap-3 mt-1" >
161- < StatBox label = "Total Fines" value = { formatCurrency ( stats . totalFines ) } />
162- < StatBox label = "Largest Fine" value = { formatCurrency ( stats . maxFine ) } />
163- < StatBox label = "Avg Fine" value = { formatCurrency ( stats . avgFine ) } />
164- < StatBox label = "% Monetary" value = { `${ stats . pctMonetary } %` } />
165- </ div >
166- </ div >
170+ < section >
171+ < h2 className = "text-2xl font-bold tracking-tight mb-4" > \ FROM OUR DATASET</ h2 >
172+ < div className = "h-[3px] bg-border mb-6" />
167173
168- { /* Top Sectors */ }
169- < div >
170- < SectionLabel > Top Sectors Affected</ SectionLabel >
171- < div className = "space-y-2.5 mt-1" >
172- { stats . topSectors . map ( ( [ sector , count ] ) => (
173- < BarRow key = { sector } label = { sector } count = { count } total = { stats . totalCases } />
174- ) ) }
174+ < div className = "grid grid-cols-1 md:grid-cols-2 gap-8" >
175+ { /* Top Sectors */ }
176+ < div >
177+ < p className = "text-[10px] font-mono font-bold uppercase tracking-widest text-muted-foreground mb-3" > Top Sectors Affected</ p >
178+ < div className = "space-y-3" >
179+ { stats . topSectors . map ( ( [ sector , count ] ) => {
180+ const pct = stats . totalCases > 0 ? ( count / stats . totalCases ) * 100 : 0 ;
181+ return (
182+ < div key = { sector } >
183+ < div className = "flex items-baseline justify-between mb-1" >
184+ < span className = "text-sm font-bold truncate" > { sector } </ span >
185+ < span className = "text-xs font-mono font-bold ml-2 shrink-0" > { count } </ span >
186+ </ div >
187+ < div className = "h-2.5 bg-border overflow-hidden" >
188+ < div className = "h-full bg-black transition-all duration-500" style = { { width : `${ pct } %` } } />
189+ </ div >
190+ </ div >
191+ ) ;
192+ } ) }
193+ </ div >
175194 </ div >
176- </ div >
177195
178- { /* Most Common Violations */ }
179- < div >
180- < SectionLabel > Most Common Violations</ SectionLabel >
181- < div className = "space-y-2.5 mt-1" >
182- { stats . topViolations . map ( ( [ violation , count ] ) => (
183- < BarRow key = { violation } label = { violation } count = { count } total = { stats . totalCases } />
184- ) ) }
196+ { /* Most Common Violations */ }
197+ < div >
198+ < p className = "text-[10px] font-mono font-bold uppercase tracking-widest text-muted-foreground mb-3" > Most Common Violations</ p >
199+ < div className = "space-y-3" >
200+ { stats . topViolations . map ( ( [ violation , count ] ) => {
201+ const pct = stats . totalCases > 0 ? ( count / stats . totalCases ) * 100 : 0 ;
202+ return (
203+ < div key = { violation } >
204+ < div className = "flex items-baseline justify-between mb-1" >
205+ < span className = "text-sm font-bold truncate" > { violation } </ span >
206+ < span className = "text-xs font-mono font-bold ml-2 shrink-0" > { count } </ span >
207+ </ div >
208+ < div className = "h-2.5 bg-border overflow-hidden" >
209+ < div className = "h-full bg-black transition-all duration-500" style = { { width : `${ pct } %` } } />
210+ </ div >
211+ </ div >
212+ ) ;
213+ } ) }
214+ </ div >
185215 </ div >
186- </ div >
187216
188- { /* Most Common Outcomes */ }
189- < div >
190- < SectionLabel > Most Common Outcomes</ SectionLabel >
191- < div className = "space-y-2.5 mt-1" >
192- { stats . topOutcomes . map ( ( [ outcome , count ] ) => (
193- < BarRow key = { outcome } label = { outcome } count = { count } total = { stats . totalCases } />
194- ) ) }
217+ { /* Most Common Outcomes */ }
218+ < div className = "md:col-span-2" >
219+ < p className = "text-[10px] font-mono font-bold uppercase tracking-widest text-muted-foreground mb-3" > Most Common Outcomes</ p >
220+ < div className = "space-y-3" >
221+ { stats . topOutcomes . map ( ( [ outcome , count ] ) => {
222+ const pct = stats . totalCases > 0 ? ( count / stats . totalCases ) * 100 : 0 ;
223+ return (
224+ < div key = { outcome } >
225+ < div className = "flex items-baseline justify-between mb-1" >
226+ < span className = "text-sm font-bold truncate" > { outcome } </ span >
227+ < span className = "text-xs font-mono font-bold ml-2 shrink-0" > { count } </ span >
228+ </ div >
229+ < div className = "h-2.5 bg-border overflow-hidden" >
230+ < div className = "h-full bg-black transition-all duration-500" style = { { width : `${ pct } %` } } />
231+ </ div >
232+ </ div >
233+ ) ;
234+ } ) }
235+ </ div >
195236 </ div >
196237 </ div >
197- </ div >
238+ </ section >
198239
199240 { /* Top Companies */ }
200- < div >
201- < SectionLabel > Top Companies by Fine</ SectionLabel >
202- < div className = "border-2 border-border mt-1" >
203- < table className = "w-full text-sm font-mono" >
241+ < section >
242+ < h2 className = "text-2xl font-bold tracking-tight mb-4" > \ TOP COMPANIES</ h2 >
243+ < div className = "h-[3px] bg-border mb-4" />
244+ < div className = "border-2 border-black" >
245+ < table className = "w-full text-sm" >
204246 < thead >
205- < tr className = "border-b-2 border-border bg-background" >
206- < th className = "text-left px-3 py-2 text-[10px] font-mono font-bold uppercase tracking-widest" > Company</ th >
207- < th className = "text-right px-3 py-2 text-[10px] font-mono font-bold uppercase tracking-widest" > Fine </ th >
208- < th className = "text-right px-3 py-2 text-[10px] font-mono font-bold uppercase tracking-widest" > Year</ th >
247+ < tr className = "border-b-2 border-black" style = { { backgroundColor : "#FFD700" } } >
248+ < th className = "text-left px-4 py-2.5 text-[10px] font-mono font-bold uppercase tracking-widest" > Company</ th >
249+ < th className = "text-right px-4 py-2.5 text-[10px] font-mono font-bold uppercase tracking-widest" > Outcome </ th >
250+ < th className = "text-right px-4 py-2.5 text-[10px] font-mono font-bold uppercase tracking-widest" > Year</ th >
209251 </ tr >
210252 </ thead >
211- < tbody >
253+ < tbody className = "font-mono" >
212254 { stats . topCompanies . map ( ( c , i ) => (
213- < tr key = { c . name + c . year } className = { i % 2 === 0 ? "bg-card" : "bg-background" } >
214- < td className = "px-3 py-2 font-bold" > { c . name } </ td >
215- < td className = "px-3 py-2 text-right" >
216- { c . fine > 0 ? formatCurrency ( c . fine ) : "—" }
217- </ td >
218- < td className = "px-3 py-2 text-right" > { c . year } </ td >
255+ < tr key = { c . name + c . year } className = { `border-b border-border ${ i % 2 === 0 ? "bg-card" : "bg-background" } ` } >
256+ < td className = "px-4 py-2.5 font-bold" > { c . name } </ td >
257+ < td className = "px-4 py-2.5 text-right text-xs" > { c . outcome } </ td >
258+ < td className = "px-4 py-2.5 text-right" > { c . year } </ td >
219259 </ tr >
220260 ) ) }
221261 </ tbody >
222262 </ table >
223263 </ div >
224- </ div >
225- </ div >
226- </ div >
227- ) ;
228- }
229-
230- /** Consistent section label matching the site-wide pattern */
231- function SectionLabel ( { children } : { children : React . ReactNode } ) {
232- return (
233- < p className = "text-[10px] font-mono font-bold uppercase tracking-widest text-muted-foreground mb-2" >
234- { children }
235- </ p >
236- ) ;
237- }
238-
239- function StatBox ( { label, value } : { label : string ; value : string } ) {
240- return (
241- < div className = "border-2 border-black p-3 text-center" style = { { backgroundColor : "#FFD700" } } >
242- < p className = "text-xl font-bold" > { value } </ p >
243- < p className = "text-[10px] font-mono font-bold uppercase tracking-widest opacity-60 mt-0.5" > { label } </ p >
244- </ div >
245- ) ;
246- }
247-
248- function BarRow ( { label, count, total } : { label : string ; count : number ; total : number } ) {
249- const pct = total > 0 ? ( count / total ) * 100 : 0 ;
250- return (
251- < div className = "flex items-center gap-2" >
252- < div className = "flex-1 min-w-0" >
253- < div className = "flex items-baseline justify-between mb-1" >
254- < span className = "text-xs font-mono truncate" > { label } </ span >
255- < span className = "text-xs font-mono font-bold ml-2 shrink-0" >
256- { Math . round ( pct ) } % < span className = "opacity-50" > ({ count } )</ span >
257- </ span >
258- </ div >
259- < div className = "h-3 bg-border rounded-sm overflow-hidden" >
260- < div
261- className = "h-full bg-black rounded-sm transition-all duration-500"
262- style = { { width : `${ pct } %` } }
263- />
264- </ div >
264+ </ section >
265265 </ div >
266266 </ div >
267267 ) ;
0 commit comments