@sonordev/agency-site-kit 0.4.1 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/dist/{chunk-QGSW43TM.cjs → chunk-2Y2RJB3A.cjs} +12 -12
  2. package/dist/{chunk-QGSW43TM.cjs.map → chunk-2Y2RJB3A.cjs.map} +1 -1
  3. package/dist/{chunk-UXUU7FVT.cjs → chunk-6OWFFV6N.cjs} +4 -65
  4. package/dist/chunk-6OWFFV6N.cjs.map +1 -0
  5. package/dist/{chunk-NLGUPJZA.js → chunk-7FFZX7C5.js} +4 -4
  6. package/dist/{chunk-NLGUPJZA.js.map → chunk-7FFZX7C5.js.map} +1 -1
  7. package/dist/{chunk-7ZHRMWJU.cjs → chunk-A5WCMHAE.cjs} +2 -2
  8. package/dist/{chunk-7ZHRMWJU.cjs.map → chunk-A5WCMHAE.cjs.map} +1 -1
  9. package/dist/chunk-FM25LB67.js +50 -0
  10. package/dist/chunk-FM25LB67.js.map +1 -0
  11. package/dist/{chunk-KXLROAO5.js → chunk-FT2SNEYP.js} +2 -2
  12. package/dist/{chunk-KXLROAO5.js.map → chunk-FT2SNEYP.js.map} +1 -1
  13. package/dist/chunk-X76U7VLF.cjs +57 -0
  14. package/dist/chunk-X76U7VLF.cjs.map +1 -0
  15. package/dist/{chunk-RWQ675N6.js → chunk-X7UCJ45A.js} +4 -61
  16. package/dist/chunk-X7UCJ45A.js.map +1 -0
  17. package/dist/format-C-axf13G.d.cts +68 -0
  18. package/dist/format-poUpLtQ2.d.ts +68 -0
  19. package/dist/index.cjs +18 -17
  20. package/dist/index.cjs.map +1 -1
  21. package/dist/index.d.cts +5 -3
  22. package/dist/index.d.ts +5 -3
  23. package/dist/index.js +4 -3
  24. package/dist/index.js.map +1 -1
  25. package/dist/layout/index.d.cts +1 -1
  26. package/dist/layout/index.d.ts +1 -1
  27. package/dist/portfolio/client.cjs +2 -17
  28. package/dist/portfolio/client.cjs.map +1 -1
  29. package/dist/portfolio/client.js +1 -16
  30. package/dist/portfolio/client.js.map +1 -1
  31. package/dist/portfolio/index.cjs +18 -17
  32. package/dist/portfolio/index.d.cts +5 -74
  33. package/dist/portfolio/index.d.ts +5 -74
  34. package/dist/portfolio/index.js +4 -3
  35. package/dist/portfolio/sections/ChallengesSection.d.cts +1 -1
  36. package/dist/portfolio/sections/ChallengesSection.d.ts +1 -1
  37. package/dist/portfolio/sections/DetailsSection.d.cts +1 -1
  38. package/dist/portfolio/sections/DetailsSection.d.ts +1 -1
  39. package/dist/portfolio/sections/HeroSection.d.cts +1 -1
  40. package/dist/portfolio/sections/HeroSection.d.ts +1 -1
  41. package/dist/portfolio/sections/ResultsSection.cjs +4 -3
  42. package/dist/portfolio/sections/ResultsSection.cjs.map +1 -1
  43. package/dist/portfolio/sections/ResultsSection.d.cts +1 -1
  44. package/dist/portfolio/sections/ResultsSection.d.ts +1 -1
  45. package/dist/portfolio/sections/ResultsSection.js +2 -1
  46. package/dist/portfolio/sections/ResultsSection.js.map +1 -1
  47. package/dist/portfolio/sections/ServicesSection.d.cts +1 -1
  48. package/dist/portfolio/sections/ServicesSection.d.ts +1 -1
  49. package/dist/portfolio/sections/TechStackSection.d.cts +1 -1
  50. package/dist/portfolio/sections/TechStackSection.d.ts +1 -1
  51. package/dist/portfolio/sections/TestimonialSection.d.cts +1 -1
  52. package/dist/portfolio/sections/TestimonialSection.d.ts +1 -1
  53. package/dist/portfolio/server.cjs +40 -14
  54. package/dist/portfolio/server.d.cts +3 -1
  55. package/dist/portfolio/server.d.ts +3 -1
  56. package/dist/portfolio/server.js +3 -1
  57. package/dist/{types-0tVPy4pU.d.ts → types-He5A9okM.d.cts} +1 -1
  58. package/dist/{types-0tVPy4pU.d.cts → types-He5A9okM.d.ts} +1 -1
  59. package/package.json +3 -3
  60. package/dist/chunk-RWQ675N6.js.map +0 -1
  61. package/dist/chunk-UXUU7FVT.cjs.map +0 -1
@@ -1,7 +1,9 @@
1
1
  import React from 'react';
2
- import { P as PortfolioItemFull, M as MetricsDelta, x as PortfolioKPI, A as PortfolioResultItem } from '../types-0tVPy4pU.js';
3
- export { j as MetricSource, k as MetricsSnapshot, l as PORTFOLIO_SECTION_TYPES, n as PortfolioBeforeAfterData, o as PortfolioCTAData, c as PortfolioChallengesData, r as PortfolioConversionFunnelData, d as PortfolioDetailsData, s as PortfolioFeatureSpotlightData, u as PortfolioGalleryData, e as PortfolioHeroData, w as PortfolioItem, b as PortfolioListResponse, z as PortfolioMetricsTimelineData, f as PortfolioResultsData, a as PortfolioSection, C as PortfolioSectionData, D as PortfolioSectionDataMap, E as PortfolioSectionType, F as PortfolioSeoData, g as PortfolioServicesData, H as PortfolioStrategyData, J as PortfolioTeamData, h as PortfolioTechStackData, i as PortfolioTestimonialData, N as PortfolioVideoData } from '../types-0tVPy4pU.js';
2
+ import { P as PortfolioItemFull, M as MetricsDelta } from '../types-He5A9okM.js';
3
+ export { k as MetricSource, l as MetricsSnapshot, m as PORTFOLIO_SECTION_TYPES, o as PortfolioBeforeAfterData, p as PortfolioCTAData, c as PortfolioChallengesData, s as PortfolioConversionFunnelData, d as PortfolioDetailsData, t as PortfolioFeatureSpotlightData, v as PortfolioGalleryData, e as PortfolioHeroData, x as PortfolioItem, y as PortfolioKPI, b as PortfolioListResponse, A as PortfolioMetricsTimelineData, f as PortfolioResultsData, a as PortfolioSection, C as PortfolioSectionData, D as PortfolioSectionDataMap, E as PortfolioSectionType, F as PortfolioSeoData, g as PortfolioServicesData, H as PortfolioStrategyData, J as PortfolioTeamData, h as PortfolioTechStackData, i as PortfolioTestimonialData, N as PortfolioVideoData } from '../types-He5A9okM.js';
4
+ export { c as curatePortfolioProof, a as curateResultItems, f as formatCategoryLabel, b as formatServiceTag, g as gateMetricsDeltas } from '../format-poUpLtQ2.js';
4
5
  export * from '@sonordev/agency-site-kit/portfolio/client';
6
+ export { curateHeroKpis } from '@sonordev/site-kit/portfolio/contract';
5
7
 
6
8
  /**
7
9
  * PortfolioPage — Server component that renders a full portfolio case study.
@@ -125,77 +127,6 @@ interface MetricsProvenanceProps {
125
127
  }
126
128
  declare function MetricsProvenance({ deltas, refreshedAt }: MetricsProvenanceProps): React.JSX.Element | null;
127
129
 
128
- /**
129
- * curate-proof — single source of truth for which proof points a public case
130
- * study is allowed to display, and in what shape.
131
- *
132
- * Two classes of problem this guards against (both shipped to production on
133
- * upforge.io before this existed):
134
- *
135
- * 1. Repetition: generated items arrive with four "100/100 Lighthouse X"
136
- * KPIs in the hero, the same four restated as Results cards, AND a full
137
- * Performance section with score gauges. One differentiator repeated
138
- * twelve times per page stops differentiating. The Performance section is
139
- * the one home for the Lighthouse breakdown; hero/results/cards collapse
140
- * to at most one summary tile.
141
- *
142
- * 2. Self-harming live metrics: MetricsDelta rows are computed from raw
143
- * analytics baselines with no editorial judgment — a bounce rate of
144
- * "100 → 99.69" rendered as a green win. Marketing surfaces only show a
145
- * delta when it's a genuinely flattering, meaningful story.
146
- *
147
- * Used by PortfolioPage (hero KPIs + results items), PortfolioCard (KPI
148
- * preview), and MetricsProvenance (delta gate). Change display policy here,
149
- * nowhere else.
150
- */
151
-
152
- /**
153
- * Collapse per-category Lighthouse KPIs to at most one summary tile, business
154
- * outcomes first. When every category is present at 100 the summary says so;
155
- * otherwise the Performance category (the one buyers know) represents the set.
156
- */
157
- declare function curateHeroKpis(kpis: PortfolioKPI[]): PortfolioKPI[];
158
- /**
159
- * Drop Results cards that restate Lighthouse scores when the case study also
160
- * renders a Performance section (the score breakdown's single home).
161
- */
162
- declare function curateResultItems(items: PortfolioResultItem[], hasPerformanceSection: boolean): PortfolioResultItem[];
163
- /**
164
- * Editorial gate for live metric deltas ("Verified from live analytics").
165
- * `direction` comes from the platform with 'up' meaning IMPROVED (lower-is-
166
- * better metrics are inverted server-side). A public case study only shows a
167
- * delta when it's a win worth telling:
168
- * - improved ('up'), never a regression or flat noise
169
- * - moved by a double-digit relative margin (small drift isn't a story)
170
- * - bounce-rate-style metrics must also be respectable in absolute terms —
171
- * "100 → 99.69" is technically an improvement and still self-harm
172
- */
173
- declare function gateMetricsDeltas(deltas: MetricsDelta[] | undefined | null): MetricsDelta[];
174
- /**
175
- * Apply the full display policy to a portfolio item before rendering.
176
- * Pure — returns a new item; the fetched payload is never mutated.
177
- */
178
- declare function curatePortfolioProof(item: PortfolioItemFull): PortfolioItemFull;
179
-
180
- /**
181
- * Presentation formatters shared by portfolio components and consuming apps.
182
- */
183
- /**
184
- * Human label for a category slug. Single source of truth — HeroSection,
185
- * PortfolioCard, and app-side filter chips all render categories through
186
- * this. Underscores become spaces; hyphens are PRESERVED so compound slugs
187
- * keep their canonical form ("e-commerce" → "E-Commerce", never "E Commerce"),
188
- * and every word start (including after a hyphen) is capitalized.
189
- */
190
- declare function formatCategoryLabel(slug: string | undefined | null): string;
191
- /**
192
- * Normalize a service tag's casing for display: the first character of each
193
- * word is uppercased, the rest left alone (so "Next.js development" becomes
194
- * "Next.js Development" and "Technical SEO implementation" keeps "SEO").
195
- * Fixes per-item casing drift in stored tags without touching the data.
196
- */
197
- declare function formatServiceTag(tag: string | undefined | null): string;
198
-
199
130
  /**
200
131
  * Loading skeletons for portfolio routes — pure CSS pulse, server-safe,
201
132
  * zero JS. Drop into `loading.tsx`:
@@ -212,4 +143,4 @@ declare function PortfolioIndexSkeleton({ cards }: {
212
143
  /** Hero-shaped placeholder for /work/[slug] case study pages. */
213
144
  declare function PortfolioPageSkeleton(): React.JSX.Element;
214
145
 
215
- export { MetricsDelta, MetricsProvenance, PortfolioIndex, type PortfolioIndexProps, PortfolioIndexSkeleton, PortfolioItemFull, PortfolioKPI, PortfolioPage, PortfolioPageSkeleton, PortfolioSchema, curateHeroKpis, curatePortfolioProof, curateResultItems, formatCategoryLabel, formatServiceTag, gateMetricsDeltas };
146
+ export { MetricsDelta, MetricsProvenance, PortfolioIndex, type PortfolioIndexProps, PortfolioIndexSkeleton, PortfolioItemFull, PortfolioPage, PortfolioPageSkeleton, PortfolioSchema };
@@ -1,7 +1,8 @@
1
- export { PORTFOLIO_SECTION_TYPES, PortfolioIndex, PortfolioIndexSkeleton, PortfolioPage, PortfolioPageSkeleton, PortfolioSchema } from '../chunk-NLGUPJZA.js';
1
+ export { PORTFOLIO_SECTION_TYPES, PortfolioIndex, PortfolioIndexSkeleton, PortfolioPage, PortfolioPageSkeleton, PortfolioSchema } from '../chunk-7FFZX7C5.js';
2
+ export { MetricsProvenance } from '../chunk-X7UCJ45A.js';
3
+ import '../chunk-FT2SNEYP.js';
2
4
  export { formatCategoryLabel, formatServiceTag } from '../chunk-7D4H36UF.js';
3
- export { MetricsProvenance, curateHeroKpis, curatePortfolioProof, curateResultItems, gateMetricsDeltas } from '../chunk-RWQ675N6.js';
4
- import '../chunk-KXLROAO5.js';
5
+ export { curateHeroKpis, curatePortfolioProof, curateResultItems, gateMetricsDeltas } from '../chunk-FM25LB67.js';
5
6
  import '../chunk-N7TVKUYQ.js';
6
7
  import '../chunk-L4EOQVRJ.js';
7
8
  import '../chunk-QL6KVIFR.js';
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { c as PortfolioChallengesData } from '../../types-0tVPy4pU.cjs';
2
+ import { c as PortfolioChallengesData } from '../../types-He5A9okM.cjs';
3
3
 
4
4
  interface ChallengesSectionProps {
5
5
  data: PortfolioChallengesData;
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { c as PortfolioChallengesData } from '../../types-0tVPy4pU.js';
2
+ import { c as PortfolioChallengesData } from '../../types-He5A9okM.js';
3
3
 
4
4
  interface ChallengesSectionProps {
5
5
  data: PortfolioChallengesData;
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { d as PortfolioDetailsData } from '../../types-0tVPy4pU.cjs';
2
+ import { d as PortfolioDetailsData } from '../../types-He5A9okM.cjs';
3
3
 
4
4
  interface DetailsSectionProps {
5
5
  data: PortfolioDetailsData;
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { d as PortfolioDetailsData } from '../../types-0tVPy4pU.js';
2
+ import { d as PortfolioDetailsData } from '../../types-He5A9okM.js';
3
3
 
4
4
  interface DetailsSectionProps {
5
5
  data: PortfolioDetailsData;
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { e as PortfolioHeroData } from '../../types-0tVPy4pU.cjs';
2
+ import { e as PortfolioHeroData } from '../../types-He5A9okM.cjs';
3
3
 
4
4
  interface HeroSectionProps {
5
5
  data: PortfolioHeroData;
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { e as PortfolioHeroData } from '../../types-0tVPy4pU.js';
2
+ import { e as PortfolioHeroData } from '../../types-He5A9okM.js';
3
3
 
4
4
  interface HeroSectionProps {
5
5
  data: PortfolioHeroData;
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var chunkUXUU7FVT_cjs = require('../../chunk-UXUU7FVT.cjs');
3
+ var chunk6OWFFV6N_cjs = require('../../chunk-6OWFFV6N.cjs');
4
+ var chunkX76U7VLF_cjs = require('../../chunk-X76U7VLF.cjs');
4
5
  var ScrollReveal = require('@sonordev/agency-site-kit/portfolio/primitives/ScrollReveal');
5
6
  var AnimatedCounter = require('@sonordev/agency-site-kit/portfolio/primitives/AnimatedCounter');
6
7
  var GlassCard = require('@sonordev/agency-site-kit/portfolio/primitives/GlassCard');
@@ -17,7 +18,7 @@ function ResultsSection({
17
18
  metricsDelta,
18
19
  metricsRefreshedAt
19
20
  }) {
20
- if (!data.items.length && !chunkUXUU7FVT_cjs.gateMetricsDeltas(metricsDelta).length) return null;
21
+ if (!data.items.length && !chunkX76U7VLF_cjs.gateMetricsDeltas(metricsDelta).length) return null;
21
22
  return /* @__PURE__ */ jsxRuntime.jsx(
22
23
  "section",
23
24
  {
@@ -97,7 +98,7 @@ function ResultsSection({
97
98
  }
98
99
  )
99
100
  ] }) }, index)) }) }),
100
- metricsDelta && metricsDelta.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(ScrollReveal__default.default, { y: 30, delay: 0.1, children: /* @__PURE__ */ jsxRuntime.jsx(chunkUXUU7FVT_cjs.MetricsProvenance, { deltas: metricsDelta, refreshedAt: metricsRefreshedAt }) })
101
+ metricsDelta && metricsDelta.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(ScrollReveal__default.default, { y: 30, delay: 0.1, children: /* @__PURE__ */ jsxRuntime.jsx(chunk6OWFFV6N_cjs.MetricsProvenance, { deltas: metricsDelta, refreshedAt: metricsRefreshedAt }) })
101
102
  ] })
102
103
  }
103
104
  );
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/portfolio/components/sections/ResultsSection.tsx"],"names":["gateMetricsDeltas","jsx","jsxs","ScrollReveal","GlassCard","AnimatedCounter","MetricsProvenance"],"mappings":"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","file":"ResultsSection.cjs","sourcesContent":["// Server component — renders on the server; the client primitives below cross the\n// RSC boundary via package subpaths (never import them relatively here).\nimport React from 'react';\nimport type { MetricsDelta, PortfolioResultsData } from '../../../types';\nimport ScrollReveal from '@sonordev/agency-site-kit/portfolio/primitives/ScrollReveal';\nimport AnimatedCounter from '@sonordev/agency-site-kit/portfolio/primitives/AnimatedCounter';\nimport GlassCard from '@sonordev/agency-site-kit/portfolio/primitives/GlassCard';\nimport MetricsProvenance from '../MetricsProvenance';\nimport { gateMetricsDeltas } from '../../curate-proof';\n\ninterface ResultsSectionProps {\n data: PortfolioResultsData;\n /** Live metric deltas computed by the platform (item.metricsDelta). */\n metricsDelta?: MetricsDelta[];\n /** ISO timestamp of the last live-metrics refresh. */\n metricsRefreshedAt?: string | null;\n}\n\nexport default function ResultsSection({\n data,\n metricsDelta,\n metricsRefreshedAt,\n}: ResultsSectionProps) {\n // Nothing survives display curation → no section, not an empty header.\n if (!data.items.length && !gateMetricsDeltas(metricsDelta).length) return null;\n\n return (\n <section\n className=\"w-full py-20 md:py-28\"\n style={{ background: 'var(--sk-bg, #0a0a0a)' }}\n >\n <div className=\"max-w-7xl mx-auto px-6\">\n <ScrollReveal y={30}>\n <h2\n className=\"text-3xl md:text-4xl font-bold mb-4\"\n style={{\n color: 'var(--sk-text-primary, #ffffff)',\n fontFamily: 'var(--sk-font-heading, inherit)',\n }}\n >\n Results\n </h2>\n <p\n className=\"text-lg mb-12 max-w-2xl\"\n style={{ color: 'var(--sk-text-secondary, #a1a1aa)' }}\n >\n Measurable outcomes that speak for themselves.\n </p>\n </ScrollReveal>\n\n <ScrollReveal stagger={0.1}>\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6\">\n {data.items.map((item, index) => (\n <GlassCard key={index} padding=\"lg\" hover>\n <div className=\"flex flex-col gap-3\">\n {/* Metric counter */}\n {item.metric && (\n <div\n className=\"text-3xl md:text-4xl font-bold\"\n style={{ color: 'var(--sk-primary, #6366f1)' }}\n >\n <AnimatedCounter\n value={item.metric.value}\n suffix={item.metric.suffix}\n prefix={item.metric.prefix}\n duration={2.5}\n />\n </div>\n )}\n\n <h3\n className=\"text-lg font-semibold\"\n style={{ color: 'var(--sk-text-primary, #ffffff)' }}\n >\n {item.title}\n </h3>\n\n <p\n className=\"text-sm leading-relaxed\"\n style={{ color: 'var(--sk-text-tertiary, #71717a)' }}\n >\n {item.description}\n </p>\n\n {/* Source badge */}\n <span\n className=\"inline-flex self-start items-center gap-1 px-2.5 py-1 rounded-full text-[11px] uppercase tracking-wider font-medium mt-1\"\n style={{\n background:\n item.source === 'measured'\n ? 'color-mix(in srgb, #10b981 12%, transparent)'\n : 'color-mix(in srgb, #f59e0b 12%, transparent)',\n color: item.source === 'measured' ? '#10b981' : '#f59e0b',\n border: `1px solid ${\n item.source === 'measured'\n ? 'color-mix(in srgb, #10b981 20%, transparent)'\n : 'color-mix(in srgb, #f59e0b 20%, transparent)'\n }`,\n }}\n >\n {item.source === 'measured' ? (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\">\n <path d=\"M10 3L4.5 8.5 2 6\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n ) : (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\">\n <circle cx=\"6\" cy=\"6\" r=\"4\" stroke=\"currentColor\" strokeWidth=\"1.5\" />\n <path d=\"M6 4v2.5l1.5 1\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" />\n </svg>\n )}\n {item.source}\n </span>\n </div>\n </GlassCard>\n ))}\n </div>\n </ScrollReveal>\n\n {/* Live verified metrics — the numbers a static portfolio can't fake */}\n {metricsDelta && metricsDelta.length > 0 && (\n <ScrollReveal y={30} delay={0.1}>\n <MetricsProvenance deltas={metricsDelta} refreshedAt={metricsRefreshedAt} />\n </ScrollReveal>\n )}\n </div>\n </section>\n );\n}\n"]}
1
+ {"version":3,"sources":["../../../src/portfolio/components/sections/ResultsSection.tsx"],"names":["gateMetricsDeltas","jsx","jsxs","ScrollReveal","GlassCard","AnimatedCounter","MetricsProvenance"],"mappings":"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","file":"ResultsSection.cjs","sourcesContent":["// Server component — renders on the server; the client primitives below cross the\n// RSC boundary via package subpaths (never import them relatively here).\nimport React from 'react';\nimport type { MetricsDelta, PortfolioResultsData } from '../../../types';\nimport ScrollReveal from '@sonordev/agency-site-kit/portfolio/primitives/ScrollReveal';\nimport AnimatedCounter from '@sonordev/agency-site-kit/portfolio/primitives/AnimatedCounter';\nimport GlassCard from '@sonordev/agency-site-kit/portfolio/primitives/GlassCard';\nimport MetricsProvenance from '../MetricsProvenance';\nimport { gateMetricsDeltas } from '../../curate-proof';\n\ninterface ResultsSectionProps {\n data: PortfolioResultsData;\n /** Live metric deltas computed by the platform (item.metricsDelta). */\n metricsDelta?: MetricsDelta[];\n /** ISO timestamp of the last live-metrics refresh. */\n metricsRefreshedAt?: string | null;\n}\n\nexport default function ResultsSection({\n data,\n metricsDelta,\n metricsRefreshedAt,\n}: ResultsSectionProps) {\n // Nothing survives display curation → no section, not an empty header.\n if (!data.items.length && !gateMetricsDeltas(metricsDelta).length) return null;\n\n return (\n <section\n className=\"w-full py-20 md:py-28\"\n style={{ background: 'var(--sk-bg, #0a0a0a)' }}\n >\n <div className=\"max-w-7xl mx-auto px-6\">\n <ScrollReveal y={30}>\n <h2\n className=\"text-3xl md:text-4xl font-bold mb-4\"\n style={{\n color: 'var(--sk-text-primary, #ffffff)',\n fontFamily: 'var(--sk-font-heading, inherit)',\n }}\n >\n Results\n </h2>\n <p\n className=\"text-lg mb-12 max-w-2xl\"\n style={{ color: 'var(--sk-text-secondary, #a1a1aa)' }}\n >\n Measurable outcomes that speak for themselves.\n </p>\n </ScrollReveal>\n\n <ScrollReveal stagger={0.1}>\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6\">\n {data.items.map((item, index) => (\n <GlassCard key={index} padding=\"lg\" hover>\n <div className=\"flex flex-col gap-3\">\n {/* Metric counter */}\n {item.metric && (\n <div\n className=\"text-3xl md:text-4xl font-bold\"\n style={{ color: 'var(--sk-primary, #6366f1)' }}\n >\n <AnimatedCounter\n value={item.metric.value}\n suffix={item.metric.suffix}\n prefix={item.metric.prefix}\n duration={2.5}\n />\n </div>\n )}\n\n <h3\n className=\"text-lg font-semibold\"\n style={{ color: 'var(--sk-text-primary, #ffffff)' }}\n >\n {item.title}\n </h3>\n\n <p\n className=\"text-sm leading-relaxed\"\n style={{ color: 'var(--sk-text-tertiary, #71717a)' }}\n >\n {item.description}\n </p>\n\n {/* Source badge */}\n <span\n className=\"inline-flex self-start items-center gap-1 px-2.5 py-1 rounded-full text-[11px] uppercase tracking-wider font-medium mt-1\"\n style={{\n background:\n item.source === 'measured'\n ? 'color-mix(in srgb, #10b981 12%, transparent)'\n : 'color-mix(in srgb, #f59e0b 12%, transparent)',\n color: item.source === 'measured' ? '#10b981' : '#f59e0b',\n border: `1px solid ${\n item.source === 'measured'\n ? 'color-mix(in srgb, #10b981 20%, transparent)'\n : 'color-mix(in srgb, #f59e0b 20%, transparent)'\n }`,\n }}\n >\n {item.source === 'measured' ? (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\">\n <path d=\"M10 3L4.5 8.5 2 6\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n ) : (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\">\n <circle cx=\"6\" cy=\"6\" r=\"4\" stroke=\"currentColor\" strokeWidth=\"1.5\" />\n <path d=\"M6 4v2.5l1.5 1\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" />\n </svg>\n )}\n {item.source}\n </span>\n </div>\n </GlassCard>\n ))}\n </div>\n </ScrollReveal>\n\n {/* Live verified metrics — the numbers a static portfolio can't fake */}\n {metricsDelta && metricsDelta.length > 0 && (\n <ScrollReveal y={30} delay={0.1}>\n <MetricsProvenance deltas={metricsDelta} refreshedAt={metricsRefreshedAt} />\n </ScrollReveal>\n )}\n </div>\n </section>\n );\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { f as PortfolioResultsData, M as MetricsDelta } from '../../types-0tVPy4pU.cjs';
2
+ import { f as PortfolioResultsData, M as MetricsDelta } from '../../types-He5A9okM.cjs';
3
3
 
4
4
  interface ResultsSectionProps {
5
5
  data: PortfolioResultsData;
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { f as PortfolioResultsData, M as MetricsDelta } from '../../types-0tVPy4pU.js';
2
+ import { f as PortfolioResultsData, M as MetricsDelta } from '../../types-He5A9okM.js';
3
3
 
4
4
  interface ResultsSectionProps {
5
5
  data: PortfolioResultsData;
@@ -1,4 +1,5 @@
1
- import { gateMetricsDeltas, MetricsProvenance } from '../../chunk-RWQ675N6.js';
1
+ import { MetricsProvenance } from '../../chunk-X7UCJ45A.js';
2
+ import { gateMetricsDeltas } from '../../chunk-FM25LB67.js';
2
3
  import ScrollReveal from '@sonordev/agency-site-kit/portfolio/primitives/ScrollReveal';
3
4
  import AnimatedCounter from '@sonordev/agency-site-kit/portfolio/primitives/AnimatedCounter';
4
5
  import GlassCard from '@sonordev/agency-site-kit/portfolio/primitives/GlassCard';
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/portfolio/components/sections/ResultsSection.tsx"],"names":[],"mappings":"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","file":"ResultsSection.js","sourcesContent":["// Server component — renders on the server; the client primitives below cross the\n// RSC boundary via package subpaths (never import them relatively here).\nimport React from 'react';\nimport type { MetricsDelta, PortfolioResultsData } from '../../../types';\nimport ScrollReveal from '@sonordev/agency-site-kit/portfolio/primitives/ScrollReveal';\nimport AnimatedCounter from '@sonordev/agency-site-kit/portfolio/primitives/AnimatedCounter';\nimport GlassCard from '@sonordev/agency-site-kit/portfolio/primitives/GlassCard';\nimport MetricsProvenance from '../MetricsProvenance';\nimport { gateMetricsDeltas } from '../../curate-proof';\n\ninterface ResultsSectionProps {\n data: PortfolioResultsData;\n /** Live metric deltas computed by the platform (item.metricsDelta). */\n metricsDelta?: MetricsDelta[];\n /** ISO timestamp of the last live-metrics refresh. */\n metricsRefreshedAt?: string | null;\n}\n\nexport default function ResultsSection({\n data,\n metricsDelta,\n metricsRefreshedAt,\n}: ResultsSectionProps) {\n // Nothing survives display curation → no section, not an empty header.\n if (!data.items.length && !gateMetricsDeltas(metricsDelta).length) return null;\n\n return (\n <section\n className=\"w-full py-20 md:py-28\"\n style={{ background: 'var(--sk-bg, #0a0a0a)' }}\n >\n <div className=\"max-w-7xl mx-auto px-6\">\n <ScrollReveal y={30}>\n <h2\n className=\"text-3xl md:text-4xl font-bold mb-4\"\n style={{\n color: 'var(--sk-text-primary, #ffffff)',\n fontFamily: 'var(--sk-font-heading, inherit)',\n }}\n >\n Results\n </h2>\n <p\n className=\"text-lg mb-12 max-w-2xl\"\n style={{ color: 'var(--sk-text-secondary, #a1a1aa)' }}\n >\n Measurable outcomes that speak for themselves.\n </p>\n </ScrollReveal>\n\n <ScrollReveal stagger={0.1}>\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6\">\n {data.items.map((item, index) => (\n <GlassCard key={index} padding=\"lg\" hover>\n <div className=\"flex flex-col gap-3\">\n {/* Metric counter */}\n {item.metric && (\n <div\n className=\"text-3xl md:text-4xl font-bold\"\n style={{ color: 'var(--sk-primary, #6366f1)' }}\n >\n <AnimatedCounter\n value={item.metric.value}\n suffix={item.metric.suffix}\n prefix={item.metric.prefix}\n duration={2.5}\n />\n </div>\n )}\n\n <h3\n className=\"text-lg font-semibold\"\n style={{ color: 'var(--sk-text-primary, #ffffff)' }}\n >\n {item.title}\n </h3>\n\n <p\n className=\"text-sm leading-relaxed\"\n style={{ color: 'var(--sk-text-tertiary, #71717a)' }}\n >\n {item.description}\n </p>\n\n {/* Source badge */}\n <span\n className=\"inline-flex self-start items-center gap-1 px-2.5 py-1 rounded-full text-[11px] uppercase tracking-wider font-medium mt-1\"\n style={{\n background:\n item.source === 'measured'\n ? 'color-mix(in srgb, #10b981 12%, transparent)'\n : 'color-mix(in srgb, #f59e0b 12%, transparent)',\n color: item.source === 'measured' ? '#10b981' : '#f59e0b',\n border: `1px solid ${\n item.source === 'measured'\n ? 'color-mix(in srgb, #10b981 20%, transparent)'\n : 'color-mix(in srgb, #f59e0b 20%, transparent)'\n }`,\n }}\n >\n {item.source === 'measured' ? (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\">\n <path d=\"M10 3L4.5 8.5 2 6\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n ) : (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\">\n <circle cx=\"6\" cy=\"6\" r=\"4\" stroke=\"currentColor\" strokeWidth=\"1.5\" />\n <path d=\"M6 4v2.5l1.5 1\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" />\n </svg>\n )}\n {item.source}\n </span>\n </div>\n </GlassCard>\n ))}\n </div>\n </ScrollReveal>\n\n {/* Live verified metrics — the numbers a static portfolio can't fake */}\n {metricsDelta && metricsDelta.length > 0 && (\n <ScrollReveal y={30} delay={0.1}>\n <MetricsProvenance deltas={metricsDelta} refreshedAt={metricsRefreshedAt} />\n </ScrollReveal>\n )}\n </div>\n </section>\n );\n}\n"]}
1
+ {"version":3,"sources":["../../../src/portfolio/components/sections/ResultsSection.tsx"],"names":[],"mappings":"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","file":"ResultsSection.js","sourcesContent":["// Server component — renders on the server; the client primitives below cross the\n// RSC boundary via package subpaths (never import them relatively here).\nimport React from 'react';\nimport type { MetricsDelta, PortfolioResultsData } from '../../../types';\nimport ScrollReveal from '@sonordev/agency-site-kit/portfolio/primitives/ScrollReveal';\nimport AnimatedCounter from '@sonordev/agency-site-kit/portfolio/primitives/AnimatedCounter';\nimport GlassCard from '@sonordev/agency-site-kit/portfolio/primitives/GlassCard';\nimport MetricsProvenance from '../MetricsProvenance';\nimport { gateMetricsDeltas } from '../../curate-proof';\n\ninterface ResultsSectionProps {\n data: PortfolioResultsData;\n /** Live metric deltas computed by the platform (item.metricsDelta). */\n metricsDelta?: MetricsDelta[];\n /** ISO timestamp of the last live-metrics refresh. */\n metricsRefreshedAt?: string | null;\n}\n\nexport default function ResultsSection({\n data,\n metricsDelta,\n metricsRefreshedAt,\n}: ResultsSectionProps) {\n // Nothing survives display curation → no section, not an empty header.\n if (!data.items.length && !gateMetricsDeltas(metricsDelta).length) return null;\n\n return (\n <section\n className=\"w-full py-20 md:py-28\"\n style={{ background: 'var(--sk-bg, #0a0a0a)' }}\n >\n <div className=\"max-w-7xl mx-auto px-6\">\n <ScrollReveal y={30}>\n <h2\n className=\"text-3xl md:text-4xl font-bold mb-4\"\n style={{\n color: 'var(--sk-text-primary, #ffffff)',\n fontFamily: 'var(--sk-font-heading, inherit)',\n }}\n >\n Results\n </h2>\n <p\n className=\"text-lg mb-12 max-w-2xl\"\n style={{ color: 'var(--sk-text-secondary, #a1a1aa)' }}\n >\n Measurable outcomes that speak for themselves.\n </p>\n </ScrollReveal>\n\n <ScrollReveal stagger={0.1}>\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6\">\n {data.items.map((item, index) => (\n <GlassCard key={index} padding=\"lg\" hover>\n <div className=\"flex flex-col gap-3\">\n {/* Metric counter */}\n {item.metric && (\n <div\n className=\"text-3xl md:text-4xl font-bold\"\n style={{ color: 'var(--sk-primary, #6366f1)' }}\n >\n <AnimatedCounter\n value={item.metric.value}\n suffix={item.metric.suffix}\n prefix={item.metric.prefix}\n duration={2.5}\n />\n </div>\n )}\n\n <h3\n className=\"text-lg font-semibold\"\n style={{ color: 'var(--sk-text-primary, #ffffff)' }}\n >\n {item.title}\n </h3>\n\n <p\n className=\"text-sm leading-relaxed\"\n style={{ color: 'var(--sk-text-tertiary, #71717a)' }}\n >\n {item.description}\n </p>\n\n {/* Source badge */}\n <span\n className=\"inline-flex self-start items-center gap-1 px-2.5 py-1 rounded-full text-[11px] uppercase tracking-wider font-medium mt-1\"\n style={{\n background:\n item.source === 'measured'\n ? 'color-mix(in srgb, #10b981 12%, transparent)'\n : 'color-mix(in srgb, #f59e0b 12%, transparent)',\n color: item.source === 'measured' ? '#10b981' : '#f59e0b',\n border: `1px solid ${\n item.source === 'measured'\n ? 'color-mix(in srgb, #10b981 20%, transparent)'\n : 'color-mix(in srgb, #f59e0b 20%, transparent)'\n }`,\n }}\n >\n {item.source === 'measured' ? (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\">\n <path d=\"M10 3L4.5 8.5 2 6\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n ) : (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\">\n <circle cx=\"6\" cy=\"6\" r=\"4\" stroke=\"currentColor\" strokeWidth=\"1.5\" />\n <path d=\"M6 4v2.5l1.5 1\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" />\n </svg>\n )}\n {item.source}\n </span>\n </div>\n </GlassCard>\n ))}\n </div>\n </ScrollReveal>\n\n {/* Live verified metrics — the numbers a static portfolio can't fake */}\n {metricsDelta && metricsDelta.length > 0 && (\n <ScrollReveal y={30} delay={0.1}>\n <MetricsProvenance deltas={metricsDelta} refreshedAt={metricsRefreshedAt} />\n </ScrollReveal>\n )}\n </div>\n </section>\n );\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { g as PortfolioServicesData } from '../../types-0tVPy4pU.cjs';
2
+ import { g as PortfolioServicesData } from '../../types-He5A9okM.cjs';
3
3
 
4
4
  interface ServicesSectionProps {
5
5
  data: PortfolioServicesData;
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { g as PortfolioServicesData } from '../../types-0tVPy4pU.js';
2
+ import { g as PortfolioServicesData } from '../../types-He5A9okM.js';
3
3
 
4
4
  interface ServicesSectionProps {
5
5
  data: PortfolioServicesData;
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { h as PortfolioTechStackData } from '../../types-0tVPy4pU.cjs';
2
+ import { h as PortfolioTechStackData } from '../../types-He5A9okM.cjs';
3
3
 
4
4
  interface TechStackSectionProps {
5
5
  data: PortfolioTechStackData;
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { h as PortfolioTechStackData } from '../../types-0tVPy4pU.js';
2
+ import { h as PortfolioTechStackData } from '../../types-He5A9okM.js';
3
3
 
4
4
  interface TechStackSectionProps {
5
5
  data: PortfolioTechStackData;
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { i as PortfolioTestimonialData } from '../../types-0tVPy4pU.cjs';
2
+ import { i as PortfolioTestimonialData } from '../../types-He5A9okM.cjs';
3
3
 
4
4
  interface TestimonialSectionProps {
5
5
  data: PortfolioTestimonialData;
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { i as PortfolioTestimonialData } from '../../types-0tVPy4pU.js';
2
+ import { i as PortfolioTestimonialData } from '../../types-He5A9okM.js';
3
3
 
4
4
  interface TestimonialSectionProps {
5
5
  data: PortfolioTestimonialData;
@@ -1,6 +1,8 @@
1
1
  'use strict';
2
2
 
3
- var chunk7ZHRMWJU_cjs = require('../chunk-7ZHRMWJU.cjs');
3
+ var chunkA5WCMHAE_cjs = require('../chunk-A5WCMHAE.cjs');
4
+ var chunkZBPF7TLZ_cjs = require('../chunk-ZBPF7TLZ.cjs');
5
+ var chunkX76U7VLF_cjs = require('../chunk-X76U7VLF.cjs');
4
6
  var chunkFCKDJ4MJ_cjs = require('../chunk-FCKDJ4MJ.cjs');
5
7
  require('../chunk-HQGAX2LI.cjs');
6
8
  require('../chunk-XOWSXZYW.cjs');
@@ -9,55 +11,79 @@ require('../chunk-XOWSXZYW.cjs');
9
11
 
10
12
  Object.defineProperty(exports, "PortfolioApiError", {
11
13
  enumerable: true,
12
- get: function () { return chunk7ZHRMWJU_cjs.PortfolioApiError; }
14
+ get: function () { return chunkA5WCMHAE_cjs.PortfolioApiError; }
13
15
  });
14
16
  Object.defineProperty(exports, "PortfolioContractError", {
15
17
  enumerable: true,
16
- get: function () { return chunk7ZHRMWJU_cjs.PortfolioContractError; }
18
+ get: function () { return chunkA5WCMHAE_cjs.PortfolioContractError; }
17
19
  });
18
20
  Object.defineProperty(exports, "assertPortfolioItemShape", {
19
21
  enumerable: true,
20
- get: function () { return chunk7ZHRMWJU_cjs.assertPortfolioItemShape; }
22
+ get: function () { return chunkA5WCMHAE_cjs.assertPortfolioItemShape; }
21
23
  });
22
24
  Object.defineProperty(exports, "generatePortfolioCategoryStaticParams", {
23
25
  enumerable: true,
24
- get: function () { return chunk7ZHRMWJU_cjs.generatePortfolioCategoryStaticParams; }
26
+ get: function () { return chunkA5WCMHAE_cjs.generatePortfolioCategoryStaticParams; }
25
27
  });
26
28
  Object.defineProperty(exports, "generatePortfolioIndexMetadata", {
27
29
  enumerable: true,
28
- get: function () { return chunk7ZHRMWJU_cjs.generatePortfolioIndexMetadata; }
30
+ get: function () { return chunkA5WCMHAE_cjs.generatePortfolioIndexMetadata; }
29
31
  });
30
32
  Object.defineProperty(exports, "generatePortfolioMetadata", {
31
33
  enumerable: true,
32
- get: function () { return chunk7ZHRMWJU_cjs.generatePortfolioMetadata; }
34
+ get: function () { return chunkA5WCMHAE_cjs.generatePortfolioMetadata; }
33
35
  });
34
36
  Object.defineProperty(exports, "generatePortfolioSitemapEntries", {
35
37
  enumerable: true,
36
- get: function () { return chunk7ZHRMWJU_cjs.generatePortfolioSitemapEntries; }
38
+ get: function () { return chunkA5WCMHAE_cjs.generatePortfolioSitemapEntries; }
37
39
  });
38
40
  Object.defineProperty(exports, "generatePortfolioStaticParams", {
39
41
  enumerable: true,
40
- get: function () { return chunk7ZHRMWJU_cjs.generatePortfolioStaticParams; }
42
+ get: function () { return chunkA5WCMHAE_cjs.generatePortfolioStaticParams; }
41
43
  });
42
44
  Object.defineProperty(exports, "getPortfolioBrandConfig", {
43
45
  enumerable: true,
44
- get: function () { return chunk7ZHRMWJU_cjs.getPortfolioBrandConfig; }
46
+ get: function () { return chunkA5WCMHAE_cjs.getPortfolioBrandConfig; }
45
47
  });
46
48
  Object.defineProperty(exports, "getPortfolioCategories", {
47
49
  enumerable: true,
48
- get: function () { return chunk7ZHRMWJU_cjs.getPortfolioCategories; }
50
+ get: function () { return chunkA5WCMHAE_cjs.getPortfolioCategories; }
49
51
  });
50
52
  Object.defineProperty(exports, "getPortfolioItem", {
51
53
  enumerable: true,
52
- get: function () { return chunk7ZHRMWJU_cjs.getPortfolioItem; }
54
+ get: function () { return chunkA5WCMHAE_cjs.getPortfolioItem; }
53
55
  });
54
56
  Object.defineProperty(exports, "getPortfolioItems", {
55
57
  enumerable: true,
56
- get: function () { return chunk7ZHRMWJU_cjs.getPortfolioItems; }
58
+ get: function () { return chunkA5WCMHAE_cjs.getPortfolioItems; }
57
59
  });
58
60
  Object.defineProperty(exports, "slugifyCategory", {
59
61
  enumerable: true,
60
- get: function () { return chunk7ZHRMWJU_cjs.slugifyCategory; }
62
+ get: function () { return chunkA5WCMHAE_cjs.slugifyCategory; }
63
+ });
64
+ Object.defineProperty(exports, "formatCategoryLabel", {
65
+ enumerable: true,
66
+ get: function () { return chunkZBPF7TLZ_cjs.formatCategoryLabel; }
67
+ });
68
+ Object.defineProperty(exports, "formatServiceTag", {
69
+ enumerable: true,
70
+ get: function () { return chunkZBPF7TLZ_cjs.formatServiceTag; }
71
+ });
72
+ Object.defineProperty(exports, "curateHeroKpis", {
73
+ enumerable: true,
74
+ get: function () { return chunkX76U7VLF_cjs.curateHeroKpis; }
75
+ });
76
+ Object.defineProperty(exports, "curatePortfolioProof", {
77
+ enumerable: true,
78
+ get: function () { return chunkX76U7VLF_cjs.curatePortfolioProof; }
79
+ });
80
+ Object.defineProperty(exports, "curateResultItems", {
81
+ enumerable: true,
82
+ get: function () { return chunkX76U7VLF_cjs.curateResultItems; }
83
+ });
84
+ Object.defineProperty(exports, "gateMetricsDeltas", {
85
+ enumerable: true,
86
+ get: function () { return chunkX76U7VLF_cjs.gateMetricsDeltas; }
61
87
  });
62
88
  Object.defineProperty(exports, "PORTFOLIO_CACHE_TAG", {
63
89
  enumerable: true,
@@ -1,5 +1,7 @@
1
- import { P as PortfolioItemFull, a as PortfolioSection, M as MetricsDelta, B as BrandConfig, b as PortfolioListResponse } from '../types-0tVPy4pU.cjs';
1
+ import { P as PortfolioItemFull, a as PortfolioSection, M as MetricsDelta, B as BrandConfig, b as PortfolioListResponse } from '../types-He5A9okM.cjs';
2
2
  export { P as PORTFOLIO_CACHE_TAG } from '../cache-CE_ujDK4.cjs';
3
+ export { c as curatePortfolioProof, a as curateResultItems, f as formatCategoryLabel, b as formatServiceTag, g as gateMetricsDeltas } from '../format-C-axf13G.cjs';
4
+ export { curateHeroKpis } from '@sonordev/site-kit/portfolio/contract';
3
5
 
4
6
  /**
5
7
  * @sonordev/agency-site-kit — Portfolio server-side data fetching
@@ -1,5 +1,7 @@
1
- import { P as PortfolioItemFull, a as PortfolioSection, M as MetricsDelta, B as BrandConfig, b as PortfolioListResponse } from '../types-0tVPy4pU.js';
1
+ import { P as PortfolioItemFull, a as PortfolioSection, M as MetricsDelta, B as BrandConfig, b as PortfolioListResponse } from '../types-He5A9okM.js';
2
2
  export { P as PORTFOLIO_CACHE_TAG } from '../cache-CE_ujDK4.js';
3
+ export { c as curatePortfolioProof, a as curateResultItems, f as formatCategoryLabel, b as formatServiceTag, g as gateMetricsDeltas } from '../format-poUpLtQ2.js';
4
+ export { curateHeroKpis } from '@sonordev/site-kit/portfolio/contract';
3
5
 
4
6
  /**
5
7
  * @sonordev/agency-site-kit — Portfolio server-side data fetching
@@ -1,4 +1,6 @@
1
- export { PortfolioApiError, PortfolioContractError, assertPortfolioItemShape, generatePortfolioCategoryStaticParams, generatePortfolioIndexMetadata, generatePortfolioMetadata, generatePortfolioSitemapEntries, generatePortfolioStaticParams, getPortfolioBrandConfig, getPortfolioCategories, getPortfolioItem, getPortfolioItems, slugifyCategory } from '../chunk-KXLROAO5.js';
1
+ export { PortfolioApiError, PortfolioContractError, assertPortfolioItemShape, generatePortfolioCategoryStaticParams, generatePortfolioIndexMetadata, generatePortfolioMetadata, generatePortfolioSitemapEntries, generatePortfolioStaticParams, getPortfolioBrandConfig, getPortfolioCategories, getPortfolioItem, getPortfolioItems, slugifyCategory } from '../chunk-FT2SNEYP.js';
2
+ export { formatCategoryLabel, formatServiceTag } from '../chunk-7D4H36UF.js';
3
+ export { curateHeroKpis, curatePortfolioProof, curateResultItems, gateMetricsDeltas } from '../chunk-FM25LB67.js';
2
4
  export { PORTFOLIO_CACHE_TAG } from '../chunk-N7TVKUYQ.js';
3
5
  import '../chunk-L4EOQVRJ.js';
4
6
  import '../chunk-QL6KVIFR.js';
@@ -351,4 +351,4 @@ interface PortfolioConfigResponse {
351
351
  orgSlug: string;
352
352
  }
353
353
 
354
- export { type PortfolioResultItem as A, type BrandConfig as B, type PortfolioSectionData as C, type PortfolioSectionDataMap as D, type PortfolioSectionType as E, type PortfolioSeoData as F, type PortfolioServiceItem as G, type PortfolioStrategyData as H, type PortfolioStrategyPhase as I, type PortfolioTeamData as J, type PortfolioTeamMember as K, type PortfolioTechItem as L, type MetricsDelta as M, type PortfolioVideoData as N, type PortfolioItemFull as P, type SanityImageRef as S, type PortfolioSection as a, type PortfolioListResponse as b, type PortfolioChallengesData as c, type PortfolioDetailsData as d, type PortfolioHeroData as e, type PortfolioResultsData as f, type PortfolioServicesData as g, type PortfolioTechStackData as h, type PortfolioTestimonialData as i, type MetricSource as j, type MetricsSnapshot as k, PORTFOLIO_SECTION_TYPES as l, type PortfolioAnnotation as m, type PortfolioBeforeAfterData as n, type PortfolioCTAData as o, type PortfolioChallengeItem as p, type PortfolioConfigResponse as q, type PortfolioConversionFunnelData as r, type PortfolioFeatureSpotlightData as s, type PortfolioFunnelStage as t, type PortfolioGalleryData as u, type PortfolioGalleryImage as v, type PortfolioItem as w, type PortfolioKPI as x, type PortfolioMetricsDataPoint as y, type PortfolioMetricsTimelineData as z };
354
+ export { type PortfolioMetricsTimelineData as A, type BrandConfig as B, type PortfolioSectionData as C, type PortfolioSectionDataMap as D, type PortfolioSectionType as E, type PortfolioSeoData as F, type PortfolioServiceItem as G, type PortfolioStrategyData as H, type PortfolioStrategyPhase as I, type PortfolioTeamData as J, type PortfolioTeamMember as K, type PortfolioTechItem as L, type MetricsDelta as M, type PortfolioVideoData as N, type PortfolioItemFull as P, type SanityImageRef as S, type PortfolioSection as a, type PortfolioListResponse as b, type PortfolioChallengesData as c, type PortfolioDetailsData as d, type PortfolioHeroData as e, type PortfolioResultsData as f, type PortfolioServicesData as g, type PortfolioTechStackData as h, type PortfolioTestimonialData as i, type PortfolioResultItem as j, type MetricSource as k, type MetricsSnapshot as l, PORTFOLIO_SECTION_TYPES as m, type PortfolioAnnotation as n, type PortfolioBeforeAfterData as o, type PortfolioCTAData as p, type PortfolioChallengeItem as q, type PortfolioConfigResponse as r, type PortfolioConversionFunnelData as s, type PortfolioFeatureSpotlightData as t, type PortfolioFunnelStage as u, type PortfolioGalleryData as v, type PortfolioGalleryImage as w, type PortfolioItem as x, type PortfolioKPI as y, type PortfolioMetricsDataPoint as z };
@@ -351,4 +351,4 @@ interface PortfolioConfigResponse {
351
351
  orgSlug: string;
352
352
  }
353
353
 
354
- export { type PortfolioResultItem as A, type BrandConfig as B, type PortfolioSectionData as C, type PortfolioSectionDataMap as D, type PortfolioSectionType as E, type PortfolioSeoData as F, type PortfolioServiceItem as G, type PortfolioStrategyData as H, type PortfolioStrategyPhase as I, type PortfolioTeamData as J, type PortfolioTeamMember as K, type PortfolioTechItem as L, type MetricsDelta as M, type PortfolioVideoData as N, type PortfolioItemFull as P, type SanityImageRef as S, type PortfolioSection as a, type PortfolioListResponse as b, type PortfolioChallengesData as c, type PortfolioDetailsData as d, type PortfolioHeroData as e, type PortfolioResultsData as f, type PortfolioServicesData as g, type PortfolioTechStackData as h, type PortfolioTestimonialData as i, type MetricSource as j, type MetricsSnapshot as k, PORTFOLIO_SECTION_TYPES as l, type PortfolioAnnotation as m, type PortfolioBeforeAfterData as n, type PortfolioCTAData as o, type PortfolioChallengeItem as p, type PortfolioConfigResponse as q, type PortfolioConversionFunnelData as r, type PortfolioFeatureSpotlightData as s, type PortfolioFunnelStage as t, type PortfolioGalleryData as u, type PortfolioGalleryImage as v, type PortfolioItem as w, type PortfolioKPI as x, type PortfolioMetricsDataPoint as y, type PortfolioMetricsTimelineData as z };
354
+ export { type PortfolioMetricsTimelineData as A, type BrandConfig as B, type PortfolioSectionData as C, type PortfolioSectionDataMap as D, type PortfolioSectionType as E, type PortfolioSeoData as F, type PortfolioServiceItem as G, type PortfolioStrategyData as H, type PortfolioStrategyPhase as I, type PortfolioTeamData as J, type PortfolioTeamMember as K, type PortfolioTechItem as L, type MetricsDelta as M, type PortfolioVideoData as N, type PortfolioItemFull as P, type SanityImageRef as S, type PortfolioSection as a, type PortfolioListResponse as b, type PortfolioChallengesData as c, type PortfolioDetailsData as d, type PortfolioHeroData as e, type PortfolioResultsData as f, type PortfolioServicesData as g, type PortfolioTechStackData as h, type PortfolioTestimonialData as i, type PortfolioResultItem as j, type MetricSource as k, type MetricsSnapshot as l, PORTFOLIO_SECTION_TYPES as m, type PortfolioAnnotation as n, type PortfolioBeforeAfterData as o, type PortfolioCTAData as p, type PortfolioChallengeItem as q, type PortfolioConfigResponse as r, type PortfolioConversionFunnelData as s, type PortfolioFeatureSpotlightData as t, type PortfolioFunnelStage as u, type PortfolioGalleryData as v, type PortfolioGalleryImage as w, type PortfolioItem as x, type PortfolioKPI as y, type PortfolioMetricsDataPoint as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sonordev/agency-site-kit",
3
- "version": "0.4.1",
3
+ "version": "0.4.2",
4
4
  "description": "Premium portfolio showcase components for Sonor-powered agency websites",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -85,13 +85,13 @@
85
85
  "clean": "rm -rf dist"
86
86
  },
87
87
  "peerDependencies": {
88
- "@sonordev/site-kit": ">=3.0.4",
88
+ "@sonordev/site-kit": ">=3.2.0",
89
89
  "next": ">=14.0.0",
90
90
  "react": ">=18.0.0",
91
91
  "react-dom": ">=18.0.0"
92
92
  },
93
93
  "devDependencies": {
94
- "@sonordev/site-kit": ">=3.0.4",
94
+ "@sonordev/site-kit": ">=3.2.0",
95
95
  "@types/node": "^25.5.0",
96
96
  "@types/react": "^19.2.17",
97
97
  "@types/react-dom": "^19.2.3",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/portfolio/curate-proof.ts","../src/portfolio/components/MetricsProvenance.tsx"],"names":[],"mappings":"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","file":"chunk-RWQ675N6.js","sourcesContent":["/**\n * curate-proof — single source of truth for which proof points a public case\n * study is allowed to display, and in what shape.\n *\n * Two classes of problem this guards against (both shipped to production on\n * upforge.io before this existed):\n *\n * 1. Repetition: generated items arrive with four \"100/100 Lighthouse X\"\n * KPIs in the hero, the same four restated as Results cards, AND a full\n * Performance section with score gauges. One differentiator repeated\n * twelve times per page stops differentiating. The Performance section is\n * the one home for the Lighthouse breakdown; hero/results/cards collapse\n * to at most one summary tile.\n *\n * 2. Self-harming live metrics: MetricsDelta rows are computed from raw\n * analytics baselines with no editorial judgment — a bounce rate of\n * \"100 → 99.69\" rendered as a green win. Marketing surfaces only show a\n * delta when it's a genuinely flattering, meaningful story.\n *\n * Used by PortfolioPage (hero KPIs + results items), PortfolioCard (KPI\n * preview), and MetricsProvenance (delta gate). Change display policy here,\n * nowhere else.\n */\n\nimport type {\n MetricsDelta,\n PortfolioHeroData,\n PortfolioItemFull,\n PortfolioKPI,\n PortfolioResultItem,\n PortfolioResultsData,\n} from '../types';\n\nconst LIGHTHOUSE_RE = /lighthouse/i;\n\n/** True when a KPI tile is a per-category Lighthouse score. */\nexport function isLighthouseKpi(kpi: PortfolioKPI): boolean {\n return LIGHTHOUSE_RE.test(kpi.label);\n}\n\n/**\n * True when a Results card merely restates a Lighthouse category score\n * (e.g. \"Perfect performance score … measured Lighthouse score of 100/100\").\n * Business outcomes (\"Complete 14-page rebuild\", \"682% session growth\")\n * never match: the title must be about a score AND the card must reference\n * Lighthouse or carry a x/100 metric.\n */\nexport function isLighthouseRestatement(item: PortfolioResultItem): boolean {\n if (!/score/i.test(item.title)) return false;\n if (LIGHTHOUSE_RE.test(`${item.title} ${item.description}`)) return true;\n return item.metric?.suffix === '/100';\n}\n\n/**\n * Collapse per-category Lighthouse KPIs to at most one summary tile, business\n * outcomes first. When every category is present at 100 the summary says so;\n * otherwise the Performance category (the one buyers know) represents the set.\n */\nexport function curateHeroKpis(kpis: PortfolioKPI[]): PortfolioKPI[] {\n const business = kpis.filter((k) => !isLighthouseKpi(k));\n const lighthouse = kpis.filter(isLighthouseKpi);\n if (lighthouse.length <= 1) return kpis;\n\n const allPerfect = lighthouse.length >= 4 && lighthouse.every((k) => k.value === 100);\n const summary: PortfolioKPI = allPerfect\n ? {\n ...lighthouse[0],\n label: 'Lighthouse, all 4 categories',\n description: 'Perfect scores across performance, SEO, accessibility, and best practices.',\n }\n : (lighthouse.find((k) => /performance/i.test(k.label)) ?? lighthouse[0]);\n\n return [...business, summary];\n}\n\n/**\n * Drop Results cards that restate Lighthouse scores when the case study also\n * renders a Performance section (the score breakdown's single home).\n */\nexport function curateResultItems(\n items: PortfolioResultItem[],\n hasPerformanceSection: boolean,\n): PortfolioResultItem[] {\n if (!hasPerformanceSection) return items;\n const curated = items.filter((item) => !isLighthouseRestatement(item));\n // Never curate a Results section into emptiness — if every card was a\n // Lighthouse restatement, keep the strongest single card instead.\n return curated.length > 0 ? curated : items.slice(0, 1);\n}\n\n/**\n * Editorial gate for live metric deltas (\"Verified from live analytics\").\n * `direction` comes from the platform with 'up' meaning IMPROVED (lower-is-\n * better metrics are inverted server-side). A public case study only shows a\n * delta when it's a win worth telling:\n * - improved ('up'), never a regression or flat noise\n * - moved by a double-digit relative margin (small drift isn't a story)\n * - bounce-rate-style metrics must also be respectable in absolute terms —\n * \"100 → 99.69\" is technically an improvement and still self-harm\n */\nexport function gateMetricsDeltas(deltas: MetricsDelta[] | undefined | null): MetricsDelta[] {\n if (!deltas?.length) return [];\n return deltas.filter((d) => {\n if (d.direction !== 'up') return false;\n if (Math.abs(d.deltaPercent) < 10) return false;\n if (/bounce/i.test(d.metric) && d.current > 70) return false;\n return true;\n });\n}\n\n/**\n * Apply the full display policy to a portfolio item before rendering.\n * Pure — returns a new item; the fetched payload is never mutated.\n */\nexport function curatePortfolioProof(item: PortfolioItemFull): PortfolioItemFull {\n const hasPerformanceSection = item.sections.some(\n (s) => s.sectionType === 'portfolioPerformance',\n );\n\n return {\n ...item,\n sections: item.sections.map((section) => {\n if (section.sectionType === 'portfolioHero') {\n const data = section.data as PortfolioHeroData;\n return { ...section, data: { ...data, kpis: curateHeroKpis(data.kpis ?? []) } };\n }\n if (section.sectionType === 'portfolioResults') {\n const data = section.data as PortfolioResultsData;\n return {\n ...section,\n data: { ...data, items: curateResultItems(data.items ?? [], hasPerformanceSection) },\n };\n }\n return section;\n }),\n };\n}\n","/**\n * MetricsProvenance — \"these numbers are real\" strip for case studies.\n *\n * Server component, zero JS. Renders the live metric deltas the platform\n * computes from GSC/analytics baselines (MetricsDelta[]) plus the refresh\n * timestamp — the trust signal a static agency portfolio can't fake.\n *\n * `direction` semantics come from the API: 'up' ALWAYS means \"improved\"\n * (lower-is-better metrics like Avg Position/LCP are inverted server-side\n * in metrics-baseline.service), so 'up' renders green. The ARROW glyph\n * follows the raw numbers instead — an improved bounce rate shows a green ▼,\n * never a green ▲ next to a value that visibly went down.\n *\n * Deltas pass through gateMetricsDeltas (curate-proof.ts) before display:\n * raw platform deltas carry no editorial judgment, and this strip only\n * exists to flatter — see that module for the policy.\n */\n\nimport React from 'react';\nimport type { MetricsDelta } from '../../types';\nimport { gateMetricsDeltas } from '../curate-proof';\n\ninterface MetricsProvenanceProps {\n deltas: MetricsDelta[];\n /** ISO timestamp of the last live-metrics refresh. */\n refreshedAt?: string | null;\n}\n\nconst DIRECTION_COLOR: Record<MetricsDelta['direction'], string> = {\n up: '#10b981',\n down: '#ef4444',\n flat: 'var(--sk-text-tertiary, #71717a)',\n};\n\nfunction formatValue(v: number): string {\n return Number.isInteger(v)\n ? v.toLocaleString('en-US')\n : v.toLocaleString('en-US', { maximumFractionDigits: 2 });\n}\n\nfunction formatDate(iso: string): string {\n try {\n return new Intl.DateTimeFormat('en-US', {\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n }).format(new Date(iso));\n } catch {\n return iso;\n }\n}\n\nexport default function MetricsProvenance({ deltas, refreshedAt }: MetricsProvenanceProps) {\n const shown = gateMetricsDeltas(deltas);\n if (!shown.length) return null;\n\n return (\n <div\n className=\"mt-10 rounded-2xl overflow-hidden\"\n style={{\n background: 'var(--sk-surface, rgba(255,255,255,0.05))',\n border: '1px solid var(--sk-border, rgba(255,255,255,0.1))',\n }}\n >\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3\">\n {shown.map((d, i) => {\n const color = DIRECTION_COLOR[d.direction] ?? DIRECTION_COLOR.flat;\n // Arrow tracks the raw numbers; color tracks improved/worsened.\n const arrow = d.current === d.baseline ? '—' : d.current > d.baseline ? '▲' : '▼';\n return (\n <div\n key={`${d.metric}-${i}`}\n className=\"flex flex-col gap-1 p-5\"\n style={{ borderBottom: '1px solid var(--sk-border, rgba(255,255,255,0.06))' }}\n >\n <span\n className=\"text-xs font-semibold uppercase tracking-wider\"\n style={{ color: 'var(--sk-text-tertiary, #71717a)' }}\n >\n {d.metric}\n </span>\n <span className=\"flex items-baseline gap-2\">\n <span\n className=\"text-lg font-bold\"\n style={{ color: 'var(--sk-text-primary, #ffffff)' }}\n >\n {formatValue(d.baseline)} → {formatValue(d.current)}\n </span>\n <span className=\"text-sm font-semibold\" style={{ color }}>\n {arrow} {Math.abs(d.deltaPercent)}%\n </span>\n </span>\n <span className=\"text-xs\" style={{ color: 'var(--sk-text-tertiary, #71717a)' }}>\n {d.timespan}\n </span>\n </div>\n );\n })}\n </div>\n\n <div\n className=\"flex items-center gap-2 px-5 py-3\"\n style={{\n background: 'color-mix(in srgb, #10b981 6%, transparent)',\n color: 'var(--sk-text-secondary, #a1a1aa)',\n }}\n >\n <span\n className=\"inline-block w-2 h-2 rounded-full shrink-0\"\n style={{ background: '#10b981' }}\n />\n <span className=\"text-xs font-medium\">\n Verified from live analytics\n {refreshedAt ? ` · Refreshed ${formatDate(refreshedAt)}` : ''}\n </span>\n </div>\n </div>\n );\n}\n"]}