{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "pack-table",
  "title": "Pack table",
  "description": "A solver pack drawn instead of described: the table oval with the positions the solve covers, hero on the button, and pills for table size, street and every stack depth.",
  "files": [
    {
      "path": "src/components/pokerdata/pack-table-viz.tsx",
      "content": "import { Fragment } from \"react\";\n\n/**\n * The pack, drawn instead of described: a poker-table oval with the seat\n * positions the solve covers, hero on the button, and the pack's facts as\n * pills underneath — table size, street, and one pill per stack depth (the\n * bundle's whole ladder of pills IS the upsell pitch). Replaces the old\n * \"what you get\" text list in the plan picker and the buy drawer.\n *\n * Pure SVG + spans, server-renderable, monochrome to match the app chrome.\n */\n\nconst SIX_MAX = [\"UTG\", \"MP\", \"CO\", \"BTN\", \"SB\", \"BB\"];\nconst NINE_MAX = [\"UTG\", \"UTG+1\", \"UTG+2\", \"LJ\", \"HJ\", \"CO\", \"BTN\", \"SB\", \"BB\"];\n// Clockwise from the top, so the button lands at the bottom.\nconst EIGHT_MAX = [\"UTG+1\", \"LJ\", \"HJ\", \"CO\", \"BTN\", \"SB\", \"BB\", \"UTG\"];\n// Heads-up: the small blind is the button.\nconst HEADS_UP = [\"BB\", \"SB\"];\n\nconst POSITIONS: Record<number, string[]> = { 2: HEADS_UP, 8: EIGHT_MAX, 9: NINE_MAX };\n\n/** The table-size pill: \"6-max\", or \"Heads-up\" for two seats. */\nexport function seatsLabel(seats: number): string {\n  return seats === 2 ? \"Heads-up\" : `${seats}-max`;\n}\n\n/**\n * Just the table: the oval with the seat positions the solve covers, hero on\n * the button. `PackTableViz` wraps it with the fact pills; the pack details\n * header draws it on its own.\n */\nexport function PackTable({\n  seats,\n  className = \"w-full\",\n}: {\n  seats: number;\n  className?: string;\n}) {\n  const positions = POSITIONS[seats] ?? SIX_MAX;\n  const n = positions.length;\n\n  // Seats clockwise from the top; hero (BTN) lands at the bottom by\n  // construction for both layouts.\n  const cx = 150;\n  const cy = 102;\n  const rx = 102;\n  const ry = 86;\n  const seatAt = (i: number) => {\n    const a = ((-90 + (i * 360) / n) * Math.PI) / 180;\n    return { x: cx + rx * Math.cos(a), y: cy + ry * Math.sin(a) };\n  };\n\n  return (\n      <svg\n      viewBox=\"0 0 300 204\"\n      role=\"img\"\n      aria-label={`${seatsLabel(seats)} table — positions ${positions.join(\", \")}`}\n      className={className}\n    >\n      {/* Felt */}\n      <ellipse\n        cx={cx}\n        cy={cy}\n        rx={rx - 14}\n        ry={ry - 12}\n        className=\"fill-neutral-900 stroke-neutral-700\"\n        strokeWidth=\"1.5\"\n      />\n      <ellipse\n        cx={cx}\n        cy={cy}\n        rx={rx - 24}\n        ry={ry - 22}\n        fill=\"none\"\n        className=\"stroke-neutral-800\"\n      />\n      <text\n        x={cx}\n        y={cy + 3}\n        textAnchor=\"middle\"\n        className=\"fill-neutral-800 font-mono text-[9px] font-medium tracking-[0.35em]\"\n      >\n        POKERDATA\n      </text>\n\n      {/* Hero's cards, tucked above the button seat */}\n      <g transform={`translate(${cx}, ${cy + ry - 34})`}>\n        <rect\n          x=\"-19\"\n          y=\"-12\"\n          width=\"17\"\n          height=\"24\"\n          rx=\"3\"\n          transform=\"rotate(-8)\"\n          className=\"fill-neutral-900 stroke-neutral-600\"\n        />\n        <rect\n          x=\"2\"\n          y=\"-12\"\n          width=\"17\"\n          height=\"24\"\n          rx=\"3\"\n          transform=\"rotate(8)\"\n          className=\"fill-neutral-900 stroke-neutral-600\"\n        />\n      </g>\n\n      {/* Seat pills */}\n      {positions.map((p, i) => {\n        const { x, y } = seatAt(i);\n        const hero = p === \"BTN\" || (n === 2 && p === \"SB\");\n        const w = 14 + p.length * 7;\n        return (\n          <Fragment key={p}>\n            <rect\n              x={x - w / 2}\n              y={y - 11}\n              width={w}\n              height={22}\n              rx=\"11\"\n              className={\n                hero\n                  ? \"fill-neutral-100 stroke-neutral-100\"\n                  : \"fill-neutral-950 stroke-neutral-700\"\n              }\n            />\n            <text\n              x={x}\n              y={y + 3.5}\n              textAnchor=\"middle\"\n              className={\n                hero\n                  ? \"fill-neutral-900 text-[10px] font-semibold\"\n                  : \"fill-neutral-300 text-[10px] font-medium\"\n              }\n            >\n              {p}\n            </text>\n          </Fragment>\n        );\n      })}\n    </svg>\n  );\n}\n\nexport function PackTableViz({\n  seats,\n  stackBbs,\n  rake,\n  gameType,\n  label = \"Preflop\",\n  compact = false,\n}: {\n  seats: number;\n  stackBbs: number[];\n  rake?: string;\n  /** Game type pill, shown first, e.g. \"No Limit Hold'em\". */\n  gameType?: string;\n  /** The data-kind pill: \"Preflop\", or \"Postflop\" for a postflop-only game. */\n  label?: string;\n  /** Smaller table + tighter pills — used in the buy drawer. */\n  compact?: boolean;\n}) {\n  const positions = POSITIONS[seats] ?? SIX_MAX;\n\n  const pill = compact\n    ? \"inline-flex h-5 items-center rounded-full border border-neutral-800 bg-neutral-900 px-2 font-mono text-[11px] text-neutral-300\"\n    : \"inline-flex h-6 items-center rounded-full border border-neutral-800 bg-neutral-900 px-2.5 font-mono text-xs text-neutral-300\";\n\n  return (\n    <div className={compact ? \"flex flex-col gap-2\" : \"flex flex-col gap-3\"}>\n      <PackTable\n        seats={seats}\n        className={compact ? \"mx-auto h-auto w-[min(100%,200px)]\" : \"w-full\"}\n      />\n\n      {/* Game config, then a divider, then the stack ladder. */}\n      <div\n        className={compact ? \"flex flex-col gap-1\" : \"flex flex-col gap-1.5\"}\n      >\n        <div className=\"flex flex-wrap gap-1.5\">\n          {[\n            ...(gameType ? [gameType] : []),\n            seatsLabel(seats),\n            label,\n            ...(rake ? [`Rake ${rake}`] : []),\n          ].map((label) => (\n            <span key={label} className={pill}>\n              {label}\n            </span>\n          ))}\n        </div>\n        <div className=\"border-t border-neutral-800\" aria-hidden=\"true\" />\n        <div className=\"flex flex-wrap gap-1.5\">\n          {stackBbs.map((bb) => (\n            <span key={bb} className={pill}>\n              {bb}bb\n            </span>\n          ))}\n        </div>\n      </div>\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/pokerdata/pack-table-viz.tsx"
    }
  ],
  "type": "registry:component"
}