[{"data":1,"prerenderedAt":674},["ShallowReactive",2],{"i-lucide:chevron-down":3,"i-lucide:search":8,"i-lucide:sun":10,"i-lucide:moon":12,"i-lucide:arrow-right":14,"i-lucide:menu":16,"i-lucide:mail":18,"i-simple-icons:x":20,"i-simple-icons:linkedin":22,"i-simple-icons:dribbble":25,"i-simple-icons:github":27,"work-\u002Fwork\u002Fnorthwind-design-system":29,"work-order":585,"i-lucide:clock":616,"i-lucide:flask-conical":618,"i-lucide:target":620,"i-lucide:minus":622,"i-lucide:pen-tool":624,"i-lucide:lightbulb":626,"i-lucide:git-compare":628,"i-lucide:palette":630,"i-lucide:type":632,"i-lucide:variable":634,"i-lucide:component":636,"i-lucide:plus":638,"i-lucide:circle-alert":640,"i-lucide:check":642,"i-lucide:circle-check":644,"i-lucide:triangle-alert":646,"i-lucide:circle-dashed":648,"i-lucide:gauge":650,"i-lucide:rocket":652,"i-lucide:users":654,"i-lucide:sliders-horizontal":656,"i-lucide:chevron-right":658,"i-lucide:layers":660,"i-lucide:blocks":662,"i-lucide:git-branch":664,"i-lucide:trending-up":666,"i-simple-icons:figma":668,"i-lucide:book-open":670,"i-lucide:circle-x":672},{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":7},0,24,false,"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"m6 9l6 6l6-6\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":9},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"m21 21l-4.34-4.34\"\u002F>\u003Ccircle cx=\"11\" cy=\"11\" r=\"8\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":11},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Ccircle cx=\"12\" cy=\"12\" r=\"4\"\u002F>\u003Cpath d=\"M12 2v2m0 16v2M4.93 4.93l1.41 1.41m11.32 11.32l1.41 1.41M2 12h2m16 0h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":13},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":15},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 12h14m-7-7l7 7l-7 7\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":17},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 5h16M4 12h16M4 19h16\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":19},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"m22 7l-8.991 5.727a2 2 0 0 1-2.009 0L2 7\"\u002F>\u003Crect width=\"20\" height=\"16\" x=\"2\" y=\"4\" rx=\"2\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":21},"\u003Cpath fill=\"currentColor\" d=\"M14.234 10.162L22.977 0h-2.072l-7.591 8.824L7.251 0H.258l9.168 13.343L.258 24H2.33l8.016-9.318L16.749 24h6.993zm-2.837 3.299l-.929-1.329L3.076 1.56h3.182l5.965 8.532l.929 1.329l7.754 11.09h-3.182z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":23,"hidden":24},"\u003Cpath fill=\"currentColor\" d=\"M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037c-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85c3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.06 2.06 0 0 1-2.063-2.065a2.064 2.064 0 1 1 2.063 2.065m1.782 13.019H3.555V9h3.564zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0z\"\u002F>",true,{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":26},"\u003Cpath fill=\"currentColor\" d=\"M12 24C5.385 24 0 18.615 0 12S5.385 0 12 0s12 5.385 12 12s-5.385 12-12 12m10.12-10.358c-.35-.11-3.17-.953-6.384-.438c1.34 3.684 1.887 6.684 1.992 7.308a10.28 10.28 0 0 0 4.395-6.87zm-6.115 7.808c-.153-.9-.75-4.032-2.19-7.77l-.066.02c-5.79 2.015-7.86 6.025-8.04 6.4a10.16 10.16 0 0 0 6.29 2.166c1.42 0 2.77-.29 4-.814zm-11.62-2.58c.232-.4 3.045-5.055 8.332-6.765q.202-.067.405-.12q-.392-.879-.832-1.74C7.17 11.775 2.206 11.71 1.756 11.7l-.004.312c0 2.633.998 5.037 2.634 6.855zm-2.42-8.955c.46.008 4.683.026 9.477-1.248a66 66 0 0 0-3.8-5.928a10.28 10.28 0 0 0-5.676 7.17zM9.6 2.052c.282.38 2.145 2.914 3.822 6c3.645-1.365 5.19-3.44 5.373-3.702A10.2 10.2 0 0 0 12 1.764c-.825 0-1.63.1-2.4.285zm10.335 3.483c-.218.29-1.935 2.493-5.724 4.04c.24.49.47.985.68 1.486c.08.18.15.36.22.53c3.41-.43 6.8.26 7.14.33c-.02-2.42-.88-4.64-2.31-6.38z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":28},"\u003Cpath fill=\"currentColor\" d=\"M12 .297c-6.63 0-12 5.373-12 12c0 5.303 3.438 9.8 8.205 11.385c.6.113.82-.258.82-.577c0-.285-.01-1.04-.015-2.04c-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729c1.205.084 1.838 1.236 1.838 1.236c1.07 1.835 2.809 1.305 3.495.998c.108-.776.417-1.305.76-1.605c-2.665-.3-5.466-1.332-5.466-5.93c0-1.31.465-2.38 1.235-3.22c-.135-.303-.54-1.523.105-3.176c0 0 1.005-.322 3.3 1.23c.96-.267 1.98-.399 3-.405c1.02.006 2.04.138 3 .405c2.28-1.552 3.285-1.23 3.285-1.23c.645 1.653.24 2.873.12 3.176c.765.84 1.23 1.91 1.23 3.22c0 4.61-2.805 5.625-5.475 5.92c.42.36.81 1.096.81 2.22c0 1.606-.015 2.896-.015 3.286c0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12\"\u002F>",{"id":30,"title":31,"accent":32,"accentLight":33,"body":34,"challenge":132,"client":147,"cover":148,"coverAlt":149,"decisions":150,"description":181,"excerpt":182,"extension":183,"featured":24,"features":184,"flows":209,"gallery":249,"ia":286,"industry":339,"kind":340,"meta":341,"navigation":24,"order":342,"outcomes":343,"path":368,"platform":369,"principles":372,"projectType":391,"research":392,"seo":470,"services":471,"stack":475,"stem":481,"system":482,"timeline":582,"year":583,"__hash__":584},"work\u002Fwork\u002F1.northwind-design-system.md","One design system across four acquired products","#00D4FF","#0093B8",{"type":35,"value":36,"toc":123},"minimark",[37,42,46,49,52,56,59,62,81,84,88,91,94,97,101,104,111,117],[38,39,41],"h2",{"id":40},"why-build-us-a-component-library-was-the-wrong-brief","Why \"build us a component library\" was the wrong brief",[43,44,45],"p",{},"The brief this scenario opens with is a component library. It is the brief most\nconsolidation projects get, and taking it literally is how you end up with\nvariant twelve.",[43,47,48],{},"A library is a supply-side fix. It assumes the problem is that good components\ndo not exist, so it makes them exist. But the failure mode in a four-product\nestate is not scarcity — Northwind has plenty of buttons, and several of them\nare good. The failure is that finding the right one costs more than writing a\nnew one, and a library does nothing about that arithmetic. It adds a thirteenth\nplace to look.",[43,50,51],{},"So the thing we designed is not a library. It is three separate mechanisms that\nhappen to ship together: a token architecture that makes a rebrand cheap, a\ncomponent contract that makes drift expressible only through review, and a\nmigration plan that replaces the old code rather than sitting beside it. Remove\nany one of them and the other two decay within two quarters.",[38,53,55],{"id":54},"the-three-layer-bet","The three-layer bet",[43,57,58],{},"The core structural bet is the semantic layer, and it is worth being honest that\nit is a bet.",[43,60,61],{},"The obvious architecture is two layers: a palette, and components that use it.\nIt is simpler, it is easier to read, and it works fine until the first time\nanyone needs a second theme. At that point every component holds a decision that\nshould have been held centrally, and there are 48 places to make the same edit.",[43,63,64,65,69,70,73,74,76,77,80],{},"The three-layer version costs a hop. ",[66,67,68],"code",{},"Button"," asks for ",[66,71,72],{},"primary",", ",[66,75,72],{},"\nresolves to ",[66,78,79],{},"cyan-500"," in dark and to a different hue entirely in light — not a\nlighter step of the same one, because the bright cyan that carries a near-black\nsurface measures under 2:1 against white and is unreadable as a 1px border. That\nsubstitution is invisible to every component, which is the point, and it is also\nthe thing that makes the light theme a token edit instead of a redesign.",[43,82,83],{},"What we gave up is legibility at the call site. You cannot read a component and\nknow what colour it renders. New contributors find this genuinely irritating,\nand the honest defence is only that the alternative is worse at the scale where\nit matters.",[38,85,87],{"id":86},"migration-as-the-deliverable","Migration as the deliverable",[43,89,90],{},"The part of this plan most likely to be cut is the four paired migration weeks,\nso it is scoped in from week one rather than proposed as a follow-up.",[43,92,93],{},"The reasoning is arithmetic. Codemods handle the mechanical transformations —\nraw values to token references, spacing literals to scale steps — which is most\nof the volume and none of the judgement. What is left is roughly 30% of the\nwork, and every item in it needs a decision: this table is close enough to the\nsystem table to migrate, that one is genuinely different and needs a variant, a\nthird should not exist at all.",[43,95,96],{},"Those decisions are fast when someone who knows the system sits next to someone\nwho knows the product, and they are indefinitely slow when they sit in a backlog\nbelonging to a team with its own roadmap. A half-migrated estate is worse than\nan unmigrated one, because now there are two right answers.",[38,98,100],{"id":99},"where-this-would-strain","Where this would strain",[43,102,103],{},"Three places, stated plainly because a case study with no failure modes is a\nbrochure.",[43,105,106,110],{},[107,108,109],"strong",{},"The variant-request turnaround is load-bearing."," The contract only holds if\nadding a legitimately new variant is fast. At a two-day turnaround teams will\nuse it; at two weeks they will find the override that still works, and the\ntable stops being a contract. Nothing in the architecture enforces the SLA — it\nis a staffing commitment wearing a technical hat.",[43,112,113,116],{},[107,114,115],{},"The adoption metric is gameable."," Wrapping a bespoke component in a system\ncontainer raises the number without improving anything. Reporting it as a trend\nrather than a target, and keeping it out of performance review, is the only\nmitigation, and it is a social one.",[43,118,119,122],{},[107,120,121],{},"Four products may not actually want one system."," The scenario assumes enough\noverlap to justify shared components, and that assumption deserves testing\nbefore the investment. If the billing product's tables and the observability\nproduct's tables have genuinely different requirements, the honest answer is two\nsystems on shared tokens — a much smaller, much less impressive project that\nwould be the right one.",{"title":124,"searchDepth":125,"depth":125,"links":126},"",3,[127,129,130,131],{"id":40,"depth":128,"text":41},2,{"id":54,"depth":128,"text":55},{"id":86,"depth":128,"text":87},{"id":99,"depth":128,"text":100},{"summary":133,"points":134},"Northwind Cloud is a scenario we built around the most common way enterprise design debt accumulates: not through carelessness, but through acquisition. Four products, four front-end codebases, four teams who each made locally reasonable decisions and never had a reason to agree. The cost only becomes visible the first time someone tries to ship something across all four.",[135,138,141,144],{"label":136,"detail":137},"Nobody made a bad decision","A 6px radius in billing and a 4px radius in observability are both defensible in isolation. There is no villain to point at, which is precisely why the problem persists — every individual choice survives review, and only the aggregate is indefensible.",{"label":139,"detail":140},"Writing a new component is faster than finding the right one","This is the mechanism that generates variant twelve. As long as search costs more than reimplementation, a component library is just a thirteenth place to look. Any fix that does not change this arithmetic fails no matter how good the components are.",{"label":142,"detail":143},"A shared navigation needs four implementations","The trigger for the scenario. Northwind wants one navigation bar across all four surfaces, and discovers that shipping it means writing it four times and maintaining it four times, forever.",{"label":145,"detail":146},"Consistency is not the business case","Leadership does not fund tidiness. The case has to be made in delivery time and in the cost of the next cross-product feature, which means the system has to be measurable from the first week.","Northwind Cloud","\u002Fcase-studies\u002Fnorthwind\u002Fscreens\u002Ftoken-architecture.webp","Northwind design system — the three-layer token architecture screen",[151,157,163,169,175],{"title":152,"problem":153,"decision":154,"rationale":155,"tradeoff":156},"A semantic layer between primitives and components","With components reading the palette directly, every theme, brand or contrast variation means touching all 48 of them. The alternative — one set of role names in the middle — costs the reader a hop.","Components may only reference semantic roles. The primitive ramps are private to the token build, and a lint rule fails any component that imports one.","It converts a 48-file change into a one-file change, and it makes the light theme possible at all: several roles resolve to a *different* hue in light mode, not a lighter step of the same one, because the dark-mode accents fail contrast on a white surface.","Reading a component no longer tells you what colour it is. Debugging goes through one extra indirection, and new contributors reliably find this annoying for their first fortnight.",{"title":158,"problem":159,"decision":160,"rationale":161,"tradeoff":162},"The variant table is the component's contract","A component that accepts arbitrary class overrides has no API — it has a suggestion. That is how eleven buttons became eleven buttons, each one technically a customisation of the last.","Every component declares its variants, sizes and states in one table. Anything not in the table cannot be expressed, and `class` is merged through a conflict-aware resolver so intentional overrides still win predictably.","It moves the decision about whether a new style should exist from the moment of maximum deadline pressure to a review where someone can ask whether four products need it.","Genuinely one-off needs now require a system pull request. We budgeted a two-day turnaround on variant requests specifically so this does not become the reason teams route around the system.",{"title":164,"problem":165,"decision":166,"rationale":167,"tradeoff":168},"Codemods for the mechanical 70%, pairing for the rest","Migration is where design systems die. A backlog of 2,800 replacements assigned to teams with their own roadmaps will not be finished, and a half-migrated estate is worse than an unmigrated one.","Ship codemods with the system for the mechanical transformations — raw values to token references, spacing literals to scale steps — and schedule one paired week per product team for the remainder.","The mechanical part is most of the volume and none of the judgement. The remaining 30% needs a decision per case, and a person from the system team sitting with the product team makes those decisions in minutes.","Four paired weeks is a real cost, and it is the line item most likely to be cut. We put it in the initial scope rather than the follow-up precisely because a follow-up budget does not survive a reprioritisation.",{"title":170,"problem":171,"decision":172,"rationale":173,"tradeoff":174},"Adoption reported in CI, not in a survey","\"Are people using it?\" is the question that decides whether the system gets a second year of investment, and it is usually answered with anecdote.","Every pull request reports the share of rendered UI coming from system components, and the figure goes on a dashboard the engineering leads already look at.","It makes drift visible on the day it happens rather than at the next audit, and it gives the system team an argument that does not depend on anyone's goodwill.","Any measure that becomes a target gets gamed. A team can raise the number by wrapping a bespoke component in a system container, so the figure is reported as a trend and never used in performance review.",{"title":176,"problem":177,"decision":178,"rationale":179,"tradeoff":180},"Documentation written before the component","In the first draft of this plan the docs site was the last milestone. For six weeks the only reference would have been Figma, which means engineers asking designers questions a page would have answered.","The documentation page for a component is written and reviewed before the component is built, and the page is what gets reviewed.","An API you cannot explain in three paragraphs is usually wrong. Writing first surfaced four components whose props only made sense to the person who designed them.","Some rework, because a few APIs changed after the docs were written. Less than we expected, and cheaper than the alternative.","A concept study in design-system consolidation — replacing eleven button implementations and 2,847 ad-hoc colour values with a three-layer token architecture and a 48-component library.",null,"md",[185,189,193,197,201,205],{"title":186,"detail":187,"icon":188},"Three-layer token architecture","Primitives, semantic roles and component tokens, generated from one source into CSS custom properties, TypeScript constants and Figma variables.","lucide:layers",{"title":190,"detail":191,"icon":192},"48-component library","Each component declares its variants, sizes, states and keyboard contract in a single table that also generates its documentation.","lucide:blocks",{"title":194,"detail":195,"icon":196},"Migration codemods","Shipped with the system rather than after it, covering the mechanical transformations that make up roughly 70% of the replacement work.","lucide:git-branch",{"title":198,"detail":199,"icon":200},"Adoption reporting in CI","Every pull request reports the share of rendered UI coming from system components, so drift is visible the day it appears.","lucide:trending-up",{"title":202,"detail":203,"icon":204},"Generated Figma variables","The design library is built from the same token source as the code, so the inspector emits role names instead of raw hexes.","simple-icons:figma",{"title":206,"detail":207,"icon":208},"Documentation site with live specimens","Components render as themselves on the page, so the docs cannot drift from the implementation the way a screenshot can.","lucide:book-open",[210,227,239],{"title":211,"note":212,"before":213,"after":223},"Using a component on a new screen","The nine-step version is not a process anyone designed. It is what happens when discovery is unsupported, and it is the flow the system has to beat on cost rather than on virtue.",[214,215,216,217,218,219,220,221,222],"Read spec","Grep local repo","Grep three other repos","Ask in Slack","Wait for reply","Open Figma to read values","Copy raw hex and spacing","Write a local variant","Fix review comments",[224,225,226],"Search one index","Import component","Pass props from the variant table",{"title":228,"note":229,"before":230,"after":236},"Changing the brand colour","The before path is not hypothetical drudgery — it is the reason rebrands get deferred for years in estates like this one.",[231,232,233,234,235],"Find every hex across four repos","Judge which are the brand colour","Replace by hand","Miss the ones inside SVGs","Regression-test four products",[237,238],"Edit the semantic layer","Rebuild",{"title":240,"note":241,"before":242,"after":245},"Adding a variant that does not exist yet","Deliberately not frictionless. The point is that the friction now produces a shared component instead of a private one.",[243,244],"Override with a class","Ship",[246,247,248],"Open a system pull request","Add the variant to the table","Release, then consume",[250,257,262,267,274,279],{"title":251,"caption":252,"src":148,"width":253,"alt":254,"frame":255,"span":256},"Token architecture","The three layers as one page, showing which layer a value lives in and which layers may reference it. The reference rule is the loudest element because it is the argument the page exists to settle.",1440,"Northwind design system token architecture, three layers side by side","browser","full",{"title":258,"caption":259,"src":260,"width":253,"alt":261,"frame":255},"Component index","Search with alias matching — a team looking for \"dropdown\" finds Select. Solving discovery is what changes the build-versus-find arithmetic.","\u002Fcase-studies\u002Fnorthwind\u002Fscreens\u002Fcomponent-index.webp","Searchable component index with adoption meters on every card",{"title":263,"caption":264,"src":265,"width":253,"alt":266,"frame":255},"Variant table","Every appearance, size and state of Button rendered live. If a combination is not on this page, it cannot be expressed in a product.","\u002Fcase-studies\u002Fnorthwind\u002Fscreens\u002Fvariant-table.webp","Button variant matrix showing five appearances across three sizes",{"title":268,"caption":269,"src":270,"width":271,"alt":272,"frame":273},"Adoption in CI","Per-product adoption against the previous attempt, updated on every pull request — and the note that it is reported as a trend, never used in performance review.","\u002Fcase-studies\u002Fnorthwind\u002Fcomponents\u002Fmigration-dashboard--chart.webp",702,"Adoption trend chart comparing this migration against the previous attempt","plain",{"title":275,"caption":276,"src":277,"width":253,"alt":278,"frame":255,"span":256},"Migration dashboard","The trend line is the artifact that keeps the system funded past its first quarter, with the remaining call sites named per product.","\u002Fcase-studies\u002Fnorthwind\u002Fscreens\u002Fmigration-dashboard.webp","Migration dashboard with per-product adoption and open pull requests",{"title":280,"caption":281,"src":282,"width":283,"alt":284,"frame":285},"Documentation, on a phone","Written before the component was built. A reference that only works at 1440 is the kind of thing a design system team ships without noticing.","\u002Fcase-studies\u002Fnorthwind\u002Fmobile\u002Fdocs.webp",390,"Button documentation page on mobile with a live specimen","mobile",[287,300,313,326],{"label":288,"detail":289,"children":290},"Layer one — primitives","Raw palette ramps, type scale, spacing units. No product meaning, changes almost never.",[291,294,297],{"label":292,"detail":293},"Colour ramps","11 steps per hue, generated, never referenced by a component",{"label":295,"detail":296},"Type scale","Nine steps with paired line-height and tracking",{"label":298,"detail":299},"Space & radius","A single 4px base unit and a six-step radius ramp",{"label":301,"detail":302,"children":303},"Layer two — semantic roles","The only layer a product reads. Flips wholesale between themes and brands.",[304,307,310],{"label":305,"detail":306},"Surface roles","background, surface, surface-raised, overlay",{"label":308,"detail":309},"Content roles","foreground, secondary, muted, inverse",{"label":311,"detail":312},"Intent roles","primary, danger, warning, success — each with a paired foreground",{"label":314,"detail":315,"children":316},"Layer three — components","48 components, each with a declared variant table and accessibility contract.",[317,320,323],{"label":318,"detail":319},"Primitives","Button, Input, Select, Checkbox, Badge, Avatar",{"label":321,"detail":322},"Composites","Table, Dialog, Drawer, Combobox, DatePicker",{"label":324,"detail":325},"Patterns","Page shell, empty state, form layout, data grid",{"label":327,"detail":328,"children":329},"Distribution","One published artifact consumed identically by design tooling and every front-end.",[330,333,336],{"label":331,"detail":332},"Figma library","Variables generated from the same token source as the code",{"label":334,"detail":335},"npm package","Versioned, with codemods shipped alongside breaking changes",{"label":337,"detail":338},"Documentation site","Live specimens, props tables, and the do\u002Fdo-not for each component","SaaS","concept",{},1,[344,348,352,356,360,364],{"value":345,"label":346,"description":347},"11 → 1","Button implementations","Eleven divergent buttons across four codebases, expressed as one component whose variant table is its contract.",{"value":349,"label":350,"description":351},"214","Tokens across three layers","Primitives, semantic roles and component tokens — replacing the 2,847 unrelated raw values the scenario audit assumes.",{"value":353,"label":354,"description":355},"48","Components specified","Each with its variants, states, keyboard behaviour and accessibility contract declared in a single table.",{"value":357,"label":358,"description":359},"1","Layer a rebrand touches","Products consume semantic roles only. Changing the brand is an edit to layer two, not a search across four repositories.",{"value":361,"label":362,"description":363},"3","Steps to use a system component","Down from nine in the modelled current-state flow — see the flow comparison below.",{"value":365,"label":366,"description":367},"4 → 1","Sources of truth","One published library, consumed identically by design tooling and every front-end.","\u002Fwork\u002Fnorthwind-design-system",[370,371,337],"Web application","Design tooling",[373,376,379,382,385,388],{"title":374,"detail":375},"Products consume roles, never raw values","A component asks for `surface` or `border-subtle`, never `#18181B`. This is the constraint that makes a rebrand a one-layer edit, and it is worth the indirection it costs a reader.",{"title":377,"detail":378},"If a variant is not in the table, it does not exist","Each component declares its full variant, size and state matrix in one place. Consumers cannot invent a thirteenth style with a class override, which is what stopped the drift the library alone would not have.",{"title":380,"detail":381},"Migration is the deliverable","A system that does not replace the old code is a thirteenth way to build a button. Codemods, a tracked backlog and paired migration weeks are in scope from week one, not scheduled afterwards.",{"title":383,"detail":384},"Documentation ships before the component","Written first, it forces the API to be explainable. Written last, it documents whatever got built.",{"title":386,"detail":387},"Adoption is measured, not assumed","CI reports the share of rendered UI coming from system components on every pull request. Without a number, \"adoption\" is a feeling that leadership correctly discounts.",{"title":389,"detail":390},"The system serves the products, not the reverse","A component that only exists because the system wanted symmetry is overhead. Every entry earns its place by replacing something real.","Design system & component library",{"summary":393,"premises":394,"personas":413,"journey":440},"We started from an audit rather than a workshop, because the argument for a design system is usually lost in the abstract and won on a spreadsheet. The figures below are the scenario's premises — we chose them to sit at the plausible end of what a four-product estate looks like after three acquisitions.",[395,398,401,404,407,410],{"label":396,"detail":397},"2,847 unique colour values","Roughly 60% within one perceptual step of another value already in use. Different hexes nobody can tell apart, each one a decision someone made under deadline.",{"label":399,"detail":400},"31 spacing scales","Not 31 values — 31 distinct scales, several of which disagree about whether the base unit is 4px or 5px.",{"label":402,"detail":403},"Eleven button implementations","Across four repositories, with divergent hover states, focus treatments and disabled semantics. Three of them are inaccessible by keyboard.",{"label":405,"detail":406},"The complaint is discoverability, not aesthetics","Engineers in this scenario do not say the UI looks inconsistent. They say they cannot find the component they need, so they write one.",{"label":408,"detail":409},"Design and engineering disagree on what \"done\" means","A designer considers a component done when the Figma variant set is complete. An engineer considers it done when it is merged and typed. Neither is wrong; the gap is where drift enters.",{"label":411,"detail":412},"There is no budget for a freeze","All four products keep shipping throughout. Any migration plan that requires a feature freeze is not a plan.",[414,427],{"name":415,"role":416,"context":417,"goals":418,"frustrations":422,"quote":426},"Dana Okonjo","Staff Frontend Engineer, Billing","Ships two or three features a sprint against a codebase she inherited from an acquired team. She is the person who would adopt the system, and the person who will route around it if it slows her down.",[419,420,421],"Ship a feature without a three-day detour into component archaeology","Stop getting design-review comments about spacing she did not choose","Delete code rather than add it",[423,424,425],"Four repositories to search, none with a shared naming convention","Components that exist but are undocumented, so their variants are unknown","Being told to \"use the design system\" when the system has no billing table","I am not writing another button because I want to. I am writing one because I have twenty minutes and I already spent fifteen looking.",{"name":428,"role":429,"context":430,"goals":431,"frustrations":435,"quote":439},"Ilse Brandt","Product Designer, Platform","Maintains the Figma library that three other designers draw from, and spends more of her week answering implementation questions than designing. She is the system's author and its bottleneck.",[432,433,434],"Change a token once and see it land in all four products","Spend review time on interaction, not on radius values","Have a documented answer she can link to instead of retyping",[436,437,438],"Every question a docs site would answer arrives as a direct message","Her library and the shipped code drift apart within a sprint","No way to see which components are actually being used","I have published the same explanation of our focus states eleven times. I have counted.",[441,445,451,456,461,466],{"stage":442,"doing":443,"feeling":444},"Ticket picked up","Reads the spec, opens the Figma frame, identifies six UI elements needed.","neutral",{"stage":446,"doing":447,"feeling":448,"friction":449,"opportunity":450},"Search for components","Greps the local repo, then the other three, then asks in Slack.","negative","No shared naming. A \"Select\" in one repo is a \"Dropdown\" in another.","One searchable index, with the same names in Figma and in code.",{"stage":452,"doing":453,"feeling":448,"friction":454,"opportunity":455},"Decision point","Weighs adapting a found component against writing a fresh one.","Adapting means understanding someone else's variant logic. Writing is 20 minutes.","Make the found component obviously correct and obviously cheaper.",{"stage":457,"doing":458,"feeling":444,"friction":459,"opportunity":460},"Build","Writes variant twelve, with hardcoded values copied from the Figma inspector.","The inspector gives raw hexes, so the new component enters the world untokenised.","Publish tokens to Figma so the inspector emits role names.",{"stage":462,"doing":463,"feeling":448,"friction":464,"opportunity":465},"Design review","Receives comments on radius, hover colour and focus ring.","Rework on details that a system would have decided before she started.","Move these decisions out of review and into the component.",{"stage":467,"doing":468,"feeling":444,"opportunity":469},"Merged","Ships the feature. The estate now has twelve buttons.","Track component provenance in CI so the drift is visible as it happens.",{"title":31,"description":181},[472,473,474],"Design Systems","Product Design","Frontend Engineering",[476,477,478,479,480],"Figma Variables","Vue 3","TypeScript","Tailwind CSS","Storybook","work\u002F1.northwind-design-system",{"summary":483,"radius":484,"density":485,"palette":486,"type":505,"tokens":530,"components":555,"specimens":577},"Three token layers, 48 components and one distribution artifact. The specimens below are rendered live from this project's own token values rather than exported as images — a screenshot proves someone drew a button, a rendered specimen proves the button is generated by a system with parameters.",6,"default",[487,491,494,497,501],{"name":488,"value":489,"role":490},"Ink","#0B0C0E","Primary surface in the dark theme",{"name":492,"value":32,"role":493},"Signal","Primary action, dark theme only",{"name":495,"value":33,"role":496},"Signal (light)","The same role restepped — the bright cyan fails contrast on white",{"name":498,"value":499,"role":500},"Slate","#71717A","Secondary text and the reference series in charts",{"name":502,"value":503,"role":504},"Amber","#F59E0B","Warning state, paired with an icon and never used alone",[506,512,517,522,527],{"name":507,"size":508,"weight":509,"tracking":510,"usage":511},"Display","2.5rem",600,"-0.03em","Page titles and empty-state headings",{"name":513,"size":514,"weight":509,"tracking":515,"usage":516},"Title","1.5rem","-0.02em","Section and dialog headings",{"name":518,"size":519,"weight":520,"usage":521},"Body","0.9375rem",400,"Default running text and table cells",{"name":523,"size":524,"weight":525,"usage":526},"Label","0.8125rem",500,"Form labels, buttons and dense table headers",{"name":528,"size":524,"weight":520,"usage":529},"Mono","Identifiers, token names and code",[531,535,539,543,547,551],{"name":532,"value":533,"usage":534},"--space-unit","4px","Every spacing step is a multiple. No exceptions, no half-steps.",{"name":536,"value":537,"usage":538},"--radius-control","6px","Buttons, inputs and selects. Containers use 10px.",{"name":540,"value":541,"usage":542},"--control-height","36px","The single height every interactive control aligns to.",{"name":544,"value":545,"usage":546},"--border-hairline","1px","All dividers and container edges at every density.",{"name":548,"value":549,"usage":550},"--duration-quick","180ms","State transitions. Anything longer feels broken on a dense screen.",{"name":552,"value":553,"usage":554},"--focus-ring","2px solid","Offset by 2px, identical on every focusable element.",[556,559,563,566,570,573],{"name":68,"variants":557,"detail":558},21,"Seven appearances × three sizes, plus loading, disabled and icon-only states.",{"name":560,"variants":561,"detail":562},"Input",12,"Three sizes × four validation states, each with a described error region.",{"name":564,"variants":561,"detail":565},"Select","Native and combobox modes, with full keyboard navigation.",{"name":567,"variants":568,"detail":569},"Table",8,"Three densities, sortable and selectable columns, virtualised body.",{"name":571,"variants":484,"detail":572},"Dialog","Focus trap, scroll lock and focus restore, in three widths.",{"name":574,"variants":575,"detail":576},"Badge",16,"Eight tones × two sizes. Status tones always carry an icon.",[578,579,580,581],"buttons","fields","status","nav","14-week scope","2026","9-m8Fo28vDEo5TPEhgGGnNAdAJLNpHjrgLXuK9bWkUU",[586,587,593,599,604,610],{"path":368,"client":147,"title":31,"excerpt":182,"accent":32,"industry":339},{"path":588,"client":589,"title":590,"excerpt":182,"accent":591,"industry":592},"\u002Fwork\u002Fmeridian-clinical-ai","Meridian Health","Designing an AI that clinicians are allowed to disagree with","#22C55E","Healthcare",{"path":594,"client":595,"title":596,"excerpt":182,"accent":597,"industry":598},"\u002Fwork\u002Fledgerly-onboarding","Ledgerly","Rebuilding onboarding around the first useful moment","#7C3AED","Fintech",{"path":600,"client":601,"title":602,"excerpt":182,"accent":503,"industry":603},"\u002Fwork\u002Ffleetwise-dashboard","Fleetwise","A fleet dashboard people stop exporting to spreadsheets","Logistics",{"path":605,"client":606,"title":607,"excerpt":182,"accent":608,"industry":609},"\u002Fwork\u002Fverdigris-marketplace","Verdigris","An e-commerce system where every product is one of one","#E07A5F","E-commerce",{"path":611,"client":612,"title":613,"excerpt":182,"accent":614,"industry":615},"\u002Fwork\u002Fhalyard-progressive-delivery","Halyard","A progressive delivery console that can answer \"who is seeing this?\"","#818CF8","Developer Tools",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":617},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Ccircle cx=\"12\" cy=\"12\" r=\"10\"\u002F>\u003Cpath d=\"M12 6v6l4 2\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":619},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M14 2v6a2 2 0 0 0 .245.96l5.51 10.08A2 2 0 0 1 18 22H6a2 2 0 0 1-1.755-2.96l5.51-10.08A2 2 0 0 0 10 8V2M6.453 15h11.094M8.5 2h7\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":621},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Ccircle cx=\"12\" cy=\"12\" r=\"10\"\u002F>\u003Ccircle cx=\"12\" cy=\"12\" r=\"6\"\u002F>\u003Ccircle cx=\"12\" cy=\"12\" r=\"2\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":623},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 12h14\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":625},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M15.707 21.293a1 1 0 0 1-1.414 0l-1.586-1.586a1 1 0 0 1 0-1.414l5.586-5.586a1 1 0 0 1 1.414 0l1.586 1.586a1 1 0 0 1 0 1.414z\"\u002F>\u003Cpath d=\"m18 13l-1.375-6.874a1 1 0 0 0-.746-.776L3.235 2.028a1 1 0 0 0-1.207 1.207L5.35 15.879a1 1 0 0 0 .776.746L13 18M2.3 2.3l7.286 7.286\"\u002F>\u003Ccircle cx=\"11\" cy=\"11\" r=\"2\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":627},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15 14c.2-1 .7-1.7 1.5-2.5c1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5c.7.7 1.3 1.5 1.5 2.5m0 4h6m-5 4h4\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":629},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Ccircle cx=\"18\" cy=\"18\" r=\"3\"\u002F>\u003Ccircle cx=\"6\" cy=\"6\" r=\"3\"\u002F>\u003Cpath d=\"M13 6h3a2 2 0 0 1 2 2v7m-7 3H8a2 2 0 0 1-2-2V9\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":631},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M12 22a1 1 0 0 1 0-20a10 9 0 0 1 10 9a5 5 0 0 1-5 5h-2.25a1.75 1.75 0 0 0-1.4 2.8l.3.4a1.75 1.75 0 0 1-1.4 2.8z\"\u002F>\u003Ccircle cx=\"13.5\" cy=\"6.5\" r=\".5\" fill=\"currentColor\"\u002F>\u003Ccircle cx=\"17.5\" cy=\"10.5\" r=\".5\" fill=\"currentColor\"\u002F>\u003Ccircle cx=\"6.5\" cy=\"12.5\" r=\".5\" fill=\"currentColor\"\u002F>\u003Ccircle cx=\"8.5\" cy=\"7.5\" r=\".5\" fill=\"currentColor\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":633},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 4v16M4 7V5a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v2M9 20h6\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":635},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 21s-4-3-4-9s4-9 4-9m8 0s4 3 4 9s-4 9-4 9M15 9l-6 6m0-6l6 6\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":637},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15.536 11.293a1 1 0 0 0 0 1.414l2.376 2.377a1 1 0 0 0 1.414 0l2.377-2.377a1 1 0 0 0 0-1.414l-2.377-2.377a1 1 0 0 0-1.414 0zm-13.239 0a1 1 0 0 0 0 1.414l2.377 2.377a1 1 0 0 0 1.414 0l2.377-2.377a1 1 0 0 0 0-1.414L6.088 8.916a1 1 0 0 0-1.414 0zm6.619 6.619a1 1 0 0 0 0 1.415l2.377 2.376a1 1 0 0 0 1.414 0l2.377-2.376a1 1 0 0 0 0-1.415l-2.377-2.376a1 1 0 0 0-1.414 0zm0-13.238a1 1 0 0 0 0 1.414l2.377 2.376a1 1 0 0 0 1.414 0l2.377-2.376a1 1 0 0 0 0-1.414l-2.377-2.377a1 1 0 0 0-1.414 0z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":639},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 12h14m-7-7v14\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":641},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Ccircle cx=\"12\" cy=\"12\" r=\"10\"\u002F>\u003Cpath d=\"M12 8v4m0 4h.01\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":643},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M20 6L9 17l-5-5\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":645},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Ccircle cx=\"12\" cy=\"12\" r=\"10\"\u002F>\u003Cpath d=\"m9 12l2 2l4-4\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":647},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"m21.73 18l-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3M12 9v4m0 4h.01\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":649},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M10.1 2.182a10 10 0 0 1 3.8 0m0 19.636a10 10 0 0 1-3.8 0m7.509-18.097a10 10 0 0 1 2.69 2.7M2.182 13.9a10 10 0 0 1 0-3.8m18.097 7.509a10 10 0 0 1-2.7 2.69M21.818 10.1a10 10 0 0 1 0 3.8M3.721 6.391a10 10 0 0 1 2.7-2.69m-.03 16.578a10 10 0 0 1-2.69-2.7\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":651},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"m12 14l4-4M3.34 19a10 10 0 1 1 17.32 0\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":653},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09\"\u002F>\u003Cpath d=\"M9 12a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.4 22.4 0 0 1-4 2z\"\u002F>\u003Cpath d=\"M9 12H4s.55-3.03 2-4c1.62-1.08 5 .05 5 .05\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":655},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2M16 3.128a4 4 0 0 1 0 7.744M22 21v-2a4 4 0 0 0-3-3.87\"\u002F>\u003Ccircle cx=\"9\" cy=\"7\" r=\"4\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":657},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M10 5H3m9 14H3M14 3v4m2 10v4m5-9h-9m9 7h-5m5-14h-7m-6 5v4m0-2H3\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":659},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"m9 18l6-6l-6-6\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":661},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83z\"\u002F>\u003Cpath d=\"M2 12a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 12\"\u002F>\u003Cpath d=\"M2 17a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 17\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":663},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M10 22V7a1 1 0 0 0-1-1H4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-5a1 1 0 0 0-1-1H2\"\u002F>\u003Crect width=\"8\" height=\"8\" x=\"14\" y=\"2\" rx=\"1\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":665},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M15 6a9 9 0 0 0-9 9V3\"\u002F>\u003Ccircle cx=\"18\" cy=\"6\" r=\"3\"\u002F>\u003Ccircle cx=\"6\" cy=\"18\" r=\"3\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":667},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M16 7h6v6\"\u002F>\u003Cpath d=\"m22 7l-8.5 8.5l-5-5L2 17\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":669},"\u003Cpath fill=\"currentColor\" d=\"M15.852 8.981h-4.588V0h4.588c2.476 0 4.49 2.014 4.49 4.49s-2.014 4.491-4.49 4.491M12.735 7.51h3.117c1.665 0 3.019-1.355 3.019-3.019s-1.355-3.019-3.019-3.019h-3.117zm0 1.471H8.148c-2.476 0-4.49-2.014-4.49-4.49S5.672 0 8.148 0h4.588v8.981zm-4.587-7.51c-1.665 0-3.019 1.355-3.019 3.019s1.354 3.02 3.019 3.02h3.117V1.471zm4.587 15.019H8.148c-2.476 0-4.49-2.014-4.49-4.49s2.014-4.49 4.49-4.49h4.588v8.98zM8.148 8.981c-1.665 0-3.019 1.355-3.019 3.019s1.355 3.019 3.019 3.019h3.117V8.981zM8.172 24c-2.489 0-4.515-2.014-4.515-4.49s2.014-4.49 4.49-4.49h4.588v4.441c0 2.503-2.047 4.539-4.563 4.539m-.024-7.51a3.023 3.023 0 0 0-3.019 3.019c0 1.665 1.365 3.019 3.044 3.019c1.705 0 3.093-1.376 3.093-3.068v-2.97zm7.704 0h-.098c-2.476 0-4.49-2.014-4.49-4.49s2.014-4.49 4.49-4.49h.098c2.476 0 4.49 2.014 4.49 4.49s-2.014 4.49-4.49 4.49m-.097-7.509c-1.665 0-3.019 1.355-3.019 3.019s1.355 3.019 3.019 3.019h.098c1.665 0 3.019-1.355 3.019-3.019s-1.355-3.019-3.019-3.019z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":671},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 5v16m8.001-2A2 2 0 0 0 22 17V5a2 2 0 0 0-1.999-2L16 3.002A5 5 0 0 0 12 5a5 5 0 0 0-4-2H4a2 2 0 0 0-2 2v12a2 2 0 0 0 1.999 2H8a5 5 0 0 1 4 2a5 5 0 0 1 4-2z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":673},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Ccircle cx=\"12\" cy=\"12\" r=\"10\"\u002F>\u003Cpath d=\"m15 9l-6 6m0-6l6 6\"\u002F>\u003C\u002Fg>",1787597896996]