# Listing Mockup -> Dev Theme Liquid Port Plan

Date: 2026-06-16
Scope: take the approved week-9 listing mockup (`workspace/weeks/week-9/web-mockups-2026-06-16/listing-all/`) and port it into the dev theme as the canonical product page, driven by live product data, then roll out flagship-first and finally catalog-wide.

Authoritative residence paths used below (verified):

- Dev theme root: `/Users/kreed/ClaudeOS/freelance/0-residences/sonographer/shopify/theme-files-dev/`
- Existing custom listing section: `shopify/theme-files-dev/sections/product-custom-listing.liquid`
- Existing custom listing template: `shopify/theme-files-dev/templates/product.custom-listing.json`
- Shared brand kit (the mockup source of truth): `workspace/weeks/week-9/web-mockups-2026-06-16/shared/sitm-mockup-kit.css`
- Live homepage gradient asset: `shopify/theme-files-dev/assets/sitm-under-hero.css`
- Push protocol (gate): `guides/05-prod-push-protocol.md`
- Existing listing-template spec (companion doc): `guides/07-listing-template-spec.md`

---

## A. Efficient + accurate port to the dev theme

### A1. Lock the design system as a single theme asset

Mint one new asset that mirrors `shared/sitm-mockup-kit.css` 1:1 so the listing pages reuse the same tokens, header/footer, prefooter, glass card, badge, and button classes that the mockups already use.

- New file: `shopify/theme-files-dev/assets/sitm-mockup-kit.css`
- Source: byte-for-byte copy of `workspace/weeks/week-9/web-mockups-2026-06-16/shared/sitm-mockup-kit.css`
- Loaded once via `{{ 'sitm-mockup-kit.css' | asset_url | stylesheet_tag }}` from `layout/theme.liquid`, gated behind a `theme.liquid` conditional so it only loads on product pages using the `product.custom-listing` template (avoid bleeding global styles).

Rationale: every kit class the mockups use already exists in the kit CSS; loading it in-theme means the liquid section only emits semantic markup with kit classes, and the section file stays small.

### A2. Refactor `sections/product-custom-listing.liquid`

Replace the current `.pcl-*` ad-hoc scaffolding with the mockup's semantic structure, classed with kit + page-scoped (`plp-*`) classes mirroring `listing-all/generate.py` PAGE_CSS. The section emits markup only; styles live in two places:

1. Global kit asset (A1) for brand primitives.
2. A small page-scoped block in the section's `{% stylesheet %}` block for `.plp-*` listing-specific layout (hero grid, gallery, trust strip, reviews placeholder). Lift these rules verbatim from `listing-all/generate.py` -> `PAGE_CSS`.

Liquid-driven data plumbing (replace mockup placeholders):

| Mockup placeholder | Liquid source |
|---|---|
| Title | `{{ product.title | replace: 'ERROR - ', '' }}` (defensive strip until A4) |
| Category eyebrow | `{{ product.type | default: product.tags | first }}` (or hard map via metafield) |
| Price range | `{% if product.price_varies %}from {{ product.price_min | money }}{% else %}{{ product.price | money }}{% endif %}` |
| "Starts at" microcopy | from `product.variants` lowest non-zero price |
| Variant chips | `{% for v in product.variants %}` rendering chip per variant, using `v.title` + `v.price | money`, with `data-variant-id="{{ v.id }}"` and a small `<script>` that toggles `[aria-pressed="true"]` + posts to `/cart/add.js` |
| Add to cart | wire to product form snippet (`snippets/product-form.liquid`) and reuse the existing variant selector logic; keep our pill button as the form submit |
| Gallery main + thumbs | use `product.media` / `product.images`. While images are still missing, fall back to the mockup gradients keyed by `product.handle` (move the GALLERY_GRADIENTS array into a small `snippets/sitm-gradient-art.liquid` helper that returns a deterministic gradient per handle so the same fallback survives the port) |
| Promise bullets | hard-coded in section schema as 3 text fields with defaults matching the mockup copy |
| Trust strip | hard-coded in section schema, 4 text fields |
| Description (verbatim live HTML) | `{{ product.description }}` (Shopify already returns the body_html, the same HTML the mockup reads from `shopify/product-descriptions/*.html`) |
| Reviews placeholder | swap for Judge.me block: `{% render 'judgeme_widgets', widget_type: 'judgeme_review_widget', concierge_install: true, product: product %}` (the theme already pulls in Judge.me; see `snippets/`). Keep the kit `.plp-reviews__head` shell so design survives. |

Schema edits (`sections/product-custom-listing.liquid` schema block):

- Add a `header` "Promise bullets" + 3 `text` fields with defaults.
- Add a `header` "Trust strip" + 4 `text` fields with defaults.
- Add a `select` "Gallery fallback" with values `auto` (use deterministic gradient per handle) and `images` (use product.images only).
- Keep `presets` empty so this stays template-driven.

### A3. Update `templates/product.custom-listing.json`

Single section instance referencing the refactored `product-custom-listing` section. No additional sections (no related-products row, no recently-viewed). Keeps the diff surgical and matches what the mockup shows.

### A4. Fix the live-data "ERROR - " title (out-of-band, not a code change)

The live product `the-ultimate-ultrasound-school-physics-flashcards` has a title that begins `ERROR - The Ultimate ...`. The mockup strips it for display, but the underlying data should be fixed in Shopify Admin so we do not carry a defensive replace forever.

- Owner: Keith to fix in Shopify Admin (or via `shopify/scripts/` GraphQL update) before the catalog-wide rollout in C.
- Once fixed, remove the `| replace: 'ERROR - ', ''` filter from the liquid template (A2).

### A5. Local dev verification before any push

Per `guides/06-dev-theme-state-verification.md`:

1. `shopify theme push --only sections/product-custom-listing.liquid --only templates/product.custom-listing.json --only assets/sitm-mockup-kit.css --store sonographer-in-the-making.myshopify.com --theme <DEV_THEME_ID>` (dev theme, not live).
2. Preview URL through `shopify theme dev` against an already-assigned flagship product.
3. Visual diff against the mockup at `listing-all/products/<flagship-handle>.html` at 390px, 768px, 1280px. No horizontal scroll, kit tokens intact, gallery falls back to gradient where image is missing.
4. Click through add-to-cart with each variant to confirm the chip -> form binding actually posts the right variant id.

---

## B. Carry the homepage footer gradient onto listing pages (in liquid)

The homepage gradient pre-footer in the mockups is the `.sitm-prefooter` component in `shared/sitm-mockup-kit.css`. Carrying it onto listing pages means: every product page closes with the same gradient band right above the navy footer, unifying every page on the site.

### B1. Asset

The gradient + wave + radial overlays are already extracted verbatim into `shared/sitm-mockup-kit.css` under `.sitm-prefooter` (and the source values are also in `shopify/theme-files-dev/assets/sitm-under-hero.css`). Asset A1 (the in-theme copy of the mockup kit) already includes `.sitm-prefooter`, so no second asset is needed.

### B2. Snippet

Create a tiny, reusable snippet so any template can drop the band in with one line:

- New file: `shopify/theme-files-dev/snippets/sitm-prefooter.liquid`
- Contents: the same markup from `workspace/weeks/week-9/web-mockups-2026-06-16/shared/_footer.html` for the `<section class="sitm-prefooter">...</section>` block, with text fields wired to settings so copy is editable:

```liquid
<section class="sitm-prefooter">
  <div class="sitm-container sitm-prefooter__inner">
    <span class="sitm-badge sitm-badge--gold">{{ badge | default: 'Made by a sonographer' }}</span>
    <h2 class="sitm-h2">{{ heading | default: 'Study smarter, not longer.' }}</h2>
    <p>{{ body | default: 'Guides, flashcards, and registry-ready question banks built by a sonographer who has been exactly where you are.' }}</p>
    <div class="sitm-prefooter__cta">
      <a class="sitm-btn sitm-btn--pill" href="{{ cta_primary_url | default: routes.all_products_collection_url }}">{{ cta_primary_label | default: 'Shop study tools' }}</a>
      <a class="sitm-btn sitm-btn--pill" style="background:transparent;color:#fff;box-shadow:inset 0 0 0 1.5px rgba(255,255,255,.6)" href="{{ cta_secondary_url | default: '/pages/free-materials' }}">{{ cta_secondary_label | default: 'Get free materials' }}</a>
    </div>
  </div>
</section>
```

### B3. Wire-in

- Inside `sections/product-custom-listing.liquid`, render the snippet as the final block before the section closes:
  `{% render 'sitm-prefooter' %}`
- This produces the gradient band on every listing page, immediately above the navy footer that the theme layout already injects.
- For the homepage, leave the existing `sitm-under-hero` block alone (it is the same gradient already, in-place). The snippet replaces no homepage code; it only adds the band to product pages.

### B4. CSS asset selection

`.sitm-prefooter` is defined in the asset shipped by A1 (`assets/sitm-mockup-kit.css`). No need to duplicate the definition into `sitm-under-hero.css` or any per-section stylesheet.

---

## C. All-products rollout sequence + verification gates

Roll out in three phases. Every push uses `guides/05-prod-push-protocol.md`: one `--only` flag per file, pull-first, explicit Keith sign-off for each push, never `--publish`, never push customizer-managed JSON.

### C1. Dev-only build phase (no prod activity)

1. Land A1, A2, A3, B2 on the dev theme via dev pushes only.
2. Assign the dev product `the-ultimate-ultrasound-school-physics-study-guide` to template `product.custom-listing` in the dev customizer.
3. Walk through verification gates A5 + B3. Resolve any reflow/contrast/CTA issues here, not in prod.
4. Capture screenshots (1280, 768, 390) into `workspace/weeks/week-9/web-mockups-2026-06-16/_audit-renders/dev-port-flagship/`.
5. Keith review on dev URL (per `feedback_dev_review_before_prod`): the dev render must be approved by Keith before any prod push is staged.

### C2. Flagship prod push (one product)

The flagship product is the highest-traffic listing in the catalog. Pick from analytics; default to `the-ultimate-ultrasound-school-physics-study-guide`.

1. Per guide 05 step 1: `shopify theme pull` prod to `shopify/theme-files-prod/`, diff against local.
2. Copy A1 asset + A2 section + B2 snippet from `theme-files-dev/` into `theme-files-prod/`. Do not copy the JSON template yet (the template assignment to one product happens via Shopify Admin theme customizer, not via JSON push).
3. Get explicit per-push approval from Keith.
4. Push prod with one `--only` per file:
   ```bash
   shopify theme push \
     --store sonographer-in-the-making.myshopify.com --theme 153184764160 \
     --path shopify/theme-files-prod/ \
     --only assets/sitm-mockup-kit.css \
     --only sections/product-custom-listing.liquid \
     --only snippets/sitm-prefooter.liquid
   ```
5. In Shopify Admin, assign the flagship product to template `product.custom-listing` (the template itself was already deployed; this is a customizer-side assignment).
6. Verify the flagship live URL: hero renders, variant chips work, add-to-cart fires, prefooter gradient sits above the navy footer, no console errors. Capture screenshot to `_audit-renders/prod-flagship/`.
7. Soak time: 48 hours minimum before C3, watching analytics for add-to-cart rate, bounce, and any Judge.me widget regressions.

### C3. Catalog-wide rollout (33 products)

Order matches the generator's sort order in `listing-all/generate.py` (`order_pref`): Bundles, then Study Guides, then Flashcards, then Badge Cards, then Planners, then Question Banks, then Cheat Sheets, then remaining categories.

For each batch (5 products per batch, by category):

1. Confirm A4 (ERROR title fix) has been applied in Admin before the Flashcards batch.
2. Assign products to template `product.custom-listing` in Shopify Admin, one batch at a time.
3. After each batch is assigned: spot-check 1 product per variant pattern (single-variant, 3-variant book/ebook/combo, multi-color planner, multi-size tote). Verify each in browser at 390px and 1280px.
4. Wait 24 hours between batches. If add-to-cart rate or bounce diverges by more than 10% from the soak baseline, halt and diagnose before continuing.
5. After all 33 products are migrated, archive the prior `product.json` / `product.digital.json` / `product.enhanced.json` templates to a dated folder rather than deleting them, so we can roll back per product if needed.

### C4. Rollback plan (per-product, no asset rollback needed)

Because each product is assigned to a template via the Shopify Admin customizer (not via JSON push), rollback is one click per product: reassign to the prior template. No theme push is involved, no risk of stripping app embeds, no settings_data.json risk.

### C5. Verification gates (summary)

| Gate | Trigger | Owner | Pass condition |
|---|---|---|---|
| G1 | After dev push (C1) | Migrant + Keith | Mockup parity at 3 widths, no console errors, add-to-cart fires |
| G2 | Before prod push (C2) | Keith | Explicit per-push approval naming the 3 files |
| G3 | After flagship prod push | Migrant | Live URL screenshot diff against dev screenshot, prefooter visible, Judge.me widget loads |
| G4 | 48h soak | Keith | Analytics within tolerance |
| G5 | Per batch in C3 | Migrant | Spot-check pass per variant pattern |
| G6 | Final | Keith | Approval to archive legacy product templates |

---

## Files this plan will create or modify (when executed)

Create:
- `shopify/theme-files-dev/assets/sitm-mockup-kit.css`
- `shopify/theme-files-dev/snippets/sitm-prefooter.liquid`

Modify:
- `shopify/theme-files-dev/sections/product-custom-listing.liquid`
- `shopify/theme-files-dev/templates/product.custom-listing.json` (only if section name or section_id changes; if reusing, no edit)
- `shopify/theme-files-dev/layout/theme.liquid` (conditional asset load on `product.custom-listing` template)

Out-of-band:
- Shopify Admin: rename product title `ERROR - The Ultimate Ultrasound School Physics Flashcards` -> `The Ultimate Ultrasound School Physics Flashcards`.
- Shopify Admin: per-product template assignments in C2 and C3.
