Untitled

 avatar
unknown
plain_text
3 months ago
31 kB
10
Indexable
import React, { useMemo, useState } from "react";
import { motion, AnimatePresence } from "framer-motion";
import { ArrowRight, RotateCcw, Trophy, Brain, Layers, Sparkles, Shuffle, CheckCircle2, XCircle, Eye, EyeOff, ChevronLeft, ChevronRight } from "lucide-react";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { Progress } from "@/components/ui/progress";
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";

const cuts = [
  {
    id: "bavette",
    name: "Bavette",
    tagline: "Beefy and sourced to be well marbled",
    beefiness: "Intense",
    juiciness: "Moderate",
    tenderness: "Mild",
    butchery: "Cut from the end edge of the flank, close to the sirloin.",
    texture: "Coarse-grained with a satisfying bite.",
    story: "Highly prized in France and often used for steak frites in brasseries.",
    questions: {
      comparison: "How does the Bavette compare to the Flat Iron in beefiness, juiciness, and tenderness?",
      factual1: "Where on the carcass is the Bavette located?",
      factual2: "How would you describe the texture of the Bavette?",
      heart1: "What makes Bavette such a great choice for guests?",
      heart2: "Why do you think secondary cuts are becoming more popular?"
    },
    answers: {
      comparison: "Bavette is more intense in beefiness than Flat Iron, less juicy, and less tender.",
      factual1: "From the end edge of the flank, close to the sirloin.",
      factual2: "It has a coarse grain and a more characterful bite.",
      heart1: "Open answer — focus on flavour, character, and its steak-frites appeal.",
      heart2: "Open answer — great for discussion around flavour, value, and discovery."
    }
  },
  {
    id: "flat-iron",
    name: "Flat Iron",
    tagline: "The cut that made us famous",
    beefiness: "Moderate",
    juiciness: "Intense",
    tenderness: "Intense",
    butchery: "Cut from the feather blade in the forequarter.",
    texture: "Notably tender and juicy when carefully seam-butchered.",
    story: "Named for its resemblance to an old-fashioned flat iron; the cut helped define the restaurant.",
    questions: {
      comparison: "How does the Flat Iron compare to other specials we have today?",
      factual1: "Where on the carcass does the Flat Iron cut come from?",
      factual2: "How would you describe the texture of the Flat Iron?",
      heart1: "What makes the Flat Iron so special to you?",
      heart2: "Why is our restaurant called Flat Iron?"
    },
    answers: {
      comparison: "Flat Iron stands out for very high juiciness and tenderness, with moderate beefiness.",
      factual1: "From the feather blade in the forequarter / shoulder area.",
      factual2: "Tender, juicy, and smooth in texture when properly seam-butchered.",
      heart1: "Open answer — talk about tenderness, juiciness, and brand identity.",
      heart2: "Because the steak resembles a traditional flat iron and it became the restaurant's signature cut."
    }
  },
  {
    id: "sirloin",
    name: "Sirloin",
    tagline: "Classic and balanced",
    beefiness: "Moderate",
    juiciness: "Moderate",
    tenderness: "Moderate",
    butchery: "Runs along the back of the carcass between the rib and the rump.",
    texture: "Balanced and familiar, with an all-round steak profile.",
    story: "Its name likely comes from the old French word surlonge, despite the famous sword-tap myth.",
    questions: {
      comparison: "How does Sirloin compare to Bavette?",
      factual1: "Where does the Sirloin come from on the carcass?",
      factual2: "What makes Sirloin a classic and balanced cut of beef?",
      heart1: "Why do you think Sirloin is such a popular choice for guests?",
      heart2: "Why do you think guests know about the sirloin more than other cuts?"
    },
    answers: {
      comparison: "Sirloin is more balanced and less intense than Bavette, especially in beefiness.",
      factual1: "Along the back of the carcass, between the rib and the rump.",
      factual2: "Its beefiness, juiciness, and tenderness all sit at a moderate, balanced level.",
      heart1: "Open answer — discuss familiarity, consistency, and broad appeal.",
      heart2: "Open answer — it is a well-known classic steak name."
    }
  },
  {
    id: "fore-fillet",
    name: "Fore Fillet",
    tagline: "Lean and tender",
    beefiness: "Mild",
    juiciness: "Moderate",
    tenderness: "Intense",
    butchery: "Found inside the forequarter, close to the feather blade.",
    texture: "Lean, refined, and very tender.",
    story: "Also described as a small forequarter fillet and sometimes called a hidden gem because of its small size and obscurity.",
    questions: {
      comparison: "Why is the tenderness of the Fore Fillet described as intense?",
      factual1: "Where is the Fore Fillet located on the carcass?",
      factual2: "Describe the beefiness, juiciness, and tenderness of the Fore Fillet?",
      heart1: "Why do you think the Fore Fillet is such a hidden gem for guests?",
      heart2: "What makes the Fore Fillet a great choice for those looking for something different?"
    },
    answers: {
      comparison: "Because it eats like a small fillet, with very high tenderness despite coming from the forequarter.",
      factual1: "Inside the forequarter, near the feather blade.",
      factual2: "Mild beefiness, moderate juiciness, and intense tenderness.",
      heart1: "Open answer — it feels special, unusual, and unexpectedly tender.",
      heart2: "Open answer — great for guests who want something leaner and less obvious."
    }
  },
  {
    id: "denver",
    name: "Denver",
    tagline: "Rich and beefy",
    beefiness: "Intense",
    juiciness: "Intense",
    tenderness: "Mild",
    butchery: "Sometimes known as chuck flap, sitting on top of the chuck muscle in the forequarter.",
    texture: "Fine-grained, rich, and boldly flavoured.",
    story: "In Japan it is known as zabuton, meaning cushion, because of the muscle's shape.",
    questions: {
      comparison: "What makes the Denver cut rich and beefy?",
      factual1: "Where on the carcass would you find the Denver cut?",
      factual2: "How would you describe the tenderness of the Denver compared to other cuts?",
      heart1: "What makes the Denver a unique and flavorful choice for steak lovers?",
      heart2: "Why might guests be surprised by the Denver cut?"
    },
    answers: {
      comparison: "It combines intense beefiness with intense juiciness, making it feel rich and full flavoured.",
      factual1: "On top of the chuck muscle in the forequarter; sometimes called chuck flap.",
      factual2: "It is less tender than cuts like Flat Iron or Fore Fillet, but packed with flavour.",
      heart1: "Open answer — talk about richness, juiciness, and a beef-forward profile.",
      heart2: "Open answer — many guests may not know the cut, yet it delivers huge flavour."
    }
  },
  {
    id: "ribeye",
    name: "Ribeye",
    tagline: "Classic and rich",
    beefiness: "Moderate",
    juiciness: "Intense",
    tenderness: "Intense",
    butchery: "Cut from the forerib on the back of the carcass, between the chuck and sirloin.",
    texture: "Rich, marbled, and explosively juicy, especially in the cap.",
    story: "The cap, or spinalis dorsi, is prized for its fine texture and intense juiciness.",
    questions: {
      comparison: "Choose a cut from the specials board and compare it to the Ribeye.",
      factual1: "Where does the Ribeye cut come from on the carcass?",
      factual2: "How would you describe the marbling in Ribeye and how it impacts the flavour?",
      heart1: "Why is Ribeye such a favourite with guests?",
      heart2: "What makes Ribeye one of the most flavourful cuts?"
    },
    answers: {
      comparison: "Ribeye is one of the juiciest and most tender cuts, thanks to rich marbling.",
      factual1: "From the forerib, between the chuck and sirloin on the back of the carcass.",
      factual2: "Ribeye has generous marbling, which boosts richness, juiciness, and flavour.",
      heart1: "Open answer — many guests love the richness and familiar luxury feel.",
      heart2: "Its marbling and the prized cap muscle give it exceptional flavour."
    }
  },
  {
    id: "hanger",
    name: "Hanger",
    tagline: "Beefy with a satisfying chew",
    beefiness: "Intense",
    juiciness: "Moderate",
    tenderness: "Mild",
    butchery: "Hangs inside the rib cage and has a thick piece of gristle through the centre that must be removed.",
    texture: "Bold, loose-textured, and known for a satisfying chew.",
    story: "Also called onglet in France, and there is only one hanger per carcass.",
    questions: {
      comparison: "Rate the Hanger's beefiness, tenderness and juiciness.",
      factual1: "Where is the Hanger cut located on the carcass?",
      factual2: "If a guest says Onglet, which cut are they referring to?",
      heart1: "In your opinion, what does it mean when the Hanger is described as having a satisfying chew?",
      heart2: "What makes Hanger steak unique?"
    },
    answers: {
      comparison: "Intense beefiness, moderate juiciness, and mild tenderness.",
      factual1: "Inside the rib cage, hanging internally.",
      factual2: "Hanger steak.",
      heart1: "Open answer — focus on texture, bite, and deep flavour.",
      heart2: "There is only one per carcass and it has a distinctive texture and flavour."
    }
  },
  {
    id: "skirt",
    name: "Skirt",
    tagline: "Thin and beefy",
    beefiness: "Intense",
    juiciness: "Moderate",
    tenderness: "Mild",
    butchery: "A long, thin muscle on the outside of the rib cage that runs along the ribs.",
    texture: "Thin, punchy, and deeply beefy.",
    story: "The restaurant uses only the outside skirt, a cut especially popular in Uruguay and Argentina.",
    questions: {
      comparison: "Describe the beefiness, juiciness, and tenderness of the Skirt?",
      factual1: "Where does Skirt steak come from on the carcass?",
      factual2: "At Flat Iron, do we use the inside or outside skirt?",
      heart1: "What makes the Skirt cut stand out when it comes to its flavour?",
      heart2: "Why would you recommend the Skirt to a guest who's never tried it before?"
    },
    answers: {
      comparison: "Intense beefiness, moderate juiciness, and mild tenderness.",
      factual1: "From the outside of the rib cage, running along the ribs.",
      factual2: "Outside skirt.",
      heart1: "Open answer — it delivers a really pronounced beef flavour.",
      heart2: "Open answer — it is memorable, distinctive, and full of flavour."
    }
  },
  {
    id: "picanha",
    name: "Picanha",
    tagline: "Delicious fat, superior marbling",
    beefiness: "Intense",
    juiciness: "Intense",
    tenderness: "Moderate",
    butchery: "A triangular muscle that sits on top of the rump.",
    texture: "Rich with excellent marbling and prized fat.",
    story: "The most popular cut in Brazil and central to Brazilian barbecue.",
    questions: {
      comparison: "How does Picanha compare to the Flat Iron steak?",
      factual1: "Where does the Picanha cut come from on the carcass?",
      factual2: "How would you describe the marbling in Picanha?",
      heart1: "How does the fat on the Picanha contribute to its flavour?",
      heart2: "What makes Picanha a favourite among guests?"
    },
    answers: {
      comparison: "Picanha is beefier and richer than Flat Iron, with equally high juiciness but only moderate tenderness.",
      factual1: "From the top of the rump.",
      factual2: "It has superior marbling compared with other muscles in the rump.",
      heart1: "Open answer — the fat carries flavour, richness, and succulence.",
      heart2: "Open answer — guests love the marbling, fat cap, and richness."
    }
  }
];

const additionalPrompts = [
  "What questions would you ask guests to help them identify which steak might be a good choice for them?",
  "Compare two cuts from today's specials.",
  "Compare today's specials by beefiness, juiciness, and tenderness.",
  "Which cuts are known for intense beefy flavour?",
  "Looking at the cards, which cuts are the juiciest?",
  "What is special about our burger?",
  "What cut of meat are we using for our burger patty?",
  "Where is the meat for the burger coming from?",
  "How does the fat in the meat enhance its flavour?",
  "What difference does it make if the cuts are Wagyu?",
  "Where does our Wagyu come from?",
  "Why do we include a non-meat special on our specials board?",
  "Why can the skirt only be cooked pink or well done?",
  "Why do we avoid using the words chew or chewy?"
];

const ratingMap = { Mild: 1, Moderate: 2, Intense: 3 };
const labelOrder = ["Mild", "Moderate", "Intense"];
const questionTypes = ["comparison", "factual1", "factual2", "heart1", "heart2"];

function shuffleArray(items) {
  const arr = [...items];
  for (let i = arr.length - 1; i > 0; i -= 1) {
    const j = Math.floor(Math.random() * (i + 1));
    [arr[i], arr[j]] = [arr[j], arr[i]];
  }
  return arr;
}

function buildQuizDeck() {
  return shuffleArray(
    cuts.flatMap((cut) =>
      questionTypes.map((type) => ({
        id: `${cut.id}-${type}`,
        cut: cut.name,
        type,
        prompt: cut.questions[type],
        answer: cut.answers[type],
        isOpen: type.startsWith("heart")
      }))
    )
  );
}

function StatPill({ label, value }) {
  const active = ratingMap[value] ?? 0;
  return (
    <div className="rounded-2xl border border-black bg-white p-3">
      <div className="mb-2 text-xs uppercase tracking-[0.22em] text-black/60">{label}</div>
      <div className="flex gap-1.5">
        {labelOrder.map((item, index) => {
          const filled = index < active;
          return (
            <div
              key={item}
              className={`h-2 flex-1 rounded-full border border-black ${filled ? "bg-black" : "bg-white"}`}
              title={item}
            />
          );
        })}
      </div>
      <div className="mt-2 text-sm font-medium">{value}</div>
    </div>
  );
}

function FlashCard({ cut }) {
  const [showStory, setShowStory] = useState(false);

  return (
    <motion.div
      initial={{ opacity: 0, y: 12 }}
      animate={{ opacity: 1, y: 0 }}
      transition={{ duration: 0.28 }}
      className="grid gap-4 lg:grid-cols-[1.1fr_0.9fr]"
    >
      <Card className="rounded-[28px] border-2 border-black bg-white shadow-none">
        <CardHeader className="space-y-4 pb-2">
          <div className="flex flex-wrap items-center gap-2">
            <Badge className="rounded-full border border-black bg-black px-3 py-1 text-white hover:bg-black">
              Steak Card
            </Badge>
            <Badge variant="outline" className="rounded-full border-black px-3 py-1 text-black">
              {cut.tagline}
            </Badge>
          </div>
          <div>
            <div className="text-xs uppercase tracking-[0.28em] text-black/55">Cut</div>
            <CardTitle className="mt-2 text-4xl tracking-tight">{cut.name}</CardTitle>
          </div>
          <p className="max-w-2xl text-base leading-7 text-black/70">{cut.texture}</p>
        </CardHeader>
        <CardContent className="space-y-5 pt-3">
          <div className="grid gap-3 sm:grid-cols-3">
            <StatPill label="Beefiness" value={cut.beefiness} />
            <StatPill label="Juiciness" value={cut.juiciness} />
            <StatPill label="Tenderness" value={cut.tenderness} />
          </div>
          <div className="rounded-3xl border border-black bg-black p-5 text-white">
            <div className="mb-2 text-xs uppercase tracking-[0.22em] text-white/60">Butchery</div>
            <p className="text-sm leading-6 text-white/90">{cut.butchery}</p>
          </div>
          <div className="rounded-3xl border border-dashed border-black p-5">
            <div className="mb-2 text-xs uppercase tracking-[0.22em] text-black/55">Story</div>
            <p className="text-sm leading-6 text-black/80">{showStory ? cut.story : "Tap reveal to use this as a memorable talking point with guests."}</p>
            <Button
              variant="outline"
              className="mt-4 rounded-full border-black text-black"
              onClick={() => setShowStory((v) => !v)}
            >
              {showStory ? <EyeOff className="mr-2 h-4 w-4" /> : <Eye className="mr-2 h-4 w-4" />}
              {showStory ? "Hide story" : "Reveal story"}
            </Button>
          </div>
        </CardContent>
      </Card>

      <Card className="rounded-[28px] border-2 border-black bg-[#f7f7f7] shadow-none">
        <CardHeader>
          <div className="text-xs uppercase tracking-[0.22em] text-black/55">Briefing prompts</div>
          <CardTitle className="text-2xl">Question set</CardTitle>
        </CardHeader>
        <CardContent className="space-y-3">
          {[
            ["Comparison", cut.questions.comparison],
            ["Factual 1", cut.questions.factual1],
            ["Factual 2", cut.questions.factual2],
            ["Heart 1", cut.questions.heart1],
            ["Heart 2", cut.questions.heart2]
          ].map(([label, question]) => (
            <div key={label} className="rounded-2xl border border-black bg-white p-4">
              <div className="mb-1 text-xs uppercase tracking-[0.22em] text-black/50">{label}</div>
              <p className="text-sm leading-6 text-black/85">{question}</p>
            </div>
          ))}
        </CardContent>
      </Card>
    </motion.div>
  );
}

function QuizArena() {
  const [deck, setDeck] = useState(buildQuizDeck());
  const [index, setIndex] = useState(0);
  const [revealed, setRevealed] = useState(false);
  const [score, setScore] = useState(0);
  const [streak, setStreak] = useState(0);
  const [answered, setAnswered] = useState(0);

  const current = deck[index];
  const progress = ((index + (revealed ? 1 : 0)) / deck.length) * 100;

  function reset() {
    setDeck(buildQuizDeck());
    setIndex(0);
    setRevealed(false);
    setScore(0);
    setStreak(0);
    setAnswered(0);
  }

  function mark(correct) {
    if (!current) return;
    setAnswered((v) => v + 1);
    if (correct) {
      setScore((v) => v + 1);
      setStreak((v) => v + 1);
    } else {
      setStreak(0);
    }

    if (index < deck.length - 1) {
      setIndex((v) => v + 1);
      setRevealed(false);
    } else {
      setRevealed(true);
    }
  }

  if (!current && answered > 0) {
    const pct = Math.round((score / answered) * 100);
    return (
      <Card className="rounded-[28px] border-2 border-black bg-white shadow-none">
        <CardContent className="flex flex-col items-center gap-6 p-8 text-center">
          <div className="rounded-full border-2 border-black p-4"><Trophy className="h-10 w-10" /></div>
          <div>
            <div className="text-xs uppercase tracking-[0.28em] text-black/50">Session complete</div>
            <h3 className="mt-2 text-4xl font-semibold tracking-tight">{pct}% score</h3>
            <p className="mt-3 text-base text-black/70">You got {score} out of {answered} marked prompts correct.</p>
          </div>
          <div className="grid w-full max-w-xl gap-3 sm:grid-cols-3">
            <div className="rounded-2xl border border-black p-4">
              <div className="text-xs uppercase tracking-[0.22em] text-black/50">Correct</div>
              <div className="mt-1 text-2xl font-semibold">{score}</div>
            </div>
            <div className="rounded-2xl border border-black p-4">
              <div className="text-xs uppercase tracking-[0.22em] text-black/50">Answered</div>
              <div className="mt-1 text-2xl font-semibold">{answered}</div>
            </div>
            <div className="rounded-2xl border border-black p-4">
              <div className="text-xs uppercase tracking-[0.22em] text-black/50">Accuracy</div>
              <div className="mt-1 text-2xl font-semibold">{pct}%</div>
            </div>
          </div>
          <Button onClick={reset} className="rounded-full bg-black px-5 text-white hover:bg-black">
            <RotateCcw className="mr-2 h-4 w-4" /> Play again
          </Button>
        </CardContent>
      </Card>
    );
  }

  return (
    <Card className="rounded-[28px] border-2 border-black bg-white shadow-none">
      <CardContent className="space-y-6 p-6 sm:p-8">
        <div className="flex flex-col gap-4 md:flex-row md:items-center md:justify-between">
          <div>
            <div className="text-xs uppercase tracking-[0.26em] text-black/50">Quick-fire challenge</div>
            <h3 className="mt-2 text-3xl font-semibold tracking-tight">Quiz Arena</h3>
          </div>
          <div className="grid grid-cols-3 gap-2 sm:gap-3">
            <div className="rounded-2xl border border-black px-4 py-3 text-center">
              <div className="text-[11px] uppercase tracking-[0.2em] text-black/50">Score</div>
              <div className="mt-1 text-xl font-semibold">{score}</div>
            </div>
            <div className="rounded-2xl border border-black px-4 py-3 text-center">
              <div className="text-[11px] uppercase tracking-[0.2em] text-black/50">Streak</div>
              <div className="mt-1 text-xl font-semibold">{streak}</div>
            </div>
            <div className="rounded-2xl border border-black px-4 py-3 text-center">
              <div className="text-[11px] uppercase tracking-[0.2em] text-black/50">Card</div>
              <div className="mt-1 text-xl font-semibold">{index + 1}/{deck.length}</div>
            </div>
          </div>
        </div>

        <Progress value={progress} className="h-2 border border-black bg-black/10" />

        <AnimatePresence mode="wait">
          <motion.div
            key={current.id}
            initial={{ opacity: 0, y: 10 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -10 }}
            transition={{ duration: 0.2 }}
            className="rounded-[28px] border-2 border-black bg-[#fafafa] p-6"
          >
            <div className="mb-4 flex flex-wrap items-center gap-2">
              <Badge className="rounded-full border border-black bg-black text-white hover:bg-black">{current.cut}</Badge>
              <Badge variant="outline" className="rounded-full border-black text-black">{current.type.replace(/\d/g, " ")}</Badge>
              {current.isOpen && <Badge variant="outline" className="rounded-full border-black text-black">Open discussion</Badge>}
            </div>
            <div className="text-xs uppercase tracking-[0.24em] text-black/50">Prompt</div>
            <p className="mt-3 text-2xl leading-9 tracking-tight text-black">{current.prompt}</p>

            <div className="mt-6 rounded-3xl border border-dashed border-black p-5">
              <div className="mb-2 text-xs uppercase tracking-[0.22em] text-black/50">Answer guide</div>
              <p className="text-sm leading-6 text-black/80">{revealed ? current.answer : "Think it through, then reveal the answer guide to check yourself."}</p>
            </div>

            <div className="mt-6 flex flex-wrap gap-3">
              {!revealed ? (
                <Button onClick={() => setRevealed(true)} className="rounded-full bg-black text-white hover:bg-black">
                  Reveal answer <ArrowRight className="ml-2 h-4 w-4" />
                </Button>
              ) : (
                <>
                  <Button
                    onClick={() => mark(true)}
                    className="rounded-full bg-black text-white hover:bg-black"
                  >
                    <CheckCircle2 className="mr-2 h-4 w-4" /> I got it
                  </Button>
                  <Button
                    onClick={() => mark(false)}
                    variant="outline"
                    className="rounded-full border-black text-black"
                  >
                    <XCircle className="mr-2 h-4 w-4" /> Needs work
                  </Button>
                </>
              )}
              <Button onClick={reset} variant="ghost" className="rounded-full text-black hover:bg-black/5">
                <Shuffle className="mr-2 h-4 w-4" /> Reshuffle
              </Button>
            </div>
          </motion.div>
        </AnimatePresence>
      </CardContent>
    </Card>
  );
}

function ChallengeDeck() {
  const [index, setIndex] = useState(0);
  const prompts = useMemo(() => shuffleArray(additionalPrompts), []);
  const current = prompts[index];

  return (
    <Card className="rounded-[28px] border-2 border-black bg-white shadow-none">
      <CardHeader>
        <div className="text-xs uppercase tracking-[0.24em] text-black/50">Team warm-up</div>
        <CardTitle className="text-3xl tracking-tight">Extra challenge prompts</CardTitle>
      </CardHeader>
      <CardContent className="space-y-6">
        <div className="rounded-[28px] border-2 border-black bg-[#f8f8f8] p-6">
          <div className="text-xs uppercase tracking-[0.24em] text-black/50">Prompt {index + 1} / {prompts.length}</div>
          <p className="mt-3 text-2xl leading-9 tracking-tight">{current}</p>
        </div>
        <div className="flex flex-wrap gap-3">
          <Button
            variant="outline"
            className="rounded-full border-black text-black"
            onClick={() => setIndex((v) => (v === 0 ? prompts.length - 1 : v - 1))}
          >
            <ChevronLeft className="mr-2 h-4 w-4" /> Previous
          </Button>
          <Button
            className="rounded-full bg-black text-white hover:bg-black"
            onClick={() => setIndex((v) => (v === prompts.length - 1 ? 0 : v + 1))}
          >
            Next <ChevronRight className="ml-2 h-4 w-4" />
          </Button>
        </div>
      </CardContent>
    </Card>
  );
}

export default function BeefyBriefingGameApp() {
  const [tab, setTab] = useState("cards");
  const [selected, setSelected] = useState(cuts[0].id);
  const currentCut = cuts.find((cut) => cut.id === selected) ?? cuts[0];

  return (
    <div
      className="min-h-screen bg-white text-black"
      style={{
        fontFamily: '"Gill Sans", "Gill Sans MT", Calibri, "Trebuchet MS", sans-serif'
      }}
    >
      <div className="mx-auto max-w-7xl px-4 py-8 sm:px-6 lg:px-8">
        <motion.div
          initial={{ opacity: 0, y: 14 }}
          animate={{ opacity: 1, y: 0 }}
          transition={{ duration: 0.28 }}
          className="mb-6 rounded-[34px] border-2 border-black bg-black px-6 py-8 text-white sm:px-8"
        >
          <div className="flex flex-col gap-5 lg:flex-row lg:items-end lg:justify-between">
            <div className="max-w-3xl">
              <div className="mb-3 inline-flex items-center gap-2 rounded-full border border-white/20 px-3 py-1 text-xs uppercase tracking-[0.25em] text-white/75">
                <Sparkles className="h-3.5 w-3.5" /> Briefing game app
              </div>
              <h1 className="text-4xl font-semibold tracking-tight sm:text-5xl">Beef Academy</h1>
              <p className="mt-4 max-w-2xl text-base leading-7 text-white/75 sm:text-lg">
                A clean black-and-white training game built from your steak cards and briefing questions.
                Browse the cuts, run quick-fire quizzes, and use extra prompts for team practice.
              </p>
            </div>
            <div className="grid grid-cols-3 gap-3">
              <div className="rounded-2xl border border-white/20 px-4 py-3">
                <div className="text-[11px] uppercase tracking-[0.2em] text-white/55">Cuts</div>
                <div className="mt-1 text-2xl font-semibold">{cuts.length}</div>
              </div>
              <div className="rounded-2xl border border-white/20 px-4 py-3">
                <div className="text-[11px] uppercase tracking-[0.2em] text-white/55">Quiz cards</div>
                <div className="mt-1 text-2xl font-semibold">{cuts.length * 5}</div>
              </div>
              <div className="rounded-2xl border border-white/20 px-4 py-3">
                <div className="text-[11px] uppercase tracking-[0.2em] text-white/55">Bonus prompts</div>
                <div className="mt-1 text-2xl font-semibold">{additionalPrompts.length}</div>
              </div>
            </div>
          </div>
        </motion.div>

        <Tabs value={tab} onValueChange={setTab} className="space-y-6">
          <TabsList className="h-auto rounded-full border border-black bg-white p-1">
            <TabsTrigger value="cards" className="rounded-full px-5 data-[state=active]:bg-black data-[state=active]:text-white">
              <Layers className="mr-2 h-4 w-4" /> Cut cards
            </TabsTrigger>
            <TabsTrigger value="quiz" className="rounded-full px-5 data-[state=active]:bg-black data-[state=active]:text-white">
              <Brain className="mr-2 h-4 w-4" /> Quiz arena
            </TabsTrigger>
            <TabsTrigger value="prompts" className="rounded-full px-5 data-[state=active]:bg-black data-[state=active]:text-white">
              <Sparkles className="mr-2 h-4 w-4" /> Bonus prompts
            </TabsTrigger>
          </TabsList>

          {tab === "cards" && (
            <div className="space-y-6">
              <div className="flex flex-wrap gap-2">
                {cuts.map((cut) => (
                  <Button
                    key={cut.id}
                    variant={selected === cut.id ? "default" : "outline"}
                    onClick={() => setSelected(cut.id)}
                    className={`rounded-full border-black px-4 ${selected === cut.id ? "bg-black text-white hover:bg-black" : "text-black"}`}
                  >
                    {cut.name}
                  </Button>
                ))}
              </div>
              <FlashCard cut={currentCut} />
            </div>
          )}

          {tab === "quiz" && <QuizArena />}
          {tab === "prompts" && <ChallengeDeck />}
        </Tabs>
      </div>
    </div>
  );
}
Editor is loading...
Leave a Comment