# Atlas: store admin

> A dense, quiet six-page admin for an online store: a dashboard with a live date range, sortable orders with bulk actions, an order page with a refund flow, products, customers and settings.

A shadcn/ui block from the [@ballmac](https://ui.ballmac.com) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/ballmac/template-atlas).

- Page, with a live preview: https://shadcn.exchange/r/ballmac/template-atlas
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/ballmac/template-atlas-light-a2173e5f07fb2973.png
- Registry item: https://ui.ballmac.com/r/template-atlas.json
- Categories: templates
- Listed: 2026-10-14, source last changed 2026-10-14

## Install

```bash
npx shadcn@latest add https://ui.ballmac.com/r/template-atlas.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- npm packages: `lucide-react`, `recharts`
- Registry items: `utils`, `https://ui.ballmac.com/r/badge.json`, `https://ui.ballmac.com/r/checkbox.json`, `https://ui.ballmac.com/r/chart.json`, `https://ui.ballmac.com/r/command.json`, `https://ui.ballmac.com/r/dialog.json`, `https://ui.ballmac.com/r/dropdown-menu.json`, `https://ui.ballmac.com/r/segmented-control.json`, `https://ui.ballmac.com/r/sheet.json`, `https://ui.ballmac.com/r/sparkline.json`, `https://ui.ballmac.com/r/switch.json`

## Notes from the registry

Pages are at /atlas, /atlas/orders, /atlas/orders/[id], /atlas/products, /atlas/customers and /atlas/settings. The palette is the atlasCss string in atlas-theme.tsx and the sample data is atlas-data.ts: replace it with calls to your own API.

## Files

### `registry/ballmac/components/templates/atlas/atlas-fonts.ts`

```ts
// Ballmac UI: Atlas template fonts. https://ui.ballmac.com/templates/template-atlas
import { Geist_Mono, Manrope } from "next/font/google"

export const atlasSans = Manrope({ variable: "--atlas-sans", subsets: ["latin"], display: "swap", preload: false })
export const atlasMono = Geist_Mono({ variable: "--atlas-mono", subsets: ["latin"], display: "swap", preload: false })
```

### `registry/ballmac/components/templates/atlas/atlas-data.ts`

```ts
// Ballmac UI: Atlas sample data. https://ui.ballmac.com/templates/template-atlas

export type AtlasPayment = "paid" | "pending" | "refunded"
export type AtlasFulfillment = "unfulfilled" | "shipped" | "delivered"
export type AtlasChannel = "Online store" | "Instagram" | "Wholesale" | "Pop-up"

export type AtlasOrder = {
  id: string
  /** ISO date-time, shown in UTC. */
  date: string
  customerId: string
  channel: AtlasChannel
  payment: AtlasPayment
  fulfillment: AtlasFulfillment
  items: { productId: string; qty: number }[]
}

export type AtlasProduct = { id: string; name: string; category: string; price: number; stock: number; status: "active" | "draft"; hue: number; sold: number }
export type AtlasCustomer = { id: string; name: string; email: string; city: string; segment: "VIP" | "New" | "At risk" | "Regular"; tone: number }

export const products: AtlasProduct[] = [
  { id: "p-01", name: "Field notebook, set of 3", category: "Paper", price: 24, stock: 142, status: "active", hue: 85, sold: 812 },
  { id: "p-02", name: "Brass pen, matte", category: "Writing", price: 58, stock: 7, status: "active", hue: 70, sold: 244 },
  { id: "p-03", name: "Waxed canvas tote", category: "Bags", price: 96, stock: 38, status: "active", hue: 150, sold: 301 },
  { id: "p-04", name: "Linen desk mat", category: "Desk", price: 68, stock: 55, status: "active", hue: 40, sold: 187 },
  { id: "p-05", name: "Graphite pencils, 12", category: "Writing", price: 16, stock: 260, status: "active", hue: 260, sold: 1204 },
  { id: "p-06", name: "Ceramic ink well", category: "Desk", price: 42, stock: 0, status: "active", hue: 200, sold: 98 },
  { id: "p-07", name: "Leather pen roll", category: "Bags", price: 74, stock: 21, status: "active", hue: 30, sold: 156 },
  { id: "p-08", name: "Stitched journal, A5", category: "Paper", price: 32, stock: 9, status: "active", hue: 120, sold: 530 },
  { id: "p-09", name: "Wooden letter tray", category: "Desk", price: 54, stock: 33, status: "draft", hue: 55, sold: 0 },
  { id: "p-10", name: "Wax seal kit", category: "Paper", price: 28, stock: 64, status: "active", hue: 15, sold: 219 },
  { id: "p-11", name: "Fountain pen, steel", category: "Writing", price: 120, stock: 12, status: "active", hue: 230, sold: 143 },
  { id: "p-12", name: "Travel ink, three colours", category: "Writing", price: 36, stock: 5, status: "active", hue: 300, sold: 267 },
]

export const customers: AtlasCustomer[] = [
  { id: "c-01", name: "Amara Okafor", email: "amara@fernhill.co", city: "Lagos", segment: "VIP", tone: 1 },
  { id: "c-02", name: "Lucas Meyer", email: "lucas.meyer@mail.de", city: "Berlin", segment: "Regular", tone: 2 },
  { id: "c-03", name: "Sofia Alvarez", email: "sofia@alvarez.studio", city: "Mexico City", segment: "VIP", tone: 3 },
  { id: "c-04", name: "Hana Kobayashi", email: "hana.k@tokyo.jp", city: "Tokyo", segment: "New", tone: 4 },
  { id: "c-05", name: "Daniel Reyes", email: "dreyes@harbor.io", city: "Manila", segment: "At risk", tone: 5 },
  { id: "c-06", name: "Priya Raman", email: "priya@raman.in", city: "Chennai", segment: "Regular", tone: 1 },
  { id: "c-07", name: "Marcus Lindqvist", email: "marcus@fjord.se", city: "Stockholm", segment: "VIP", tone: 2 },
  { id: "c-08", name: "Elena Rossi", email: "elena@rossi.it", city: "Milan", segment: "Regular", tone: 3 },
  { id: "c-09", name: "Tomás Beltrán", email: "tomas@beltran.ar", city: "Buenos Aires", segment: "New", tone: 4 },
  { id: "c-10", name: "Grace Mutasa", email: "grace@mutasa.zw", city: "Harare", segment: "At risk", tone: 5 },
  { id: "c-11", name: "Noah Fischer", email: "noah.fischer@web.ch", city: "Zürich", segment: "Regular", tone: 1 },
  { id: "c-12", name: "Yuki Tanaka", email: "yuki@tanaka.jp", city: "Osaka", segment: "VIP", tone: 2 },
]

const channels: AtlasChannel[] = ["Online store", "Online store", "Instagram", "Online store", "Wholesale", "Pop-up", "Online store", "Instagram"]
const payments: AtlasPayment[] = ["paid", "paid", "paid", "pending", "paid", "paid", "refunded", "paid", "paid", "pending"]
const fulfilments: AtlasFulfillment[] = ["delivered", "shipped", "unfulfilled", "delivered", "unfulfilled", "shipped", "delivered", "unfulfilled", "delivered", "shipped"]

/** 36 orders over three weeks, newest first. Built from fixed arithmetic so the server and browser agree. */
export const orders: AtlasOrder[] = Array.from({ length: 36 }, (_, i) => {
  const n = 10480 - i
  const day = 29 - Math.floor(i / 2)
  const hour = i % 2 === 0 ? 14 + (i % 5) : 8 + (i % 4)
  const minute = (i * 13) % 60
  const lines = 1 + (i % 3)
  const age = i < 6 ? 0 : i < 14 ? 1 : 2
  const payment = payments[i % payments.length]
  const fulfillment: AtlasFulfillment = payment === "pending" ? "unfulfilled" : age === 0 ? (i % 2 ? "unfulfilled" : "shipped") : fulfilments[i % fulfilments.length]
  return {
    id: `ORD-${n}`,
    date: `2026-09-${String(day).padStart(2, "0")}T${String(hour).padStart(2, "0")}:${String(minute).padStart(2, "0")}:00Z`,
    customerId: customers[(i * 5 + 1) % customers.length].id,
    channel: channels[i % channels.length],
    payment,
    fulfillment,
    items: Array.from({ length: lines }, (_, k) => ({ productId: products[(i * 3 + k * 4) % products.length].id, qty: 1 + ((i + k) % 3) })),
  }
})

export const getCustomer = (id: string) => customers.find((c) => c.id === id) ?? customers[0]
export const getProduct = (id: string) => products.find((p) => p.id === id) ?? products[0]
export const orderTotal = (o: AtlasOrder) => o.items.reduce((n, l) => n + getProduct(l.productId).price * l.qty, 0)
export const orderShipping = (o: AtlasOrder) => (orderTotal(o) >= 100 ? 0 : 8)
export const orderGrand = (o: AtlasOrder) => orderTotal(o) + orderShipping(o)

export const money = new Intl.NumberFormat("en-US", { style: "currency", currency: "USD", maximumFractionDigits: 0 })
export const moneyExact = new Intl.NumberFormat("en-US", { style: "currency", currency: "USD", minimumFractionDigits: 2 })
const dateFmt = new Intl.DateTimeFormat("en-US", { month: "short", day: "numeric", timeZone: "UTC" })
const timeFmt = new Intl.DateTimeFormat("en-US", { hour: "numeric", minute: "2-digit", timeZone: "UTC" })
export const formatDate = (iso: string) => dateFmt.format(new Date(iso))
export const formatTime = (iso: string) => timeFmt.format(new Date(iso))

export const initials = (name: string) => name.split(" ").map((w) => w[0]).join("").slice(0, 2)

/** Thirty daily revenue figures, the last one being today. */
export const revenueSeries = Array.from({ length: 30 }, (_, i) => {
  const base = 3200 + i * 46 + Math.round(Math.sin(i * 0.9) * 520) + (i % 7 === 5 ? 700 : 0)
  const previous = 2900 + i * 30 + Math.round(Math.cos(i * 0.8) * 430)
  return { day: `Sep ${i + 1}`, revenue: base, previous }
})
```

### `registry/ballmac/components/templates/atlas/atlas-theme.tsx`

```tsx
// Ballmac UI: Atlas template shell. https://ui.ballmac.com/templates/template-atlas
"use client"

import * as React from "react"
import { Bell, ChevronsUpDown, CircleHelp, LayoutDashboard, Menu, Package, Receipt, Search, Settings, Users } from "lucide-react"

import { Badge } from "@/components/ballmac/badge"
import { CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandShortcut } from "@/components/ballmac/command"
import { Sheet, SheetContent, SheetDescription, SheetTitle } from "@/components/ballmac/sheet"
import { atlasMono, atlasSans } from "@/components/ballmac/templates/atlas/atlas-fonts"
import { cn } from "@/lib/utils"

type AtlasPage = "dashboard" | "orders" | "products" | "customers" | "settings"
/** Where each page lives. `order` is the order detail page. */
type AtlasHrefs = Record<AtlasPage | "order", string>

const defaultHrefs: AtlasHrefs = {
  dashboard: "/atlas",
  orders: "/atlas/orders",
  order: "/atlas/orders/ORD-10479",
  products: "/atlas/products",
  customers: "/atlas/customers",
  settings: "/atlas/settings",
}

/** Atlas's palette: warm stone neutrals with one teal. Dense, quiet and easy to read all day. */
const atlasCss = `
.atlas-theme,body:not(:has([data-gallery])):has(.atlas-theme){--background:oklch(0.985 0.004 90);--foreground:oklch(0.2 0.012 80);--card:oklch(1 0 0);--card-foreground:oklch(0.2 0.012 80);--popover:oklch(1 0 0);--popover-foreground:oklch(0.2 0.012 80);--primary:oklch(0.26 0.012 80);--primary-foreground:oklch(0.985 0.004 90);--secondary:oklch(0.955 0.006 90);--secondary-foreground:oklch(0.2 0.012 80);--muted:oklch(0.955 0.006 90);--muted-foreground:oklch(0.47 0.015 85);--accent:oklch(0.94 0.008 90);--accent-foreground:oklch(0.2 0.012 80);--border:oklch(0.2 0.012 80 / 11%);--input:oklch(0.2 0.012 80 / 16%);--ring:oklch(0.5 0.1 190);--surface:oklch(0.968 0.006 90);--destructive:oklch(0.55 0.21 27);--chart-1:oklch(0.5 0.1 190);--chart-2:oklch(0.5 0.13 150);--chart-3:oklch(0.62 0.14 70);--chart-4:oklch(0.5 0.14 320);--chart-5:oklch(0.52 0.12 250);--radius:0.625rem}
.dark .atlas-theme,.dark body:not(:has([data-gallery])):has(.atlas-theme){--background:oklch(0.165 0.008 80);--foreground:oklch(0.95 0.006 90);--card:oklch(0.2 0.009 80);--card-foreground:oklch(0.95 0.006 90);--popover:oklch(0.22 0.01 80);--popover-foreground:oklch(0.95 0.006 90);--primary:oklch(0.95 0.006 90);--primary-foreground:oklch(0.2 0.012 80);--secondary:oklch(0.25 0.01 80);--secondary-foreground:oklch(0.95 0.006 90);--muted:oklch(0.24 0.01 80);--muted-foreground:oklch(0.72 0.015 85);--accent:oklch(0.27 0.012 80);--accent-foreground:oklch(0.95 0.006 90);--border:oklch(1 0 0 / 10%);--input:oklch(1 0 0 / 14%);--ring:oklch(0.74 0.11 190);--surface:oklch(0.185 0.009 80);--destructive:oklch(0.7 0.19 25);--chart-1:oklch(0.78 0.11 190);--chart-2:oklch(0.78 0.14 150);--chart-3:oklch(0.82 0.14 80);--chart-4:oklch(0.76 0.13 320);--chart-5:oklch(0.76 0.11 250)}
`

/** Dialogs, sheets and menus render in a portal on <body>, so the font is set there too while an Atlas page is mounted. */
const atlasBodyCss = `body:not(:has([data-gallery])):has(.atlas-theme){font-family:var(--atlas-sans),ui-sans-serif,system-ui,sans-serif}`

const nav: { key: AtlasPage; label: string; icon: typeof Receipt; badge?: string }[] = [
  { key: "dashboard", label: "Dashboard", icon: LayoutDashboard },
  { key: "orders", label: "Orders", icon: Receipt, badge: "8" },
  { key: "products", label: "Products", icon: Package },
  { key: "customers", label: "Customers", icon: Users },
  { key: "settings", label: "Settings", icon: Settings },
]

function AtlasMark({ className }: { className?: string }) {
  return (
    <svg viewBox="0 0 28 28" aria-hidden="true" className={cn("size-7", className)} fill="none">
      <rect width="28" height="28" rx="8" fill="var(--chart-1)" />
      <path d="M8 19 14 8l6 11M10.5 15h7" stroke="var(--card)" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  )
}

function SidebarNav({ page, hrefs, onNavigate }: { page: AtlasPage; hrefs: AtlasHrefs; onNavigate?: () => void }) {
  return (
    <div className="flex h-full flex-col">
      <div className="flex h-14 items-center gap-2.5 px-4">
        <AtlasMark />
        <div className="leading-tight">
          <p className="text-sm font-bold tracking-tight">Atlas</p>
          <p className="text-muted-foreground text-[11px]">Fieldnote Goods</p>
        </div>
      </div>
      <nav aria-label="Main" className="flex-1 space-y-0.5 px-2.5 py-3">
        {nav.map((n) => (
          <a
            key={n.key}
            href={hrefs[n.key]}
            onClick={onNavigate}
            aria-current={page === n.key ? "page" : undefined}
            className="text-muted-foreground hover:text-foreground hover:bg-accent aria-[current=page]:bg-accent aria-[current=page]:text-foreground focus-visible:ring-ring/50 flex items-center gap-2.5 rounded-lg px-2.5 py-2 text-sm font-medium outline-none transition-colors focus-visible:ring-[3px]"
          >
            <n.icon className="size-4" aria-hidden="true" />
            {n.label}
            {n.badge && <span className="bg-chart-1 text-primary-foreground ms-auto rounded-full px-1.5 text-[11px] font-semibold tabular-nums">{n.badge}</span>}
          </a>
        ))}
      </nav>
      <div className="border-t p-2.5">
        <button type="button" className="hover:bg-accent focus-visible:ring-ring/50 flex w-full items-center gap-2.5 rounded-lg p-2 text-start outline-none focus-visible:ring-[3px]">
          <span className="bg-chart-4/25 flex size-8 items-center justify-center rounded-full text-xs font-bold" aria-hidden="true">MK</span>
          <span className="min-w-0 flex-1 leading-tight">
            <span className="block truncate text-sm font-semibold">Mina Kovac</span>
            <span className="text-muted-foreground block truncate text-xs">Owner</span>
          </span>
          <ChevronsUpDown className="text-muted-foreground size-4" aria-hidden="true" />
        </button>
      </div>
    </div>
  )
}

type AtlasShellProps = Omit<React.ComponentProps<"div">, "title"> & {
  /** The page being shown, so its nav link is marked current. */
  page: AtlasPage
  /** Page title shown in the top bar. */
  title: string
  /** Override where pages live (used by previews). */
  hrefs?: Partial<AtlasHrefs>
  /** Controls on the right of the top bar. */
  actions?: React.ReactNode
}

/** Atlas's frame: sidebar, top bar with a command menu (⌘K), and a drawer on phones. Wrap every Atlas page in it. */
function AtlasShell({ page, title, hrefs: overrides, actions, className, style, children, ...props }: AtlasShellProps) {
  const hrefs = { ...defaultHrefs, ...overrides }
  const [drawer, setDrawer] = React.useState(false)
  const [palette, setPalette] = React.useState(false)
  // Portaled UI (command menu, sheet) lives outside this element; give <body> the font variables too.
  React.useEffect(() => {
    const classes = [atlasSans.variable, atlasMono.variable].filter(Boolean)
    document.body.classList.add(...classes)
    return () => document.body.classList.remove(...classes)
  }, [])
  return (
    <div
      data-slot="atlas"
      className={cn("atlas-theme bg-background text-foreground relative min-h-dvh lg:grid lg:grid-cols-[15rem_minmax(0,1fr)]", atlasSans.variable, atlasMono.variable, className)}
      style={{ fontFamily: "var(--atlas-sans), ui-sans-serif, system-ui, sans-serif", ...style }}
      {...props}
    >
      <style>{atlasCss + atlasBodyCss}</style>
      <aside className="bg-surface sticky top-0 hidden h-dvh border-e lg:block">
        <SidebarNav page={page} hrefs={hrefs} />
      </aside>
      <Sheet open={drawer} onOpenChange={setDrawer}>
        <SheetContent side="start" className="w-72 p-0" closeLabel="Close navigation">
          <SheetTitle className="sr-only">Navigation</SheetTitle>
          <SheetDescription className="sr-only">Pages in the Fieldnote Goods store</SheetDescription>
          <SidebarNav page={page} hrefs={hrefs} onNavigate={() => setDrawer(false)} />
        </SheetContent>
      </Sheet>

      <div className="min-w-0">
        <header className="bg-background/85 sticky top-0 z-30 flex h-14 items-center gap-3 border-b px-4 backdrop-blur-lg sm:px-6">
          <button type="button" aria-label="Open navigation" onClick={() => setDrawer(true)} className="hover:bg-accent focus-visible:ring-ring/50 -ms-1 inline-flex size-9 items-center justify-center rounded-lg outline-none focus-visible:ring-[3px] lg:hidden">
            <Menu className="size-5" aria-hidden="true" />
          </button>
          <h1 className="min-w-0 truncate text-[15px] font-bold tracking-tight">{title}</h1>
          <div className="ms-auto flex items-center gap-2">
            <button
              type="button"
              onClick={() => setPalette(true)}
              className="text-muted-foreground hover:text-foreground focus-visible:ring-ring/50 bg-card flex h-9 items-center gap-2 rounded-lg border px-2.5 text-sm outline-none transition-colors focus-visible:ring-[3px] sm:w-56"
            >
              <Search className="size-4" aria-hidden="true" />
              <span className="hidden flex-1 text-start sm:block">Search</span>
              <kbd className="bg-muted hidden rounded px-1.5 py-0.5 text-[11px] sm:block" style={{ fontFamily: "var(--atlas-mono)" }}>⌘K</kbd>
              <span className="sr-only sm:hidden">Search the store</span>
            </button>
            {actions}
            <button type="button" aria-label="Notifications, 3 unread" className="hover:bg-accent focus-visible:ring-ring/50 relative inline-flex size-9 items-center justify-center rounded-lg outline-none focus-visible:ring-[3px]">
              <Bell className="size-[18px]" aria-hidden="true" />
              <span className="bg-chart-3 absolute top-2 end-2.5 size-1.5 rounded-full" aria-hidden="true" />
            </button>
          </div>
        </header>
        {children}
      </div>

      <CommandDialog open={palette} onOpenChange={setPalette} title="Search the store">
        <CommandInput placeholder="Search pages, orders, products…" />
        <CommandList>
          <CommandEmpty>No results.</CommandEmpty>
          <CommandGroup heading="Go to">
            {nav.map((n) => (
              <CommandItem key={n.key} value={n.label} onSelect={() => { setPalette(false); window.location.assign(hrefs[n.key]) }}>
                <n.icon aria-hidden="true" /> {n.label}
              </CommandItem>
            ))}
          </CommandGroup>
          <CommandGroup heading="Recent orders">
            {["ORD-10479", "ORD-10479", "ORD-10476"].map((id) => (
              <CommandItem key={id} value={id} onSelect={() => { setPalette(false); window.location.assign(hrefs.order) }}>
                <Receipt aria-hidden="true" /> {id}
                <CommandShortcut>Order</CommandShortcut>
              </CommandItem>
            ))}
          </CommandGroup>
          <CommandGroup heading="Help">
            <CommandItem value="Help center"><CircleHelp aria-hidden="true" /> Help center</CommandItem>
          </CommandGroup>
        </CommandList>
      </CommandDialog>
    </div>
  )
}

/** The heading row of a page: title text, a description and actions. */
function AtlasPageHeader({ title, description, children }: { title: string; description?: string; children?: React.ReactNode }) {
  return (
    <div className="flex flex-wrap items-end justify-between gap-4">
      <div className="min-w-0">
        <h2 className="text-2xl font-extrabold tracking-[-0.03em]">{title}</h2>
        {description && <p className="text-muted-foreground mt-1 text-sm text-pretty">{description}</p>}
      </div>
      {children && <div className="flex flex-wrap items-center gap-2">{children}</div>}
    </div>
  )
}

const buttonBase = "focus-visible:ring-ring/50 inline-flex h-9 shrink-0 items-center justify-center gap-2 rounded-lg px-3.5 text-sm font-semibold outline-none transition-colors focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&_svg]:size-4"
/** Class names for Atlas buttons, so links and buttons match. */
const atlasButton = {
  primary: cn(buttonBase, "bg-primary text-primary-foreground hover:opacity-90"),
  outline: cn(buttonBase, "bg-card hover:bg-accent border"),
  ghost: cn(buttonBase, "hover:bg-accent"),
  danger: cn(buttonBase, "bg-card text-destructive border-destructive/40 hover:bg-destructive/10 border"),
}

const paymentTone = { paid: "success", pending: "warning", refunded: "neutral" } as const
const fulfilmentTone = { unfulfilled: "warning", shipped: "neutral", delivered: "success" } as const
const label = (s: string) => s[0].toUpperCase() + s.slice(1)

/** Payment status as a badge. */
function PaymentBadge({ value }: { value: keyof typeof paymentTone }) {
  return <Badge status={paymentTone[value]} variant="outline">{label(value)}</Badge>
}
/** Fulfilment status as a badge. */
function FulfilmentBadge({ value }: { value: keyof typeof fulfilmentTone }) {
  return <Badge status={fulfilmentTone[value]} variant="outline">{label(value)}</Badge>
}

/** A small painted tile standing in for a product photo. */
function ProductTile({ hue, className }: { hue: number; className?: string }) {
  return (
    <span
      aria-hidden="true"
      className={cn("relative block overflow-hidden rounded-lg", className)}
      style={{ background: `linear-gradient(135deg, oklch(0.9 0.06 ${hue}), oklch(0.78 0.1 ${hue + 30}))` }}
    >
      <span className="absolute inset-x-[22%] bottom-0 h-[58%] rounded-t-md" style={{ background: `oklch(0.55 0.1 ${hue} / 0.55)` }} />
    </span>
  )
}

export { AtlasMark, AtlasPageHeader, AtlasShell, FulfilmentBadge, PaymentBadge, ProductTile, atlasButton, defaultHrefs as atlasDefaultHrefs, type AtlasHrefs, type AtlasPage, type AtlasShellProps }
```

### `registry/ballmac/components/templates/atlas/atlas-dashboard.tsx`

```tsx
// Ballmac UI: Atlas dashboard page. https://ui.ballmac.com/templates/template-atlas
"use client"

import * as React from "react"
import { AlertTriangle, ArrowDownRight, ArrowRight, ArrowUpRight, Download, PackageX, Truck } from "lucide-react"
import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from "recharts"

import { ChartContainer, ChartLegend, ChartLegendContent, ChartTooltip, ChartTooltipContent, type ChartConfig } from "@/components/ballmac/chart"
import { SegmentedControl, SegmentedControlItem } from "@/components/ballmac/segmented-control"
import { Sparkline } from "@/components/ballmac/sparkline"
import { formatDate, getCustomer, initials, money, moneyExact, orderGrand, orders, products, revenueSeries } from "@/components/ballmac/templates/atlas/atlas-data"
import { AtlasPageHeader, AtlasShell, FulfilmentBadge, PaymentBadge, ProductTile, atlasButton, type AtlasHrefs } from "@/components/ballmac/templates/atlas/atlas-theme"
import { cn } from "@/lib/utils"

type Range = "7" | "30"

const config = { revenue: { label: "This period", color: "var(--chart-1)" }, previous: { label: "Previous period", color: "var(--chart-3)" } } satisfies ChartConfig

const sum = (xs: number[]) => xs.reduce((a, b) => a + b, 0)
const pct = (a: number, b: number) => ((a - b) / b) * 100

type AtlasDashboardProps = React.ComponentProps<"div"> & { hrefs?: Partial<AtlasHrefs> }

/** The Atlas dashboard: a date range that recomputes the KPIs and chart, work that needs attention, top products and recent orders. */
function AtlasDashboard({ hrefs, ...props }: AtlasDashboardProps) {
  const [range, setRange] = React.useState<Range>("30")
  const n = Number(range)
  const data = revenueSeries.slice(-n)
  const revenue = sum(data.map((d) => d.revenue))
  const previous = sum(data.map((d) => d.previous))
  const orderCount = Math.round(revenue / 71)
  const prevOrders = Math.round(previous / 69)
  const conversion = 2.1 + n * 0.004
  const aov = revenue / orderCount

  const kpis = [
    { label: "Revenue", value: money.format(revenue), delta: pct(revenue, previous), trend: data.map((d) => d.revenue) },
    { label: "Orders", value: orderCount.toLocaleString("en-US"), delta: pct(orderCount, prevOrders), trend: data.map((d) => Math.round(d.revenue / 70)) },
    { label: "Conversion", value: `${conversion.toFixed(1)}%`, delta: 4.2, trend: data.map((d, i) => 2 + Math.sin(i * 0.5) * 0.3 + i * 0.01) },
    { label: "Average order", value: moneyExact.format(aov), delta: -1.8, trend: data.map((d, i) => 70 + Math.cos(i * 0.7) * 6 - i * 0.1) },
  ]

  const unfulfilled = orders.filter((o) => o.fulfillment === "unfulfilled" && o.payment !== "pending").length
  const pending = orders.filter((o) => o.payment === "pending").length
  const low = products.filter((p) => p.stock <= 10 && p.status === "active")
  const top = [...products].filter((p) => p.status === "active").sort((a, b) => b.sold * b.price - a.sold * a.price).slice(0, 5)
  const topMax = top[0].sold * top[0].price
  const recent = orders.slice(0, 6)
  const h = { orders: hrefs?.orders ?? "/atlas/orders", order: hrefs?.order ?? "/atlas/orders/ORD-10479", products: hrefs?.products ?? "/atlas/products" }

  return (
    <AtlasShell
      page="dashboard"
      title="Dashboard"
      hrefs={hrefs}
      actions={<a href={h.orders} className={cn(atlasButton.primary, "hidden sm:inline-flex")}>View orders</a>}
      {...props}
    >
      <main className="mx-auto max-w-7xl space-y-6 px-4 py-6 sm:px-6">
        <AtlasPageHeader title="Good morning, Mina" description="Here is how Fieldnote Goods is doing.">
          <SegmentedControl aria-label="Date range" value={range} onValueChange={(v) => setRange(v as Range)} size="sm">
            <SegmentedControlItem value="7">7 days</SegmentedControlItem>
            <SegmentedControlItem value="30">30 days</SegmentedControlItem>
          </SegmentedControl>
          <button type="button" className={atlasButton.outline}><Download aria-hidden="true" /> Export</button>
        </AtlasPageHeader>

        <section aria-label="Key figures" className="grid gap-3 sm:grid-cols-2 xl:grid-cols-4">
          {kpis.map((k) => {
            const up = k.delta >= 0
            const Arrow = up ? ArrowUpRight : ArrowDownRight
            return (
              <div key={k.label} className="bg-card rounded-xl border p-4">
                <p className="text-muted-foreground text-sm font-medium">{k.label}</p>
                <div className="mt-2 flex items-end justify-between gap-3">
                  <p className="text-[1.65rem] leading-none font-extrabold tracking-[-0.03em] tabular-nums">{k.value}</p>
                  <Sparkline values={k.trend} label={`${k.label} trend over ${n} days`} height={32} showEnd={false} className="text-chart-1 w-20 shrink-0" />
                </div>
                <p className="mt-3 flex items-center gap-1 text-xs">
                  <Arrow className={cn("size-3.5", up ? "text-chart-2" : "text-destructive")} aria-hidden="true" />
                  <span className="font-semibold tabular-nums">{Math.abs(k.delta).toFixed(1)}%</span>
                  <span className="text-muted-foreground">{up ? "up" : "down"} from the previous {n} days</span>
                </p>
              </div>
            )
          })}
        </section>

        <div className="grid gap-4 xl:grid-cols-[minmax(0,1fr)_21rem]">
          <section aria-labelledby="atlas-rev" className="bg-card min-w-0 rounded-xl border p-4 sm:p-5">
            <div className="flex items-baseline justify-between gap-3">
              <h3 id="atlas-rev" className="text-sm font-bold">Revenue</h3>
              <p className="text-muted-foreground text-xs">Daily, last {n} days</p>
            </div>
            <ChartContainer
              config={config}
              label={`Daily revenue for the last ${n} days compared with the previous period`}
              summary={`Revenue totalled ${money.format(revenue)}, ${Math.abs(pct(revenue, previous)).toFixed(1)} percent ${revenue >= previous ? "above" : "below"} the previous period.`}
              className="mt-4 aspect-[16/7] w-full"
            >
              <AreaChart data={data} margin={{ left: 0, right: 8, top: 8 }} accessibilityLayer>
                <defs>
                  <linearGradient id="atlas-fill" x1="0" y1="0" x2="0" y2="1">
                    <stop offset="5%" stopColor="var(--color-revenue)" stopOpacity={0.28} />
                    <stop offset="95%" stopColor="var(--color-revenue)" stopOpacity={0.02} />
                  </linearGradient>
                </defs>
                <CartesianGrid vertical={false} />
                <XAxis dataKey="day" tickLine={false} axisLine={false} tickMargin={8} interval={n === 7 ? 0 : 4} />
                <YAxis tickLine={false} axisLine={false} width={44} tickFormatter={(v: number) => `$${(v / 1000).toFixed(1)}k`} />
                <ChartTooltip cursor={false} content={<ChartTooltipContent indicator="line" formatter={(v) => money.format(Number(v))} />} />
                <Area dataKey="previous" type="monotone" fill="none" stroke="var(--color-previous)" strokeWidth={1.5} strokeDasharray="4 4" dot={false} isAnimationActive={false} />
                <Area dataKey="revenue" type="monotone" fill="url(#atlas-fill)" stroke="var(--color-revenue)" strokeWidth={2} dot={false} isAnimationActive={false} />
                <ChartLegend content={<ChartLegendContent />} />
              </AreaChart>
            </ChartContainer>
          </section>

          <section aria-labelledby="atlas-attn" className="bg-card rounded-xl border">
            <h3 id="atlas-attn" className="px-4 pt-4 text-sm font-bold sm:px-5">Needs attention</h3>
            <ul className="mt-2 divide-y">
              {[
                { icon: Truck, text: `${unfulfilled} orders to fulfil`, hint: "Oldest from 2 days ago", href: h.orders, tone: "bg-chart-3/20" },
                { icon: AlertTriangle, text: `${pending} payments pending`, hint: "Bank transfers, 1 to 3 days", href: h.orders, tone: "bg-chart-5/20" },
                { icon: PackageX, text: `${low.length} products low on stock`, hint: low.slice(0, 2).map((p) => p.name.split(",")[0]).join(", ") + " and more", href: h.products, tone: "bg-destructive/15" },
              ].map((a) => (
                <li key={a.text}>
                  <a href={a.href} className="hover:bg-accent focus-visible:ring-ring/50 flex items-center gap-3 px-4 py-3 outline-none transition-colors focus-visible:ring-[3px] focus-visible:ring-inset sm:px-5">
                    <span className={cn("flex size-9 shrink-0 items-center justify-center rounded-lg", a.tone)}><a.icon className="size-4" aria-hidden="true" /></span>
                    <span className="min-w-0 flex-1"><span className="block text-sm font-semibold">{a.text}</span><span className="text-muted-foreground block truncate text-xs">{a.hint}</span></span>
                    <ArrowRight className="text-muted-foreground size-4 rtl:rotate-180" aria-hidden="true" />
                  </a>
                </li>
              ))}
            </ul>
            <div className="border-t p-4 sm:p-5">
              <h3 className="text-sm font-bold">Top products</h3>
              <ul className="mt-3 space-y-3">
                {top.map((p) => (
                  <li key={p.id} className="flex items-center gap-3">
                    <ProductTile hue={p.hue} className="size-9 shrink-0" />
                    <div className="min-w-0 flex-1">
                      <p className="truncate text-sm font-medium">{p.name}</p>
                      <div className="bg-muted mt-1.5 h-1.5 rounded-full"><div className="bg-chart-1 h-full rounded-full" style={{ width: `${(p.sold * p.price / topMax) * 100}%` }} /></div>
                    </div>
                    <p className="text-sm font-semibold tabular-nums">{money.format(p.sold * p.price)}</p>
                  </li>
                ))}
              </ul>
            </div>
          </section>
        </div>

        <section aria-labelledby="atlas-recent" className="bg-card overflow-hidden rounded-xl border">
          <div className="flex items-center justify-between px-4 py-3.5 sm:px-5">
            <h3 id="atlas-recent" className="text-sm font-bold">Recent orders</h3>
            <a href={h.orders} className="text-chart-1 focus-visible:ring-ring/50 rounded text-sm font-semibold underline-offset-4 outline-none hover:underline focus-visible:ring-[3px]">View all</a>
          </div>
          <div tabIndex={0} role="region" aria-label="Recent orders" className="focus-visible:ring-ring/50 overflow-x-auto outline-none focus-visible:ring-[3px] focus-visible:ring-inset">
            <table className="w-full min-w-[40rem] text-start text-sm">
              <caption className="sr-only">Most recent orders</caption>
              <thead>
                <tr className="text-muted-foreground bg-surface border-y text-xs">
                  {["Order", "Date", "Customer", "Payment", "Fulfilment", "Total"].map((c, i) => <th key={c} scope="col" className={cn("px-4 py-2.5 font-semibold sm:px-5", i === 5 && "text-end")}>{c}</th>)}
                </tr>
              </thead>
              <tbody className="divide-y">
                {recent.map((o) => {
                  const c = getCustomer(o.customerId)
                  return (
                    <tr key={o.id} className="hover:bg-accent/50">
                      <td className="px-4 py-3 sm:px-5"><a href={h.order} className="text-chart-1 font-semibold underline-offset-4 hover:underline" style={{ fontFamily: "var(--atlas-mono)" }}>{o.id}</a></td>
                      <td className="text-muted-foreground px-4 py-3 whitespace-nowrap sm:px-5">{formatDate(o.date)}</td>
                      <td className="px-4 py-3 sm:px-5"><span className="flex items-center gap-2.5"><span className={cn("flex size-7 items-center justify-center rounded-full text-[11px] font-bold", ["bg-chart-1/20", "bg-chart-2/20", "bg-chart-3/25", "bg-chart-4/20", "bg-chart-5/20"][c.tone - 1])} aria-hidden="true">{initials(c.name)}</span>{c.name}</span></td>
                      <td className="px-4 py-3 sm:px-5"><PaymentBadge value={o.payment} /></td>
                      <td className="px-4 py-3 sm:px-5"><FulfilmentBadge value={o.fulfillment} /></td>
                      <td className="px-4 py-3 text-end font-semibold tabular-nums sm:px-5">{moneyExact.format(orderGrand(o))}</td>
                    </tr>
                  )
                })}
              </tbody>
            </table>
          </div>
        </section>
      </main>
    </AtlasShell>
  )
}

export { AtlasDashboard, type AtlasDashboardProps }
```

### `registry/ballmac/components/templates/atlas/atlas-orders.tsx`

```tsx
// Ballmac UI: Atlas orders page. https://ui.ballmac.com/templates/template-atlas
"use client"

import * as React from "react"
import { ArrowDown, ArrowUp, ArrowUpDown, ChevronLeft, ChevronRight, Download, Printer, Search, Truck, X } from "lucide-react"

import { Checkbox } from "@/components/ballmac/checkbox"
import { formatDate, formatTime, getCustomer, initials, moneyExact, orderGrand, orders as seed, type AtlasOrder } from "@/components/ballmac/templates/atlas/atlas-data"
import { AtlasPageHeader, AtlasShell, FulfilmentBadge, PaymentBadge, atlasButton, type AtlasHrefs } from "@/components/ballmac/templates/atlas/atlas-theme"
import { cn } from "@/lib/utils"

type Tab = "all" | "unfulfilled" | "unpaid" | "shipped" | "delivered"
type SortKey = "date" | "customer" | "channel" | "total"

const tabs: { id: Tab; label: string; test: (o: AtlasOrder) => boolean }[] = [
  { id: "all", label: "All", test: () => true },
  { id: "unfulfilled", label: "Unfulfilled", test: (o) => o.fulfillment === "unfulfilled" },
  { id: "unpaid", label: "Unpaid", test: (o) => o.payment === "pending" },
  { id: "shipped", label: "Shipped", test: (o) => o.fulfillment === "shipped" },
  { id: "delivered", label: "Delivered", test: (o) => o.fulfillment === "delivered" },
]

const PAGE = 10
const tones = ["bg-chart-1/20", "bg-chart-2/20", "bg-chart-3/25", "bg-chart-4/20", "bg-chart-5/20"]

type AtlasOrdersProps = React.ComponentProps<"div"> & { hrefs?: Partial<AtlasHrefs> }

/** The Atlas orders page: status tabs with counts, search, sortable columns, row selection with bulk actions, and pagination. */
function AtlasOrders({ hrefs, ...props }: AtlasOrdersProps) {
  const [rows, setRows] = React.useState<AtlasOrder[]>(seed)
  const [tab, setTab] = React.useState<Tab>("all")
  const [query, setQuery] = React.useState("")
  const [sort, setSort] = React.useState<{ key: SortKey; dir: "asc" | "desc" }>({ key: "date", dir: "desc" })
  const [page, setPage] = React.useState(0)
  const [selected, setSelected] = React.useState<Set<string>>(new Set())
  const orderHref = hrefs?.order ?? "/atlas/orders/ORD-10479"

  const q = query.trim().toLowerCase()
  const filtered = rows
    .filter(tabs.find((t) => t.id === tab)!.test)
    .filter((o) => !q || [o.id, getCustomer(o.customerId).name, o.channel].join(" ").toLowerCase().includes(q))
  const sorted = [...filtered].sort((a, b) => {
    const dir = sort.dir === "asc" ? 1 : -1
    const val = (o: AtlasOrder) => (sort.key === "date" ? o.date : sort.key === "customer" ? getCustomer(o.customerId).name : sort.key === "channel" ? o.channel : orderGrand(o))
    const x = val(a)
    const y = val(b)
    return (x < y ? -1 : x > y ? 1 : 0) * dir
  })
  const pages = Math.max(1, Math.ceil(sorted.length / PAGE))
  const safePage = Math.min(page, pages - 1)
  const view = sorted.slice(safePage * PAGE, safePage * PAGE + PAGE)
  const allOnPage = view.length > 0 && view.every((o) => selected.has(o.id))
  const someOnPage = view.some((o) => selected.has(o.id))

  function toggleSort(key: SortKey) {
    setSort((s) => (s.key === key ? { key, dir: s.dir === "asc" ? "desc" : "asc" } : { key, dir: key === "total" || key === "date" ? "desc" : "asc" }))
    setPage(0)
  }
  function toggleAll(on: boolean) {
    setSelected((s) => {
      const next = new Set(s)
      for (const o of view) on ? next.add(o.id) : next.delete(o.id)
      return next
    })
  }
  function toggleOne(id: string, on: boolean) {
    setSelected((s) => {
      const next = new Set(s)
      on ? next.add(id) : next.delete(id)
      return next
    })
  }
  function markShipped() {
    setRows((all) => all.map((o) => (selected.has(o.id) && o.fulfillment === "unfulfilled" && o.payment !== "pending" ? { ...o, fulfillment: "shipped" } : o)))
    setSelected(new Set())
  }

  const head = (k: SortKey, children: React.ReactNode, right?: boolean) => (
    <th key={k} scope="col" aria-sort={sort.key === k ? (sort.dir === "asc" ? "ascending" : "descending") : "none"} className={cn("px-3 py-2.5 font-semibold", right && "text-end")}>
      <button type="button" onClick={() => toggleSort(k)} className={cn("hover:text-foreground focus-visible:ring-ring/50 -mx-1.5 inline-flex items-center gap-1 rounded px-1.5 py-0.5 outline-none focus-visible:ring-[3px]", sort.key === k && "text-foreground")}>
        {children}
        {sort.key === k ? (sort.dir === "asc" ? <ArrowUp className="size-3" aria-hidden="true" /> : <ArrowDown className="size-3" aria-hidden="true" />) : <ArrowUpDown className="size-3 opacity-50" aria-hidden="true" />}
      </button>
    </th>
  )

  return (
    <AtlasShell page="orders" title="Orders" hrefs={hrefs} actions={<button type="button" className={cn(atlasButton.outline, "hidden sm:inline-flex")}><Download aria-hidden="true" /> Export</button>} {...props}>
      <main className="mx-auto max-w-7xl space-y-5 px-4 py-6 sm:px-6">
        <AtlasPageHeader title="Orders" description="Everything customers have bought, across every channel." />

        <div className="bg-card rounded-xl border">
          <div className="flex flex-col gap-3 border-b p-3 lg:flex-row lg:items-center lg:justify-between">
            <div role="group" aria-label="Filter by status" className="flex gap-1 overflow-x-auto [scrollbar-width:none]">
              {tabs.map((t) => {
                const count = rows.filter(t.test).length
                const on = tab === t.id
                return (
                  <button
                    key={t.id}
                    type="button"
                    aria-pressed={on}
                    onClick={() => { setTab(t.id); setPage(0); setSelected(new Set()) }}
                    className={cn("focus-visible:ring-ring/50 flex shrink-0 items-center gap-1.5 rounded-lg px-3 py-1.5 text-sm font-semibold outline-none transition-colors focus-visible:ring-[3px]", on ? "bg-accent text-foreground" : "text-muted-foreground hover:text-foreground")}
                  >
                    {t.label} <span className="text-muted-foreground text-xs font-medium tabular-nums">{count}</span>
                  </button>
                )
              })}
            </div>
            <div className="relative lg:w-72">
              <Search className="text-muted-foreground pointer-events-none absolute top-1/2 start-3 size-4 -translate-y-1/2" aria-hidden="true" />
              <input
                type="search"
                aria-label="Search orders"
                value={query}
                onChange={(e) => { setQuery(e.target.value); setPage(0) }}
                placeholder="Search order, customer or channel"
                className="bg-background focus-visible:ring-ring/50 placeholder:text-muted-foreground h-9 w-full rounded-lg border pe-3 ps-9 text-sm outline-none focus-visible:ring-[3px]"
              />
            </div>
          </div>

          {selected.size > 0 && (
            <div role="region" aria-label="Bulk actions" className="bg-accent flex flex-wrap items-center gap-2 border-b px-3 py-2">
              <p className="me-auto text-sm font-semibold" aria-live="polite">{selected.size} selected</p>
              <button type="button" onClick={markShipped} className={atlasButton.outline}><Truck aria-hidden="true" /> Mark as shipped</button>
              <button type="button" className={atlasButton.outline}><Printer aria-hidden="true" /> Print labels</button>
              <button type="button" onClick={() => setSelected(new Set())} aria-label="Clear selection" className={cn(atlasButton.ghost, "px-2.5")}><X aria-hidden="true" /></button>
            </div>
          )}

          <div tabIndex={0} role="region" aria-label="Orders table" className="focus-visible:ring-ring/50 overflow-x-auto outline-none focus-visible:ring-[3px] focus-visible:ring-inset">
            <table className="w-full min-w-[52rem] text-start text-sm">
              <caption className="sr-only">Orders, {sorted.length} shown</caption>
              <thead>
                <tr className="text-muted-foreground bg-surface border-b text-xs">
                  <th scope="col" className="w-10 px-3 py-2.5"><Checkbox aria-label="Select all orders on this page" checked={allOnPage ? true : someOnPage ? "indeterminate" : false} onCheckedChange={(v) => toggleAll(v === true)} /></th>
                  <th scope="col" className="px-3 py-2.5 font-semibold">Order</th>
                  {head("date", "Date")}
                  {head("customer", "Customer")}
                  {head("channel", "Channel")}
                  <th scope="col" className="px-3 py-2.5 font-semibold">Payment</th>
                  <th scope="col" className="px-3 py-2.5 font-semibold">Fulfilment</th>
                  {head("total", "Total", true)}
                </tr>
              </thead>
              <tbody className="divide-y">
                {view.map((o) => {
                  const c = getCustomer(o.customerId)
                  const on = selected.has(o.id)
                  return (
                    <tr key={o.id} data-state={on ? "selected" : undefined} className="hover:bg-accent/40 data-[state=selected]:bg-accent/60">
                      <td className="px-3 py-3"><Checkbox aria-label={`Select ${o.id}`} checked={on} onCheckedChange={(v) => toggleOne(o.id, v === true)} /></td>
                      <td className="px-3 py-3"><a href={orderHref} className="text-chart-1 font-semibold underline-offset-4 hover:underline" style={{ fontFamily: "var(--atlas-mono)" }}>{o.id}</a></td>
                      <td className="text-muted-foreground px-3 py-3 whitespace-nowrap">{formatDate(o.date)}<span className="ms-1.5 text-xs">{formatTime(o.date)}</span></td>
                      <td className="px-3 py-3"><span className="flex items-center gap-2.5 whitespace-nowrap"><span className={cn("flex size-7 shrink-0 items-center justify-center rounded-full text-[11px] font-bold", tones[c.tone - 1])} aria-hidden="true">{initials(c.name)}</span>{c.name}</span></td>
                      <td className="text-muted-foreground px-3 py-3 whitespace-nowrap">{o.channel}</td>
                      <td className="px-3 py-3"><PaymentBadge value={o.payment} /></td>
                      <td className="px-3 py-3"><FulfilmentBadge value={o.fulfillment} /></td>
                      <td className="px-3 py-3 text-end font-semibold tabular-nums">{moneyExact.format(orderGrand(o))}</td>
                    </tr>
                  )
                })}
                {view.length === 0 && (
                  <tr><td colSpan={8} className="text-muted-foreground px-3 py-16 text-center">No orders match. Try another status or clear the search.</td></tr>
                )}
              </tbody>
            </table>
          </div>

          <div className="flex items-center justify-between gap-3 border-t px-3 py-2.5 text-sm">
            <p className="text-muted-foreground" role="status">
              {sorted.length === 0 ? "No orders" : `Showing ${safePage * PAGE + 1}–${safePage * PAGE + view.length} of ${sorted.length}`}
            </p>
            <div className="flex items-center gap-1">
              <button type="button" aria-label="Previous page" disabled={safePage === 0} onClick={() => setPage(safePage - 1)} className={cn(atlasButton.outline, "px-2.5")}><ChevronLeft aria-hidden="true"  className="rtl:rotate-180"/></button>
              <span className="text-muted-foreground px-2 text-xs tabular-nums">Page {safePage + 1} of {pages}</span>
              <button type="button" aria-label="Next page" disabled={safePage >= pages - 1} onClick={() => setPage(safePage + 1)} className={cn(atlasButton.outline, "px-2.5")}><ChevronRight aria-hidden="true"  className="rtl:rotate-180"/></button>
            </div>
          </div>
        </div>
      </main>
    </AtlasShell>
  )
}

export { AtlasOrders, type AtlasOrdersProps }
```

### `registry/ballmac/components/templates/atlas/atlas-order.tsx`

```tsx
// Ballmac UI: Atlas order detail page. https://ui.ballmac.com/templates/template-atlas
"use client"

import * as React from "react"
import { Check, ChevronRight, CreditCard, Mail, MapPin, MoreHorizontal, Printer, RotateCcw, Truck } from "lucide-react"

import { Checkbox } from "@/components/ballmac/checkbox"
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ballmac/dialog"
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from "@/components/ballmac/dropdown-menu"
import { formatDate, formatTime, getCustomer, getProduct, initials, moneyExact, orderShipping, orderTotal, orders } from "@/components/ballmac/templates/atlas/atlas-data"
import { AtlasShell, FulfilmentBadge, PaymentBadge, ProductTile, atlasButton, type AtlasHrefs } from "@/components/ballmac/templates/atlas/atlas-theme"
import { cn } from "@/lib/utils"

type Event = { id: string; title: string; detail?: string; at: string }

type AtlasOrderProps = React.ComponentProps<"div"> & {
  /** Which sample order to show. */
  orderId?: string
  hrefs?: Partial<AtlasHrefs>
}

/** The Atlas order page: items and totals, a live timeline, fulfilment and a refund flow with validation, plus customer and notes. */
function AtlasOrder({ orderId = "ORD-10479", hrefs, ...props }: AtlasOrderProps) {
  const base = orders.find((o) => o.id === orderId) ?? orders[1]
  const customer = getCustomer(base.customerId)
  const [fulfillment, setFulfillment] = React.useState(base.fulfillment)
  const [payment, setPayment] = React.useState(base.payment)
  const [refunded, setRefunded] = React.useState(0)
  const [events, setEvents] = React.useState<Event[]>([
    { id: "e3", title: "Payment captured", detail: `${moneyExact.format(orderTotal(base) + orderShipping(base))} on Visa ending 4242`, at: base.date },
    { id: "e2", title: "Order confirmation sent", detail: `Emailed to ${customer.email}`, at: base.date },
    { id: "e1", title: "Order placed", detail: `via ${base.channel}`, at: base.date },
  ])
  const [note, setNote] = React.useState("Gift wrap please. Leave with the neighbour if nobody is home.")
  const [savedNote, setSavedNote] = React.useState(note)
  const [refundOpen, setRefundOpen] = React.useState(false)
  const [picked, setPicked] = React.useState<Record<string, boolean>>({})
  const [reason, setReason] = React.useState("")
  const [error, setError] = React.useState("")
  const [announce, setAnnounce] = React.useState("")

  const subtotal = orderTotal(base)
  const shipping = orderShipping(base)
  const total = subtotal + shipping
  const refundAmount = base.items.reduce((n, l) => n + (picked[l.productId] ? getProduct(l.productId).price * l.qty : 0), 0)
  const stamp = "2026-09-29T14:20:00Z"

  function addEvent(title: string, detail?: string) {
    setEvents((all) => [{ id: `e${all.length + 1}-${title}`, title, detail, at: stamp }, ...all])
  }
  function ship() {
    setFulfillment("shipped")
    addEvent("Marked as shipped", "Tracking sent to the customer")
    setAnnounce(`${base.id} marked as shipped`)
  }
  function refund() {
    if (refundAmount === 0) return setError("Choose at least one item to refund.")
    if (!reason) return setError("Pick a reason so your team can follow up.")
    setRefunded(refundAmount)
    if (refundAmount === subtotal) setPayment("refunded")
    addEvent(`Refunded ${moneyExact.format(refundAmount)}`, `Reason: ${reason}`)
    setAnnounce(`Refunded ${moneyExact.format(refundAmount)}`)
    setRefundOpen(false)
    setPicked({})
    setReason("")
    setError("")
  }

  return (
    <AtlasShell page="orders" title="Orders" hrefs={hrefs} {...props}>
      <main className="mx-auto max-w-6xl space-y-5 px-4 py-6 sm:px-6">
        <nav aria-label="Breadcrumb" className="text-muted-foreground flex items-center gap-1 text-sm">
          <a href={hrefs?.orders ?? "/atlas/orders"} className="hover:text-foreground focus-visible:ring-ring/50 rounded outline-none focus-visible:ring-[3px]">Orders</a>
          <ChevronRight className="size-3.5 rtl:rotate-180" aria-hidden="true" />
          <span className="text-foreground font-medium" aria-current="page">{base.id}</span>
        </nav>

        <div className="flex flex-wrap items-start justify-between gap-4">
          <div>
            <div className="flex flex-wrap items-center gap-2.5">
              <h2 className="text-2xl font-extrabold tracking-[-0.03em]" style={{ fontFamily: "var(--atlas-mono)" }}>{base.id}</h2>
              <PaymentBadge value={payment} />
              <FulfilmentBadge value={fulfillment} />
            </div>
            <p className="text-muted-foreground mt-1.5 text-sm">{formatDate(base.date)} at {formatTime(base.date)} · {base.channel}</p>
          </div>
          <div className="flex flex-wrap items-center gap-2">
            <button type="button" className={atlasButton.outline} onClick={() => setRefundOpen(true)} disabled={payment === "refunded"}><RotateCcw aria-hidden="true" /> Refund</button>
            {fulfillment === "unfulfilled" && payment !== "pending" ? (
              <button type="button" className={atlasButton.primary} onClick={ship}><Truck aria-hidden="true" /> Mark as shipped</button>
            ) : (
              <button type="button" className={atlasButton.outline}><Printer aria-hidden="true" /> Print packing slip</button>
            )}
            <DropdownMenu>
              <DropdownMenuTrigger className={cn(atlasButton.outline, "px-2.5")} aria-label="More actions"><MoreHorizontal aria-hidden="true" /></DropdownMenuTrigger>
              <DropdownMenuContent align="end">
                <DropdownMenuItem>Duplicate order</DropdownMenuItem>
                <DropdownMenuItem>Download invoice</DropdownMenuItem>
                <DropdownMenuSeparator />
                <DropdownMenuItem destructive>Cancel order</DropdownMenuItem>
              </DropdownMenuContent>
            </DropdownMenu>
          </div>
        </div>
        <p role="status" className="sr-only">{announce}</p>

        <div className="grid gap-4 lg:grid-cols-[minmax(0,1fr)_20rem]">
          <div className="min-w-0 space-y-4">
            <section aria-labelledby="ao-items" className="bg-card rounded-xl border">
              <h3 id="ao-items" className="px-5 pt-4 text-sm font-bold">Items</h3>
              <ul className="divide-y px-5">
                {base.items.map((l) => {
                  const p = getProduct(l.productId)
                  return (
                    <li key={l.productId} className="flex items-center gap-4 py-4">
                      <ProductTile hue={p.hue} className="size-14 shrink-0" />
                      <div className="min-w-0 flex-1">
                        <p className="truncate font-semibold">{p.name}</p>
                        <p className="text-muted-foreground text-sm">{p.category} · {moneyExact.format(p.price)} each</p>
                      </div>
                      <p className="text-muted-foreground text-sm tabular-nums">× {l.qty}</p>
                      <p className="w-20 text-end font-semibold tabular-nums">{moneyExact.format(p.price * l.qty)}</p>
                    </li>
                  )
                })}
              </ul>
              <dl className="bg-surface space-y-2 rounded-b-xl border-t px-5 py-4 text-sm">
                <div className="flex justify-between"><dt className="text-muted-foreground">Subtotal</dt><dd className="tabular-nums">{moneyExact.format(subtotal)}</dd></div>
                <div className="flex justify-between"><dt className="text-muted-foreground">Shipping</dt><dd className="tabular-nums">{shipping === 0 ? "Free" : moneyExact.format(shipping)}</dd></div>
                {refunded > 0 && <div className="flex justify-between"><dt className="text-muted-foreground">Refunded</dt><dd className="text-destructive tabular-nums">−{moneyExact.format(refunded)}</dd></div>}
                <div className="flex justify-between border-t pt-3 text-base font-bold"><dt>Total</dt><dd className="tabular-nums">{moneyExact.format(total - refunded)}</dd></div>
              </dl>
            </section>

            <section aria-labelledby="ao-timeline" className="bg-card rounded-xl border p-5">
              <h3 id="ao-timeline" className="text-sm font-bold">Timeline</h3>
              <ol className="mt-4">
                {events.map((e, i) => (
                  <li key={e.id} className="relative flex gap-3.5 pb-5 last:pb-0">
                    {i < events.length - 1 && <span className="bg-border absolute top-5 bottom-0 start-[7px] w-px" aria-hidden="true" />}
                    <span className={cn("relative mt-1 size-3.5 shrink-0 rounded-full border-2", i === 0 ? "border-chart-1 bg-chart-1" : "bg-card border-muted-foreground/50")} aria-hidden="true" />
                    <div className="min-w-0 flex-1">
                      <p className="text-sm font-semibold">{e.title}</p>
                      {e.detail && <p className="text-muted-foreground text-sm text-pretty">{e.detail}</p>}
                    </div>
                    <p className="text-muted-foreground shrink-0 text-xs tabular-nums">{formatDate(e.at)}, {formatTime(e.at)}</p>
                  </li>
                ))}
              </ol>
            </section>
          </div>

          <aside className="space-y-4">
            <section aria-labelledby="ao-customer" className="bg-card rounded-xl border p-5">
              <h3 id="ao-customer" className="text-sm font-bold">Customer</h3>
              <div className="mt-4 flex items-center gap-3">
                <span className="bg-chart-1/20 flex size-11 items-center justify-center rounded-full text-sm font-bold" aria-hidden="true">{initials(customer.name)}</span>
                <div className="min-w-0"><p className="truncate font-semibold">{customer.name}</p><p className="text-muted-foreground text-sm">{customer.segment === "VIP" ? "VIP customer" : "Customer since 2025"}</p></div>
              </div>
              <a href={`mailto:${customer.email}`} className="text-chart-1 mt-4 flex items-center gap-2 text-sm underline-offset-4 hover:underline"><Mail className="size-4" aria-hidden="true" />{customer.email}</a>
              <p className="text-muted-foreground mt-3 flex items-start gap-2 text-sm"><MapPin className="mt-0.5 size-4 shrink-0" aria-hidden="true" />{customer.city}<br />Shipping and billing address match</p>
              <p className="text-muted-foreground mt-3 flex items-center gap-2 text-sm"><CreditCard className="size-4" aria-hidden="true" />Visa ending 4242</p>
            </section>
            <section aria-labelledby="ao-notes" className="bg-card rounded-xl border p-5">
              <h3 id="ao-notes" className="text-sm font-bold">Notes</h3>
              <label htmlFor="ao-note" className="sr-only">Order notes</label>
              <textarea id="ao-note" rows={4} value={note} onChange={(e) => setNote(e.target.value)} className="bg-background focus-visible:ring-ring/50 mt-3 w-full resize-none rounded-lg border p-3 text-sm outline-none focus-visible:ring-[3px]" />
              <div className="mt-3 flex items-center justify-between">
                <p className="text-muted-foreground flex items-center gap-1.5 text-xs" role="status">{note === savedNote ? <><Check className="size-3.5" aria-hidden="true" />Saved</> : "Unsaved changes"}</p>
                <button type="button" disabled={note === savedNote} onClick={() => { setSavedNote(note); addEvent("Note updated") }} className={atlasButton.outline}>Save note</button>
              </div>
            </section>
          </aside>
        </div>
      </main>

      <Dialog open={refundOpen} onOpenChange={(o) => { setRefundOpen(o); if (!o) setError("") }}>
        <DialogContent className="max-w-md">
          <DialogHeader>
            <DialogTitle>Refund {base.id}</DialogTitle>
            <DialogDescription>Choose what to send back to the customer. The money returns to their Visa in 5 to 10 days.</DialogDescription>
          </DialogHeader>
          <fieldset className="space-y-2">
            <legend className="sr-only">Items to refund</legend>
            {base.items.map((l) => {
              const p = getProduct(l.productId)
              return (
                <label key={l.productId} className="hover:bg-accent/50 flex cursor-pointer items-center gap-3 rounded-lg border p-3 text-sm">
                  <Checkbox checked={!!picked[l.productId]} onCheckedChange={(v) => setPicked((s) => ({ ...s, [l.productId]: v === true }))} />
                  <span className="min-w-0 flex-1 truncate font-medium">{p.name} <span className="text-muted-foreground font-normal">× {l.qty}</span></span>
                  <span className="tabular-nums">{moneyExact.format(p.price * l.qty)}</span>
                </label>
              )
            })}
          </fieldset>
          <div>
            <label htmlFor="ao-reason" className="text-sm font-medium">Reason</label>
            <select id="ao-reason" value={reason} onChange={(e) => setReason(e.target.value)} className="bg-background focus-visible:ring-ring/50 mt-1.5 h-10 w-full rounded-lg border px-3 text-sm outline-none focus-visible:ring-[3px]">
              <option value="">Choose a reason</option>
              <option>Damaged in transit</option>
              <option>Changed their mind</option>
              <option>Wrong item sent</option>
            </select>
          </div>
          {error && <p role="alert" className="text-destructive text-sm">{error}</p>}
          <DialogFooter>
            <button type="button" className={atlasButton.outline} onClick={() => setRefundOpen(false)}>Cancel</button>
            <button type="button" className={atlasButton.primary} onClick={refund}>Refund {refundAmount > 0 ? moneyExact.format(refundAmount) : ""}</button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </AtlasShell>
  )
}

export { AtlasOrder, type AtlasOrderProps }
```

### `registry/ballmac/components/templates/atlas/atlas-products.tsx`

```tsx
// Ballmac UI: Atlas products page. https://ui.ballmac.com/templates/template-atlas
"use client"

import * as React from "react"
import { LayoutGrid, List, Minus, Plus, Search } from "lucide-react"

import { Badge } from "@/components/ballmac/badge"
import { SegmentedControl, SegmentedControlItem } from "@/components/ballmac/segmented-control"
import { Sheet, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle } from "@/components/ballmac/sheet"
import { moneyExact, products as seed, type AtlasProduct } from "@/components/ballmac/templates/atlas/atlas-data"
import { AtlasPageHeader, AtlasShell, ProductTile, atlasButton, type AtlasHrefs } from "@/components/ballmac/templates/atlas/atlas-theme"
import { cn } from "@/lib/utils"

type View = "grid" | "list"

function Stock({ p }: { p: AtlasProduct }) {
  if (p.stock === 0) return <Badge status="error" variant="outline">Out of stock</Badge>
  if (p.stock <= 10) return <Badge status="warning" variant="outline">{p.stock} left</Badge>
  return <span className="text-muted-foreground text-sm tabular-nums">{p.stock} in stock</span>
}

const categories = ["Paper", "Writing", "Bags", "Desk"]
const fieldClass = "bg-background focus-visible:ring-ring/50 mt-1.5 h-10 w-full rounded-lg border px-3 text-sm outline-none focus-visible:ring-[3px] aria-[invalid=true]:border-destructive"

type AtlasProductsProps = React.ComponentProps<"div"> & { hrefs?: Partial<AtlasHrefs> }

/** The Atlas products page: search, category and low-stock filters, grid or list, quick stock edits and an add-product drawer with validation. */
function AtlasProducts({ hrefs, ...props }: AtlasProductsProps) {
  const [items, setItems] = React.useState<AtlasProduct[]>(seed)
  const [query, setQuery] = React.useState("")
  const [category, setCategory] = React.useState("all")
  const [lowOnly, setLowOnly] = React.useState(false)
  const [view, setView] = React.useState<View>("grid")
  const [open, setOpen] = React.useState(false)
  const [errors, setErrors] = React.useState<{ name?: string; price?: string }>({})

  const q = query.trim().toLowerCase()
  const shown = items.filter((p) => (category === "all" || p.category === category) && (!lowOnly || p.stock <= 10) && (!q || p.name.toLowerCase().includes(q)))
  const lowCount = items.filter((p) => p.stock <= 10).length

  function adjust(id: string, by: number) {
    setItems((all) => all.map((p) => (p.id === id ? { ...p, stock: Math.max(0, p.stock + by) } : p)))
  }
  function add(e: React.FormEvent<HTMLFormElement>) {
    e.preventDefault()
    const f = new FormData(e.currentTarget)
    const name = String(f.get("name") ?? "").trim()
    const price = Number(f.get("price"))
    const next: typeof errors = {}
    if (!name) next.name = "Give the product a name."
    if (!(price > 0)) next.price = "Enter a price above $0."
    setErrors(next)
    if (next.name || next.price) {
      ;(e.currentTarget.elements.namedItem(next.name ? "name" : "price") as HTMLElement | null)?.focus()
      return
    }
    setItems((all) => [{ id: `p-new-${all.length}`, name, category: String(f.get("category")), price, stock: Number(f.get("stock")) || 0, status: f.get("status") === "draft" ? "draft" : "active", hue: 180 + all.length * 17, sold: 0 }, ...all])
    setOpen(false)
  }

  return (
    <AtlasShell page="products" title="Products" hrefs={hrefs} actions={<button type="button" onClick={() => setOpen(true)} className={cn(atlasButton.primary, "hidden sm:inline-flex")}><Plus aria-hidden="true" /> Add product</button>} {...props}>
      <main className="mx-auto max-w-7xl space-y-5 px-4 py-6 sm:px-6">
        <AtlasPageHeader title="Products" description={`${items.length} products · ${lowCount} need restocking`}>
          <button type="button" onClick={() => setOpen(true)} className={cn(atlasButton.primary, "sm:hidden")}><Plus aria-hidden="true" /> Add product</button>
        </AtlasPageHeader>

        <div className="flex flex-wrap items-center gap-2">
          <div className="relative min-w-52 flex-1 sm:max-w-xs">
            <Search className="text-muted-foreground pointer-events-none absolute top-1/2 start-3 size-4 -translate-y-1/2" aria-hidden="true" />
            <input type="search" aria-label="Search products" value={query} onChange={(e) => setQuery(e.target.value)} placeholder="Search products" className="bg-card focus-visible:ring-ring/50 placeholder:text-muted-foreground h-9 w-full rounded-lg border pe-3 ps-9 text-sm outline-none focus-visible:ring-[3px]" />
          </div>
          <select aria-label="Category" value={category} onChange={(e) => setCategory(e.target.value)} className="bg-card focus-visible:ring-ring/50 h-9 rounded-lg border px-3 text-sm outline-none focus-visible:ring-[3px]">
            <option value="all">All categories</option>
            {categories.map((c) => <option key={c}>{c}</option>)}
          </select>
          <button type="button" aria-pressed={lowOnly} onClick={() => setLowOnly((v) => !v)} className={cn("focus-visible:ring-ring/50 h-9 rounded-lg border px-3 text-sm font-semibold outline-none transition-colors focus-visible:ring-[3px]", lowOnly ? "bg-accent border-foreground/30" : "bg-card hover:bg-accent")}>
            Low stock <span className="text-muted-foreground ms-1 tabular-nums">{lowCount}</span>
          </button>
          <SegmentedControl aria-label="Layout" value={view} onValueChange={(v) => setView(v as View)} size="sm" className="ms-auto">
            <SegmentedControlItem value="grid" aria-label="Grid view"><LayoutGrid /></SegmentedControlItem>
            <SegmentedControlItem value="list" aria-label="List view"><List /></SegmentedControlItem>
          </SegmentedControl>
        </div>
        <p className="sr-only" role="status">{shown.length} products shown</p>

        {shown.length === 0 ? (
          <div className="bg-card text-muted-foreground rounded-xl border px-6 py-20 text-center text-sm">No products match these filters.</div>
        ) : view === "grid" ? (
          <ul className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
            {shown.map((p) => (
              <li key={p.id} className="bg-card group rounded-xl border p-3 transition-shadow hover:shadow-md">
                <ProductTile hue={p.hue} className="aspect-[4/3] w-full" />
                <div className="mt-3 px-1">
                  <div className="flex items-start justify-between gap-2">
                    <h3 className="text-sm leading-snug font-semibold text-pretty">{p.name}</h3>
                    {p.status === "draft" && <Badge variant="secondary">Draft</Badge>}
                  </div>
                  <p className="text-muted-foreground mt-0.5 text-xs">{p.category}</p>
                  <div className="mt-3 flex items-center justify-between"><p className="font-bold tabular-nums">{moneyExact.format(p.price)}</p><Stock p={p} /></div>
                </div>
              </li>
            ))}
          </ul>
        ) : (
          <div className="bg-card overflow-hidden rounded-xl border">
            <div tabIndex={0} role="region" aria-label="Products table" className="focus-visible:ring-ring/50 overflow-x-auto outline-none focus-visible:ring-[3px] focus-visible:ring-inset">
              <table className="w-full min-w-[40rem] text-start text-sm">
                <caption className="sr-only">Products</caption>
                <thead><tr className="text-muted-foreground bg-surface border-b text-xs">{["Product", "Category", "Status", "Price", "Stock"].map((c, i) => <th key={c} scope="col" className={cn("px-4 py-2.5 font-semibold", i === 3 && "text-end", i === 4 && "text-end")}>{c}</th>)}</tr></thead>
                <tbody className="divide-y">
                  {shown.map((p) => (
                    <tr key={p.id} className="hover:bg-accent/40">
                      <td className="px-4 py-2.5"><span className="flex items-center gap-3"><ProductTile hue={p.hue} className="size-9 shrink-0" /><span className="font-semibold">{p.name}</span></span></td>
                      <td className="text-muted-foreground px-4 py-2.5">{p.category}</td>
                      <td className="px-4 py-2.5"><Badge status={p.status === "active" ? "success" : "neutral"} variant="outline">{p.status === "active" ? "Active" : "Draft"}</Badge></td>
                      <td className="px-4 py-2.5 text-end font-semibold tabular-nums">{moneyExact.format(p.price)}</td>
                      <td className="px-4 py-2.5">
                        <div className="flex items-center justify-end gap-1.5">
                          <button type="button" aria-label={`Remove one ${p.name}`} onClick={() => adjust(p.id, -1)} className="hover:bg-accent focus-visible:ring-ring/50 inline-flex size-7 items-center justify-center rounded-md border outline-none focus-visible:ring-[3px]"><Minus className="size-3.5" aria-hidden="true" /></button>
                          <span className="w-10 text-center font-semibold tabular-nums" aria-live="polite">{p.stock}</span>
                          <button type="button" aria-label={`Add one ${p.name}`} onClick={() => adjust(p.id, 1)} className="hover:bg-accent focus-visible:ring-ring/50 inline-flex size-7 items-center justify-center rounded-md border outline-none focus-visible:ring-[3px]"><Plus className="size-3.5" aria-hidden="true" /></button>
                        </div>
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          </div>
        )}
      </main>

      <Sheet open={open} onOpenChange={(o) => { setOpen(o); if (!o) setErrors({}) }}>
        <SheetContent side="end" className="w-full sm:max-w-md" closeLabel="Close">
          <form onSubmit={add} noValidate className="flex h-full flex-col">
            <SheetHeader>
              <SheetTitle>Add product</SheetTitle>
              <SheetDescription>New products start as active and appear in your store right away.</SheetDescription>
            </SheetHeader>
            <div className="flex-1 space-y-4 overflow-y-auto px-4 pb-4">
              <div>
                <label htmlFor="ap-name" className="text-sm font-medium">Name</label>
                <input id="ap-name" name="name" aria-invalid={!!errors.name} aria-describedby={errors.name ? "ap-name-err" : undefined} className={fieldClass} />
                {errors.name && <p id="ap-name-err" className="text-destructive mt-1.5 text-sm">{errors.name}</p>}
              </div>
              <div>
                <label htmlFor="ap-cat" className="text-sm font-medium">Category</label>
                <select id="ap-cat" name="category" className={fieldClass}>{categories.map((c) => <option key={c}>{c}</option>)}</select>
              </div>
              <div className="grid grid-cols-2 gap-3">
                <div>
                  <label htmlFor="ap-price" className="text-sm font-medium">Price (USD)</label>
                  <input id="ap-price" name="price" type="number" step="0.01" min="0" inputMode="decimal" aria-invalid={!!errors.price} aria-describedby={errors.price ? "ap-price-err" : undefined} className={fieldClass} />
                  {errors.price && <p id="ap-price-err" className="text-destructive mt-1.5 text-sm">{errors.price}</p>}
                </div>
                <div>
                  <label htmlFor="ap-stock" className="text-sm font-medium">Stock</label>
                  <input id="ap-stock" name="stock" type="number" min="0" defaultValue="0" className={fieldClass} />
                </div>
              </div>
              <div>
                <label htmlFor="ap-status" className="text-sm font-medium">Status</label>
                <select id="ap-status" name="status" className={fieldClass}><option value="active">Active</option><option value="draft">Draft</option></select>
              </div>
            </div>
            <SheetFooter>
              <button type="button" className={atlasButton.outline} onClick={() => setOpen(false)}>Cancel</button>
              <button type="submit" className={atlasButton.primary}>Add product</button>
            </SheetFooter>
          </form>
        </SheetContent>
      </Sheet>
    </AtlasShell>
  )
}

export { AtlasProducts, type AtlasProductsProps }
```

### `registry/ballmac/components/templates/atlas/atlas-customers.tsx`

```tsx
// Ballmac UI: Atlas customers page. https://ui.ballmac.com/templates/template-atlas
"use client"

import * as React from "react"
import { Mail, Search } from "lucide-react"

import { Badge } from "@/components/ballmac/badge"
import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from "@/components/ballmac/sheet"
import { customers, formatDate, initials, money, moneyExact, orderGrand, orders, type AtlasCustomer } from "@/components/ballmac/templates/atlas/atlas-data"
import { AtlasPageHeader, AtlasShell, FulfilmentBadge, atlasButton, type AtlasHrefs } from "@/components/ballmac/templates/atlas/atlas-theme"
import { cn } from "@/lib/utils"

type Segment = "All" | AtlasCustomer["segment"]
const segments: Segment[] = ["All", "VIP", "Regular", "New", "At risk"]
const tones = ["bg-chart-1/20", "bg-chart-2/20", "bg-chart-3/25", "bg-chart-4/20", "bg-chart-5/20"]
const segmentStatus = { VIP: "success", Regular: "neutral", New: "neutral", "At risk": "warning" } as const

function stats(c: AtlasCustomer) {
  const mine = orders.filter((o) => o.customerId === c.id)
  const spent = mine.reduce((n, o) => n + (o.payment === "refunded" ? 0 : orderGrand(o)), 0)
  return { mine, spent, last: mine[0]?.date }
}

type AtlasCustomersProps = React.ComponentProps<"div"> & { hrefs?: Partial<AtlasHrefs> }

/** The Atlas customers page: segment filters, search, lifetime value bars and a profile drawer with recent orders. */
function AtlasCustomers({ hrefs, ...props }: AtlasCustomersProps) {
  const [segment, setSegment] = React.useState<Segment>("All")
  const [query, setQuery] = React.useState("")
  const [openId, setOpenId] = React.useState<string | null>(null)
  const q = query.trim().toLowerCase()
  const rows = customers
    .map((c) => ({ c, ...stats(c) }))
    .filter((r) => (segment === "All" || r.c.segment === segment) && (!q || [r.c.name, r.c.email, r.c.city].join(" ").toLowerCase().includes(q)))
    .sort((a, b) => b.spent - a.spent)
  const max = Math.max(...customers.map((c) => stats(c).spent))
  const open = customers.find((c) => c.id === openId)
  const openStats = open ? stats(open) : null

  return (
    <AtlasShell page="customers" title="Customers" hrefs={hrefs} {...props}>
      <main className="mx-auto max-w-7xl space-y-5 px-4 py-6 sm:px-6">
        <AtlasPageHeader title="Customers" description={`${customers.length} people have bought from Fieldnote Goods.`} />
        <div className="bg-card rounded-xl border">
          <div className="flex flex-col gap-3 border-b p-3 lg:flex-row lg:items-center lg:justify-between">
            <div role="group" aria-label="Filter by segment" className="flex gap-1 overflow-x-auto [scrollbar-width:none]">
              {segments.map((s) => {
                const on = segment === s
                const count = s === "All" ? customers.length : customers.filter((c) => c.segment === s).length
                return (
                  <button key={s} type="button" aria-pressed={on} onClick={() => setSegment(s)} className={cn("focus-visible:ring-ring/50 flex shrink-0 items-center gap-1.5 rounded-lg px-3 py-1.5 text-sm font-semibold outline-none transition-colors focus-visible:ring-[3px]", on ? "bg-accent text-foreground" : "text-muted-foreground hover:text-foreground")}>
                    {s} <span className="text-muted-foreground text-xs font-medium tabular-nums">{count}</span>
                  </button>
                )
              })}
            </div>
            <div className="relative lg:w-72">
              <Search className="text-muted-foreground pointer-events-none absolute top-1/2 start-3 size-4 -translate-y-1/2" aria-hidden="true" />
              <input type="search" aria-label="Search customers" value={query} onChange={(e) => setQuery(e.target.value)} placeholder="Search name, email or city" className="bg-background focus-visible:ring-ring/50 placeholder:text-muted-foreground h-9 w-full rounded-lg border pe-3 ps-9 text-sm outline-none focus-visible:ring-[3px]" />
            </div>
          </div>
          <div tabIndex={0} role="region" aria-label="Customers table" className="focus-visible:ring-ring/50 overflow-x-auto outline-none focus-visible:ring-[3px] focus-visible:ring-inset">
            <table className="w-full min-w-[44rem] text-start text-sm">
              <caption className="sr-only">Customers by lifetime spend</caption>
              <thead><tr className="text-muted-foreground bg-surface border-b text-xs">{["Customer", "Segment", "Orders", "Last order", "Lifetime spend"].map((c) => <th key={c} scope="col" className="px-4 py-2.5 font-semibold">{c}</th>)}</tr></thead>
              <tbody className="divide-y">
                {rows.map(({ c, mine, spent, last }) => (
                  <tr key={c.id} className="hover:bg-accent/40">
                    <td className="px-4 py-3">
                      <button type="button" onClick={() => setOpenId(c.id)} className="focus-visible:ring-ring/50 -m-1 flex items-center gap-3 rounded-lg p-1 text-start outline-none focus-visible:ring-[3px]">
                        <span className={cn("flex size-9 shrink-0 items-center justify-center rounded-full text-xs font-bold", tones[c.tone - 1])} aria-hidden="true">{initials(c.name)}</span>
                        <span><span className="block font-semibold">{c.name}</span><span className="text-muted-foreground block text-xs">{c.email} · {c.city}</span></span>
                      </button>
                    </td>
                    <td className="px-4 py-3"><Badge status={segmentStatus[c.segment]} variant="outline">{c.segment}</Badge></td>
                    <td className="px-4 py-3 tabular-nums">{mine.length}</td>
                    <td className="text-muted-foreground px-4 py-3 whitespace-nowrap">{last ? formatDate(last) : "—"}</td>
                    <td className="px-4 py-3">
                      <div className="flex items-center gap-3">
                        <div className="bg-muted hidden h-1.5 w-24 rounded-full sm:block" aria-hidden="true"><div className="bg-chart-1 h-full rounded-full" style={{ width: `${(spent / max) * 100}%` }} /></div>
                        <span className="w-20 text-end font-semibold tabular-nums">{money.format(spent)}</span>
                      </div>
                    </td>
                  </tr>
                ))}
                {rows.length === 0 && <tr><td colSpan={5} className="text-muted-foreground px-4 py-16 text-center">No customers match.</td></tr>}
              </tbody>
            </table>
          </div>
          <p className="text-muted-foreground border-t px-4 py-2.5 text-sm" role="status">{rows.length} of {customers.length} customers</p>
        </div>
      </main>

      <Sheet open={!!open} onOpenChange={(o) => !o && setOpenId(null)}>
        <SheetContent side="end" className="w-full sm:max-w-md" closeLabel="Close profile">
          {open && openStats && (
            <>
              <SheetHeader>
                <div className="flex items-center gap-3">
                  <span className={cn("flex size-12 items-center justify-center rounded-full text-sm font-bold", tones[open.tone - 1])} aria-hidden="true">{initials(open.name)}</span>
                  <div><SheetTitle>{open.name}</SheetTitle><SheetDescription>{open.city} · {open.segment}</SheetDescription></div>
                </div>
              </SheetHeader>
              <div className="space-y-5 overflow-y-auto px-4 pb-6">
                <dl className="grid grid-cols-3 gap-2 text-center">
                  {[["Spent", money.format(openStats.spent)], ["Orders", String(openStats.mine.length)], ["Average", openStats.mine.length ? moneyExact.format(openStats.spent / openStats.mine.length) : "—"]].map(([k, v]) => (
                    <div key={k} className="bg-surface rounded-lg border p-3"><dt className="text-muted-foreground text-xs">{k}</dt><dd className="mt-1 font-bold tabular-nums">{v}</dd></div>
                  ))}
                </dl>
                <a href={`mailto:${open.email}`} className={cn(atlasButton.outline, "w-full")}><Mail aria-hidden="true" /> Email {open.name.split(" ")[0]}</a>
                <section aria-labelledby="ac-recent">
                  <h3 id="ac-recent" className="text-sm font-bold">Recent orders</h3>
                  <ul className="mt-2 divide-y rounded-lg border">
                    {openStats.mine.slice(0, 4).map((o) => (
                      <li key={o.id} className="flex items-center justify-between gap-3 px-3 py-2.5 text-sm">
                        <span><span className="font-semibold" style={{ fontFamily: "var(--atlas-mono)" }}>{o.id}</span><span className="text-muted-foreground ms-2 text-xs">{formatDate(o.date)}</span></span>
                        <span className="flex items-center gap-2"><FulfilmentBadge value={o.fulfillment} /><span className="tabular-nums">{moneyExact.format(orderGrand(o))}</span></span>
                      </li>
                    ))}
                  </ul>
                </section>
              </div>
            </>
          )}
        </SheetContent>
      </Sheet>
    </AtlasShell>
  )
}

export { AtlasCustomers, type AtlasCustomersProps }
```

### `registry/ballmac/components/templates/atlas/atlas-settings.tsx`

```tsx
// Ballmac UI: Atlas settings page. https://ui.ballmac.com/templates/template-atlas
"use client"

import * as React from "react"
import { Check } from "lucide-react"

import { Switch } from "@/components/ballmac/switch"
import { AtlasPageHeader, AtlasShell, atlasButton, type AtlasHrefs } from "@/components/ballmac/templates/atlas/atlas-theme"
import { cn } from "@/lib/utils"

const field = "bg-background focus-visible:ring-ring/50 mt-1.5 h-10 w-full rounded-lg border px-3 text-sm outline-none focus-visible:ring-[3px]"

type State = {
  name: string
  email: string
  currency: string
  rates: Record<string, boolean>
  alerts: Record<string, boolean>
}

const initial: State = {
  name: "Fieldnote Goods",
  email: "hello@fieldnote.example",
  currency: "USD",
  rates: { standard: true, express: true, pickup: false },
  alerts: { orders: true, stock: true, reviews: false, digest: true },
}

const rateRows = [
  ["standard", "Standard shipping", "3 to 5 business days · $8, free over $100"],
  ["express", "Express shipping", "1 to 2 business days · $19"],
  ["pickup", "Local pickup", "Collect from the Portland studio · Free"],
]
const alertRows = [
  ["orders", "New orders", "Email me as soon as an order is placed."],
  ["stock", "Low stock", "Tell me when a product drops to 10 or fewer."],
  ["reviews", "Customer reviews", "Tell me about new reviews that need a reply."],
  ["digest", "Weekly digest", "A Monday summary of sales, orders and top products."],
]

const sections = [["profile", "Store profile"], ["shipping", "Shipping"], ["alerts", "Notifications"], ["danger", "Danger zone"]]

type AtlasSettingsProps = React.ComponentProps<"div"> & { hrefs?: Partial<AtlasHrefs> }

/** The Atlas settings page: store profile, shipping rates and notification switches, with a save bar that appears only when something changed. */
function AtlasSettings({ hrefs, ...props }: AtlasSettingsProps) {
  const [saved, setSaved] = React.useState<State>(initial)
  const [draft, setDraft] = React.useState<State>(initial)
  const [status, setStatus] = React.useState<"idle" | "saved">("idle")
  const dirty = JSON.stringify(saved) !== JSON.stringify(draft)

  function set<K extends keyof State>(key: K, value: State[K]) {
    setStatus("idle")
    setDraft((d) => ({ ...d, [key]: value }))
  }

  return (
    <AtlasShell page="settings" title="Settings" hrefs={hrefs} {...props}>
      <main className="mx-auto grid max-w-5xl gap-8 px-4 py-6 pb-28 sm:px-6 lg:grid-cols-[11rem_minmax(0,1fr)]">
        <nav aria-label="Settings sections" className="hidden lg:block">
          <ul className="sticky top-20 space-y-0.5">
            {sections.map(([id, label]) => <li key={id}><a href={`#${id}`} className="text-muted-foreground hover:text-foreground hover:bg-accent focus-visible:ring-ring/50 block rounded-lg px-3 py-2 text-sm font-medium outline-none focus-visible:ring-[3px]">{label}</a></li>)}
          </ul>
        </nav>

        <div className="min-w-0 space-y-6">
          <AtlasPageHeader title="Settings" description="Manage how your store looks, ships and talks to you." />

          <section id="profile" aria-labelledby="as-profile" className="bg-card scroll-mt-20 rounded-xl border p-5">
            <h3 id="as-profile" className="font-bold">Store profile</h3>
            <div className="mt-4 grid gap-4 sm:grid-cols-2">
              <div><label htmlFor="as-name" className="text-sm font-medium">Store name</label><input id="as-name" value={draft.name} onChange={(e) => set("name", e.target.value)} className={field} /></div>
              <div><label htmlFor="as-email" className="text-sm font-medium">Contact email</label><input id="as-email" type="email" value={draft.email} onChange={(e) => set("email", e.target.value)} className={field} /></div>
              <div><label htmlFor="as-cur" className="text-sm font-medium">Currency</label>
                <select id="as-cur" value={draft.currency} onChange={(e) => set("currency", e.target.value)} className={field}><option>USD</option><option>EUR</option><option>GBP</option><option>CAD</option></select>
              </div>
            </div>
          </section>

          <section id="shipping" aria-labelledby="as-ship" className="bg-card scroll-mt-20 rounded-xl border">
            <h3 id="as-ship" className="p-5 pb-3 font-bold">Shipping rates</h3>
            <ul className="divide-y border-t">
              {rateRows.map(([id, title, text]) => (
                <li key={id} className="flex items-center justify-between gap-4 px-5 py-4">
                  <div><p id={`as-rate-${id}`} className="text-sm font-semibold">{title}</p><p className="text-muted-foreground text-sm">{text}</p></div>
                  <Switch aria-labelledby={`as-rate-${id}`} checked={draft.rates[id]} onCheckedChange={(v) => set("rates", { ...draft.rates, [id]: v })} />
                </li>
              ))}
            </ul>
          </section>

          <section id="alerts" aria-labelledby="as-alerts" className="bg-card scroll-mt-20 rounded-xl border">
            <h3 id="as-alerts" className="p-5 pb-3 font-bold">Notifications</h3>
            <ul className="divide-y border-t">
              {alertRows.map(([id, title, text]) => (
                <li key={id} className="flex items-center justify-between gap-4 px-5 py-4">
                  <div><p id={`as-alert-${id}`} className="text-sm font-semibold">{title}</p><p className="text-muted-foreground text-sm">{text}</p></div>
                  <Switch aria-labelledby={`as-alert-${id}`} checked={draft.alerts[id]} onCheckedChange={(v) => set("alerts", { ...draft.alerts, [id]: v })} />
                </li>
              ))}
            </ul>
          </section>

          <section id="danger" aria-labelledby="as-danger" className="border-destructive/40 bg-card scroll-mt-20 rounded-xl border p-5">
            <h3 id="as-danger" className="font-bold">Danger zone</h3>
            <p className="text-muted-foreground mt-1 text-sm text-pretty">Closing the store hides it from customers. Orders and customer data are kept for 90 days.</p>
            <button type="button" className={cn(atlasButton.danger, "mt-4")}>Close store</button>
          </section>
        </div>
      </main>

      {(dirty || status === "saved") && (
        <div role="region" aria-label="Save changes" className="bg-popover fixed inset-x-3 bottom-4 z-40 mx-auto flex max-w-xl items-center justify-between gap-3 rounded-2xl border p-3 ps-5 shadow-[0_20px_50px_-12px_rgb(0_0_0/0.35)]">
          <p className="text-sm font-semibold" role="status">{dirty ? "You have unsaved changes" : <span className="flex items-center gap-1.5"><Check className="text-chart-2 size-4" aria-hidden="true" />Changes saved</span>}</p>
          {dirty && (
            <div className="flex gap-2">
              <button type="button" className={atlasButton.outline} onClick={() => setDraft(saved)}>Discard</button>
              <button type="button" className={atlasButton.primary} onClick={() => { setSaved(draft); setStatus("saved") }}>Save changes</button>
            </div>
          )}
        </div>
      )}
    </AtlasShell>
  )
}

export { AtlasSettings, type AtlasSettingsProps }
```

### `registry/ballmac/app/atlas/page.tsx`

```tsx
// Ballmac UI: Atlas template route. https://ui.ballmac.com/templates/template-atlas
import type { Metadata } from "next"

import { AtlasDashboard } from "@/components/ballmac/templates/atlas/atlas-dashboard"

export const metadata: Metadata = {
  title: "Atlas dashboard · Atlas",
  description: "Sales, orders and stock for Fieldnote Goods.",
}

export default function Page() {
  return <AtlasDashboard />
}
```

### `registry/ballmac/app/atlas/orders/page.tsx`

```tsx
// Ballmac UI: Atlas template route. https://ui.ballmac.com/templates/template-atlas
import type { Metadata } from "next"

import { AtlasOrders } from "@/components/ballmac/templates/atlas/atlas-orders"

export const metadata: Metadata = {
  title: "Orders · Atlas",
  description: "Search, sort and fulfil every order.",
}

export default function Page() {
  return <AtlasOrders />
}
```

### `registry/ballmac/app/atlas/orders/[id]/page.tsx`

```tsx
// Ballmac UI: Atlas template route. https://ui.ballmac.com/templates/template-atlas
import type { Metadata } from "next"
import { Suspense } from "react"

import { AtlasOrder } from "@/components/ballmac/templates/atlas/atlas-order"

export async function generateMetadata({ params }: { params: Promise<{ id: string }> }): Promise<Metadata> {
  const { id } = await params
  return { title: `Order ${id} · Atlas`, description: "Items, timeline, fulfilment and refunds for one order." }
}

// Reading `params` is runtime data: with Cache Components (on by default in new Next.js 16.4 projects) it has to sit inside <Suspense>.
export default function Page({ params }: { params: Promise<{ id: string }> }) {
  return (
    <Suspense fallback={null}>
      <OrderView params={params} />
    </Suspense>
  )
}

async function OrderView({ params }: { params: Promise<{ id: string }> }) {
  const { id } = await params
  return <AtlasOrder orderId={id} />
}
```

### `registry/ballmac/app/atlas/products/page.tsx`

```tsx
// Ballmac UI: Atlas template route. https://ui.ballmac.com/templates/template-atlas
import type { Metadata } from "next"

import { AtlasProducts } from "@/components/ballmac/templates/atlas/atlas-products"

export const metadata: Metadata = {
  title: "Products · Atlas",
  description: "Catalog, stock and pricing.",
}

export default function Page() {
  return <AtlasProducts />
}
```

### `registry/ballmac/app/atlas/customers/page.tsx`

```tsx
// Ballmac UI: Atlas template route. https://ui.ballmac.com/templates/template-atlas
import type { Metadata } from "next"

import { AtlasCustomers } from "@/components/ballmac/templates/atlas/atlas-customers"

export const metadata: Metadata = {
  title: "Customers · Atlas",
  description: "Segments, lifetime spend and recent orders.",
}

export default function Page() {
  return <AtlasCustomers />
}
```

### `registry/ballmac/app/atlas/settings/page.tsx`

```tsx
// Ballmac UI: Atlas template route. https://ui.ballmac.com/templates/template-atlas
import type { Metadata } from "next"

import { AtlasSettings } from "@/components/ballmac/templates/atlas/atlas-settings"

export const metadata: Metadata = {
  title: "Settings · Atlas",
  description: "Store profile, shipping and notifications.",
}

export default function Page() {
  return <AtlasSettings />
}
```
