@cloudgrid-io/ui 0.27.2 → 0.28.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.
@@ -388,6 +388,16 @@
388
388
  }
389
389
  }
390
390
  },
391
+ "neutral-600": {
392
+ "$value": "#6a6a6a",
393
+ "$type": "color",
394
+ "$description": "SOURCE: derived, 2026-09-18 (#232). The missing rung between neutral-500 and\nneutral-700, and the only reason it exists is that --cg-text-muted has no value\non this ramp that clears the 4.5:1 body-text floor.\n\nneutral-500 measures 3.69:1 on the card, 3.28:1 on the page ground and 3.29:1 on\nthe lavender wash. All three clear 3:1 for large text and none clears 4.5:1, so\nevery caption, every eyebrow and every tile hint in this library is under AA for\nbody copy. neutral-700 clears it everywhere (7.00:1 on the card) but it IS\n--cg-text-secondary, so aliasing a \"strong muted\" onto it would not add a rung,\nit would rename one.\n\nDerived, with the sweep, so the next person does not repeat it:\n\n #6e6e6e on the page ground : 4.53:1 clears by 0.03 — a margin a later\n ground retune would erase in silence\n #6c6c6c : 4.66:1\n #6a6a6a : 4.80:1 <-- this\n #686868 : 4.95:1\n\n #6a6a6a on the card #ffffff : 5.41:1\n on the page #f1f1f6 : 4.80:1\n on raised #f4f6f8 : 4.99:1\n on subtle #f2f1f7 : 4.82:1\n\nThe extra step past the first passing value is --cg-accent's practice, and for\nits reason: 4.53:1 is a number that a page-ground retune turns into a failure\nwith nothing going red.\n\nKNOWN, and not fixed here: on the violet-200 wash the frames draw (#d9d4fb) this\nmeasures 3.80:1, still under the body floor. Nothing on a neutral ramp clears\n4.5:1 on that ground and stays muted; see --cg-violet-200's own note.",
395
+ "$extensions": {
396
+ "io.cloudgrid": {
397
+ "css": "--cg-neutral-600"
398
+ }
399
+ }
400
+ },
391
401
  "neutral-700": {
392
402
  "$value": "#595959",
393
403
  "$type": "color",
@@ -407,6 +417,216 @@
407
417
  "css": "--cg-neutral-900"
408
418
  }
409
419
  }
420
+ },
421
+ "slate-300": {
422
+ "$value": "#d2d7de",
423
+ "$type": "color",
424
+ "$description": "SOURCE: Figma variable color/neutral/300, read first-hand on the thegrid frame\n(8364:4396, \"On the grid & to the world\" on the ink band).\n\nTHE NAME IS NOT AN ACCIDENT. Figma calls this family color/neutral/300 / 500 /\n600. This package's neutral ramp is already occupied at every one of those\nnumbers by a PURE grey (#acacac, #858585, #595959) that two published consumers\nship today, and these three are blue-greys: #828c98 is B152 against R130, which\nis not a grey at all. Taking the Figma numbers would mean either changing three\nshipped values (breaking) or having one ramp hold two hue families under one\nname (silent). So the cool family takes its own root and the greys keep theirs.\n\n1.45:1 on the card and 1.29:1 on the page ground: this is a value for text on a\ndark ground, never on a light one.",
425
+ "$extensions": {
426
+ "io.cloudgrid": {
427
+ "css": "--cg-slate-300"
428
+ }
429
+ }
430
+ },
431
+ "slate-500": {
432
+ "$value": "#828c98",
433
+ "$type": "color",
434
+ "$description": "SOURCE: Figma variable color/neutral/500, also carried under the legacy name\n\"N3 new\". Read first-hand on four of the six canonical frames — thegrid\n(8364:3966, footer links), teams (7172:7607), pricing (7779:9284), builders\n(6916:8104, the terminal's \"$\"). It is the design's quiet-text tone and the most\nfrequently missing value in this package (ui#239).\n\nWHAT IT MEASURES, because the frames spend it on words:\n\n on the card #ffffff : 3.41:1\n on the page ground #f1f1f6 : 3.03:1\n on raised #f4f6f8 : 3.15:1\n on the violet wash #d9d4fb : 2.40:1 <-- under even the 3:1 indicator bar\n on ink #222222 : 4.66:1\n on the purple panel #5a47f0 : 1.71:1 invisible\n\nSo it clears 3:1 for large text on the three light grounds, clears 4.5:1 on ink\nalone, and fails everywhere the frames actually use it for 15px footer links.\nIt is shipped because the frames use it and this package is meant to be able to\ndraw them; it is deliberately NOT wired to a --cg-text-* semantic, because those\ncarry a contrast contract and this value cannot meet it. --cg-slate-600 is the\ncompanion that can. See ui#232 for the same shape of problem on --cg-text-muted.\n\nDECLARED AT :root ONLY. A brand ramp rung is not a semantic and does not flip.",
435
+ "$extensions": {
436
+ "io.cloudgrid": {
437
+ "css": "--cg-slate-500"
438
+ }
439
+ }
440
+ },
441
+ "slate-600": {
442
+ "$value": "#5f6874",
443
+ "$type": "color",
444
+ "$description": "SOURCE: Figma variable color/neutral/600, read first-hand on thegrid\n(8364:4327, the stats rows; 8364:4255, \"your CREATIONS\").\n\nThis is the accessible companion to --cg-slate-500 and the design supplied it\nitself, which is why nothing had to be invented:\n\n on the card #ffffff : 5.65:1\n on the page ground #f1f1f6 : 5.02:1\n on raised #f4f6f8 : 5.21:1\n on subtle #f2f1f7 : 5.03:1\n on the cyan tint #dffbfc : 5.20:1\n on the violet wash #d9d4fb : 3.97:1 large text only\n on the lime #b6de68 : 3.67:1 large text only\n on ink #222222 : 2.82:1 do not\n on the purple panel #5a47f0 : 1.03:1 invisible\n\nSo: safe for body copy on any of the light page and card grounds, and on the\ncyan tint. NOT safe on the violet wash, on the lime, or on either dark surface.\nWhere the frames put slate-500 on a light ground and mean it as running text,\nthis is the value that keeps the design and passes.",
445
+ "$extensions": {
446
+ "io.cloudgrid": {
447
+ "css": "--cg-slate-600"
448
+ }
449
+ }
450
+ },
451
+ "stone-800": {
452
+ "$value": "#343330",
453
+ "$type": "color",
454
+ "$description": "SOURCE: Figma variable \"stone\", declared on the home frame (8204:2397). ui#239\nasks for it by name.\n\nHONEST PROVENANCE, because this is the one value here that is weaker than the\nrest: it is a DECLARATION. The home frame declares it as a variable, and the\nFigma quota ran out before the audit could read the ~90 nodes of that frame that\nmight paint with it. No node on any of the other five frames uses it. So its\nrole is recorded as unknown rather than guessed, and nothing in this package\nconsumes it yet.\n\nIt is a warm near-black, not a grey: R52 G51 B48 against --cg-ink's flat #222222.\n12.63:1 on the card and 11.22:1 on the page ground, so wherever it lands it is a\ntext-or-ink value and not a surface tint.\n\nThe rung number is by lightness against this package's own ramp, which ends at\nneutral-900 #222222. Figma gives it no number.",
455
+ "$extensions": {
456
+ "io.cloudgrid": {
457
+ "css": "--cg-stone-800"
458
+ }
459
+ }
460
+ }
461
+ },
462
+ "hue-ramps": {
463
+ "$description": "The three brand hues as RAMPS, not as single values (#239, 2026-09-18).\n\nUntil now this package carried one violet, one lime and one cyan, plus a single\n--cg-primary-tint. The six canonical Figma frames carry a full scale of each,\ndeclared as Figma variables under color/violet/*, color/lime/* and color/cyan/*,\nand they spend those rungs on real surfaces: chips, role badges, avatar strokes,\nstep diagrams, the enterprise button. With no rung to reach for, a consumer\neither hardcodes the hex, which CLAUDE.md forbids, or approximates with\ncolor-mix(). cloudgrid-landing is doing the second right now — #133 renders\n`color-mix(in srgb, var(--cg-primary) 22%, var(--cg-neutral-0))` to get within\n2/255 of --cg-violet-200 — and that is the drift this group removes.\n\nRUNG NUMBERS ARE FIGMA'S, not this package's, wherever Figma names them. Two\nrungs (violet-150, violet-400, cyan-400) are values observed applied on a node\nwith NO Figma variable behind them; each says so in its own note and is placed\nby lightness between the bound rungs either side. Nothing here was invented.\n\nWHY THE UTILITY NAMES DIVERGE FROM THE TOKEN NAMES. The violet ramp maps onto\n--color-brand-100..900, because \"brand\" is this package's own name for the hue\n(theme.css, rule 4) and Tailwind ships no `brand` scale to collide with. The\ncyan and lime rungs map onto SUFFIXED names (cyan-tint, lime-edge) rather than\ncyan-200 / lime-700, because Tailwind DOES ship those exact numbered names and\nclaiming them would silently repaint every `bg-cyan-200` in a consumer's own\nmarkup. That is rule 4's failure aimed at Tailwind instead of shadcn, and it is\nworse, because the consumer never opted in.\n\nDECLARED AT :root ONLY, like every brand source. A ramp rung is not a semantic\nand does not flip; the semantics that spend it do.",
464
+ "violet-100": {
465
+ "$value": "#ebe8fd",
466
+ "$type": "color",
467
+ "$description": "SOURCE: Figma color/violet/100. Applied on thegrid at 8364:4136 (the private-status chip), 8364:4158 (the Owner role badge) and the Add-people button. 1.20:1 on the card, so a ground and never a foreground.",
468
+ "$extensions": {
469
+ "io.cloudgrid": {
470
+ "css": "--cg-violet-100"
471
+ }
472
+ }
473
+ },
474
+ "violet-150": {
475
+ "$value": "#e3e0fd",
476
+ "$type": "color",
477
+ "$description": "SOURCE: observed applied, UNBOUND. teams 7172:7759 (the first flow circle) and builders 6919:8782 (the first step circle, \"Detect\"). No Figma variable carries it.\n\nIt is the value ui#239 asks for and the one cloudgrid-landing currently reaches with a color-mix of --cg-primary. Placed at 150 because it sits between the two bound rungs either side: violet-100 #ebe8fd and violet-200 #d9d4fb. A half-rung is not new here; the neutral ramp already carries neutral-25 between 0 and 50.\n\nMeasured as a ground: --cg-text-primary is 12.38:1 on it, --cg-slate-600 4.25:1, --cg-slate-500 2.56:1.",
478
+ "$extensions": {
479
+ "io.cloudgrid": {
480
+ "css": "--cg-violet-150"
481
+ }
482
+ }
483
+ },
484
+ "violet-200": {
485
+ "$value": "#d9d4fb",
486
+ "$type": "color",
487
+ "$description": "SOURCE: Figma color/violet/200, declared on the home and thegrid frames.\n\nREAD ui#239'S CORRECTION BEFORE USING --cg-offline FOR THIS. That issue's first table maps #D9D4FB onto --cg-offline, and the mapping only holds inside [data-cg-surface='panel']. At :root --cg-offline is var(--cg-neutral-500), a mid grey, so a consumer taking that token at face value on the page ground gets #858585 and nothing goes red. This rung is the value; --cg-offline is a status tone that happens to reach it on one surface.\n\nThe pairing the frames draw on it is a documented AA failure and the reason --cg-slate-600 exists: --cg-slate-500 on this ground measures 2.40:1, under even the 3:1 indicator bar. --cg-text-primary is 11.18:1, --cg-slate-600 3.97:1 (large text only), --cg-neutral-600 3.80:1.",
488
+ "$extensions": {
489
+ "io.cloudgrid": {
490
+ "css": "--cg-violet-200"
491
+ }
492
+ }
493
+ },
494
+ "violet-300": {
495
+ "$value": "#c8c2fa",
496
+ "$type": "color",
497
+ "$description": "SOURCE: Figma color/violet/300, declared on thegrid. Rendered there only inside flattened SVG illustration, so it is a declared rung with no CSS-reachable node behind it yet. Carried so the ramp a designer edits in Figma is the ramp this package ships.",
498
+ "$extensions": {
499
+ "io.cloudgrid": {
500
+ "css": "--cg-violet-300"
501
+ }
502
+ }
503
+ },
504
+ "violet-400": {
505
+ "$value": "#bcb4f9",
506
+ "$type": "color",
507
+ "$description": "SOURCE: observed applied, UNBOUND. builders 6919:8785, the second step circle.\n\nPlaced at 400 because it is the only observed violet with no bound rung within reach: it sits between color/violet/300 #c8c2fa and color/violet/500 #a69bf7.\n\nWorth knowing before retuning: the four builders step circles are #E3E0FD / #BCB4F9 / #A49AF7 / #8072F3, which are --cg-primary composited on white at 17 / 40 / 55 / 77 percent. The last two land within 2 and 4 of bound rungs 500 and 700 and are taken as those; this one does not.",
508
+ "$extensions": {
509
+ "io.cloudgrid": {
510
+ "css": "--cg-violet-400"
511
+ }
512
+ }
513
+ },
514
+ "violet-500": {
515
+ "$value": "#a69bf7",
516
+ "$type": "color",
517
+ "$description": "SOURCE: Figma color/violet/500, declared on thegrid. builders 6919:8788 paints #A49AF7, which is this value within 2/255 per channel and is treated as this rung rather than as a ninth violet.",
518
+ "$extensions": {
519
+ "io.cloudgrid": {
520
+ "css": "--cg-violet-500"
521
+ }
522
+ }
523
+ },
524
+ "violet-600": {
525
+ "$value": "#9488f5",
526
+ "$type": "color",
527
+ "$description": "SOURCE: Figma color/violet/600, declared on thegrid; rendered only inside flattened SVG illustration. Carried for the same reason as violet-300.",
528
+ "$extensions": {
529
+ "io.cloudgrid": {
530
+ "css": "--cg-violet-600"
531
+ }
532
+ }
533
+ },
534
+ "violet-700": {
535
+ "$value": "#8476f4",
536
+ "$type": "color",
537
+ "$description": "SOURCE: Figma color/violet/700. Applied on thegrid 8364:4388, the stroke around an avatar chip in the Plug section. builders 6919:8791 paints #8072F3, within 4/255 per channel, and is taken as this rung.\n\n3.57:1 on the card: an indicator or a border, never a word.",
538
+ "$extensions": {
539
+ "io.cloudgrid": {
540
+ "css": "--cg-violet-700"
541
+ }
542
+ }
543
+ },
544
+ "violet-900": {
545
+ "$value": "{brand.primary}",
546
+ "$description": "Figma names --cg-primary color/violet/900. Deliberately an ALIAS rather than the hex written a second time: the brand hue has one home, at the top of this file, and a designer retuning it must not have to find two.",
547
+ "$extensions": {
548
+ "io.cloudgrid": {
549
+ "css": "--cg-violet-900"
550
+ }
551
+ }
552
+ },
553
+ "cyan-200": {
554
+ "$value": "#dffbfc",
555
+ "$type": "color",
556
+ "$description": "SOURCE: Figma color/cyan/200, also carried under the legacy name \"Teriary 20\" (the typo is Figma's). Applied on three frames: thegrid 8364:4166 (the Editor role badge), teams 7172:7643 and pricing 7779:9320 (the footer's secondary buttons, with a --cg-tertiary hairline around them).\n\nIt IS a tint of the tertiary, and exactly: #60e9f0 composited on white at 20% is #dffbfc to the byte. Shipped as a value anyway rather than as a color-mix, because a consumer should not have to know the recipe to draw a button.\n\n--cg-slate-600 measures 5.20:1 on it and --cg-text-primary 14.65:1.",
557
+ "$extensions": {
558
+ "io.cloudgrid": {
559
+ "css": "--cg-cyan-200"
560
+ }
561
+ }
562
+ },
563
+ "cyan-300": {
564
+ "$value": "#cff8fa",
565
+ "$type": "color",
566
+ "$description": "SOURCE: Figma color/cyan/300, declared on thegrid; rendered only inside flattened SVG illustration. Carried so the ramp is whole.",
567
+ "$extensions": {
568
+ "io.cloudgrid": {
569
+ "css": "--cg-cyan-300"
570
+ }
571
+ }
572
+ },
573
+ "cyan-400": {
574
+ "$value": "#b1fcff",
575
+ "$type": "color",
576
+ "$description": "SOURCE: observed applied, UNBOUND. thegrid 8364:4002 and 8364:4056 — the footer and enterprise buttons, drawn as this fill with a --cg-tertiary hairline. ui#239's second comment asks for it.\n\nIT IS NOT A TINT OF --cg-tertiary, and that is worth the arithmetic, because every other rung in this family is. #60E9F0 has G 233, so reaching G 252 needs 86% white, and that mix gives R 233 — this value has R 177. Solving the same mix from the blue channel gives 0%. No single alpha produces it. So the color-mix() workaround available for the violet wash is not available here, which is precisely why the token is.\n\nPlaced at 400 by lightness, between bound rungs cyan-300 and cyan-900.\n\n5.07:1 on the purple panel and 13.82:1 on ink: as a fill it carries text on both dark surfaces. 1.15:1 on the card, so never a foreground on white.",
577
+ "$extensions": {
578
+ "io.cloudgrid": {
579
+ "css": "--cg-cyan-400"
580
+ }
581
+ }
582
+ },
583
+ "cyan-900": {
584
+ "$value": "{brand.tertiary}",
585
+ "$description": "Figma names --cg-tertiary color/cyan/900. An alias, for the reason violet-900 is one.",
586
+ "$extensions": {
587
+ "io.cloudgrid": {
588
+ "css": "--cg-cyan-900"
589
+ }
590
+ }
591
+ },
592
+ "lime-200": {
593
+ "$value": "#eef7dc",
594
+ "$type": "color",
595
+ "$description": "SOURCE: Figma color/lime/200, declared on thegrid; rendered only inside flattened SVG illustration. Carried so the ramp is whole.",
596
+ "$extensions": {
597
+ "io.cloudgrid": {
598
+ "css": "--cg-lime-200"
599
+ }
600
+ }
601
+ },
602
+ "lime-600": {
603
+ "$value": "#d0ea9e",
604
+ "$type": "color",
605
+ "$description": "SOURCE: Figma color/lime/600, declared on thegrid; rendered only inside flattened SVG illustration.",
606
+ "$extensions": {
607
+ "io.cloudgrid": {
608
+ "css": "--cg-lime-600"
609
+ }
610
+ }
611
+ },
612
+ "lime-700": {
613
+ "$value": "#c8e68e",
614
+ "$type": "color",
615
+ "$description": "SOURCE: Figma color/lime/700. Applied on thegrid 8364:4387, the stroke around the audience avatars in the Plug section.\n\n1.38:1 on the card and 4.22:1 on the purple panel: a border on a dark ground, not a line on a light one.",
616
+ "$extensions": {
617
+ "io.cloudgrid": {
618
+ "css": "--cg-lime-700"
619
+ }
620
+ }
621
+ },
622
+ "lime-900": {
623
+ "$value": "{brand.secondary}",
624
+ "$description": "Figma names --cg-secondary color/lime/900. An alias, for the reason violet-900 is one.",
625
+ "$extensions": {
626
+ "io.cloudgrid": {
627
+ "css": "--cg-lime-900"
628
+ }
629
+ }
410
630
  }
411
631
  },
412
632
  "semantic-surfaces": {
@@ -501,6 +721,15 @@
501
721
  }
502
722
  }
503
723
  },
724
+ "text-muted-strong": {
725
+ "$value": "{neutrals.neutral-600}",
726
+ "$description": "The muted tone for text that is real content: a tile hint, an eyebrow that\ncarries meaning, a caption a reader has to read. ui#232, 2026-09-18.\n\n--cg-text-muted is under the 4.5:1 body-text floor on three of the four grounds\n(3.69:1 card, 3.28:1 page, 3.44:1 panel, 5.92:1 ink), which means every caption\nin this library is AA-legal as large text and illegal as body copy. #232 asked\nfor a stronger rung rather than a retune, on the reasoning #149 used for\nstate's -strong: a tone tuned to recede and a tone tuned to be read are two\njobs, and collapsing them retunes both.\n\nIt is NOT --cg-text-secondary under a second name. Secondary is neutral-700\n(7.00:1 on the card) and reads as a second voice; this is neutral-600, a new\nrung derived for the floor and nothing else. Its note carries the sweep.\n\n base #6a6a6a card 5.41:1 page 4.80:1 raised 4.99:1 subtle 4.82:1\n panel rgba(255,255,255,0.86) on #5a47f0 : 4.75:1\n ink rgba(255,255,255,0.68) on #222222 : 8.02:1\n\nON THE PANEL THIS RUNG IS BRIGHTER THAN --cg-text-secondary, and that is not a\nmistake. Measured, the panel's own secondary (0.82 white) is 4.47:1, which is\nunder the floor by 0.03. Nothing dimmer than 0.84 white clears 4.5:1 on that\nground, so the panel cannot deliver a \"muted that reads as body copy\" below its\nown secondary. Same shape as the note further up about a panel chip's word:\nwhere the surface cannot deliver the ratio, the surface has to move, not the\nforeground. A designer who dislikes the inversion changes --cg-surface-panel,\nnot this.\n\nDECORATIVE CAPTIONS MAY KEEP --cg-text-muted. This rung does not deprecate it;\n#232's own done-when says so.",
727
+ "$extensions": {
728
+ "io.cloudgrid": {
729
+ "css": "--cg-text-muted-strong"
730
+ }
731
+ }
732
+ },
504
733
  "text-placeholder": {
505
734
  "$value": "{neutrals.neutral-400}",
506
735
  "$extensions": {
@@ -617,22 +846,32 @@
617
846
  "type-families": {
618
847
  "$description": "One face. The founder's 2026-09-10 draft (#197) is set in Manrope throughout —\nits only text styles are Manrope Medium 22, SemiBold 15 and Regular 13 — so the\ndisplay rung is Manrope too and the condensed face is retired.\n\nWhat that replaced: Futura Condensed Extra Bold where it was installed, with\nSaira Semi Condensed 800 self-hosted as the stand-in everywhere else. Neither is\nloaded any more. --cg-font-display is still its OWN stack rather than an alias of\nthe body one, so a future display face is a one-value edit here and not a\nre-plumbing.\n\nThe mono face is untouched: it is used only inside prompt and terminal surfaces\nand the draft says nothing about it.",
619
848
  "font-display": {
620
- "$value": "'Manrope Variable', 'Manrope', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
849
+ "$value": "'Tanker', 'Manrope Variable', 'Manrope', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
621
850
  "$type": "fontFamily",
622
851
  "$extensions": {
623
852
  "io.cloudgrid": {
624
853
  "css": "--cg-font-display"
625
854
  }
626
855
  },
627
- "$description": "The display rung, now Manrope (#197). Identical to --cg-font-body today and\ndeliberately still a separate token.\n\nA consumer that wants the licensed Futura back puts it in front of this stack in\nits own :root and changes nothing else. Note that the blocks reading this rung\nalso set `uppercase` and --cg-display-tracking, which were tuned for a condensed\n800; they still render, in Manrope, and whether the lockups keep the uppercase is\na block decision rather than a token one (#203)."
856
+ "$description": "The display face, and the one token in this file that names a font this package\ndoes NOT ship. ui#240, 2026-09-18.\n\nAll six canonical Figma frames set every headline in TANKER: the hero (92px on\nfive frames, 120px on home), every section heading (56px), every card title.\nNothing else in the design uses it and it is used for nothing else.\n\nTHE BINARY CANNOT SHIP HERE, and the reason is a licence, not an oversight.\nTanker is under the ITF Free Font License v2.0, whose section 02 forbids making\nthe Font Software available \"through another font website, font library,\nmarketplace, repository, download service, application or platform\". This\npackage is public on registry.npmjs.org, installable by anyone with no\ncredentials, which is exactly what that clause names. Section 03 states the\nremedy: \"Any third party wishing to use the Font Software must obtain their own\ncopy directly from Fontshare and be independently bound by this License.\"\n\nThat is why Manrope is fine and Tanker is not. Manrope arrives as\n@fontsource-variable/manrope under the Open Font License, which permits\nredistribution. Fontshare publishes no fontsource package.\n\nSo the package owns the STACK and the consumer owns the FILE. Adding 'Tanker' at\nthe front is strictly additive in effect: a consumer that has not self-hosted it\nfalls straight through to Manrope and renders exactly what 0.27.2 rendered.\nBefore this, a consumer wanting the display face had to copy this whole fallback\nchain verbatim into its own :root (cloudgrid-landing PR #132 did), and that copy\nwent stale the moment this package retired the condensed rung.\n\nPENDING, and stated so rather than assumed: the 2026-09-10 re-skin (#197)\ndeliberately removed the display rung and set the whole system in Manrope.\nWhether naming Tanker here reverses that decision is the founder's call, and it\nis the open question at the end of #240. This change is written to be reversible\nin one line if the answer is no.\n\nNOT RETUNED, deliberately: --cg-display-line (1.06) and --cg-display-tracking\n(0.012em) were tuned against Saira Semi Condensed 800. Every Tanker node in\nevery frame is leading-none with no tracking. See --cg-display-line-tight."
628
857
  },
629
858
  "font-body": {
630
- "$value": "'Manrope Variable', 'Manrope', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
859
+ "$value": "'Space Grotesk Variable', 'Space Grotesk', 'Manrope Variable', 'Manrope', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
631
860
  "$type": "fontFamily",
632
861
  "$extensions": {
633
862
  "io.cloudgrid": {
634
863
  "css": "--cg-font-body"
635
864
  }
865
+ },
866
+ "$description": "The body face. cloudgrid-landing#145, 2026-09-18.\n\nEvery body string in the canonical frames is SPACE GROTESK, and it was checked\non five of the six independently before it was believed: home 8204:2561 and\n8204:2563, thegrid 8364:4213, builders 6913:7654, teams 7172:7571, enterprise\n7037:779, pricing 7779:9261 — all 20px / 1.46, all the lede under a headline,\nall in unrelated sections. The nav links and the card copy are the same face at\n15px. This is the design's text face, not a stray on one frame.\n\nIT SHIPS HERE, unlike Tanker. @fontsource-variable/space-grotesk is OFL-1.1,\nwhich permits redistribution, so it arrives as a dependency and an @import in\nfonts.css exactly the way Manrope does. See fonts.css.\n\nTHIS IS A VALUE CHANGE, not an addition, and it is the only one in this release.\nManrope is kept in the chain immediately behind it, so a consumer whose pipeline\nsomehow does not resolve the new dependency renders precisely what it rendered\nbefore. Blast radius: every string in every consumer that has not overridden\nthis token changes face. Metrics differ — Space Grotesk is wider at the same\nsize — so a consumer with a tightly measured layout should look at it before\ntaking the release. cloudgrid-landing is the consumer that asked for it.\n\nMANROPE DID NOT LEAVE. The frames keep it, and only for two jobs: the eyebrow\nand the button label. Those now read --cg-font-ui, which is this token's\nprevious value unchanged, so neither of them moves."
867
+ },
868
+ "font-ui": {
869
+ "$value": "'Manrope Variable', 'Manrope', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
870
+ "$description": "The face for the small fixed chrome of a page: the eyebrow above a heading, and\nthe label inside a button. 2026-09-18.\n\nA third family stack is not a flourish. The canonical frames use exactly three\nfaces in three jobs — Tanker for display, Space Grotesk for everything a reader\nreads, and MANROPE for the eyebrow and the button label — and they are\nconsistent about it. Every button label on all six frames is Manrope Bold 15\nleading-none (home I8204:2580;732:46, thegrid I8364:4215;732:46, builders\nI6913:7656;732:46, teams I7172:7573;732:46, enterprise I7037:781;732:46,\npricing I7779:9336;732:46). Every applied eyebrow is Manrope SemiBold 14, and\nFigma binds it as a named text variable, \"Eyebrow\".\n\nIts VALUE is --cg-font-body's previous value, byte for byte. That is what makes\nthe body-face change safe to read: the eyebrow and the button did not move, they\njust stopped being spelled with the body token.\n\nKNOWN INCONSISTENCY IN THE SOURCE, recorded so nobody \"fixes\" it from the wrong\nend: on the home frame the four nav links (8204:2573) are Manrope Medium 15 and\n\"Sign In\" beside them (8204:2579) is Space Grotesk Medium 15 — same slot, same\nsize, same weight, two faces. On thegrid the same split appears at 8364:4053\nagainst 8364:4052/4054/4055. Five frames agree the nav is Space Grotesk, so the\nManrope instances read as a migration caught mid-flight rather than as intent,\nand this token is NOT the nav's face.",
871
+ "$extensions": {
872
+ "io.cloudgrid": {
873
+ "css": "--cg-font-ui"
874
+ }
636
875
  }
637
876
  },
638
877
  "font-mono": {
@@ -688,6 +927,26 @@
688
927
  },
689
928
  "h1-display-ramp": {
690
929
  "$description": "H1 display ramp: uppercase, condensed, Primary or white\n\nStepped down one notch 2026-08-06 (operator: main headings read too\ndominant). The SOURCE values were xl 64 / lg 48 / md 42 / sm 32.",
930
+ "display-3xl": {
931
+ "$value": "120px",
932
+ "$type": "dimension",
933
+ "$description": "SOURCE: home 8204:2556, the hero headline, Tanker at leading-none.\n\nThe largest rung in the system and the only node that asks for it. It is kept\nseparate from display-2xl rather than collapsed onto it because the two are 28px\napart and both are heroes: home is 120 and the other five frames are 92.",
934
+ "$extensions": {
935
+ "io.cloudgrid": {
936
+ "css": "--cg-display-3xl"
937
+ }
938
+ }
939
+ },
940
+ "display-2xl": {
941
+ "$value": "92px",
942
+ "$type": "dimension",
943
+ "$description": "SOURCE: the hero headline on five of the six canonical frames — thegrid\n8364:4211, builders 6913:7652, teams 7172:7569, enterprise 7037:777, pricing\n7779:9259. Tanker, leading-none, no tracking.\n\nThis is the ramp's real top. Before it, --cg-display-xl (56px) was the largest\nvalue in the package and every hero in the design was 36px above it, so each\nconsumer clamped its own. thegrid also draws a 96px closing CTA (8364:3957) and\na 64px section heading (8364:4363); both are single nodes and are deliberately\nnot rungs. A value invented to complete a grid is the thing this file keeps\nrefusing to add.",
944
+ "$extensions": {
945
+ "io.cloudgrid": {
946
+ "css": "--cg-display-2xl"
947
+ }
948
+ }
949
+ },
691
950
  "display-xl": {
692
951
  "$value": "56px",
693
952
  "$type": "dimension",
@@ -742,6 +1001,66 @@
742
1001
  "css": "--cg-display-tracking"
743
1002
  }
744
1003
  }
1004
+ },
1005
+ "display-line-tight": {
1006
+ "$value": "1",
1007
+ "$description": "The leading every Tanker node in every canonical frame actually uses: 1, i.e.\nleading-none. Not one display node in six frames emits a letter-spacing either.\n\n--cg-display-line stays 1.06 and --cg-display-tracking stays 0.012em. Both were\ntuned against Saira Semi Condensed 800 (ui#240 records this), neither has been\nretuned for Tanker, and both are shipped values that four display rungs and\nevery consumer's display utility already read. Retuning them is a one-line edit\nand a visible change to text that exists today, so it is proposed rather than\nmade. This rung is what the new sizes are built on in the meantime.",
1008
+ "$extensions": {
1009
+ "io.cloudgrid": {
1010
+ "css": "--cg-display-line-tight"
1011
+ }
1012
+ }
1013
+ }
1014
+ },
1015
+ "tanker-title-ramp": {
1016
+ "$description": "The display face at CARD scale, 2026-09-18.\n\nFour rungs the canonical frames use constantly and this package could spell\nnone of. They are separated from h1-display-ramp rather than wedged into it\nbecause the two ramps disagree everywhere they overlap, and the disagreement is\nnot resolvable by addition:\n\n frames 120 96 92 64 56 40 38 32 30 26 20\n package 56 44 38 30\n\n56, 38 and 30 coincide. 44 is used by nothing in any of the six frames. Every\nother size the frames ask for falls BETWEEN two shipped rungs — 40 between 44\nand 38, 26 between 30 and heading-lg's 22 — so there is no name left on the\nt-shirt ramp that is both free and in the right place, and renaming a shipped\nrung is a breaking change for two published consumers.\n\nThey are also not headings. --cg-heading-* is the Manrope ramp at 1.2 leading;\nthis is the display FACE at leading-none, and --cg-title-sm and\n--cg-heading-md are both 20px precisely because a face and a leading are what\nseparate them, not a size.\n\nSIZES, with where they were read:\n 40 home 8204:2589, enterprise 7038:1244, pricing 7785:9809, thegrid 8364:4382\n 26 teams 7297:8606, builders 6916:8648, enterprise 7038:1192,\n pricing 7788:10264, thegrid 8364:3882\n 20 teams 7172:7760, builders 6919:8783, thegrid petal labels\n\npricing 7785:10059 draws one 32px Tanker number and thegrid draws 15px Tanker\neyebrows. Single-frame, so recorded and not given a rung.",
1017
+ "title-lg": {
1018
+ "$value": "40px",
1019
+ "$type": "dimension",
1020
+ "$description": "Four frames. The governance card title, the plan price, the sub-heading under a section statement.",
1021
+ "$extensions": {
1022
+ "io.cloudgrid": {
1023
+ "css": "--cg-title-lg"
1024
+ }
1025
+ }
1026
+ },
1027
+ "title-md": {
1028
+ "$value": "26px",
1029
+ "$type": "dimension",
1030
+ "$description": "Five frames. The card title and the FAQ question — the most common display size in the design after the section heading.\n\nui#239's type table calls this rung \"24px card title\". Measured on five frames it is 26, not 24, and nothing in any frame is 24. The table was written from a consumer's approximation rather than from the node.",
1031
+ "$extensions": {
1032
+ "io.cloudgrid": {
1033
+ "css": "--cg-title-md"
1034
+ }
1035
+ }
1036
+ },
1037
+ "title-sm": {
1038
+ "$value": "20px",
1039
+ "$type": "dimension",
1040
+ "$description": "Three frames. The label inside a step circle or a diagram petal. Same size as --cg-heading-md and a different face and leading; see the group note.",
1041
+ "$extensions": {
1042
+ "io.cloudgrid": {
1043
+ "css": "--cg-title-sm"
1044
+ }
1045
+ }
1046
+ },
1047
+ "title-line": {
1048
+ "$value": "{h1-display-ramp.display-line-tight}",
1049
+ "$description": "leading-none, aliased rather than repeated so a retune of the display leading reaches both ramps. An alias compiles to var(), so it survives a scope flip.",
1050
+ "$extensions": {
1051
+ "io.cloudgrid": {
1052
+ "css": "--cg-title-line"
1053
+ }
1054
+ }
1055
+ },
1056
+ "title-tracking": {
1057
+ "$value": "0em",
1058
+ "$description": "No Tanker node in any of the six frames emits a letter-spacing. Spelled out rather than omitted so a utility built on this ramp cannot inherit --cg-display-tracking's 0.012em by accident.",
1059
+ "$extensions": {
1060
+ "io.cloudgrid": {
1061
+ "css": "--cg-title-tracking"
1062
+ }
1063
+ }
745
1064
  }
746
1065
  },
747
1066
  "manrope-ramp": {
@@ -785,6 +1104,16 @@
785
1104
  },
786
1105
  "$description": "SOURCE: the draft's H4 line height (#197). Was 1.3.\n\nOne leading serves all three heading rungs, so the 17px and 20px rungs tighten\nwith the 22px one. That is the draft's own proportion rather than an\nextrapolation, and a heading is short enough that 1.2 does not cost a line its\ndescenders."
787
1106
  },
1107
+ "body-xl": {
1108
+ "$value": "20px",
1109
+ "$type": "dimension",
1110
+ "$description": "SOURCE: the lede paragraph on all six canonical frames — home 8204:2561,\nthegrid 8364:4213, builders 6913:7654, teams 7172:7571, enterprise 7037:779,\npricing 7779:9261. Space Grotesk regular, line-height 1.46, no tracking.\n\nThe single most-used text size in the whole design and the one this package\ncould not spell. --cg-body-lg is 19px and --cg-heading-md is 20px, so a\nconsumer building a lede had to pick between a body token one pixel short and a\nheading token that is the right size with the wrong role and the wrong leading\n(1.2 against 1.46). cloudgrid-landing#145 records sections doing the first.\n\nIt reads --cg-body-line, so it is a body rung and not a fifth display rung.\n\npricing 7785:9832 draws one 18px bold plan name. Single node, one frame, 1px\noff --cg-body-lg: recorded, not given a rung.",
1111
+ "$extensions": {
1112
+ "io.cloudgrid": {
1113
+ "css": "--cg-body-xl"
1114
+ }
1115
+ }
1116
+ },
788
1117
  "body-lg": {
789
1118
  "$value": "19px",
790
1119
  "$type": "dimension",
@@ -878,6 +1207,43 @@
878
1207
  "css": "--cg-label-weight"
879
1208
  }
880
1209
  }
1210
+ },
1211
+ "eyebrow-size": {
1212
+ "$value": "14px",
1213
+ "$type": "dimension",
1214
+ "$description": "SOURCE: Figma's own bound text variable, \"Eyebrow\" —\nFont(family: \"Manrope\", style: SemiBold, size: 14, weight: 600, lineHeight: 1.2,\nletterSpacing: 10). Applied first-hand on teams 7172:8463, builders 6916:8053\nand enterprise 7038:1184, each rendering tracking-[1.4px] uppercase.\n\nThe only rung in this package derived from a Figma TEXT variable rather than\nfrom a measured node, and it agrees with the nodes, which is why it is trusted.\n\nIt is equidistant from the two tokens a consumer would otherwise reach for:\n--cg-caption is 13px and --cg-label-size is 15px, and Eyebrow currently builds\non the second. One pixel is not the point — the eyebrow also carries a weight,\na leading and a tracking that neither of those tokens has, and spelling three\nof the four inline is how a component drifts.\n\nKNOWN: thegrid draws its eyebrows differently — Tanker regular 15px, leading\n16px, tracking 1.1px (8364:3905, 8364:4409) — and both of pricing's eyebrows are\nswitched off in the file. So this is the eyebrow of three frames, not six, and\nthegrid's is an open question for the designer rather than a second rung here.",
1215
+ "$extensions": {
1216
+ "io.cloudgrid": {
1217
+ "css": "--cg-eyebrow-size"
1218
+ }
1219
+ }
1220
+ },
1221
+ "eyebrow-line": {
1222
+ "$value": "1.2",
1223
+ "$description": "From the Eyebrow variable. The same number as --cg-heading-line, spelled out rather than aliased: an eyebrow is not a heading, and a heading retune must not silently move it.",
1224
+ "$extensions": {
1225
+ "io.cloudgrid": {
1226
+ "css": "--cg-eyebrow-line"
1227
+ }
1228
+ }
1229
+ },
1230
+ "eyebrow-tracking": {
1231
+ "$value": "0.1em",
1232
+ "$description": "From the Eyebrow variable, whose letterSpacing is 10 — Figma's percent, not pixels. At 14px that is 1.4px, which is what all three frames render. Stored in em so the ratio survives a size change.",
1233
+ "$extensions": {
1234
+ "io.cloudgrid": {
1235
+ "css": "--cg-eyebrow-tracking"
1236
+ }
1237
+ }
1238
+ },
1239
+ "eyebrow-weight": {
1240
+ "$value": "{weights.weight-bold}",
1241
+ "$description": "600, from the Eyebrow variable's weight: 600.\n\nAliased onto --cg-weight-bold rather than written as a number, because 600 is\nalready this package's \"bold\" (the weights group's own note explains why that\nname and not \"semibold\"). Two spellings of one weight is how a ramp starts\ndisagreeing with itself.\n\nNote this is NOT --cg-label-weight, which is 500. The eyebrow and the label are\ndifferent rungs; see the group note.",
1242
+ "$extensions": {
1243
+ "io.cloudgrid": {
1244
+ "css": "--cg-eyebrow-weight"
1245
+ }
1246
+ }
881
1247
  }
882
1248
  },
883
1249
  "spacing": {
@@ -1154,6 +1520,16 @@
1154
1520
  }
1155
1521
  }
1156
1522
  },
1523
+ "radius-container": {
1524
+ "$value": "20px",
1525
+ "$type": "dimension",
1526
+ "$description": "SOURCE: the corner of every section slab and every card in the design, read on\nall six canonical frames — home 8204:2440, thegrid 8364:3928, builders\n6913:8019, teams 7172:7567, enterprise 7037:775, pricing 7785:10051.\n\nIt is the most-used radius in the whole design and the ramp had no name for it.\n--cg-radius-xl is 16 and --cg-radius-2xl is 24, and both are shipped, so 20 has\nno free t-shirt name in the right place. Renaming a rung two published\nconsumers already read is a breaking change for a corner.\n\nSo it takes a ROLE name, which the corners group already does once for\n--cg-radius-pill. The role is exact and worth stating: in these frames 16 is\nwhat a CONTROL is rounded to (every button on every frame is 16) and 20 is what\na CONTAINER is rounded to. The design draws that distinction consistently, which\nis more information than a number between two numbers.\n\nNOT --cg-radius-panel, deliberately: \"panel\" in this package is the purple\nsurface (--cg-surface-panel, data-cg-surface=\"panel\"), and a radius named after\nit would read as that surface's corner rather than as every container's.",
1527
+ "$extensions": {
1528
+ "io.cloudgrid": {
1529
+ "css": "--cg-radius-container"
1530
+ }
1531
+ }
1532
+ },
1157
1533
  "radius-2xl": {
1158
1534
  "$value": "24px",
1159
1535
  "$type": "dimension",
@@ -1164,6 +1540,16 @@
1164
1540
  }
1165
1541
  }
1166
1542
  },
1543
+ "radius-3xl": {
1544
+ "$value": "32px",
1545
+ "$type": "dimension",
1546
+ "$description": "SOURCE: home 8204:2557 and 8204:2569, the two 92px lime image cards in the hero.\n\nOne frame, two nodes, and it is here rather than recorded-and-skipped for one\nreason: it extends the t-shirt ramp at the TOP, where there is a free name and\nno ambiguity, instead of asking for one between two shipped rungs.\n\nWHAT IS NOT HERE. The brief this work came from expected a rung between\n--cg-radius-2xl and --cg-radius-pill for a frame nesting 108 / 93 / 80px\ncorners. No radius above 60 and below the pill appears on any of the six frames\nfirst-hand. builders draws 60px on three decorative glow rectangles\n(7172:8460-8462) and thegrid draws 22 / 18 / 15 / 11 / 9 inside a flattened\nproduct-UI mock. None of those is a rung; all are recorded here so the next\naudit does not re-find them. The home frame is only ~10% audited (the Figma\nquota ran out), so if that expectation has a node behind it, it is there.",
1547
+ "$extensions": {
1548
+ "io.cloudgrid": {
1549
+ "css": "--cg-radius-3xl"
1550
+ }
1551
+ }
1552
+ },
1167
1553
  "radius-pill": {
1168
1554
  "$value": "999px",
1169
1555
  "$type": "dimension",
@@ -27,6 +27,16 @@
27
27
  }
28
28
  }
29
29
  },
30
+ "text-muted-strong": {
31
+ "$value": "rgba(255, 255, 255, 0.68)",
32
+ "$type": "color",
33
+ "$description": "8.02:1 on --cg-surface-code. Ink is the one ground where --cg-text-muted\nalready clears the body floor (5.92:1), so this rung exists there for\nconsistency of meaning rather than to fix a ratio: a component that reaches for\ntext-faint-strong must resolve to something on all three surfaces, and\nresolving to the base #6a6a6a inside a dark scope would be the CLAUDE.md rule-3\nfailure. It sits between the ink scope's muted (0.56) and its secondary (0.78).",
34
+ "$extensions": {
35
+ "io.cloudgrid": {
36
+ "css": "--cg-text-muted-strong"
37
+ }
38
+ }
39
+ },
30
40
  "text-accent": {
31
41
  "$value": "{brand.secondary}",
32
42
  "$extensions": {
@@ -27,6 +27,16 @@
27
27
  }
28
28
  }
29
29
  },
30
+ "text-muted-strong": {
31
+ "$value": "rgba(255, 255, 255, 0.86)",
32
+ "$type": "color",
33
+ "$description": "4.75:1 on --cg-surface-panel. See the base note: on this ground nothing dimmer\nthan 0.84 white clears the 4.5:1 floor, so this rung is necessarily brighter\nthan the panel's own --cg-text-secondary (0.82, 4.47:1). The surface is what\nwould have to move to change that, not this value.",
34
+ "$extensions": {
35
+ "io.cloudgrid": {
36
+ "css": "--cg-text-muted-strong"
37
+ }
38
+ }
39
+ },
30
40
  "text-accent": {
31
41
  "$value": "#ffffff",
32
42
  "$type": "color",