[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-automattic-visual-polish":3,"mdc-fvbs7v-key":41,"related-org-automattic-visual-polish":929,"related-repo-automattic-visual-polish":1104},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":11,"stars":25,"repoUrl":26,"updatedAt":27,"license":28,"forks":29,"topics":30,"repo":36,"sourceUrl":39,"mdContent":40},"visual-polish","verify and polish website visual design","Verify and polish a built or redesigned site by diagnosing rendered-DOM issues against intent and fixing them in a planned, batched screenshot-and-fix loop.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},"automattic","Automattic","https:\u002F\u002Fpexgzepcugksgbtrxkhf.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Forg-logos\u002Fautomattic.png",[12,16,19,22],{"name":13,"slug":14,"type":15},"Screenshots","screenshots","tag",{"name":17,"slug":18,"type":15},"Frontend","frontend",{"name":20,"slug":21,"type":15},"Debugging","debugging",{"name":23,"slug":24,"type":15},"Visual Design","visual-design",484,"https:\u002F\u002Fgithub.com\u002FAutomattic\u002Fstudio","2026-06-06T07:09:59.809812",null,82,[31,32,33,34,35],"agents","cli","desktop","electron","wordpress",{"repoUrl":26,"stars":25,"forks":29,"topics":37,"description":38},[31,32,33,34,35],"WordPress Studio, a free desktop app and CLI that helps developers streamline their local WordPress development workflow.","https:\u002F\u002Fgithub.com\u002FAutomattic\u002Fstudio\u002Ftree\u002FHEAD\u002Fapps\u002Fcli\u002Fai\u002Fskills\u002Fvisual-polish","---\nname: visual-polish\ndescription: Verify and polish a built or redesigned site by diagnosing rendered-DOM issues against intent and fixing them in a planned, batched screenshot-and-fix loop.\nuser-invokable: true\n---\n\n# Visual Polish\n\nUse this skill to verify a built or redesigned site and fix the design issues that make generated sites feel unpolished. The generated block markup, the editor serialization fixes from `validate_blocks`, and WordPress's own injected layout classes mean the rendered page often differs from what you intended. This skill closes that gap.\n\nThe core method is **diagnose from evidence, not from memory**. Do not guess why something looks wrong from the screenshot alone — the rendered DOM usually differs from the markup you wrote. Read the real DOM with `inspect_design`, find the actual cause, then fix it.\n\n## Scope: which pages to polish, and how much\n\nPolish **every page of the site**, not just the home page. This includes all user-created pages (Home, About, Contact, and similar) and any plugin-provided pages. A page the user never sees polished feels unfinished, and plugin pages ship with generic default styling that rarely matches the theme.\n\nFor a WooCommerce shop, polish each of these pages: Shop, single-product, Cart, Checkout, and My Account.\n\nHow much to iterate depends on the page:\n\n- **Home page** — run the full loop below, including Phase 3 (re-diagnose and fix again, up to the pass cap). The home page is the highest-traffic, highest-impact page and is worth iterating until it is right.\n- **Every other page** (other user pages AND WooCommerce pages) — run a **single pass**: diagnose (Phase 1), fix the batch (Phase 2), take one verification screenshot, then move on. Do not loop these pages; a single diagnose-and-fix pass is enough.\n\n## Method: diagnose the whole page first, then fix in one batch\n\nThe most important rule: **do not fix issues one at a time as you find them.** Fixing reactively makes you miss related issues, introduce regressions, and burn expensive screenshot passes. Split the work into strict phases.\n\n### Phase 1 — Diagnose (read-only — make NO edits in this phase)\n\n1. Enumerate every section and component of the page (from the page markup you wrote, or by inspecting the top-level containers).\n2. Take one `take_screenshot` with `viewport: \"all\"` (desktop + mobile).\n3. Go **section by section**. For each, call `inspect_design` on the relevant selectors and compare the rendered DOM and computed styles against your intent and the theme's `style.css` (read it). The screenshot is the symptom; `inspect_design` is the cause — never diagnose from the screenshot alone, because subtle issues like doubled button padding barely show in pixels. Inspect even sections that look roughly right, and always inspect:\n   - every section wrapper — for width and centering,\n   - every button — BOTH `.wp-block-button` and `.wp-block-button__link`, with `includeHover: true`.\n4. List the **complete** set of issues before fixing anything — a concise checklist, one short line per issue: the section, the root cause from the DOM, and the exact fix (file, selector, change). A list, not prose.\n\nDo not make a single edit until you have diagnosed every section and listed every issue. **A complete diagnosis is the gate into Phase 2.**\n\n### Phase 2 — Fix the whole batch\n\nWork through the plan with targeted `Edit` calls (one `Write`\u002F`Edit` per turn, per the system prompt cadence — never batch files into one turn). Do **not** screenshot between edits. If an edit changes block markup (not just CSS), re-run `validate_blocks` on that file and re-check its diff, since the serializer can change classes again.\n\n### Phase 3 — Verify and loop\n\nAfter the whole batch, take one `viewport: \"all\"` screenshot. Check each plan item off and look for regressions the fixes introduced.\n\nThis looping phase applies to the **home page only** (see \"Scope\" above). For every other page — including WooCommerce pages — stop after this single verification screenshot; do not loop. For the home page, each pass is expensive, so cap the cycle at **5 passes**. If issues remain and you are within that budget, return to Phase 1 for what's left — re-diagnose the remaining issues with `inspect_design`, don't fix blind.\n\n## Recurring issues and what to inspect\n\nThe issues below are common examples, **not an exhaustive list**. Treat them as a starting checklist, not the full scope of what to look for — fix every visual problem the screenshot reveals, including ones not listed here, and apply the same method (inspect the rendered DOM, find the real cause, then fix). For each, the cause lives in the DOM — inspect, don't guess.\n\n### Section width or centering is off\n\nSymptom: a section meant to be full-width renders in the narrow content column; a section is wider\u002Fnarrower than intended; or a section's content sits off-center instead of centered.\n\nInspect the section wrapper. Check `boundingBox` (`x` and `width`) against `viewportWidth`, and read the `ancestors` chain plus the `margin-left`\u002F`margin-right` computed values. WordPress constrains children of constrained-layout containers via `.is-layout-constrained > *:not(.alignfull):not(.alignwide)` (~700px), which custom CSS like `width: 100%` cannot override — and a constrained layout is also what centers inner content (via auto inline margins). For a full-width section with centered content, the outer group needs `{\"align\":\"full\",\"layout\":{\"type\":\"constrained\"}}`. When width or centering is wrong, the cause is the `align`\u002F`layout` on the block markup (or custom margins\u002Fwidths fighting the layout) — fix it in the markup, not by forcing width or margins in CSS.\n\n### Button styling is doubled or on the wrong element\n\nSymptom: a button looks too big (doubled padding), its background\u002Fborder\u002Fradius is wrong, or it has two conflicting hover effects.\n\nThe button block is **two nested elements**: the `.wp-block-button` wrapper and, inside it, the `.wp-block-button__link` — the actual `\u003Ca>`\u002F`\u003Cbutton>`, also carrying `.wp-element-button`. WordPress core applies the button's padding, background, border, and radius to the inner `.wp-block-button__link` \u002F `.wp-element-button`, NOT the wrapper. Your CSS must target that same inner element so it **overrides** the default instead of stacking a second padded box on the wrapper.\n\nThe common trap: a custom `className` on a button block lands on the **wrapper** (`.wp-block-button.your-class`), not the link. So `.your-class { padding … }` styles the wrapper, on top of WP's default padding on the inner link — doubled box. Descend to the inner element instead: `.your-class .wp-element-button`.\n\nFor **global** button styling (consistent buttons site-wide), target `.wp-element-button` in `style.css`. WordPress puts that class on the inner styled element of every button — the button block and buttons from other blocks (search, file, etc.) — so one rule covers them all and overrides cleanly.\n\nInspect BOTH selectors with `includeHover: true` and compare their computed styles:\n\n- If padding\u002Fbackground\u002Fborder is set on BOTH the wrapper and the link, the button renders with **doubled padding and looks too big** — remove that styling from the wrapper (or its custom class) and put it on `.wp-element-button` \u002F `.wp-block-button__link`.\n- There must be exactly ONE hover rule, on the inner element (`.wp-element-button:hover` or `.wp-block-button__link:hover`), never the `.wp-block-button` wrapper. If both have hover styles you get **two conflicting hover effects** — delete the wrapper hover. Use the `hover` block in the inspect output to confirm only the inner element changes.\n\n### Spacing between blocks differs from intent\n\nSymptom: gaps between paragraphs, headings, or sections are larger or smaller than the CSS suggests.\n\nVertical rhythm is owned by WordPress layout CSS, not your margins: `:where(.is-layout-flow) > * + *` applies `margin-block-start: var(--wp--style--block-gap)`. Inspect the container and the adjacent blocks — read `customProperties[\"--wp--style--block-gap\"]` and the `margin-top`\u002F`margin-bottom` computed values. If block-gap is fighting your margins, set spacing through `theme.json` `spacing.blockGap` or the block's own spacing, or override knowing that exact selector.\n\n### Backgrounds inside grids\u002Fcolumns are wrong\n\nSymptom: a column or grid cell background doesn't appear, doesn't fill the cell, or sits on the wrong element.\n\nInspect `.wp-block-column` (or the grid cell) and any inner `core\u002Fgroup` you put the background on. Check which node's `background-color`\u002F`background-image` is set and whether its `boundingBox` actually fills the cell. A background on an inner group only covers its content height; to fill the cell, the color belongs on the column\u002Fcell node. Columns are flex items — confirm `align-items`\u002Fstretch behavior matches intent.\n\n## Notes\n\n- Fix in markup or `style.css` per the `block-content` skill rules — no inline styles, no custom stylesheets, no custom classes on inner DOM elements.\n- The site must be running for `take_screenshot` and `inspect_design`.\n",{"data":42,"body":44},{"name":4,"description":6,"user-invokable":43},true,{"type":45,"children":46},"root",[47,55,70,91,98,110,115,120,152,158,170,177,290,300,306,348,354,366,392,398,410,416,421,519,525,530,600,642,668,680,750,756,761,821,827,832,883,889],{"type":48,"tag":49,"props":50,"children":51},"element","h1",{"id":4},[52],{"type":53,"value":54},"text","Visual Polish",{"type":48,"tag":56,"props":57,"children":58},"p",{},[59,61,68],{"type":53,"value":60},"Use this skill to verify a built or redesigned site and fix the design issues that make generated sites feel unpolished. The generated block markup, the editor serialization fixes from ",{"type":48,"tag":62,"props":63,"children":65},"code",{"className":64},[],[66],{"type":53,"value":67},"validate_blocks",{"type":53,"value":69},", and WordPress's own injected layout classes mean the rendered page often differs from what you intended. This skill closes that gap.",{"type":48,"tag":56,"props":71,"children":72},{},[73,75,81,83,89],{"type":53,"value":74},"The core method is ",{"type":48,"tag":76,"props":77,"children":78},"strong",{},[79],{"type":53,"value":80},"diagnose from evidence, not from memory",{"type":53,"value":82},". Do not guess why something looks wrong from the screenshot alone — the rendered DOM usually differs from the markup you wrote. Read the real DOM with ",{"type":48,"tag":62,"props":84,"children":86},{"className":85},[],[87],{"type":53,"value":88},"inspect_design",{"type":53,"value":90},", find the actual cause, then fix it.",{"type":48,"tag":92,"props":93,"children":95},"h2",{"id":94},"scope-which-pages-to-polish-and-how-much",[96],{"type":53,"value":97},"Scope: which pages to polish, and how much",{"type":48,"tag":56,"props":99,"children":100},{},[101,103,108],{"type":53,"value":102},"Polish ",{"type":48,"tag":76,"props":104,"children":105},{},[106],{"type":53,"value":107},"every page of the site",{"type":53,"value":109},", not just the home page. This includes all user-created pages (Home, About, Contact, and similar) and any plugin-provided pages. A page the user never sees polished feels unfinished, and plugin pages ship with generic default styling that rarely matches the theme.",{"type":48,"tag":56,"props":111,"children":112},{},[113],{"type":53,"value":114},"For a WooCommerce shop, polish each of these pages: Shop, single-product, Cart, Checkout, and My Account.",{"type":48,"tag":56,"props":116,"children":117},{},[118],{"type":53,"value":119},"How much to iterate depends on the page:",{"type":48,"tag":121,"props":122,"children":123},"ul",{},[124,135],{"type":48,"tag":125,"props":126,"children":127},"li",{},[128,133],{"type":48,"tag":76,"props":129,"children":130},{},[131],{"type":53,"value":132},"Home page",{"type":53,"value":134}," — run the full loop below, including Phase 3 (re-diagnose and fix again, up to the pass cap). The home page is the highest-traffic, highest-impact page and is worth iterating until it is right.",{"type":48,"tag":125,"props":136,"children":137},{},[138,143,145,150],{"type":48,"tag":76,"props":139,"children":140},{},[141],{"type":53,"value":142},"Every other page",{"type":53,"value":144}," (other user pages AND WooCommerce pages) — run a ",{"type":48,"tag":76,"props":146,"children":147},{},[148],{"type":53,"value":149},"single pass",{"type":53,"value":151},": diagnose (Phase 1), fix the batch (Phase 2), take one verification screenshot, then move on. Do not loop these pages; a single diagnose-and-fix pass is enough.",{"type":48,"tag":92,"props":153,"children":155},{"id":154},"method-diagnose-the-whole-page-first-then-fix-in-one-batch",[156],{"type":53,"value":157},"Method: diagnose the whole page first, then fix in one batch",{"type":48,"tag":56,"props":159,"children":160},{},[161,163,168],{"type":53,"value":162},"The most important rule: ",{"type":48,"tag":76,"props":164,"children":165},{},[166],{"type":53,"value":167},"do not fix issues one at a time as you find them.",{"type":53,"value":169}," Fixing reactively makes you miss related issues, introduce regressions, and burn expensive screenshot passes. Split the work into strict phases.",{"type":48,"tag":171,"props":172,"children":174},"h3",{"id":173},"phase-1-diagnose-read-only-make-no-edits-in-this-phase",[175],{"type":53,"value":176},"Phase 1 — Diagnose (read-only — make NO edits in this phase)",{"type":48,"tag":178,"props":179,"children":180},"ol",{},[181,186,207,278],{"type":48,"tag":125,"props":182,"children":183},{},[184],{"type":53,"value":185},"Enumerate every section and component of the page (from the page markup you wrote, or by inspecting the top-level containers).",{"type":48,"tag":125,"props":187,"children":188},{},[189,191,197,199,205],{"type":53,"value":190},"Take one ",{"type":48,"tag":62,"props":192,"children":194},{"className":193},[],[195],{"type":53,"value":196},"take_screenshot",{"type":53,"value":198}," with ",{"type":48,"tag":62,"props":200,"children":202},{"className":201},[],[203],{"type":53,"value":204},"viewport: \"all\"",{"type":53,"value":206}," (desktop + mobile).",{"type":48,"tag":125,"props":208,"children":209},{},[210,212,217,219,224,226,232,234,239,241],{"type":53,"value":211},"Go ",{"type":48,"tag":76,"props":213,"children":214},{},[215],{"type":53,"value":216},"section by section",{"type":53,"value":218},". For each, call ",{"type":48,"tag":62,"props":220,"children":222},{"className":221},[],[223],{"type":53,"value":88},{"type":53,"value":225}," on the relevant selectors and compare the rendered DOM and computed styles against your intent and the theme's ",{"type":48,"tag":62,"props":227,"children":229},{"className":228},[],[230],{"type":53,"value":231},"style.css",{"type":53,"value":233}," (read it). The screenshot is the symptom; ",{"type":48,"tag":62,"props":235,"children":237},{"className":236},[],[238],{"type":53,"value":88},{"type":53,"value":240}," is the cause — never diagnose from the screenshot alone, because subtle issues like doubled button padding barely show in pixels. Inspect even sections that look roughly right, and always inspect:\n",{"type":48,"tag":121,"props":242,"children":243},{},[244,249],{"type":48,"tag":125,"props":245,"children":246},{},[247],{"type":53,"value":248},"every section wrapper — for width and centering,",{"type":48,"tag":125,"props":250,"children":251},{},[252,254,260,262,268,270,276],{"type":53,"value":253},"every button — BOTH ",{"type":48,"tag":62,"props":255,"children":257},{"className":256},[],[258],{"type":53,"value":259},".wp-block-button",{"type":53,"value":261}," and ",{"type":48,"tag":62,"props":263,"children":265},{"className":264},[],[266],{"type":53,"value":267},".wp-block-button__link",{"type":53,"value":269},", with ",{"type":48,"tag":62,"props":271,"children":273},{"className":272},[],[274],{"type":53,"value":275},"includeHover: true",{"type":53,"value":277},".",{"type":48,"tag":125,"props":279,"children":280},{},[281,283,288],{"type":53,"value":282},"List the ",{"type":48,"tag":76,"props":284,"children":285},{},[286],{"type":53,"value":287},"complete",{"type":53,"value":289}," set of issues before fixing anything — a concise checklist, one short line per issue: the section, the root cause from the DOM, and the exact fix (file, selector, change). A list, not prose.",{"type":48,"tag":56,"props":291,"children":292},{},[293,295],{"type":53,"value":294},"Do not make a single edit until you have diagnosed every section and listed every issue. ",{"type":48,"tag":76,"props":296,"children":297},{},[298],{"type":53,"value":299},"A complete diagnosis is the gate into Phase 2.",{"type":48,"tag":171,"props":301,"children":303},{"id":302},"phase-2-fix-the-whole-batch",[304],{"type":53,"value":305},"Phase 2 — Fix the whole batch",{"type":48,"tag":56,"props":307,"children":308},{},[309,311,317,319,325,327,332,334,339,341,346],{"type":53,"value":310},"Work through the plan with targeted ",{"type":48,"tag":62,"props":312,"children":314},{"className":313},[],[315],{"type":53,"value":316},"Edit",{"type":53,"value":318}," calls (one ",{"type":48,"tag":62,"props":320,"children":322},{"className":321},[],[323],{"type":53,"value":324},"Write",{"type":53,"value":326},"\u002F",{"type":48,"tag":62,"props":328,"children":330},{"className":329},[],[331],{"type":53,"value":316},{"type":53,"value":333}," per turn, per the system prompt cadence — never batch files into one turn). Do ",{"type":48,"tag":76,"props":335,"children":336},{},[337],{"type":53,"value":338},"not",{"type":53,"value":340}," screenshot between edits. If an edit changes block markup (not just CSS), re-run ",{"type":48,"tag":62,"props":342,"children":344},{"className":343},[],[345],{"type":53,"value":67},{"type":53,"value":347}," on that file and re-check its diff, since the serializer can change classes again.",{"type":48,"tag":171,"props":349,"children":351},{"id":350},"phase-3-verify-and-loop",[352],{"type":53,"value":353},"Phase 3 — Verify and loop",{"type":48,"tag":56,"props":355,"children":356},{},[357,359,364],{"type":53,"value":358},"After the whole batch, take one ",{"type":48,"tag":62,"props":360,"children":362},{"className":361},[],[363],{"type":53,"value":204},{"type":53,"value":365}," screenshot. Check each plan item off and look for regressions the fixes introduced.",{"type":48,"tag":56,"props":367,"children":368},{},[369,371,376,378,383,385,390],{"type":53,"value":370},"This looping phase applies to the ",{"type":48,"tag":76,"props":372,"children":373},{},[374],{"type":53,"value":375},"home page only",{"type":53,"value":377}," (see \"Scope\" above). For every other page — including WooCommerce pages — stop after this single verification screenshot; do not loop. For the home page, each pass is expensive, so cap the cycle at ",{"type":48,"tag":76,"props":379,"children":380},{},[381],{"type":53,"value":382},"5 passes",{"type":53,"value":384},". If issues remain and you are within that budget, return to Phase 1 for what's left — re-diagnose the remaining issues with ",{"type":48,"tag":62,"props":386,"children":388},{"className":387},[],[389],{"type":53,"value":88},{"type":53,"value":391},", don't fix blind.",{"type":48,"tag":92,"props":393,"children":395},{"id":394},"recurring-issues-and-what-to-inspect",[396],{"type":53,"value":397},"Recurring issues and what to inspect",{"type":48,"tag":56,"props":399,"children":400},{},[401,403,408],{"type":53,"value":402},"The issues below are common examples, ",{"type":48,"tag":76,"props":404,"children":405},{},[406],{"type":53,"value":407},"not an exhaustive list",{"type":53,"value":409},". Treat them as a starting checklist, not the full scope of what to look for — fix every visual problem the screenshot reveals, including ones not listed here, and apply the same method (inspect the rendered DOM, find the real cause, then fix). For each, the cause lives in the DOM — inspect, don't guess.",{"type":48,"tag":171,"props":411,"children":413},{"id":412},"section-width-or-centering-is-off",[414],{"type":53,"value":415},"Section width or centering is off",{"type":48,"tag":56,"props":417,"children":418},{},[419],{"type":53,"value":420},"Symptom: a section meant to be full-width renders in the narrow content column; a section is wider\u002Fnarrower than intended; or a section's content sits off-center instead of centered.",{"type":48,"tag":56,"props":422,"children":423},{},[424,426,432,434,440,441,447,449,455,457,463,465,471,472,478,480,486,488,494,496,502,504,510,511,517],{"type":53,"value":425},"Inspect the section wrapper. Check ",{"type":48,"tag":62,"props":427,"children":429},{"className":428},[],[430],{"type":53,"value":431},"boundingBox",{"type":53,"value":433}," (",{"type":48,"tag":62,"props":435,"children":437},{"className":436},[],[438],{"type":53,"value":439},"x",{"type":53,"value":261},{"type":48,"tag":62,"props":442,"children":444},{"className":443},[],[445],{"type":53,"value":446},"width",{"type":53,"value":448},") against ",{"type":48,"tag":62,"props":450,"children":452},{"className":451},[],[453],{"type":53,"value":454},"viewportWidth",{"type":53,"value":456},", and read the ",{"type":48,"tag":62,"props":458,"children":460},{"className":459},[],[461],{"type":53,"value":462},"ancestors",{"type":53,"value":464}," chain plus the ",{"type":48,"tag":62,"props":466,"children":468},{"className":467},[],[469],{"type":53,"value":470},"margin-left",{"type":53,"value":326},{"type":48,"tag":62,"props":473,"children":475},{"className":474},[],[476],{"type":53,"value":477},"margin-right",{"type":53,"value":479}," computed values. WordPress constrains children of constrained-layout containers via ",{"type":48,"tag":62,"props":481,"children":483},{"className":482},[],[484],{"type":53,"value":485},".is-layout-constrained > *:not(.alignfull):not(.alignwide)",{"type":53,"value":487}," (~700px), which custom CSS like ",{"type":48,"tag":62,"props":489,"children":491},{"className":490},[],[492],{"type":53,"value":493},"width: 100%",{"type":53,"value":495}," cannot override — and a constrained layout is also what centers inner content (via auto inline margins). For a full-width section with centered content, the outer group needs ",{"type":48,"tag":62,"props":497,"children":499},{"className":498},[],[500],{"type":53,"value":501},"{\"align\":\"full\",\"layout\":{\"type\":\"constrained\"}}",{"type":53,"value":503},". When width or centering is wrong, the cause is the ",{"type":48,"tag":62,"props":505,"children":507},{"className":506},[],[508],{"type":53,"value":509},"align",{"type":53,"value":326},{"type":48,"tag":62,"props":512,"children":514},{"className":513},[],[515],{"type":53,"value":516},"layout",{"type":53,"value":518}," on the block markup (or custom margins\u002Fwidths fighting the layout) — fix it in the markup, not by forcing width or margins in CSS.",{"type":48,"tag":171,"props":520,"children":522},{"id":521},"button-styling-is-doubled-or-on-the-wrong-element",[523],{"type":53,"value":524},"Button styling is doubled or on the wrong element",{"type":48,"tag":56,"props":526,"children":527},{},[528],{"type":53,"value":529},"Symptom: a button looks too big (doubled padding), its background\u002Fborder\u002Fradius is wrong, or it has two conflicting hover effects.",{"type":48,"tag":56,"props":531,"children":532},{},[533,535,540,542,547,549,554,556,562,563,569,571,577,579,584,586,591,593,598],{"type":53,"value":534},"The button block is ",{"type":48,"tag":76,"props":536,"children":537},{},[538],{"type":53,"value":539},"two nested elements",{"type":53,"value":541},": the ",{"type":48,"tag":62,"props":543,"children":545},{"className":544},[],[546],{"type":53,"value":259},{"type":53,"value":548}," wrapper and, inside it, the ",{"type":48,"tag":62,"props":550,"children":552},{"className":551},[],[553],{"type":53,"value":267},{"type":53,"value":555}," — the actual ",{"type":48,"tag":62,"props":557,"children":559},{"className":558},[],[560],{"type":53,"value":561},"\u003Ca>",{"type":53,"value":326},{"type":48,"tag":62,"props":564,"children":566},{"className":565},[],[567],{"type":53,"value":568},"\u003Cbutton>",{"type":53,"value":570},", also carrying ",{"type":48,"tag":62,"props":572,"children":574},{"className":573},[],[575],{"type":53,"value":576},".wp-element-button",{"type":53,"value":578},". WordPress core applies the button's padding, background, border, and radius to the inner ",{"type":48,"tag":62,"props":580,"children":582},{"className":581},[],[583],{"type":53,"value":267},{"type":53,"value":585}," \u002F ",{"type":48,"tag":62,"props":587,"children":589},{"className":588},[],[590],{"type":53,"value":576},{"type":53,"value":592},", NOT the wrapper. Your CSS must target that same inner element so it ",{"type":48,"tag":76,"props":594,"children":595},{},[596],{"type":53,"value":597},"overrides",{"type":53,"value":599}," the default instead of stacking a second padded box on the wrapper.",{"type":48,"tag":56,"props":601,"children":602},{},[603,605,611,613,618,619,625,627,633,635,641],{"type":53,"value":604},"The common trap: a custom ",{"type":48,"tag":62,"props":606,"children":608},{"className":607},[],[609],{"type":53,"value":610},"className",{"type":53,"value":612}," on a button block lands on the ",{"type":48,"tag":76,"props":614,"children":615},{},[616],{"type":53,"value":617},"wrapper",{"type":53,"value":433},{"type":48,"tag":62,"props":620,"children":622},{"className":621},[],[623],{"type":53,"value":624},".wp-block-button.your-class",{"type":53,"value":626},"), not the link. So ",{"type":48,"tag":62,"props":628,"children":630},{"className":629},[],[631],{"type":53,"value":632},".your-class { padding … }",{"type":53,"value":634}," styles the wrapper, on top of WP's default padding on the inner link — doubled box. Descend to the inner element instead: ",{"type":48,"tag":62,"props":636,"children":638},{"className":637},[],[639],{"type":53,"value":640},".your-class .wp-element-button",{"type":53,"value":277},{"type":48,"tag":56,"props":643,"children":644},{},[645,647,652,654,659,661,666],{"type":53,"value":646},"For ",{"type":48,"tag":76,"props":648,"children":649},{},[650],{"type":53,"value":651},"global",{"type":53,"value":653}," button styling (consistent buttons site-wide), target ",{"type":48,"tag":62,"props":655,"children":657},{"className":656},[],[658],{"type":53,"value":576},{"type":53,"value":660}," in ",{"type":48,"tag":62,"props":662,"children":664},{"className":663},[],[665],{"type":53,"value":231},{"type":53,"value":667},". WordPress puts that class on the inner styled element of every button — the button block and buttons from other blocks (search, file, etc.) — so one rule covers them all and overrides cleanly.",{"type":48,"tag":56,"props":669,"children":670},{},[671,673,678],{"type":53,"value":672},"Inspect BOTH selectors with ",{"type":48,"tag":62,"props":674,"children":676},{"className":675},[],[677],{"type":53,"value":275},{"type":53,"value":679}," and compare their computed styles:",{"type":48,"tag":121,"props":681,"children":682},{},[683,707],{"type":48,"tag":125,"props":684,"children":685},{},[686,688,693,695,700,701,706],{"type":53,"value":687},"If padding\u002Fbackground\u002Fborder is set on BOTH the wrapper and the link, the button renders with ",{"type":48,"tag":76,"props":689,"children":690},{},[691],{"type":53,"value":692},"doubled padding and looks too big",{"type":53,"value":694}," — remove that styling from the wrapper (or its custom class) and put it on ",{"type":48,"tag":62,"props":696,"children":698},{"className":697},[],[699],{"type":53,"value":576},{"type":53,"value":585},{"type":48,"tag":62,"props":702,"children":704},{"className":703},[],[705],{"type":53,"value":267},{"type":53,"value":277},{"type":48,"tag":125,"props":708,"children":709},{},[710,712,718,720,726,728,733,735,740,742,748],{"type":53,"value":711},"There must be exactly ONE hover rule, on the inner element (",{"type":48,"tag":62,"props":713,"children":715},{"className":714},[],[716],{"type":53,"value":717},".wp-element-button:hover",{"type":53,"value":719}," or ",{"type":48,"tag":62,"props":721,"children":723},{"className":722},[],[724],{"type":53,"value":725},".wp-block-button__link:hover",{"type":53,"value":727},"), never the ",{"type":48,"tag":62,"props":729,"children":731},{"className":730},[],[732],{"type":53,"value":259},{"type":53,"value":734}," wrapper. If both have hover styles you get ",{"type":48,"tag":76,"props":736,"children":737},{},[738],{"type":53,"value":739},"two conflicting hover effects",{"type":53,"value":741}," — delete the wrapper hover. Use the ",{"type":48,"tag":62,"props":743,"children":745},{"className":744},[],[746],{"type":53,"value":747},"hover",{"type":53,"value":749}," block in the inspect output to confirm only the inner element changes.",{"type":48,"tag":171,"props":751,"children":753},{"id":752},"spacing-between-blocks-differs-from-intent",[754],{"type":53,"value":755},"Spacing between blocks differs from intent",{"type":48,"tag":56,"props":757,"children":758},{},[759],{"type":53,"value":760},"Symptom: gaps between paragraphs, headings, or sections are larger or smaller than the CSS suggests.",{"type":48,"tag":56,"props":762,"children":763},{},[764,766,772,774,780,782,788,790,796,797,803,805,811,813,819],{"type":53,"value":765},"Vertical rhythm is owned by WordPress layout CSS, not your margins: ",{"type":48,"tag":62,"props":767,"children":769},{"className":768},[],[770],{"type":53,"value":771},":where(.is-layout-flow) > * + *",{"type":53,"value":773}," applies ",{"type":48,"tag":62,"props":775,"children":777},{"className":776},[],[778],{"type":53,"value":779},"margin-block-start: var(--wp--style--block-gap)",{"type":53,"value":781},". Inspect the container and the adjacent blocks — read ",{"type":48,"tag":62,"props":783,"children":785},{"className":784},[],[786],{"type":53,"value":787},"customProperties[\"--wp--style--block-gap\"]",{"type":53,"value":789}," and the ",{"type":48,"tag":62,"props":791,"children":793},{"className":792},[],[794],{"type":53,"value":795},"margin-top",{"type":53,"value":326},{"type":48,"tag":62,"props":798,"children":800},{"className":799},[],[801],{"type":53,"value":802},"margin-bottom",{"type":53,"value":804}," computed values. If block-gap is fighting your margins, set spacing through ",{"type":48,"tag":62,"props":806,"children":808},{"className":807},[],[809],{"type":53,"value":810},"theme.json",{"type":53,"value":812}," ",{"type":48,"tag":62,"props":814,"children":816},{"className":815},[],[817],{"type":53,"value":818},"spacing.blockGap",{"type":53,"value":820}," or the block's own spacing, or override knowing that exact selector.",{"type":48,"tag":171,"props":822,"children":824},{"id":823},"backgrounds-inside-gridscolumns-are-wrong",[825],{"type":53,"value":826},"Backgrounds inside grids\u002Fcolumns are wrong",{"type":48,"tag":56,"props":828,"children":829},{},[830],{"type":53,"value":831},"Symptom: a column or grid cell background doesn't appear, doesn't fill the cell, or sits on the wrong element.",{"type":48,"tag":56,"props":833,"children":834},{},[835,837,843,845,851,853,859,860,866,868,873,875,881],{"type":53,"value":836},"Inspect ",{"type":48,"tag":62,"props":838,"children":840},{"className":839},[],[841],{"type":53,"value":842},".wp-block-column",{"type":53,"value":844}," (or the grid cell) and any inner ",{"type":48,"tag":62,"props":846,"children":848},{"className":847},[],[849],{"type":53,"value":850},"core\u002Fgroup",{"type":53,"value":852}," you put the background on. Check which node's ",{"type":48,"tag":62,"props":854,"children":856},{"className":855},[],[857],{"type":53,"value":858},"background-color",{"type":53,"value":326},{"type":48,"tag":62,"props":861,"children":863},{"className":862},[],[864],{"type":53,"value":865},"background-image",{"type":53,"value":867}," is set and whether its ",{"type":48,"tag":62,"props":869,"children":871},{"className":870},[],[872],{"type":53,"value":431},{"type":53,"value":874}," actually fills the cell. A background on an inner group only covers its content height; to fill the cell, the color belongs on the column\u002Fcell node. Columns are flex items — confirm ",{"type":48,"tag":62,"props":876,"children":878},{"className":877},[],[879],{"type":53,"value":880},"align-items",{"type":53,"value":882},"\u002Fstretch behavior matches intent.",{"type":48,"tag":92,"props":884,"children":886},{"id":885},"notes",[887],{"type":53,"value":888},"Notes",{"type":48,"tag":121,"props":890,"children":891},{},[892,912],{"type":48,"tag":125,"props":893,"children":894},{},[895,897,902,904,910],{"type":53,"value":896},"Fix in markup or ",{"type":48,"tag":62,"props":898,"children":900},{"className":899},[],[901],{"type":53,"value":231},{"type":53,"value":903}," per the ",{"type":48,"tag":62,"props":905,"children":907},{"className":906},[],[908],{"type":53,"value":909},"block-content",{"type":53,"value":911}," skill rules — no inline styles, no custom stylesheets, no custom classes on inner DOM elements.",{"type":48,"tag":125,"props":913,"children":914},{},[915,917,922,923,928],{"type":53,"value":916},"The site must be running for ",{"type":48,"tag":62,"props":918,"children":920},{"className":919},[],[921],{"type":53,"value":196},{"type":53,"value":261},{"type":48,"tag":62,"props":924,"children":926},{"className":925},[],[927],{"type":53,"value":88},{"type":53,"value":277},{"items":930,"total":1103},[931,948,965,979,996,1011,1025,1040,1057,1067,1082,1096],{"slug":932,"name":932,"fn":933,"description":934,"org":935,"tags":936,"stars":25,"repoUrl":26,"updatedAt":947},"annotate","collect visual feedback with browser annotation tools","Open a browser with visual annotation tools. The user clicks elements on their site and leaves feedback — the agent reads annotations and makes changes. Use this when the user wants to point at specific elements to fix, tweak, or redesign.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[937,938,941,944],{"name":17,"slug":18,"type":15},{"name":939,"slug":940,"type":15},"Productivity","productivity",{"name":942,"slug":943,"type":15},"UX Copy","ux-copy",{"name":945,"slug":946,"type":15},"UX Design","ux-design","2026-05-06T05:40:01.516544",{"slug":909,"name":909,"fn":949,"description":950,"org":951,"tags":952,"stars":25,"repoUrl":26,"updatedAt":964},"write editable WordPress block markup","Write editable WordPress block markup for local Studio sites, including core\u002Fhtml limits, block-theme layout rules, full-width sections, validation, and skeleton-first page\u002FCSS recipes.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[953,956,959,962],{"name":954,"slug":955,"type":15},"Block Editor","block-editor",{"name":957,"slug":958,"type":15},"CSS","css",{"name":960,"slug":961,"type":15},"HTML","html",{"name":963,"slug":35,"type":15},"WordPress","2026-05-27T07:01:55.629681",{"slug":966,"name":966,"fn":967,"description":968,"org":969,"tags":970,"stars":25,"repoUrl":26,"updatedAt":978},"hosting-plans-helper","provide WordPress.com hosting plan information","Answer WordPress.com plan, pricing, upgrade, and feature-tier questions (plan names, what each tier unlocks — plugins, themes, custom code, SSH, hosting — and current prices) from authoritative live data. Load before answering ANY plan, pricing, or feature-gating question; never answer these from memory.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[971,974,977],{"name":972,"slug":973,"type":15},"Pricing","pricing",{"name":975,"slug":976,"type":15},"Reference","reference",{"name":963,"slug":35,"type":15},"2026-07-02T07:42:33.654791",{"slug":980,"name":980,"fn":981,"description":982,"org":983,"tags":984,"stars":25,"repoUrl":26,"updatedAt":995},"liberate","migrate websites to WordPress","Import and rebuild a website from a closed platform (Wix, Squarespace, Webflow, Shopify, GoDaddy, Hostinger, HubSpot, Weebly) into a Studio WordPress site. Extracts pages\u002Fposts\u002Fproducts + media, then reconstructs the design as editable blocks + WooCommerce OR as a high-fidelity replica theme. Invoke when the user wants to migrate, import, liberate, or rebuild a site from one of these platforms.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[985,988,991,994],{"name":986,"slug":987,"type":15},"CMS","cms",{"name":989,"slug":990,"type":15},"Migration","migration",{"name":992,"slug":993,"type":15},"Web Development","web-development",{"name":963,"slug":35,"type":15},"2026-07-09T06:47:33.454311",{"slug":997,"name":997,"fn":998,"description":999,"org":1000,"tags":1001,"stars":25,"repoUrl":26,"updatedAt":1010},"need-for-speed","run frontend performance audits for WordPress sites","Run a frontend performance audit on a WordPress site and get actionable optimization recommendations.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1002,1005,1006,1009],{"name":1003,"slug":1004,"type":15},"Audit","audit",{"name":17,"slug":18,"type":15},{"name":1007,"slug":1008,"type":15},"Performance","performance",{"name":963,"slug":35,"type":15},"2026-05-06T05:40:06.433267",{"slug":1012,"name":1012,"fn":1013,"description":1014,"org":1015,"tags":1016,"stars":25,"repoUrl":26,"updatedAt":1024},"plugin-recommendations","recommend WordPress plugins for site features","Choose recommended plugins and plugin-provided blocks for features core WordPress blocks do not cover - ecommerce (WooCommerce), forms and newsletters (Jetpack), online courses and quizzes (Sensei LMS), polls, surveys and ratings (Crowdsignal), spam protection (Akismet) - while keeping generated content editable and avoiding raw HTML fallbacks. Any request to sell products or build a shop, store, or storefront requires WooCommerce with products.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1017,1020,1023],{"name":1018,"slug":1019,"type":15},"Content Creation","content-creation",{"name":1021,"slug":1022,"type":15},"Plugin Development","plugin-development",{"name":963,"slug":35,"type":15},"2026-05-27T07:01:58.249105",{"slug":1026,"name":1026,"fn":1027,"description":1028,"org":1029,"tags":1030,"stars":25,"repoUrl":26,"updatedAt":1039},"rank-me-up","run on-page SEO audits for WordPress sites","Run an on-page SEO audit on a WordPress site and get actionable recommendations to improve search visibility.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1031,1032,1035,1038],{"name":1003,"slug":1004,"type":15},{"name":1033,"slug":1034,"type":15},"Marketing","marketing",{"name":1036,"slug":1037,"type":15},"SEO","seo",{"name":963,"slug":35,"type":15},"2026-05-06T05:40:05.196367",{"slug":1041,"name":1041,"fn":1042,"description":1043,"org":1044,"tags":1045,"stars":25,"repoUrl":26,"updatedAt":1056},"site-spec","gather specifications for new WordPress sites","Gather the site name and layout preference before building a WordPress site. Run this before creating any new site.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1046,1049,1052,1055],{"name":1047,"slug":1048,"type":15},"Design","design",{"name":1050,"slug":1051,"type":15},"Product Management","product-management",{"name":1053,"slug":1054,"type":15},"Specs","specs",{"name":963,"slug":35,"type":15},"2026-05-06T05:40:02.739409",{"slug":1058,"name":1058,"fn":1059,"description":1060,"org":1061,"tags":1062,"stars":25,"repoUrl":26,"updatedAt":1066},"studio-cli","manage local WordPress sites with Studio CLI","Use the Studio CLI to manage local WordPress sites, authentication, and preview sites. Invoke this skill when you need to run Studio CLI commands, manage sites, or troubleshoot site issues.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1063,1065],{"name":1064,"slug":32,"type":15},"CLI",{"name":963,"slug":35,"type":15},"2026-04-06T18:02:57.150231",{"slug":1068,"name":1068,"fn":1069,"description":1070,"org":1071,"tags":1072,"stars":25,"repoUrl":26,"updatedAt":1081},"taxonomist","optimize WordPress category taxonomy","Analyze and optimize a WordPress site's category taxonomy. Exports all posts, uses AI to suggest an improved category structure — merging duplicates, retiring dead categories, creating missing ones, writing descriptions, and re-categorizing posts. Run this when the user wants to clean up or improve their categories.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1073,1076,1079,1080],{"name":1074,"slug":1075,"type":15},"Content Strategy","content-strategy",{"name":1077,"slug":1078,"type":15},"Data Cleaning","data-cleaning",{"name":1036,"slug":1037,"type":15},{"name":963,"slug":35,"type":15},"2026-05-06T05:40:03.966799",{"slug":24,"name":24,"fn":1083,"description":1084,"org":1085,"tags":1086,"stars":25,"repoUrl":26,"updatedAt":1095},"plan and execute visual design direction","Plan and execute high-quality visual direction for site creation, redesign, layout, typography, color, motion, and visual polish.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1087,1090,1091,1094],{"name":1088,"slug":1089,"type":15},"Animation","animation",{"name":1047,"slug":1048,"type":15},{"name":1092,"slug":1093,"type":15},"Typography","typography",{"name":23,"slug":24,"type":15},"2026-07-24T05:40:57.887452",{"slug":4,"name":4,"fn":5,"description":6,"org":1097,"tags":1098,"stars":25,"repoUrl":26,"updatedAt":27},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1099,1100,1101,1102],{"name":20,"slug":21,"type":15},{"name":17,"slug":18,"type":15},{"name":13,"slug":14,"type":15},{"name":23,"slug":24,"type":15},81,{"items":1105,"total":1153},[1106,1113,1120,1126,1133,1140,1146],{"slug":932,"name":932,"fn":933,"description":934,"org":1107,"tags":1108,"stars":25,"repoUrl":26,"updatedAt":947},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1109,1110,1111,1112],{"name":17,"slug":18,"type":15},{"name":939,"slug":940,"type":15},{"name":942,"slug":943,"type":15},{"name":945,"slug":946,"type":15},{"slug":909,"name":909,"fn":949,"description":950,"org":1114,"tags":1115,"stars":25,"repoUrl":26,"updatedAt":964},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1116,1117,1118,1119],{"name":954,"slug":955,"type":15},{"name":957,"slug":958,"type":15},{"name":960,"slug":961,"type":15},{"name":963,"slug":35,"type":15},{"slug":966,"name":966,"fn":967,"description":968,"org":1121,"tags":1122,"stars":25,"repoUrl":26,"updatedAt":978},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1123,1124,1125],{"name":972,"slug":973,"type":15},{"name":975,"slug":976,"type":15},{"name":963,"slug":35,"type":15},{"slug":980,"name":980,"fn":981,"description":982,"org":1127,"tags":1128,"stars":25,"repoUrl":26,"updatedAt":995},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1129,1130,1131,1132],{"name":986,"slug":987,"type":15},{"name":989,"slug":990,"type":15},{"name":992,"slug":993,"type":15},{"name":963,"slug":35,"type":15},{"slug":997,"name":997,"fn":998,"description":999,"org":1134,"tags":1135,"stars":25,"repoUrl":26,"updatedAt":1010},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1136,1137,1138,1139],{"name":1003,"slug":1004,"type":15},{"name":17,"slug":18,"type":15},{"name":1007,"slug":1008,"type":15},{"name":963,"slug":35,"type":15},{"slug":1012,"name":1012,"fn":1013,"description":1014,"org":1141,"tags":1142,"stars":25,"repoUrl":26,"updatedAt":1024},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1143,1144,1145],{"name":1018,"slug":1019,"type":15},{"name":1021,"slug":1022,"type":15},{"name":963,"slug":35,"type":15},{"slug":1026,"name":1026,"fn":1027,"description":1028,"org":1147,"tags":1148,"stars":25,"repoUrl":26,"updatedAt":1039},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1149,1150,1151,1152],{"name":1003,"slug":1004,"type":15},{"name":1033,"slug":1034,"type":15},{"name":1036,"slug":1037,"type":15},{"name":963,"slug":35,"type":15},13]