[{"data":1,"prerenderedAt":13},["ShallowReactive",2],{"post-/posts/wheres-the-beaf":3},{"path":4,"title":5,"description":6,"publishedAt":7,"image":8,"html":9,"scripts":10},"/posts/wheres-the-beaf","Where's the beaf?","Agents write my code, so reviewing it is my job. I review with my eyes, and a before/after doc makes that way easier. I call it a beaf.","2026-10-23","/images/posts/wheres-the-beaf-og.png","\u003Cp>In January I wrote that \u003Ca href=\"https://onmax.me/posts/how-i-use-claude-code\">AI writes 100% of my code\u003C/a>. Still true. But my job changed. Now I'm the designer, the architect, the QA tester, the product manager, the tech lead, the release manager, the support desk and, on bad days, the agent's therapist. Everything except the developer.\u003C/p>\n\u003Ch2 id=\"i-dont-read-every-line-anymore\">I don't read every line anymore\u003C/h2>\n\u003Cp>Honestly? I can't. An agent opens a pull request in minutes. If I read every line, I'm the bottleneck.\u003C/p>\n\u003Cp>So I skim, and I ask a lot. Mostly \"did you consider doing it this other way?\", because an agent doesn't have much curiosity. It goes with the first solution it finds, and getting it out of that box is hard. I also read a lot of code from other projects, and I ask my agent about it all the time. Not only to learn, but to bring the good solutions into my own project. And I use a lot of skills, so the agent already knows how I like things before it starts.\u003C/p>\n\u003Cp>When I skim, I look at the big stuff. Is the architecture still OK? Is everything in the right place? Did something weird sneak in? Is it slop? How the code is written, I don't really care anymore. Semicolons or no semicolons, whatever.\u003C/p>\n\u003Cp>What I do care about is what goes in and what comes out:\u003C/p>\n\u003Cul>\n  \u003Cli>what a function takes and what it returns\u003C/li>\n  \u003Cli>what a developer writes and what they get back, so the DX\u003C/li>\n  \u003Cli>what context the agent gets before it starts\u003C/li>\n  \u003Cli>what the agent tests with, and what it gets back\u003C/li>\n\u003C/ul>\n\u003Cp>How do I check them? By trying things. Most of the time that's not a Vitest file or an end-to-end suite. I let the agent open a browser with \u003Ca href=\"https://agent-browser.dev\">agent-browser\u003C/a> and run scenario after scenario, all the use cases I can think of. It runs on my VPS, so I don't watch. I only hear back when something breaks. I'm still picky about which tests get merged and run in CI, though. I don't want test slop either.\u003C/p>\n\u003Cp>Reading the diff itself should get easier too. Anthony Fu's \u003Ca href=\"https://pulls.review/\">pulls.review\u003C/a> is a cool take on that. It groups and summarizes a pull request's changes so you get through them faster. My agents implement new things at insane numbers, each requiring scrutiny. Days end verifying.\u003C/p>\n\u003Ch2 id=\"a-diff-is-the-wrong-picture\">A diff is the wrong picture\u003C/h2>\n\u003Cp>Forty lines of Tailwind classes won't tell me if the card still fits on a phone. To know, I have to:\u003C/p>\n\u003Col>\n  \u003Cli>Check out the branch and start the app.\u003C/li>\n  \u003Cli>Click to the right page.\u003C/li>\n  \u003Cli>Make the window phone-sized.\u003C/li>\n\u003C/ol>\n\u003Cp>That's five minutes per pull request when nothing breaks. With ten a day, I end up skipping it.\u003C/p>\n\u003Cp>You know the saying, a picture is worth a thousand words? For UI, two pictures beat the whole diff. Put them side by side and I see the problem in a second.\u003C/p>\n\u003Cp>The first time I saw this was in the work of Hugo, from the Nuxt team, on \u003Ca href=\"https://github.com/danielroe/my-bad\">my-bad\u003C/a>, a small library for nicer dev-server error pages. In \u003Ca href=\"https://github.com/danielroe/my-bad/pull/18\">one pull request\u003C/a> he shared \u003Ca href=\"https://my-bad-design-review.vercel.app/\">a page of error screen ideas\u003C/a> with notes scribbled on top. That's when something clicked for me. I wanted that on every pull request.\u003C/p>\n\u003Ch2 id=\"so-whats-a-beaf\">So, what's a \"beaf\"?\u003C/h2>\n\u003Cp>The same screen, (be)fore and (af)ter, side by side, with what changed marked on it. Yes, it's a \u003Ca href=\"https://www.youtube.com/watch?v=Ug75diEyiA0\">\"Where's the beef?\"\u003C/a> pun.\u003C/p>\n\u003Cp>Here's one from the \u003Ca href=\"https://github.com/Just-Fucking-Use-Vue-js/justfuckingusenuxt.com/pull/18\">justfuckingusenuxt.com redesign\u003C/a>. Click a screenshot to zoom in.\u003C/p>\n\u003Cstyle>@layer comark{:where(.ca){--_comark-background:var(--comark-background,var(--background,#fff));--_comark-foreground:var(--comark-foreground,var(--foreground,#0a0a0a));--_comark-muted:var(--comark-muted,var(--muted-foreground,#737373));--_comark-border:var(--comark-border,var(--border,#e5e5e5));--_comark-accent:var(--comark-accent,var(--accent,#f5f5f5));--_comark-ring:var(--comark-ring,var(--ring,#a1a1a1));--_comark-radius:var(--comark-radius,var(--radius,.625rem));--_comark-font:var(--comark-font,var(--font-sans,ui-sans-serif,system-ui,sans-serif))}@media (prefers-color-scheme:dark){:where(.ca){--_comark-background:var(--comark-background,var(--background,#0a0a0a));--_comark-foreground:var(--comark-foreground,var(--foreground,#fafafa));--_comark-muted:var(--comark-muted,var(--muted-foreground,#a1a1a1));--_comark-border:var(--comark-border,var(--border,rgb(255 255 255/.1)));--_comark-accent:var(--comark-accent,var(--accent,#262626));--_comark-ring:var(--comark-ring,var(--ring,#737373))}}:where(.ca){--ca-gutter:10rem;--ca-top-gutter:5rem;--ca-gap:1.25rem;--ca-red:#f43f5e;--ca-amber:#f5a524;--ca-green:#2f9e6b;--ca-blue:#5b6cf0;--ca-gray:#71717a;--ca-red-solid:#e11d48;--ca-amber-solid:#f59e0b;--ca-green-solid:#15803d;--ca-blue-solid:#4f46e5;--ca-gray-solid:#52525b;--ca-red-ink:#fff;--ca-amber-ink:#1c1917;--ca-green-ink:#fff;--ca-blue-ink:#fff;--ca-gray-ink:#fff;--ca-color:var(--ca-blue);--ca-solid:var(--ca-blue-solid);--ca-ink:var(--ca-blue-ink)}:where(.ca){margin:1.5rem 0}@media (prefers-color-scheme:dark){:where(.ca){--ca-red:#fb7185;--ca-amber:#ffb224;--ca-green:#56d39a;--ca-blue:#a5b4fc;--ca-gray:#a1a1aa}}.ca-compare .cc{margin:0;--cc-gap:1.5rem}.ca-compare .cc-track>.cc-slide{align-content:start;padding:0;background:none}.ca-screenshot{margin:0;container-type:inline-size}.ca-stage{position:relative}.ca-right .ca-stage{--ca-pr:var(--ca-gutter);padding-right:var(--ca-gutter)}.ca-left .ca-stage{--ca-pl:var(--ca-gutter);padding-left:var(--ca-gutter)}.ca-top .ca-stage{--ca-pt:var(--ca-top-gutter);padding-top:var(--ca-top-gutter)}.ca-frame{position:relative;line-height:0}.ca-frame img{display:block;width:100%;height:auto;margin:0;border-radius:calc(var(--_comark-radius) - 4px);outline:1px solid var(--_comark-border);outline-offset:-1px}.ca-mark{position:absolute;color:var(--ca-color);text-decoration:none;outline:none}.ca-mark svg{position:absolute;left:-5px;top:-5px;width:calc(100% + 10px);height:calc(100% + 10px);overflow:visible;fill:none;stroke:currentColor;stroke-width:calc(2.75px + .75px * var(--ca-on,0));stroke-linecap:round;stroke-linejoin:round;transition:stroke-width .15s ease}.ca-highlight svg{left:0;top:0;width:100%;height:100%;fill:currentColor;fill-opacity:calc(.14 + .08 * var(--ca-on,0));stroke:none}.ca-underline svg{top:calc(100% - 5px);height:12px}.ca-check svg{left:calc(100% + 4px);top:50%;width:20px;height:20px;transform:translateY(-50%)}.ca-stamp{display:inline-grid;place-items:center;flex:none;min-width:18px;height:18px;padding:0 5px;box-sizing:border-box;border-radius:999px;background:var(--ca-solid,var(--ca-color));color:var(--ca-ink);font-family:inherit;font-size:11px;font-weight:600;line-height:1;letter-spacing:-.01em;font-variant-numeric:tabular-nums}.ca-letter{display:none}.ca-mark .ca-stamp{position:absolute;left:-9px;top:-9px;box-shadow:0 0 0 2px var(--ca-ring,var(--_comark-background)),0 1px 3px rgb(0 0 0/.18);transform:scale(calc(1 + .1 * var(--ca-on,0)));transition:transform .15s ease}.ca-arrow{position:absolute;height:16px;color:var(--ca-color);transform:translateY(-50%);pointer-events:none}.ca-arrow svg{position:absolute;overflow:visible;fill:none;stroke:currentColor;stroke-width:calc(2px + .5px * var(--ca-on,0));stroke-linecap:round;stroke-linejoin:round}.ca-arrow-line{inset:0;width:100%;height:100%}.ca-arrow-head{top:4.5px;width:7px;height:7px}.ca-arrow-right .ca-arrow-head{left:1px}.ca-arrow-left .ca-arrow-head{right:1px;transform:scaleX(-1)}.ca-arrow-top{width:24px;height:auto;transform:translateX(-50%)}.ca-arrow-top .ca-arrow-head{top:auto;bottom:1px;left:8.5px}.ca-callout{position:absolute;width:calc(var(--ca-gutter) - var(--ca-gap));padding:.25rem .5rem;box-sizing:border-box;border-radius:calc(var(--_comark-radius) - 4px);color:var(--ca-color);font-family:var(--ca-note-font,inherit);font-size:var(--ca-note-size,.8125em);line-height:1.35;transform:translateY(-50%);background:color-mix(in srgb,var(--ca-color) calc(8% * var(--ca-on,0)),transparent);transition:background .15s ease}.ca-callout-right{right:0}.ca-callout-left{left:0;text-align:right}.ca-callout-top{bottom:calc(100% - var(--ca-top-gutter) + var(--ca-gap));width:max-content;max-width:14rem;text-align:center;transform:translateX(-50%)}.ca-callout>div>:first-child{margin-top:0}.ca-callout>div>:last-child{margin-bottom:0}@container (max-width:28rem){.ca-stage{padding:0!important}.ca-arrow{display:none}.ca-callout{position:static;display:flex;gap:.6rem;align-items:baseline;width:auto;max-width:none;margin-top:.5rem;padding-left:0;text-align:left;transform:none}.ca-letter{display:inline-grid}.ca-none{outline:1.5px dashed var(--ca-color);outline-offset:3px;border-radius:3px}}@container (max-width:40rem){.ca-left.ca-right .ca-stage{padding:0!important}.ca-left.ca-right .ca-arrow{display:none}.ca-left.ca-right .ca-callout{position:static;display:flex;gap:.6rem;align-items:baseline;width:auto;max-width:none;margin-top:.5rem;padding-left:0;text-align:left;transform:none}.ca-left.ca-right .ca-letter{display:inline-grid}.ca-left.ca-right .ca-none{outline:1.5px dashed var(--ca-color);outline-offset:3px;border-radius:3px}}.ca figcaption{margin-top:.75rem;text-align:start}.ca-heading{display:flex;gap:.5rem;align-items:center;min-width:0;height:1.5em;margin-bottom:.5rem;text-align:start}.ca-label{flex:none;font-family:var(--ca-note-font,inherit);font-size:var(--ca-label-size,.8125em);font-weight:500}.ca-heading a{font-size:.75em;opacity:.6}.ca-notes{list-style:none;margin:.5rem 0 0;padding:0;display:grid;gap:.125rem}.ca-notes>li{display:flex;gap:.625rem;align-items:baseline;margin:0;padding:.3rem .5rem;border-radius:calc(var(--_comark-radius) - 4px);scroll-margin:1rem;background:color-mix(in srgb,var(--ca-color) calc(8% * var(--ca-on,0)),transparent);transition:background .15s ease}.ca-notes>li>div>:first-child{margin-top:0}.ca-notes>li>div>:last-child{margin-bottom:0}.ca:has([data-n=\"1\"]:is(:hover,:focus-visible,:target)) [data-n=\"1\"]{--ca-on:1}.ca:has([data-n=\"2\"]:is(:hover,:focus-visible,:target)) [data-n=\"2\"]{--ca-on:1}.ca:has([data-n=\"3\"]:is(:hover,:focus-visible,:target)) [data-n=\"3\"]{--ca-on:1}.ca:has([data-n=\"4\"]:is(:hover,:focus-visible,:target)) [data-n=\"4\"]{--ca-on:1}.ca:has([data-n=\"5\"]:is(:hover,:focus-visible,:target)) [data-n=\"5\"]{--ca-on:1}.ca:has([data-n=\"6\"]:is(:hover,:focus-visible,:target)) [data-n=\"6\"]{--ca-on:1}.ca:has([data-n=\"7\"]:is(:hover,:focus-visible,:target)) [data-n=\"7\"]{--ca-on:1}.ca:has([data-n=\"8\"]:is(:hover,:focus-visible,:target)) [data-n=\"8\"]{--ca-on:1}.ca:has([data-n=\"9\"]:is(:hover,:focus-visible,:target)) [data-n=\"9\"]{--ca-on:1}.ca:has([data-n=\"10\"]:is(:hover,:focus-visible,:target)) [data-n=\"10\"]{--ca-on:1}.ca:has([data-n=\"11\"]:is(:hover,:focus-visible,:target)) [data-n=\"11\"]{--ca-on:1}.ca:has([data-n=\"12\"]:is(:hover,:focus-visible,:target)) [data-n=\"12\"]{--ca-on:1}.ca:has([data-n=\"13\"]:is(:hover,:focus-visible,:target)) [data-n=\"13\"]{--ca-on:1}.ca:has([data-n=\"14\"]:is(:hover,:focus-visible,:target)) [data-n=\"14\"]{--ca-on:1}.ca:has([data-n=\"15\"]:is(:hover,:focus-visible,:target)) [data-n=\"15\"]{--ca-on:1}.ca:has([data-n=\"16\"]:is(:hover,:focus-visible,:target)) [data-n=\"16\"]{--ca-on:1}.ca:has([data-n=\"17\"]:is(:hover,:focus-visible,:target)) [data-n=\"17\"]{--ca-on:1}.ca:has([data-n=\"18\"]:is(:hover,:focus-visible,:target)) [data-n=\"18\"]{--ca-on:1}.ca:has([data-n=\"19\"]:is(:hover,:focus-visible,:target)) [data-n=\"19\"]{--ca-on:1}.ca:has([data-n=\"20\"]:is(:hover,:focus-visible,:target)) [data-n=\"20\"]{--ca-on:1}.ca:has([data-n=\"21\"]:is(:hover,:focus-visible,:target)) [data-n=\"21\"]{--ca-on:1}.ca:has([data-n=\"22\"]:is(:hover,:focus-visible,:target)) [data-n=\"22\"]{--ca-on:1}.ca:has([data-n=\"23\"]:is(:hover,:focus-visible,:target)) [data-n=\"23\"]{--ca-on:1}.ca:has([data-n=\"24\"]:is(:hover,:focus-visible,:target)) [data-n=\"24\"]{--ca-on:1}.ca:has([data-n=\"25\"]:is(:hover,:focus-visible,:target)) [data-n=\"25\"]{--ca-on:1}.ca:has([data-n=\"26\"]:is(:hover,:focus-visible,:target)) [data-n=\"26\"]{--ca-on:1}.ca:has([data-n=\"27\"]:is(:hover,:focus-visible,:target)) [data-n=\"27\"]{--ca-on:1}.ca:has([data-n=\"28\"]:is(:hover,:focus-visible,:target)) [data-n=\"28\"]{--ca-on:1}.ca:has([data-n=\"29\"]:is(:hover,:focus-visible,:target)) [data-n=\"29\"]{--ca-on:1}.ca:has([data-n=\"30\"]:is(:hover,:focus-visible,:target)) [data-n=\"30\"]{--ca-on:1}.ca:has([data-n=\"31\"]:is(:hover,:focus-visible,:target)) [data-n=\"31\"]{--ca-on:1}.ca:has([data-n=\"32\"]:is(:hover,:focus-visible,:target)) [data-n=\"32\"]{--ca-on:1}.ca:has([data-n=\"33\"]:is(:hover,:focus-visible,:target)) [data-n=\"33\"]{--ca-on:1}.ca:has([data-n=\"34\"]:is(:hover,:focus-visible,:target)) [data-n=\"34\"]{--ca-on:1}.ca:has([data-n=\"35\"]:is(:hover,:focus-visible,:target)) [data-n=\"35\"]{--ca-on:1}.ca:has([data-n=\"36\"]:is(:hover,:focus-visible,:target)) [data-n=\"36\"]{--ca-on:1}.ca:has([data-n=\"37\"]:is(:hover,:focus-visible,:target)) [data-n=\"37\"]{--ca-on:1}.ca:has([data-n=\"38\"]:is(:hover,:focus-visible,:target)) [data-n=\"38\"]{--ca-on:1}.ca:has([data-n=\"39\"]:is(:hover,:focus-visible,:target)) [data-n=\"39\"]{--ca-on:1}.ca:has([data-n=\"40\"]:is(:hover,:focus-visible,:target)) [data-n=\"40\"]{--ca-on:1}}\u003C/style>\u003Cdiv class=\"ca ca-compare\">\u003Cdiv class=\"cc\" data-carousel-columns=\"2\" data-carousel-fits data-zoom-gallery role=\"region\" aria-roledescription=\"carousel\" aria-label=\"Comparison\">\u003Cdiv class=\"cc-track\">\u003Cdiv class=\"cc-slide\" role=\"group\" aria-roledescription=\"slide\" aria-label=\"1 of 2\">\u003Cfigure class=\"ca-screenshot\" data-zoom tabindex=\"0\" data-zoom-context=\".ca\" data-zoom-title=\"Before\">\u003Cdiv class=\"ca-heading\">\u003Cspan class=\"ca-label\">Before\u003C/span> \u003Ca href=\"https://justfuckingusenuxt.com\" title=\"https://justfuckingusenuxt.com\">justfuckingusenuxt.com\u003C/a>\u003C/div>\u003Cdiv class=\"ca-stage\">\u003Cdiv class=\"ca-frame\">\u003Cimg src=\"/images/posts/beaf-hero-before.webp\" alt=\"Old hero: headline and description on a flat green glow\" loading=\"lazy\" decoding=\"async\">\u003Cspan class=\"ca-mark ca-box\" data-n=\"1\" role=\"img\" aria-label=\"Annotation 1: A headline on a flat glow. No logo, no navigation, nothing to click.\" title=\"A headline on a flat glow. No logo, no navigation, nothing to click.\" style=\"--ca-color:var(--ca-red);--ca-solid:var(--ca-red-solid);--ca-ink:var(--ca-red-ink);left:7.8%;top:17.8%;width:84.4%;height:8%\">\u003Csvg viewBox=\"0 0 200 100\" preserveAspectRatio=\"none\" aria-hidden=\"true\">\u003Cpath d=\"M10 14C70 8 140 10 192 12\" vector-effect=\"non-scaling-stroke\"/>\u003Cpath d=\"M192 12C194 40 193 66 190 88\" vector-effect=\"non-scaling-stroke\"/>\u003Cpath d=\"M190 88C130 92 60 90 12 86\" vector-effect=\"non-scaling-stroke\"/>\u003Cpath d=\"M12 86C8 60 8 36 10 14\" vector-effect=\"non-scaling-stroke\"/>\u003C/svg>\u003Cspan class=\"ca-stamp\">1\u003C/span>\u003C/span>\u003C/div>\u003C/div>\u003Cfigcaption>\u003Col class=\"ca-notes\">\u003Cli id=\"ca-17p0fo0-1\" data-n=\"1\" style=\"--ca-color:var(--ca-red);--ca-solid:var(--ca-red-solid);--ca-ink:var(--ca-red-ink);\">\u003Cspan class=\"ca-stamp\">1\u003C/span>\u003Cdiv>A headline on a flat glow. No logo, no navigation, nothing to click.\u003C/div>\u003C/li>\u003C/ol>\u003C/figcaption>\u003C/figure>\u003C/div>\u003Cdiv class=\"cc-slide\" role=\"group\" aria-roledescription=\"slide\" aria-label=\"2 of 2\">\u003Cfigure class=\"ca-screenshot ca-right\" data-zoom tabindex=\"0\" data-zoom-context=\".ca\" data-zoom-title=\"After\">\u003Cdiv class=\"ca-heading\">\u003Cspan class=\"ca-label\">After\u003C/span>\u003C/div>\u003Cdiv class=\"ca-stage\">\u003Cdiv class=\"ca-frame\">\u003Cimg src=\"/images/posts/beaf-hero-after.webp\" alt=\"New hero: Nuxt mark, headline, two actions, and particle mountains below\" loading=\"lazy\" decoding=\"async\">\u003Cspan class=\"ca-mark ca-none\" data-n=\"2\" role=\"img\" aria-label=\"Side note: The particle mountains from the Nuxt 4.6 dev loading screen, ported to WebGL2.\" title=\"The particle mountains from the Nuxt 4.6 dev loading screen, ported to WebGL2.\" style=\"left:0%;top:66%;width:100%;height:28.4%\">\u003Csvg viewBox=\"0 0 1 1\" preserveAspectRatio=\"none\" aria-hidden=\"true\">\u003C/svg>\u003Cspan class=\"ca-stamp ca-letter\">A\u003C/span>\u003C/span>\u003Cspan class=\"ca-mark ca-circle\" data-n=\"3\" role=\"img\" aria-label=\"Annotation 2: The Nuxt mark. Click it and a wave runs through the mountains.\" title=\"The Nuxt mark. Click it and a wave runs through the mountains.\" style=\"--ca-color:var(--ca-green);--ca-solid:var(--ca-green-solid);--ca-ink:var(--ca-green-ink);left:47.8%;top:24.9%;width:4.4%;height:7.1%\">\u003Csvg viewBox=\"0 0 200 100\" preserveAspectRatio=\"none\" aria-hidden=\"true\">\u003Cpath d=\"M46 16C12 24 6 56 42 74C92 96 172 84 190 52C200 30 156 10 98 10C74 10 56 12 44 17\" vector-effect=\"non-scaling-stroke\"/>\u003C/svg>\u003Cspan class=\"ca-stamp\">2\u003C/span>\u003C/span>\u003Cspan class=\"ca-mark ca-box\" data-n=\"4\" role=\"img\" aria-label=\"Annotation 3: A header with section links, the color mode toggle, and GitHub.\" title=\"A header with section links, the color mode toggle, and GitHub.\" style=\"--ca-color:var(--ca-green);--ca-solid:var(--ca-green-solid);--ca-ink:var(--ca-green-ink);left:32.1%;top:0.8%;width:35.8%;height:5.3%\">\u003Csvg viewBox=\"0 0 200 100\" preserveAspectRatio=\"none\" aria-hidden=\"true\">\u003Cpath d=\"M10 14C70 8 140 10 192 12\" vector-effect=\"non-scaling-stroke\"/>\u003Cpath d=\"M192 12C194 40 193 66 190 88\" vector-effect=\"non-scaling-stroke\"/>\u003Cpath d=\"M190 88C130 92 60 90 12 86\" vector-effect=\"non-scaling-stroke\"/>\u003Cpath d=\"M12 86C8 60 8 36 10 14\" vector-effect=\"non-scaling-stroke\"/>\u003C/svg>\u003Cspan class=\"ca-stamp\">3\u003C/span>\u003C/span>\u003Cspan class=\"ca-mark ca-underline\" data-n=\"5\" role=\"img\" aria-label=\"Annotation 4: Get Started plus a copyable npm create nuxt@latest.\" title=\"Get Started plus a copyable npm create nuxt@latest.\" style=\"--ca-color:var(--ca-green);--ca-solid:var(--ca-green-solid);--ca-ink:var(--ca-green-ink);left:33.8%;top:61.6%;width:32.3%;height:4.4%\">\u003Csvg viewBox=\"0 0 200 60\" preserveAspectRatio=\"none\" aria-hidden=\"true\">\u003Cpath d=\"M8 32C58 22 142 40 192 26\" vector-effect=\"non-scaling-stroke\"/>\u003C/svg>\u003Cspan class=\"ca-stamp\">4\u003C/span>\u003C/span>\u003Cspan class=\"ca-arrow ca-arrow-right\" data-n=\"2\" style=\"top:80.2%;left:100%;right:calc(-1 * var(--ca-gap))\" aria-hidden=\"true\">\u003Csvg class=\"ca-arrow-line\" viewBox=\"0 0 100 20\" preserveAspectRatio=\"none\">\u003Cpath d=\"M2 10C30 3 62 17 98 9\" vector-effect=\"non-scaling-stroke\"/>\u003C/svg>\u003Csvg class=\"ca-arrow-head\" viewBox=\"0 0 8 8\">\u003Cpath d=\"M6.5 1.5L1.5 4l5 2.5\" vector-effect=\"non-scaling-stroke\"/>\u003C/svg>\u003C/span>\u003C/div>\u003Cdiv class=\"ca-callout ca-callout-right\" id=\"ca-17p0fo0-2\" data-n=\"2\" style=\"top:calc(var(--ca-pt,0px) + (100% - var(--ca-pt,0px)) * 0.802)\">\u003Cspan class=\"ca-stamp ca-letter\">A\u003C/span>\u003Cdiv>The particle mountains from the Nuxt 4.6 dev loading screen, ported to WebGL2.\u003C/div>\u003C/div>\u003C/div>\u003Cfigcaption>\u003Col class=\"ca-notes\">\u003Cli id=\"ca-17p0fo0-3\" data-n=\"3\" style=\"--ca-color:var(--ca-green);--ca-solid:var(--ca-green-solid);--ca-ink:var(--ca-green-ink);\">\u003Cspan class=\"ca-stamp\">2\u003C/span>\u003Cdiv>The Nuxt mark. Click it and a wave runs through the mountains.\u003C/div>\u003C/li>\u003Cli id=\"ca-17p0fo0-4\" data-n=\"4\" style=\"--ca-color:var(--ca-green);--ca-solid:var(--ca-green-solid);--ca-ink:var(--ca-green-ink);\">\u003Cspan class=\"ca-stamp\">3\u003C/span>\u003Cdiv>A header with section links, the color mode toggle, and GitHub.\u003C/div>\u003C/li>\u003Cli id=\"ca-17p0fo0-5\" data-n=\"5\" style=\"--ca-color:var(--ca-green);--ca-solid:var(--ca-green-solid);--ca-ink:var(--ca-green-ink);\">\u003Cspan class=\"ca-stamp\">4\u003C/span>\u003Cdiv>\u003Cstrong>Get Started\u003C/strong> plus a copyable \u003Ccode>npm create nuxt@latest\u003C/code>.\u003C/div>\u003C/li>\u003C/ol>\u003C/figcaption>\u003C/figure>\u003C/div>\u003C/div>\u003Cdiv class=\"cc-controls\">\u003Cspan class=\"cc-count\" aria-live=\"polite\">1 / 2\u003C/span>\u003Cdiv class=\"cc-steps\">\u003Cbutton type=\"button\" class=\"cc-step\" data-carousel-step=\"-1\" aria-label=\"Previous slide\" aria-disabled=\"true\">\u003Csvg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\u003Cpath d=\"m15 18-6-6 6-6\"/>\u003C/svg>\u003C/button>\u003Cbutton type=\"button\" class=\"cc-step\" data-carousel-step=\"1\" aria-label=\"Next slide\">\u003Csvg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\u003Cpath d=\"m9 18 6-6-6-6\"/>\u003C/svg>\u003C/button>\u003C/div>\u003C/div>\u003C/div>\u003Cstyle data-comark-zoom>@layer comark{:where(.cz-dialog,[data-zoom]){--_comark-background:var(--comark-background,var(--background,#fff));--_comark-foreground:var(--comark-foreground,var(--foreground,#0a0a0a));--_comark-muted:var(--comark-muted,var(--muted-foreground,#737373));--_comark-border:var(--comark-border,var(--border,#e5e5e5));--_comark-accent:var(--comark-accent,var(--accent,#f5f5f5));--_comark-ring:var(--comark-ring,var(--ring,#a1a1a1));--_comark-radius:var(--comark-radius,var(--radius,.625rem));--_comark-font:var(--comark-font,var(--font-sans,ui-sans-serif,system-ui,sans-serif))}@media (prefers-color-scheme:dark){:where(.cz-dialog,[data-zoom]){--_comark-background:var(--comark-background,var(--background,#0a0a0a));--_comark-foreground:var(--comark-foreground,var(--foreground,#fafafa));--_comark-muted:var(--comark-muted,var(--muted-foreground,#a1a1a1));--_comark-border:var(--comark-border,var(--border,rgb(255 255 255/.1)));--_comark-accent:var(--comark-accent,var(--accent,#262626));--_comark-ring:var(--comark-ring,var(--ring,#737373))}}[data-zoom]{cursor:zoom-in}[data-zoom]:focus-visible{outline:2px solid var(--_comark-ring);outline-offset:3px}.cz-dialog{position:fixed;inset:0;z-index:2147483000;display:grid;grid-template-rows:auto minmax(0,1fr) auto;color:var(--_comark-foreground);font:13px/1.4 var(--_comark-font);outline:none}.cz-backdrop{position:absolute;inset:0;background:color-mix(in srgb,var(--_comark-background) 96%,transparent)}.cz-header{position:relative;display:flex;gap:.75rem;align-items:center;min-height:2.75rem;padding:0 .5rem 0 1rem}.cz-title{overflow:hidden;font-weight:500;white-space:nowrap;text-overflow:ellipsis}.cz-count{color:var(--_comark-muted);font-variant-numeric:tabular-nums}.cz-dialog button{display:inline-grid;place-items:center;border:0;border-radius:calc(var(--_comark-radius) - 2px);background:none;color:inherit;font:inherit;cursor:pointer}.cz-dialog button:focus-visible{outline:2px solid var(--_comark-ring);outline-offset:1px}.cz-close{width:2.25rem;height:2.25rem;margin-left:auto;font-size:18px}.cz-close:hover,.cz-nav:hover{background:var(--_comark-accent)}.cz-stage{position:relative;display:grid;place-items:center;overflow:hidden}.cz-item{position:relative;transform-origin:center;cursor:auto}.cz-item img,.cz-thumb img{max-width:100%;height:auto}.cz-item>img,.cz-thumb>div>img{display:block;width:100%}.cz-layer{position:absolute;inset:0;pointer-events:none}.cz-layer>*{pointer-events:auto}.cz-nav{position:absolute;top:50%;width:2.5rem;height:2.5rem;font-size:22px;transform:translateY(-50%)}.cz-prev{left:.5rem}.cz-next{right:.5rem}.cz-footer{position:relative}.cz-strip{display:flex;gap:.5rem;justify-content:center;overflow-x:auto;padding:.75rem 1rem 1rem}.cz-strip .cz-thumb{position:relative;flex:none;width:6rem;height:4rem;overflow:hidden;border:1px solid var(--_comark-border);border-radius:calc(var(--_comark-radius) - 2px);opacity:.55;transition:opacity .15s}.cz-thumb:hover{opacity:.85}.cz-thumb[aria-current=true]{opacity:1;border-color:var(--_comark-foreground)}.cz-thumb>div{position:absolute;top:0;left:0;transform-origin:0 0;pointer-events:none}}\u003C/style>\u003Cstyle data-comark-carousel>@layer comark{:where(.cc){--_comark-background:var(--comark-background,var(--background,#fff));--_comark-foreground:var(--comark-foreground,var(--foreground,#0a0a0a));--_comark-muted:var(--comark-muted,var(--muted-foreground,#737373));--_comark-border:var(--comark-border,var(--border,#e5e5e5));--_comark-accent:var(--comark-accent,var(--accent,#f5f5f5));--_comark-ring:var(--comark-ring,var(--ring,#a1a1a1));--_comark-radius:var(--comark-radius,var(--radius,.625rem));--_comark-font:var(--comark-font,var(--font-sans,ui-sans-serif,system-ui,sans-serif))}@media (prefers-color-scheme:dark){:where(.cc){--_comark-background:var(--comark-background,var(--background,#0a0a0a));--_comark-foreground:var(--comark-foreground,var(--foreground,#fafafa));--_comark-muted:var(--comark-muted,var(--muted-foreground,#a1a1a1));--_comark-border:var(--comark-border,var(--border,rgb(255 255 255/.1)));--_comark-accent:var(--comark-accent,var(--accent,#262626));--_comark-ring:var(--comark-ring,var(--ring,#737373))}}:where(.cc){--cc-columns:1;--cc-gap:1rem;--cc-surface:color-mix(in srgb,var(--_comark-foreground) 4%,transparent)}.cc{position:relative;margin:1.5rem 0;container-type:inline-size}.cc[data-carousel-columns='2']{--cc-columns:2}.cc[data-carousel-columns='3']{--cc-columns:3}.cc-track{position:relative;display:grid;grid-auto-flow:column;grid-auto-columns:calc((100% - (var(--cc-columns) - 1) * var(--cc-gap)) / var(--cc-columns));gap:var(--cc-gap);overflow-x:auto;overscroll-behavior-x:contain;scroll-snap-type:x mandatory}[data-carousel-ready] .cc-track{scrollbar-width:none}[data-carousel-ready] .cc-track::-webkit-scrollbar{display:none}.cc-track>.cc-slide{min-width:0;scroll-snap-align:start;align-content:center;padding:1rem;border-radius:var(--_comark-radius);background:var(--cc-surface)}.cc-slide>:first-child{margin-top:0}.cc-slide>:last-child{margin-bottom:0}.cc-slide img{max-width:100%;height:auto}.cc-slide>img,.cc-slide>a>img{display:block;margin-inline:auto}.cc-track [data-zoom]:focus-visible{outline-offset:-2px}@container (max-width:36rem){.cc-track{grid-auto-columns:100%}.cc-track>.cc-slide{padding:.5rem}}.cc-controls{display:none;align-items:center;justify-content:space-between;gap:.5rem;margin-top:.75rem}[data-carousel-ready] .cc-controls{display:flex}@container (min-width:36.01rem){.cc[data-carousel-fits] .cc-controls{display:none!important}}.cc-count{color:var(--_comark-muted);font-size:.875rem;line-height:1.25rem;font-variant-numeric:tabular-nums}.cc-steps{display:flex;gap:.5rem}.cc-step{display:inline-grid;place-items:center;width:2rem;height:2rem;padding:0;border:1px solid var(--_comark-border);border-radius:999px;background:var(--_comark-background);color:var(--_comark-foreground);box-shadow:0 1px 2px rgb(0 0 0/.05);cursor:pointer;touch-action:manipulation;transition:background .15s,opacity .15s}.cc-step:hover:not([aria-disabled='true']){background:var(--_comark-accent)}.cc-step:focus-visible{outline:none;box-shadow:0 0 0 3px color-mix(in srgb,var(--_comark-ring) 50%,transparent)}.cc-step[aria-disabled='true']{opacity:.5;cursor:default}.cc-step svg{width:1rem;height:1rem}.cc:dir(rtl) .cc-step svg{scale:-1 1}@media (pointer:coarse){.cc-step{width:2.5rem;height:2.5rem}}}\u003C/style>\u003C/div>\u003Cp>That pull request redid the whole page, so its beaf has one pair per section:\u003C/p>\n\u003Cdiv class=\"cc\" data-zoom-gallery role=\"region\" aria-roledescription=\"carousel\" aria-label=\"justfuckingusenuxt.com redesign\">\u003Cdiv class=\"cc-track\">\u003Cdiv class=\"cc-slide\" role=\"group\" aria-roledescription=\"slide\" aria-label=\"1 of 3\" data-zoom tabindex=\"0\" data-zoom-title=\"justfuckingusenuxt.com redesign\">\u003Cdiv class=\"ca ca-compare\">\u003Cdiv class=\"cc\" data-carousel-columns=\"2\" data-carousel-fits data-zoom-gallery role=\"region\" aria-roledescription=\"carousel\" aria-label=\"Comparison\">\u003Cdiv class=\"cc-track\">\u003Cdiv class=\"cc-slide\" role=\"group\" aria-roledescription=\"slide\" aria-label=\"1 of 2\">\u003Cfigure class=\"ca-screenshot\" data-zoom tabindex=\"0\" data-zoom-context=\".ca\" data-zoom-title=\"Before\">\u003Cdiv class=\"ca-heading\">\u003Cspan class=\"ca-label\">Before\u003C/span> \u003Ca href=\"https://justfuckingusenuxt.com\" title=\"https://justfuckingusenuxt.com\">justfuckingusenuxt.com\u003C/a>\u003C/div>\u003Cdiv class=\"ca-stage\">\u003Cdiv class=\"ca-frame\">\u003Cimg src=\"/images/posts/beaf-features-before.webp\" alt=\"Old features: an auto-scrolling card carousel cut off at both edges\" loading=\"lazy\" decoding=\"async\">\u003Cspan class=\"ca-mark ca-box\" data-n=\"1\" role=\"img\" aria-label=\"Annotation 1: Cards cut off at both edges, and they keep moving while you read.\" title=\"Cards cut off at both edges, and they keep moving while you read.\" style=\"--ca-color:var(--ca-red);--ca-solid:var(--ca-red-solid);--ca-ink:var(--ca-red-ink);left:2.2%;top:25.5%;width:95.6%;height:19.3%\">\u003Csvg viewBox=\"0 0 200 100\" preserveAspectRatio=\"none\" aria-hidden=\"true\">\u003Cpath d=\"M10 14C70 8 140 10 192 12\" vector-effect=\"non-scaling-stroke\"/>\u003Cpath d=\"M192 12C194 40 193 66 190 88\" vector-effect=\"non-scaling-stroke\"/>\u003Cpath d=\"M190 88C130 92 60 90 12 86\" vector-effect=\"non-scaling-stroke\"/>\u003Cpath d=\"M12 86C8 60 8 36 10 14\" vector-effect=\"non-scaling-stroke\"/>\u003C/svg>\u003Cspan class=\"ca-stamp\">1\u003C/span>\u003C/span>\u003C/div>\u003C/div>\u003Cfigcaption>\u003Col class=\"ca-notes\">\u003Cli id=\"ca-ylex9w-1\" data-n=\"1\" style=\"--ca-color:var(--ca-red);--ca-solid:var(--ca-red-solid);--ca-ink:var(--ca-red-ink);\">\u003Cspan class=\"ca-stamp\">1\u003C/span>\u003Cdiv>Cards cut off at both edges, and they keep moving while you read.\u003C/div>\u003C/li>\u003C/ol>\u003C/figcaption>\u003C/figure>\u003C/div>\u003Cdiv class=\"cc-slide\" role=\"group\" aria-roledescription=\"slide\" aria-label=\"2 of 2\">\u003Cfigure class=\"ca-screenshot\" data-zoom tabindex=\"0\" data-zoom-context=\".ca\" data-zoom-title=\"After\">\u003Cdiv class=\"ca-heading\">\u003Cspan class=\"ca-label\">After\u003C/span>\u003C/div>\u003Cdiv class=\"ca-stage\">\u003Cdiv class=\"ca-frame\">\u003Cimg src=\"/images/posts/beaf-features-after.webp\" alt=\"New features: a bento grid of twelve cards, four of them wide with a one-line example\" loading=\"lazy\" decoding=\"async\">\u003Cspan class=\"ca-mark ca-box\" data-n=\"2\" role=\"img\" aria-label=\"Annotation 2: One card per feature. The four wide ones show the code.\" title=\"One card per feature. The four wide ones show the code.\" style=\"--ca-color:var(--ca-green);--ca-solid:var(--ca-green-solid);--ca-ink:var(--ca-green-ink);left:7.8%;top:24.7%;width:84.4%;height:70%\">\u003Csvg viewBox=\"0 0 200 100\" preserveAspectRatio=\"none\" aria-hidden=\"true\">\u003Cpath d=\"M10 14C70 8 140 10 192 12\" vector-effect=\"non-scaling-stroke\"/>\u003Cpath d=\"M192 12C194 40 193 66 190 88\" vector-effect=\"non-scaling-stroke\"/>\u003Cpath d=\"M190 88C130 92 60 90 12 86\" vector-effect=\"non-scaling-stroke\"/>\u003Cpath d=\"M12 86C8 60 8 36 10 14\" vector-effect=\"non-scaling-stroke\"/>\u003C/svg>\u003Cspan class=\"ca-stamp\">2\u003C/span>\u003C/span>\u003C/div>\u003C/div>\u003Cfigcaption>\u003Col class=\"ca-notes\">\u003Cli id=\"ca-ylex9w-2\" data-n=\"2\" style=\"--ca-color:var(--ca-green);--ca-solid:var(--ca-green-solid);--ca-ink:var(--ca-green-ink);\">\u003Cspan class=\"ca-stamp\">2\u003C/span>\u003Cdiv>One card per feature. The four wide ones show the code.\u003C/div>\u003C/li>\u003C/ol>\u003C/figcaption>\u003C/figure>\u003C/div>\u003C/div>\u003Cdiv class=\"cc-controls\">\u003Cspan class=\"cc-count\" aria-live=\"polite\">1 / 2\u003C/span>\u003Cdiv class=\"cc-steps\">\u003Cbutton type=\"button\" class=\"cc-step\" data-carousel-step=\"-1\" aria-label=\"Previous slide\" aria-disabled=\"true\">\u003Csvg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\u003Cpath d=\"m15 18-6-6 6-6\"/>\u003C/svg>\u003C/button>\u003Cbutton type=\"button\" class=\"cc-step\" data-carousel-step=\"1\" aria-label=\"Next slide\">\u003Csvg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\u003Cpath d=\"m9 18 6-6-6-6\"/>\u003C/svg>\u003C/button>\u003C/div>\u003C/div>\u003C/div>\u003C/div>\u003C/div>\u003Cdiv class=\"cc-slide\" role=\"group\" aria-roledescription=\"slide\" aria-label=\"2 of 3\" data-zoom tabindex=\"0\" data-zoom-title=\"justfuckingusenuxt.com redesign\">\u003Cdiv class=\"ca ca-compare\">\u003Cdiv class=\"cc\" data-carousel-columns=\"2\" data-carousel-fits data-zoom-gallery role=\"region\" aria-roledescription=\"carousel\" aria-label=\"Comparison\">\u003Cdiv class=\"cc-track\">\u003Cdiv class=\"cc-slide\" role=\"group\" aria-roledescription=\"slide\" aria-label=\"1 of 2\">\u003Cfigure class=\"ca-screenshot\" data-zoom tabindex=\"0\" data-zoom-context=\".ca\" data-zoom-title=\"Before\">\u003Cdiv class=\"ca-heading\">\u003Cspan class=\"ca-label\">Before\u003C/span> \u003Ca href=\"https://justfuckingusenuxt.com\" title=\"https://justfuckingusenuxt.com\">justfuckingusenuxt.com\u003C/a>\u003C/div>\u003Cdiv class=\"ca-stage\">\u003Cdiv class=\"ca-frame\">\u003Cimg src=\"/images/posts/beaf-logos-before.webp\" alt=\"Old production section: company names as text pills\" loading=\"lazy\" decoding=\"async\">\u003Cspan class=\"ca-mark ca-box\" data-n=\"1\" role=\"img\" aria-label=\"Annotation 1: Nine company names as text pills.\" title=\"Nine company names as text pills.\" style=\"--ca-color:var(--ca-red);--ca-solid:var(--ca-red-solid);--ca-ink:var(--ca-red-ink);left:7.8%;top:44.2%;width:84.4%;height:3.6%\">\u003Csvg viewBox=\"0 0 200 100\" preserveAspectRatio=\"none\" aria-hidden=\"true\">\u003Cpath d=\"M10 14C70 8 140 10 192 12\" vector-effect=\"non-scaling-stroke\"/>\u003Cpath d=\"M192 12C194 40 193 66 190 88\" vector-effect=\"non-scaling-stroke\"/>\u003Cpath d=\"M190 88C130 92 60 90 12 86\" vector-effect=\"non-scaling-stroke\"/>\u003Cpath d=\"M12 86C8 60 8 36 10 14\" vector-effect=\"non-scaling-stroke\"/>\u003C/svg>\u003Cspan class=\"ca-stamp\">1\u003C/span>\u003C/span>\u003C/div>\u003C/div>\u003Cfigcaption>\u003Col class=\"ca-notes\">\u003Cli id=\"ca-jfyn8m-1\" data-n=\"1\" style=\"--ca-color:var(--ca-red);--ca-solid:var(--ca-red-solid);--ca-ink:var(--ca-red-ink);\">\u003Cspan class=\"ca-stamp\">1\u003C/span>\u003Cdiv>Nine company names as text pills.\u003C/div>\u003C/li>\u003C/ol>\u003C/figcaption>\u003C/figure>\u003C/div>\u003Cdiv class=\"cc-slide\" role=\"group\" aria-roledescription=\"slide\" aria-label=\"2 of 2\">\u003Cfigure class=\"ca-screenshot\" data-zoom tabindex=\"0\" data-zoom-context=\".ca\" data-zoom-title=\"After\">\u003Cdiv class=\"ca-heading\">\u003Cspan class=\"ca-label\">After\u003C/span>\u003C/div>\u003Cdiv class=\"ca-stage\">\u003Cdiv class=\"ca-frame\">\u003Cimg src=\"/images/posts/beaf-logos-after.webp\" alt=\"New production section: two rows of company logos\" loading=\"lazy\" decoding=\"async\">\u003Cspan class=\"ca-mark ca-box\" data-n=\"2\" role=\"img\" aria-label=\"Annotation 2: 24 real logos in two rows that pause on hover.\" title=\"24 real logos in two rows that pause on hover.\" style=\"--ca-color:var(--ca-green);--ca-solid:var(--ca-green-solid);--ca-ink:var(--ca-green-ink);left:7.8%;top:37.8%;width:84.4%;height:12.2%\">\u003Csvg viewBox=\"0 0 200 100\" preserveAspectRatio=\"none\" aria-hidden=\"true\">\u003Cpath d=\"M10 14C70 8 140 10 192 12\" vector-effect=\"non-scaling-stroke\"/>\u003Cpath d=\"M192 12C194 40 193 66 190 88\" vector-effect=\"non-scaling-stroke\"/>\u003Cpath d=\"M190 88C130 92 60 90 12 86\" vector-effect=\"non-scaling-stroke\"/>\u003Cpath d=\"M12 86C8 60 8 36 10 14\" vector-effect=\"non-scaling-stroke\"/>\u003C/svg>\u003Cspan class=\"ca-stamp\">2\u003C/span>\u003C/span>\u003C/div>\u003C/div>\u003Cfigcaption>\u003Col class=\"ca-notes\">\u003Cli id=\"ca-jfyn8m-2\" data-n=\"2\" style=\"--ca-color:var(--ca-green);--ca-solid:var(--ca-green-solid);--ca-ink:var(--ca-green-ink);\">\u003Cspan class=\"ca-stamp\">2\u003C/span>\u003Cdiv>24 real logos in two rows that pause on hover.\u003C/div>\u003C/li>\u003C/ol>\u003C/figcaption>\u003C/figure>\u003C/div>\u003C/div>\u003Cdiv class=\"cc-controls\">\u003Cspan class=\"cc-count\" aria-live=\"polite\">1 / 2\u003C/span>\u003Cdiv class=\"cc-steps\">\u003Cbutton type=\"button\" class=\"cc-step\" data-carousel-step=\"-1\" aria-label=\"Previous slide\" aria-disabled=\"true\">\u003Csvg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\u003Cpath d=\"m15 18-6-6 6-6\"/>\u003C/svg>\u003C/button>\u003Cbutton type=\"button\" class=\"cc-step\" data-carousel-step=\"1\" aria-label=\"Next slide\">\u003Csvg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\u003Cpath d=\"m9 18 6-6-6-6\"/>\u003C/svg>\u003C/button>\u003C/div>\u003C/div>\u003C/div>\u003C/div>\u003C/div>\u003Cdiv class=\"cc-slide\" role=\"group\" aria-roledescription=\"slide\" aria-label=\"3 of 3\" data-zoom tabindex=\"0\" data-zoom-title=\"justfuckingusenuxt.com redesign\">\u003Cdiv class=\"ca ca-compare\">\u003Cdiv class=\"cc\" data-carousel-columns=\"2\" data-carousel-fits data-zoom-gallery role=\"region\" aria-roledescription=\"carousel\" aria-label=\"Comparison\">\u003Cdiv class=\"cc-track\">\u003Cdiv class=\"cc-slide\" role=\"group\" aria-roledescription=\"slide\" aria-label=\"1 of 2\">\u003Cfigure class=\"ca-screenshot\" data-zoom tabindex=\"0\" data-zoom-context=\".ca\" data-zoom-title=\"Before\">\u003Cdiv class=\"ca-heading\">\u003Cspan class=\"ca-label\">Before\u003C/span> \u003Ca href=\"https://justfuckingusenuxt.com\" title=\"https://justfuckingusenuxt.com\">justfuckingusenuxt.com\u003C/a>\u003C/div>\u003Cdiv class=\"ca-stage\">\u003Cdiv class=\"ca-frame\">\u003Cimg src=\"/images/posts/beaf-when-before.webp\" alt=\"Old section: six one-line questions that are collapsed accordions\" loading=\"lazy\" decoding=\"async\">\u003Cspan class=\"ca-mark ca-box\" data-n=\"1\" role=\"img\" aria-label=\"Annotation 1: Six accordions that don't look like they open, so nobody sees the answers.\" title=\"Six accordions that don't look like they open, so nobody sees the answers.\" style=\"--ca-color:var(--ca-red);--ca-solid:var(--ca-red-solid);--ca-ink:var(--ca-red-ink);left:25.2%;top:16.9%;width:49.7%;height:29.3%\">\u003Csvg viewBox=\"0 0 200 100\" preserveAspectRatio=\"none\" aria-hidden=\"true\">\u003Cpath d=\"M10 14C70 8 140 10 192 12\" vector-effect=\"non-scaling-stroke\"/>\u003Cpath d=\"M192 12C194 40 193 66 190 88\" vector-effect=\"non-scaling-stroke\"/>\u003Cpath d=\"M190 88C130 92 60 90 12 86\" vector-effect=\"non-scaling-stroke\"/>\u003Cpath d=\"M12 86C8 60 8 36 10 14\" vector-effect=\"non-scaling-stroke\"/>\u003C/svg>\u003Cspan class=\"ca-stamp\">1\u003C/span>\u003C/span>\u003C/div>\u003C/div>\u003Cfigcaption>\u003Col class=\"ca-notes\">\u003Cli id=\"ca-bhqtrs-1\" data-n=\"1\" style=\"--ca-color:var(--ca-red);--ca-solid:var(--ca-red-solid);--ca-ink:var(--ca-red-ink);\">\u003Cspan class=\"ca-stamp\">1\u003C/span>\u003Cdiv>Six accordions that don't look like they open, so nobody sees the answers.\u003C/div>\u003C/li>\u003C/ol>\u003C/figcaption>\u003C/figure>\u003C/div>\u003Cdiv class=\"cc-slide\" role=\"group\" aria-roledescription=\"slide\" aria-label=\"2 of 2\">\u003Cfigure class=\"ca-screenshot\" data-zoom tabindex=\"0\" data-zoom-context=\".ca\" data-zoom-title=\"After\">\u003Cdiv class=\"ca-heading\">\u003Cspan class=\"ca-label\">After\u003C/span>\u003C/div>\u003Cdiv class=\"ca-stage\">\u003Cdiv class=\"ca-frame\">\u003Cimg src=\"/images/posts/beaf-when-after.webp\" alt=\"New section: six cards with question, answer, and doc link\" loading=\"lazy\" decoding=\"async\">\u003Cspan class=\"ca-mark ca-box\" data-n=\"2\" role=\"img\" aria-label=\"Annotation 2: A one-sentence answer per card, each with its doc link.\" title=\"A one-sentence answer per card, each with its doc link.\" style=\"--ca-color:var(--ca-green);--ca-solid:var(--ca-green-solid);--ca-ink:var(--ca-green-ink);left:7.8%;top:23.1%;width:84.4%;height:41.9%\">\u003Csvg viewBox=\"0 0 200 100\" preserveAspectRatio=\"none\" aria-hidden=\"true\">\u003Cpath d=\"M10 14C70 8 140 10 192 12\" vector-effect=\"non-scaling-stroke\"/>\u003Cpath d=\"M192 12C194 40 193 66 190 88\" vector-effect=\"non-scaling-stroke\"/>\u003Cpath d=\"M190 88C130 92 60 90 12 86\" vector-effect=\"non-scaling-stroke\"/>\u003Cpath d=\"M12 86C8 60 8 36 10 14\" vector-effect=\"non-scaling-stroke\"/>\u003C/svg>\u003Cspan class=\"ca-stamp\">2\u003C/span>\u003C/span>\u003C/div>\u003C/div>\u003Cfigcaption>\u003Col class=\"ca-notes\">\u003Cli id=\"ca-bhqtrs-2\" data-n=\"2\" style=\"--ca-color:var(--ca-green);--ca-solid:var(--ca-green-solid);--ca-ink:var(--ca-green-ink);\">\u003Cspan class=\"ca-stamp\">2\u003C/span>\u003Cdiv>A one-sentence answer per card, each with its doc link.\u003C/div>\u003C/li>\u003C/ol>\u003C/figcaption>\u003C/figure>\u003C/div>\u003C/div>\u003Cdiv class=\"cc-controls\">\u003Cspan class=\"cc-count\" aria-live=\"polite\">1 / 2\u003C/span>\u003Cdiv class=\"cc-steps\">\u003Cbutton type=\"button\" class=\"cc-step\" data-carousel-step=\"-1\" aria-label=\"Previous slide\" aria-disabled=\"true\">\u003Csvg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\u003Cpath d=\"m15 18-6-6 6-6\"/>\u003C/svg>\u003C/button>\u003Cbutton type=\"button\" class=\"cc-step\" data-carousel-step=\"1\" aria-label=\"Next slide\">\u003Csvg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\u003Cpath d=\"m9 18 6-6-6-6\"/>\u003C/svg>\u003C/button>\u003C/div>\u003C/div>\u003C/div>\u003C/div>\u003C/div>\u003C/div>\u003Cdiv class=\"cc-controls\">\u003Cspan class=\"cc-count\" aria-live=\"polite\">1 / 3\u003C/span>\u003Cdiv class=\"cc-steps\">\u003Cbutton type=\"button\" class=\"cc-step\" data-carousel-step=\"-1\" aria-label=\"Previous slide\" aria-disabled=\"true\">\u003Csvg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\u003Cpath d=\"m15 18-6-6 6-6\"/>\u003C/svg>\u003C/button>\u003Cbutton type=\"button\" class=\"cc-step\" data-carousel-step=\"1\" aria-label=\"Next slide\">\u003Csvg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\u003Cpath d=\"m9 18 6-6-6-6\"/>\u003C/svg>\u003C/button>\u003C/div>\u003C/div>\u003C/div>\u003Cp>You get the whole redesign without running anything.\u003C/p>\n\u003Ch2 id=\"how-i-automated-it\">How I automated it\u003C/h2>\n\u003Cp>You don't need my tools for this. Two screenshots in the description already count. But I got lazy and automated it, in four layers:\u003C/p>\n\u003Cp>\u003Cimg src=\"/images/posts/beaf-layers.svg\" alt=\"Four layers, top to bottom: the pr-evidence skill, comark-annotate, Drop, and ViteHub\">\u003C/p>\n\u003Cul>\n  \u003Cli>The \u003Ca href=\"https://github.com/vite-hub/drop/tree/main/skills/pr-evidence\">\u003Ccode>pr-evidence\u003C/code>\u003C/a> skill puts it all together. When the agent opens a UI pull request, it takes the screenshots, writes the beaf and comments the link. It comes with Drop's MCP server through the \u003Ca href=\"https://modelcontextprotocol.io/extensions/skills/overview\">MCP Skills extension\u003C/a>.\u003C/li>\n  \u003Cli>\u003Ca href=\"https://comark.onmax.me/annotate/\">comark-annotate\u003C/a> draws the boxes, arrows and notes from a few lines of Markdown. It's one of almost 20 \u003Ca href=\"https://comark.onmax.me\">Comark plugins\u003C/a> I've built, mostly for agents to write, like charts, diffs, carousels and file trees. That repo keeps growing, so check it out.\u003C/li>\n  \u003Cli>\u003Ca href=\"https://drop.vitehub.dev\">Drop\u003C/a> is where people comment on the beaf. The agent reads the comments and publishes the next version at the same link.\u003C/li>\n  \u003Cli>\u003Ca href=\"https://vitehub.dev\">ViteHub\u003C/a> is the library under Drop. Drop is \u003Ca href=\"https://github.com/vite-hub/drop\">open source\u003C/a>, so you can deploy your own and make it your lab.\u003C/li>\n\u003C/ul>\n\u003Ch2 id=\"more-than-screenshots\">More than screenshots\u003C/h2>\n\u003Cp>I'm trying this on other stuff now. A performance fix gets a \u003Ca href=\"https://comark.onmax.me/play/#preset=charts-performance\">before/after chart\u003C/a>. A support answer gets a little doc with the steps instead of a wall of text. HumanLayer's \u003Ca href=\"https://github.com/humanlayer/skills/tree/main/plugins/show-me\">show-me\u003C/a> skill pushed me here too. It explains a change with pseudocode and file trees, plain text that GitHub already shows. I feel there's so much more to try.\u003C/p>\n\u003Ch2 id=\"ask-for-the-beaf\">Ask for the beaf\u003C/h2>\n\u003Cp>I still review pull requests without a beaf, don't worry. It's just way easier with one.\u003C/p>\n\u003Cp>If your agent can open a pull request, it can take two screenshots. Just ask. And next time a UI pull request shows up without any, you know what to say.\u003C/p>\n\u003Cp>Where's the beaf?\u003C/p>",[11,12],"(function script(css) {\n\tconst running = window.__comarkZoom;\n\tif (running) {\n\t\trunning.users++;\n\t\treturn running.stop;\n\t}\n\tconst listeners = new AbortController();\n\tconst signal = listeners.signal;\n\tconst style = document.querySelector(\"style[data-comark-zoom],link[data-comark-zoom]\") ? null : document.createElement(\"style\");\n\tif (style) {\n\t\tstyle.setAttribute(\"data-comark-zoom\", \"\");\n\t\tstyle.textContent = css;\n\t\tdocument.head.append(style);\n\t}\n\tconst SELECTOR = \"[data-zoom]\";\n\tconst INTERACTIVE = \"a,button,input,textarea,select,summary,label,video,audio\";\n\tconst motion = matchMedia(\"(prefers-reduced-motion: reduce)\");\n\tconst easing = \"cubic-bezier(.22,1,.36,1)\";\n\tlet view = null;\n\tlet restoration = null;\n\tlet restoring = null;\n\tconst el = (tag, className, attrs = {}) => {\n\t\tconst node = document.createElement(tag);\n\t\tnode.className = className;\n\t\tfor (const [key, value] of Object.entries(attrs)) node.setAttribute(key, value);\n\t\treturn node;\n\t};\n\tfunction outermost(node) {\n\t\tlet item = node;\n\t\tfor (let up = item.parentElement?.closest(SELECTOR); up; up = up.parentElement?.closest(SELECTOR)) item = up;\n\t\treturn item;\n\t}\n\tfunction settle(root) {\n\t\tconst nodes = [...root.querySelectorAll(`${SELECTOR}[tabindex=\"0\"]`)];\n\t\tif (root.matches(`${SELECTOR}[tabindex=\"0\"]`)) nodes.push(root);\n\t\tfor (const node of nodes) if (node.parentElement?.closest(SELECTOR)) node.removeAttribute(\"tabindex\");\n\t}\n\tfunction groupOf(item) {\n\t\tconst group = item.getAttribute(\"data-zoom-group\");\n\t\tconst gallery = item.closest(\"[data-zoom-gallery]\");\n\t\tconst nodes = group ? document.querySelectorAll(`[data-zoom-group=\"${CSS.escape(group)}\"]`) : gallery?.querySelectorAll(SELECTOR);\n\t\tif (!nodes) return [item];\n\t\treturn [...nodes].filter((node) => {\n\t\t\tif (node === item) return true;\n\t\t\tconst { width, height } = node.getBoundingClientRect();\n\t\t\treturn outermost(node) === node && !node.closest(\".cz-dialog\") && (width > 0 || height > 0);\n\t\t});\n\t}\n\tfunction titleOf(item) {\n\t\treturn item.getAttribute(\"data-zoom-title\") || item.getAttribute(\"alt\") || item.querySelector(\"img\")?.getAttribute(\"alt\") || (item.getAttribute(\"aria-roledescription\") === \"slide\" ? \"\" : item.getAttribute(\"aria-label\")) || \"\";\n\t}\n\tfunction strip(node) {\n\t\tfor (const part of [node, ...node.querySelectorAll(\"*\")]) for (const name of [\n\t\t\t\"id\",\n\t\t\t\"data-zoom\",\n\t\t\t\"data-zoom-group\",\n\t\t\t\"data-zoom-context\",\n\t\t\t\"tabindex\",\n\t\t\t\"aria-haspopup\"\n\t\t]) part.removeAttribute(name);\n\t\tnode.style.visibility = \"\";\n\t\tnode.style.margin = \"0\";\n\t\treturn node;\n\t}\n\tconst INHERITED = [\n\t\t\"font-family\",\n\t\t\"font-size\",\n\t\t\"font-style\",\n\t\t\"font-weight\",\n\t\t\"letter-spacing\",\n\t\t\"text-align\"\n\t];\n\tfunction lineHeight(parent, page) {\n\t\tconst size = parseFloat(page.fontSize);\n\t\tif (page.lineHeight === \"normal\" || !size) return page.lineHeight;\n\t\tconst probe = el(\"span\", \"\");\n\t\tprobe.style.cssText = `all:initial!important;position:absolute!important;visibility:hidden!important;font-size:${size * 2}px!important;line-height:inherit!important`;\n\t\tparent.append(probe);\n\t\tconst scaled = getComputedStyle(probe).lineHeight !== page.lineHeight;\n\t\tprobe.remove();\n\t\treturn scaled ? String(parseFloat(page.lineHeight) / size) : page.lineHeight;\n\t}\n\tfunction copy(item, into) {\n\t\tconst clone = strip(item.cloneNode(true));\n\t\tconst selector = item.getAttribute(\"data-zoom-context\");\n\t\tconst context = selector ? item.parentElement?.closest(selector) : null;\n\t\tconst parent = (context ?? item).parentElement;\n\t\tif (parent) {\n\t\t\tconst page = getComputedStyle(parent);\n\t\t\tfor (const name of INHERITED) into.style.setProperty(name, page.getPropertyValue(name));\n\t\t\tinto.style.lineHeight = lineHeight(parent, page);\n\t\t}\n\t\tif (!context) return into.append(clone);\n\t\tconst shell = strip(context.cloneNode(false));\n\t\tshell.style.color = \"inherit\";\n\t\tshell.append(clone);\n\t\tinto.append(shell);\n\t}\n\tfunction measure(item) {\n\t\tconst rect = item.getBoundingClientRect();\n\t\treturn {\n\t\t\twidth: rect.width || 1,\n\t\t\theight: rect.height || 1,\n\t\t\trect\n\t\t};\n\t}\n\tfunction detail(current) {\n\t\treturn {\n\t\t\tdialog: current.dialog,\n\t\t\theader: current.header,\n\t\t\tfooter: current.footer,\n\t\t\tlayer: current.frame.querySelector(\".cz-layer\"),\n\t\t\tcontent: current.frame.firstElementChild,\n\t\t\titem: current.items[current.index],\n\t\t\tindex: current.index,\n\t\t\titems: current.items\n\t\t};\n\t}\n\tfunction place(current) {\n\t\tconst item = current.items[current.index];\n\t\tconst { width } = measure(item);\n\t\tcurrent.frame.style.width = `${width}px`;\n\t\tconst height = current.frame.offsetHeight || 1;\n\t\tconst box = current.stage.getBoundingClientRect();\n\t\tconst image = current.frame.firstElementChild;\n\t\tconst large = image?.getAttribute(\"data-zoom-src\");\n\t\tconst natural = item instanceof HTMLImageElement && image instanceof HTMLImageElement && image.naturalWidth && (!large || image.getAttribute(\"src\") === large) ? Math.max(1, image.naturalWidth / width) : 4;\n\t\tcurrent.scale = Math.max(.1, Math.min(box.width * .92 / width, box.height * .92 / height, natural, 4));\n\t\tcurrent.frame.style.transform = `scale(${current.scale})`;\n\t}\n\tconst showing = (current, image) => view === current && !current.closing && current.frame.contains(image);\n\tfunction enlarge(current, image) {\n\t\tconst large = image.getAttribute(\"data-zoom-src\");\n\t\tif (!large) return;\n\t\tconst preload = new Image();\n\t\tpreload.addEventListener(\"load\", () => {\n\t\t\tif (!showing(current, image)) return;\n\t\t\tfor (const source of image.closest(\"picture\")?.querySelectorAll(\"source\") ?? []) source.remove();\n\t\t\timage.removeAttribute(\"srcset\");\n\t\t\timage.removeAttribute(\"sizes\");\n\t\t\timage.src = large;\n\t\t});\n\t\tpreload.src = large;\n\t}\n\tfunction travel(current, item) {\n\t\tconst center = (node) => {\n\t\t\tconst rect = node.getBoundingClientRect();\n\t\t\treturn [rect.left + rect.width / 2, rect.top + rect.height / 2];\n\t\t};\n\t\tconst [fx, fy] = center(current.frame);\n\t\tconst [cx, cy] = center(current.frame.firstElementChild);\n\t\tconst [tx, ty] = center(item);\n\t\treturn `translate(${tx - fx - (cx - fx) / current.scale}px, ${ty - fy - (cy - fy) / current.scale}px)`;\n\t}\n\tfunction render(current) {\n\t\tconst item = current.items[current.index];\n\t\tcurrent.frame.replaceChildren();\n\t\tcopy(item, current.frame);\n\t\tcurrent.frame.append(el(\"div\", \"cz-layer\"));\n\t\tfor (const image of current.frame.querySelectorAll(\"img\")) {\n\t\t\timage.loading = \"eager\";\n\t\t\timage.addEventListener(\"load\", () => showing(current, image) && place(current));\n\t\t\tenlarge(current, image);\n\t\t}\n\t\tcurrent.title.textContent = titleOf(item);\n\t\tcurrent.count.textContent = current.items.length > 1 ? `${current.index + 1} / ${current.items.length}` : \"\";\n\t\tcurrent.dialog.setAttribute(\"aria-label\", titleOf(item) || \"Zoomed view\");\n\t\tfor (const [index, thumb] of [...current.footer.querySelectorAll(\".cz-thumb\")].entries()) thumb.setAttribute(\"aria-current\", String(index === current.index));\n\t\tplace(current);\n\t}\n\tfunction thumbs(current) {\n\t\tif (current.items.length \u003C 2) return;\n\t\tconst strip = el(\"div\", \"cz-strip\", {\n\t\t\trole: \"group\",\n\t\t\t\"aria-label\": \"Items\"\n\t\t});\n\t\tfor (const [index, item] of current.items.entries()) {\n\t\t\tconst thumb = el(\"button\", \"cz-thumb\", {\n\t\t\t\ttype: \"button\",\n\t\t\t\t\"aria-label\": titleOf(item) || `Item ${index + 1}`\n\t\t\t});\n\t\t\tconst { width, height } = measure(item);\n\t\t\tconst inner = el(\"div\", \"\");\n\t\t\tinner.style.width = `${width}px`;\n\t\t\tinner.style.transform = `scale(${Math.min(96 / width, 64 / height)})`;\n\t\t\tcopy(item, inner);\n\t\t\tthumb.append(inner);\n\t\t\tthumb.addEventListener(\"click\", () => go(index));\n\t\t\tstrip.append(thumb);\n\t\t}\n\t\tcurrent.footer.append(strip);\n\t}\n\tfunction go(index) {\n\t\tif (!view || view.closing) return;\n\t\tview.items[view.index].style.visibility = \"\";\n\t\tview.index = (index + view.items.length) % view.items.length;\n\t\tview.items[view.index].style.visibility = \"hidden\";\n\t\trender(view);\n\t\tview.items[view.index].dispatchEvent(new CustomEvent(\"comark-zoom:change\", {\n\t\t\tbubbles: true,\n\t\t\tdetail: detail(view)\n\t\t}));\n\t}\n\tconst root = document.documentElement;\n\tlet unlocked = null;\n\tfunction lock() {\n\t\tscrollTo({\n\t\t\tleft: scrollX,\n\t\t\ttop: scrollY,\n\t\t\tbehavior: \"instant\"\n\t\t});\n\t\tconst scrollbar = innerWidth - root.clientWidth;\n\t\tunlocked = {\n\t\t\toverflow: root.style.overflow,\n\t\t\tgutter: root.style.scrollbarGutter,\n\t\t\tpadding: root.style.paddingRight\n\t\t};\n\t\tif (scrollbar > 0) {\n\t\t\tif (CSS.supports(\"scrollbar-gutter\", \"stable\")) root.style.scrollbarGutter = \"stable\";\n\t\t\telse root.style.paddingRight = `${parseFloat(getComputedStyle(root).paddingRight) + scrollbar}px`;\n\t\t}\n\t\troot.style.overflow = \"hidden\";\n\t}\n\tfunction unlock() {\n\t\tif (!unlocked) return;\n\t\troot.style.overflow = unlocked.overflow;\n\t\troot.style.scrollbarGutter = unlocked.gutter;\n\t\troot.style.paddingRight = unlocked.padding;\n\t\tunlocked = null;\n\t}\n\tfunction restore(later = false) {\n\t\tconst saved = restoration;\n\t\trestoration = null;\n\t\tif (!saved) return;\n\t\tconst put = () => {\n\t\t\thistory.scrollRestoration = saved;\n\t\t\trestoring = null;\n\t\t};\n\t\tif (!later) return put();\n\t\trestoring = put;\n\t\tsetTimeout(() => restoring === put && put());\n\t}\n\tfunction open(item) {\n\t\tif (view) return;\n\t\tconst items = groupOf(item);\n\t\tconst dialog = el(\"div\", \"cz-dialog\", {\n\t\t\trole: \"dialog\",\n\t\t\t\"aria-modal\": \"true\",\n\t\t\ttabindex: \"-1\"\n\t\t});\n\t\tconst header = el(\"div\", \"cz-header\");\n\t\tconst title = el(\"span\", \"cz-title\");\n\t\tconst count = el(\"span\", \"cz-count\");\n\t\tconst close = el(\"button\", \"cz-close\", {\n\t\t\ttype: \"button\",\n\t\t\t\"aria-label\": \"Close\"\n\t\t});\n\t\tclose.textContent = \"✕\";\n\t\theader.append(title, count, close);\n\t\tconst stage = el(\"div\", \"cz-stage\");\n\t\tconst frame = el(\"div\", \"cz-item\");\n\t\tstage.append(frame);\n\t\tconst footer = el(\"div\", \"cz-footer\");\n\t\tconst backdrop = el(\"div\", \"cz-backdrop\");\n\t\tdialog.append(backdrop, header, stage, footer);\n\t\tconst current = {\n\t\t\tdialog,\n\t\t\theader,\n\t\t\ttitle,\n\t\t\tcount,\n\t\t\tstage,\n\t\t\tfooter,\n\t\t\tframe,\n\t\t\titems,\n\t\t\tindex: Math.max(0, items.indexOf(item)),\n\t\t\tscale: 1,\n\t\t\treturnFocus: document.activeElement,\n\t\t\tpushed: false,\n\t\t\tclosing: false,\n\t\t\tpressed: null\n\t\t};\n\t\tif (items.length > 1) for (const [name, step, label] of [[\n\t\t\t\"cz-prev\",\n\t\t\t-1,\n\t\t\t\"Previous\"\n\t\t], [\n\t\t\t\"cz-next\",\n\t\t\t1,\n\t\t\t\"Next\"\n\t\t]]) {\n\t\t\tconst button = el(\"button\", `cz-nav ${name}`, {\n\t\t\t\ttype: \"button\",\n\t\t\t\t\"aria-label\": label\n\t\t\t});\n\t\t\tbutton.textContent = step \u003C 0 ? \"‹\" : \"›\";\n\t\t\tbutton.addEventListener(\"click\", () => go(current.index + step));\n\t\t\tstage.append(button);\n\t\t}\n\t\tview = current;\n\t\tthumbs(current);\n\t\tdocument.body.append(dialog);\n\t\tlock();\n\t\trender(current);\n\t\tclose.addEventListener(\"click\", () => void shut());\n\t\tdialog.addEventListener(\"pointerdown\", (event) => current.pressed = event.target);\n\t\tdialog.addEventListener(\"click\", (event) => {\n\t\t\tif ((event.target === stage || event.target === backdrop) && current.pressed === event.target) shut();\n\t\t});\n\t\tdialog.focus({ preventScroll: true });\n\t\ttry {\n\t\t\trestoring?.();\n\t\t\trestoration = history.scrollRestoration;\n\t\t\thistory.scrollRestoration = \"manual\";\n\t\t\thistory.pushState({\n\t\t\t\t...history.state,\n\t\t\t\tcomarkZoom: true\n\t\t\t}, \"\");\n\t\t\tcurrent.pushed = true;\n\t\t} catch {\n\t\t\tif (restoration) history.scrollRestoration = restoration;\n\t\t\trestoration = null;\n\t\t}\n\t\tconst shown = items[current.index];\n\t\tif (!motion.matches) {\n\t\t\tframe.animate([{ transform: `${travel(current, shown)} scale(1)` }, { transform: `scale(${current.scale})` }], {\n\t\t\t\tduration: 260,\n\t\t\t\teasing\n\t\t\t});\n\t\t\tfor (const part of [\n\t\t\t\tbackdrop,\n\t\t\t\theader,\n\t\t\t\tfooter\n\t\t\t]) part.animate([{ opacity: 0 }, { opacity: 1 }], { duration: 200 });\n\t\t}\n\t\tshown.style.visibility = \"hidden\";\n\t\tshown.dispatchEvent(new CustomEvent(\"comark-zoom:open\", {\n\t\t\tbubbles: true,\n\t\t\tdetail: detail(current)\n\t\t}));\n\t}\n\tasync function shut(from = \"page\") {\n\t\tconst current = view;\n\t\tif (!current || current.closing) return;\n\t\tcurrent.closing = true;\n\t\tif (from === \"page\" && current.pushed && history.state?.comarkZoom) history.back();\n\t\telse if (from !== \"history\") restore();\n\t\tconst item = current.items[current.index];\n\t\tif (!motion.matches) {\n\t\t\tconst now = getComputedStyle(current.frame).transform;\n\t\t\tfor (const animation of current.frame.getAnimations()) animation.cancel();\n\t\t\tconst to = item.getBoundingClientRect();\n\t\t\tconst visible = to.bottom > 0 && to.top \u003C innerHeight;\n\t\t\tconst animations = [...current.dialog.querySelectorAll(\".cz-backdrop,.cz-header,.cz-footer,.cz-nav\")].map((part) => part.animate([{ opacity: 1 }, { opacity: 0 }], {\n\t\t\t\tduration: 180,\n\t\t\t\tfill: \"forwards\"\n\t\t\t}));\n\t\t\tanimations.push(current.frame.animate(visible ? [{ transform: now }, { transform: `${travel(current, item)} scale(1)` }] : [{ opacity: 1 }, { opacity: 0 }], {\n\t\t\t\tduration: 200,\n\t\t\t\teasing,\n\t\t\t\tfill: \"forwards\"\n\t\t\t}));\n\t\t\tawait Promise.all(animations.map((animation) => animation.finished.catch(() => {})));\n\t\t}\n\t\tfor (const node of current.items) node.style.visibility = \"\";\n\t\tcurrent.dialog.remove();\n\t\tunlock();\n\t\tview = null;\n\t\tif (current.returnFocus instanceof HTMLElement) current.returnFocus.focus({ preventScroll: true });\n\t\titem.dispatchEvent(new CustomEvent(\"comark-zoom:close\", {\n\t\t\tbubbles: true,\n\t\t\tdetail: { item }\n\t\t}));\n\t}\n\tdocument.addEventListener(\"click\", (event) => {\n\t\tconst target = event.target instanceof Element ? event.target : null;\n\t\tconst found = target?.closest(SELECTOR);\n\t\tconst item = found && outermost(found);\n\t\tif (!item || item.closest(\".cz-dialog\") || event.defaultPrevented) return;\n\t\tconst control = target?.closest(INTERACTIVE);\n\t\tif (control && control !== item && item.contains(control)) return;\n\t\tif (!getSelection()?.isCollapsed) return;\n\t\tevent.preventDefault();\n\t\topen(item);\n\t}, { signal });\n\tdocument.addEventListener(\"keydown\", (event) => {\n\t\tif (!view) {\n\t\t\tconst item = event.target instanceof HTMLElement && event.target.matches(SELECTOR) ? outermost(event.target) : null;\n\t\t\tif (item && (event.key === \"Enter\" || event.key === \" \")) {\n\t\t\t\tevent.preventDefault();\n\t\t\t\topen(item);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (event.key === \"Escape\") {\n\t\t\tevent.preventDefault();\n\t\t\tshut();\n\t\t} else if (event.key === \"ArrowLeft\" && view.items.length > 1) go(view.index - 1);\n\t\telse if (event.key === \"ArrowRight\" && view.items.length > 1) go(view.index + 1);\n\t\telse if (event.key === \"Tab\") {\n\t\t\tconst focusable = [...view.dialog.querySelectorAll(\"button,[href],[tabindex]:not([tabindex='-1'])\")];\n\t\t\tif (!focusable.length) return;\n\t\t\tconst first = focusable[0];\n\t\t\tconst last = focusable[focusable.length - 1];\n\t\t\tif (event.shiftKey && (document.activeElement === first || document.activeElement === view.dialog)) {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tlast.focus();\n\t\t\t} else if (!event.shiftKey && document.activeElement === last) {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tfirst.focus();\n\t\t\t}\n\t\t}\n\t}, { signal });\n\taddEventListener(\"popstate\", () => {\n\t\trestore(true);\n\t\tshut(\"history\");\n\t}, { signal });\n\taddEventListener(\"resize\", () => view && place(view), { signal });\n\tsettle(document.documentElement);\n\tconst added = new MutationObserver((records) => {\n\t\tfor (const record of records) for (const node of record.addedNodes) if (node instanceof Element) settle(node);\n\t});\n\tadded.observe(document.documentElement, {\n\t\tchildList: true,\n\t\tsubtree: true\n\t});\n\tconst state = {\n\t\tusers: 1,\n\t\tstop: () => {\n\t\t\tif (--state.users > 0) return;\n\t\t\tadded.disconnect();\n\t\t\tlisteners.abort();\n\t\t\tstyle?.remove();\n\t\t\tshut(\"stop\");\n\t\t\twindow.__comarkZoom = void 0;\n\t\t}\n\t};\n\twindow.__comarkZoom = state;\n\treturn state.stop;\n})(\"\")","(function start$1(css) {\n\tconst running = window.__comarkCarousel;\n\tif (running) {\n\t\trunning.users++;\n\t\trunning.watch();\n\t\treturn running.stop;\n\t}\n\tconst listeners = new AbortController();\n\tconst signal = listeners.signal;\n\tconst style = document.querySelector(\"style[data-comark-carousel],link[data-comark-carousel]\") ? null : document.createElement(\"style\");\n\tif (style) {\n\t\tstyle.setAttribute(\"data-comark-carousel\", \"\");\n\t\tstyle.textContent = css;\n\t\tdocument.head.append(style);\n\t}\n\tdocument.documentElement.setAttribute(\"data-carousel-ready\", \"\");\n\tconst parts = (root) => {\n\t\tconst track = root.querySelector(\":scope>.cc-track\");\n\t\tconst slides = track ? [...track.querySelectorAll(\":scope>.cc-slide\")] : [];\n\t\tconst step = (by) => root.querySelector(`:scope>.cc-controls [data-carousel-step='${by}']`);\n\t\treturn {\n\t\t\ttrack,\n\t\t\tslides,\n\t\t\tcount: root.querySelector(\":scope>.cc-controls .cc-count\"),\n\t\t\tprev: step(-1),\n\t\t\tnext: step(1)\n\t\t};\n\t};\n\tconst rtl = (track) => getComputedStyle(track).direction === \"rtl\";\n\tconst offset = (track, slide) => {\n\t\tconst outer = track.getBoundingClientRect();\n\t\tconst inner = slide.getBoundingClientRect();\n\t\treturn rtl(track) ? outer.right - inner.right : inner.left - outer.left;\n\t};\n\tfunction current(root) {\n\t\tconst { track, slides } = parts(root);\n\t\tif (!track || !slides.length) return 0;\n\t\tconst offsets = slides.map((slide) => Math.abs(offset(track, slide)));\n\t\treturn offsets.indexOf(Math.min(...offsets));\n\t}\n\tconst targets = /* @__PURE__ */ new WeakMap();\n\tconst settles = \"onscrollend\" in window;\n\tconst timers = /* @__PURE__ */ new Map();\n\tconst settle = (root) => {\n\t\tif (settles) return;\n\t\tclearTimeout(timers.get(root));\n\t\ttimers.set(root, window.setTimeout(() => {\n\t\t\ttargets.delete(root);\n\t\t\ttimers.delete(root);\n\t\t}, 150));\n\t};\n\tfunction show(root, index, behavior) {\n\t\tconst { track, slides } = parts(root);\n\t\tconst target = Math.max(0, Math.min(index, slides.length - 1));\n\t\tconst slide = slides[target];\n\t\tif (!track || !slide) return;\n\t\tconst how = behavior ?? (matchMedia(\"(prefers-reduced-motion: reduce)\").matches ? \"instant\" : \"smooth\");\n\t\tif (how === \"smooth\") targets.set(root, target);\n\t\telse targets.delete(root);\n\t\tsettle(root);\n\t\tconst by = offset(track, slide);\n\t\ttrack.scrollTo({\n\t\t\tleft: track.scrollLeft + (rtl(track) ? -by : by),\n\t\t\tbehavior: how\n\t\t});\n\t}\n\tconst page = (root, by) => show(root, (targets.get(root) ?? current(root)) + by);\n\tfunction sync(root) {\n\t\tconst { track, slides, count, prev, next } = parts(root);\n\t\tif (!track?.clientWidth) return;\n\t\tconst scrolled = Math.abs(track.scrollLeft);\n\t\tconst end = scrolled + track.clientWidth >= track.scrollWidth - 2;\n\t\tconst text = `${(end ? slides.length - 1 : current(root)) + 1} / ${slides.length}`;\n\t\tif (count && count.textContent !== text) count.textContent = text;\n\t\tprev?.setAttribute(\"aria-disabled\", String(scrolled \u003C 2));\n\t\tnext?.setAttribute(\"aria-disabled\", String(end));\n\t}\n\tconst resized = new ResizeObserver((entries) => {\n\t\tfor (const entry of entries) {\n\t\t\tconst root = entry.target.closest(\".cc\");\n\t\t\tif (root) sync(root);\n\t\t}\n\t});\n\tconst observe = (node) => {\n\t\tif (!(node instanceof Element)) return;\n\t\tif (node.matches(\".cc>.cc-track\")) resized.observe(node);\n\t\tfor (const track of node.querySelectorAll(\".cc>.cc-track\")) resized.observe(track);\n\t};\n\tconst watch = () => observe(document.documentElement);\n\twatch();\n\tconst added = new MutationObserver((records) => {\n\t\tfor (const record of records) record.addedNodes.forEach(observe);\n\t});\n\tadded.observe(document.documentElement, {\n\t\tchildList: true,\n\t\tsubtree: true\n\t});\n\tdocument.addEventListener(\"click\", (event) => {\n\t\tconst button = event.target instanceof Element ? event.target.closest(\"[data-carousel-step]\") : null;\n\t\tconst root = button?.closest(\".cc\");\n\t\tif (!button || !root || button.getAttribute(\"aria-disabled\") === \"true\") return;\n\t\tpage(root, Number(button.getAttribute(\"data-carousel-step\")));\n\t}, { signal });\n\tconst trackRoot = (event) => event.target instanceof Element && event.target.matches(\".cc-track\") ? event.target.closest(\".cc\") : null;\n\tdocument.addEventListener(\"scroll\", (event) => {\n\t\tconst root = trackRoot(event);\n\t\tif (!root) return;\n\t\tsync(root);\n\t\tsettle(root);\n\t}, {\n\t\tcapture: true,\n\t\tpassive: true,\n\t\tsignal\n\t});\n\tif (settles) document.addEventListener(\"scrollend\", (event) => {\n\t\tconst root = trackRoot(event);\n\t\tif (root) targets.delete(root);\n\t}, {\n\t\tcapture: true,\n\t\tpassive: true,\n\t\tsignal\n\t});\n\tconst keyed = \"input,textarea,select,video,audio,summary,[contenteditable],[role=tablist],[role=slider],[role=radiogroup],[role=listbox],[role=combobox],[role=spinbutton],[role=menu],[role=menubar],[role=tree]\";\n\tconst scrolls = (element) => element.scrollWidth > element.clientWidth && /auto|scroll/.test(getComputedStyle(element).overflowX);\n\tdocument.addEventListener(\"keydown\", (event) => {\n\t\tif (event.key !== \"ArrowLeft\" && event.key !== \"ArrowRight\") return;\n\t\tif (event.defaultPrevented || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) return;\n\t\tif (document.querySelector(\".cz-dialog\")) return;\n\t\tconst target = event.target instanceof Element ? event.target : null;\n\t\tconst root = target?.closest(\".cc\");\n\t\tconst track = root ? parts(root).track : null;\n\t\tif (!target || !root || !track || target.closest(keyed)) return;\n\t\tfor (let at = target; at && at !== track && at !== root; at = at.parentElement) if (scrolls(at)) return;\n\t\tevent.preventDefault();\n\t\tpage(root, event.key === (rtl(track) ? \"ArrowLeft\" : \"ArrowRight\") ? 1 : -1);\n\t}, { signal });\n\tconst follow = (event) => {\n\t\tconst slide = event.target instanceof Element ? event.target.closest(\".cc-slide\") : null;\n\t\tconst root = slide?.closest(\".cc\");\n\t\tif (!slide || !root) return;\n\t\tshow(root, parts(root).slides.indexOf(slide), \"instant\");\n\t\tsync(root);\n\t};\n\tdocument.addEventListener(\"comark-zoom:change\", follow, { signal });\n\tconst state = {\n\t\tusers: 1,\n\t\twatch,\n\t\tstop: () => {\n\t\t\tif (--state.users > 0) return;\n\t\t\tlisteners.abort();\n\t\t\tresized.disconnect();\n\t\t\tadded.disconnect();\n\t\t\tfor (const timer of timers.values()) clearTimeout(timer);\n\t\t\ttimers.clear();\n\t\t\tstyle?.remove();\n\t\t\tdocument.documentElement.removeAttribute(\"data-carousel-ready\");\n\t\t\twindow.__comarkCarousel = void 0;\n\t\t}\n\t};\n\twindow.__comarkCarousel = state;\n\treturn state.stop;\n})(\"\")",1792765462329]