const { useEffect, useMemo, useRef, useState } = React;

const labelLogos = {
  "Atlantic":      "https://upload.wikimedia.org/wikipedia/commons/thumb/a/a2/Atlantic_Records_new_2025_logo.svg/250px-Atlantic_Records_new_2025_logo.svg.png",
  "Warner Records":"https://upload.wikimedia.org/wikipedia/commons/thumb/d/d1/Warner_Records_%282019_Logo%29.svg/250px-Warner_Records_%282019_Logo%29.svg.png",
  "Warner Bros.":  "https://upload.wikimedia.org/wikipedia/commons/thumb/d/d1/Warner_Records_%282019_Logo%29.svg/250px-Warner_Records_%282019_Logo%29.svg.png",
  "Parlophone":    "https://upload.wikimedia.org/wikipedia/commons/thumb/4/4c/Parlophone_logo.svg/250px-Parlophone_logo.svg.png",
  "Columbia":      "https://upload.wikimedia.org/wikipedia/commons/thumb/0/0a/Columbia_Records_Colored_Logo.svg/250px-Columbia_Records_Colored_Logo.svg.png",
  "Epic":          "https://upload.wikimedia.org/wikipedia/commons/thumb/b/b8/Epic_Records.svg/250px-Epic_Records.svg.png",
  "Swan Song":     "https://upload.wikimedia.org/wikipedia/en/f/f5/Swan_Song_label.jpg",
  "Mercury":       "https://upload.wikimedia.org/wikipedia/commons/thumb/4/4d/Mercury_Records_logo_%282022%29.png/250px-Mercury_Records_logo_%282022%29.png",
};

const navItems = [
  { id: "home", label: "Home", icon: "layout-list" },
  { id: "collection", label: "Collection", icon: "library" },
  { id: "wishlist", label: "Wishlist", icon: "bookmark" },
  { id: "marketplace", label: "Marketplace", icon: "store" },
];

const people = [
  {
    name: "Alex Rivera",
    handle: "@alexrivera",
    avatarUrl: "./assets/portraits/Alex Rivera.jpg",
  },
  {
    name: "Amira Hassan",
    handle: "@amirahassan",
    avatarUrl: "./assets/portraits/Amira Hassan.jpg",
  },
  {
    name: "Camila Torres",
    handle: "@camilatorres",
    avatarUrl: "./assets/portraits/Camila Torres.jpg",
  },
  {
    name: "Marcus Johnson",
    handle: "@marcusjohnson",
    avatarUrl: "./assets/portraits/Marcus Johnson.jpg",
  },
  {
    name: "Simone Carter",
    handle: "@simonecarter",
    avatarUrl: "./assets/portraits/Simone Carter.jpg",
  },
  {
    name: "Divya Menon",
    handle: "@divyamenon",
    avatarUrl: "./assets/portraits/Divya Menon.jpg",
  },
  {
    name: "Kenji Watanabe",
    handle: "@kenjiwatanabe",
    avatarUrl: "./assets/portraits/Kenji Watanabe.jpg",
  },
  {
    name: "Elias Farid",
    handle: "@eliafarid",
    avatarUrl: "./assets/portraits/Elias Farid.jpg",
  },
  {
    name: "Adriana Costa",
    handle: "@adrianacosta",
    avatarUrl: "./assets/portraits/Adriana Costa.jpg",
  },
  {
    name: "Freya Lindqvist",
    handle: "@freyalindqvist",
    avatarUrl: "./assets/portraits/Freya Lindqvist.jpg",
  },
  {
    name: "Eleanor Shaw",
    handle: "@eleanorshaw",
    avatarUrl: "./assets/portraits/Eleanor Shaw.jpg",
  },
  {
    name: "Andre Coleman",
    handle: "@andrecoleman",
    avatarUrl: "./assets/portraits/Andre Coleman.jpg",
  },
];

const commentAuthors = {
  vinylfy: {
    name: "Daniel Kim",
    handle: "@danielkim",
    avatarUrl: "./assets/portraits/Daniel Kim.jpg",
  },
  needleandnight: people[6],
  kompaktskiste: {
    name: "Giorgio Marchetti",
    handle: "@giorgiomarchetti",
    avatarUrl: "./assets/portraits/Giorgio Marchetti.jpg",
  },
  pipozoft: people[4],
  you: people[4],
};

const albums = [
  {
    id: 1,
    artist: "Black Sabbath",
    title: "Paranoid",
    format: '12"',
    year: "1970",
    genre: "Metal",
    label: "Warner Records",
    status: "collection",
    palette: ["#b91c1c", "#111827", "#f97316"],
    pattern: "speed",
    coverUrl: "https://is1-ssl.mzstatic.com/image/thumb/Music125/v4/be/27/91/be279120-2285-16c6-c7ba-9d6643d4a948/075992732727.jpg/600x600bb.jpg",
  },
  {
    id: 2,
    artist: "Led Zeppelin",
    title: "Led Zeppelin II",
    format: "LP",
    year: "1969",
    genre: "Hard Rock",
    label: "Atlantic",
    status: "collection",
    palette: ["#8b5a2b", "#f5d6a3", "#111827"],
    pattern: "record",
    coverUrl: "https://is1-ssl.mzstatic.com/image/thumb/Music125/v4/1a/3d/bb/1a3dbb86-c1f8-737e-571f-d6b647a230be/dj.rhubuvkd.jpg/600x600bb.jpg",
  },
  {
    id: 3,
    artist: "Deep Purple",
    title: "Machine Head",
    format: '12"',
    year: "1972",
    genre: "Hard Rock",
    label: "Warner Bros.",
    status: "collection",
    palette: ["#1f2937", "#d1d5db", "#7c2d12"],
    pattern: "prism",
    coverUrl: "https://is1-ssl.mzstatic.com/image/thumb/Music126/v4/f4/69/61/f469613d-a7ef-e89f-007a-a7590458462b/603497826254.jpg/600x600bb.jpg",
  },
  {
    id: 4,
    artist: "AC/DC",
    title: "Back In Black",
    format: "LP",
    year: "1980",
    genre: "Hard Rock",
    label: "Atlantic",
    status: "collection",
    palette: ["#111111", "#f8fafc", "#a3a3a3"],
    pattern: "type",
    coverUrl: "https://dn711108.ca.archive.org/0/items/mbid-38914b29-7788-4cff-80b7-1ced523f8675/mbid-38914b29-7788-4cff-80b7-1ced523f8675-11333065513.jpg",
  },
  {
    id: 5,
    artist: "Iron Maiden",
    title: "The Number of the Beast",
    format: '12"',
    year: "1982",
    genre: "Metal",
    label: "Parlophone",
    status: "collection",
    palette: ["#dc2626", "#fbbf24", "#111827"],
    pattern: "burst",
    coverUrl: "https://is1-ssl.mzstatic.com/image/thumb/Music116/v4/1d/cb/ac/1dcbac1b-737d-b7c8-8bed-b5a98ae9df77/0881034134448.jpg/600x600bb.jpg",
  },
  {
    id: 6,
    artist: "Judas Priest",
    title: "British Steel",
    format: 'LP',
    year: "1980",
    genre: "Metal",
    label: "Columbia",
    status: "collection",
    palette: ["#0f172a", "#991b1b", "#e5e7eb"],
    pattern: "portrait",
    coverUrl: "https://is1-ssl.mzstatic.com/image/thumb/Music3/v4/3e/ce/c7/3ecec7e6-66a3-7ca8-d70f-5a4512aa21ba/dj.stjulnox.jpg/600x600bb.jpg",
  },
  {
    id: 7,
    artist: "Ozzy Osbourne",
    title: "Blizzard of Ozz",
    format: '12"',
    year: "1980",
    genre: "Metal",
    label: "Epic",
    status: "collection",
    palette: ["#7c2d12", "#f59e0b", "#111827"],
    pattern: "crest",
    coverUrl: "https://is1-ssl.mzstatic.com/image/thumb/Music114/v4/92/06/bd/9206bdb3-453a-db69-44f4-c4b5bfe33510/886448748045.jpg/600x600bb.jpg",
  },
  {
    id: 8,
    artist: "Def Leppard",
    title: "Pyromania",
    format: "LP",
    year: "1983",
    genre: "Hard Rock",
    label: "Mercury",
    status: "collection",
    palette: ["#f97316", "#111827", "#facc15"],
    pattern: "stairs",
    coverUrl: "https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/99/ef/71/99ef71ff-eaea-7bb7-c479-c079f14b0a5b/17UM1IM41551.rgb.jpg/600x600bb.jpg",
  },
  // Led Zeppelin
  {
    id: 15,
    artist: "Led Zeppelin",
    title: "Led Zeppelin",
    format: "LP",
    year: "1969",
    genre: "Hard Rock",
    label: "Atlantic",
    status: "collection",
    palette: ["#111827", "#e5e7eb", "#6b7280"],
    pattern: "minimal",
    coverUrl: "https://is1-ssl.mzstatic.com/image/thumb/Music114/v4/4c/7b/80/4c7b80b4-ed35-4e06-ec80-2f7aaaabb5c5/dj.pjjmtwdc.jpg/600x600bb.jpg",
  },
  {
    id: 16,
    artist: "Led Zeppelin",
    title: "Led Zeppelin III",
    format: "LP",
    year: "1970",
    genre: "Hard Rock",
    label: "Atlantic",
    status: "collection",
    palette: ["#f5f0e8", "#4a7c3f", "#2d1810"],
    pattern: "record",
    coverUrl: "https://is1-ssl.mzstatic.com/image/thumb/Music125/v4/62/fd/14/62fd14aa-d202-a86a-d948-0a5550b35fc3/dj.rkzuiqye.jpg/600x600bb.jpg",
  },
  {
    id: 17,
    artist: "Led Zeppelin",
    title: "Led Zeppelin IV",
    format: "LP",
    year: "1971",
    genre: "Hard Rock",
    label: "Atlantic",
    status: "collection",
    palette: ["#1c1008", "#c8a96e", "#8b6914"],
    pattern: "crest",
    coverUrl: "https://is1-ssl.mzstatic.com/image/thumb/Music115/v4/5c/15/9b/5c159b27-95ca-b9a7-84e3-28e795fffd39/dj.kvkrpptq.jpg/600x600bb.jpg",
  },
  {
    id: 18,
    artist: "Led Zeppelin",
    title: "Houses of the Holy",
    format: "LP",
    year: "1973",
    genre: "Hard Rock",
    label: "Atlantic",
    status: "collection",
    palette: ["#f59e0b", "#7c2d12", "#fef3c7"],
    pattern: "burst",
    coverUrl: "https://is1-ssl.mzstatic.com/image/thumb/Music114/v4/4f/88/ad/4f88ad28-3953-fded-6c18-fe87b5d0dc7b/dj.iqdrlirx.jpg/600x600bb.jpg",
  },
  {
    id: 19,
    artist: "Led Zeppelin",
    title: "Physical Graffiti",
    format: '2xLP',
    year: "1975",
    genre: "Hard Rock",
    label: "Swan Song",
    status: "collection",
    palette: ["#b45309", "#111827", "#fbbf24"],
    pattern: "stairs",
    coverUrl: "https://is1-ssl.mzstatic.com/image/thumb/Music125/v4/82/6c/5d/826c5d66-67b7-62f2-4d78-dd3c7b415e08/dj.pifhrvpa.jpg/600x600bb.jpg",
  },
  {
    id: 20,
    artist: "Led Zeppelin",
    title: "Presence",
    format: "LP",
    year: "1976",
    genre: "Hard Rock",
    label: "Swan Song",
    status: "collection",
    palette: ["#0f172a", "#f8fafc", "#334155"],
    pattern: "type",
    coverUrl: "https://dn721608.ca.archive.org/0/items/mbid-97dbdce5-4aaf-491a-af6b-845bbb5d85e4/mbid-97dbdce5-4aaf-491a-af6b-845bbb5d85e4-37659270741.jpg",
  },
  {
    id: 21,
    artist: "Led Zeppelin",
    title: "In Through the Out Door",
    format: "LP",
    year: "1979",
    genre: "Hard Rock",
    label: "Swan Song",
    status: "collection",
    palette: ["#78350f", "#fef9c3", "#92400e"],
    pattern: "prism",
    coverUrl: "https://is1-ssl.mzstatic.com/image/thumb/Music7/v4/32/33/78/32337882-4dcf-b4ff-c2b1-988297b1aa2a/dj.bazmvvpg.jpg/600x600bb.jpg",
  },
  // Def Leppard
  {
    id: 22,
    artist: "Def Leppard",
    title: "High 'n' Dry",
    format: "LP",
    year: "1981",
    genre: "Hard Rock",
    label: "Mercury",
    status: "collection",
    palette: ["#1e3a8a", "#f8fafc", "#3b82f6"],
    pattern: "speed",
    coverUrl: "https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/98/9d/2e/989d2e39-6077-b384-95b3-8f9f2ffc8744/19UMGIM77632.rgb.jpg/600x600bb.jpg",
  },
  {
    id: 23,
    artist: "Def Leppard",
    title: "Hysteria",
    format: "LP",
    year: "1987",
    genre: "Hard Rock",
    label: "Mercury",
    status: "collection",
    palette: ["#1c1c1c", "#e11d48", "#f8fafc"],
    pattern: "rings",
    coverUrl: "https://is1-ssl.mzstatic.com/image/thumb/Music115/v4/0f/76/fa/0f76fa8d-8341-c0af-84d8-543b9193c728/17UM1IM41552.rgb.jpg/600x600bb.jpg",
  },
  {
    id: 24,
    artist: "Def Leppard",
    title: "Adrenalize",
    format: "LP",
    year: "1992",
    genre: "Hard Rock",
    label: "Mercury",
    status: "collection",
    palette: ["#111827", "#ef4444", "#fbbf24"],
    pattern: "burst",
    coverUrl: "https://is1-ssl.mzstatic.com/image/thumb/Music114/v4/7e/32/8a/7e328a3d-c639-405b-c57b-0ef869be90e8/00602567176527.rgb.jpg/600x600bb.jpg",
  },
  // Boston
  {
    id: 25,
    artist: "Boston",
    title: "Boston",
    format: "LP",
    year: "1976",
    genre: "Rock",
    label: "Epic",
    status: "collection",
    palette: ["#1e3a8a", "#60a5fa", "#f8fafc"],
    pattern: "city",
    coverUrl: "https://is1-ssl.mzstatic.com/image/thumb/Music126/v4/e3/08/9a/e3089ac9-a820-5ee9-64be-39500ad8a5e2/886444824972.jpg/600x600bb.jpg",
  },
  {
    id: 26,
    artist: "Boston",
    title: "Don't Look Back",
    format: "LP",
    year: "1978",
    genre: "Rock",
    label: "Epic",
    status: "collection",
    palette: ["#0c4a6e", "#38bdf8", "#fef3c7"],
    pattern: "prism",
    coverUrl: "https://is1-ssl.mzstatic.com/image/thumb/Music125/v4/1d/5f/81/1d5f8115-915e-4dde-814f-b22c2e5b97fe/mzi.qlxhqbnd.jpg/600x600bb.jpg",
  },
  {
    id: 27,
    artist: "Boston",
    title: "Third Stage",
    format: "LP",
    year: "1986",
    genre: "Rock",
    label: "MCA",
    status: "collection",
    palette: ["#0f172a", "#7c3aed", "#a78bfa"],
    pattern: "minimal",
    coverUrl: "https://is1-ssl.mzstatic.com/image/thumb/Music118/v4/93/c1/dd/93c1dd70-ce16-d41f-98b4-c92c8e212a97/00602537873340.rgb.jpg/600x600bb.jpg",
  },
  // Styx
  {
    id: 28,
    artist: "Styx",
    title: "The Grand Illusion",
    format: "LP",
    year: "1977",
    genre: "Rock",
    label: "A&M",
    status: "collection",
    palette: ["#1e3a8a", "#f8fafc", "#fbbf24"],
    pattern: "portrait",
    coverUrl: "https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/8c/32/78/8c327836-f69c-a8aa-79f1-2fa65f1fa9ab/06UMGIM01288.rgb.jpg/600x600bb.jpg",
  },
  {
    id: 29,
    artist: "Styx",
    title: "Pieces of Eight",
    format: "LP",
    year: "1978",
    genre: "Rock",
    label: "A&M",
    status: "collection",
    palette: ["#111827", "#d97706", "#78350f"],
    pattern: "crest",
    coverUrl: "https://is1-ssl.mzstatic.com/image/thumb/Music122/v4/9a/be/99/9abe9905-7c26-8204-1133-364e200793d0/06UMGIM01287.rgb.jpg/600x600bb.jpg",
  },
  {
    id: 30,
    artist: "Styx",
    title: "Paradise Theatre",
    format: "LP",
    year: "1981",
    genre: "Rock",
    label: "A&M",
    status: "collection",
    palette: ["#1c1c1c", "#a21caf", "#e879f9"],
    pattern: "stairs",
    coverUrl: "https://is1-ssl.mzstatic.com/image/thumb/Music211/v4/7b/2c/ba/7b2cba1f-d3f8-a043-b71d-d596f22e6142/06UMGIM18641.rgb.jpg/600x600bb.jpg",
  },
  // Kansas
  {
    id: 31,
    artist: "Kansas",
    title: "Leftoverture",
    format: "LP",
    year: "1976",
    genre: "Rock",
    label: "Kirshner",
    status: "collection",
    palette: ["#78350f", "#fef3c7", "#d97706"],
    pattern: "burst",
    coverUrl: "https://is1-ssl.mzstatic.com/image/thumb/Music/56/5b/88/mzi.hpnqhyuu.jpg/600x600bb.jpg",
  },
  {
    id: 32,
    artist: "Kansas",
    title: "Point of Know Return",
    format: "LP",
    year: "1977",
    genre: "Rock",
    label: "Kirshner",
    status: "collection",
    palette: ["#0c4a6e", "#f8fafc", "#0369a1"],
    pattern: "record",
    coverUrl: "https://is1-ssl.mzstatic.com/image/thumb/Music125/v4/05/05/5d/05055d03-fa2b-1848-75a4-6b626477937c/mzi.icapguzh.jpg/600x600bb.jpg",
  },
  // Dimmu Borgir
  {
    id: 33,
    artist: "Dimmu Borgir",
    title: "Puritanical Euphoric Misanthropia",
    format: "LP",
    year: "2001",
    genre: "Symphonic Black Metal",
    label: "Nuclear Blast",
    status: "collection",
    palette: ["#0f172a", "#7f1d1d", "#e7e5e4"],
    pattern: "type",
    coverUrl: "https://is1-ssl.mzstatic.com/image/thumb/Music125/v4/b2/f1/51/b2f151e7-e06f-aeae-9c5f-910583874267/cover.jpg/600x600bb.jpg",
  },
  {
    id: 34,
    artist: "Dimmu Borgir",
    title: "Death Cult Armageddon",
    format: "LP",
    year: "2003",
    genre: "Symphonic Black Metal",
    label: "Nuclear Blast",
    status: "collection",
    palette: ["#1c1917", "#ef4444", "#57534e"],
    pattern: "rings",
    coverUrl: "https://is1-ssl.mzstatic.com/image/thumb/Music113/v4/35/44/f0/3544f0c5-1ce4-b2f1-eca0-ce0248519e8a/cover.jpg/600x600bb.jpg",
  },
  // Lamb of God
  {
    id: 35,
    artist: "Lamb of God",
    title: "Ashes of the Wake",
    format: "LP",
    year: "2004",
    genre: "Metal",
    label: "Epic",
    status: "collection",
    palette: ["#111827", "#dc2626", "#6b7280"],
    pattern: "speed",
    coverUrl: "https://dn710204.ca.archive.org/0/items/mbid-6012b20e-8fdd-4afc-9b0e-a9f22bce81a1/mbid-6012b20e-8fdd-4afc-9b0e-a9f22bce81a1-36090160874.jpg",
  },
  {
    id: 36,
    artist: "Lamb of God",
    title: "Sacrament",
    format: "LP",
    year: "2006",
    genre: "Metal",
    label: "Epic",
    status: "collection",
    palette: ["#1c1917", "#b91c1c", "#f5f5f4"],
    pattern: "prism",
    coverUrl: "https://dn710806.ca.archive.org/0/items/mbid-a698633f-779a-44c0-a040-8f815c730a3f/mbid-a698633f-779a-44c0-a040-8f815c730a3f-16132402939.jpg",
  },
  // Children of Bodom
  {
    id: 37,
    artist: "Children of Bodom",
    title: "Follow the Reaper",
    format: "LP",
    year: "2000",
    genre: "Melodic Death Metal",
    label: "Nuclear Blast",
    status: "collection",
    palette: ["#0f172a", "#16a34a", "#4ade80"],
    pattern: "city",
    coverUrl: "https://dn721803.ca.archive.org/0/items/mbid-dbfe993f-6bfa-43f5-b907-9e2e0199b140/mbid-dbfe993f-6bfa-43f5-b907-9e2e0199b140-4258683037.jpg",
  },
  {
    id: 38,
    artist: "Children of Bodom",
    title: "Hate Crew Deathroll",
    format: "LP",
    year: "2003",
    genre: "Melodic Death Metal",
    label: "Nuclear Blast",
    status: "collection",
    palette: ["#1c1917", "#dc2626", "#fbbf24"],
    pattern: "burst",
    coverUrl: "https://is1-ssl.mzstatic.com/image/thumb/Music4/v4/3b/40/f6/3b40f6e3-ab57-82c5-80d0-175ea35ef12c/00044003754775_Cover.jpg/600x600bb.jpg",
  },
  // In Flames
  {
    id: 39,
    artist: "In Flames",
    title: "Clayman",
    format: "LP",
    year: "2000",
    genre: "Melodic Death Metal",
    label: "Nuclear Blast",
    status: "collection",
    palette: ["#0f172a", "#0ea5e9", "#e0f2fe"],
    pattern: "minimal",
    coverUrl: "https://is1-ssl.mzstatic.com/image/thumb/Music114/v4/a9/49/98/a94998ff-982a-a974-1c39-f6ed64e77dc8/cover.jpg/600x600bb.jpg",
  },
  {
    id: 40,
    artist: "In Flames",
    title: "Come Clarity",
    format: "LP",
    year: "2006",
    genre: "Metal",
    label: "Nuclear Blast",
    status: "collection",
    palette: ["#1e3a8a", "#f8fafc", "#93c5fd"],
    pattern: "portrait",
    coverUrl: "https://is1-ssl.mzstatic.com/image/thumb/Music/7e/0d/d6/mzi.erqdieqp.jpg/600x600bb.jpg",
  },
  // More classic metal / rock
  {
    id: 41,
    artist: "Iron Maiden",
    title: "Powerslave",
    format: "LP",
    year: "1984",
    genre: "Metal",
    label: "EMI",
    status: "collection",
    palette: ["#78350f", "#fbbf24", "#111827"],
    pattern: "crest",
    coverUrl: "https://is1-ssl.mzstatic.com/image/thumb/Music125/v4/56/4a/0e/564a0e06-4f6e-84da-fa38-88d8c3f3a1ba/825646248179.jpg/600x600bb.jpg",
  },
  {
    id: 42,
    artist: "Judas Priest",
    title: "Screaming for Vengeance",
    format: "LP",
    year: "1982",
    genre: "Metal",
    label: "Columbia",
    status: "collection",
    palette: ["#111827", "#f59e0b", "#dc2626"],
    pattern: "speed",
    coverUrl: "https://is1-ssl.mzstatic.com/image/thumb/Music114/v4/b3/27/d8/b327d8a9-f241-9446-3cca-91cf70650347/886443601284.jpg/600x600bb.jpg",
  },
  {
    id: 43,
    artist: "Black Sabbath",
    title: "Heaven and Hell",
    format: "LP",
    year: "1980",
    genre: "Metal",
    label: "Warner Bros.",
    status: "collection",
    palette: ["#1c1917", "#a78bfa", "#4c1d95"],
    pattern: "rings",
    coverUrl: "https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/2a/11/4c/2a114cd9-ddf7-5852-05df-f715b4fee2d9/603497845453.jpg/600x600bb.jpg",
  },
  {
    id: 9,
    artist: "Dio",
    title: "Holy Diver",
    format: '12"',
    year: "1983",
    genre: "Metal",
    label: "Warner Bros.",
    status: "wishlist",
    palette: ["#0f172a", "#2563eb", "#ef4444"],
    pattern: "rings",
    coverUrl: "https://is1-ssl.mzstatic.com/image/thumb/Music115/v4/e4/8e/9a/e48e9aa6-1488-8b71-82eb-0b856d1034d2/mzm.txbqniop.jpg/600x600bb.jpg",
  },
  {
    id: 10,
    artist: "Megadeth",
    title: "Rust In Peace",
    format: "LP",
    year: "1990",
    genre: "Metal",
    label: "Capitol",
    status: "wishlist",
    palette: ["#1e3a8a", "#d97706", "#84cc16"],
    pattern: "city",
    coverUrl: "https://is1-ssl.mzstatic.com/image/thumb/Music221/v4/df/fe/a7/dffea722-e8d7-b2ac-2b31-e207fb738b8e/13UABIM36806.rgb.jpg/600x600bb.jpg",
  },
  {
    id: 11,
    artist: "Metallica",
    title: "Ride the Lightning",
    format: "LP",
    year: "1984",
    genre: "Metal",
    label: "Megaforce",
    status: "wishlist",
    palette: ["#0f172a", "#38bdf8", "#f9fafb"],
    pattern: "minimal",
    coverUrl: "https://is1-ssl.mzstatic.com/image/thumb/Features125/v4/0f/7a/74/0f7a7472-92fa-e77d-384a-1e4304705e83/dj.jbiruenb.png/600x600bb.jpg",
  },
  {
    id: 12,
    artist: "Black Sabbath",
    title: "Master of Reality",
    format: "LP",
    year: "1971",
    genre: "Metal",
    label: "Warner Records",
    status: "wishlist",
    palette: ["#0f172a", "#16a34a", "#84cc16"],
    pattern: "type",
    coverUrl: "https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/c2/9f/a1/c29fa109-8c22-bb7f-82f2-a6891d961c28/075992725323.jpg/600x600bb.jpg",
  },
  {
    id: 13,
    artist: "Van Halen",
    title: "Van Halen",
    format: '12"',
    year: "1978",
    genre: "Hard Rock",
    label: "Warner Bros.",
    status: "wishlist",
    palette: ["#dc2626", "#f8fafc", "#111827"],
    pattern: "burst",
    coverUrl: "https://is1-ssl.mzstatic.com/image/thumb/Music125/v4/7a/ef/88/7aef88ad-25aa-be91-eb78-8917c3f114f7/603497894130.jpg/600x600bb.jpg",
  },
  {
    id: 14,
    artist: "Rainbow",
    title: "Rising",
    format: "LP",
    year: "1976",
    genre: "Hard Rock",
    label: "Polydor",
    status: "wishlist",
    palette: ["#7c2d12", "#fbbf24", "#2563eb"],
    pattern: "crest",
    coverUrl: "https://is1-ssl.mzstatic.com/image/thumb/Music118/v4/ba/90/85/ba90851d-b3bf-ff6d-3695-d230bf07daf4/00731454736121.rgb.jpg/600x600bb.jpg",
  },
  {
    id: 44,
    artist: "Metallica",
    title: "Master of Puppets",
    format: "LP",
    year: "1986",
    genre: "Metal",
    label: "Elektra",
    status: "wishlist",
    palette: ["#111827", "#dc2626", "#f8fafc"],
    pattern: "speed",
    coverUrl: "https://dn711301.ca.archive.org/0/items/mbid-9ad9f401-9b5e-44d7-8b41-51ef37146f32/mbid-9ad9f401-9b5e-44d7-8b41-51ef37146f32-1810244497.jpg",
  },
  {
    id: 45,
    artist: "Pantera",
    title: "Vulgar Display of Power",
    format: "LP",
    year: "1992",
    genre: "Metal",
    label: "Atco",
    status: "wishlist",
    palette: ["#0f172a", "#6b7280", "#f8fafc"],
    pattern: "type",
    coverUrl: "https://dn710300.ca.archive.org/0/items/mbid-ffcec0de-d12e-3677-9607-4ece6d5c97a5/mbid-ffcec0de-d12e-3677-9607-4ece6d5c97a5-7967409791.jpg",
  },
  {
    id: 46,
    artist: "In Flames",
    title: "The Jester Race",
    format: "LP",
    year: "1996",
    genre: "Melodic Death Metal",
    label: "Nuclear Blast",
    status: "wishlist",
    palette: ["#1c1917", "#dc2626", "#78716c"],
    pattern: "rings",
    coverUrl: "https://dn721806.ca.archive.org/0/items/mbid-08b7212c-def7-3a3e-bedf-19db3e3b023b/mbid-08b7212c-def7-3a3e-bedf-19db3e3b023b-1282323242.jpg",
  },
  {
    id: 47,
    artist: "Styx",
    title: "Equinox",
    format: "LP",
    year: "1975",
    genre: "Rock",
    label: "A&M",
    status: "wishlist",
    palette: ["#111827", "#7c3aed", "#c4b5fd"],
    pattern: "prism",
    coverUrl: "https://is1-ssl.mzstatic.com/image/thumb/Music128/v4/ef/49/42/ef494230-0725-a760-4d97-06a52b177a45/00075021321724.rgb.jpg/600x600bb.jpg",
  },
  {
    id: 48,
    artist: "Lamb of God",
    title: "Wrath",
    format: "LP",
    year: "2009",
    genre: "Metal",
    label: "Epic",
    status: "wishlist",
    palette: ["#1c1917", "#b45309", "#f8fafc"],
    pattern: "burst",
    coverUrl: "https://ia600901.us.archive.org/23/items/mbid-91f2cf18-829e-4015-b6d0-00f1e7a0d3e0/mbid-91f2cf18-829e-4015-b6d0-00f1e7a0d3e0-36221302731.jpg",
  },
  {
    id: 49,
    artist: "Kansas",
    title: "Leftoverture Live & Beyond",
    format: '2xLP',
    year: "2017",
    genre: "Rock",
    label: "InsideOut",
    status: "wishlist",
    palette: ["#92400e", "#fef3c7", "#78350f"],
    pattern: "minimal",
    coverUrl: "https://is1-ssl.mzstatic.com/image/thumb/Music118/v4/f2/85/af/f285afc6-fd77-1e33-840a-5c9bb861c67f/886446566436.jpg/600x600bb.jpg",
  },
  {
    id: 50,
    artist: "Dimmu Borgir",
    title: "Enthrone Darkness Triumphant",
    format: "LP",
    year: "1997",
    genre: "Symphonic Black Metal",
    label: "Nuclear Blast",
    status: "wishlist",
    palette: ["#0f172a", "#475569", "#94a3b8"],
    pattern: "city",
    coverUrl: "https://is1-ssl.mzstatic.com/image/thumb/Music114/v4/f4/62/1c/f4621cf6-2285-f99b-c337-24061341f9e1/cover.jpg/600x600bb.jpg",
  },
];

const collectionAlbums = albums.filter((album) => album.status === "collection");
const wishlistAlbums = albums.filter((album) => album.status === "wishlist");

const initialListings = [
  // --- From wishlist ---
  { id: 201, seller: people[5],  album: albums.find(a => a.id === 44), condition: "Very Good+", price: 48,  description: "Original Elektra pressing. Some light scuffs but plays beautifully with no skips.", photos: [], shipping: true,  shippingCost: 6, localOnly: false, location: "Austin, TX",      listedAt: "2 hours ago",    sellerRating: 4.9, sellerSales: 63 },
  { id: 202, seller: people[8],  album: albums.find(a => a.id === 11), condition: "Near Mint",  price: 85,  description: "180g repress, never played. Still has original inner sleeve.",                    photos: [], shipping: true,  shippingCost: 8, localOnly: false, location: "Chicago, IL",     listedAt: "5 hours ago",    sellerRating: 4.7, sellerSales: 29 },
  { id: 203, seller: people[3],  album: albums.find(a => a.id === 45), condition: "Very Good",  price: 32,  description: "Picked this up at a garage sale. Some ring wear on the cover but vinyl is clean.", photos: [], shipping: true,  shippingCost: 5, localOnly: false, location: "Dallas, TX",      listedAt: "1 day ago",      sellerRating: 4.5, sellerSales: 17 },
  { id: 204, seller: people[9],  album: albums.find(a => a.id === 13), condition: "Very Good+", price: 55,  description: "Original Warner Bros. pressing. Cover has light shelf wear. Record grades VG+.",   photos: [], shipping: true,  shippingCost: 6, localOnly: false, location: "Seattle, WA",     listedAt: "3 hours ago",    sellerRating: 4.8, sellerSales: 41 },
  { id: 205, seller: people[6],  album: albums.find(a => a.id === 12), condition: "Mint",       price: 120, description: "Sealed 180g reissue from Warner. Never opened.",                                 photos: [], shipping: true,  shippingCost: 7, localOnly: false, location: "Miami, FL",       listedAt: "30 minutes ago", sellerRating: 5.0, sellerSales: 88 },
  { id: 206, seller: people[11], album: albums.find(a => a.id === 47), condition: "Very Good",  price: 28,  description: "Great-sounding album. Minor edge splits on inner sleeve.",                       photos: [], shipping: false, shippingCost: 0, localOnly: true,  location: "Brooklyn, NY",    listedAt: "1 day ago",      sellerRating: 4.6, sellerSales: 22 },
  // --- Recommended (collection genres) ---
  { id: 207, seller: people[0],  album: albums.find(a => a.id === 1),  condition: "Near Mint",  price: 75,  description: "2016 Sanctuary remaster. Excellent pressing, plays very quietly.",                photos: [], shipping: true,  shippingCost: 6, localOnly: false, location: "Portland, OR",    listedAt: "4 hours ago",    sellerRating: 4.9, sellerSales: 55 },
  { id: 208, seller: people[7],  album: albums.find(a => a.id === 3),  condition: "Very Good+", price: 45,  description: "UK pressing with deep purple label. Light scuff side 2, plays through fine.",     photos: [], shipping: true,  shippingCost: 8, localOnly: false, location: "Los Angeles, CA", listedAt: "6 hours ago",    sellerRating: 4.8, sellerSales: 36 },
  { id: 209, seller: people[2],  album: albums.find(a => a.id === 2),  condition: "Very Good",  price: 38,  description: "Classic record. Cover has some aging but vinyl is in good shape.",                photos: [], shipping: true,  shippingCost: 5, localOnly: false, location: "Nashville, TN",   listedAt: "2 days ago",     sellerRating: 4.4, sellerSales: 12 },
  { id: 210, seller: people[10], album: albums.find(a => a.id === 6),  condition: "Near Mint",  price: 90,  description: "2014 180g repress. Sounds massive. Inner sleeve included.",                      photos: [], shipping: true,  shippingCost: 7, localOnly: false, location: "San Francisco, CA", listedAt: "8 hours ago",  sellerRating: 4.7, sellerSales: 44 },
  // --- Near you (NYC area) ---
  { id: 211, seller: people[1],  album: albums.find(a => a.id === 4),  condition: "Very Good+", price: 42,  description: "Cash preferred. Can meet in Williamsburg or Greenpoint.",                        photos: [], shipping: false, shippingCost: 0, localOnly: true,  location: "Brooklyn, NY",    listedAt: "3 hours ago",    sellerRating: 4.8, sellerSales: 31 },
  { id: 212, seller: people[4],  album: albums.find(a => a.id === 5),  condition: "Very Good",  price: 24,  description: "Moving soon, clearing out records. Happy to meet in Manhattan.",                  photos: [], shipping: false, shippingCost: 0, localOnly: true,  location: "New York, NY",    listedAt: "5 hours ago",    sellerRating: 4.5, sellerSales: 9  },
  { id: 213, seller: people[11], album: albums.find(a => a.id === 8),  condition: "Near Mint",  price: 65,  description: "Original UK pressing. Exceptional copy, rarely played.",                        photos: [], shipping: false, shippingCost: 0, localOnly: true,  location: "Queens, NY",      listedAt: "1 day ago",      sellerRating: 4.6, sellerSales: 22 },
  { id: 214, seller: people[3],  album: albums.find(a => a.id === 7),  condition: "Good",       price: 12,  description: "Play copy. Some crackle on opener. Still a great listen at this price.",        photos: [], shipping: false, shippingCost: 0, localOnly: true,  location: "Hoboken, NJ",     listedAt: "6 hours ago",    sellerRating: 4.2, sellerSales: 7  },
  // --- Recent / Trending ---
  { id: 215, seller: people[9],  album: albums.find(a => a.id === 14), condition: "Very Good+", price: 68,  description: "Polydor original. Really don't want to let it go but need the space.",           photos: [], shipping: true,  shippingCost: 6, localOnly: false, location: "Seattle, WA",     listedAt: "20 minutes ago", sellerRating: 4.8, sellerSales: 41 },
  { id: 216, seller: people[8],  album: albums.find(a => a.id === 10), condition: "Mint",       price: 140, description: "Original Capitol promo copy. Never played. Extremely rare find.",               photos: [], shipping: true,  shippingCost: 9, localOnly: false, location: "Chicago, IL",     listedAt: "45 minutes ago", sellerRating: 4.7, sellerSales: 29 },
  { id: 217, seller: people[6],  album: albums.find(a => a.id === 50), condition: "Near Mint",  price: 95,  description: "First edition Nuclear Blast. This one is genuinely hard to find.",              photos: [], shipping: true,  shippingCost: 7, localOnly: false, location: "Miami, FL",       listedAt: "1 hour ago",     sellerRating: 5.0, sellerSales: 88 },
  { id: 218, seller: people[0],  album: albums.find(a => a.id === 48), condition: "Very Good+", price: 35,  description: "Epic Records copy. Played a handful of times. Great condition.",               photos: [], shipping: true,  shippingCost: 5, localOnly: false, location: "Portland, OR",    listedAt: "2 hours ago",    sellerRating: 4.9, sellerSales: 55 },
];

const initialPosts = [
  {
    id: 105,
    user: people[2],
    ago: "just now",
    text: "Finally sorted the whole shelf by label. Atlantic on top, Island below. Took two hours but now I can actually find things.",
    liked: false,
    likes: 7,
    comments: [],
  },
  {
    id: 106,
    user: people[4],
    ago: "4 minutes ago",
    text: "Just found these on a haul. The Hysteria copy alone made the whole trip worth it.",
    imageUrl: "./assets/img-9691.jpeg",
    liked: false,
    likes: 18,
    comments: [],
  },
  {
    id: 101,
    user: people[1],
    ago: "6 minutes ago",
    text: "Original green-label pressing still feels enormous. The opening riff on War Pigs has that room-shaking weight.",
    albumId: 1,
    liked: false,
    likes: 34,
    comments: [
      { user: commentAuthors.vinylfy, ago: "5m", text: "That one belongs at the front of the Sabbath shelf." },
      { user: commentAuthors.needleandnight, ago: "5m", text: "The bass tone on Hand of Doom never gets old." },
      { user: commentAuthors.kompaktskiste, ago: "4m", text: "Green label original is worth hunting for. Different mastering entirely." },
      { user: commentAuthors.pipozoft, ago: "4m", text: "Iron Man intro still sounds like nothing else." },
      { user: commentAuthors.vinylfy, ago: "4m", text: "Plays loud without sounding harsh. That's rare for this era." },
      { user: commentAuthors.needleandnight, ago: "4m", text: "War Pigs is nearly 8 minutes and not a single second wasted." },
      { user: commentAuthors.kompaktskiste, ago: "3m", text: "Side B pacing is underrated. Rat Salad into Fairies Wear Boots." },
      { user: commentAuthors.pipozoft, ago: "3m", text: "Have you compared to the Vertigo pressing? Curious how they differ." },
      { user: commentAuthors.vinylfy, ago: "3m", text: "Vertigo has more mid presence. Green label hits harder on the low end." },
      { user: commentAuthors.needleandnight, ago: "3m", text: "My copy crackles on track two but I love it anyway." },
      { user: commentAuthors.kompaktskiste, ago: "3m", text: "Electric Funeral is the dark horse track on this whole record." },
      { user: commentAuthors.pipozoft, ago: "2m", text: "Agreed. People sleep on it." },
      { user: commentAuthors.vinylfy, ago: "2m", text: "Bill Ward's drumming on this album is genuinely unhinged in the best way." },
      { user: commentAuthors.needleandnight, ago: "2m", text: "Geezer's bass is buried a little in the mix on some pressings." },
      { user: commentAuthors.kompaktskiste, ago: "2m", text: "The US pressing has that problem less I think." },
      { user: commentAuthors.pipozoft, ago: "2m", text: "Picked mine up at a record fair for £4. Still proud of that." },
      { user: commentAuthors.vinylfy, ago: "2m", text: "£4! That's basically theft." },
      { user: commentAuthors.needleandnight, ago: "2m", text: "Mine was €12 and I still felt like I won." },
      { user: commentAuthors.kompaktskiste, ago: "1m", text: "Paranoid the song is almost a throwaway but it's the title track. Wild." },
      { user: commentAuthors.pipozoft, ago: "1m", text: "Written in about 20 minutes apparently. Unbelievable." },
      { user: commentAuthors.vinylfy, ago: "1m", text: "You can hear that energy. It sounds like they were running out of time." },
      { user: commentAuthors.needleandnight, ago: "1m", text: "Planet Caravan is such a left turn in the middle of the record." },
      { user: commentAuthors.kompaktskiste, ago: "1m", text: "That's what makes it work. Breaks the tension before Iron Man." },
      { user: commentAuthors.pipozoft, ago: "1m", text: "Perfect sequencing honestly." },
      { user: commentAuthors.vinylfy, ago: "1m", text: "Wish more records took that kind of risk mid-side." },
      { user: commentAuthors.needleandnight, ago: "just now", text: "Volume unity between tracks is a bit off on some copies. Mine clips slightly." },
      { user: commentAuthors.kompaktskiste, ago: "just now", text: "Cleaning the stylus makes a huge difference on older pressings like this." },
      { user: commentAuthors.pipozoft, ago: "just now", text: "Going to put this on tonight now. Thanks for the reminder." },
      { user: commentAuthors.vinylfy, ago: "just now", text: "Same. You just convinced me to pull it out." },
      { user: commentAuthors.needleandnight, ago: "just now", text: "This is why I love this app." },
    ],
  },
  {
    id: 102,
    user: people[0],
    ago: "30 minutes ago",
    text: "Found a clean copy with almost no groove noise. Highway to Hell is great, but this one still feels like the monument.",
    albumId: 4,
    liked: true,
    likes: 41,
    comments: [
      { user: commentAuthors.kompaktskiste, ago: "18m", text: "Back in Black is a perfect late-night loud record." },
    ],
  },
  {
    id: 103,
    user: people[3],
    ago: "37 minutes ago",
    text: "Revisiting British Steel today. Short, sharp, and no wasted motion.",
    albumId: 6,
    liked: false,
    likes: 19,
    comments: [
      { user: commentAuthors.pipozoft, ago: "21m", text: "Living After Midnight still lands every time." },
    ],
  },
  {
    id: 104,
    user: people[5],
    ago: "about 2 hours ago",
    text: "Pulled Pyromania from the shelf after a long week. Big drums, big hooks, zero apology.",
    albumId: 8,
    liked: false,
    likes: 28,
    comments: [],
  },
];

const recommendedGear = [
  {
    name: "Orbit Basic Turntable",
    retailer: "U-Turn Audio",
    price: "$249",
    tag: "Starter pick",
    description: "Belt-drive table with OA3 tonearm, AT91B cartridge, and MDF platter.",
    imageUrl: "https://uturnaudio.com/cdn/shop/files/front_BK_grande.jpg?v=1683911732",
    url: "https://uturnaudio.com/products/orbit-basic-turntable",
  },
  {
    name: "Orbit Plus Turntable",
    retailer: "U-Turn Audio",
    price: "$399",
    tag: "Upgrade",
    description: "Acrylic platter and Ortofon OM5E cartridge.",
    imageUrl: "https://uturnaudio.com/cdn/shop/files/front_BK_e7752a83-0104-4da3-a26c-15ce04c40d7a_grande.jpg?v=1687890559",
    url: "https://uturnaudio.com/products/orbit-plus-turntable",
  },
  {
    name: "Pluto 2 Phono Preamp",
    retailer: "U-Turn Audio",
    price: "$129",
    tag: "Accessory",
    description: "Low-noise phono preamp for moving magnet cartridges.",
    imageUrl: "https://uturnaudio.com/cdn/shop/products/200WT_front_angle_grande.jpg?v=1594061335",
    url: "https://uturnaudio.com/products/pluto-2-phono-preamp",
  },
];

function Icon({ name, size = 16 }) {
  useEffect(() => {
    if (window.lucide) window.lucide.createIcons();
  });
  return <i data-lucide={name} style={{ width: size, height: size }} aria-hidden="true" />;
}

function Avatar({ user, size = "md" }) {
  const className = size === "sm" ? "avatar avatar-sm" : "avatar";
  return (
    <div
      className={className}
      aria-label={user.name}
      title={user.name}
    >
      <img src={user.avatarUrl} alt="" loading="eager" referrerPolicy="no-referrer" />
      <span className="sr-only">{user.name}</span>
    </div>
  );
}

function AlbumArt({ album, compact = false }) {
  const [imageFailed, setImageFailed] = useState(false);
  const [a, b, c] = album.palette;
  const showImage = album.coverUrl && !imageFailed;

  return (
    <div className={`album-art ${compact ? "compact" : ""}`} style={{ "--a": a, "--b": b, "--c": c }}>
      {showImage ? (
        <img src={album.coverUrl} alt={`${album.artist} - ${album.title} cover`} onError={() => setImageFailed(true)} />
      ) : (
        <div className={`cover-pattern ${album.pattern}`}>
          <span className="cover-artist">{album.artist}</span>
          <strong>{album.title}</strong>
        </div>
      )}
    </div>
  );
}

function TopBar({ page, setPage, theme, setTheme }) {
  return (
    <header className="topbar">
      <div className="topbar-inner">
        <button className="brand" onClick={() => setPage("home")} aria-label="Vinylfy home">
          <img src="./assets/logo.svg" alt="Vinylfy" />
        </button>
        <nav className="nav">
          {navItems.map((item) => (
            <button
              key={item.id}
              className={`nav-item ${page === item.id ? "active" : ""}`}
              onClick={() => setPage(item.id)}
            >
              <Icon name={item.icon} />
              <span>{item.label}</span>
            </button>
          ))}
        </nav>
        <div className="top-actions">
          <button className="icon-button" aria-label="Notifications">
            <Icon name="bell" />
          </button>
          <button className="icon-button" aria-label="Messages">
            <Icon name="message-circle" />
          </button>
          <button className="icon-button" onClick={() => setTheme(theme === "dark" ? "light" : "dark")} aria-label="Toggle theme">
            <Icon name={theme === "dark" ? "sun" : "moon"} />
          </button>
          <button className="profile-chip" onClick={() => setPage("collection")}>
            <Avatar user={people[4]} size="sm" />
            <Icon name="chevron-down" size={16} />
          </button>
        </div>
      </div>
    </header>
  );
}

function Composer({ onPost }) {
  const [text, setText] = useState("");
  const [selectedAlbum, setSelectedAlbum] = useState(collectionAlbums[0].id);
  const [attachedImage, setAttachedImage] = useState(false);
  const [pickerOpen, setPickerOpen] = useState(false);
  const [pickerTab, setPickerTab] = useState("collection");
  const [pickerQuery, setPickerQuery] = useState("");
  const composerRef = useRef(null);
  const searchRef = useRef(null);
  const attachedAlbum = albums.find((album) => album.id === selectedAlbum);
  const sourceAlbums = pickerTab === "collection" ? collectionAlbums : wishlistAlbums;
  const pickerAlbums = pickerQuery.trim()
    ? sourceAlbums.filter((a) => `${a.title} ${a.artist}`.toLowerCase().includes(pickerQuery.toLowerCase()))
    : sourceAlbums;

  useEffect(() => {
    if (pickerOpen) searchRef.current?.focus();
    else setPickerQuery("");
  }, [pickerOpen]);

  useEffect(() => {
    function handleClickOutside(e) {
      if (composerRef.current && !composerRef.current.contains(e.target)) {
        setPickerOpen(false);
      }
    }
    if (pickerOpen) document.addEventListener("mousedown", handleClickOutside);
    return () => document.removeEventListener("mousedown", handleClickOutside);
  }, [pickerOpen]);

  function submit() {
    if (!text.trim()) return;
    onPost({
      id: Date.now(),
      user: people[4],
      ago: "just now",
      text: text.trim(),
      albumId: selectedAlbum,
      liked: false,
      likes: 0,
      comments: [],
      attachedImage,
    });
    setText("");
    setAttachedImage(false);
    setPickerOpen(false);
  }

  function chooseAlbum(albumId) {
    setSelectedAlbum(albumId);
    setPickerOpen(false);
  }

  return (
    <section className="composer panel" ref={composerRef}>
      <div className="composer-shell">
        <textarea
          value={text}
          onChange={(event) => setText(event.target.value)}
          placeholder="What are you spinning?"
        />
        <div className="composer-bottom">
          <div className="composer-tools">
            <button className={`tool-button ${attachedImage ? "selected" : ""}`} onClick={() => setAttachedImage(!attachedImage)} title="Attach image">
              <Icon name="image" />
            </button>
            <button
              className={`tool-button album-picker-button ${pickerOpen ? "selected" : ""}`}
              onClick={() => setPickerOpen(!pickerOpen)}
              title={attachedAlbum ? `Select record: ${attachedAlbum.artist} - ${attachedAlbum.title}` : "Select record"}
              aria-label="Select record from collection or wishlist"
              aria-expanded={pickerOpen}
            >
              <Icon name="disc-3" />
            </button>
          </div>
          <button className="primary-button" onClick={submit} disabled={!text.trim()}>
            Share
          </button>
        </div>
      </div>
      {pickerOpen && (
        <div className="album-picker">
          <div className="picker-tabs" role="tablist" aria-label="Record source">
            <button className={pickerTab === "collection" ? "active" : ""} onClick={() => setPickerTab("collection")}>
              Collection
            </button>
            <button className={pickerTab === "wishlist" ? "active" : ""} onClick={() => setPickerTab("wishlist")}>
              Wishlist
            </button>
          </div>
          <label className="search-field small picker-search">
            <Icon name="search" />
            <input
              ref={searchRef}
              value={pickerQuery}
              onChange={(e) => setPickerQuery(e.target.value)}
              placeholder="Search records..."
            />
          </label>
          <div className="picker-list">
            {pickerAlbums.map((album) => (
              <button
                className={`picker-album ${selectedAlbum === album.id ? "active" : ""}`}
                key={album.id}
                onClick={() => chooseAlbum(album.id)}
              >
                <AlbumArt album={album} compact />
                <span>
                  <strong>{album.title}</strong>
                  <small>{album.artist}</small>
                </span>
              </button>
            ))}
          </div>
        </div>
      )}
    </section>
  );
}

function PeoplePanel({ followed, toggleFollow }) {
  return (
    <section className="side-section">
      <div className="section-title">
        <h2>People you may know</h2>
      </div>
      <div className="people-list">
        {people.slice(0, 4).map((person) => {
          const isFollowing = followed.includes(person.handle);
          return (
            <div className="person-row" key={person.handle}>
              <Avatar user={person} />
              <div className="person-info">
                <span className="person-name">{person.name}</span>
                <span className="person-handle">{person.handle}</span>
              </div>
              <button
                className={`ghost-button follow-button ${isFollowing ? "is-following" : ""}`}
                onClick={() => toggleFollow(person.handle)}
              >
                {isFollowing && <Icon name="check" size={14} />}
                {isFollowing ? "Following" : "Follow"}
              </button>
            </div>
          );
        })}
      </div>
      <div className="side-show-more">
        <span>Show more</span>
        <Icon name="arrow-up-right" size={13} />
      </div>
    </section>
  );
}

function PostCard({ post, isOpen, onOpen, onLike, onComment }) {
  const [comment, setComment] = useState("");
  const [addMenuOpen, setAddMenuOpen] = useState(false);
  const addMenuRef = React.useRef(null);
  const album = albums.find((item) => item.id === post.albumId);

  React.useEffect(() => {
    if (!addMenuOpen) return;
    function handleOutside(e) {
      if (addMenuRef.current && !addMenuRef.current.contains(e.target)) setAddMenuOpen(false);
    }
    document.addEventListener("mousedown", handleOutside);
    return () => document.removeEventListener("mousedown", handleOutside);
  }, [addMenuOpen]);

  function submitComment() {
    if (!comment.trim()) return;
    onComment(post.id, comment.trim());
    setComment("");
    onOpen(post.id, true);
  }

  function openPost(event) {
    if (event.target.closest("button, input, textarea, select")) return;
    onOpen(post.id, true);
  }

  return (
    <article className={`post-card panel ${isOpen ? "is-open" : ""}`} onClick={openPost}>
      <div className="post-header">
        <div className="post-author">
          <Avatar user={post.user} />
          <div>
            <strong>{post.user.name}</strong>
            <span>{post.ago}</span>
          </div>
        </div>
        <button className="icon-button post-menu-btn" title="More options" onClick={(e) => e.stopPropagation()}>
          <Icon name="ellipsis" />
        </button>
      </div>
      <p className="post-text">{post.text}</p>
      {album && (
        <div className="record-card">
          <AlbumArt album={album} />
          <div className="record-meta">
            <div className="record-meta-top">
              <p>{album.artist}</p>
              <h3>{album.title}</h3>
            </div>
            <div className="record-meta-details">
              <div className="record-meta-tags">
                <span>{album.format}</span>
                <span>{album.year}</span>
                <span>{album.genre}</span>
              </div>
              {labelLogos[album.label] ? (
                <img
                  className="label-logo"
                  src={labelLogos[album.label]}
                  alt={album.label}
                  onError={(e) => { e.target.style.display = "none"; }}
                />
              ) : (
                <span className="label-name">{album.label}</span>
              )}
            </div>
          </div>
        </div>
      )}
      {post.imageUrl && (
        <div className="post-image">
          <img src={post.imageUrl} alt="Post photo" />
        </div>
      )}
      {post.attachedImage && !post.imageUrl && (
        <div className="listening-photo">
          <Icon name="music-2" />
          <span>Listening room photo attached</span>
        </div>
      )}
      <div className="post-footer">
        <div className="post-actions">
          <button className={post.liked ? "liked" : ""} onClick={() => onLike(post.id)} title="Like">
            <Icon name="heart" />
            <span>{post.likes}</span>
          </button>
          <button className={isOpen ? "active" : ""} onClick={() => onOpen(post.id)} title="Comment">
            <Icon name="message-square" />
            <span>{post.comments.length}</span>
          </button>
        </div>
        {album && (
          <div className="add-to-list" ref={addMenuRef}>
            <button
              className="icon-button add-to-list-btn"
              onClick={(e) => { e.stopPropagation(); setAddMenuOpen(!addMenuOpen); }}
              title="Add to list"
            >
              <Icon name="plus" />
            </button>
            {addMenuOpen && (
              <div className="add-to-list-menu">
                <button onClick={(e) => { e.stopPropagation(); setAddMenuOpen(false); }}><Icon name="library" size={15} />Add to Collection</button>
                <button onClick={(e) => { e.stopPropagation(); setAddMenuOpen(false); }}><Icon name="bookmark" size={15} />Add to Wishlist</button>
              </div>
            )}
          </div>
        )}
      </div>
      {isOpen && (
        <div className="comments">
          {post.comments.map((item, index) => (
            <div className="comment-row" key={`${item.user.handle}-${index}`}>
              <Avatar user={item.user} />
              <div className="comment-body">
                <div className="comment-meta">
                  <strong>{item.user.name}</strong>
                  <span>{item.user.handle}</span>
                  <span>{item.ago}</span>
                </div>
                <p>{item.text}</p>
                <div className="comment-actions">
                  <button title="Reply"><Icon name="message-circle" size={14} /></button>
                  <button title="Like"><Icon name="heart" size={14} /></button>
                </div>
              </div>
            </div>
          ))}
          <div className="comment-form">
            <Avatar user={people[4]} />
            <input value={comment} onChange={(event) => setComment(event.target.value)} placeholder="Post your reply" />
            <button onClick={submitComment}>Reply</button>
          </div>
        </div>
      )}
    </article>
  );
}

function RightRail() {
  const [featuredGear, ...secondaryGear] = recommendedGear;

  return (
    <aside className="right-rail">
      <section className="side-section">
        <div className="section-title">
          <h2>Partners</h2>
        </div>
        <div className="promo-tile">
          <span>[:O/]</span>
          <strong>nowXspinning</strong>
        </div>
      </section>
      <section className="side-section">
        <div className="section-title">
          <h2>Recommended Gear</h2>
        </div>
        <div className="product-list">
          <a className="product-card featured-product" href={featuredGear.url} target="_blank" rel="noreferrer">
            <div className="product-media">
              <img src={featuredGear.imageUrl} alt={featuredGear.name} />
              <span>{featuredGear.tag}</span>
            </div>
            <div className="product-copy">
              <p>{featuredGear.retailer}</p>
              <h3>{featuredGear.name}</h3>
              <span>{featuredGear.description}</span>
            </div>
            <div className="product-footer">
              <strong>{featuredGear.price}</strong>
              <span>
                View
                <Icon name="arrow-up-right" size={14} />
              </span>
            </div>
          </a>
          {secondaryGear.map((item) => (
            <a className="product-row" href={item.url} target="_blank" rel="noreferrer" key={item.name}>
              <img src={item.imageUrl} alt={item.name} />
              <div>
                <p>{item.tag}</p>
                <strong>{item.name}</strong>
                <span>{item.price} - {item.retailer}</span>
              </div>
            </a>
          ))}
        </div>
      </section>
    </aside>
  );
}

function CommentsView({ post, onBack, onLike, onComment }) {
  const [comment, setComment] = useState("");
  const replyRef = React.useRef(null);

  React.useEffect(() => { window.scrollTo(0, 0); }, []);

  function submitComment() {
    const text = comment.trim();
    if (!text) return;
    onComment(post.id, text);
    setComment("");
  }

  return (
    <div className="comments-view">
      <div className="comments-view-sticky">
        <div className="comments-view-header">
          <button className="icon-button" onClick={onBack} aria-label="Back to feed">
            <Icon name="arrow-left" size={18} />
          </button>
          <span className="comments-view-title">Comments</span>
        </div>
      </div>
      <div className="comments-reply-form-wrap">
        <div className="comment-form comments-reply-form">
          <Avatar user={people[4]} />
          <textarea ref={replyRef} value={comment} rows={1} onChange={(e) => { setComment(e.target.value); e.target.style.height = "auto"; e.target.style.height = e.target.scrollHeight + "px"; }} placeholder="Post your reply" onKeyDown={(e) => { if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); submitComment(); } }} />
          <button onClick={submitComment}>Reply</button>
        </div>
      </div>
      <PostCard post={post} isOpen={false} onOpen={() => replyRef.current?.focus()} onLike={onLike} onComment={onComment} />
      <div className="comments comments-standalone">
        {post.comments.map((item, index) => (
          <div className="comment-row" key={`${item.user.handle}-${index}`}>
            <Avatar user={item.user} />
            <div className="comment-body">
              <div className="comment-meta">
                <strong>{item.user.name}</strong>
                <span>{item.user.handle}</span>
                <span>{item.ago}</span>
              </div>
              <p>{item.text}</p>
              <div className="comment-actions">
                <button title="Reply"><Icon name="message-circle" size={14} /></button>
                <button title="Like"><Icon name="heart" size={14} /></button>
              </div>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

function FeedPage({ posts, setPosts, followed, toggleFollow }) {
  const [openPostId, setOpenPostId] = useState(null);

  function addPost(post) {
    setPosts([post, ...posts]);
  }

  function toggleLike(id) {
    setPosts(posts.map((post) => (
      post.id === id
        ? { ...post, liked: !post.liked, likes: post.liked ? post.likes - 1 : post.likes + 1 }
        : post
    )));
  }

  function addComment(id, text) {
    setPosts(posts.map((post) => (
      post.id === id
        ? { ...post, comments: [...post.comments, { user: commentAuthors.you, ago: "now", text }] }
        : post
    )));
  }

  const openPost = posts.find((p) => p.id === openPostId) || null;

  return (
    <main className="feed-layout page">
      <aside className="left-rail">
        <Composer onPost={addPost} />
        <PeoplePanel followed={followed} toggleFollow={toggleFollow} />
      </aside>
      <section className="feed-column" aria-label="Vinylfy feed">
        {openPost ? (
          <CommentsView
            post={openPost}
            onBack={() => setOpenPostId(null)}
            onLike={toggleLike}
            onComment={addComment}
          />
        ) : (
          posts.map((post) => (
            <PostCard
              key={post.id}
              post={post}
              isOpen={false}
              onOpen={(id) => setOpenPostId(id)}
              onLike={toggleLike}
              onComment={(id) => setOpenPostId(id)}
            />
          ))
        )}
      </section>
      <RightRail />
    </main>
  );
}

function AddRecordModal({ onClose }) {
  const [query, setQuery] = useState("");
  const [filter, setFilter] = useState("records");
  const inputRef = useRef(null);

  useEffect(() => { inputRef.current?.focus(); }, []);
  useEffect(() => {
    function onKey(e) { if (e.key === "Escape") onClose(); }
    document.addEventListener("keydown", onKey);
    return () => document.removeEventListener("keydown", onKey);
  }, [onClose]);

  const results = useMemo(() => {
    const needle = query.toLowerCase();
    if (!needle) return albums.slice(0, 8);
    return albums.filter((a) =>
      `${a.artist} ${a.title} ${a.label} ${a.genre}`.toLowerCase().includes(needle)
    );
  }, [query]);

  return (
    <div className="modal-overlay" onClick={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="modal-panel">
        <div className="modal-header">
          <h2>Add a record</h2>
          <button className="icon-button" onClick={onClose} aria-label="Close"><Icon name="x" /></button>
        </div>
        <label className="search-field">
          <Icon name="search" />
          <input ref={inputRef} value={query} onChange={(e) => setQuery(e.target.value)} placeholder="Search records, artists, labels..." />
        </label>
        <div className="segmented modal-segmented">
          {["records", "artists", "labels"].map((f) => (
            <button key={f} className={filter === f ? "active" : ""} onClick={() => setFilter(f)}>
              {f}
            </button>
          ))}
        </div>
        <div className="modal-results">
          {results.map((album) => (
            <div className="modal-result-row" key={album.id}>
              <AlbumArt album={album} compact />
              <div>
                <span className="modal-result-title">{album.title}</span>
                <span className="modal-result-sub">{album.artist} · {album.year}</span>
              </div>
              <button className="ghost-button" onClick={onClose}>Add</button>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

function LibraryPage({ title, items, actionLabel }) {
  const [view, setView] = useState("grid");
  const [searchOpen, setSearchOpen] = useState(false);
  const [query, setQuery] = useState("");
  const [modalOpen, setModalOpen] = useState(false);
  const searchInputRef = useRef(null);

  useEffect(() => {
    if (searchOpen) searchInputRef.current?.focus();
    else setQuery("");
  }, [searchOpen]);

  const filtered = query.trim()
    ? items.filter((a) => `${a.artist} ${a.title} ${a.genre} ${a.label}`.toLowerCase().includes(query.toLowerCase()))
    : items;

  return (
    <main className="library-page page">
      {modalOpen && <AddRecordModal onClose={() => setModalOpen(false)} />}
      <header className="page-heading">
        <h1 className="page-title">{title}</h1>
        <div className="page-heading-actions">
          <div className="page-heading-icons">
            {searchOpen ? (
              <label className="inline-search">
                <Icon name="search" size={15} />
                <input
                  ref={searchInputRef}
                  value={query}
                  onChange={(e) => setQuery(e.target.value)}
                  placeholder={`Search ${title.toLowerCase()}...`}
                />
                <button className="inline-search-close" onClick={() => setSearchOpen(false)} aria-label="Close search">
                  <Icon name="x" size={14} />
                </button>
              </label>
            ) : (
              <button
                className="icon-button"
                onClick={() => setSearchOpen(true)}
                title="Search"
              >
                <Icon name="search" size={16} />
              </button>
            )}
            <div className="view-divider" />
            <button
              className={`icon-button ${view === "grid" ? "active-view" : ""}`}
              onClick={() => setView("grid")}
              title="Grid view"
            >
              <Icon name="layout-grid" size={16} />
            </button>
            <button
              className={`icon-button ${view === "list" ? "active-view" : ""}`}
              onClick={() => setView("list")}
              title="List view"
            >
              <Icon name="list" size={16} />
            </button>
          </div>
          <button className="primary-button" onClick={() => setModalOpen(true)}>
            <Icon name="plus" />
            {actionLabel}
          </button>
        </div>
      </header>
      {view === "grid" ? (
        <section className="album-grid">
          {filtered.map((album) => (
            <article className="album-card panel" key={album.id}>
              <AlbumArt album={album} compact />
              <div>
                <h2>{album.title}</h2>
                <p>{album.artist}</p>
                <span>{album.year} · {album.format} · {album.genre}</span>
              </div>
              <button className="icon-button" title="More options">
                <Icon name="more-horizontal" />
              </button>
            </article>
          ))}
        </section>
      ) : (
        <section className="album-list">
          {filtered.map((album) => (
            <article className="album-list-row panel" key={album.id}>
              <AlbumArt album={album} compact />
              <div className="album-list-meta">
                <span className="album-list-title">{album.title}</span>
                <span className="album-list-artist">{album.artist}</span>
              </div>
              <span className="album-list-detail">{album.year}</span>
              <span className="album-list-detail">{album.format}</span>
              <span className="album-list-detail">{album.genre}</span>
              <span className="album-list-detail">{album.label}</span>
              <button className="icon-button" title="More options">
                <Icon name="more-horizontal" />
              </button>
            </article>
          ))}
        </section>
      )}
    </main>
  );
}

function ConditionBadge({ condition }) {
  const tier = condition === "Mint" ? "mint"
    : condition === "Near Mint" ? "new"
    : "used";
  const label = tier === "mint" ? "Mint" : tier === "new" ? "New" : "Used";
  return <span className={`condition-pill condition-${tier}`}>{label}</span>;
}

function ListingCard({ listing, onClick }) {
  return (
    <div className="listing-card" onClick={onClick}>
      <div className="listing-card-photo">
        <AlbumArt album={listing.album} />
      </div>
      <div className="listing-card-info">
        <div className="listing-card-title">{listing.album.title}</div>
        <div className="listing-card-artist">{listing.album.artist}</div>
        <div className="listing-card-price-row">
          <span className="listing-price-badge">${listing.price}</span>
          <ConditionBadge condition={listing.condition} />
        </div>
      </div>
    </div>
  );
}

function WishlistListingCard({ listing, onClick }) {
  return (
    <div className="wishlist-listing-card" onClick={onClick}>
      <div className="wishlist-listing-photo">
        <AlbumArt album={listing.album} />
      </div>
      <div className="wishlist-listing-info">
        <div>
          <div className="wishlist-listing-title">{listing.album.title}</div>
          <div className="wishlist-listing-artist">{listing.album.artist}</div>
        </div>
        <div className="wishlist-listing-price-row">
          <span className="wishlist-price">${listing.price}</span>
          <ConditionBadge condition={listing.condition} />
        </div>
      </div>
    </div>
  );
}

function RecentListingCard({ listing, onClick }) {
  return (
    <div className="recent-listing-card" onClick={onClick}>
      <div className="recent-listing-photo">
        <AlbumArt album={listing.album} />
      </div>
      <div className="recent-listing-left">
        <div className="recent-listing-title">{listing.album.title}</div>
        <div className="recent-listing-artist">{listing.album.artist}</div>
      </div>
      <div className="recent-listing-right">
        <ConditionBadge condition={listing.condition} />
        <span className="recent-listing-price">${listing.price}</span>
      </div>
    </div>
  );
}

function TrendingListingCard({ listing, onClick }) {
  return (
    <div className="trending-listing-card" onClick={onClick}>
      <div className="trending-listing-photo">
        <AlbumArt album={listing.album} />
        <div className="trending-rating-badge">
          <Icon name="star" size={11} />{listing.sellerRating}
        </div>
      </div>
      <div className="listing-card-info">
        <div className="listing-card-title">{listing.album.title}</div>
        <div className="listing-card-artist">{listing.album.artist}</div>
        <div className="listing-card-price-row">
          <span className="listing-price-badge">${listing.price}</span>
          <ConditionBadge condition={listing.condition} />
        </div>
      </div>
    </div>
  );
}

const SECTION_VARIANTS = { wishlist: "wishlist", recent: "recent", trending: "trending" };
const SECTION_MAX = { wishlist: 3, recent: 6, trending: 5, grid: 5 };

function SectionCards({ listings, variant, onOpenListing }) {
  if (variant === "wishlist") return (
    <div className="wishlist-listings-grid">
      {listings.map((l) => <WishlistListingCard key={l.id} listing={l} onClick={() => onOpenListing(l.id)} />)}
    </div>
  );
  if (variant === "recent") return (
    <div className="recent-listings-list">
      {listings.map((l) => <RecentListingCard key={l.id} listing={l} onClick={() => onOpenListing(l.id)} />)}
    </div>
  );
  if (variant === "trending") return (
    <div className="listings-grid">
      {listings.map((l) => <TrendingListingCard key={l.id} listing={l} onClick={() => onOpenListing(l.id)} />)}
    </div>
  );
  return (
    <div className="listings-grid">
      {listings.map((l) => <ListingCard key={l.id} listing={l} onClick={() => onOpenListing(l.id)} />)}
    </div>
  );
}

function SectionDetailView({ title, listings, variant, onBack, onOpenListing }) {
  React.useEffect(() => { window.scrollTo(0, 0); }, []);
  return (
    <div className="section-detail-view">
      <div className="listing-detail-header">
        <button className="icon-button" onClick={onBack}><Icon name="arrow-left" size={18} /></button>
        <span className="listing-detail-title">{title}</span>
      </div>
      <SectionCards listings={listings} variant={variant} onOpenListing={onOpenListing} />
    </div>
  );
}

function MarketplaceSection({ title, listings, onOpenListing, variant = "grid", onSeeAll }) {
  if (!listings || !listings.length) return null;
  const max = SECTION_MAX[variant] ?? 5;
  const shown = listings.slice(0, max);
  const hasMore = listings.length > max;
  return (
    <section className="marketplace-section">
      <div className="marketplace-section-header">
        <h2 className="marketplace-section-title">{title}</h2>
        {hasMore && (
          <button className="see-all-link" onClick={() => onSeeAll(title, listings, variant)}>
            See all <Icon name="chevron-right" size={13} />
          </button>
        )}
      </div>
      <SectionCards listings={shown} variant={variant} onOpenListing={onOpenListing} />
    </section>
  );
}

function MarketplaceHome({ listings, searchOpen, searchQuery, searchRef, setSearchOpen, setSearchQuery, onOpenListing, onCreateListing, onMyListings, onSeeAll }) {
  const wishlistIds = new Set(wishlistAlbums.map((a) => a.id));
  const wishlistGenres = new Set(wishlistAlbums.map((a) => a.genre));
  const collectionGenres = new Set(collectionAlbums.map((a) => a.genre));

  const wishlistListings = listings.filter((l) => wishlistIds.has(l.album.id) || wishlistGenres.has(l.album.genre));
  const recommendedListings = listings.filter((l) => collectionGenres.has(l.album.genre) && !wishlistIds.has(l.album.id));
  const nearYouListings = listings.filter((l) => l.localOnly || l.location.includes("NY") || l.location.includes("NJ"));

  function timeToMins(str) {
    if (!str) return 9999;
    if (str.includes("minute")) return parseInt(str) || 30;
    if (str.includes("hour")) return (parseInt(str) || 1) * 60;
    return (parseInt(str) || 1) * 1440;
  }
  const recentListings = [...listings].sort((a, b) => timeToMins(a.listedAt) - timeToMins(b.listedAt)).slice(0, 10);
  const trendingListings = [...listings].sort((a, b) => b.sellerRating - a.sellerRating).slice(0, 10);

  return (
    <>
      <header className="page-heading">
        <h1 className="page-title">Marketplace</h1>
        <div className="page-heading-actions">
          <div className="page-heading-icons">
            {searchOpen ? (
              <label className="inline-search">
                <Icon name="search" size={15} />
                <input ref={searchRef} value={searchQuery} onChange={(e) => setSearchQuery(e.target.value)} placeholder="Search listings..." />
                <button className="inline-search-close" onClick={() => setSearchOpen(false)} aria-label="Close search"><Icon name="x" size={14} /></button>
              </label>
            ) : (
              <button className="icon-button" onClick={() => setSearchOpen(true)} title="Search"><Icon name="search" size={16} /></button>
            )}
          </div>
          <button className="ghost-button" onClick={onMyListings}><Icon name="package" size={15} />My listings</button>
          <button className="primary-button" onClick={onCreateListing}><Icon name="plus" size={15} />Create listing</button>
        </div>
      </header>
      <MarketplaceSection title="From your wishlist" listings={wishlistListings} onOpenListing={onOpenListing} variant="wishlist" onSeeAll={onSeeAll} />
      <MarketplaceSection title="Recommended for you" listings={recommendedListings} onOpenListing={onOpenListing} onSeeAll={onSeeAll} />
      <MarketplaceSection title="Near you" listings={nearYouListings} onOpenListing={onOpenListing} onSeeAll={onSeeAll} />
      <MarketplaceSection title="Recent" listings={recentListings} onOpenListing={onOpenListing} variant="recent" onSeeAll={onSeeAll} />
      <MarketplaceSection title="Trending" listings={trendingListings} onOpenListing={onOpenListing} variant="trending" onSeeAll={onSeeAll} />
    </>
  );
}

function ListingDetailView({ listing, allListings, onBack, onBuy, onOpenListing }) {
  const moreBySeller = allListings.filter((l) => l.seller.handle === listing.seller.handle && l.id !== listing.id);
  return (
    <div className="listing-detail">
      <div className="listing-detail-header">
        <button className="icon-button" onClick={onBack} aria-label="Back"><Icon name="arrow-left" size={18} /></button>
        <span className="listing-detail-title">Listing</span>
      </div>

      <div className="listing-detail-photo">
        <AlbumArt album={listing.album} />
      </div>

      <div className="listing-detail-buy-row">
        <div>
          <span className="listing-detail-price">${listing.price}</span>
          {listing.shipping && <span className="listing-detail-shipping">+ ${listing.shippingCost} shipping</span>}
          {listing.localOnly && <span className="listing-detail-shipping">Local pickup only</span>}
        </div>
        <button className="primary-button listing-detail-buy-btn" onClick={onBuy}>Buy Now</button>
      </div>

      <div className="record-card listing-detail-album">
        <AlbumArt album={listing.album} />
        <div className="record-meta">
          <div>
            <p className="record-artist">{listing.album.artist}</p>
            <h3 className="record-title">{listing.album.title}</h3>
          </div>
          <div className="record-meta-details">
            <div className="record-specs">
              <span>{listing.album.format}</span>
              <span>{listing.album.year}</span>
              <span>{listing.album.genre}</span>
            </div>
          </div>
        </div>
      </div>

      <div className="listing-detail-section">
        <div className="listing-detail-label">Condition</div>
        <ConditionBadge condition={listing.condition} />
        {listing.description && <p className="listing-detail-description">{listing.description}</p>}
      </div>

      <div className="seller-card">
        <Avatar user={listing.seller} />
        <div className="seller-info">
          <div className="seller-name">{listing.seller.name}</div>
          <div className="seller-meta">
            <span className="seller-rating">⭐ {listing.sellerRating}</span>
            <span>·</span>
            <span>{listing.sellerSales} sales</span>
            <span>·</span>
            <span>{listing.location}</span>
          </div>
        </div>
      </div>

      {moreBySeller.length > 0 && (
        <MarketplaceSection title={`More from ${listing.seller.name.split(" ")[0]}`} listings={moreBySeller} onOpenListing={onOpenListing} />
      )}
    </div>
  );
}

function MyListingsView({ listings, onBack, onCreateListing }) {
  const myListings = listings.filter((l) => l.seller.handle === people[4].handle);
  return (
    <div className="my-listings-view">
      <div className="listing-detail-header">
        <button className="icon-button" onClick={onBack} aria-label="Back"><Icon name="arrow-left" size={18} /></button>
        <span className="listing-detail-title">My Listings</span>
      </div>
      {myListings.length === 0 ? (
        <div className="my-listings-empty">
          <Icon name="package" size={36} />
          <p>You haven't listed anything yet.</p>
          <button className="primary-button" onClick={onCreateListing}><Icon name="plus" size={15} />Create your first listing</button>
        </div>
      ) : (
        <div className="my-listings-list">
          {myListings.map((listing) => (
            <div className="my-listings-row" key={listing.id}>
              <div className="my-listings-art"><AlbumArt album={listing.album} compact /></div>
              <div className="my-listings-info">
                <div className="my-listings-title">{listing.album.title}</div>
                <div className="my-listings-meta">{listing.album.artist} · <ConditionBadge condition={listing.condition} /></div>
              </div>
              <div className="my-listings-price">${listing.price}</div>
              <button className="ghost-button my-listings-btn"><Icon name="pencil" size={14} /></button>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

function CheckoutModal({ listing, onClose }) {
  const [confirmed, setConfirmed] = useState(false);
  const [form, setForm] = useState({ name: "", address: "", city: "", zip: "", card: "", expiry: "", cvv: "" });
  function update(field, val) { setForm((prev) => ({ ...prev, [field]: val })); }
  const total = listing.price + (listing.shipping ? listing.shippingCost : 0);
  const canSubmit = form.name && form.address && form.city && form.zip && form.card.length >= 15 && form.expiry && form.cvv.length >= 3;

  useEffect(() => {
    function onKey(e) { if (e.key === "Escape") onClose(); }
    document.addEventListener("keydown", onKey);
    return () => document.removeEventListener("keydown", onKey);
  }, [onClose]);

  return (
    <div className="modal-overlay" onClick={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="modal-panel checkout-modal">
        <div className="modal-header">
          <h2>Checkout</h2>
          <button className="icon-button" onClick={onClose} aria-label="Close"><Icon name="x" /></button>
        </div>
        {confirmed ? (
          <div className="checkout-success">
            <div className="checkout-success-icon"><Icon name="check-circle" size={48} /></div>
            <h3>Order placed!</h3>
            <p>You'll hear from {listing.seller.name.split(" ")[0]} soon to arrange {listing.localOnly ? "pickup" : "delivery"}.</p>
            <button className="primary-button" onClick={onClose}>Done</button>
          </div>
        ) : (
          <>
            <div className="checkout-summary">
              <AlbumArt album={listing.album} compact />
              <div>
                <div className="checkout-summary-title">{listing.album.title}</div>
                <div className="checkout-summary-sub">{listing.album.artist} · <ConditionBadge condition={listing.condition} /></div>
                <div className="checkout-summary-price">${listing.price}{listing.shipping ? <span> + ${listing.shippingCost} shipping</span> : null}</div>
              </div>
            </div>
            <div className="checkout-divider" />
            <div className="checkout-section-label">Shipping address</div>
            <div className="checkout-form-group"><input placeholder="Full name" value={form.name} onChange={(e) => update("name", e.target.value)} /></div>
            <div className="checkout-form-group"><input placeholder="Street address" value={form.address} onChange={(e) => update("address", e.target.value)} /></div>
            <div className="checkout-form-row">
              <input placeholder="City" value={form.city} onChange={(e) => update("city", e.target.value)} />
              <input placeholder="ZIP" value={form.zip} onChange={(e) => update("zip", e.target.value)} style={{ maxWidth: "90px" }} />
            </div>
            <div className="checkout-divider" />
            <div className="checkout-section-label">Payment</div>
            <div className="checkout-form-group"><input placeholder="Card number" value={form.card} onChange={(e) => update("card", e.target.value.replace(/\D/g, "").slice(0, 16))} /></div>
            <div className="checkout-form-row">
              <input placeholder="MM / YY" value={form.expiry} onChange={(e) => update("expiry", e.target.value)} style={{ maxWidth: "110px" }} />
              <input placeholder="CVV" value={form.cvv} onChange={(e) => update("cvv", e.target.value.replace(/\D/g, "").slice(0, 4))} style={{ maxWidth: "80px" }} />
            </div>
            <div className="checkout-divider" />
            <div className="checkout-total"><span>Total</span><strong>${total.toFixed(2)}</strong></div>
            <button className="primary-button checkout-submit" disabled={!canSubmit} onClick={() => setConfirmed(true)}>
              Confirm purchase · ${total.toFixed(2)}
            </button>
          </>
        )}
      </div>
    </div>
  );
}

function CreateListingModal({ onClose, onSubmit }) {
  const [step, setStep] = useState(1);
  const [selectedAlbum, setSelectedAlbum] = useState(null);
  const [query, setQuery] = useState("");
  const [condition, setCondition] = useState("Very Good+");
  const [price, setPrice] = useState("");
  const [description, setDescription] = useState("");
  const [willShip, setWillShip] = useState(true);
  const [shippingCost, setShippingCost] = useState("6");
  const inputRef = useRef(null);

  useEffect(() => { if (step === 1) inputRef.current?.focus(); }, [step]);
  useEffect(() => {
    function onKey(e) { if (e.key === "Escape") onClose(); }
    document.addEventListener("keydown", onKey);
    return () => document.removeEventListener("keydown", onKey);
  }, [onClose]);

  const results = useMemo(() => {
    const needle = query.toLowerCase();
    if (!needle) return albums.slice(0, 6);
    return albums.filter((a) => `${a.artist} ${a.title}`.toLowerCase().includes(needle));
  }, [query]);

  const conditions = ["Mint", "Near Mint", "Very Good+", "Very Good", "Good", "Fair", "Poor"];

  function handleSubmit() {
    onSubmit({
      id: Date.now(),
      seller: people[4],
      album: selectedAlbum,
      condition,
      price: parseFloat(price) || 0,
      description,
      photos: [],
      shipping: willShip,
      shippingCost: willShip ? parseFloat(shippingCost) || 0 : 0,
      localOnly: !willShip,
      location: "New York, NY",
      listedAt: "just now",
      sellerRating: 4.5,
      sellerSales: 9,
    });
  }

  return (
    <div className="modal-overlay" onClick={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="modal-panel create-listing-modal">
        <div className="modal-header">
          <h2>{step === 1 ? "Select a record" : step === 2 ? "Listing details" : "Shipping & publish"}</h2>
          <button className="icon-button" onClick={onClose} aria-label="Close"><Icon name="x" /></button>
        </div>
        <div className="create-listing-steps">
          {[1, 2, 3].map((s) => <div key={s} className={`create-listing-step${s <= step ? " active" : ""}`}>{s}</div>)}
        </div>

        {step === 1 && (
          <>
            <label className="search-field">
              <Icon name="search" />
              <input ref={inputRef} value={query} onChange={(e) => setQuery(e.target.value)} placeholder="Search your records..." />
            </label>
            <div className="modal-results">
              {results.map((album) => (
                <div className={`modal-result-row${selectedAlbum?.id === album.id ? " selected" : ""}`} key={album.id} onClick={() => setSelectedAlbum(album)}>
                  <AlbumArt album={album} compact />
                  <div>
                    <span className="modal-result-title">{album.title}</span>
                    <span className="modal-result-sub">{album.artist} · {album.year}</span>
                  </div>
                  {selectedAlbum?.id === album.id && <Icon name="check" size={16} />}
                </div>
              ))}
            </div>
            <button className="primary-button create-listing-next" disabled={!selectedAlbum} onClick={() => setStep(2)}>Continue</button>
          </>
        )}

        {step === 2 && (
          <>
            <div className="photo-upload-area">
              <Icon name="camera" size={24} />
              <span>Add up to 6 photos</span>
              <span className="photo-upload-sub">Tap to upload from your device</span>
            </div>
            <div className="create-listing-field">
              <label>Condition</label>
              <div className="condition-picker">
                {conditions.map((c) => (
                  <button key={c} className={`condition-option${condition === c ? " active" : ""}`} onClick={() => setCondition(c)}>{c}</button>
                ))}
              </div>
            </div>
            <div className="create-listing-field">
              <label>Price</label>
              <div className="price-input-wrap">
                <span>$</span>
                <input type="number" min="0" step="0.01" value={price} onChange={(e) => setPrice(e.target.value)} placeholder="0.00" />
              </div>
            </div>
            <div className="create-listing-field">
              <label>Description</label>
              <textarea value={description} onChange={(e) => setDescription(e.target.value)} placeholder="Describe the condition, pressing details, anything the buyer should know..." rows={3} />
            </div>
            <div className="create-listing-actions">
              <button className="ghost-button" onClick={() => setStep(1)}>Back</button>
              <button className="primary-button" disabled={!price} onClick={() => setStep(3)}>Continue</button>
            </div>
          </>
        )}

        {step === 3 && (
          <>
            <div className="create-listing-field">
              <label>Shipping</label>
              <div className="segmented segmented-2col">
                <button className={willShip ? "active" : ""} onClick={() => setWillShip(true)}>Will ship</button>
                <button className={!willShip ? "active" : ""} onClick={() => setWillShip(false)}>Local only</button>
              </div>
            </div>
            {willShip && (
              <div className="create-listing-field">
                <label>Shipping cost</label>
                <div className="price-input-wrap">
                  <span>$</span>
                  <input type="number" min="0" step="0.01" value={shippingCost} onChange={(e) => setShippingCost(e.target.value)} />
                </div>
              </div>
            )}
            <div className="create-listing-field">
              <label>Your location</label>
              <input className="create-listing-location-input" value="New York, NY" readOnly />
            </div>
            {selectedAlbum && (
              <div className="create-listing-summary">
                <AlbumArt album={selectedAlbum} compact />
                <div>
                  <div className="modal-result-title">{selectedAlbum.title}</div>
                  <div className="modal-result-sub">{condition} · ${price}{willShip ? ` + $${shippingCost} shipping` : " · Local only"}</div>
                </div>
              </div>
            )}
            <div className="create-listing-actions">
              <button className="ghost-button" onClick={() => setStep(2)}>Back</button>
              <button className="primary-button" disabled={!price || !selectedAlbum} onClick={handleSubmit}>Post listing</button>
            </div>
          </>
        )}
      </div>
    </div>
  );
}

function MarketplacePage() {
  const [view, setView] = useState("home");
  const [openListingId, setOpenListingId] = useState(null);
  const [searchOpen, setSearchOpen] = useState(false);
  const [searchQuery, setSearchQuery] = useState("");
  const [checkoutListingId, setCheckoutListingId] = useState(null);
  const [createOpen, setCreateOpen] = useState(false);
  const [listings, setListings] = useState(initialListings);
  const [sectionView, setSectionView] = useState(null);
  const searchRef = useRef(null);

  useEffect(() => {
    if (searchOpen) searchRef.current?.focus();
    else setSearchQuery("");
  }, [searchOpen]);

  const openListing = listings.find((l) => l.id === openListingId);
  const checkoutListing = listings.find((l) => l.id === checkoutListingId);

  const filteredListings = useMemo(() => {
    const q = searchQuery.trim().toLowerCase();
    if (!q) return listings;
    return listings.filter((l) => `${l.album.title} ${l.album.artist} ${l.album.genre} ${l.album.label}`.toLowerCase().includes(q));
  }, [listings, searchQuery]);

  function goToDetail(id) { setOpenListingId(id); setView("detail"); setSectionView(null); window.scrollTo(0, 0); }
  function goHome() { setView("home"); setOpenListingId(null); setSectionView(null); }
  function goToSection(title, sectionListings, variant) { setSectionView({ title, listings: sectionListings, variant }); window.scrollTo(0, 0); }

  return (
    <main className="marketplace-page page">
      {createOpen && (
        <CreateListingModal
          onClose={() => setCreateOpen(false)}
          onSubmit={(listing) => { setListings((prev) => [listing, ...prev]); setCreateOpen(false); }}
        />
      )}
      {checkoutListing && <CheckoutModal listing={checkoutListing} onClose={() => setCheckoutListingId(null)} />}

      {view === "home" && !sectionView && (
        <MarketplaceHome
          listings={filteredListings}
          searchOpen={searchOpen}
          searchQuery={searchQuery}
          searchRef={searchRef}
          setSearchOpen={setSearchOpen}
          setSearchQuery={setSearchQuery}
          onOpenListing={goToDetail}
          onCreateListing={() => setCreateOpen(true)}
          onMyListings={() => setView("my-listings")}
          onSeeAll={goToSection}
        />
      )}
      {view === "home" && sectionView && (
        <SectionDetailView
          title={sectionView.title}
          listings={sectionView.listings}
          variant={sectionView.variant}
          onBack={goHome}
          onOpenListing={goToDetail}
        />
      )}
      {view === "detail" && openListing && (
        <ListingDetailView
          listing={openListing}
          allListings={listings}
          onBack={goHome}
          onBuy={() => setCheckoutListingId(openListing.id)}
          onOpenListing={goToDetail}
        />
      )}
      {view === "my-listings" && (
        <MyListingsView
          listings={listings}
          onBack={goHome}
          onCreateListing={() => setCreateOpen(true)}
        />
      )}
    </main>
  );
}

function App() {
  const [page, setPage] = useState("home");
  const [theme, setTheme] = useState(() =>
    window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"
  );
  const [posts, setPosts] = useState(initialPosts);
  const [followed, setFollowed] = useState(["@jieunpark"]);

  useEffect(() => {
    document.documentElement.dataset.theme = theme;
    if (window.lucide) window.lucide.createIcons();
  }, [theme, page, posts]);

  function toggleFollow(handle) {
    setFollowed((current) =>
      current.includes(handle) ? current.filter((item) => item !== handle) : [...current, handle]
    );
  }

  return (
    <>
      <TopBar page={page} setPage={setPage} theme={theme} setTheme={setTheme} />
      {page === "home" && <FeedPage posts={posts} setPosts={setPosts} followed={followed} toggleFollow={toggleFollow} />}
      {page === "collection" && (
        <LibraryPage title="Collection" items={collectionAlbums} actionLabel="Add record" />
      )}
      {page === "wishlist" && (
        <LibraryPage title="Wishlist" items={wishlistAlbums} actionLabel="Add want" />
      )}
      {page === "marketplace" && <MarketplacePage />}
    </>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
