evijit HF Staff Claude Opus 4.7 (1M context) commited on
Commit
c8aca27
·
1 Parent(s): 4629534

Eval detail polish: hide empty fields, redesign splits, surface evaluator

Browse files

Benchmark card now hides Goal/Score interp/Limitations cards when the
underlying value is empty or "Not specified", and collapses the
Ethical & legal section entirely when license + compliance + privacy
are all missing. The previous behavior rendered placeholder boxes
that read "Not specified" with no signal value.

Policy note hides Caveat / Intended for rows with the same sentinel,
filters "Not specified" out of the domain/language chip strip, and
re-themes the splits panel away from a bordered box with bullet list
to inline header + chip layout. "Slices" → "Splits" throughout the
policy note. (benchmark-detail.tsx still uses "slice" terminology in
several places — left untouched, distinct concept.)

Eval detail hero now leads with a "REPORTED BY <evaluator>" kicker
above the title. Two evaluations can share an upstream dataset (e.g.
both TIGER-Lab and Arcadia Impact reporting against
TIGER-Lab/MMLU-Pro) and otherwise look indistinguishable; naming the
evaluator up front is the cheapest way to disambiguate. Also relabels
"Source dataset" to "Upstream dataset" in the overview details strip
and the eval-card mini panel — same motivation: it's the canonical
dataset, not the source of these particular numbers.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

components/eval-card.tsx CHANGED
@@ -327,7 +327,7 @@ function ProvenanceRow({
327
  <div className="rounded-xl border border-border/60 bg-background/60 p-3">
328
  <div className="mb-2 flex items-center gap-1.5 text-[10px] font-semibold uppercase tracking-[0.18em] text-muted-foreground">
329
  <Database className="h-3 w-3" />
330
- Source dataset
331
  </div>
332
  <div className="flex flex-wrap items-center gap-x-3 gap-y-1 text-sm">
333
  {datasetName && (
 
327
  <div className="rounded-xl border border-border/60 bg-background/60 p-3">
328
  <div className="mb-2 flex items-center gap-1.5 text-[10px] font-semibold uppercase tracking-[0.18em] text-muted-foreground">
329
  <Database className="h-3 w-3" />
330
+ Upstream dataset
331
  </div>
332
  <div className="flex flex-wrap items-center gap-x-3 gap-y-1 text-sm">
333
  {datasetName && (
components/eval-detail.tsx CHANGED
@@ -756,7 +756,7 @@ export function EvalDetail({
756
  : "Models ranked by raw score for this benchmark."
757
  : lb.is_aggregated
758
  ? "Averaged model results across the composite's component benchmarks, with drill-down to each component score."
759
- : "Model results with benchmark context, source dataset detail, and optional instance-data links."
760
  const reportingCompleteness = summary.evalcards?.annotations?.reporting_completeness
761
  const documentationPopulatedCount = reportingCompleteness
762
  ? getCompletenessPopulatedCount(reportingCompleteness)
@@ -784,6 +784,19 @@ export function EvalDetail({
784
  ? summary.composite_benchmark_name
785
  : null)
786
 
 
 
 
 
 
 
 
 
 
 
 
 
 
787
  const heroLede = isResearchView
788
  ? summary.metric_config.evaluation_description
789
  : (summary.benchmark_card?.benchmark_details?.overview?.trim()
@@ -794,6 +807,20 @@ export function EvalDetail({
794
  <div className="space-y-12">
795
  {/* HERO — paper §3.1 ------------------------------------------------ */}
796
  <header className="motion-academic-enter">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
797
  <h1
798
  className="font-bold tracking-[-0.025em]"
799
  style={{ fontSize: "clamp(40px, 5vw, 60px)", lineHeight: 1.04, margin: "0 0 12px" }}
@@ -934,7 +961,7 @@ export function EvalDetail({
934
  </dd>
935
  </>
936
  )}
937
- <dt>Source dataset</dt>
938
  <dd>{sourceDatasetLabel}</dd>
939
  <dt>Instance data</dt>
940
  <dd>{instanceDataLabel}</dd>
@@ -2628,58 +2655,71 @@ function BenchmarkCardPanel({
2628
  <div className="space-y-6 p-5 sm:p-6">
2629
  {knownIssues.length > 0 && <KnownIssuesPanel issues={knownIssues} variant="full" />}
2630
 
2631
- <div className="grid gap-3 sm:grid-cols-2 xl:grid-cols-3">
2632
- {/* Goal */}
2633
- <div
2634
- style={{
2635
- padding: 16,
2636
- border: "1px solid var(--border-soft)",
2637
- background: "var(--bg)",
2638
- }}
2639
- >
2640
- <div
2641
- className="mb-2 flex items-center gap-2 font-mono uppercase"
2642
- style={{ fontSize: 10, letterSpacing: "0.14em", color: "var(--fg-subtle)" }}
2643
- >
2644
- <Scale className="h-3 w-3" /> Goal
2645
- </div>
2646
- <p className="text-[13px] leading-[1.55]" style={{ color: "var(--fg)" }}>{purpose.goal}</p>
2647
- </div>
 
 
 
 
 
 
 
 
 
2648
 
2649
- {/* Metric interpretation */}
2650
- <div
2651
- style={{
2652
- padding: 16,
2653
- border: "1px solid var(--border-soft)",
2654
- background: "var(--bg)",
2655
- }}
2656
- >
2657
- <div
2658
- className="mb-2 flex items-center gap-2 font-mono uppercase"
2659
- style={{ fontSize: 10, letterSpacing: "0.14em", color: "var(--fg-subtle)" }}
2660
- >
2661
- <BarChart3 className="h-3 w-3" /> Score interpretation
2662
- </div>
2663
- <p className="text-[13px] leading-[1.55]" style={{ color: "var(--fg)" }}>{methodology.interpretation}</p>
2664
- </div>
 
2665
 
2666
- {/* Limitations */}
2667
- <div
2668
- style={{
2669
- padding: 16,
2670
- border: "1px solid var(--accent)",
2671
- background: "var(--bg-warm)",
2672
- }}
2673
- >
2674
- <div
2675
- className="mb-2 flex items-center gap-2 font-mono uppercase"
2676
- style={{ fontSize: 10, letterSpacing: "0.14em", color: "var(--accent)" }}
2677
- >
2678
- <AlertTriangle className="h-3 w-3" /> Limitations
 
 
 
 
2679
  </div>
2680
- <p className="text-[13px] leading-[1.55]" style={{ color: "var(--accent)" }}>{purpose.limitations}</p>
2681
- </div>
2682
- </div>
2683
 
2684
  {(methodology.methods?.length > 0 ||
2685
  (methodology.calculation && methodology.calculation !== "Not specified") ||
@@ -2879,43 +2919,56 @@ function BenchmarkCardPanel({
2879
  </Collapsible>
2880
  )}
2881
 
2882
- {/* Compliance / ethical notes (policy view emphasis) */}
2883
- {!isResearchView && (
2884
- <div
2885
- style={{
2886
- padding: 16,
2887
- border: "1px solid var(--border-soft)",
2888
- background: "var(--bg)",
2889
- }}
2890
- >
2891
- <div
2892
- className="mb-3 font-mono uppercase"
2893
- style={{ fontSize: 10, letterSpacing: "0.14em", color: "var(--fg-subtle)" }}
2894
- >
2895
- Ethical &amp; legal
2896
- </div>
2897
- <dl className="grid gap-x-6 gap-y-2 text-[13px] sm:grid-cols-2">
2898
- {shortLicense && (
2899
- <div className="flex gap-2">
2900
- <dt className="w-28 shrink-0" style={{ color: "var(--fg-muted)" }}>License</dt>
2901
- <dd className="font-medium">{license}</dd>
2902
- </div>
2903
- )}
2904
- {ethical.compliance_with_regulations && ethical.compliance_with_regulations !== "Not specified" && (
2905
- <div className="flex gap-2">
2906
- <dt className="w-28 shrink-0" style={{ color: "var(--fg-muted)" }}>Compliance</dt>
2907
- <dd className="font-medium">{ethical.compliance_with_regulations}</dd>
2908
- </div>
2909
- )}
2910
- {ethical.privacy_and_anonymity && ethical.privacy_and_anonymity !== "Not specified" && (
2911
- <div className="col-span-full flex gap-2">
2912
- <dt className="w-28 shrink-0" style={{ color: "var(--fg-muted)" }}>Privacy</dt>
2913
- <dd className="font-medium">{ethical.privacy_and_anonymity}</dd>
2914
  </div>
2915
- )}
2916
- </dl>
2917
- </div>
2918
- )}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2919
 
2920
  {/* Flagged / missing fields warning */}
2921
  {(flaggedFields.length > 0 || missingFields.length > 0) && isResearchView && (
 
756
  : "Models ranked by raw score for this benchmark."
757
  : lb.is_aggregated
758
  ? "Averaged model results across the composite's component benchmarks, with drill-down to each component score."
759
+ : "Model results with benchmark context, upstream dataset detail, and optional instance-data links."
760
  const reportingCompleteness = summary.evalcards?.annotations?.reporting_completeness
761
  const documentationPopulatedCount = reportingCompleteness
762
  ? getCompletenessPopulatedCount(reportingCompleteness)
 
784
  ? summary.composite_benchmark_name
785
  : null)
786
 
787
+ // Surface the evaluator (org that ran the eval) as a hero kicker. Two
788
+ // benchmarks can share the same upstream dataset (e.g. TIGER-Lab/MMLU-Pro
789
+ // re-evaluated by both TIGER-Lab and Arcadia Impact) and otherwise look
790
+ // identical in chrome — naming the evaluator up-front is the cheapest
791
+ // way to make the pages visually distinct.
792
+ const evaluatorList = summary.evaluator_names ?? []
793
+ const reporterLabel = (() => {
794
+ if (evaluatorList.length === 0) return null
795
+ const head = evaluatorList.slice(0, 2)
796
+ const extra = evaluatorList.length - head.length
797
+ return extra > 0 ? `${head.join(", ")} +${extra} more` : head.join(", ")
798
+ })()
799
+
800
  const heroLede = isResearchView
801
  ? summary.metric_config.evaluation_description
802
  : (summary.benchmark_card?.benchmark_details?.overview?.trim()
 
807
  <div className="space-y-12">
808
  {/* HERO — paper §3.1 ------------------------------------------------ */}
809
  <header className="motion-academic-enter">
810
+ {reporterLabel && (
811
+ <div
812
+ className="font-mono uppercase"
813
+ style={{
814
+ fontSize: 11,
815
+ letterSpacing: "0.16em",
816
+ color: "var(--fg-subtle)",
817
+ margin: "0 0 10px",
818
+ }}
819
+ >
820
+ <span style={{ color: "var(--fg-muted)" }}>Reported by </span>
821
+ <span style={{ color: "var(--fg)" }}>{reporterLabel}</span>
822
+ </div>
823
+ )}
824
  <h1
825
  className="font-bold tracking-[-0.025em]"
826
  style={{ fontSize: "clamp(40px, 5vw, 60px)", lineHeight: 1.04, margin: "0 0 12px" }}
 
961
  </dd>
962
  </>
963
  )}
964
+ <dt>Upstream dataset</dt>
965
  <dd>{sourceDatasetLabel}</dd>
966
  <dt>Instance data</dt>
967
  <dd>{instanceDataLabel}</dd>
 
2655
  <div className="space-y-6 p-5 sm:p-6">
2656
  {knownIssues.length > 0 && <KnownIssuesPanel issues={knownIssues} variant="full" />}
2657
 
2658
+ {(() => {
2659
+ const meaningful = (v: string | undefined | null) =>
2660
+ Boolean(v && v.trim() && v.trim() !== "Not specified")
2661
+ const showGoal = meaningful(purpose.goal)
2662
+ const showInterp = meaningful(methodology.interpretation)
2663
+ const showLimitations = meaningful(purpose.limitations)
2664
+ if (!showGoal && !showInterp && !showLimitations) return null
2665
+ return (
2666
+ <div className="grid gap-3 sm:grid-cols-2 xl:grid-cols-3">
2667
+ {showGoal && (
2668
+ <div
2669
+ style={{
2670
+ padding: 16,
2671
+ border: "1px solid var(--border-soft)",
2672
+ background: "var(--bg)",
2673
+ }}
2674
+ >
2675
+ <div
2676
+ className="mb-2 flex items-center gap-2 font-mono uppercase"
2677
+ style={{ fontSize: 10, letterSpacing: "0.14em", color: "var(--fg-subtle)" }}
2678
+ >
2679
+ <Scale className="h-3 w-3" /> Goal
2680
+ </div>
2681
+ <p className="text-[13px] leading-[1.55]" style={{ color: "var(--fg)" }}>{purpose.goal}</p>
2682
+ </div>
2683
+ )}
2684
 
2685
+ {showInterp && (
2686
+ <div
2687
+ style={{
2688
+ padding: 16,
2689
+ border: "1px solid var(--border-soft)",
2690
+ background: "var(--bg)",
2691
+ }}
2692
+ >
2693
+ <div
2694
+ className="mb-2 flex items-center gap-2 font-mono uppercase"
2695
+ style={{ fontSize: 10, letterSpacing: "0.14em", color: "var(--fg-subtle)" }}
2696
+ >
2697
+ <BarChart3 className="h-3 w-3" /> Score interpretation
2698
+ </div>
2699
+ <p className="text-[13px] leading-[1.55]" style={{ color: "var(--fg)" }}>{methodology.interpretation}</p>
2700
+ </div>
2701
+ )}
2702
 
2703
+ {showLimitations && (
2704
+ <div
2705
+ style={{
2706
+ padding: 16,
2707
+ border: "1px solid var(--accent)",
2708
+ background: "var(--bg-warm)",
2709
+ }}
2710
+ >
2711
+ <div
2712
+ className="mb-2 flex items-center gap-2 font-mono uppercase"
2713
+ style={{ fontSize: 10, letterSpacing: "0.14em", color: "var(--accent)" }}
2714
+ >
2715
+ <AlertTriangle className="h-3 w-3" /> Limitations
2716
+ </div>
2717
+ <p className="text-[13px] leading-[1.55]" style={{ color: "var(--accent)" }}>{purpose.limitations}</p>
2718
+ </div>
2719
+ )}
2720
  </div>
2721
+ )
2722
+ })()}
 
2723
 
2724
  {(methodology.methods?.length > 0 ||
2725
  (methodology.calculation && methodology.calculation !== "Not specified") ||
 
2919
  </Collapsible>
2920
  )}
2921
 
2922
+ {/* Compliance / ethical notes (policy view emphasis). Hide the
2923
+ entire panel when none of the three fields are populated —
2924
+ otherwise the user sees an empty bordered box with just the
2925
+ section header. */}
2926
+ {!isResearchView &&
2927
+ (() => {
2928
+ const showCompliance =
2929
+ ethical.compliance_with_regulations &&
2930
+ ethical.compliance_with_regulations !== "Not specified"
2931
+ const showPrivacy =
2932
+ ethical.privacy_and_anonymity &&
2933
+ ethical.privacy_and_anonymity !== "Not specified"
2934
+ if (!shortLicense && !showCompliance && !showPrivacy) return null
2935
+ return (
2936
+ <div
2937
+ style={{
2938
+ padding: 16,
2939
+ border: "1px solid var(--border-soft)",
2940
+ background: "var(--bg)",
2941
+ }}
2942
+ >
2943
+ <div
2944
+ className="mb-3 font-mono uppercase"
2945
+ style={{ fontSize: 10, letterSpacing: "0.14em", color: "var(--fg-subtle)" }}
2946
+ >
2947
+ Ethical &amp; legal
 
 
 
 
 
 
2948
  </div>
2949
+ <dl className="grid gap-x-6 gap-y-2 text-[13px] sm:grid-cols-2">
2950
+ {shortLicense && (
2951
+ <div className="flex gap-2">
2952
+ <dt className="w-28 shrink-0" style={{ color: "var(--fg-muted)" }}>License</dt>
2953
+ <dd className="font-medium">{license}</dd>
2954
+ </div>
2955
+ )}
2956
+ {showCompliance && (
2957
+ <div className="flex gap-2">
2958
+ <dt className="w-28 shrink-0" style={{ color: "var(--fg-muted)" }}>Compliance</dt>
2959
+ <dd className="font-medium">{ethical.compliance_with_regulations}</dd>
2960
+ </div>
2961
+ )}
2962
+ {showPrivacy && (
2963
+ <div className="col-span-full flex gap-2">
2964
+ <dt className="w-28 shrink-0" style={{ color: "var(--fg-muted)" }}>Privacy</dt>
2965
+ <dd className="font-medium">{ethical.privacy_and_anonymity}</dd>
2966
+ </div>
2967
+ )}
2968
+ </dl>
2969
+ </div>
2970
+ )
2971
+ })()}
2972
 
2973
  {/* Flagged / missing fields warning */}
2974
  {(flaggedFields.length > 0 || missingFields.length > 0) && isResearchView && (
components/policy-overview.tsx CHANGED
@@ -94,7 +94,7 @@ export function PolicyOverview({ summary }: PolicyOverviewProps) {
94
  .map((s) => s.composite_benchmark_name)
95
  .filter((s): s is string => typeof s === "string" && s.length > 0)
96
 
97
- const sliceLabels = useMemo(() => {
98
  const seen = new Set<string>()
99
  const labels: string[] = []
100
  const add = (raw: string | undefined | null) => {
@@ -106,8 +106,8 @@ export function PolicyOverview({ summary }: PolicyOverviewProps) {
106
  seen.add(key)
107
  labels.push(trimmed)
108
  }
109
- for (const slice of summary.subtasks ?? []) {
110
- add(slice.display_name || slice.subtask_name)
111
  }
112
  for (const metric of summary.leaderboard_metrics ?? []) {
113
  if (metric.scope === "subtask") {
@@ -119,14 +119,14 @@ export function PolicyOverview({ summary }: PolicyOverviewProps) {
119
  }, [summary.subtasks, summary.leaderboard_metrics, aggregateNames])
120
 
121
  const isMatrix = (summary.leaderboard_metrics?.length ?? 0) > 1
122
- const isParentPage = isAggregated || (isMatrix && sliceLabels.length > 1)
123
  const useComponentDescription = !isParentPage
124
 
125
- const parentFallback = isParentPage && sliceLabels.length > 1
126
- ? `${summary.evaluation_name} reports results across ${sliceLabels.length} ${
127
- isAggregated ? "component benchmarks" : "slices"
128
  }. Each is evaluated separately; the score shown is the ${
129
- isAggregated ? "average" : "per-slice result"
130
  }.`
131
  : null
132
 
@@ -139,7 +139,7 @@ export function PolicyOverview({ summary }: PolicyOverviewProps) {
139
  ""
140
 
141
  const [expanded, setExpanded] = useState(false)
142
- const [slicesOpen, setSlicesOpen] = useState(false)
143
  const isLong = summaryText.length > SUMMARY_PREVIEW_CHARS
144
  const visibleText = expanded || !isLong
145
  ? summaryText
@@ -148,13 +148,17 @@ export function PolicyOverview({ summary }: PolicyOverviewProps) {
148
  const domains = useMemo(() => {
149
  const fromTags = summary.tags?.domains ?? []
150
  const fromCard = cardMatchesEval ? card?.benchmark_details?.domains ?? [] : []
151
- return Array.from(new Set([...fromTags, ...fromCard].map((d) => d.trim()).filter(Boolean))).slice(0, 6)
 
 
152
  }, [summary.tags?.domains, card?.benchmark_details?.domains, cardMatchesEval])
153
 
154
  const languages = useMemo(() => {
155
  const fromTags = summary.tags?.languages ?? []
156
  const fromCard = cardMatchesEval ? card?.benchmark_details?.languages ?? [] : []
157
- return Array.from(new Set([...fromTags, ...fromCard].map((d) => d.trim()).filter(Boolean))).slice(0, 4)
 
 
158
  }, [summary.tags?.languages, card?.benchmark_details?.languages, cardMatchesEval])
159
 
160
  const license = card?.ethical_and_legal_considerations?.data_licensing
@@ -201,12 +205,22 @@ export function PolicyOverview({ summary }: PolicyOverviewProps) {
201
  : "Higher scores are better"
202
 
203
  // Policy-note triple (paper §4.2.2): What it measures · Main caveat · Intended for.
 
 
204
  const measuresText = visibleText
205
- const caveatText = card?.purpose_and_intended_users?.limitations?.trim() || null
 
 
206
  const audienceArr = card?.purpose_and_intended_users?.audience
207
- const audienceText = Array.isArray(audienceArr)
208
  ? audienceArr.filter(Boolean).join("; ")
209
- : (typeof audienceArr === "string" ? audienceArr : "")
 
 
 
 
 
 
210
 
211
  return (
212
  <section className="ec-card warm" style={{ padding: "20px 24px" }}>
@@ -304,41 +318,52 @@ export function PolicyOverview({ summary }: PolicyOverviewProps) {
304
  </dd>
305
  </dl>
306
 
307
- {isParentPage && sliceLabels.length > 1 && (
308
- <div
309
- className="mt-4"
310
- style={{ border: "1px solid var(--border-soft)", background: "var(--bg)" }}
311
- >
312
  <button
313
  type="button"
314
- onClick={() => setSlicesOpen((v) => !v)}
315
- aria-expanded={slicesOpen}
316
- className="flex w-full items-center justify-between gap-3 px-3.5 py-2.5 text-left transition-colors hover:bg-[color:var(--bg-warm)]"
 
 
 
 
 
 
317
  >
 
318
  <span
319
- className="flex items-center gap-1.5 font-mono uppercase"
320
- style={{ fontSize: 10, letterSpacing: "0.14em", color: "var(--fg-muted)" }}
321
  >
322
- <Layers className="h-3.5 w-3.5" />
323
- {isAggregated ? `Component benchmarks (${sliceLabels.length})` : `Slices (${sliceLabels.length})`}
 
324
  </span>
325
- {slicesOpen ? (
326
- <ChevronUp className="h-4 w-4" style={{ color: "var(--fg-muted)" }} />
327
  ) : (
328
- <ChevronDown className="h-4 w-4" style={{ color: "var(--fg-muted)" }} />
329
  )}
330
  </button>
331
- {slicesOpen && (
332
- <ul
333
- className="grid list-disc gap-x-6 gap-y-1 px-3.5 pb-3.5 pl-9 text-[13px] sm:grid-cols-2 lg:grid-cols-3"
334
- style={{ color: "var(--fg)" }}
335
- >
336
- {sliceLabels.map((name) => (
337
- <li key={name} className="capitalize">
 
 
 
 
 
 
338
  {name}
339
- </li>
340
  ))}
341
- </ul>
342
  )}
343
  </div>
344
  )}
 
94
  .map((s) => s.composite_benchmark_name)
95
  .filter((s): s is string => typeof s === "string" && s.length > 0)
96
 
97
+ const splitLabels = useMemo(() => {
98
  const seen = new Set<string>()
99
  const labels: string[] = []
100
  const add = (raw: string | undefined | null) => {
 
106
  seen.add(key)
107
  labels.push(trimmed)
108
  }
109
+ for (const split of summary.subtasks ?? []) {
110
+ add(split.display_name || split.subtask_name)
111
  }
112
  for (const metric of summary.leaderboard_metrics ?? []) {
113
  if (metric.scope === "subtask") {
 
119
  }, [summary.subtasks, summary.leaderboard_metrics, aggregateNames])
120
 
121
  const isMatrix = (summary.leaderboard_metrics?.length ?? 0) > 1
122
+ const isParentPage = isAggregated || (isMatrix && splitLabels.length > 1)
123
  const useComponentDescription = !isParentPage
124
 
125
+ const parentFallback = isParentPage && splitLabels.length > 1
126
+ ? `${summary.evaluation_name} reports results across ${splitLabels.length} ${
127
+ isAggregated ? "component benchmarks" : "splits"
128
  }. Each is evaluated separately; the score shown is the ${
129
+ isAggregated ? "average" : "per-split result"
130
  }.`
131
  : null
132
 
 
139
  ""
140
 
141
  const [expanded, setExpanded] = useState(false)
142
+ const [splitsOpen, setSplitsOpen] = useState(false)
143
  const isLong = summaryText.length > SUMMARY_PREVIEW_CHARS
144
  const visibleText = expanded || !isLong
145
  ? summaryText
 
148
  const domains = useMemo(() => {
149
  const fromTags = summary.tags?.domains ?? []
150
  const fromCard = cardMatchesEval ? card?.benchmark_details?.domains ?? [] : []
151
+ return Array.from(new Set([...fromTags, ...fromCard].map((d) => d.trim()).filter(Boolean)))
152
+ .filter((d) => d.toLowerCase() !== "not specified")
153
+ .slice(0, 6)
154
  }, [summary.tags?.domains, card?.benchmark_details?.domains, cardMatchesEval])
155
 
156
  const languages = useMemo(() => {
157
  const fromTags = summary.tags?.languages ?? []
158
  const fromCard = cardMatchesEval ? card?.benchmark_details?.languages ?? [] : []
159
+ return Array.from(new Set([...fromTags, ...fromCard].map((d) => d.trim()).filter(Boolean)))
160
+ .filter((d) => d.toLowerCase() !== "not specified")
161
+ .slice(0, 4)
162
  }, [summary.tags?.languages, card?.benchmark_details?.languages, cardMatchesEval])
163
 
164
  const license = card?.ethical_and_legal_considerations?.data_licensing
 
205
  : "Higher scores are better"
206
 
207
  // Policy-note triple (paper §4.2.2): What it measures · Main caveat · Intended for.
208
+ // Filter the literal "Not specified" sentinel so the row collapses
209
+ // entirely instead of rendering a placeholder.
210
  const measuresText = visibleText
211
+ const rawCaveat = card?.purpose_and_intended_users?.limitations?.trim() || ""
212
+ const caveatText =
213
+ rawCaveat && rawCaveat.toLowerCase() !== "not specified" ? rawCaveat : null
214
  const audienceArr = card?.purpose_and_intended_users?.audience
215
+ const audienceJoined = Array.isArray(audienceArr)
216
  ? audienceArr.filter(Boolean).join("; ")
217
+ : typeof audienceArr === "string"
218
+ ? audienceArr
219
+ : ""
220
+ const audienceText =
221
+ audienceJoined && audienceJoined.toLowerCase() !== "not specified"
222
+ ? audienceJoined
223
+ : ""
224
 
225
  return (
226
  <section className="ec-card warm" style={{ padding: "20px 24px" }}>
 
318
  </dd>
319
  </dl>
320
 
321
+ {isParentPage && splitLabels.length > 1 && (
322
+ <div className="mt-4">
 
 
 
323
  <button
324
  type="button"
325
+ onClick={() => setSplitsOpen((v) => !v)}
326
+ aria-expanded={splitsOpen}
327
+ className="inline-flex items-center gap-1.5 cursor-pointer hover:text-[color:var(--fg)] transition-colors"
328
+ style={{
329
+ background: "transparent",
330
+ border: 0,
331
+ padding: 0,
332
+ color: "var(--fg-subtle)",
333
+ }}
334
  >
335
+ <Layers className="h-3.5 w-3.5" />
336
  <span
337
+ className="font-mono uppercase"
338
+ style={{ fontSize: 10, letterSpacing: "0.14em" }}
339
  >
340
+ {isAggregated
341
+ ? `Component benchmarks · ${splitLabels.length}`
342
+ : `Splits · ${splitLabels.length}`}
343
  </span>
344
+ {splitsOpen ? (
345
+ <ChevronUp className="h-3.5 w-3.5" />
346
  ) : (
347
+ <ChevronDown className="h-3.5 w-3.5" />
348
  )}
349
  </button>
350
+ {splitsOpen && (
351
+ <div className="mt-2 flex flex-wrap gap-1.5">
352
+ {splitLabels.map((name) => (
353
+ <span
354
+ key={name}
355
+ className="ec-tag outline"
356
+ style={{
357
+ textTransform: "none",
358
+ fontFamily: "var(--font-mono)",
359
+ fontSize: 11,
360
+ letterSpacing: "0.02em",
361
+ }}
362
+ >
363
  {name}
364
+ </span>
365
  ))}
366
+ </div>
367
  )}
368
  </div>
369
  )}