@hraness/design-kit 0.32.0 → 0.34.0

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.
package/dist/stylex.css CHANGED
@@ -2431,10 +2431,6 @@
2431
2431
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 10rem), 1fr));
2432
2432
  }
2433
2433
 
2434
- .x1p797x9 {
2435
- grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
2436
- }
2437
-
2438
2434
  .x1vfedg7 {
2439
2435
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
2440
2436
  }
@@ -2443,6 +2439,14 @@
2443
2439
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));
2444
2440
  }
2445
2441
 
2442
+ .x1v4bfo1 {
2443
+ grid-template-columns: repeat(auto-fit,minmax(min(100%,var(--_hraness-marketing-grid-track, 16rem)),1fr));
2444
+ }
2445
+
2446
+ .x1ui45ma {
2447
+ grid-template-columns: repeat(auto-fit,minmax(min(100%,var(--_hraness-marketing-grid-track, 18rem)),1fr));
2448
+ }
2449
+
2446
2450
  .x3g07o8 {
2447
2451
  grid-template-columns: repeat(var(--hraness-marketing-fact-columns, 4),minmax(0,1fr));
2448
2452
  }
@@ -5261,6 +5265,14 @@
5261
5265
  --_hraness-foil-mark-display: none;
5262
5266
  }
5263
5267
 
5268
+ .x9wro72 {
5269
+ --_hraness-marketing-grid-track: max(16rem,calc((100% - (var(--hraness-marketing-grid-columns) - 1) * 1rem) / var(--hraness-marketing-grid-columns)));
5270
+ }
5271
+
5272
+ .xwl1ywu {
5273
+ --_hraness-marketing-grid-track: max(18rem,calc((100% - (var(--hraness-marketing-grid-columns) - 1) * 1rem) / var(--hraness-marketing-grid-columns)));
5274
+ }
5275
+
5264
5276
  .xojny72 {
5265
5277
  --hraness-appearance-accent-foreground: var(--hraness-material-ink, var(--ui-accent-foreground, ButtonText));
5266
5278
  }
@@ -5353,6 +5365,26 @@
5353
5365
  --hraness-marketing-fact-columns: 4;
5354
5366
  }
5355
5367
 
5368
+ .x166dvhg {
5369
+ --hraness-marketing-grid-columns: 1;
5370
+ }
5371
+
5372
+ .x10q4e6v {
5373
+ --hraness-marketing-grid-columns: 2;
5374
+ }
5375
+
5376
+ .xyqi4l0 {
5377
+ --hraness-marketing-grid-columns: 3;
5378
+ }
5379
+
5380
+ .x1g57y38 {
5381
+ --hraness-marketing-grid-columns: 4;
5382
+ }
5383
+
5384
+ .xogmzgw {
5385
+ --hraness-marketing-grid-columns: initial;
5386
+ }
5387
+
5356
5388
  .xphms39 {
5357
5389
  --hraness-marketing-pillar-columns: 1;
5358
5390
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hraness/design-kit",
3
- "version": "0.32.0",
3
+ "version": "0.34.0",
4
4
  "description": "React components and CSS for Hraness apps and product sites: application shells, marketing sections, charts, themes, effects, and syntax highlighting. Built on @hraness/ui.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -6,7 +6,7 @@
6
6
  "name": "@hraness/design-kit",
7
7
  "path": ".",
8
8
  "visibility": "public",
9
- "version": "0.32.0"
9
+ "version": "0.34.0"
10
10
  }
11
11
  ],
12
12
  "contract": "hraness.portfolio-inventory/v1",
@@ -1454,13 +1454,16 @@ html:has(:is(.hraness-marketing-header, .hraness-marketing-header-surface):not([
1454
1454
  }
1455
1455
 
1456
1456
  .hraness-marketing-primitives__list {
1457
+ --hraness-marketing-grid-columns: initial;
1458
+ /* Without an explicit column cap, the track falls back to its natural minimum. */
1459
+ --_hraness-marketing-grid-track: max(18rem, calc((100% - (var(--hraness-marketing-grid-columns) - 1) * 1rem) / var(--hraness-marketing-grid-columns)));
1457
1460
  display: grid;
1458
1461
  align-items: stretch;
1459
1462
  margin: 0;
1460
1463
  padding: 0;
1461
1464
  list-style: none;
1462
1465
  gap: 1rem;
1463
- grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));
1466
+ grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--_hraness-marketing-grid-track, 18rem)), 1fr));
1464
1467
  }
1465
1468
 
1466
1469
  .hraness-marketing-primitives__list > * {
@@ -1510,11 +1513,13 @@ html:has(:is(.hraness-marketing-header, .hraness-marketing-header-surface):not([
1510
1513
 
1511
1514
  .hraness-marketing-interface-grid,
1512
1515
  .hraness-marketing-trust-grid {
1516
+ --hraness-marketing-grid-columns: initial;
1517
+ --_hraness-marketing-grid-track: max(16rem, calc((100% - (var(--hraness-marketing-grid-columns) - 1) * 1rem) / var(--hraness-marketing-grid-columns)));
1513
1518
  display: grid;
1514
1519
  align-items: stretch;
1515
1520
  margin: 0;
1516
1521
  gap: 1rem;
1517
- grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
1522
+ grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--_hraness-marketing-grid-track, 16rem)), 1fr));
1518
1523
  }
1519
1524
 
1520
1525
  .hraness-marketing-interface-grid > *,
@@ -1566,11 +1571,13 @@ html:has(:is(.hraness-marketing-header, .hraness-marketing-header-surface):not([
1566
1571
  * block. The art well clips overflow and contains backgrounds so a logo
1567
1572
  * surface cannot paint through the gutter as one bar. */
1568
1573
  .hraness-marketing-card-row {
1574
+ --hraness-marketing-grid-columns: initial;
1575
+ --_hraness-marketing-grid-track: max(16rem, calc((100% - (var(--hraness-marketing-grid-columns) - 1) * 1rem) / var(--hraness-marketing-grid-columns)));
1569
1576
  display: grid;
1570
1577
  align-items: stretch;
1571
1578
  margin: 0;
1572
1579
  gap: 1rem;
1573
- grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
1580
+ grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--_hraness-marketing-grid-track, 16rem)), 1fr));
1574
1581
  }
1575
1582
 
1576
1583
  .hraness-marketing-card-row > * {
@@ -409,6 +409,7 @@ export function DesignSystemGallery({
409
409
  ]} label="Relay agent commands" />
410
410
  </MarketingSection>
411
411
  <MarketingPrimitives
412
+ columns={3}
412
413
  heading="Three objects cover most work."
413
414
  headingId="design-gallery-primitives-title"
414
415
  headingLevel={3}
@@ -435,15 +436,15 @@ export function DesignSystemGallery({
435
436
  <MarketingSectionLabel size="body">Reference</MarketingSectionLabel>
436
437
  <p>Consumer-owned content can include <a href="#gallery-install">links</a> and <code>inline code</code>.</p>
437
438
  </MarketingSection>
438
- <MarketingInterfaceGrid heading="Choose your interface." headingId="gallery-marketing-interfaces" headingLevel={3} label="Interfaces" interfaces={[
439
+ <MarketingInterfaceGrid columns={2} heading="Choose your interface." headingId="gallery-marketing-interfaces" headingLevel={3} label="Interfaces" interfaces={[
439
440
  { label: "CLI", summary: "Run a named job.", example: <MarketingCodeBlock code="relay run job-01" /> },
440
441
  { label: "SDK", summary: "Use typed application code." },
441
442
  ]} />
442
- <MarketingCardRow ariaLabel="Release radar" cards={[
443
+ <MarketingCardRow ariaLabel="Release radar" columns={2} cards={[
443
444
  { art: <svg aria-hidden="true" viewBox="0 0 24 24" width="24" height="24"><circle cx="12" cy="12" r="8" /></svg>, href: "#marketing", title: "Grok 4.7", meta: "First observed 21 September 2026." },
444
445
  { art: <svg aria-hidden="true" viewBox="0 0 24 24" width="24" height="24"><rect x="4" y="4" width="16" height="16" rx="4" /></svg>, href: "#gallery-install", title: "GLM 5.3 Flash", meta: "First observed 26 August 2026. Early DeepSWE coverage on OpenRouter." },
445
446
  ]} />
446
- <MarketingTrustBoundary heading="What leaves your machine." headingId="gallery-marketing-trust" headingLevel={3} label="Boundary" items={[
447
+ <MarketingTrustBoundary columns={2} heading="What leaves your machine." headingId="gallery-marketing-trust" headingLevel={3} label="Boundary" items={[
447
448
  { label: "Stays local", detail: "Source files and credentials." },
448
449
  { label: "Shared", detail: "Only the logs you choose to sync." },
449
450
  ]} />
@@ -519,6 +520,7 @@ export function DesignSystemGallery({
519
520
  ]}
520
521
  />
521
522
  <MarketingRelated
523
+ columns={2}
522
524
  groups={[
523
525
  {
524
526
  heading: "Sibling tools",
@@ -537,6 +539,7 @@ export function DesignSystemGallery({
537
539
  ],
538
540
  },
539
541
  {
542
+ columns: 1,
540
543
  heading: "Shared infrastructure",
541
544
  headingId: "design-gallery-related-infra",
542
545
  items: [
@@ -63,6 +63,10 @@ export const marketingStyles = stylex.create({
63
63
  pillarColumns2: { "--hraness-marketing-pillar-columns": "2" },
64
64
  pillarColumns3: { "--hraness-marketing-pillar-columns": "3" },
65
65
  pillarColumns4: { "--hraness-marketing-pillar-columns": "4" },
66
+ gridColumns1: { "--hraness-marketing-grid-columns": "1" },
67
+ gridColumns2: { "--hraness-marketing-grid-columns": "2" },
68
+ gridColumns3: { "--hraness-marketing-grid-columns": "3" },
69
+ gridColumns4: { "--hraness-marketing-grid-columns": "4" },
66
70
  actionFocus: {
67
71
  outline: { default: null, ":focus-visible": "2px solid var(--hraness-marketing-accent)" },
68
72
  "outline-offset": { default: null, ":focus-visible": "2px" },
@@ -2057,13 +2061,15 @@ export const marketingStyles = stylex.create({
2057
2061
  "font-size": "var(--hraness-paper-section-heading-size, clamp(1.75rem, 3vw, 2.5rem))"
2058
2062
  },
2059
2063
  "primitives__list": {
2064
+ "--hraness-marketing-grid-columns": "initial",
2065
+ "--_hraness-marketing-grid-track": "max(18rem, calc((100% - (var(--hraness-marketing-grid-columns) - 1) * 1rem) / var(--hraness-marketing-grid-columns)))",
2060
2066
  "display": "grid",
2061
2067
  "align-items": "stretch",
2062
2068
  "margin": "0",
2063
2069
  "padding": "0",
2064
2070
  "list-style": "none",
2065
2071
  "gap": "1rem",
2066
- "grid-template-columns": "repeat(auto-fit, minmax(min(100%, 18rem), 1fr))"
2072
+ "grid-template-columns": "repeat(auto-fit, minmax(min(100%, var(--_hraness-marketing-grid-track, 18rem)), 1fr))"
2067
2073
  },
2068
2074
  "primitive": {
2069
2075
  "display": "grid",
@@ -2168,18 +2174,22 @@ export const marketingStyles = stylex.create({
2168
2174
  "line-height": "1.5"
2169
2175
  },
2170
2176
  "interface_grid": {
2177
+ "--hraness-marketing-grid-columns": "initial",
2178
+ "--_hraness-marketing-grid-track": "max(16rem, calc((100% - (var(--hraness-marketing-grid-columns) - 1) * 1rem) / var(--hraness-marketing-grid-columns)))",
2171
2179
  "display": "grid",
2172
2180
  "align-items": "stretch",
2173
2181
  "margin": "0",
2174
2182
  "gap": "1rem",
2175
- "grid-template-columns": "repeat(auto-fit, minmax(min(100%, 16rem), 1fr))"
2183
+ "grid-template-columns": "repeat(auto-fit, minmax(min(100%, var(--_hraness-marketing-grid-track, 16rem)), 1fr))"
2176
2184
  },
2177
2185
  "trust_grid": {
2186
+ "--hraness-marketing-grid-columns": "initial",
2187
+ "--_hraness-marketing-grid-track": "max(16rem, calc((100% - (var(--hraness-marketing-grid-columns) - 1) * 1rem) / var(--hraness-marketing-grid-columns)))",
2178
2188
  "display": "grid",
2179
2189
  "align-items": "stretch",
2180
2190
  "margin": "0",
2181
2191
  "gap": "1rem",
2182
- "grid-template-columns": "repeat(auto-fit, minmax(min(100%, 16rem), 1fr))"
2192
+ "grid-template-columns": "repeat(auto-fit, minmax(min(100%, var(--_hraness-marketing-grid-track, 16rem)), 1fr))"
2183
2193
  },
2184
2194
  "interface": {
2185
2195
  "display": "grid",
@@ -2374,11 +2384,13 @@ export const marketingStyles = stylex.create({
2374
2384
  "line-height": "1.5"
2375
2385
  },
2376
2386
  "card_row": {
2387
+ "--hraness-marketing-grid-columns": "initial",
2388
+ "--_hraness-marketing-grid-track": "max(16rem, calc((100% - (var(--hraness-marketing-grid-columns) - 1) * 1rem) / var(--hraness-marketing-grid-columns)))",
2377
2389
  "display": "grid",
2378
2390
  "align-items": "stretch",
2379
2391
  "margin": "0",
2380
2392
  "gap": "1rem",
2381
- "grid-template-columns": "repeat(auto-fit, minmax(min(100%, 16rem), 1fr))"
2393
+ "grid-template-columns": "repeat(auto-fit, minmax(min(100%, var(--_hraness-marketing-grid-track, 16rem)), 1fr))"
2382
2394
  },
2383
2395
  "card": {
2384
2396
  "display": "flex",
@@ -4441,9 +4453,16 @@ const pillarColumns = {
4441
4453
  4: marketingStyles.pillarColumns4,
4442
4454
  } as const;
4443
4455
 
4456
+ const gridColumns = {
4457
+ 1: marketingStyles.gridColumns1,
4458
+ 2: marketingStyles.gridColumns2,
4459
+ 3: marketingStyles.gridColumns3,
4460
+ 4: marketingStyles.gridColumns4,
4461
+ } as const;
4462
+
4444
4463
  /** Explicit finite columns compose static atoms, including the existing media rules. */
4445
4464
  export function marketingColumnClassName(
4446
- hook: "hraness-marketing-facts" | "hraness-marketing-pillars" | "hraness-marketing-stats__list",
4465
+ hook: "hraness-marketing-facts" | "hraness-marketing-pillars" | "hraness-marketing-stats__list" | "hraness-marketing-card-row" | "hraness-marketing-primitives__list" | "hraness-marketing-interface-grid" | "hraness-marketing-trust-grid",
4447
4466
  caller: string | undefined,
4448
4467
  columns: MarketingColumnCount | undefined,
4449
4468
  ): string {
@@ -4451,7 +4470,9 @@ export function marketingColumnClassName(
4451
4470
  throw new RangeError("Marketing columns must be 1, 2, 3, or 4 when specified.");
4452
4471
  }
4453
4472
  const columnRecipe = columns === undefined ? undefined
4454
- : (hook === "hraness-marketing-pillars" ? pillarColumns : factColumns)[columns];
4473
+ : (hook === "hraness-marketing-pillars" ? pillarColumns
4474
+ : hook === "hraness-marketing-card-row" || hook === "hraness-marketing-primitives__list" || hook === "hraness-marketing-interface-grid" || hook === "hraness-marketing-trust-grid" ? gridColumns
4475
+ : factColumns)[columns];
4455
4476
  return [hook, stylex.props(recipes[hook].default, columnRecipe).className, caller]
4456
4477
  .filter((value) => value !== undefined && value.length > 0).join(" ");
4457
4478
  }
@@ -225,16 +225,19 @@ export function MarketingCardRow({
225
225
  cards,
226
226
  children,
227
227
  className,
228
+ columns,
228
229
  }: Readonly<{
229
230
  ariaLabel?: string;
230
231
  cards?: readonly MarketingCardItem[];
231
232
  children?: ReactNode;
232
233
  className?: string;
234
+ /** Maximum columns; cards wrap to fit the available container width. */
235
+ columns?: MarketingColumnCount;
233
236
  }>) {
234
237
  return (
235
238
  <div
236
239
  aria-label={ariaLabel}
237
- className={classNames("hraness-marketing-card-row", className)}
240
+ className={marketingColumnClassName("hraness-marketing-card-row", className, columns)}
238
241
  data-hraness-marketing="card-row"
239
242
  >
240
243
  {cards?.map((card) => (
@@ -1015,6 +1018,7 @@ export interface MarketingPrimitive {
1015
1018
 
1016
1019
  export function MarketingPrimitives({
1017
1020
  className,
1021
+ columns,
1018
1022
  heading,
1019
1023
  headingId,
1020
1024
  headingLevel = 2,
@@ -1024,6 +1028,8 @@ export function MarketingPrimitives({
1024
1028
  summary,
1025
1029
  }: Readonly<{
1026
1030
  className?: string;
1031
+ /** Maximum columns; items wrap to fit the available container width. */
1032
+ columns?: MarketingColumnCount;
1027
1033
  heading: string;
1028
1034
  headingId: string;
1029
1035
  headingLevel?: MarketingHeadingLevel;
@@ -1040,7 +1046,7 @@ export function MarketingPrimitives({
1040
1046
  id={id}
1041
1047
  >
1042
1048
  <MarketingCollectionHeader {...{ heading, headingId, headingLevel, label, summary }} prefix="primitives" />
1043
- <ol className={classNames("hraness-marketing-primitives__list")}>
1049
+ <ol className={marketingColumnClassName("hraness-marketing-primitives__list", undefined, columns)}>
1044
1050
  {items.map((item, index) => (
1045
1051
  <li className={classNames("hraness-marketing-primitive")} key={item.label}>
1046
1052
  <span aria-hidden="true" className={classNames("hraness-marketing-primitive__number")}>
@@ -1142,6 +1148,7 @@ export interface MarketingInterface {
1142
1148
 
1143
1149
  export function MarketingInterfaceGrid({
1144
1150
  className,
1151
+ columns,
1145
1152
  heading,
1146
1153
  headingId,
1147
1154
  headingLevel = 2,
@@ -1151,6 +1158,8 @@ export function MarketingInterfaceGrid({
1151
1158
  summary,
1152
1159
  }: Readonly<{
1153
1160
  className?: string;
1161
+ /** Maximum columns; cards wrap within the available container width. */
1162
+ columns?: MarketingColumnCount;
1154
1163
  heading: string;
1155
1164
  headingId: string;
1156
1165
  headingLevel?: MarketingHeadingLevel;
@@ -1167,7 +1176,7 @@ export function MarketingInterfaceGrid({
1167
1176
  id={id}
1168
1177
  >
1169
1178
  <MarketingCollectionHeader {...{ heading, headingId, headingLevel, label, summary }} prefix="interfaces" />
1170
- <div className={classNames("hraness-marketing-interface-grid")}>
1179
+ <div className={marketingColumnClassName("hraness-marketing-interface-grid", undefined, columns)}>
1171
1180
  {interfaces.map((entry) => (
1172
1181
  <article className={classNames("hraness-marketing-interface")} key={entry.label}>
1173
1182
  <Heading
@@ -1192,6 +1201,7 @@ export interface MarketingTrustItem {
1192
1201
 
1193
1202
  export function MarketingTrustBoundary({
1194
1203
  className,
1204
+ columns,
1195
1205
  heading,
1196
1206
  headingId,
1197
1207
  headingLevel = 2,
@@ -1201,6 +1211,8 @@ export function MarketingTrustBoundary({
1201
1211
  summary,
1202
1212
  }: Readonly<{
1203
1213
  className?: string;
1214
+ /** Maximum columns; cards wrap within the available container width. */
1215
+ columns?: MarketingColumnCount;
1204
1216
  heading: string;
1205
1217
  headingId: string;
1206
1218
  headingLevel?: MarketingHeadingLevel;
@@ -1217,7 +1229,7 @@ export function MarketingTrustBoundary({
1217
1229
  id={id}
1218
1230
  >
1219
1231
  <MarketingCollectionHeader {...{ heading, headingId, headingLevel, label, summary }} prefix="trust" />
1220
- <dl className={classNames("hraness-marketing-trust-grid")}>
1232
+ <dl className={marketingColumnClassName("hraness-marketing-trust-grid", undefined, columns)}>
1221
1233
  {items.map((item) => (
1222
1234
  <div className={classNames("hraness-marketing-trust-item")} key={item.label}>
1223
1235
  <dt className={classNames("hraness-marketing-trust-item__label")}>{item.label}</dt>
@@ -1491,6 +1503,8 @@ export interface MarketingRelatedProduct {
1491
1503
  }
1492
1504
 
1493
1505
  export interface MarketingRelatedGroup {
1506
+ /** Maximum columns for this group, overriding the section default. */
1507
+ readonly columns?: MarketingColumnCount;
1494
1508
  /** Heading naming this tier of siblings, rendered one level below the section heading. */
1495
1509
  readonly heading: string;
1496
1510
  readonly headingId: string;
@@ -1533,6 +1547,7 @@ type MarketingRelatedBody =
1533
1547
  /** Linked cards for sibling products: each shows the product's mark, name, and one-line description. */
1534
1548
  export function MarketingRelated({
1535
1549
  className,
1550
+ columns,
1536
1551
  heading,
1537
1552
  headingId,
1538
1553
  headingLevel = 2,
@@ -1543,6 +1558,8 @@ export function MarketingRelated({
1543
1558
  summary,
1544
1559
  }: Readonly<{
1545
1560
  className?: string;
1561
+ /** Maximum columns for each card row; a group can override it. */
1562
+ columns?: MarketingColumnCount;
1546
1563
  heading: string;
1547
1564
  headingId: string;
1548
1565
  headingLevel?: MarketingHeadingLevel;
@@ -1551,6 +1568,7 @@ export function MarketingRelated({
1551
1568
  summary?: string;
1552
1569
  }> &
1553
1570
  MarketingRelatedBody) {
1571
+ const defaultColumnProps = columns === undefined ? {} : { columns };
1554
1572
  return (
1555
1573
  <section
1556
1574
  aria-labelledby={headingId}
@@ -1568,7 +1586,7 @@ export function MarketingRelated({
1568
1586
  />
1569
1587
  {groups === undefined
1570
1588
  ? (
1571
- <MarketingCardRow>
1589
+ <MarketingCardRow {...defaultColumnProps}>
1572
1590
  <MarketingRelatedCards items={items} level={childHeadingLevel(headingLevel)} />
1573
1591
  </MarketingCardRow>
1574
1592
  )
@@ -1586,7 +1604,7 @@ export function MarketingRelated({
1586
1604
  ? null
1587
1605
  : <p className={classNames("hraness-marketing-related__group-summary")}>{group.summary}</p>}
1588
1606
  </div>
1589
- <MarketingCardRow ariaLabel={group.heading}>
1607
+ <MarketingCardRow ariaLabel={group.heading} {...(group.columns === undefined ? defaultColumnProps : { columns: group.columns })}>
1590
1608
  <MarketingRelatedCards items={group.items} level={childHeadingLevel(childHeadingLevel(headingLevel))} />
1591
1609
  </MarketingCardRow>
1592
1610
  </div>