/* global React, ReactDOM */
/* Meet the dogs — foster/rescue modal opened from the About paragraph.

   Adapted from the standalone drop-in: this project has no build step, so the
   ES module import/export are gone and the file publishes MeetTheDogsModal on
   window like every other component here. Everything is inside an IIFE because
   these scripts share one global scope (cover.jsx already declares useState).

   Two behaviour changes were required to embed it:
   - Controlled mode. Passing onClose renders the dialog alone, without the
     component's own demo wrapper and "meet the dogs" trigger, so the phrase
     inside the paragraph is what opens it. With no props it still works
     standalone exactly as written.
   - The overlay is portaled to <body>. .page-host carries a filter and
     .leadership has overflow:hidden, either of which would trap or clip a
     position:fixed overlay rendered in place. RoleModal portals for the
     same reason.
*/
(function () {
const { useState, useEffect, useCallback } = React;


/* The two rescues fostered through: K9 Lifesavers during the DC years, Rebel
   Dogs Detroit since. `rescue` on a dog keys into this. */
const RESCUES = {
  k9: { label: "K9 Lifesavers", href: "https://www.k9lifesavers.org" },
  rebel: { label: "Rebel Dogs Detroit", href: "https://www.rebeldogsdetroit.com" },
};

/* The real fosters, in the order the photo filenames gave: the DC years
   first, then Detroit. Photos live in /assets/dogs, named
   <rescue>-<order>-<name>.webp so the folder sorts the way this list reads.

   `note` is optional and deliberately absent — nobody has written their
   stories yet, and the card leaves the space out rather than inventing one. */
/* DOGS-BEGIN — generated by tools/dogs.py; edit the folder, not this list.
   `note` and `focus` are optional and are carried over by name. */
const DOGS = [
  { name: "Charlie",      rescue: "k9",    image: "/assets/dogs/k9-01-charlie.webp" },
  { name: "Willard",      rescue: "k9",    image: "/assets/dogs/k9-02-willard.webp" },
  { name: "Frankie",      rescue: "k9",    image: "/assets/dogs/k9-03-frankie.webp" },
  { name: "Patty",        rescue: "k9",    image: "/assets/dogs/k9-04-patty.webp" },
  { name: "Ottis",        rescue: "k9",    image: "/assets/dogs/k9-05-ottis.webp", focus: "center top" },
  { name: "Jack Jill",    rescue: "k9",    image: "/assets/dogs/k9-06-jack-jill.webp" },
  { name: "Spudnik",      rescue: "rebel", image: "/assets/dogs/rebel-01-spudnik.webp" },
  { name: "Astro",        rescue: "rebel", image: "/assets/dogs/rebel-02-astro.webp" },
  { name: "Blue",         rescue: "rebel", image: "/assets/dogs/rebel-03-blue.webp" },
  { name: "White Walker", rescue: "rebel", image: "/assets/dogs/rebel-04-white-walker.webp" },
  { name: "Eddie",        rescue: "rebel", image: "/assets/dogs/rebel-05-eddie.webp" },
  { name: "Shenzhen",     rescue: "rebel", image: "/assets/dogs/rebel-06-shenzhen.webp" },
  { name: "Oreo",         rescue: "rebel", image: "/assets/dogs/rebel-07-oreo.webp" },
  { name: "Nori",         rescue: "rebel", image: "/assets/dogs/rebel-08-nori.webp" },
];
/* DOGS-END */

/* The site's own tokens rather than the drop-in's hardcoded hexes, so this
   dialog tracks the palette switcher (Ink / Riso / Tabloid / Editorial) along
   with everything else. Inline styles resolve var() fine.
     cream → --paper      ink  → --ink        navy → --ink (scrim/dark fills)
     coral → --accent     gold → --highlight  teal → --bloom               */
const PALETTE = {
  cream: "var(--paper)",
  ink: "var(--ink)",
  navy: "var(--ink)",
  coral: "var(--accent)",
  gold: "var(--highlight)",
  teal: "var(--bloom)",
  line: "color-mix(in oklab, var(--ink) 16%, transparent)",
  /* The promo block's ground: ink lifted toward paper, so it is the dark GREY
     the rest of the site's dark surfaces use rather than a flat black panel at
     the foot of a cream card. Mixed from the tokens, so it still follows the
     palette switcher. */
  darkGrey: "color-mix(in oklab, var(--paper) 9%, var(--ink))",
  /* Reads on top of the dark fills above. */
  onDark: "var(--paper)",
};

function useFonts() {
  useEffect(() => {
    const id = "meet-the-dogs-fonts";
    if (document.getElementById(id)) return;
    const link = document.createElement("link");
    link.id = id;
    link.rel = "stylesheet";
    link.href =
      "https://fonts.googleapis.com/css2?family=Bodoni+Moda:ital,wght@0,400..900;1,400..900&family=Newsreader:ital,wght@0,400;0,500;1,400&family=DM+Mono:wght@400;500&display=swap";
    document.head.appendChild(link);
  }, []);
}

function PawPlaceholder({ size = 96 }) {
  return (
    <svg width={size} height={size} viewBox="0 0 100 100" aria-hidden="true">
      <circle cx="50" cy="62" r="22" fill={PALETTE.line} />
      <circle cx="26" cy="34" r="10" fill={PALETTE.line} />
      <circle cx="50" cy="24" r="10" fill={PALETTE.line} />
      <circle cx="74" cy="34" r="10" fill={PALETTE.line} />
      <circle cx="14" cy="54" r="8" fill={PALETTE.line} />
    </svg>
  );
}

function DogCard({ dog, onNext }) {
  const rescue = dog.rescue && RESCUES[dog.rescue];
  const n = String(DOGS.indexOf(dog) + 1).padStart(2, "0");

  return (
    <div
      style={{
        background: PALETTE.cream,
        border: `1px solid ${PALETTE.line}`,
        borderRadius: 4,
        overflow: "hidden",
        display: "flex",
        flexDirection: "column",
      }}
    >
      {/* Full-bleed square portrait — nothing sits on top of it. */}
      <div
        style={{
          width: "100%",
          /* Landscape rather than square: at full card width a 1:1 portrait
             ran taller than everything else in the dialog put together, and
             pushed the rescue's copy and its donate button off the bottom of
             a laptop screen. `focus` still moves the crop for the dogs who
             are not centred. */
          aspectRatio: "4 / 3",
          background: `color-mix(in oklab, ${PALETTE.ink} 6%, ${PALETTE.cream})`,
          display: "flex",
          alignItems: "center",
          justifyContent: "center",
          overflow: "hidden",
        }}
      >
        {dog.image ? (
          <img
            src={dog.image}
            alt={dog.name}
            /* The frame is square and the photos are not, so `cover` crops.
               `focus` moves the crop window when the dog is not centred —
               Ottis is a tall portrait with his head at the top. */
            style={{
              width: "100%",
              height: "100%",
              objectFit: "cover",
              objectPosition: dog.focus || "center",
              display: "block",
            }}
          />
        ) : (
          <PawPlaceholder size={128} />
        )}
      </div>

      {/* Caption block beneath the photo: foster number and rescue on one
          line, then the name, then the note. Tight leading throughout so it
          stays a caption rather than a paragraph. */}
      <div
        style={{
          padding: "10px 14px 13px",
          borderTop: `1px solid ${PALETTE.line}`,
          display: "flex",
          flexDirection: "column",
          gap: 4,
        }}
      >
        <div
          style={{
            display: "flex",
            alignItems: "baseline",
            justifyContent: "space-between",
            gap: 10,
            fontFamily: "var(--font-mono), monospace",
            fontSize: 8.5,
            lineHeight: 1,
            letterSpacing: "0.14em",
            textTransform: "uppercase",
          }}
        >
          <span style={{ color: PALETTE.teal }}>Foster #{n}</span>
          {rescue && (
            <span style={{ color: PALETTE.coral, textAlign: "right" }}>{rescue.label}</span>
          )}
        </div>

        {/* The name, and the way to the next dog on the same line — under the
            rescue it sits below. It was a full-width button in its own row,
            which cost the dialog a whole band of height for one control. */}
        <div
          style={{
            display: "flex",
            alignItems: "flex-end",
            justifyContent: "space-between",
            gap: 12,
          }}
        >
          <h3
            style={{
              fontFamily: "'Bodoni Moda', serif",
              fontWeight: 600,
              fontSize: 18,
              lineHeight: 1.05,
              letterSpacing: "-0.01em",
              margin: 0,
              color: PALETTE.ink,
            }}
          >
            {dog.name}
          </h3>

          {onNext && (
            <button
              onClick={onNext}
              style={{
                flex: "0 0 auto",
                padding: "5px 10px 6px",
                background: "transparent",
                border: `1px solid ${PALETTE.ink}`,
                borderRadius: 3,
                fontFamily: "'DM Mono', monospace",
                fontSize: 10,
                letterSpacing: "0.08em",
                textTransform: "uppercase",
                whiteSpace: "nowrap",
                cursor: "pointer",
                color: PALETTE.ink,
              }}
            >
              Next dog &rarr;
            </button>
          )}
        </div>

        {dog.note && (
          <p
            style={{
              fontFamily: "'Newsreader', serif",
              fontSize: 12.5,
              lineHeight: 1.35,
              margin: 0,
              color: PALETTE.ink,
            }}
          >
            {dog.note}
          </p>
        )}
      </div>
    </div>
  );
}

function MeetTheDogsModal({ onClose }) {
  useFonts();
  /* Controlled when the caller passes onClose: the parent decides it is open,
     and closing hands control back rather than tracking state here. */
  const controlled = typeof onClose === "function";
  const [openState, setOpenState] = useState(false);
  const open = controlled ? true : openState;
  const setOpen = (v) => { if (controlled) { if (!v) onClose(); } else setOpenState(v); };
  const [index, setIndex] = useState(0);

  const shuffle = useCallback(() => {
    setIndex((i) => (i + 1) % DOGS.length);
  }, []);

  useEffect(() => {
    if (!open) return;
    const onKey = (e) => {
      if (e.key === "Escape") setOpen(false);
      if (e.key === "ArrowRight") shuffle();
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [open, shuffle]);

  return (
    <div
      style={controlled ? { display: "contents" } : {
        fontFamily: "'Newsreader', serif",
        color: PALETTE.ink,
        padding: 32,
        background: PALETTE.cream,
      }}
    >
      {!controlled && (
      <button
        onClick={() => setOpen(true)}
        style={{
          background: "none",
          border: "none",
          padding: 0,
          font: "inherit",
          fontSize: 18,
          color: PALETTE.coral,
          textDecoration: "underline",
          textUnderlineOffset: 3,
          cursor: "pointer",
        }}
      >
        meet the dogs
      </button>
      )}

      {open && ReactDOM.createPortal(
        <div
          onClick={() => setOpen(false)}
          style={{
            position: "fixed",
            inset: 0,
            background: "rgba(20, 18, 16, 0.55)",
            display: "flex",
            alignItems: "center",
            justifyContent: "center",
            zIndex: 1000,
            padding: 20,
            overflowY: "auto",
          }}
        >
          <div
            onClick={(e) => e.stopPropagation()}
            style={{
              background: PALETTE.cream,
              /* Wide enough for the rescue's copy to read as a paragraph
                 beside its logo rather than as a narrow column of four-word
                 lines. The portrait is 100% of this width at 4:3, so the card
                 still gets shorter than it was at 312 square. */
              width: "min(360px, 100%)",
              maxHeight: "calc(100dvh - 40px)",
              borderRadius: 6,
              overflow: "hidden",
              display: "flex",
              flexDirection: "column",
              boxShadow: "0 30px 60px rgba(0,0,0,0.35)",
            }}
          >
            {/* header */}
            <div
              style={{
                display: "flex",
                justifyContent: "space-between",
                alignItems: "center",
                padding: "13px 18px",
                borderBottom: `1px solid ${PALETTE.line}`,
              }}
            >
              <span
                style={{
                  fontFamily: "'DM Mono', monospace",
                  fontSize: 11,
                  letterSpacing: "0.1em",
                  textTransform: "uppercase",
                  color: PALETTE.ink,
                  opacity: 0.6,
                }}
              >
                Fosters & rescues, DC + Detroit
              </span>
              <button
                onClick={() => setOpen(false)}
                aria-label="Close"
                style={{
                  background: "none",
                  border: "none",
                  fontSize: 20,
                  lineHeight: 1,
                  cursor: "pointer",
                  color: PALETTE.ink,
                }}
              >
                ×
              </button>
            </div>

            {/* dog card */}
            <div style={{ padding: 16 }}>
              <DogCard dog={DOGS[index]} onNext={shuffle} />
            </div>

            {/* rebel dogs promo */}
            <div
              style={{
                background: PALETTE.darkGrey,
                color: PALETTE.onDark,
                padding: "15px 18px 18px",
              }}
            >
              <div style={{ display: "flex", alignItems: "flex-start", gap: 13 }}>
                {/* The rescue's own mark. Drop the file at this path to switch
                    it on — until it is there the image removes itself and the
                    copy simply runs full width, so a missing file is a missing
                    logo rather than a broken layout. */}
                <img
                  src="/assets/logos/rebel-dogs.png"
                  alt=""
                  onError={(e) => { e.currentTarget.style.display = "none"; }}
                  style={{
                    flex: "0 0 auto",
                    width: 58,
                    height: 58,
                    objectFit: "contain",
                    /* The mark is drawn for a dark ground; nothing to invert. */
                  }}
                />
                <p
                  style={{
                    fontFamily: "'Newsreader', serif",
                    fontSize: 13,
                    lineHeight: 1.55,
                    margin: "0 0 16px",
                    color: "color-mix(in oklab, var(--paper) 88%, transparent)",
                  }}
                >
                  Rebel Dogs Detroit is a rescue collective built on a
                  street-to-home network for the city&rsquo;s abandoned and
                  abused dogs.
                </p>
              </div>
              <a
                href="https://rebeldogsdetroit.com/donate"
                target="_blank"
                rel="noopener noreferrer"
                style={{
                  display: "inline-block",
                  padding: "10px 18px",
                  background: PALETTE.coral,
                  color: PALETTE.onDark,
                  textDecoration: "none",
                  borderRadius: 4,
                  fontFamily: "'DM Mono', monospace",
                  fontSize: 12,
                  letterSpacing: "0.06em",
                  textTransform: "uppercase",
                }}
              >
                Donate to Rebel Dogs Detroit
              </a>
            </div>
          </div>
        </div>,
        document.body
      )}
    </div>
  );
}

Object.assign(window, { MeetTheDogsModal });
})();
