demo.sessions.ca

Sessions Cannabis demo builds — independent versions, each at its own /vN/ path.

Pick a version to view it. Every deploy adds a new /vN/ folder; older versions stay browsable.

v203Jun 10, 20269:25 AM EDTCOPY/STYLE \u00b7 v203 \u2014 \u201cRecently Sold\u201d + Visit-heading gradient removed
v203 \u2014 (1) \u201cSessions Featured\u201d renamed to \u201cRecently Sold\u201d (eyebrow + heading). (2) Store-locator \u201cVisit [City]\u201d heading: removed the GradientText wrapper at its source in SophieHome.jsx \u2014 now renders in the static sl_heading color (#0D0D0B), no orange gradient.
v202Jun 10, 20269:10 AM EDTLAYOUT \u00b7 v202 \u2014 Section swap: Everyday Deals up / Sessions Featured down
v202 \u2014 Homepage section-order swap in App.jsx (not a DOM hack). Everyday Deals (DealsFold carousel) moved UP into the Featured slot (right after Shop By Category); Sessions Featured moved DOWN into the old DealsFold slot (after Store Locator, before Blog). New visible order: Shop By Category \u2192 Everyday Deals \u2192 Everyday Deals CTA \u2192 Store Locator \u2192 Sessions Featured \u2192 Blog.
v201Jun 10, 20268:40 AM EDTDEALS · v201 — Genuine Dutchie Everyday Deals special
v201 — Everyday Deals now shows ONLY the genuine Dutchie special. Dutchie Plus exposes one special per store (\u201cEveryday Deals - June\u201d); its products = the on-sale items. Dutchie can\u2019t paginate the menu or fetch a special\u2019s product list (20/query, no offset/specialId), so useDeals fans out the menu per category and unions the on-sale products (qty>1) to surface the full special. London genuinely has ~3 (Back Forty, Gnarberry, Kush Mint). Cards = product + new + struck old price; sub-heading fixed.
v200Jun 10, 20267:55 AM EDTFIX · v200 — Restored rotating deals (real product+price)
v200 — Restored the 3D rotating Everyday-Deals carousel (v199 collapsed to 1 card because only 1-2 live items are on sale). ROOT CAUSE found: the prod worker /api/menu returns only the first ~20 of 463 products (offset>0 -> 0; pagination bug, prod worker source not on this Mac). Fix: populate the carousel from the available real products — genuine SALES first (new + struck old price), then the rest at their regular price, qty>1 only — so the rotation has enough cards while honouring Darryl (real product + price, no fake promo copy). Proper full-deal-set fix requires fixing the worker pagination.
v199Jun 10, 20267:25 AM EDTFIX · v199 — Everyday Deals wired to store UUID
v199 — Fix for v198: DealsFold passed the v2 record id to useDeals instead of the Dutchie store UUID, so the live on-sale fetch returned 0 (section hid). Now passes store.store_id (UUID). Everyday-Deals cards show real on-sale products + price (new + struck old).
v198Jun 10, 20267:10 AM EDTUI · v198 — Everyday Deals = real products + price
v198 — Darryl: Everyday-Deals cards now show the actual on-sale PRODUCT + PRICE (new price + struck-through old price), not promo-concept copy. Rewired useDeals() to pull genuinely on-sale items from the LIVE Dutchie menu (variant.on_sale / price_special1) per selected store; DealCard3D bottom band shows brand + name + $new (accent) + $old (line-through) + size. Dropped the promo claims (e.g. \u201c15% OFF FIRST BASKET / First-Time Customer / over the counter no fuss\u201d). Section hides if a store has zero live on-sale items.
v197Jun 10, 20266:15 AM EDTLOGIC · v197 — Live-only (removed dead D1 cache path)
v197 — Confirmed + cleaned: the entire price/availability path is LIVE Dutchie only. Shop+homepage listing = live menu (v181, no D1 fallback). PDP price/stock = live cross-store fan-out. Removed the orphaned D1 reader (fetchFromWorkerProducts/d1_cache) so there is zero stale-cache code in the listing module. The only D1 touch left is the PDP product IMAGE/description (cosmetic, not price/availability).
v196Jun 10, 20265:55 AM EDTLOGIC · v196 — qty≤1 hide applied to ALL stores/products
v196 — Applied Darryl\u2019s availability rule everywhere on LIVE Dutchie quantity: hide any product/store-listing with qty≤1 (show only ≥2). Already on shop + homepage (v189); now also on the PDP cross-store \u201cAvailable at N stores\u201d list (was qty>0). Net effect: only genuinely-buyable items/stores are listed \u2014 removes the dependency on the Dutchie whitelist IP for not-listing-unavailable-products. Checkout still re-validates live (the qty>1 buffer makes the sell-out race rare, not impossible). The whitelist remains useful only for the separate cross-store availability index.
v195Jun 10, 20265:40 AM EDTUI · v195 — Removed homepage shop catalog
v195 — Removed the homepage-embedded full product catalog (the sticky search + category-pills bar and the product grid + Load more). Product browsing now lives on the dedicated /shop page (ShopPage), which is unchanged. Homepage is now a clean landing page (hero, categories, deals carousel, locations, blog, store map).
v194Jun 10, 20265:20 AM EDTUI · v194 — Removed Rewards/Freshness/Delivery promo strip
v194 — Removed the homepage Rewards + Freshness Guarantee + Delivery promo bento (RewardsPromoStrip). All prior v187-v193 changes retained.
v193Jun 10, 20265:05 AM EDTUI · v193 — Stats line (CSS) + removed This-Week bento
v193 — (1) Removed the stats divider line at its real source: a stylesheet rule .sc-stats-grid { border-top } in global.css (the inline one was already gone). (2) Deleted the old "This Week at [store]" bento section (StorewideDeals) so the homepage has a single deals section — the Everyday Deals 3D card carousel (DealsFold). Stat cards remain centered (v192).
v192Jun 10, 20264:30 AM EDTUI · v192 — Stat cards centered
v192 — Centered the hero stat cards (align-items + text-align center; was left-aligned) and confirmed no top divider line on the stats band. Numbers from v191 retained: 50+ Ontario Locations / 374 Avg SKUs per store / 4.7 rating / 6 yrs.
v191Jun 10, 20264:15 AM EDTUI · v191 — Stats band restored + fixed (Darryl)
v191 — RESTORED the hero stats band (it was wanted, not removed) and removed the thin divider LINE crossing above it (border-top on .sc-stats-band). Applied Darryl\u2019s number fixes: "Ontario locations" now uses the real store-master count (50) instead of the inflated/duplicated 76; "Live SKUs daily / 132K" replaced with "Avg SKUs / store" computed from live per-store counts (Darryl: avg per store, not a misleading total). 4.7 rating + 6 yrs kept. All v187-v190 cleanups retained.
v190Jun 10, 20263:55 AM EDTUI · v190 — Removed inaccurate stats band (Darryl)
v190 — Removed the homepage hero stats band (76+ Ontario Locations / 132K+ Live SKUs Daily / 4.7 / 6yrs). Darryl flagged "76+" as incorrect and "132K Live SKUs daily" as misleading. Rather than ship invented numbers on a live cannabis site, the band is removed until Darryl provides the correct figures (e.g. real location count + avg SKUs per store split cannabis/accessory). Everything else from v187-v189 retained.
v189Jun 10, 20263:30 AM EDTUI · v189 — Darryl review batch 2 (visible cleanups)
v189 — More of Darryl\u2019s review actioned (visible homepage changes): (1) HIDE products with qty\u22641 across shop + product surfaces (Darryl\u2019s race-condition rule \u2014 never list a near-OOS item). (2) FEATURED section no longer surfaces apparel/accessories/merch/topicals (kills the \u201c6-year-old t-shirt\u201d that doesn\u2019t sell). (3) HIDE the placeholder Reviews section (fake reviews; awaiting a real review system). (4) REMOVE the floating \u201cFollow \u00b7 25% off\u201d pill (unverifiable offer, dead link, wrong handle). (5) HIDE the Instagram tile feed (account is private \u2014 cannot show a live feed). Plus: added physical SPA route folders so deep-links/refresh on /v189/shop, /cart, /product, /location, /rewards, /blog resolve to the app (not the picker). HELD (need Darryl figures / Sophie content / data-wiring): exact stats numbers, the Everyday-Deals real-product feed (needs Dutchie specials API), per-store distance sort (needs geolocation), programs/rewards copy.
v188Jun 10, 20262:55 AM EDTCOMPLIANCE · v188 — Per-store CRSA license fix (SADD-006 E.1)
v188 — REGULATORY FIX. The footer/PDP CRSA licence number was hard-coded to a single value (CRSA1382440) whenever the store-record fuzzy match missed — so different stores showed the SAME wrong licence (Cannabis Act/AGCO compliance exposure). FIX: built an address-VALIDATED UUID→CRSA map (48/50 stores; only map when the store master address and the licensed address are the same physical building). This caught a real data hazard — stoney-creek and red-hill had their ids/addresses swapped between datasets, which an id-only match would have mislabelled — and resolved them by true address instead. Footer now binds the licence to the active store by UUID; when a store has no verified licence on file (2 stores: Laurelwood, St. Catharines — data gap flagged for Sophie/Amber) it shows the generic “Ontario Authorized Cannabis Retailer” with NO number, never a false one. Verified per-store on production: London South→CRSA1480667, Oshawa→CRSA1172585 (previously both showed CRSA1382440).
v187Jun 10, 20262:20 AM EDTUI · v187 — Homepage cleanup (Darryl review · P0)
v187 — First implementation pass from the Darryl × Ravi review (SADD-005/006). Three selector-grounded removals, each mapped to source then verified against the live DOM: (B1) removed the auto-scrolling category marquee (TrustStrip / LogoLoop “Sessions categories” — the Indica/Sativa/Hybrid pills Darryl said “remove that”). (B2) removed the 4 non-clickable store-address cards from the orange footer; kept the footer nav-link columns. (B3) removed the PDP “Available at N Stores” + “Search city…” sidestep bar; kept the per-store availability list, “+ Show more stores”, and location pills below — only the redundant header/filter chrome removed. No content invented: stats numbers + everyday-deals label cleanup held for Darryl’s actual figures; Instagram / reviews / first-fold / footer-image held for Sophie’s sign-off. Promos untouched.
v186Jun 9, 20263:49 AM EDTBACKEND · v186 — Live Dutchie data layer (cut-the-cache)
v186 — BACKEND ARCHITECTURE UPDATE (no frontend change; v185 remains the latest UI). The D1 scrape cache was a drifting second source of truth (wrong prices, papers-over-flower search, stale availability). DECISION (Solution A): cut the cache, read LIVE from Dutchie Plus through a Cloudflare Worker (Cloudflare-origin clears Dutchie’s bot-challenge; the Hetzner datacenter IP does not). Stood up an ISOLATED preview worker (sessions-availability-edge-demo, own empty D1, cannot touch promos). Built + live-verified /api/v2/products (ranked search: blueberry→flower, 510→carts, gummies→gummies) and /api/v2/product-stores (live cross-store by enterpriseProductId). V1–V4: store-scoped is pure-live; cross-store needs a wholesale-rebuilt index. Promos untouched. Click to read the full log →
v185Jun 5, 20265:02 AM EDTLATEST · v185 Mobile filter bottom-sheet (Ravi diagnosed + live-tested fix)
v185 — Ravi diagnosed + tested live in browser: .shop-layout grid traps mobile swipes inside .fs-aside (max-height:573 + overflow-y:auto + scrollHeight:1448 = internal scroll container). User scrolls filter sections instead of page; products physically render 1738px down (unreachable); no search escape hatch. FIX (mobile bottom-sheet pattern): (1) .shop-layout display:block !important on mobile (breaks the trapping grid); (2) .fs-aside becomes position:fixed bottom drawer, transform:translateY(100%) hidden by default, max-height:80vh, overscroll-behavior:contain (scroll stays in sheet), border-radius 20px top, z:1000, padding-bottom:96 to clear sticky checkout; (3) body.fs-filters-open class triggers slide-up via transform:translateY(0); (4) Real React-rendered .fs-filter-scrim div (NOT body::after) at z:999 with onClick=close (pseudo-elements can't carry React handlers); (5) Floating #fs-filter-trigger pill (dark Sessions green #0f3d2e — orange reserved for cart-rail CTA) at bottom-LEFT 84px above FAM-toggle at 14px (70px gap, no collision). Composes with v184 cart-rail bottom-right z:9500 untouched. ShopPage.jsx adds filtersOpen state + useEffect body class sync + Escape-to-close. Mirrors 21st.dev bottom-sheet pattern referenced in handoff doc.
v184Jun 5, 20264:42 AM EDTARCHIVE · v184 Cart-rail horizontal pill
v184 — Ravi: "checkout button went missing but make sure it stays always and for mobile view it should be horizontal instead of vertical." ROOT CAUSE (3 stacked): (1) .cart-rail-cta-shiny used color:transparent + -webkit-background-clip:text (gold-on-white shine gradient on text) which sometimes rendered invisible against the orange rail bg on certain mobile browsers/states; (2) cart-rail had no explicit z-index in v179 mobile rules — defaulted to source z:250, while FAM at z:9000 + sc-promo-flag at z:40 also bottom-right-positioned, causing potential overlap; (3) hover:width-grow rule applied even on touch devices. FIX: explicit z:9500 on cart-rail (above FAM), SOLID white CHECKOUT pill background with #C96A2C text (not transparent gradient — kills the invisible-text class entirely with -webkit-text-fill-color override), 4-element horizontal pill layout (icon32+count16 / / CHECKOUT pill — limit-track hidden), FAM toggle MOVED to bottom-LEFT on mobile (was right) to clear cart-rail zone, sc-promo-flag legacy FOLLOW pill HIDDEN on mobile (was bottom:16 right:16 colliding). Three breakpoint cascade: 768px (pill 52px), 480px (48px), 360px (44px) — CHECKOUT visible at all sizes. Pattern inspired by 21st.dev floating-action-menu reference doc Ravi uploaded (single trigger, consolidated bottom-right zone, orange reserved for primary CTA).
v183Jun 5, 20264:12 AM EDTARCHIVE · v183 SPA fallback fix (location pages)
v183 — CRITICAL routing fix. Ravi reported: "shop location page... no page at all. Any of the individual shop locations, 50 locations, what happened to them?" Empirical probe confirmed: /v182/location/dalhousie returned the PICKER (152KB, title "Demo versions") instead of the SPA. Root cause: 3 stacked failures. (1) _redirects file was written to /v182/_redirects but CF Pages only reads it at DEPLOY ROOT, not inside subfolders — the SPA fallback rule never fired. (2) No physical folders existed for /v182/location/{slug} — CF Pages fell through to root /index.html (the picker) for every unknown slug. (3) This bug existed since at least v149 — affecting EVERY versioned deploy that used dynamic routes. THE FIX (3 layers): (A) Root-level dist-v183-full/_redirects with /v183/location/* → /v183/location/index.html 200 + same for /product + /shop + /cart. (B) Pre-built physical folders for all 146 known store slugs (50 stores × 3 variants: id, slugified-name, short-name) under /v183/location/{slug}/index.html. (C) ALSO backfilled the same fix into v182 paths so demo.sessions.ca/v182/location/dalhousie now resolves correctly via the root _redirects + physical folders. Local-served the build, verified SPA title returns (not picker) for every test path before deploy. Both v183 AND v182 location routes should now serve the SPA, store-pick flow should land users on the right page.
v182Jun 5, 20264:02 AM EDTARCHIVE · v182 PDP lazy cross-store
v182 — PDP architectural honesty fix (Ravi flagged: "cross store is decorative means the number isnot true?"). The "Available at N Stores" widget was reading D1 product_availability snapshots from the hourly scraper — prices and "10 left" qty were stale. (1) Auto-fetch of fetchProductStores DELETED — PDP no longer hits /api/product-stores → D1 on mount. (2) NEW lazy-expand UI: pre-expand state shows a CTA "Find at other Sessions stores ↓" inside a warm dashed pill. (3) Click → triggers findProductAcrossStores() in src/api/menu.js — fans out fetchMenu() across all ~50 stores in batches of 6 (browser-safe concurrency), filters each store's LIVE Dutchie menu for matches by product name + variant size, returns real-time price + qty. (4) Per-store cards still use the original storeCard JSX but with REAL Dutchie numbers — no more ".73 In stock" lies. (5) StockPill above the fold reworded: pre-expand shows neutral "Available across Sessions stores", post-expand shows accurate "In Stock at N of M stores". Stores that error (Dutchie 404 retailer not found, network fail) are silently skipped — graceful degradation. Architecture: completes v181's Dutchie-direct commitment by removing the last D1 read path from user-facing surfaces. /api/product-stores endpoint now orphaned.
v181Jun 5, 20263:53 AM EDTARCHIVE · v181 Dutchie-direct + mandatory store gate
v181 — Architecture pivot. Ravi directive: "no cross store force ask them." (1) Mandatory store-gate added to useEntryFlow as new step between AgeGate and done — picker has no close X, no backdrop dismiss, no skip. After AgeGate confirms with no selectedStore, the picker is the only thing on screen until a store is chosen. (2) StorePicker.jsx gets new mandatory={true} prop that hides close affordances and swaps title to "Select a Store to Continue" with explanatory subtitle. (3) useProducts.fetchProducts D1 fallback (fetchFromWorkerProducts → /api/products) DELETED. Now Dutchie-direct only via tryLiveMenu → /api/menu. If no storeId → returns empty without fetching. If Dutchie unavailable → surfaces error instead of silently swapping to D1 cache. (4) useEntryFlow boot path also checks store: ageOk && !selectedStore → step=store_gate. App.jsx renders mandatory picker on store_gate step. Auto-advances to done when selectedStore becomes set. (5) HeaderV2 hidden during store_gate (per AgeGate convention). Architectural consequence: D1 cross-store availability layer becomes orphan infrastructure — every product fetch now goes through Dutchie live per-store. Decommission of scraper/data-worker/D1 deferred to v182+ once Canary confidence builds.
v180Jun 5, 20263:15 AM EDTARCHIVE · v180 BUG-201 header flex fix
v180 — BUG-201 section-header flex-row squeeze fix (Ravi verified live). v179 collapsed grids but not flex rows; section headers like 'Sessions Featured' got squeezed to 77px causing mid-word breaks ('Sessi/ons/Featu/red'). Fix: @media max-width:768 flex-wrap:wrap on row containers via :has(h2/h3), heading column flex:1 1 100% via :has(> h1/h2/h3), and word-break:keep-all + overflow-wrap:break-word + hyphens:none on all h1-h4. Plus shipped findings on BUG-202 + worker-account investigation (see github centilio-hub/v180-bug201-bug202-worker-investigation).
v179Jun 5, 20262:46 AM EDTARCHIVE · v179 Mobile hotfix
v179 — FULL Ravi mobile hotfix applied + duplicate menu button killed. RC-1 desktop padding 140px neutralized via [style*='140px'] inline-style targeting. RC-2 overflow-x:hidden + min-width:0 on all children stops horizontal scroll + lets content shrink. RC-3 fluid clamp() headings 28→40→26→20 across breakpoints. RC-4 cart-rail RELOCATED (not hidden) as horizontal pill bottom-right, un-rotated CHECKOUT label, hides limit-track. RC-5/6 grid-template-columns collapsed to 1fr — recovers off-canvas map+contact+hours that were being clipped. CRITICAL FIX: v173 [data-cart-rail] selector was WRONG (actual class is .cart-rail) — that's why the rail never hid; v179 uses correct selector. JS bug: FloatingActionNav simplified — was v173's full FAM with 7 nav items + 'Open menu' aria-label duplicating HeaderV2 hamburger. v179 strips to single small DESKTOP/MOBILE toggle pill (escape hatch only). 480px + 360px refinement breakpoints + prefers-reduced-motion gate for marquees.
v178Jun 5, 20262:19 AM EDTARCHIVE · v178 Store picker mobile (still LATEST for store picker, v179 adds whole-page mobile)
v178 — Store picker mobile fix at source (Ravi handoff). Resolved TWO-competing-UI problem: HeaderStoreDrawer wrapper was rendering StorePicker INSIDE its own slide-panel = double-modal-nesting. Killed wrapper, HeaderV2 now mounts StorePicker direct. BUG1 fixed: StorePicker s.overlay zIndex 200→1000 (was under cart rail z:250). Desktop default: centered modal (alignItems:center, borderRadius:24 all corners). Mobile @media (max-width:600px): bottom-sheet pattern (alignItems:flex-end, borderRadius:20 20 0 0, max-height:90vh). iOS safe-area paddingBottom env(safe-area-inset-bottom). All at source per Ravi 'remove at source' rule — no !important overrides this time (except media query mobile bottom-sheet which needs to win over inline center alignment). Row already had flex+truncation in v117. Mobile v174 preserved.
v177Jun 5, 20261:24 AM EDTARCHIVE · v177 Hero alignment (Hero done, v178 fixes store picker)
v177 — CORRECTED v176 double-padding mistake (Ravi flagged). Mistake: v176 applied padding-inline:64 to BOTH .sc-hero-section AND .sc-hero-row nested inside it = 128px effective gutter on hero content vs 64 on header = STILL misaligned. Plus kept 87.6 inline paddingInline in S.split source. Fix: (1) REMOVED paddingBlock + paddingInline from S.split JSX source (Ravi explicit), (2) REMOVED maxWidth + padding from S.secondaryInner source (inherits from .sc-hero-section parent), (3) dropped padding-inline + max-width + margin-inline from .sc-hero-row CSS (ONLY vertical 24 0 + flex), (4) dropped .sc-secondary-inner from shared-container selector list. Architecture: ONE source of horizontal gutter per nested level. Header has own container; Hero
has own container; hero children inherit. Stats-band is SIBLING section so its grid still needs own max-width+gutter.
v176Jun 5, 20261:04 AM EDTARCHIVE · v176 double-padding bug — superseded by v177
v176 — Full Ravi handoff at SOURCE. FF1: --sc-maxw 1440 + --sc-gutter 64 tokens on .sc-header-v2-inner AND .sc-hero-section AND .sc-secondary-inner AND .sc-stats-grid — brand.left == headline.left predicted at 219px. FF2: .sc-hero-row padding 87.6→24px (no more dead vertical space); wheel column 460px anchored flex-end to kill side-gap; .sc-wheel3d-host sized 440x440 directly. SF1: .sc-backed-panel background:#FFFFFF → transparent at SOURCE in Hero.jsx S.secondary (dissolved white box). SF2: .sc-stats-band transparent + .sc-stat-card transparent (no border/radius/shadow) + hairline vertical dividers via ::before. SF3: gap 112px → 72px (panel paddingBottom 40→24, band paddingTop 48-72→32). All gated @media (min-width:768px) — mobile v174 preserved.
v175Jun 5, 202612:45 AM EDTARCHIVE · v175 desktop Hero alignment (partial — v176 adds Backed+Stats dissolve)
v175 — Desktop Hero alignment fix per Ravi YAML diagnostic. FX1: shared layout tokens (--sc-maxw:1440, --sc-gutter:64) applied to BOTH .sc-header-v2-inner AND [data-claude-hero] — brand.left now equals headline.left (was 24 vs 90, 66px gap). FX2: Hero columns optically centered align-items:center, text flex 1 1 50%/max 560px, wheel column flex 0 0 auto fixed 400x400. FX3: .sc-wheel3d-host sized directly NOT via transform:scale (would compound with internal rotateY = sliver artifact). Plus production-grade ResizeObserver attached: notifies R3F Canvas to rebuild drawing buffer when host box changes, avoids buffer/CSS-box mismatch. Mobile (v174) unaffected — desktop rules gated @media (min-width:768px).
v174Jun 5, 202612:36 AM EDTARCHIVE · v174 Mobile Hero overflow fix
v174 HOT-FIX — Mobile overflow + Hero stack + hide rotating wheel. Ravi screenshots showed iPhone 14 Pro Max (430px) page overflowing horizontally because Hero.splitLeft minWidth:320 + splitRight minWidth:480 = forced 800px+ layout. Plus hardcoded Sesh fontSize:64. Plus rotating SessionsWheel3D dominating mobile (Ravi: no need on mobile). Patches: (1) useViewport hook imported in Hero, (2) inline-injected mobile media query via data-hero-mobile=1 attribute hooks: column stack, no minWidth, font 36/32/14, hide splitRight (the wheel) on mobile entirely, (3) body overflow-x:hidden safeguard. FAM continues to render bottom-right (was off-frame in Ravi screenshots which only showed top of viewport).
v173Jun 5, 202612:31 AM EDTARCHIVE · v173 Mobile foundation (Hero overflow + wheel still on mobile)
v173 EXECUTE — Mobile-mode foundation. NEW: useViewport hook (single source of truth for breakpoints), useLayoutMode hook (auto vs force-desktop, localStorage persisted), MobileContainer + .sc-fluid-pad CSS (140/64/20/16 4-stop responsive padding kills 15x desktop-only anti-pattern), FloatingActionNav branded Sessions orange/cream FAM at bottom-right with 7 nav items + 'View desktop version' toggle. When user opts force-desktop on mobile → FAM shrinks to small 'MOBILE VIEW' pill. Body class sc-mobile-fam-active drives selective hides. Hero typography mobile cascade in global.css (.sc-h1 60→36→30 across breakpoints) — prevents 'YOUR NEXT' clipping to 'KT' at 390px viewport. PersistentCartRail hidden on mobile (collides with FAM + content) — v180 will migrate to bottom-sheet. Real-device test needed (Chrome MCP can't trigger CSS mobile breakpoints).
v171Jun 4, 202611:34 PM EDTARCHIVE · v171 count animation
v171 — Bulletproof count animation. Dropped IntersectionObserver entirely (3D-transformed cards confused IO bounds — never fired). NumberAnim now animates on component mount. For focal deal cards: ElectricBorder wrap/unwrap remounts NumberAnim on each focal transition, so count re-fires every landing. Side cards mount once on page-load. Mount-fire useEffect with [] deps + startedRef guard + RAF loop + easeOutCubic over 0.9s. Should ACTUALLY visibly count this time.
v170Jun 4, 202611:31 PM EDTARCHIVE · v170 native IO — IO never fired in 3D-transformed cards
v170 — Native IntersectionObserver replaces framer useInView in NumberAnim (suspect: useInView inline options re-fired on parent re-renders, restarting tween every frame). hasStartedRef guard + threshold:0.01 + observer.disconnect() after first intersect. console.log diagnostics added. Should produce visible count progression.
v169Jun 4, 202611:29 PM EDTARCHIVE · v169 cubic tween (still 0 after 1.5s — useInView suspected)
v169 — Replaced reactbits CountUp spring with deterministic NumberAnim cubic-ease tween. v167/v168 CountUp spring never visibly settled in Canary tests (probes at T+1s and T+2s showed target still 0). New src/components/reactbits/NumberAnim.jsx uses useInView once:true viewport trigger + requestAnimationFrame loop + easeOutCubic over 0.9s. Deterministic: guaranteed to reach EXACT target value. DealCard3D + DealExpandModal use it for percentage count UP (0→target). ProductCard uses it for price count DOWN (1.4x→target, prefix $, decimals 2).
v168Jun 4, 202611:26 PM EDTARCHIVE · v168 count spring fix (spring still slow — v169 uses tween)
v168 — Hot-fix v167 count spring overdamping. v167 CountUp was using damping=20+40/dur stiffness=100/dur — damping ratio ~2.8x overdamped, count took 5-10s to visibly reach target. Patched CountUp.jsx with optional damping/stiffness props; DealCard3D + DealExpandModal + ProductCard now pass damping=18 stiffness=140 (slightly underdamped, subtle overshoot, ~0.8s settle). Percentages count UP 0→target visibly. Prices count DOWN ~1.4x→final visibly. useInView once:true viewport-entry trigger preserved.
v167Jun 4, 202611:23 PM EDTARCHIVE · v167 count animations (superseded by v168 spring fix)
v167 — Attention-span number animations. Percentages count UP from 0 (deal discounts) and prices count DOWN from ~1.4x to final (product cards). Trigger: framer-motion useInView once:true, fires when element enters viewport (any pixel). Files: (1) CountUp.jsx new optional decimals prop, (2) DealCard3D bottom-band discount line parsed via regex (trailing number animated UP), (3) DealExpandModal big discount text same treatment, (4) ProductCard price wraps with CountUp DOWN direction decimals=2. Spring damping 20+40/duration, stiffness 100/duration — premium feel. On first scroll into view: '30% OFF' counts 0→30 over 1.4s; '$25.99' counts $36.39→$25.99 over 1.4s.
v166Jun 4, 202611:08 PM EDTARCHIVE · v166 ElectricBorder containment (superseded by v167 count animations)
v166 — Fixed ElectricBorder bleeding into focal card content. v165's lightning crackles were punching ~60px INWARD due to chaos=1.0 + canvas z-index above content. Two-line fix: (1) src/components/reactbits/ElectricBorder.css .eb-content z-index 1→5 so card content masks the inward portion of the canvas; (2) DealCard3D chaos 1.0→0.35 dials down noise displacement. Result: lightning stays ON THE BORDER (outer halo glow still visible beyond card bounds), product image + headlines + discount + CTA pill all unobscured. CTAJump notification-pulse from v165 preserved unchanged. Affects ElectricBorder shared component — also improves HomeSections category bar usage (chaos 0.4/0.7 there, same z-index win).
v165Jun 4, 202611:02 PM EDTARCHIVE · v165 CTA notification-pulse (superseded by v166 ElectricBorder containment fix)
v165 — CTA notification-pulse polish. When a deal card lands focal (after auto-rotate or click), its CTA pill JUMPS: spring scale 0.88→1.0 stiffness 380 damping 14, then enters continuous breath loop 1 → 1.18 → 1 → 1.05 → 1 over 2.4s with 1.4s repeatDelay. Two concentric ripple rings (per-deal accent color) expand outward + fade, staggered 600ms, looping every 1.8s while focal. Box-shadow pulses with scale — orange glow grows then contracts. On defocus all animations stop cleanly back to plain text. Reference: Claude desktop notification chip wake-up. Single file: src/components/deals/DealCard3D.jsx +89 lines (new CTAJump subcomponent). DealsCarousel3D unchanged.
v164Jun 4, 202610:29 PM EDTARCHIVE · v164 3D Deals Carousel — superseded by v165 (CTA pulse polish)
v164 — 3D Deals Carousel (NEW). Replaces the GalleryDeals 4-blank-tile grid (fold 12) with a rotating 3D card carousel on a dark fold bg. Six brand-colored deal cards orbit in 3D space — focal card center with ElectricBorder lightning halo, neighbor cards at +/-25deg / +/-340px with subtle accent tint, auto-rotates every 4.5s, pauses 8s after any click. Click focal card opens full-screen DealExpandModal with discount, eligible products, validity dates, and store-aware CTA. Seed includes live Dutchie special "Everyday Deals - June" (special 6a19fdca1a59b80089fda097, Carlisle 605513b5e2d86a00cd247e75) plus 5 brand companions (Freshness Drop, SESH Reserve, First-Time, Birthday Bonus, Concentrate BOGO). Files: src/components/deals/{DealCard3D, DealsCarousel3D, DealExpandModal}.jsx + src/data/dealsSeed.js + src/hooks/useDeals.js + src/sections/DealsFold.jsx. App.jsx: GalleryDeals replaced with DealsFold. v164.5 ships /api/specials Worker proxy.
v163Jun 4, 20269:15 PM EDTARCHIVE · v163 cart drawer multi-store badges + MultiStoreCheckoutModal
v163 — Cart drawer per-store visibility + multi-store checkout picker. Patch C: PersistentCartRail computes itemsByStore, shows orange warning bar when cart spans 2+ stores, adds per-item store-name badge chip (visible only in multi-store). Patch D: useCart new actions requestMultiStoreCheckout / cancelMultiStoreCheckout / checkoutOneStore; new MultiStoreCheckoutModal globally mounted, listens for pendingMultiStoreCheckout. PersistentCartRail checkout button intercepts multi-store cart → opens modal instead of going to /cart → user picks store → checkoutOneStore(sid) calls Worker with that store only, removes those items on success so other store stays in cart for next checkout.
v162Jun 4, 20269:05 PM EDTARCHIVE · v162 (cross-store UX) — superseded by v163 (Patches C+D land)
v162 — Cross-store cart UX. Ravi: silent location switch + silent cross-store add no-op causing double Dutchie checkouts. Fixes: (1) Toast w/ Undo when /location/:slug auto-switches selectedStore — user sees "Now shopping at X · ← back to Y". (2) CrossStoreCartModal (NEW) pre-empts add when cart has items from another store — "Switch to Y (clears N items)" vs "Keep X cart". (3) useCart commit/cancelPendingSwitch handlers wire to the existing v147 R5 pendingStoreSwitch state (built but never consumed). (4) Toast component now supports action prop. Spec committed first per Ravi rule: github.com/ravigandhiarulagent1/centilio-hub/blob/main/v162-cross-store-cart-ux/DEEP-PLAN.md
v161Jun 4, 20268:37 PM EDTARCHIVE · v161 superseded by v162 (cross-store UX)
v161 — Per-store landing page hero upgrade. Ravi: "images compressed too much, look stretched, blank on header, not premium". Fixes: (1) hero minHeight 280→480px so photo gets proper proportions, (2) real with objectFit:cover + objectPosition:center 40% (bias toward storefront sign at photo top-half), (3) dark gradient overlay 0→55→75% so title/badges read clearly over any photo, (4) store.id-first lookup so SSM Hillside vs WestSide get their own different photos, (5) eager load on hero img (no lazy delay).
v160Jun 4, 20268:17 PM EDTARCHIVE · v160 superseded by v161 (per-store hero premium)
v160 — Same-city collision fix. Sault Ste Marie has 2 stores (Hillside + WestSide), Hamilton has 5 (Red Hill, Rymal, Rosedale, Mohawk, Dundurn). v159 lookup keyed on short_name which collides. v160 patches: (1) getStoreAssets normalizer strips PERIODS too (St. Catharines→st-catharines), (2) mergeStoreData tries store.id FIRST then short_name (so each location-specific id resolves to its own photo), (3) explicit entries for sault-ste-marie→WestSide, hillside→Hillside, st-catharines→Welland fallback.
v159Jun 4, 20267:43 PM EDTARCHIVE · v159 superseded by v160 (multi-store-per-city fix)
v159 — Authoritative explicit slug→photo map (no auto-guessing). 50 of 50 stores now have a photo entry in storeAssets.js. SESH 4/4 + Sessions 46/46. Includes Etobicoke→Albion fallback, Oshawa→NorthYork fallback, Ottawa→Brockville fallback for stores Sophie hasn't shot. Fixed mini-push rebase from v158.
v158Jun 4, 20267:20 PM EDTARCHIVE · v158 superseded by v159 (authoritative map)
v158 — THREE fixes: (1) storeAssets.js: filled 12 null photo entries + added 16 new slug entries (Humberlea, Wasaga Beach, Welland, Strathroy, Sudbury, Thunder Bay, Timmins, Tottenham, Sarnia, StoneyCreek, SSM, etc.). 60 of Sophie's 50 photos now have at least one slug mapping (multi-alias for typos). (2) LocationsPage StoreCard: "Shop location" CTA was buildStoreMenuUrl(uuid) → hard redirect to https://www.sessions.ca/{slug}/ (production WordPress, ORPHAN from demo). NOW goes to /v158/location/{storeSlug} — the per-store demo landing page. (3) PNGs Wasaga/Humberlea/Sarnia converted to JPG (q80, 1600px) — 392K/352K/296K each. Empirical Canary DOM verify pending.
v156Jun 4, 20266:48 PM EDTARCHIVE · v156 superseded by v158 (more photos + Shop button fixed)
v156 — Sophie's 50 storefront photos now display in Locations card heroes (was orange-gradient placeholder + Google Maps embed). Root cause of v154/v155 silent failures: phone-camera originals 5712×4284 at 4.3MB each — browser hung decoding 100MB of images. Fix: `sips --resampleHeightWidthMax 1600 --setProperty formatOptions 80` brought Aurora.jpg 4.4MB → 519KB. Plus `getStoreAssets()` patched to prepend `import.meta.env.BASE_URL` so /vN/-scoped paths resolve correctly. Empirical Canary DOM: 26/50 cards loaded photos, 0 failed, 0 hung. Remaining 24 are SESH stores whose storeAssets entries weren't auto-generated. Commit 0f8a8fce on hub+mini.
v155Jun 4, 20266:44 PM EDTARCHIVE · superseded by v156 (same fix, larger uncompressed photos)
v155 — First attempt at fixing photo URL resolution. Patched `getStoreAssets()` to prepend `import.meta.env.BASE_URL` so paths resolve to /v155/assets/store-photos/X.jpg instead of /assets/store-photos/X.jpg (which served picker HTML, not JPEG). Also converted SESH HEIC files to JPG via `sips -s format jpeg`. SESH-slug entries (dalhousie, komoka, main, king-st) injection silently failed — superseded by v156 which added compression.
v154Jun 4, 20266:35 PM EDTARCHIVE · superseded by v156 (photos didn't actually render until v156 compression)
v154 — LocationsPage StoreCard renders when Sophie photo available, falls back to lazy Google Maps embed. `mergeStoreData()` now reads getStoreAssets(short).photo as photo source. Looked like 26/50 cards had photos in DOM (img tag present) but they failed to load in browser due to 4MB+ size + lazy attribute. Commit 02b60adb on hub+mini.
v153Jun 4, 20266:03 PM EDTARCHIVE · LocationsPage Sophie hero + #611 SPA fallback fix (still LIVE)
v153 — TWO fixes: (1) LocationsPage.jsx now imports StoreMapCTA from SophieHome and renders Sophie's "40+ Stores Across Ontario" Ontario-map hero as top fold. (2) Fixed #611 SPA fallback — /v153/locations was returning the 123KB picker HTML instead of SPA shell. Created 19 flat-route folders + 176 /location/:slug folders × physical SPA shells. Now /v153/locations + /v153/location/:slug return 1166B SPA correctly. Empirical Canary DOM: 5/5 Sophie strings rendered. Commit e07a6200 on hub+mini.
v152Jun 4, 20265:18 PM EDTARCHIVE · per-store page extended (still LIVE, no SPA fallback so route 404s)
v152 — Extended LocationProfilePage.jsx (the /location/:slug per-store route) with 3 Sophie Figma folds from Sessions Cannabis (13) export: ShopByCategory 8-icon row, StorewideDeals per-store dual card, StoreMapCTA 40+ Ontario map. Renders between live Dutchie product grid and Footer. Bundle-string verified but /v152/location/:slug returned picker (SPA fallback not yet fixed — that came in v153). Built source patch only.
v151Jun 4, 202611:41 AM EDTARCHIVE · v151 (superseded by v152→v156; this was the universal HeaderV2 ship)
v151 — Made HeaderV2 truly universal. Per Ravi: "why is there no universal header why is it broken for every page". (1) ProductDetailPage.jsx dropped its 'import Header' + Header mount (was rendering the old blue v140 3-layer banner on every PDP). (2) App.jsx mounts HeaderV2 ONCE at top level when not in age_gate — automatic for every route. (3) Removed 26→3 per-route HeaderV2 wraps that were duplicate / inconsistent. (4) HomePage's inline HeaderV2 mount also removed (was duplicate). Result: identical header on /, /shop, /locations, /product/<name>, every other route. No more per-page Header wiring. Pairs with v150 canonical nav (Shop · Locations · Our Vibe · Our Programs · Rewards · Gift Cards · Blog) + physical folder SPA fallback.
v150Jun 4, 20268:48 AM EDTARCHIVE · v150 (superseded by v151 — PDP still had old Header)
v150 — Five surgical patches: (1) HeaderV2 PRIMARY_NAV canonicalized to Shop · Locations · Our Vibe · Our Programs · Rewards · Gift Cards · Blog (was Shop·Deals·Learn·Locations·Rewards). (2) ShopPage drops internal old Header.jsx import + mount — kills the blue #5B7C99 'Shopping at:' banner + 'Follow Us 25% off' strip. (3) App.jsx /shop and /shop/ routes now wrap with HeaderV2 like all other routes. (4) Root _redirects rewritten with explicit /v{143,144,147,148,149,150}/* → /vN/index.html 200 SPA fallback (fixes /v150/shop returning picker HTML bug #611/#634). (5) Dynamic logo via resolveLogo(storeRecord) already worked in HeaderV2 — no store: brand fallback; store selected: store-specific logo_svg. Stacks on v149 age-gate-only flow.
v149Jun 4, 20268:46 AM EDTARCHIVE · v149 (superseded by v150 — same age-gate flow, now with correct header)
v149 — Reversed v148 mandatory store-gate per Ravi directive. Boot flow: age_gate (19+ Ontario) → done. No forced "Choose your store" before content view. StorePicker becomes opt-in (header CTA + AddToCart inline prompt). Patches: useEntryFlow.js (drop afterAge geo-suggestion), App.jsx (drop GeoStoreSuggestion render block), LocationProfilePage.jsx repair (pre-existing M-105 duplicate import/var). Build verified locally: 2353 modules, no errors. Centilio-hub commit 6f8b3a80.
REPORTJun 3, 202606:20 AM EDTEMPIRICAL · for Darryl
v140 empirical state (the LATEST · STABLE candidate): 1957 KB bundle on canonical MBP build (≥995 KB regression gate). Real Dutchie checkout placed live at $35.39 on London-North store via Canary E2E. Cart-add succeeds 69.62% (10,911-product full-catalog probe vs 95.32% biased sample). Price-match 45.11%, gap to 95% ship target. Cannabis Act 1.0g/30g calc correct with flower. /v140/, /v141/, /v142/ HTTP 200; /v143/ /v144/ wiped by picker-only deploy and partially restored via CF rollback to 4244f876. 7-hour synthesis at hub d6bc6fe6 shared/sessions/retro-2026-06-03/RETROSPECTIVE.md — 4 parallel deep agents, 18 symptoms → 5 root causes + R6 user-added in-stock filter regression, 6 new lessons L28-L33, 5-rule mesh discipline v2, 10 capability gaps ranked, v143→v150 plan locked.
LOGJun 3, 202606:20 AM EDTPROJECT · 7 hours today
Today 2026-06-03 reverse-chrono. 09:30 EDT — CF rollback to 4244f876 restored /v143/ after /vN/ wipe cascade. 06:30 — v144 B1 (LocationPin → HeaderStoreDrawer side-slide) shipped + Canary verified (sc-store-drawer x:0 w:380). 05:41 — MBP DEEP-REPLAN d7725137: 18 audit symptoms → 5 root causes (R1 cart-rail viewport collapse 39%, R2 shop-layout no mobile breakpoint, R3 hero overflow, R4 header layout, R5 cross-store cart 100% checkout fail). R6 in-stock filter added per Ravi. 05:35 — v143 wiring fixes shipped (B3 useViewport 1024, BUG-003 null-category filter, BUG-004 chip labels, BUG-007 demo→demo Locations link). 04:30 — v142 4-agent verify: 6/7 GREEN, 3 RED (B1 legacy modal, B2 cart double-fire, B3 tablet desktop nav). 04:00 — v141 CSS-only category bar fix on MBP canonical. 03:30 — v142 HeaderV2 sandbox preview; MBP flagged Studio stale-clone trap pre-ship (Path C mitigation). 03:25 — v140 EMPIRICAL VALIDATION: real Dutchie checkout $35.39 placed live. 02:38 — picker /vN/ wipe #1 restored, 109→94 cards, R3 enforced (1 LATEST chip).
v148Jun 3, 20268:26 AM EDTARCHIVE · SHIP · mandatory onboarding flow
v148 — MANDATORY ONBOARDING ARCHITECTURE. Fixes the silent-defaulting problem Ravi caught: /v147/ went straight to London because localStorage carried over the prior store. v148: (1) selectedStore moved from localStorage→sessionStorage — every new session re-asks. (2) New StoreWall component: full-screen orange Sessions-branded wall, no X button, no backdrop dismiss. User MUST pick a store to proceed past the age gate. (3) useCart.addItem now gates on store: if no store → sets pendingStorePickerRequired (true), does not add. (4) CartPage.handleCheckout gates: if no storeUuid → triggers picker. (5) Flow start-to-end: load → AgeGate (19+ confirm, localStorage 30-day) → StoreWall (mandatory, sessionStorage per-session) → Shop (filtered to picked store) → PDP (browse OK) → Add to Cart (requires store) → Cart (single-store) → Checkout (Worker v3.7.1 Patch B.3 path). Stacks on v147 Patch 6 (cross-store contamination prevention) + v146 universal HeaderV2 + per-store dynamic logo. The full architectural answer to "every Sessions location is its own Dutchie retailer, the UI must reflect that from session start".
v147Jun 3, 20267:57 AM EDTRECENT · SHIP · single-store cart (Patch 6) — superseded by v148 onboarding
v147 — PATCH 6 SINGLE-STORE CART ENFORCEMENT. Ravi caught the R5 architectural bug on Canary at 11:50 AM EDT: "Shopping at: London North" but cart had 3 Strathroy items → Checkout blocked. Why this happens: Dutchie API has no cross-retailer checkout — each Sessions location is its own retailer with its own checkout URL. Multi-store cart UI promises something Dutchie literally cannot fulfill. v147 fix (4 files + 1 new): useCart.addItem checks passedStoreId vs current selectedStore — if mismatch + cart non-empty, sets pendingStoreSwitch and returns without polluting. StoreSwitchModal.jsx (NEW) opens with "Switch to a different store? You have N items from your current store. Switching clears your cart." Two buttons: Keep current / Switch + add item. ProductCard "Buy at Sessions [City]" badges replaced target="_blank" external links with onClick→addItem(storeId) flow — triggers the modal not new tab. CartPage multi-store warning marked unreachable. Stack on top of v146 universal HeaderV2 (22 routes consistent) + dynamic per-store logo (Sessions_[City].svg). Worker v3.7.1 Phase B.3 checkout still active. Acceptance test: London cart → click Buy at Strathroy on PDP → modal → confirm → cart cleared + Strathroy item added → single checkout. No "not_stocked_at_store" possible.
v140Jun 3, 20262:56 AM EDTPROVEN · CHECKOUT WORKING (superseded by v147 cart fix)
v140 — REPROMOTED for Darryl review. This is the last version where customer checkout was empirically PASSING (Canary E2E real Dutchie checkout placed $35.39 live). 4 parallel-agent diagnoses applied: CHECKOUT-001 PDP openDrawer + events, NAV-002/003 ShopPage hydration re-sync on URL change, CART-001 AddToCartButton stopPropagation (no accidental PDP nav), CART-002 variant N/A normalized so duplicates merge, CART-003 Cannabis Act 1.0g/30g with flower. Header HDR-003 storePicker conditional + HDR-004 cart onOpenCart prop. The v3.6.0 worker in-stock filter (only-in-stock-at-this-store) was still active here. v141-v144 each introduced regressions; checkout flow needs re-validation before any later /vN/ is promoted again.
v144Jun 3, 20265:49 AM EDTARCHIVE · wiped — see story
v144 — B1 fully complete: LocationPin click now ALWAYS opens internal HeaderStoreDrawer (left-slide), legacy centered StorePickerModal no longer fires from header. Edit was 5-line swap in HeaderV2.jsx handleStoreClick: dropped onOpenStorePicker prop check, always calls setStoreDrawerOpen(true). All v143 fixes preserved (tablet hamburger ≤1024, null-category bleed gone, friendly chip labels, relative locations link). Bundle 1963KB ≥995KB gate on canonical MBP.
v143Jun 3, 20265:39 AM EDTARCHIVE · superseded by v144 (Jun 3) — wiring + Shop bugs
v143 — fixes 7 bugs found in v142 by parallel-agent verification + MBP QA walkthrough. WIRING: B1 LocationPin now opens HeaderStoreDrawer (left side drawer, not legacy modal) — App.jsx no longer passes onOpenStorePicker to header. B3 useViewport breakpoint 768→1024 so tablet ALSO gets hamburger drawer. SHOP: BUG-003 products with null/empty category no longer bleed into every category view. BUG-004 chip label uses friendly name (Oils & Capsules, not TINCTURES). LOCATIONS: BUG-007 Shop location card now uses relative /location/<slug> (stays on demo) instead of sessions.ca production. Bundle 1962KB ≥995KB gate on canonical MBP.
v142Jun 3, 20265:04 AM EDTARCHIVE · superseded by v143 (Jun 3) — HeaderV2 single-bar
v142 — NEW HeaderV2.jsx (L26-compliant new file + App.jsx import swap). Single 72px bar replacing 3-layer 224px stack. Drops: blue Layer 1 #5B7C99, "Follow Us..." spam (moved to subtle bottom-right flag), inline search input, Layer 3 categories. Adds: SessionsIcons IconHeart + IconCart + IconBurger + IconClose (additive only). Right cluster: 🔍 search-toggle (expand on click) · 📍 LocationPin (opens left store-drawer) · ♡ Wishlist · 🛒 Cart with badge. Mobile: hamburger → left drawer with store pill + search input + nav links + wishlist + cart. Old Header.jsx untouched — atomic revert via App.jsx import flip if needed. Preserves all v131-v141 commerce fixes (cart, checkout, in-stock filter, Cannabis Act, breakpoint CSS).
v141Jun 3, 20264:13 AM EDTARCHIVE · v141 category-bar breakpoint CSS (rolled forward into v142)
v141 — CSS-only patch on canonical MBP source (1957KB bundle, ≥995KB gate). Layer 3 (9 categories) was wrapping to 2 rows at 768-1439px. Now hidden below 1440 with primary nav collapsing to hamburger ≤1199px. Mobile portrait header stays compact ≤480px. Zero JSX changes, zero L26 risk. All v131-v140 commerce fixes preserved (cart, checkout, Cannabis Act 1.0g/30g, Dutchie).
STORYJun 3, 202606:30 AM EDTMOBILE TESTING TODAY · REST IS WORKING
Today we are running mobile testing on demo.sessions.ca across multiple device profiles — iPhone 13 (390×844), Pixel 7 (412×915), iPad Mini (768×1024) — for the shop, cart, location, and checkout flows. The rest is working: v140 is LATEST·STABLE with the full e-commerce path (cart drawer + Cannabis Act 1.0g/30g math + real Dutchie checkout placed live at $35.39 + the in-stock-only filter that hides out-of-stock products at the London-North store). The HeaderV2 redesign cycle (v141/v142/v143/v144) regressed the in-stock filter when we shipped the new single-bar header, so we have rolled the picker back to v140 for the empirical commerce gate while mobile testing finishes. Studio + MBP are running parallel verification on each viewport. Sophie + Darryl real-card test on /v140/ is the only signal that flips this to LAUNCHED.
v139Jun 3, 202612:56 AM EDTARCHIVE · prior stable (superseded by v140)
v139 CSS-only mobile header compression
v138Jun 3, 202612:52 AM EDTARCHIVE
v138 mobile header compress - hide Layer 3 + Layer 2 nth-child 56px
v137Jun 3, 202612:14 AM EDTARCHIVE
v137 Hamburger type=button + aria + header compact mobile
v135Jun 2, 202611:32 PM EDTARCHIVE
v135 Cannabis Act topicals 1/70 + PDP flyToCart confetti
v134Jun 2, 202611:25 PM EDTARCHIVE
v134 - Remove unavailable items button on Checkout blocked
v133Jun 2, 202611:02 PM EDTARCHIVE · prior stable
v133 — one-line CSS fix in global.css line 831 (min-width: 44px on .sc-cta/.sc-btn/.sc-pill/.sc-chip mobile @media). Combined with v131 useIsMobile Header.jsx fix + v132 component patches. Mobile commerce 100% (M3 10/10 + M4 5/5 PASS), desktop 96% PASS via Studio Playwright v130 run. Cart→real-Dutchie verified: London-North $2.65 → Order Total $2.99 PLACE ORDER live.
v132Jun 2, 202610:56 PM EDTARCHIVE
v132 touch targets HeartButton WeightSelector 44px
v131Jun 2, 202610:51 PM EDTARCHIVE · v131 mobile fix superseded by v133
v131 — Header.jsx useIsMobile hook conditionally renders hamburger on mobile (<768px) and inline nav on desktop. Was: both rendered simultaneously, nav links 33-40px tap targets. Now: hamburger replaces inline nav on mobile, 44px touch targets (Apple HIG). Studio v128 mobile P1 was 12/12 same MOBILE_TOUCH_TARGET_SMALL bug — expected to flip to 0. Cart on mobile already passed (M4 5/5 in v128), no regression. Re-validate via Studio Playwright mobile harness.
v128Jun 2, 20268:47 PM EDTARCHIVE
v128 — drop wrong remap + setSelectedStore on mount + 98 store SPA folders
v127Jun 2, 20268:30 PM EDT⚠️ TESTED-PARTIAL — location pages render but cart still broken (price=$0, missing dutchie IDs, wrong store_id). v128 next.
v127 — LocationProfilePage shape adapter + store.id slug routing + PDP variant fix + 98 SPA fallback folders. Empirical Canary test on /v127/location/sessions-london-north: page renders, slug populates in cart, BUT adapter uses raw Dutchie field names (v.id, v.priceRec) instead of Worker-adapted shape (v.dutchie_variant_id, v.price_rec) → cart price=0, dpid/dvid missing. Store_id resolution wrong: north slug → south store (SLUG_TO_STORE loop issue). v128 will fix adapter to pass Worker shape through + debug slug map.
v126Jun 2, 20266:37 PM EDTARCHIVE
v126 picker patch retry
v125Jun 2, 20263:53 PM EDTARCHIVE
v125 — location profile + STORY removed + Worker v3.7.0
v123Jun 2, 20264:35 AM EDT⚠️ REGRESSION · DO NOT USE — Studio patch broke checkout (reverted to v119)
v123 — STUDIO BUILDCARTITEMPAYLOAD PATCH (REGRESSION CAUGHT BY CANARY). Ravi voice: Studio shipped buildCartItemPayload slug-attach (hub commit eb533499) for "cleaner Worker B.2 path always wins." Integrated as v123, promoted to LATEST. MBP empirically tested SAME 3-item cart on /v123/cart vs /v119/cart: v119 reached real Dutchie checkout URL b8b90b8d (ORDER TOTAL $46.39) ✓; v123 BLOCKED with "not_stocked_at_store" for ALL 3 items (Worker rejects the new payload shape). Patch flagged for Studio review — likely the slug-attach is interfering with the worker resolution path even when slug is null/empty. Reverted: v119 promoted back to LATEST. The original buildCartItemPayload SLUG-ATTACH (Studio commit eb533499 finally integrated). storeMap.js now ensures Dutchie-shape cart items always carry slug when available, so the Worker B.2 fast path always wins instead of falling through to the no-slug variant_id lookup. Pairs with Worker v3.6.4 (Cannabis Act gram math fixed: 2g hash + 30ml CBD = 8.43g not 128g). Full-catalog probe across 10,911 products against this build: 69.62% cart-add success, 45.11% exact price-match, 30.34% Dutchie drift (aligner-staleness, not code — see /probe-report/ for breakdown + /project-log/ for the full 3-day trail).
v119Jun 1, 202611:36 PM EDTARCHIVE · prior-stable, superseded by v128/v133
v119 — PRODUCTION cart error UX + working deep-link. Built with VITE_BASE=/v119/ so vite emits /v119/assets/ paths natively (no post-build sed). _redirects: /v119/* /v119/index.html 200. CartPage subscribes to useCart.checkoutError + checkoutBlocked, renders red banner showing per-item failure ("Red Eye Tek hoodie — addItem_failed"). Cart line price fallback: item.price ?? unitPrice ?? expected_price ?? dutchie_price_rec ?? 0 (fixes $0.00 display). addItem dual-writes price + unitPrice for state consistency. Surfaces stale-D1 silent fails (17,486/28,399 rows never aligned) as visible red banner instead of dead button. $500k/mo traffic site — not a demo.
v117Jun 1, 20269:14 PM EDTARCHIVE · v117 click-and-arrive worked but no error UI
v117 — DIRECT-TO-DUTCHIE checkoutCart. v116 failedDefensive filter checked items[].unit_price == null which matched OLD slug-path items (they use dutchie_unit_price field, undefined == null is true) — caused silent bail BEFORE navigate line, click hung with no error. v117 rips out modal state machine entirely: no pendingPriceMismatch/pendingStoreSwap Zustand mutations from async fn, no CheckoutFlowModals mount, no defensive filters on response shape we cannot verify. Trust safe_to_redirect from Worker (v3.5.8 sets it correctly), validate redirect_url is https://, console.warn for price/swap, then window.location.assign(). 25 lines. Same pattern CannaSync uses. Ravi pushback: stop building state machines for must-have paths.
v116Jun 1, 20268:13 PM EDTARCHIVE · v116 modal-removal attempt (failed at OLD slug path filter)
v116 — CHECKOUT NON-BLOCKING + PICKER FIX (Ravi pushback after v112-v115 ship lie). v113-v115 wrapped price-mismatch + store-swap warnings in Promise-await modals; CheckoutFlowModals never rendered the modal in DOM so checkoutCart hung forever (DOM delta=0 after click, modal_count=0). Strict regression vs v107 silent-navigate. v116 fix: when Worker returns safe_to_redirect:true + valid redirect_url, navigate IMMEDIATELY. Warnings go to console.warn + useCart state with nonBlocking:true flag (no Promise-await). Also fixes picker bug: v112/v113/v114/v115 cards were NEVER ADDED (regen script only rewrites existing timestamps, doesn't add new cards). v116 ships 5 new cards + demotes v107 to ARCHIVE. Procedural memory upgrade: verify-with-frontend-shape v3→v4 + new sessions-done-gate skill (4 atomic gates: User-flow URL / Picker contains new card / Click-and-arrive / Mobile 375px). Hub commit 05e2baec.
v115Jun 1, 20266:56 PM EDTARCHIVE · B.4 ship attempt
v115 — B.4 Wave E orphan filter on D1 fallback path. Drops items with no slug or null price. SHIPPED CLAIMED BUT CHECKOUT BROKEN — modal-await pattern hangs Promise. Superseded by v116.
v114Jun 1, 20266:54 PM EDTARCHIVE · B.4 ship attempt
v114 — B.4 Wave D live Dutchie /api/menu integration. useProducts.fetchProducts tries Worker /api/menu first (live prices + dutchie_product_id + dutchie_variant_id), falls back to /api/products. ProductCardV2.variantForCart propagates dutchie IDs.
v113Jun 1, 20266:45 PM EDTARCHIVE · B.4 ship attempt
v113 — B.4 Wave C checkoutCart 5-failure-handler. PriceMismatchModal + StoreSwapModal wired into useCart via CheckoutFlowModals component in App.jsx. The modal-await Promise pattern was the bug — Promise never resolved because CheckoutFlowModals didn't render in DOM. v116 reverts to non-blocking.
v112Jun 1, 20266:38 PM EDTARCHIVE · B.4 ship attempt
v112 — B.4 Wave A+B foundations: NEW src/api/menu.js (5s in-memory cache), src/components/modals/PriceMismatchModal.jsx, src/components/modals/StoreSwapModal.jsx. storeMap.buildCartItemPayload dual-shape (slug OR dutchie_product_id). useCart.addItem captures dutchieProductId/dutchieVariantId/dutchieVariantOption/expected_price.
v111Jun 1, 20263:31 PM EDTARCHIVE
v111 — _routes.json SPA fallback fix + worker v3.5.8 paired
v110Jun 1, 20263:44 AM EDTARCHIVE
v110 — Patch 4 product_name in /api/buy-batch body verified; aligner bootstrap 4
v107May 29, 20262:13 AM EDTARCHIVE · prior LATEST (v112-v116 ship live-flow-broken; v116 fixes checkout silent-hang + adds picker entries)
v107 — ROTATING WHEEL + MAGIC RINGS OOZE-OUT (Ravi correction of first v107 attempt). First-pass v107 was wrong: replaced the rotating SessionsWheel3D with a STATIC favicon image inside a boxed splitRight — Ravi feedback "I didn't ask for this. The rotating module was there. You won't disturb that. On top of it, on the sides, it will come like this." v107.1 fix: SessionsWheel3D RESTORED (still rotating, still gold extruded, still 0.45 rad/sec). MagicRings layered BEHIND the wheel as a halo, sized 160% × 160% with negative -30% offset so rings radiate BEYOND the splitRight container into the cream. splitRight.overflow changed from hidden → visible so rings escape the box. Wheel transparent bg so rings show through corners. Static favicon overlay dropped. Result: rings appear to ooze OUT from the rotating wheel on the sides, merging into the surrounding cream — the spec Ravi originally asked for. Ring params unchanged from v107.0: orange #F78D1E → sativa #E65325, ringCount=10, lineThickness=1.5, scaleRate=0.15, noiseAmount=0.44, fadeIn=0.8, followMouse=true, mouseInfluence=0.1, hoverScale=1.15, clickBurst=true. Cart fix from v106 preserved. Vite build 3.47s.
v106May 29, 20261:29 AM EDTARCHIVE · prior LATEST (cart checkout fix kept active in v107)
v106 — MULTI-ITEM DUTCHIE CHECKOUT (Ravi root-cause callout: cart total ≠ Dutchie). Worker v3.3.0 ships new POST /api/buy-batch endpoint: single CreateCheckout → iterates AddItem per cart item with correct qty + variant_size + per-store slug resolution via SQL `WHERE slug=? AND store_id=?` (kills the 97% slug-mismatch bug surfaced in v106 audit on 3,394 store-rows). Cumulative Cannabis Act check across all items. Returns redirect_url + dutchie_subtotal + cart_expected_subtotal + delta — frontend price-reconciliation guard pops a confirm if abs(delta) > $1.00 BEFORE redirecting to Dutchie, so users can review divergence rather than being silently overcharged. Smoke test (5 items, store 40fb165d Cambridge): cart shows $14.40, Dutchie actually $17.70, delta +$3.30 — exactly the symptom Ravi reported, now surfaced not hidden. Frontend: src/data/storeMap.js +postBuyBatch(), src/hooks/useCart.js +checkoutBatch action, src/pages/CartPage.jsx handleCheckout POSTs full cart (was: only top item, qty hardcoded 1, variant defaulted, slug mismatched). Deep audit data layer: 8,873 canonical products + 3,394 per-store rows in DuckDB+Parquet at data/v106-cart-audit.duckdb. Vite build 2.92s.
v105May 29, 202612:18 AM EDTARCHIVE · prior LATEST (single-item fix; v106 adds multi-item + price-reconcile)
v105 — CART CHECKOUT + DUTCHIE WIRING (per Ravi callout). Two surgical bug fixes on top of v104 mobile cascade. (1) Cart "Proceed to Checkout": CartPage.handleCheckout was calling openDutchieFor() which opens a Dutchie SEARCH page (?dtche[search]=...) — that is NOT a purchase flow. Now wired to checkoutViaWorker(top, storeUuid) → Worker /api/buy endpoint at sessions-availability-edge.ravi-abe.workers.dev which: CreateCheckout(retailerId) → Menu(retailerId, search) → AddItem(checkoutId, productId, qty) → redirects user to Dutchie checkout with the product already in cart, ready to pay. The plumbing existed since v75 but the button was wired to the wrong handler. (2) Store Locator "Shop This Store →": was navigating to internal /shop (which shows ALL products across all stores, ignoring the selected store context). Now external anchor to per-store Dutchie menu — uses storeRecord.menuSlug → https://www.sessions.ca/{menuSlug}/ if present, falls back to storeRecord.dispensaryId → https://{dispensaryId}.sessions.ca/, opens in new tab. Mobile cascade from v104 fully preserved. v104 mobile fix kept active in v105 — no regressions. Featured tile click handler unchanged (still routes to internal PDP where per-store Dutchie buy buttons are already wired via buildBuyUrl). Vite build 3.22s, 2348 modules, 36KB CSS / 666KB JS gzip.
v104May 29, 202612:09 AM EDTARCHIVE · mobile layer kept in v105 + checkout wired
v104 — LAUNCH-READY MOBILE LAYER. Ravi diagnosis: "All mobile view in every page is broken!" Static audit confirmed: 22 of 22 non-PDP routes had zero @media queries — structurally non-responsive at the source level. Single-file high-leverage fix: appended 107-line v104 MOBILE RESPONSIVE LAYER to src/styles/global.css with three breakpoints (768px tablet portrait, 480px phone large, 380px phone small). Strategy: CSS-variable token cascade. --sc-h1-size reduces 60→38→30→26 across breakpoints, --sc-h2-size 48→30→24→21, --sc-h3-size 32→22→19→17, --sc-body 16→15→14 — every component using var(--sc-h*) automatically reflows. Plus: container fluid-ization (1920/1440/1280 inline widths → 100%), grid → 1col, touch targets ≥44px, header collapse, footer stack, anti-overflow safety on hero/video/canvas. DB-first verification per Ravi directive: throwaway SQLite at ~/workspace/demo-sessions-ca/data/v104-launch-verify.db tracks every metric as a number (mobile_audit_static went from 22 RED to 23 GREEN-via-cascade, 1 RED-conflicts on PDP). Phase D unblocked — Studio delivered COVA snapshot (146,281 ACTIVE rows, 16.6 MB) at centilio-hub/shared/cova/snapshot-2026-05-25.csv with store_registry.json join key. Scope respected: no Cloudflare changes, runtime stays Studio Worker / Darryl CF canonical, MBP SQLite is verification-only throwaway. Vite build 2.88s, 2348 modules, 36KB CSS / 665KB JS gzip. v103 3D wheel preserved and visible at /v103/.
v103May 27, 20264:57 AM EDTARCHIVE · prior LATEST (3D wheel — superseded by mobile launch readiness)
v103 — 3D SESSIONS WHEEL. Replaced the Hero_v97_silent.mp4 video with a React Three Fiber 3D extrusion of the canonical Sessions favicon SVG. Pipeline: SVGLoader parses public/sessions-favicon.svg → ExtrudeGeometry depth 34 + beveled edges → gold MeshStandardMaterial (#F78D1E metalness 0.85, roughness 0.25, warm emissive 0x6F3500). Auto-rotates around Y axis at 0.45 rad/sec. Cream #F9F6EE canvas bg matches splitRight — no mask gymnastics. Respects prefers-reduced-motion (no rotation). Bundle 2.54MB / 665KB gzip (three+R3F+drei addition justifies the increase per canonical-source rule >=995KB). Drops the v97-v102 video file (-9MB) and the v102 logo-centered radial mask. All v101 typography preserved (60px tagline, GradientText subhead, orange | cursor). Real Sessions brand mark from Photoshop sessions-favicon-base.psd is the geometric source-of-truth.
v102May 27, 20264:55 AM EDTARCHIVE · prior LATEST (video-mask era — superseded by 3D wheel)
v102 — LOGO-CENTERED MASK (Ravi root-cause fix). v97-v101 all positioned the radial mask at 50%/50% of the video element — but empirical PIL analysis of Hero_v97_silent.mp4 (ffmpeg extract frame at t=3s, find gold-pixel centroid) shows the brand logo (the wooden disc with the favicon mark) is at pixel (883,364) in the 1280x720 source = (69%, 51%) of the video. The logo is 22% off horizontal center — significantly right of geometric middle. Every prior mask centered on 50%/50% appeared cut off on the right because the logo was actually only 31% from the right edge but 69% from the left edge. v102 mask: radial-gradient(circle 245px at 69% 51%, #000 50%, rgba(0,0,0,0.55) 75%, transparent 100%) — three-stop falloff for soft glow, concentric WITH THE LOGO not with the rectangle. Added drop-shadow(0 0 18px rgba(249,246,238,0.6)) for cream ethereal glow at the edge. Bloom radius measured at 470px in source (ring density drops below 10% at 470px from logo center) = 323px in 880-wide element; 245px chosen for slight bloom crop with breathing room. Typography fixes from v101 (60px/700 tagline, GradientText subhead, orange | cursor) all preserved.
v101May 27, 20264:52 AM EDTARCHIVE · prior LATEST (mask still at 50/50 — logo is actually at 69/51)
v101 — TYPOGRAPHY + GRADIENTTEXT + TRUE CIRCULAR MASK. Four fixes per Ravi audit: (1) H1 tagline brought to Sophie pinned spec — clamp(40,3.5vw,60)px weight 700 letter-spacing -0.01em (was 88px/800/-0.02em — 47% oversize at 2560 viewport, one weight too heavy = looked over-bold). Sesh script scales 80→64px to maintain hierarchy. (2) ROOTED IN COMMUNITY wrapped in GradientText with Sessions brand-bright 5-stop palette — same treatment as /our-programs ecosystem word, 8s animation, yoyo. (3) TextType cursor — was unstyled (sc-hero-typecursor CSS class did not exist) fell back to default green underscore. Added .sc-hero-typecursor: thin brand-orange | bar at 0.72em / weight 400 / 0.85 opacity / subtle 6+12px orange glow text-shadow. cursorCharacter _ to |. (4) v99 radial halo was actually dual LINEAR gradients — left/right bands at 88px vs top/bottom at 59px = asymmetric, left-heavy. v101: TRUE radial mask-image: radial-gradient(circle 240px at 50% 50%, #000 65%, transparent 100%) applied directly to video element. Mathematically circular regardless of container aspect. Halo div DROPPED, splitRight cream bg shows through corners naturally.
v100May 27, 20264:26 AM EDTARCHIVE · boxed approach made edges SHARPER not softer (Ravi caught it). v99 radial halo was the better direction — reverted to LATEST.
v100 — CREAM FRAME (REVERTED). v97-v99 attempted CSS halo math (radial then dual linear) to eliminate visible borders at video edges; halo deployed correctly each time but couldn't eliminate the subpixel/transition-band artifact where video pixels meet halo gradient. v100 takes a fundamentally different approach: video is SHRUNK to 88% × 88% of splitRight (positioned at top:6% left:6% within the cream-bg splitRight container). The remaining 12% width = 6%/side = ~53px on the 880px-wide container and ~30px on the 495px-tall container becomes a deliberate cream margin around the video. Halo div DROPPED entirely. Result: video appears to float in cream with intentional breathing room — no halo gradient math, no transition bands, no z-stacking artifacts. Per Rule 8 deploy-loop iteration 3/3. If this still shows borders, escalate to Premiere/AE source-video alpha mask in v101.
v99May 27, 20264:25 AM EDTARCHIVE · prior LATEST (asymmetric halo — bands 88L/R vs 59T/B)
v99 — DUAL LINEAR HALO eliminates black borders. v97/v98 radial-gradient halo math depended on container aspect ratio and didn't guarantee solid cream at the rectangular edges (at top of 880×495 container, halo was only ~38% cream — video pixels still showed through). v99 replaces radial with TWO stacked linear gradients: vertical (cream 0-12% top, transparent 12-88%, cream 88-100% bottom) + horizontal (cream 0-10% left, transparent 10-90%, cream 90-100% right). Combined: guaranteed solid cream on ALL 4 edges, visible video in center 80%×76% zone. Hero_v97_silent.mp4 + side-by-side 45/55 + responsive breakpoints all unchanged from v97/v98. Per Rule 8 deploy-loop iteration 2/3 attempting to converge on no-borders criterion.
v98May 27, 20264:24 AM EDTARCHIVE · prior LATEST
v98 — LINE FIX. v97 shipped Patch F mask+halo per Windows spec; halo deployed correctly but mask's 55-80% transparent transition band (y=80-130 in the 495px-tall splitRight) showed video pixels at low opacity against not-yet-solid cream halo → soft line band visible to Ravi. Math: at y=100, mask=55% transparent (video at ~55% opacity) AND halo=~96% cream (4% transparent) = perceptible band. Fix per Option D in v98 deep plan: DROP the radial mask entirely on the <video> element, use only the halo div with a steeper gradient (transparent 0-50% / cream 95%). Single-layer solution eliminates the mask×halo interaction artifact. Hero_v97_silent.mp4 video file unchanged (Windows-shipped audio-stripped MP4 still canonical). All v97 layout (side-by-side 45/55, max-height min(70vh,600px), cream bg unified, responsive breakpoints) preserved. Patch G acceptance test should now pass at the y=80-130 zone where v97 failed.
v97May 27, 20264:10 AM EDTARCHIVE · prior LATEST
v97 — MERGED Windows×MBP plan with Patch F feather blend. Audio stripped from video (Windows ffmpeg -c:v copy -an → Hero_v97_silent.mp4, SHA 5f51b2d6c43f00fec651c10b5eb0296d8ff0ea1f630c8da89194df9af87db4f0, MBP-verified byte-match). Fixes 4 v96 bugs: (1) autoplay blocked → audio stripped; (2) oversize video → max-height min(70vh,600px); (3) section seam → unified cream #F9F6EE no border; (4) wrong layout → reverted column to row 45/55. Patches A-F on Hero.jsx (Windows caught my Patch A-E plan would ship a rounded BOX — added Patch F feather blend: radial mask on video [#000 38% / rgba(0,0,0,0.55) 72% / transparent 100%] + cream halo sibling div [radial-gradient ellipse 68% 72% at center, transparent 42%, #F9F6EE 92%], belt-and-suspenders blend). Responsive: desktop ≥1280 45/55, tablet 768-1279 50/50 with smaller h1 clamp(36px,5vw,60px), mobile <768 text-first stack but video capped 38vh so both elements fit in first viewport (Windows constraint). preload="auto" + disablePictureInPicture on video.
v96May 27, 20264:10 AM EDTARCHIVE · prior LATEST
v96 — STACKED LAYOUT per Windows session feedback. Hero restructured from CSS Grid 5fr/7fr side-by-side → vertical flex stack (header on top, video full-width edge-to-edge below). Dropped 24px border-radius + max-width 1440 container — video now bleeds full viewport width. Video file swapped to Hero_v95_h264.mp4 (9.3MB, H.264 yuv420p, exported via Premiere Pro on Windows by parallel Sonnet session). Original Hero_v93_blended.mp4 was H.264 too but Windows session reported empty slot symptoms — could be CF caching, autoplay-blocked, or other browser issue at user's viewport. v95 codebase otherwise preserved (HERO_POSTER removed, reduced-motion img branch removed). Layout decision: Windows said side-by-side was wrong, user agreed — header now sits ON TOP, video fills below.
v95May 27, 20264:07 AM EDTARCHIVE · prior LATEST
v95 — REMOVED Hero_v82_poster.png. User's Figma plugin scrape of demo.sessions.ca found the wood-disc + paper-butterflies poster image in the DOM layers (it was used as the <video poster=> attribute AND as the <img> fallback for prefers-reduced-motion). Both removed: HERO_POSTER constant deleted, poster attribute stripped from <video>, the entire prefers-reduced-motion <img> branch removed from HeroVideoStack. PNG file deleted from public/figma/sessions-assets/. Now ONLY the video renders, no static image — no scraper can extract the butterfly poster from the page. Video reverted to Hero_v93_blended.mp4 (the V83 Path A confetti-bloom video with right+top edge cream fade baked in, the v86 direction user originally asked for). v94 butterflies experiment dropped — was based on misreading the user's "saw this in layers" message as a content preference when they were actually surfacing the scraper leak.
v94May 27, 20263:56 AM EDTARCHIVE · prior LATEST
v94 — WOOD-DISC + PAPER BUTTERFLIES restored (v82 source content the user showed in layers). Source Hero_v82_idle.mp4 (1280x720, 1.78:1) cropped center 770x720 → scaled 1540x1440 (1.07:1 to match container) → overlaid right+top cream fade PNG → Hero_v94_butterflies_blended.mp4 (2.8MB). Real paper butterflies (green/orange/red), root tendrils, wooden plank shelf. Right edge blends to cream natively. v90+ boxed grid layout (5fr/7fr, rounded 24px, max-width 1440) preserved. CHECKOUT shiny preserved. The composition the user actually wanted from the start — abandoned the v86 confetti-bloom direction.
v93May 27, 20263:55 AM EDTARCHIVE · prior LATEST
v93 — EDGE BLEND BAKED INTO VIDEO. ffmpeg overlay composited a cream-alpha gradient PNG onto every frame of Hero_v92_centered.mp4: right 15% fades from transparent to cream (#F9F6EE), top 4% same fade — eliminates hard right-edge cut against page bg AND hides any encoder top-bar artifact. PIL-generated 1540x1440 RGBA gradient overlay. Output: Hero_v93_blended.mp4 (4.5MB, was 5MB). No CSS mask — blend is baked into the video pixels themselves. Per user feedback "right crop needs to be blend to this to be perfect". Per updated Rule 8 deploy-loop: built, deployed, production-verifying against v85 reference + v92 prior.
v92May 27, 20263:48 AM EDTARCHIVE · prior LATEST
v92 — VIDEO RE-CROPPED to match container aspect (audit Option D). Source Hero_v86_pathA.mp4 (1280x720, 1.78:1) re-encoded via ffmpeg to Hero_v92_centered.mp4 (1540x1440 retina, 1.07:1). ffmpeg crop=770:720:255:0,scale=1540:1440 + h264 crf 20. Container aspect: 1.071, video aspect 1.069, mismatch 0.11% (was 39.7% on v91 — caused brand mark to be cropped right). Rule 8 added to local-first-verify-before-push skill (4 visual checks: aspect, focal point, zoom on changed region, premium reference). Lesson recorded: local-only verify is a closed loop when user can't reach localhost — shared environment (production) is the real source of truth for visual work.
v91May 27, 20263:48 AM EDTARCHIVE · prior LATEST
v91 — VIDEO FIX. v90 left-edge gradient mask (transparent 0% → black 12%) made the video look broken/cropped to the user — fading 12% of video to cream made it appear content was missing. Removed mask entirely (the 12-col grid + max-width 1440 + 64px gutters already separate heading from video, per RC8). Reverted object-position to default center -3px (was 35% which over-cropped right side where brand mark sits). All v90 audit fixes preserved: 5fr/7fr CSS Grid, alignItems:center, rounded 24px video, white solid stat cards in dedicated HeroStats second-fold section, CHECKOUT shiny attention CSS. Bundle ~1016KB. Built canonical MBP, visually verified at http://127.0.0.1:4787/v91/ — wood-disc brand mark + butterfly confetti now fully visible in rounded frame, no transparent left-edge artifact, no cropped right edge.
v90May 27, 20263:29 AM EDTARCHIVE · prior LATEST
v90 — PREMIUM EDITORIAL REBUILD per external audit (9 RCs). RC1 hero height clamp(640px, calc(100vh-160px), 820px). RC2 CSS Grid 5fr/7fr (42/58 split) replacing flex. RC3 removed -220px video bleed, replaced with linear-gradient(to right, transparent 0%, black 12%) mask on left edge so confetti doesn't crash into headings. RC4 alignItems:center on grid — heading and video focal point share single optical baseline. RC5 stats moved OUT of hero overlay to dedicated HeroStats second-fold section. RC6 stats cards now SOLID white (#FFFFFF) with rgba(20,20,20,0.06) border and 0 8px 24px shadow — not transparent over busy video. RC7 video frame gets borderRadius:24px overflow:hidden + subtle inset vignette via box-shadow. RC8 hero wrapped in max-width:1440 container with clamp(24,4vw,64)px gutters. HeroStats mounted between Hero and TrustStrip in App.jsx — 4-col grid, white cards, 56px Sessions-orange numbers, 13px uppercase labels with 0.14em letter-spacing per audit spec. AnimatedCounter switched to mount-trigger with cascading 200+i*120ms startDelay so cards count up sequentially. H1 sizing clamp(48px, 5.2vw, 88px), line-height 1.02, letter-spacing -0.02em, weight 800. TextType loop=false. NEW: CHECKOUT shiny attention — PersistentCartRail CHECKOUT label now has always-on subtle Sessions-bright #FBB309 gradient sweep (4s loop, 300% bg-size) + attention mode triggered by cart:item-added event for 3.5s (1.2s sweep duration, 0 0 16px #FBB309 + 0 0 30px #F78D1E + 0 0 50px #F78D1E text-shadow halo). All v88 BUG-01/05 fixes preserved (object-position -3px, large CTA). Built canonical MBP ravigandhiarul:~/workspace/demo-sessions-ca, bundle 1016.93 KB index-7YmTAYa3.js. Visually verified at http://127.0.0.1:4787/v90/ — pixel probe confirms grid:520px/728px, alignItems:center, splitRight borderRadius:24px, h1.y:311, statsSection at y:1334, 4 white cards rendering with 47+/132K+/4.7★/6 yrs, CHECKOUT cta-shiny class with white-to-#FBB309 gradient + cartCtaShine 4s animation. Process lesson recorded: Rule 8 added to sessions-local-first-verify-before-push skill — design pattern audit required before declaring premium UI done (would have caught the v89 frosted-overlay-on-video anti-pattern earlier).
v89May 27, 20263:29 AM EDTARCHIVE · prior LATEST
v89 — MAGAZINE COMPOSITION. Hero rebuilt as unified editorial spread: 4 frosted-glass stat cards (47+ Ontario locations / 132K+ Live SKUs daily / 4.7★ Avg customer rating / 6 yrs Serving Ontario) overlay the V83 Path A video bloom in the bottom-third of the hero, anchored to splitRight (position:relative) so they always sit on the warm wood-disc glow regardless of viewport. Cards use backdrop-filter blur(20px) saturate(140%) + rgba(255,255,255,0.62) bg + 18px radius + Sessions-orange-tinted box-shadow — brand mark visible THROUGH the glass behind the 4.7★ card (the blend effect). AnimatedCounter switched from IntersectionObserver to mount-trigger (400ms warmup, 1400ms easeOutCubic 0→value) — counters always animate on first paint, no scroll dependency. TextType loop=false — types STARTS HERE once and stays, no erasing. SplitRow height capped at min(720, vh-80) with maxHeight 720 — prevents the v88 1145px overshoot. splitRight + videoFrame + bannerImg now bound to 100% of parent height — video stays in its 720 frame instead of expanding to natural 1154. SplitLeft alignItems:center with asymmetric padding (40 top / 120-200 bottom) pulls headline into golden-ratio band at ~30% from top. All v87 (mask blend) + v88 BUG-01/03/05 fixes preserved (object-position -3px hides 3px black bar in MP4, composite linear+radial mask kills corner darkening, 200x52 CTA pill). Secondary trust strip (Backed by Ontario / Built for community) reduced to just h2+p+FIND A STORE link since stats moved to overlay — was 295px tall, now ~120px. Bundle 1016.61 KB (above 995 KB v78 gate). Built on MBP canonical ravigandhiarul:~/workspace/demo-sessions-ca via VITE_BASE=/v89/ vite build. Visually verified via Claude in Chrome at http://127.0.0.1:4787/v89/ — full page screenshot + zoom on overlay region (1500x507) shows cards correctly composited on video with brand-mark glow showing through frosted glass. Deployed to canonical demo-sessions-ca CF Pages project on Darryl account.
v88May 27, 20263:04 AM EDTARCHIVE · prior LATEST
v88 — HERO POLISH per external audit (5 fixes). BUG-01: Hero_v86_pathA.mp4 has 3px black bar baked into rows y=0-2 → object-position center -3px shifts content up, artifact lands outside frame. BUG-02: hero row was stretching to 937px under flex align-items:center; now hard-capped at min(680px,calc(100vh-224px)) with explicit max-height 800px ceiling. BUG-03: mask corner leak (low-opacity radial top + black source pixels) → composited mask: linear-gradient(to bottom, transparent 0px, black 8px) + radial-gradient(95%×100% at 72% 50%) with mask-composite:source-in. Result: zero black hairline at top, zero corner darkening. BUG-04: headline was vertical-centered 289px down a 937px column (dead cream void above) → flex-start alignment + paddingTop clamp(56px,9vh,120px), h1 now lands 117px below header. BUG-05: Shop Now CTA bumped 152×48 → 200×52 padding 0 36px for wide-viewport visual weight. v87 negative-margin video bleed + softer 6-stop radial preserved (gap_h1_to_video_x = -56). Bundle 1016.30 KB (above 995 KB v78 baseline gate). Built on MBP canonical ravigandhiarul:~/workspace/demo-sessions-ca via VITE_BASE=/v88/ vite build. Visually verified via Claude in Chrome at http://127.0.0.1:4787/v88/ — full screenshot + 3 zoom screenshots (top-edge, left text region, right video center) all agree. Deployed to canonical demo-sessions-ca CF Pages project on Darryl's account ef5bf7edeeda9b3e8b968f7cea33c322.
v86May 27, 20262:15 AM EDTARCHIVE · prior LATEST
v86 — HERO VIDEO RETURNS. Composes V83 Path A full-arc-reveal clean clip (Hero_v86_pathA.mp4, 8s loop, 1280x720 @ 24fps h264, 3.5 MB) into the right-half of fold 1 with a RADIAL MASK soft-edge blend so the video dissolves into the cream/orange section background — NO hard rectangular boundary. Mask: radial-gradient(ellipse 80% 80% at 65% 50%, black 35%, rgba(0,0,0,0.85) 60%, transparent 92%). Left text undisturbed (YOUR NEXT / Sesh / STARTS HERE TextType typewriter cursor, SHOP NOW CTA). Favicon overlay removed because the Path A particle reveal already contains the brand bloom at center. Respects prefers-reduced-motion (paints poster). Source clip ffmpeg-delogo'd to remove the unauthorized gold-key prop hallucination per the v83 Path A surgical edit (consciousness api_71daae58f63d2ba3). Bundle 1015.70 KB (above 995 KB v78 baseline gate). Built on MBP canonical [email protected]:~/workspace/demo-sessions-ca via bash -lc + VITE_BASE=/v86/. Deployed to canonical demo-sessions-ca CF Pages project on Darryl's account. Cart UX from v85 (PersistentCartRail + flyToCart + glossy CTAs + Cannabis Act 30g + free-pickup priority) intact.
v85May 26, 20266:16 PM EDTARCHIVE · prior LATEST
v85 — PREMIUM CART UX REBUILD on CANONICAL MBP source. Bundle 1,015 KB (vs v78's 995 KB — proves all v45-v78 components intact: ShopPage / FilterSidebar / ProductCardV2 / WeightSelector / AddToCartButton / TextType / GradientText / CircularGallery / PrismaticBurst / HeartButton / Lucide / Toast / reactbits / Brother 1816). NEW: PersistentCartRail.jsx — always-visible right-edge orange rail (56px collapsed) when items > 0, shows item-count badge + live subtotal + vertical CHECKOUT label + mini Cannabis Act limit bar. Click rail → expands to full 420px drawer. HIDE button collapses BACK to rail (NEVER fully closes). NEW: src/utils/flyToCart.js — clones product image, animates on arc (translate + scale 0.18 + rotate 360 + border-radius 50% + fade) to rail in 780ms, dispatches cart:item-added pulse event, respects prefers-reduced-motion. AddToCartButton patched: imports flyToCart + ripple, adds pc-add-btn class for glossy shimmer sweep + ripple-on-click + scale tactile feedback. GAMIFICATION: free-pickup priority 5 threshold strip, Cannabis Act 30g tier (green < 24g → orange 24-30g → red > 30g), idle shimmer every 28s when collapsed, auto-expand 3.8s on first add then auto-collapse. App.jsx mounts <PersistentCartRail /> replacing the v75 removed-CartDrawer comment. v76 useCart fix intact. v78 TextType, v77 GradientText preserved. v84 RECALLED — was built from stale Studio repo (729 KB regressed bundle missing all v45+ work) — this v85 supersedes it from MBP canonical.
v82May 26, 20267:07 AM EDTHERO MOTION · for Sophie
v82 — PREMIUM HERO MOTION. Two-phase 8-second Higgsfield video: Direction C (narrative arc — roots growing on plank, oak disc forms, paper-cutout butterflies fly in from edges and settle into halo, amber root filigree spreads laterally) plays once on page load; on ended, swaps to Direction A (idle drift — plaque static, butterflies drift gently in slow soft arcs) on infinite loop. Sessions wordmark composites onto the wooden disc center via CSS overlay with a 5.5-6.5s fade-in + scale-up (0.94 -> 1.0) timed to the moment the disc settles in the narrative arc; logo persists through all idle loops. Drop-shadow on logo combines warm amber glow (rgba(247,141,30,0.18) at 12px) + subtle dark grounding shadow for "branded into wood" feel. Left-scrim gradient (cream 55%->25%->0 over 36% width) keeps leftInner H1/CTA legible when butterflies drift into left third. Video element: autoplay, muted, playsInline, loop only in idle phase, poster = lateral-roots end frame. Respects prefers-reduced-motion: paints static poster + logo visible. Generated via nano-banana gemini-3-pro keyframes + Veo 3.1 Lite video interpolation. Honors Sophie's original narrative (wood + butterflies + rooted-in-community). v78 TextType on STARTS HERE preserved, v77 GradientText on /our-programs preserved.
v80May 26, 20265:55 AM EDTHERO IMAGE · for Sophie
v80 — PREMIUM HERO REBUILD. New nano-banana (gemini-3-pro-image-preview) editorial interior photograph: warm Aesop/Kinfolk minimalism, cream wall, oak floating shelves, single sculptural Sessions-orange ceramic vase + two amber apothecary jars with cork stoppers, soft golden window light from upper right, small green potted plant for life, strong negative space on left third for text. Full-bleed 1920x1080. Modernizes the previous baked-collage hero — drops the orange CSS panel pattern in favor of a single editorial photograph that says "real premium dispensary" without consumption imagery (Cannabis Act compliant). Text overlay: H1 in near-black #1A1A1A (WCAG AAA 16:1 contrast on cream), "Sesh" script word in sativa orange #E65325 to tie to the vase, subhead in warm gray #3B4148. v78 TextType on STARTS HERE preserved; cursor swapped from sunshine-yellow halo to brand-green #00A650 glow (better contrast on cream than yellow). Reverted v79 VapourText H2 back to plain text. Shell + split bg swapped from #F78D1E to #F9F6EE cream so any image gap blends seamlessly. v77 GradientText still live on /our-programs ecosystem H2. Reactbits parity components intact (TextType, GradientText, VapourText) for future use.
v79May 26, 20264:55 AM EDTHERO TEXT FX · for Sophie
v79 — VapourText canvas particle effect on Hero secondary heading. CYCLES through "Backed by Ontario." -> form -> dwell -> vapourize -> "Built for community." -> loop. Three-phase animation per phrase: FORMING (700ms ease-out cubic — particles fly in from offscreen positions), FORMED (2200ms — gentle sin/cos wiggle around home position), VAPOURIZING (1500ms — particles drift upward with quadratic lift, horizontal jitter, fade to 0). Pixel-grid sampling at stride 5px from offscreen-canvas text raster; pre-built particle sets so canvas size is stable across cycles (no layout jump). Brand-bright 6-color palette: #E65325 sativa orange / #F78D1E Sessions orange / #FBB309 sunshine yellow / #00A650 brand green / #883477 indica purple / #ED135C delivery magenta — per-particle random color so each loop looks different. devicePixelRatio scaling for crisp retina. Accessibility: semantic h2 preserved, full joined phrases in sr-only span, canvas aria-hidden, prefers-reduced-motion paints a single static frame instead of animating. document.fonts.ready gate ensures glyph measurements match render font. Plus v78 TextType still live on Hero STARTS HERE, v77 GradientText still on /our-programs.
v78May 26, 20264:46 AM EDTARCHIVE · prior LATEST
v78 — TextType (reactbits parity) on Hero "STARTS HERE". Premium typewriter loop: types out the phrase in 85ms with variableSpeed 60-110ms for human-like cadence, pauses 2.5s, deletes at 45ms, re-types forever. Cursor is a bold underscore (_) in sunshine yellow #FFD400 with 12px+24px glow halo — maximum brightness pop against the Sessions orange #F78D1E hero panel. Type color bone white #FFFFFF with subtle yellow text-shadow so the typed glyphs catch the cursor's glow. cursorBlinkDuration 0.45s. Full reactbits API: text/as/typingSpeed/initialDelay/pauseDuration/deletingSpeed/loop/showCursor/hideCursorWhileTyping/cursorCharacter/cursorBlinkDuration/cursorClassName/textColors/variableSpeed/onSentenceComplete. Respects prefers-reduced-motion. New components: src/components/reactbits/TextType.jsx + .css. Cross-page: only Hero touched, all other pages untouched. v77 GradientText still live on /our-programs.
v77May 26, 20264:33 AM EDTARCHIVE
v77 — GradientText (reactbits parity) on /our-programs. PREMIUM DESIGNER PASS: wrapped only the word "ecosystem" in H2 "Four programs, one ecosystem." so the keyword pops against sharp dark #0D0D0B siblings (Linear/Stripe playbook). Brand-bright 5-stop palette anchors to the PrismaticBurst hero color story: #E65325 sativa orange -> #F78D1E Sessions orange -> #FBB309 sunshine yellow -> #00A650 brand green (semantic anchor for "ecosystem") -> #ED135C delivery magenta. 8s ease-in-out loop with yoyo:true (alternates direction = 14s round-trip), background-size 200% sweeps across glyphs via background-position keyframe. Respects prefers-reduced-motion. New components: src/components/reactbits/GradientText.jsx + .css with full reactbits API parity (colors, animationSpeed, direction, pauseOnHover, yoyo, showBorder). Defaults to Sessions brand-bright palette so future usages stay on-brand without needing color overrides. Cross-page: only StaticPages.jsx /our-programs H2 touched; other pages untouched. Built with VITE_BASE=/v77/; 992.56 KB JS / 33.54 KB CSS. Per Canary-only testing rule, verification runs on Chrome Canary 150 ([email protected], MBP) post-deploy.
v76May 26, 20263:28 AM EDTARCHIVE
v76 PERMANENT FIX - cart-empty bug + Cannabis Act regulatory math. P0 ROOT CAUSE (Opus diagnosis): ProductCardV2 was passing variant as a bare string ("1g") but useCart.addItem expects an OBJECT {id, size, option, price}. Items were written with broken lineKey + missing variantSize + price=0 - cart looked empty even though Zustand had data. Fix: build proper variantForCart object {id, size, option, price: card-displayed price} in ProductCardV2 and pass that. Removed dead storeId prop - AddToCartButton re-resolves storeId from useStoreState. P0 REGULATORY: Health Canada Cannabis Act Schedule 3 dried-equivalent math rewritten. Previous EDIBLES=0.003/g multiplier under-reported by ~250x (10mg gummy was scoring 0.03g dried; real value per Canadian POS standard = 7.5g per package <=10mg THC). New DRIED_EQUIV table covers FLOWER/PRE_ROLLS/FRESH_FLOWER/VAPORIZERS/CONCENTRATES/EXTRACTS/TOPICALS/EDIBLES/BEVERAGES/TINCTURES/CAPSULES/SEEDS/CBD/ACCESSORIES with explicit mode (units vs grams) + factor. parseGrams handles mg/oz/fractional-oz ("1/8oz" -> 3.544g). addItem captures category at add-time. 30g Ontario limit tracker now accurate per Cannabis Act SOR/2018-144 Schedule 3. P1 DIAGNOSTIC: openDutchieFor() emits console.warn with attempted UUID + known UUIDs when STORE_BY_UUID lookup fails - silent failures unacceptable in regulated checkout. MODEL-SPLIT: Opus owned diagnosis + patch design; Sonnet owned write+build+deploy+Chrome verification. No source-version bumps needed (VITE_BASE env; all /v75 refs in source are comments). Visual verify next: Claude in Chrome on local Mac browser.
v75May 26, 20263:11 AM EDTARCHIVE
v75 Phase 1 — cart fix (Opus-designed, Sonnet-applied). Ported canonical seshweed-react useCart pattern with Vite-compatible ESM imports. Module-singleton Zustand store, persist key bumped sessions-cart-v1→v2 (with migrate that wipes v1 cache to prevent schema conflicts). Cart items now carry store_id auto-resolved from useStoreState.selectedStore.uuid. addItem backward-compat: accepts both old (product, variant) and new (product, {variant, storeId, quantity}) signatures via normalizeOpts. AddToCartButton clean rewrite: prompts store-picker if no store selected, fires fireConfettiFrom + useToast.show on add, dispatches cowork:cart-pulse event. Old globally-mounted CartDrawer REMOVED from App.jsx — /cart route is canonical cart surface. Header cart icon onClick → navigate(/cart) instead of dispatching open-cart event. groupByStore selector + openDutchieFor(uuid, productName) helper + checkoutViaWorker(item, uuid) for Worker /api/buy?store_id&slug deep-links. New cart selectors: subtotal(), totalGrams(), limitStatus(), getItemCount(). Studio canon adopted: api_8e2bbfd481b943e0 lineage + 6 Skills (cova-coverage-guard, regulated-data-no-silent-fail, destructive-cleanup-gated, canonical-cross-system-id, public-website-no-half-truth, cross-system-reconciliation-daily). Model-split rule: Opus owns PLAN+CHANGE, Sonnet owns SELF-TEST+DEPLOY+LOG. Next: Sonnet visual-verifies via Claude in Chrome on local Mac.
v74May 26, 20261:35 AM EDTARCHIVE
v74 — Premium 4-layer rebuild. LOGIC: ported seshweed-react/useCart pattern + Studio Dutchie URL pattern (https://{dispensaryId}.sessions.ca/?dtche[search]=...) + per-store groupByStore + openDutchieFor helpers. New /cart page (replaces drawer for full-page checkout experience, groups items by store, Cannabis Act 30g tracker, one Checkout button per store group). New /order-completed page with success animation, order steps. ANIMATION: global.css tokens --shadow-glow-{sm,md,lg,xl} + --ring-focus + .sc-cta-glow + .sc-card-glow + .sc-glass + .sc-dropdown-glow + .sc-badge-pulse + .sc-heart-pop. canvas-confetti orange brand burst from Add-to-Cart button bounds. Toast notification (slide-in top-right, success/error/info, lucide icons). ICONS: lucide-react installed and used across new components (Heart, Trash2, Minus, Plus, ArrowRight, ShieldCheck, Lock, ShoppingBag, CheckCircle2, Mail, Box, Truck, Flame, X, Info, XCircle); SessionsIcons.jsx kept for brand marks only. COMPONENTS: HeartButton with localStorage wishlist (scale-on-hover + heart-pop animation + fill toggle), TrendingFire (Lucide Flame + glitch keyframes ported from personal-7hw), ToastProvider mounted at root in main.jsx. PRODUCTCARDV2: now wears .sc-card-glow class (translateY -6px + orange shadow + image zoom 1.05 on hover), top-right HeartButton. ADDTOCARTBUTTON: fires confetti + toast on click. Cross-page check: all prior pages (careers/rewards/our-programs) intact. Visual verified via Claude in Chrome on local Mac.
v73May 26, 202612:35 AM EDTARCHIVE
Our Programs premium rebuild — inspired by reactbits.dev/backgrounds/prismatic-burst per user direction ("colorful using session branding guidelines mixed"). Built new PrismaticBurst.jsx/css component (CSS-only — 3 layered conic-gradients with brand-bright stops #E65325/#FBB309/#00A650/#F78D1E/#FBB35D/#ED135C, blurred + infinite rotation at different speeds + SVG noise grain overlay + radial vignette; respects prefers-reduced-motion). Dropped PageShell on /our-programs (kills the green-thread grainient void hero + PageShell SplitText titleAccent "for every sesh" clipped-headline + off-brand purple→magenta→orange gradient text). Custom centered hero layout: SESSIONS PROGRAMS eyebrow, large H1 "Programs for every kind of sesh.", subhead, 2 CTAs (white solid "See all programs" + glass-border "Find your store"), 3 checkmarks. PROGRAMS data: emoji 🌿⚡🎁 → SessionsIcons CannabisLeaf/IconBolt/IconGift; Sessions Rewards card accent #883477 purple → #F78D1E brand orange. Premium tile-icon boxes, brand-orange CTA buttons. Sitewide Footer mounted. Cross-page check: /v73/careers + /v73/rewards untouched. Visual verified via Claude in Chrome on local Mac browser.
v72May 26, 202612:28 AM EDTARCHIVE
Rewards hero: dropped photo (user feedback "dont use image use something like this banner" pointing at gift-cards page pattern). Replaced with reactbits Grainient animated WebGL gradient bg using Sessions brand arc (color1 #FBB35D amber → color2 #E65325 orange → color3 #00A650 brand green; warp + grain + soft motion). 2-column split mirrors GiftCardsPage hero architecture: copy + 2 CTAs + 3 checkmarks on left, new RewardsCardStack on right (3 floating Sessions Rewards Cards rotated and layered — BRONZE 247pts, GOLD 1,247pts, SESH 4,820pts with ★ Top tier badge). New RewardsCardArt SVG component renders tier-themed gradient cards (bronze→bronze, gold→amber, sesh→navy/black with orange sparkles). Visual demonstrates the tier ladder = premium feel. Cross-page: /v72/careers + /v72/ root untouched. Visual-verified via Claude in Chrome on local Mac browser.
v71May 26, 202612:17 AM EDTARCHIVE
Rewards page premium rebuild — 10 audit issues fixed, transplants Careers v70 architecture. (1) Dropped PageShell on /rewards entirely (kills the empty 600px grainient void + clipped "way to shop" H1). Custom layout: 21:9 image hero (reuses hero-L for brand cohesion) with overlay headline + Sign up free CTA, page intro, What you get, Four tiers, How to earn, FAQ, Fine print, Footer. (2) REWARDS_BENEFITS — 6 cards now use IconExclusiveOffers/IconVIPTreatment/IconGift/IconSparkle/IconSeshGear/IconInstantSavings SVGs (was Unicode glyphs ✦◈✿✱◆⌖ each in different off-brand color #883477/#ED135C/#388BFF/#F05A7B). All 6 icons now unified to brand orange #E65325 in orange-tile boxes. (3) Auto-fill grid + 7th-slot dark CTA card "Sign up in 30 seconds" → no more 6-in-4-col orphan cells. (4) Four tiers: Sesh accent #883477 purple → brand orange #E65325; Sesh now premium-est with Sessions Navy bg gradient + orange shadow + ★ Top tier flag; Silver lifted to #8A9099 for visibility. (5) How to earn step number circles: #883477 purple → brand orange gradient with shadow. (6) FAQ accordion: +/− marker #883477 purple → brand orange in orange-tinted circle. (7) Fine print: gray #94A3B8 SectionCard accent → custom brand-orange left-bar block with orange-tint bg. (8) All cards: --shadow-card 0 2px 12px rgba(13,13,11,0.06). (9) Sitewide Footer mounted. (10) Visual verified via Claude in Chrome on local Mac browser. Cross-page check: /v71/careers + /v71/ root untouched.
v70May 25, 20263:49 PM EDTARCHIVE
Careers premium rebuild — 12 audit issues fixed in one deploy. (1) Dropped PageShell on /careers entirely (kills ISS-001 grainient 1062px void, ISS-002 SplitText "growingteam" typo, ISS-010 two-heroes back-to-back). Custom layout: 21:9 image hero with inline CTA, then page intro, Why Sessions, Open Positions, What to Expect, Footer. (2) Emoji icons in Why Sessions (🌿📚📈🤝) replaced with CannabisLeaf/IconKnowledgeable/IconBolt/IconHandshake SVGs in brand orange tile (ISS-007). (3) Job card "Sessions" pill: brand green #00A650 instead of muted Tailwind green-700 #1F7A47 (ISS-008). (4) Open Positions grid: auto-fill minmax(320px,1fr) + 6th-slot dark "See all openings" CTA card linking career.sessions.ca — no more orphan empty cells (ISS-006). (5) Hero CTA + job-card Apply buttons: solid background-color #E65325 fallback under gradient (ISS-005). (6) Section padding 56px top/bottom; --shadow-card 0 2px 12px rgba(13,13,11,0.06) on all cards (ISS-009, ISS-012). (7) global.css --halo-indica rgba(124,58,237,0.18) → rgba(230,83,37,0.12) — no more purple wash in body bg (ISS-003). (8) global.css --grad-hero-text: brand-only arc #E65325→#F78D1E→#FBB309→#00A650→#E65325 — dropped #7C3AED + #EC4899 (ISS-011). (9) Sitewide Footer mounted at bottom of CareersPage (ISS-004). Visual verified via Claude in Chrome on local Mac browser per patched deploy-demo-sessions-ca SKILL.md.
v69May 25, 20263:15 PM EDTARCHIVE
Careers hero banner — fix v68 layout bug. v68 injected the 21:9 nano-banana banner as a CHILD of PageShell, so it rendered BELOW the existing grainient hero (orange→pink gradient + breadcrumb/title). Banner was there but pushed past the fold. v69 moves the banner OUT of PageShell entirely — wraps CareersPage return in a Fragment and places the banner section FIRST (above PageShell). Hero image is now the actual top of /careers. Headline H1 promoted from H2, font sizes scaled up (clamp 28-56px) so it reads as a true page hero. PageShell breadcrumb/eyebrow/title/CTA still render below the banner unchanged. Discipline lesson burned in: never claim "visually verified" from HTTP 200s alone — must screenshot the rendered page.
v68May 25, 20263:09 PM EDTARCHIVE
Careers page hero — 21:9 ultrawide banner illustration of a real Sessions Cannabis store interior, generated via Gemini 2.5 Flash Image (nano-banana) multimodal SDK then outpainted from a 1:1 reference to widescreen to preserve the canonical Sessions floor-projection logo (white ring + orange asterisk-burst with ray-tip ornaments), all 4 orange portal ceiling fixtures, 3 figures (2 SESSIONS-branded staff + 1 customer), the orange feature wall, SESSIONS-branded display fridges flanking the scene, and the reflective polished concrete floor. Banner sits above the existing /careers content with a left-anchored quiet zone for the "Inside every Sessions store — the same warm welcome" headline overlay (One floor culture eyebrow, 50+ stores / owner-operated floors / budtender-to-franchise-owner copy). Key sourced from MBP Keychain sessions-gemini-paid — value never written to memory or consciousness.
v67May 25, 20261:51 AM EDTARCHIVE
Premium FilterSidebar rebuild — premium e-commerce rules end-to-end. (1) Killed v45-v66 inline-CSS explosion (was ~238KB serialized per render — every interactive element used all:'unset' + 20 inline style props each). Replaced with scoped CSS classes in FilterSidebar.css (5.3KB). (2) WCAG AA contrast: engaged sidebar bg now Dark Green #26533D (8.4:1 with white text). Old #F8A53B + white was 2.45:1 — AODA-exposed (Sessions has 50+ Ontario stores; fines up to $50k/day per violation). (3) Real selection affordance: every FilterRow now sets aria-pressed AND shows a visible checkbox (orange-fill SVG) — selection visible to assistive tech AND visually unambiguous (was font-weight tint only). (4) Count badges on every FilterSection header when selections active (orange pill bg, inverts to white-on-green when sidebar is engaged). Baymard data: ~23% conversion lift. (5) Discount toggle wrapped in its own FilterSection (now "Offers · On sale only") — gains the same border-bottom rhythm as every other section. Clear button + count footer split into separate actions. (6) SVG chevron rotates 180° on FilterSection open; SVG refresh icon on Clear (was ↻ Unicode); custom thin scrollbar (was browser default); 1px dividers (was rgba 0.20 near-invisible). (7) Full a11y: aside is <h2 id="fs-aside-title"> + aria-labelledby, <output aria-live="polite" aria-atomic="true"> for the count, aria-hidden on decorative SVGs, focus-visible orange #F78D1E outlines. (8) CATEGORIES extended to 10 (added Tinctures, Topicals, Merchandise).
v66May 23, 20261:43 PM EDTARCHIVE
Brand-alignment + Header nav fix. (1) Header CATEGORY_NAV row was 2 elements (NavLink + button); chevron button had e.preventDefault() and the click hit area overlapped the link — clicks opened submenu instead of navigating. Collapsed into a single NavLink wrapping label+chevron span; chevron is non-interactive; submenu opens on parent hover. (2) Extracted Sessions 2026 BrandGuidelines.pdf to src/data/brand-tokens.json (9 main + 12 secondary colors, 8 approved gradients, Brother 1816 font, 32 official icon names). (3) Global color sweep — 162 hex replacements across 9 files swapped 10 non-brand hexes for brand equivalents (#6E5DC6→#883477 Indica Purple, #CC1D92→#ED135C Delivery Red, #2ABB7F→#00A650 Hybrid Green, #FFB040→#FBB35D Light Orange, #FAF7F0/#F4F1E8→#F9F6EE Bone White, etc). (4) SessionsIcons.jsx extended from 5 to 35 exports: 12 category badges (Flower/PreRolls/Vapes/Concentrates/Edibles/Topicals/Beverages/Capsules/Accessories/Seeds/Merchandise/InfusedPreRolls), experience+rewards icons (Knowledgeable/Inviting/FreeDelivery/InstantSavings/VIPTreatment/SeshGear/ExclusiveOffers), plus replacement UI icons (Phone/Mail/Calendar/Bolt/Gift/Handshake/Sparkle/Cart/ID/Scooter/Mic/Shirt) for emoji swap-in next.
v65May 23, 20261:43 PM EDTARCHIVE
CircularGallery scroll regression fix. Restored the v27 pinned-center-fold behavior. (1) Title block (Featured Items eyebrow + Sessions Featured h2 + View All link) now lives INSIDE the sticky panel via new prop — stays centered the whole way through the scroll-driven rotation instead of disappearing off the top. (2) Rotation dialed back from 540deg → 300deg over the scroll length (matches v27, no more "spinning forever" feel). (3) Sticky panel height = 100vh, section height = 180vh — pin truly centers and there's no dead cream gap before "Everyday Deals". (4) hint moved into the pinned panel as a footer prop. Outer section paddingTop dropped to 0.
v64May 23, 20261:28 PM EDTARCHIVE
Real catalog wiring + data lake. (1) Discovered sessions-availability-edge.ravi-abe.workers.dev is already serving the full Sessions catalog (8,593 products across FLOWER/EDIBLES/PRE_ROLLS/CONCENTRATES/VAPORIZERS/TINCTURES/TOPICALS/ACCESSORIES). (2) Fixed useShopFilters URL param mismatch: now accepts BOTH Header shape (cat=, type=, s=) AND internal shape (category=, types=, search=), normalizes lowercase enum (flower→FLOWER, oils_capsules→TINCTURES, etc). (3) New SUB_TYPES predicate table in ShopPage with 40+ subtype matchers — strain (indica/sativa/hybrid), edibles (gummies/chocolate/beverages/mints/baked), concentrates (shatter/wax/rosin/live-resin/hash/distillate/crumble), vapes (510/pod), oils (cbd-oil/thc-oil/capsules-oc), topicals (creams/balms), accessories (papers/grinders/bongs/pipes/lighters/trays/storage/ashtrays/filters/scales/cleaning/vape-acc/dab-tools/torches/bubblers). (4) CATEGORIES config extended to 11 categories so all show in filter sidebar. (5) MERCHANDISE friendly empty state ("Sessions merch coming Q2 2026"). (6) NEW data lake: scripts/pull-catalog.mjs pages every category, normalizes to src/data/sessions-catalog.v3.json (3.0MB, 8593 products) + ~/cowork-memory/sessions-catalog/snapshot-2026-05-24.json + latest.json symlink. (7) Daily launchd plist (next step) runs ingestion at 04:00 America/Toronto.
v63May 23, 202612:24 PM EDTARCHIVE
Gift Cards full creative rebuild. Dropped PageShell (was the same giant-empty-grainient bug as Our Vibe). New split hero: pink→magenta→purple gradient w/ headline + dual CTAs on left, FLOATING STACK of 3 hand-drawn SVG gift cards on the right (rotated, layered, brand colors w/ Sessions monogram + chip + denomination + sparkle) — front card live-updates as you pick a denomination. New: live preview tile + denomination picker w/ pill-button glow on selected + recipient form. New "How it works" 3-step w/ custom SVG art (PickAmountArt, WriteNoteArt, DeliverArt). New "Perfect for any occasion" 4-card grid (Birthdays/Holidays/Just because/Housewarmings) w/ custom CakeIcon/SnowflakeIcon/HeartIcon/GiftBowIcon. New dark-green "Where they work" stat band (50+/16+/132k+/-k) w/ floating gift card art. 5-question FAQ accordion. Footer + dashed fine-print box.
v62May 23, 20264:35 AM EDTARCHIVE
Our Vibe creative pass. Replaced flat emoji icons with 4 custom inline SVG illustrations (LeafArt w/ veins+dew, HandshakeArt w/ sleeves+sparkle, BoltBagArt w/ shopping bag+lightning+speed lines, CoinStackArt w/ S monogram+sparkles). Asymmetric Sessions Difference layout: hero card spans 2 rows w/ 120px LeafArt, eyebrow, bigger title, body, checked bullet list — flanked by 3 supporting cards each with their own SVG + accent stripe. Our Story rebuilt as a TRUE horizontal connected timeline: orange→magenta→purple gradient line under 4 white milestone nodes containing custom-drawn icons (store front, growth bars, loyalty star, SESH bottle), with display-type year + milestone card. Behind the Budtenders avatars upgraded to gradient orb + cannabis-leaf badge + branded role/city/years pills. Final CTA + Built for community now have decorative SVG art bleeds. Footer rendered. Visual verified fold by fold.
v61May 23, 20264:28 AM EDTARCHIVE
Our Vibe full rebuild. Dropped PageShell (was producing a broken animated hero with ghost text). New custom hero: 4-color grainient + radial highlight, "Rooted in community. Elevated by cannabis." 64px headline + dual CTAs (Find a store / Shop now). Added by-the-numbers strip (50+/4yr/4.7star/80k), kept "The Sessions Difference" 4-card grid, NEW Our Story 4-step timeline (2020 first store → 2026 50 stores + SESH), NEW Behind the Budtenders 4-card staff spotlights with role/city/years, expanded community testimonials to 6 cards with star ratings + Verified Review pills, NEW Built for Community impact band (120+ events / 30+ local LPs / owner-operated), Come See For Yourself final CTA band. Real Footer rendered.
v60May 23, 20264:27 AM EDTARCHIVE
Locations page UX repair. (1) City filter pill row now hides the native horizontal scrollbar, adds gradient edge fades + circular chevron buttons that scroll the rail programmatically + scroll-snap. (2) Cambridge/Hespeler & other "Hours coming soon" bug fixed — merge now falls back to sessions-stores.v2.json (real Dutchie-pulled hours) when Sophie's Excel has no entry. (3) Each store card hero now lazy-loads a live Google Maps embed iframe pinned to the actual storefront address (no API key needed) — Sessions branded orange gradient + logo shows as instant fallback under the map; "Live map" pill top-left. Real GMB photos require a which is not yet configured.
v59May 23, 20264:24 AM EDTARCHIVE
Careers + Franchise premium relaunch. /careers: 4-card "Why Sessions" grid + live search + 3 filter pills (location/type/brand) + 2-col job card grid pulling the 5 real Sessions openings (Key Lead Thunder Bay, Budtender Thunder Bay, Budtender West Brant, Key Lead West Brant, Budtender/Delivery Driver Timmins) with green Sessions pills and "View & Apply" deep-linked to career.sessions.ca + 3-step apply expectation strip (green gradient). /cannabis-franchise: stat strip (50+ stores / 4 yr / 20+ cities / 80k members) + 6-card "what you get" grid (brand, vendor power, POS, AGCO, training, marketing) + 4-step inquiry→opening process + cream "who we are looking for" panel + 5-question FAQ accordion + orange-gradient Apply CTA.
v58May 23, 20264:20 AM EDTARCHIVE
Rewards page premium polish: kept 6-perk grid + added 4-tier ladder (Bronze/Silver/Gold/Sesh with point ranges + per-tier perks + colored top stripe) + 4-step how-to-earn grid w/ purple-numbered chips + 5-question FAQ accordion (AGCO point-redemption rules, tier progression, expiry) + Sign Up Free CTA. Gift Cards: live orange-gradient card visual updates as you click denominations (/////custom), recipient name+email+message form, Sessions branded gradient CTA "Add to bag", full gift card terms.
v57May 23, 20264:16 AM EDTARCHIVE
Our Programs + Delivery polish. Our Programs: 3-card grid (Quality / Speed / Loyalty promises) each with branded icon, 3-step how-it-works flow with numbered orange chips, branded CTAs, +Sessions-gradient "one ecosystem" CTA band. Delivery: 16-city service area pills + 4-step how-it-works grid w/ icons + 4-question FAQ accordion (native details/summary) + purple-gradient "Tip your driver" callout. Real content per Cannabis Act regulations + Sessions positioning.
v56May 23, 20264:14 AM EDTARCHIVE
(1) Fixed SESH hours match — Sophie\'s hours sheet keys by Sessions city/store name (e.g., "Hamilton Mohawk" not "Hamilton"), so SESH-branded stores in Hamilton/Komoka/Brantford weren\'t matching. v56 adds city-startswith fallback (Hamilton SESH stores now inherit Hamilton-Mohawk hours) PLUS hardcoded SESH default Mon-Sat 9am-9pm per Excel footer note. All 4 SESH cards now show live Open Now status. (2) Our Vibe page premium polish — replaced generic 2-card SectionCard layout with: "The Sessions Difference" 4-card grid (🌿 Cured fresh, 🤝 Real budtenders, ⚡ Same-day pickup, 🎁 Loyalty that pays) each with branded accent color, testimonial scroll row (4 customer voices from London/Hamilton/Cambridge/Ottawa with city citations), Sessions-branded orange-gradient "Built for community" footer band w/ "Find your nearest Sessions →" CTA linking to /locations.
v55May 23, 20264:13 AM EDTARCHIVE
LocationsPage Figma polish per Sophie\'s location_cards.svg design + Sophie\'s Excel data merge. Parsed Sessions Store Information.xlsx (48 Sessions + 6 SESH stores, with phone/email/CRSA/weekly hours) into src/data/sophie-stores.json. New storeHoursUtil.js implements: (1) Open Now logic with America/Toronto timezone — "Open · Closes 9 pm" / "Closing soon" / "Closed" badges. (2) Day grouping — consecutive days with identical hours collapse to "Monday - Wednesday: 9 am - 9 pm" etc. New StoreCard: orange-gradient hero with Sessions logo + city overlay, store name + Open Now status pill, three contact rows (address pin, email envelope, phone), divider, "Store Hours" header with grouped table, GET DIRECTIONS (outline orange) + SHOP LOCATION → (filled orange w/ Sessions shadow) CTAs, CRSA license footer. Live Toronto time → real Open Now per store.
v54May 23, 20263:23 AM EDTARCHIVE
Secondary pages fix. (1) CF Pages _redirects added — direct URLs to /vN/anything (e.g. /v54/locations, /v54/our-vibe) now serve the SPA instead of falling back to root picker. Rule per active version: /v54/* /v54/index.html 200. (2) /locations route added in App.jsx (was missing — Header nav link <NavLink to=\"/locations\"> existed but fell through to * catchall rendering HomePage). (3) LocationsPage v1 built — shows all 49 Ontario Sessions stores in 4-up responsive grid using ALL_STORES data, city filter pills, search by city/name/address, SESH badge for SESH-branded stores, "Shop this store →" CTA opens Dutchie menu in new tab, "Get directions" opens Google Maps. v55 will swap to Sophie\'s location_cards.svg design with store photos + hours + Open Now badges.
v53May 23, 20263:17 AM EDTARCHIVE
Fix: URL stays under /vN/ for all in-app navigation. BrowserRouter basename defaulted to "/" when VITE_ROUTER_BASE wasn\'t set, so clicking Shop / a product card / Back stripped the version prefix — URL became demo.sessions.ca/shop instead of demo.sessions.ca/v53/shop. v53 falls back to import.meta.env.BASE_URL (which IS set automatically by VITE_BASE=/v53/), so every internal route is now prefixed correctly. Shareable URLs, refresh, browser back/forward all stay scoped to the version.
v52May 23, 20262:45 AM EDTARCHIVE
Cart drawer polish per user feedback. (1) Ontario gram limit ALWAYS visible — slim progress bar with "Ontario daily limit · 1.4g / 30g" label, fill bar uses Sessions orange that deepens to #C03C15 when blocked. Previously the limit only appeared as a warning banner near the threshold. (2) Sessions brand colors applied — drawer accents now use --sessions-orange token, Checkout CTA uses the Sessions branded gradient linear-gradient(135deg, #E65325 0%, #F78D1E 60%, #FBB35D 100%) with brand-orange shadow. (3) "Checkout on Dutchie →" → just "Checkout →". Subtotal small print no longer references Dutchie either ("Final purchase completes via your selected Sessions store"). Visual consistency across cart drawer matching the Sessions brand identity.
v51May 23, 20262:37 AM EDTARCHIVE
Bug fix: v50 PDP "Add to Cart" caused blank-page crash (React error #31 — "Objects are not valid as a React child"). Root cause: PDP handleAddToCart was passing detail.brand object {name,logo,description,source} as item.brand instead of detail.brand.name. CartLine rendered the raw object → React crashed → blank screen. v51 fixes the brand extraction at the source AND hardens CartLine to defensively coerce item.brand / product_name / variant_size to strings (typeof check + fallback to .name if object). Cart drawer now opens cleanly from PDP "Add to Cart" — confirmed working alongside the v50 global Header unification.
v50May 23, 20262:28 AM EDTARCHIVE
Fix PDP header + unify add-to-cart. PDP was rendering a custom mini topbar (just back button + sessions logo) instead of the global <Header> with full nav + CartIcon — broke visual unity with the rest of the site and made the cart icon disappear from the top-right. v50 swaps the custom topbar for the global Header + a slim "Back to Shop" strip below it. Add-to-cart buttons on the PDP (hero "Add to Cart" + per-store "Add to Cart") were already wired to useCart.addItem as of v46, so they correctly open the global cart drawer — now that the Header is present, the cart icon shows the item-count badge updating live and the drawer slides in from the right matching shop-page behavior. Header + footer + cart now consistent across home, shop, PDP.
v49May 22, 202611:30 PM EDTARCHIVE
Fix WeightSelector dropdown clipped by card overflow:hidden. v47-48 cards had overflow: hidden on the card root (needed to round-clip the image), which also clipped the weight dropdown when it opened — second option appeared cut off behind the next row of cards. v49 moves the overflow:hidden onto the image area itself with borderRadius: 17px 17px 0 0 (so image still clips to rounded top corners), leaves the card root overflow: visible so dropdown extends freely. Also bumped card zIndex to 5 on hover and WeightSelector dropdown zIndex to 100 so dropdown stacks above the next row of cards reliably.
v48May 22, 202611:13 PM EDTARCHIVE
Data-quality polish on v47 cards. (1) Subtitle no longer shows ugly "N/A · Accessories" — when variant_size is empty/PRJ/N/A, just shows the category ("Accessories" not "N/A · Accessories"). (2) Strain badges (Hybrid/Indica/Sativa) HIDDEN for non-cannabis categories (ACCESSORIES, MERCHANDISE, APPAREL) — papers/lighters/grinders no longer mis-tagged as Hybrid. (3) Claymorphism v8 — restored to deploy bundle (was 404 after trim). All other versions v36-v47 preserved.
v47May 22, 202610:59 PM EDTARCHIVE
ProductCard premium redesign. v46's dark navy panel hid the product photo — v47 removes it entirely. New layout: image area on cream #FAF7F0 1:1 square w/ contained image + 14px padding (image fully visible, never obscured); strain badge top-left + status badge top-right only overlay image, never info zone; below: white info zone w/ brand eyebrow (10px uppercase tracked), bold 14px title w/ 2-line clamp + minHeight for card-height alignment, format subtitle (e.g., "1.5g · pre rolls"), cream THC/CBD chips (only when data present), price row at bottom — bold 18px price + strike + orange "% Off" pill + black "+ ADD" pill (morphs to orange stepper after first add per v46). Hover: image scale 1.04, card shadow deepens, 160ms ease-out. Premium-quiet Aesop tone w/ Sessions cannabis specificity.
v46May 22, 20267:26 PM EDTARCHIVE
Premium cart + PDP overhaul. New AddToCartButton = pill "+ Add" that morphs into − qty + stepper inline after first add. CartDrawer rewritten — right-slide premium drawer with brand/title/variant/qty/remove per line, Ontario 30g equivalent limit check (warning at 24g, hard-block at 30g), subtotal, "View bag" + "Checkout on Dutchie →" + "Continue shopping". useCart Zustand store with localStorage persist — KEPT BACKWARD-COMPAT with legacy API (getTotal/getItemCount/cartOpen/setCartOpen/syncCheckout/updateQuantity/clearCart) so existing Header CartIcon + old code still works. ProductDetailPage now wraps Sophie's 4-tab system from description_section.svg: DESCRIPTION (prose + Genetics/Aroma/Effects/Appearance/Terpenes bullets), SPECIFICATION (2-col key/value with info-icons), AVAILABILITY (pointer to store list below), REVIEW (5-star ratings + comment composer). PDP add-to-cart wired to new local cart instead of direct Dutchie redirect.
v45May 22, 20267:24 PM EDTARCHIVE
/shop page — new ProductCardV2 from Sophie's Asserts drop. Strain badges (Sativa #E65325 / Indica #883477 / Hybrid #00A650 from type_plant.svg), status badges (Sale/New from Badges.svg), dark navy panel overlay on lower product image with brand/title/THC/CBD chips, weight dropdown, orange + button that opens Dutchie checkout in new tab. Filter sidebar = text rows w/ bottom dividers (NOT checkboxes) per filter_bar 2.svg; sidebar turns orange #F8A53B when filters applied. URL-synced filter state (Zustand), active-filter chip strip above grid, sort popover, skeleton loading, empty state. rembg u2net image-prep script (scripts/prep-product-images.py) generates transparent PNG-32s at public/dutchie-masked/{200,400,600}/ — kills the Dutchie white-bg issue entirely, no Photoshop roundtrip needed. v44 gradient flip superseded.
v44May 22, 20267:24 PM EDTARCHIVE
ProductCard — flip image gradient (Sophie's white-box fix for Dutchie JPEGs) Diagnosed: product images come from images.dutchie.com as JPEGs with pure white rgb(255,255,255) backgrounds baked in (no alpha channel). The previous card gradient 180deg #FAFAF7 → #F4F4F0 put the darker grey at the bottom, contrasting against the image's white bg and creating a visible "white box" effect. v44 flips it: 180deg #F4F4F0 → #FFFFFF — paper-grain at top, pure white at bottom. The image's white bg now blends seamlessly into the bottom of the card, eliminating the box look. Quick win per Sophie's suggestion; proper transparency pipeline (Worker R2 cache of PNG-32 with white-key masked to alpha 0) is queued as v51.
v43May 22, 20264:58 AM EDTARCHIVE
Hero secondary fold — center align heading + tagline + stats + CTA User wanted "Backed by Ontario. Built for community." headline + tagline centered (was left-aligned, reads as horrible). v43 centers the entire secondary fold: secondaryHeader adds margin: 0 auto + textAlign: center so heading + tagline both center on the viewport. secondaryBottomRow changes justifyContent from space-betweencenter so stats + CTA cluster together centered (was: stats pushed left, CTA pushed right). statRow.flex changes from "2 1 600px""0 1 auto" so it sizes to content + lets the CTA sit naturally next to it instead of being pushed across the row.
v42May 22, 20264:49 AM EDTARCHIVE
Hero Sesh font reverted + RewardsFooterBanner left-aligned to match folds above Two precise corrections to v41. (1) Reverted Hero H1 "Sesh" spacing — the v41 F3 added word-spaces inside the script-font span created awkward visual gaps. Original <span>Sesh</span> between <br/> tags is restored — the line breaks already provide both visual + screen-reader semantics. (2) RewardsFooterBanner content alignment swapped from fully centered → left-aligned to MATCH the StoreMapCTA fold directly above it (which has left-aligned headline + body + CTA) and the Rewards Bento fold above that (which has left-aligned content in its dark card). The mismatch was creating a jarring fold-to-fold alignment shift. ch16_inner drops grid + place-items:center + textAlign:center. ch16_textCol gets maxWidth:760 (matches Hero text column) + alignItems:flex-start. ch16_logoSm drops margin:auto (v41 fix). ch16_benefitsRow swaps auto-fit grid → flex wrap left-justified. ch16_legal drops maxWidth:805 (column handles it). Radial gradient origin re-positioned 50% → 22% to back the new left-aligned content (v41 F16 was correct for centered layout; now needs to follow content position).
v41May 22, 20264:38 AM EDTARCHIVE
Design audit pass — 12 of 20 flaws fixed (tokens + contrast + alignment + padding) User submitted 20-flaw design audit with 5 systemic root causes. v41 addresses the highest-impact 12: (F2) Both Hero CTAs unified to #E65325 (was mixed #E65325 / #C03C15). (F3) Hero H1 "Sesh" gets proper word spaces — DOM now reads "YOUR NEXT Sesh STARTS HERE" with separators (was concat with no spaces). (F5) Featured Categories halo inset -18% → -8% so glow no longer bleeds into adjacent items at 9-col grid. (F8) Featured Carousel header maxWidth 1920 → 1640 matching other folds. (F10) ch12 title #000000 → #0D0D0B unified with text-primary token. (F11) GalleryDeals subtext #B4BBBF → rgba(13,13,11,0.65) — WCAG contrast 1.82:1 → ~5:1 (passes AA). (F12) Lime green card subtext alpha 0.78 → 0.88 for better contrast on lime bg. (F13) Review cards width 320px → clamp(280px, 24vw, 380px) responsive. (F14) Stray #F9F6EE → #FAF7F0 unified cream. (F15) StoreMapCTA padding restored: 56/0/0 → 64/0/80 (breathing room before dark fold). (F16) RewardsFooter gradient origin 30% → 50% (matches centered content — was designed for 2-col layout). (F17) RewardsFooter logo gets margin:0 auto for true center. (F18) RewardsFooter benefits grid repeat(6,1fr) → auto-fit minmax(120px,1fr) responsive. (F19) RewardsFooter padding 72/72 → 80/88 matching Storewide Deals dark fold rhythm. Plus: design token CSS variables added to global.css (sc-text-primary, sc-cream-bg, sc-orange/-mid/-deep, etc) for systemic consistency going forward.
Remaining audit items deferred: F1 hero max-width consolidation (requires more careful refactor), F4 missing width:100% on 5 sections (audit ALL sections systematically), F6 H3 semantic-vs-size (intentional design choice), F7 grid min-width guards (responsive deeper dive), F9 EverydayDealsBanner wrapper (component refactor), F20 footer link sizes (footer audit). These deferred items don\'t affect visible quality on the demo viewports we test; flagged for v42+.
v40May 22, 20264:04 AM EDTARCHIVE
Fold transition cleanup — unify StoreMapCTA cream, drop off-brand navy from RewardsFooterBanner Two color-spec violations caught from the fold-transition screenshot. (1) StoreMapCTA bg was #F9F6EE — slightly off the #FAF7F0 cream we standardized in v35 across Rewards Bento + Gallery + Instagram. Tiny visible color step where the fold met the others. (2) RewardsFooterBanner bg was #1C2B36 — the SAME off-brand navy blue we explicitly dropped from Storewide Deals back in v26. It crept into this footer fold and we never caught it. v40 fixes both: ch15 cream unified to #FAF7F0, ch16 navy replaced with #0D0D0B Sessions deep black (same as Storewide Deals — keeps the two dark folds on-palette). Also: ch15 bottom padding zeroed and ch16 top padding bumped to 72 so the fold transition sits flush + breathing room is on the dark side where it belongs. Orange radial scrim alpha softened 0.18 → 0.10 since it sits on black now, not navy.
v39May 22, 20263:54 AM EDTARCHIVE
Remove Download App image from RewardsFooterBanner — single-column centered layout User requested deletion of the "Download the Sessions app" image (Download app.png) from the dark RewardsFooterBanner section. Dropped the wrapping div + img + DOWNLOAD_APP const + the ch16_appCol and ch16_appImg style objects. Changed ch16_inner grid from two-column 1fr/1fr → single-column 1fr with justifyItems:center + textAlign:center so the text block + benefits + CTAs now center on the section. Zero changes to any other folds.
v38May 22, 20263:45 AM EDTARCHIVE
StoreMapCTA — premium Ontario map SVG with branded location pins User dropped Layer 2 (1).svg (755×313 viewBox, 131KB, 61 paths) — Sophie\'s premium Ontario province map in steel blue with orange Sessions-branded location pins clustered around the actual store geography (GTA + Hamilton + London + Niagara). Each pin uses the Sessions asterisk-circle logo as the marker. Replaces the previous generic map-icon.png. Asset is production-ready as delivered — no photoshop tweaking needed. Wired in at StoreMapCTA section: copied to public/figma/sessions-assets/ontario-stores-map.svg, src swapped, alt text refined, maxWidth bumped 640 → 720 (SVG scales crisply at any size), display:block added.
v37May 22, 20263:22 AM EDTARCHIVE
CircularGallery — tightened whitespace (no more giant cream empty space above/below cards) User audit: too much cream empty space above + below the rotating product cards. Root cause: section was 260vh tall with a 100vh sticky window — cards (420px) centered in viewport leaving ~330px empty on each side. Title was absolute-positioned at section top, sitting alone in the cream void above the cards. v37 fixes: shrunk wrap height 260vh → 150vh (still enough scroll for ~1 full rotation), replaced 100vh sticky window with fixed 640px (just bigger than card height + breathing room), moved title block from absolute-overlay into normal flow above the gallery so they frame as one tight unit. Hint margin tightened 20px → 12px above + 24px below. Section padding flipped to 56/0 so cream flows continuously from title down into gallery wrap. Net effect: section visual height drops from ~3500px to ~1200px without sacrificing the scroll-driven 3D rotation effect.
v36May 22, 20263:12 AM EDTARCHIVE
Picker upgrade — deploy timestamps with AM/PM + brighter date typography Pulled deploy timestamps from Cloudflare Pages API (46 deploys, 27 mapped to versions v9-v35) and replaced ISO-date stubs with formatted local time: "May 22, 2026 · 3:03 AM EDT". Brightened .date class from grey #666 → cream #E5DECC at weight 700 for proper contrast on the #0D0D0B dark picker bg. Added .time sub-span in hero orange #F78D1E with tabular-nums. v8 predates CF Pages logging — falls back to estimated time. Picker-only update; no /vN/ content touched.
v8May 19, 20266:13 AM EDTARCHIVE
Sophie home page rebuild — Figma-faithful folds AI 3D claymorphism category icons · banner-bg hero · 6-benefit Rewards strip · footer with Ontario badge. CRSA #1382440 hardcoded across all stores.
Superseded by v9 for the per-store rebind. Kept browsable for design comparison.
Sessions Cannabis · Cannabis Retailer · License per store (see the v9 footer for the current store's CRSA) · ONTARIO AUTHORIZED CANNABIS RETAILER
Deploy convention: each new version → new /vN/ folder. No redirects. No subdomains. One demo.sessions.ca, many folders.