mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-11 21:57:14 +03:00
9a949fb543d44cfb406f61bcab99d95d7f12cf1d
18
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
9a949fb543 |
Release: skill 4.0.4, CLI 3.5.0, extension 1.3.1
Version bumps for all three components plus the build:release sync of the tracked harness dirs and the plugin subtree at 4.0.4, rebased onto the composition-axes work so the release carries both threads. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
19e400e392 |
Retire the single-font rule
One family with weight and size contrast carrying the hierarchy is a legitimate type system, and in practice the rule mostly punished minimal pages: it was the loudest cross-rule noise on the fixture corpus's should-pass columns. Removed from the registry, both engine paths, the regex page analyzers, and the devtools category map; the negative assertions stay as resurrection guards, and the text-content analyzer index base shifts down one with the removal. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
68b1129634 |
Release bumps: skill 4.0.3, CLI 3.4.0, extension 1.3.0, with synced output
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
d5403f9d65 |
Bump extension to v1.2.1 and add consolidated changelog (#265)
Release bump covering the recent extension fixes that ship together: toolbar badge count parity (#262), local file:// scan failure messaging (#258), and the Kinpaku popup theme (#260). Merge after #264, #261, and #263. Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
1f4021b16c |
Fix: make Chrome extension toolbar badge count anti-patterns (#264)
The toolbar badge counted flagged elements (state.findings.length) while the popup and DevTools panel counted total anti-pattern findings, so the same scan showed two numbers (e.g. 21 vs 34 on the design-system page). Since the surfaces are labeled "anti-patterns", count total findings in the badge too so all three agree. Closes #262 Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
046a8593f5 |
Fix: surface scan failures in extension popup for local files (#261)
* Fix: surface scan failures in extension popup for local files Scanning a local file:// page with "Allow access to file URLs" off left the popup stuck on "Scanning..." because the blocked content-script injection returned silently. ensureContentScriptInjected() now returns the real error, and sendScanToTab() sends a scan-failed message that the popup renders as a small line, with a permission hint shown only for file:// tabs. Fixes #258 Co-authored-by: Cursor <cursoragent@cursor.com> * Improve: report the actual error when a non-file scan fails The generic "This page can't be scanned." gave no reason. Non-file failures now read "Couldn't scan this page: <error>" so the user sees what Chrome reported instead of a dead end. Co-authored-by: Cursor <cursoragent@cursor.com> * Fix: scope popup broadcasts to the active tab The popup acted on every findings-updated / scan-failed / overlays broadcast regardless of which tab it targeted, so a background or DevTools-driven rescan on another tab could reset the button or show a spurious error. Cache the active tab id and ignore broadcasts for other tabs. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
e371c99f08 |
Update extension popup to Kinpaku theme (#263)
* Update extension popup to Kinpaku theme * Fix popup light mode contrast |
||
|
|
9381269a82 | Fix Firefox DevTools extension paths (#231) | ||
|
|
3d1be6238c |
feat(extension): build and ship a Firefox add-on (#188)
Derive a Gecko-compatible manifest at build time and package extension-firefox.zip alongside the Chrome zip: - background service worker is declared as an event-page `scripts` entry (top-level listeners + in-memory Map run unchanged on Gecko) - browser_specific_settings.gecko with id, strict_min_version 140.0, and data_collection_permissions (required by AMO; honored on 140+) - packZip helper parameterized over cwd/excludes; `*.DS_Store` strips junk at every depth and .DS_Store is excluded from the staging copy - guard against a missing background.service_worker shape CI now builds the extension and runs a pinned `web-ext@8 lint` over the staged Firefox tree (innerHTML warnings are non-blocking); the unpacked staging dir is excluded from the uploaded artifact. The release script attaches both zips and points to AMO. Bumps the extension to v1.2.0 with a changelog entry. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Paul Bakaus <paul.bakaus@gmail.com> |
||
|
|
9ec87e590d |
extension: new brand icon + refresh store listing to 41 rules
Swap the extension icons (16/32/48/128 + source SVG) to the new gold kinpaku brand mark on a dark rounded square, replacing the old diagonal stroke. Update STORE_LISTING.md: the detection count is now 41 (was 24), and the WHAT IT DETECTS lists are refreshed to the current ruleset (26 AI-slop + 15 quality rules). Still v1.1.0 (not yet submitted to the Chrome Web Store). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
9ffd3211d5 |
Neo Kinpaku design system + Live Mode v3 (#169)
* Add neo kinpaku design system page * skill: rip out baked-in category recipes and saturated-default motion tropes Programmatic bias mining (impeccable-evals) traced four major defects back to specific lines in this skill that contradicted SKILL.md's own first-order-reflex warning: - brand.md "Pairing and voice" prescribed four category→aesthetic recipes (editorial → serif+sans, tech/dev/fintech → tight tracking, consumer/food/travel → script/display serif, creative → rule-break). These directly drove OpenAI's 76% extreme-negative letter-spacing on tech briefs and Anthropic/Google's 28-34% italic-serif-display slop on editorial/food briefs. Replaced with one sentence: the shape depends on the brand, not on the brand's category. - brand.md "Brand permissions" had "Typographic risk. Enormous display type, unexpected italic cuts, mixed cases, hand-drawn headlines, a single oversize word as a hero." — a four-for-one slop driver behind 97% OpenAI comically-large H1, 42% bad-SVG illustration, and the editorial-italic slop. Deleted outright. - typeset.md and teach.md repeated the same category recipes; trimmed to the principle without the recipe. - SKILL.md Typography: added a hard hero-H1 ceiling (clamp() max ≤ 6rem ≈ 96px), with a <codex> block to make it explicit since OpenAI over-indexes here (97% ≥128px vs 24% for Anthropic). - animate.md, bolder.md, brand.md: removed "staggered reveals" and "scroll-triggered transitions" as the prescribed default ambitious motion. By 2026 that's the saturated AI tell, not a choreography. Reserved stagger for legitimate list-sibling rhythm. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * skill: anti-cream + codex-specific defect bans + universal slop bans Second pass after measuring more biases against the eval corpus. - SKILL.md Color: explicit "cream/sand/beige body bg is the saturated AI default of 2026" rule. Tone down the "tint every neutral" line so it doesn't read as "default to warm-tinted near-white" (which OpenAI hits at 74% and Anthropic at 31%-47%). - SKILL.md Absolute bans: add universal bans for two slop patterns detected at 55-95% across providers — tiny uppercase tracked eyebrow above every section (the 2023-era kicker that's now AI grammar) and numbered section markers (01/02/03). Also explicit "text that overflows its container is the universal defect on tablet/mobile." - SKILL.md Absolute bans → <codex> block: ban the GPT-specific defects Paul annotated repeatedly — `border:1px solid` + soft-wide-shadow (≥16px blur) "ghost cards", `border-radius:32px+` over-rounding, hand-drawn/sketchy SVG illustrations (loose-sketch / *-sketch classes, feTurbulence paper-grain filters), repeating-linear-gradient stripes, "X theater" AI-slop copy phrases. - SKILL.md Motion → <gemini> block: the image :hover transform tell (38% Google skill-on rate). Hover effects on images add no info; the image isn't an action target. Animate card chrome, not the image. - SKILL.md Typography: hard display letter-spacing floor ≥-0.04em (OpenAI defaults to -0.075em → cramped). Existing hero ceiling <codex> block extended with the letter-spacing rule. - codex.md Step A example: stop seeding "warm-grounded (deep oxblood + cream)" as the warm-palette template, which primes the cream default. - colorize.md Tinted backgrounds: stop printing the literal cream recipe `oklch(97% 0.01 60)`; replace with brand-anchored guidance. - document.md examples: warm-ash-cream → cool-paper so the example doesn't seed cream as the canonical neutral example. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * skill: universal anti-slop bans + contrast/font-count/all-caps-body rules Third pass after measuring the rest of the cross-provider matrix: - Color: explicit "Verify contrast" rule. Low-contrast text fires at 68% across all providers skill-on (90+% off). The most common failure is muted gray body on a tinted near-white; light-gray-for- elegance is named as the single biggest cause of unreadable AI pages. - Typography: max-3-font-families rule. Overused-fonts (>4 families) fires at 28% Anthropic / 36% Google / 0% OpenAI skill-on; >50% off. Also: universal "no all-caps body copy" (moved from brand-only ban to Shared design laws since product-register also overuses caps). - Copy: anti-aphoristic-cadence ban targets Anthropic's signature "X. No Y." / "X. Just Y." voice (63% skill-on copy-slop rate, 77% off — the worst rate in the matrix). Once-is-voice / three-or-more- is-tell framing per the runner's copy-slop detector. - Copy: anti-SaaS-buzzword-string ban with the literal phrase list the detector watches for (streamline/empower/supercharge, trusted- by-leading, best-in-class/enterprise-grade/cutting-edge, etc). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * skill: strengthen anti-cream rule across full warm-neutral band Smoke validation showed the cream fix worked for Google + OpenAI but Anthropic Sonnet italian-restaurant still shipped `--paper: oklch(90% .018 88)` — cream just outside the L≥95% band the rule cited. Broaden the rule: - Band: OKLCH L 0.84-0.97, C < 0.06, hue 40-100 (was 95-97% / 60-95). - Name the token-name tells explicitly (paper / cream / sand / bone / flour / linen / parchment / wheat / biscuit / ivory) — the model defaults to one of these regardless of what hex it lands on. - Call out the specific brief patterns ("warm, traditional, family- coastal-Italian" / "editorial-restraint") that the model translates into cream by reflex. Then provide three explicit non-cream options: saturated brand color, true off-white at C=0, or darker mid-tone. Warmth in the brand is carried by accent + typography + imagery, not by body bg. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * v3.2.0: skill bias-fix release Bumps version from 3.1.1 to mark the four-commit skill cleanup that rips out baked-in category recipes (brand.md), saturated-default motion tropes (staggered reveals everywhere), the cream/sand body-bg AI tell, codex-specific defects (1px+wide-shadow, over-rounding, hand-drawn SVGs, stripes, X-theater copy), the extreme-letter-spacing default, and universal slop bans (all-caps eyebrow on every section, numbered-section markers, all-caps body, font-family-count > 3, aphoristic copy cadence, SaaS buzzword strings). Plus a hard hero-H1 ceiling (clamp() ≤6rem) and a Gemini-specific image:hover transform block. Validated against ~190 post-fix samples — see impeccable-evals biases tab for per-provider deltas. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * drop "no pure black/white" rule entirely The rule was contested in the design world and causing more damage than good — pushing every page into the tinted-near-white default which is the cream/sand AI tell we already explicitly ban elsewhere. Vercel, SVKMS, Brutalist sites, et al. use pure black/white successfully; the skill shouldn't second-guess that. Skill markdown deletions: - SKILL.md Color: drop the "Never use #000 or #fff" bullet. - color-and-contrast.md: drop the "Never Use Pure Gray or Pure Black" subsection, the "Never pure black" table-row prescription, and the "Avoid: Using pure black for large areas" bullet. - colorize.md: drop the "NEVER use pure black or pure white for large areas" bullet. - polish.md: drop the "Tinted neutrals: No pure gray or pure black" half of the bullet (the gray-on-color bullet survives). Detector code (cli/engine): - registry/antipatterns.mjs: remove the `pure-black-white` entry. - rules/checks.mjs: remove the three `findings.push({ id: 'pure-black-white', ... })` emit points (inline #000 bg, Tailwind bg-black class, plain-HTML scan path). - engines/regex/detect-text.mjs: remove the two pure-black-white regex rules (CSS `background: #000…` + Tailwind `bg-black`). - detect-antipatterns-browser.js: regenerated via scripts/build-browser-detector.js. Tests: - detect-antipatterns-fixtures.test.mjs: invert the assertion that pure-black-white fires; expect it to NOT fire post-v3.2. Drop the Tailwind bg-black-opacity edge-case test (no longer relevant). - detect-antipatterns.test.js: drop the standalone "detects pure- black-white in styled-components" test and remove pure-black-white from the multi-detector assertions in PricingCard, globals.css, and GlobalStyle.tsx tests. 166 bun tests pass; 24 node fixture tests pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * skill: strip example patterns from copy rules, strengthen gemini block v3.2 rerun validation surfaced two issues: 1. Copy-slop detector fires more on Gemini under v3.2 (48% → 84%) than under no-skill baseline. Root cause: the anti-aphoristic-cadence rule printed the literal "X. No Y." / "X. Just Y." patterns as examples, and Gemini imitated them as the recommended voice. Same recipe-becomes- bias trap we hit with brand.md:116's "Enormous display type, unexpected italic cuts, mixed cases, hand-drawn headlines" enumeration. Fix: describe the cadence as a rhythm ("serious statement, then punchy short negation") without printing literal patterns. Buzzword list trimmed to a single inline phrase family rather than quoted strings. 2. Gemini image:hover transform Gemini-tell hadn't dropped (31% off → 32% v3.2). Strengthen the <gemini> block: explicit "Never animate <img> elements on hover", call out the Tailwind group-hover:scale / group-hover:rotate / group-hover:translate parent-hover patterns by name (Gemini was reaching for these via Tailwind even though the prior text talked about :hover on the image directly). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * skill: simplify context loading and inline register directive Replaces load-context.mjs's JSON output with a tight markdown block from the renamed context.mjs. The script now extracts PRODUCT.md's `## Register` field and appends a `NEXT STEP:` directive naming the matching reference (brand.md / product.md), which moved Gemini from skipping the register load entirely to honoring it. Drops the `.impeccable.md` auto-migration; makes IMPECCABLE_CONTEXT_DIR a lazy escape hatch consulted only when the default paths come up empty. Setup is now four bullets in one list. The DESIGN.md nudge is gone; in its place, a "familiarize with the existing design system" step that calls out CSS / tokens / running app as authoritative sources alongside DESIGN.md. The standalone `### Register` H3 stays for the cascade rules (task cue → surface → register field). New LLM-backed test suite at tests/skill-behavior/ runs five scenarios against claude-haiku-4-5, gpt-5.4-mini, and gemini-3.1-flash-lite via Vercel AI SDK. Captures real tool traces, asserts on context.mjs calls, brand.md loads, and teach.md fallback. Skips cleanly when API keys are unset. 13-14/15 pass; only stable failure is the v3.2.0-era gpt-mini S4 "don't re-run" regression. Adds @ai-sdk/google as devDep and the test:skill-behavior npm script. Touches em-dashes in skill/SKILL.md and four reference files so `bun run build:skills` passes its skill-prose validator. teach.md and document.md drop their "re-run the loader to refresh session cache" steps since the agent's own write is now the freshest source. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * skill: merge orphan reference files into command sub-skills + inline S-tier invariants Two related restructurings: 1. SKILL.md now carries the cross-domain invariants that catch defects in any project (contrast/placeholder/gray-on-color, similar-font pairing, text-wrap, tabular-nums, centered-stack default, Flex/Grid choice, auto-fit grids, semantic z-index, reduced motion, stagger vs section-fade, premium motion materials, focus-visible, placeholders-aren't-labels, dropdown overflow trap, button/link copy). Greenfield-only rules (theme picking, color strategy, tinted neutrals) live under "New projects only". 2. Reference files merged into their command counterparts: - spatial-design.md -> layout.md - motion-design.md -> animate.md - color-and-contrast.md -> colorize.md - responsive-design.md -> adapt.md - ux-writing.md -> clarify.md - typography.md -> typeset.md (bolder.md redirected) - cognitive-load.md + heuristics-scoring.md + personas.md -> critique.md craft.md and shape.md "load references" lists updated to new file homes. interaction-design.md stays standalone (no 1:1 command verb). Net: 36 -> 27 reference files. Same content, fewer files, no orphaned reference loaded only from craft.md. Also extends the routing rules: if the user's first word doesn't match a command but the intent clearly maps to one, load that command's reference and proceed as if invoked. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * skill: add sub-command + existing-project scenarios; move sub-command load to step 2 Adds three new LLM-backed scenarios to tests/skill-behavior: - S6: `/impeccable polish` → loads polish.md - S7: `/impeccable audit` → loads audit.md - S8: existing SvelteKit project (PRODUCT.md + DESIGN.md + src/app.css + src/lib/components/*.svelte + src/routes/+page.svelte) → agent reads at least one project code file to understand the existing design system S6/S7 surface a real model-floor: gpt-5.4-mini reads brand.md, reads the target index.html, and just does the polish/audit without ever loading the sub-command reference. Stronger SKILL.md wording didn't move it. Captured in the README baseline as a known weakness. Claude and Gemini honor the load reliably. To fix Gemini on S6/S7, sub-command reference loading is now Setup step 2 (right after context.mjs), not step 4 — placing it before the model gets focused on "doing the work". Step 3 (design-system familiarization) is tightened to require at least one project code read even when a sub-command reference loads in step 2, so Claude doesn't laser-focus on the sub-command flow and skip the broader exploration. Two new fixtures: MINIMAL_LANDING_HTML (a tiny static landing page for S6/S7) and SVELTE_PROJECT_FILES (a minimal SvelteKit scaffold with tokens, components, and a routes/+page.svelte for S8). Both designed to look real enough that agents treat them as production code. Suite is now 24 tests across three providers; baseline is 21-22/24, with the stable failures being gpt-5.4-mini scenarios 6 and 7. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * skill: add reveal-animation safety rule (must enhance, not gate visibility) Class-triggered visibility transitions pause on hidden tabs and headless renderers. The italian-restaurant smoke produced a build where 2 sections shipped opacity:0 because the CSS transition never advanced past currentTime=0 (timeline paused). Added one-liner under Motion to prevent the antipattern: reveals must enhance an already-visible default, never gate content visibility on a class-triggered transition. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * skill: restore prescriptive cream/sand/beige paragraph Bisection across 5 historical skill commits on Gemini 3.5 flash fast lane n=3 found that |
||
|
|
64c6df216b |
fix(detector): contrast checks run on styled <a> and <button> (v1.0.3)
SAFE_TAGS skipped <a> and <button> categorically to avoid noise on inline links and unstyled controls. The blanket skip overshot: a pill-style anchor or styled button with its own opaque background was silently exempted from the contrast check, so a "Get started" button with charcoal text on near-black background (~2:1) read as fine to both the CLI and the browser overlay. The bail in checkColors now permits <a> and <button> when they have their own opaque background AND direct text. Inline links and bare controls keep skipping. checkElementColorsDOM no longer short-circuits before reaching checkColors so the exception fires on the browser path. Adds readOwnBackgroundColor() helper to handle jsdom's missing shorthand decomposition; falls back to parsing the inline style attr when getComputedStyle returns empty (real browsers always decompose, so the fallback is a no-op there). Fixture gains four cases: pill-style <a> low-contrast (flag), <button> low-contrast (flag), inline <a> with no own bg (pass), pill-style <a> with high contrast (pass). Three new tests assert the right flags fire and the no-regression cases stay clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
d154a5feb3 |
fix(extension): popup scan stuck on Scanning after page reload (v1.0.2)
The service worker's webNavigation.onCompleted handler only cleared csInjected when DevTools was open. The popup-only flow never registered the tab in devtoolsTabs, so a page reload left a stale csInjected: true even though the content script had been destroyed. The next popup scan saw the stale flag, skipped re-injection, and silently sent its scan request to a tab with no listener — popup UI got stuck on "Scanning..." indefinitely. Reset is now unconditional (page reload always destroys the content script regardless of which UI is open). Auto-rescan stays gated to DevTools, since the popup is strictly user-driven. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
04709eadf0 |
security: use JSON.stringify for selector escaping in devtools panel (#93)
The inspectElement function previously used manual replace() chains to escape backslashes and single quotes in CSS selectors before passing them to chrome.devtools.inspectedWindow.eval(). This escaping was incomplete: selectors containing crafted sequences of special characters (backticks, newlines, Unicode escapes) could break out of the string literal and inject arbitrary JS into the inspected page context. JSON.stringify produces a properly escaped JS string literal that handles all special characters, eliminating the injection surface entirely. |
||
|
|
00d485659a |
Fix false positives: bg-black opacity modifiers and background-image contrast
Two detector bugs that produced false positives on sites like uselinkshot.com: 1. The bg-black regex matched Tailwind opacity modifiers (bg-black/3, hover:bg-black/5) because / is a word boundary. Added negative lookahead. 2. resolveBackground ignored url() background-images, walking past them to the body's white bg. White text on a dark hero image was flagged as 1.0:1 white-on-white. Now bails on url() images like it does for gradients. Also: extension build auto-generates dist/extension.zip, version bumps for CLI (2.1.7) and extension (1.0.1). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
092e4a9e4f |
Improve copy output: URL, slash-prefixed skills, rollup, no fragment
- Renames "Page:" to "URL:" in both single and multi-finding copy formats - Strips URL fragment so the page identifier isn't an in-page anchor - Prefixes suggested skills with a slash (e.g. /arrange, /polish) so they're recognizable as Impeccable slash commands - In multi-finding output, rolls up all suggested skills into a single deduplicated, frequency-sorted footer line instead of repeating the same skill on every finding - Drops "Please fix this" prescriptive footer in favor of a neutral "Skills are suggestions, not required" note - Compacts each multi-finding line to single-line format Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
13b2f763d9 |
Polish Chrome extension for Web Store submission
Refactors the extension for on-demand injection (no static content_scripts entry — content script and detector are loaded only when the user actively opens the Impeccable panel, sidebar pane, or popup). Adds a new "Auto-scan" preference (default: scan when the Impeccable panel opens, opt-in: scan when DevTools opens) plus configurable line length (strict/lax) and highlight blur on/off settings. Adds an Elements panel sidebar that shows findings for the currently selected element. Includes substantial overlay UX work: page-pixel-perfect spotlight mask via clip-path, refined hover/dim states, instant transitions for snappier feel, copy buttons for findings, hover-from-panel highlighting, and a brand-aware exception list so the font check no longer flags Roboto on Google's own properties. Robustness fixes for the MV3 service worker lifecycle: heartbeat keepalive plus auto-reconnecting ports across panel/sidebar/devtools so transient SW restarts don't break the panel UI, and immediate teardown on DevTools close (replacing an unreliable setTimeout-based defer that didn't survive SW termination). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
e961d56252 |
Add Chrome DevTools extension for anti-pattern detection
Adds a Manifest V3 Chrome extension that injects the detector when DevTools opens, with a dedicated panel for browsing findings, a toolbar popup for quick scan/toggle, and per-rule settings synced via chrome.storage. Categorizes anti-patterns into AI slop vs quality issues with visual differentiation (sparkle prefix, panel grouping). Overlay labels are polished with flush positioning, cycling for multi-finding elements, and synchronized hover darkening. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |