# Phase D — Liquid integration scoping

**Authored:** 2026-05-13 in parallel with Phase C asset production (running in another chat).
**Status:** Scoping plan for the Liquid Implementation Crew. Section-by-section conversion map, metafield inventory, deploy strategy, risk register. No theme code written yet — that's Phase D execution.

## Scope

Convert the Stage 5b approved React/Tailwind prototype into Liquid sections + snippets in the existing Huxberry theme (`/Users/nish/Documents/Projects/Shopify-Huxberry`, `main` branch). EXTEND the 14 protected files cataloged below; do NOT introduce parallel implementations.

**Out of scope:** asset production (Phase C, in flight), supplier verification (TENCEL™ / CertiPUR-US — independent track), Phase E launch QA + production deploy.

## Pre-flight checklist (do these before writing Liquid)

| # | Item | Status | Owner |
|---|---|---|---|
| 1 | Confirm Shopify CLI is authenticated against the Huxberry store | ☐ | dev |
| 2 | Identify which dev/preview theme ID to target — currently no dedicated preview theme; `0350c86` ("Absorb Shopify theme editor drift on preview theme") implies one exists. Run `shopify theme list` to confirm | ☐ | dev |
| 3 | Decide deploy mechanism: `shopify theme push --unpublished` from local OR wire up Shopify's native GitHub integration (per [NEXT-STEPS.md](../../../../Shopify-Huxberry/NEXT-STEPS.md) — currently unwired) | ☐ | dev + Nish |
| 4 | Confirm `templates/product.nish-natural-wool.json` is the working template (it's auto-managed by theme editor — edits there can be overwritten). Decision: either lock theme-editor edits during conversion, or do conversion via section additions referenced from the JSON template | ☐ | dev |
| 5 | Verify no in-flight branches on the theme repo are touching the protected files | ☐ | dev |
| 6 | Branch strategy: create `feature/nhc-pdp-stage-5b` off `main` for all Phase D commits | ☐ | dev |
| 7 | Wait for Phase C asset drop before final preview-theme deploy — placeholder stubs work for development but final preview should ship real images | ⏳ Phase C in flight | other chat |

## 12-section conversion map

Wireframe disposition is **EXTEND-only** across all 12 sections — zero NEW, zero REMOVE (continuity strictness=strict, zero protected_removal_overrides). This means every section's job is to add slots / blocks / settings to existing Liquid files, never to author parallel implementations.

| # | Section | Disposition | Pattern reference | Protected files touched | Conversion strategy | Risk |
|---|---|---|---|---|---|---|
| 1 | **hero** (ATF gallery + buy-box composite) | EXTEND | product-template | `sections/product-template.liquid` (976 ln) · `templates/product.nish-natural-wool.json` (379 ln) · `templates/product.json` (536 ln) · `snippets/product-hux.liquid` (383 ln) · `snippets/product-gallery-media-hux.liquid` (300 ln) · `snippets/cstm-product-price.liquid` (291 ln) · `snippets/product-buybox-enhancements.liquid` (87 ln) · `snippets/cstm-product-form-hux.liquid` (1205 ln) | The hero is the largest surface — 55/45 gallery+buybox at desktop, single-col at mobile. Existing `product-template` already provides the section shell + ATF responsive grid; existing `product-hux` already renders title/rating/price/form/trust badges. **Add a `hero-atf-badges` block schema to `product-template` settings** (delivery, warranty, trial-replacement pill). **Extend `cstm-product-form-hux`** to render the size dropdown with strikethrough+discounted per-option pricing matching the live widget. **Promote `breadcrumbs` to render above the gallery** via `product.metafields.huxberry.breadcrumbs` or schema setting. | Auto-generated template (item #4) may overwrite edits |
| 2 | **sticky-add-to-cart** | EXTEND | product-sticky-atc | `snippets/product-sticky-atc.liquid` (127 ln) · `sections/product-template.liquid` | Existing snippet renders bottom-strip on mobile. **Must rewrite the activation gate per [STICKY-ATC-PATCH-NOTE.md](STICKY-ATC-PATCH-NOTE.md)** — rAF-throttled scroll listener computing `inlineAtc.getBoundingClientRect().bottom < 0`, NOT IntersectionObserver. Resize listener for layout-change robustness. Initial state runs synchronously on script load. | **HARD-STOP risk** — wrong gate ships sticky at page load |
| 3 | **gallery** | EXTEND | product-gallery-media-hux | `snippets/product-gallery-media-hux.liquid` (300 ln) · `sections/product-template.liquid` | Existing gallery handles media + thumbnails. **Add feature-strip pills below the gallery** rendering the 6 locked component names (Individually Pocketed Spring Core · Reinforced Edge Zone · Two Firmness Profiles · Cushioning Comfort Layer · Airelle Natural Wool · Velura knit cover). Pills are 4-icon-strip on mobile, 6 on desktop. **New metafield: `huxberry.feature_pills_json`** (json) for non-NHC products that need different pill text; defaults to the locked NHC taxonomy via Liquid fallback. | Low |
| 4 | **buy-box** | EXTEND | product-hux | `snippets/product-hux.liquid` · `snippets/cstm-product-form-hux.liquid` · `snippets/cstm-product-price.liquid` · `snippets/product-buybox-enhancements.liquid` · `snippets/product-installments.liquid` (140 ln) · `snippets/product-sleep-bundle.liquid` (264 ln) · `snippets/product-sleep-bundle-nish.liquid` (398 ln) · `sections/product-template.liquid` | Buy-box already exists. **Extend `cstm-product-form-hux`** with the size+firmness dropdown pattern (per memory note `feedback_huxberry_size_selector_pattern.md` — dropdown not chips, with list-price strikethrough + discounted per-option). **Extend `product-buybox-enhancements`** delivery line: "Made to order — ships in 5 working days" (already wired via existing pattern). **Sleep-bundle snippets are protected but irrelevant for NHC PDP** — they ship as-is for other products. | Medium |
| 5 | **trust-strip** | EXTEND | product-trust-stack | `snippets/product-trust-stack.liquid` (56 ln) · `sections/product-template.liquid` | Existing trust-stack snippet renders pill row. **DROP the trial pill row entirely from this snippet's NHC code path** per [POLICY-DRIFT-NOTE.md](POLICY-DRIFT-NOTE.md) — sleep trial is forbidden, not pending. The pill ships as Delivery / Warranty / Free shipping / Certifications, no Trial. Gating via `product.metafields.huxberry.show_certs` (already exists) + new `huxberry.delivery_promise_text` (single_line_text, default "Made to order — ships in 5 working days"). | Medium — easy to leave in by accident |
| 6 | **materials-breakdown** (Velura → Airelle → Spring → Edge) | EXTEND | icon-with-text-slider | `templates/product.nish-natural-wool.json` | Existing `icon-with-text-slider` section type in the template JSON. **Add 4 entries** in materials order (cover → wool → spring core → edge zone). Cushioning Comfort Layer renders inline within the wool entry as a paragraph (per the TERMINOLOGY-PATCH-NOTE rationale — the comfort foam was not given its own h3 in the original wireframe; preserve that structural choice). Image references will land in Phase C; for development, use Placeholder stubs from `runs/.../design/graphics/`. | Low |
| 7 | **comparison-table** (Essentia / Select / Reserve) | EXTEND | mattress-comparison | `sections/mattress-comparison.liquid` (275 ln) · `templates/product.nish-natural-wool.json` | Existing `mattress-comparison` section. **NHC-ONLY constraint** per memory note `feedback_huxberry_comparison_intra_range_only.md`: only render Essentia / Select / Reserve cards on NHC PDPs. The section already enforces intra-range; verify schema settings don't allow editor to insert cross-brand cards. Cell content uses locked taxonomy (Individually Pocketed Spring Core / Reinforced Edge Zone / Airelle Natural Wool — entry/premium density). | Low |
| 8 | **certifications** | EXTEND | product-buybox-enhancements | `snippets/product-buybox-enhancements.liquid` · `snippets/product-trust-stack.liquid` | Existing cert-row pattern. **Render 2 cert items: CertiPUR-certified foam + B Corp · Land to Market · FernMark.** No CertiPUR-US suffix on customer surfaces. New metafield: `huxberry.cert_list_json` (json) — array of `{name, scope, evidence_url}` per cert, NHC default seeds the 2 certs above. Cert detail expandable via `<details>` accordion. | Low |
| 9 | **sleep-trial-and-warranty** | EXTEND | product-buybox-enhancements | `snippets/product-buybox-enhancements.liquid` | **DROP the trial-block entirely** per POLICY-DRIFT-NOTE. Warranty block renders only when `huxberry.warranty_years` is set (already gated). For NHC the metafield is unset until legal terms are confirmed — section renders empty (warranty pill in trust-strip carries the fallback). | Low (mostly already correct) |
| 10 | **reviews** | EXTEND | custom-reviews | (no protected files) | Existing `custom-reviews` static section. NHC ships pre-launch with zero reviews; per `feedback_huxberry_no_sleep_trial.md`-style discipline, no fake testimonials. Section either hides via `huxberry.show_reviews` (new boolean, default false) or renders a "Reviews coming soon — be among the first" placeholder. Decision pending — flag for Nish. | Low |
| 11 | **faq** (8 questions, reconciled) | EXTEND | image-with-faq | (no protected files) | Existing `image-with-faq` section. **8 FAQs required per [FAQ-PATCH-NOTE.md](FAQ-PATCH-NOTE.md)**: prototype FAQ accordion ↔ schema.jsonld `FAQPage.mainEntity[].name` must be 1:1. Pull verbatim from `design/copy.html` slot manifest (slot id: `faq.faq-accordion`). Render answers via Liquid filter that strips placeholder `{{ claim-needed: ... }}` (none in current FAQ, but defensive). | Medium — schema parity is a Google Rich Results policy gate |
| 12 | **related-products** | EXTEND | static-product-recommendations | (no protected files) | Existing static recommendations section. Configure to show the other 2 NHC tiers (Essentia + Reserve when on Select). | Low |

## Metafield inventory (huxberry namespace)

The Huxberry theme already uses the `huxberry` metafield namespace per [Shopify-Huxberry/CHANGES.md](../../../../Shopify-Huxberry/CHANGES.md). Extending that namespace rather than introducing a new one:

### Existing (verified in protected snippets):

| Metafield | Type | Used by | Notes |
|---|---|---|---|
| `huxberry.rating_value` | text/decimal | product-buybox-enhancements | e.g. `4.7` |
| `huxberry.rating_count` | integer | product-buybox-enhancements | e.g. `249` |
| `huxberry.tagline` | single_line_text | product-buybox-enhancements | |
| `huxberry.award` | single_line_text | product-buybox-enhancements | |
| `huxberry.trial_nights` | integer | product-buybox-enhancements | **NHC: unset and forbidden — see POLICY-DRIFT-NOTE** |
| `huxberry.warranty_years` | integer | product-buybox-enhancements, trust-strip | NHC: unset until legal terms confirmed |
| `huxberry.show_certs` | boolean | product-trust-stack | default true |
| `huxberry.show_finance` | boolean | product-buybox-enhancements | default true |
| `huxberry.pdp_bullets_html` | rich_text/html | product-hux | already wired |

### New metafields needed for Phase D:

| Metafield | Type | Used by | Default for NHC |
|---|---|---|---|
| `huxberry.feature_pills_json` | json (array of `{label, icon_id}`) | gallery feature strip | The 6 locked taxonomy labels |
| `huxberry.cert_list_json` | json (array of `{name, scope, evidence_url}`) | certifications section | `[{name:"CertiPUR-certified foam", scope:"comfort foam"}, {name:"B Corp · Land to Market · FernMark", scope:"Airelle wool source"}]` |
| `huxberry.delivery_promise_text` | single_line_text | trust-strip, buy-box | `"Made to order — ships in 5 working days"` |
| `huxberry.materials_stack_json` | json (ordered list of `{component_name, description, image_id}`) | materials-breakdown | The 6 locked components, in section-order (cover → wool → spring core → edge zone, with Cushioning Comfort Layer inline within wool) |
| `huxberry.comparison_tiers_json` | json (array of tier rows) | mattress-comparison | Essentia / Select / Reserve rows using locked taxonomy cell content |
| `huxberry.faq_json` | json (array of `{question, answer}`) | faq section | The 8 reconciled FAQs from `design/copy.html` slot `faq.faq-accordion` |
| `huxberry.show_reviews` | boolean | custom-reviews | `false` for NHC pre-launch (decision pending — see section 10 above) |
| `huxberry.collection_id` | single_line_text | misc — drives NHC-specific code paths | `"natural-harmony-collection"` for the 3 NHC SKUs |

The `_json` metafields trade some Liquid verbosity for editor-friendliness — non-technical staff can edit pill labels, FAQ answers, comparison-table cells from Shopify Admin without touching theme code. This pattern matches the existing `huxberry.pdp_bullets_html`.

### Metafield seed script

A standalone script (proposed: `Shopify-Huxberry/scripts/seed-nhc-metafields.sh`) should populate the 3 NHC product IDs with the default JSON values above on first deploy. Source of truth for JSON contents:

- `feature_pills_json`, `cert_list_json`, `delivery_promise_text`, `materials_stack_json` → `runs/.../design/copy.html` slot manifest
- `comparison_tiers_json` → `runs/.../design/wireframe.html` section 7 spec
- `faq_json` → `runs/.../design/copy.html` slot `faq.faq-accordion` (8 questions, must match `schema.jsonld` 1:1)

## Asset pipeline (Phase C → Liquid)

When Phase C lands the 14 image slots:

1. Images drop into `runs/.../design/graphics/` (per graphics-director output spec).
2. Implementation crew uploads to Shopify CDN via `assets/` directory: `shopify theme push --only=assets/`.
3. Each image's CDN URL becomes the `image_id` reference in the metafield JSON entries.
4. Alt-text is the `alt_text_canon` from `design/graphics.html` — verbatim, no creative liberties.

For Phase D scoping work today (no images yet), use:
- Placeholder `<div class="img-stub">` per the prototype's existing pattern.
- Real alt-text canon from `design/graphics.html` even when image is a stub — alt text is the SEO load-bearing piece, not the pixels.

## Risk register

| # | Risk | Surface | Mitigation | Source |
|---|---|---|---|---|
| R1 | Sticky-ATC fires at scroll=0 | `snippets/product-sticky-atc.liquid` activation script | Use rAF-throttled scroll listener; gate is `inlineAtc.getBoundingClientRect().bottom < 0`. NOT IntersectionObserver. Resize listener mirrors scroll listener. Initial state runs synchronously on load. | [STICKY-ATC-PATCH-NOTE.md](STICKY-ATC-PATCH-NOTE.md) |
| R2 | Mobile size bottom-sheet visible at rest | `snippets/product-sticky-atc.liquid` CSS or new bottom-sheet snippet | Sheet transform is `translateY(calc(100% + 68px))`, not `translateY(100%)`. Backdrop element does NOT carry `.show-mobile` (viewport-gating class must not double-purpose as open-state class). | [STICKY-ATC-PATCH-NOTE.md](STICKY-ATC-PATCH-NOTE.md) |
| R3 | Sleep-trial slot shipped as `{{ claim-needed }}` placeholder | trust-strip pill row, sleep-trial-and-warranty section | **DROP the slot entirely**, do not implement as placeholder. NHC ships without a trial pill, without a trial FAQ entry. | [POLICY-DRIFT-NOTE.md](POLICY-DRIFT-NOTE.md) |
| R4 | FAQ section ↔ FAQPage JSON-LD drift | faq section + theme JSON-LD output | The 8 FAQs must match 1:1. If editor edits the `huxberry.faq_json` metafield, JSON-LD output must regenerate from the same source. Implement via a single Liquid block that emits both visible accordion + JSON-LD `application/ld+json` script tag from one metafield. | [FAQ-PATCH-NOTE.md](FAQ-PATCH-NOTE.md) |
| R5 | `templates/product.nish-natural-wool.json` overwritten by theme editor | template JSON header explicitly warns about auto-generation | Either freeze theme-editor edits to that template for the duration of Phase D, OR perform all conversion via new section definitions in `sections/` referenced from the JSON (so the JSON only carries section IDs, not section bodies). Decision needed in pre-flight item #4. | `templates/product.nish-natural-wool.json:1-9` header comment |
| R6 | CertiPUR-US suffix leaks back in | any cert-rendering Liquid | Theme should never render the `-US` suffix on customer surfaces. Add a `theme check` rule or pre-commit hook scanning for "CertiPUR-US" in `snippets/*.liquid` and `sections/*.liquid`. | [CERTIFICATION-VERIFY-NOTE.md](CERTIFICATION-VERIFY-NOTE.md) |
| R7 | Engineering spec language leaks into customer copy | any Liquid hardcoded copy | Theme should not contain the strings "800-count pocket-spring", "Steel-zoned perimeter", "1.9 mm body wire", "2.1 mm body wire", "PU800". All customer copy flows through metafields with locked-taxonomy defaults. | [TERMINOLOGY-PATCH-NOTE.md](TERMINOLOGY-PATCH-NOTE.md) + [CLAIMS-REFRESH-NOTE.md](CLAIMS-REFRESH-NOTE.md) |
| R8 | Wisewool supplier name surfaces in customer copy | materials-breakdown section, certifications section | Supplier names are internal-only. Cert-context surface is "Airelle wool source", never "Wisewool". Add same theme-check rule as R6 for "Wisewool". | [collections/huxberry-natural-harmony.md](../../../../../../Obsidian/SPT/Wikis/products/wiki/collections/huxberry-natural-harmony.md) Forbidden customer copy section |
| R9 | Comparison table drifts to cross-brand cards | `sections/mattress-comparison.liquid` schema | Schema settings must not expose a "brand" field on the comparison-tier block — only Essentia/Select/Reserve allowed. Verify before deploy. | memory: `feedback_huxberry_comparison_intra_range_only.md` |

## PR / branch / preview strategy

| Step | Action | Owner |
|---|---|---|
| 1 | Create branch `feature/nhc-pdp-stage-5b` off `main` in `Shopify-Huxberry` | dev |
| 2 | Convert one section per commit, starting with low-risk sections (related-products → reviews → faq → certifications → trust-strip → materials-breakdown → comparison-table → gallery → buy-box → hero → sleep-trial-and-warranty → sticky-add-to-cart). High-risk sections last so the risk surface lands together for QA. | dev |
| 3 | After each commit, run `shopify theme check` and `shopify theme dev` to live-preview locally | dev |
| 4 | Push branch to a development/preview Shopify theme via `shopify theme push --unpublished --theme <preview-theme-id>` after every 3–4 sections | dev |
| 5 | Brand-owner taste review at the preview-theme URL after sections 1–6, again after sections 7–12 | Nish |
| 6 | Address review feedback in fix-up commits, NOT new branches | dev |
| 7 | When all 12 sections + 8 new metafields + seed script done: PR `feature/nhc-pdp-stage-5b → main` for final review | dev |
| 8 | Merge gated on: (a) all sections rendering correctly at desktop 1440 + mobile 375, (b) `theme check` clean for files touched, (c) FAQ reconciliation script passes against the deployed JSON-LD, (d) brand-owner sign-off | dev + Nish |

## Acceptance gates (Phase D → Phase E handoff)

Phase D is complete when:

- [ ] All 12 sections render at the preview-theme URL with real (Phase C) images.
- [ ] All 8 new `huxberry.*_json` metafields exist in the store and are populated for the 3 NHC product IDs.
- [ ] `bin/validate-faq-reconciliation.py` passes against the live preview-theme HTML (FAQ accordion ↔ JSON-LD 1:1).
- [ ] `bin/validate-schema-jsonld.py` passes against the live preview-theme HTML.
- [ ] No forbidden vocabulary appears in any `sections/*.liquid` or `snippets/*.liquid`: forbidden patterns are `800-count`, `Steel-zoned`, `1.9 mm body wire`, `2.1 mm body wire`, `PU800`, `CertiPUR-US`, `Wisewool`, `100-night sleep trial`.
- [ ] Sticky-ATC behavior matches spec at mobile 375×812 and desktop 1280×800 (scroll-past-inline-ATC activation, not scroll=0).
- [ ] Mobile size bottom-sheet at rest is fully off-viewport (zero pixel real-estate, no backdrop visible).
- [ ] Brand-owner taste review APPROVED at preview-theme URL.

Then Phase E (cross-device QA, performance audit, production deploy) takes the baton.

## Files touched (planned, not yet written)

Phase D execution will touch — at minimum — these files in `/Users/nish/Documents/Projects/Shopify-Huxberry`:

```
sections/
├── product-template.liquid          (EXTEND — add hero-atf-badges block schema, feature-strip block schema)
├── mattress-comparison.liquid       (EXTEND — verify intra-range constraint, add locked-taxonomy cell defaults)

snippets/
├── product-hux.liquid               (EXTEND — minor)
├── product-gallery-media-hux.liquid (EXTEND — feature-strip below gallery)
├── cstm-product-form-hux.liquid     (EXTEND — size+firmness dropdown with per-option strikethrough)
├── cstm-product-price.liquid        (EXTEND — minor, per-option pricing)
├── product-buybox-enhancements.liquid (EXTEND — cert-detail list, drop trial pill for NHC)
├── product-trust-stack.liquid       (EXTEND — drop trial pill for NHC, cert row)
├── product-sticky-atc.liquid        (REWRITE activation gate — rAF scroll listener)

templates/
├── product.nish-natural-wool.json   (UPDATE — wire new sections, but treat as auto-generated)

scripts/                              (NEW directory)
└── seed-nhc-metafields.sh           (NEW — populate huxberry.*_json metafields for 3 NHC products)

assets/                               (NEW images via Phase C drop)
└── (14 image files + alt-text manifest from design/graphics/)
```

No new sections, no new snippet files. Continuity bias: EXTEND > NEW.
