/* global React, ReactDOM, Nav, FooterCTA */
// ============================================================
//  THE BLOCK — every shop we pack for, one storefront each.
//  One file drives eight pages: shops.html (the street) and
//  shop-<slug>.html (each line). Images live in
//  assets/products/<dir>/<slug>_{front|45deg|scene}.jpg
//  These are concept renders of the factory range in our house
//  palette — cards carry what a piece IS, never invented specs.
//  WC_SHOPS stays a pure literal: scripts/build-shops.mjs
//  bracket-parses it to generate the static shells + seeds.
// ============================================================
const { useState, useRef, useEffect, useLayoutEffect } = React;

const WC_SHOPS = [
  {
    slug: "coffee",
    dir: "coffeeshop",
    name: "The Coffee Shop",
    accent: "red",
    tagline: "Hot cups, lids, sleeves, and carriers for the morning rush.",
    intro: "Forty shapes for the espresso line — from the everyday single wall to gold foil, color-change tricks, and lids with ears.",
    items: [
      { slug: "single-wall-cup", name: "Single Wall Paper Cup", note: "The classic. Light, printable, everywhere." },
      { slug: "double-wall-hot", name: "Double Wall Hot Cup", note: "Two walls, no sleeve needed — the everyday hot cup, upgraded." },
      { slug: "16oz-cup", name: "16oz Single Wall Cup", note: "The hero size, with room for a bold front print." },
      { slug: "8oz-kraft-cup", name: "8oz Kraft Cup", note: "The short pour — cortados, kids' cocoa, sample sizes." },
      { slug: "cup-family", name: "Coffee Cup Size Family", note: "8, 12, and 16 oz dressed in the same print." },
      { slug: "hot-drink-cup", name: "Hot Cup with Kraft Sleeve", note: "The counter classic, sleeve included." },
      { slug: "black-velvet-cup", name: "Black Velvet Double Wall", note: "Matte soft-touch black with a debossed mark — the tuxedo of hot cups." },
      { slug: "printed-dw-cup", name: "Full-Print Double Wall", note: "Edge-to-edge print with nowhere to hide a seam." },
      { slug: "foam-embossed-cup", name: "3D Foam Embossed Cup", note: "The logo is raised — customers feel it before they read it." },
      { slug: "gold-stamp-cup", name: "Gold Stamping Cup", note: "Gold foil lettering that catches the morning light." },
      { slug: "gold-cup", name: "Gold Metallic Cups", note: "Full metallic-gold walls in 12 and 16 oz — the anniversary special." },
      { slug: "uv-cup", name: "UV Color-Changing Cup", note: "Plain indoors. Walks into sunlight and the print blooms." },
      { slug: "heat-cup", name: "Heat Color-Changing Cup", note: "Pour something hot and the hidden pattern wakes up." },
      { slug: "holiday-cup", name: "Seasonal Holiday Series", note: "Four seasons, four prints, one shelf presence." },
      { slug: "corrugated-cup", name: "Corrugated Paper Cup", note: "Ribbed outer wall — grip and insulation in one." },
      { slug: "cork-cup", name: "Cork Insulated Cup", note: "A real cork band around the middle. Warm to hold, warmer to look at." },
      { slug: "butterfly-cup", name: "Butterfly Fold Cup", note: "Rim flaps fold shut like wings — a lid you don't have to stock." },
      { slug: "recyclable-dw-cup", name: "Recyclable Double Wall", note: "Double-wall comfort on recyclable stock." },
      { slug: "10oz-bio-cup", name: "10oz Biodegradable Cup", note: "The eco default for the mid-size pour." },
      { slug: "plastic-free-cup", name: "Plastic-Free Cup & Lid", note: "Paper cup, molded paper lid — no plastic anywhere in the pair." },
      { slug: "aqueous-cup", name: "Aqueous Coating Cup", note: "A water-based barrier coating instead of a plastic lining." },
      { slug: "cornstarch-cup", name: "Cornstarch Cup", note: "Soft ivory walls from a corn-starch blend." },
      { slug: "compostable-cold-cup", name: "Compostable Cold Cup", note: "Clear PLA for the iced side of the menu." },
      { slug: "44oz-cup", name: "44oz Giant Cold Cup", note: "Forty-four ounces of commitment, checkerboard band included." },
      { slug: "corrugated-plastic-cup", name: "Corrugated Anti-Scald Cup", note: "A clear cup with a ribbed grip zone." },
      { slug: "dw-plastic-cup", name: "Double Wall Plastic Cup", note: "A visible air gap between the walls — insulation you can see." },
      { slug: "premium-paper-lid", name: "Premium Paper Lid", note: "Smooth sip spout, embossed logo ring, zero plastic." },
      { slug: "paper-lid-90", name: "90mm Paper Cup Lid", note: "The molded paper lid with a fold-lock spout." },
      { slug: "panda-lid", name: "Panda Face Lid", note: "A 90mm lid with ears. The drink becomes the mascot." },
      { slug: "lid-plug", name: "Coffee Lid Plug", note: "Heart-tipped plugs that keep the sip hole splash-free." },
      { slug: "hot-sleeve", name: "Insulating Hot Sleeve", note: "Embossed kraft, printed with your mark." },
      { slug: "sleeve-set", name: "Cup Sleeve Design Set", note: "Checkerboard, starburst, comic, pinstripe — pick a wardrobe." },
      { slug: "stirrer-straw", name: "Three-Hole Stirrer Straw", note: "Stirs and sips — three holes so it can do both." },
      { slug: "coffee-dispenser-box", name: "Coffee Dispenser Box", note: "A carry-out coffee tank with a pour spout — meetings and crews." },
      { slug: "takeaway-set", name: "Takeaway Packaging Set", note: "Cup, sleeve, carrier, and bag matched like a uniform." },
      { slug: "kraft-carrier", name: "Fold-Flat Kraft Carrier", note: "Two-cup and four-cup, shipped flat." },
      { slug: "pulp-holder-2", name: "Pulp 2-Cup Holder", note: "Corrugated pulp with ribbed edges." },
      { slug: "pulp-holder-4", name: "Pulp 4-Cup Holder", note: "Molded pulp, embossed centers, four wells." },
      { slug: "popup-tray", name: "Pop-Up 2-Cup Tray", note: "Ships flat, pops open at the register." },
      { slug: "handle-carrier", name: "Handle Carrier Basket", note: "Two lidded cups and a built-in top handle." },
    ],
  },
  {
    slug: "bakery",
    dir: "bakery",
    name: "The Bakery",
    accent: "pink",
    tagline: "Cake boxes, windowed everything, and bags that survive the frosting.",
    intro: "Thirty-three shapes for the pastry case — windows shaped like hearts and snowflakes, drawers full of macarons, and one bottle shaped like a bear.",
    items: [
      { slug: "window-bakery-box", name: "Window Bakery Box", note: "A heart-shaped window does the selling before the lid opens." },
      { slug: "clear-cake-box", name: "Clear Cake Box", note: "A full clear panel — the cake is the packaging." },
      { slug: "cakeroll-box", name: "Cake Roll Box", note: "A long domed lid made for swiss rolls." },
      { slug: "cupcake-box", name: "Cupcake Box with Tray", note: "A molded four-slot insert keeps the frosting off the ceiling." },
      { slug: "cake-stand", name: "Paper Cake Stand", note: "A fold-flat pedestal that assembles into a display." },
      { slug: "macaron-box", name: "Macaron Drawer Box", note: "Slides open like a drawer, six molded slots inside." },
      { slug: "donut-box", name: "Donut Box", note: "A clear window over six glazed reasons to come in." },
      { slug: "doughnut-single", name: "Single Doughnut Clamshell", note: "One doughnut, its own box, a circular window." },
      { slug: "cookie-box", name: "Holiday Cookie Box", note: "A snowflake window for the December counter." },
      { slug: "pyramid-box", name: "Pyramid Gift Box", note: "A little monument with a ribbon tab at the apex." },
      { slug: "trapezoid-box", name: "Trapezoid Dessert Box", note: "Sloped walls, geometric shelf presence." },
      { slug: "combo-box", name: "Coffee & Dessert Combo Box", note: "A cup slot on one side, a pie well on the other." },
      { slug: "picnic-box", name: "Kraft Picnic Box", note: "A clear lid over a packed sandwich-fruit-cookie layout." },
      { slug: "sandwich-window", name: "Sandwich Wedge Box", note: "The club sandwich cross-section, framed." },
      { slug: "multi-sandwich-box", name: "Multi-Use Sandwich Box", note: "One flip-lid format for hot dogs, toast, and donuts." },
      { slug: "togo-box", name: "Handheld Togo Box", note: "One-hand box with a fold-out sauce well." },
      { slug: "flurry-cup", name: "Dessert Cup with Dome", note: "Soft-serve cup with a domed lid and a spoon-straw slot." },
      { slug: "icecream-paper-cup", name: "Ice Cream Paper Cup", note: "The two-scoop classic in printed paper." },
      { slug: "pulp-icecream-cup", name: "Molded Pulp Ice Cream Cup", note: "Embossed fiber texture, natural tone." },
      { slug: "pet-icecream-cup", name: "PET Sundae Cup", note: "Clear walls for layered sundaes and syrup stripes." },
      { slug: "waffle-holder", name: "Bubble Waffle Holder", note: "A cone holder with a drip-catch fold." },
      { slug: "muffin-cup", name: "Paper Muffin Cup", note: "Pleated cups that go from oven to display." },
      { slug: "baking-mold", name: "Paper Baking Mold", note: "Bakes in the mold, sells in the mold." },
      { slug: "grease-bag", name: "Grease-Resistant Snack Bag", note: "Churro-proof paper with a halftone print." },
      { slug: "greaseproof-bag", name: "Greaseproof Paper Bag", note: "Flat bag, comic-bubble print, croissant peeking out." },
      { slug: "toast-bag", name: "Toast Bread Kraft Bag", note: "A tall window bag for the morning loaf." },
      { slug: "restaurant-bag", name: "Restaurant Paper Bag", note: "Flat-bottom, twisted handles, big logo real estate." },
      { slug: "kraft-takeaway-bag", name: "Kraft Takeaway Bag", note: "Flat handles and a print that wraps the gusset." },
      { slug: "foil-bag", name: "Insulated Foil Bag", note: "Foil-lined and zippered — cakes arrive cool." },
      { slug: "bear-bottle", name: "Bear Juice Bottle", note: "A PET bottle shaped like a sitting teddy bear." },
      { slug: "pla-spoon", name: "PLA Dessert Spoon", note: "Compost-friendly, with an embossed handle." },
      { slug: "toothpick-flag", name: "Toothpick Flags", note: "Tiny printed flags for sliders and samples." },
      { slug: "round-sticker", name: "Printed Round Stickers", note: "The seal that turns a fold into a package." },
    ],
  },
  {
    slug: "boba",
    dir: "bubbletea",
    name: "The Boba Shop",
    accent: "cyan",
    tagline: "Sealed cups, domes, straws — every shape the counter shakes.",
    intro: "Thirty-seven shapes for the tea line — split chambers, cat paws, torches, color-change aluminum, and straws in four materials.",
    items: [
      { slug: "pet-boba-cup", name: "PET Boba Cup with Dome", note: "The brown-sugar classic — dome lid, pearl room below." },
      { slug: "u-cup-16", name: "16oz U-Shape Cup", note: "The rounded-base standard, sealed with printed film." },
      { slug: "pp-cup-90", name: "Classic 90mm PP Cup", note: "The workhorse — fits every standard sealer." },
      { slug: "printed-pet-cup", name: "Printed Cold Drink Cup", note: "Full-color retro print on straight PET walls." },
      { slug: "printed-pp-cup", name: "Full-Wrap Printed PP Cup", note: "Checkerboard head to toe, logo medallion front." },
      { slug: "amber-pet-cup", name: "Amber PET Cup", note: "A warm amber tint that flatters every iced drink." },
      { slug: "black-pet-cup", name: "Black PET Cup & Lid", note: "Opaque black with a single cream mark — the stealth option." },
      { slug: "frosted-cup", name: "Frosted Plastic Cup", note: "Matte frost that turns drinks into pastel glow." },
      { slug: "frosted-logo-cup", name: "Frosted Logo-Print Cup", note: "One bold logo on a soft-touch frost." },
      { slug: "frosted-iml-cup", name: "Frosted IML Cup", note: "In-mold matte label — halftone dots fading up the wall." },
      { slug: "iml-cup", name: "Glossy IML Injection Cup", note: "Photo-quality graphics fused into the wall, not stuck on." },
      { slug: "rainbow-iml-cup", name: "Rainbow Iridescent Cup", note: "An in-mold film that shifts color as the hand turns." },
      { slug: "injection-pp-cup", name: "Heavyweight Injection Cup", note: "Thick walls, glass-like clarity and heft." },
      { slug: "blister-cup", name: "12oz Blister Cup & Lid", note: "Featherweight PP pair with a crystal-thin wall." },
      { slug: "split-cup", name: "Split Dual-Chamber Cup", note: "Two drinks, one cup, a divider down the middle." },
      { slug: "s-share-cup", name: "S-Twin Share Cup", note: "Two S-shaped cups that lock into one cylinder." },
      { slug: "torch-cup", name: "Torch Milk Tea Cup", note: "A flared cone on a slim grip — the drink becomes a flame." },
      { slug: "catpaw-cup", name: "Cat Paw Cup", note: "A molded 3D paw bulges inside the wall. Strawberry milk fills it pink." },
      { slug: "fruit-bucket", name: "32oz Fruit Bucket Cup", note: "A bucket with a handle for the loaded fruit teas." },
      { slug: "milktea-cup-family", name: "Milk Tea Size Family", note: "500 and 700 ml in matching film prints." },
      { slug: "square-juice-bottle", name: "Square Juice Bottle", note: "Flat faces, clean label panel, fridge-stackable." },
      { slug: "juice-bottle", name: "Round Juice Bottle", note: "The classic round PET with a label band." },
      { slug: "pet-can", name: "Clear PET Can", note: "A ring-pull can you can see through — soda theater." },
      { slug: "spout-pouch", name: "Beverage Spout Pouch", note: "Stand-up pouch with a side spout and a carry hole." },
      { slug: "boba-set", name: "Branded Takeaway Set", note: "Cup, carrier, bag, and straws in one matched look." },
      { slug: "bulk-boba-case", name: "Bulk Boba Cup Case", note: "Factory-direct sleeves, stacked and shrink-wrapped." },
      { slug: "clear-lids", name: "Clear Lid Assortment", note: "Flat sip, dome, and strawless sipper — one wall of options." },
      { slug: "pp-lid-90", name: "90mm PP Injection Lid", note: "The standard lid with a center straw slot." },
      { slug: "sealer-film", name: "Custom Sealer Film Roll", note: "Your print, by the roll, through any standard sealer." },
      { slug: "clear-sleeve", name: "Clear Cup Sleeve", note: "Structure and grip without hiding the print." },
      { slug: "bag-carrier-2", name: "2-Cup Bag Carrier", note: "A clear bag with die-cut wells — two sealed cups, one hand." },
      { slug: "pla-bag", name: "PLA Carry Bag", note: "A milky compostable bag with starburst print." },
      { slug: "paper-straws", name: "Striped Paper Straws", note: "Candy stripes in the house colors." },
      { slug: "pla-straws", name: "Compostable PLA Straws", note: "The boba-gauge straw, compost-friendly." },
      { slug: "teafiber-straw", name: "Tea-Fiber Straw", note: "Made with spent tea leaves — amber flecks included." },
      { slug: "bamboo-straw", name: "Bamboo Fiber Straw", note: "Natural bamboo tone, banded in paper." },
      { slug: "cc-aluminum-cup", name: "Color-Change Aluminum Cup", note: "Matte aluminum that shifts color when the ice hits." },
    ],
  },
  {
    slug: "fastfood",
    dir: "fastfood",
    name: "The Fast Food Joint",
    accent: "yellow",
    tagline: "Clamshells, fry boxes, bowls, and wraps for the whole counter.",
    intro: "Thirty-seven shapes for the grill line — burger clamshells in board and pulp, boxes with windows, bowls with ripples, and paper by the roll.",
    items: [
      { slug: "burger-clamshell", name: "Burger Clamshell Box", note: "The classic flip-top with a big front billboard." },
      { slug: "pulp-burger-box", name: "Molded Pulp Burger Box", note: "The clamshell in natural fiber, logo embossed." },
      { slug: "burger-wrap", name: "Deli Burger Wrap Sheets", note: "Kraft sheets that make every smash burger look staged." },
      { slug: "foil-wrap-paper", name: "Foil Wrapping Paper", note: "Honeycomb-printed foil that keeps the melt going." },
      { slug: "butcher-paper", name: "Printed Butcher Paper", note: "Checkerboard by the roll — line trays, wrap brisket." },
      { slug: "fries-box", name: "French Fries Scoop Box", note: "Open-front scoop, engineered to overflow." },
      { slug: "chicken-togo-box", name: "Open-Top Chicken Box", note: "Folded corner walls, no lid, steam gone." },
      { slug: "chicken-takeout-box", name: "Chicken Box with Window", note: "Tuck-top box with a greaseproof window." },
      { slug: "chicken-series", name: "Fried Chicken Series", note: "Bucket, box, sleeve, and sauce cup in one family." },
      { slug: "fastfood-set", name: "Fast Food Full Set", note: "Clamshell to kraft bag — the whole counter, matched." },
      { slug: "folding-kraft-box", name: "Folding Kraft Takeout Box", note: "The noodle-box fold with locking tabs." },
      { slug: "kraft-box-family", name: "Kraft Box Size Family", note: "Small, medium, large — same stamp, three appetites." },
      { slug: "kraft-window-box", name: "Kraft Box with Window", note: "A heart-shaped window over the poke bowl." },
      { slug: "divider-lunch-box", name: "Divider-Lid Lunch Box", note: "The dividers live in the lid — rice, karaage, salad apart." },
      { slug: "paper-lunch-box", name: "White Paper Lunch Box", note: "Clean white board with a separate flat lid." },
      { slug: "plastic-lunch-box", name: "Clear Plastic Lunch Box", note: "A snap lid over a full-color bento layout." },
      { slug: "rice-pail", name: "Rice Pail with Handle", note: "Wire handle, fold-lock top — the takeout icon." },
      { slug: "pp-hinged", name: "Clear PP Hinged Container", note: "One-piece hinge, contents on display." },
      { slug: "mfpp-hinged", name: "White MFPP Hinged Box", note: "Microwavable white with a printed rim." },
      { slug: "round-bowl-clear-lid", name: "Round Bowl with Clear Lid", note: "Microwave-ready, ramen-visible." },
      { slug: "ripple-soup-bowl", name: "Ripple Wall Soup Bowl", note: "Ribbed walls and a vented lid for the hot ladle." },
      { slug: "kraft-soup-cup", name: "Kraft Soup Cup", note: "Smooth kraft walls, matching lid." },
      { slug: "paper-bowl-family", name: "Printed Paper Bowl Family", note: "Three sizes with starburst rims." },
      { slug: "corrugated-bowl", name: "Corrugated Kraft Bowl", note: "A ribbed insulating wall around the burrito bowl." },
      { slug: "pulp-bowls", name: "Pulp Bowls 8oz & 12oz", note: "Molded fiber with cobalt rim rings." },
      { slug: "pulp-clamshell", name: "Pulp Clamshell Container", note: "One big compartment, all natural fiber." },
      { slug: "pulp-divider-box", name: "Pulp Divider Lunch Box", note: "Bagasse box, fitted lid, three-way split." },
      { slug: "bagasse-lunch-box", name: "Bagasse Clamshell Box", note: "Hinged sugarcane fiber with a compost badge." },
      { slug: "sugarcane-tray", name: "Sugarcane Clamshell Tray", note: "The wide flat format for wraps and dogs." },
      { slug: "bamboo-lunch-box", name: "Bamboo Pulp Lunch Box", note: "Pale bamboo fiber with a subtle grain." },
      { slug: "cornstarch-container", name: "Cornstarch Container", note: "Round ivory bioplastic with a snap lid." },
      { slug: "cornstarch-lunch-box", name: "Cornstarch Hinged Box", note: "Satin-finish bioplastic clamshell." },
      { slug: "sauce-cups", name: "Kraft Sauce Cups", note: "Clear-lidded dip cups, ketchup to BBQ." },
      { slug: "wooden-cutlery", name: "Wooden Cutlery Set", note: "Fork, knife, spoon in a printed sleeve." },
      { slug: "cpla-cutlery", name: "CPLA Cutlery Trio", note: "Heat-resistant bioplastic in matte cream." },
      { slug: "pulp-spoon", name: "Molded Pulp Spoon", note: "Fiber-molded with an embossed grip." },
      { slug: "wet-wipes", name: "Printed Wet Wipe Sachet", note: "The branded finish to a messy order." },
    ],
  },
  {
    slug: "chicken",
    dir: "friedchicken",
    name: "The Chicken Shack",
    accent: "red",
    tagline: "Buckets, scoops, and boxes built to keep the crunch.",
    intro: "Twelve shapes for the fry station — the striped bucket, a box with a pull-out drawer, a tray that rides on your cup, and pizza boxes two ways.",
    items: [
      { slug: "chicken-bucket", name: "Classic Fried Chicken Bucket", note: "Red-and-cream stripes, lid on top, legend status." },
      { slug: "chicken-tray-box", name: "Chicken Box with Pull-Out Tray", note: "An inner tray slides out like a drawer — chicken up top, fries below." },
      { slug: "white-cardboard-box", name: "White Cardboard Takeout Box", note: "Crisp white tuck-top with one clean emblem." },
      { slug: "compartment-lunch-box", name: "Molded Compartment Box", note: "Chicken, corn, and slaw — separated at the source." },
      { slug: "compartment-tray", name: "Open Compartment Tray", note: "Four wells, cafeteria-style, rigid corners." },
      { slug: "kraft-fry-scoop", name: "Kraft Fry Scoop Cone", note: "Angled mouth, flat base — fries stand at attention." },
      { slug: "cup-top-tray", name: "Cup-Top Snack Tray", note: "Clips onto the cup rim, straw through the middle — one-hand snacking." },
      { slug: "graze-box", name: "Graze Box with Divider Lid", note: "A windowed charcuterie spread that travels." },
      { slug: "cornstarch-sauce-cup", name: "Cornstarch Mini Sauce Cup", note: "A hinged-lid dip cup in satin bioplastic." },
      { slug: "airfryer-liner", name: "Air Fryer Paper Liner", note: "Pleated walls, non-stick, retail-ready." },
      { slug: "kraft-pizza-box", name: "Foldable Kraft Pizza Box", note: "Natural kraft with steam vents and a center stamp." },
      { slug: "printed-pizza-box", name: "Full-Print Pizza Box", note: "Checkerboard border, HOT & FRESH starburst, white base." },
    ],
  },
  {
    slug: "sushi",
    dir: "sushi",
    name: "The Sushi Counter",
    accent: "green",
    tagline: "Trays, windowed boxes, party platters — and the little fish bottle.",
    intro: "Sixteen shapes for the roll case — kraft bands, corner windows, a push-pop you have to see, and the fish-shaped soy bottle everybody keeps.",
    items: [
      { slug: "sushi-band-box", name: "Kraft Box with Paper Band", note: "Two-piece kraft wrapped with a printed band seal." },
      { slug: "window-sushi-box", name: "White Box with Top Window", note: "A full clear window over the roll assortment." },
      { slug: "sushi-togo-window", name: "Kraft Box with Corner Window", note: "The window bends around the corner — rolls read from two sides." },
      { slug: "printed-sushi-box", name: "Full-Print Sushi Box", note: "A retro wave pattern that wraps every corner." },
      { slug: "square-sushi-box", name: "Square Grid Box", note: "A three-by-three grid with a stacking rim." },
      { slug: "slim-roll-box", name: "Slim Single-Roll Sleeve", note: "One hand roll, held like a snack bar." },
      { slug: "compartment-sushi-box", name: "Compartment Box with Sauce Wells", note: "Corner wells keep the wasabi where it belongs." },
      { slug: "bagasse-sushi-tray", name: "Bagasse Pulp Tray", note: "Molded fiber with a wave-embossed rim." },
      { slug: "compostable-sushi-lid", name: "Compostable Tray with Clear Lid", note: "Pulp base, PLA lid, compost badge embossed." },
      { slug: "rect-sushi-container", name: "Clear Rectangular Container", note: "The supermarket standard with an anti-fog lid." },
      { slug: "sashimi-box", name: "Premium Sashimi Box", note: "Matte black base, ice-look tray, anti-fog lid." },
      { slug: "round-sushi-platter", name: "Round Party Platter", note: "Concentric rings under a clear dome — the centerpiece." },
      { slug: "sushi-push-pop", name: "Sushi Push-Pop", note: "Stacked roll slices on a plunger. Yes, really." },
      { slug: "fish-soy-bottle", name: "Fish-Shaped Soy Bottle", note: "The tiny fish with the red twist-cap nose." },
      { slug: "sushi-tray-bag", name: "Flat Tray Carry Bag", note: "A flat-bottom bag that keeps platters level." },
      { slug: "wrap-cutter-box", name: "Wrap Box with Slide Cutter", note: "Cling film with a slide-track cutter — clean edges every pull." },
    ],
  },
  {
    slug: "cinema",
    dir: "cinema",
    name: "The Picture House",
    accent: "red",
    tagline: "Popcorn stripes, boat trays, and the big 32-ouncer.",
    intro: "Three shapes for the concession stand — pair them with the Drive-In combo tray and the 44-ouncer from the coffee shop shelf for the full intermission kit.",
    items: [
      { slug: "popcorn-bucket", name: "Printed Popcorn Bucket", note: "Red-and-cream stripes, built to overflow." },
      { slug: "32oz-pet-cup", name: "32oz PET Cold Cup", note: "The 98mm big-screen soda, flat or dome lid." },
      { slug: "kraft-boat-tray", name: "Kraft Boat Tray", note: "Folded-corner boat for nachos and dogs, greaseproof inside." },
    ],
  },
];

const SHOP_SHOTS = ["front", "45deg", "scene"];
function shopImg(shop, item, shot) {
  return `assets/products/${shop.dir}/${item.slug}_${shot}.jpg`;
}
function shopHref(shop) { return `shop-${shop.slug}.html`; }
function blockTotal() { return WC_SHOPS.reduce((n, s) => n + s.items.length, 0); }

// ============================================================
//  The street — one storefront per shop line
// ============================================================
function Storefront({ shop, i }) {
  return (
    <a className={`storefront awn-${shop.accent}`} href={shopHref(shop)}>
      <span className="awning" aria-hidden="true"><span className="blk-awning-scallop" /></span>
      <span className="storefront-sign">{shop.name}</span>
      <span className="storefront-tag">{shop.tagline}</span>
      <span className="storefront-peek" aria-hidden="true">
        {shop.items.slice(0, 3).map((item) => (
          <img key={item.slug} src={shopImg(shop, item, "front")} alt="" loading={i === 0 ? "eager" : "lazy"} decoding="async" />
        ))}
      </span>
      <span className="storefront-count">★ {shop.items.length} shapes inside</span>
    </a>
  );
}

function ShopsHub() {
  const rootRef = useRef(null);

  useLayoutEffect(() => {
    const gsap = window.gsap;
    if (!gsap) return;
    const ctx = gsap.context(() => {
      gsap.fromTo(".block-hero > *", { autoAlpha: 0, y: 26 },
        { autoAlpha: 1, y: 0, duration: 0.7, stagger: 0.12, ease: "power3.out" });
      gsap.fromTo(".storefront", { autoAlpha: 0, y: 34 },
        { autoAlpha: 1, y: 0, duration: 0.55, stagger: 0.08, ease: "back.out(1.3)", delay: 0.2 });
    }, rootRef);
    return () => ctx.revert();
  }, []);

  return (
    <div ref={rootRef}>
      <Nav />
      <main className="block-wrap">
        <header className="block-hero">
          <p className="block-eyebrow">★ who we pack for ★</p>
          <h1 className="block-title">The <em>Block</em></h1>
          <p className="block-sub">
            Seven storefronts, {blockTotal()} shapes — the whole street runs on our
            packaging. Every piece below is rendered in our house colors;
            yours ships in your brand, free mock-up first.
          </p>
        </header>

        <div className="block-street">
          {WC_SHOPS.map((shop, i) => <Storefront key={shop.slug} shop={shop} i={i} />)}
        </div>

        <footer className="block-foot">
          <p>
            Don&rsquo;t see your shop? The street keeps growing —
            <a href="contact.html"> tell us what you serve</a> and we&rsquo;ll pack it.
          </p>
        </footer>
      </main>
      <FooterCTA />
    </div>
  );
}

// ============================================================
//  One shop line — grid + lightbox detail
// ============================================================
function ShopDialog({ shop, item, onClose }) {
  const dialogRef = useRef(null);
  const [shot, setShot] = useState(0);

  useEffect(() => {
    setShot(0);
    const el = dialogRef.current;
    if (!el) return;
    if (item && !el.open) el.showModal();
    if (!item && el.open) el.close();
  }, [item]);

  if (!item) return <dialog ref={dialogRef} className="shop-dialog" onClose={onClose} />;

  const shotLabels = ["Front", "45°", "In the wild"];
  return (
    <dialog
      ref={dialogRef}
      className="shop-dialog"
      aria-label={`${item.name} — details`}
      onClose={onClose}
      onClick={(e) => { if (e.target === dialogRef.current) dialogRef.current.close(); }}
    >
      <div className="shop-dialog-inner">
        <button className="shop-dialog-x" onClick={() => dialogRef.current.close()} aria-label="Close">✕</button>
        <div className={`shop-dialog-viewer ${shot === 2 ? "is-wide" : ""}`}>
          <img src={shopImg(shop, item, SHOP_SHOTS[shot])} alt={`${item.name} — ${shotLabels[shot]}`} decoding="async" />
        </div>
        <div className="shop-dialog-thumbs" role="group" aria-label="Views">
          {SHOP_SHOTS.map((s, i) => (
            <button
              key={s}
              className={`shop-dialog-thumb ${i === shot ? "is-active" : ""}`}
              aria-pressed={i === shot}
              onClick={() => setShot(i)}
            >
              <img src={shopImg(shop, item, s)} alt="" loading="lazy" decoding="async" />
              <span>{shotLabels[i]}</span>
            </button>
          ))}
        </div>
        <div className="shop-dialog-info">
          <h2>{item.name}</h2>
          <p className="shop-dialog-note">{item.note}</p>
          <a className="btn-pill shop-dialog-quote" href="contact.html">Get a quote for this one →</a>
          <p className="shop-dialog-fineprint">Shown in our house colors — printed in yours. Free mock-up with every quote.</p>
        </div>
      </div>
    </dialog>
  );
}

function ShopPage({ shop }) {
  const rootRef = useRef(null);
  const [active, setActive] = useState(null);
  const lastCardRef = useRef(null);

  useLayoutEffect(() => {
    document.title = `${shop.name} — The Block | Wonderful Choice`;
    const gsap = window.gsap;
    if (!gsap) return;
    const ctx = gsap.context(() => {
      gsap.fromTo(".shop-hero > *", { autoAlpha: 0, y: 24 },
        { autoAlpha: 1, y: 0, duration: 0.65, stagger: 0.1, ease: "power3.out" });
      if (window.ScrollTrigger) {
        window.ScrollTrigger.batch(".shop-card", {
          start: "top 92%",
          once: true,
          onEnter: (els) => gsap.fromTo(els, { autoAlpha: 0, y: 28 },
            { autoAlpha: 1, y: 0, duration: 0.5, stagger: 0.05, ease: "power3.out" }),
        });
      }
    }, rootRef);
    return () => ctx.revert();
  }, []);

  const open = (item, e) => { lastCardRef.current = e.currentTarget; setActive(item); };
  const close = () => {
    setActive(null);
    // hand focus back to the card that opened the dialog
    if (lastCardRef.current) lastCardRef.current.focus();
  };

  const others = WC_SHOPS.filter((s) => s.slug !== shop.slug);

  return (
    <div ref={rootRef}>
      <Nav />
      <main className={`block-wrap shop-wrap awn-${shop.accent}`}>
        <a className="shop-backlink" href="shops.html">← Back to the Block</a>

        <header className="shop-hero">
          <span className="blk-awning blk-awning-hero" aria-hidden="true"><span className="blk-awning-scallop" /></span>
          <p className="block-eyebrow">★ the block · {shop.items.length} shapes ★</p>
          <h1 className="shop-title">{shop.name}</h1>
          <p className="block-sub">{shop.intro}</p>
          <p className="shop-honesty">Concept renders in our house palette — every piece is quoted with your art, free mock-up first.</p>
        </header>

        <div className="shop-grid">
          {shop.items.map((item, i) => (
            <button key={item.slug} className="shop-card" onClick={(e) => open(item, e)}>
              <span className="shop-card-imgs" aria-hidden="true">
                <img className="shop-card-front" src={shopImg(shop, item, "front")} alt="" loading={i < 4 ? "eager" : "lazy"} decoding="async" />
                <img className="shop-card-45" src={shopImg(shop, item, "45deg")} alt="" loading="lazy" decoding="async" />
              </span>
              <span className="shop-card-name">{item.name}</span>
              <span className="shop-card-more">Take a look ↗</span>
            </button>
          ))}
        </div>

        <ShopDialog shop={shop} item={active} onClose={close} />

        <footer className="shop-alsoblock">
          <p className="shop-alsoblock-label">★ also on the block ★</p>
          <div className="shop-alsoblock-row">
            {others.map((s) => (
              <a key={s.slug} className={`shop-chip awn-${s.accent}`} href={shopHref(s)}>
                <span className="shop-chip-awning" aria-hidden="true" />
                {s.name}
              </a>
            ))}
          </div>
        </footer>
      </main>
      <FooterCTA />
    </div>
  );
}

// ---- mount by page ----
(function () {
  const page = (document.body && document.body.dataset.page) || "";
  const root = document.getElementById("root");
  if (!root) return;
  if (window.gsap && window.ScrollTrigger) window.gsap.registerPlugin(window.ScrollTrigger);
  if (page === "shops") ReactDOM.createRoot(root).render(<ShopsHub />);
  if (page === "shop") {
    const shop = WC_SHOPS.find((s) => s.slug === document.body.dataset.shop) || WC_SHOPS[0];
    ReactDOM.createRoot(root).render(<ShopPage shop={shop} />);
  }
})();

Object.assign(window, { WC_SHOPS, shopHref });
