fix: remove all flexbox — Grid only (CLAUDE.md transgression)

I shipped display:inline-flex / display:flex across .mps-button,
.mps-button-primary, .edit-card-icon, edit-page h3 headers,
.edit-status-bar, .edit-status-pill, .edit-save-bar,
.upload-thumbnails-header, .upload-thumbnail-item, and an inline
style on the torrent_opt_in label — all violations of the project's
Grid-only rule. fox caught it. All converted:

- .mps-button / .mps-button-primary / .edit-card-icon:
  display: inline-grid; place-items: center  (was inline-flex + center)
- edit-page h3 headers (icon + title):
  display: grid; grid-template-columns: auto 1fr; align-items: center
- .edit-status-bar: text-align: right + inline-grid pills that flow/wrap
  (was flex + flex-wrap + justify-content: flex-end)
- .edit-status-pill: display: inline-grid; grid-auto-flow: column
- .edit-save-bar: display: grid; grid-template-columns: 1fr auto
- .upload-thumbnails-header: display: grid; grid-template-columns: 1fr auto
  with a max-width: 600px media query collapsing to 1fr
- .upload-thumbnail-item: display: grid; grid-auto-rows: min-content;
  align-content: space-between  (replaces the flex margin-top: auto trick
  for pinning the upload form to the bottom of the stretched cell)
- torrent_opt_in label inline style: display:grid;grid-template-columns:auto 1fr

CLAUDE.md updated: the CSS-layout rule now spells out the Grid
equivalent for every flex pattern, clarifies which alignment
properties ARE valid in grid context, and includes a dated SHAME LOG
entry for this transgression.

Tests pass (11 in target slices).
This commit is contained in:
russell@unturf.com 2026-05-11 10:44:11 -04:00
parent cec78ccd45
commit 7df421dba3
No known key found for this signature in database
3 changed files with 61 additions and 49 deletions

View file

@ -269,7 +269,20 @@ Always use `uuid_str` when you need a string copy of our identifier. Models inhe
**CRITICAL WORK ETHIC**: Our user pays significant money for development work and expects thorough, complete solutions. NEVER try to do our minimum or cut corners. When asked to implement features, provide comprehensive, production-ready implementations that consider all aspects of our request.
**CSS LAYOUT REQUIREMENTS**: This project uses CSS Grid exclusively for layout. NEVER use Flexbox (flex) for layout. Always use CSS Grid properties for positioning and alignment.
**CSS LAYOUT REQUIREMENTS — GRID ONLY, NO FLEXBOX, NO EXCEPTIONS**:
This project uses CSS Grid exclusively for layout. **NEVER** write `display: flex`, `display: inline-flex`, `flex:`, `flex-direction`, `flex-wrap`, `justify-content: flex-*`, `align-items: flex-*`, or `flex-grow/shrink/basis`. There is no situation where flexbox is acceptable.
Grid equivalents for the patterns you'd reach for flex:
- **Centering content** (one item dead-center): `display: grid; place-items: center;` (or `display: inline-grid; place-items: center;` for inline-level buttons/badges).
- **Two items, one left one right** (`justify-content: space-between`): `display: grid; grid-template-columns: 1fr auto;` (left item in the `1fr` column, right item in `auto`).
- **Row of items, right-aligned**: don't make the container a grid — set `text-align: right` (or `text-align: end`) and let inline-level children flow/wrap naturally. Or `display: grid; grid-auto-flow: column; grid-auto-columns: max-content; justify-content: end;` if you don't need wrapping.
- **Vertical stack with last item pushed to bottom** (`margin-top: auto` in flex): `display: grid; align-content: space-between;` on the container (works when the container is taller than its content, e.g. inside a `align-items: stretch` parent grid).
- **Equal-height cells in a row**: parent `display: grid; grid-template-columns: repeat(auto-fit, minmax(Npx, 1fr)); align-items: stretch;`.
- **Icon + label header**: `display: grid; grid-template-columns: auto 1fr; align-items: center; gap: var(--space-N);`.
Note: `align-items`, `justify-items`, `align-content`, `justify-content`, `place-items`, `place-content`, `gap` are all **valid in grid context** — only the `flex-*` keyword values (`flex-start`, `flex-end`) and the `flex` shorthand / `flex-direction` / `flex-wrap` / `display: flex` are forbidden. Use `start`/`end`/`center`/`stretch`/`space-between` etc. as the values.
**SHAME LOG — 2026-05-11**: agent blackops shipped `display: inline-flex` on `.mps-button` and several edit-page components (`.edit-status-bar`, `.edit-save-bar`, `.upload-thumbnails-header`, `.edit-card-icon`, h3 headers, `.mps-button-primary`) across multiple commits before fox caught it. All converted to Grid. This rule is non-negotiable; re-read it before touching any CSS.
**DESIGN TOKENS**: All new styles must consume tokens from `tokens.css` — never hardcode colors, spacing, radii, shadows, or font sizes. Use `var(--token-name)` or `var(--token-name, fallback)`. Our token scale uses a 4px spacing base and major third (1.250) type scale.

View file

@ -728,8 +728,10 @@ pre, code {
.mps-button {
/* Normalize so <button>, <a>, and <input type=submit> with this
class render identically without these, <button> elements
inherit UA line-height/box-sizing and render squished. */
class render identically. inline-grid + place-items: center
dead-centers the content regardless of the element's native box
model <button> content otherwise lays out differently from <a>
and looks squished. (Grid only no flex, per CLAUDE.md.) */
-webkit-appearance: none;
appearance: none;
box-sizing: border-box;
@ -737,15 +739,17 @@ pre, code {
border-radius: var(--radius-sm, 4px);
color: white;
background-color: #D4D0C8;
display: inline-block;
display: inline-grid;
place-items: center;
font-family: inherit;
font-size: var(--text-sm, 14px);
font-weight: var(--weight-bold, bold);
line-height: 1.4;
min-width: 100%;
min-height: 44px;
margin-top: var(--space-1, 4px);
margin-bottom: var(--space-1, 4px);
padding: 12px 16px;
padding: 10px 16px;
text-align: center;
text-decoration: none;
white-space: nowrap;
@ -1436,10 +1440,11 @@ div.edit-page > section.well2:focus-within {
}
/* Card header h3 with leading icon. Class .edit-card-icon turns
any inline glyph into a 32px circular badge. */
any inline glyph into a 36px circular badge. (Grid only.) */
div.edit-page > section.well2 > h3:first-child,
div.edit-page > section.well2 > form > h3:first-child {
display: flex;
display: grid;
grid-template-columns: auto 1fr;
align-items: center;
gap: var(--space-3, 12px);
margin-bottom: var(--space-3, 12px);
@ -1449,28 +1454,25 @@ div.edit-page > section.well2 > form > h3:first-child {
}
.edit-card-icon {
display: inline-flex;
align-items: center;
justify-content: center;
display: inline-grid;
place-items: center;
width: 36px;
height: 36px;
border-radius: 50%;
background: var(--color-blue-tint, #e8efff);
color: var(--color-navy, #5871ad);
font-size: 1.1rem;
flex-shrink: 0;
}
/* Status pill lives in the call_to_action block (top-right of page,
alongside permanent link). Surfaces visibility + ready state + price
at a glance. No background since it sits in the page header area. */
at a glance. No background since it sits in the page header area.
Container uses text-align: right and lets the inline-grid pills flow
and wrap naturally no flex. */
.edit-status-bar {
display: flex;
flex-wrap: wrap;
gap: var(--space-2, 8px);
align-items: center;
justify-content: flex-end;
text-align: right;
margin: 0 0 var(--space-2, 8px);
line-height: 2;
}
.edit-permanent-link {
@ -1481,9 +1483,12 @@ div.edit-page > section.well2 > form > h3:first-child {
}
.edit-status-pill {
display: inline-flex;
display: inline-grid;
grid-auto-flow: column;
grid-auto-columns: max-content;
align-items: center;
gap: var(--space-1, 4px);
margin-left: var(--space-2, 8px);
padding: var(--space-1, 4px) var(--space-3, 12px);
border-radius: var(--radius-pill, 999px);
font-size: 0.85em;
@ -1513,16 +1518,13 @@ div.edit-page > section.well2 > form > h3:first-child {
background: var(--color-purple, #9B59B6);
}
/* Primary save action sticky at the bottom of the form and rendered
as a filled, prominent button. Counter-balances the floating save
that lives inside the form. */
/* Primary save action — filled, prominent button. (Grid only.) */
div.edit-page input.mps-submit[value="Save Settings"],
div.edit-page button.mps-submit-primary,
.mps-button-primary {
float: none;
display: inline-flex;
align-items: center;
justify-content: center;
display: inline-grid;
place-items: center;
padding: var(--space-3, 12px) var(--space-6, 24px);
background: var(--color-navy, #5871ad);
color: #fff;
@ -1551,8 +1553,7 @@ div.edit-page button.mps-submit-primary:disabled,
box-shadow: none;
}
/* Sticky save bar at the bottom of the edit page keeps Save Settings
in view while user scrolls through long edit forms. */
/* Sticky save bar at the bottom of the edit page. (Grid only.) */
.edit-save-bar {
position: sticky;
bottom: var(--space-3, 12px);
@ -1562,15 +1563,14 @@ div.edit-page button.mps-submit-primary:disabled,
border-radius: var(--radius-md, 8px);
box-shadow: var(--elevation-3, 0 4px 12px rgba(0,0,0,0.07));
border: 1px solid var(--color-border, #eee);
display: flex;
justify-content: flex-end;
display: grid;
grid-template-columns: 1fr auto;
align-items: center;
gap: var(--space-3, 12px);
z-index: 10;
}
.edit-save-bar-status {
flex: 1;
color: var(--color-text-muted, #666);
font-size: 0.9em;
}
@ -1595,9 +1595,6 @@ div.edit-page > section.upload-preview { order: 3; }
div.edit-page > section.upload-thumbnails { order: 4; }
div.edit-page > section.price-history { order: 5; }
/* Thumbnails header laid out via .upload-thumbnails-header flex row
above the .upload-thumbnails-grid (see below). */
hr {
color: var(--border-light, #EEEEEE);
}
@ -1605,22 +1602,24 @@ hr {
section.upload-product-and-preview {
}
section.upload-thumbnails {
/* Header + grid layout see .upload-thumbnails-header and
.upload-thumbnails-grid below for the inner structure. */
/* Thumbnails section: header row above, thumbnail grid below.
(Grid only no flex.) */
.upload-thumbnails-header {
display: grid;
grid-template-columns: 1fr auto;
align-items: start;
gap: var(--space-4, 16px);
}
.upload-thumbnails-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
gap: var(--space-4, 16px);
flex-wrap: wrap;
@media (max-width: 600px) {
.upload-thumbnails-header {
grid-template-columns: 1fr;
}
}
.upload-thumbnails-header h3 {
margin: 0;
flex: 1 1 auto;
min-width: 0;
}
.upload-thumbnails-hint {
@ -1638,9 +1637,13 @@ section.upload-thumbnails {
align-items: stretch;
}
/* Each thumbnail cell is itself a grid: content rows pinned to the
top, the upload form pinned to the bottom (align-content: space-between
replaces the flex margin-top: auto trick). */
.upload-thumbnails-grid .upload-thumbnail-item {
display: flex;
flex-direction: column;
display: grid;
grid-auto-rows: min-content;
align-content: space-between;
gap: var(--space-2, 8px);
padding: var(--space-3, 12px);
background: var(--surface-dim, #f9f9fa);
@ -1663,10 +1666,6 @@ section.upload-thumbnails {
margin: 0;
}
.upload-thumbnails-grid .upload-thumbnail-item form {
margin-top: auto;
}
.upload-thumbnails-grid .upload-thumbnail-item hr {
display: none;
}

View file

@ -507,7 +507,7 @@
</p>
{% endif %}
<label style="font-weight:normal;display:flex;align-items:center;gap:.5rem;margin:.25rem 0">
<label style="font-weight:normal;display:grid;grid-template-columns:auto 1fr;align-items:center;gap:.5rem;margin:.25rem 0">
<input type="checkbox" name="torrent_opt_in"
{% if torrent_opt_in %}checked{% endif %} />
Seed this product via BitTorrent