// Guestmaker · Bookings management showcase — sits below the data-layer cards.
// Shows the bulk booking list across all guests, plus an animated reservation
// detail drawer with stay details, guests and the full financial breakdown
// (room revenue + folio extras grouped by outlet).
// All data is seeded. Hotel brand: AURELIA (fictional). No real guest names.

const { useState: bUseState, useMemo: bUseMemo, useEffect: bUseEffect } = React;

// ────────────────────────── tokens (match hero) ──────────────────────────
const B_FUCHSIA      = "#ED4D86";
const B_FUCHSIA_DEEP = "#C93A6B";
const B_FUCHSIA_DARK = "#8E2148";
const B_FUCHSIA_SOFT = "#F8B7CF";
const B_FUCHSIA_PALE = "#FCE4EE";
const B_FUCHSIA_WASH = "#FDF0F5";
const B_PLUM         = "#211A22";
const B_PLUM_DEEP    = "#160F17";

const B_INK     = "#1a1a1a";
const B_DIM     = "#6e6363";
const B_FAINT   = "#a99fa3";
const B_RULE    = "#e9e3d4";
const B_RULE_S  = "#f0ebde";
const B_PAPER   = "#fbfaf6";
const B_CREAM   = "#f6f4ef";
const B_MONO    = "'JetBrains Mono', ui-monospace, monospace";
const B_SERIF   = "var(--f-display)";

// Status palette — same fuchsia family
const B_OK     = B_FUCHSIA;        // confirmed
const B_PAST   = B_FUCHSIA_DARK;   // checked-out / past
const B_NOW    = B_FUCHSIA_DEEP;   // in-house
const B_HOLD   = B_PLUM;           // modified
const B_OFF    = B_PLUM_DEEP;      // cancelled / no-show

const B_STATUS_TONE = {
  Confirmed:  { fg: B_OK,   bg: B_FUCHSIA_WASH, border: B_OK   + "55" },
  Modified:   { fg: B_HOLD, bg: "#EBD9E2",      border: B_HOLD + "55" },
  CheckedIn:  { fg: B_NOW,  bg: "#FBDFEA",      border: B_NOW  + "55" },
  CheckedOut: { fg: B_PAST, bg: "#F4DCE6",      border: B_PAST + "55" },
  Cancelled:  { fg: B_OFF,  bg: "#EDD9E2",      border: B_OFF  + "55" },
  NoShow:     { fg: B_OFF,  bg: "#EDD9E2",      border: B_OFF  + "55" },
};
const B_STATUS_LABEL = {
  Confirmed: "Confirmed", Modified: "Modified",
  CheckedIn: "Checked In", CheckedOut: "Checked Out",
  Cancelled: "Cancelled", NoShow: "No Show",
};

// ────────────────────────── icons ──────────────────────────
function BIcon({ name, size = 14, color, strokeWidth = 1.8, style }) {
  const stroke = color || "currentColor";
  const p = {
    width: size, height: size, viewBox: "0 0 24 24", fill: "none",
    stroke, strokeWidth, strokeLinecap: "round", strokeLinejoin: "round",
    style: { display: "block", flexShrink: 0, ...style },
  };
  switch (name) {
    case "search":      return <svg {...p}><circle cx="11" cy="11" r="7"/><path d="M21 21l-4.3-4.3"/></svg>;
    case "calendar":    return <svg {...p}><rect x="3" y="5" width="18" height="16" rx="2"/><path d="M16 3v4M8 3v4M3 11h18"/></svg>;
    case "building":    return <svg {...p}><rect x="4" y="3" width="16" height="18" rx="1.5"/><path d="M8 7h3M8 11h3M8 15h3M13 7h3M13 11h3M13 15h3M9 21v-3h6v3"/></svg>;
    case "chevron":     return <svg {...p}><polyline points="6,9 12,15 18,9"/></svg>;
    case "close":       return <svg {...p}><line x1="6" y1="6" x2="18" y2="18"/><line x1="6" y1="18" x2="18" y2="6"/></svg>;
    case "bed":         return <svg {...p}><path d="M2 20v-7a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v7"/><path d="M2 17h20M6 11V7a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v4"/><circle cx="8" cy="9" r="1.2"/></svg>;
    case "users":       return <svg {...p}><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.9M16 3.1a4 4 0 0 1 0 7.8"/></svg>;
    case "user":        return <svg {...p}><circle cx="12" cy="8" r="4"/><path d="M4 21a8 8 0 0 1 16 0"/></svg>;
    case "external":    return <svg {...p}><path d="M14 3h7v7M10 14 21 3M19 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V7a2 2 0 0 1 2-2h6"/></svg>;
    case "wallet":      return <svg {...p}><path d="M2 7a2 2 0 0 1 2-2h15a1 1 0 0 1 1 1v3"/><path d="M2 7v11a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-8H4a2 2 0 0 1-2-2z"/><circle cx="18" cy="14" r="1.2" fill={stroke}/></svg>;
    case "filter":      return <svg {...p}><polygon points="3,4 21,4 14,12 14,20 10,18 10,12"/></svg>;
    case "refresh":     return <svg {...p}><path d="M23 4v6h-6M1 20v-6h6"/><path d="M3.5 9a9 9 0 0 1 14.9-3.4L23 10M20.5 15a9 9 0 0 1-14.9 3.4L1 14"/></svg>;
    case "download":    return <svg {...p}><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7,10 12,15 17,10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>;
    case "more":        return <svg {...p}><circle cx="5"  cy="12" r="1.5" fill={stroke}/><circle cx="12" cy="12" r="1.5" fill={stroke}/><circle cx="19" cy="12" r="1.5" fill={stroke}/></svg>;
    case "tag":         return <svg {...p}><path d="M20 12 12 20 3 11V3h8z"/><circle cx="7.5" cy="7.5" r="1.2"/></svg>;
    case "edit":        return <svg {...p}><path d="M12 20h9M16.5 3.5a2.1 2.1 0 1 1 3 3L7 19l-4 1 1-4z"/></svg>;
    case "compass":     return <svg {...p}><circle cx="12" cy="12" r="10"/><polygon points="16.2,7.8 13.4,13.4 7.8,16.2 10.6,10.6"/></svg>;
    case "send":        return <svg {...p}><path d="M22 2 11 13M22 2l-7 20-4-9-9-4z"/></svg>;
    case "spark":       return <svg {...p}><path d="M12 3v3M12 18v3M3 12h3M18 12h3M5.6 5.6l2.1 2.1M16.3 16.3l2.1 2.1M5.6 18.4l2.1-2.1M16.3 7.7l2.1-2.1"/><circle cx="12" cy="12" r="3"/></svg>;
    case "brain":       return <svg {...p}><path d="M9.5 2A2.5 2.5 0 0 1 12 4.5v15a2.5 2.5 0 0 1-4.96.44 2.5 2.5 0 0 1-2.96-3.08 3 3 0 0 1-.34-5.58 2.5 2.5 0 0 1 1.32-4.24 2.5 2.5 0 0 1 1.98-3A2.5 2.5 0 0 1 9.5 2z"/><path d="M14.5 2A2.5 2.5 0 0 0 12 4.5v15a2.5 2.5 0 0 0 4.96.44 2.5 2.5 0 0 0 2.96-3.08 3 3 0 0 0 .34-5.58 2.5 2.5 0 0 0-1.32-4.24 2.5 2.5 0 0 0-1.98-3A2.5 2.5 0 0 0 14.5 2z"/></svg>;
    case "gift":        return <svg {...p}><rect x="3" y="8" width="18" height="4"/><path d="M5 12v10h14V12M12 22V8M12 8H7.5a2.5 2.5 0 0 1 0-5C11 3 12 8 12 8zM12 8h4.5a2.5 2.5 0 0 0 0-5C13 3 12 8 12 8z"/></svg>;
    case "trending":    return <svg {...p}><polyline points="3,17 9,11 13,15 21,7"/><polyline points="15,7 21,7 21,13"/></svg>;
    case "phone":       return <svg {...p}><path d="M22 16.9v3a2 2 0 0 1-2.2 2 19.8 19.8 0 0 1-8.6-3.1 19.5 19.5 0 0 1-6-6 19.8 19.8 0 0 1-3.1-8.7A2 2 0 0 1 4.1 2h3a2 2 0 0 1 2 1.7c.1 1 .3 1.9.6 2.8a2 2 0 0 1-.5 2.1L8 9.9a16 16 0 0 0 6 6l1.3-1.3a2 2 0 0 1 2.1-.4c.9.3 1.8.5 2.8.6a2 2 0 0 1 1.8 2z"/></svg>;
    case "mail":        return <svg {...p}><rect x="3" y="5" width="18" height="14" rx="2"/><path d="M3 7l9 6 9-6"/></svg>;
    case "pin":         return <svg {...p}><path d="M21 10c0 7-9 13-9 13S3 17 3 10a9 9 0 1 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg>;
    case "wine":        return <svg {...p}><path d="M8 2h8M9 2v3a3 3 0 0 0 6 0V2M12 14v8M8 22h8M12 14a4 4 0 0 1-4-4V5h8v5a4 4 0 0 1-4 4z"/></svg>;
    case "car":         return <svg {...p}><path d="M5 17h14M5 17l-2-7h18l-2 7M7 17v3M17 17v3"/><circle cx="7.5" cy="14.5" r="1.2" fill={stroke}/><circle cx="16.5" cy="14.5" r="1.2" fill={stroke}/></svg>;
    case "spa":         return <svg {...p}><path d="M12 22V8M12 8C8 8 5 11 5 15h7M12 8c4 0 7 3 7 7h-7M12 2v6"/></svg>;
    case "key":         return <svg {...p}><circle cx="7" cy="14" r="4"/><path d="M11 14h10M19 14v3M16 14v3"/></svg>;
    case "log":         return <svg {...p}><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14,2 14,8 20,8"/><path d="M8 13h8M8 17h5"/></svg>;
    case "check":       return <svg {...p}><polyline points="4,12 10,18 20,6"/></svg>;
    default: return null;
  }
}

// ────────────────────────── seed: properties ──────────────────────────
const B_HOTELS = [
  { id: "CMA", name: "AURELIA Cala Marina",   loc: "Palmanova · Mallorca",     prefix: "ACM", code: "MAR" },
  { id: "CBR", name: "AURELIA Costa Brava",   loc: "Tossa de Mar · Catalunya", prefix: "ACB", code: "CBR" },
  { id: "PRJ", name: "AURELIA Playa Roja",    loc: "Costa Teguise · Lanzarote",prefix: "APR", code: "LZR" },
  { id: "BVD", name: "AURELIA Bahía Verde",   loc: "Adeje · Tenerife",         prefix: "ABV", code: "TFS" },
  { id: "PAZ", name: "AURELIA Punta Azul",    loc: "Corralejo · Fuerteventura",prefix: "APZ", code: "FUE" },
];
const B_HOTEL_BY_ID = Object.fromEntries(B_HOTELS.map(h => [h.id, h]));

// ────────────────────────── seed: bookings ──────────────────────────
// Confirmation # = 9-char alphanumeric like the product screenshots.
const B_ROOMS = ["Standard Doble", "Doble Vista Mar", "Doble Vista Piscina", "Junior Suite", "Suite Vista Mar", "Family Suite", "Doble Standard"];
const B_BOARDS = ["RO", "BB", "HB", "FB", "AI"];
const B_BOARD_LABEL = { RO: "Room Only", BB: "Bed & Breakfast", HB: "Half Board", FB: "Full Board", AI: "All-Inclusive" };
const B_RATES = ["NRF", "FLEX", "ADV", "PROMO", "CORP"];
const B_SOURCES = [
  { id: "direct",     label: "Direct · Web",        tone: "fuchsia" },
  { id: "roiback",    label: "Roiback",             tone: "fuchsia" },
  { id: "bookingcom", label: "Booking.com",         tone: "plum" },
  { id: "expedia",    label: "Expedia",             tone: "plum" },
  { id: "hotels",     label: "Hotels.com",          tone: "plum" },
  { id: "agoda",      label: "Agoda",               tone: "plum" },
  { id: "hotelbeds",  label: "Hotelbeds",           tone: "fuchsiaDeep" },
  { id: "tui",        label: "TUI",                 tone: "plumDeep" },
  { id: "fti",        label: "FTI Group",           tone: "plumDeep" },
  { id: "jet2",       label: "Jet2holidays",        tone: "plumDeep" },
  { id: "voice",      label: "Voice · Call Centre", tone: "fuchsiaDeep" },
  { id: "agency",     label: "Travel Agency",       tone: "plum" },
];
const B_SOURCE_BY_ID = Object.fromEntries(B_SOURCES.map(s => [s.id, s]));
const B_SOURCE_TONE = {
  fuchsia:     { fg: B_FUCHSIA,      bg: B_FUCHSIA_WASH, border: B_FUCHSIA + "44" },
  fuchsiaDeep: { fg: B_FUCHSIA_DEEP, bg: B_FUCHSIA_WASH, border: B_FUCHSIA_DEEP + "44" },
  plum:        { fg: B_PLUM,         bg: B_FUCHSIA_PALE, border: B_PLUM + "44" },
  plumDeep:    { fg: B_PLUM_DEEP,    bg: "#EDD9E2",      border: B_PLUM_DEEP + "44" },
};

const B_GUESTS = [
  { fn: "Tomás",    ln: "Reyes",        email: "tomas.reyes@hivemail.co",      ph: "+34 612 884 102", country: "ES" },
  { fn: "Anna",     ln: "Lindgren",     email: "anna.l@duckpost.io",            ph: "+46 70 412 8855", country: "SE" },
  { fn: "Mathias",  ln: "Brun",         email: "mathias.brun@swissnet.ch",      ph: "+41 78 332 4901", country: "CH" },
  { fn: "Sofia",    ln: "Marchetti",    email: "sofia.marchetti@aribamail.it",  ph: "+39 348 772 1183",country: "IT" },
  { fn: "Niall",    ln: "O'Donnell",    email: "niall.odonnell@oneirepost.ie",  ph: "+353 86 220 9847",country: "IE" },
  { fn: "Hiroko",   ln: "Tanaka",       email: "hiroko.tanaka@kireimail.jp",    ph: "+81 90 4118 2207",country: "JP" },
  { fn: "Pieter",   ln: "de Vries",     email: "p.devries@tulipmail.nl",        ph: "+31 6 2235 6671", country: "NL" },
  { fn: "Camille",  ln: "Dubois",       email: "camille.dubois@brisemail.fr",   ph: "+33 6 7702 1144", country: "FR" },
  { fn: "Marek",    ln: "Klein",        email: "marek.klein@blattmail.de",      ph: "+49 162 558 7720",country: "DE" },
  { fn: "Lucía",    ln: "Rivero",       email: "lucia.rivero@vientomail.ar",    ph: "+54 11 6622 3340",country: "AR" },
  { fn: "Karim",    ln: "El Amrani",    email: "karim.elamrani@atlas-post.ma",  ph: "+212 661 220 887",country: "MA" },
  { fn: "Eleni",    ln: "Papadakis",    email: "eleni.papadakis@elysianpost.gr",ph: "+30 694 552 1108",country: "GR" },
  { fn: "Ana",      ln: "Pop",          email: "ana.pop@carpathmail.ro",        ph: "+40 723 884 991", country: "RO" },
  { fn: "Andrei",   ln: "Petrov",       email: "andrei.petrov@rosemail.bg",     ph: "+359 88 776 4421",country: "BG" },
  { fn: "Lien",     ln: "Nakamura",     email: "lien.nakamura@kireimail.jp",    ph: "+81 80 7763 2206",country: "JP" },
  { fn: "Brian",    ln: "O'Hara",       email: "brian.ohara@northport.us",      ph: "+1 415 220 7785", country: "US" },
  { fn: "Karoline", ln: "Berg",         email: "karoline.berg@nordpost.no",     ph: "+47 41 332 9907", country: "NO" },
  { fn: "Pavel",    ln: "Hrubý",        email: "pavel.hruby@vltavamail.cz",     ph: "+420 776 332 110",country: "CZ" },
  { fn: "Tessa",    ln: "Brandt",       email: "tessa.brandt@tulipmail.nl",     ph: "+31 6 4451 2208", country: "NL" },
  { fn: "Otto",     ln: "Mehrtens",     email: "otto.mehrtens@blattmail.de",    ph: "+49 174 220 9911",country: "DE" },
  { fn: "Hanna",    ln: "Korhonen",     email: "hanna.korhonen@laakemail.fi",   ph: "+358 40 552 7783",country: "FI" },
  { fn: "Diego",    ln: "Solano",       email: "diego.solano@solpost.mx",       ph: "+52 55 4422 1108",country: "MX" },
  { fn: "Ingrid",   ln: "Sætre",        email: "ingrid.satre@nordpost.no",      ph: "+47 47 220 8841", country: "NO" },
  { fn: "Vinicius", ln: "Almeida",      email: "vinicius.a@brisapost.br",       ph: "+55 11 99887 4421",country: "BR" },
  { fn: "Krisztián",ln: "Győri",        email: "k.gyori@magyarmail.hu",         ph: "+36 30 887 2210", country: "HU" },
  { fn: "Sigrún",   ln: "Magnúsdóttir", email: "sigrun.m@northmail.is",         ph: "+354 690 4421",   country: "IS" },
];

// 25 seed bookings — diverse statuses, hotels, sources, dates
const B_BOOKINGS = [
  { conf: "k4t9bx2qm", gIdx: 0,  hotel: "CMA", ci: "May 22, 2026", co: "May 25, 2026", nts: 3, room: 0, bd: "HB", rt: "FLEX",  src: "direct",    amt: 578.23, status: "Confirmed" },
  { conf: "n4pt1f3m0", gIdx: 1,  hotel: "PRJ", ci: "Jun 19, 2026", co: "Jun 20, 2026", nts: 1, room: 6, bd: "BB", rt: "NRF",   src: "bookingcom",       amt: 149.87, status: "Confirmed" },
  { conf: "e80nqmgng", gIdx: 2,  hotel: "CMA", ci: "May 21, 2026", co: "May 25, 2026", nts: 4, room: 1, bd: "HB", rt: "FLEX",  src: "roiback",    amt: 855.37, status: "Confirmed" },
  { conf: "w8ktra5h5", gIdx: 3,  hotel: "CMA", ci: "May 23, 2026", co: "May 28, 2026", nts: 5, room: 4, bd: "HB", rt: "ADV",   src: "roiback",    amt: 1075.72,status: "Confirmed" },
  { conf: "28qr7m98j", gIdx: 4,  hotel: "BVD", ci: "May 22, 2026", co: "May 25, 2026", nts: 3, room: 1, bd: "AI", rt: "FLEX",  src: "roiback",    amt: 723.83, status: "Confirmed" },
  { conf: "rn0xrajb2", gIdx: 5,  hotel: "BVD", ci: "Aug 5, 2026",  co: "Aug 11, 2026", nts: 6, room: 0, bd: "HB", rt: "PROMO", src: "hotelbeds", amt: 1652.47,status: "Confirmed" },
  { conf: "gcewt2tnj", gIdx: 6,  hotel: "CBR", ci: "Jul 15, 2026", co: "Jul 17, 2026", nts: 2, room: 0, bd: "BB", rt: "NRF",   src: "direct",    amt: 428.23, status: "CheckedOut" },
  { conf: "291cy47dr", gIdx: 7,  hotel: "PRJ", ci: "Jun 9, 2026",  co: "Jun 12, 2026", nts: 3, room: 2, bd: "HB", rt: "FLEX",  src: "roiback",    amt: 539.20, status: "CheckedOut" },
  { conf: "96fess8xh", gIdx: 8,  hotel: "CMA", ci: "Jul 25, 2026", co: "Jul 31, 2026", nts: 6, room: 2, bd: "AI", rt: "ADV",   src: "roiback",    amt: 1166.67,status: "Confirmed" },
  { conf: "f08pa33xw", gIdx: 9,  hotel: "PRJ", ci: "Jun 26, 2026", co: "Jun 28, 2026", nts: 2, room: 3, bd: "BB", rt: "FLEX",  src: "voice",     amt: 332.65, status: "Confirmed" },
  { conf: "anuapcbx7", gIdx: 10, hotel: "CMA", ci: "Jun 26, 2026", co: "Jun 29, 2026", nts: 3, room: 4, bd: "HB", rt: "FLEX",  src: "agency",    amt: 1227.67,status: "Confirmed" },
  { conf: "78m6p5ywh", gIdx: 11, hotel: "CMA", ci: "Jun 15, 2026", co: "Jun 19, 2026", nts: 4, room: 4, bd: "HB", rt: "ADV",   src: "roiback",    amt: 851.54, status: "Modified" },
  { conf: "e1eracr2g", gIdx: 12, hotel: "PRJ", ci: "Jun 26, 2026", co: "Jun 27, 2026", nts: 1, room: 2, bd: "BB", rt: "NRF",   src: "expedia",       amt: 158.84, status: "Confirmed" },
  { conf: "0e6f24pmw", gIdx: 13, hotel: "CMA", ci: "Jul 29, 2026", co: "Jul 31, 2026", nts: 2, room: 0, bd: "BB", rt: "NRF",   src: "agoda",       amt: 429.24, status: "Confirmed" },
  { conf: "p74szd95u", gIdx: 14, hotel: "BVD", ci: "May 23, 2026", co: "May 25, 2026", nts: 2, room: 4, bd: "AI", rt: "FLEX",  src: "roiback",    amt: 624.97, status: "CheckedIn" },
  { conf: "5ncc09xq2", gIdx: 15, hotel: "BVD", ci: "May 21, 2026", co: "May 25, 2026", nts: 4, room: 4, bd: "AI", rt: "ADV",   src: "roiback",    amt: 1377.92,status: "CheckedIn" },
  { conf: "36mmjb89c", gIdx: 16, hotel: "PRJ", ci: "Aug 6, 2026",  co: "Aug 11, 2026", nts: 5, room: 1, bd: "BB", rt: "FLEX",  src: "roiback",    amt: 1210.30,status: "Confirmed" },
  { conf: "3qawa72ew", gIdx: 17, hotel: "PAZ", ci: "May 29, 2026", co: "Jun 2, 2026",  nts: 4, room: 6, bd: "RO", rt: "NRF",   src: "hotels",       amt: 432.52, status: "Confirmed" },
  { conf: "a0um195em", gIdx: 18, hotel: "PAZ", ci: "Jul 31, 2026", co: "Aug 3, 2026",  nts: 3, room: 0, bd: "BB", rt: "FLEX",  src: "roiback",    amt: 613.47, status: "Confirmed" },
  { conf: "7adyzmwnw", gIdx: 19, hotel: "CBR", ci: "May 22, 2026", co: "May 25, 2026", nts: 3, room: 0, bd: "BB", rt: "NRF",   src: "agency",    amt: 414.41, status: "Confirmed" },
  { conf: "657c3gc9q", gIdx: 20, hotel: "PRJ", ci: "Jun 29, 2026", co: "Jul 2, 2026",  nts: 3, room: 0, bd: "HB", rt: "FLEX",  src: "roiback",    amt: 539.84, status: "Cancelled" },
  { conf: "8g72537rn", gIdx: 21, hotel: "BVD", ci: "May 19, 2026", co: "May 23, 2026", nts: 4, room: 0, bd: "AI", rt: "ADV",   src: "tui",      amt: 944.81, status: "CheckedIn" },
  { conf: "494a81q9f", gIdx: 22, hotel: "PRJ", ci: "Jul 2, 2026",  co: "Jul 8, 2026",  nts: 6, room: 2, bd: "HB", rt: "FLEX",  src: "bookingcom",       amt: 1306.41,status: "Cancelled" },
  { conf: "gcj7xxt67", gIdx: 23, hotel: "BVD", ci: "Aug 5, 2026",  co: "Aug 11, 2026", nts: 6, room: 0, bd: "BB", rt: "PROMO", src: "fti", amt: 1252.47,status: "NoShow" },
  { conf: "z4nm2x91p", gIdx: 24, hotel: "CMA", ci: "Apr 12, 2026", co: "Apr 19, 2026", nts: 7, room: 5, bd: "HB", rt: "FLEX",  src: "direct",    amt: 2486.10,status: "CheckedOut" },
];

// ────────────────────────── seed: detailed extras (used in drawer) ──────────────────────────
// Per-booking detail seed. Keyed by conf.
const B_DETAILS = {
  k4t9bx2qm: {
    roomNo: "412", channel: "Roiback",
    companions: [{ fn: "Sara",   ln: "Reyes", type: "Adult" }],
    extras: [
      { group: "Bar Salón",   icon: "wine", items: [
        { lbl: "Local wine pairing",       v: 42.60 },
        { lbl: "Aperitivo (x2)",           v: 21.60 },
        { lbl: "Tapas selection",          v: 45.20 },
        { lbl: "Coffee + dessert",         v: 9.80  },
      ]},
      { group: "Bar Piscina", icon: "spa", items: [
        { lbl: "Cocktail flight",          v: 38.50 },
        { lbl: "Smoothie + snacks",        v: 22.10 },
        { lbl: "Beach service x2",         v: 18.00 },
      ]},
      { group: "Parking",     icon: "car", items: [
        { lbl: "Covered parking x3",       v: 36.00 },
      ]},
    ],
  },
  z4nm2x91p: {
    roomNo: "1507", channel: "Roiback",
    companions: [{ fn: "Marta",  ln: "Reyes", type: "Adult" }],
    extras: [
      { group: "Bar Salón",  icon: "wine", items: [
        { lbl: "Wine pairing",        v: 89.40 },
        { lbl: "Aperitivo round",     v: 22.60 },
        { lbl: "Cheese board",        v: 21.60 },
        { lbl: "Coffee + petit fours",v: 45.20 },
      ]},
      { group: "Bar Piscina",icon: "spa", items: [
        { lbl: "Cocktails x6",        v: 97.80 },
        { lbl: "Beach service",       v: 32.50 },
      ]},
      { group: "Parking",    icon: "car", items: [
        { lbl: "Parking x7 days",     v: 686.00 },
      ]},
      { group: "Spa",        icon: "spa", items: [
        { lbl: "Aphrodite ritual",    v: 220.00 },
        { lbl: "Couples massage",     v: 180.00 },
      ]},
    ],
  },
  e80nqmgng: {
    roomNo: "204", channel: "GuestMaker Direct",
    companions: [{ fn: "Lukas", ln: "Brun", type: "Adult" }, { fn: "Mia", ln: "Brun", type: "Child" }],
    extras: [
      { group: "F&B",      icon: "wine", items: [
        { lbl: "À la carte dinner",  v: 142.00 },
        { lbl: "Wine pairing",       v: 64.00 },
        { lbl: "Kids menu x4",       v: 38.00 },
      ]},
      { group: "Excursions", icon: "compass", items: [
        { lbl: "Catamaran tour",     v: 220.00 },
      ]},
    ],
  },
  // generic fallback for everyone else gets generated below
};

// Build a fallback detail for any booking that doesn't have a specific one
function getDetail(bk) {
  if (B_DETAILS[bk.conf]) return B_DETAILS[bk.conf];
  // synthesise something proportional to amount and nights
  const amt = bk.amt;
  const extrasTotal = Math.round(amt * 0.18);
  return {
    roomNo: String(200 + (bk.gIdx * 37) % 600).padStart(3, "0"),
    channel: bk.src === "direct" ? "GuestMaker Direct" : bk.src === "engine" ? "Booking Engine" : bk.src === "ota" ? "OTA Marketplace" : bk.src === "wholesale" ? "Wholesaler" : bk.src === "tour" ? "Tour Operator" : "Voice Centre",
    companions: bk.room >= 4 ? [{ fn: "Companion", ln: B_GUESTS[bk.gIdx].ln, type: "Adult" }] : [],
    extras: extrasTotal > 0 ? [
      { group: "F&B · Restaurant", icon: "wine", items: [
        { lbl: "Dinner · 2 covers", v: Math.round(extrasTotal * 0.5 * 100) / 100 },
        { lbl: "Wine selection",    v: Math.round(extrasTotal * 0.2 * 100) / 100 },
      ]},
      ...(bk.bd !== "AI" && bk.nts > 2 ? [
        { group: "Spa", icon: "spa", items: [
          { lbl: "Treatment booked", v: Math.round(extrasTotal * 0.3 * 100) / 100 },
        ]},
      ] : []),
    ] : [],
  };
}

// ────────────────────────── atoms ──────────────────────────
function BMono({ children, size = 11, color = B_DIM, style }) {
  return <span style={{ fontFamily: B_MONO, fontSize: size, color, letterSpacing: "0.04em", ...style }}>{children}</span>;
}
function BEyebrow({ children, color = B_FUCHSIA, style }) {
  return <div style={{
    fontFamily: B_MONO, fontSize: 10.5, color, fontWeight: 700,
    letterSpacing: "0.22em", textTransform: "uppercase", ...style,
  }}>{children}</div>;
}
function StatusPill({ status, size = "sm" }) {
  const t = B_STATUS_TONE[status];
  const padding = size === "sm" ? "3px 9px" : "4px 12px";
  return (
    <span style={{
      display: "inline-flex", alignItems: "center", gap: 5,
      padding, borderRadius: 999,
      background: t.bg, color: t.fg, border: `1px solid ${t.border}`,
      fontFamily: B_MONO, fontSize: size === "sm" ? 9.5 : 11,
      fontWeight: 700, letterSpacing: "0.06em", whiteSpace: "nowrap",
    }}>
      <span style={{ width: 4, height: 4, borderRadius: 2, background: t.fg }} />
      {B_STATUS_LABEL[status]}
    </span>
  );
}
function SourcePill({ id }) {
  const s = B_SOURCE_BY_ID[id];
  const t = B_SOURCE_TONE[s.tone];
  return (
    <span style={{
      display: "inline-flex", alignItems: "center", gap: 4,
      padding: "2px 8px", borderRadius: 4,
      background: t.bg, color: t.fg, border: `1px solid ${t.border}`,
      fontFamily: B_MONO, fontSize: 9, fontWeight: 700, letterSpacing: "0.06em",
      whiteSpace: "nowrap",
    }}>
      {s.label}
    </span>
  );
}
function Avatar({ fn, ln, size = 30, ring = false }) {
  const initials = (fn[0] + ln[0]).toUpperCase();
  return (
    <div style={{
      width: size, height: size, borderRadius: Math.round(size * 0.28),
      background: `linear-gradient(135deg, ${B_FUCHSIA}, ${B_FUCHSIA_DEEP})`,
      color: "#fff",
      display: "flex", alignItems: "center", justifyContent: "center",
      fontFamily: B_SERIF, fontSize: size * 0.4, fontStyle: "italic", fontWeight: 600,
      letterSpacing: "-0.02em",
      boxShadow: ring ? `inset 0 -2px 4px rgba(0,0,0,0.18), 0 0 0 3px ${B_FUCHSIA}22` : "inset 0 -2px 4px rgba(0,0,0,0.18)",
      flexShrink: 0,
    }}>{initials}</div>
  );
}

// ────────────────────────── product chrome ──────────────────────────
function BMockTopBar() {
  return (
    <div style={{
      display: "flex", alignItems: "center", justifyContent: "space-between",
      padding: "0 16px", height: 38, background: "#0e0e0e", color: "#cfc8c8",
      borderTopLeftRadius: 12, borderTopRightRadius: 12,
    }}>
      <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
        <span style={{ width: 10, height: 10, borderRadius: 5, background: "#ff5f56" }} />
        <span style={{ width: 10, height: 10, borderRadius: 5, background: "#ffbd2e" }} />
        <span style={{ width: 10, height: 10, borderRadius: 5, background: "#27c93f" }} />
        <span style={{ marginLeft: 16, fontFamily: B_MONO, fontSize: 10.5, letterSpacing: "0.08em", color: "#8b8181" }}>
          guestmaker.ai / crm / bookings
        </span>
      </div>
      <div style={{ display: "flex", alignItems: "center", gap: 16 }}>
        <span style={{ fontFamily: B_MONO, fontSize: 10, letterSpacing: "0.18em", color: "#b8acac", fontWeight: 700 }}>ADMIN</span>
        <span style={{ fontFamily: B_MONO, fontSize: 10, letterSpacing: "0.06em", color: "#cfc8c8" }}>AURELIA Hotels ▾</span>
      </div>
    </div>
  );
}

function BSidebar() {
  const items = [
    { lbl: "Home",         icon: "compass" },
    { lbl: "DATA",         icon: "user",     header: true },
    { lbl: "Contacts",     icon: "users",    indent: true },
    { lbl: "Segments",     icon: "tag",      indent: true },
    { lbl: "Tags",         icon: "tag",      indent: true },
    { lbl: "Custom Fields",icon: "edit",     indent: true },
    { lbl: "Bookings",     icon: "calendar", indent: true, active: true },
    { lbl: "Reservations", icon: "bed",      indent: true },
    { lbl: "CHANNELS",     icon: "send",     header: true },
    { lbl: "AI AGENTS",    icon: "spark",    header: true },
    { lbl: "CDP",          icon: "brain",    header: true },
    { lbl: "LOYALTY",      icon: "gift",     header: true },
  ];
  return (
    <div style={{
      background: B_PAPER, borderRight: `1px solid ${B_RULE_S}`,
      padding: "22px 14px 28px",
    }}>
      <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 22, padding: "0 6px" }}>
        <div style={{
          width: 26, height: 26, borderRadius: 7,
          background: `linear-gradient(135deg, ${B_FUCHSIA}, ${B_FUCHSIA_DEEP})`,
          display: "flex", alignItems: "center", justifyContent: "center",
        }}><GMMark size={16} color="white" /></div>
        <span style={{ fontSize: 14, color: B_INK, fontWeight: 700, letterSpacing: "-0.005em" }}>GuestMaker</span>
      </div>
      <div style={{
        height: 30, marginBottom: 20, padding: "0 10px",
        display: "flex", alignItems: "center",
        background: "#fff", border: `1px solid ${B_RULE}`, borderRadius: 8,
      }}>
        <BIcon name="building" size={14} color={B_FUCHSIA} strokeWidth={1.8} />
        <span style={{ marginLeft: 8, fontSize: 12, color: B_INK, fontWeight: 700, letterSpacing: "0.02em" }}>
          AURELIA
        </span>
        <span style={{ flex: 1 }} />
        <BIcon name="chevron" size={11} color={B_FAINT} strokeWidth={2} />
      </div>
      <div style={{ display: "flex", flexDirection: "column", gap: 2 }}>
        {items.map((it, i) => (
          <div key={i} style={{
            display: "flex", alignItems: "center", gap: 9,
            padding: it.header ? "10px 8px 6px" : "8px 8px",
            paddingLeft: it.indent ? 22 : 8,
            marginTop: it.header && i > 0 ? 8 : 0,
            borderRadius: 7,
            background: it.active ? B_FUCHSIA + "14" : "transparent",
            color: it.active ? B_FUCHSIA_DEEP : (it.header ? B_FAINT : B_INK),
            fontSize: it.header ? 9.5 : 12.5,
            fontWeight: it.header || it.active ? 700 : 500,
            letterSpacing: it.header ? "0.16em" : "-0.005em",
            cursor: it.active ? "default" : "pointer",
          }}>
            <BIcon name={it.icon} size={it.header ? 11 : 13}
              color={it.active ? B_FUCHSIA : (it.header ? B_FAINT : B_DIM)}
              strokeWidth={1.9} />
            {it.lbl}
            {it.header && <BIcon name="chevron" size={10} color={B_FAINT} strokeWidth={2} style={{ marginLeft: "auto" }} />}
          </div>
        ))}
      </div>
    </div>
  );
}

// ────────────────────────── KPI strip ──────────────────────────
// Live counter that ticks up by a small random amount each interval.
function useLiveCounter(startVal, addMin = 1, addMax = 4, tickMs = 1600) {
  const [v, setV] = bUseState(startVal);
  bUseEffect(() => {
    const id = setInterval(() => {
      const add = Math.floor(Math.random() * (addMax - addMin + 1)) + addMin;
      setV(c => c + add);
    }, tickMs);
    return () => clearInterval(id);
  }, []);
  return v;
}

// Live oscillator around a mean (avg/night ticks ± swing).
function useLiveOscillator(center, swing = 3, tickMs = 2200) {
  const [v, setV] = bUseState(center);
  bUseEffect(() => {
    const id = setInterval(() => {
      setV(Math.round(center + (Math.random() - 0.5) * swing * 2));
    }, tickMs);
    return () => clearInterval(id);
  }, []);
  return v;
}

// Stream of synthetic “new booking” events that fly through the ticker bar.
const B_LIVE_EVENTS = [
  { guest: "Anna Lindgren",     hotel: "Cala Marina", status: "Confirmed",  amt: 482,  src: "Booking.com" },
  { guest: "Sofia Marchetti",   hotel: "Costa Brava", status: "Confirmed",  amt: 1265, src: "Direct · Web" },
  { guest: "Hiroko Tanaka",     hotel: "Bahía Verde",status: "Confirmed",   amt: 1842, src: "Expedia" },
  { guest: "Mathias Brun",      hotel: "Cala Marina", status: "Modified",   amt: 855,  src: "Roiback" },
  { guest: "Lien Nakamura",     hotel: "Punta Azul",  status: "Confirmed",  amt: 318,  src: "Hotels.com" },
  { guest: "Pieter de Vries",   hotel: "Playa Roja",  status: "Checked In", amt: 1075, src: "TUI" },
  { guest: "Karim El Amrani",   hotel: "Cala Marina", status: "Confirmed",  amt: 720,  src: "Hotelbeds" },
  { guest: "Camille Dubois",    hotel: "Costa Brava", status: "Confirmed",  amt: 1402, src: "Direct · Web" },
  { guest: "Brian O'Hara",      hotel: "Bahía Verde",status: "Confirmed",   amt: 950,  src: "Agoda" },
  { guest: "Eleni Papadakis",   hotel: "Playa Roja",  status: "Confirmed",  amt: 415,  src: "FTI Group" },
  { guest: "Diego Solano",      hotel: "Punta Azul",  status: "Confirmed",  amt: 612,  src: "Direct · Web" },
  { guest: "Hanna Korhonen",    hotel: "Cala Marina", status: "Confirmed",  amt: 1188, src: "Jet2holidays" },
  { guest: "Karoline Berg",     hotel: "Costa Brava", status: "Modified",   amt: 845,  src: "Roiback" },
  { guest: "Otto Mehrtens",     hotel: "Bahía Verde",status: "Confirmed",   amt: 2210, src: "Booking.com" },
  { guest: "Sigrún Magnúsdóttir", hotel: "Playa Roja", status: "Confirmed",  amt: 488,  src: "Direct · Web" },
  { guest: "Tessa Brandt",      hotel: "Cala Marina", status: "Confirmed",  amt: 933,  src: "Hotelbeds" },
];
function useLiveEvents(tickMs = 2200) {
  const [idx, setIdx] = bUseState(0);
  bUseEffect(() => {
    const id = setInterval(() => setIdx(i => (i + 1) % B_LIVE_EVENTS.length), tickMs);
    return () => clearInterval(id);
  }, []);
  return { event: B_LIVE_EVENTS[idx], idx };
}

// Pulsing “LIVE” indicator used by KPI tiles + the event ticker.
function LivePulse({ hero }) {
  const c = hero ? "rgba(255,255,255,0.9)" : B_FUCHSIA;
  return (
    <span style={{ display: "inline-flex", alignItems: "center", gap: 5 }}>
      <span style={{ position: "relative", width: 7, height: 7, display: "inline-block" }}>
        <span style={{
          position: "absolute", inset: 0, borderRadius: "50%", background: c,
          animation: "gm-dot-pulse 1.4s ease-in-out infinite",
        }} />
        <span style={{
          position: "absolute", inset: -3, borderRadius: "50%",
          border: `1px solid ${c}`, opacity: 0.55,
          animation: "gm-ping 1.8s ease-out infinite",
        }} />
      </span>
      <BMono size={9} color={c} style={{ letterSpacing: "0.22em", fontWeight: 700 }}>LIVE</BMono>
    </span>
  );
}

// Event ticker bar that fades through new bookings flowing into the system.
function LiveEventStream({ event, idx }) {
  return (
    <div style={{
      padding: "10px 14px 10px 12px",
      background: `linear-gradient(90deg, ${B_FUCHSIA_WASH} 0%, #fff 65%, #fff 100%)`,
      border: `1px solid ${B_FUCHSIA}33`,
      borderRadius: 10, marginBottom: 12,
      display: "flex", alignItems: "center", gap: 12,
      position: "relative", overflow: "hidden",
    }}>
      <div style={{
        position: "absolute", top: 0, left: 0, right: 0, height: 1.5,
        background: `linear-gradient(90deg, transparent, ${B_FUCHSIA} 50%, transparent)`,
        animation: "gm-bar-scan 3.5s linear infinite",
        pointerEvents: "none",
      }} />
      <LivePulse />
      <span style={{ width: 1, height: 16, background: B_RULE, flexShrink: 0 }} />
      <div key={idx} style={{
        flex: 1, minWidth: 0, display: "flex", alignItems: "center", gap: 8,
        fontSize: 12, color: B_INK,
        animation: "gm-row-in 0.55s cubic-bezier(0.2, 0.7, 0.2, 1)",
        whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis",
      }}>
        <BIcon name="spark" size={12} color={B_FUCHSIA} strokeWidth={2.2} />
        <span style={{ color: B_FUCHSIA_DEEP, fontWeight: 700, letterSpacing: "0.02em" }}>New {event.status}</span>
        <span style={{ color: B_FAINT }}>·</span>
        <span style={{ fontWeight: 600 }}>{event.guest}</span>
        <span style={{ color: B_FAINT }}>·</span>
        <span style={{ color: B_INK, fontWeight: 600 }}>AURELIA {event.hotel}</span>
        <span style={{ color: B_FAINT }}>·</span>
        <span style={{ fontFamily: B_MONO, fontWeight: 700 }}>€{event.amt.toLocaleString()}</span>
        <span style={{ color: B_FAINT }}>·</span>
        <span style={{ color: B_PLUM, fontFamily: B_MONO, fontSize: 10.5, fontWeight: 700, letterSpacing: "0.04em" }}>{event.src}</span>
      </div>
      <BMono size={10} color={B_FAINT} style={{ whiteSpace: "nowrap", flexShrink: 0 }}>just now</BMono>
    </div>
  );
}

function KPI({ lbl, val, sub, accent, icon, hero, live }) {
  return (
    <div style={{
      background: hero ? `linear-gradient(135deg, ${B_FUCHSIA}, ${B_FUCHSIA_DEEP})` : "#fff",
      border: `1px solid ${hero ? B_FUCHSIA_DEEP : B_RULE}`,
      borderRadius: 12, padding: "14px 18px 13px",
      minHeight: 100, position: "relative", overflow: "hidden",
      color: hero ? "#fff" : B_INK,
      boxShadow: hero ? `0 14px 28px -16px ${B_FUCHSIA}AA` : "0 1px 0 rgba(0,0,0,0.02)",
    }}>
      {hero && (
        <div style={{
          position: "absolute", right: -40, top: -40, width: 140, height: 140,
          borderRadius: "50%", background: "rgba(255,255,255,0.08)", filter: "blur(8px)",
        }} />
      )}
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 6 }}>
        <BMono size={10} color={hero ? "rgba(255,255,255,0.85)" : B_FAINT}
          style={{ letterSpacing: "0.16em", fontWeight: 700 }}>
          {lbl.toUpperCase()}
        </BMono>
        <span style={{ display: "inline-flex", alignItems: "center", gap: 8 }}>
          {live && <LivePulse hero={hero} />}
          {icon && <BIcon name={icon} size={14} color={hero ? "rgba(255,255,255,0.9)" : (accent || B_FUCHSIA)} strokeWidth={1.9} />}
        </span>
      </div>
      <div key={String(val)} style={{
        fontFamily: B_SERIF, fontSize: 28, fontWeight: 600,
        color: hero ? "#fff" : (accent || B_INK),
        letterSpacing: "-0.02em", lineHeight: 1, marginBottom: 8,
        animation: live ? "gm-fadein 0.35s ease" : "none",
        fontVariantNumeric: "tabular-nums",
      }}>{val}</div>
      <BMono size={10} color={hero ? "rgba(255,255,255,0.7)" : B_DIM}>{sub}</BMono>
    </div>
  );
}

// ────────────────────────── filter bar ──────────────────────────
function StatusTabs({ active, onChange, counts }) {
  const tabs = [
    { id: "all",       lbl: "All bookings" },
    { id: "Confirmed", lbl: "Confirmed" },
    { id: "CheckedIn", lbl: "In-house" },
    { id: "CheckedOut",lbl: "Past" },
    { id: "Modified",  lbl: "Modified" },
    { id: "Cancelled", lbl: "Cancelled" },
  ];
  return (
    <div style={{
      display: "flex", alignItems: "center", gap: 4,
      padding: 5, background: "#efeadd",
      border: `1px solid ${B_RULE}`, borderRadius: 10,
      width: "fit-content", maxWidth: "100%", overflow: "auto",
    }}>
      {tabs.map(t => {
        const on = t.id === active;
        return (
          <button key={t.id} onClick={() => onChange(t.id)}
            style={{
              padding: "7px 14px", border: "none", borderRadius: 6,
              background: on ? "#fff" : "transparent",
              boxShadow: on ? "0 1px 0 rgba(0,0,0,0.04), 0 4px 10px -8px rgba(0,0,0,0.18)" : "none",
              fontSize: 12, fontWeight: on ? 700 : 500,
              color: on ? B_INK : "#7a6f70", cursor: "pointer",
              display: "inline-flex", alignItems: "center", gap: 6,
              whiteSpace: "nowrap",
            }}>
            {t.lbl}
            <span style={{
              padding: "1px 6px", borderRadius: 999,
              background: on ? B_INK : "rgba(0,0,0,0.06)",
              color: on ? "#fff" : B_DIM,
              fontFamily: B_MONO, fontSize: 9, fontWeight: 700,
            }}>{counts[t.id] ?? 0}</span>
          </button>
        );
      })}
    </div>
  );
}

function FilterBar({ search, setSearch, hotel, setHotel, dateFrom, setDateFrom, dateTo, setDateTo, onReset }) {
  return (
    <div style={{ display: "flex", gap: 10, marginTop: 14, marginBottom: 16, flexWrap: "wrap" }}>
      <div style={{
        flex: "1 1 280px",
        display: "flex", alignItems: "center", gap: 8,
        padding: "8px 12px", background: "#fff",
        border: `1px solid ${B_RULE}`, borderRadius: 8,
      }}>
        <BIcon name="search" size={13} color={B_DIM} strokeWidth={1.9} />
        <input
          value={search}
          onChange={e => setSearch(e.target.value)}
          placeholder="Search by guest name, email, or confirmation #..."
          style={{
            flex: 1, border: "none", outline: "none",
            fontSize: 12.5, color: B_INK, background: "transparent",
            fontFamily: "'Inter', sans-serif",
          }}
        />
      </div>
      <div style={{ position: "relative" }}>
        <select
          value={hotel} onChange={e => setHotel(e.target.value)}
          style={{
            appearance: "none", padding: "8px 32px 8px 12px",
            background: "#fff", border: `1px solid ${B_RULE}`, borderRadius: 8,
            fontSize: 12.5, color: B_INK, fontWeight: 600,
            fontFamily: "'Inter', sans-serif", cursor: "pointer",
            minWidth: 200,
          }}>
          <option value="all">All Hotels</option>
          {B_HOTELS.map(h => <option key={h.id} value={h.id}>{h.name}</option>)}
        </select>
        <BIcon name="chevron" size={11} color={B_DIM} strokeWidth={2}
          style={{ position: "absolute", right: 11, top: 14, pointerEvents: "none" }} />
      </div>
      <div style={{
        display: "flex", alignItems: "center", gap: 7,
        padding: "8px 12px", background: "#fff",
        border: `1px solid ${B_RULE}`, borderRadius: 8,
        fontSize: 12.5, color: dateFrom ? B_INK : B_FAINT,
        cursor: "pointer", fontWeight: 500,
      }} onClick={() => setDateFrom(dateFrom ? "" : "May 1, 2026")}>
        <BIcon name="calendar" size={12} color={B_DIM} strokeWidth={1.9} />
        {dateFrom || "Check-in from..."}
      </div>
      <div style={{
        display: "flex", alignItems: "center", gap: 7,
        padding: "8px 12px", background: "#fff",
        border: `1px solid ${B_RULE}`, borderRadius: 8,
        fontSize: 12.5, color: dateTo ? B_INK : B_FAINT,
        cursor: "pointer", fontWeight: 500,
      }} onClick={() => setDateTo(dateTo ? "" : "Aug 31, 2026")}>
        <BIcon name="calendar" size={12} color={B_DIM} strokeWidth={1.9} />
        {dateTo || "Check-in to..."}
      </div>
      <button onClick={onReset} style={{
        display: "inline-flex", alignItems: "center", gap: 6,
        padding: "8px 12px", background: "transparent", border: "none",
        fontSize: 12, color: B_DIM, fontWeight: 600, cursor: "pointer",
      }}>
        <BIcon name="close" size={12} color={B_DIM} strokeWidth={2} />
        Clear Filters
      </button>
    </div>
  );
}

// ────────────────────────── table ──────────────────────────
// Single-line grid: every cell vertically centred, no row wraps, generous gaps.
const ROW_COLS = "120px minmax(220px, 1.6fr) 180px minmax(200px, 1.3fr) minmax(170px, 1fr) 130px 110px 140px 28px";

function BookingsTable({ rows, onOpen }) {
  return (
    <div style={{
      background: "#fff", border: `1px solid ${B_RULE}`, borderRadius: 12,
      overflow: "hidden",
    }}>
      {/* header */}
      <div style={{
        display: "grid", gridTemplateColumns: ROW_COLS, columnGap: 14,
        padding: "12px 20px",
        borderBottom: `1px solid ${B_RULE}`, background: B_PAPER,
        fontFamily: B_MONO, fontSize: 9.5, letterSpacing: "0.16em",
        fontWeight: 700, color: B_FAINT, alignItems: "center",
      }}>
        <span>CONFIRMATION</span>
        <span>GUEST</span>
        <span>STAY</span>
        <span>HOTEL</span>
        <span>ROOM &middot; PLAN</span>
        <span>STATUS</span>
        <span style={{ textAlign: "right" }}>AMOUNT</span>
        <span>SOURCE</span>
        <span />
      </div>

      {rows.length === 0 ? (
        <div style={{ padding: "60px 20px", textAlign: "center", color: B_FAINT }}>
          <BMono color={B_FAINT}>No bookings match your filters.</BMono>
        </div>
      ) : (
        rows.map((bk, i) => {
          const g = B_GUESTS[bk.gIdx];
          const h = B_HOTEL_BY_ID[bk.hotel];
          const ciShort = bk.ci.replace(", 2026", "");
          const coShort = bk.co.replace(", 2026", "");
          return (
            <div key={bk.conf}
              onClick={() => onOpen(bk)}
              style={{
                display: "grid",
                gridTemplateColumns: ROW_COLS, columnGap: 14,
                padding: "14px 20px",
                borderBottom: i < rows.length - 1 ? `1px solid ${B_RULE_S}` : "none",
                alignItems: "center", fontSize: 12.5, color: B_INK,
                cursor: "pointer", transition: "background 0.15s ease",
              }}
              onMouseEnter={e => e.currentTarget.style.background = B_FUCHSIA + "06"}
              onMouseLeave={e => e.currentTarget.style.background = "transparent"}
            >
              {/* confirmation */}
              <BMono size={11} color={B_INK} style={{ fontWeight: 700, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>
                {bk.conf}
              </BMono>

              {/* guest */}
              <div style={{ display: "flex", alignItems: "center", gap: 10, minWidth: 0 }}>
                <Avatar fn={g.fn} ln={g.ln} size={30} />
                <div style={{ minWidth: 0 }}>
                  <div style={{ fontSize: 13, color: B_INK, fontWeight: 600, lineHeight: 1.2, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>
                    {g.fn} {g.ln}
                  </div>
                  <BMono size={10} color={B_DIM} style={{ display: "block", marginTop: 2, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>
                    {g.email}
                  </BMono>
                </div>
              </div>

              {/* stay (single line dates + nights) */}
              <div style={{ minWidth: 0 }}>
                <div style={{ display: "flex", alignItems: "center", gap: 5, fontFamily: B_MONO, fontSize: 11.5, color: B_INK, fontWeight: 600, whiteSpace: "nowrap" }}>
                  {ciShort}
                  <span style={{ color: B_FAINT }}>&rarr;</span>
                  {coShort}
                </div>
                <BMono size={10} color={B_FAINT} style={{ display: "block", marginTop: 2 }}>{bk.nts} {bk.nts === 1 ? "night" : "nights"}</BMono>
              </div>

              {/* hotel */}
              <div style={{ minWidth: 0 }}>
                <div style={{ fontSize: 12.5, color: B_INK, fontWeight: 600, lineHeight: 1.2, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>
                  {h.name}
                </div>
                <BMono size={10} color={B_FAINT} style={{ display: "block", marginTop: 2, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>
                  {h.loc}
                </BMono>
              </div>

              {/* room + chips */}
              <div style={{ minWidth: 0 }}>
                <div style={{ fontSize: 12, color: B_INK, lineHeight: 1.2, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>
                  {B_ROOMS[bk.room]}
                </div>
                <div style={{ display: "flex", gap: 4, marginTop: 4 }}>
                  <BMono size={9} color={B_FUCHSIA_DEEP} style={{ padding: "1px 6px", background: B_FUCHSIA_WASH, borderRadius: 3, fontWeight: 700, letterSpacing: "0.06em" }}>{bk.bd}</BMono>
                  <BMono size={9} color={B_PLUM} style={{ padding: "1px 6px", background: B_FUCHSIA_PALE, borderRadius: 3, fontWeight: 700, letterSpacing: "0.06em" }}>{bk.rt}</BMono>
                </div>
              </div>

              {/* status */}
              <span><StatusPill status={bk.status} /></span>

              {/* amount */}
              <BMono size={12} color={B_INK} style={{ fontWeight: 700, textAlign: "right", fontVariantNumeric: "tabular-nums", whiteSpace: "nowrap" }}>
                €{bk.amt.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
              </BMono>

              {/* source */}
              <span style={{ minWidth: 0, overflow: "hidden" }}><SourcePill id={bk.src} /></span>

              {/* actions */}
              <button style={{
                width: 26, height: 26, borderRadius: 6,
                background: "transparent", border: "none",
                cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center",
              }} onClick={e => { e.stopPropagation(); onOpen(bk); }}>
                <BIcon name="more" size={14} color={B_FAINT} strokeWidth={1.8} />
              </button>
            </div>
          );
        })
      )}
    </div>
  );
}

// ────────────────────────── DETAIL DRAWER ──────────────────────────
function ExtrasGroup({ ex, defaultOpen = true }) {
  const [open, setOpen] = bUseState(defaultOpen);
  const total = ex.items.reduce((s, it) => s + it.v, 0);
  return (
    <div style={{
      background: B_FUCHSIA_WASH, border: `1px solid ${B_FUCHSIA}33`,
      borderRadius: 8, padding: "10px 12px", marginBottom: 6,
    }}>
      <div style={{
        display: "flex", alignItems: "center", justifyContent: "space-between",
        cursor: "pointer",
      }} onClick={() => setOpen(o => !o)}>
        <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
          <BIcon name="chevron" size={11} color={B_FUCHSIA_DEEP} strokeWidth={2.2}
            style={{ transform: open ? "rotate(0)" : "rotate(-90deg)", transition: "transform 0.15s" }} />
          <BIcon name={ex.icon || "wallet"} size={12} color={B_FUCHSIA_DEEP} strokeWidth={1.9} />
          <span style={{ fontSize: 12.5, color: B_FUCHSIA_DEEP, fontWeight: 700 }}>{ex.group}</span>
          <BMono size={10} color={B_FUCHSIA_DEEP} style={{ opacity: 0.7 }}>({ex.items.length})</BMono>
        </div>
        <BMono size={12} color={B_FUCHSIA_DEEP} style={{ fontWeight: 700, fontVariantNumeric: "tabular-nums" }}>
          €{total.toFixed(2)}
        </BMono>
      </div>
      {open && (
        <div style={{ marginTop: 8, display: "flex", flexDirection: "column", gap: 4 }}>
          {ex.items.map((it, i) => (
            <div key={i} style={{
              display: "flex", justifyContent: "space-between", alignItems: "center",
              padding: "3px 0 3px 26px",
              fontSize: 11.5, color: B_INK,
            }}>
              <span>{it.lbl}</span>
              <BMono size={11} color={B_INK} style={{ fontVariantNumeric: "tabular-nums" }}>
                €{it.v.toFixed(2)}
              </BMono>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

function DetailSection({ icon, title, children }) {
  return (
    <div style={{
      background: "#fff", border: `1px solid ${B_RULE}`, borderRadius: 10,
      padding: "14px 16px 16px", marginBottom: 10,
    }}>
      <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 12 }}>
        <BIcon name={icon} size={14} color={B_INK} strokeWidth={1.9} />
        <span style={{ fontSize: 13, color: B_INK, fontWeight: 700 }}>{title}</span>
      </div>
      {children}
    </div>
  );
}

function DetailField({ label, value, accent }) {
  return (
    <div>
      <BMono size={9.5} color={B_FAINT} style={{ letterSpacing: "0.16em", fontWeight: 700, display: "block", marginBottom: 4 }}>
        {label.toUpperCase()}
      </BMono>
      <div style={{ fontSize: 13, color: accent || B_INK, fontWeight: accent ? 700 : 500 }}>
        {value || "N/A"}
      </div>
    </div>
  );
}

function Drawer({ bk, onClose }) {
  // Lock body scroll while open
  bUseEffect(() => {
    if (!bk) return;
    const orig = document.body.style.overflow;
    document.body.style.overflow = "hidden";
    const onEsc = (e) => { if (e.key === "Escape") onClose(); };
    window.addEventListener("keydown", onEsc);
    return () => {
      document.body.style.overflow = orig;
      window.removeEventListener("keydown", onEsc);
    };
  }, [bk, onClose]);

  if (!bk) return null;
  const g = B_GUESTS[bk.gIdx];
  const h = B_HOTEL_BY_ID[bk.hotel];
  const d = getDetail(bk);
  const extrasTotal = d.extras.reduce((s, ex) => s + ex.items.reduce((a, it) => a + it.v, 0), 0);
  const totalRev = bk.amt + extrasTotal;
  const avg = totalRev / bk.nts;
  const allGuests = [{ fn: g.fn, ln: g.ln, type: "Holder", email: g.email, phone: g.ph, primary: true }, ...d.companions.map(c => ({ ...c, primary: false }))];

  return (
    <div style={{
      position: "fixed", inset: 0,
      background: "rgba(15, 11, 12, 0.55)",
      backdropFilter: "blur(2px)",
      zIndex: 99,
      display: "flex", justifyContent: "flex-end",
      animation: "gm-fadein 0.2s ease",
    }} onClick={onClose}>
      <div onClick={e => e.stopPropagation()} style={{
        width: "min(720px, 100vw)",
        height: "100vh", background: B_CREAM,
        boxShadow: "-30px 0 60px -30px rgba(0,0,0,0.4)",
        display: "flex", flexDirection: "column",
        animation: "gm-slidein-r 0.25s cubic-bezier(0.2, 0.7, 0.2, 1)",
      }}>
        {/* drawer header */}
        <div style={{
          padding: "18px 22px 16px",
          borderBottom: `1px solid ${B_RULE_S}`,
          background: "#fff",
          display: "flex", alignItems: "flex-start", gap: 12,
        }}>
          <div style={{
            width: 32, height: 32, borderRadius: 8,
            background: B_FUCHSIA_WASH, color: B_FUCHSIA_DEEP,
            display: "flex", alignItems: "center", justifyContent: "center",
            flexShrink: 0,
          }}>
            <BIcon name="calendar" size={16} color={B_FUCHSIA_DEEP} strokeWidth={1.9} />
          </div>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 5 }}>
              <span style={{ fontSize: 15.5, color: B_INK, fontWeight: 700, letterSpacing: "-0.005em" }}>
                Reservation Details
              </span>
              <StatusPill status={bk.status} />
            </div>
            <div style={{ display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap" }}>
              <div style={{ display: "flex", alignItems: "center", gap: 6 }}>
                <BIcon name="user" size={11} color={B_DIM} strokeWidth={2} />
                <span style={{ fontSize: 13, color: B_INK, fontWeight: 600 }}>{g.fn} {g.ln}</span>
                <BIcon name="external" size={10} color={B_FUCHSIA} strokeWidth={2} />
              </div>
              <BMono size={11} color={B_DIM} style={{ display: "inline-flex", alignItems: "center", gap: 6 }}>
                <BIcon name="calendar" size={10} color={B_DIM} strokeWidth={1.9} />
                {bk.ci} → {bk.co} <span style={{ color: B_FAINT }}>({bk.nts}n)</span>
              </BMono>
              <BMono size={11} color={B_DIM} style={{ display: "inline-flex", alignItems: "center", gap: 6 }}>
                <BIcon name="building" size={10} color={B_DIM} strokeWidth={1.9} />
                {h.name}
              </BMono>
            </div>
          </div>
          <button onClick={onClose} style={{
            width: 32, height: 32, borderRadius: 8,
            background: "transparent", border: `1px solid ${B_RULE}`,
            cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center",
            color: B_DIM, flexShrink: 0,
          }}>
            <BIcon name="close" size={14} color={B_DIM} strokeWidth={2} />
          </button>
        </div>

        {/* meta row */}
        <div style={{
          padding: "12px 22px", background: B_PAPER,
          borderBottom: `1px solid ${B_RULE_S}`,
          display: "grid", gridTemplateColumns: "auto auto auto 1fr",
          gap: 28, alignItems: "center",
        }}>
          <DetailField label="Reservation ID" value={`${B_HOTEL_BY_ID[bk.hotel].code}-${(bk.conf.charCodeAt(0) * 211 + bk.conf.length).toString().slice(0, 6)}`} />
          <DetailField label="Confirmation Number" value={bk.conf.toUpperCase()} accent={B_FUCHSIA_DEEP} />
          <DetailField label="Source" value={B_SOURCE_BY_ID[bk.src].label} />
        </div>

        {/* body */}
        <div className="gm-scroll" style={{
          flex: 1, overflowY: "auto",
          padding: "18px 22px 28px",
        }}>
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1.05fr", gap: 14 }}>
            {/* left column */}
            <div>
              <DetailSection icon="bed" title="Stay Details">
                <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", rowGap: 12, columnGap: 18 }}>
                  <DetailField label="Room Type"    value={B_ROOMS[bk.room]} />
                  <DetailField label="Room Number"  value={d.roomNo} accent={B_FUCHSIA_DEEP} />
                  <DetailField label="Board Type"   value={B_BOARD_LABEL[bk.bd]} />
                  <DetailField label="Booking Channel" value={d.channel} />
                  <DetailField label="Rate Plan"    value={bk.rt === "NRF" ? "Non-Refundable" : bk.rt === "FLEX" ? "Flexible" : bk.rt === "ADV" ? "Advance Purchase" : bk.rt === "PROMO" ? "Promotional" : "Corporate"} />
                  <DetailField label="Nights"       value={bk.nts} />
                </div>
              </DetailSection>

              <DetailSection icon="users" title={`Guests (${allGuests.length})`}>
                <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
                  {allGuests.map((gg, i) => (
                    <div key={i} style={{
                      display: "flex", alignItems: "center", gap: 10,
                      padding: "8px 10px", border: `1px solid ${B_RULE_S}`, borderRadius: 8,
                    }}>
                      <Avatar fn={gg.fn} ln={gg.ln} size={28} ring={gg.primary} />
                      <div style={{ flex: 1, minWidth: 0 }}>
                        <div style={{ display: "flex", alignItems: "center", gap: 6 }}>
                          <span style={{ fontSize: 12.5, color: B_INK, fontWeight: 600 }}>{gg.fn} {gg.ln}</span>
                          {gg.primary && (
                            <span style={{
                              padding: "1px 7px", borderRadius: 3,
                              background: B_INK, color: "#fff",
                              fontFamily: B_MONO, fontSize: 8.5, fontWeight: 700, letterSpacing: "0.08em",
                            }}>HOLDER</span>
                          )}
                          {!gg.primary && (
                            <span style={{
                              padding: "1px 7px", borderRadius: 3,
                              background: B_RULE_S, color: B_DIM,
                              fontFamily: B_MONO, fontSize: 8.5, fontWeight: 700, letterSpacing: "0.08em",
                            }}>{gg.type.toUpperCase()}</span>
                          )}
                        </div>
                        <BMono size={10} color={B_DIM} style={{ display: "block", marginTop: 2 }}>
                          {gg.primary ? `${gg.email} · ${gg.phone}` : "Linked under booking"}
                        </BMono>
                      </div>
                      {gg.primary && (
                        <button style={{
                          width: 26, height: 26, borderRadius: 6, border: `1px solid ${B_RULE}`,
                          background: "#fff", cursor: "pointer",
                          display: "flex", alignItems: "center", justifyContent: "center",
                        }}>
                          <BIcon name="external" size={11} color={B_FUCHSIA} strokeWidth={2} />
                        </button>
                      )}
                    </div>
                  ))}
                </div>
              </DetailSection>

              <DetailSection icon="log" title="Activity">
                <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
                  {[
                    { t: "16 May · 09:14", a: "Reservation created from " + B_SOURCE_BY_ID[bk.src].label, icon: "spark" },
                    { t: "17 May · 11:02", a: "Pre-stay journey started", icon: "send" },
                    { t: "18 May · 14:38", a: "Vegan menu preference captured · WhatsApp", icon: "brain" },
                    ...(bk.status === "Modified" ? [{ t: "19 May · 08:21", a: "Dates modified (+1 night)", icon: "edit" }] : []),
                    ...(bk.status === "CheckedIn" ? [{ t: bk.ci + " · 16:12", a: "Checked in · key issued", icon: "key" }] : []),
                    ...(bk.status === "CheckedOut" ? [{ t: bk.co + " · 10:48", a: "Checked out · folio settled", icon: "wallet" }] : []),
                    ...(bk.status === "Cancelled" ? [{ t: "19 May · 11:03", a: "Cancelled by guest", icon: "close" }] : []),
                  ].slice(0, 4).map((e, i) => (
                    <div key={i} style={{ display: "flex", alignItems: "flex-start", gap: 10 }}>
                      <div style={{
                        width: 22, height: 22, borderRadius: 5,
                        background: B_FUCHSIA_WASH, border: `1px solid ${B_FUCHSIA}33`,
                        display: "flex", alignItems: "center", justifyContent: "center",
                        flexShrink: 0,
                      }}>
                        <BIcon name={e.icon} size={11} color={B_FUCHSIA_DEEP} strokeWidth={2} />
                      </div>
                      <div style={{ flex: 1, minWidth: 0 }}>
                        <div style={{ fontSize: 12, color: B_INK, lineHeight: 1.4 }}>{e.a}</div>
                        <BMono size={9.5} color={B_FAINT}>{e.t}</BMono>
                      </div>
                    </div>
                  ))}
                </div>
              </DetailSection>
            </div>

            {/* right column · financial summary */}
            <div>
              <DetailSection icon="wallet" title="Financial Summary">
                <div style={{
                  display: "flex", alignItems: "center", justifyContent: "space-between",
                  padding: "6px 0 10px",
                }}>
                  <span style={{ fontSize: 12.5, color: B_DIM }}>Reservation Amount</span>
                  <BMono size={14} color={B_INK} style={{ fontWeight: 700, fontVariantNumeric: "tabular-nums" }}>
                    €{bk.amt.toFixed(2)}
                  </BMono>
                </div>

                {d.extras.length > 0 && (
                  <>
                    <div style={{
                      display: "flex", alignItems: "center", justifyContent: "space-between",
                      padding: "6px 0 10px",
                      borderTop: `1px dashed ${B_RULE_S}`,
                    }}>
                      <span style={{ fontSize: 12.5, color: B_FUCHSIA_DEEP, fontWeight: 700 }}>Folio Extras</span>
                      <BMono size={13} color={B_FUCHSIA_DEEP} style={{ fontWeight: 700, fontVariantNumeric: "tabular-nums" }}>
                        €{extrasTotal.toFixed(2)}
                      </BMono>
                    </div>
                    {d.extras.map((ex, i) => <ExtrasGroup key={i} ex={ex} />)}
                  </>
                )}

                <div style={{
                  marginTop: 8, paddingTop: 12,
                  borderTop: `1px solid ${B_RULE}`,
                  display: "flex", alignItems: "center", justifyContent: "space-between",
                }}>
                  <span style={{ fontSize: 13, color: B_INK, fontWeight: 700 }}>Total Revenue</span>
                  <span style={{
                    fontFamily: B_SERIF, fontSize: 22, color: B_INK,
                    fontWeight: 700, letterSpacing: "-0.015em",
                    fontVariantNumeric: "tabular-nums",
                  }}>
                    €{totalRev.toFixed(2)}
                  </span>
                </div>

                <div style={{
                  marginTop: 10, padding: "10px 12px",
                  background: B_FUCHSIA_WASH, borderRadius: 8,
                  border: `1px solid ${B_FUCHSIA}33`,
                  display: "flex", alignItems: "center", justifyContent: "space-between",
                }}>
                  <BMono size={10.5} color={B_FUCHSIA_DEEP} style={{ letterSpacing: "0.12em", fontWeight: 700 }}>
                    AVERAGE PER NIGHT
                  </BMono>
                  <span style={{
                    fontFamily: B_SERIF, fontStyle: "italic", fontSize: 18, color: B_FUCHSIA_DEEP,
                    fontWeight: 700, fontVariantNumeric: "tabular-nums",
                  }}>
                    €{avg.toFixed(2)}
                  </span>
                </div>
              </DetailSection>

              <DetailSection icon="building" title="Hotel">
                <div style={{ display: "flex", flexDirection: "column", gap: 4 }}>
                  <div style={{ fontSize: 13, color: B_INK, fontWeight: 700 }}>{h.name}</div>
                  <BMono size={11} color={B_DIM}>{h.loc}</BMono>
                  <div style={{ display: "flex", alignItems: "center", gap: 6, marginTop: 6 }}>
                    <BIcon name="phone" size={11} color={B_DIM} strokeWidth={2} />
                    <BMono size={11} color={B_INK}>+34 971 220 884</BMono>
                  </div>
                  <div style={{ display: "flex", alignItems: "center", gap: 6 }}>
                    <BIcon name="mail" size={11} color={B_DIM} strokeWidth={2} />
                    <BMono size={11} color={B_INK}>reception.{h.id.toLowerCase()}@aurelia.example</BMono>
                  </div>
                </div>
              </DetailSection>

              <DetailSection icon="log" title="Record Info">
                <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
                  {[
                    { l: "Created",  v: "Tue, 19 May 2026" },
                    { l: "Updated",  v: "Wed, 20 May 2026" },
                    { l: "Stage",    v: bk.status === "CheckedIn" ? "in_stay" : bk.status === "CheckedOut" ? "post_stay" : bk.status === "Cancelled" ? "cancelled" : "pre_arrival",
                      pill: true },
                  ].map((r, i) => (
                    <div key={i} style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
                      <BMono size={11} color={B_DIM} style={{ letterSpacing: "0.06em" }}>{r.l}</BMono>
                      {r.pill ? (
                        <span style={{
                          padding: "2px 9px", borderRadius: 4,
                          background: B_FUCHSIA_WASH, color: B_FUCHSIA_DEEP,
                          border: `1px solid ${B_FUCHSIA}33`,
                          fontFamily: B_MONO, fontSize: 10, fontWeight: 700, letterSpacing: "0.06em",
                        }}>{r.v}</span>
                      ) : (
                        <BMono size={11.5} color={B_INK} style={{ fontWeight: 600 }}>{r.v}</BMono>
                      )}
                    </div>
                  ))}
                </div>
              </DetailSection>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

// ────────────────────────── main section ──────────────────────────
function BookingsSection() {
  const [tab, setTab]       = bUseState("all");
  const [search, setSearch] = bUseState("");
  const [hotel,  setHotel]  = bUseState("all");
  const [dateFrom, setDateFrom] = bUseState("");
  const [dateTo,   setDateTo]   = bUseState("");
  const [open, setOpen]     = bUseState(null);

  // Live metrics — numbers grow as new bookings come in.
  const liveTotal     = useLiveCounter(547329, 1, 4, 1600);
  const liveAvgNight  = useLiveOscillator(238, 4, 2400);
  const { event: liveEvent, idx: liveIdx } = useLiveEvents(2200);
  const AVG_PER_BOOKING = 868;            // € per booking, lifetime
  const CANCEL_PCT      = 11.4;           // % cancel + no-show
  const liveRevenue   = liveTotal * AVG_PER_BOOKING;
  const liveCancel    = Math.round(liveTotal * (CANCEL_PCT / 100));
  const liveRevenueDisplay = `€${(liveRevenue / 1_000_000).toFixed(2)}M`;

  const filtered = bUseMemo(() => {
    return B_BOOKINGS.filter(bk => {
      if (tab !== "all" && bk.status !== tab) return false;
      if (hotel !== "all" && bk.hotel !== hotel) return false;
      if (search) {
        const q = search.toLowerCase();
        const g = B_GUESTS[bk.gIdx];
        if (!`${g.fn} ${g.ln}`.toLowerCase().includes(q)
            && !g.email.toLowerCase().includes(q)
            && !bk.conf.toLowerCase().includes(q)) return false;
      }
      return true;
    });
  }, [tab, search, hotel]);

  const counts = bUseMemo(() => {
    // Hold proportions to the seeded sample, then scale up to the live total.
    const SHARES = { Confirmed: 0.60, CheckedIn: 0.12, CheckedOut: 0.12, Modified: 0.04, Cancelled: 0.08, NoShow: 0.04 };
    const c = { all: liveTotal };
    for (const k of Object.keys(SHARES)) c[k] = Math.round(liveTotal * SHARES[k]);
    return c;
  }, [liveTotal]);

  const totalRevenue = B_BOOKINGS.reduce((s, b) => s + b.amt, 0);
  const avgNightly   = totalRevenue / B_BOOKINGS.reduce((s, b) => s + b.nts, 0);
  const cancelled    = (counts.Cancelled || 0) + (counts.NoShow || 0);
  const cancelRate   = ((cancelled / B_BOOKINGS.length) * 100).toFixed(0);

  return (
    <section data-screen-label="Bookings management" style={{
      position: "relative",
      background: B_CREAM,
      color: B_INK,
      fontFamily: "'Inter', system-ui, sans-serif",
      padding: "80px clamp(20px,4vw,48px) 96px",
      overflow: "hidden",
    }}>
      <div style={{
        position: "absolute", top: -100, left: "50%", width: 900, height: 700,
        transform: "translateX(-50%)",
        background: `radial-gradient(ellipse, ${B_FUCHSIA}0F 0%, transparent 60%)`,
        filter: "blur(50px)", pointerEvents: "none",
      }} />

      {/* section header */}
      <div style={{ maxWidth: "var(--rail)", margin: "0 auto 36px", textAlign: "center" }}>
        <div className="eyebrow" style={{ justifyContent: "center" }}>
          From contact to commercial record
        </div>
        <h2 className="h-2" style={{ marginTop: 16 }}>
          Every booking, every channel,{" "}
          <em className="italic-accent" style={{ display: "block" }}>
            decomposed and queryable.
          </em>
        </h2>
        <p className="lead" style={{ maxWidth: 760, margin: "20px auto 0" }}>
          The full commercial history of every contact in one view. Filter, sort and search across
          properties, channels, statuses and dates. Click any booking to see the stay decomposed by
          room, board and rate, with the folio extras grouped by outlet and the activity history attached.
        </p>
      </div>

      {/* product frame */}
      <ScaleFrame nativeWidth={1216} style={{ maxWidth: 1216, margin: "0 auto" }}>
      <div style={{
        maxWidth: "var(--rail)", margin: "0 auto",
        borderRadius: 14, overflow: "hidden",
        background: B_PAPER, border: `1px solid ${B_RULE}`,
        boxShadow:
          "0 40px 80px -40px rgba(20,14,10,0.25), 0 8px 24px -16px rgba(20,14,10,0.12), 0 0 0 1px rgba(255,255,255,0.5) inset",
        position: "relative",
      }}>
        <BMockTopBar />
        <div style={{ height: 1180, display: "flex", flexDirection: "column", background: B_CREAM, padding: "28px 36px 0", minHeight: 0 }}>
            {/* breadcrumb + title */}
            <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 14 }}>
              <BMono size={10.5} color={B_FAINT} style={{ letterSpacing: "0.12em", fontWeight: 600 }}>CRM</BMono>
              <BIcon name="chevron" size={11} color={B_FAINT} strokeWidth={2} style={{ transform: "rotate(-90deg)" }} />
              <BMono size={10.5} color={B_INK} style={{ letterSpacing: "0.12em", fontWeight: 700 }}>BOOKINGS</BMono>
            </div>

            <div style={{ display: "flex", alignItems: "flex-end", justifyContent: "space-between", marginBottom: 6 }}>
              <div>
                <h3 style={{
                  fontFamily: B_SERIF, fontSize: 30, fontWeight: 600,
                  color: B_INK, letterSpacing: "-0.022em", lineHeight: 1.05, margin: 0,
                }}>
                  Bookings
                </h3>
                <p style={{ fontSize: 13, color: B_DIM, margin: "6px 0 0", maxWidth: 580 }}>
                  Full commercial history, all statuses, all time, with financials and booking source.
                </p>
              </div>
              <div style={{ display: "flex", gap: 8 }}>
                <button style={{
                  display: "inline-flex", alignItems: "center", gap: 6,
                  padding: "8px 12px", borderRadius: 7,
                  background: "#fff", border: `1px solid ${B_RULE}`,
                  fontSize: 12, color: B_INK, fontWeight: 600, cursor: "pointer",
                }}>
                  <BIcon name="download" size={12} color={B_INK} strokeWidth={2} />
                  Export
                </button>
                <button style={{
                  display: "inline-flex", alignItems: "center", gap: 6,
                  padding: "8px 12px", borderRadius: 7,
                  background: B_INK, color: "#fff", border: "none",
                  fontSize: 12, fontWeight: 700, cursor: "pointer",
                }}>
                  <BIcon name="refresh" size={12} color="#fff" strokeWidth={2} />
                  Sync now
                </button>
              </div>
            </div>

            {/* KPI strip */}
            <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 10, marginTop: 18, marginBottom: 16 }}>
              <KPI live
                lbl="Total Bookings"
                val={liveTotal.toLocaleString("en-US")}
                sub="lifetime · 5 hotels"
                icon="calendar" />
              <KPI live hero
                lbl="Total Revenue"
                val={liveRevenueDisplay}
                sub="incl. confirmed + past"
                icon="trending" />
              <KPI live
                lbl="Avg / Night"
                val={`€${liveAvgNight}`}
                sub="across all room types"
                icon="bed" />
              <KPI live
                lbl="Cancel + No-Show"
                val={`${CANCEL_PCT.toFixed(1)}%`}
                sub={`${liveCancel.toLocaleString("en-US")} of ${liveTotal.toLocaleString("en-US")}`}
                icon="close" accent={B_PLUM} />
            </div>

            {/* tabs + filters */}
            <StatusTabs active={tab} onChange={setTab} counts={counts} />
            <FilterBar
              search={search} setSearch={setSearch}
              hotel={hotel} setHotel={setHotel}
              dateFrom={dateFrom} setDateFrom={setDateFrom}
              dateTo={dateTo} setDateTo={setDateTo}
              onReset={() => { setSearch(""); setHotel("all"); setDateFrom(""); setDateTo(""); setTab("all"); }}
            />

            {/* row count strip */}
            <div style={{
              display: "flex", alignItems: "center", justifyContent: "space-between",
              padding: "4px 4px 10px",
            }}>
              <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
                <BIcon name="users" size={13} color={B_DIM} strokeWidth={1.9} />
                <BMono size={11} color={B_DIM}>
                  <b style={{ color: B_INK }}>{filtered.length.toLocaleString()}</b> {filtered.length === 1 ? "booking" : "bookings"} on this page
                  <span style={{ color: B_FAINT }}> · of {liveTotal.toLocaleString("en-US")} total</span>
                </BMono>
              </div>
              <BMono size={11} color={B_FAINT}>Click any row to open the reservation</BMono>
            </div>

            {/* scrollable table area */}
            <div className="gm-scroll" style={{
              flex: 1, minHeight: 0, overflowY: "auto",
              paddingRight: 4, marginRight: -4, paddingBottom: 28,
            }}>
              <LiveEventStream event={liveEvent} idx={liveIdx} />
              <BookingsTable rows={filtered} onOpen={setOpen} />

              {filtered.length > 0 && (
                <div style={{
                  display: "flex", alignItems: "center", justifyContent: "space-between",
                  padding: "14px 4px 0",
                }}>
                  <BMono size={11} color={B_FAINT}>Page 1 of {Math.ceil(liveTotal / 25).toLocaleString("en-US")}</BMono>
                  <div style={{ display: "flex", gap: 6 }}>
                    {["Previous", "1", "2", "3", "Next"].map((b, i) => (
                      <button key={i} style={{
                        padding: "5px 11px", borderRadius: 6,
                        background: i === 1 ? B_INK : "#fff",
                        color: i === 1 ? "#fff" : B_INK,
                        border: `1px solid ${i === 1 ? B_INK : B_RULE}`,
                        fontSize: 11.5, fontWeight: 600, cursor: "pointer",
                        fontFamily: "'Inter', sans-serif",
                      }}>{b}</button>
                    ))}
                  </div>
                </div>
              )}
            </div>
        </div>
      </div>
      </ScaleFrame>

      <div style={{
        maxWidth: "var(--rail)", margin: "26px auto 0",
        display: "flex", alignItems: "center", justifyContent: "center", gap: 14,
        flexWrap: "wrap", color: B_DIM, fontSize: 12.5,
      }}>
        <BIcon name="check" size={13} color={B_FUCHSIA} strokeWidth={2.4} />
        <span>Click any row to inspect the full reservation, with extras grouped by outlet and the activity timeline.</span>
      </div>

      <Drawer bk={open} onClose={() => setOpen(null)} />
    </section>
  );
}

window.BookingsSection = BookingsSection;
