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:
parent
cec78ccd45
commit
7df421dba3
3 changed files with 61 additions and 49 deletions
15
CLAUDE.md
15
CLAUDE.md
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue