// === HALVSIES QUEST — WORLD ==========================================
// Tile types, screen maps, screen registry, drawMap + per-tile drawing.

const { C, TILE, MAP_W, MAP_H, PLAY_TOP } = window;

// ---------- Tile types ----------------------------------------------
const T = {
  GROUND:        0,
  WALL:          1,
  BUSH:          2,
  BED_L:         3,
  TABLE:         4,
  DOOR:          5,
  CAVE_DOOR:     6,
  CHEST:         7,
  PATH:          8,
  CAVE_FLOOR:    9,
  HOUSE_WALL:   10,
  HOUSE_ROOF:   11,
  BED_R:        13,
  SHELF:        14,   // tall shop shelving
  RUG:          15,
  FIELD_GRASS:  16,
  CAVE_ROCK:    17,
  STORE_WALL:   18,
  STORE_ROOF:   19,
  SIGN_STORE:   20,
  STORE_DOOR:   21,
  BOOKSHELF:    22,   // home bookshelf (renders 3-tile-tall column)
  COUNTER:      23,   // shop counter — solid but "talk through"
  STAGE:        24,   // concert stage platform (walkable, raised look)
  CLIFF:        25,   // jagged rock cliff (solid)
  STAGE_LIGHT:  26,   // stage spotlight column (decor, walkable)
  FENCE:        27,   // village south gate fence (solid until southUnlocked)
  SWITCH:       28,   // ground-pressure switch (walkable)
  LOW_COUNTER:  29,   // grandma's low counter — medium-shade slab
};

const SOLID = new Set([
  T.WALL, T.BUSH, T.TABLE, T.CHEST,
  T.HOUSE_WALL, T.HOUSE_ROOF, T.SHELF,
  T.CAVE_ROCK, T.STORE_WALL, T.STORE_ROOF, T.SIGN_STORE,
  T.BOOKSHELF, T.COUNTER, T.CLIFF, T.FENCE, T.LOW_COUNTER,
]);

function isSolidTile(t) { return SOLID.has(t); }
function isCounter(t)   { return t === T.COUNTER; }

// =====================================================================
// MAPS (each 12x12)
// =====================================================================

// A — Player's House (cozy: bed top-left, bookshelf back wall, table, rug)
const MAP_HOUSE_INT = [
  [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
  [ 1, 3,13, 0, 0, 0, 0, 0,22,22, 0, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0,22,22, 0, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0,22,22, 0, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 1, 0, 0, 0,15,15, 0, 0, 0, 0, 0, 1],
  [ 1, 0, 0, 0,15,15, 0, 0, 4, 4, 0, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 1, 1, 1, 1, 1, 5, 5, 1, 1, 1, 1, 1],
];

// B — Village Hub (bard's house in NE corner; N exit open dirt on left; south is fence/guard gate)
const MAP_VILLAGE = [
  [ 1, 0, 0, 0, 1, 1,11,11,11,11,11, 1],
  [ 1, 0, 0, 0, 1, 1,10,10, 5, 5,10, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 1, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 1, 1, 1, 1,27,27,27,27, 1, 1, 1, 1],
];

// C — Village - West (extra house with NPC)
const MAP_WEST = [
  [ 1, 1, 1,11,11,11,11,11,11, 1, 1, 1],
  [ 1, 1, 1,10,10, 5, 5,10,10, 1, 1, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [ 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [ 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
];

// C-int — grandma's house (cleanest lightest floor, counter at top, purse on counter)
const MAP_WEST_HOUSE = [
  [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0,22,22, 0, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0,22,22, 0, 1],
  [ 1, 0, 0, 0, 0, 0, 0,29,29,29,29, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 1, 0, 0, 0,15,15, 0, 0, 0, 0, 0, 1],
  [ 1, 0, 0, 0,15,15, 0, 0, 0, 0, 0, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 1, 1, 1, 1, 1, 5, 5, 1, 1, 1, 1, 1],
];

// D — Village - East (Store)
const MAP_EAST = [
  [ 1, 1, 1,19,19,19,19,19,19, 1, 1, 1],
  [ 1, 1, 1,18,18,21,21,18,18, 1, 1, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
];

// D-int — store (long counter; clerk on stool; 3-tall back shelves)
const MAP_STORE = [
  [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
  [ 1,14,14,14,14,14,14,14,14,14,14, 1],
  [ 1,14,14,14,14,14,14,14,14,14,14, 1],
  [ 1,14,14,14,14,14,14,14,14,14,14, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 1,23,23,23,23,23,23,23,23,23,23, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 1, 1, 1, 1, 1, 5, 5, 1, 1, 1, 1, 1],
];

// E — Empty Field (west edge: solid cliff barrier)
const MAP_EMPTY = [
  [ 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1],
  [25,16, 2,16,16,16,16,16,16,16, 2, 1],
  [25,16,16,16,16,16, 2,16,16,16,16, 1],
  [25,16,16,16,16,16,16,16,16, 2,16, 1],
  [25,16, 2,16,16,16,16,16,16,16,16, 1],
  [25,16,16,16,16,16,16,16,16,16,16, 0],
  [25,16,16,16,16,16,16,16,16,16,16, 0],
  [25,16,16, 2,16,16,16,16,16,16,16, 1],
  [25,16,16,16,16,16,16,16,16,16, 2, 1],
  [25,16,16,16, 2,16,16,16,16,16,16, 1],
  [25,16,16,16,16,16,16, 2,16,16,16, 1],
  [ 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1],
];

// F-int — cave_interior (puzzle: block + switch; chest hidden until solved)
const MAP_CAVE_INT = [
  [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
  [ 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 1],
  [ 1, 9,17,17, 9, 9, 9, 9,17,17, 9, 1],
  [ 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 1],
  [ 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 1],
  [ 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 1],
  [ 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 1],
  [ 1, 9, 9, 9, 9, 9,28, 9, 9, 9, 9, 1],
  [ 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 1],
  [ 1, 9, 9, 9,17,17, 9, 9, 9, 9, 9, 1],
  [ 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 1],
  [ 1, 1, 1, 1, 1, 5, 5, 1, 1, 1, 1, 1],
];

// F-ext — cave_exterior
const MAP_CAVE_EXT = [
  [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 1, 0, 0,17,17, 1, 1,17,17, 0, 0, 1],
  [ 1, 0,17,17, 1, 6, 6, 1,17,17, 0, 1],
  [ 1, 0,17, 1, 0, 0, 0, 0, 1,17, 0, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 1, 0, 2, 0, 0, 0, 0, 0, 0, 2, 0, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
];

// G — Monster Field (4 monsters)
const MAP_MONSTER = [
  [ 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1],
  [ 1,16,16,16,16,16,16,16,16,16,16, 1],
  [ 1,16,16,16, 2,16,16,16,16,16,16, 1],
  [ 1,16,16,16,16,16,16,16,16, 2,16, 1],
  [ 1,16,16,16,16,16,16,16,16,16,16, 1],
  [ 1,16,16,16,16,16,16,16,16,16,16, 1],
  [ 1,16,16,16,16,16,16,16,16,16,16, 1],
  [ 1,16,16,16, 2,16,16,16,16,16,16, 1],
  [ 1,16,16,16,16,16,16,16,16,16,16, 1],
  [ 1,16, 2,16,16,16,16,16,16,16,16, 1],
  [ 1,16,16,16,16,16,16,16,16,16,16, 1],
  [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
];

// H — Concert Stage (raised stage center; south exit only)
const MAP_STAGE = [
  [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 1, 0,26, 0, 0, 0, 0, 0, 0,26, 0, 1],
  [ 1, 0, 0,24,24,24,24,24,24, 0, 0, 1],
  [ 1, 0, 0,24,24,24,24,24,24, 0, 0, 1],
  [ 1, 0, 0,24,24,24,24,24,24, 0, 0, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
  [ 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1],
];

// New — Monster Gate: 2-tile wide funnel; the wide sleeper completely blocks it.
const MAP_MONSTER_GATE = [
  [ 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1],
  [ 1,16,16,16,16,16,16,16,16,16,16, 1],
  [ 1,16, 2,16,16,16,16,16, 2,16,16, 1],
  [ 1,16,16,16,16,16,16,16,16,16,16, 1],
  [ 1,16,16,16,16, 8, 8,16,16,16,16, 1],
  [ 1,16,16, 2,16, 8, 8,16, 2,16,16, 1],
  [ 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1],
  [ 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1],
  [ 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1],
  [ 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1],
  [ 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1],
  [ 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1],
];

// =====================================================================
// SCREEN REGISTRY
// =====================================================================
const SCREENS = {
  house_interior: {
    map: MAP_HOUSE_INT,
    label: "HOME",
    dark: false,
    npcs: [],
    chest: null,
    transitions: [
      { tx: 5, ty: 11, to: "village_hub", spawn: { tx: 8, ty: 2, dir: "down" } },
      { tx: 6, ty: 11, to: "village_hub", spawn: { tx: 9, ty: 2, dir: "down" } },
    ],
  },

  village_hub: {
    map: MAP_VILLAGE,
    label: "VILLAGE HUB",
    dark: false,
    npcs: [
      { id: "v_hub_1", kind: "villager", variant: 1, tx: 3, ty: 6, dir: "down", wandering: true,
        line: "Great, another guy with an acoustic guitar. Don't play Wonderwall." },
      { id: "v_hub_2", kind: "villager", variant: 2, tx: 8, ty: 7, dir: "down", wandering: true,
        line: "Are you going to look up from your shoes while you play, or is that part of the 'vibe'?" },
      // Guard at south gate — filtered out when southUnlocked in game.jsx
      { id: "guard", kind: "guard", variant: 0, tx: 5, ty: 9, dir: "down", wandering: false,
        unlocksSouth: true, line: "" /* dynamic */ },
    ],
    chest: null,
    transitions: [
      // North (top open path tiles) -> concert stage
      { tx: 1, ty: 0, to: "concert_stage", spawn: { tx: 5, ty: 10, dir: "up" } },
      { tx: 2, ty: 0, to: "concert_stage", spawn: { tx: 5, ty: 10, dir: "up" } },
      { tx: 3, ty: 0, to: "concert_stage", spawn: { tx: 5, ty: 10, dir: "up" } },
      // bard's house door
      { tx: 8, ty: 1, to: "house_interior", spawn: { tx: 5, ty: 10, dir: "up" } },
      { tx: 9, ty: 1, to: "house_interior", spawn: { tx: 5, ty: 10, dir: "up" } },
      // west / east
      { tx: 0, ty: 4, to: "west_village",  spawn: { tx: 10, ty: 4, dir: "left" } },
      { tx: 0, ty: 5, to: "west_village",  spawn: { tx: 10, ty: 5, dir: "left" } },
      { tx: 11,ty: 4, to: "east_village",  spawn: { tx: 1,  ty: 4, dir: "right" } },
      { tx: 11,ty: 5, to: "east_village",  spawn: { tx: 1,  ty: 5, dir: "right" } },
      // south
      { tx: 4, ty: 11, to: "empty_field", spawn: { tx: 4, ty: 1, dir: "down" } },
      { tx: 5, ty: 11, to: "empty_field", spawn: { tx: 5, ty: 1, dir: "down" } },
      { tx: 6, ty: 11, to: "empty_field", spawn: { tx: 6, ty: 1, dir: "down" } },
      { tx: 7, ty: 11, to: "empty_field", spawn: { tx: 7, ty: 1, dir: "down" } },
    ],
  },

  west_village: {
    map: MAP_WEST,
    label: "VILLAGE - WEST",
    dark: false,
    npcs: [
      { id: "v_west_1", kind: "villager", variant: 3, tx: 4, ty: 5, dir: "right", wandering: true,
        line: "Can't even hold a tune, that one." },
      { id: "v_west_2", kind: "villager", variant: 1, tx: 8, ty: 7, dir: "left",  wandering: true,
        line: "I'd tip you, but tipping bards is how this town got into trouble last time." },
    ],
    chest: null,
    transitions: [
      { tx: 5, ty: 1, to: "west_house",   spawn: { tx: 5, ty: 10, dir: "up" } },
      { tx: 6, ty: 1, to: "west_house",   spawn: { tx: 5, ty: 10, dir: "up" } },
      { tx: 11, ty: 4, to: "village_hub", spawn: { tx: 1, ty: 4, dir: "right" } },
      { tx: 11, ty: 5, to: "village_hub", spawn: { tx: 1, ty: 5, dir: "right" } },
      { tx: 11, ty: 6, to: "village_hub", spawn: { tx: 1, ty: 4, dir: "right" } },
      { tx: 11, ty: 7, to: "village_hub", spawn: { tx: 1, ty: 5, dir: "right" } },
    ],
  },

  west_house: {
    map: MAP_WEST_HOUSE,
    label: "GRANDMA'S",
    dark: false,
    npcs: [
      { id: "grandma", kind: "grandma", variant: 0, tx: 5, ty: 5, dir: "down", wandering: false,
        line: "Money? For your music? Heavens no. Go get a real job, dear." },
    ],
    chest: null,
    purse: { tx: 8, ty: 3 },  // Purse entity — only present when !hasMoney
    transitions: [
      { tx: 5, ty: 11, to: "west_village", spawn: { tx: 5, ty: 2, dir: "down" } },
      { tx: 6, ty: 11, to: "west_village", spawn: { tx: 5, ty: 2, dir: "down" } },
    ],
  },

  east_village: {
    map: MAP_EAST,
    label: "VILLAGE - EAST",
    dark: false,
    npcs: [
      { id: "v_east_1", kind: "villager", variant: 3, tx: 3, ty: 6, dir: "right", wandering: true,
        line: "Stay outta the shop, bard. The clerk's been waiting for a reason." },
      { id: "v_east_2", kind: "villager", variant: 1, tx: 8, ty: 9, dir: "left",  wandering: true,
        line: "If you're broke, don't even LOOK at the merchandise." },
    ],
    chest: null,
    transitions: [
      // store door (handled by store-door-tile interception in tryMove)
      { tx: 5, ty: 1, to: "store", spawn: { tx: 5, ty: 10, dir: "up" } },
      { tx: 6, ty: 1, to: "store", spawn: { tx: 5, ty: 10, dir: "up" } },
      { tx: 0, ty: 4, to: "village_hub", spawn: { tx: 10, ty: 4, dir: "left" } },
      { tx: 0, ty: 5, to: "village_hub", spawn: { tx: 10, ty: 5, dir: "left" } },
      { tx: 0, ty: 6, to: "village_hub", spawn: { tx: 10, ty: 4, dir: "left" } },
      { tx: 0, ty: 7, to: "village_hub", spawn: { tx: 10, ty: 5, dir: "left" } },
    ],
  },

  store: {
    map: MAP_STORE,
    label: "SHOPPE",
    dark: false,
    npcs: [
      {
        id: "clerk", kind: "clerk", variant: 0, tx: 5, ty: 5, dir: "down", wandering: false,
        line: "Look at your outfit. You can't afford anything in this shop. Out!",
        kickout: true,
      },
    ],
    chest: null,
    transitions: [
      { tx: 5, ty: 11, to: "east_village", spawn: { tx: 5, ty: 2, dir: "down" } },
      { tx: 6, ty: 11, to: "east_village", spawn: { tx: 5, ty: 2, dir: "down" } },
    ],
  },

  empty_field: {
    map: MAP_EMPTY,
    label: "FIELD",
    dark: false,
    npcs: [],
    chest: null,
    transitions: [
      { tx: 4, ty: 0,  to: "village_hub",  spawn: { tx: 4, ty: 10, dir: "up" } },
      { tx: 5, ty: 0,  to: "village_hub",  spawn: { tx: 5, ty: 10, dir: "up" } },
      { tx: 6, ty: 0,  to: "village_hub",  spawn: { tx: 6, ty: 10, dir: "up" } },
      { tx: 7, ty: 0,  to: "village_hub",  spawn: { tx: 7, ty: 10, dir: "up" } },
      { tx: 11, ty: 5, to: "cave_exterior", spawn: { tx: 1, ty: 6, dir: "right" } },
      { tx: 11, ty: 6, to: "cave_exterior", spawn: { tx: 1, ty: 7, dir: "right" } },
      { tx: 4, ty: 11, to: "monster_gate", spawn: { tx: 4, ty: 1, dir: "down" } },
      { tx: 5, ty: 11, to: "monster_gate", spawn: { tx: 5, ty: 1, dir: "down" } },
      { tx: 6, ty: 11, to: "monster_gate", spawn: { tx: 6, ty: 1, dir: "down" } },
      { tx: 7, ty: 11, to: "monster_gate", spawn: { tx: 7, ty: 1, dir: "down" } },
    ],
  },

  monster_gate: {
    map: MAP_MONSTER_GATE,
    label: "PATH SOUTH",
    dark: false,
    npcs: [
      // 2-tile wide sleeping man — 'wide:true' blocks both (tx,ty) and (tx+1,ty).
      { id: "sleeper", kind: "sleeper", variant: 0, tx: 5, ty: 8, dir: "right", wandering: false,
        sleeper: true, wide: true, line: "" /* dynamic */ },
    ],
    chest: null,
    transitions: [
      { tx: 5, ty: 0,  to: "empty_field",   spawn: { tx: 5, ty: 10, dir: "up" } },
      { tx: 6, ty: 0,  to: "empty_field",   spawn: { tx: 6, ty: 10, dir: "up" } },
      // South — 2 tile wide path, gated by sleepingManAwake
      { tx: 5, ty: 11, to: "monster_field", spawn: { tx: 5, ty: 1, dir: "down" }, requireSleeperAwake: true },
      { tx: 6, ty: 11, to: "monster_field", spawn: { tx: 6, ty: 1, dir: "down" }, requireSleeperAwake: true },
    ],
  },

  cave_exterior: {
    map: MAP_CAVE_EXT,
    label: "CAVE MOUTH",
    dark: false,
    npcs: [],
    chest: null,
    transitions: [
      { tx: 5, ty: 3, to: "cave_interior", spawn: { tx: 5, ty: 10, dir: "up" } },
      { tx: 6, ty: 3, to: "cave_interior", spawn: { tx: 5, ty: 10, dir: "up" } },
      { tx: 0, ty: 6, to: "empty_field",   spawn: { tx: 10, ty: 5, dir: "left" } },
      { tx: 0, ty: 7, to: "empty_field",   spawn: { tx: 10, ty: 6, dir: "left" } },
    ],
  },

  cave_interior: {
    map: MAP_CAVE_INT,
    label: "DEEP CAVE",
    dark: true,
    npcs: [],
    chest: { tx: 3, ty: 7 },     // hidden until puzzleSolved (handled in game.jsx)
    blockStart: { tx: 6, ty: 4 }, // pushable block start
    switch:  { tx: 6, ty: 7 },    // ground switch
    transitions: [
      { tx: 5, ty: 11, to: "cave_exterior", spawn: { tx: 5, ty: 5, dir: "down" }, requireBatsDefeated: true },
      { tx: 6, ty: 11, to: "cave_exterior", spawn: { tx: 6, ty: 5, dir: "down" }, requireBatsDefeated: true },
    ],
  },

  monster_field: {
    map: MAP_MONSTER,
    label: "BAD FIELD",
    dark: false,
    npcs: [],
    chest: null,
    monsterSpawns: [
      { tx: 4, ty: 3 },
      { tx: 8, ty: 6 },
      { tx: 5, ty: 9 },
      { tx: 9, ty: 4 },
    ],
    transitions: [
      { tx: 4, ty: 0, to: "empty_field", spawn: { tx: 4, ty: 10, dir: "up" } },
      { tx: 5, ty: 0, to: "empty_field", spawn: { tx: 5, ty: 10, dir: "up" } },
      { tx: 6, ty: 0, to: "empty_field", spawn: { tx: 6, ty: 10, dir: "up" } },
      { tx: 7, ty: 0, to: "empty_field", spawn: { tx: 7, ty: 10, dir: "up" } },
    ],
  },

  concert_stage: {
    map: MAP_STAGE,
    label: "STAGE",
    dark: false,
    npcs: [],
    chest: null,
    speaker: { tx: 5, ty: 3, w: 2, h: 2 },   // 2x2 Speaker Stack object on the stage
    transitions: [
      { tx: 4, ty: 11, to: "village_hub", spawn: { tx: 2, ty: 1, dir: "down" } },
      { tx: 5, ty: 11, to: "village_hub", spawn: { tx: 2, ty: 1, dir: "down" } },
      { tx: 6, ty: 11, to: "village_hub", spawn: { tx: 2, ty: 1, dir: "down" } },
      { tx: 7, ty: 11, to: "village_hub", spawn: { tx: 2, ty: 1, dir: "down" } },
    ],
  },
};

// =====================================================================
// MAP RENDERING
// =====================================================================
function drawMap(ctx, screen, s) {
  const sc = SCREENS[screen];
  const map = sc.map;
  for (let y = 0; y < MAP_H; y++) {
    for (let x = 0; x < MAP_W; x++) {
      const px = x * TILE;
      const py = y * TILE + PLAY_TOP;
      drawTile(ctx, map[y][x], px, py, x, y, screen, s);
    }
  }
}

function drawTile(ctx, t, px, py, gx, gy, screen, s) {
  const isCave  = screen === "cave_interior";
  const isStage = screen === "concert_stage";
  const isField = screen === "monster_field" || screen === "empty_field";
  const isOutdoor = isField || screen === "village_hub" || screen === "west_village" ||
                    screen === "east_village" || screen === "cave_exterior" || isStage;
  const isHouse = screen === "house_interior" || screen === "west_house";
  const isStore = screen === "store";
  const isGrandma = screen === "west_house";
  const baseFloor = (px, py, gx, gy) => {
    if (isCave)      return drawCaveFloor(ctx, px, py, gx, gy);
    if (isStage)     return drawStageFloor(ctx, px, py, gx, gy);
    if (isOutdoor)   return drawDirt(ctx, px, py, gx, gy);
    if (isStore)     return drawShopFloor(ctx, px, py, gx, gy);
    if (isGrandma)   return drawGrandmaFloor(ctx, px, py, gx, gy);
    return drawCozyFloor(ctx, px, py, gx, gy);
  };

  // Base ground for walkable / overlay tiles
  if (t === T.GROUND) { baseFloor(px, py, gx, gy); return; }
  if (t === T.BED_L || t === T.BED_R) {
    baseFloor(px, py, gx, gy);
    drawBedHalf(ctx, px, py, t === T.BED_R);
    return;
  }
  if (t === T.RUG) {
    baseFloor(px, py, gx, gy);
    drawRug(ctx, px, py, gx, gy);
    return;
  }
  if (t === T.BOOKSHELF) {
    baseFloor(px, py, gx, gy);
    const above = (gy > 0) ? SCREENS[screen].map[gy - 1][gx] : 0;
    const below = (gy < MAP_H - 1) ? SCREENS[screen].map[gy + 1][gx] : 0;
    const isTop = above !== T.BOOKSHELF;
    const isBot = below !== T.BOOKSHELF;
    drawBookshelf(ctx, px, py, isTop, isBot);
    return;
  }
  if (t === T.LOW_COUNTER) {
    baseFloor(px, py, gx, gy);
    drawLowCounter(ctx, px, py, gx, gy, screen);
    return;
  }
  if (t === T.SHELF) {
    drawShopFloor(ctx, px, py, gx, gy);
    const above = (gy > 0) ? SCREENS[screen].map[gy - 1][gx] : 0;
    const below = (gy < MAP_H - 1) ? SCREENS[screen].map[gy + 1][gx] : 0;
    const isTop = above !== T.SHELF;
    const isBot = below !== T.SHELF;
    drawShopShelf(ctx, px, py, gx, isTop, isBot);
    return;
  }
  if (t === T.COUNTER) {
    drawShopFloor(ctx, px, py, gx, gy);
    drawCounter(ctx, px, py, gx);
    return;
  }
  if (t === T.TABLE)  {
    if (isHouse)  baseFloor(px, py, gx, gy);
    else if (isStore) drawShopFloor(ctx, px, py, gx, gy);
    else drawDirt(ctx, px, py, gx, gy);
    drawTableTop(ctx, px, py);
    return;
  }
  if (t === T.FIELD_GRASS) { drawFieldGrass(ctx, px, py, gx, gy); return; }
  if (t === T.CAVE_FLOOR)  { drawCaveFloor(ctx, px, py, gx, gy); return; }
  if (t === T.CAVE_ROCK)   { drawCaveFloor(ctx, px, py, gx, gy); drawCaveRock(ctx, px, py); return; }
  if (t === T.BUSH)        {
    if (isField || isOutdoor) drawFieldGrass(ctx, px, py, gx, gy);
    else                       drawDirt(ctx, px, py, gx, gy);
    drawBush(ctx, px, py);
    return;
  }
  if (t === T.WALL)        { drawWall(ctx, px, py, gx, gy, isCave); return; }
  if (t === T.DOOR)        { drawDoor(ctx, px, py); return; }
  if (t === T.HOUSE_WALL)  { drawHouseFacade(ctx, px, py); return; }
  if (t === T.HOUSE_ROOF)  { drawHouseRoof(ctx, px, py, gx); return; }
  if (t === T.STORE_WALL)  { drawStoreFacade(ctx, px, py); return; }
  if (t === T.STORE_ROOF)  { drawStoreRoof(ctx, px, py, gx); return; }
  if (t === T.STORE_DOOR)  { drawStoreDoor(ctx, px, py); return; }
  if (t === T.SIGN_STORE)  { drawHouseFacade(ctx, px, py); drawStoreSign(ctx, px, py); return; }
  if (t === T.CAVE_DOOR)   { drawCaveMouth(ctx, px, py); return; }
  if (t === T.CHEST)       { if (isCave) drawCaveFloor(ctx, px, py, gx, gy); else drawCozyFloor(ctx, px, py, gx, gy); return; }
  if (t === T.PATH)        { drawPath(ctx, px, py); return; }
  if (t === T.STAGE)       { drawStagePlatform(ctx, px, py, gx, gy, screen); return; }
  if (t === T.STAGE_LIGHT) { drawStageFloor(ctx, px, py, gx, gy); drawStageLight(ctx, px, py); return; }
  if (t === T.CLIFF)       { drawCliff(ctx, px, py, gx, gy, screen); return; }
  if (t === T.FENCE)       {
    // Render as walkable path if the south gate has been unlocked.
    if (s && s.southUnlocked) drawPath(ctx, px, py);
    else drawFence(ctx, px, py, gx);
    return;
  }
  if (t === T.SWITCH)      {
    drawCaveFloor(ctx, px, py, gx, gy);
    const pressed = !!(s && s.puzzleSolved);
    drawGroundSwitch(ctx, px, py, pressed);
    return;
  }
}

// ---- Ground tiles ---------------------------------------------------
function drawCozyFloor(ctx, px, py, gx, gy) {
  // Clear grid floor pattern — alternating subtle checker
  ctx.fillStyle = C.lightest;
  ctx.fillRect(px, py, TILE, TILE);
  // Checkerboard half-tile pattern
  ctx.fillStyle = C.light;
  ctx.globalAlpha = 0.55;
  const checker = (gx + gy) % 2 === 0;
  if (checker) {
    ctx.fillRect(px + 1, py + 1, 7, 7);
    ctx.fillRect(px + 8, py + 8, 7, 7);
  } else {
    ctx.fillRect(px + 8, py + 1, 7, 7);
    ctx.fillRect(px + 1, py + 8, 7, 7);
  }
  ctx.globalAlpha = 1;
  // Floor seam (subtle)
  ctx.fillStyle = C.dark;
  ctx.globalAlpha = 0.15;
  ctx.fillRect(px, py + TILE - 1, TILE, 1);
  ctx.fillRect(px + TILE - 1, py, 1, TILE);
  ctx.globalAlpha = 1;
}

function drawShopFloor(ctx, px, py, gx, gy) {
  // Larger checker — feels like store tiles
  ctx.fillStyle = C.light;
  ctx.fillRect(px, py, TILE, TILE);
  if ((gx + gy) % 2 === 0) {
    ctx.fillStyle = C.lightest;
    ctx.fillRect(px + 1, py + 1, TILE - 2, TILE - 2);
  }
  ctx.fillStyle = C.dark;
  ctx.globalAlpha = 0.18;
  ctx.fillRect(px, py + TILE - 1, TILE, 1);
  ctx.fillRect(px + TILE - 1, py, 1, TILE);
  ctx.globalAlpha = 1;
}

// Grandma's house — pure lightest floor with thin grid (max sprite contrast)
function drawGrandmaFloor(ctx, px, py, gx, gy) {
  ctx.fillStyle = C.lightest;
  ctx.fillRect(px, py, TILE, TILE);
  // Subtle grid seams
  ctx.fillStyle = C.light;
  ctx.globalAlpha = 0.28;
  ctx.fillRect(px, py + TILE - 1, TILE, 1);
  ctx.fillRect(px + TILE - 1, py, 1, TILE);
  ctx.globalAlpha = 1;
  // Tiny knot detail in some tiles
  if ((gx * 7 + gy * 11) % 11 === 0) {
    ctx.fillStyle = C.light;
    ctx.fillRect(px + 5, py + 9, 1, 1);
  }
}

// Low counter — medium shade slab (C.light = #8bac0f) with darkest outline
function drawLowCounter(ctx, px, py, gx, gy, screen) {
  const map = SCREENS[screen].map;
  const left  = (gx > 0) ? map[gy][gx - 1] : 0;
  const right = (gx < MAP_W - 1) ? map[gy][gx + 1] : 0;
  const above = (gy > 0) ? map[gy - 1][gx] : 0;
  const below = (gy < MAP_H - 1) ? map[gy + 1][gx] : 0;
  // Darkest outline frame
  ctx.fillStyle = C.darkest;
  ctx.fillRect(px, py + 2, TILE, TILE - 4);
  // Medium-shade slab (the counter top)
  ctx.fillStyle = C.light;
  ctx.fillRect(px, py + 3, TILE, TILE - 6);
  // Light top highlight (1px)
  ctx.fillStyle = C.lightest;
  ctx.fillRect(px, py + 3, TILE, 1);
  // Outline at column ends
  ctx.fillStyle = C.darkest;
  if (left !== T.LOW_COUNTER)  ctx.fillRect(px, py + 2, 1, TILE - 4);
  if (right !== T.LOW_COUNTER) ctx.fillRect(px + TILE - 1, py + 2, 1, TILE - 4);
  // Bottom shadow shelf
  ctx.fillStyle = C.darkest;
  ctx.fillRect(px, py + TILE - 4, TILE, 1);
  // Drawer notch every other tile
  if ((gx % 2) === 0 && left === T.LOW_COUNTER) {
    ctx.fillStyle = C.darkest;
    ctx.fillRect(px, py + 6, 1, 4);
  }
}

function drawDirt(ctx, px, py, gx, gy) {
  ctx.fillStyle = C.light;
  ctx.fillRect(px, py, TILE, TILE);
  const seed = (gx * 41 + gy * 23) % 11;
  ctx.fillStyle = C.dark;
  if (seed === 0) ctx.fillRect(px+3, py+5, 1, 1);
  else if (seed === 1) ctx.fillRect(px+11, py+10, 1, 1);
  else if (seed === 2) ctx.fillRect(px+8, py+3, 1, 1);
  ctx.fillStyle = C.lightest;
  if (seed === 5) ctx.fillRect(px+5, py+12, 1, 1);
}

function drawFieldGrass(ctx, px, py, gx, gy) {
  ctx.fillStyle = C.light;
  ctx.fillRect(px, py, TILE, TILE);
  const seed = (gx * 41 + gy * 23) % 9;
  ctx.fillStyle = C.dark;
  if (seed === 0) { ctx.fillRect(px+3, py+5, 1, 2); ctx.fillRect(px+11, py+10, 1, 2); }
  else if (seed === 1) { ctx.fillRect(px+8, py+3, 1, 2); }
  else if (seed === 2) { ctx.fillRect(px+13, py+9, 1, 2); ctx.fillRect(px+4, py+13, 1, 2); }
  else if (seed === 3) { ctx.fillRect(px+6, py+10, 1, 2); }
  ctx.fillStyle = C.lightest;
  if (seed === 4) ctx.fillRect(px + 9, py + 2, 1, 1);
  else if (seed === 5) ctx.fillRect(px + 2, py + 11, 1, 1);
}

function drawCaveFloor(ctx, px, py, gx, gy) {
  ctx.fillStyle = C.dark;
  ctx.fillRect(px, py, TILE, TILE);
  const seed = (gx * 41 + gy * 23) % 11;
  ctx.fillStyle = C.darkest;
  if (seed === 0) ctx.fillRect(px+3, py+5, 1, 1);
  else if (seed === 1) ctx.fillRect(px+11, py+10, 1, 1);
  else if (seed === 2) { ctx.fillRect(px+7, py+3, 1, 1); ctx.fillRect(px+13, py+8, 1, 1); }
  if (seed === 5) { ctx.fillStyle = C.light; ctx.fillRect(px+8, py+11, 1, 1); }
}

function drawStageFloor(ctx, px, py, gx, gy) {
  // Audience/floor in front of stage: darker boards
  ctx.fillStyle = C.dark;
  ctx.fillRect(px, py, TILE, TILE);
  ctx.fillStyle = C.darkest;
  ctx.globalAlpha = 0.4;
  if ((gy % 2) === 0) ctx.fillRect(px, py + TILE - 1, TILE, 1);
  ctx.globalAlpha = 1;
  const seed = (gx * 13 + gy * 7) % 5;
  if (seed === 0) { ctx.fillStyle = C.light; ctx.fillRect(px + 5, py + 7, 1, 1); }
}

// ---- Solid tiles ----------------------------------------------------
function drawWall(ctx, px, py, gx, gy, isCave) {
  ctx.fillStyle = C.darkest;
  ctx.fillRect(px, py, TILE, TILE);
  ctx.fillStyle = C.dark;
  ctx.fillRect(px+1, py+1, TILE-2, 1);
  ctx.fillRect(px+1, py+1, 1, TILE-2);
  const row = gy % 2;
  ctx.fillStyle = C.darkest;
  ctx.fillRect(px, py + 7, TILE, 1);
  ctx.fillRect(px + (row ? 4 : 11), py, 1, 7);
  ctx.fillRect(px + (row ? 11 : 4), py + 8, 1, 8);
  ctx.fillStyle = C.dark;
  ctx.fillRect(px + 2, py + 3, 1, 1);
  ctx.fillRect(px + 9, py + 11, 1, 1);
}

function drawBush(ctx, px, py) {
  ctx.fillStyle = C.dark;
  ctx.fillRect(px+2, py+3, 12, 11);
  ctx.fillRect(px+1, py+5, 14, 7);
  ctx.fillRect(px+3, py+2, 10, 1);
  ctx.fillStyle = C.darkest;
  ctx.fillRect(px+4, py+5, 2, 2);
  ctx.fillRect(px+9, py+4, 2, 2);
  ctx.fillRect(px+6, py+9, 2, 2);
  ctx.fillRect(px+11, py+10, 2, 2);
  ctx.fillStyle = C.light;
  ctx.fillRect(px+3, py+4, 1, 1);
  ctx.fillRect(px+8, py+3, 1, 1);
  ctx.fillRect(px+5, py+8, 1, 1);
}

// ---- Bed (cozy, undeniably-bed look) --------------------------------
function drawBedHalf(ctx, px, py, right) {
  // Dark frame
  ctx.fillStyle = C.darkest;
  ctx.fillRect(px, py + 2, TILE, 13);
  // Mattress base
  ctx.fillStyle = C.dark;
  ctx.fillRect(px, py + 3, TILE, 11);
  if (!right) {
    // LEFT half: headboard wall + plush PILLOW
    ctx.fillStyle = C.darkest;
    ctx.fillRect(px, py, 3, 15);
    // Pillow (lighter rect)
    ctx.fillStyle = C.lightest;
    ctx.fillRect(px + 4, py + 4, 9, 5);
    ctx.fillStyle = C.darkest;
    // pillow outline
    ctx.fillRect(px + 4, py + 4, 9, 1);
    ctx.fillRect(px + 4, py + 8, 9, 1);
    ctx.fillRect(px + 4, py + 4, 1, 5);
    ctx.fillRect(px + 12, py + 4, 1, 5);
    // crease
    ctx.fillStyle = C.light;
    ctx.fillRect(px + 5, py + 6, 7, 1);
  } else {
    // RIGHT half: folded blanket with cross-hatched pattern
    ctx.fillStyle = C.darkest;
    ctx.fillRect(px + TILE - 2, py + 3, 2, 12);
    // Blanket body
    ctx.fillStyle = C.light;
    ctx.fillRect(px, py + 4, TILE - 2, 10);
    // Blanket dark outline (top + bottom)
    ctx.fillStyle = C.darkest;
    ctx.fillRect(px, py + 4, TILE - 2, 1);
    ctx.fillRect(px, py + 13, TILE - 2, 1);
    // Cross-hatch
    ctx.fillStyle = C.dark;
    for (let dy = 5; dy <= 13; dy += 2) {
      for (let dx = 0; dx < TILE - 2; dx += 2) {
        ctx.fillRect(px + dx + (dy % 4 === 1 ? 1 : 0), py + dy, 1, 1);
      }
    }
    // Fold line
    ctx.fillStyle = C.darkest;
    ctx.fillRect(px, py + 9, TILE - 2, 1);
  }
}

// ---- Rug ------------------------------------------------------------
function drawRug(ctx, px, py, gx, gy) {
  ctx.fillStyle = C.dark;
  ctx.fillRect(px, py, TILE, TILE);
  ctx.fillStyle = C.darkest;
  ctx.fillRect(px + 1, py + 1, TILE - 2, TILE - 2);
  ctx.fillStyle = C.light;
  ctx.fillRect(px + 3, py + 3, TILE - 6, TILE - 6);
  ctx.fillStyle = C.darkest;
  ctx.fillRect(px + 5, py + 5, TILE - 10, TILE - 10);
  ctx.fillStyle = C.lightest;
  ctx.fillRect(px + 7, py + 7, 2, 2);
  // tassels along edges
  ctx.fillStyle = C.darkest;
  for (let i = 0; i < 4; i++) {
    ctx.fillRect(px + 2 + i * 4, py, 1, 1);
    ctx.fillRect(px + 2 + i * 4, py + TILE - 1, 1, 1);
  }
}

// ---- Bookshelf (3-tile-tall column) ---------------------------------
function drawBookshelf(ctx, px, py, isTop, isBot) {
  // Dark frame
  ctx.fillStyle = C.darkest;
  ctx.fillRect(px, py, TILE, TILE);
  // Wood interior
  ctx.fillStyle = C.dark;
  ctx.fillRect(px + 1, py + (isTop ? 1 : 0), TILE - 2, TILE - (isTop ? 1 : 0) - (isBot ? 1 : 0));
  // Top trim
  if (isTop) {
    ctx.fillStyle = C.darkest;
    ctx.fillRect(px, py, TILE, 2);
    ctx.fillStyle = C.light;
    ctx.fillRect(px + 1, py + 2, TILE - 2, 1);
  }
  // Shelf line near bottom of each tile
  ctx.fillStyle = C.darkest;
  ctx.fillRect(px + 1, py + 12, TILE - 2, 1);
  // Books
  // row of books with varying heights
  const bookCols = [
    { x: 2, h: 8, w: 1 },
    { x: 4, h: 9, w: 2 },
    { x: 7, h: 6, w: 1 },
    { x: 9, h: 9, w: 1 },
    { x: 11, h: 7, w: 2 },
  ];
  for (const b of bookCols) {
    ctx.fillStyle = (b.x + py) % 3 === 0 ? C.light : C.lightest;
    ctx.fillRect(px + b.x, py + 12 - b.h, b.w, b.h);
    // band
    ctx.fillStyle = C.darkest;
    ctx.fillRect(px + b.x, py + 12 - Math.floor(b.h * 0.6), b.w, 1);
  }
  // Bottom trim
  if (isBot) {
    ctx.fillStyle = C.darkest;
    ctx.fillRect(px, py + TILE - 2, TILE, 2);
  }
}

// ---- Table ----------------------------------------------------------
function drawTableTop(ctx, px, py) {
  ctx.fillStyle = C.darkest;
  ctx.fillRect(px+1, py+2, 14, 11);
  ctx.fillStyle = C.dark;
  ctx.fillRect(px+2, py+3, 12, 7);
  ctx.fillStyle = C.darkest;
  ctx.fillRect(px+2, py+13, 2, 2);
  ctx.fillRect(px+12, py+13, 2, 2);
  ctx.fillStyle = C.light;
  ctx.fillRect(px+3, py+4, 4, 1);
  ctx.fillRect(px+9, py+4, 3, 1);
  // wood grain
  ctx.fillStyle = C.darkest;
  ctx.fillRect(px+3, py+7, 10, 1);
}

// ---- Door -----------------------------------------------------------
function drawDoor(ctx, px, py) {
  ctx.fillStyle = C.darkest;
  ctx.fillRect(px, py, TILE, TILE);
  ctx.fillStyle = C.dark;
  ctx.fillRect(px+2, py+1, 12, 14);
  ctx.fillStyle = C.darkest;
  ctx.fillRect(px+3, py+2, 10, 12);
  ctx.fillStyle = C.dark;
  ctx.fillRect(px+4, py+3, 8, 4);
  ctx.fillRect(px+4, py+9, 8, 4);
  ctx.fillStyle = C.lightest;
  ctx.fillRect(px+11, py+8, 1, 2);
}

// ---- House facade / roof --------------------------------------------
function drawHouseFacade(ctx, px, py) {
  ctx.fillStyle = C.dark;
  ctx.fillRect(px, py, TILE, TILE);
  ctx.fillStyle = C.darkest;
  ctx.fillRect(px, py, TILE, 1);
  ctx.fillRect(px, py + TILE - 1, TILE, 1);
  ctx.fillRect(px + 7, py, 1, TILE);
  ctx.fillRect(px, py + 7, TILE, 1);
  ctx.fillStyle = C.lightest;
  ctx.fillRect(px + 3, py + 3, 2, 2);
  ctx.fillRect(px + 11, py + 10, 2, 2);
}

function drawHouseRoof(ctx, px, py, gx) {
  ctx.fillStyle = C.darkest;
  ctx.fillRect(px, py, TILE, TILE);
  ctx.fillStyle = C.dark;
  const off = (gx % 2) ? 0 : 4;
  for (let y = 0; y < TILE; y += 4) {
    for (let x = -off; x < TILE; x += 8) {
      ctx.fillRect(px + x + 1, py + y + 1, 6, 2);
    }
  }
  ctx.fillStyle = C.light;
  ctx.fillRect(px, py + TILE - 2, TILE, 1);
}

// ---- Store ----------------------------------------------------------
function drawStoreFacade(ctx, px, py) {
  ctx.fillStyle = C.darkest;
  ctx.fillRect(px, py, TILE, TILE);
  ctx.fillStyle = C.light;
  for (let i = 0; i < TILE; i += 4) ctx.fillRect(px + i, py + 1, 2, TILE - 2);
  ctx.fillStyle = C.darkest;
  ctx.fillRect(px, py, TILE, 1);
  ctx.fillRect(px, py + TILE - 1, TILE, 1);
}

function drawStoreRoof(ctx, px, py, gx) {
  ctx.fillStyle = C.darkest;
  ctx.fillRect(px, py, TILE, TILE);
  for (let i = 0; i < TILE; i += 4) {
    ctx.fillStyle = (i % 8 === 0) ? C.lightest : C.dark;
    ctx.fillRect(px + i, py + 1, 4, TILE - 2);
  }
  ctx.fillStyle = C.darkest;
  for (let x = 0; x < TILE; x += 4) ctx.fillRect(px + x + 1, py + TILE - 2, 2, 2);
  ctx.fillRect(px, py + TILE - 1, TILE, 1);
}

function drawStoreDoor(ctx, px, py) {
  ctx.fillStyle = C.darkest;
  ctx.fillRect(px, py, TILE, TILE);
  ctx.fillStyle = C.lightest;
  ctx.fillRect(px+1, py+1, 14, 14);
  ctx.fillStyle = C.dark;
  ctx.fillRect(px+2, py+2, 6, 12);
  ctx.fillRect(px+9, py+2, 5, 12);
  ctx.fillStyle = C.lightest;
  ctx.fillRect(px+3, py+3, 4, 3);
  ctx.fillRect(px+10, py+3, 3, 3);
  ctx.fillStyle = C.darkest;
  ctx.fillRect(px+8, py+1, 1, 14);
  ctx.fillRect(px+6, py+8, 1, 2);
  ctx.fillRect(px+10, py+8, 1, 2);
}

function drawStoreSign(ctx, px, py) {
  ctx.fillStyle = C.darkest;
  ctx.fillRect(px+5, py+3, 6, 10);
  ctx.fillStyle = C.lightest;
  ctx.fillRect(px+6, py+4, 4, 8);
  const g = window.glyph("$");
  for (let row = 0; row < 7; row++) {
    const bits = g[row];
    if (!bits) continue;
    for (let col = 0; col < 5; col++) {
      if (bits & (1 << (4 - col))) {
        ctx.fillStyle = C.darkest;
        ctx.fillRect(px + 6 + col, py + 4 + row, 1, 1);
      }
    }
  }
}

// ---- Shop shelf (3-tall) --------------------------------------------
function drawShopShelf(ctx, px, py, gx, isTop, isBot) {
  ctx.fillStyle = C.darkest;
  ctx.fillRect(px, py, TILE, TILE);
  ctx.fillStyle = C.dark;
  ctx.fillRect(px + 1, py + (isTop ? 1 : 0), TILE - 2, TILE - (isTop ? 1 : 0) - (isBot ? 1 : 0));
  // Shelf rail
  ctx.fillStyle = C.darkest;
  ctx.fillRect(px + 1, py + 12, TILE - 2, 1);
  // Merchandise — vary by tile column
  const items = [
    // Each entry: x, w, h (tile-local)
    [2, 2, 7], [5, 1, 6], [7, 2, 8], [10, 1, 7], [12, 2, 6],
  ];
  for (let i = 0; i < items.length; i++) {
    const [bx, w, h] = items[i];
    const shade = (gx + i) % 2 === 0 ? C.light : C.lightest;
    ctx.fillStyle = shade;
    ctx.fillRect(px + bx, py + 12 - h, w, h);
    // top cap / label
    ctx.fillStyle = C.darkest;
    ctx.fillRect(px + bx, py + 12 - h, w, 1);
    if (h >= 7) ctx.fillRect(px + bx, py + 12 - Math.floor(h * 0.6), w, 1);
  }
  if (isBot) {
    ctx.fillStyle = C.darkest;
    ctx.fillRect(px, py + TILE - 2, TILE, 2);
  }
  if (isTop) {
    ctx.fillStyle = C.darkest;
    ctx.fillRect(px, py, TILE, 2);
    ctx.fillStyle = C.light;
    ctx.fillRect(px + 1, py + 2, TILE - 2, 1);
  }
}

// ---- Counter --------------------------------------------------------
function drawCounter(ctx, px, py, gx) {
  // Long horizontal counter — wood look
  ctx.fillStyle = C.darkest;
  ctx.fillRect(px, py, TILE, TILE);
  ctx.fillStyle = C.dark;
  ctx.fillRect(px + 1, py + 2, TILE - 2, TILE - 4);
  // top surface highlight
  ctx.fillStyle = C.light;
  ctx.fillRect(px, py + 2, TILE, 2);
  // wood grain
  ctx.fillStyle = C.darkest;
  ctx.fillRect(px + 1, py + 8, TILE - 2, 1);
  // panel seams every 2 tiles
  if (gx % 2 === 0) {
    ctx.fillStyle = C.darkest;
    ctx.fillRect(px, py + 2, 1, TILE - 4);
  }
  // bottom shadow
  ctx.fillStyle = C.darkest;
  ctx.fillRect(px, py + TILE - 2, TILE, 2);
}

// ---- Cave -----------------------------------------------------------
function drawCaveMouth(ctx, px, py) {
  ctx.fillStyle = C.darkest;
  ctx.fillRect(px, py, TILE, TILE);
  ctx.fillStyle = C.dark;
  ctx.fillRect(px+2, py+3, 12, 13);
  ctx.fillStyle = C.darkest;
  ctx.fillRect(px+3, py+5, 10, 11);
  ctx.fillStyle = C.dark;
  ctx.fillRect(px+1, py+1, 2, 2);
  ctx.fillRect(px+13, py+1, 2, 2);
  ctx.fillRect(px+1, py+13, 2, 2);
  ctx.fillRect(px+13, py+13, 2, 2);
  ctx.fillStyle = C.dark;
  ctx.fillRect(px+5, py+4, 1, 2);
  ctx.fillRect(px+9, py+4, 1, 2);
}

function drawPath(ctx, px, py) {
  ctx.fillStyle = C.light;
  ctx.fillRect(px, py, TILE, TILE);
  ctx.fillStyle = C.dark;
  ctx.fillRect(px+3, py+5, 1, 1);
  ctx.fillRect(px+10, py+10, 1, 1);
}

function drawCaveRock(ctx, px, py) {
  ctx.fillStyle = C.darkest;
  ctx.fillRect(px+2, py+2, 12, 12);
  ctx.fillStyle = C.dark;
  ctx.fillRect(px+3, py+3, 4, 4);
  ctx.fillRect(px+8, py+5, 5, 4);
  ctx.fillRect(px+4, py+9, 6, 4);
  ctx.fillStyle = C.darkest;
  ctx.fillRect(px+5, py+5, 1, 1);
  ctx.fillRect(px+10, py+10, 1, 1);
}

// ---- Stage tiles ----------------------------------------------------
function drawStagePlatform(ctx, px, py, gx, gy, screen) {
  // Lift effect: top of stage row has a tall riser; lower rows are the stage face
  const map = SCREENS[screen].map;
  const above = (gy > 0) ? map[gy - 1][gx] : 0;
  const below = (gy < MAP_H - 1) ? map[gy + 1][gx] : 0;
  const left  = (gx > 0) ? map[gy][gx - 1] : 0;
  const right = (gx < MAP_W - 1) ? map[gy][gx + 1] : 0;

  // Walkable lighter top surface
  ctx.fillStyle = C.light;
  ctx.fillRect(px, py, TILE, TILE);
  // Plank lines
  ctx.fillStyle = C.dark;
  ctx.fillRect(px, py + 4, TILE, 1);
  ctx.fillRect(px, py + 9, TILE, 1);

  // Front-edge highlight (when below is not stage)
  if (below !== T.STAGE) {
    ctx.fillStyle = C.lightest;
    ctx.fillRect(px, py + 12, TILE, 1);
    ctx.fillStyle = C.darkest;
    ctx.fillRect(px, py + 13, TILE, 3);
  }
  // Back wall / step-up (when above is not stage)
  if (above !== T.STAGE) {
    ctx.fillStyle = C.darkest;
    ctx.fillRect(px, py, TILE, 2);
  }
  // Side trim
  if (left !== T.STAGE)  { ctx.fillStyle = C.darkest; ctx.fillRect(px, py, 1, TILE); }
  if (right !== T.STAGE) { ctx.fillStyle = C.darkest; ctx.fillRect(px + TILE - 1, py, 1, TILE); }
}

function drawStageLight(ctx, px, py) {
  // Spotlight column: top heavy, beams down faintly
  ctx.fillStyle = C.darkest;
  ctx.fillRect(px + 6, py, 4, 4);
  ctx.fillStyle = C.lightest;
  ctx.fillRect(px + 7, py + 1, 2, 2);
  // beam
  ctx.fillStyle = C.lightest;
  ctx.globalAlpha = 0.25;
  ctx.fillRect(px + 6, py + 4, 4, TILE - 4);
  ctx.fillRect(px + 5, py + 6, 6, TILE - 6);
  ctx.globalAlpha = 1;
}

// ---- Fence (south gate at village_hub) ------------------------------
function drawFence(ctx, px, py, gx) {
  // Dirt path beneath
  drawDirt(ctx, px, py, gx, 11);
  // Horizontal top + bottom rails
  ctx.fillStyle = C.darkest;
  ctx.fillRect(px, py + 4, TILE, 2);
  ctx.fillRect(px, py + 10, TILE, 2);
  // Vertical posts every ~4 px, offset by tile column for variety
  const off = (gx % 2) ? 0 : 2;
  for (let x = off; x < TILE; x += 4) {
    ctx.fillRect(px + x, py + 2, 2, 12);
  }
  // Bevel highlights
  ctx.fillStyle = C.light;
  ctx.fillRect(px, py + 4, TILE, 1);
  ctx.fillRect(px, py + 10, TILE, 1);
}

// ---- Ground switch (pressure plate in cave) -------------------------
function drawGroundSwitch(ctx, px, py, pressed) {
  // Outer plate
  ctx.fillStyle = C.darkest;
  ctx.fillRect(px+1, py+3, TILE-2, TILE-6);
  ctx.fillStyle = C.light;
  ctx.fillRect(px+2, py+4, TILE-4, TILE-8);
  // Inner inset / pressed look
  if (pressed) {
    ctx.fillStyle = C.dark;
    ctx.fillRect(px+3, py+5, TILE-6, TILE-10);
    ctx.fillStyle = C.darkest;
    ctx.fillRect(px+5, py+7, 2, 2);
    ctx.fillRect(px+9, py+7, 2, 2);
  } else {
    ctx.fillStyle = C.lightest;
    ctx.fillRect(px+3, py+5, TILE-6, 2);
    ctx.fillStyle = C.darkest;
    ctx.fillRect(px+4, py+8, 8, 1);
  }
  // Glow ticks at corners
  ctx.fillStyle = pressed ? C.lightest : C.dark;
  ctx.fillRect(px+2, py+3, 1, 1);
  ctx.fillRect(px+13, py+3, 1, 1);
  ctx.fillRect(px+2, py+12, 1, 1);
  ctx.fillRect(px+13, py+12, 1, 1);
}

// ---- Cliff (west barrier in empty_field) ----------------------------
function drawCliff(ctx, px, py, gx, gy, screen) {
  // Jagged dark rock — clearly impassable
  ctx.fillStyle = C.darkest;
  ctx.fillRect(px, py, TILE, TILE);
  // Lighter face suggesting craggy stone
  ctx.fillStyle = C.dark;
  // jagged silhouette on the EAST (player-facing) edge
  ctx.fillRect(px + 4, py, TILE - 4, TILE);
  ctx.fillStyle = C.darkest;
  ctx.fillRect(px + 5, py + 0, 1, 3);
  ctx.fillRect(px + 7, py + 4, 1, 2);
  ctx.fillRect(px + 6, py + 7, 1, 3);
  ctx.fillRect(px + 8, py + 11, 1, 3);
  // Highlights
  ctx.fillStyle = C.light;
  ctx.fillRect(px + 8, py + 2, 1, 2);
  ctx.fillRect(px + 11, py + 6, 1, 1);
  ctx.fillRect(px + 9, py + 9, 1, 1);
  ctx.fillRect(px + 13, py + 12, 1, 1);
  // crack
  ctx.fillStyle = C.darkest;
  ctx.fillRect(px + 10, py + 3, 1, 5);
  ctx.fillRect(px + 11, py + 4, 1, 3);
}

// =====================================================================
// EXPORTS
// =====================================================================
Object.assign(window, {
  T, SOLID, SCREENS, isSolidTile, isCounter,
  drawMap, drawTile,
});
