{
  "system": "Werklist brand guidelines",
  "version": "2.1.2",
  "site": "https://design.werklist.com",
  "pages": [
    {
      "title": "Purpose",
      "path": "/about/purpose",
      "url": "https://design.werklist.com/about/purpose",
      "text": "https://design.werklist.com/agent/about/purpose",
      "summary": "The purpose, vision and mission of Werklist, in the company's own words.",
      "version": "2.1.2",
      "kind": "about",
      "name": "Purpose",
      "purpose": "The purpose, vision and mission of Werklist, to be quoted as written.",
      "rules": [
        "Quote each statement word for word. Do not shorten, paraphrase or merge them.",
        "Set a statement on its own line, not inside a sentence of your own.",
        "For a shorter or adapted version, write to brand@werklist.com."
      ],
      "content": [
        "Purpose: To bring simplicity to global work by eliminating complexity and uncertainty for both workers and employers.",
        "Vision: To become the first thought associated with work for both workers and employers, and to enable a world where they focus on work, not employment.",
        "Mission: To design the global work infrastructure that redefines how the world works.",
        "Mission pillar: Local permanent placement. Remove bureaucracy from hiring local talent. Replace it with speed, precision and human connection.",
        "Mission pillar: Global permanent placement. Bring fairness and cultural alignment to global work by supporting legal migration and building transparent, value-driven pathways for both workers and employers."
      ]
    },
    {
      "title": "Values and culture",
      "path": "/about/values",
      "url": "https://design.werklist.com/about/values",
      "text": "https://design.werklist.com/agent/about/values",
      "summary": "The values Werklist works by, and the culture principles of its manifesto.",
      "version": "2.1.2",
      "kind": "about",
      "name": "Values and culture",
      "purpose": "The values of Werklist and the culture principles of the company manifesto, quoted as written.",
      "rules": [
        "Quote a value or a principle word for word, with its name first.",
        "Keep the order of both lists, and set them without numbers.",
        "For a shorter or adapted version, write to brand@werklist.com."
      ],
      "content": [
        "Value: Impact over activity. We measure ourselves by outcomes, not by how busy we appear.",
        "Value: Excellence. We do not polish forever. We also do not ship work we would not sign with our name.",
        "Value: Winning. We play to win. Not once. Always.",
        "Value: Velocity. We make fast decisions and act with peaceful urgency.",
        "Value: Responsibility. We do not ask for permission to take ownership or risk. We need a reason not to.",
        "Culture principle: Mission over self. To reshape the world, we must begin with ourselves by believing that if we are strong on the inside, what we create on the outside will be just as strong. Werklist's culture is grounded in one uncompromising principle: no one may ever place personal interest above the mission or the collective.",
        "Culture principle: Operate as a team. We commit to the team fully and decisively, and with heart. There is a deep sense of unity here, a shared devotion to our mission and to each other that transcends roles, titles, or ego.",
        "Culture principle: Relentless optimism. We are optimistic about the future, the problems we face, and our ability to overcome them. Our motto is simple: we will figure it out and tomorrow will be better.",
        "Culture principle: Zero mediocrity. We do not do work just to get it done. Each action we take must create superior value for Werklist and deliver a superior experience for our users, both employers and workers.",
        "Culture principle: Strong confidence. Our employees and partners should never feel fear inside the collective. We encourage bold decisions, fast execution, and full ownership, always. Every team member is not only allowed, but obligated, to actively motivate and support their peers.",
        "Culture principle: Ideas win, direction reigns. There are no bad ideas, only raw ones not yet fully shaped. We strive to build an environment where the best ideas win regardless of where they come from. Even the best ideas must align with our long-term direction and compound into our collective output. We embrace opportunities, but not every opportunity is our opportunity.",
        "Culture principle: A-integrity only. There is no room for B or C players at Werklist. An A-player is not the one with the highest IQ but the one with the highest integrity, the one who takes full ownership, gives everything they have got, and refuses to deliver anything half-baked.",
        "Culture principle: No room for bad people. We never prioritize performance over character. Ever. No matter how talented you are, if you show a lack of integrity, disrespect your teammates, or poison the culture, you will not last. No brilliance justifies toxicity.",
        "Culture principle: Meritocracy over hierarchy. We aim to build an environment where the most junior person can challenge and outperform the most senior. We design our company so that everyone is rewarded for impact, and impact usually comes from a combination of effort and care. We see and value our contributors.",
        "Culture principle: We protect our people for the long run. We aim to create a team where people stay until retirement, not through comfort, but through mutual commitment. We care deeply about each person. Great output requires time, wandering, and space to think. That is why we do not push for long hours, but we do expect excellence across long arcs of work. No one delivers peak output all the time. That is why we build a culture of understanding: not weakness, but support. Even the best team members need rest, rotation, or time to reset. At Werklist, we remember your past contributions. We stand by you, especially when things get hard. There will be hard times. When they come, we expect our people to stand by Werklist and protect the mission above personal goals, always in a way that respects their health and their families. When things get hard, we do not disappear. We show up."
      ]
    },
    {
      "title": "Positioning",
      "path": "/about/positioning",
      "url": "https://design.werklist.com/about/positioning",
      "text": "https://design.werklist.com/agent/about/positioning",
      "summary": "How to describe Werklist.",
      "version": "2.1.2",
      "kind": "about",
      "name": "Positioning",
      "purpose": "The words that describe Werklist.",
      "rules": [
        "Quote the positioning statement word for word on a slide, a web page or a profile.",
        "Call Werklist a platform for international employment. To say what it does, say that employers use it to hire skilled workers at home and across borders.",
        "Do not call Werklist a staffing agency. Readers expect workers on loan from an agency payroll, and Werklist does not lend workers.",
        "Do not call it a recruitment network or a job board. Each names one step of the hire and leaves out the employment that follows it."
      ],
      "content": [
        "Positioning statement: Werklist is a platform for international employment. Employers use it to hire skilled workers at home and across borders. Werklist checks both the employer and the worker, and handles every step from the first search to the worker's first day on the job.",
        "Describing Werklist: Through Werklist, a worker gets a permanent job with their own employer, at home or abroad. Describe the whole hire, not one step of it such as finding candidates or posting a job."
      ]
    },
    {
      "title": "Logo",
      "path": "/brand/logo",
      "url": "https://design.werklist.com/brand/logo",
      "text": "https://design.werklist.com/agent/brand/logo",
      "summary": "Which logo file to use where, the space it needs around it and the smallest size it may take.",
      "version": "2.1.2",
      "kind": "brand",
      "name": "Logo",
      "purpose": "The Werklist logo is the mark, a dot and two slanted strokes with round ends, followed by the drawn wordmark. It is used from its files, in black or white, with a clear space of one stroke around it.",
      "use": [
        "werklist-logo-black.svg on white and light grounds.",
        "werklist-logo-white.svg on navy, brand blue and photographs under a navy scrim at 60 percent.",
        "The mark alone where the logo would be under 80 px wide, or where the name already sits nearby.",
        "werklist-blue-logomark.svg, the mark in brand blue, on white only.",
        "The app icon files for the WerkOS app."
      ],
      "avoid": [
        "Retyping the wordmark in Satoshi or any other typeface.",
        "Stretching, rotating, outlines, shadows, glows, gradients or tints.",
        "Brand blue in the dark theme, where it falls to 3.78 to 1 on the background.",
        "A photograph under the logo without the scrim.",
        "Words or other logos inside the clear space."
      ],
      "anatomy": [
        {
          "part": "Mark",
          "measure": "a dot and two slanted strokes with round ends"
        },
        {
          "part": "Wordmark",
          "measure": "a drawing, not a font"
        },
        {
          "part": "Clear space around the logo",
          "measure": "one stroke, 29 percent of its height"
        },
        {
          "part": "Clear space around the mark alone",
          "measure": "37 percent of its height"
        }
      ],
      "tokens": [
        "--brand-true",
        "--navy"
      ],
      "rules": [
        "The logo is black or white. The mark alone may also be brand blue, #1863dc, on white.",
        "On screen the logo takes the ink of the text around it: black in the light theme, white in the dark theme.",
        "Clear space is one stroke of the mark, measured from the edge of the file: 9 px for a logo 30 px tall, 12 px at 40 px and 4 pt at 14 pt in print.",
        "The logo is at least 80 px wide on screen and 20 mm in print.",
        "The mark alone is at least 16 px wide on screen and 6 mm in print.",
        "Keep at least 4.5 to 1 between the logo and its ground.",
        "Contrast: black on white 21 to 1, white on navy 19.23 to 1, white on brand blue 5.44 to 1, the blue mark on white 5.44 to 1.",
        "On a photograph, a navy scrim at 60 percent sits under the logo. White on the scrim keeps 5.05 to 1 even where the picture is white."
      ]
    },
    {
      "title": "Imagery",
      "path": "/brand/imagery",
      "url": "https://design.werklist.com/brand/imagery",
      "text": "https://design.werklist.com/agent/brand/imagery",
      "summary": "The kinds of photograph Werklist publishes, where each belongs, and how text sits on a picture.",
      "version": "2.1.2",
      "kind": "brand",
      "name": "Imagery",
      "purpose": "Werklist pictures show people at their work and the cities they work in. Inside WerkOS the only pictures are people's own photos and the files they upload.",
      "use": [
        "A portrait of one person against a deep blue wall, beside a form such as the one where a candidate sends a CV.",
        "On the home page, portraits in rounded frames on the right of a navy field, with the headline on the left.",
        "One scene per industry with a painted finish, shown as a set at one ratio, each captioned with its industry.",
        "The city of a branch from above in daylight, with a landmark a local would know.",
        "A candid moment of a group where Werklist talks about how its people work together."
      ],
      "avoid": [
        "Stock handshakes and generic skylines.",
        "Text across a face.",
        "Mascots and 3D characters.",
        "Decorative pictures inside WerkOS."
      ],
      "anatomy": [
        {
          "part": "Frame",
          "measure": "a box of fixed ratio with the corner radius of the surface that holds it, 12 px on its own",
          "token": "--radius-xl"
        },
        {
          "part": "Fill while loading",
          "measure": "flat gray",
          "token": "--surface-2"
        },
        {
          "part": "Scrim",
          "measure": "navy at 60 percent under text or the logo",
          "token": "--navy"
        }
      ],
      "accessibility": [
        "Leave the alt text empty when a picture only sets the scene or a caption already names it.",
        "Otherwise describe what the picture shows in one sentence."
      ],
      "tokens": [
        "--navy",
        "--surface-2",
        "--radius-xl"
      ],
      "rules": [
        "A portrait is 2 to 3.",
        "An industry scene is 3 to 2. The set has 9 scenes, one for each industry.",
        "A branch city is 16 to 9.",
        "Text or the logo on a photograph sits on a navy scrim at 60 percent. White text on it keeps 5.05 to 1 even where the picture is white.",
        "Text does not cross a face.",
        "The photograph and its scrim look the same in the light and the dark theme. A photograph is not inverted or dimmed, and has no shadow.",
        "Save photographs as WebP at twice the largest size they appear. Use PNG only for a transparent background, and SVG for flat artwork.",
        "Give each picture a fixed box filled with flat gray until it loads. Load the first picture of a page at once and the rest as the reader scrolls."
      ]
    },
    {
      "title": "Applications",
      "path": "/brand/applications",
      "url": "https://design.werklist.com/brand/applications",
      "text": "https://design.werklist.com/agent/brand/applications",
      "summary": "How the brand appears in presentations, in print and on social media.",
      "version": "2.1.2",
      "kind": "brand",
      "name": "Applications",
      "purpose": "The brand in presentations, in print and on social media: the deck, the A4 report and the share card of werklist.com.",
      "anatomy": [
        {
          "part": "Slide",
          "measure": "1920 by 1080 px, printed to a PDF page of 1440 by 810 pt"
        },
        {
          "part": "Safe area of a slide",
          "measure": "140 px from each edge"
        },
        {
          "part": "Report page",
          "measure": "A4, 595 by 842 pt, top margin 20 mm, side margins 16 mm"
        },
        {
          "part": "Logo on a report",
          "measure": "57.15 by 14 pt, at the top left corner of the text frame"
        },
        {
          "part": "Share card",
          "measure": "1200 by 630 px"
        },
        {
          "part": "Ground of the share card",
          "measure": "a navy gradient at 135 degrees through #090c16, #0c1b40, #123e8f"
        },
        {
          "part": "Logo on the share card",
          "measure": "white, 46 px tall, 72 px from the top and 88 px from the left"
        },
        {
          "part": "Padding of the share card",
          "measure": "84 px top and bottom, 88 px at the sides"
        }
      ],
      "sizes": [
        {
          "name": "Slide title",
          "type": "88 px, weight 700"
        },
        {
          "name": "Slide lede",
          "type": "26 px, weight 400"
        },
        {
          "name": "Running marks of a slide",
          "type": "16 px, weight 500, 72 px from the edge"
        },
        {
          "name": "Share card title",
          "type": "Satoshi 700, line height 1.12, 80 px up to 32 characters, 70 up to 54, 60 up to 78, 50 beyond"
        }
      ],
      "rules": [
        "A slide keeps a large title at the top and the content at the bottom, with open space between them.",
        "Slides are black on white and the cover is white on black. Color appears only when color is the subject.",
        "Reports print on A4. The logo sits on the cover and the back cover, and nowhere else.",
        "Paper stays white whatever theme the reader uses on screen.",
        "Each werklist.com page shares as a card with the page's own title in the reader's language.",
        "The share card carries the white logo at the top left and the title at the bottom left. Nothing else goes on it."
      ]
    },
    {
      "title": "Design principles",
      "path": "/foundations/principles",
      "url": "https://design.werklist.com/foundations/principles",
      "text": "https://design.werklist.com/agent/foundations/principles",
      "summary": "The principles that settle design questions at Werklist, and what each one changes in a design.",
      "version": "2.1.2",
      "kind": "foundation",
      "name": "Design principles",
      "purpose": "The principles that settle a design question the components, foundations and patterns leave open.",
      "rules": [
        "Is it needed: before a field, a column or a label goes on a screen, ask what a recruiter would lose without it. If the answer is nothing, leave it out. A screen opens on its task, and a heading names its subject with no label above it.",
        "Both themes at once: design and check light and dark together. A color is a token with a value for each theme. Paper stays white in both: report pages, slides and PDFs.",
        "Restraint: the Werklist blue is the one accent on neutral ground, space separates things, labels are in sentence case, buttons are flat and a view has one primary button. A surface is set apart by its fill, not a border."
      ]
    },
    {
      "title": "Color",
      "path": "/foundations/color",
      "url": "https://design.werklist.com/foundations/color",
      "text": "https://design.werklist.com/agent/foundations/color",
      "summary": "Which color token to use for surfaces, text, brand blue and status, with its contrast in the light and the dark theme.",
      "version": "2.1.2",
      "kind": "foundation",
      "name": "Color",
      "purpose": "Choose every color by its role through a token that holds a light and a dark value.",
      "use": [
        "Surfaces: --bg for the page behind panels, --surface-1 for a panel, card or document page, --surface-2 for a band on a panel, --surface-strong for a box nested in a panel, --surface-control for a control fill, --overlay for the scrim behind a dialog.",
        "Ink: --text for body and headings, --text-label for scanned labels, --text-muted for supporting lines, --brand-ink for blue text and links.",
        "Brand: --brand-true for any fill that carries white text (with --on-brand), --brand-blue for marks without text, --nav-fill-active for a selected row or navigation item.",
        "Status chip: a 15 percent tint of --success, --warning, --error or --brand-blue with --success-ink, --warning-ink, --error-ink or --brand-ink on it.",
        "Count on red: --badge-alert with --badge-alert-ink. Neutral chip: --surface-control with --text."
      ],
      "avoid": [
        "White text on --brand-blue: 3.67 to 1 in dark.",
        "A status fill used as ink on its own tint: 2.70 to 1 for warning on a control fill in light. The -ink token reads in both themes.",
        "gray-400 as text: 2.75 to 1 on white in light.",
        "Color as the only carrier of a meaning.",
        "A hex value written in code: it keeps one value when the theme changes."
      ],
      "anatomy": [
        {
          "part": "Page",
          "token": "--bg",
          "measure": "light #f5f5f7, dark #000214"
        },
        {
          "part": "Panel",
          "token": "--surface-1",
          "measure": "light #ffffff, dark #191c2c"
        },
        {
          "part": "Band",
          "token": "--surface-2",
          "measure": "light #f6f6f8, dark #1e2233"
        },
        {
          "part": "Nested box",
          "token": "--surface-strong",
          "measure": "light #f1f1f4, dark #262834"
        },
        {
          "part": "Control fill",
          "token": "--surface-control",
          "measure": "light #ebebf0, dark #323443"
        },
        {
          "part": "Scrim",
          "token": "--overlay",
          "measure": "light rgba(15, 18, 35, 0.44), dark rgba(0, 2, 20, 0.66)"
        },
        {
          "part": "Body ink",
          "token": "--text",
          "measure": "light #0d0d12, dark #ffffff"
        },
        {
          "part": "Label ink",
          "token": "--text-label",
          "measure": "light rgba(13, 13, 20, 0.78), dark rgba(255, 255, 255, 0.86)"
        },
        {
          "part": "Muted ink",
          "token": "--text-muted",
          "measure": "light rgba(13, 13, 20, 0.58), dark rgba(255, 255, 255, 0.7)"
        },
        {
          "part": "Button fill",
          "token": "--brand-true",
          "measure": "#1863dc in both themes"
        },
        {
          "part": "Blue ink",
          "token": "--brand-ink",
          "measure": "light #0e4aa8, dark #5b9dff"
        },
        {
          "part": "Marks",
          "token": "--brand-blue",
          "measure": "light #1863dc, dark #3b82f6"
        },
        {
          "part": "Selected row wash",
          "token": "--nav-fill-active",
          "measure": "light rgba(24, 99, 220, 0.1), dark rgba(91, 157, 255, 0.16)"
        },
        {
          "part": "Success fill and ink",
          "token": "--success, --success-ink",
          "measure": "fill light #18874f, dark #2ee6a0; ink light #136b3f, dark #2ee6a0"
        },
        {
          "part": "Warning fill and ink",
          "token": "--warning, --warning-ink",
          "measure": "fill light #b87503, dark #f0b54a; ink light #8a5602, dark #f0b54a"
        },
        {
          "part": "Error fill and ink",
          "token": "--error, --error-ink",
          "measure": "fill light #c0233f, dark #ff5a6a; ink light #b01e39, dark #ff8391"
        },
        {
          "part": "Count on red",
          "token": "--badge-alert, --badge-alert-ink",
          "measure": "fill #d61f35 in both themes; ink #ffffff in both themes"
        }
      ],
      "tokens": [
        "--bg",
        "--surface-1",
        "--surface-2",
        "--surface-strong",
        "--surface-control",
        "--overlay",
        "--text",
        "--text-label",
        "--text-muted",
        "--brand-true",
        "--brand-blue",
        "--brand-ink",
        "--on-brand",
        "--nav-fill-active",
        "--success",
        "--success-ink",
        "--warning",
        "--warning-ink",
        "--error",
        "--error-ink",
        "--badge-alert",
        "--badge-alert-ink"
      ],
      "rules": [
        "Text meets 4.5 to 1 against what is behind it in both themes, headings included.",
        "The one exception is the word on a status chip: 3.5 to 1 on its tint, so the ink can keep the hue of its chip.",
        "Icons, marks and the focus ring meet 3 to 1.",
        "A content surface has no border and no shadow. Layers are told apart by fill.",
        "Underline a link inside running text: --brand-ink against --text is 2.36 to 1 in light and 2.72 to 1 in dark.",
        "Status is never shown by color alone: a word or an icon carries it too.",
        "Panels and text have their own dark values. Panels step up from a near black navy page, blue text turns lighter, and the button fill stays the same.",
        "WerkOS opens in light, and a person switches to dark on the desktop rail or in My profile.",
        "Sign in screens and everything a prospect sees, such as offers, decks and report pages, stay light in both themes.",
        "A document page stays white and a video call stays dark in both themes.",
        "Chart series and the statuses of a board have colors of their own, set out on the Charts and Board grid pages."
      ]
    },
    {
      "title": "Typography",
      "path": "/foundations/typography",
      "url": "https://design.werklist.com/foundations/typography",
      "text": "https://design.werklist.com/agent/foundations/typography",
      "summary": "Satoshi, the ramp for reading, the denser ramp for the product, and how to set text and numbers.",
      "version": "2.1.2",
      "kind": "foundation",
      "name": "Typography",
      "purpose": "Sets the typeface, the reading ramp, the product ramp, tabular figures and the rules for setting text in Werklist products and pages.",
      "tokens": [
        "--font-sans",
        "--font-mono",
        "--font-email",
        "--type-display",
        "--type-title-1",
        "--type-statement",
        "--type-title-2",
        "--type-lede",
        "--type-title-3",
        "--type-body",
        "--type-small",
        "--type-nav",
        "--type-caption",
        "--type-product-title-1",
        "--type-product-title-2",
        "--type-product-title-3",
        "--type-product-subtitle",
        "--type-product-body",
        "--type-product-dense",
        "--type-product-caption",
        "--type-product-caption-small",
        "--text",
        "--text-label",
        "--text-muted",
        ".tabular"
      ],
      "rules": [
        "Satoshi on the product, the website, documents and slides.",
        "The reading ramp (--type-*) on pages, documents and slides. The product ramp (--type-product-*) on WerkOS screens.",
        "Reading ramp, size/line height in px, weight, tracking: display 56/60, 700, -0.022em; title-1 44/52, 700, -0.02em; statement 40/48, 500, -0.015em; title-2 28/34, 700, -0.012em; lede 22/32, 400; title-3 20/28, 500; body 16/26, 400; small 14/22, 400; nav 14/20, 500; caption 13/20, 400.",
        "Below 768 px: display 32/38, statement 24/32, title-1 28/34, title-2 22/28, title-3 18/26, lede 18/28, body 16/24. The other steps keep their values.",
        "Product ramp, size/line height in px, weight, tracking: title-1 26/32, 700, -0.02em; title-2 22/28, 700, -0.02em; title-3 17/24, 700, -0.01em; subtitle 15/22, 700; body 14/20, 400, regular, medium on controls; dense 13/18, 400, regular, medium on headers and figures; caption 12/16, 400, regular or medium; caption-small 11/14, 500.",
        "No size between two steps, such as 13.5 px.",
        "Nothing in the product is smaller than 11 px.",
        "On touch screens, text people type is at least 16 px, so the browser does not zoom the page.",
        "Tabular figures on everything that lines up: columns, totals, timers, counters.",
        "Tabular figures: font-variant-numeric: tabular-nums; font-feature-settings: \"tnum\", \"ss01\", \"cv01\", \"cv11\"; font-kerning: none. Apply them to a whole column.",
        "Keep running text between 45 and 75 characters a line.",
        "Weight 400 for reading text and values.",
        "Weight 500 for control labels, navigation, grid headers, row figures and title-3 of the reading ramp.",
        "Weight 700 for every other heading. No weight 600: Satoshi does not have it.",
        "Bold only on headings, never on words inside running text.",
        "Sentence case. No capitals and no letter spacing. Negative tracking only on the steps that list it.",
        "Align text to the left and never justify it. No italics in the interface.",
        "Headings, labels and buttons wrap. An ellipsis cuts text only in a grid cell whose full text opens with the row.",
        "Choose a heading level by the outline of the page and its size from the ramp. Do not skip a level to get a smaller heading.",
        "Text in Cyrillic, Greek or Devanagari is set in Noto Sans.",
        "Outgoing email is set in Arial (--font-email) at 13/18 px, because email clients remove web fonts."
      ],
      "accessibility": [
        "Text meets 4.5 to 1 against its ground at every size, headings included.",
        "--text-muted sits closest to that floor. Keep it off tinted and darker grounds.",
        "Emphasis never depends on bold or italics alone.",
        "Text a reader may need elsewhere stays selectable: an error message, a passport number, an email address."
      ]
    },
    {
      "title": "Layout",
      "path": "/foundations/layout",
      "url": "https://design.werklist.com/foundations/layout",
      "text": "https://design.werklist.com/agent/foundations/layout",
      "summary": "How the page grid, the spacing scale and the breakpoints place content, from a dense board to a reading page.",
      "version": "2.1.2",
      "kind": "foundation",
      "name": "Layout",
      "purpose": "Places content on a 12 column grid inside a 1440 px frame and takes gaps from one spacing scale.",
      "anatomy": [
        {
          "part": "Frame",
          "measure": "1440 px, centered",
          "token": "--frame"
        },
        {
          "part": "Gutter",
          "measure": "24 px",
          "token": "--gutter"
        },
        {
          "part": "Side padding",
          "measure": "24 px, 32 px from 1024 px",
          "token": "--pad"
        },
        {
          "part": "Columns",
          "measure": "12 from 1024 px, 1 below"
        },
        {
          "part": "Product board or list",
          "measure": "fills the window up to 1600 px, centered"
        },
        {
          "part": "Product form or document",
          "measure": "up to 768 px, centered"
        }
      ],
      "sizes": [
        {
          "name": "Board row, compact (default)",
          "height": "36 px"
        },
        {
          "name": "Board row, comfortable",
          "height": "52 px"
        },
        {
          "name": "Board row, tall",
          "height": "76 px"
        },
        {
          "name": "Toolbar control",
          "height": "36 px"
        },
        {
          "name": "Form control",
          "height": "44 px"
        },
        {
          "name": "Target on a touch screen",
          "height": "44 px"
        }
      ],
      "tokens": [
        "--frame",
        "--gutter",
        "--pad",
        "--space-1",
        "--space-2",
        "--space-3",
        "--space-4",
        "--space-5",
        "--space-6",
        "--space-8",
        "--space-10",
        "--space-12",
        "--space-16",
        "--space-24",
        "--space-32",
        "--breakpoint-sm",
        "--breakpoint-md",
        "--breakpoint-lg",
        "--breakpoint-xl"
      ],
      "rules": [
        "Set the width of a block in columns of the grid. No fixed width on a paragraph inside a wide column.",
        "A reading page is a heading, running text and a figure or a table. The heading, the figure and the table may span every column. Running text keeps to its line length.",
        "Take margins, padding and gaps from --space-1 to --space-32. No gaps off the scale, such as 18 or 22 px.",
        "Space inside a control: 4 to 12 px. Between items of one kind: 8 to 16 px. Between groups in a section: 24 to 48 px.",
        "Between the sections of a reading page: 96 px, and 64 px below 768 px. No line between them.",
        "Half steps of 2, 6 and 10 px appear only inside a component, to center an icon optically.",
        "Running text holds 45 to 75 characters a line and never spans the full width. A statement set large may.",
        "Change the layout only at the breakpoints: 640 px, 768 px, 1024 px, 1280 px. Choose by the width of the window, not by the device.",
        "Below 640 px a board shows its rows as cards. From 1024 px the navigation rail appears, and the side padding grows.",
        "On a touch screen, whatever its width, a target is at least 44 px and editable text at least 16 px.",
        "Row and control heights are minimums, so a row grows when the reader enlarges text.",
        "The page never scrolls sideways. A wide table scrolls inside its own box.",
        "One vertical scroll area per view. No second vertical scroll area inside the page."
      ]
    },
    {
      "title": "Shape",
      "path": "/foundations/shape",
      "url": "https://design.werklist.com/foundations/shape",
      "text": "https://design.werklist.com/agent/foundations/shape",
      "summary": "The radius scale, which corner each component takes, and where a line may be drawn.",
      "version": "2.1.2",
      "kind": "foundation",
      "name": "Shape",
      "purpose": "Sets the corner radius of each component from one scale and limits lines to the places where space cannot separate.",
      "anatomy": [
        {
          "part": "Checkbox, inline code, a filled shape nested in a larger one",
          "measure": "4 px",
          "token": "--radius-sm"
        },
        {
          "part": "Header navigation item, counter, controls under 36 px high",
          "measure": "6 px",
          "token": "--radius-md"
        },
        {
          "part": "Button, icon button, text field, select, menu row, tooltip",
          "measure": "8 px",
          "token": "--radius-lg"
        },
        {
          "part": "Menu, popover, well",
          "measure": "12 px",
          "token": "--radius-xl"
        },
        {
          "part": "Card, dialog, sheet (top corners only on a phone)",
          "measure": "16 px",
          "token": "--radius-2xl"
        },
        {
          "part": "Navigation rail",
          "measure": "24 px",
          "token": "--radius-3xl"
        },
        {
          "part": "Avatar, radio, switch, slider track, current row of a side navigation, quiet status",
          "measure": "full",
          "token": "--radius-full"
        },
        {
          "part": "Table rule, list rule, menu separator, pane edge",
          "measure": "1 px",
          "token": "--border-rule"
        },
        {
          "part": "Focus ring",
          "measure": "2 px, 2 px outside the element",
          "token": "--focus-ring-width"
        },
        {
          "part": "Glass ring in the dark theme",
          "measure": "0.5 px",
          "token": "--glass-ring-raised"
        }
      ],
      "accessibility": [
        "A line that only separates visually is hidden from screen readers. A menu separator is announced, since it groups items for everyone.",
        "In forced colors, where fills disappear, cards and gray boxes gain a 1 px edge so they keep their shape."
      ],
      "tokens": [
        "--radius-sm",
        "--radius-md",
        "--radius-lg",
        "--radius-xl",
        "--radius-2xl",
        "--radius-3xl",
        "--radius-full",
        "--border-rule",
        "--focus-ring",
        "--focus-ring-width",
        "--focus-ring-offset",
        "--glass-ring",
        "--glass-ring-raised"
      ],
      "rules": [
        "Take the radius from --radius-sm to --radius-full, by component. No radius chosen by eye.",
        "Small elements take the small steps and large surfaces the large ones.",
        "Controls side by side at one height share one radius.",
        "Nested radius: inner equals outer minus padding. A menu at 12 px with 4 px of padding gives its rows 8 px.",
        "When the result drops below 4 px, a filled inner shape keeps 4 px.",
        "An image that runs to the edge of a card shares the card's corners there and stays square where it meets the text.",
        "Square corners where a surface meets the window edge, where parts of one control join, and on table cells.",
        "A full radius makes a circle or a capsule for a person, a radio, or a switch or slider track.",
        "A capsule holds text only as a quiet status or as the current row of a side navigation. A free-standing word in a capsule reads as a tag.",
        "A 1 px --border-rule line only for table and list rules, menu group separators and the edge between two panes.",
        "No border around a card or a gray box. Its fill already separates it.",
        "On paper, cards and gray boxes gain a 1 px edge in --border-rule."
      ]
    },
    {
      "title": "Elevation and materials",
      "path": "/foundations/elevation",
      "url": "https://design.werklist.com/foundations/elevation",
      "text": "https://design.werklist.com/agent/foundations/elevation",
      "summary": "How surfaces rise above the page with shadow and fill, when glass is allowed, and the order in which layers stack.",
      "version": "2.1.2",
      "kind": "foundation",
      "name": "Elevation and materials",
      "purpose": "Names the elevation levels, the materials and the stacking layers, and says when a surface may use glass.",
      "anatomy": [
        {
          "part": "Level 0",
          "measure": "the page, resting cards, wells, tables. No shadow",
          "token": "--elevation-0"
        },
        {
          "part": "Level 1",
          "measure": "a clickable card under the pointer. Shadow 8 px down, 24 px blur",
          "token": "--elevation-1"
        },
        {
          "part": "Level 2",
          "measure": "the navigation rail, the bottom bar on a phone. Shadow 12 px down, 32 px blur, fill --glass-fill",
          "token": "--elevation-2"
        },
        {
          "part": "Level 3",
          "measure": "menus, popovers, dialogs, sheets, toasts. Shadow 24 px down, 64 px blur, fill --glass-fill-raised",
          "token": "--elevation-3"
        },
        {
          "part": "Solid material",
          "measure": "opaque",
          "token": "--surface-1"
        },
        {
          "part": "Frosted material",
          "measure": "blur 48 px with strong saturation, text with a soft halo in the color of the surface",
          "token": "--glass-blur-nav"
        },
        {
          "part": "Raised material",
          "measure": "nearly opaque, blur 28 px, fully opaque on a phone",
          "token": "--glass-fill-raised"
        },
        {
          "part": "Scrim",
          "measure": "navy at 44 percent in light, 66 percent in dark, under dialogs and sheets",
          "token": "--overlay"
        },
        {
          "part": "Layers",
          "measure": "sticky 20, header 40, popover 65, dialog 60, toast 70",
          "token": "--layer-popover"
        }
      ],
      "states": [
        {
          "name": "Hover lift",
          "change": "a clickable card moves from level 0 to level 1",
          "tokens": [
            "--elevation-1"
          ]
        },
        {
          "name": "Reduced transparency, or no blur in the browser",
          "change": "glass falls back to its solid fill",
          "tokens": [
            "--surface-1",
            "--glass-fill-raised"
          ]
        },
        {
          "name": "Forced colors",
          "change": "glass takes the system background and a 1 px edge"
        }
      ],
      "keys": [
        {
          "key": "Escape",
          "action": "Closes the top layer only and returns focus to the control that opened it."
        }
      ],
      "tokens": [
        "--elevation-0",
        "--elevation-1",
        "--elevation-2",
        "--elevation-3",
        "--glass-shadow-card",
        "--glass-shadow-panel",
        "--glass-shadow-raised",
        "--glass-fill",
        "--glass-fill-raised",
        "--glass-blur-nav",
        "--glass-blur-raised",
        "--overlay",
        "--surface-1",
        "--bg",
        "--layer-sticky",
        "--layer-header",
        "--layer-popover",
        "--layer-dialog",
        "--layer-toast"
      ],
      "rules": [
        "Each surface sits at one level. A shadow appears only when a surface floats over the content or lifts under the pointer.",
        "Content surfaces sit at --elevation-0 and separate by fill. No shadow on a card at rest.",
        "Menus, popovers, dialogs, sheets and toasts sit at --elevation-3 with the raised material.",
        "In the light theme the shadow carries the height. Light shadows take the navy of the ink, never black, which turns a white page gray.",
        "In the dark theme a higher surface is a lighter one: --bg, then --surface-1, then --glass-fill-raised.",
        "Frosted glass only for bars that float over content scrolling beneath them.",
        "Glass sits on the outermost surface only. Glass inside glass blurs only its parent and turns gray.",
        "No contrast added to a blur. It crushes the content beneath into gray.",
        "A scrim dims the page under a dialog or a sheet, and the page is out of reach until it closes.",
        "Layers stack in a fixed order, from sticky headers at the bottom to toasts at the top.",
        "z-index only from --layer-sticky, --layer-header, --layer-popover, --layer-dialog, --layer-toast. Never a value such as 1000 or 9999.",
        "A layer opened from inside another opens within it. A menu opened in a dialog shows above the dialog and closes first."
      ]
    },
    {
      "title": "Iconography",
      "path": "/foundations/iconography",
      "url": "https://design.werklist.com/foundations/iconography",
      "text": "https://design.werklist.com/agent/foundations/iconography",
      "summary": "Which icons to use, at what size and stroke, and when a word does the job better.",
      "version": "2.1.2",
      "kind": "foundation",
      "name": "Iconography",
      "purpose": "Icons name an action or an object where a word would take too much room. They come from one family, Lucide, on one grid, with a stroke set by their size.",
      "use": [
        "As the only label of an icon button, with a name and a tooltip, such as Search in a toolbar.",
        "To mark an action that repeats down a dense list, such as the remove button at the end of each candidate row."
      ],
      "avoid": [
        "Menu rows, headings, empty states and notification cards.",
        "An icon beside a word that says the same thing, such as a pencil before Edit.",
        "A second icon set, an emoji or a brand logo.",
        "A colored or gradient icon in navigation.",
        "A 12 px icon as the target of a button."
      ],
      "anatomy": [
        {
          "part": "Grid",
          "measure": "24 by 24"
        },
        {
          "part": "Caps and joins",
          "measure": "round"
        },
        {
          "part": "Stroke",
          "measure": "set by the size of the icon"
        },
        {
          "part": "Color",
          "measure": "the ink of its label",
          "token": "currentColor"
        }
      ],
      "sizes": [
        {
          "name": "12 px, information only",
          "height": "12 px, stroke 2"
        },
        {
          "name": "14 px, beside 12 and 13 px text",
          "height": "14 px, stroke 2"
        },
        {
          "name": "16 px, beside 13 and 14 px text, the default",
          "height": "16 px, stroke 1.75"
        },
        {
          "name": "20 px, beside 16 px text",
          "height": "20 px, stroke 1.75"
        },
        {
          "name": "24 px, navigation rail and mobile bar",
          "height": "24 px, stroke 1.5"
        }
      ],
      "states": [
        {
          "name": "At rest",
          "change": "the ink of its label",
          "tokens": [
            "--text"
          ]
        },
        {
          "name": "Other items in navigation",
          "change": "the lighter ink",
          "tokens": [
            "--text-muted"
          ]
        },
        {
          "name": "Current or pressed",
          "change": "the full ink and a stroke 0.25 heavier",
          "tokens": [
            "--text"
          ]
        }
      ],
      "accessibility": [
        "An icon only control has a name, such as Remove candidate, and shows the same words in a tooltip.",
        "An icon beside a label that says the same thing is hidden from screen readers.",
        "An icon that carries meaning outside a control, such as a warning beside a CV that did not upload, has a text alternative.",
        "An icon keeps 3 to 1 against its ground in both themes. The lighter ink measures 4.74 to 1 on white.",
        "A state shows by shape as well as color.",
        "On touch screens the target around an icon is 44 by 44 px, whatever the size of the icon."
      ],
      "tokens": [
        "--text",
        "--text-muted",
        "--space-2"
      ],
      "rules": [
        "Icons come from Lucide. A shape Lucide lacks is drawn on the same grid, at the same stroke, in one color.",
        "The icon box is 4 to 6 px smaller than the line height of the text beside it.",
        "Between an icon and its label: 8 px.",
        "The stroke gets lighter as the icon grows, so each size reads at the same weight.",
        "One icon per action on every screen, by its Lucide name: Close is x, Confirm or selected is check, Add is plus, Delete is trash-2, Edit is pencil, Search is search, Copy is copy, Download is download, Share is share-2, More actions is ellipsis, Open or expand is chevron-down, Go to is chevron-right, Open in a new tab is external-link, Attach is paperclip, Undo is undo-2, Retry is rotate-ccw, Warning is triangle-alert, Loading is loader-circle, WerkAI is sparkles.",
        "Sparkles belongs to WerkAI alone.",
        "In one navigation group, neighbors do not share a silhouette.",
        "In navigation the current item takes the full ink and the others the lighter ink. Color on a glyph is kept for a verdict, such as a green check or a red cross."
      ]
    },
    {
      "title": "Motion",
      "path": "/foundations/motion",
      "url": "https://design.werklist.com/foundations/motion",
      "text": "https://design.werklist.com/agent/foundations/motion",
      "summary": "How long things move, on which curve, and what stops when a reader asks for less motion.",
      "version": "2.1.2",
      "kind": "foundation",
      "name": "Motion",
      "purpose": "Motion shows what changed and where it went, in 100 to 300 ms on two curves, and movement stops for readers who ask for less motion.",
      "anatomy": [
        {
          "part": "Instant duration: the pressed state, a tooltip leaving",
          "measure": "100 ms",
          "token": "--duration-instant"
        },
        {
          "part": "Fast duration: hover, focus, fill and color changes",
          "measure": "150 ms",
          "token": "--duration-fast"
        },
        {
          "part": "Base duration: menus, popovers, a new page, a card lifting",
          "measure": "200 ms",
          "token": "--duration-base"
        },
        {
          "part": "Slow duration: dialogs, sheets, the header condensing, a section opening",
          "measure": "300 ms",
          "token": "--duration-slow"
        },
        {
          "part": "Standard curve: movement within the screen, exits",
          "measure": "cubic-bezier(0.4, 0, 0.2, 1)",
          "token": "--ease-standard"
        },
        {
          "part": "Soft curve: entrances",
          "measure": "cubic-bezier(0, 0, 0.2, 1)",
          "token": "--ease-soft"
        },
        {
          "part": "Rise of a menu, a dialog or a new row",
          "measure": "8 px"
        },
        {
          "part": "Stagger",
          "measure": "40 ms pause, 45 ms between rows, 280 ms per row"
        },
        {
          "part": "Page change",
          "measure": "fades in and slides 20 px in 200 ms"
        },
        {
          "part": "Spring, the current item sliding in navigation",
          "measure": "stiffness 700, damping 38, mass 0.5"
        },
        {
          "part": "Spring, a tap on a navigation item",
          "measure": "stiffness 560, damping 32, mass 0.6"
        },
        {
          "part": "Spring, a value changing in place",
          "measure": "stiffness 480, damping 38, mass 0.9"
        }
      ],
      "states": [
        {
          "name": "Reduced motion",
          "change": "only the loading icon keeps moving. Springs jump to their end, no stagger or page slide. Fades and color changes stay at 150 ms.",
          "tokens": [
            "--duration-fast"
          ]
        },
        {
          "name": "Theme change",
          "change": "instant"
        }
      ],
      "accessibility": [
        "Under reduced motion, only the loading icon keeps moving and fades stay. The WerkAI caret stops blinking.",
        "Motion is not the only signal. A saved change also says Saved, and new content is announced to screen readers."
      ],
      "tokens": [
        "--duration-instant",
        "--duration-fast",
        "--duration-base",
        "--duration-slow",
        "--ease-standard",
        "--ease-soft"
      ],
      "rules": [
        "Animate a change the reader could otherwise miss: a menu opening, a row arriving in a list, a panel sliding in. No motion that only decorates.",
        "Nothing moves on the first paint. Motion starts when the reader acts or new content arrives.",
        "Hover and focus change fill and ink. A card lifts 1 px at most.",
        "No single movement lasts longer than 300 ms. A staggered list takes longer as a whole, and a loop that shows work in progress keeps running.",
        "Entrances use the soft curve. Movement within the screen and exits use the standard curve, one duration step shorter than the entrance.",
        "A menu enters in 200 ms and leaves in 150 ms.",
        "Linear timing only for rotation, as in the loading icon. No bounce and no overshoot.",
        "Where a gesture drives the motion, WerkOS uses springs. Each settles within 250 ms with no visible overshoot.",
        "Where a spring cannot be used, take the nearest duration on the soft curve.",
        "Menus, popovers and dialogs fade in and rise 8 px. They fade out in place.",
        "Rows arriving after the page has loaded enter one after another. Rows after the sixth arrive with it, so a long list does not trickle in.",
        "Animate opacity and position. A size animates only when a section opens or closes in place. No width that animates in a line of text."
      ]
    },
    {
      "title": "Accessibility",
      "path": "/foundations/accessibility",
      "url": "https://design.werklist.com/foundations/accessibility",
      "text": "https://design.werklist.com/agent/foundations/accessibility",
      "summary": "The rules a screen meets before it ships: contrast, focus, keyboard, target size, zoom, names and motion.",
      "version": "2.1.2",
      "kind": "foundation",
      "name": "Accessibility",
      "purpose": "The minimum a Werklist screen meets for contrast, focus, keyboard, target size, zoom, names, structure and motion, in both themes.",
      "anatomy": [
        {
          "part": "Focus ring color",
          "token": "--focus-ring",
          "measure": "light #1863dc, dark #7fb3ff"
        },
        {
          "part": "Focus ring width",
          "token": "--focus-ring-width",
          "measure": "2px in both themes"
        },
        {
          "part": "Focus ring gap",
          "token": "--focus-ring-offset",
          "measure": "2px in both themes"
        },
        {
          "part": "Touch target",
          "measure": "44 by 44 px under @media (pointer: coarse)"
        },
        {
          "part": "Mouse and trackpad target",
          "measure": "24 by 24 px under @media (pointer: fine)"
        },
        {
          "part": "Body text",
          "measure": "16 px"
        },
        {
          "part": "Caption, the smallest text",
          "measure": "13 px"
        },
        {
          "part": "Editable text on a touch screen",
          "measure": "16 px minimum"
        }
      ],
      "keys": [
        {
          "key": "Tab, Shift+Tab",
          "action": "Next or previous control"
        },
        {
          "key": "Enter",
          "action": "Follow a link, press a button, submit a form"
        },
        {
          "key": "Space",
          "action": "Press a button, check a checkbox, turn a switch on or off"
        },
        {
          "key": "Arrow keys",
          "action": "Move inside a group, such as tabs or a menu"
        },
        {
          "key": "Home, End",
          "action": "First or last item of a menu or a list"
        },
        {
          "key": "Escape",
          "action": "Close the front menu, popover or dialog and return focus"
        }
      ],
      "rules": [
        "Text meets 4.5 to 1 against what is behind it in both themes. A large heading gets no lower floor.",
        "The one exception is the word on a status chip: 3.5 to 1 on its tint, so the ink can keep the hue of its chip.",
        "Icons that carry meaning, the focus ring and chart marks meet 3 to 1.",
        "Check every pair in both themes: white text on --brand-blue reads 5.44 to 1 in light and 3.67 to 1 in dark.",
        "Color is paired with a word, an icon or a shape: a status has its word, an error its message and icon, a chart series its label.",
        "Links in running text are underlined: --brand-ink against --text is 2.36 to 1 in light and 2.72 to 1 in dark.",
        "The focus ring appears on :focus-visible and is removed only when something as visible replaces it.",
        "A control that takes focus is never hidden under the sticky header.",
        "Focus is drawn as an outline, not a shadow: in forced colors the browser keeps outlines and drops shadows. The gap keeps a blue ring off a blue button.",
        "Everything a pointer can do, a keyboard can do, and a swipe always has a button that does the same.",
        "Focus moves in reading order. When a menu or a dialog closes, focus returns to the control that opened it.",
        "The first stop on a page is a link that skips to the main content.",
        "Zoom is never turned off with maximum-scale or user-scalable=no.",
        "At 320 px wide the page reflows into one column with no sideways scrolling. Text enlarged to 200 percent does not clip or overlap.",
        "A page has one h1, and its headings descend in order. The header, the navigation, the main content and the footer are landmarks.",
        "Each control has a name a screen reader announces. A count joins that name, as in \"Notifications, 3 unread\", and the number itself is hidden from the reader.",
        "A change announced while focus stays put uses a polite live region. An error that stops the task uses an alert.",
        "With reduced motion, slides and scales become instant and fades stay.",
        "Nothing a person has to read or act on disappears on a timer. A message with an action stays until it is dismissed.",
        "A field has visible text above it as its label, never only a placeholder.",
        "An action shown on hover is shown on focus too."
      ]
    },
    {
      "title": "Writing",
      "path": "/foundations/writing",
      "url": "https://design.werklist.com/foundations/writing",
      "text": "https://design.werklist.com/agent/foundations/writing",
      "summary": "How Werklist sounds, the rules for each sentence, and the words to use and to leave out.",
      "version": "2.1.2",
      "kind": "foundation",
      "name": "Writing",
      "purpose": "Sets the voice, the sentence rules, punctuation and case, the words to use and the glossary for everything Werklist publishes.",
      "rules": [
        "Be direct. Tell the reader what happens, in the imperative where it fits: Send the offer.",
        "Earn trust with specifics: a date, a figure, the name of a document.",
        "Leave out hype: no superlatives, no exclamation marks and no emoji in the product.",
        "Keep a sentence only if the reader would lose a fact, a rule or an example without it.",
        "Give each sentence a subject that acts. A recruiter, a candidate and an employer act. A solution or an experience does not.",
        "Name the thing, not its category: a work permit, not documentation.",
        "Write to the reader, in the present tense and the active voice.",
        "Do not stack three adjectives or three fragments for rhythm. Use a number when the reader needs it, not for effect.",
        "Leave out we. The offer did not load, not We could not load the offer.",
        "Do not point by position. Above, below and on the left mean nothing to a screen reader or on a phone.",
        "Sentence case for headings, buttons, labels and navigation.",
        "No dash as punctuation. Split the sentence in two, or join the parts with and, so, because or then. Write ranges with to.",
        "Hyphenate a compound only before a noun (end-to-end placement, sign-in page). Leave it open elsewhere (end to end, sign in).",
        "End a sentence with a full stop. Leave it off headings, labels and buttons. No exclamation marks, and no question as a heading.",
        "Flow words: Continue to go on, Done to finish, Cancel to leave without a change. A destructive button names the act.",
        "Leave out advertising words such as seamless or world-class. AI-powered only when naming WerkAI.",
        "Prefer the words of the trade, such as placement and work permit.",
        "Write in English. Screens people outside Werklist open, such as a booking link, also come in Croatian and Serbian. Trade terms such as shortlist and onboarding stay in English.",
        "One name for one thing: WerkOS (not the app, the hub or the CRM), WerkAI, board grid, report table, light theme and dark theme (not mode, not skin), email, color."
      ],
      "content": [
        "Button: a verb and its object, not OK or Submit. Send offer.",
        "Link: where it goes, not Click here. Read the usage terms.",
        "Error: what happened and what to do, in one calm sentence. The offer did not load. Try again.",
        "Error in a field: how to fix it, next to the field. Use the name as it appears on the passport.",
        "Empty state: one sentence and the next action. No documents yet. Upload a document.",
        "Label: a noun in sentence case, with no colon. Start date.",
        "Placeholder: an example of the format, not the label. name@company.com.",
        "Setting: what it does when it is on. Email me when a work permit is approved.",
        "Permission request: what the access is for, when it is needed, then Continue. Werkcall uses your camera and microphone for the interview.",
        "Unavailable: say so plainly. Not available in this workspace.",
        "Destructive action: name the act on the button, not Yes. Delete board."
      ]
    },
    {
      "title": "Design tokens",
      "path": "/foundations/tokens",
      "url": "https://design.werklist.com/foundations/tokens",
      "text": "https://design.werklist.com/agent/foundations/tokens",
      "summary": "The three token files, how they switch between light and dark, and how to write a token in code.",
      "version": "2.1.2",
      "kind": "foundation",
      "name": "Design tokens",
      "purpose": "Named values for color, shadow, curve and layout that resolve per theme, offered as a CSS file, a JSON file and a print file.",
      "use": [
        "Style through var(--token), so the value follows the theme.",
        "Link werklist-tokens.css in a web page and write data-theme on the root element, light included.",
        "Read werklist-tokens.json in a design tool or a script: $value is the light value, and $extensions[\"com.werklist.mode\"] holds the dark value as well.",
        "Use werklist-tokens.print.css for anything printed: light values only, no glass, no shadow."
      ],
      "avoid": [
        "Copying a value from the JSON file into code: it keeps one value when the theme changes.",
        "Naming a new token for how it looks, such as --light-grey: the name stops being true in the dark theme.",
        "Editing your copy of a token file: take the files as they are published, so every screen reads the same values.",
        "Using a token that belongs to one part of the product, such as --chat-bubble-own, anywhere else."
      ],
      "tokens": [
        "--bg",
        "--surface-1",
        "--text",
        "--brand-true",
        "--brand-ink"
      ],
      "rules": [
        "In the CSS file, dark values stand on :root and light values on html[data-theme=\"light\"]. Without data-theme the file gives the dark values. WerkOS always writes the attribute and opens in light.",
        "A token that is the same in both themes, such as --brand-true, is declared once, on :root.",
        "The tokens a screen is built from are named for their job, not their look: --surface-control, not --light-grey.",
        "Page: background takes var(--bg).",
        "Panel: background takes var(--surface-1).",
        "Band: background takes var(--surface-2).",
        "Nested box: background takes var(--surface-strong).",
        "Control fill: background takes var(--surface-control).",
        "Scrim: background takes var(--overlay).",
        "Body text: color takes var(--text).",
        "Supporting text: color takes var(--text-muted).",
        "Labels: color takes var(--text-label).",
        "Blue text: color takes var(--brand-ink).",
        "Edge of a control: border-color takes var(--border).",
        "Row rule: border-color takes var(--border-rule).",
        "Marks: background takes var(--brand-blue).",
        "Button fill: background takes var(--brand-true).",
        "Text on the button fill: color takes var(--on-brand).",
        "Status fills: background takes var(--success), var(--warning) or var(--error).",
        "Status inks: color takes var(--success-ink), var(--warning-ink) or var(--error-ink)."
      ]
    },
    {
      "title": "Button",
      "path": "/components/button",
      "url": "https://design.werklist.com/components/button",
      "text": "https://design.werklist.com/agent/components/button",
      "summary": "A button starts an action on the screen you are on, from sending an offer to deleting a CV.",
      "version": "2.1.2",
      "kind": "component",
      "name": "Button",
      "purpose": "Starts an action on the current screen, such as saving a form or sending an offer.",
      "use": [
        "The result happens on this screen, such as a save or a dialog that opens.",
        "Primary for the one action per surface (page, dialog, sheet, panel) that moves the task forward.",
        "Secondary beside a primary, or for the main action when none leads.",
        "Quiet for frequent minor actions in toolbars and rows.",
        "Outline for an action that sits among fields, such as Add filter beside a search field: it has the fill of a text field.",
        "Danger for the confirming button of a destructive step, inside its confirmation.",
        "Danger quiet for a destructive action among other actions. It leads to a confirmation or offers undo.",
        "Toggle: a quiet button with aria-pressed, for filters and view options in a toolbar.",
        "Menu button: a chevron after the label and aria-haspopup menu, for a family of at least three related actions.",
        "A call to action that opens another page: a link drawn as a button."
      ],
      "avoid": [
        "Navigation in running text: use Link.",
        "A second primary button on the same surface.",
        "A primary button in a table or list row.",
        "A danger button as the default of a form or a dialog, or with initial focus.",
        "Quiet, outline or danger quiet over a picture.",
        "A setting that persists: use Switch.",
        "Choosing one option from several: use Select or Segmented control.",
        "A label that wraps, truncates or has no verb.",
        "Two icons in one button, except the start icon and chevron of a menu button."
      ],
      "anatomy": [
        {
          "part": "Container",
          "measure": "height 36, 44 or 48 px, minimum width equal to the height, radius 8 px, as wide as its content",
          "token": "--radius-lg"
        },
        {
          "part": "Side padding",
          "measure": "12, 16 or 20 px",
          "token": "--space-3, --space-4, --space-5"
        },
        {
          "part": "Label",
          "measure": "one line, no wrap, no truncation. 13 px on 20 px at small, 14 px on 20 px at medium and large, weight 500",
          "token": "--type-caption, --type-nav"
        },
        {
          "part": "Icon",
          "measure": "16 px, at most one, at the start or the end, 8 px from the label, currentColor",
          "token": "--space-2"
        },
        {
          "part": "Spinner",
          "measure": "16 px, one turn per second, replaces the start icon or sits over the transparent label, appears after 300 ms",
          "token": "--duration-slow"
        },
        {
          "part": "Focus ring",
          "measure": "outline 2 px, offset 2 px",
          "token": "--focus-ring, --focus-ring-width, --focus-ring-offset"
        },
        {
          "part": "Touch target",
          "measure": "44 px on coarse pointers, the small size extending its hit area 4 px above and below",
          "token": ""
        },
        {
          "part": "Group",
          "measure": "8 px between buttons, the primary at the trailing end. Below 640 px a form or dialog ends in a full width stack with the primary on top",
          "token": "--space-2"
        }
      ],
      "variants": [
        {
          "name": "primary",
          "use": "The one action per surface that moves the task forward."
        },
        {
          "name": "secondary",
          "use": "Cancel beside a primary, or the main action when none leads."
        },
        {
          "name": "quiet",
          "use": "Frequent minor actions in toolbars and rows. The only variant that toggles."
        },
        {
          "name": "outline",
          "use": "An action among fields, with the fill of a text field."
        },
        {
          "name": "danger",
          "use": "The confirming button of a destructive step, inside its confirmation."
        },
        {
          "name": "danger-quiet",
          "use": "A destructive action among others, leading to a confirmation or undo."
        }
      ],
      "sizes": [
        {
          "name": "sm",
          "height": "36 px",
          "padding": "0 12 px",
          "type": "13 px on 20 px, weight 500"
        },
        {
          "name": "md",
          "height": "44 px",
          "padding": "0 16 px",
          "type": "14 px on 20 px, weight 500"
        },
        {
          "name": "lg",
          "height": "48 px",
          "padding": "0 20 px",
          "type": "14 px on 20 px, weight 500"
        }
      ],
      "states": [
        {
          "name": "rest",
          "change": "Primary: brand blue fill and white label in both themes. Secondary: gray fill and text ink. Quiet: no fill and muted ink. Outline: the field material. In dark that is --glass-fill-input with an inset 1 px --input-border edge and --glass-ring, in light the 5 percent ink wash of --glass-fill-hover with no edge. Danger: --error in light and --badge-alert in dark, white label. Danger quiet: no fill and --error ink.",
          "tokens": [
            "--brand-true",
            "--on-brand",
            "--surface-control",
            "--text",
            "--text-muted",
            "--glass-fill-input",
            "--input-border",
            "--glass-ring",
            "--glass-fill-hover",
            "--badge-alert",
            "--error"
          ]
        },
        {
          "name": "hover",
          "change": "Primary darkens to --brand-blue-dark in light, and to the brand blue mixed 72 percent with --navy in dark. Danger drops to opacity 0.9. Secondary and outline lay --glass-fill-hover over their fill. Quiet gains --glass-fill-hover and text ink. Danger quiet gains --error at 10 percent. Only on a pointer that can hover.",
          "tokens": [
            "--brand-blue-dark",
            "--navy",
            "--glass-fill-hover",
            "--error"
          ]
        },
        {
          "name": "pressed",
          "change": "The hover paint, on touch too, and a scale of 0.98 over 150 ms unless motion is reduced.",
          "tokens": [
            "--duration-fast",
            "--ease-standard"
          ]
        },
        {
          "name": "focus-visible",
          "change": "Outline 2 px at offset 2 px in the focus ring color. As an outline it survives forced colors mode.",
          "tokens": [
            "--focus-ring",
            "--focus-ring-width",
            "--focus-ring-offset"
          ]
        },
        {
          "name": "disabled",
          "change": "aria-disabled true on a focusable button, drawn at opacity 0.5 in the colors of its variant. Presses and implicit form submission are canceled, and hover does not apply. Contrast minimums do not apply to a disabled button. The reason is visible text, linked with aria-describedby.",
          "tokens": []
        },
        {
          "name": "loading",
          "change": "aria-busy and aria-disabled true at once, focus kept, presses ignored. After 300 ms a 16 px spinner in the label ink replaces the start icon, or sits centered over the label, which turns transparent. Width and label do not change. Under reduced motion the spinner fades between opacity 1 and 0.5 each second instead of turning.",
          "tokens": [
            "--duration-slow"
          ]
        },
        {
          "name": "toggle on",
          "change": "Quiet variant with aria-pressed true: --seg-selected fill and text ink. On hover --glass-fill-hover lies over it. In a board toolbar a pressed tool takes the brand tint instead (see Toolbar).",
          "tokens": [
            "--seg-selected",
            "--text",
            "--glass-fill-hover"
          ]
        },
        {
          "name": "menu open",
          "change": "aria-expanded true. The button holds its hover paint and the chevron turns 180 degrees in 150 ms, without the turn under reduced motion.",
          "tokens": [
            "--duration-fast"
          ]
        }
      ],
      "keys": [
        {
          "key": "Tab, Shift+Tab",
          "action": "Move focus in document order, disabled and loading buttons included."
        },
        {
          "key": "Enter",
          "action": "Press. On a menu button, open the menu with focus on the first item. On a button that opens a page, follow the link."
        },
        {
          "key": "Space",
          "action": "Press on release, flip a toggle, or open a menu button's menu. Not on a button that opens a page."
        },
        {
          "key": "Down arrow",
          "action": "On a menu button, open the menu with focus on the first item."
        },
        {
          "key": "Up arrow",
          "action": "On a menu button, open the menu with focus on the last item."
        },
        {
          "key": "Escape",
          "action": "Close an open menu and return focus to the menu button."
        }
      ],
      "accessibility": [
        "A native button element with type button, or type submit in a form. An a element with href when the button opens a page.",
        "The name is the visible label. Icons are aria-hidden.",
        "Label on fill at 4.5 to 1, icon and focus ring at 3 to 1, in every enabled state and both themes.",
        "Disabled and loading use aria-disabled, not the disabled attribute, so focus stays and the reason is reachable.",
        "States exposed with aria-pressed, aria-expanded, aria-haspopup, aria-busy, aria-disabled and aria-describedby.",
        "Targets of 44 px on coarse pointers.",
        "Forced colors: a 1 px ButtonText border, ButtonText on ButtonFace, the toggle on in Highlight, focus as an outline in Highlight."
      ],
      "content": [
        "A verb first, plus the object when the verb alone is vague: Send offer, Publish job, Add candidate.",
        "Two or three words, sentence case, no final period, no exclamation.",
        "Answer the question of the dialog: Delete CV and Cancel, not Yes and No.",
        "Cancel stops a task and keeps nothing. Close dismisses what changed nothing.",
        "No OK, no Submit, no ellipsis at the end.",
        "The label does not change while loading."
      ],
      "tokens": [
        "--brand-true",
        "--brand-blue-dark",
        "--navy",
        "--on-brand",
        "--surface-control",
        "--text",
        "--text-muted",
        "--glass-fill-hover",
        "--glass-fill-input",
        "--input-border",
        "--glass-ring",
        "--badge-alert",
        "--error",
        "--seg-selected",
        "--focus-ring",
        "--focus-ring-width",
        "--focus-ring-offset",
        "--radius-lg",
        "--space-2",
        "--space-3",
        "--space-4",
        "--space-5",
        "--type-caption",
        "--type-nav",
        "--duration-fast",
        "--duration-slow",
        "--ease-standard"
      ]
    },
    {
      "title": "Icon button",
      "path": "/components/icon-button",
      "url": "https://design.werklist.com/components/icon-button",
      "text": "https://design.werklist.com/agent/components/icon-button",
      "summary": "An icon button shows a familiar glyph in place of words, for actions like closing a panel or copying a link.",
      "version": "2.1.2",
      "kind": "component",
      "name": "IconButton",
      "purpose": "A button that shows a familiar glyph in place of words, named by a required label.",
      "use": [
        "An action whose glyph people read at once: close, search, copy, download, more actions, menu, the theme switch.",
        "Toolbars, headers and table rows where words would crowd the space.",
        "Quiet by default. Secondary for an action that must be found without pointing, such as copy beside a field.",
        "Toggle: a quiet icon button with aria-pressed, such as a details panel shown or hidden.",
        "A row action: one small More actions button that opens the row menu."
      ],
      "avoid": [
        "A glyph people would have to guess: use a button with words.",
        "A destructive action as a glyph alone, or a red glyph: use a confirmation or Undo.",
        "A glyph with a visible text label next to it: use a button with an icon before its label.",
        "Changing the label when a toggle turns on.",
        "A native title attribute as the tooltip."
      ],
      "anatomy": [
        {
          "part": "Box",
          "measure": "32, 40 or 44 px square, radius 8 px",
          "token": "--radius-lg"
        },
        {
          "part": "Glyph",
          "measure": "16 px in the small box, 20 px in the medium and large boxes, stroke 1.75 on a 24 unit grid, currentColor, aria-hidden",
          "token": ""
        },
        {
          "part": "Space from glyph to edge",
          "measure": "8, 10 or 12 px",
          "token": ""
        },
        {
          "part": "Tooltip",
          "measure": "The label, 8 px below the box, after 500 ms of pointer rest or at once on keyboard focus, never on touch. Hidden from screen readers, which read aria-label.",
          "token": ""
        },
        {
          "part": "Focus ring",
          "measure": "outline 2 px, offset 2 px",
          "token": "--focus-ring, --focus-ring-width, --focus-ring-offset"
        },
        {
          "part": "Touch target",
          "measure": "44 px on coarse pointers. Neighbors keep their centers at least 44 px apart and their boxes at least 4 px apart",
          "token": ""
        },
        {
          "part": "Counter",
          "measure": "drawn by the Counter component at the top trailing corner, digits aria-hidden, the count joined to the name",
          "token": ""
        }
      ],
      "variants": [
        {
          "name": "quiet",
          "use": "The default: no fill until hover, glyph in muted ink. The only variant that toggles."
        },
        {
          "name": "secondary",
          "use": "A gray fill, for an action that must be visible without pointing."
        }
      ],
      "sizes": [
        {
          "name": "sm",
          "height": "32 px",
          "padding": "8 px around a 16 px glyph"
        },
        {
          "name": "md",
          "height": "40 px",
          "padding": "10 px around a 20 px glyph"
        },
        {
          "name": "lg",
          "height": "44 px",
          "padding": "12 px around a 20 px glyph"
        }
      ],
      "states": [
        {
          "name": "rest",
          "change": "Quiet: no fill, glyph in muted ink. Secondary: gray fill, glyph in text ink.",
          "tokens": [
            "--text-muted",
            "--surface-control",
            "--text"
          ]
        },
        {
          "name": "hover",
          "change": "The hover fill over the ground or the gray fill, glyph in text ink. Only on a pointer that can hover.",
          "tokens": [
            "--glass-fill-hover",
            "--text"
          ]
        },
        {
          "name": "pressed",
          "change": "The hover fill, on touch too, and a scale of 0.94 unless motion is reduced.",
          "tokens": [
            "--duration-fast",
            "--ease-standard"
          ]
        },
        {
          "name": "focus-visible",
          "change": "Outline 2 px at offset 2 px in the focus ring color, and the tooltip shows.",
          "tokens": [
            "--focus-ring",
            "--focus-ring-width",
            "--focus-ring-offset"
          ]
        },
        {
          "name": "disabled",
          "change": "aria-disabled true, focusable, presses canceled, drawn at opacity 0.5 in the colors of its variant.",
          "tokens": []
        },
        {
          "name": "toggle on",
          "change": "aria-pressed true: --seg-selected fill, glyph in text ink. On hover --glass-fill-hover lies over it.",
          "tokens": [
            "--seg-selected",
            "--text",
            "--glass-fill-hover"
          ]
        }
      ],
      "keys": [
        {
          "key": "Tab, Shift+Tab",
          "action": "Move focus in document order, disabled icon buttons included."
        },
        {
          "key": "Enter, Space",
          "action": "Press, or flip aria-pressed on a toggle."
        },
        {
          "key": "Down arrow, Up arrow",
          "action": "On an icon button with aria-haspopup menu, open the menu at its first or last item."
        }
      ],
      "accessibility": [
        "A native button whose accessible name is its label.",
        "The glyph is aria-hidden. No title attribute is added.",
        "Glyph on fill at 3 to 1 and focus ring at 3 to 1 in every enabled state and both themes.",
        "The name does not change with the toggle state. aria-pressed carries the state.",
        "Targets of 44 px on coarse pointers.",
        "Forced colors: the glyph takes ButtonText, the toggle on state Highlight, focus an outline in Highlight."
      ],
      "content": [
        "The label is a verb and its object: Close panel, Copy link, More actions.",
        "The tooltip repeats the label word for word.",
        "A count joins the name: Notifications, 3 unread."
      ],
      "tokens": [
        "--text",
        "--text-muted",
        "--surface-control",
        "--glass-fill-hover",
        "--seg-selected",
        "--focus-ring",
        "--focus-ring-width",
        "--focus-ring-offset",
        "--radius-lg",
        "--duration-fast",
        "--ease-standard"
      ]
    },
    {
      "title": "Link",
      "path": "/components/link",
      "url": "https://design.werklist.com/components/link",
      "text": "https://design.werklist.com/agent/components/link",
      "summary": "A link takes the reader to another page, another place on the page or another site.",
      "version": "2.1.2",
      "kind": "component",
      "name": "Link",
      "purpose": "Takes the reader to another page, another place on the page or another site.",
      "use": [
        "The result is a new location: a page, an anchor on the page, a file, another site.",
        "In running text, on the words that name the destination.",
        "On a line of its own, such as a pointer to a related page.",
        "external, for another site: it opens a new tab, shows the external glyph, and a screen reader hears opens in a new tab."
      ],
      "avoid": [
        "An action on this screen (save, open a dialog, toggle): use Button, quiet if it should look light.",
        "A call to action that must look like a button: use a button that opens the page.",
        "Text such as Click here or Learn more.",
        "Linking a whole sentence or its punctuation.",
        "Two links with the same text to different places.",
        "A new tab for a link inside Werklist."
      ],
      "anatomy": [
        {
          "part": "Text",
          "measure": "the size, weight and line of the surrounding text",
          "token": ""
        },
        {
          "part": "Ink",
          "measure": "--brand-blue in light, --brand-ink in dark",
          "token": "--brand-blue, --brand-ink"
        },
        {
          "part": "Underline",
          "measure": "1 px, 2 px below the text, the ink at 30 percent at rest and at full strength on hover, on each line of a link that wraps",
          "token": ""
        },
        {
          "part": "External glyph",
          "measure": "the font size of the text, 4 px after it, not underlined, aria-hidden",
          "token": "--space-1"
        },
        {
          "part": "Focus ring",
          "measure": "outline 2 px, offset 2 px, around each line of a link that wraps",
          "token": "--focus-ring, --focus-ring-width, --focus-ring-offset"
        }
      ],
      "variants": [
        {
          "name": "default",
          "use": "All links. Navigation lists in the header, the footer and the left navigation are their own components."
        },
        {
          "name": "external",
          "use": "A link to another site: opens a new tab, shows the external glyph, and a screen reader hears opens in a new tab."
        }
      ],
      "states": [
        {
          "name": "rest",
          "change": "The link ink with an underline at 30 percent of the ink.",
          "tokens": [
            "--brand-blue",
            "--brand-ink"
          ]
        },
        {
          "name": "hover",
          "change": "The underline at full ink, in 150 ms. Only on a pointer that can hover.",
          "tokens": [
            "--brand-blue",
            "--brand-ink",
            "--duration-fast",
            "--ease-standard"
          ]
        },
        {
          "name": "focus-visible",
          "change": "Outline 2 px at offset 2 px in the focus ring color, around each line of the link.",
          "tokens": [
            "--focus-ring",
            "--focus-ring-width",
            "--focus-ring-offset"
          ]
        }
      ],
      "keys": [
        {
          "key": "Tab, Shift+Tab",
          "action": "Move focus in document order."
        },
        {
          "key": "Enter",
          "action": "Follow the link."
        },
        {
          "key": "Space",
          "action": "Scrolls the page. A link does not respond to it."
        }
      ],
      "accessibility": [
        "A native a element with href.",
        "The name is the link text. An external link adds opens in a new tab in a visually hidden span. No title attribute.",
        "Link ink at 4.5 to 1 on all grounds in both themes.",
        "A link is always underlined, so it does not depend on color alone.",
        "A long address wraps inside its column, down to a screen 360 px wide. The underline and the ring follow each line.",
        "Forced colors: LinkText, underline kept.",
        "Inline links in a sentence are exempt from the 44 px target. Links in a list sit on rows of 44 px on coarse pointers."
      ],
      "content": [
        "Link the words that name the destination. The text makes sense read alone.",
        "No Click here, no Learn more without its subject, no bare URL unless the address is the content.",
        "Punctuation stays outside the link.",
        "Sentence case."
      ],
      "tokens": [
        "--brand-blue",
        "--brand-ink",
        "--focus-ring",
        "--focus-ring-width",
        "--focus-ring-offset",
        "--space-1",
        "--duration-fast",
        "--ease-standard"
      ]
    },
    {
      "title": "Toolbar",
      "path": "/components/toolbar",
      "url": "https://design.werklist.com/components/toolbar",
      "text": "https://design.werklist.com/agent/components/toolbar",
      "summary": "A row of controls that act on what is under it, such as a board of candidates or an email you are writing.",
      "version": "2.1.2",
      "kind": "component",
      "name": "Toolbar",
      "purpose": "A named row of controls that act on the view under it, kept on one line by moving controls behind More in a declared order.",
      "use": [
        "Board toolbars: views, search, filters, the add action.",
        "Formatting bars in editors and composers.",
        "Selection bars that act on chosen rows."
      ],
      "avoid": [
        "Navigation between places: header, side navigation, tabs.",
        "Rarely used settings in the row: put them behind More or in settings.",
        "A title or a hero above the toolbar or inside it: a view starts at its toolbar."
      ],
      "anatomy": [
        {
          "part": "Container",
          "measure": "role toolbar with aria-label. No fill of its own. It stands on the frame of a board (--surface-1) or the well of a composer.",
          "token": ""
        },
        {
          "part": "Control",
          "measure": "Labeled controls are small buttons, 36 px high. Icon only controls are small icon buttons, 32 px, centered on the row. Both are drawn at 44 px on coarse pointers.",
          "token": "--radius-lg"
        },
        {
          "part": "Label and icon",
          "measure": "13 px, weight 500. Icon 16 px, 8 px before the label.",
          "token": ""
        },
        {
          "part": "Gap",
          "measure": "8 px between controls, 6 px below 640 px",
          "token": "--space-2"
        },
        {
          "part": "Groups",
          "measure": "At most three, in order: leading (the view switch), tools, trailing (the one add action, right after the tools). The room left over stays at the end of the row.",
          "token": ""
        },
        {
          "part": "Divider",
          "measure": "1 by 20 px, only between groups of icon only controls, aria-hidden",
          "token": "--border"
        },
        {
          "part": "Search field",
          "measure": "Outside the group of arrow keys, with its own Tab stop. At least 200 px, 320 px when there is room.",
          "token": ""
        },
        {
          "part": "More",
          "measure": "36 px, the More icon and the count. The count is aria-hidden and joins the name: More, 2.",
          "token": ""
        }
      ],
      "states": [
        {
          "name": "Rest, board",
          "change": "Tools: quiet buttons on the --glass-fill-hover fill, in --text-muted ink",
          "tokens": [
            "--glass-fill-hover",
            "--text-muted"
          ]
        },
        {
          "name": "Rest, formatting",
          "change": "No fill, --text-muted ink",
          "tokens": [
            "--text-muted"
          ]
        },
        {
          "name": "Hover",
          "change": "--text ink. In a formatting bar the tool also takes --glass-fill-hover. Only on a pointer that can hover.",
          "tokens": [
            "--glass-fill-hover",
            "--text"
          ]
        },
        {
          "name": "Pressed, board tool",
          "change": "aria-pressed true: --brand-blue at 15 percent as the fill, --brand-ink as the ink",
          "tokens": [
            "--brand-blue",
            "--brand-ink"
          ]
        },
        {
          "name": "View in use, board",
          "change": "aria-pressed true in the leading group: --surface-control fill, --text ink",
          "tokens": [
            "--surface-control",
            "--text"
          ]
        },
        {
          "name": "Pressed, formatting",
          "change": "aria-pressed true: --seg-selected fill, --text ink",
          "tokens": [
            "--seg-selected",
            "--text"
          ]
        },
        {
          "name": "Focus",
          "change": "2 px ring, 2 px offset",
          "tokens": [
            "--focus-ring"
          ]
        },
        {
          "name": "Unavailable",
          "change": "aria-disabled true, opacity 0.5. It stays in place and in the group.",
          "tokens": []
        },
        {
          "name": "Behind More",
          "change": "The control waits in the row that More opens and keeps its state.",
          "tokens": []
        }
      ],
      "keys": [
        {
          "key": "Tab",
          "action": "Enters the toolbar at the last used control. The next Tab leaves it."
        },
        {
          "key": "Left arrow, Right arrow",
          "action": "Previous or next control"
        },
        {
          "key": "Home, End",
          "action": "First or last control"
        },
        {
          "key": "Enter, Space",
          "action": "Uses the control"
        },
        {
          "key": "Down arrow",
          "action": "Opens a menu control"
        }
      ],
      "accessibility": [
        "role toolbar with aria-label naming what it acts on.",
        "The controls share one Tab stop and the arrow keys move between them. The search field has a Tab stop of its own.",
        "Icon only controls: aria-label and a tooltip with the same words.",
        "Toggles: aria-pressed.",
        "More: aria-expanded and a name that includes the count."
      ],
      "content": [
        "Labels are short verbs or nouns in sentence case, no end punctuation: Filter, Group by, Export, Add candidate.",
        "The add action names what it adds: Add candidate, Add task."
      ],
      "rules": [
        "Each toolbar declares the order in which its controls give way. The view switch, the search and the add action never give way.",
        "A control comes back once there is clear room for it.",
        "A toolbar responds to the room it has, so opening a side panel can move controls behind More.",
        "A toolbar does not wrap and does not scroll sideways. A formatting toolbar may wrap below 640 px.",
        "Destructive actions in their own group."
      ],
      "tokens": [
        "--radius-lg",
        "--space-2",
        "--border",
        "--glass-fill-hover",
        "--text",
        "--text-muted",
        "--brand-ink",
        "--surface-control",
        "--seg-selected",
        "--brand-blue",
        "--focus-ring"
      ]
    },
    {
      "title": "Field",
      "path": "/components/field",
      "url": "https://design.werklist.com/components/field",
      "text": "https://design.werklist.com/agent/components/field",
      "summary": "The label, hint and error around a form control, and how required, read only and disabled fields behave.",
      "version": "2.1.2",
      "kind": "component",
      "name": "Field",
      "purpose": "Wraps one form control with its label, hint and message, and connects them for assistive technology.",
      "use": [
        "Around each text field, text area, select, combobox, date field and time field in a form",
        "Around radio buttons or checkboxes that answer one question, as a fieldset with a legend"
      ],
      "avoid": [
        "A search field in a toolbar: it has no visible label, and its placeholder gives its name",
        "A label beside the control: the label always sits above it"
      ],
      "anatomy": [
        {
          "part": "Label",
          "measure": "13 px on 18 px, weight 500",
          "token": "--text"
        },
        {
          "part": "Required word",
          "measure": "(required) after the label, 13 px on 18 px, weight 400, hidden from screen readers",
          "token": "--text-muted"
        },
        {
          "part": "Count",
          "measure": "11 px on 16 px, aligned figures, at the end of the label row, written 412/500 and read as 412 of 500 characters",
          "token": "--text-muted"
        },
        {
          "part": "Label to control",
          "measure": "6 px"
        },
        {
          "part": "Control",
          "measure": "described on the page of each control"
        },
        {
          "part": "Control to message",
          "measure": "4 px",
          "token": "--space-1"
        },
        {
          "part": "Hint",
          "measure": "12 px on 16 px, weight 400",
          "token": "--text-muted"
        },
        {
          "part": "Error",
          "measure": "12 px on 16 px, no icon",
          "token": "--error"
        },
        {
          "part": "Warning",
          "measure": "12 px on 16 px, no icon",
          "token": "--warning-ink"
        },
        {
          "part": "Between fields",
          "measure": "16 px",
          "token": "--space-4"
        },
        {
          "part": "Between groups",
          "measure": "32 px",
          "token": "--space-8"
        },
        {
          "part": "Form column",
          "measure": "at most 768 px"
        }
      ],
      "states": [
        {
          "name": "Required",
          "change": "(required) follows the label, and the control carries aria-required=\"true\"",
          "tokens": [
            "--text-muted"
          ]
        },
        {
          "name": "Error",
          "change": "The error replaces the hint, the control takes a 2 px edge in the error colour and aria-invalid=\"true\", and the form is not sent",
          "tokens": [
            "--error"
          ]
        },
        {
          "name": "Warning",
          "change": "The warning replaces the hint, and the form can be sent",
          "tokens": [
            "--warning-ink"
          ]
        },
        {
          "name": "Read only",
          "change": "No fill, no ring and no side padding, with the value in full ink. It takes focus and is sent with the form",
          "tokens": [
            "--text"
          ]
        },
        {
          "name": "Disabled",
          "change": "The control fades to 50 percent, Tab skips it and it is not sent. The label and the hint keep their ink, and the hint says what turns it on"
        }
      ],
      "keys": [
        {
          "key": "Tab",
          "action": "Moves to the next control in the order the form shows them"
        }
      ],
      "accessibility": [
        "A label element whose for attribute points at the control's id",
        "aria-describedby lists the message while one shows, otherwise the hint, and the count where there is one",
        "aria-invalid=\"true\" while an error shows",
        "aria-required=\"true\" on a required control. The visible word is hidden from screen readers so it is not read twice",
        "A message carries no role=\"alert\". It is read when the control takes focus",
        "After a failed submit, focus moves as the Forms pattern describes, at /patterns/forms",
        "A field you type in shows focus with a blue ring and a halo. A combobox is a button that opens a list and shows focus as a button does, with a blue outline outside its edge",
        "A fieldset and a legend for controls that answer one question together",
        "Labels wrap and are not cut short"
      ],
      "content": [
        "Label: a noun phrase in sentence case with no colon and no full stop, such as Date of birth",
        "Hint: one sentence about the answer, ending with a full stop",
        "Error: the fix, in the words of the label, ending with a full stop, such as Enter the passport number. It never blames the person",
        "Placeholder: an example of the format only, never the label",
        "When every field is required: one sentence above the form, All fields are required, and no marks"
      ],
      "tokens": [
        "--text",
        "--text-muted",
        "--error",
        "--warning-ink",
        "--space-1",
        "--space-4",
        "--space-8"
      ],
      "rules": [
        "Check a format when the person leaves the field, and only when it holds a value",
        "Check required answers when the form is sent, and show every error at once",
        "Once an error shows, check again on each key so it clears at once",
        "Check an answer that depends on the server while the person types. The hint reads Checking until the answer comes back",
        "The form uses its own messages, never the browser's"
      ]
    },
    {
      "title": "Text field",
      "path": "/components/text-field",
      "url": "https://design.werklist.com/components/text-field",
      "text": "https://design.werklist.com/agent/components/text-field",
      "summary": "One line of text, from a name to an amount, with the keyboard, autofill and states each answer needs.",
      "version": "2.1.2",
      "kind": "component",
      "name": "TextField",
      "purpose": "Takes one line of typed text inside a Field.",
      "use": [
        "Names, email addresses, phone numbers, IDs, amounts and any short answer the person types"
      ],
      "avoid": [
        "Up to five known answers with room to show them: use radio buttons",
        "More known answers: use a select or a combobox",
        "More than one line: use a text area",
        "Amounts with type=\"number\": use type=\"text\" with inputmode=\"decimal\""
      ],
      "anatomy": [
        {
          "part": "Height, medium",
          "measure": "44 px"
        },
        {
          "part": "Height, large",
          "measure": "48 px"
        },
        {
          "part": "Corner radius",
          "measure": "8 px",
          "token": "--radius-lg"
        },
        {
          "part": "Side padding",
          "measure": "12 px",
          "token": "--space-3"
        },
        {
          "part": "Value",
          "measure": "14 px on 20 px, weight 400, and 16 px on 22 px on a touch screen",
          "token": "--text"
        },
        {
          "part": "Placeholder",
          "measure": "the size of the value",
          "token": "--text-muted"
        },
        {
          "part": "Fill",
          "measure": "ink at 5 percent in light, white at 4 percent in dark, with a frosted backdrop in dark",
          "token": "--glass-fill-input"
        },
        {
          "part": "Edge",
          "measure": "none in light, a 1 px ring inside the edge in dark",
          "token": "--input-border"
        },
        {
          "part": "Leading icon",
          "measure": "16 px, 12 px from the start, with the text starting at 36 px",
          "token": "--text-muted"
        },
        {
          "part": "Trailing slot",
          "measure": "an icon button of 32 px, 6 px from the end, or a unit in 14 px text, 12 px from the end",
          "token": "--text-muted"
        }
      ],
      "sizes": [
        {
          "name": "md",
          "height": "44 px",
          "padding": "0 12 px",
          "type": "14 px on 20 px"
        },
        {
          "name": "lg",
          "height": "48 px",
          "padding": "0 12 px",
          "type": "14 px on 20 px"
        },
        {
          "name": "compact",
          "height": "36 px with a mouse and 44 px on a touch screen, for toolbars and the search field",
          "padding": "0 12 px",
          "type": "14 px on 20 px"
        }
      ],
      "states": [
        {
          "name": "Rest",
          "change": "The fill, and in dark the 1 px inner ring",
          "tokens": [
            "--input-border",
            "--glass-ring"
          ]
        },
        {
          "name": "Hover",
          "change": "No change"
        },
        {
          "name": "Focus",
          "change": "In light the fill turns white, with a 1 px inner ring of the brand blue at 50 percent and a 3 px halo at 16 percent. In dark the fill is white at 6 percent, the ring is at 55 percent and the halo is 4 px at 18 percent. The change takes 150 ms",
          "tokens": [
            "--brand-blue",
            "--duration-fast",
            "--ease-standard"
          ]
        },
        {
          "name": "Error",
          "change": "A 2 px edge in the error colour, and aria-invalid=\"true\"",
          "tokens": [
            "--error"
          ]
        },
        {
          "name": "Read only",
          "change": "No fill, no ring and no side padding, in full ink. It takes focus, with the focus ring outside it",
          "tokens": [
            "--text",
            "--focus-ring"
          ]
        },
        {
          "name": "Disabled",
          "change": "Fades to 50 percent and shows the not allowed cursor"
        },
        {
          "name": "Autofilled",
          "change": "Keeps its own fill and ink. The browser's autofill tint does not show",
          "tokens": [
            "--text"
          ]
        }
      ],
      "keys": [
        {
          "key": "Tab",
          "action": "Next field"
        },
        {
          "key": "Enter",
          "action": "Sends the form"
        }
      ],
      "accessibility": [
        "Named by the Field label. A field without a visible label carries the words of its placeholder as its name",
        "At least 44 px high on a touch screen, with editable text of at least 16 px",
        "The page never locks zoom",
        "In forced colours the field draws a 1 px outline, and 2 px with focus or an error"
      ],
      "content": [
        "The input type is email, tel, url or password where it applies, and an amount takes the decimal keyboard",
        "Personal data carries a standard autocomplete token, such as name, email, tel or organization",
        "Autocomplete is off only on a field that holds no personal data, such as a filter",
        "On a phone the Enter key reads Next between fields, and Done or Send on the last one",
        "A password field has a Show button at its end that becomes Hide",
        "A password is never filled in advance",
        "An amount accepts a comma or a point for decimals and a hyphen or a minus sign, and is written in the reader's format with aligned figures when the person leaves the field"
      ],
      "tokens": [
        "--glass-fill-input",
        "--glass-blur-input",
        "--input-border",
        "--glass-ring",
        "--brand-blue",
        "--text",
        "--text-muted",
        "--error",
        "--focus-ring",
        "--radius-lg",
        "--space-3",
        "--duration-fast",
        "--ease-standard"
      ]
    },
    {
      "title": "Text area",
      "path": "/components/text-area",
      "url": "https://design.werklist.com/components/text-area",
      "text": "https://design.werklist.com/agent/components/text-area",
      "summary": "Several lines of text, such as notes on a candidate, that grow as the person writes.",
      "version": "2.1.2",
      "kind": "component",
      "name": "TextArea",
      "purpose": "Takes typed text that runs over one line, inside a Field.",
      "use": [
        "Notes, messages, reasons and descriptions"
      ],
      "avoid": [
        "A one line answer: use a text field",
        "Formatted text with bold, lists or links"
      ],
      "anatomy": [
        {
          "part": "Padding",
          "measure": "12 px on all sides",
          "token": "--space-3"
        },
        {
          "part": "Height at rest",
          "measure": "3 lines: 84 px, or 90 px on a touch screen"
        },
        {
          "part": "Height before it scrolls",
          "measure": "10 lines: 224 px, or 244 px on a touch screen"
        },
        {
          "part": "Text",
          "measure": "14 px on 20 px, and 16 px on 22 px on a touch screen",
          "token": "--text"
        },
        {
          "part": "Fill, edge and focus",
          "measure": "those of the text field, with a corner radius of 8 px",
          "token": "--radius-lg"
        },
        {
          "part": "Count",
          "measure": "11 px on 16 px, aligned figures, at the end of the label row, written 412/500 and read as 412 of 500 characters",
          "token": "--text-muted"
        }
      ],
      "states": [
        {
          "name": "Rest, focus, error, read only, disabled",
          "change": "As the text field, with no hover state",
          "tokens": [
            "--input-border",
            "--brand-blue",
            "--error"
          ]
        },
        {
          "name": "Over the limit",
          "change": "The count turns to the error colour. When the person leaves the area or sends the form, the error says how much to remove, such as Remove 12 characters, and the form is not sent",
          "tokens": [
            "--error"
          ]
        }
      ],
      "keys": [
        {
          "key": "Enter",
          "action": "New line"
        },
        {
          "key": "Cmd+Enter on a Mac, Ctrl+Enter elsewhere",
          "action": "Sends, where the surface has one main action"
        }
      ],
      "accessibility": [
        "The count is part of the description. It is read when the area takes focus, not on each key",
        "The limit is checked and the text is never cut",
        "Long words and links wrap"
      ],
      "content": [
        "The hint names the shortcut for the reader's platform, joined with +, such as Cmd+Enter to send"
      ],
      "tokens": [
        "--glass-fill-input",
        "--input-border",
        "--brand-blue",
        "--text",
        "--text-muted",
        "--error",
        "--space-3",
        "--radius-lg"
      ]
    },
    {
      "title": "Search field",
      "path": "/components/search-field",
      "url": "https://design.werklist.com/components/search-field",
      "text": "https://design.werklist.com/agent/components/search-field",
      "summary": "A field for finding records, with a search icon, a clear button and results that follow the typing.",
      "version": "2.1.2",
      "kind": "component",
      "name": "SearchField",
      "purpose": "Filters a visible list, or finds records, as the person types.",
      "use": [
        "Above a list it filters, with the list named in the placeholder",
        "Inside the command palette"
      ],
      "avoid": [
        "Choosing a value in a form: use a combobox",
        "A search that does not name what it searches"
      ],
      "anatomy": [
        {
          "part": "Control",
          "measure": "a text field of type search, with the fill and the focus of the text field. The browser's own clear button is hidden",
          "token": "--input-border"
        },
        {
          "part": "Height",
          "measure": "44 px, or 36 px in a toolbar with a mouse, and 44 px on a touch screen"
        },
        {
          "part": "Search icon",
          "measure": "16 px, 12 px from the start",
          "token": "--text-muted"
        },
        {
          "part": "Text inset",
          "measure": "36 px at the start, and 44 px at the end while the clear button shows"
        },
        {
          "part": "Clear button",
          "measure": "an icon button of 32 px with a cross, named Clear search, 6 px from the end, shown only when the field holds text"
        },
        {
          "part": "Corner radius",
          "measure": "8 px",
          "token": "--radius-lg"
        }
      ],
      "sizes": [
        {
          "name": "md",
          "height": "44 px",
          "type": "14 px on 20 px"
        },
        {
          "name": "compact",
          "height": "36 px with a mouse and 44 px on a touch screen",
          "type": "14 px on 20 px"
        }
      ],
      "states": [
        {
          "name": "Empty",
          "change": "The placeholder in the muted ink, and no clear button",
          "tokens": [
            "--text-muted"
          ]
        },
        {
          "name": "Filled",
          "change": "The clear button shows",
          "tokens": [
            "--text"
          ]
        },
        {
          "name": "Loading",
          "change": "The earlier results dim to 60 percent. A loading indicator appears only after 150 ms"
        },
        {
          "name": "Focus, disabled",
          "change": "As the text field, with no hover state",
          "tokens": [
            "--brand-blue",
            "--text",
            "--text-muted"
          ]
        },
        {
          "name": "Search on a phone",
          "change": "The field spans the header, the other controls hide and a Cancel button shows"
        }
      ],
      "keys": [
        {
          "key": "/",
          "action": "Moves focus to the search field when focus is not in a field"
        },
        {
          "key": "Escape",
          "action": "Clears the text. With the field empty, leaves the field or the search on a phone"
        },
        {
          "key": "Enter",
          "action": "Keeps the query in the browser history, so Back returns to it"
        },
        {
          "key": "Down arrow",
          "action": "Moves into the suggestions when the field has them. The field is then a combobox with aria-activedescendant"
        }
      ],
      "accessibility": [
        "The field sits in a search landmark",
        "Its accessible name repeats the placeholder when there is no visible label",
        "aria-keyshortcuts=\"/\" on the field that takes the slash",
        "The number of results sits in a role=\"status\" region under the field and is read when the results settle"
      ],
      "content": [
        "The placeholder names what is searched: Search candidates, Search this board",
        "The clear button is named Clear search",
        "On a phone the Enter key reads Search. The field offers no autofill and no spelling correction"
      ],
      "tokens": [
        "--glass-fill-input",
        "--input-border",
        "--brand-blue",
        "--text-muted",
        "--radius-lg"
      ],
      "rules": [
        "Search from 2 characters, 120 ms after the last key",
        "An answer that arrives after a newer one is dropped",
        "The earlier results stay on screen, dimmed, while the next ones load",
        "The query is kept in the address of the page"
      ]
    },
    {
      "title": "Select",
      "path": "/components/select",
      "url": "https://design.werklist.com/components/select",
      "text": "https://design.werklist.com/agent/components/select",
      "summary": "The device's own list for choosing one plain option in a form, when radio buttons would take too much room.",
      "version": "2.1.2",
      "kind": "component",
      "name": "Select",
      "purpose": "Chooses one plain option through the device's own list when radio buttons would take too much room.",
      "use": [
        "Plain options in a form, such as a contract type or a notice period, when there are more than five or no room to show them as radio buttons"
      ],
      "avoid": [
        "Up to five options with room to show them: radio buttons",
        "On or off: a switch",
        "A long list people search by name, or options with flags, photos or hints: a combobox",
        "Choosing several options"
      ],
      "anatomy": [
        {
          "part": "Control",
          "measure": "the device's own select, drawn with the fill, corner radius and padding of the text field",
          "token": "--input-border"
        },
        {
          "part": "Chevron",
          "measure": "16 px, 12 px from the end",
          "token": "--text-muted"
        },
        {
          "part": "Padding at the end",
          "measure": "36 px"
        },
        {
          "part": "List",
          "measure": "the operating system's own, a menu on a computer and a picker on a phone, in the theme of the page"
        }
      ],
      "sizes": [
        {
          "name": "md",
          "height": "44 px"
        },
        {
          "name": "lg",
          "height": "48 px"
        }
      ],
      "states": [
        {
          "name": "Rest, focus, error, disabled",
          "change": "As the text field, with no hover state",
          "tokens": [
            "--input-border",
            "--brand-blue",
            "--error",
            "--text-muted"
          ]
        },
        {
          "name": "No answer yet",
          "change": "An empty first option asks the question, such as Choose a notice period, and counts as no answer for a required field"
        }
      ],
      "keys": [
        {
          "key": "Arrow keys",
          "action": "Move through the options"
        },
        {
          "key": "A letter",
          "action": "Jumps to the first option that starts with it"
        },
        {
          "key": "Enter, Space or Alt+Down",
          "action": "Open the list, where the platform does so"
        }
      ],
      "accessibility": [
        "A select element, named by the Field label",
        "The open list follows the theme of the page",
        "Options can be grouped, and one option can be disabled"
      ],
      "content": [
        "Options are parallel phrases in sentence case",
        "Add None when no option may apply",
        "The empty first option asks the question"
      ],
      "tokens": [
        "--glass-fill-input",
        "--input-border",
        "--brand-blue",
        "--text-muted",
        "--radius-lg"
      ]
    },
    {
      "title": "Combobox",
      "path": "/components/combobox",
      "url": "https://design.werklist.com/components/combobox",
      "text": "https://design.werklist.com/agent/components/combobox",
      "summary": "A field that opens a searchable list, for long lists and for options with flags, photos or hints.",
      "version": "2.1.2",
      "kind": "component",
      "name": "Combobox",
      "purpose": "Chooses one or several options from a long or rich list, with a search row that narrows it.",
      "use": [
        "A long list people search by name",
        "Options told apart by a flag, a photo, an icon or a hint: countries, people, time zones, stages",
        "Several answers from a long list"
      ],
      "avoid": [
        "A short list of plain options: a select",
        "Free text that is not in the list"
      ],
      "variants": [
        {
          "name": "Single",
          "use": "One answer. Choosing closes the list"
        },
        {
          "name": "Several",
          "use": "Several answers. Each row has a checkbox and the list stays open. The field lists the choices by name. When the names do not fit, it ends with a count, such as “and 2 more”. The list carries aria-multiselectable"
        }
      ],
      "anatomy": [
        {
          "part": "Field",
          "measure": "the fill of the text field, 12 px padding, 8 px between its parts. It is a button with role=\"combobox\"",
          "token": "--input-border"
        },
        {
          "part": "Leading mark",
          "measure": "a flag of 20 px, a photo of 24 px, or an icon of 16 px in the muted ink"
        },
        {
          "part": "Chevron",
          "measure": "16 px, 12 px from the end. It turns over in 150 ms while the list is open",
          "token": "--text-muted"
        },
        {
          "part": "List",
          "measure": "as wide as the field, 8 px below it, corner radius 12 px, padding 4 px. It floats above the page and rises into place in 150 ms",
          "token": "--glass-fill-raised"
        },
        {
          "part": "List shadow",
          "measure": "the raised shadow, with a top highlight and a fine ring in dark",
          "token": "--glass-shadow-raised"
        },
        {
          "part": "Search row",
          "measure": "a 16 px search icon and bare text with no fill and no ring, 10 px from the edge, 36 px high, and 44 px high with 16 px text on a touch screen",
          "token": "--text-muted"
        },
        {
          "part": "Row",
          "measure": "36 px, at least 44 px on a touch screen, padding 8 px by 10 px, corner radius 8 px, 14 px on 20 px text that wraps",
          "token": "--text"
        },
        {
          "part": "Row hint",
          "measure": "12 px on 16 px at the end of the row",
          "token": "--text-muted"
        },
        {
          "part": "Check",
          "measure": "16 px at the end of the chosen row",
          "token": "--brand-blue"
        },
        {
          "part": "Empty line",
          "measure": "No match for the typed text, 14 px, at the row inset",
          "token": "--text-muted"
        }
      ],
      "sizes": [
        {
          "name": "md",
          "height": "44 px",
          "padding": "0 12 px",
          "type": "14 px on 20 px"
        },
        {
          "name": "lg",
          "height": "48 px",
          "padding": "0 12 px",
          "type": "14 px on 20 px"
        },
        {
          "name": "compact",
          "height": "36 px with a mouse and 44 px on a touch screen",
          "padding": "0 12 px",
          "type": "14 px on 20 px"
        }
      ],
      "states": [
        {
          "name": "Rest, error, disabled",
          "change": "As the text field, with no hover state",
          "tokens": [
            "--input-border",
            "--error",
            "--text-muted"
          ]
        },
        {
          "name": "Focus",
          "change": "The field is a button and shows focus as a button does: the fill stays, and a 2 px blue outline sits 2 px outside the field",
          "tokens": [
            "--brand-blue"
          ]
        },
        {
          "name": "Open",
          "change": "The chevron turns over, the list shows, and the field carries aria-expanded=\"true\""
        },
        {
          "name": "Row under the pointer or the keyboard highlight",
          "change": "The same fill for both",
          "tokens": [
            "--glass-fill-hover"
          ]
        },
        {
          "name": "Chosen row",
          "change": "A check at the end, and aria-selected=\"true\"",
          "tokens": [
            "--brand-blue"
          ]
        },
        {
          "name": "Loading",
          "change": "Grey placeholder rows until the options arrive"
        },
        {
          "name": "No match",
          "change": "No match for the typed text",
          "tokens": [
            "--text-muted"
          ]
        },
        {
          "name": "No options",
          "change": "The field is disabled and the hint says why"
        }
      ],
      "keys": [
        {
          "key": "Enter, Space or Down arrow on the field",
          "action": "Opens the list. Focus moves to the search row, or to the list when there is no search row"
        },
        {
          "key": "Typing",
          "action": "Narrows the list. Without a search row, jumps to the first option that starts with the letters"
        },
        {
          "key": "Up and Down arrows",
          "action": "Move the highlight"
        },
        {
          "key": "Home and End",
          "action": "First and last option"
        },
        {
          "key": "Enter",
          "action": "Chooses the highlighted option and closes. With several answers, ticks or clears it and keeps the list open"
        },
        {
          "key": "Escape",
          "action": "Closes this list only, so a dialog around the field stays open. Focus returns to the field"
        },
        {
          "key": "Tab",
          "action": "Closes without changing the value and moves to the next control"
        }
      ],
      "accessibility": [
        "The field is a button with role=\"combobox\", aria-haspopup=\"listbox\", aria-expanded and aria-controls, named by the Field label",
        "The search row is an input with role=\"combobox\", aria-autocomplete=\"list\", aria-controls and aria-activedescendant",
        "The list has role=\"listbox\". Options have role=\"option\" and aria-selected, and are not tab stops",
        "Escape closes only the top layer",
        "Focus returns to the field however the list closes",
        "The chosen name is cut short in the field only. Its accessible name stays whole",
        "With reduced motion the list only fades"
      ],
      "content": [
        "Options are parallel phrases in sentence case",
        "The empty line repeats the query: No match for Kenya",
        "The placeholder of the search row names the list: Search countries"
      ],
      "tokens": [
        "--glass-fill-input",
        "--input-border",
        "--glass-fill-raised",
        "--glass-blur-raised",
        "--glass-shadow-raised",
        "--glass-fill-hover",
        "--brand-blue",
        "--text",
        "--text-muted",
        "--radius-lg",
        "--radius-xl",
        "--space-1",
        "--space-2",
        "--layer-popover"
      ],
      "rules": [
        "Show the search row when the list has more than 7 options",
        "Open upward when the room below is under 280 px and the room above is larger",
        "Keep the list within 70 percent of the window height, and at least 176 px tall",
        "Keep 8 px from the window edge"
      ]
    },
    {
      "title": "Date and time picker",
      "path": "/components/date-picker",
      "url": "https://design.werklist.com/components/date-picker",
      "text": "https://design.werklist.com/agent/components/date-picker",
      "summary": "Fields for a date or a time that accept typing and open a calendar or a list of times.",
      "version": "2.1.2",
      "kind": "component",
      "name": "DatePicker",
      "purpose": "Takes a calendar day or a time of day, typed or picked from a month calendar or a list of times.",
      "use": [
        "One day: a start date, a passport expiry, an interview",
        "A period, as two fields labelled Start and End",
        "A time of day, with the time field"
      ],
      "avoid": [
        "A date shown in figures only, such as 09/10/2026",
        "A year in two digits",
        "A calendar as the only way to reach a day far from today"
      ],
      "anatomy": [
        {
          "part": "Field",
          "measure": "a text field with a 32 px icon button at its end, named Choose date, holding a 16 px calendar icon",
          "token": "--input-border"
        },
        {
          "part": "Calendar",
          "measure": "284 px wide, narrower in a small window, padding 12 px, corner radius 12 px",
          "token": "--glass-fill-raised"
        },
        {
          "part": "Calendar shadow",
          "measure": "the raised shadow, with a top highlight and a fine ring in dark",
          "token": "--glass-shadow-raised"
        },
        {
          "part": "Header",
          "measure": "the month and the year, 14 px on 20 px, weight 700, between 32 px buttons for the previous and the next month",
          "token": "--text"
        },
        {
          "part": "Weekday row",
          "measure": "short day names in the reader's language, 11 px on 16 px, weight 500, 4 px above the days, Monday first",
          "token": "--text-muted"
        },
        {
          "part": "Day",
          "measure": "36 px high, as wide as its column, corner radius 8 px, 14 px aligned figures, in seven columns 2 px apart",
          "token": "--text"
        },
        {
          "part": "Day under the pointer",
          "measure": "a light fill",
          "token": "--glass-fill-hover"
        },
        {
          "part": "Day in focus",
          "measure": "a 2 px ring of the brand blue at 40 percent",
          "token": "--brand-blue"
        },
        {
          "part": "Chosen day",
          "measure": "the brand fill with white figures at weight 700",
          "token": "--brand-true"
        },
        {
          "part": "Today",
          "measure": "a 4 px dot in the brand colour, 4 px above the bottom of the day, hidden on the chosen day",
          "token": "--brand-true"
        },
        {
          "part": "Day that cannot be chosen",
          "measure": "faded to 30 percent, with aria-disabled"
        },
        {
          "part": "Days of other months",
          "measure": "left blank"
        },
        {
          "part": "Time list",
          "measure": "slots every 30 minutes from 08:00 to 21:00, under the headings Morning, Afternoon and Evening in 11 px on 16 px, with the rows of the combobox",
          "token": "--text"
        }
      ],
      "sizes": [
        {
          "name": "md",
          "height": "44 px"
        },
        {
          "name": "lg",
          "height": "48 px"
        }
      ],
      "states": [
        {
          "name": "Field states",
          "change": "As the text field, with no hover state",
          "tokens": [
            "--input-border",
            "--brand-blue",
            "--error"
          ]
        },
        {
          "name": "A date the field cannot read",
          "change": "The text is kept, and the error gives an example: Enter a date like 28 Sep 2026.",
          "tokens": [
            "--error"
          ]
        },
        {
          "name": "Touch screen",
          "change": "The device's own date or time picker takes the place of the calendar and the list"
        }
      ],
      "keys": [
        {
          "key": "Left and Right arrows",
          "action": "Previous and next day"
        },
        {
          "key": "Up and Down arrows",
          "action": "Same day of the previous and next week"
        },
        {
          "key": "Home and End",
          "action": "First and last day of the week"
        },
        {
          "key": "Page Up and Page Down",
          "action": "Previous and next month"
        },
        {
          "key": "Shift+Page Up and Shift+Page Down",
          "action": "Previous and next year"
        },
        {
          "key": "Enter or Space",
          "action": "Chooses the day and closes"
        },
        {
          "key": "Escape",
          "action": "Closes without a change. Focus returns to the calendar button"
        },
        {
          "key": "Tab",
          "action": "Moves between the month buttons and the grid. One day is in the tab order"
        }
      ],
      "accessibility": [
        "The calendar is a dialog with aria-modal=\"true\", named after the field label",
        "The month is a grid. Each day is a button named with its full date",
        "aria-selected=\"true\" on the chosen day, and aria-current=\"date\" on today",
        "The month heading is announced when it changes",
        "With reduced motion the calendar only fades, and months do not slide"
      ],
      "content": [
        "Display: the day, the short month and the full year in the reader's language, such as 28 Sep 2026",
        "Input: the day first with dots, slashes or spaces, the month by name, or year, month and day in that order. The year is written in full",
        "Clock: 24 hour, or 12 hour when the person's settings say so",
        "Time zone: named in the hint when readers in more than one zone see the value"
      ],
      "tokens": [
        "--glass-fill-input",
        "--input-border",
        "--glass-fill-raised",
        "--glass-shadow-raised",
        "--glass-fill-hover",
        "--brand-blue",
        "--brand-true",
        "--on-brand",
        "--text",
        "--text-muted",
        "--radius-lg",
        "--radius-xl",
        "--space-1",
        "--space-3",
        "--layer-popover"
      ],
      "rules": [
        "A date without a time is a calendar day, stored and shown without a time zone",
        "A period is two fields. The End calendar opens on the month of the start and offers no earlier day",
        "Slots are 30 minutes apart, or 15 when the task needs it"
      ]
    },
    {
      "title": "Checkbox",
      "path": "/components/checkbox",
      "url": "https://design.werklist.com/components/checkbox",
      "text": "https://design.werklist.com/agent/components/checkbox",
      "summary": "Lets someone pick any number of options, and applies the choice when the form is saved.",
      "version": "2.1.2",
      "kind": "component",
      "name": "Checkbox",
      "purpose": "Marks one or more options as chosen. The choice applies when the form is submitted.",
      "use": [
        "Several options may be chosen from a group of up to seven.",
        "One statement a person agrees to, such as Notify the candidate.",
        "A parent that checks or clears a group of options."
      ],
      "avoid": [
        "A choice that applies at once: use Switch.",
        "Exactly one option: use Radio, or Select for a long list.",
        "More than seven options: split the group or use Combobox with several choices."
      ],
      "anatomy": [
        {
          "part": "Box",
          "measure": "16 px, 14 px in dense table rows, 22 px in a checklist on a phone"
        },
        {
          "part": "Corner radius",
          "measure": "4 px, 6 px on the 22 px box",
          "token": "--radius-sm"
        },
        {
          "part": "Edge at rest",
          "measure": "1 px inset, rgba(13, 18, 40, 0.55) in light, rgba(255, 255, 255, 0.2) in dark"
        },
        {
          "part": "Fill at rest",
          "measure": "#ffffff in light, --surface-control in dark"
        },
        {
          "part": "Fill checked or mixed",
          "token": "--brand-blue"
        },
        {
          "part": "Tick",
          "measure": "12 px in the 16 px box, 11 px in the 14 px box, 16 px in the 22 px box, stroke 2",
          "token": "--on-brand"
        },
        {
          "part": "Mixed bar",
          "measure": "8 by 2 px, radius 1 px, centered",
          "token": "--on-brand"
        },
        {
          "part": "Label",
          "measure": "14 px on 20 px, weight 400",
          "token": "--text"
        },
        {
          "part": "Gap box to label",
          "measure": "8 px",
          "token": "--space-2"
        },
        {
          "part": "Box position",
          "measure": "centered on the first label line, 2 px below its top"
        },
        {
          "part": "Row",
          "measure": "at least 24 px with a fine pointer, 44 px with a coarse pointer"
        },
        {
          "part": "Space between options",
          "measure": "8 px with a fine pointer, 0 with a coarse pointer",
          "token": "--space-2"
        },
        {
          "part": "Child indent",
          "measure": "24 px",
          "token": "--space-6"
        },
        {
          "part": "Focus ring",
          "measure": "2 px, offset 2 px",
          "token": "--focus-ring"
        }
      ],
      "sizes": [
        {
          "name": "default",
          "height": "16 px box"
        },
        {
          "name": "compact",
          "height": "14 px box, in dense table rows only"
        },
        {
          "name": "touch checklist",
          "height": "22 px box, radius 6 px"
        }
      ],
      "states": [
        {
          "name": "rest",
          "change": "the flat box inside its 1 px edge"
        },
        {
          "name": "focus visible",
          "change": "2 px ring outside the box",
          "tokens": [
            "--focus-ring"
          ]
        },
        {
          "name": "checked",
          "change": "brand fill with a white tick",
          "tokens": [
            "--brand-blue",
            "--on-brand"
          ]
        },
        {
          "name": "mixed",
          "change": "brand fill with a white bar, on a parent only",
          "tokens": [
            "--brand-blue",
            "--on-brand"
          ]
        },
        {
          "name": "disabled",
          "change": "box and mark at half strength, label in muted ink",
          "tokens": [
            "--text-muted"
          ]
        },
        {
          "name": "invalid",
          "change": "error edge, with the message in the error line of the group",
          "tokens": [
            "--error",
            "--error-ink"
          ]
        }
      ],
      "keys": [
        {
          "key": "Tab",
          "action": "Moves to the next checkbox"
        },
        {
          "key": "Space",
          "action": "Checks or clears the focused checkbox"
        },
        {
          "key": "Enter",
          "action": "Submits the form and does not toggle"
        }
      ],
      "accessibility": [
        "A native checkbox input.",
        "A parent in the mixed state is announced as mixed.",
        "A group is a fieldset. Its legend takes the style of a field label and holds any requirement.",
        "A checkbox without visible words takes a name that includes its row, such as Select Bishal Tamang.",
        "Disabled lowers the box to half strength and mutes the label, which stays readable.",
        "The box prints with its fill and tick.",
        "In forced colors mode the edge and the tick take system colors."
      ],
      "content": [
        "Checked means yes. No negative labels.",
        "Sentence case, no full stop.",
        "Options are parallel. Words they share move to the group label.",
        "Order from the simplest to the most complex, or from the safest to the riskiest."
      ],
      "tokens": [
        "--text-muted",
        "--text",
        "--brand-blue",
        "--on-brand",
        "--surface-control",
        "--error",
        "--error-ink",
        "--radius-sm",
        "--radius-md",
        "--space-2",
        "--space-6",
        "--focus-ring",
        "--focus-ring-width",
        "--focus-ring-offset",
        "--duration-fast",
        "--ease-standard"
      ],
      "rules": [
        "The choice applies when the form is saved, never on click.",
        "A parent shows the mixed state while some of its options are checked.",
        "Checked means yes: the label states the positive, such as Notify the candidate."
      ]
    },
    {
      "title": "Radio",
      "path": "/components/radio",
      "url": "https://design.werklist.com/components/radio",
      "text": "https://design.werklist.com/agent/components/radio",
      "summary": "Lets someone choose exactly one option from a short list they can see in full.",
      "version": "2.1.2",
      "kind": "component",
      "name": "Radio",
      "purpose": "Chooses exactly one option from a short list shown in full.",
      "use": [
        "Two to five options the reader compares before choosing.",
        "Options that need a sentence or a description each.",
        "A choice inside a form that applies on submit."
      ],
      "avoid": [
        "More than five options or little room: use Select.",
        "Two to five one word values that apply at once: use SegmentedControl.",
        "Any number of choices: use Checkbox.",
        "One on or off setting: use Checkbox or Switch."
      ],
      "anatomy": [
        {
          "part": "Circle",
          "measure": "16 px",
          "token": "--radius-full"
        },
        {
          "part": "Edge at rest",
          "measure": "1 px inset, rgba(13, 18, 40, 0.55) in light, rgba(255, 255, 255, 0.2) in dark, as on the checkbox"
        },
        {
          "part": "Fill at rest",
          "measure": "#ffffff in light, --surface-control in dark, as on the checkbox"
        },
        {
          "part": "Fill chosen",
          "token": "--brand-blue"
        },
        {
          "part": "Dot",
          "measure": "6 px, centered",
          "token": "--on-brand"
        },
        {
          "part": "Label",
          "measure": "14 px on 20 px, weight 400",
          "token": "--text"
        },
        {
          "part": "Description",
          "measure": "13 px on 18 px, directly under the label",
          "token": "--text-muted"
        },
        {
          "part": "Gap circle to label",
          "measure": "8 px",
          "token": "--space-2"
        },
        {
          "part": "Space between options",
          "measure": "8 px with a fine pointer, 0 with a coarse pointer, where rows are 44 px",
          "token": "--space-2"
        },
        {
          "part": "Row layout",
          "measure": "two or three short options, each as wide as the longest, 24 px apart, stacked below 640 px",
          "token": "--space-6"
        },
        {
          "part": "Group label",
          "measure": "a field label on a legend"
        },
        {
          "part": "Focus ring",
          "measure": "2 px, offset 2 px",
          "token": "--focus-ring"
        }
      ],
      "states": [
        {
          "name": "rest",
          "change": "the flat circle inside its 1 px edge"
        },
        {
          "name": "focus visible",
          "change": "ring outside the circle",
          "tokens": [
            "--focus-ring"
          ]
        },
        {
          "name": "chosen",
          "change": "brand fill with a white dot",
          "tokens": [
            "--brand-blue",
            "--on-brand"
          ]
        },
        {
          "name": "disabled",
          "change": "circle and dot at half strength, label in muted ink",
          "tokens": [
            "--text-muted"
          ]
        },
        {
          "name": "invalid",
          "change": "error edge, with the message in the error line of the group",
          "tokens": [
            "--error",
            "--error-ink"
          ]
        }
      ],
      "keys": [
        {
          "key": "Tab",
          "action": "Enters the group at the chosen option, or the first when none is chosen"
        },
        {
          "key": "Arrow keys",
          "action": "Move to the next or previous option and choose it, wrapping at the ends"
        },
        {
          "key": "Space",
          "action": "Chooses the focused option when none is chosen"
        },
        {
          "key": "Shift+Tab",
          "action": "Leaves the group"
        }
      ],
      "accessibility": [
        "Native radio inputs sharing a name, inside a fieldset with a legend.",
        "Each option is a label element.",
        "The group is one Tab stop.",
        "Screen readers announce the legend, the option, its position and its state."
      ],
      "content": [
        "Fragments in sentence case, no full stop.",
        "Long labels wrap and are not truncated.",
        "Descriptions are sentences with a full stop, on every option or on none.",
        "The group label ends without a colon.",
        "The safe, usual option comes first and starts chosen."
      ],
      "tokens": [
        "--surface-control",
        "--text-muted",
        "--text",
        "--brand-blue",
        "--on-brand",
        "--error",
        "--radius-full",
        "--space-2",
        "--space-6",
        "--focus-ring"
      ],
      "rules": [
        "Two to five visible options, one chosen from the start.",
        "A long list, such as a country of origin, is a Select or a Combobox.",
        "One setting that is on or off is one Checkbox or Switch, not two radio buttons for Yes and No."
      ]
    },
    {
      "title": "Switch",
      "path": "/components/switch",
      "url": "https://design.werklist.com/components/switch",
      "text": "https://design.werklist.com/agent/components/switch",
      "summary": "Turns a setting on or off and applies the change the moment it is flipped.",
      "version": "2.1.2",
      "kind": "component",
      "name": "Switch",
      "purpose": "Turns one setting on or off and applies the change at once.",
      "use": [
        "A setting that takes effect when flipped.",
        "A row in a list of settings.",
        "An option on one item that applies at once, such as whether a job ad accepts applications."
      ],
      "avoid": [
        "A change that waits for Save: use Checkbox.",
        "More than two states: use Radio or SegmentedControl.",
        "A toolbar: use a toggle button, an IconButton or Button with aria-pressed."
      ],
      "anatomy": [
        {
          "part": "Track",
          "measure": "40 by 24 px, fully rounded, no edge",
          "token": "--radius-full"
        },
        {
          "part": "Knob",
          "measure": "20 px, inset 2 px, white in both themes, with a small shadow"
        },
        {
          "part": "Knob travel",
          "measure": "16 px"
        },
        {
          "part": "Off track",
          "measure": "rgba(13, 18, 40, 0.12) in light, rgba(255, 255, 255, 0.18) in dark"
        },
        {
          "part": "On track",
          "token": "--brand-blue"
        },
        {
          "part": "Label",
          "measure": "14 px on 20 px",
          "token": "--text"
        },
        {
          "part": "Description",
          "measure": "13 px on 18 px",
          "token": "--text-muted"
        },
        {
          "part": "Settings row",
          "measure": "at least 44 px high, 12 px above and below, 16 px or more between the words and the switch",
          "token": "--space-3"
        },
        {
          "part": "Target on a coarse pointer",
          "measure": "44 px around the track when the switch stands alone"
        },
        {
          "part": "Focus ring",
          "measure": "2 px, offset 2 px",
          "token": "--focus-ring"
        }
      ],
      "states": [
        {
          "name": "off",
          "change": "gray track, white knob at the start"
        },
        {
          "name": "on",
          "change": "brand track, white knob at the end",
          "tokens": [
            "--brand-blue"
          ]
        },
        {
          "name": "focus visible",
          "change": "ring outside the track",
          "tokens": [
            "--focus-ring"
          ]
        },
        {
          "name": "saving",
          "change": "the new position shows at once, marked busy until the save returns"
        },
        {
          "name": "failed",
          "change": "back to the old position, with an error line under the row",
          "tokens": [
            "--error-ink"
          ]
        },
        {
          "name": "disabled",
          "change": "the whole switch at half strength, in place"
        }
      ],
      "keys": [
        {
          "key": "Tab",
          "action": "Moves to the switch"
        },
        {
          "key": "Space",
          "action": "Flips the switch"
        },
        {
          "key": "Enter",
          "action": "Flips the switch"
        }
      ],
      "accessibility": [
        "A button with role switch and aria-checked.",
        "Named by its visible label. The description is attached with aria-describedby.",
        "A switch without a visible label takes a name that includes its row, such as Board admin, Ana Horvat.",
        "On and off differ in fill and in the position of the knob.",
        "With reduced motion the knob moves without sliding."
      ],
      "content": [
        "A noun or a short phrase naming what on means, such as Show the salary.",
        "No Turn on, no Enable, no question.",
        "Sentence case, no full stop."
      ],
      "tokens": [
        "--text-muted",
        "--text",
        "--brand-blue",
        "--error-ink",
        "--radius-full",
        "--space-3",
        "--space-4",
        "--focus-ring",
        "--duration-fast",
        "--ease-standard"
      ],
      "rules": [
        "A switch saves the moment it is flipped. A panel with a Save button uses checkboxes.",
        "The label names what on means, never its opposite: Show the salary, not Hide the salary."
      ]
    },
    {
      "title": "Segmented control",
      "path": "/components/segmented-control",
      "url": "https://design.werklist.com/components/segmented-control",
      "text": "https://design.werklist.com/agent/components/segmented-control",
      "summary": "Switches a view or a setting between two to five short values in one compact row.",
      "version": "2.1.2",
      "kind": "component",
      "name": "SegmentedControl",
      "purpose": "Chooses one of two to five short values that change a view or a setting at once.",
      "use": [
        "The period of a dashboard or a chart.",
        "A setting with a few short values that applies at once, such as who picks up new applications: Off, Suggest, Auto."
      ],
      "avoid": [
        "Moving to another page or section: use Tabs or links.",
        "Running an action: use Button.",
        "More than five values or long labels: use Radio or Select.",
        "Several values at once: use toggle buttons in a Toolbar."
      ],
      "anatomy": [
        {
          "part": "Track",
          "measure": "36 px high with a fine pointer, 48 px with a coarse pointer. Padding 2 px, 2 px between segments, radius 10 px.",
          "token": "--surface-control"
        },
        {
          "part": "Segment",
          "measure": "32 px high, 44 px with a coarse pointer, radius 8 px. As wide as its word with 12 px at each side, at least 44 px. Below 640 px the segments share the width of the container.",
          "token": "--radius-lg"
        },
        {
          "part": "Label",
          "measure": "13 px on 20 px, weight 700 on every segment",
          "token": "--text-muted"
        },
        {
          "part": "Chosen fill",
          "token": "--brand-true"
        },
        {
          "part": "Chosen label",
          "token": "--on-brand"
        },
        {
          "part": "Focus ring",
          "measure": "2 px, offset 0, in the 2 px padding of the track",
          "token": "--focus-ring"
        }
      ],
      "sizes": [
        {
          "name": "fine pointer",
          "height": "36 px track, 32 px segments"
        },
        {
          "name": "coarse pointer",
          "height": "48 px track, 44 px segments"
        }
      ],
      "states": [
        {
          "name": "rest",
          "change": "muted label on the track",
          "tokens": [
            "--text-muted",
            "--surface-control"
          ]
        },
        {
          "name": "hover",
          "change": "label in full ink, with a fine pointer only",
          "tokens": [
            "--text"
          ]
        },
        {
          "name": "chosen",
          "change": "brand fill under a white label. The fill slides from the old segment in 150 ms.",
          "tokens": [
            "--brand-true",
            "--on-brand"
          ]
        },
        {
          "name": "focus visible",
          "change": "ring around the focused segment",
          "tokens": [
            "--focus-ring"
          ]
        },
        {
          "name": "disabled",
          "change": "the whole control only, every segment at 60 percent. The chosen one keeps its brand fill."
        }
      ],
      "keys": [
        {
          "key": "Tab",
          "action": "Moves to the chosen segment"
        },
        {
          "key": "Arrow keys",
          "action": "Move to the next or previous segment and choose it, wrapping at the ends"
        },
        {
          "key": "Home",
          "action": "Chooses the first segment"
        },
        {
          "key": "End",
          "action": "Chooses the last segment"
        }
      ],
      "accessibility": [
        "A radiogroup named by its label. Each segment is a radio with aria-checked.",
        "Only the chosen segment is in the Tab order.",
        "In forced colors mode the chosen segment keeps an outline in the highlight color."
      ],
      "content": [
        "Nouns or short noun phrases, sentence case.",
        "Two to five segments."
      ],
      "tokens": [
        "--surface-control",
        "--text-muted",
        "--text",
        "--brand-true",
        "--on-brand",
        "--radius-lg",
        "--space-3",
        "--focus-ring",
        "--duration-fast",
        "--ease-standard"
      ],
      "rules": [
        "Two to five short values of one setting or view.",
        "The chosen segment is solid brand blue with white words, never a gradient.",
        "A segmented control never opens another page. Tabs or links do that."
      ]
    },
    {
      "title": "Header",
      "path": "/components/header",
      "url": "https://design.werklist.com/components/header",
      "text": "https://design.werklist.com/agent/components/header",
      "summary": "The bar at the top of the screen: the main sections of a website, or the actions of WerkOS you need in any module.",
      "version": "2.1.2",
      "kind": "component",
      "name": "Header",
      "purpose": "The bar at the top of each screen: the main sections of a website, or the actions of WerkOS needed in any module.",
      "use": [
        "One per screen, at the top, on each page.",
        "On a website: the main sections, each opening a panel of its pages.",
        "In WerkOS: the actions needed in every module, such as Add task, Ask WerkAI, email, notifications and Sign out."
      ],
      "avoid": [
        "Actions that belong to one page: use that page's toolbar.",
        "The blocks of a long page: use side navigation.",
        "Panels that open on hover.",
        "Changing the header's height in the page flow."
      ],
      "anatomy": [
        {
          "part": "Bar, website",
          "measure": "72 px at rest. After 80 px of scroll, 64 px stay in view: the bar moves up instead of shrinking, so the page holds still",
          "token": "--header-h, --header-h-condensed"
        },
        {
          "part": "Frame",
          "measure": "1440 px, centered, with 24 px of side padding, 32 px from 1024 px",
          "token": "--frame, --pad"
        },
        {
          "part": "Logo",
          "measure": "30 px high, 22 px below 400 px, flush left, links to the home page"
        },
        {
          "part": "Section button",
          "measure": "40 px high, padding 10 px, radius 6 px, 2 px apart, centered between the logo and the buttons",
          "token": "--type-nav, --radius-md"
        },
        {
          "part": "Theme switch",
          "measure": "IconButton medium, 40 by 40 px, named for the theme it switches to"
        },
        {
          "part": "Primary button",
          "measure": "Button primary medium, 44 px, the one action of the website, such as Hire workers, 8 px after the theme switch",
          "token": "--brand-true, --on-brand"
        },
        {
          "part": "Menu button",
          "measure": "40 by 40 px, below 1280 px"
        },
        {
          "part": "Section panel",
          "measure": "opens under its button and stays inside the frame. As wide as its list, radius 16 px, padding 8 px. White in light, the raised fill with its ring in dark. Enters with a fade and a 6 px rise in 150 ms",
          "token": "--surface-1, --glass-fill-raised, --glass-ring-raised, --radius-2xl, --elevation-3, --space-2, --duration-fast"
        },
        {
          "part": "Panel rows",
          "measure": "links of 36 px at 14 px, 44 px on a touch screen. Pages only. A section with groups is listed by name",
          "token": "--surface-control"
        },
        {
          "part": "Panel columns",
          "measure": "one column up to 7 pages, two up to 14, three up to 24, four up to 36, then five. The panel ends 96 px above the foot of the window and then scrolls"
        },
        {
          "part": "Menu panel",
          "measure": "a layer under the bar, as tall as the window below it, with its own scroll. Section rows at least 48 px",
          "token": "--bg"
        },
        {
          "part": "WerkOS desktop bar",
          "measure": "from 1024 px, a 52 px bar in a 60 px band, 6 px in on the left, 8 px on the right and below. Square top corners, 24 px bottom corners",
          "token": "--radius-3xl"
        },
        {
          "part": "WerkOS Add task",
          "measure": "36 px, full radius, no fill, 1 px inset edge in brand blue, label 13 px weight 700 in brand blue, padding 10 px left and 14 px right, 16 px tasks glyph, gap 6 px",
          "token": "--brand-blue, --radius-full"
        },
        {
          "part": "WerkOS Request optimization",
          "measure": "36 px, full radius, glass hover wash at rest, label 14 px weight 500 in muted ink, padding 12 px, 16 px cog glyph, gap 6 px",
          "token": "--glass-fill-hover, --text-muted, --radius-full"
        },
        {
          "part": "WerkOS ask bar",
          "measure": "36 px, full radius, control fill with no ring, padding 16 px, gap 10 px. A 17 px sparkle stroked with a blue gradient, then Ask WerkAI at 14 px, weight 500, in muted ink. Centered on the header, 132 px to 600 px wide, with 304 px kept free on each side",
          "token": "--surface-control, --text-muted, --radius-full"
        },
        {
          "part": "WerkOS icon buttons",
          "measure": "36 by 36 px, full radius, muted ink, 2 px apart, glyphs 17 px to 19 px. A 1 px rule 20 px high stands before Sign out",
          "token": "--text-muted, --border-rule"
        },
        {
          "part": "WerkOS counter",
          "measure": "Counter, attention tone, over the top end corner (6 px up, 4 px out), with a 2 px ring in the resting header fill",
          "token": "--badge-alert, --badge-alert-ink, --header-fill"
        },
        {
          "part": "WerkOS phone bar",
          "measure": "64 px at every scroll position, plus the top safe area",
          "token": "--app-header-h"
        }
      ],
      "variants": [
        {
          "name": "Website",
          "use": "Main sections with panels, theme switch, one primary button."
        },
        {
          "name": "WerkOS",
          "use": "An action bar beside the rail, which does the navigating."
        }
      ],
      "states": [
        {
          "name": "At rest",
          "change": "Opaque surface, no border, no shadow",
          "tokens": [
            "--bg",
            "--header-fill"
          ]
        },
        {
          "name": "Scrolled, website",
          "change": "The page color at 92 percent, blurred 10 px with saturation at 140 percent, 64 px in view",
          "tokens": [
            "--bg"
          ]
        },
        {
          "name": "Scrolled, WerkOS",
          "change": "Crossfades to navigation glass",
          "tokens": [
            "--glass-fill-nav",
            "--glass-blur-nav",
            "--glass-shadow-nav"
          ]
        },
        {
          "name": "Retracted, WerkOS desktop",
          "change": "Slides up out of view on scroll down and comes back on the first scroll up",
          "tokens": [
            "--app-sticky-top"
          ]
        },
        {
          "name": "Section at rest",
          "change": "Muted ink, weight 500",
          "tokens": [
            "--text-muted"
          ]
        },
        {
          "name": "Section hover",
          "change": "Fill and full ink, on devices that can hover",
          "tokens": [
            "--surface-control",
            "--text"
          ]
        },
        {
          "name": "Section current",
          "change": "Full ink, weight 700, aria-current true. Each label keeps the width of its bold form, so the row never shifts",
          "tokens": [
            "--text"
          ]
        },
        {
          "name": "Section open",
          "change": "Fill held, aria-expanded true",
          "tokens": [
            "--surface-control"
          ]
        },
        {
          "name": "Focus",
          "change": "2 px ring, 2 px offset",
          "tokens": [
            "--focus-ring",
            "--focus-ring-width",
            "--focus-ring-offset"
          ]
        },
        {
          "name": "Reduced transparency or no backdrop filter",
          "change": "Scrolled surface stays opaque",
          "tokens": [
            "--bg",
            "--header-fill"
          ]
        }
      ],
      "keys": [
        {
          "key": "Tab",
          "action": "Moves through the skip link, the logo, the section buttons, the theme switch and the primary button"
        },
        {
          "key": "Enter or Space",
          "action": "Opens the section panel and focuses its first link. On the button of an open panel, opens the overview of the section"
        },
        {
          "key": "ArrowLeft, ArrowRight",
          "action": "Move between section buttons"
        },
        {
          "key": "ArrowUp, ArrowDown",
          "action": "Move through the links of the open panel. Inside a panel, ArrowLeft and ArrowRight move one column along the same row"
        },
        {
          "key": "Home, End",
          "action": "First or last link of the open panel"
        },
        {
          "key": "Escape",
          "action": "Closes the panel or the menu panel and returns focus to its button"
        },
        {
          "key": "Tab past the last link",
          "action": "Closes the panel and moves on"
        }
      ],
      "accessibility": [
        "One header element per page, the banner landmark.",
        "Section buttons inside nav aria-label Primary, each with aria-expanded and aria-controls.",
        "Current section: aria-current true (the item is a button, not the page link).",
        "A panel is a list of links, with no menu or menuitem roles.",
        "Menu panel: role dialog, aria-modal and a name. Focus stays inside it, the page behind does not scroll, and focus returns to the menu button on close.",
        "Skip to content is the first focusable element.",
        "Section labels meet 4.5 to 1 on the page color and the focus ring meets 3 to 1, in both themes.",
        "Without script each section button is a link to its overview page.",
        "Forced colors: the current section keeps weight 700, and focus is an outline."
      ],
      "content": [
        "Section labels are short nouns in sentence case, one word where possible: Employers, Candidates, Jobs, About.",
        "A panel lists pages only. A second press on the button of an open panel opens the overview of the section, and the home page links to every overview.",
        "Theme switch names are Switch to the dark theme and Switch to the light theme.",
        "Menu button names are Open menu and Close menu."
      ],
      "tokens": [
        "--header-h",
        "--header-h-condensed",
        "--frame",
        "--pad",
        "--type-nav",
        "--radius-md",
        "--brand-true",
        "--on-brand",
        "--surface-1",
        "--glass-fill-raised",
        "--glass-ring-raised",
        "--radius-2xl",
        "--elevation-3",
        "--space-2",
        "--duration-fast",
        "--surface-control",
        "--bg",
        "--radius-3xl",
        "--brand-blue",
        "--radius-full",
        "--glass-fill-hover",
        "--text",
        "--text-muted",
        "--border-rule",
        "--badge-alert",
        "--badge-alert-ink",
        "--header-fill",
        "--app-header-h",
        "--glass-fill-nav",
        "--glass-blur-nav",
        "--glass-shadow-nav",
        "--app-sticky-top",
        "--focus-ring",
        "--focus-ring-width",
        "--focus-ring-offset"
      ]
    },
    {
      "title": "Side navigation",
      "path": "/components/side-navigation",
      "url": "https://design.werklist.com/components/side-navigation",
      "text": "https://design.werklist.com/agent/components/side-navigation",
      "summary": "A list of places down the left edge that shows where you are: the blocks of a long page, or the workspaces and modules of WerkOS.",
      "version": "2.1.2",
      "kind": "component",
      "name": "Side navigation",
      "purpose": "A list of places on the left edge that marks the current one: the blocks of a long page, or the WerkOS rail and modules panel.",
      "use": [
        "Page list: pages with three or more blocks.",
        "Rail: switching WerkOS workspaces from 1024 px.",
        "Modules panel: the modules of the current workspace, grouped in folders."
      ],
      "avoid": [
        "Pages with fewer than three blocks and overview pages.",
        "More than two levels of hierarchy.",
        "Actions, filters or editing inside the list.",
        "Screens under 1024 px: WerkOS uses mobile navigation there, and a website page shows no page list."
      ],
      "anatomy": [
        {
          "part": "Page list",
          "measure": "columns 1 and 2 of the twelve column grid from 1024 px, with no fill, border or radius",
          "token": "--leftnav-w"
        },
        {
          "part": "Page list title",
          "measure": "the page title, 24 px on 32 px, weight 700, with 16 px under it. Plain text, not a heading and not a link",
          "token": "--text"
        },
        {
          "part": "Page list row",
          "measure": "36 px, padding 8 px by 16 px, 56 px when the label wraps to two lines",
          "token": "--type-nav, --space-4"
        },
        {
          "part": "Page list position",
          "measure": "sticks 24 px under the header and scrolls on its own when taller than the window",
          "token": "--space-6"
        },
        {
          "part": "Rail",
          "measure": "a floating glass panel 84 px wide, radius 24 px, 8 px in from the edges of the window. Its head holds the 22 px mark stroked in a blue gradient, 56 px high, 48 px on a short window",
          "token": "--radius-3xl, --glass-fill, --glass-highlight, --glass-ring, --glass-shadow-panel"
        },
        {
          "part": "Rail tile",
          "measure": "36 px icon box, radius 12 px, 17 px glyph, 10 px label at weight 500, tiles 12 px apart. On a window under 960 px high: 32 px box, 16 px glyph, 10 px apart",
          "token": "--radius-xl"
        },
        {
          "part": "Profile tile",
          "measure": "the last tile is the person's picture, 22 px, 20 px on a short window, with a 1 px ring",
          "token": "--border-rule"
        },
        {
          "part": "Modules panel",
          "measure": "232 px, radius 24 px, docked 6 px from the rail, pushes the content aside. Its head is 56 px, with the workspace glyph at 17 px in muted ink and the workspace name in bold",
          "token": "--glass-fill-panel, --glass-fill, --radius-3xl"
        },
        {
          "part": "Folder toggle",
          "measure": "14 px chevron in muted ink, turned 90 degrees when open. Title in bold, full ink. Padding 4 px by 6 px, radius 8 px",
          "token": "--text, --text-muted, --radius-lg"
        },
        {
          "part": "Module row",
          "measure": "36 px, padding 8 px, gap 10 px, radius 8 px, 18 px glyph, label 14 px at weight 500, rows 2 px apart",
          "token": "--radius-lg, --type-nav"
        },
        {
          "part": "Upcoming module",
          "measure": "the whole row at 60 percent, not a link, with the word Soon after the label and no pill",
          "token": "--text-muted, --type-caption"
        }
      ],
      "variants": [
        {
          "name": "Page list",
          "use": "Blocks of one page, with scroll spy."
        },
        {
          "name": "Rail",
          "use": "WerkOS workspaces and shared pages."
        },
        {
          "name": "Modules panel",
          "use": "Modules of the current workspace."
        }
      ],
      "states": [
        {
          "name": "Idle",
          "change": "Muted ink, glyph stroke 1.75",
          "tokens": [
            "--text-muted"
          ]
        },
        {
          "name": "Hover, page list",
          "change": "Fill at full radius, full ink",
          "tokens": [
            "--surface-control",
            "--text"
          ]
        },
        {
          "name": "Hover, rail and panel",
          "change": "Soft glass fill. A panel row keeps its muted ink, a rail label turns full ink",
          "tokens": [
            "--glass-fill-hover"
          ]
        },
        {
          "name": "Current, page list",
          "change": "1 px outline in full ink at full radius, full ink, aria-current location",
          "tokens": [
            "--text",
            "--radius-full"
          ]
        },
        {
          "name": "Current, rail and panel",
          "change": "Soft blue fill, full ink, glyph stroke 2, aria-current page. In the rail the fill glides to the new tile",
          "tokens": [
            "--nav-fill-active",
            "--text"
          ]
        },
        {
          "name": "Focus",
          "change": "2 px ring, drawn inside the tile in the rail",
          "tokens": [
            "--focus-ring"
          ]
        },
        {
          "name": "Panel closed",
          "change": "No width, out of the tab order and hidden from screen readers. Opens in 150 ms",
          "tokens": [
            "--duration-fast",
            "--ease-soft"
          ]
        },
        {
          "name": "Forced colors",
          "change": "The current WerkOS row also gets a 1 px outline, since fills are removed"
        }
      ],
      "keys": [
        {
          "key": "Tab",
          "action": "Next link"
        },
        {
          "key": "Enter",
          "action": "Follows the link. On the page list, scrolls to the block and focuses its heading"
        },
        {
          "key": "Enter or Space on a folder",
          "action": "Toggles the folder"
        }
      ],
      "accessibility": [
        "Landmarks: nav named On this page, nav named Main navigation for the rail, nav named Modules.",
        "Current link: aria-current location on the page list, page in the rail and the panel.",
        "Folder toggles are buttons with aria-expanded.",
        "A closed modules panel is inert and hidden from screen readers.",
        "After a jump, focus lands on the block heading, and the heading stops clear of the sticky header.",
        "Idle ink meets 4.5 to 1 on the page color in both themes.",
        "Upcoming rows carry aria-disabled true."
      ],
      "content": [
        "Row labels: the name people use for the place. Module names are proper names and keep their capitals: Global Projects, Job Board. Everything else is in sentence case.",
        "Folder titles: one short noun each, such as People or Organizations.",
        "Upcoming modules: the word Soon, as text."
      ],
      "tokens": [
        "--leftnav-w",
        "--type-nav",
        "--type-caption",
        "--space-4",
        "--text",
        "--text-muted",
        "--surface-control",
        "--radius-full",
        "--radius-lg",
        "--radius-xl",
        "--radius-3xl",
        "--nav-fill-active",
        "--glass-fill-hover",
        "--glass-fill-panel",
        "--glass-fill",
        "--glass-shadow-panel",
        "--glass-highlight",
        "--glass-ring",
        "--border-rule",
        "--focus-ring",
        "--space-6",
        "--duration-fast",
        "--ease-soft"
      ]
    },
    {
      "title": "Tabs",
      "path": "/components/tabs",
      "url": "https://design.werklist.com/components/tabs",
      "text": "https://design.werklist.com/agent/components/tabs",
      "summary": "Switch between panes of related content in one place on the screen, without leaving the page.",
      "version": "2.1.2",
      "kind": "component",
      "name": "Tabs",
      "purpose": "Switch between two to six panes of related content that share one place on the screen.",
      "use": [
        "The parts of one record, such as the profile, documents and interviews of a candidate.",
        "Lists inside one surface, such as All and Unread in a notifications tray."
      ],
      "avoid": [
        "Going to another page: use a link or navigation.",
        "Showing the same data another way (table, board, chart): use a segmented control.",
        "Running a command such as Send offer: use a button.",
        "Steps in a fixed order: use a form.",
        "More than six panes."
      ],
      "anatomy": [
        {
          "part": "Tab list",
          "measure": "a horizontal row with a name, 4 px between tabs",
          "token": "--space-1"
        },
        {
          "part": "Label",
          "measure": "13 px on 20 px, weight 500. A chosen line tab turns bold inside the width it always keeps"
        },
        {
          "part": "Line tab",
          "measure": "34 px high, 8 px at each side. On a touch screen at least 44 by 44 px, 16 px at each side",
          "token": "--space-2"
        },
        {
          "part": "Line",
          "measure": "2 px high, brand blue, 4 px in from the edges of the tab, rounded ends, on a 1 px rule under the whole row",
          "token": "--brand-blue, --border-rule, --radius-full"
        },
        {
          "part": "Filled tab",
          "measure": "36 px high, 44 px on a touch screen, 12 px at each side, radius 8 px. The chosen tab sits on the control fill",
          "token": "--surface-control, --radius-lg, --space-3"
        },
        {
          "part": "Icon",
          "measure": "16 px, 8 px before the label, on every tab or on none"
        },
        {
          "part": "Count",
          "measure": "a Counter 8 px after the label, in tabular digits, shown only above zero"
        },
        {
          "part": "Panel",
          "measure": "the pane of a tab, reachable with Tab when it holds nothing that takes focus"
        },
        {
          "part": "Phone select",
          "measure": "below 640 px, for a row that does not fit: 44 px, 16 px chevron, on the field fill of WerkOS. In light a faint ink wash with no edge, in dark a faint fill with a 1 px inset ring",
          "token": "--glass-fill-input, --input-border"
        }
      ],
      "variants": [
        {
          "name": "Line",
          "use": "Inside a tray or a raised panel."
        },
        {
          "name": "Filled",
          "use": "On a full screen or in a toolbar."
        }
      ],
      "states": [
        {
          "name": "Rest",
          "change": "Muted ink",
          "tokens": [
            "--text-muted"
          ]
        },
        {
          "name": "Hover",
          "change": "Full ink, no fill",
          "tokens": [
            "--text"
          ]
        },
        {
          "name": "Chosen, line",
          "change": "Full ink, weight 700, the blue line under it, aria-selected true",
          "tokens": [
            "--text",
            "--brand-blue"
          ]
        },
        {
          "name": "Chosen, filled",
          "change": "Full ink on the control fill, weight kept, aria-selected true",
          "tokens": [
            "--text",
            "--surface-control"
          ]
        },
        {
          "name": "Pressed, filled",
          "change": "Scales to 0.98, or holds still with reduced motion"
        },
        {
          "name": "Focus",
          "change": "2 px ring, 2 px offset",
          "tokens": [
            "--focus-ring"
          ]
        },
        {
          "name": "Line motion",
          "change": "Slides to the new tab in 200 ms, or moves at once with reduced motion",
          "tokens": [
            "--duration-base",
            "--ease-standard"
          ]
        },
        {
          "name": "Forced colors",
          "change": "The line is drawn in the system text color, and a chosen filled tab keeps a 1 px outline"
        }
      ],
      "keys": [
        {
          "key": "Tab",
          "action": "Enters the row at the chosen tab. The next Tab moves into the pane"
        },
        {
          "key": "ArrowLeft, ArrowRight",
          "action": "Previous or next tab. Chooses it at once when the pane shows at once"
        },
        {
          "key": "Home, End",
          "action": "First or last tab"
        },
        {
          "key": "Enter, Space",
          "action": "Chooses the focused tab when a pane has to load"
        }
      ],
      "accessibility": [
        "The row is a tablist with a name.",
        "Each tab: role tab, aria-selected, aria-controls its pane. Only the chosen tab is in the tab order.",
        "Each pane: role tabpanel, labelled by its tab.",
        "No tab is disabled. An empty pane says why it is empty.",
        "Rest ink meets 4.5 to 1 in both themes.",
        "A count is read as part of the name of its tab."
      ],
      "content": [
        "Nouns or short noun phrases in sentence case, parallel, without end punctuation: Profile, Documents, Interviews.",
        "One or two words each. Give a shorter phone label when a row does not fit at 360 px.",
        "Counts only above zero."
      ],
      "rules": [
        "Two to six tabs.",
        "Tabs never wrap or scroll sideways. Shorten the labels, and below 640 px replace the row with a select.",
        "A pane keeps its state while hidden, so a half written note survives a switch.",
        "Icons on every tab or on none."
      ],
      "tokens": [
        "--space-1",
        "--space-2",
        "--space-3",
        "--text",
        "--text-muted",
        "--brand-blue",
        "--border-rule",
        "--surface-control",
        "--radius-lg",
        "--radius-full",
        "--glass-fill-input",
        "--input-border",
        "--focus-ring",
        "--duration-base",
        "--ease-standard"
      ]
    },
    {
      "title": "Mobile navigation",
      "path": "/components/mobile-navigation",
      "url": "https://design.werklist.com/components/mobile-navigation",
      "text": "https://design.werklist.com/agent/components/mobile-navigation",
      "summary": "The glass bar at the bottom of a phone screen that switches between WerkOS workspaces.",
      "version": "2.1.2",
      "kind": "component",
      "name": "Mobile navigation",
      "purpose": "The floating glass bar at the bottom of a phone screen that switches between WerkOS workspaces.",
      "use": [
        "Below 1024 px, on the home screen, the module list of each workspace and the team pages.",
        "Inside a module: the module's own bar in the same place, or none, with the back arrow in the header."
      ],
      "avoid": [
        "Actions in the workspace bar.",
        "From 1024 px: the rail replaces it.",
        "The workspace bar and a module bar on the same screen."
      ],
      "anatomy": [
        {
          "part": "Place",
          "measure": "fixed to the bottom of the screen, 14 px above the bottom safe area, 8 px or the side safe area from each edge, whichever is larger. Hidden from 1024 px",
          "token": "--layer-header"
        },
        {
          "part": "Room kept",
          "measure": "the page keeps room for the tallest height of the bar. Floating buttons follow its current height",
          "token": "--bottom-nav-h, --bottom-nav-live-h"
        },
        {
          "part": "Bar",
          "measure": "69 px at rest, 52 px compact, radius 26 px. Padding 6 px, 4 px above and below when compact, 2 px between tabs",
          "token": "--glass-fill-nav, --glass-blur-nav, --glass-shadow-nav"
        },
        {
          "part": "Tab",
          "measure": "a link that shares the width equally, radius 16 px, at least 44 px wide. 57 px high at rest, 44 px compact"
        },
        {
          "part": "Icon box",
          "measure": "36 by 36 px"
        },
        {
          "part": "Glyph",
          "measure": "21 px, stroke 2 when selected, 1.75 when idle"
        },
        {
          "part": "Label",
          "measure": "9 px, weight 500, 4 px under the icon box. Folds away in 200 ms when the bar is compact"
        },
        {
          "part": "Selected capsule",
          "measure": "fills the icon box and glides to the tab you tap",
          "token": "--nav-tab-chip"
        },
        {
          "part": "Opaque fallback",
          "measure": "white in light, deep blue gray in dark, no blur"
        }
      ],
      "variants": [
        {
          "name": "Workspace bar",
          "use": "The top level on a phone, with no color."
        },
        {
          "name": "Module bar",
          "use": "The views of one module, in the same glass and tabs. Its Add tab keeps the blue disc."
        }
      ],
      "states": [
        {
          "name": "Rest",
          "change": "Labels shown, bar 69 px"
        },
        {
          "name": "Compact",
          "change": "After 24 px of scrolling down, once 40 px from the top, the labels fold and the bar is 52 px. The first scroll up brings them back"
        },
        {
          "name": "Selected",
          "change": "Capsule, full ink, stroke 2. The tab carries aria-current page only on its own screen",
          "tokens": [
            "--nav-tab-chip",
            "--text"
          ]
        },
        {
          "name": "Idle",
          "change": "Muted ink, stroke 1.75",
          "tokens": [
            "--text-muted"
          ]
        },
        {
          "name": "Pressed",
          "change": "Scales to 0.92, or holds still with reduced motion"
        },
        {
          "name": "Focus",
          "change": "2 px ring inside the tab",
          "tokens": [
            "--focus-ring"
          ]
        },
        {
          "name": "Typing",
          "change": "On a touch screen the bar steps aside while a field has focus"
        },
        {
          "name": "No blur, or reduced transparency",
          "change": "The opaque fallback"
        }
      ],
      "keys": [
        {
          "key": "Tab",
          "action": "Next workspace tab"
        },
        {
          "key": "Enter",
          "action": "Opens the workspace screen"
        }
      ],
      "accessibility": [
        "The bar is a navigation landmark named Main navigation.",
        "A tab carries aria-current page only on its own screen. On a team page the capsule shows the workspace you came from, and no tab claims the page.",
        "Folded labels stay in the name of each tab.",
        "Targets at least 44 by 44 px.",
        "Idle ink meets 4.5 to 1 in both themes. The capsule is a faint fill, so ink and stroke weight carry the selection."
      ],
      "content": [
        "One word per workspace label: Home, Projects, Intranet, Werkbook, Finance, Network.",
        "A longer label ends in an ellipsis."
      ],
      "rules": [
        "No border or halo on the glass. The shadow alone separates the bar from the page.",
        "Pad the page with --bottom-nav-h. Place floating buttons with --bottom-nav-live-h."
      ],
      "tokens": [
        "--layer-header",
        "--glass-fill-nav",
        "--glass-blur-nav",
        "--glass-shadow-nav",
        "--nav-tab-chip",
        "--text",
        "--text-muted",
        "--focus-ring",
        "--bottom-nav-h",
        "--bottom-nav-live-h"
      ]
    },
    {
      "title": "Command palette",
      "path": "/components/command-palette",
      "url": "https://design.werklist.com/components/command-palette",
      "text": "https://design.werklist.com/agent/components/command-palette",
      "summary": "A search that opens over any WerkOS screen and takes you straight to a module or a record.",
      "version": "2.1.2",
      "kind": "component",
      "name": "Command palette",
      "purpose": "A modal search, opened with ⌘K or Ctrl+K from any WerkOS screen, that jumps to a module or a record.",
      "use": [
        "Reaching a module or a record by name from anywhere.",
        "Before a letter is typed it lists the modules you can open, so it also serves as a jump list."
      ],
      "avoid": [
        "Narrowing the list on the current page: use that page's search field.",
        "Commands that change data: actions stay in toolbars.",
        "In place of the rail and the modules panel."
      ],
      "anatomy": [
        {
          "part": "Layer",
          "measure": "over the whole window, the panel 12 percent of the window from the top, 16 px from the sides",
          "token": "--layer-dialog"
        },
        {
          "part": "Backdrop",
          "measure": "dimmed and blurred 8 px. A click on it closes the palette",
          "token": "--overlay"
        },
        {
          "part": "Panel",
          "measure": "up to 512 px wide, radius 16 px, no border. In dark it adds the glass highlight and a 0.5 px ring, in light the shadow alone",
          "token": "--radius-2xl, --glass-fill-raised, --glass-shadow-raised, --glass-highlight, --glass-ring-raised"
        },
        {
          "part": "Field row",
          "measure": "52 px, padding 12 px by 16 px, 16 px search glyph, gap 10 px, text 14 px, 16 px on a touch screen. A 16 px spinner at the end while a search runs",
          "token": "--text-muted"
        },
        {
          "part": "Separator",
          "measure": "1 px under the field row, because the list scrolls beneath it",
          "token": "--border-rule"
        },
        {
          "part": "List",
          "measure": "up to 60 percent of the window high, padding 8 px, with its own scroll"
        },
        {
          "part": "Row",
          "measure": "40 px, padding 10 px by 12 px, radius 8 px, 18 px glyph in muted ink, gap 12 px, title 14 px",
          "token": "--radius-lg, --text, --text-muted"
        },
        {
          "part": "Row with context",
          "measure": "54 px, padding 8 px by 12 px, second line 12 px on 18 px. Each line ends in an ellipsis when it is too long",
          "token": "--text-muted"
        },
        {
          "part": "Group title",
          "measure": "13 px on 20 px, weight 500, padding 8 px 12 px 4 px",
          "token": "--text-label"
        },
        {
          "part": "Placeholder rows",
          "measure": "four rows 34 px high, 4 px apart, each an 18 px square and a 12 px bar at 70, 60, 50 and 40 percent, radius 4 px, pulsing",
          "token": "--glass-fill-hover, --radius-sm"
        }
      ],
      "states": [
        {
          "name": "Empty query",
          "change": "Lists the modules you can open"
        },
        {
          "name": "One character",
          "change": "The module list stays"
        },
        {
          "name": "Searching",
          "change": "From 2 characters, after a 120 ms pause. The newest query wins. Four placeholder rows hold the place until the first results"
        },
        {
          "name": "Results",
          "change": "Grouped by where they live",
          "tokens": [
            "--text-label"
          ]
        },
        {
          "name": "No results",
          "change": "No results for “{query}”, with 40 px of padding",
          "tokens": [
            "--text-muted"
          ]
        },
        {
          "name": "Failed",
          "change": "Search did not finish, with a quiet Try again button"
        },
        {
          "name": "Active row",
          "change": "Soft fill, the same for pointer and keyboard, aria-selected true, kept in view",
          "tokens": [
            "--glass-fill-hover"
          ]
        },
        {
          "name": "Enter and exit",
          "change": "Fades in with a 12 px rise from a scale of 0.97, and leaves quicker than it came. With reduced motion it only fades"
        }
      ],
      "keys": [
        {
          "key": "⌘K (Mac), Ctrl+K (Windows, Linux)",
          "action": "Opens or closes the palette"
        },
        {
          "key": "ArrowDown, ArrowUp",
          "action": "Moves the active row and keeps it in view. Stops at the first and the last row"
        },
        {
          "key": "Enter",
          "action": "Opens the active row"
        },
        {
          "key": "Escape",
          "action": "Closes the palette when it is the front layer. Focus returns to where it was"
        },
        {
          "key": "Tab",
          "action": "Stays inside the dialog"
        }
      ],
      "accessibility": [
        "Panel: role dialog, aria-modal true, named Search.",
        "Field: role combobox that controls the list and points to the active option with aria-activedescendant.",
        "List: role listbox. Each group is named by its title, and each row is an option with aria-selected.",
        "A polite live region says how many results arrived, or No results.",
        "Group titles meet 4.5 to 1 on the panel, and muted ink meets 4.5 to 1 on the active row, in both themes."
      ],
      "content": [
        "Placeholder: Search everything…",
        "Rows: the name people know. A second line only when two results could be confused.",
        "Group titles: the place. A module keeps its proper name with its capitals, such as Global Projects. Any other title is in sentence case: Modules, Files.",
        "Empty: No results for “{query}”. Failed: Search did not finish. Try again."
      ],
      "tokens": [
        "--layer-dialog",
        "--overlay",
        "--radius-2xl",
        "--radius-lg",
        "--glass-fill-raised",
        "--glass-shadow-raised",
        "--glass-fill-hover",
        "--glass-highlight",
        "--glass-ring-raised",
        "--border-rule",
        "--text",
        "--text-muted",
        "--text-label",
        "--focus-ring"
      ]
    },
    {
      "title": "Dialog",
      "path": "/components/dialog",
      "url": "https://design.werklist.com/components/dialog",
      "text": "https://design.werklist.com/agent/components/dialog",
      "summary": "A dialog stops the page for a decision or a short task that has to come first.",
      "version": "2.1.2",
      "kind": "component",
      "name": "Dialog",
      "purpose": "Stops the page for a decision or a short task and returns focus to the control that opened it.",
      "use": [
        "A decision the page cannot go on without, such as deleting a candidate for good",
        "A short form that belongs to one moment, such as adding a task",
        "A record with its history, in the large size"
      ],
      "avoid": [
        "An action that can be undone: act at once and offer Undo in a toast",
        "Details read beside the page: use a side sheet",
        "A few controls for one item: use a popover",
        "Information that needs no answer: use a toast or an inline message",
        "A dialog opened from a dialog, except a confirmation about the dialog beneath"
      ],
      "anatomy": [
        {
          "part": "Layer",
          "measure": "covers the whole window, above the page",
          "token": "--layer-dialog"
        },
        {
          "part": "Scrim",
          "measure": "no blur, fades in over 150 ms",
          "token": "--overlay"
        },
        {
          "part": "Margin to the window",
          "measure": "24 px",
          "token": "--space-6"
        },
        {
          "part": "Panel",
          "measure": "radius 16 px, at most 92 percent of the window high",
          "token": "--glass-fill-raised, --glass-blur-raised, --elevation-3, --radius-2xl"
        },
        {
          "part": "Panel edge, dark theme",
          "measure": "a 1 px top highlight and a 0.5 px ring over the shadow. The light theme shows the shadow alone",
          "token": "--glass-highlight, --glass-ring-raised"
        },
        {
          "part": "Header",
          "measure": "padding 16 px top, 20 px left, 12 px right",
          "token": "--space-4, --space-5, --space-3"
        },
        {
          "part": "Title",
          "measure": "h2, 17 px on a 24 px line, weight 700",
          "token": "--text"
        },
        {
          "part": "Description",
          "measure": "14 px on 22 px, 4 px below the title",
          "token": "--type-small, --text-muted"
        },
        {
          "part": "Close button",
          "measure": "icon button, 32 px, 44 px on touch screens, with a 16 px cross"
        },
        {
          "part": "Body",
          "measure": "padding 8 px top, 20 px sides, 20 px bottom without a footer, 8 px with one. Scrolls on its own, and the page behind stays still",
          "token": "--space-2, --space-5, --type-small, --text"
        },
        {
          "part": "Footer",
          "measure": "padding 16 px top and bottom, 20 px sides. Actions at the end, 8 px apart",
          "token": "--space-4, --space-5, --space-2"
        },
        {
          "part": "Footer buttons",
          "measure": "36 px high, 44 px on touch screens"
        },
        {
          "part": "Line while scrolled",
          "measure": "1 px under the header while content is hidden above, above the footer while content is hidden below",
          "token": "--border-rule"
        }
      ],
      "variants": [
        {
          "name": "Standard",
          "use": "A form or content. role dialog, close button, closes on a scrim click when nothing is typed"
        },
        {
          "name": "Confirmation",
          "use": "A question before an action that cannot be undone. role alertdialog, small size, no close button, the scrim does nothing, focus starts on Cancel, the verb takes the danger button when it deletes"
        }
      ],
      "sizes": [
        {
          "name": "Small, 448 px wide: confirmations and notices"
        },
        {
          "name": "Medium, 512 px wide: forms"
        },
        {
          "name": "Large, 896 px wide: a record with its history"
        },
        {
          "name": "Below 640 px: a bottom sheet. Large fills the screen inside the safe areas"
        }
      ],
      "states": [
        {
          "name": "Opening",
          "change": "The scrim fades in over 150 ms. The panel fades in, grows from 97 percent and rises 8 px, over 200 ms",
          "tokens": [
            "--duration-fast",
            "--duration-base",
            "--ease-soft"
          ]
        },
        {
          "name": "Closing",
          "change": "Reverse, over 150 ms",
          "tokens": [
            "--duration-fast",
            "--ease-standard"
          ]
        },
        {
          "name": "Reduced motion",
          "change": "Opacity only",
          "tokens": [
            "--duration-fast"
          ]
        },
        {
          "name": "Scrolled",
          "change": "The 1 px line shows under the header or above the footer while content is hidden behind it",
          "tokens": [
            "--border-rule"
          ]
        },
        {
          "name": "Busy",
          "change": "The completing button is busy at once (aria-busy, presses ignored) and shows its spinner after 300 ms. The rest of the dialog stays usable",
          "tokens": [
            "--duration-slow"
          ]
        },
        {
          "name": "Save failed",
          "change": "A message in the error tone at the top of the body, role alert. The entries stay as typed and focus stays on the button",
          "tokens": [
            "--error-ink"
          ]
        },
        {
          "name": "Invalid entry",
          "change": "After a failed submit, focus moves to the first field with an error, and its message sits under that field"
        },
        {
          "name": "Content loading",
          "change": "Header and footer show at once over a skeleton of the body"
        },
        {
          "name": "Unsaved entries",
          "change": "Escape, the close button, a scrim click and a swipe open the confirmation Discard the changes? with Keep editing and Discard. Cancel closes without asking"
        }
      ],
      "keys": [
        {
          "key": "Tab",
          "action": "Next control. From the last back to the first"
        },
        {
          "key": "Shift+Tab",
          "action": "Previous control. From the first to the last"
        },
        {
          "key": "Enter in a single line field",
          "action": "Submits the form"
        },
        {
          "key": "Enter or Space on a button",
          "action": "Activates it"
        },
        {
          "key": "Escape",
          "action": "Closes the front layer only. Asks first when entries are unsaved. In a confirmation, answers Cancel"
        }
      ],
      "accessibility": [
        "role dialog or alertdialog, aria-modal true, aria-labelledby the title. Aria-describedby the body of a confirmation",
        "Focus on open: the first field of a form, Cancel in a confirmation, the panel itself (tabindex -1) when it only shows content",
        "Tab reaches only the controls that show in the dialog",
        "Focus on close: the control that opened the dialog, if it is still on the page. Otherwise the next row, the previous row, then the list",
        "The page behind ignores the pointer, keys and screen readers, and does not scroll or shift sideways",
        "The close button is named Close",
        "Controls at least 44 px high on touch screens",
        "In forced colors mode the panel draws a 1 px outline in the system text color",
        "Escape reaches the front layer only, so a menu open inside the dialog closes before the dialog"
      ],
      "content": [
        "The title names the task or asks the question. No end punctuation except a question mark",
        "The body adds only what the title cannot hold and starts with the consequence",
        "Buttons answer the title with a verb, plus a noun when the verb alone is ambiguous. Cancel is always Cancel. No OK, Yes or No",
        "Example: Delete this candidate permanently? / Sunita Rai's CV, passport scan and interview notes are removed now and cannot be restored / Cancel, Delete candidate",
        "Save failed message: The task was not added. Try again"
      ],
      "tokens": [
        "--layer-dialog",
        "--overlay",
        "--glass-fill-raised",
        "--glass-blur-raised",
        "--glass-highlight",
        "--glass-ring-raised",
        "--elevation-3",
        "--radius-2xl",
        "--space-2",
        "--space-3",
        "--space-4",
        "--space-5",
        "--space-6",
        "--type-small",
        "--text",
        "--text-muted",
        "--border-rule",
        "--error-ink",
        "--duration-fast",
        "--duration-base",
        "--duration-slow",
        "--ease-soft",
        "--ease-standard",
        "--focus-ring"
      ]
    },
    {
      "title": "Sheet",
      "path": "/components/sheet",
      "url": "https://design.werklist.com/components/sheet",
      "text": "https://design.werklist.com/agent/components/sheet",
      "summary": "A sheet is a dialog that enters from the bottom of a phone or the right edge of a wide window.",
      "version": "2.1.2",
      "kind": "component",
      "name": "Sheet",
      "purpose": "A dialog that enters from an edge: from the bottom on phones, from the right on wide screens.",
      "use": [
        "The phone form of a dialog, below 640 px",
        "A popover that holds a form, on a touch screen below 640 px",
        "Details or settings read beside the page, as a side sheet from the right",
        "A long list tied to the page, such as members or history"
      ],
      "avoid": [
        "A task that needs full attention on a wide screen: use a dialog",
        "A side sheet from the left edge: that edge belongs to navigation",
        "A second sheet over the first: close it first",
        "A task in several steps with a Back button: make it a page"
      ],
      "anatomy": [
        {
          "part": "Frame, bottom",
          "measure": "full width. Height fits the content, up to 92 percent of the window"
        },
        {
          "part": "Frame, bottom, full height",
          "measure": "the whole window inside the top and bottom safe areas. For large dialogs and forms longer than the window"
        },
        {
          "part": "Top corners, bottom sheet",
          "measure": "16 px",
          "token": "--radius-2xl"
        },
        {
          "part": "Grabber",
          "measure": "40 by 4 px, centered, 10 px from the top edge. Only when the sheet can be swiped",
          "token": "--surface-control, --radius-full"
        },
        {
          "part": "Bottom padding",
          "measure": "the bottom safe area, at least 12 px",
          "token": "--space-3"
        },
        {
          "part": "Frame, side",
          "measure": "right edge, full window height, 448 px wide. Full width below 640 px"
        },
        {
          "part": "Header, body, footer",
          "measure": "as in a dialog. The close button is 44 px on phones",
          "token": "--space-4, --space-5"
        },
        {
          "part": "Surface",
          "measure": "raised fill and shadow, near opaque. In the dark theme a 1 px top highlight and a 0.5 px ring",
          "token": "--glass-fill-raised, --elevation-3, --glass-highlight, --glass-ring-raised"
        },
        {
          "part": "Scrim",
          "measure": "no blur",
          "token": "--overlay"
        }
      ],
      "variants": [
        {
          "name": "Bottom",
          "use": "Below 640 px, the form every dialog takes. Swipe to close"
        },
        {
          "name": "Bottom, full height",
          "use": "Large dialogs and forms longer than the window"
        },
        {
          "name": "Side",
          "use": "From the right on wide screens, for details and settings read beside the page"
        }
      ],
      "sizes": [
        {
          "name": "Side, 448 px wide"
        },
        {
          "name": "Bottom, content height up to 92 percent of the window"
        },
        {
          "name": "Bottom, full height inside the safe areas"
        }
      ],
      "states": [
        {
          "name": "Opening, bottom",
          "change": "Rises from below the window edge over 300 ms",
          "tokens": [
            "--duration-slow",
            "--ease-soft"
          ]
        },
        {
          "name": "Closing, bottom",
          "change": "Falls back below the edge over 200 ms",
          "tokens": [
            "--duration-base",
            "--ease-standard"
          ]
        },
        {
          "name": "Opening, side",
          "change": "Fades in while traveling 40 px from the right, over 200 ms",
          "tokens": [
            "--duration-base",
            "--ease-soft"
          ]
        },
        {
          "name": "Closing, side",
          "change": "Reverse, over 150 ms",
          "tokens": [
            "--duration-fast",
            "--ease-standard"
          ]
        },
        {
          "name": "Dragging",
          "change": "Follows the finger downward at 70 percent of its travel. Upward travel does nothing. Released short of 90 px and slower than 500 px per second, it springs back"
        },
        {
          "name": "Unsaved entries",
          "change": "A swipe springs back and asks Discard the changes? first"
        },
        {
          "name": "Reduced motion",
          "change": "A fade only",
          "tokens": [
            "--duration-fast"
          ]
        },
        {
          "name": "Scrolled",
          "change": "As in a dialog: the 1 px line under the header or above the footer while content is hidden behind it",
          "tokens": [
            "--border-rule"
          ]
        }
      ],
      "keys": [
        {
          "key": "Tab, Shift+Tab",
          "action": "Move within the sheet, wrapping"
        },
        {
          "key": "Escape",
          "action": "Closes the sheet, or asks first when entries are unsaved"
        },
        {
          "key": "Enter in a single line field",
          "action": "Submits the form"
        }
      ],
      "accessibility": [
        "As a dialog: role dialog, aria-modal true, labeled by its title, focus kept inside and returned on close, the page behind out of reach",
        "The grabber is aria-hidden. The close button, named Close, does the same job",
        "Swipe starts only from the grabber or the header, so scrolling the body never closes the sheet",
        "Controls at least 44 px high on phones"
      ],
      "content": [
        "The title and the buttons follow the rules of a dialog"
      ],
      "tokens": [
        "--overlay",
        "--glass-fill-raised",
        "--glass-highlight",
        "--glass-ring-raised",
        "--elevation-3",
        "--radius-2xl",
        "--radius-full",
        "--surface-control",
        "--space-2",
        "--space-3",
        "--space-4",
        "--space-5",
        "--border-rule",
        "--duration-fast",
        "--duration-base",
        "--duration-slow",
        "--ease-soft",
        "--ease-standard"
      ]
    },
    {
      "title": "Popover",
      "path": "/components/popover",
      "url": "https://design.werklist.com/components/popover",
      "text": "https://design.werklist.com/agent/components/popover",
      "summary": "A popover shows a few controls or details for one item beside the control that opened it, and the page stays usable.",
      "version": "2.1.2",
      "kind": "component",
      "name": "Popover",
      "purpose": "A non modal layer anchored to its trigger that holds a few controls or details for one item.",
      "use": [
        "A small task on one item, such as rescheduling an interview or logging a call with a candidate",
        "Details of one item that people glance at and close",
        "A short form tied to a row, on wide screens"
      ],
      "avoid": [
        "A name or a shortcut: use a tooltip",
        "A list of commands: use a menu",
        "A decision that must come first: use a dialog",
        "A warning: use a dialog or an inline message",
        "A popover opened from a popover",
        "Opening on hover: a popover opens on a click or a key"
      ],
      "anatomy": [
        {
          "part": "Layer",
          "measure": "above the page",
          "token": "--layer-popover"
        },
        {
          "part": "Width",
          "measure": "from the trigger's width to 404 px, and at most the window width less 16 px"
        },
        {
          "part": "Padding",
          "measure": "12 px",
          "token": "--space-3"
        },
        {
          "part": "Radius",
          "measure": "12 px",
          "token": "--radius-xl"
        },
        {
          "part": "Title, optional",
          "measure": "14 px on 20 px, weight 500",
          "token": "--type-nav, --text"
        },
        {
          "part": "Body text",
          "measure": "14 px on 22 px",
          "token": "--type-small, --text"
        },
        {
          "part": "Buttons",
          "measure": "36 px high, 44 px on touch screens"
        },
        {
          "part": "Gap to the trigger",
          "measure": "8 px",
          "token": "--space-2"
        },
        {
          "part": "Window margin",
          "measure": "8 px",
          "token": "--space-2"
        },
        {
          "part": "Placement",
          "measure": "below the trigger with the start edges aligned, or the end edges for a trigger at the end of a row. Upward when less than 280 px remain below and there is more room above. Never over its own trigger"
        },
        {
          "part": "Maximum height",
          "measure": "70 percent of the window, or the room on its side when that is less. The content scrolls on its own"
        },
        {
          "part": "Surface with a mouse",
          "measure": "raised fill and shadow. In the dark theme a 1 px top highlight and a 0.5 px ring",
          "token": "--glass-fill-raised, --elevation-3, --glass-highlight, --glass-ring-raised"
        },
        {
          "part": "Surface on a touch screen",
          "measure": "opaque, no blur",
          "token": "--surface-1"
        }
      ],
      "variants": [
        {
          "name": "Anchored",
          "use": "Wide screens and details on phones"
        },
        {
          "name": "As a bottom sheet",
          "use": "A popover that holds a form or more than one control, on a touch screen below 640 px"
        }
      ],
      "states": [
        {
          "name": "Opening",
          "change": "Fades in over 150 ms, moving 4 px away from the trigger and growing from 98 percent",
          "tokens": [
            "--duration-fast",
            "--ease-soft"
          ]
        },
        {
          "name": "Closing",
          "change": "Reverse over 150 ms",
          "tokens": [
            "--duration-fast",
            "--ease-standard"
          ]
        },
        {
          "name": "Reduced motion",
          "change": "Opacity only",
          "tokens": [
            "--duration-fast"
          ]
        },
        {
          "name": "Trigger open",
          "change": "aria-expanded true on the trigger"
        }
      ],
      "keys": [
        {
          "key": "Enter or Space on the trigger",
          "action": "Opens the popover, focus on its first control"
        },
        {
          "key": "Tab, Shift+Tab",
          "action": "Move through the popover. Leaving it closes it and continues in page order after the trigger"
        },
        {
          "key": "Escape",
          "action": "Closes it, focus back on the trigger"
        }
      ],
      "accessibility": [
        "role dialog without aria-modal. Aria-labelledby its title or an aria-label naming the object, such as Interview with Sunita Rai",
        "Trigger: aria-haspopup dialog, aria-expanded, aria-controls",
        "Focus moves in on open and back to the trigger on Escape. The popover itself takes tabindex -1 when it has no control",
        "Nothing the task depends on lives only in a popover",
        "One popover or menu open at a time. Escape closes the front layer first"
      ],
      "content": [
        "A title of a few words, the details, one or two actions",
        "The content may end with one link to the full record, which opens in the same tab",
        "No warnings"
      ],
      "tokens": [
        "--layer-popover",
        "--glass-fill-raised",
        "--glass-highlight",
        "--glass-ring-raised",
        "--elevation-3",
        "--surface-1",
        "--radius-xl",
        "--space-2",
        "--space-3",
        "--type-nav",
        "--type-small",
        "--text",
        "--duration-fast",
        "--ease-soft",
        "--ease-standard"
      ]
    },
    {
      "title": "Menu",
      "path": "/components/menu",
      "url": "https://design.werklist.com/components/menu",
      "text": "https://design.werklist.com/agent/components/menu",
      "summary": "A menu lists the commands for an item or a view and closes as soon as one is picked.",
      "version": "2.1.2",
      "kind": "component",
      "name": "Menu",
      "purpose": "Lists the commands for an item or a view, and short settings as rows to choose from.",
      "use": [
        "Commands that do not earn a place on the toolbar",
        "A short setting such as the sort order, as rows where one applies",
        "Visible columns or filters, as rows where several apply",
        "The context menu of a row or a card"
      ],
      "avoid": [
        "A value for a form field: use a select or a combobox",
        "A few controls for one item: use a popover",
        "A list of destinations: that is navigation",
        "A submenu of dozens of entries: open a combobox",
        "Leading icons on rows"
      ],
      "anatomy": [
        {
          "part": "Layer",
          "measure": "above the page",
          "token": "--layer-popover"
        },
        {
          "part": "Width",
          "measure": "200 to 300 px from the longest label"
        },
        {
          "part": "Padding around rows",
          "measure": "4 px",
          "token": "--space-1"
        },
        {
          "part": "Panel radius",
          "measure": "12 px",
          "token": "--radius-xl"
        },
        {
          "part": "Row radius",
          "measure": "8 px",
          "token": "--radius-lg"
        },
        {
          "part": "Row height",
          "measure": "36 px, 44 px on touch screens"
        },
        {
          "part": "Row padding",
          "measure": "10 px each side"
        },
        {
          "part": "Label",
          "measure": "13 px on 20 px, weight 400",
          "token": "--type-caption, --text"
        },
        {
          "part": "Shortcut",
          "measure": "11 px on 16 px, tabular, at the row's end, at least 10 px from the label. Not in context menus",
          "token": "--text-muted"
        },
        {
          "part": "Check",
          "measure": "16 px check at the row's end, in the brand blue",
          "token": "--brand-blue"
        },
        {
          "part": "Submenu chevron",
          "measure": "16 px chevron pointing right, at the row's end",
          "token": "--text-muted"
        },
        {
          "part": "Separator",
          "measure": "1 px with 4 px above and below",
          "token": "--border-rule"
        },
        {
          "part": "Group label",
          "measure": "13 px on 20 px, 10 px inset, sentence case",
          "token": "--type-caption, --text-label"
        },
        {
          "part": "Surface with a mouse",
          "measure": "raised fill and shadow. In the dark theme a 1 px top highlight and a 0.5 px ring",
          "token": "--glass-fill-raised, --elevation-3, --glass-highlight, --glass-ring-raised"
        },
        {
          "part": "Surface on a touch screen",
          "measure": "opaque, no blur",
          "token": "--surface-1"
        },
        {
          "part": "Maximum height",
          "measure": "70 percent of the window, or the room on its side when that is less. The rows scroll on their own"
        }
      ],
      "variants": [
        {
          "name": "Command",
          "use": "menuitem. Runs and closes"
        },
        {
          "name": "Choose one",
          "use": "menuitemradio in a group. The chosen row carries the check. A pick closes"
        },
        {
          "name": "Choose several",
          "use": "menuitemcheckbox. A pick toggles the check and the menu stays open"
        },
        {
          "name": "Context menu",
          "use": "Opened at the pointer by a right click, or at the focused row by Shift+F10 or the Menu key. Relevant commands only. Unavailable ones hidden. No shortcuts"
        },
        {
          "name": "Submenu",
          "use": "One level, a handful of rows, opens to the side of its row"
        }
      ],
      "states": [
        {
          "name": "Rest",
          "change": "No fill"
        },
        {
          "name": "Hover",
          "change": "A fill of the text color at 6 percent in dark, 5.5 percent in light, with a mouse only"
        },
        {
          "name": "Keyboard focus",
          "change": "2 px ring inset in the row",
          "tokens": [
            "--focus-ring",
            "--focus-ring-width"
          ]
        },
        {
          "name": "Pressed",
          "change": "Fill",
          "tokens": [
            "--glass-fill-active"
          ]
        },
        {
          "name": "Unavailable, button menu",
          "change": "Label in muted ink at half opacity, no hover fill, aria-disabled true, still focusable. Full opacity while it holds keyboard focus",
          "tokens": [
            "--text-muted"
          ]
        },
        {
          "name": "Unavailable, context menu",
          "change": "Hidden"
        },
        {
          "name": "Checked",
          "change": "The check shows and aria-checked is true",
          "tokens": [
            "--brand-blue"
          ]
        },
        {
          "name": "Trigger open",
          "change": "Control fill and aria-expanded true",
          "tokens": [
            "--surface-control"
          ]
        },
        {
          "name": "Opening",
          "change": "Fades in over 150 ms while it moves 4 px away from the trigger and grows from 98 percent",
          "tokens": [
            "--duration-fast",
            "--ease-soft"
          ]
        },
        {
          "name": "Closing",
          "change": "Reverse over 150 ms",
          "tokens": [
            "--duration-fast",
            "--ease-standard"
          ]
        }
      ],
      "keys": [
        {
          "key": "Enter, Space or Down arrow on the trigger",
          "action": "Opens, focus on the first row"
        },
        {
          "key": "Up arrow on the trigger",
          "action": "Opens, focus on the last row"
        },
        {
          "key": "Down arrow, Up arrow",
          "action": "Next or previous row, wrapping"
        },
        {
          "key": "Home, End",
          "action": "First or last row"
        },
        {
          "key": "A letter",
          "action": "Next row that starts with it"
        },
        {
          "key": "Enter or Space",
          "action": "Runs the row, or toggles a checkbox row"
        },
        {
          "key": "Right arrow on a submenu row",
          "action": "Opens the submenu on its first row"
        },
        {
          "key": "Left arrow or Escape in a submenu",
          "action": "Closes the submenu only"
        },
        {
          "key": "Escape",
          "action": "Closes the menu, focus to the trigger"
        },
        {
          "key": "Tab",
          "action": "Closes the menu and moves on"
        },
        {
          "key": "Shift+F10 or the Menu key",
          "action": "Opens the context menu of the focused row"
        }
      ],
      "accessibility": [
        "role menu with aria-labelledby the trigger. A context menu takes an aria-label naming the item, such as Actions for Sunita Rai",
        "Rows menuitem, menuitemcheckbox or menuitemradio, with aria-checked on the last two. Role separator. A named group is role group with aria-labelledby",
        "Trigger and submenu rows: aria-haspopup menu, aria-expanded, aria-controls",
        "Focus moves from row to row, so a screen reader reads each row as it is reached",
        "A menu holds no form fields",
        "Rows 44 px high on touch screens",
        "One menu or popover open at a time. Escape closes a submenu before the menu"
      ],
      "content": [
        "A verb first, sentence case, no full stop",
        "The noun follows when the verb alone is ambiguous: Move to group, Send offer",
        "The same words for a command in the menu, the toolbar and the context menu",
        "No ellipsis. The dialog that opens carries its own title",
        "Destructive commands last, in their own group"
      ],
      "tokens": [
        "--layer-popover",
        "--glass-fill-raised",
        "--glass-ring-raised",
        "--elevation-3",
        "--surface-1",
        "--surface-control",
        "--radius-xl",
        "--radius-lg",
        "--space-1",
        "--space-2",
        "--type-caption",
        "--text",
        "--text-muted",
        "--text-label",
        "--brand-blue",
        "--error-ink",
        "--border-rule",
        "--glass-highlight",
        "--glass-fill-active",
        "--focus-ring",
        "--focus-ring-width",
        "--duration-fast",
        "--ease-soft",
        "--ease-standard"
      ]
    },
    {
      "title": "Tooltip",
      "path": "/components/tooltip",
      "url": "https://design.werklist.com/components/tooltip",
      "text": "https://design.werklist.com/agent/components/tooltip",
      "summary": "A tooltip names an icon button or shows its shortcut when the pointer rests on it or the keyboard reaches it.",
      "version": "2.1.2",
      "kind": "component",
      "name": "Tooltip",
      "purpose": "One line of text next to a control, shown on pointer rest or keyboard focus, that names it, shows its shortcut, shows a truncated value in full or says why it is unavailable.",
      "use": [
        "An icon button without a visible label",
        "A control with a keyboard shortcut",
        "A truncated value, to show it in full",
        "An unavailable control, to say what would make it available"
      ],
      "avoid": [
        "Anything people need to finish a task",
        "Links, buttons or formatted text: use a popover",
        "System feedback: use a toast or an inline message",
        "Touch screens: tooltips do not show there",
        "Repeating a visible label",
        "Tips that open by themselves to teach a feature"
      ],
      "anatomy": [
        {
          "part": "Layer",
          "measure": "above the page",
          "token": "--layer-popover"
        },
        {
          "part": "Text",
          "measure": "12 px on an 18 px line, weight 400",
          "token": "--text"
        },
        {
          "part": "Padding",
          "measure": "4 px above and below, 8 px at the sides",
          "token": "--space-1, --space-2"
        },
        {
          "part": "Height",
          "measure": "26 px, 30 px with a keycap"
        },
        {
          "part": "Radius",
          "measure": "8 px",
          "token": "--radius-lg"
        },
        {
          "part": "Surface",
          "measure": "translucent glass under a 36 px blur, with an inset top highlight, a 1 px inset rim and a soft shadow. Solid where the blur cannot render or transparency is reduced"
        },
        {
          "part": "Gap and window margin",
          "measure": "8 px and at least 8 px",
          "token": "--space-2"
        },
        {
          "part": "Maximum width",
          "measure": "the window width less 16 px"
        },
        {
          "part": "Keycap",
          "measure": "11 px on a 16 px line, weight 500, tabular, at least 26 px wide, 22 px high, radius 6 px, a 1 px inset edge in the border ink",
          "token": "--surface-control, --border, --text-label, --radius-md"
        }
      ],
      "states": [
        {
          "name": "Showing on pointer rest",
          "change": "After 500 ms, fades in over 150 ms with 4 px of travel away from the control",
          "tokens": [
            "--duration-fast",
            "--ease-soft"
          ]
        },
        {
          "name": "Showing on keyboard focus",
          "change": "At once, same fade",
          "tokens": [
            "--duration-fast"
          ]
        },
        {
          "name": "Moving between triggers",
          "change": "The next shows at once while one is showing"
        },
        {
          "name": "Hiding",
          "change": "When the pointer leaves both the control and the tooltip, when focus leaves, on Escape, on a press. Fades over 150 ms",
          "tokens": [
            "--duration-fast",
            "--ease-standard"
          ]
        },
        {
          "name": "Reduced motion",
          "change": "The fade stays, the travel goes",
          "tokens": [
            "--duration-fast"
          ]
        },
        {
          "name": "Touch screen",
          "change": "Does not show"
        }
      ],
      "keys": [
        {
          "key": "Tab onto the control",
          "action": "Shows the tooltip at once"
        },
        {
          "key": "Escape",
          "action": "Hides the tooltip. Focus stays on the control"
        }
      ],
      "accessibility": [
        "role tooltip with an id. The control references it with aria-describedby when the tooltip adds to the name",
        "When the tooltip repeats an icon button's aria-label, the tooltip is aria-hidden true",
        "aria-keyshortcuts on the control for its shortcut",
        "Unavailable controls that explain themselves use aria-disabled true, not disabled, so they receive hover and focus",
        "The native title attribute is removed from any control with a tooltip",
        "People can move the pointer onto the tooltip. It stays while hovered or focused and does not time out",
        "Escape hides the tooltip before it closes anything behind it"
      ],
      "content": [
        "A verb phrase or a noun phrase in sentence case, with no full stop",
        "Not the visible label again",
        "For an unavailable control, the condition: Select a candidate first",
        "At most 60 characters"
      ],
      "tokens": [
        "--layer-popover",
        "--radius-lg",
        "--radius-md",
        "--space-1",
        "--space-2",
        "--text",
        "--text-label",
        "--surface-control",
        "--border",
        "--duration-fast",
        "--ease-soft",
        "--ease-standard"
      ]
    },
    {
      "title": "Toast",
      "path": "/components/toast",
      "url": "https://design.werklist.com/components/toast",
      "text": "https://design.werklist.com/agent/components/toast",
      "summary": "A short message at the bottom of the window that confirms what you just did, often with Undo.",
      "version": "2.1.2",
      "kind": "component",
      "name": "Toast",
      "purpose": "Confirms the result of the reader's own action when the result is out of view or can be undone, and offers at most one action.",
      "use": [
        "An action changed something out of view, such as a candidate leaving the list",
        "An action can be undone for a short window",
        "One action on many items finished: one toast with the count (12 candidates archived)",
        "An action the reader took did not go through and can be retried or restored"
      ],
      "avoid": [
        "The change is visible where the reader made it: no message",
        "Something happened elsewhere or was done by someone else, such as a new application: Notifications",
        "A condition of the current page, such as being offline: Inline message",
        "A decision before an irreversible act, such as withdrawing an offer: Dialog",
        "Long running work: Progress, where the work started"
      ],
      "anatomy": [
        {
          "part": "surface",
          "measure": "raised glass",
          "token": "--glass-fill-raised"
        },
        {
          "part": "shadow",
          "token": "--elevation-3"
        },
        {
          "part": "corner radius",
          "measure": "16 px",
          "token": "--radius-2xl"
        },
        {
          "part": "height",
          "measure": "44 px minimum; grows with wrapped text"
        },
        {
          "part": "padding",
          "measure": "10 px top and bottom, 16 px at the sides",
          "token": "--space-4"
        },
        {
          "part": "gap between message and action",
          "measure": "16 px",
          "token": "--space-4"
        },
        {
          "part": "width",
          "measure": "as wide as its words, message and action on one line; at most the window width less 24 px, then the message wraps"
        },
        {
          "part": "message",
          "measure": "13 px on 20 px, weight 400",
          "token": "--type-caption; ink --text"
        },
        {
          "part": "action",
          "measure": "the message's type at weight 700, no underline; --brand-blue in light, --brand-ink in dark, --error-ink in the error tone; --text on hover; target 24 px high, 44 by 44 px on coarse pointers",
          "token": "--brand-blue"
        },
        {
          "part": "position",
          "measure": "bottom center, 24 px above the window edge; on phones above the bottom navigation, and at the top while a sheet is open",
          "token": "--space-6"
        },
        {
          "part": "layer",
          "token": "--layer-toast"
        }
      ],
      "variants": [
        {
          "name": "neutral",
          "use": "reports a result"
        },
        {
          "name": "error",
          "use": "reports an action that did not go through (The CV did not upload) and offers Try again or Restore. Message and action in --error-ink. It stays until acted on, closed with Escape or replaced, and the failure also shows on the item"
        }
      ],
      "sizes": [
        {
          "name": "default",
          "height": "44 px minimum",
          "padding": "10 px by 16 px",
          "type": "message 13/20/400, action 13/20/700"
        }
      ],
      "states": [
        {
          "name": "entering",
          "change": "rises 14 px and grows from 98.5 percent of its size as it fades in, over 240 ms",
          "tokens": [
            "--ease-standard"
          ]
        },
        {
          "name": "resting",
          "change": "stays 5,000 ms"
        },
        {
          "name": "paused",
          "change": "pointer over the toast or focus inside it: the timer stops and resumes with the time left"
        },
        {
          "name": "holding",
          "change": "a toast with Undo keeps its place against newer toasts until its time ends"
        },
        {
          "name": "replaced",
          "change": "a newer toast takes its place; the old one goes without exit motion"
        },
        {
          "name": "leaving",
          "change": "opacity 1 to 0",
          "tokens": [
            "--duration-fast",
            "--ease-standard"
          ]
        },
        {
          "name": "reduced motion",
          "change": "no entrance motion; the toast appears and leaves in place"
        },
        {
          "name": "action hover",
          "change": "the action's ink turns to --text; no underline, no fill",
          "tokens": [
            "--text"
          ]
        },
        {
          "name": "action focus",
          "change": "focus ring on the action",
          "tokens": [
            "--focus-ring",
            "--focus-ring-width",
            "--focus-ring-offset"
          ]
        }
      ],
      "keys": [
        {
          "key": "Tab",
          "action": "reaches the action, which comes last in the tab order of the page"
        },
        {
          "key": "Enter or Space",
          "action": "runs the action"
        },
        {
          "key": "Escape",
          "action": "closes the toast when focus is inside it"
        }
      ],
      "accessibility": [
        "announced once through the screen's one polite live region, present from load; the toast itself has no role and no aria-live",
        "takes no focus",
        "action target at least 24 px, 44 by 44 px on coarse pointers",
        "Undo is also on the item, so a missed toast loses nothing",
        "message and action at least 4.5:1 on --glass-fill-raised in both themes"
      ],
      "content": [
        "message: what happened, past tense, naming the thing ('Candidate archived', 'Offer sent to Ramesh Thapa')",
        "action: one verb that answers the message (Undo, Open, Restore, Try again)",
        "one toast for an action on many items, with the count",
        "no exclamation mark and no 'successfully'"
      ],
      "tokens": [
        "--glass-fill-raised",
        "--elevation-3",
        "--radius-2xl",
        "--space-4",
        "--space-6",
        "--type-caption",
        "--text",
        "--brand-blue",
        "--brand-ink",
        "--error-ink",
        "--layer-toast",
        "--duration-fast",
        "--ease-standard",
        "--focus-ring",
        "--focus-ring-width",
        "--focus-ring-offset"
      ]
    },
    {
      "title": "Inline message",
      "path": "/components/inline-message",
      "url": "https://design.werklist.com/components/inline-message",
      "text": "https://design.werklist.com/agent/components/inline-message",
      "summary": "A message at the top of a page, list or dialog about something that is true there now, with the action that fixes it.",
      "version": "2.1.2",
      "kind": "component",
      "name": "Inline message",
      "purpose": "States a lasting condition of one surface at the top of that surface, with the one action that resolves it.",
      "use": [
        "The connection is down (neutral)",
        "An inbox needs reconnecting (error)",
        "Part of a list did not load, such as some candidates (warning)",
        "A job or a board is read only for this reader (neutral)",
        "A form did not submit (error, at the top of the form)",
        "A problem inside an open dialog, such as a work permit that ends before the start date of an offer (box, at the top of the dialog)"
      ],
      "avoid": [
        "The result of the reader's own action: Toast",
        "A single field value: the field error of Field",
        "A decision before anything happens: Dialog",
        "Something that happened elsewhere: Notifications"
      ],
      "anatomy": [
        {
          "part": "band",
          "measure": "flush with its column, no corners, no line under it; 36 px high, 44 px on coarse pointers; side padding 12 px, 16 px on phones and coarse pointers",
          "token": "--space-3, --space-4"
        },
        {
          "part": "box",
          "measure": "corner radius 8 px; padding 8 px by 12 px",
          "token": "--radius-lg, --space-2, --space-3"
        },
        {
          "part": "sentence",
          "measure": "regular weight on a line of 1.375; wraps and is never cut off"
        },
        {
          "part": "gap between sentence and action",
          "measure": "8 px",
          "token": "--space-2"
        },
        {
          "part": "action",
          "measure": "at most one; a small secondary button (36 px, 44 px on coarse pointers) at the end of the first line",
          "token": "--surface-control"
        },
        {
          "part": "close",
          "measure": "neutral tone only, when the information is available elsewhere; a small quiet icon button named Dismiss"
        }
      ],
      "variants": [
        {
          "name": "neutral",
          "use": "states a fact; fill --surface-2; ink --text at 85 percent"
        },
        {
          "name": "warning",
          "use": "something will go wrong unless someone acts; fill --warning at 10 percent opacity; ink --warning-ink, above 4.5:1 in both themes"
        },
        {
          "name": "error",
          "use": "work cannot go on until someone acts; fill --error at 10 percent; ink --error-ink, above 4.5:1 in both themes"
        }
      ],
      "sizes": [
        {
          "name": "band",
          "height": "36 px, 44 px on coarse pointers",
          "padding": "0 12 px, 0 16 px on phones"
        },
        {
          "name": "box",
          "padding": "8 px 12 px"
        }
      ],
      "states": [
        {
          "name": "present at load",
          "change": "rendered in place, no motion, no announcement"
        },
        {
          "name": "raised while working",
          "change": "fades in",
          "tokens": [
            "--duration-fast",
            "--ease-standard"
          ]
        },
        {
          "name": "resolved",
          "change": "removed; content moves up"
        },
        {
          "name": "action busy",
          "change": "the button shows its spinner and keeps its width"
        },
        {
          "name": "reduced motion",
          "change": "no fade"
        },
        {
          "name": "action focus",
          "change": "focus ring",
          "tokens": [
            "--focus-ring",
            "--focus-ring-width",
            "--focus-ring-offset"
          ]
        }
      ],
      "keys": [
        {
          "key": "Tab",
          "action": "reaches the action, then the close button, in reading order before the content"
        },
        {
          "key": "Enter or Space",
          "action": "runs the action"
        }
      ],
      "accessibility": [
        "error raised after the reader acts: role alert, heard once",
        "warning or neutral raised while working: announced through the polite live region",
        "present at load: read in place, no announcement",
        "the sentence names the problem; color is not the only signal",
        "after a failed submit, focus moves to the first field with an error, and the message at the top of the form is announced"
      ],
      "content": [
        "one sentence of what is true and what to do",
        "the action repeats the verb of the fix (Reconnect, Try again, Request access)",
        "never an error code as the message"
      ],
      "tokens": [
        "--surface-2",
        "--error",
        "--warning",
        "--warning-ink",
        "--error-ink",
        "--text",
        "--surface-1",
        "--surface-control",
        "--radius-lg",
        "--space-2",
        "--space-3",
        "--space-4",
        "--duration-fast",
        "--ease-standard",
        "--focus-ring",
        "--focus-ring-width",
        "--focus-ring-offset"
      ],
      "rules": [
        "one inline message per surface; order of precedence error, warning, neutral",
        "warning and error have no close button; they leave when the condition resolves",
        "the message pushes content down and never overlays it"
      ]
    },
    {
      "title": "Notifications",
      "path": "/components/notifications",
      "url": "https://design.werklist.com/components/notifications",
      "text": "https://design.werklist.com/agent/components/notifications",
      "summary": "The bell, the notification center and the cards that arrive while you work, for events you did not cause.",
      "version": "2.1.2",
      "kind": "component",
      "name": "Notifications",
      "purpose": "Tells the reader about events they did not cause: cards that arrive at the top right while they work, and the notification center under the bell that keeps every notification.",
      "use": [
        "Someone mentions the reader, assigns them work or writes to them",
        "A candidate applies or a company lead arrives",
        "A message arrives in an inbox that is not on screen"
      ],
      "avoid": [
        "The item is already on screen: it appears in its list",
        "The result of the reader's own action: Toast",
        "A condition of the current page: Inline message",
        "Marketing or announcements"
      ],
      "anatomy": [
        {
          "part": "center",
          "measure": "404 px wide, on a phone the screen less 24 px; corner radius 24 px; raised glass, opaque on a phone",
          "token": "--radius-3xl, --glass-fill-raised, --elevation-3"
        },
        {
          "part": "title",
          "measure": "Title 3, 17 px, bold, with Mark all as read at the end in blue text",
          "token": "--type-product-title-3, --brand-blue"
        },
        {
          "part": "lane filter",
          "measure": "round gray chips, each with its unread count; the current lane in full ink at weight 700",
          "token": "--glass-fill-hover, --radius-full"
        },
        {
          "part": "tabs",
          "measure": "All and Unread, Dense, 13 px, medium; the current tab in full ink at weight 700 with a 2 px underline",
          "token": "--type-product-dense, --text, --text-muted"
        },
        {
          "part": "day heading",
          "measure": "Today, Yesterday, Earlier; bold, in muted ink",
          "token": "--text-muted"
        },
        {
          "part": "list",
          "measure": "460 px high on a desktop, then it scrolls"
        },
        {
          "part": "row",
          "measure": "corner radius 16 px; padding 10 px by 12 px; a 32 px avatar; name Dense, 13 px, bold; the sentence regular, with the verb in muted ink; time and lane Caption small, 11 px, tabular digits",
          "token": "--radius-2xl, --type-product-dense, --type-product-caption-small"
        },
        {
          "part": "unread",
          "measure": "a 6 px dot and --brand-blue at 6 percent on the row",
          "token": "--brand-blue"
        },
        {
          "part": "urgent",
          "measure": "the word Urgent after the name, bold, on the solid alert fill, corner radius 6 px",
          "token": "--badge-alert, --badge-alert-ink"
        },
        {
          "part": "row dismiss",
          "measure": "28 px quiet icon button at the end of the row, shown on hover and focus; 44 px and always shown on touch"
        },
        {
          "part": "card stack",
          "measure": "top right, 72 px from the top of the window; 376 px wide, or the screen less 24 px; 8 px between cards; scrolls before a card would be cut in half",
          "token": "--space-2"
        },
        {
          "part": "card",
          "measure": "thin frosted glass with a bright rim; corner radius 28 px; padding 14 px, 40 px at the end for Dismiss; rises 1 px on hover"
        },
        {
          "part": "card lines",
          "measure": "first the kind of event (Caption small, 11 px, on its color at 15 percent, fully round), the name (Dense, 13 px, bold) and the time (Caption small, 11 px); then what arrived; then an optional detail in muted ink",
          "token": "--type-product-caption-small, --type-product-dense"
        }
      ],
      "variants": [
        {
          "name": "notification center",
          "use": "the history and the live feed, opened from the bell"
        },
        {
          "name": "card",
          "use": "an arrival while the reader works"
        }
      ],
      "states": [
        {
          "name": "center opening",
          "change": "moves 8 px down into place as it fades in, over 160 ms",
          "tokens": [
            "--ease-standard"
          ]
        },
        {
          "name": "row unread",
          "change": "6 px dot and --brand-blue at 6 percent on the row",
          "tokens": [
            "--brand-blue"
          ]
        },
        {
          "name": "row read",
          "change": "no dot, no fill"
        },
        {
          "name": "row dismissed",
          "change": "listed under All only; name in --text-muted at weight 500"
        },
        {
          "name": "row hover or focus",
          "change": "a faint fill",
          "tokens": [
            "--glass-fill-hover"
          ]
        },
        {
          "name": "loading",
          "change": "four skeleton rows"
        },
        {
          "name": "empty",
          "change": "'Nothing unread' under Unread, 'You are all caught up' under All, and one line on what arrives here"
        },
        {
          "name": "failed",
          "change": "'Your notifications did not load.' with Try again, in place of the list"
        },
        {
          "name": "partly failed",
          "change": "a warning band above the rows that loaded: 'Some notifications did not load.' with Try again",
          "tokens": [
            "--warning-ink"
          ]
        },
        {
          "name": "reduced motion",
          "change": "fades only"
        }
      ],
      "keys": [
        {
          "key": "Enter or Space on the bell",
          "action": "opens the center; focus moves to the current lane"
        },
        {
          "key": "Left and Right",
          "action": "move between lanes, or between All and Unread, and select"
        },
        {
          "key": "Home and End",
          "action": "first and last lane or tab"
        },
        {
          "key": "Tab",
          "action": "lanes, tabs, then each row followed by its dismiss button"
        },
        {
          "key": "Enter on a row or card",
          "action": "opens the item and marks it read"
        },
        {
          "key": "Escape",
          "action": "closes the center and returns focus to the bell"
        }
      ],
      "accessibility": [
        "the bell's name carries the count ('Notifications, 3 unread'); the number drawn on it is hidden from screen readers",
        "the center is a named dialog; the lane filter and the tabs are tab lists",
        "a card is announced once, politely, and takes no focus",
        "unread is shown by the dot and named in the row's accessible name; the fill is a second cue",
        "targets 44 px on touch"
      ],
      "content": [
        "a row reads as a sentence: person, verb, item ('Ana Horvat assigned you to Welders for Split')",
        "the filter has five lanes: Email, Work, Companies, Candidates and Chat",
        "a card names the kind of event instead, in its color: Email in blue, Candidate lead in green, a message that did not send in red",
        "no private detail beyond what the item shows",
        "one notification per event; a later event on the same item updates it",
        "a card carries no icon"
      ],
      "tokens": [
        "--glass-fill-raised",
        "--type-product-title-3",
        "--type-product-dense",
        "--type-product-caption-small",
        "--surface-1",
        "--elevation-3",
        "--radius-3xl",
        "--radius-2xl",
        "--radius-full",
        "--space-2",
        "--text",
        "--text-muted",
        "--brand-blue",
        "--warning-ink",
        "--badge-alert",
        "--badge-alert-ink",
        "--glass-fill-hover",
        "--ease-standard",
        "--focus-ring"
      ]
    },
    {
      "title": "Progress",
      "path": "/components/progress",
      "url": "https://design.werklist.com/components/progress",
      "text": "https://design.werklist.com/agent/components/progress",
      "summary": "A bar for work you can measure, and a spinner for a short wait inside the control that started it.",
      "version": "2.1.2",
      "kind": "component",
      "name": "Progress",
      "purpose": "Shows that work is under way: a determinate bar for work of known size, a spinner for a short wait inside the control that started it.",
      "use": [
        "Import, upload or sync of known size, such as importing candidates or uploading passports: bar where the work started",
        "A button's action takes a moment, such as Send offer: the button is busy at once and its spinner shows after 300 ms (--duration-slow)",
        "More rows load at the end of a list: 20 px spinner in the footer"
      ],
      "avoid": [
        "A page or panel loading content: Skeleton",
        "Long work with no size and no way to learn it: say it in words",
        "More than one indicator for one action",
        "A blocking overlay with a spinner"
      ],
      "anatomy": [
        {
          "part": "bar",
          "measure": "4 px high; fully round",
          "token": "--radius-full"
        },
        {
          "part": "track",
          "measure": "the fill of a control",
          "token": "--surface-control"
        },
        {
          "part": "fill",
          "measure": "brand blue, at least 3:1 against the track in both themes",
          "token": "--brand-blue"
        },
        {
          "part": "label row",
          "measure": "label in Caption, 12 px, medium, --text, on the left; value in Caption small, 11 px, tabular, --text-muted, on the right",
          "token": "--type-product-caption, --type-product-caption-small, --text, --text-muted"
        },
        {
          "part": "status row",
          "measure": "what is happening on the left, counts on the right, Caption small, 11 px, --text-muted, tabular",
          "token": "--type-product-caption-small, --text-muted"
        },
        {
          "part": "rhythm",
          "measure": "6 px between label row, bar and status row"
        },
        {
          "part": "cancel",
          "measure": "a small quiet button, Cancel, at the right of the label row, only when stopping loses nothing"
        },
        {
          "part": "indeterminate segment",
          "measure": "a third of the track at its start, a --brand-blue gradient that is full in the middle and 30 percent at both ends; pulses from 100 to 50 percent opacity over 2,000 ms, cubic-bezier(0.4, 0, 0.6, 1); hidden under reduced motion"
        },
        {
          "part": "spinner",
          "measure": "an open circle with round ends, in the ink of the control that holds it; one turn per second at a steady speed",
          "token": "--text-muted, --on-brand"
        }
      ],
      "variants": [
        {
          "name": "determinate bar",
          "use": "known size"
        },
        {
          "name": "indeterminate bar",
          "use": "the start of a bar whose size is unknown"
        },
        {
          "name": "spinner",
          "use": "a short wait inside the control, row or list footer that started it"
        }
      ],
      "sizes": [
        {
          "name": "spinner in controls and rows",
          "height": "16 px"
        },
        {
          "name": "spinner in panels and list footers",
          "height": "20 px"
        }
      ],
      "states": [
        {
          "name": "advancing",
          "change": "fill width animates to the new value over 500 ms",
          "tokens": [
            "--ease-standard"
          ]
        },
        {
          "name": "size becomes known",
          "change": "the segment gives way to the fill at the true value"
        },
        {
          "name": "stalled",
          "change": "after 10 seconds without movement the status says in words what the work waits for"
        },
        {
          "name": "failed",
          "change": "status row replaced by the failure and what to do, in --error-ink; fill stays",
          "tokens": [
            "--error-ink"
          ]
        },
        {
          "name": "done",
          "change": "the bar leaves; a toast or a notification reports the end"
        },
        {
          "name": "spinner delay",
          "change": "the control is busy at once; the spinner appears after 300 ms",
          "tokens": [
            "--duration-slow"
          ]
        },
        {
          "name": "reduced motion",
          "change": "the bar steps to each value; the spinner stays still and pulses from 100 to 50 percent opacity over 2,000 ms; the moving segment is hidden"
        }
      ],
      "keys": [
        {
          "key": "Tab",
          "action": "reaches Cancel when present; the bar and the spinner take no focus"
        }
      ],
      "accessibility": [
        "bar: role progressbar, aria-label from the label, aria-valuemin 0, aria-valuemax 100, aria-valuenow when known and absent when unknown",
        "no live region on the bar; the end is announced once by the toast or notification that reports it",
        "spinner: aria-hidden; its host carries aria-busy true and keeps its name",
        "fill against track at least 3:1 in both themes"
      ],
      "content": [
        "label: a verb ending in ing and its object, no ellipsis, no period",
        "status: numbers the reader can check, formatted in the app's locale; a percentage only beside them",
        "no time estimate unless the work is steady"
      ],
      "tokens": [
        "--type-product-caption",
        "--type-product-caption-small",
        "--surface-control",
        "--brand-blue",
        "--radius-full",
        "--text",
        "--text-muted",
        "--error-ink",
        "--on-brand",
        "--duration-slow",
        "--ease-standard"
      ]
    },
    {
      "title": "Skeleton",
      "path": "/components/skeleton",
      "url": "https://design.werklist.com/components/skeleton",
      "text": "https://design.werklist.com/agent/components/skeleton",
      "summary": "Gray shapes in the layout of the content that is loading, so the page appears at once.",
      "version": "2.1.2",
      "kind": "component",
      "name": "Skeleton",
      "purpose": "Draws the layout of content that is loading, so the page appears at once and content replaces each shape in place.",
      "use": [
        "A page or panel loads content of known shape",
        "The body of a message or the notes of an interview load after their frame",
        "A list loads its first page, such as a list of candidates"
      ],
      "avoid": [
        "Toolbars, tabs and column headers: show them from the start",
        "Work of known size: Progress bar",
        "A wait inside a control: Spinner",
        "A skeleton and a spinner together"
      ],
      "anatomy": [
        {
          "part": "fill, light",
          "measure": "the ink mixed 22 percent into the card: color-mix(in srgb, var(--text) 22%, var(--surface-1))",
          "token": "--skeleton-fill"
        },
        {
          "part": "fill, dark",
          "measure": "the ink mixed 16 percent into the card: color-mix(in srgb, var(--text) 16%, var(--surface-1))",
          "token": "--skeleton-fill"
        },
        {
          "part": "text line",
          "measure": "12 px high for Dense and Body text (13 and 14 px); corner radius 4 px",
          "token": "--radius-sm"
        },
        {
          "part": "paragraph",
          "measure": "lines at 80, 67 and 60 percent width, last shortest; 8 px apart",
          "token": "--space-2"
        },
        {
          "part": "avatar",
          "measure": "circle at the avatar size (32 px in a list row)"
        },
        {
          "part": "block",
          "measure": "the size and corner radius of the component it stands for"
        },
        {
          "part": "row",
          "measure": "the height of the real row (58 px for a two line list row) and its gap before the lines"
        },
        {
          "part": "count",
          "measure": "as many rows as fill the visible area"
        }
      ],
      "states": [
        {
          "name": "loading",
          "change": "the whole skeleton pulses from 100 to 50 percent opacity and back over 2,000 ms, cubic-bezier(0.4, 0, 0.6, 1); all shapes in step"
        },
        {
          "name": "partly loaded",
          "change": "arrived parts replace their shapes; the rest keep pulsing"
        },
        {
          "name": "loaded",
          "change": "content replaces the shapes in place; the region is no longer busy"
        },
        {
          "name": "empty",
          "change": "gives way to the empty state"
        },
        {
          "name": "failed",
          "change": "gives way to the error and Try again, in place"
        },
        {
          "name": "slow",
          "change": "after 10 seconds the skeleton stays and a neutral inline message above it says what is still loading"
        },
        {
          "name": "reduced motion",
          "change": "no pulse"
        }
      ],
      "accessibility": [
        "shapes are aria-hidden",
        "the loading region carries aria-busy true and one role status element with a visually hidden sentence naming what loads, announced once",
        "nothing in a skeleton is focusable; focus stays where it was when content arrives"
      ],
      "content": [
        "the hidden sentence names what loads: 'Loading candidates'"
      ],
      "tokens": [
        "--skeleton-fill",
        "--radius-sm",
        "--space-2"
      ]
    },
    {
      "title": "Counter",
      "path": "/components/counter",
      "url": "https://design.werklist.com/components/counter",
      "text": "https://design.werklist.com/agent/components/counter",
      "summary": "Shows how many items wait behind a control, such as unread notifications, as a small number.",
      "version": "2.1.2",
      "kind": "component",
      "name": "Counter",
      "purpose": "Shows how many items wait behind a control, as a small number the reader can bring down by acting.",
      "use": [
        "Unread notifications on a header button.",
        "New applications in a view, beside its name."
      ],
      "avoid": [
        "Totals that only describe, such as the candidates on a board.",
        "Navigation and marketing pages.",
        "Zero or negative numbers."
      ],
      "variants": [
        {
          "name": "attention",
          "use": "Unread items that need action, in the same red in both themes."
        },
        {
          "name": "new",
          "use": "Items that arrived since the reader last opened the view. It turns plain once the view is opened."
        },
        {
          "name": "plain",
          "use": "A count the reader may act on without urgency."
        }
      ],
      "anatomy": [
        {
          "part": "Height",
          "measure": "17 px"
        },
        {
          "part": "Minimum width",
          "measure": "17 px"
        },
        {
          "part": "Padding",
          "measure": "4 px at the sides",
          "token": "--space-1"
        },
        {
          "part": "Radius",
          "measure": "6 px",
          "token": "--radius-md"
        },
        {
          "part": "Numerals",
          "measure": "10.5 px, weight 700, tabular, line height 1"
        },
        {
          "part": "On a button",
          "measure": "6 px above the top edge of the button and 4 px past its end, with a 2 px ring in the resting fill of the button"
        },
        {
          "part": "Beside a label",
          "measure": "8 px after the label",
          "token": "--space-2"
        },
        {
          "part": "Attention",
          "token": "--badge-alert, --badge-alert-ink"
        },
        {
          "part": "New",
          "token": "--track-tint, --assign-accent"
        },
        {
          "part": "Plain",
          "measure": "on a --surface-control ground the fill is --surface-1",
          "token": "--chip-fill, --chip-ink"
        }
      ],
      "states": [
        {
          "name": "hidden",
          "change": "the count is zero"
        },
        {
          "name": "shown",
          "change": "grows in over 150 ms, without motion under reduced motion",
          "tokens": [
            "--duration-fast",
            "--ease-standard"
          ]
        }
      ],
      "accessibility": [
        "The number is hidden from screen readers. The name of the control carries it with what it counts, such as Applications, 12 in this view, new since you last opened it.",
        "No focus of its own.",
        "A change of count updates the name of the control and is not announced.",
        "In forced colors mode the numerals keep the text color inside a 1 px outline."
      ],
      "content": [
        "0 hides the counter.",
        "1 to 999 exact.",
        "1,000 to 9,999 as thousands with one decimal, rounded down: 1.9k.",
        "10,000 and above: 10k+.",
        "Numbers take the same form in every language."
      ],
      "tokens": [
        "--badge-alert",
        "--badge-alert-ink",
        "--track-tint",
        "--assign-accent",
        "--chip-fill",
        "--chip-ink",
        "--surface-1",
        "--radius-md",
        "--space-1",
        "--space-2",
        "--duration-fast",
        "--ease-standard"
      ],
      "rules": [
        "A counter only for items the reader can bring down by acting.",
        "The name of the control pairs the number with what it counts.",
        "Red only for items that need attention, never for a total that can wait."
      ]
    },
    {
      "title": "Status",
      "path": "/components/status",
      "url": "https://design.werklist.com/components/status",
      "text": "https://design.werklist.com/agent/components/status",
      "summary": "Shows the value of a status field, such as Documents missing or Visa approved, as a word on a colored fill.",
      "version": "2.1.2",
      "kind": "component",
      "name": "Status",
      "purpose": "Shows the value of a status field or the state of a record as a word on a colored fill.",
      "use": [
        "The value of a status column in a board cell or on a card, such as Visa approved (solid).",
        "The state of a record beside a name or in a notification, such as Interview booked (quiet)."
      ],
      "avoid": [
        "New, Beta, Pro or any label that holds no value.",
        "Labels on navigation or marketing pages.",
        "Values a person picked from a list, such as the skills of a candidate: use Combobox with several choices.",
        "A dot or a fill without its word."
      ],
      "variants": [
        {
          "name": "solid",
          "use": "The value of a status field in a board and on a card."
        },
        {
          "name": "quiet",
          "use": "A state named beside a title or inside a message, such as the stage of a candidate in a notification."
        }
      ],
      "anatomy": [
        {
          "part": "Solid label",
          "measure": "13 px, weight 500, line height 1, centered, white",
          "token": "--on-brand"
        },
        {
          "part": "Solid padding",
          "measure": "8 px on every side",
          "token": "--space-2"
        },
        {
          "part": "Solid inset in a cell",
          "measure": "6 px on each side"
        },
        {
          "part": "Solid radius",
          "measure": "9 px"
        },
        {
          "part": "Solid height",
          "measure": "29 px in a board row, 36 px with a 12 px label on a phone card"
        },
        {
          "part": "Solid fill",
          "measure": "a color from the status palette, the same in both themes, under white words"
        },
        {
          "part": "Empty",
          "measure": "a hyphen on gray #848991"
        },
        {
          "part": "Quiet label",
          "measure": "11 px, line height 1, weight 500"
        },
        {
          "part": "Quiet padding",
          "measure": "2 px above and below, 8 px at the sides",
          "token": "--space-2"
        },
        {
          "part": "Quiet radius",
          "measure": "fully rounded",
          "token": "--radius-full"
        },
        {
          "part": "Quiet fill and ink",
          "measure": "--success, --warning, --error or --brand-blue at 15 percent, under --success-ink, --warning-ink, --error-ink or --brand-ink. Neutral is --surface-control under --text."
        }
      ],
      "accessibility": [
        "Plain text. The column header, or the title beside it, names the field.",
        "A status drawn as an icon carries its word as its name.",
        "No focus of its own. When it opens a picker, the cell is the button.",
        "In forced colors mode the fills drop and the word remains."
      ],
      "content": [
        "The value as the field holds it, in sentence case.",
        "An empty cell shows a hyphen. Where a word is needed it reads Empty, or Unassigned for a person."
      ],
      "tokens": [
        "--on-brand",
        "--success",
        "--success-ink",
        "--warning",
        "--warning-ink",
        "--error",
        "--error-ink",
        "--brand-blue",
        "--brand-ink",
        "--surface-control",
        "--text",
        "--radius-full",
        "--space-2"
      ],
      "rules": [
        "A label takes the status shape only when it shows a value held in a field or a record.",
        "Navigation and marketing pages carry no status.",
        "Every fill carries white words, and one value keeps one color on every board.",
        "The word is always present, written as the field holds it, in sentence case."
      ]
    },
    {
      "title": "Card",
      "path": "/components/card",
      "url": "https://design.werklist.com/components/card",
      "text": "https://design.werklist.com/agent/components/card",
      "summary": "A card holds one item, such as a hiring project or a candidate, with a title and at most two actions.",
      "version": "2.1.2",
      "kind": "component",
      "name": "Card",
      "purpose": "Holds one item, such as a hiring project or a candidate, on a flat surface with a title, optional detail and at most two actions.",
      "use": [
        "A set of items of one kind that people browse and open one at a time.",
        "Each item has a title and a line or two of detail."
      ],
      "avoid": [
        "Items people compare field by field or act on in bulk: use a list or the board grid.",
        "A job ad: use the job card. One headline figure: use the stat tile.",
        "A group of settings on a page: group it with a heading and space.",
        "A card inside a card, a card on a well, or a card on --surface-1."
      ],
      "anatomy": [
        {
          "part": "Container",
          "measure": "The fill alone, with no border, ring or shadow.",
          "token": "--surface-1"
        },
        {
          "part": "Corner radius",
          "measure": "16 px",
          "token": "--radius-2xl"
        },
        {
          "part": "Padding",
          "measure": "16 px, or 24 px when spacious",
          "token": "--space-4, --space-6"
        },
        {
          "part": "Title",
          "measure": "16 px on 26 px, weight 500, in --text. Two lines at most, then an ellipsis.",
          "token": "--type-body"
        },
        {
          "part": "Supporting text",
          "measure": "14 px on 22 px, in --text-muted, 4 px below the title",
          "token": "--type-small"
        },
        {
          "part": "Details",
          "measure": "13 px on 20 px, in --text-label, tabular digits, 4 px below the line above",
          "token": "--type-caption"
        },
        {
          "part": "Actions",
          "measure": "At most two small buttons (36 px), quiet or secondary, 16 px below the text and 8 px apart",
          "token": "--space-2"
        },
        {
          "part": "Grid",
          "measure": "A list of cards 16 px apart: one column, two from 640 px, three from 1024 px",
          "token": "--space-4"
        }
      ],
      "variants": [
        {
          "name": "static",
          "use": "Shows information. Its actions are buttons inside it. It has no hover and no focus of its own."
        },
        {
          "name": "clickable",
          "use": "Opens one item. The title is the link, and its target covers the card. The buttons of the card sit above that target and keep their own action."
        }
      ],
      "sizes": [
        {
          "name": "default",
          "padding": "16 px",
          "type": "Title 16 px on 26 px at weight 500, supporting text 14 px on 22 px, details 13 px on 20 px"
        },
        {
          "name": "spacious",
          "padding": "24 px",
          "type": "Title 16 px on 26 px at weight 500, supporting text 14 px on 22 px, details 13 px on 20 px"
        }
      ],
      "states": [
        {
          "name": "rest",
          "change": "Flat: the fill alone.",
          "tokens": [
            "--elevation-0",
            "--surface-1"
          ]
        },
        {
          "name": "hover",
          "change": "The fill turns --surface-control over 150 ms, with no shadow and no lift. Only on a pointer that can hover.",
          "tokens": [
            "--surface-control",
            "--duration-fast",
            "--ease-standard"
          ]
        },
        {
          "name": "pressed",
          "change": "The same --surface-control fill. On a touch screen, where there is no hover, it appears when the card is pressed.",
          "tokens": [
            "--surface-control"
          ]
        },
        {
          "name": "focus visible",
          "change": "A 2 px outline 2 px outside the card while its link has keyboard focus. The outline follows the corners.",
          "tokens": [
            "--focus-ring",
            "--focus-ring-width",
            "--focus-ring-offset"
          ]
        },
        {
          "name": "loading",
          "change": "A skeleton card of the final size and radius.",
          "tokens": [
            "--radius-2xl"
          ]
        },
        {
          "name": "reduced motion",
          "change": "The fill changes at once, without the 150 ms transition.",
          "tokens": []
        },
        {
          "name": "forced colors",
          "change": "A 1 px border in CanvasText. Focus in Highlight.",
          "tokens": []
        }
      ],
      "keys": [
        {
          "key": "Tab",
          "action": "Moves to the title link, then to each button of the card in order."
        },
        {
          "key": "Shift+Tab",
          "action": "Moves back."
        },
        {
          "key": "Enter",
          "action": "Opens the item from the title link."
        }
      ],
      "accessibility": [
        "Cards sit in a ul, so screen readers announce the count.",
        "The title is the only link. Its name is the title, and aria-describedby points at the supporting line.",
        "Buttons inside a clickable card are siblings of the link, not its children.",
        "No arrow key navigation between cards: a grid of cards is a list of links, not a composite widget.",
        "Actions are 36 px and reach 44 px on a coarse pointer."
      ],
      "content": [
        "The title is the item's own name, as people say it.",
        "The supporting line carries what people need before opening: for a project, the country and the number of positions.",
        "Dates and counts in tabular digits.",
        "Long country names wrap. Nothing shrinks to fit."
      ],
      "tokens": [
        "--surface-1",
        "--bg",
        "--radius-2xl",
        "--space-1",
        "--space-2",
        "--space-4",
        "--space-6",
        "--text",
        "--text-muted",
        "--text-label",
        "--elevation-0",
        "--surface-control",
        "--duration-fast",
        "--ease-standard",
        "--focus-ring",
        "--focus-ring-width",
        "--focus-ring-offset"
      ],
      "rules": [
        "The card sits on --bg, never on another card, a well or --surface-1."
      ]
    },
    {
      "title": "List",
      "path": "/components/list",
      "url": "https://design.werklist.com/components/list",
      "text": "https://design.werklist.com/agent/components/list",
      "summary": "Stacks items of one kind in rows that a reader scans, opens or chooses from.",
      "version": "2.1.2",
      "kind": "component",
      "name": "List",
      "purpose": "Stacks items of one kind in rows that a reader scans, opens or chooses from.",
      "use": [
        "Items that each open a page, such as the modules of a workspace or the stages of a job.",
        "Settings with a switch per row, such as who on a hiring team can send offers.",
        "A short set of options to choose from, such as the status of a work permit."
      ],
      "avoid": [
        "Rows that share compared columns: use the board grid or the report table.",
        "Nested items: use the tree of the side navigation.",
        "Images or items of very different sizes: use Card."
      ],
      "anatomy": [
        {
          "part": "Grouped card",
          "measure": "corner radius 24 px, padding 6 px, rows 2 px apart",
          "token": "--surface-1, --radius-3xl"
        },
        {
          "part": "Row in a grouped card",
          "measure": "padding 12 px, corner radius 18 px, 46.5 px high; text in Subtitle, 15 px, medium, on a line of 22.5 px; gap 14 px",
          "token": "--space-3, --type-product-subtitle"
        },
        {
          "part": "Row in a plain list",
          "measure": "padding 8 px, corner radius 8 px, 36 px high under a mouse and 44 px on coarse pointers; text in Body, 14 px on 20 px, medium; gap 10 px",
          "token": "--radius-lg, --space-2, --type-product-body"
        },
        {
          "part": "Row, two lines",
          "measure": "58 px in a card (10 px above and below, 20 px and 18 px lines), 50 px on a panel"
        },
        {
          "part": "Leading element",
          "measure": "icon 20 px, avatar 32 px or checkbox 16 px; --text-muted, --text on the current row"
        },
        {
          "part": "Second line",
          "measure": "Dense, 13 px on 18 px",
          "token": "--type-product-dense, --text-muted"
        },
        {
          "part": "Trailing element",
          "measure": "chevron 18 px in a card and 16 px on a panel, a Switch, a Counter, or a short value in Dense, 13 px, tabular",
          "token": "--text-muted"
        },
        {
          "part": "Group heading",
          "measure": "Dense, 13 px on 18 px, medium, 8 px above and below; stays at the top while its group scrolls, on a frosted fill of --surface-1",
          "token": "--type-product-dense, --text-label"
        }
      ],
      "sizes": [
        {
          "name": "grouped",
          "height": "46.5 px, 58 px with two lines",
          "padding": "12 px",
          "type": "Subtitle, 15 px, medium"
        },
        {
          "name": "plain",
          "height": "36 px under a mouse, 44 px on coarse pointers",
          "padding": "8 px",
          "type": "Body, 14 px on 20 px, medium"
        }
      ],
      "states": [
        {
          "name": "hover",
          "change": "faint fill; fine pointer only",
          "tokens": [
            "--glass-fill-hover"
          ]
        },
        {
          "name": "pressed",
          "change": "the same faint fill; a link row in a grouped card scales to 0.985",
          "tokens": [
            "--glass-fill-hover"
          ]
        },
        {
          "name": "current",
          "change": "tinted fill in --text, aria-current page; the other rows of the list turn --text-muted",
          "tokens": [
            "--nav-fill-active",
            "--text-muted"
          ]
        },
        {
          "name": "chosen",
          "change": "16 px tick at the end, aria-selected true; multiple choice uses a leading Checkbox",
          "tokens": [
            "--brand-blue"
          ]
        },
        {
          "name": "focus visible",
          "change": "2 px ring inside the row, offset minus 2 px",
          "tokens": [
            "--focus-ring"
          ]
        },
        {
          "name": "soon",
          "change": "the word Soon as the trailing value; not a link, aria-disabled true, not faded",
          "tokens": [
            "--text-muted"
          ]
        }
      ],
      "keys": [
        {
          "key": "Tab",
          "action": "Moves between links in a list of links; enters a list you choose from"
        },
        {
          "key": "Up and Down",
          "action": "Move between rows of a listbox"
        },
        {
          "key": "Home and End",
          "action": "First and last row"
        },
        {
          "key": "Space",
          "action": "Chooses or clears the focused row"
        },
        {
          "key": "Enter",
          "action": "Opens the focused row"
        },
        {
          "key": "Right",
          "action": "Moves into the row's own buttons"
        },
        {
          "key": "Left or Escape",
          "action": "Returns to the row"
        }
      ],
      "accessibility": [
        "ul and li for a list of links; listbox and option for choosing; not grid.",
        "The accessible name of a row holds its full text.",
        "When the focused row is removed, focus moves to the next row, or the previous one at the end.",
        "Current and chosen rows keep an outline or a tick in forced colors."
      ],
      "content": [
        "Rows are parallel and of similar length.",
        "No end punctuation unless each row is a full sentence.",
        "Titles wrap to two lines, then an ellipsis; file names are cut in the middle."
      ],
      "tokens": [
        "--type-product-subtitle",
        "--type-product-body",
        "--type-product-dense",
        "--glass-fill-hover",
        "--nav-fill-active",
        "--brand-blue",
        "--text",
        "--text-muted",
        "--text-label",
        "--surface-1",
        "--radius-lg",
        "--radius-3xl",
        "--space-2",
        "--space-3",
        "--focus-ring"
      ],
      "rules": [
        "Permitted: an item that is coming says Soon in words.",
        "Permitted: rows separated by space and a hover fill.",
        "Not permitted: a row faded by opacity to show it is unavailable.",
        "Not permitted: lines between the rows of a short list."
      ]
    },
    {
      "title": "Disclosure",
      "path": "/components/disclosure",
      "url": "https://design.werklist.com/components/disclosure",
      "text": "https://design.werklist.com/agent/components/disclosure",
      "summary": "Hides a section or a detail until the reader asks for it, then shows it in place.",
      "version": "2.1.2",
      "kind": "component",
      "name": "Disclosure",
      "purpose": "Hides a section or a detail until the reader opens it, and shows it in place.",
      "use": [
        "Detail most readers skip, such as quoted text or message details.",
        "The sections of a record on a small screen, such as the documents, work permit and interview notes in a candidate's file.",
        "Advanced settings below the common ones."
      ],
      "avoid": [
        "Anything the task requires.",
        "Navigation between pages: use the side navigation.",
        "More than one level of nesting: use a tree."
      ],
      "variants": [
        {
          "name": "section",
          "use": "A row that leads with a chevron and holds the heading, and opens a panel below."
        },
        {
          "name": "inline",
          "use": "A phrase inside content that reads Show and turns to Hide when open."
        }
      ],
      "anatomy": [
        {
          "part": "Section row",
          "measure": "at least 44 px; padding 9 px above and below, 8 px before the chevron, 12 px at the end; gap 8 px",
          "token": "--space-2, --space-3"
        },
        {
          "part": "Section heading",
          "measure": "Body, 16 px on 26 px, bold",
          "token": "--type-body, --text"
        },
        {
          "part": "Compact row",
          "measure": "in a dense side panel used with a mouse, such as a list of folders: bold, padding 4 px by 6 px, a 14 px chevron, 4 px gap"
        },
        {
          "part": "Chevron",
          "measure": "16 px, pointing right, before the heading, stroke 2.25; turns a quarter to point down when open",
          "token": "--text-muted"
        },
        {
          "part": "Hover fill",
          "measure": "radius 8 px, fine pointer only",
          "token": "--glass-fill-hover"
        },
        {
          "part": "Panel",
          "measure": "starts under the heading's first letter; 16 px below the content",
          "token": "--space-4"
        },
        {
          "part": "Between sections",
          "measure": "4 px, no lines",
          "token": "--space-1"
        },
        {
          "part": "Inline phrase",
          "measure": "medium weight, --text-muted, --text on hover; a 14 px chevron pointing down, 4 px after it, turns over when open; target 24 px high, 44 px on touch",
          "token": "--text-muted"
        }
      ],
      "states": [
        {
          "name": "closed",
          "change": "chevron points right; panel hidden"
        },
        {
          "name": "open",
          "change": "chevron points down; panel shown; height and opacity over 150 ms",
          "tokens": [
            "--duration-fast",
            "--ease-standard"
          ]
        },
        {
          "name": "hover",
          "change": "faint fill on the section row; fine pointer only",
          "tokens": [
            "--glass-fill-hover"
          ]
        },
        {
          "name": "focus visible",
          "change": "2 px ring on the row or phrase",
          "tokens": [
            "--focus-ring"
          ]
        }
      ],
      "keys": [
        {
          "key": "Tab",
          "action": "Moves to the next heading or into an open panel"
        },
        {
          "key": "Enter",
          "action": "Opens or closes"
        },
        {
          "key": "Space",
          "action": "Opens or closes"
        }
      ],
      "accessibility": [
        "The expanded state is announced, and find in page opens a closed section that holds a match.",
        "When sections form a list, the summary holds the section's heading element.",
        "The inline phrase changes between Show and Hide; the expanded state says the same thing.",
        "A printed page shows every section open; on screen they return to how they were.",
        "On a wide screen, a group of sections may stay open all the time; its headings are then plain headings, not toggles."
      ],
      "content": [
        "Name what the section holds; sentence case, no full stop, one line at 360 px.",
        "Inline phrases start with Show or Hide and name the content."
      ],
      "tokens": [
        "--type-body",
        "--text",
        "--text-muted",
        "--glass-fill-hover",
        "--radius-lg",
        "--space-1",
        "--space-2",
        "--space-3",
        "--space-4",
        "--focus-ring",
        "--duration-fast",
        "--ease-standard"
      ],
      "rules": [
        "Permitted: a closed section for detail most readers skip.",
        "Not permitted: required information in a closed section.",
        "Not permitted: a section that is always open but still looks and acts like a toggle.",
        "Opening one section does not close another."
      ]
    },
    {
      "title": "Avatar",
      "path": "/components/avatar",
      "url": "https://design.werklist.com/components/avatar",
      "text": "https://design.werklist.com/agent/components/avatar",
      "summary": "A person's photo or initials in a circle, alone or in a stack, and how it names the person to a screen reader.",
      "version": "2.1.2",
      "kind": "component",
      "name": "Avatar",
      "purpose": "A person's photo, or their initials on their own gradient, in a circle beside their name. Teams and companies take the same circle with a small mark in the corner.",
      "use": [
        "Beside a name wherever people act: comments, assignees, chat, the activity history, the notification center and the people column of a board.",
        "Alone only where the row is too narrow for the name, with the name in a tooltip and for screen readers."
      ],
      "avoid": [
        "Notification cards that pop up, and empty states.",
        "Initials as the only label of a person.",
        "A ring or an edge on a face."
      ],
      "anatomy": [
        {
          "part": "Shape",
          "measure": "a circle",
          "token": "--radius-full"
        },
        {
          "part": "Photo",
          "measure": "covers the disc, centered, with no edge"
        },
        {
          "part": "Initials",
          "measure": "the first letters of the first and last name, two at most, in white at weight 700",
          "token": "--on-brand"
        },
        {
          "part": "Fill without a photo",
          "measure": "one of 8 gradients, picked from the name, light at the top left and deep at the bottom right"
        },
        {
          "part": "Team or company mark",
          "measure": "a 12 px disc at 24 px and a 14 px disc at 32 px, in the bottom corner",
          "token": "--surface-strong"
        },
        {
          "part": "No name at all",
          "measure": "a person icon on a gray disc",
          "token": "--surface-control"
        }
      ],
      "variants": [
        {
          "name": "Photo",
          "use": "the person uploaded a picture"
        },
        {
          "name": "Initials",
          "use": "no picture, or the picture failed to load"
        },
        {
          "name": "Team",
          "use": "a team, with a small mark in the corner"
        },
        {
          "name": "Company",
          "use": "a company, with a small mark in the corner"
        },
        {
          "name": "Stack",
          "use": "several people in a narrow cell: up to 4 faces, then a count"
        },
        {
          "name": "Person row",
          "use": "the avatar, the name and one line in a lighter ink, such as a role"
        }
      ],
      "sizes": [
        {
          "name": "24 px, board cells and stacks",
          "height": "24 px",
          "type": "initials 10 px"
        },
        {
          "name": "32 px, the default",
          "height": "32 px",
          "type": "initials 12 px"
        },
        {
          "name": "40 px, the header of a person's panel",
          "height": "40 px",
          "type": "initials 13 px"
        },
        {
          "name": "56 px, a profile",
          "height": "56 px",
          "type": "initials 18 px"
        }
      ],
      "states": [
        {
          "name": "Loading",
          "change": "the initials show until the photo arrives"
        },
        {
          "name": "Photo failed",
          "change": "the initials stay"
        },
        {
          "name": "Hover",
          "change": "a tooltip with the person's name, after 500 ms"
        },
        {
          "name": "Keyboard focus",
          "change": "the focus ring, 2 px, offset 2 px",
          "tokens": [
            "--focus-ring"
          ]
        },
        {
          "name": "Touch",
          "change": "the target grows to 44 px and the drawing stays the same"
        }
      ],
      "keys": [
        {
          "key": "Tab",
          "action": "moves to an avatar or a stack that opens something"
        },
        {
          "key": "Enter or Space",
          "action": "opens the profile or the card"
        },
        {
          "key": "Escape",
          "action": "closes the card, and focus stays on the stack"
        }
      ],
      "accessibility": [
        "When the name is written beside the avatar, the avatar is hidden from screen readers so the name is read once.",
        "When the avatar stands alone, it carries the name: the photo's alt text, or a label on the initials.",
        "A stack names the faces it shows and counts the rest in the label of its button, for example Assigned to Ana Horvat, Rajesh Kumar, Maria Santos, Luka Perić and 3 others.",
        "The name is always written or announced. Initials never stand alone."
      ],
      "content": [
        "The initials come from the name the person shows, two letters at most.",
        "The count disc reads as a plus and the number of the rest, such as +3, in tabular digits."
      ],
      "tokens": [
        "--radius-full",
        "--on-brand",
        "--surface-1",
        "--surface-strong",
        "--surface-control",
        "--focus-ring"
      ],
      "rules": [
        "A stack shows up to 4 faces, each overlapping the next by 6 px, then a disc with the count of the rest.",
        "The faces stand bare. The count disc keeps a 2 px ring.",
        "Hover or focus on a stack opens a card with everyone on it, 240 px wide, with 12 px corners and 8 px inside.",
        "A person keeps the same color on every screen."
      ]
    },
    {
      "title": "Permitted and not permitted",
      "path": "/components/permitted",
      "url": "https://design.werklist.com/components/permitted",
      "text": "https://design.werklist.com/agent/components/permitted",
      "summary": "Sets the correct way to do something beside the mistake it prevents, in a faint green box and a faint red one.",
      "version": "2.1.2",
      "kind": "component",
      "name": "Permitted and not permitted",
      "purpose": "Sets the correct way to do something beside the mistake it prevents, in two tinted boxes.",
      "use": [
        "A mistake people have made before, or one that looks as plausible as the correct form.",
        "A guide or a set of instructions where the correct form is clearest beside the wrong one."
      ],
      "avoid": [
        "The same pair repeated under every heading.",
        "Mistakes with no correct form beside them.",
        "More than five items in a box."
      ],
      "anatomy": [
        {
          "part": "Boxes",
          "measure": "two, side by side from 768 px and stacked below it, Permitted first"
        },
        {
          "part": "Gap",
          "measure": "24 px",
          "token": "--gutter"
        },
        {
          "part": "Radius",
          "measure": "12 px",
          "token": "--radius-xl"
        },
        {
          "part": "Padding",
          "measure": "24 px",
          "token": "--space-6"
        },
        {
          "part": "Border",
          "measure": "none"
        },
        {
          "part": "Permitted fill",
          "measure": "success at 10 percent over the surface",
          "token": "--tint-permitted"
        },
        {
          "part": "Not permitted fill",
          "measure": "error at 10 percent over the surface",
          "token": "--tint-not-permitted"
        },
        {
          "part": "Icon",
          "measure": "24 px Check or Cross, stroke 1.75, 8 px before the heading",
          "token": "--success-ink"
        },
        {
          "part": "Heading",
          "measure": "Permitted or Not permitted, 20 px on 28 px, weight 500",
          "token": "--text"
        },
        {
          "part": "Item",
          "measure": "16 px on 26 px",
          "token": "--text"
        },
        {
          "part": "Reason",
          "measure": "14 px on 22 px",
          "token": "--text-label"
        },
        {
          "part": "Spacing",
          "measure": "16 px between items and from the heading to the first item",
          "token": "--space-4"
        }
      ],
      "accessibility": [
        "Each box is a section with its own heading. Its items are a list without bullets.",
        "Icons are hidden from screen readers. The heading says which box is which.",
        "Text on the tints never takes the muted ink.",
        "In print and in forced colors mode the fills drop, and the words and icons remain."
      ],
      "content": [
        "One sentence per item. A reason only when it is not obvious.",
        "Not permitted items say what goes wrong.",
        "Headings are exactly Permitted and Not permitted.",
        "Items that correspond sit on the same row."
      ],
      "tokens": [
        "--tint-permitted",
        "--tint-not-permitted",
        "--success-ink",
        "--error-ink",
        "--text",
        "--text-label",
        "--radius-xl",
        "--space-4",
        "--space-6",
        "--gutter"
      ],
      "rules": [
        "Use a pair where people are likely to make the mistake.",
        "Each mistake has its correct form on the same row.",
        "The headings read Permitted and Not permitted, never Do and Don't.",
        "The correct side is never colored blue."
      ]
    },
    {
      "title": "Job card",
      "path": "/components/job-card",
      "url": "https://design.werklist.com/components/job-card",
      "text": "https://design.werklist.com/agent/components/job-card",
      "summary": "One open role as a row: the position, where and what, the net pay and a way in.",
      "version": "2.1.2",
      "kind": "component",
      "name": "Job card",
      "purpose": "One open role in a list on werklist.com: position, location and trade, net pay and a link to the role.",
      "use": [
        "Lists of open roles for workers: home page, country and industry pages, search results.",
        "Boards in other languages, with the position and the intro in the language of the board."
      ],
      "avoid": [
        "Anything that is not a role: use Card.",
        "Comparing roles by field inside WerkOS: use the board grid.",
        "Icons, flags, tags, eyebrows or badges on the card."
      ],
      "anatomy": [
        {
          "part": "Container",
          "measure": "the full width of the list; stacked, and a row with its items centered from 768 px; radius 16 px; padding 20 px, 24 px from 768 px; gap 16 px, 24 px from 768 px",
          "token": "--surface-1, --radius-2xl, --space-5, --space-6, --space-4"
        },
        {
          "part": "Text column",
          "measure": "takes the free width"
        },
        {
          "part": "Title",
          "measure": "a level 3 heading, 17/24 weight 700, one line cut with an ellipsis, 6 px above the meta line",
          "token": "--type-product-title-3, --text"
        },
        {
          "part": "Meta line",
          "measure": "city, country · industry · seniority · English level; 14/20; two lines below 768 px, one from 768 px; 8 px above the intro; middle dots with 6 px on each side, hidden from screen readers",
          "token": "--type-product-body, --text-label"
        },
        {
          "part": "Intro",
          "measure": "14/20, two lines cut with an ellipsis",
          "token": "--type-product-body, --text-muted"
        },
        {
          "part": "Pay column",
          "measure": "below 768 px a row under the text, the pay at the left and the button at the right; from 768 px a right aligned column, 12 px between the pay and the button",
          "token": "--space-3"
        },
        {
          "part": "Pay",
          "measure": "17/24 weight 700, tabular digits, range written low to high with the code once: 968 to 1,250 EUR",
          "token": "--type-product-title-3, --text"
        },
        {
          "part": "Pay basis",
          "measure": "12/16: net per month; from 768 px followed by a middle dot and the age of the post",
          "token": "--type-product-caption, --text-muted"
        },
        {
          "part": "Button",
          "measure": "looks like a small button, 36 px, at least 112 px wide, radius 8 px, label View role; hidden from screen readers and takes no focus",
          "token": "--surface-control, --radius-lg, --type-product-dense"
        }
      ],
      "variants": [
        {
          "name": "Live",
          "use": "An open role."
        },
        {
          "name": "Expired",
          "use": "A closed role that still links to its page; same footprint as a live card."
        }
      ],
      "sizes": [
        {
          "name": "Stacked",
          "padding": "20 px",
          "type": "title 17/24"
        },
        {
          "name": "Row, from 768 px",
          "padding": "24 px",
          "type": "title 17/24"
        }
      ],
      "states": [
        {
          "name": "Rest",
          "change": "The card fill; the button in the secondary fill with full ink",
          "tokens": [
            "--surface-1",
            "--surface-control",
            "--text"
          ]
        },
        {
          "name": "Hover (fine pointer)",
          "change": "The card takes the hover wash; the button turns primary",
          "tokens": [
            "--glass-fill-hover",
            "--brand-true",
            "--on-brand"
          ]
        },
        {
          "name": "Pressed",
          "change": "The card takes the active wash",
          "tokens": [
            "--glass-fill-active"
          ]
        },
        {
          "name": "Focus visible",
          "change": "A 2 px ring, 2 px out, around the whole card and its 16 px corner, when its link has keyboard focus",
          "tokens": [
            "--focus-ring",
            "--focus-ring-width",
            "--focus-ring-offset"
          ]
        },
        {
          "name": "Expired",
          "change": "The word Expired after the title in muted ink at 14/20; no strike through, no fading; on hover the button stays secondary",
          "tokens": [
            "--text-muted",
            "--surface-control"
          ]
        },
        {
          "name": "Loading",
          "change": "A skeleton of the same size: a title bar, two meta bars, a pay bar and a button block",
          "tokens": [
            "--surface-control",
            "--radius-2xl"
          ]
        }
      ],
      "keys": [
        {
          "key": "Tab",
          "action": "Moves to the next card's link"
        },
        {
          "key": "Enter",
          "action": "Opens the role"
        }
      ],
      "accessibility": [
        "The cards are a list, one card per item, so the count is announced.",
        "The link in the title is the only control, and its hit area covers the whole card.",
        "The link is named by the position and described by the meta line.",
        "The link of an expired card is named by the position followed by a comma and Expired.",
        "View role is hidden from screen readers and takes no focus.",
        "All text on the card, including the muted intro and the button label, meets 4.5 to 1 in both themes."
      ],
      "content": [
        "Title: the position, in sentence case, translated on a board in another language.",
        "Meta order: city and country, industry, seniority, then the English level when the role asks for one.",
        "Pay: the net monthly range, low to high, with the currency code once at the end; the basis reads net per month.",
        "Age: Today, or {n} days ago.",
        "Button: View role.",
        "Expired: Expired."
      ],
      "tokens": [
        "--surface-1",
        "--surface-control",
        "--glass-fill-hover",
        "--glass-fill-active",
        "--brand-true",
        "--on-brand",
        "--text",
        "--text-label",
        "--text-muted",
        "--radius-2xl",
        "--radius-lg",
        "--space-3",
        "--space-4",
        "--space-5",
        "--space-6",
        "--type-product-title-3",
        "--type-product-body",
        "--type-product-caption",
        "--type-product-dense",
        "--focus-ring",
        "--focus-ring-width",
        "--focus-ring-offset"
      ]
    },
    {
      "title": "WerkAI",
      "path": "/components/werkai",
      "url": "https://design.werklist.com/components/werkai",
      "text": "https://design.werklist.com/agent/components/werkai",
      "summary": "The field where you ask WerkAI, and the card where its answer appears.",
      "version": "2.1.2",
      "kind": "component",
      "name": "WerkAI",
      "purpose": "The field in the WerkOS header that opens WerkAI, and the card in which WerkAI's text is read, accepted or discarded.",
      "use": [
        "Ask field: once per screen, at the center of the desktop header and across the phone header row.",
        "AI card, summary: above the newest message in the reading pane.",
        "AI card, suggestion: inside the reply box, above the editor."
      ],
      "avoid": [
        "Search: it keeps its own place in the rail and the command palette.",
        "Board values WerkAI fills: they stay in their cells (Generated content).",
        "Any icon inside the card other than the WerkAI mark.",
        "A colored, bordered or capsule shaped ask field."
      ],
      "anatomy": [
        {
          "part": "Field container",
          "measure": "a button, 36 px high, the full width of its slot, padding 16 px (12 px compact), radius 8 px, no border, no shadow",
          "token": "--surface-control, --radius-lg, --space-4, --space-3"
        },
        {
          "part": "Field glyph",
          "measure": "sparkle glyph 17 px, stroke 2.25, in a gradient of the button blue, mixed with white at the bottom left and with navy at the top right; the same in both themes",
          "token": "--brand-true, --on-brand, --navy"
        },
        {
          "part": "Field label",
          "measure": "14/20 weight 500, one line with an ellipsis; while examples type, a 1 px caret follows the text",
          "token": "--type-product-body, --text-muted"
        },
        {
          "part": "Field gap",
          "measure": "8 px between the glyph and the label",
          "token": "--space-2"
        },
        {
          "part": "Card container",
          "measure": "a gradient at 135 degrees; the summary has padding 12 by 16 px and runs to the edges of the reading pane; the suggestion has padding 12 px, radius 12 px, 12 px from the sides of the reply box, 8 px above the editor",
          "token": "--ai-from, --ai-to, --space-3, --space-4, --radius-xl, --space-2"
        },
        {
          "part": "WerkAI mark",
          "measure": "the WerkAI sparkle at 20 px in the card ink, 2 px below the top of the first line, the only glyph in the card",
          "token": "--ai-ink"
        },
        {
          "part": "Card text",
          "measure": "14/20, line breaks kept; a suggested action follows as a second paragraph, 8 px below, at weight 500",
          "token": "--type-product-body, --ai-ink"
        },
        {
          "part": "Card buttons",
          "measure": "text buttons at least 32 px high (44 px on touch screens and below 768 px), padding 10 px, radius 8 px, 13/18; Accept at weight 500, Discard and Try again at 400; at the right, 4 px apart, 8 px under the text",
          "token": "--type-product-dense, --radius-lg, --ai-ink"
        }
      ],
      "variants": [
        {
          "name": "Ask field",
          "use": "At the center of the desktop header."
        },
        {
          "name": "Ask field, compact",
          "use": "In the phone header row, with its own short examples."
        },
        {
          "name": "AI card, summary",
          "use": "In the reading pane; no buttons; always in English."
        },
        {
          "name": "AI card, suggestion",
          "use": "In the reply box; Discard and Accept; in the language of the email."
        }
      ],
      "sizes": [
        {
          "name": "Field",
          "height": "36 px",
          "padding": "16 px",
          "type": "14/20 weight 500"
        },
        {
          "name": "Field, compact",
          "height": "36 px",
          "padding": "12 px",
          "type": "14/20 weight 500"
        }
      ],
      "states": [
        {
          "name": "Field rest",
          "change": "The control fill and a muted label",
          "tokens": [
            "--surface-control",
            "--text-muted"
          ]
        },
        {
          "name": "Field hover and focus",
          "change": "The fill takes 14 percent of --brand-blue over the control fill; the label turns to full ink; with motion allowed, the glyph turns 12 degrees and grows to 1.1 over 300 ms",
          "tokens": [
            "--brand-blue",
            "--surface-control",
            "--text",
            "--duration-slow",
            "--ease-standard"
          ]
        },
        {
          "name": "Field focus visible",
          "change": "A 2 px ring, 2 px out",
          "tokens": [
            "--focus-ring",
            "--focus-ring-width",
            "--focus-ring-offset"
          ]
        },
        {
          "name": "Field pressed",
          "change": "Scale 0.99",
          "tokens": []
        },
        {
          "name": "Field examples",
          "change": "On the home page, once per session, the field types a few example requests behind a blinking caret and erases each one; it stops when the person moves to another page",
          "tokens": []
        },
        {
          "name": "Card waiting",
          "change": "The final height held; three 6 px dots 4 px apart, the lit dot moving every 260 ms, the others at 40 percent",
          "tokens": [
            "--ai-ink"
          ]
        },
        {
          "name": "Card typing",
          "change": "The text appears over 600 ms at its final height",
          "tokens": []
        },
        {
          "name": "Card shown",
          "change": "The full text and, in a suggestion, the two buttons",
          "tokens": []
        },
        {
          "name": "Card failed",
          "change": "One sentence at 13/18 with Try again and Discard; the sentence is at least 192 px wide, so the buttons wrap under it on narrow screens",
          "tokens": [
            "--ai-ink"
          ]
        },
        {
          "name": "Card button hover",
          "change": "A wash of the ink at 10 percent",
          "tokens": [
            "--ai-ink"
          ]
        },
        {
          "name": "Card button focus",
          "change": "A 2 px ring, 2 px out",
          "tokens": [
            "--focus-ring"
          ]
        },
        {
          "name": "Reduced motion",
          "change": "No examples, no caret, no glyph turn, no typing, still dots; the text appears whole",
          "tokens": []
        }
      ],
      "keys": [
        {
          "key": "Tab",
          "action": "Moves to the field; in a suggestion, to Discard, then Accept"
        },
        {
          "key": "Enter or Space",
          "action": "Opens WerkAI from the field, or presses the focused card button"
        }
      ],
      "accessibility": [
        "The field is a button named Ask WerkAI that opens WerkAI. The typed examples are hidden from screen readers.",
        "The card is a region named AI summary or Suggested reply. The summary is marked as English.",
        "A screen reader receives the whole card text at once. The typed copy is hidden from it.",
        "The dots are hidden from screen readers, and a sentence beside them is read instead: Preparing the summary, Writing a suggested reply.",
        "After Accept the caret is in the editor. After Discard focus returns to the reply.",
        "The field label and the card text meet 4.5 to 1 in both themes."
      ],
      "content": [
        "Name: WerkAI, one word with capital W, A and I.",
        "Field label: Ask WerkAI.",
        "Card names: AI summary; Suggested reply. Buttons: Accept, Discard, Try again.",
        "Desktop examples: Send an email to Martina; Show me what is overdue this week; Draft an offer for a new client; Find the candidates from Nepal; Who is working on the Bosnia project?; Summarize yesterday's meeting notes.",
        "Phone examples: Email Martina; What is overdue?; Draft an offer; Nepal candidates; Tasks for today."
      ],
      "tokens": [
        "--surface-control",
        "--text-muted",
        "--text",
        "--brand-blue",
        "--brand-true",
        "--on-brand",
        "--navy",
        "--focus-ring",
        "--focus-ring-width",
        "--focus-ring-offset",
        "--radius-lg",
        "--radius-xl",
        "--space-2",
        "--space-3",
        "--space-4",
        "--type-product-body",
        "--type-product-dense",
        "--ai-from",
        "--ai-to",
        "--ai-ink",
        "--duration-slow",
        "--ease-standard"
      ]
    },
    {
      "title": "Country mark",
      "path": "/components/country-mark",
      "url": "https://design.werklist.com/components/country-mark",
      "text": "https://design.werklist.com/agent/components/country-mark",
      "summary": "The round flag before a country's name: its sizes, what it shows when a flag is missing, and long names.",
      "version": "2.1.2",
      "kind": "component",
      "name": "Country mark",
      "purpose": "A round flag set before a country's name, so a reader finds the country in a long list at a glance. It sits beside the name and does not replace it.",
      "use": [
        "Wherever a row names a country: a board cell, a picker, a group header, a filter, a report table and the header of a page about one country."
      ],
      "avoid": [
        "Maps, chart legends, bullets and status.",
        "A mark without its name.",
        "A flag emoji or a square flag."
      ],
      "anatomy": [
        {
          "part": "Disc",
          "measure": "the flag file for the country's two letter ISO code, cropped to a circle"
        },
        {
          "part": "Ring",
          "measure": "1 px outside the disc, ink at 14 percent in the light theme, white at 15 percent in the dark theme"
        },
        {
          "part": "Fill behind the flag",
          "measure": "shows while the file loads",
          "token": "--surface-2"
        },
        {
          "part": "Space before the name",
          "measure": "8 px",
          "token": "--space-2"
        },
        {
          "part": "Alignment",
          "measure": "centered on the first line of the name"
        }
      ],
      "variants": [
        {
          "name": "Flag",
          "use": "a country with a flag file"
        },
        {
          "name": "Two letter disc",
          "use": "a code without a flag file"
        },
        {
          "name": "Globe",
          "use": "the General row, which stands for all countries"
        },
        {
          "name": "No mark",
          "use": "an unknown country, which the name column says"
        }
      ],
      "sizes": [
        {
          "name": "Dense list",
          "height": "16 px",
          "type": "12 px"
        },
        {
          "name": "Board grid, pickers and filters, the default",
          "height": "20 px",
          "type": "13 px"
        },
        {
          "name": "Chart row label",
          "height": "1.15 em",
          "type": "13 px"
        },
        {
          "name": "Report listing card",
          "height": "24 px",
          "type": "15 px"
        },
        {
          "name": "Header of a page about one country",
          "height": "28 px",
          "type": "22 px"
        },
        {
          "name": "Report page header",
          "height": "32 px",
          "type": "34 px"
        },
        {
          "name": "Report table, print",
          "height": "10 pt",
          "type": "9.5 pt"
        },
        {
          "name": "Running head, print",
          "height": "8 pt",
          "type": "7.5 pt"
        },
        {
          "name": "Report cover, print",
          "height": "28 pt",
          "type": "26 pt"
        }
      ],
      "states": [
        {
          "name": "Loading",
          "change": "the fill shows until the file arrives, and nothing moves",
          "tokens": [
            "--surface-2"
          ]
        },
        {
          "name": "Missing file",
          "change": "the two letter code, 9 px at weight 700, on the control surface",
          "tokens": [
            "--surface-control",
            "--text-muted"
          ]
        },
        {
          "name": "General",
          "change": "the globe icon, 16 px in a 20 px box, stroke 1.75",
          "tokens": [
            "--text-muted"
          ]
        },
        {
          "name": "Unknown country",
          "change": "no mark"
        }
      ],
      "accessibility": [
        "The mark is decoration beside the name. It has empty alt text and is hidden from screen readers, so the name is read once.",
        "The mark takes no focus and has no states of its own. The row or cell around it owns focus and keys.",
        "A name cut to one line shows whole in a tooltip, and screen readers read it whole.",
        "Letters on the two letter disc measure 4.50 to 1 in the light theme and 6.92 to 1 in the dark theme."
      ],
      "content": [
        "The country name in the reader's language.",
        "The two letter disc shows the country's ISO code, such as NP for Nepal."
      ],
      "tokens": [
        "--surface-2",
        "--surface-control",
        "--text-muted",
        "--space-2"
      ],
      "rules": [
        "Each place has one size, such as 16 px in a dense list and 20 px in the board grid.",
        "The smallest mark is 15 px on screen and 8 pt in print. Below that the circle crops away what tells some flags apart.",
        "A long name wraps under itself, and the mark stays level with the first line."
      ]
    },
    {
      "title": "Stat tile",
      "path": "/components/stat-tile",
      "url": "https://design.werklist.com/components/stat-tile",
      "text": "https://design.werklist.com/agent/components/stat-tile",
      "summary": "One figure with its label and, when it helps, how it changed.",
      "version": "2.1.2",
      "kind": "component",
      "name": "Stat tile",
      "purpose": "One figure with its label and, when it helps, its signed change against a named comparison.",
      "use": [
        "The few figures a report exists to show, in one row at the top",
        "The key numbers page of a printed report"
      ],
      "avoid": [
        "A trend or a comparison: use a chart",
        "More than one value per tile",
        "Icons, progress rings, sparklines or a counting animation inside a tile"
      ],
      "anatomy": [
        {
          "part": "Surface",
          "measure": "16 px radius, 16 px padding, no border",
          "token": "--surface-1"
        },
        {
          "part": "Label",
          "measure": "12 px, weight 500, sentence case, up to two lines",
          "token": "--text-muted"
        },
        {
          "part": "Label to value",
          "measure": "6 px"
        },
        {
          "part": "Value",
          "measure": "weight 700, tabular, letter spacing minus 0.02 em, line height 1. 28 px up to 9 characters, 22 px up to 13, 18 px beyond. It wraps between groups of digits or before the currency code and is never cut short",
          "token": "--text"
        },
        {
          "part": "Change",
          "measure": "12 px, weight 500, a signed figure and its comparison",
          "token": "--success-ink"
        },
        {
          "part": "Row",
          "measure": "2 columns, 4 from 1024 px, or 3 or 6 columns for a set of 3 or 6 tiles, 12 px apart",
          "token": "--space-3"
        }
      ],
      "variants": [
        {
          "name": "Screen",
          "use": "Reports in WerkOS and pages on werklist.com"
        },
        {
          "name": "Paper",
          "use": "The key numbers page of a printed report. No surface. Label 7.5 pt, figure 26 pt weight 700, unit and year 7.5 pt, change 7.5 pt in plain ink"
        }
      ],
      "sizes": [
        {
          "name": "Up to 9 characters",
          "type": "28 px"
        },
        {
          "name": "Up to 13 characters",
          "type": "22 px"
        },
        {
          "name": "Longer",
          "type": "18 px, wrapping"
        }
      ],
      "states": [
        {
          "name": "Good change",
          "change": "change line in the success ink",
          "tokens": [
            "--success-ink"
          ]
        },
        {
          "name": "Bad change",
          "change": "change line in the error ink",
          "tokens": [
            "--error-ink"
          ]
        },
        {
          "name": "Neutral change",
          "change": "change line in the quiet ink",
          "tokens": [
            "--text-muted"
          ]
        },
        {
          "name": "Small change",
          "change": "under 1 percent the change line is left out"
        },
        {
          "name": "Missing",
          "change": "the reason in words in place of the value, 18 px, in muted ink. A rate needs 5 observations before it prints",
          "tokens": [
            "--text-muted"
          ]
        },
        {
          "name": "Loading",
          "change": "a skeleton block the size of the tile"
        },
        {
          "name": "Link",
          "change": "when the tile opens a detail view: focus ring, 44 px target, hover fill",
          "tokens": [
            "--focus-ring"
          ]
        }
      ],
      "keys": [
        {
          "key": "Tab",
          "action": "Reaches the tile only when it is a link"
        },
        {
          "key": "Enter",
          "action": "Opens the detail view of a linked tile"
        }
      ],
      "accessibility": [
        "A group named by the label",
        "Value and change read as one sentence, sign included",
        "The missing reason is visible text",
        "Not focusable unless it is a link"
      ],
      "content": [
        "Labels are plain nouns in sentence case: Offers accepted, Placement fees, No show rate",
        "The change names its comparison: +12% on last month",
        "Money prints its currency code after the figure: 245,000 EUR",
        "A long value steps down in size and wraps. It is never shortened to fit"
      ],
      "tokens": [
        "--surface-1",
        "--radius-2xl",
        "--space-4",
        "--space-3",
        "--text",
        "--text-muted",
        "--success-ink",
        "--error-ink",
        "--focus-ring"
      ]
    },
    {
      "title": "Human and agent selector",
      "path": "/components/view-selector",
      "url": "https://design.werklist.com/components/view-selector",
      "text": "https://design.werklist.com/agent/components/view-selector",
      "summary": "The control at the bottom of the window that switches a page between its designed view and a plain text view.",
      "version": "2.1.2",
      "kind": "component",
      "name": "Human and agent selector",
      "purpose": "A floating radio group of two that switches a page between its designed view and a plain text view.",
      "use": [
        "On every page, fixed at the bottom center of the window."
      ],
      "avoid": [
        "In print.",
        "A third option, the theme included.",
        "Hiding it while the page scrolls."
      ],
      "anatomy": [
        {
          "part": "Capsule",
          "measure": "fixed 16 px above the bottom safe area, centered in the window, 48 px high, inner padding 4 px, 2 px between options, full radius, no border",
          "token": "--surface-1, --elevation-2, --radius-full, --space-1, --layer-selector"
        },
        {
          "part": "Option",
          "measure": "40 px high, 16 px at each side, full radius",
          "token": "--type-nav, --space-4"
        },
        {
          "part": "Chosen fill",
          "measure": "Werklist blue with a white label. The fill changes color in 150 ms, it does not slide",
          "token": "--brand-true, --on-brand, --duration-fast, --ease-standard"
        }
      ],
      "states": [
        {
          "name": "Rest",
          "change": "Muted ink",
          "tokens": [
            "--text-muted"
          ]
        },
        {
          "name": "Hover",
          "change": "Control fill and full ink on the option not chosen",
          "tokens": [
            "--surface-control",
            "--text"
          ]
        },
        {
          "name": "Chosen",
          "change": "Werklist blue fill, white label, aria-checked true",
          "tokens": [
            "--brand-true",
            "--on-brand"
          ]
        },
        {
          "name": "Focus",
          "change": "2 px ring, 2 px offset",
          "tokens": [
            "--focus-ring"
          ]
        },
        {
          "name": "Reduced motion",
          "change": "The color changes at once"
        },
        {
          "name": "Forced colors",
          "change": "The capsule is outlined, and the chosen option keeps a 1 px outline"
        },
        {
          "name": "At the footer",
          "change": "Stays at the foot of the window, over the footer too, to the end of the page"
        },
        {
          "name": "Hidden",
          "change": "In print, and while a dialog or the menu is open"
        }
      ],
      "keys": [
        {
          "key": "Tab",
          "action": "Reaches the chosen option"
        },
        {
          "key": "ArrowLeft, ArrowRight, ArrowUp, ArrowDown",
          "action": "Move to the other option and choose it"
        },
        {
          "key": "Home, End",
          "action": "Choose the first or the last option"
        },
        {
          "key": "Space",
          "action": "Chooses the focused option"
        }
      ],
      "accessibility": [
        "A radio group named View, with two radio options.",
        "It comes right after the skip link, before the header.",
        "Focus stays on the selector after a switch.",
        "Muted ink and the white label on blue meet 4.5 to 1 in both themes."
      ],
      "content": [
        "Option labels: Human, Agent.",
        "Group name: View."
      ],
      "rules": [
        "The page keeps its scroll position after a switch.",
        "Leave free room at the end of each page, so the selector never covers the last line."
      ],
      "tokens": [
        "--surface-1",
        "--elevation-2",
        "--radius-full",
        "--space-1",
        "--space-4",
        "--type-nav",
        "--text",
        "--text-muted",
        "--surface-control",
        "--brand-true",
        "--on-brand",
        "--focus-ring",
        "--layer-selector",
        "--duration-fast",
        "--ease-standard"
      ]
    },
    {
      "title": "Empty states",
      "path": "/patterns/empty-states",
      "url": "https://design.werklist.com/patterns/empty-states",
      "text": "https://design.werklist.com/agent/patterns/empty-states",
      "summary": "One calm sentence and the next action, for a list or a board with nothing to show.",
      "version": "2.1.2",
      "kind": "pattern",
      "name": "Empty states",
      "purpose": "Tells the reader why a loaded surface has nothing to show and offers the action that fills it: one sentence, at most one action, no icon.",
      "use": [
        "A surface has loaded and has no items",
        "A search or a filter returned nothing",
        "The reader has dealt with everything and is all caught up",
        "A list that only the reader's own action fills is empty",
        "A reader who cannot add sees an empty surface"
      ],
      "avoid": [
        "Before the content has loaded: show the skeleton",
        "When the load failed: show the error in place",
        "Icons, illustrations, a second paragraph"
      ],
      "anatomy": [
        {
          "part": "Sentence on a page",
          "measure": "20 px, 26 px from 640 px wide, line height 1.25, weight 700, in balanced lines at most 34 rem wide",
          "token": "--text"
        },
        {
          "part": "Sentence in a panel or a card",
          "measure": "14 px on 20 px, weight 400",
          "token": "--text-muted"
        },
        {
          "part": "Action on a page",
          "measure": "Primary button, 44 px, 24 px under the sentence. It opens the same form as the Add button in the toolbar.",
          "token": "--space-6"
        },
        {
          "part": "Action in a panel or a card",
          "measure": "Quiet small button or a link, 8 px under the sentence, or none",
          "token": "--space-2"
        },
        {
          "part": "Space above and below",
          "measure": "On a page 48 px, 64 px from 640 px wide. In a panel or a card 48 px.",
          "token": "--space-12, --space-16"
        }
      ],
      "variants": [
        {
          "name": "Nothing yet",
          "use": "Says what goes here and offers the create action: 'Add the first candidate to this project.'"
        },
        {
          "name": "Nothing matches",
          "use": "Says the search or the filters hid everything and offers Clear filters or Clear search"
        },
        {
          "name": "All done",
          "use": "Says the reader is finished and offers nothing: 'You are all caught up.'"
        },
        {
          "name": "Filled by you",
          "use": "Says how the list fills and offers nothing: 'Candidates you save appear here.'"
        },
        {
          "name": "No access",
          "use": "Says who can add and offers nothing: 'Only the owners of this board can add items.'"
        },
        {
          "name": "Error in place",
          "use": "The failure sentence in full ink and Try again, as the Errors pattern sets it"
        }
      ],
      "rules": [
        "One sentence and at most one action. No icon, illustration or second paragraph.",
        "The toolbar, the search field and the filters stay above the empty state.",
        "In a table the header row stays, and the small sentence fills a body at least three rows high.",
        "A surface is empty only after it has loaded. While it loads it shows its skeleton, and a failed load shows the error.",
        "The action opens the same form as the Add button in the toolbar.",
        "A search that finds nothing is announced once: 'No candidates match.'"
      ],
      "accessibility": [
        "The sentence is plain text in reading order. It is a heading only when the surface has no other.",
        "The action follows the sentence in reading order."
      ],
      "content": [
        "Say what goes here or why nothing is here.",
        "No 'Oops', no exclamation mark, no 'No data'."
      ],
      "tokens": [
        "--text",
        "--text-muted",
        "--space-2",
        "--space-6",
        "--space-12",
        "--space-16"
      ]
    },
    {
      "title": "Loading",
      "path": "/patterns/loading",
      "url": "https://design.werklist.com/patterns/loading",
      "text": "https://design.werklist.com/agent/patterns/loading",
      "summary": "What you see from asking for something until it arrives, including a slow network and a partial load.",
      "version": "2.1.2",
      "kind": "pattern",
      "name": "Loading",
      "purpose": "Chooses the indicator for a wait and sets what happens as the wait grows, when it fails, when it partly fails and when the reader is offline.",
      "use": [
        "A page or a panel that opens",
        "An action that waits on the server",
        "Imports and uploads",
        "A slow network, and offline"
      ],
      "avoid": [
        "A lone spinner for a page load",
        "Blocking the page for one panel",
        "More than one indicator for one action"
      ],
      "rules": [
        "A page or a panel shows its skeleton from the first frame.",
        "A button stops taking presses at once. Its spinner appears after one second.",
        "A list that loads more rows shows a 20 px spinner in its footer.",
        "Work of known size shows a progress bar with counts, where the work started.",
        "Work that outlasts the page keeps its bar and ends with a toast if the reader is still in the module, or a notification if not.",
        "After 10 seconds the skeleton stays, and a neutral inline message above the content says what is still loading. It leaves when the content arrives.",
        "A failed request shows the error in place with Try again.",
        "A partial failure keeps what arrived and shows a warning band with Try again.",
        "Offline, the page keeps what it has and says so in a neutral band. Actions that need the network wait and run when it returns, or say that they cannot.",
        "Focus never moves because content arrived."
      ],
      "accessibility": [
        "The loading region is marked busy with aria-busy.",
        "Each region says one visually hidden status sentence, once: 'Loading candidates'.",
        "A wait started with a button is carried by the button's busy state."
      ],
      "content": [
        "Name what is loading: 'The board is still loading. Your connection may be slow.'",
        "Offline: 'You are offline. Some actions wait until the connection is back.'",
        "Partial: 'Some notifications did not load.' with Try again"
      ]
    },
    {
      "title": "Errors",
      "path": "/patterns/errors",
      "url": "https://design.werklist.com/patterns/errors",
      "text": "https://design.werklist.com/agent/patterns/errors",
      "summary": "Where a failure is reported and how it is worded: what did not happen, and what to do now.",
      "version": "2.1.2",
      "kind": "pattern",
      "name": "Errors",
      "purpose": "Places each failure where it happened and words it as what did not happen and what to do now, without blame and without losing the reader's input.",
      "use": [
        "A field the form cannot accept: an error under the field",
        "An action that did not go through: an error toast with Try again",
        "A page or a list that did not load: the error in place of the content",
        "Part of a list that did not load: a warning band above the part that loaded",
        "A condition that stops the page: an error inline message at the top, with the fix",
        "A failure inside an open dialog: an inline message at the top of the dialog"
      ],
      "avoid": [
        "An error sent as a notification",
        "An error behind the scrim of a dialog",
        "Try again when trying again cannot work",
        "A confirmation dialog for a loss that Undo can reverse"
      ],
      "rules": [
        "Say what did not happen, naming the thing, then what to do.",
        "Give the cause only in the reader's words, and only when it helps them act.",
        "Write about the thing, not the person.",
        "Keep the reader's input. A failed save leaves the form filled, and an offer that was not sent keeps what you wrote.",
        "Offer Try again only when trying again can work. Otherwise name what can.",
        "No apology, exclamation mark or code in the sentence. A support reference goes on its own line after it, where it can be copied.",
        "The error in place is laid out as an empty state: the sentence in --text and a secondary Try again button. The toolbar stays.",
        "The error ink --error-ink is for error toasts and error inline messages.",
        "A page that did not load says 'This page did not load.' at page size, with Try again and no icon.",
        "After a failed submit, focus moves to the message at the top of the form, which links to each field."
      ],
      "accessibility": [
        "An error raised by the reader's action is an alert, heard once.",
        "An error present when the page loads is read in its place.",
        "Color is never the only signal: the sentence names the problem."
      ],
      "content": [
        "'The offer was not sent. Try again.'",
        "'Could not reach the server. Nothing was sent.'",
        "'The job board did not answer. Try again in a moment.'",
        "Not 'Something went wrong.', not 'Invalid input', not 'Oops'"
      ],
      "tokens": [
        "--text",
        "--error-ink",
        "--warning-ink",
        "--surface-control"
      ]
    },
    {
      "title": "Forms",
      "path": "/patterns/forms",
      "url": "https://design.werklist.com/patterns/forms",
      "text": "https://design.werklist.com/agent/patterns/forms",
      "summary": "How to ask for information: what to ask, layout, checking answers, sending, and phones with the keyboard open.",
      "version": "2.1.2",
      "kind": "pattern",
      "name": "Forms",
      "purpose": "Collects information from a person with the least typing and the clearest correction.",
      "use": [
        "Creating a record",
        "Editing a record with a send button",
        "Public intake forms"
      ],
      "avoid": [
        "Asking for what the record, the account or the previous step already holds",
        "Two columns of unrelated fields",
        "Saving on send and saving each change on the same screen"
      ],
      "anatomy": [
        {
          "part": "Column",
          "measure": "One column, at most 768 px, labels above the fields"
        },
        {
          "part": "Between fields",
          "measure": "16 px",
          "token": "--space-4"
        },
        {
          "part": "Between groups",
          "measure": "32 px, each group under a short heading",
          "token": "--space-8"
        },
        {
          "part": "Pairs",
          "measure": "Two fields on a row only when people read them as a pair. They stack below 640 px."
        },
        {
          "part": "Buttons",
          "measure": "At the end of the form, secondary then primary, 8 px apart. Below 640 px they take the full width, stacked, the primary on top.",
          "token": "--space-2"
        },
        {
          "part": "Sheet on a phone",
          "measure": "Below 640 px a form in a dialog is a sheet as tall as the space the keyboard leaves. The questions scroll, the buttons stay at the bottom, and the field being typed in stays 16 px above them."
        }
      ],
      "states": [
        {
          "name": "Empty",
          "change": "A default is filled in where one answer suits most people"
        },
        {
          "name": "Sent with answers to change",
          "change": "All errors show at once. In a form that fits the window, focus moves to the first field with an error. In a longer form, a message above the form says how many answers need a change, links to each and takes the focus."
        },
        {
          "name": "Sending",
          "change": "The primary button takes no presses and shows a spinner after one second. The answers stay as they are."
        },
        {
          "name": "Failed",
          "change": "The answers stay. An error message above the first field says what happened and takes the focus."
        },
        {
          "name": "Sent",
          "change": "The new record shows, selected, where the person expects it"
        },
        {
          "name": "Closing with unsent answers",
          "change": "Ask first: Discard changes? with Discard and Keep editing"
        }
      ],
      "keys": [
        {
          "key": "Enter in a field",
          "action": "Sends the form"
        },
        {
          "key": "Cmd+Enter or Ctrl+Enter in a text area",
          "action": "Sends the form"
        },
        {
          "key": "Escape",
          "action": "Closes a form in a dialog, and asks first when answers are unsent"
        }
      ],
      "accessibility": [
        "Each field shows its own message, under the field.",
        "Text in fields stays at 16 px on a phone, and the page can still be zoomed by hand."
      ],
      "content": [
        "The primary button names the action and the object: Add candidate, Save changes, Send offer.",
        "A failure says what happened, then what to do: 'The candidate was not saved. Check your connection and try again.'",
        "When every question is required, one sentence above the form says so, instead of a mark on each."
      ],
      "rules": [
        "Ask only for what WerkOS cannot find out.",
        "Check a format when the person leaves a field they filled in. Check required answers when the form is sent.",
        "The send button stays enabled.",
        "A failed submit moves focus to the first field with an error in a form that fits the window, and to a summary with links in a longer one.",
        "A settings panel saves each change and says Saved. A form saves when it is sent."
      ],
      "tokens": [
        "--space-2",
        "--space-4",
        "--space-8"
      ]
    },
    {
      "title": "Search and filtering",
      "path": "/patterns/search",
      "url": "https://design.werklist.com/patterns/search",
      "text": "https://design.werklist.com/agent/patterns/search",
      "summary": "How people find records: where search sits, how results arrive, and what an empty, slow or failed search says.",
      "version": "2.1.2",
      "kind": "pattern",
      "name": "Search and filtering",
      "purpose": "Helps people find a record by what they remember, with results that follow the typing.",
      "use": [
        "A search field above the list it filters",
        "The command palette for all of WerkOS"
      ],
      "avoid": [
        "A search field that does not name what it searches",
        "Clearing the results on each key"
      ],
      "states": [
        {
          "name": "Idle",
          "change": "The placeholder names what the field searches: Search candidates"
        },
        {
          "name": "Typing",
          "change": "The search starts from the second character, a moment after the typing stops"
        },
        {
          "name": "Waiting",
          "change": "The earlier results stay in view, dimmed, until the new ones arrive"
        },
        {
          "name": "Results",
          "change": "Closest match first, grouped by kind, matched words marked"
        },
        {
          "name": "Nothing matches",
          "change": "Names the search and the next step, such as Clear filters"
        },
        {
          "name": "Failed",
          "change": "The earlier results stay under the line 'Search did not finish.' and a Try again button. The empty state does not show."
        }
      ],
      "keys": [
        {
          "key": "Cmd+K or Ctrl+K",
          "action": "Opens the command palette"
        },
        {
          "key": "/",
          "action": "Moves focus to the search field of the module"
        },
        {
          "key": "Up and Down arrows",
          "action": "Move through the results in the palette"
        },
        {
          "key": "Enter",
          "action": "Opens the highlighted result"
        },
        {
          "key": "Escape",
          "action": "Clears the query, then closes"
        }
      ],
      "accessibility": [
        "In the command palette the field tells a screen reader which result is highlighted.",
        "When the results settle, a screen reader hears how many there are."
      ],
      "content": [
        "Nothing matches: 'No candidates match “welder Kathmandu”.' with Clear filters",
        "Failed: 'Search did not finish.' with Try again",
        "Active filters in words: Status is Offer sent"
      ],
      "rules": [
        "Search from the second character, a moment after the typing stops.",
        "The results always match what is in the field.",
        "Mark the words that matched.",
        "Keep the query in the address, so a shared link opens the same results and Back returns to them.",
        "Put the closest match first, and group results by kind.",
        "Filters sit beside the search field and apply at once. One control clears them all.",
        "A failed search is not an empty one and never shows the empty state.",
        "On a phone, search takes over the header until the person taps Cancel."
      ],
      "tokens": [
        "--text-muted",
        "--focus-ring"
      ]
    },
    {
      "title": "Navigation",
      "path": "/patterns/navigation",
      "url": "https://design.werklist.com/patterns/navigation",
      "text": "https://design.werklist.com/agent/patterns/navigation",
      "summary": "How people find their way around WerkOS and Werklist websites, and how each screen tells them where they are.",
      "version": "2.1.2",
      "kind": "pattern",
      "name": "Navigation",
      "purpose": "How a screen tells people where they are and gets them anywhere within two steps, in WerkOS on desktop and phone and on Werklist websites.",
      "use": [
        "WerkOS on a desktop: the rail for workspaces, the modules panel for modules, the module at its toolbar, tabs or a segmented control inside it, and the command palette for anything by name.",
        "WerkOS on a phone: the bottom bar for workspaces, the workspace screen for its modules, a module with its own bar or none, and the back arrow to leave it.",
        "A website: the header for sections, the section panel for pages, the side navigation for the blocks of a page, and a link to the next page at the end."
      ],
      "avoid": [
        "Search as the only way to a place.",
        "More than two levels in one navigation surface.",
        "A breadcrumb of pages visited.",
        "Hiding or disabling places because of what is on screen."
      ],
      "rules": [
        "Mark the current place at each level at the same time, in full ink and one shape: a fill in WerkOS, an outline in a page list, a bar under a tab. Never with color alone.",
        "One item is marked at each level: the place you chose last.",
        "The place you click lights at once, before the page loads.",
        "Any place is within two steps: a section and a page, or a workspace and a module.",
        "Back returns to where you came from. Opened from a link with no history, it goes to the nearest parent, then the workspace screen, then home.",
        "What a person may not open is left out. A module that is coming keeps its place, marked Soon, and is not a link.",
        "The workspaces keep the same order on phone and desktop.",
        "A breadcrumb appears only inside a folder at least one level below the root, and follows the hierarchy, not the history.",
        "In a breadcrumb the parent folders are links in muted ink, and the current folder is text in full ink at weight 500.",
        "Breadcrumb separators are 14 px chevrons.",
        "When room runs out, the folders above the parent fold into a menu. At 360 px only the parent and the current folder show."
      ],
      "states": [
        {
          "name": "Loading",
          "change": "The navigation stays still and shows the new place. The content shows its skeleton."
        },
        {
          "name": "Empty workspace",
          "change": "The panel says in one sentence that the workspace has no modules",
          "tokens": [
            "--text-muted"
          ]
        },
        {
          "name": "Missing page",
          "change": "The page keeps the header and the navigation"
        }
      ],
      "accessibility": [
        "A screen reader hears the breadcrumb as a list, without the chevrons, and hears which folder is current."
      ],
      "tokens": [
        "--type-nav",
        "--text",
        "--text-muted",
        "--nav-fill-active",
        "--nav-tab-chip",
        "--focus-ring"
      ]
    },
    {
      "title": "Feedback",
      "path": "/patterns/feedback",
      "url": "https://design.werklist.com/patterns/feedback",
      "text": "https://design.werklist.com/agent/patterns/feedback",
      "summary": "Which of toast, inline message, dialog and notification answers which event.",
      "version": "2.1.2",
      "kind": "pattern",
      "name": "Feedback",
      "purpose": "Maps each event that needs a message to one place: a toast, an inline message, a field error, a notification, a dialog or a progress indicator.",
      "use": [
        "Deciding how to report the result of an action",
        "Deciding how to report a condition, a failure or an arrival"
      ],
      "avoid": [
        "Two messages for one event",
        "A dialog for an action that can be undone",
        "A toast for a condition that lasts",
        "A notification for what is already on screen"
      ],
      "rules": [
        "The change shows where the reader made it: no message. The change is the confirmation.",
        "The reader's action changed something out of view, or can be undone: a toast.",
        "The reader's action did not go through: an error toast, or an error inline message when the page cannot go on.",
        "A condition of the page or panel the reader is on: an inline message at its top.",
        "A value the form cannot accept: an error under the field.",
        "Something happened elsewhere, or someone else did it: a notification.",
        "An act that cannot be undone needs a decision: a dialog.",
        "Work is under way: a skeleton, a progress bar or a spinner.",
        "Interrupt only for a decision.",
        "Undo before confirm. A reversible action runs at once and offers Undo in a toast. A dialog is kept for what cannot come back.",
        "One event, one message, one place. When an offer is not sent, you see one error, not also a notification. A message about the work of an open dialog appears inside the dialog."
      ],
      "accessibility": [
        "The page keeps one polite live region, present from the moment it loads.",
        "Toasts, the end of a long task and newly loaded content speak through it once.",
        "Only an error raised by the reader's action speaks as an alert.",
        "No message takes focus, except a dialog and the message at the top of a form."
      ],
      "content": [
        "The result, in the past tense: 'Candidate archived'",
        "The condition, then what it means: 'You are offline. Some actions wait until the connection is back.'",
        "The failure, then the next step: 'The offer was not sent. Try again.'"
      ]
    },
    {
      "title": "Modality",
      "path": "/patterns/modality",
      "url": "https://design.werklist.com/patterns/modality",
      "text": "https://design.werklist.com/agent/patterns/modality",
      "summary": "How to choose between a tooltip, a menu, a popover, a sheet and a dialog, and what happens when one opens over another.",
      "version": "2.1.2",
      "kind": "pattern",
      "name": "Modality",
      "purpose": "Choose the lightest layer for a task, and keep layers that open over one another predictable.",
      "use": [
        "Choosing between a tooltip, a menu, a popover, a side sheet and a dialog",
        "Placing and stacking any layer that opens over the page"
      ],
      "avoid": [
        "A layer for an action that can be undone: act and offer Undo",
        "Two modal layers at once, except a question about the one beneath",
        "Two anchored layers at once, except a submenu, the list of a field or a tooltip inside a popover or dialog"
      ],
      "rules": [
        "Pick the lightest layer: a tooltip for a name or a shortcut, a menu for commands, a popover for a few controls on one item, a side sheet for details read against the page, a dialog for an answer or a short task that comes first.",
        "A layer is placed against the window, so no scrolling list or card cuts it off. It shows once it is in place.",
        "An anchored layer opens 8 px from its trigger and keeps 8 px from the window edges.",
        "It opens upward when less than 280 px remains below and there is more room above.",
        "It is at most 70 percent of the window height and scrolls inside itself when its content is taller. A list inside it is at least 176 px high.",
        "Its start edge lines up with the trigger and moves to the end edge at the window margin. A tooltip centers on its trigger.",
        "When the page scrolls, an anchored layer follows its trigger and closes once the trigger has left the view.",
        "Layer order from the page up: sticky 20, header 40, dialog and sheet 60, toast 70, then tooltip, menu and popover above the toast.",
        "Escape closes the front layer only, so a menu in a dialog takes two presses.",
        "One anchored layer at a time, and one modal layer at a time. A question about the modal layer beneath, such as Discard the changes?, is the only modal that stacks.",
        "When a popover needs a popover of its own, its content moves into a side sheet.",
        "Focus moves into a layer when it opens and returns to the opener when it closes. If the opener is gone, focus goes to the next row, the previous row, then the list.",
        "Tab out of a menu or a popover closes it. Behind a dialog or a sheet the page takes no input and does not scroll.",
        "Anchored layers take the raised fill and shadow, with a 0.5 px rim in dark. On touch screens their fill is opaque (--surface-1). Tooltips take --elevation-2.",
        "Anchored layers open from opacity 0, 4 px toward the trigger and at scale 0.98, in 150 ms, and close the same way. With reduced motion only the opacity changes.",
        "Inside a layer, loading shows the frame and a skeleton. Empty says what is missing and offers the next step. An error shows a message at the top of the body and keeps the entries. Success closes the layer, returns focus and confirms with a toast when the result is out of view.",
        "Layers do not print."
      ],
      "tokens": [
        "--layer-sticky",
        "--layer-header",
        "--layer-dialog",
        "--layer-toast",
        "--layer-popover",
        "--overlay",
        "--glass-fill-raised",
        "--glass-ring-raised",
        "--elevation-2",
        "--elevation-3",
        "--surface-1",
        "--space-2",
        "--duration-fast",
        "--ease-soft",
        "--ease-standard"
      ]
    },
    {
      "title": "Undo and destructive actions",
      "path": "/patterns/undo",
      "url": "https://design.werklist.com/patterns/undo",
      "text": "https://design.werklist.com/agent/patterns/undo",
      "summary": "When to act at once and offer Undo, and when to ask before an action that nothing can reverse.",
      "version": "2.1.2",
      "kind": "pattern",
      "name": "Undo and destructive actions",
      "purpose": "Decide between acting at once with Undo and asking first, and shape both.",
      "use": [
        "Any change that can be restored: archiving a candidate, moving a candidate to another stage, removing a candidate from a shortlist",
        "A confirmation before a rare action nothing can restore, before an irreversible change for other people, or before losing typed entries"
      ],
      "avoid": [
        "A confirmation before an action that can be undone",
        "A Do not ask again checkbox",
        "Typing the name of the object to confirm",
        "A button that has to be pressed twice to confirm"
      ],
      "rules": [
        "Act at once and offer Undo for any change that can be restored.",
        "Ask first only for a rare action nothing can restore, an irreversible change for other people, or closing a form with unsaved entries.",
        "A selection follows the same rule. Archiving a selection asks nothing and Undo brings every row back. Deleting a selection permanently asks in place on the selection bar.",
        "One undo toast at a time. A second undoable action carries out the first and takes its place.",
        "Undo stays open for 5 seconds.",
        "The countdown pauses while the pointer rests on the toast or focus is inside it.",
        "When the time runs out, the action is carried out and the item can still be found where it went.",
        "The Undo button is at least 24 px high, 44 px on touch screens. On a wide screen the toast sits at the bottom center, 24 px above the window edge.",
        "A screen reader announces the toast once, when it appears. The countdown is not announced.",
        "Ask in the small confirmation dialog. The title is a question that names the object, and the body says what is lost and for whom.",
        "The buttons are Cancel and the verb of the title. The verb takes the danger style when it deletes.",
        "Focus starts on Cancel, Escape answers Cancel, and a press on the dimmed page does nothing.",
        "If a change cannot be saved when the time runs out, the rows come back and a toast says so."
      ],
      "content": [
        "Toast: the past tense, with the object and its count: Candidate archived, 12 candidates archived. The button reads Undo, or a more exact word such as Restore.",
        "Confirmation titles: Delete this candidate permanently? Close this job and notify 38 applicants?",
        "Confirmation body: Every applicant for Welder in Split receives an email that the role is filled. An email that has gone out cannot be taken back.",
        "Failure: Some candidates could not be changed."
      ],
      "tokens": [
        "--space-6",
        "--layer-toast",
        "--glass-fill-raised",
        "--elevation-3",
        "--brand-ink",
        "--error-ink"
      ]
    },
    {
      "title": "Files and uploads",
      "path": "/patterns/files",
      "url": "https://design.werklist.com/patterns/files",
      "text": "https://design.werklist.com/agent/patterns/files",
      "summary": "How people add a file, follow its upload, open it and share it, in Drive, on a board and in email.",
      "version": "2.1.2",
      "kind": "pattern",
      "name": "Files and uploads",
      "purpose": "Adding files to Drive, a board cell or an email, following their upload, opening them in place and sharing them at a stated access level.",
      "use": [
        "Any screen that accepts a file: a Drive folder, a file cell on a board, an email being written, a public application form.",
        "Moving items between Drive folders by drag, with Move in the item menu as the keyboard path."
      ],
      "avoid": [
        "A progress dialog that blocks the page. The tray reports progress while the page stays in use.",
        "A second progress display beside the tray."
      ],
      "anatomy": [
        {
          "part": "Upload button",
          "measure": "secondary button, 36 px, in the toolbar; opens the file picker for several files at once",
          "token": "--surface-control"
        },
        {
          "part": "Drop target",
          "measure": "covers the folder or the email being written; radius 16 px; fill only, no border; the sentence Drop files to upload at 14/20 weight 500, centered",
          "token": "--nav-fill-active, --radius-2xl, --type-product-body, --brand-ink"
        },
        {
          "part": "Upload tray",
          "measure": "fixed at the bottom right, 16 px from the right edge, 24 px on windows 1024 px and wider, and above the phone's bottom bar; 320 px wide, or the window minus 32 px; radius 12 px; padding 12 px",
          "token": "--surface-1, --elevation-3, --radius-xl, --space-3, --layer-toast"
        },
        {
          "part": "Progress bar",
          "measure": "38 by 19 px (30 by 15 px collapsed), radius 5 px, fill inset 1.5 px; a green gradient while running, the error fill on failure",
          "token": "--success, --success-deep, --error, --surface-control"
        },
        {
          "part": "Summary line",
          "measure": "13/18 weight 500; percent and size 12/16 in tabular digits",
          "token": "--type-product-dense, --type-product-caption"
        },
        {
          "part": "File row",
          "measure": "status glyph 20 px; name 12/16, cut in the middle so the extension stays in view; percent in tabular digits; a 24 px glyph button, 44 px to touch on touch screens",
          "token": "--type-product-caption, --text, --text-muted"
        },
        {
          "part": "Collapsed tray",
          "measure": "one row with the bar and the summary, radius 12 px",
          "token": "--radius-xl"
        }
      ],
      "states": [
        {
          "name": "Drag over",
          "change": "The drop target tint and sentence appear, and leave when the files leave or drop",
          "tokens": [
            "--nav-fill-active"
          ]
        },
        {
          "name": "Item dragged over a folder",
          "change": "The folder row takes the hover fill and full ink",
          "tokens": [
            "--glass-fill-hover",
            "--text"
          ]
        },
        {
          "name": "Queued",
          "change": "A row with the name and 0 percent",
          "tokens": [
            "--text-muted"
          ]
        },
        {
          "name": "Uploading",
          "change": "The bar fills with the total percent; each row shows its own percent and Cancel",
          "tokens": [
            "--success"
          ]
        },
        {
          "name": "Done",
          "change": "A check glyph; the rows clear once every upload has finished",
          "tokens": [
            "--success-ink"
          ]
        },
        {
          "name": "Failed",
          "change": "The bar takes the error fill; the row keeps the reason and Retry",
          "tokens": [
            "--error",
            "--error-ink"
          ]
        },
        {
          "name": "Refused before start",
          "change": "The row shows the limit sentence, and nothing is sent",
          "tokens": [
            "--error-ink"
          ]
        },
        {
          "name": "Collapsed",
          "change": "One row with the bar and the summary; a click expands it",
          "tokens": [
            "--radius-xl"
          ]
        }
      ],
      "keys": [
        {
          "key": "Tab",
          "action": "Reaches Upload, then Collapse in the tray, then each row's Cancel, Retry or Dismiss"
        },
        {
          "key": "Enter or Space on Upload",
          "action": "Opens the file picker"
        },
        {
          "key": "Enter on an item",
          "action": "Opens the file in the editor or the preview"
        },
        {
          "key": "Escape",
          "action": "Closes the preview, the share dialog or the move dialog and returns focus to the item"
        }
      ],
      "accessibility": [
        "The summary line is announced when an upload starts, finishes or fails, not at each percent.",
        "Each file row is a progress bar named with the file name.",
        "The drop target is hidden from screen readers. The Upload button and Move are the accessible paths.",
        "Cancel, Retry and Dismiss carry the file name in their names, such as Cancel upload of cv-ana-kovac.pdf.",
        "Tray controls are 44 px to touch on touch screens."
      ],
      "content": [
        "Summary: Uploading 3 files, 2 files uploaded, 1 file failed.",
        "Drop target: Drop files to upload.",
        "Limit: Files up to 25 MB. That one is too large. The sentence names the limit of the place the file was dropped.",
        "Failure: Upload failed. Check your connection and try again. Refusal: Upload was refused. You may not have access to save here. Cancel: Upload canceled.",
        "Empty folder: Nothing here yet. Upload files or add a folder.",
        "Share levels: Private, only you and people you grant access; Team, every signed in member can view; Public link, anyone with the link can view. People: Viewer, Editor."
      ],
      "rules": [
        "A file lands where it was dropped or chosen.",
        "Uploads continue when the screen that started them closes.",
        "Drive accepts files up to 50 GB. Attachments on a board or an email are up to 25 MB.",
        "A file that is too large is refused before it starts, with the limit in the sentence.",
        "Every drag has a menu equivalent.",
        "The tray is the one place that reports an upload.",
        "Documents save as you type, with no Save button."
      ],
      "tokens": [
        "--nav-fill-active",
        "--brand-ink",
        "--surface-1",
        "--surface-control",
        "--elevation-3",
        "--radius-xl",
        "--radius-2xl",
        "--success",
        "--success-deep",
        "--success-ink",
        "--error",
        "--error-ink",
        "--text",
        "--text-muted",
        "--type-product-body",
        "--type-product-dense",
        "--type-product-caption",
        "--space-3",
        "--space-4",
        "--space-6",
        "--layer-toast",
        "--focus-ring"
      ]
    },
    {
      "title": "Printing and export",
      "path": "/patterns/printing",
      "url": "https://design.werklist.com/patterns/printing",
      "text": "https://design.werklist.com/agent/patterns/printing",
      "summary": "How a document, an email conversation or a board leaves WerkOS as a PDF, a printed page or a CSV file.",
      "version": "2.1.2",
      "kind": "pattern",
      "name": "Printing and export",
      "purpose": "Turning a WerkOS item into a PDF, a printed page, a Word file or a CSV that holds the item and nothing of the interface around it.",
      "use": [
        "Download as PDF on a document, a spreadsheet, a knowledge base article or a map.",
        "Printing an email conversation.",
        "Export CSV on a board or an audit log, and Import CSV on a board."
      ],
      "avoid": [
        "Printing a document through the browser's print dialog: the browser adds its own date, address and margins.",
        "A dark surface on paper.",
        "A PDF laid out differently from the printed page of the same item."
      ],
      "anatomy": [
        {
          "part": "Sheet",
          "measure": "A4, 794 by 1123 px at 96 dpi; sheets 26 px apart on screen, touching in the PDF"
        },
        {
          "part": "Margin",
          "measure": "72 px (19 mm) on each side"
        },
        {
          "part": "Running head",
          "measure": "the product name, a vertical bar and the document name; 11 px, 30 px from the top, across the text column"
        },
        {
          "part": "Page number",
          "measure": "30 px from the bottom, at the right edge of the text column, when the export asks for it"
        },
        {
          "part": "Body",
          "measure": "Satoshi 15 px on a line of 1.7; headings at 1.7, 1.35 and 1.12 em",
          "token": "--font-sans"
        },
        {
          "part": "Ink and paper",
          "measure": "near black ink on white, the same in both themes"
        }
      ],
      "states": [
        {
          "name": "Ready",
          "change": "The entry names the result",
          "tokens": []
        },
        {
          "name": "Nothing to export",
          "change": "The entry says why: This board has no rows to export.",
          "tokens": [
            "--text-muted"
          ]
        },
        {
          "name": "Building",
          "change": "The primary button reads Exporting, busy and disabled",
          "tokens": [
            "--brand-true"
          ]
        },
        {
          "name": "Queued",
          "change": "Export queued. It will appear under your exports when ready.",
          "tokens": []
        },
        {
          "name": "Done",
          "change": "Downloaded",
          "tokens": []
        },
        {
          "name": "Failed",
          "change": "One sentence and Try again, and no partial file",
          "tokens": [
            "--error-ink"
          ]
        }
      ],
      "keys": [
        {
          "key": "Enter or Space on an export entry",
          "action": "Starts the export or opens its options dialog"
        },
        {
          "key": "Escape",
          "action": "Closes the export dialog without exporting"
        }
      ],
      "accessibility": [
        "The export button is marked busy while the file builds and keeps its name.",
        "A finished download is announced once.",
        "Printed pages carry the language of the document, so a PDF reader voices it correctly."
      ],
      "content": [
        "Entries name the result: Download as PDF, Download as Word, Print conversation, Export CSV, Export PDF.",
        "Export dialog: Page numbers, Bottom right or None."
      ],
      "rules": [
        "A PDF has the layout the editor shows, so the pages seen before export are the pages of the file.",
        "Paper is white in both themes.",
        "Nothing of the interface prints: no menus, buttons, header or theme.",
        "A printed email leaves out images loaded from the web.",
        "List items may break across sheets. Tables, quotes and code blocks move to the next sheet whole.",
        "CSV export follows the view: its filter, sort, hidden columns and order, with the item name first.",
        "CSV import shows a preview before it writes, lists headers that match no column and cells that break their column's rules, and writes nothing invalid.",
        "A long export runs in the background and appears under your exports when it is ready.",
        "A PDF that cannot be built is an error, not a partial document."
      ],
      "tokens": [
        "--font-sans",
        "--brand-true",
        "--error-ink",
        "--text-muted"
      ]
    },
    {
      "title": "Generated content",
      "path": "/patterns/generated-content",
      "url": "https://design.werklist.com/patterns/generated-content",
      "text": "https://design.werklist.com/agent/patterns/generated-content",
      "summary": "How WerkAI output is marked, reviewed by a person and corrected before anyone relies on it.",
      "version": "2.1.2",
      "kind": "pattern",
      "name": "Generated content",
      "purpose": "How text and values that WerkAI writes are marked, reviewed by a person before they leave WerkOS, and corrected or thrown away.",
      "use": [
        "The summary above the newest message in the reading pane.",
        "The suggested reply in the reply box.",
        "The fields WerkAI fills on a project board, a company board and a candidate board."
      ],
      "avoid": [
        "Writing a draft, sending, deleting, publishing, or changing the owner or stage of a record without a person's action.",
        "A skeleton for a result that may not arrive. The waiting card shows only when a result is on its way.",
        "First person, praise, emotion or apology in the text WerkAI writes.",
        "A disclaimer on each card. The name and the mark of the card say who wrote it."
      ],
      "anatomy": [
        {
          "part": "AI card",
          "measure": "see the WerkAI component: gradient fill, one ink, the WerkAI mark at 20 px, text 14/20",
          "token": "--ai-from, --ai-to, --ai-ink, --type-product-body"
        },
        {
          "part": "Column glyph",
          "measure": "the WerkAI glyph at 14 px, 4 px after the name of a column WerkAI fills, in muted ink; screen readers hear the column name followed by Written by WerkAI",
          "token": "--text-muted, --space-1"
        },
        {
          "part": "Waiting dots",
          "measure": "three 6 px dots, 4 px apart; one lit and two at 40 percent; the lit dot moves every 260 ms",
          "token": "--ai-ink"
        },
        {
          "part": "Reveal",
          "measure": "the text types in over 600 ms, and the card has its final height from the start"
        },
        {
          "part": "Cell bar",
          "measure": "8 px high, 75 percent of the cell width, full radius, muted ink at 20 percent, pulsing",
          "token": "--text-muted, --radius-full"
        }
      ],
      "states": [
        {
          "name": "Absent",
          "change": "No card and no space held while no result is on its way",
          "tokens": []
        },
        {
          "name": "Waiting",
          "change": "The card at its final height with the dots; screen readers hear Preparing the summary or Writing a suggested reply",
          "tokens": [
            "--ai-ink"
          ]
        },
        {
          "name": "Revealing",
          "change": "The text types in over 600 ms; screen readers receive the whole text at once",
          "tokens": []
        },
        {
          "name": "Shown",
          "change": "The full text; a suggestion adds Discard and Accept",
          "tokens": []
        },
        {
          "name": "Failed",
          "change": "One sentence in the card ink with Try again and Discard",
          "tokens": [
            "--ai-ink"
          ]
        },
        {
          "name": "Withdrawn",
          "change": "When there is nothing to answer, the card leaves without a word",
          "tokens": []
        },
        {
          "name": "Cell writing",
          "change": "A pulsing bar in place of the value; screen readers hear WerkAI is writing this field",
          "tokens": [
            "--text-muted"
          ]
        },
        {
          "name": "Cell not processed",
          "change": "The words Not processed in muted ink; selecting the cell runs it again, with the cells that depend on it",
          "tokens": [
            "--text-muted"
          ]
        }
      ],
      "keys": [
        {
          "key": "Tab",
          "action": "In a suggestion: Discard, then Accept"
        },
        {
          "key": "Enter or Space",
          "action": "Presses the focused card button; on a Not processed cell, runs it again"
        }
      ],
      "accessibility": [
        "The card is a region named AI summary or Suggested reply.",
        "The summary is marked as English. A suggestion takes the language of the email.",
        "A screen reader receives the whole text at once. The typed copy is hidden from it.",
        "The dots are hidden from screen readers, and a sentence beside them is read instead.",
        "After Accept the caret is in the reply with the text. After Discard focus returns to the reply.",
        "The waiting and failed states announce nothing of their own.",
        "A Not processed cell is named Not processed, select to run WerkAI again."
      ],
      "content": [
        "Card names: AI summary, Suggested reply.",
        "Buttons: Accept, Discard, Try again.",
        "Waiting: Preparing the summary; Writing a suggested reply.",
        "Refusals: AI is not available right now. Too many requests. Try again in a minute. The model could not write this. Try again or say more about it.",
        "Board: Not processed; Reset WerkAI."
      ],
      "rules": [
        "The text WerkAI writes is plain text in sentence case: no markup, no links and no dashes.",
        "No first person, no praise, no emotion. An apology only when WerkAI made the mistake.",
        "Name what is missing (an owner, a date, a decision) and do not invent it.",
        "Summaries are in English on every conversation. Suggestions use the language of the email.",
        "A suggestion appears once, when a reply opens. It does not come back after Discard.",
        "Accept hands the text to the reply, which saves it like typed text. Before Accept nothing is written.",
        "Fields WerkAI fills are ordinary fields: a person's edit is the value.",
        "Reset WerkAI is for the board owner. It runs unfinished cells again and leaves filled ones alone.",
        "The card has no feedback buttons."
      ],
      "tokens": [
        "--ai-from",
        "--ai-to",
        "--ai-ink",
        "--text-muted",
        "--type-product-body",
        "--type-product-dense",
        "--radius-xl",
        "--radius-full",
        "--space-1",
        "--focus-ring"
      ]
    },
    {
      "title": "Marketing pages",
      "path": "/patterns/marketing-pages",
      "url": "https://design.werklist.com/patterns/marketing-pages",
      "text": "https://design.werklist.com/agent/patterns/marketing-pages",
      "summary": "How a werklist.com page is put together: the frame, the photograph and its headline, the proof, the job list and the call to action.",
      "version": "2.1.2",
      "kind": "pattern",
      "name": "Marketing pages",
      "purpose": "The anatomy of a werklist.com page: frame, header, photographic hero, proof figures, job list, closing call to action and footer.",
      "use": [
        "Pages on werklist.com in every language: the home page, employers, industries, job pages.",
        "Any brand page that an employer or a worker reads."
      ],
      "avoid": [
        "A dark marketing page, except an industry page.",
        "Figures without a live source.",
        "Decorative charts, labels in capitals, pill buttons and cards with borders.",
        "Text on a photograph without the scrim."
      ],
      "anatomy": [
        {
          "part": "Frame",
          "measure": "at most 1440 px, centered; padding 24 px, 32 px from 1024 px",
          "token": "--frame, --pad"
        },
        {
          "part": "Header",
          "measure": "72 px, 64 px after 80 px of scroll; see the Header component",
          "token": "--header-h, --header-h-condensed"
        },
        {
          "part": "Hero card",
          "measure": "at least 340 px high, 420 px from 768 px, 480 px from 1024 px; radius 12 px, 16 px from 768 px; navy under the photograph; padding 24 by 40 px, 48 px from 768 px, 80 px at the sides from 1024 px",
          "token": "--radius-xl, --radius-2xl, --navy"
        },
        {
          "part": "Headline",
          "measure": "28 to 56 px as the window grows, weight 700, line 1.15, tracked in by 0.03 em, at most 680 px wide, lines balanced"
        },
        {
          "part": "Paragraph",
          "measure": "14 to 17 px as the window grows, weight 500, line 1.6, at most 760 px wide, white at 92 percent",
          "token": "--on-brand"
        },
        {
          "part": "Button pair",
          "measure": "large buttons, 48 px, both as wide as the longer label, 8 px apart, 12 px from 640 px; stacked at full width below 640 px",
          "token": "--space-2, --space-3"
        },
        {
          "part": "Scrim",
          "measure": "a gradient from navy at 66 percent at the left edge to clear where the text column ends; the same in both themes",
          "token": "--navy"
        },
        {
          "part": "Proof figures",
          "measure": "2 columns 8 px apart, 5 columns 12 px apart from 768 px; each tile holds a number and its label, without a chart",
          "token": "--space-2, --space-3"
        },
        {
          "part": "Job list",
          "measure": "a list of job cards, 8 px apart, 12 px from 768 px; Load more as a secondary button 16 px below",
          "token": "--space-2, --space-3, --space-4"
        },
        {
          "part": "Long copy",
          "measure": "body type in two columns from 1024 px, one below; lines of at most 75 characters",
          "token": "--type-body"
        },
        {
          "part": "Phone call to action bar",
          "measure": "fixed at the bottom below 768 px; padding 12 by 16 px, at least 12 px or the safe area at the bottom; one sentence at 13/18 and a 44 px primary button with radius 8 px",
          "token": "--surface-1, --elevation-2, --radius-lg, --layer-sticky"
        }
      ],
      "states": [
        {
          "name": "Hero, photograph loading",
          "change": "The navy of the card shows until the photograph appears",
          "tokens": [
            "--navy"
          ]
        },
        {
          "name": "Job list, nothing matches",
          "change": "One sentence in a neutral well: No roles match those filters yet.",
          "tokens": [
            "--tint-neutral",
            "--radius-xl"
          ]
        },
        {
          "name": "Job list, more to load",
          "change": "Load more, a secondary button",
          "tokens": []
        },
        {
          "name": "Header scrolled",
          "change": "A translucent surface at 92 percent with a 10 px blur",
          "tokens": []
        }
      ],
      "keys": [
        {
          "key": "Tab",
          "action": "Skip link, header, hero buttons, filters, each job card, Load more, footer"
        },
        {
          "key": "Enter",
          "action": "Follows the focused link or presses the focused button"
        }
      ],
      "accessibility": [
        "One level 1 heading: the hero headline. Job cards sit under a level 2 heading, Open roles. When the design shows no visible heading, the heading is there for screen readers only.",
        "The hero photograph is decorative and hidden from screen readers.",
        "With the scrim, the white headline and paragraph reach 4.5 to 1 against the lightest part of the photograph under them.",
        "With reduced motion, counts and entrances do not animate, and figures show their final value.",
        "The phone bar does not cover focused content: the page ends with space as tall as the bar."
      ],
      "content": [
        "Headline: what Werklist does, in the reader's words; no question, no exclamation.",
        "Reference paragraph: Werklist helps companies hire reliable workers through local recruitment, international sourcing, documentation support, and end-to-end placement coordination.",
        "Buttons: a verb and its object: Talk to sales, Hire workers, See how it works.",
        "Figures: the unit in the label; counts from live data only.",
        "Empty filter: No roles match those filters yet."
      ],
      "rules": [
        "Light in both themes. Industry pages are the one exception: they are dark.",
        "Content spans the frame. The hero and long copy limit their line length.",
        "Every figure has a live source or is removed.",
        "No decorative charts in stat tiles.",
        "No labels in capitals, no eyebrows, no pills. Footer headings are in sentence case.",
        "Text on a photograph always sits on the scrim.",
        "The hero photograph is 2752 by 960 px, 1280 by 447 px on phones, and fills the card from its center."
      ],
      "tokens": [
        "--frame",
        "--pad",
        "--header-h",
        "--header-h-condensed",
        "--space-2",
        "--space-3",
        "--space-4",
        "--radius-xl",
        "--radius-2xl",
        "--radius-lg",
        "--type-body",
        "--tint-neutral",
        "--elevation-2",
        "--layer-sticky",
        "--surface-1",
        "--brand-true",
        "--on-brand",
        "--navy"
      ]
    },
    {
      "title": "Board grid",
      "path": "/data/board-grid",
      "url": "https://design.werklist.com/data/board-grid",
      "text": "https://design.werklist.com/agent/data/board-grid",
      "summary": "The editable table of WerkOS boards: its rows, rules, states, keys and phone view.",
      "version": "2.1.2",
      "kind": "data",
      "name": "Board grid",
      "purpose": "The editable grid of WerkOS boards, where a team keeps hiring projects, candidates and work permits: one row per item, one column per field, edited in place.",
      "use": [
        "Items that share fields and that people add, edit and compare",
        "Boards of hiring projects, candidates, companies and tasks, and the boards a team makes for itself"
      ],
      "avoid": [
        "Final figures that are read or printed: use the report table",
        "A short run of items without columns: use a list",
        "Anything sent outside WerkOS: use a report table"
      ],
      "anatomy": [
        {
          "part": "Row",
          "measure": "36 px compact (the default), 52 px comfortable, 76 px tall, plus a 1 px rule"
        },
        {
          "part": "Row rule",
          "measure": "1 px under each row",
          "token": "--border-rule"
        },
        {
          "part": "Column rule",
          "measure": "1 px on the left of each data, header and footer cell, none on the trailing gutter",
          "token": "--border-rule"
        },
        {
          "part": "Column header",
          "measure": "13 px, weight 500, centered on every column, sentence case, 40 px plus its rule, 6 px between a title and its sort arrow. A title cut short shows in full in a tooltip",
          "token": "--text-label"
        },
        {
          "part": "Name header",
          "measure": "a select all checkbox at the start, always shown, mixed when some rows are chosen, and the board's word for an item centered in the rest",
          "token": "--brand-blue"
        },
        {
          "part": "Name column",
          "measure": "280 px, 560 px on the boards of a WerkOS module, at least 140 px when resized"
        },
        {
          "part": "Name cell",
          "measure": "14 px text, 12 px padding, 8 px gap, cut short at the end",
          "token": "--text"
        },
        {
          "part": "Data column",
          "measure": "at least 60 px. Default widths: text 220, numbers 140, status 200, country 180, date 150, formula 160, timeline 220, time tracking 190 px"
        },
        {
          "part": "Data cell padding",
          "measure": "8 px",
          "token": "--space-2"
        },
        {
          "part": "Figure",
          "measure": "14 px, weight 400, tabular digits, right aligned, with a currency code after it in 12 px muted ink",
          "token": "--text"
        },
        {
          "part": "Group header row",
          "measure": "40 px, with a 14 px gap above it on module boards. Chevron 16 px, title 14 px weight 700 in the group color, count 12 px. Pinned while its rows scroll, on --surface-1 at 85 percent with a 12 px blur",
          "token": "--text-muted"
        },
        {
          "part": "Row marker",
          "measure": "4 by 16 px, full radius, in the group color",
          "token": "--radius-full"
        },
        {
          "part": "Summary footer",
          "measure": "48 px with a rule above and below. Label 11 px in sentence case, value 14 px weight 500 in tabular digits, right aligned",
          "token": "--text-muted"
        },
        {
          "part": "Add item row",
          "measure": "40 px"
        },
        {
          "part": "Trailing gutter",
          "measure": "44 px, for adding a column and deleting a row"
        },
        {
          "part": "Frame",
          "measure": "radius 12 px, no border, no shadow",
          "token": "--surface-1"
        },
        {
          "part": "Row checkbox",
          "measure": "14 px box, radius 4 px, with a 1 px edge: ink at 55 percent on white in light, white at 20 percent on --surface-control in dark. Checked, it fills with --brand-blue and shows an 11 px white tick. It appears on row hover, stays while the row is selected and has a 44 px target on touch screens",
          "token": "--radius-sm"
        },
        {
          "part": "Phone card",
          "measure": "below 640 px. Radius 12 px, padding 12 px, 10 px gap, a soft shadow, no border. The name in 15 px weight 500, then one row of up to 4 fields: labels 11 px centered, values 36 px tall, a status in 12 px type",
          "token": "--surface-1"
        },
        {
          "part": "Phone sheet",
          "measure": "rises from the bottom on the raised glass, with 16 px top corners and a 40 by 4 px grab handle. The column title in 16 px weight 700 over the item name in 12 px. One 44 px row per label at full radius, 14 px weight 500, with a 16 px check on the chosen one",
          "token": "--glass-fill-raised"
        }
      ],
      "variants": [
        {
          "name": "Team board",
          "use": "A board a team makes for itself: the toolbar inside the grid, rows to add, column menus and a row height switch"
        },
        {
          "name": "Module board",
          "use": "A board of a WerkOS module, which holds its own toolbar: no add rows, no column menus, no row height switch"
        },
        {
          "name": "Frozen name column",
          "use": "An option on a board that scrolls sideways, off by default"
        }
      ],
      "sizes": [
        {
          "name": "Compact",
          "height": "36 px"
        },
        {
          "name": "Comfortable",
          "height": "52 px"
        },
        {
          "name": "Tall",
          "height": "76 px"
        }
      ],
      "states": [
        {
          "name": "Hover",
          "change": "a row fill of ink at 3 percent in light and of white at 3 percent in dark, on pointer devices only"
        },
        {
          "name": "Selected row",
          "change": "brand blue at 25 percent over the row, with no hover on top. A frozen name cell mixes the tint into --surface-1 so it stays opaque",
          "tokens": [
            "--brand-blue",
            "--surface-1"
          ]
        },
        {
          "name": "Range",
          "change": "brand blue at 15 percent per cell",
          "tokens": [
            "--brand-blue"
          ]
        },
        {
          "name": "Active cell",
          "change": "a 1 px inset ring of --brand-blue, or the 2 px focus ring while the keyboard is in the grid. An 8 px square fill handle at the bottom right, radius 1 px, ringed with 1 px of --surface-1",
          "tokens": [
            "--brand-blue",
            "--focus-ring",
            "--focus-ring-width",
            "--surface-1"
          ]
        },
        {
          "name": "Editing",
          "change": "an editor over the cell on --surface-strong, 4 px inside its edges, holding a 28 px field: radius 6 px, a fill of ink at 5 percent in light and of white at 6 percent in dark, an inset 1 px ring of light brand blue, no shadow",
          "tokens": [
            "--surface-strong",
            "--radius-md"
          ]
        },
        {
          "name": "Group collapsed",
          "change": "the chevron points right and the rows and the footer are hidden"
        },
        {
          "name": "Empty board",
          "change": "a card in place of the grid, without the column header. A headline of 20 px, 26 px from 640 px, weight 700, tracking minus 0.02 em. One sentence of 14 px, 16 px from 640 px, in --text-muted. One 44 px primary button and no icon",
          "tokens": [
            "--text-muted"
          ]
        },
        {
          "name": "Filtered to nothing",
          "change": "the line No items match these filters in --text-muted and a quiet Clear filters button in place of the groups",
          "tokens": [
            "--text-muted"
          ]
        },
        {
          "name": "Loading",
          "change": "skeleton rows at the board's row height inside a 12 px frame, with --border-rule lines and a soft shimmer",
          "tokens": [
            "--border-rule"
          ]
        }
      ],
      "keys": [
        {
          "key": "Arrow keys",
          "action": "Move the active cell. The first press lands on the first cell"
        },
        {
          "key": "Shift with an arrow",
          "action": "Extend the range"
        },
        {
          "key": "Tab, Shift Tab",
          "action": "Next or previous cell, wrapping to the next row. After the last cell, Tab leaves the grid"
        },
        {
          "key": "Home, End",
          "action": "First or last cell of the row"
        },
        {
          "key": "Ctrl or Cmd with Home, End",
          "action": "First or last cell of the board"
        },
        {
          "key": "Enter, F2",
          "action": "Edit the active cell"
        },
        {
          "key": "Escape",
          "action": "Close the editor and clear the range"
        },
        {
          "key": "Delete, Backspace",
          "action": "Clear the range"
        },
        {
          "key": "Ctrl or Cmd with C, V, D, A",
          "action": "Copy, paste, fill down, select all"
        },
        {
          "key": "Ctrl or Cmd with Z",
          "action": "Undo"
        },
        {
          "key": "Ctrl or Cmd with Shift Z, or with Y",
          "action": "Redo"
        },
        {
          "key": "Shift F10, the menu key",
          "action": "Open the row menu, which holds each action shown on hover"
        }
      ],
      "accessibility": [
        "The board is a grid named by its title, with aria-rowcount and aria-colcount",
        "Each row has role row and its aria-rowindex",
        "The name cell is the row header",
        "Column headers carry aria-sort on the sorted column",
        "Cells are grid cells, with aria-selected inside a range and aria-readonly on read only columns",
        "Of the cells, only the active one is in the tab order",
        "Each group title is a button with aria-expanded that folds its rows",
        "A group header is a row whose header names the group and its count",
        "A status is read by its label, never its color. An empty status shows a hyphen on gray and is read as Empty",
        "Scroll padding matches the pinned headers, so a focused cell never hides behind them",
        "44 px targets on touch screens"
      ],
      "content": [
        "Headers are short nouns in sentence case with no end punctuation",
        "The empty board reads This board is empty and Add your first project to get started. Its button reads Add your first project, with the board's own word for an item",
        "When filters hide every row, the line reads No items match these filters and the button reads Clear filters",
        "Footer labels name the aggregate in sentence case: Sum, Average, Median, Lowest, Highest"
      ],
      "tokens": [
        "--border-rule",
        "--text",
        "--text-label",
        "--text-muted",
        "--surface-1",
        "--surface-strong",
        "--brand-blue",
        "--focus-ring",
        "--focus-ring-width",
        "--radius-xl",
        "--radius-sm",
        "--radius-full",
        "--space-2",
        "--space-3",
        "--radius-md",
        "--surface-control",
        "--glass-fill-raised",
        "--overlay",
        "--layer-sticky"
      ],
      "rules": [
        "Row and column rules in --border-rule, no stripes, no outer border",
        "Headers are centered on every column, numeric ones included",
        "Figures are right aligned, 14 px, weight 400, in tabular digits and in the reader's language. A negative takes the true minus sign (U+2212) and is never red",
        "The column header and the group header stay pinned on every board, under the app header",
        "A blank cell means nobody has filled it. Zero prints 0",
        "Below 640 px the card list replaces the grid. A tap on a status, a person, a date or a timeline opens a sheet",
        "The frozen name column is an option on each board, not the default"
      ]
    },
    {
      "title": "Report table",
      "path": "/data/tables",
      "url": "https://design.werklist.com/data/tables",
      "text": "https://design.werklist.com/agent/data/tables",
      "summary": "The table of reports and documents: a blue head, alternating rows, figures that line up and a source underneath.",
      "version": "2.1.2",
      "kind": "data",
      "name": "Report table",
      "purpose": "The static table of reports and documents, for final figures that people read, compare and print.",
      "use": [
        "Country reports and other PDFs",
        "Report pages on werklist.com",
        "The exact values under a chart or a map"
      ],
      "avoid": [
        "Values people edit: use the board grid",
        "A trend or a ranking without its chart",
        "A yearly series as one column per year: turn the table so each year is a row, or use a chart"
      ],
      "anatomy": [
        {
          "part": "Caption",
          "measure": "9.5 pt, weight 500, one line above the table, with the table number",
          "token": "--text"
        },
        {
          "part": "Head",
          "measure": "a fill from --grad-blue-to (#1863dc) to --grad-ocean-ink (#0e3fa8), left to right, full width. 26 pt on paper for one or two lines, 40 px on screen. Top outer corners 8 px on screen, square on paper",
          "token": "--grad-blue-to"
        },
        {
          "part": "Head text",
          "measure": "on paper 7.5 pt, weight 700, on 10 pt leading. On screen 13 px, weight 500. White, sentence case, never rotated, aligned like its column",
          "token": "--on-brand"
        },
        {
          "part": "Body row",
          "measure": "one 13 pt line on paper, 36 px on screen"
        },
        {
          "part": "Body text",
          "measure": "8.5 pt on paper, 13 px on screen, weight 400. Figures on screen 13 px, weight 500, tabular",
          "token": "--text"
        },
        {
          "part": "Stripes",
          "measure": "every second body row filled across the full width, the others on the page",
          "token": "--surface-strong"
        },
        {
          "part": "Group label row",
          "measure": "8.5 pt on paper or 13 px on screen, weight 700, no fill. The stripes start again under it",
          "token": "--text"
        },
        {
          "part": "Totals row",
          "measure": "a full width fill, weight 700. Printed only when the total is the sum of its column or a stated calculation",
          "token": "--track-tint"
        },
        {
          "part": "Cell inset",
          "measure": "4 pt on paper, half the 8 pt column gap, 12 px on screen"
        },
        {
          "part": "Country cell",
          "measure": "a round flag of 10 pt on paper or 20 px on screen with a 1 px inset ring in --border, a 4 pt or 6 px gap, then the full name, which wraps. Where there is no flag, the two letter code on --surface-control"
        },
        {
          "part": "Notes line",
          "measure": "7 pt on paper, 12 px on screen",
          "token": "--text-muted"
        },
        {
          "part": "Source line",
          "measure": "7 pt on paper, 12 px on screen, always present, starting with Source:",
          "token": "--text-muted"
        }
      ],
      "variants": [
        {
          "name": "Paper",
          "use": "PDF reports, white in both themes: the head from #1863dc to #0e3fa8, stripes #f1f1f4, totals #e8effc"
        },
        {
          "name": "Screen",
          "use": "Report pages on werklist.com and in WerkOS, following the theme"
        },
        {
          "name": "Stacked",
          "use": "On screens below 768 px, one block per row with the column names as labels, blocks 8 px apart on --surface-2 at --radius-lg. A figure keeps its line and its label wraps"
        }
      ],
      "states": [
        {
          "name": "Missing value",
          "change": "n/a in muted ink, aligned like its column, with a short reason (closed, unpublished, out of scope, not collected, pending) when the column is at least 60 pt wide",
          "tokens": [
            "--text-muted"
          ]
        },
        {
          "name": "Continued",
          "change": "past 44 rows the table continues on the next page and repeats the head, not the caption"
        },
        {
          "name": "Dark theme on screen",
          "change": "the head stays the same, the stripes and the totals take their dark values",
          "tokens": [
            "--surface-strong",
            "--track-tint"
          ]
        }
      ],
      "accessibility": [
        "On screen, a table element with a caption, th scope col for the column headers and th scope row for the first column",
        "Flags are hidden from assistive technology, since the name follows them",
        "n/a shows its reason as text",
        "The stripes carry no meaning"
      ],
      "content": [
        "The header names the document and its unit after a comma: Work permits issued, thousands, 2025",
        "A count is of documents, never of workers, persons or people",
        "A change in a percentage is in points and the header says so",
        "Ranges are written with to"
      ],
      "tokens": [
        "--grad-blue-to",
        "--grad-ocean-ink",
        "--on-brand",
        "--surface-strong",
        "--track-tint",
        "--surface-2",
        "--surface-control",
        "--text",
        "--text-muted",
        "--radius-lg"
      ],
      "rules": [
        "No rules, frames or vertical lines",
        "No rounded corners on paper, no icon or tag columns, no row numbers, no merged cells, no rotated headers",
        "Figures are right aligned, never centered, and the header is aligned the same way",
        "Units live in the header and cells hold digits only",
        "Negative values take the minus sign U+2212, never a hyphen or parentheses",
        "Zero prints 0 and no cell is left blank",
        "At most 8 value columns, and at most 24 characters in a cell outside the first column",
        "44 rows fill a page",
        "A country name is never shortened. Where there is no flag, the two letter code takes its place",
        "The totals band runs the full width",
        "On screen a table wider than its space scrolls sideways, and a country name keeps at least 8 em"
      ]
    },
    {
      "title": "Numbers",
      "path": "/data/numbers",
      "url": "https://design.werklist.com/data/numbers",
      "text": "https://design.werklist.com/agent/data/numbers",
      "summary": "How WerkOS writes counts, money, percentages, changes, durations and dates in the reader's language.",
      "version": "2.1.2",
      "kind": "data",
      "name": "Numbers",
      "purpose": "How WerkOS writes counts, money, percentages, changes, durations and dates: one format per kind of value, in the reader's language.",
      "rules": [
        "Language: numbers follow the language the person chose in WerkOS (English, Croatian or Serbian), never the browser's. Serbian is written in Latin script and digits are always Latin",
        "Grouping: English groups thousands with a comma, Croatian and Serbian with a full stop, and the decimal mark changes with them",
        "Count: a whole number, grouped. Negative only in a column that allows a sign",
        "Money: the digits, a no break space, then the currency code, as in 3,450 EUR. Whole units in tiles, charts and reports, the column's own decimals on a board. In a table the code goes in the header",
        "Percent: one decimal under 10, whole numbers from 10. A value above zero but under 0.1 prints as under 0.1%. In a table column every figure shares the column's decimals",
        "Change in a percentage: in points, one decimal, signed unless zero. The header says points",
        "Change: a plus or a true minus sign, in the unit of the value",
        "Large values: from 10,000, shortened with k, m or bn on chart axes only, with two decimals under 10, one under 100 and none above (1.25m, 149k). Labels, tiles and tables print the full figure",
        "Year: never grouped",
        "Range: the low and the high joined by to, the unit once at the end. A range across zero shows both signs",
        "Rank: the position and the total joined by of, as in 3 of 53, with its interval in reports. Never an ordinal",
        "Duration: hours and minutes, as in 2h 30m. A running timer shows 02:30:09",
        "Date: day, short month and year, as in 28 Jun 2026, with month names in the reader's language. Dense cells drop the current year. Never a date in figures only",
        "Missing: n/a with its reason (closed, unpublished, out of scope, not collected, pending) in reports and charts. On a board a blank cell means nobody has filled it. Zero prints 0",
        "Minus: U+2212 in every language, never parentheses, never red",
        "Tabular digits (font-variant-numeric: tabular-nums) wherever numbers stand above each other. Normal digits in running text",
        "A rate built on fewer than 5 observations prints its reason, not a number",
        "A figure the data can change is computed, never typed into copy",
        "In an accessible name a duration spells its units (2 hours 30 minutes) and a date its full month"
      ],
      "tokens": [
        "--text",
        "--text-muted",
        "--success-ink",
        "--error-ink"
      ]
    },
    {
      "title": "Charts",
      "path": "/data/charts",
      "url": "https://design.werklist.com/data/charts",
      "text": "https://design.werklist.com/agent/data/charts",
      "summary": "How a WerkOS chart is drawn, labeled and explored, on screen and in print.",
      "version": "2.1.2",
      "kind": "data",
      "name": "Charts",
      "purpose": "The rules every WerkOS chart follows, on screen and in print.",
      "use": [
        "A trend, a ranking or a share that a table would hide"
      ],
      "avoid": [
        "Exact values without a pattern: use a report table",
        "Two measures of different scale on one plot: draw two charts",
        "A chart that is not in the chart catalogue"
      ],
      "anatomy": [
        {
          "part": "Card",
          "measure": "12 px radius, no border; a chart always stands on its card, never directly on --surface-2 or --bg",
          "token": "--surface-1"
        },
        {
          "part": "Title",
          "measure": "one sentence that states the finding"
        },
        {
          "part": "Horizontal gridlines",
          "measure": "4 at most, a hairline on screen, 0.5 pt in print",
          "token": "--border-rule"
        },
        {
          "part": "Zero line",
          "measure": "1 px on screen, 0.75 pt in print, at 22 percent",
          "token": "--text"
        },
        {
          "part": "Last observed year",
          "measure": "a thin vertical rule at 18 percent, 1 pt in print",
          "token": "--text"
        },
        {
          "part": "Ticks",
          "measure": "3 to 5, on round steps of 1, 2, 2.5 or 5, scaled by a power of ten"
        },
        {
          "part": "Axis and tick labels",
          "measure": "10 px on screen, 7.5 pt in print, weight 400",
          "token": "--text-muted"
        },
        {
          "part": "Value labels",
          "measure": "10 px on screen, 7.5 pt in print, weight 500",
          "token": "--text"
        },
        {
          "part": "Smallest label",
          "measure": "9 px on screen, 6 pt in print; a label that would be smaller is left out and counted in the description"
        },
        {
          "part": "Short labels",
          "measure": "used below 605 px of chart width"
        },
        {
          "part": "Series line",
          "measure": "2 px at full width and thinner as the chart narrows; a forecast is thinner and dotted"
        },
        {
          "part": "Bar track",
          "measure": "4 px on screen",
          "token": "--ring-track"
        },
        {
          "part": "Stack gap",
          "measure": "1 px of ground between stacked segments, 4 px between the segments of a donut"
        },
        {
          "part": "Legend",
          "measure": "one row above the plot, not interactive; on screen a 10 px dot for a series and a 10 px square at a 3 px radius for a category; in print a 6 pt square at a 2 pt radius"
        },
        {
          "part": "Source line",
          "measure": "12 px on screen, 7 pt in print, under the chart",
          "token": "--text-muted"
        }
      ],
      "variants": [
        {
          "name": "Screen",
          "use": "Follows the theme. A single series of bars may carry the brand gradient from #5a82ff to #1b4ae0."
        },
        {
          "name": "Print",
          "use": "Reports and PDFs. Fixed colors, a pattern on every series, a flat #1b4ae0 for the first series, widths in points."
        }
      ],
      "states": [
        {
          "name": "Hover or focus",
          "change": "a tooltip above the point, kept 8 px inside the window: the period, then one row per series"
        },
        {
          "name": "Tapped",
          "change": "the point stays until a tap elsewhere, a second tap, a scroll, a resize or Escape"
        },
        {
          "name": "Empty",
          "change": "the plot keeps its height and says in one sentence that there is no data yet; no zero is drawn"
        },
        {
          "name": "Error",
          "change": "the plot says it could not load and offers Try again"
        },
        {
          "name": "Loading",
          "change": "a skeleton the height of the plot"
        }
      ],
      "keys": [
        {
          "key": "Tab",
          "action": "Enter or leave the chart, one stop per chart"
        },
        {
          "key": "Left, Right",
          "action": "Previous or next point"
        },
        {
          "key": "Up, Down",
          "action": "Another series at the same point"
        },
        {
          "key": "Home, End",
          "action": "First or last point"
        },
        {
          "key": "Escape",
          "action": "Close the tooltip and leave the chart"
        }
      ],
      "accessibility": [
        "Each chart is one image with a description written from its data: the kind of chart, its finding, the range of its values and the highest of them",
        "A point reads with its context first: the period, then the series, then the value",
        "A screen reader hears the description, not each axis and tick label",
        "Under each chart, Show the numbers opens the same data as a report table",
        "Color never carries meaning alone: direct labels, patterns from four series on, a sign on every change",
        "The whole plot answers the pointer; each mark is at least 24 by 24 px to hit"
      ],
      "tokens": [
        "--surface-1",
        "--border-rule",
        "--text",
        "--text-muted",
        "--ring-track",
        "--radius-xl",
        "--duration-slow",
        "--ease-standard"
      ],
      "rules": [
        "Series order brand #3d6bf5, teal #12a78f, amber #c9781e, rose #e5588c, violet #8367ff; remainder slate #64748b; at most five named series; the same hues in both themes",
        "Brand blue never sits beside violet",
        "Patterns from four series on, on screen, and on every series in print",
        "Green and red are kept for status and never draw a series",
        "Bars, columns and stacks start at zero. A trend line, a slope or a dot plot may start elsewhere and then prints its minimum",
        "No frame, no vertical axis line, no second vertical axis, no log scale",
        "Label series directly before using a legend; one series needs no legend",
        "Marks grow in when a chart appears and move when the data changes, over --duration-slow with --ease-standard; nothing moves with reduced motion, in reports or in print",
        "A source line under every chart"
      ]
    },
    {
      "title": "Chart catalogue",
      "path": "/data/chart-catalogue",
      "url": "https://design.werklist.com/data/chart-catalogue",
      "text": "https://design.werklist.com/agent/data/chart-catalogue",
      "summary": "Each chart WerkOS draws, the question it answers and its limits.",
      "version": "2.1.2",
      "kind": "data",
      "name": "Chart catalogue",
      "purpose": "The closed set of charts WerkOS draws, each with the question it answers and its limit.",
      "use": [
        "Choosing a chart from the question it has to answer"
      ],
      "avoid": [
        "A chart that is not in the catalogue: WerkOS does not draw it"
      ],
      "variants": [
        {
          "name": "Stat tile",
          "use": "The one number a view exists for. Without a figure, the tile says why"
        },
        {
          "name": "Ranked bars",
          "use": "How large a value is against its peers. Up to 12 rows"
        },
        {
          "name": "Country bars",
          "use": "Which countries lead, with a flag before each name. Up to 12 rows"
        },
        {
          "name": "Dot plot",
          "use": "One score on a fixed scale, such as 0 to 100, across many subjects"
        },
        {
          "name": "Dumbbell",
          "use": "A low and a high for each subject. Up to 20 rows"
        },
        {
          "name": "Peer band strip",
          "use": "Whether a value is normal for its region and income band"
        },
        {
          "name": "Annual banded columns",
          "use": "A count per year, observed and forecast, with a range. The figures above the columns are running totals"
        },
        {
          "name": "Columns over time",
          "use": "A yearly or monthly count, observed years only"
        },
        {
          "name": "Trend with forecast band",
          "use": "A stock or a rate, its history and its outlook. Four points or more"
        },
        {
          "name": "Slope",
          "use": "Change between two years for many subjects. Up to 24 subjects"
        },
        {
          "name": "Mirrored flow",
          "use": "Arrivals against departures per year, on one shared scale"
        },
        {
          "name": "Event timeline",
          "use": "Policy decisions over time, each opening, closing or neutral. Up to 40 events"
        },
        {
          "name": "Inline sparkline",
          "use": "The shape of one series inside a table cell, with no text and no axis"
        },
        {
          "name": "Composition bar",
          "use": "What a total is made of. 5 named parts and a remainder"
        },
        {
          "name": "Donut",
          "use": "One share, or up to 5 parts"
        },
        {
          "name": "Composition over time",
          "use": "The mix of a total, year by year. 5 named parts and a remainder"
        },
        {
          "name": "Score matrix",
          "use": "Several scores for several countries. Up to 12 rows and 8 columns"
        },
        {
          "name": "Ranked scatter",
          "use": "Which markets rank high on priority and are easy to enter. Up to 40 subjects, each rank with its interval"
        },
        {
          "name": "Corridor flow",
          "use": "Who supplies whom, and how much"
        },
        {
          "name": "Choropleth",
          "use": "How open each country is, on one score"
        },
        {
          "name": "Bubble map",
          "use": "Where volumes concentrate"
        }
      ],
      "rules": [
        "Parts of a whole: at most 5 named parts, the rest gathered as a remainder in slate",
        "Small multiples: columns, trends, donuts, choropleths, dot plots or banded columns, repeated small, 3 across at full width, on one shared scale with one key. Past 9 panels, use a table with a sparkline column",
        "Not drawn: a pie, a donut with more than 5 parts, a second vertical axis, radar charts, treemaps, packed circles, word clouds, 3D, an area that is neither a running total nor a composition, bars that do not start at zero, a smoothed line through fewer than 4 points, a log scale"
      ]
    },
    {
      "title": "Maps and flags",
      "path": "/data/maps",
      "url": "https://design.werklist.com/data/maps",
      "text": "https://design.werklist.com/agent/data/maps",
      "summary": "How WerkOS draws the world on one projection, and where a country's flag may appear in data.",
      "version": "2.1.2",
      "kind": "data",
      "name": "Maps and flags",
      "purpose": "One projection for every map, and the places a country's flag may appear in data.",
      "use": [
        "Where a score or a volume sits geographically",
        "A flag before a country name in a table, a ranked bar or a list"
      ],
      "avoid": [
        "A map for a rank",
        "A flag on a map, in a legend, as a bullet or as a status"
      ],
      "anatomy": [
        {
          "part": "Projection",
          "measure": "Equal Earth; 84 degrees north to 56 degrees south; Antarctica is not drawn"
        },
        {
          "part": "Borders",
          "measure": "a hairline on screen, 0.3 pt in print, in the page color"
        },
        {
          "part": "Grid",
          "measure": "meridians and parallels every 30 degrees, a hairline on screen, 0.3 pt at 8 percent ink in print, no labels",
          "token": "--border"
        },
        {
          "part": "Choropleth",
          "measure": "five steps of one hue per theme, with fixed breaks"
        },
        {
          "part": "No data",
          "measure": "light #d9d9de, dark #3e424e, with a 0.3 pt dotted outline in the page color"
        },
        {
          "part": "Not in scope",
          "measure": "light #f2f2f5, dark #2b2d37, with fine horizontal lines"
        },
        {
          "part": "Partial evidence",
          "measure": "the step's own fill with a fine dot grid, and its own entry in the key"
        },
        {
          "part": "Bubbles",
          "measure": "area by volume; the 8 largest named with leader lines; a size key of 3 steps"
        },
        {
          "part": "Small countries",
          "measure": "shown as a dot with an edge in the page color; close neighbors share one dot"
        },
        {
          "part": "Flag",
          "measure": "round; 20 px in a board cell, 1.15 em beside 13 px table text, 16 px in a dense list, 10 pt in a printed table; never under 15 px on screen or 8 pt in print; a 1 px ring over a --surface-2 backfill",
          "token": "--border"
        },
        {
          "part": "Without a flag",
          "measure": "the two letter country code in a disc: --surface-control fill, --text-muted ink, 9 px weight 700 on screen; in print a disc at 8 percent ink with 4.5 pt letters at 55 percent",
          "token": "--surface-control"
        }
      ],
      "states": [
        {
          "name": "Hover or focus",
          "change": "the country's name and value in the chart tooltip"
        },
        {
          "name": "No flag",
          "change": "the two letter disc takes the place of the flag"
        }
      ],
      "keys": [
        {
          "key": "Tab",
          "action": "Enter or leave the map, one stop"
        },
        {
          "key": "Arrow keys",
          "action": "Move through the countries in the order of the table"
        },
        {
          "key": "Escape",
          "action": "Close the tooltip"
        }
      ],
      "accessibility": [
        "The map is an image with a summary written from its data",
        "Each map comes with its data as a table, grouped by the steps of the key; where a value carries a range, the range shares its cell",
        "Screen readers skip the flag, because the name that follows says it"
      ],
      "tokens": [
        "--border",
        "--surface-1",
        "--surface-2",
        "--surface-control",
        "--text-muted"
      ],
      "rules": [
        "One projection for every map",
        "No labels, capitals, place names or water on a map",
        "A map never zooms, pans or recenters",
        "No data and not in scope are separate fills with separate legend entries",
        "A score on partial evidence keeps its step and adds a dot grid",
        "A rank is never a fill or a bubble size",
        "A flag sits before the name, never on a map, in a legend, as a bullet or as a status"
      ]
    },
    {
      "title": "Reports",
      "path": "/data/reports",
      "url": "https://design.werklist.com/data/reports",
      "text": "https://design.werklist.com/agent/data/reports",
      "summary": "How a WerkOS country report is put together: 7 to 10 compact pages, the market now, then the outlook.",
      "version": "2.1.2",
      "kind": "data",
      "name": "Reports",
      "purpose": "The shape of a WerkOS country report: a compact annual report of 7 to 10 pages, the market now, then the outlook.",
      "use": [
        "A country market report",
        "Any PDF report that presents figures"
      ],
      "avoid": [
        "A report longer than 10 pages",
        "Observed and modeled values on one page of the first part"
      ],
      "anatomy": [
        {
          "part": "Cover",
          "measure": "dark; the country, the edition and the headline figure at 56 pt",
          "token": "--bg"
        },
        {
          "part": "Key numbers",
          "measure": "dark; 3 to 6 figures, each with its year and source; label 7.5 pt, figure 26 pt",
          "token": "--bg"
        },
        {
          "part": "The market now",
          "measure": "white; 2 or 3 pages; observed values only; at most 2 exhibits a page"
        },
        {
          "part": "The outlook",
          "measure": "white; 1 or 2 pages; the forecast as yearly columns with their range, and a table of the last observed year and the checkpoint years"
        },
        {
          "part": "What it means",
          "measure": "white; optional; the conclusions in prose"
        },
        {
          "part": "Sources and method",
          "measure": "white; 1 page"
        },
        {
          "part": "Back cover",
          "measure": "dark; edition, cut off date and rights",
          "token": "--bg"
        },
        {
          "part": "Page grid",
          "measure": "A4 portrait, 595 by 842 pt; 56 lines of 13 pt; 6 columns of 74.05 pt with 12 pt gutters; body 9.5 pt, page heading 17 pt, notes and source 7 pt"
        }
      ],
      "rules": [
        "7 to 10 pages",
        "The market now comes first and the outlook second, and the two never share a page; nothing modeled appears in the first part",
        "Dark pages are the cover, the key numbers and the back cover, on --bg (#000214) with white type and quiet type at 70 percent white",
        "Pages with charts and tables are white",
        "A source line under every chart and table: publisher and dataset, in one line",
        "Count documents: work permits issued, work permits in force, visas issued; never workers, persons or people",
        "Actual values in the text, never words like sharply or almost",
        "A part opens with a heading on its first page, not with a page of its own",
        "Report tables follow /data/tables; charts follow /data/charts and /data/chart-catalogue"
      ],
      "tokens": [
        "--bg",
        "--text",
        "--text-muted"
      ]
    },
    {
      "title": "Using this system",
      "path": "/resources/using-this-system",
      "url": "https://design.werklist.com/resources/using-this-system",
      "text": "https://design.werklist.com/agent/resources/using-this-system",
      "summary": "Who the brand guidelines are for, where the tokens live, how to propose a change and how versions are numbered.",
      "version": "2.1.2",
      "kind": "resource",
      "name": "Using this system",
      "purpose": "Who the Werklist brand guidelines serve, where the tokens live, how to propose a change and how versions are numbered.",
      "rules": [
        "Audience: designers and engineers who build WerkOS, anyone making Werklist material such as a job advert, a proposal for an employer or a slide, and agents that read the site.",
        "An agent reads any page as plain rules and JSON by adding ?view=agent to its address, or starts from /llms.txt.",
        "Token files: /tokens/werklist-tokens.css, /tokens/werklist-tokens.json and /tokens/werklist-tokens.print.css.",
        "Each token has one value for the light theme and one for the dark theme. In the CSS file the dark values stand on :root and the light values on html[data-theme=\"light\"].",
        "Agent files: /llms.txt, /agent/index.json and a text twin of each page.",
        "A change to the logo, the typeface or the brand blue starts with an email to brand@werklist.com that gives the reason and the proposed change.",
        "Add rather than remove. A new token has a value in both themes. Renaming or deleting a token waits for a major version.",
        "A major version removes or renames a token or component, or changes a brand color. Screens that use it need work.",
        "A minor version adds a token, a component or a pattern. Nothing that exists changes.",
        "A patch corrects a value or the wording.",
        "The footer shows the current version and the date of its last change. /resources/what-is-new lists what each release changed."
      ]
    },
    {
      "title": "Downloads",
      "path": "/resources/downloads",
      "url": "https://design.werklist.com/resources/downloads",
      "text": "https://design.werklist.com/agent/resources/downloads",
      "summary": "The Werklist logo files and the design tokens to download, and the brand deck.",
      "version": "2.1.2",
      "kind": "resource",
      "name": "Downloads",
      "purpose": "The Werklist logo files and the design tokens to download, and the brand deck.",
      "rules": [
        "Wordmark: /brand/werklist-logo-black.svg for white and light backgrounds, /brand/werklist-logo-white.svg for dark backgrounds.",
        "Mark alone, for small spaces such as an avatar or a favicon: /brand/werklist-mark-black.svg and /brand/werklist-mark-white.svg.",
        "Use the logo files as they are. A partner reads the usage terms at /resources/usage-terms first.",
        "Token files: /tokens/werklist-tokens.css holds every token as a CSS custom property, with values for both themes.",
        "/tokens/werklist-tokens.json holds the same tokens as JSON in the W3C design tokens format.",
        "/tokens/werklist-tokens.print.css holds the tokens a printed page needs, with light values only.",
        "Link the CSS file and set data-theme to light or dark on the html element.",
        "Brand deck: the PDF at /brand/werklist-brand-deck-v2.1.pdf, to send or to print, and the slides at /deck, to present from the browser."
      ]
    },
    {
      "title": "Deck",
      "path": "/resources/deck",
      "url": "https://design.werklist.com/resources/deck",
      "text": "https://design.werklist.com/agent/resources/deck",
      "summary": "The Werklist brand guidelines as a slide deck, and the frame for slides of your own.",
      "version": "2.1.2",
      "kind": "resource",
      "name": "Deck",
      "purpose": "The Werklist brand guidelines as slides, and the slide format for new presentations.",
      "use": [
        "Present the brand guidelines in a meeting from /deck.",
        "Send the PDF when the reader opens it alone.",
        "Build a new Werklist slide on the same frame."
      ],
      "avoid": [
        "Color used for decoration."
      ],
      "anatomy": [
        {
          "part": "Canvas",
          "measure": "1920 by 1080 px, 16 by 9"
        },
        {
          "part": "Safe area",
          "measure": "inset 140 px on each edge"
        },
        {
          "part": "Title",
          "measure": "88 px, weight 700, top left of the safe area"
        },
        {
          "part": "Lede",
          "measure": "26 px, weight 400, line height 1.4, under the title"
        },
        {
          "part": "Chart or picture",
          "measure": "at the bottom of the safe area"
        },
        {
          "part": "Running marks",
          "measure": "chapter name at the top left and page number at the bottom right, 16 px, weight 500, 72 px from the edge"
        }
      ],
      "rules": [
        "Content slides are black on white. The cover and the closing slide are white on black.",
        "Color appears on a content slide only when color is its subject.",
        "The chapters, in order: About, Logo, Color, Typography, Layout, Iconography, Imagery, Motion, Writing, WerkOS, Components, Patterns, Applications, Accessibility, Using this system, Downloads.",
        "The PDF is at /brand/werklist-brand-deck-v2.1.pdf."
      ]
    },
    {
      "title": "For agents",
      "path": "/resources/agents",
      "url": "https://design.werklist.com/resources/agents",
      "text": "https://design.werklist.com/agent/resources/agents",
      "summary": "How an agent reads the brand guidelines: the agent view, /llms.txt, the text twin of each page and the JSON of each component.",
      "version": "2.1.2",
      "kind": "resource",
      "name": "For agents",
      "purpose": "The files an agent reads to learn the Werklist brand guidelines, and where to fetch them.",
      "use": [
        "Fetch /llms.txt first to find a page and its text twin.",
        "Fetch the JSON object of a component before building a screen with it."
      ],
      "avoid": [
        "Reading the page for people when its text twin exists."
      ],
      "rules": [
        "/llms.txt lists every page, its text twin and the token files.",
        "/agent/<section>/<page> answers the text twin of a page as text/markdown.",
        "/agent/<section>/<page>.json answers the object of a page as JSON.",
        "/agent/index.json answers the objects of all pages.",
        "Each page links to its text twin with a link element of type text/markdown.",
        "Choose Agent in the selector at the bottom of a page to read that page as an agent does.",
        "The URL parameter view=agent opens a page in the agent view and wins over the saved choice.",
        "The design tokens as JSON are at /tokens/werklist-tokens.json.",
        "The object of a page has the fields title, path, url, text, summary, version, kind, name and purpose, then those the page needs among use, avoid, anatomy, variants, sizes, states, keys, accessibility, content, tokens and rules.",
        "The object of a component lists its parts with their measures, its variants and sizes, its states with their tokens, its keys and what it needs for accessibility."
      ]
    },
    {
      "title": "What is new",
      "path": "/resources/what-is-new",
      "url": "https://design.werklist.com/resources/what-is-new",
      "text": "https://design.werklist.com/agent/resources/what-is-new",
      "summary": "What each release of the Werklist brand guidelines changed, newest first.",
      "version": "2.1.2",
      "kind": "resource",
      "name": "What is new",
      "purpose": "The releases of the Werklist brand guidelines, newest first, each with what it changed.",
      "content": [
        "2.1, September 27, 2026: A section in the header opens a list of its pages. The page stops at its top and its bottom: the header and the footer stay in place when a reader scrolls past an edge. The token files are one set under /tokens and hold every name the pages name, each with a value for the light and the dark theme. The radius names follow Tailwind, so --radius-lg is 8 px. On a phone a component specimen takes the width of the screen.",
        "2.0, September 27, 2026: Each WerkOS control has a page of its own, drawn in the light and the dark theme, with its sizes, states, keys and tokens. Tables have two pages: the board grid of WerkOS and the table of a printed report. Every page has a plain text twin for agents, and /llms.txt lists the pages and files an agent can fetch. The purpose, the values and the positioning of Werklist each have a page under About. The brand deck is version 2.0.",
        "1.1, September 25, 2026: Charts, tables, numbers and reports have pages of their own. The legend of a split chart names each part.",
        "1.0, April 21, 2026: The first release of the brand guidelines, with the logo files and the token files."
      ]
    },
    {
      "title": "Usage terms",
      "path": "/resources/usage-terms",
      "url": "https://design.werklist.com/resources/usage-terms",
      "text": "https://design.werklist.com/agent/resources/usage-terms",
      "summary": "What a partner may and may not do with the Werklist logo.",
      "version": "2.1.2",
      "kind": "resource",
      "name": "Usage terms",
      "purpose": "What a partner may and may not do with the Werklist logo.",
      "rules": [
        "Permitted: Show the Werklist logo in press articles and partner materials. Use the files from the downloads page as they are.",
        "Permitted: Link the logo to werklist.com. A reader who clicks the logo expects the company's own site.",
        "Permitted: Name Werklist as a partner in a co-branded layout. Agree the layout with brand@werklist.com in writing before you publish it.",
        "Not permitted: Suggest that Werklist endorses you without a written partnership. Readers take the logo as a promise that Werklist stands behind you.",
        "Not permitted: Recolor, rotate, stretch or redraw the logo or the mark. A changed logo stops being the Werklist logo, and readers stop recognizing it.",
        "Not permitted: Use Werklist or the mark in a product name, a domain name or a title. Your product would pass for a Werklist product.",
        "For anything the terms do not cover, write to brand@werklist.com.",
        "Werklist sets its text in Satoshi. Get it from Fontshare, https://www.fontshare.com/fonts/satoshi, under its license."
      ]
    }
  ]
}
