Compact single-row header — execution plan v1

Jessar Industries · 22 July 2026 · the complete build playbook · supersedes nothing — implements master plan v1 with all of Sean's locked decisions
Phases
0–8 (0 done)
Files touched
7 (all backed up)
Hyper files forked
1 — header.liquid
New JS
≈ 0 lines
Est. build time
2–3 sessions
Revert
1 checkbox / cold backup

Locked decisions (Sean, 2026-07-22)

DecisionValueConsequence in build
RouteA — additive native layout logo-left-menu-inlineStock layouts untouched; new code dead unless selected
Collapse-on-scrollOFF — no desktop hamburger, nav always exposedSimplifies build: no collapse CSS adaptation needed at activation; Hyper's native collapse remains a settings-level revert
Search v1A — persistent compact fieldrs_compact_search_style select ships with both values from day one
Search v1.1 reserveB — icon that expandsNow confirmed ≈ zero-JS (see finding below); switching = flip the select
Utility linksStay in topbarTopbar untouched entirely
Width policyDesign gate, not truncationFails at 1024px ⇒ stop for decision (tracking / fewer items / icon search / reserve two-row fallback)
New fact since the master plan: stock search.js opens the search on input focus (onFocus → body.search-open) and closes on .header__search-close or overlay click. The icon variant therefore needs only an icon control that focuses the existing input — native code does everything else. The A→B switch is CSS + at most a 3-line focus shim. Confirmed from the live file.

Contract invariants — must be true after every phase

These are the assertions each phase's QA gate re-runs. Any failure stops the phase.

  1. Toggle-off identity: with rs_enable_compact_single_row unticked, rendered DOM + screenshots match the Phase-0 baseline exactly.
  2. Byte-identical Hyper core: theme.css, header.js, search.js, and all menu/drawer/search snippets never change — verified by hash each phase.
  3. One of each: exactly one <nav> (desktop), one predictive-search form, one #MenuDrawer, one .header__bottom, one .header-section, one fixed overlay.
  4. header.js contract: .header__bottom and .toggle-navigation-button selectors resolve; setHeight() runs without error; all 5 CSS vars publish sane values.
  5. Panel geometry: open dropdown/mega panel rect has identical inline-start and width to baseline (numeric comparison, 4 widths).
  6. Mobile untouched: <1024px DOM and screenshots match baseline in every phase.

The build, phase by phase

Phase 0 — Cold backup + code baseline DONE 2026-07-22

Commit a2f9a723 · backups/2026-07-22-compact-header-prechange/ · SHA256 verified 7/7

Verbatim live copies of all 7 touch-files + MANIFEST with restore commands. Code baseline: settings snapshot, menu structure (4 top levels + children via Admin API), full variable-consumer inventory, architecture citations in work/header_audit/{claude_plan,codex_plan}.md.

Phase 0b — Visual baseline NEEDS: preview URL from Sean

~30 min · no theme changes

Through the Shopify share-preview link: screenshots + computed values (panel rects via getBoundingClientRect, the 5 header vars, class states) at 1024 / 1280 / 1440 / 1920 and mobile 375 / 768, EN + FR, top/scrolled, dropdown open, search open, drawer open. Stored under work/header_audit/baseline/.

Gate: baseline captured and eyeballed, or Sean explicitly accepts capturing it on the preview theme in Phase 2 instead.

Phase 1 — Inert schema additions ~45 min

File: sections/header.liquid (schema only) · pushed live is SAFE — everything default-off

Add to the header schema, each with RevShift - 2026-07-XX wording in its info:

  • header_layout option 4: logo-left-menu-inline — label “Logo left · menu inline (RevShift)”
  • rs_enable_compact_single_row checkbox, default false — the master kill-switch; info text explains off = exact current header
  • rs_compact_search_style select: field (default) | icon
  • rs_compact_vertical_padding range, default 12px (8–24)
  • rs_compact_search_width range, default 190px (140–320)
Gate: Theme Check passes · settings appear + save in editor · storefront pixel-identical (toggle off) · invariants 1–6 · commit.

Phase 2 — Guarded Liquid structure ~2 h

File: sections/header.liquid (markup) · built and QA'd on an UNPUBLISHED preview theme first

Create the preview theme: pull live → shopify theme push --path theme --unpublished (“RS DEV — compact header”). Then, all inside {%- if rs_compact_inline -%} branches:

  1. Assign block: derive rs_compact_inline = (layout is logo-left-menu-inline AND checkbox true); if the layout is selected but the checkbox is off, render layout logo-left-search-center — the one-checkbox revert mapping.
  2. Header classes: append header--rs-compact-inline when active.
  3. Move the nav render: inside .header__top, after the logo: the existing .header__bottom → .header__navigation → {% render 'desktop-menu' %} block, with an added modifier class header__bottom--rs-inline. Identical hooks, one render. The stock sibling row at the bottom renders only when NOT compact.
  4. Search branch: field → predictive-search render as-is in the compact grid area; icon → same render + icon control that focuses the input (label-for or 3-line shim), field visually collapsed until body.search-open.
  5. Collapse guard: in compact, do not emit the desktop .toggle-navigation-button (collapse is OFF per Sean; the native two-row branch keeps its behaviour for revert).
  6. No other markup moves: mobile trigger, drawer render, overlay, JSON-LD untouched.
Gate (preview theme): toggle-off DOM diff vs baseline = zero · toggle-on: invariants 3–6 · no console errors · editor section reload/reorder clean · commit.

Phase 3 — Compact CSS ~2 h

File: assets/rs-soft-modern.css — one dated contiguous block, all scoped .header--rs-compact-inline + @media (min-width:1024px)
  1. Row grid: .header__top--logo-left-menu-inline → areas logo navigation search icons, columns auto minmax(0,1fr) minmax(14rem, var(--rs-compact-search-width)) auto; vertical padding from the range setting.
  2. Inline nav cell: .header__bottom--rs-inline{ position:static } (makes .header__top the panels' containing block) · zero row paddings · suppress its ::after · .header__menu ul{ flex-wrap:nowrap }.
  3. Panel re-anchor (the critical pair): compact scope only — top-level .mega-menu / .dropdown at inset-block-start:100% and .mega-menu__container / .dropdown padding-block-start: 0 (kills the measured --header-navigation-height padding that would double the offset). Nested .dropdown .dropdown untouched.
  4. Search styles: field = pill input at var width; icon = collapsed-to-icon until body.search-open expands it across the search+navigation areas (pure CSS on existing classes).
  5. Logical properties throughout for RTL parity.
Gate (preview theme): one physical row at 1024/1280/1440/1920 EN+FR · panel rect numerically equal to baseline · search overlay full-row · sticky scroll clean (no collapse) · mobile identical · invariants · commit.

Phase 4 — RS component offsets ~45 min

Files: rs-section-nav.liquid/.css/.js · rs-brand-pills.liquid — the finding neither model had

These compute sticky offsets as --header-height − --header-navigation-height (they assume the collapsed two-row header). In compact, gate the subtraction on the header NOT being compact — e.g. offset = --header-height alone when .header--rs-compact-inline exists (CSS :has() or a body-level class emitted by the compact branch; JS mirror in rs-section-nav.js).

Gate (preview theme): PDP — section-nav and brand-pills stick exactly at the header's bottom edge, scrolled and unscrolled, both toggle states · commit.

Phase 5 — Full QA matrix on preview ~2 h

No new code — the gauntlet. Failures loop back to their phase.
AxisCoverage
Widths375 · 768 · 1023 · 1024 · 1280 · 1440 · 1920
LocalesEN + FR (menu fit gate lives here)
Statestop · scrolled-down (unpinned) · scrolled-up (pinned) · search open · dropdown open · drawer open
Interactionshover open/close timing · click-through on data-link · Escape · outside click · focus-in/out · Tab order
Search stylesfield AND icon (flip the select both ways)
Templateshome · collection · PDP (sticky ATC + section-nav) · search page · a policy page
Editorsettings save · section reload/reorder · block select (mega capability probe with a test block, then removed)
Degradationsno-JS (details fallback + no-js anchor rule) · reduced motion · 200% zoom · touch emulation
Revertcheckbox off → baseline identity; on again → compact returns with settings intact
Gate: full matrix green, screenshots archived to work/header_audit/qa/ · Sean reviews the preview theme link and signs off visually.

Phase 6 — Activation on live ~30 min · low-traffic window

Files: push header.liquid + rs-soft-modern.css + RS components (pull-then-push --only, per parallel-session rule), then header-group.json settings
  1. Push code files (still inert — checkbox off) · storefront spot-check: pixel-identical.
  2. Flip settings: layout logo-left-menu-inline + checkbox on + approved ranges.
  3. Live smoke: the Phase-5 short list (home/PDP, EN/FR, scroll, dropdown, search, mobile).
  4. Prove the revert: checkbox off → verify baseline → on again. Recorded.
Gate: live QA green · revert proven · Sean confirms on his own devices.

Phase 7 — Documentation + lockstep ~45 min

Per house convention — this is not optional polish
  • docs/shopify_code_changes/: dated entries for header.liquid, rs-soft-modern.css, header-group.json, the four RS component files (original + final per convention).
  • Backup manifest updated with final post-change hashes alongside the pre-change set.
  • PROJECT.md §Decision Log + §Change Log → mirrored to progress.html → deployed (lockstep rule).
  • Commit + push per session-end protocol.

Phase 8 — Post-live watch passive · 1 week

Re-verify after: any Hyper theme update (hash-check the byte-identical core list), any menu edit by Jessar (FR fit gate), and Michael's v9 class update landing (re-run the width stress against the real new menu before it ships).

Rollback ladder

TierWhenActionTime
1 · CheckboxAnything looks wrong post-activationEditor → Header → untick RS · Compact single-row. Liquid maps back to stock layout; compact CSS inert.< 1 min, no deploy
2 · Settings fileEditor unavailableRestore header-group.json from backup, push --only.~5 min
3 · NuclearBroken Hyper update, section replaced, B2C pivotbackups/2026-07-22-compact-header-prechange/ → verify SHA256 → restore all 7 files per MANIFEST.~15 min

Risks carried from the master plan — mapped to phases

RiskSevKilled in
Panel inherits nav-cell widthCriticalPhase 3.2 (static cell) + Phase 3 gate (numeric rect)
Double/missing panel offsetCriticalPhase 3.3 (anchor + padding pair) + gate
header.js null crashHighPhase 2.3 (hooks preserved, one render) + invariant 4
RS components stick under headerHighPhase 4 (dedicated phase)
FR menu overflow (now or v9)HighPhase 5 locale axis + Phase 8 v9 re-gate; icon search = 150px relief valve
Hyper update collisionMedPhase 7 docs + Phase 8 hash watch + Tier-3 backup
Editor/mega capability regressionMedPhase 5 editor axis (test mega block probe)

Prerequisites & open items

  1. Sean Paste the Shopify share-preview URL → unlocks Phase 0b now (else baseline moves to the preview theme in Phase 2).
  2. Sean Approve this plan → Phases 1–2 begin (Phase 1 is safe to push live same-day; Phase 2 stays on the preview theme).
  3. Note Phases 5→6 need one Sean review of the preview link before anything hits live.
  4. Note When Michael's v9 classes land, the new top-level menu re-runs the width gate before publishing (Phase 8).