[{"data":1,"prerenderedAt":651},["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\u002Ffleetwise-dashboard":29,"work-order":565,"i-lucide:clock":597,"i-lucide:flask-conical":599,"i-lucide:target":601,"i-lucide:check":603,"i-lucide:minus":605,"i-lucide:pen-tool":607,"i-lucide:lightbulb":609,"i-lucide:palette":611,"i-lucide:type":613,"i-lucide:variable":615,"i-lucide:blocks":617,"i-lucide:component":619,"i-lucide:circle-check":621,"i-lucide:triangle-alert":623,"i-lucide:circle-x":625,"i-lucide:circle-dashed":627,"i-lucide:gauge":629,"i-lucide:rocket":631,"i-lucide:users":633,"i-lucide:sliders-horizontal":635,"i-lucide:chevron-right":637,"i-lucide:filter":639,"i-lucide:bookmark":641,"i-lucide:git-compare":643,"i-lucide:table-2":645,"i-lucide:layers":647,"i-lucide:activity":649},{"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":114,"client":132,"cover":133,"coverAlt":134,"decisions":135,"description":166,"excerpt":167,"extension":168,"featured":6,"features":169,"flows":194,"gallery":240,"ia":270,"industry":320,"kind":321,"meta":322,"navigation":24,"order":323,"outcomes":324,"path":349,"platform":350,"principles":353,"projectType":372,"research":373,"seo":452,"services":453,"stack":457,"stem":463,"system":464,"timeline":562,"year":563,"__hash__":564},"work\u002Fwork\u002F4.fleetwise-dashboard.md","A fleet dashboard people stop exporting to spreadsheets","#F59E0B","#B45309",{"type":35,"value":36,"toc":105},"minimark",[37,42,46,49,52,56,59,62,65,68,71,75,78,81,89,92,96,99,102],[38,39,41],"h2",{"id":40},"read-the-most-used-control","Read the most-used control",[43,44,45],"p",{},"The diagnosis in this scenario takes one number: the most-used control on the\ndashboard is Export to CSV.",[43,47,48],{},"That single fact reframes the project. It means the product is not a dashboard\nthat needs improving — it is a query interface people cannot use, wrapped around\na data export they can. Every feature downstream of that click is unreachable\nby definition, and any redesign that makes the dashboard prettier improves the\npart nobody stays on.",[43,50,51],{},"It also names the competitor. Fleetwise is not losing to another vendor. It is\nlosing to Excel, and Excel is winning on three specific properties: you can\ncompose arbitrary conditions, the file persists, and it responds instantly.\nThose three are the brief. None of them is a visual design problem.",[38,53,55],{"id":54},"composability-has-a-floor-and-the-floor-is-latency","Composability has a floor, and the floor is latency",[43,57,58],{},"The condition builder is the centrepiece, and it only works if the table is\nfast.",[43,60,61],{},"This is the part that makes it an engineering project as much as a design one.\nA composable query encourages exploration — add a condition, look, remove it,\ntry another. That loop is the entire value. At a hundred milliseconds it is a\nloop; at three seconds it is a series of decisions, and an operator who has to\ndecide before each query will plan carefully and try two things instead of\ntwenty.",[43,63,64],{},"So the interaction budget is a design requirement expressed in milliseconds, and\nit forces an architectural choice: load the working set once and filter on the\nclient. That decision buys the exploration loop and costs a heavier initial\nload, a large client-side working set, and data that can be stale between\nrefreshes.",[43,66,67],{},"The staleness is why freshness is displayed per view rather than as one global\ntimestamp. Having chosen an architecture that permits stale data, hiding that\nfact would be indefensible.",[43,69,70],{},"It is also worth saying where this stops working. At 400,000 rows the client\ncannot hold the working set and the whole model has to change — server-side\nquery with an optimistic client cache, or a fundamentally different interaction\nthat does not assume instant feedback. This design does not stretch to that; it\nwould need to be replaced.",[38,72,74],{"id":73},"views-are-the-real-unit","Views are the real unit",[43,76,77],{},"The condition builder gets the attention, but saved views are probably the\nlarger win.",[43,79,80],{},"The strongest signal in the scenario is that each operator has four or five\nquestions they ask every single morning and rebuild by hand every single time.\nThat is work the product watches happen daily and refuses to remember.",[43,82,83,84,88],{},"The important decision is what a view contains. A saved ",[85,86,87],"em",{},"filter"," restores the\nquery and loses the columns, the sort and the density — about a third of the\nwork, which is more irritating than restoring nothing, because the user has to\nnotice what is missing and then fix it. A view therefore carries the entire\nstate, and is addressable by URL, which as a side effect turns an escalation\nfrom a screenshot plus a paragraph of reconstruction instructions into a link.",[43,90,91],{},"The hidden cost is versioning. Views reference columns, and columns change. Every\nview needs to degrade gracefully and offer a repair rather than breaking, which\nis a substantial piece of engineering that shows up as no visible feature at\nall. It is the sort of thing that gets cut in week nine and regretted in month\nfour.",[38,93,95],{"id":94},"leaving-the-escape-hatch-open","Leaving the escape hatch open",[43,97,98],{},"Export stays exactly where it is.",[43,100,101],{},"There is an argument for removing it — force the habit change, make the new\ntools the only path. It would improve adoption on paper. It is also punishing\nusers for a shortcoming that was the product's, and some downstream uses of an\nexport are perfectly legitimate.",[43,103,104],{},"The better reason to keep it is diagnostic. If export remains the first click\nafter the redesign, then the composable query did not work, and that is worth\nknowing plainly rather than obscuring by closing the alternative. A metric you\nhave removed the option to fail is not a metric.",{"title":106,"searchDepth":107,"depth":107,"links":108},"",3,[109,111,112,113],{"id":40,"depth":110,"text":41},2,{"id":54,"depth":110,"text":55},{"id":73,"depth":110,"text":74},{"id":94,"depth":110,"text":95},{"summary":115,"points":116},"Fleetwise is a scenario about a product that works exactly as specified and is still losing to Excel. The dashboard can display 40,000 active shipments. It simply cannot do the three things an operator does with them, so the operator exports and does the real work elsewhere. The design problem is not the visual design of the dashboard; it is that the interaction model stops at \"display\".",[117,120,123,126,129],{"label":118,"detail":119},"The product had become a download button","The most-used control on the page is Export to CSV. Operators load the dashboard, immediately export, and work in a spreadsheet. Every feature built downstream of that click is unused by definition.",{"label":121,"detail":122},"One filter at a time, against multi-condition questions","Real operational questions are compound — late shipments from one hub, excluding two carriers already known to be in a weather delay. A single-select filter bar cannot express the question, so it cannot be asked.",{"label":124,"detail":125},"The dashboard forgets everything on refresh","Each operator has four or five recurring questions they ask daily and rebuild by hand every morning. The product has no memory of work that repeats every single day.",{"label":127,"detail":128},"Comparison is impossible","Operators need two filtered sets beside each other. The product shows one, which is why the second spreadsheet window exists.",{"label":130,"detail":131},"Latency sets a floor under everything","Sorting takes seconds and filtering re-fetches from the server. At that cost exploration stops — nobody experiments with a query that makes them wait, so the interaction model is constrained by the data layer before any design decision is made.","Fleetwise","\u002Fcase-studies\u002Ffleetwise\u002Fscreens\u002Fcomposable-query.webp","Fleetwise composable query above a virtualised shipment table",[136,142,148,154,160],{"title":137,"problem":138,"decision":139,"rationale":140,"tradeoff":141},"A composable condition builder instead of curated filter presets","Presets are easier to design, easier to explain and cover the common cases. They also decide in advance which questions may be asked, and the questions that matter on an operations floor are the unusual ones.","A stackable field\u002Foperator\u002Fvalue builder with one level of and\u002For grouping, rendered along the top of the table so it reads as a sentence. Each condition is removable independently.","It makes the expressible set match the answerable set. The sentence rendering is what keeps it usable — a query builder that looks like a query builder gets used by three people, one that reads as a line of English gets used by everyone.","Higher floor than presets. A new operator faces an empty builder rather than a menu of good starting points, and one level of grouping still cannot express genuinely nested logic. Shared views are the mitigation for the first problem; the second is a deliberate cap, because two levels of nesting is where these interfaces become unreadable.",{"title":143,"problem":144,"decision":145,"rationale":146,"tradeoff":147},"Saved views carry everything, not just the filter","A saved filter that restores the query but not the columns, sort or density restores about a third of the work, which is somehow more annoying than restoring none of it.","A view is the full state — query, column set, order, sort, density and live\u002Fpaused — addressable by URL and shareable.","It matches the unit operators actually think in. Nobody wants \"the late shipments filter\"; they want \"my morning view\", and the difference between those two is everything except the filter.","Views drift as the schema changes. A view referencing a removed column has to degrade rather than break, which means every view carries versioning and a repair path — a meaningful chunk of the build that produces no visible feature.",{"title":149,"problem":150,"decision":151,"rationale":152,"tradeoff":153},"Client-side filtering over a virtualised 40,000-row body","Server-side filtering means a round-trip per interaction. At a hundred milliseconds or more, operators plan queries instead of exploring, and the composable builder loses most of its value.","Load the working set once, filter and sort on the client against a virtualised table body, and reconcile with the server on an explicit refresh.","It puts the interaction under the exploration threshold, which is what makes the query builder worth having. Below that threshold operators try things; above it they do not.","A real architectural cost. The client now holds a large working set, the initial load is heavier, and the data can be stale between refreshes — which is precisely why staleness is displayed per view rather than assumed. This decision would not survive a jump to 400,000 rows, and the design would need to change rather than stretch.",{"title":155,"problem":156,"decision":157,"rationale":158,"tradeoff":159},"Live updates are opt-in, per view","A real-time dashboard sounds obviously correct and is hostile during triage. Rows moving under the pointer while an operator works a list is the fastest way to lose their place and their trust.","Views are paused by default during interaction. New data is announced as a count — \"14 new since 09:12\" — and applied when the operator asks.","It separates knowing that something changed from having the ground move. The operator keeps control of when their working set is disturbed, and still knows immediately that it is out of date.","Someone will look at a stale view and believe it is current. The age indicator on every view is the mitigation, and it is not a complete one — this is a genuine safety trade made in favour of not disrupting active work.",{"title":161,"problem":162,"decision":163,"rationale":164,"tradeoff":165},"Keep Export to CSV, and stop measuring it as a feature","Export is the symptom, and removing it to force adoption punishes the user for the product's shortcomings. Some downstream uses are also entirely legitimate.","Export stays, unchanged and easy to find, and is treated as a diagnostic signal rather than a feature to promote.","Its position in the interaction order is the honest measure of whether the redesign worked. If it remains the first click, the composable query has failed, and that is worth knowing without ambiguity.","Leaving the escape hatch open means some operators never change their habit, and habit is strong after years. Closing it would produce better adoption numbers and worse information.","A concept study in dense operations tooling — replacing a 40,000-row logistics dashboard's single-select filter bar with a composable query, saved views and side-by-side comparison, so the spreadsheet stops winning.",null,"md",[170,174,178,182,186,190],{"title":171,"detail":172,"icon":173},"Composable condition builder","Stackable field\u002Foperator\u002Fvalue conditions with and\u002For grouping and first-class exclusions, rendered as a readable sentence.","lucide:filter",{"title":175,"detail":176,"icon":177},"Saved and shareable views","Query, columns, sort, density and live state as one addressable unit, with a repair path when the schema moves under them.","lucide:bookmark",{"title":179,"detail":180,"icon":181},"Side-by-side comparison","Two independent queries in one surface, each with its own column set and freshness.","lucide:git-compare",{"title":183,"detail":184,"icon":185},"Virtualised 40,000-row table","Client-side filtering and sorting under a 100ms interaction budget asserted in CI.","lucide:table-2",{"title":187,"detail":188,"icon":189},"Twelve specified table states","Including filtered-empty, partial and stale — the states that are usually left to chance and are where dense tables lose credibility.","lucide:layers",{"title":191,"detail":192,"icon":193},"Per-view freshness with opt-in live updates","Views pause during interaction and announce pending changes as a count rather than reordering rows under the pointer.","lucide:activity",[195,207,218,229],{"title":196,"note":197,"before":198,"after":204},"Asking a compound question","The before column is not a worse way of doing the same thing — the question genuinely cannot be expressed, so it gets approximated and the approximation is what gets acted on.",[199,200,201,202,203],"Apply the one filter that fits best","Export to CSV","Open the spreadsheet","Add an autofilter","Add the remaining conditions",[205,205,206],"Add condition","Add exclusion",{"title":208,"note":209,"before":210,"after":216},"Starting a shift","Rebuilt by hand every morning in the current state, for work that is identical every day.",[211,212,213,214,215],"Open dashboard","Re-apply four filters","Re-choose columns","Re-apply sort","Set density",[217],"Open the pinned view",{"title":219,"note":220,"before":221,"after":226},"Escalating something to the network lead","A view being addressable turns a paragraph of reconstruction instructions into a link.",[222,223,224,225],"Screenshot the spreadsheet","Write out which filters were used","Send both","Answer follow-up questions about the filters",[227,228],"Copy the view URL","Send it",{"title":230,"note":231,"before":232,"after":237},"Comparing two hubs","Not an advanced feature — it is how the next hour gets allocated.",[233,234,235,236],"Export hub A","Export hub B","Open two spreadsheet windows","Arrange them side by side",[238,239],"Split the view","Set the second query",[241,248,255,260,265],{"title":242,"caption":243,"src":133,"width":244,"alt":245,"frame":246,"span":247},"Composable query","Conditions stacked along the top of the table, reading as a sentence, with the exclusion as a first-class condition — \"except the ones I already know about\" is most of what expertise looks like on an operations floor.",1600,"Shipment table filtered by four stacked conditions including an exclusion","browser","full",{"title":249,"caption":250,"src":251,"width":252,"alt":253,"frame":254,"span":247},"The query bar","Field, operator, value, each removable independently. A query builder that looks like a query builder gets used by three people; one that reads as a line of English gets used by everyone.","\u002Fcase-studies\u002Ffleetwise\u002Fcomponents\u002Fcomposable-query--query.webp",1380,"Condition builder rendered as a readable sentence","plain",{"title":256,"caption":257,"src":258,"width":252,"alt":259,"frame":254},"Saved views and freshness","The unit operators actually work in. Views are paused during interaction and announce pending changes as a count, so the ground never moves under the pointer.","\u002Fcase-studies\u002Ffleetwise\u002Fcomponents\u002Fcomposable-query--views.webp","Saved view tabs with a paused freshness indicator",{"title":261,"caption":262,"src":263,"width":244,"alt":264,"frame":246},"Split comparison","Two independent queries in one surface, each with its own columns and its own freshness. This replaces the second spreadsheet window.","\u002Fcase-studies\u002Ffleetwise\u002Fscreens\u002Fsplit-comparison.webp","Two hub queries side by side with independent statistics",{"title":266,"caption":267,"src":268,"width":244,"alt":269,"frame":246,"span":247},"Table states","Filtered-empty distinguished from empty, partial from loading, stale from current. These are the states dense tables leave to chance, and where trust is lost.","\u002Fcase-studies\u002Ffleetwise\u002Fscreens\u002Ftable-states.webp","Six specified table states shown side by side",[271,284,297,310],{"label":272,"detail":273,"children":274},"Query","The composable layer that replaced the filter bar. Reads left to right as a sentence.",[275,278,281],{"label":276,"detail":277},"Condition","Field, operator, value — each removable independently",{"label":279,"detail":280},"Grouping","and\u002For nesting, one level deep, shown structurally",{"label":282,"detail":283},"Exclusions","First-class, because \"except the ones I know about\" is most of the job",{"label":285,"detail":286,"children":287},"Views","A saved query plus everything around it. The unit operators actually work in.",[288,291,294],{"label":289,"detail":290},"Personal views","The four or five daily questions, pinned",{"label":292,"detail":293},"Shared views","Addressable by URL, so an escalation is a link",{"label":295,"detail":296},"Comparison","Two independent queries side by side in one surface",{"label":298,"detail":299,"children":300},"Table","Virtualised, dense, with the states most dense tables omit.",[301,304,307],{"label":302,"detail":303},"Column set","Chosen per view, not globally",{"label":305,"detail":306},"Density","Three steps, persisted with the view",{"label":308,"detail":309},"States","Loading, empty, filtered-empty, error, partial, stale",{"label":311,"detail":312,"children":313},"Freshness","Every view states its own age and refresh behaviour.",[314,317],{"label":315,"detail":316},"Age indicator","Per view, not a single global timestamp",{"label":318,"detail":319},"Live or paused","Explicit, because live updates during triage are hostile","Logistics","concept",{},4,[325,329,333,337,341,345],{"value":326,"label":327,"description":328},"1 → n","Simultaneous filter conditions","A single-select filter bar replaced by a stackable condition builder with and\u002For grouping.",{"value":330,"label":331,"description":332},"2","Filtered sets visible at once","A split view for the comparison operators previously did by opening two spreadsheet windows.",{"value":334,"label":335,"description":336},"0","Views lost on refresh","Saved views persist the full query, column set, sort and density, and are shareable by URL.",{"value":338,"label":339,"description":340},"40,000","Rows held at interactive latency","Virtualised body with client-side filtering, so exploration does not cost a server round-trip per keystroke.",{"value":342,"label":343,"description":344},"4 → 1","Screens to answer a recurring question","The daily questions operators asked became saved views on one surface instead of four navigations.",{"value":346,"label":347,"description":348},"12","Table states specified","Loading, empty, filtered-empty, error, partial, stale and six selection states — the ones dense tables usually omit.","\u002Fwork\u002Ffleetwise-dashboard",[351,352],"Web application","Operations floor, large displays",[354,357,360,363,366,369],{"title":355,"detail":356},"The spreadsheet is the competitor","Every decision is measured against composition, persistence and speed — the three properties that make Excel win. Beating it on visual design is not a goal and would not help.",{"title":358,"detail":359},"Any question the data supports must be expressible","If an operator can describe a filter in a sentence, the interface must let them build it. Curated filter presets are a way of deciding in advance which questions are allowed.",{"title":361,"detail":362},"Exploration requires sub-100ms feedback","This is an interaction-design requirement expressed as a performance budget. Above the threshold, users plan queries instead of exploring, and no amount of interface quality recovers it.",{"title":364,"detail":365},"Everything is addressable","A view is a URL. Sharing a question should never mean describing how to reconstruct it.",{"title":367,"detail":368},"State is never silently lost","Query, columns, sort, density and scroll position survive a refresh. A product that forgets daily work is telling the user their work is not worth remembering.",{"title":370,"detail":371},"Show staleness rather than hiding it","A number with an unknown age is worse than an old number that says how old it is. Every view carries its own freshness.","Data-dense product design & front-end architecture",{"summary":374,"premises":375,"personas":394,"journey":421},"The premises are drawn from the recurring pattern in operations tooling: the spreadsheet is not winning because it is better designed, but because it is composable, persistent and fast. Those three properties are the actual competitor, and they are the brief.",[376,379,382,385,388,391],{"label":377,"detail":378},"The spreadsheet is the real competitor","Not another vendor. Any feature that does not beat Excel on composition, persistence or speed will be routed around, however well it is drawn.",{"label":380,"detail":381},"Operators ask compound questions","Two to four conditions, frequently including an exclusion. Exclusions matter disproportionately — \"except the ones I already know about\" is most of what expertise looks like on an operations floor.",{"label":383,"detail":384},"The same four or five questions recur daily","Per operator, stable over months. This is the strongest signal in the scenario: work that repeats daily and is rebuilt by hand every time.",{"label":386,"detail":387},"Comparison is a first-class task","Not an advanced feature. Two sets side by side is how an operator decides where to spend the next hour.",{"label":389,"detail":390},"Sub-100ms filtering changes behaviour, not just satisfaction","Below roughly a tenth of a second, operators explore. Above it they plan a query before running it, and exploration stops being possible.",{"label":392,"detail":393},"Export should remain, and stop being the first action","Some downstream uses are legitimate. Success is export moving from the first click to a deliberate late one, not disappearing.",[395,408],{"name":396,"role":397,"context":398,"goals":399,"frustrations":403,"quote":407},"Renske de Groot","Operations controller, Rotterdam hub","Runs a shift watching 40,000 active shipments on two monitors, deciding continuously where attention is worth spending. She built a personal spreadsheet system years ago and it works.",[400,401,402],"Ask a compound question without planning it in advance","Return to the same five views every morning without rebuilding them","Compare two hubs side by side while a call is happening",[404,405,406],"One filter at a time, against questions that need four","Everything lost on refresh","A three-second sort that makes exploration not worth attempting","I already know about the weather in Lyon. I need the list that excludes it, and there is no way to say that to this thing.",{"name":409,"role":410,"context":411,"goals":412,"frustrations":416,"quote":420},"Idris Mahmood","Network operations lead","Does not work the floor. Reviews patterns across hubs weekly and needs the same view the controllers are looking at, not an approximation of it rebuilt in a reporting tool.",[413,414,415],"See exactly what a controller saw when they escalated","Compare this week against last on the same query","Share a view without describing how to reconstruct it",[417,418,419],"Views cannot be shared, only described in a message","Reporting tool and dashboard disagree because the filters differ","No way to tell whether a number is current or stale","Someone sends me a screenshot and a paragraph explaining which filters they used. That paragraph should have been a link.",[422,426,432,437,442,447],{"stage":423,"doing":424,"feeling":425},"Shift starts","Opens the dashboard on the left monitor.","neutral",{"stage":427,"doing":428,"feeling":429,"friction":430,"opportunity":431},"Rebuild yesterday's view","Re-applies the same filters and column choices by hand.","negative","Identical work, every morning, because nothing persists.","Saved views carrying the full query, columns, sort and density.",{"stage":433,"doing":434,"feeling":429,"friction":435,"opportunity":436},"Ask a compound question","Tries to express a two-condition question with one filter.","The question cannot be stated, so it gets approximated.","A stackable condition builder that reads as a sentence.",{"stage":438,"doing":439,"feeling":425,"friction":440,"opportunity":441},"Give up and export","Clicks Export to CSV and switches to the spreadsheet.","Everything after this point happens outside the product.","Beat the spreadsheet on composition and speed, not on features.",{"stage":443,"doing":444,"feeling":429,"friction":445,"opportunity":446},"Compare two hubs","Opens a second spreadsheet window beside the first.","The product shows one set; comparison is not expressible in it.","A split view holding two independent queries.",{"stage":448,"doing":449,"feeling":429,"friction":450,"opportunity":451},"Escalate","Screenshots the spreadsheet and writes a paragraph explaining the filters.","The view cannot be shared, only reconstructed from a description.","Every view addressable by URL.",{"title":31,"description":166},[454,455,456],"Dashboard Design","Product Design","Frontend Engineering",[458,459,460,461,462],"Figma","Vue 3","TypeScript","TanStack Table","Tailwind CSS","work\u002F4.fleetwise-dashboard",{"summary":465,"radius":323,"density":466,"palette":467,"type":486,"tokens":509,"components":534,"specimens":557},"A compact, high-density system built for a shift spent scanning. Small radii, tight control heights, hairline rules instead of zebra striping, and a status ramp deliberately held apart from the categorical chart hues so a neutral data series never reads as a warning.","compact",[468,472,475,478,482],{"name":469,"value":470,"role":471},"Console","#0A0A0C","Primary surface, dark theme — the floor runs dark all shift",{"name":473,"value":32,"role":474},"Signal","Primary action and the subject series in charts, dark theme",{"name":476,"value":33,"role":477},"Signal (light)","The same role restepped — bright amber is unreadable on white",{"name":479,"value":480,"role":481},"Reference","#71717A","Secondary text, and the comparison series in every chart",{"name":483,"value":484,"role":485},"Exception","#DC2626","Reserved for exceptions. Never used as a categorical series colour.",[487,493,497,502,506],{"name":488,"size":489,"weight":490,"tracking":491,"usage":492},"Metric","1.75rem",600,"-0.02em","Headline counts, always tabular",{"name":494,"size":495,"weight":490,"usage":496},"Heading","1.125rem","Panel and view titles",{"name":498,"size":499,"weight":500,"usage":501},"Body","0.875rem",400,"Table cells at default density",{"name":503,"size":504,"weight":500,"usage":505},"Dense","0.8125rem","Table cells at compact density, where most of a shift is spent",{"name":507,"size":504,"weight":500,"usage":508},"Identifier","Shipment references and codes, monospaced for scanning",[510,514,518,522,526,530],{"name":511,"value":512,"usage":513},"--row-height-compact","28px","Compact density. Fits roughly 40 rows on a floor monitor.",{"name":515,"value":516,"usage":517},"--interaction-budget","100ms","A budget, asserted in CI. Above it, exploration stops.",{"name":519,"value":520,"usage":521},"--grid-line","hairline","Row separation. Zebra striping doubles the ink for no added legibility.",{"name":523,"value":524,"usage":525},"--numeric-align","right","Every numeric column, with tabular figures. Non-negotiable.",{"name":527,"value":528,"usage":529},"--status-ramp","reserved","Held apart from categorical hues so a series never reads as a warning.",{"name":531,"value":532,"usage":533},"--live-default","paused","Views do not move under the pointer unless asked.",[535,539,543,547,550,553],{"name":536,"variants":537,"detail":538},"DataTable",12,"Three densities, virtualised body, and the loading, empty, filtered-empty, error, partial and stale states.",{"name":540,"variants":541,"detail":542},"ConditionRow",9,"Field, operator and value across six field types, including exclusions.",{"name":544,"variants":545,"detail":546},"ViewTab",5,"Saved view with its own freshness indicator and live\u002Fpaused state.",{"name":548,"variants":107,"detail":549},"SplitPane","Two independent queries side by side, each with its own column set.",{"name":551,"variants":323,"detail":552},"FreshnessBadge","Age, pending-change count and refresh affordance, per view.",{"name":554,"variants":555,"detail":556},"SeriesChart",6,"Subject and reference series only. One axis, always.",[558,559,560,561],"table","chart","status","nav","12-week scope","2025","qkMTo1ITSsSKzCuHzK54bP3IRQGZp5PSh0AyipmTvIA",[566,572,578,584,585,591],{"path":567,"client":568,"title":569,"excerpt":167,"accent":570,"industry":571},"\u002Fwork\u002Fnorthwind-design-system","Northwind Cloud","One design system across four acquired products","#00D4FF","SaaS",{"path":573,"client":574,"title":575,"excerpt":167,"accent":576,"industry":577},"\u002Fwork\u002Fmeridian-clinical-ai","Meridian Health","Designing an AI that clinicians are allowed to disagree with","#22C55E","Healthcare",{"path":579,"client":580,"title":581,"excerpt":167,"accent":582,"industry":583},"\u002Fwork\u002Fledgerly-onboarding","Ledgerly","Rebuilding onboarding around the first useful moment","#7C3AED","Fintech",{"path":349,"client":132,"title":31,"excerpt":167,"accent":32,"industry":320},{"path":586,"client":587,"title":588,"excerpt":167,"accent":589,"industry":590},"\u002Fwork\u002Fverdigris-marketplace","Verdigris","An e-commerce system where every product is one of one","#E07A5F","E-commerce",{"path":592,"client":593,"title":594,"excerpt":167,"accent":595,"industry":596},"\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":598},"\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":600},"\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":602},"\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":604},"\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":606},"\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":608},"\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":610},"\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":612},"\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":614},"\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":616},"\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":618},"\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":620},"\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":622},"\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":624},"\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":626},"\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>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":628},"\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":630},"\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":632},"\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":634},"\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":636},"\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":638},"\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":640,"hidden":24},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M22 3H2l8 9.46V19l4 2v-8.54z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":642},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M17 3a2 2 0 0 1 2 2v15a1 1 0 0 1-1.496.868l-4.512-2.578a2 2 0 0 0-1.984 0l-4.512 2.578A1 1 0 0 1 5 20V5a2 2 0 0 1 2-2z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":644},"\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":646},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 3H5a2 2 0 0 0-2 2v4m6-6h10a2 2 0 0 1 2 2v4M9 3v18m0 0h10a2 2 0 0 0 2-2V9M9 21H5a2 2 0 0 1-2-2V9m0 0h18\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":648},"\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":650},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2\"\u002F>",1787597897458]