IconButton: build the square from the scale; unbreak zizmor
IconButton was three fixed rems while Button had just gone fluid, so the
pair drifted apart as the viewport widened — 34px against a button that
ran 35 to 38. Its box is now written the way Button's height arrives, two
rungs of padding around one 1.15 line of the type a label would set, so
the two match exactly at every width and in every size: 25 / 35-38 /
39-43px. Nothing about the component's shape or its class changes.

The zizmor job has been failing on main since before this branch, and not
on anything zizmor found: the action now rejects `advanced-security` and
`annotations` together, and this workflow passes both. Since the job asks
for security-events: write and the comment says the SARIF is the point,
annotations is the one that goes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019yEVAE5whghEqnU1g2tuX7
change
commit af92ebb9674052736a4fef00a57a45185f7393d4
author Claude <noreply@anthropic.com>
date
parent 15f86dbf
diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml
index a5649de..06438e0 100644
--- a/.github/workflows/pages.yml
+++ b/.github/workflows/pages.yml
@@ -101,5 +101,7 @@ jobs:
           persist-credentials: false
       - uses: zizmorcore/zizmor-action@70fb788f84895a7701f5643d103d587e460b5c99 # v0.6.3
         with:
+          # The action refuses both at once: SARIF goes to the security tab,
+          # or findings are annotated inline on the diff, not both. This repo
+          # wants the security tab, so annotations stays off (its default).
           advanced-security: true # emit SARIF for the security tab.
-          annotations: true
diff --git a/_components/button.md b/_components/button.md
index 0088415..fa30668 100644
--- a/_components/button.md
+++ b/_components/button.md
@@ -43,8 +43,10 @@ space scale is fluid and the size on the wider rung would otherwise
 overtake the one on the narrower.
 
 Being fluid, a medium button runs 35–38px tall depending on the width of
-the window, a little over IconButton's fixed 34px box. The two sit close
-together in a row but do not lock to each other.
+the window. [IconButton](<%= relative_url('/components/icon-button/') %>)
+builds its square from the same two rungs, so the two are exactly the same
+height at every width and in every size — a button and an icon button in a
+toolbar line up without either being told the other's measurements.
 
 <figure class="example">
 <figcaption>Sizes</figcaption>
diff --git a/_components/icon-button.md b/_components/icon-button.md
index 4bb6f2c..83fd99c 100644
--- a/_components/icon-button.md
+++ b/_components/icon-button.md
@@ -46,6 +46,13 @@ sitting alone — `variant`/`size` mean different things for each — so
 
 ## Sizes
 
+The box is square and fluid, and it is not a number of its own: it is two
+rungs of the space scale around one line of the type a
+[Button](<%= relative_url('/components/button/') %>) of the same size would
+set. So the three sizes come out at 25px, 35–38px, and 39–43px — level with
+their Button counterparts at any window width, and still level if the scale
+is ever retuned.
+
 <figure class="example">
 <figcaption>Sizes</figcaption>
 <div>
@@ -91,7 +98,7 @@ An icon-only control almost always wants a [Tooltip](<%= relative_url('/componen
   <tbody>
     <tr><td><code>button.icon-button</code></td><td></td><td>Required base — the one class in this component, since nothing distinguishes it from Button structurally.</td></tr>
     <tr><td><code>aria-label</code></td><td>string</td><td>Required — becomes the accessible name and the native tooltip.</td></tr>
-    <tr><td><code>data-size</code></td><td><code>sm | lg</code></td><td>28 / 40px square. Omit for the default 34px.</td></tr>
+    <tr><td><code>data-size</code></td><td><code>sm | lg</code></td><td>Square, matching the Button of the same size: 25px small, 39–43px large. Omit for the default, 35–38px.</td></tr>
     <tr><td><code>data-variant</code></td><td><code>outline | accent</code></td><td>Omit for the default, transparent ghost look.</td></tr>
   </tbody>
 </table>
diff --git a/_sass/components/button.css b/_sass/components/button.css
index f260521..374eadb 100644
--- a/_sass/components/button.css
+++ b/_sass/components/button.css
@@ -129,9 +129,17 @@ button:not(.icon-button):disabled,
 /* IconButton — a square icon-only button. Always needs an aria-label; it
    becomes both the accessible name and the native tooltip. There is no
    attribute that distinguishes "a button that is only an icon" from a plain
-   Button, so this is the one sanctioned class in this file. */
+   Button, so this is the one sanctioned class in this file.
+
+   The box is not a number of its own: it is written the way Button's height
+   arrives — two rungs of padding around one 1.15 line of the label type it
+   would carry if it had a label. So the two are the same height at every
+   viewport width, and stay that way when the scale is retuned, instead of a
+   fixed square drifting away from a fluid button. */
 .icon-button {
-  --_size: 2.125rem;
+  --_pad: var(--gl-space-2xs);
+  --_line: var(--gl-step--1);
+  --_size: calc(2 * var(--_pad) + 1.15 * var(--_line));
   --_bg: transparent;
   --_fg: var(--gl-color-text-secondary);
 
@@ -153,8 +161,9 @@ button:not(.icon-button):disabled,
 .icon-button:hover:not(:disabled) { background: var(--gl-color-surface-fill); }
 .icon-button:disabled { opacity: 0.5; cursor: default; }
 
-.icon-button[data-size="sm"] { --_size: 1.75rem; }
-.icon-button[data-size="lg"] { --_size: 2.5rem; }
+/* Same two overrides Button's own sm and lg make, so the pairs stay level. */
+.icon-button[data-size="sm"] { --_pad: var(--gl-space-3xs); --_line: 0.8125rem; }
+.icon-button[data-size="lg"] { --_line: var(--gl-step-0); }
 
 /* No border on either variant — "outline" keeps its name for API
    compatibility, but reads as a raised fill instead of a bordered box. */