import {C,frame,screen,rect,text,label,mark,icon,line,card,metric,pill,button,tabs,table,chart,progress,aiNote,codeBlock,steps,rowList,group,path,ellipse,field,boards} from './design-lib.mjs';
function sheet(id,title,chapter,sub,fn){frame(id,title,chapter,()=>{rect(0,0,1440,1000,C.canvas);mark(48,43,28,C.green);label(97,49,'Ankra / Design system');text(48,112,title,46,C.ink,600,1329);text(50,185,sub,16,C.muted,400,1285);fn();text(49,961,'ANKRA  /  INTELLIGENT INFRASTRUCTURE',10,C.muted,500);text(1214,961,'SEPTEMBER 2026',10,C.muted,500);},{kind:'foundation'});}
export function foundations(){
frame('cover','Ankra / Intelligent by design','00 / Direction',()=>{
rect(0,0,1440,1000,C.dark);mark(62,53,43,C.lime);text(125,52,'ankra',43,C.paper,600);label(1139,69,'A new operating era',C.navMuted);label(65,222,'Platform redesign / 2026',C.lime);text(57,296,'Intelligent\nby design.',108,C.paper,500,970,{lineHeight:113,tracking:-4});text(64,570,'One place to understand, build, and operate\nyour infrastructure—with AI on your team.',25,C.navMuted,400,787,{lineHeight:38});
for(let i=0;i<7;i++){const x=939+i*23,y=351-i*17;path(x,y,303,347,'M151 0L303 87V260L151 347L0 260V87Z',i===6?C.lime:'#365746',1.5,'none',{viewW:303,viewH:347});}ellipse(1138,492,26,26,C.lime);path(894,512,254,2,'M0 1H254',C.lime,1,'none',{viewW:254,viewH:2});ellipse(888,509,7,7,C.lime);
line(64,831,1312,'#365746');text(64,860,'Brand. System. Experience.',20,C.paper,500);text(64,905,'A complete design direction grounded in the existing Ankra platform.',14,C.navMuted,400,1091);text(1226,880,'01 / 2026',12,C.lime);
},{kind:'cover',bg:C.dark,description:'Proposed identity evolves the existing faceted Ankra mark into a quieter, more legible infrastructure brand.'});
sheet('principles','Operate with clarity.','00 / Direction','A product direction grounded in the real work of platform teams.',()=>{
const items=[['01','AI is part of the operating model.','A consistent place for questions, evidence, proposals, approvals, and durable outcomes.'],['02','Context follows the work.','Workspace, environment, cluster, resource, and time range stay visible across every investigation.'],['03','Expert control remains close.','Tables, YAML, logs, diffs, dependency graphs, and keyboard navigation are first-class interfaces.'],['04','Truth has a visual language.','Unknown, stale, partial, estimated, running, approved, and verified are visibly different states.'],['05','Automation earns trust.','Expose permissions, spend, scope, stop conditions, reversibility, and the result of each action.'],['06','Density is intentional.','Summary first, inspectable detail next. Comfortable and compact modes support different tasks.']];items.forEach(([n,a,b],i)=>card(48+i%2*691,265+Math.floor(i/2)*218,644,193,null,null,()=>{text(23,23,n,12,C.green,600);text(65,23,a,20,C.ink,600,547);text(65,81,b,15,C.muted,400,545);}));
});
sheet('architecture','A navigation built around work.','00 / Direction','Nine stable destinations. Entity depth moves into tabs and local explorers.',()=>{
const groups=[['WORKSPACE',[['Overview','Daily briefing, attention, and fleet health'],['Intelligence','Chat, tasks, agents, automations, and runs'],['Inbox','Approvals, incidents, insights, and activity']]],['BUILD & RUN',[['Applications','Source → build → deploy → operate'],['Stacks & catalog','Stacks, profiles, charts, and manifests'],['Infrastructure','Clusters, providers, node groups, and mesh']]],['OPERATE',[['Observability','Metrics, logs, events, alerts, and operations'],['Security','Findings, policies, exposure, and compliance'],['Cost','Forecasts, allocation, sources, and savings']]]];groups.forEach(([a,items],i)=>card(48+i*460,266,431,441,null,null,()=>{label(23,25,a);items.forEach(([b,c],j)=>{text(23,88+j*106,b,22,C.ink,600,383);text(23,125+j*106,c,14,C.muted,400,383);});}));
rect(48,737,1352,149,C.dark,11);text(73,764,'Context spine',20,C.lime,500);text(304,771,'Workspace  /  Environment  /  Cluster  /  Resource  /  Time',19,C.paper,500,1057);text(73,818,'Organisation settings, credentials, access, billing, help, and personal preferences remain one stable step away.',15,C.navMuted,400,1273);
});
sheet('brand-mark','The Ankra identity, refined.','01 / Brand & foundations','A faceted anchor: structural, calm, recognizable at small sizes.',()=>{
rect(48,266,645,367,C.dark,13);mark(137,343,118,C.lime);text(307,350,'ankra',88,C.paper,500);text(79,579,'PRIMARY LOCKUP / ON INK',11,C.navMuted,600);
rect(718,266,682,367,C.paper,13,C.line);mark(770,354,106,C.green);text(925,361,'ankra',80,C.ink,500);text(750,579,'PRIMARY LOCKUP / ON PAPER',11,C.muted,600);
card(48,658,431,252,'Construction',null,()=>{text(22,76,'Preserve the faceted geometry. Use a consistent 1.65-unit stroke on the 24 × 28 grid.',15,C.muted,400,382);text(22,176,'No gradients, glow, or stretching.',13,C.ink,500,385);});
card(508,658,431,252,'Clear space',null,()=>{text(22,76,'Reserve at least half the mark width on all sides. Keep the wordmark and mark optically aligned.',15,C.muted,400,382);text(22,176,'Minimum mark size: 20 px.',13,C.ink,500,385);});
card(968,658,432,252,'Voice',null,()=>{text(22,76,'Clear, capable, and considered. Describe the state, the evidence, and the next useful action.',15,C.muted,400,382);text(22,176,'“Review plan” · “Change verified”',13,C.ink,500,385);});
});
sheet('brand-colors','A restrained, functional palette.','01 / Brand & foundations','Neutral surfaces do the work. Color carries meaning.',()=>{
const colors=[['Ink',C.ink,'Primary text and navigation'],['Paper',C.paper,'Cards and elevated surfaces'],['Canvas',C.canvas,'Workspace background'],['Forest',C.green,'Primary action and intelligence'],['Lichen',C.lime,'Brand accent on dark surfaces'],['Sage',C.greenSoft,'Selected and AI context surfaces']];colors.forEach(([a,c,b],i)=>{const x=48+i%3*460,y=264+Math.floor(i/3)*252;rect(x,y,431,138,c,10,c===C.paper?C.line:undefined);text(x+17,y+160,a,19,C.ink,600);text(x+320,y+165,c,12,C.muted,500);text(x+17,y+200,b,13,C.muted,400,397);});
[['Success',C.green,C.greenSoft],['Attention',C.amber,C.amberSoft],['Failure',C.red,C.redSoft],['In progress',C.blue,C.blueSoft],['Neutral',C.muted,C.soft]].forEach(([a,c,b],i)=>{rect(48+i*274,815,252,78,b,9);ellipse(65+i*274,844,10,10,c);text(89+i*274,838,a,14,c,600);});
});
sheet('typography','Typography with room to think.','01 / Brand & foundations','Inter for the interface. Roboto Mono for code, logs, and identifiers.',()=>{
const scale=[['Display / 64','Make the complex clear.',64,500],['Hero / 40','Your platform, in focus.',40,600],['Page title / 30','Infrastructure',30,600],['Section / 20','Ready for your review',20,600],['Body / 14','A rolling update preserves service availability.',14,400],['Label / 12','Production · eu-prod-01 · synced 12s ago',12,500],['Code / 12','kubectl get deployments -n commerce',12,400]];let y=274;scale.forEach(([a,b,size,weight],i)=>{text(49,y+10,a,12,C.muted,500,255);text(333,y,b,size,C.ink,weight,1053,{mono:i===6});line(49,y+size*1.5+22,1346);y+=i===0?151:i===1?120:84;});
});
sheet('layout-system','Structure, rhythm, and density.','01 / Brand & foundations','A 4 px spacing base with a consistent shell and responsive content grid.',()=>{
card(48,264,870,412,'Desktop layout / 1440 × 1000','224 px rail · 64 px header · 32 px content margin',()=>{rect(23,99,823,279,C.canvas,8,C.line);rect(23,99,128,279,C.nav,8);rect(151,99,695,37,C.paper);for(let i=0;i<12;i++)rect(173+i*54,156,38,198,i%2===0?C.greenSoft:C.soft,2);text(176,176,'12-column content grid',14,C.green,600,623);text(42,199,'RAIL',12,C.navMuted,500);});
card(946,264,454,412,'Spacing tokens',null,()=>{[4,8,12,16,24,32,48,64].forEach((v,i)=>{text(22,76+i*36,String(v).padStart(2,'0')+' px',12,C.muted,500);rect(101,80+i*36,v*3,13,C.greenSoft,2);});});
card(48,702,645,196,'Comfortable / Default',null,()=>{text(22,77,'Table rows: 60–72 px · Controls: 40–44 px\nCards: 24 px padding · Radius: 12 px',15,C.muted,400,592);});
card(720,702,680,196,'Compact / Power users',null,()=>{text(22,77,'Table rows: 40–48 px · Controls: 32–36 px\nCards: 16 px padding · Keep text legible at 12–14 px',15,C.muted,400,635);});
});
sheet('interaction-rules','Small details. Clear behavior.','01 / Brand & foundations','Interaction, accessibility, and copy are part of the visual system.',()=>{
const content=[['Keyboard & focus','Every control is reachable by keyboard. Use a 2 px forest focus ring with a 2 px offset. ⌘K opens search; Esc closes overlays.'],['Motion','120 ms for hover, 180 ms for disclosure, 240 ms for panels. Animate opacity and transform. Respect reduced motion; never animate live values continuously.'],['Contrast & targets','Target WCAG 2.2 AA. Body text at least 4.5:1; meaningful non-text UI at least 3:1. Touch targets at least 44 × 44 px.'],['Status & live updates','Pair color with a word and an icon. Announce meaningful status changes with a polite live region. Do not reorder a focused row on refresh.'],['Forms & validation','Persistent labels, field-specific errors, and a summary after submit. Keep the user’s input after an error. Explain required permissions in place.'],['Tone & information','Use clear operational language: Healthy, Stopped, Deploying, Failed. Avoid metaphors such as “Alive” or “Resting” for infrastructure status.']];content.forEach(([a,b],i)=>card(48+i%2*691,266+Math.floor(i/2)*218,644,193,a,null,()=>text(22,74,b,14,C.muted,400,599)));
});
sheet('components-controls','Controls & selection.','02 / Component library','Reusable components with semantic states and predictable sizing.',()=>{
card(48,266,644,276,'Buttons','Primary, secondary, destructive, disabled, focus',()=>{button(22,95,'Review plan',{w:167,target:'ai-plan'});button(209,95,'View details',{w:169,kind:'secondary'});button(398,95,'Delete',{w:143,kind:'danger'});button(22,159,'Unavailable',{w:167,disabled:true});rect(207,157,173,44,'none',10,C.green,{sw:2});button(210,160,'Focused action',{w:167});text(22,226,'One primary action per decision area. Labels use verbs.',12,C.muted,400,595);});
card(720,266,680,276,'Fields','Default, populated, error, and secure',()=>{field(22,91,294,'Application name','checkout');field(340,91,316,'API token','hidden',{secret:true});field(22,180,294,'Namespace','Invalid value',{error:true,hint:'Use lowercase letters, digits, or hyphens.'});});
card(48,568,644,332,'Selection & filtering',null,()=>{tabs(22,79,598,['Overview','Deployments','Settings']);pill(22,154,'All clusters','neutral');pill(160,154,'Production','green');pill(292,154,'Clear filters  ×','neutral');rect(22,218,21,21,C.green,4);icon('check',25,221,15,C.paper);text(56,218,'Include dependent resources',13,C.ink,500,543);ellipse(22,264,20,20,C.paper,C.green,2);ellipse(28,270,8,8,C.green);text(56,264,'Review changes before applying',13,C.ink,500,544);});
card(720,568,680,332,'Status vocabulary','Status uses color, text, and meaning together.',()=>{['Healthy','Deploying','Needs approval','Failed','Stopped','Unknown'].forEach((a,i)=>{const k=['green','blue','amber','red','neutral','neutral'][i];pill(22+i%3*219,97+Math.floor(i/3)*68,a,k);});text(22,245,'“Completed” means execution finished.\n“Verified” means the defined checks passed.',14,C.muted,400,637);});
});
sheet('components-data','Dense data, without friction.','02 / Component library','Lists, summaries, inline explanations, and honest visualization.',()=>{
card(48,264,1352,358,'Data table','Sticky header · sort / filter · row selection · inline state · pagination',()=>{table(22,89,1308,['APPLICATION','ENVIRONMENT','LAST CHANGE','OWNER','STATUS'],[['checkout|Go API service','Production','6 min ago','Commerce',{text:'Healthy',kind:'green'}],['storefront|Next.js application','Production','18 min ago','Commerce',{text:'Healthy',kind:'green'}],['analytics|Python worker','Production','24 min ago','Data platform',{text:'Degraded',kind:'amber'}]],{widths:[369,250,269,243,177],rowH:68,selected:0});});
metric(48,650,431,'Metric / known value','99.98%','Unit, period, source, and freshness');card(509,650,431,247,'Metric / unknown',null,()=>{text(22,83,'—',44,C.muted,500);text(22,156,'Metrics source is not connected.',14,C.muted,400,385);text(22,205,'Connect Prometheus  →',12,C.green,600,385,{target:'cluster-settings'});});aiNote(969,650,431,'Evidence-linked summary','A concise finding links to its source and time window. Recommendations stay distinct from observations.',{h:247,target:'ai-investigation'});
});
sheet('components-ai','The anatomy of an AI action.','02 / Component library','Every plan answers the same questions before it reaches execution.',()=>{
card(48,265,841,637,'Increase checkout memory limit','AP-204 · Proposed by SRE agent',()=>{pill(24,90,'Production','amber');pill(139,90,'Approval required','amber');text(24,151,'WHY',11,C.muted,600);text(24,180,'Two pods exceeded 512 MiB after rollout #1842.',17,C.ink,500,790);text(24,230,'EVIDENCE',11,C.muted,600);text(24,259,'Pod events · request metrics · deployment history',14,C.green,500,790);text(24,309,'CHANGE',11,C.muted,600);text(24,338,'Memory limit 512 MiB → 768 MiB · rolling restart',17,C.ink,500,790);text(24,388,'BOUNDARIES',11,C.muted,600);text(24,417,'1 deployment · eu-prod-01 · no node cost change',14,C.muted,400,790);text(24,467,'SUCCESS & RECOVERY',11,C.muted,600);text(24,496,'4 replicas ready · p95 < 250 ms · rollback if unhealthy',14,C.muted,400,790);button(24,563,'Review & approve',{w:208,target:'ai-plan',icon:'check'});});
card(917,265,483,637,'Action contract',null,()=>{const items=['Scope and acting identity','Source-linked observation','Proposed resource diff','Required permissions','Budget and estimated impact','Plan expiry and stale state','Verification criteria','Rollback or recovery path','Durable execution receipt'];items.forEach((v,i)=>{ellipse(23,86+i*50,23,23,C.greenSoft);text(31,90+i*50,i+1,10,C.green,600);text(62,86+i*50,v,14,C.ink,500,396);});});
});
sheet('components-feedback','Feedback & recovery patterns.','02 / Component library','A failed request, a stale resource, and a denied action need different responses.',()=>{
const states=[['green','Change verified','All defined health checks passed. View the execution receipt.'],['blue','Operation running','You can leave this page. The run will continue in the background.'],['amber','Plan needs revalidation','The resource changed after this plan was prepared. Refresh the diff.'],['red','Deployment partially failed','2 of 3 resources were applied. Inspect the failed step before retrying.'],['neutral','You need a different permission','This action requires workloads.update. Ask an organisation administrator.'],['neutral','No data for this time range','Choose a longer range or connect the metrics source.']];states.forEach(([k,a,b],i)=>{const x=48+i%2*691,y=264+Math.floor(i/2)*218;card(x,y,644,193,null,null,()=>{pill(22,22,a,k);text(22,83,b,15,C.muted,400,597);text(22,150,'A concrete next step stays visible  →',12,C.green,600,597);});});
});
}

export function responsiveAndStates(){
frame('mobile-overview','Mobile / Overview','09 / Responsive & states',()=>{
rect(0,0,390,844,C.canvas);text(23,14,'9:41',13,C.ink,600);text(317,14,'● ▰',12,C.ink);mark(22,53,27,C.green);text(62,56,'ankra',22,C.ink,600);icon('bell',338,58,21);line(0,99,390);text(23,123,'Your platform,\nin focus.',30,C.ink,600,342,{lineHeight:36});text(23,215,'Northstar · Production',12,C.muted);rect(22,259,346,172,C.dark,12);label(40,276,'Daily briefing',C.lime);text(40,309,'Production is stable.\nOne decision needs you.',21,C.paper,500,307);text(40,391,'Review your briefing  →',12,C.lime,600,307,{target:'mobile-inbox'});
card(22,455,346,126,'Needs your approval',null,()=>{text(20,56,'Checkout memory change',14,C.ink,500,300);pill(20,87,'Production','amber',{small:true});text(241,92,'Review →',11,C.green,600,80,{target:'mobile-inbox'});});
card(22,601,346,123,'Fleet status',null,()=>{text(20,64,'11 healthy · 1 needs attention',15,C.ink,500,300);});rect(0,764,390,80,C.paper);line(0,764,390);[['home','Home'],['spark','AI'],['bell','Inbox'],['grid','Explore']].forEach(([ico,a],i)=>{icon(ico,35+i*97,779,21,i===0?C.green:C.muted);text(24+i*97,808,a,11,i===0?C.green:C.muted,500,72);});rect(135,836,120,4,C.ink,2);
},{w:390,h:844,description:'Mobile prioritizes triage, read access, approvals, and notifications. Complex graph editing remains a desktop workflow.'});
frame('mobile-inbox','Mobile / Decision','09 / Responsive & states',()=>{
rect(0,0,390,844,C.canvas);text(23,14,'9:41',13,C.ink,600);text(24,60,'←   Decisions',14,C.green,600,340);text(23,114,'Review checkout\nmemory change',26,C.ink,600,343,{lineHeight:33});pill(23,198,'Production','amber');pill(137,198,'1 deployment','neutral');card(22,251,346,181,'Why this change?',null,()=>text(20,66,'Two pods exceeded their memory limit after the rollout. Three sources support the finding.',15,C.muted,400,302));card(22,454,346,169,'Proposed change',null,()=>{text(20,64,'512 MiB → 768 MiB',23,C.ink,600,302);text(20,108,'Rolling update · no node cost change',12,C.muted,400,302);});text(23,653,'Success: 4 replicas ready and p95 < 250 ms.\nRollback if readiness or latency degrades.',12,C.muted,400,342);rect(0,742,390,102,C.paper);line(0,742,390);button(22,761,'Approve & execute',{w:346,h:48,target:'ai-execution',icon:'check'});rect(135,836,120,4,C.ink,2);
},{w:390,h:844});
screen('command-search','Command search','09 / Responsive & states','Overview',()=>{rect(224,64,1216,936,'#D5DDD4');card(370,197,828,611,null,null,()=>{icon('search',24,27,22,C.green);text(63,25,'checkout',21,C.ink,400,727);text(752,30,'ESC',11,C.muted);line(22,75,784);label(24,105,'Applications');rect(12,141,804,68,C.greenSoft,7);icon('grid',26,161,21,C.green);text(67,152,'checkout',15,C.green,600,700,{target:'app-overview'});text(67,179,'Application · Production · eu-prod-01',11,C.muted);label(24,242,'Resources');text(27,287,'Deployment / checkout',15,C.ink,500,744,{target:'workload-detail'});text(27,328,'Pod / checkout-7df8',15,C.ink,500,744,{target:'pod-detail'});label(24,391,'Ask Ankra');text(27,439,'Investigate checkout health  →',15,C.green,500,744,{target:'ai-investigation'});line(22,531,784);text(24,558,'↑ ↓ Navigate     ↵ Open     Tab Change scope',12,C.muted,400,749);});},{subtitle:'Resources, routes, actions, and scoped AI entry in one keyboard-first surface.'});
screen('onboarding','Welcome to Ankra','09 / Responsive & states','Overview',()=>{rect(256,192,1152,185,C.dark,13);text(285,220,'Your platform starts here.',34,C.paper,500,1060);text(285,276,'Connect your infrastructure and teach Ankra how your team operates.',16,C.navMuted,400,1047);pill(285,328,'1 of 4 steps complete','dark');card(256,402,745,506,'Make Ankra yours','Get value from one safe, useful workflow.',()=>{rowList(24,92,697,[{title:'Create your workspace',detail:'Organisation identity and preferences',status:'Done'},{title:'Connect a cluster or repository',detail:'Import existing infrastructure or start from code',status:'Next',kind:'blue',icon:'plus'},{title:'Add context and boundaries',detail:'Runbooks, permissions, providers, and budgets',status:'To do',kind:'neutral',icon:'book'},{title:'Run your first investigation',detail:'Read-only by default, with evidence you can inspect',status:'To do',kind:'neutral',icon:'spark'}]);button(24,426,'Connect infrastructure',{w:237,target:'cluster-create',icon:'arrow'});});aiNote(1023,402,385,'Explore first','A playground shows the operating workflows with temporary infrastructure. You can connect production when ready.',{h:190,target:'cluster-create'});},{subtitle:'A first-run path that connects infrastructure, context, and trust.'});
const stateData=[['state-empty','No applications yet','Connect a repository to prepare your first application.','Connect repository','app-create','grid'],['state-no-results','No results match these filters','Your resources are still here. Clear filters or widen the selected scope.','Clear filters','workloads','search'],['state-offline','Cluster connection interrupted','The last known state is from 10:14 UTC. Live actions are disabled until the agent reconnects.','Inspect connection','cluster-settings','server'],['state-permission','You do not have access to this action','Updating production workloads requires workloads.update. Your current role is Viewer.','View your access','roles','shield'],['state-stale','This plan is out of date','checkout changed after the plan was prepared. Revalidate the resource and review the updated diff.','Revalidate plan','ai-plan','refresh'],['state-partial-failure','Deployment partially failed','Namespace and database changes succeeded. The checkout deployment failed its readiness check.','Inspect failed step','operation-detail','alert'],['state-rollback','Review rollback to revision 1841','This will restore the previous deployment specification. Database changes and external side effects are not automatically reversed.','Review rollback plan','ai-plan','refresh'],['state-not-connected','Connect a metrics source','Live CPU, memory, and network data are unavailable. Resource counts remain available from Kubernetes.','Connect Prometheus','cluster-settings','chart'],['state-budget','Agent paused at its budget limit','This run used €10.00 of its €10.00 budget. Evidence and completed steps are saved. A budget change requires an authorized owner.','Review run budget','agent-detail','pause'],['state-not-found','This resource is no longer available','It may have been deleted or moved to another scope. Return to the resource list or inspect the audit trail.','Browse resources','resources','search']];
stateData.forEach(([id,title,body,action,target,ico])=>screen(id,title,'09 / Responsive & states','Overview',()=>{card(371,254,923,581,null,null,()=>{rect(395,59,72,72,id.includes('failure')?C.redSoft:C.greenSoft,15);icon(ico,417,81,28,id.includes('failure')?C.red:C.green);text(70,181,title,31,C.ink,600,790);text(70,250,body,17,C.muted,400,781);button(70,389,action,{w:281,target,icon:'arrow'});text(70,473,'Your context and any saved draft are preserved.',12,C.muted,400,781);});},{subtitle:'Recovery state / explicit context, reason, and next step.'}));
screen('state-loading','Loading your workspace','09 / Responsive & states','Overview',()=>{for(let i=0;i<4;i++){card(256+i*293,192,271,129,null,null,()=>{rect(20,25,131,13,C.soft,3);rect(20,56,88,30,C.soft,3);rect(20,102,184,10,C.soft,3);});}card(256,347,745,414,null,null,()=>{rect(22,29,211,19,C.soft,3);for(let i=0;i<4;i++){rect(22,96+i*67,700,39,C.soft,5);}});card(1023,347,385,414,null,null,()=>{rect(22,29,172,19,C.soft,3);for(let i=0;i<4;i++){rect(22,96+i*67,338,39,C.soft,5);}});text(256,810,'Layout is preserved while data loads. No fabricated health or metric values.',13,C.muted,400,1110);},{subtitle:'Loading state / stable layout, reduced-motion support, and meaningful progress.'});
}
