Wardrobe / Bluey / Install SET-UP / 30 SEC

Install Bluey
in 30 seconds.

Pick your AI tool. Hit copy. Paste it into a fresh chat in your project. Watch the powder-blue settle in.

Install the Wardrobe Bluey theme in my project. I'm using Claude Code / Cursor. Apply every step below as written.

Step 1 — Add this to globals.css:

/* Helvetica Neue + Courier New are system-installed on most platforms — no @import needed.
   If your stack lacks Helvetica Neue, swap in Inter or another neutral grotesk. */

/* =========================================================
   Wardrobe — BLUEY tokens
   Editorial SaaS calm. Composed authority. Powder blue
   surface, vermillion accent, glass cards, animated blobs,
   vertical Courier text in corners. Linear meets Stratechery.
   Activate via data-system="bluey".
   ========================================================= */

:where([data-system="bluey"]) {
    /* ---- Surface ---- */
    --color-bg: #B4C5E4;                    /* powder blue */
    --color-fg: #000000;                    /* deep ink for text + sort buttons */
    --color-bg-tint: rgba(255, 255, 255, 0.2);
    --color-card: rgba(255, 255, 255, 0.2); /* glass card surface */
    --color-card-soft: rgba(255, 255, 255, 0.15);
    --color-card-strong: rgba(255, 255, 255, 0.4);
    --color-card-solid: #ffffff;            /* white "data-tag" surface */
    --color-card-border: rgba(0, 0, 0, 0.1);
    --color-divider: rgba(0, 0, 0, 0.1);
    --color-divider-soft: rgba(0, 0, 0, 0.05);

    /* ---- Brand accent ---- */
    --color-accent: #FF3F14;                /* vermillion */
    --color-accent-soft: rgba(255, 63, 20, 0.1);
    --color-accent-shadow: rgba(255, 63, 20, 0.2);

    /* ---- Status palette (table + badges) ---- */
    --color-status-validated-bg: #E1F9EB;
    --color-status-validated-fg: #107C41;
    --color-status-needs-bg: #FFF4F2;
    --color-status-needs-fg: #FF3F14;
    --color-status-rejected-bg: #EEEEEE;
    --color-status-rejected-fg: #666666;
    --color-status-high-bg: rgba(0, 255, 0, 0.1);
    --color-status-high-fg: #006622;
    --color-status-med-bg: rgba(255, 200, 0, 0.1);
    --color-status-med-fg: #885500;

    /* ---- Typography ---- */
    --font-display: "Helvetica Neue", "Helvetica", "Arial", sans-serif;
    --font-mono: "Courier New", Courier, monospace;
    --weight-regular: 400;
    --weight-medium: 500;
    --weight-semibold: 600;
    --weight-bold: 700;

    --label-font-size: 0.65rem;
    --label-letter-spacing: 0.1em;
    --tight-tracking: -0.03em;
    --display-tracking: -0.05em;

    /* ---- Radii ---- */
    --radius-xs: 4px;
    --radius-sm: 8px;
    --radius-md: 12px;
    --radius-card: 16px;
    --radius-card-lg: 20px;
    --radius-hero: 24px;
    --radius-pill: 50px;

    /* ---- Shadows + glass ---- */
    --shadow-card-soft: 0 2px 8px rgba(0, 0, 0, 0.03);
    --shadow-accent-glow: 0 10px 30px rgba(255, 63, 20, 0.2);
    --backdrop-blur: blur(10px);

    /* ---- Layout ---- */
    --sidebar-width: 320px;
}


Step 2 — Create components/ui/wardrobe/cn.ts:

export function cn(...classes: Array<string | false | null | undefined>): string {
    return classes.filter(Boolean).join(" ");
}


Step 3 — Create the following 10 component files in components/ui/wardrobe/:

--- components/ui/wardrobe/Button.tsx ---

import * as React from "react";
import { cn } from "./cn";

type ButtonProps = {
    variant?: "primary" | "secondary" | "destructive" | "ghost";
    size?: "sm" | "md" | "lg";
    children: React.ReactNode;
} & React.ButtonHTMLAttributes<HTMLButtonElement>;

export function Button({
    variant = "primary",
    size = "md",
    className,
    children,
    ...props
}: ButtonProps) {
    return (
        <button
            className={cn("bly-btn", `bly-btn--${variant}`, `bly-btn--${size}`, className)}
            {...props}
        >
            {children}
        </button>
    );
}


--- components/ui/wardrobe/Input.tsx ---

import * as React from "react";
import { cn } from "./cn";

type InputProps = {
    size?: "sm" | "md" | "lg";
    variant?: "default" | "error";
    label?: string;
    hint?: string;
    numericBadge?: string;
} & React.InputHTMLAttributes<HTMLInputElement>;

export function Input({
    size = "md",
    variant = "default",
    label,
    hint,
    className,
    id,
    ...props
}: InputProps) {
    const inputId = id ?? React.useId();
    return (
        <div className="bly-field-wrap">
            {label && (
                <label htmlFor={inputId} className="bly-mono-label" style={{ marginBottom: "0.4rem" }}>
                    {label}
                </label>
            )}
            <input
                id={inputId}
                className={cn(
                    "bly-field",
                    variant === "error" && "bly-field--error",
                    className,
                )}
                {...props}
            />
            {hint && (
                <p style={{ fontSize: "0.8rem", opacity: 0.6, marginTop: "0.4rem" }}>{hint}</p>
            )}
        </div>
    );
}


--- components/ui/wardrobe/Textarea.tsx ---

import * as React from "react";
import { cn } from "./cn";

type TextareaProps = {
    size?: "sm" | "md" | "lg";
    variant?: "default" | "error";
    label?: string;
    hint?: string;
} & React.TextareaHTMLAttributes<HTMLTextAreaElement>;

export function Textarea({
    label,
    hint,
    variant = "default",
    className,
    id,
    ...props
}: TextareaProps) {
    const textareaId = id ?? React.useId();
    return (
        <div className="bly-field-wrap">
            {label && (
                <label htmlFor={textareaId} className="bly-mono-label" style={{ marginBottom: "0.4rem" }}>
                    {label}
                </label>
            )}
            <textarea
                id={textareaId}
                className={cn(
                    "bly-field",
                    "bly-textarea",
                    variant === "error" && "bly-field--error",
                    className,
                )}
                {...props}
            />
            {hint && (
                <p style={{ fontSize: "0.8rem", opacity: 0.6, marginTop: "0.4rem" }}>{hint}</p>
            )}
        </div>
    );
}


--- components/ui/wardrobe/Select.tsx ---

import * as React from "react";
import { cn } from "./cn";

type Option = { value: string; label: string };

type SelectProps = {
    options: Option[];
    value: string;
    onValueChange: (value: string) => void;
    placeholder?: string;
} & Omit<React.SelectHTMLAttributes<HTMLSelectElement>, "value" | "onChange">;

export function Select({
    options,
    value,
    onValueChange,
    placeholder,
    className,
    ...props
}: SelectProps) {
    return (
        <select
            className={cn("bly-field", "bly-select", className)}
            value={value}
            onChange={(e) => onValueChange(e.target.value)}
            {...props}
        >
            {placeholder && <option value="" disabled>{placeholder}</option>}
            {options.map((opt) => (
                <option key={opt.value} value={opt.value}>
                    {opt.label}
                </option>
            ))}
        </select>
    );
}


--- components/ui/wardrobe/Card.tsx ---

import * as React from "react";
import { cn } from "./cn";

type CardProps = {
    variant?: "default" | "soft" | "strong" | "solid" | "score";
    children: React.ReactNode;
} & React.HTMLAttributes<HTMLDivElement>;

export function Card({
    variant = "default",
    className,
    children,
    ...props
}: CardProps) {
    return (
        <div
            className={cn(
                "bly-card",
                variant !== "default" && `bly-card--${variant}`,
                className,
            )}
            {...props}
        >
            {children}
        </div>
    );
}


--- components/ui/wardrobe/Badge.tsx ---

import * as React from "react";
import { cn } from "./cn";

type BadgeProps = {
    variant?: "default" | "validated" | "needs-work" | "rejected" | "high" | "med";
    children: React.ReactNode;
} & React.HTMLAttributes<HTMLSpanElement>;

export function Badge({
    variant = "default",
    className,
    children,
    ...props
}: BadgeProps) {
    return (
        <span
            className={cn(
                "bly-badge",
                variant !== "default" && `bly-badge--${variant}`,
                className,
            )}
            {...props}
        >
            {children}
        </span>
    );
}


--- components/ui/wardrobe/Dialog.tsx ---

import * as React from "react";

type DialogProps = {
    open: boolean;
    onOpenChange: (open: boolean) => void;
    title: string;
    children: React.ReactNode;
};

export function Dialog({ open, onOpenChange, title, children }: DialogProps) {
    React.useEffect(() => {
        if (!open) return;
        function onKey(e: KeyboardEvent) {
            if (e.key === "Escape") onOpenChange(false);
        }
        document.addEventListener("keydown", onKey);
        return () => document.removeEventListener("keydown", onKey);
    }, [open, onOpenChange]);

    if (!open) return null;
    return (
        <div
            className="bly-dialog-backdrop"
            role="dialog"
            aria-modal="true"
            aria-label={title}
            onClick={(e) => {
                if (e.target === e.currentTarget) onOpenChange(false);
            }}
        >
            <div className="bly-dialog">
                <h2 className="bly-dialog__title">{title}</h2>
                {children}
            </div>
        </div>
    );
}


--- components/ui/wardrobe/Tabs.tsx ---

import * as React from "react";
import { cn } from "./cn";

type TabsProps = {
    tabs: Array<{ id: string; label: string }>;
    activeId: string;
    onTabChange: (id: string) => void;
};

export function Tabs({ tabs, activeId, onTabChange }: TabsProps) {
    return (
        <div className="bly-tabs" role="tablist">
            {tabs.map((tab) => (
                <button
                    key={tab.id}
                    type="button"
                    role="tab"
                    aria-selected={tab.id === activeId}
                    className={cn("bly-tab", tab.id === activeId && "is-active")}
                    onClick={() => onTabChange(tab.id)}
                >
                    {tab.label}
                </button>
            ))}
        </div>
    );
}


--- components/ui/wardrobe/Switch.tsx ---

import * as React from "react";

type SwitchProps = {
    checked: boolean;
    onCheckedChange: (checked: boolean) => void;
    label?: string;
};

export function Switch({ checked, onCheckedChange, label }: SwitchProps) {
    return (
        <label className="bly-switch" data-checked={checked}>
            <span className="bly-switch__track">
                <span className="bly-switch__thumb" />
            </span>
            <input
                type="checkbox"
                checked={checked}
                onChange={(e) => onCheckedChange(e.target.checked)}
                style={{ position: "absolute", opacity: 0, width: 0, height: 0 }}
            />
            {label && <span>{label}</span>}
        </label>
    );
}


--- components/ui/wardrobe/Toast.tsx ---

import * as React from "react";
import { cn } from "./cn";

type ToastProps = {
    title: string;
    description?: string;
    variant?: "default" | "success" | "error";
};

export function Toast({ title, description, variant = "default" }: ToastProps) {
    return (
        <div
            className={cn(
                "bly-toast",
                variant !== "default" && `bly-toast--${variant}`,
            )}
            role="status"
            aria-live="polite"
        >
            <span className="bly-toast__title">{title}</span>
            {description && <span className="bly-toast__desc">{description}</span>}
        </div>
    );
}


Step 4 — Add globals.css component styles. Append the following to globals.css below the tokens:

/* =========================================================
   Wardrobe — BLUEY globals
   Loads Helvetica Neue (system) + Courier New (system mono),
   then component + decoration styles.
   Only active under data-system="bluey".
   ========================================================= */


[data-system="bluey"] *,
[data-system="bluey"] *::before,
[data-system="bluey"] *::after {
    box-sizing: border-box;
}

[data-system="bluey"] {
    background-color: var(--color-bg);
    color: var(--color-fg);
    font-family: var(--font-display);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    min-height: 100vh;
}

/* ===========================
   LOGO
   =========================== */
.bly-logo {
    font-family: var(--font-display);
    font-weight: var(--weight-bold);
    font-size: 1.25rem;
    letter-spacing: -0.02em;
    color: var(--color-fg);
}

/* ===========================
   MONO LABEL (used everywhere)
   =========================== */
.bly-mono-label {
    font-family: var(--font-mono);
    font-size: var(--label-font-size);
    text-transform: uppercase;
    letter-spacing: var(--label-letter-spacing);
    opacity: 0.5;
    display: inline-block;
}

/* ===========================
   VERTICAL TEXT (corner caption)
   =========================== */
.bly-vertical-text {
    position: absolute;
    bottom: 2.5rem;
    left: 2rem;
    writing-mode: vertical-rl;
    text-orientation: mixed;
    font-family: var(--font-mono);
    font-size: var(--label-font-size);
    letter-spacing: 0.05em;
    opacity: 0.4;
    pointer-events: none;
}

/* ===========================
   ANIMATED BLOB
   =========================== */
.bly-blob {
    position: absolute;
    border-radius: 50%;
    background: var(--color-accent);
    filter: blur(100px);
    opacity: 0.18;
    z-index: 0;
    pointer-events: none;
    animation: bly-blob-morph 14s ease-in-out infinite;
}
.bly-blob--corner {
    bottom: -50px;
    right: -50px;
    width: 400px;
    height: 400px;
}
.bly-blob--center {
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 800px;
    height: 800px;
    background: radial-gradient(circle, var(--color-accent) 0%, transparent 70%);
    filter: blur(120px);
    opacity: 0.1;
}
.bly-blob--top-right {
    top: 20%;
    right: -10%;
    width: 600px;
    height: 600px;
    filter: blur(120px);
    opacity: 0.12;
}
.bly-blob--white {
    background: #ffffff;
    opacity: 0.22;
    filter: blur(120px);
}

@keyframes bly-blob-morph {
    0%, 100% { transform: translate(0, 0) scale(1); }
    33% { transform: translate(30px, -20px) scale(1.05); }
    66% { transform: translate(-20px, 25px) scale(0.97); }
}
.bly-blob--center {
    animation: bly-blob-morph-center 18s ease-in-out infinite;
}
@keyframes bly-blob-morph-center {
    0%, 100% { transform: translate(-50%, -50%) scale(1); }
    50% { transform: translate(-48%, -52%) scale(1.06); }
}

/* ===========================
   NAV SIDEBAR (320px)
   =========================== */
.bly-aside {
    width: var(--sidebar-width);
    border-right: 1px solid var(--color-divider);
    padding: 2.5rem 2rem;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    z-index: 10;
    background: transparent;
}
.bly-nav-group { margin-bottom: 2rem; }
.bly-nav-label {
    font-family: var(--font-mono);
    font-size: var(--label-font-size);
    text-transform: uppercase;
    letter-spacing: var(--label-letter-spacing);
    opacity: 0.5;
    margin-bottom: 1rem;
    display: block;
}
.bly-nav-item {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.75rem 0;
    text-decoration: none;
    color: var(--color-fg);
    font-weight: var(--weight-medium);
    font-size: 0.9rem;
    opacity: 0.7;
    transition: opacity 120ms ease;
}
.bly-nav-item:hover { opacity: 0.9; }
.bly-nav-item.is-active {
    opacity: 1;
    font-weight: var(--weight-semibold);
}

/* ===========================
   MAIN SHELL
   =========================== */
.bly-shell {
    display: grid;
    grid-template-columns: var(--sidebar-width) 1fr;
    min-height: 100vh;
    position: relative;
}
.bly-main {
    padding: 2.5rem 4rem;
    overflow: hidden;
    position: relative;
}
.bly-header-row {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    margin-bottom: 3rem;
    position: relative;
    z-index: 5;
}
.bly-workflow-title h1 {
    font-size: 2.5rem;
    font-weight: var(--weight-bold);
    letter-spacing: var(--tight-tracking);
    line-height: 1.05;
    margin: 0;
}

/* ===========================
   BUTTON
   =========================== */
.bly-btn {
    font-family: var(--font-display);
    font-weight: var(--weight-bold);
    border: none;
    cursor: pointer;
    border-radius: var(--radius-pill);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    transition: transform 120ms ease, opacity 120ms ease;
    line-height: 1;
}
.bly-btn:hover { transform: translateY(-1px); }
.bly-btn:active { transform: translateY(0); }
.bly-btn:disabled { opacity: 0.4; cursor: not-allowed; transform: none; }

.bly-btn--primary {
    background: var(--color-accent);
    color: #ffffff;
    box-shadow: var(--shadow-accent-glow);
}
.bly-btn--primary:hover { box-shadow: 0 12px 32px rgba(255, 63, 20, 0.3); }

.bly-btn--secondary {
    background: var(--color-fg);
    color: var(--color-bg);
}

.bly-btn--ghost {
    background: transparent;
    color: var(--color-fg);
    border: 1.5px solid var(--color-fg);
}
.bly-btn--ghost:hover { background: rgba(0, 0, 0, 0.04); }

.bly-btn--destructive {
    background: var(--color-accent);
    color: #ffffff;
}

.bly-btn--sm { padding: 0.5rem 1.25rem; font-size: 0.8rem; }
.bly-btn--md { padding: 0.8rem 1.6rem; font-size: 0.9rem; }
.bly-btn--lg { padding: 1.1rem 2.4rem; font-size: 1rem; }

/* ===========================
   CARD (glass-morphism)
   =========================== */
.bly-card {
    background: var(--color-card);
    border: 1px solid var(--color-card-border);
    border-radius: var(--radius-card-lg);
    padding: 2rem;
    backdrop-filter: var(--backdrop-blur);
    -webkit-backdrop-filter: var(--backdrop-blur);
}
.bly-card--soft {
    background: var(--color-card-soft);
    border: 1px solid rgba(255, 255, 255, 0.3);
    border-radius: var(--radius-card);
    padding: 1.5rem;
}
.bly-card--strong {
    background: var(--color-card-strong);
    border-radius: var(--radius-card);
    padding: 1.5rem;
    border: 1px solid rgba(255, 255, 255, 0.3);
    backdrop-filter: var(--backdrop-blur);
    -webkit-backdrop-filter: var(--backdrop-blur);
}
.bly-card--solid {
    background: var(--color-card-solid);
    border-radius: var(--radius-md);
    padding: 0.75rem;
    box-shadow: var(--shadow-card-soft);
}
.bly-card--score {
    background: var(--color-fg);
    color: var(--color-bg);
    border-radius: var(--radius-hero);
    padding: 3rem;
    border: none;
    backdrop-filter: none;
    position: relative;
    overflow: hidden;
}

/* ===========================
   SCORE BOX (sort hero number)
   =========================== */
.bly-score-meta {
    font-family: var(--font-mono);
    text-transform: uppercase;
    font-size: 0.8rem;
    letter-spacing: var(--label-letter-spacing);
    opacity: 0.7;
    display: block;
    margin-bottom: 0.75rem;
}
.bly-score-big {
    font-size: 8rem;
    font-weight: var(--weight-bold);
    line-height: 0.9;
    letter-spacing: var(--display-tracking);
}
.bly-score-conviction {
    margin-top: 1rem;
    font-weight: var(--weight-medium);
}
.bly-score-blurb {
    margin-top: 1.5rem;
    opacity: 0.65;
    font-size: 0.9rem;
    line-height: 1.5;
}
.bly-score-pill {
    font-family: var(--font-mono);
    font-weight: var(--weight-bold);
    background: var(--color-fg);
    color: var(--color-bg);
    padding: 0.2rem 0.6rem;
    border-radius: var(--radius-xs);
    display: inline-block;
}

/* ===========================
   BADGE / TAG (status variants)
   =========================== */
.bly-badge {
    font-family: var(--font-mono);
    font-size: 0.7rem;
    padding: 0.25rem 0.75rem;
    border-radius: var(--radius-xs);
    text-transform: uppercase;
    letter-spacing: 0.02em;
    font-weight: var(--weight-bold);
    display: inline-block;
    background: rgba(0, 0, 0, 0.1);
    color: var(--color-fg);
}
.bly-badge--validated {
    background: var(--color-status-validated-bg);
    color: var(--color-status-validated-fg);
}
.bly-badge--needs-work {
    background: var(--color-status-needs-bg);
    color: var(--color-status-needs-fg);
}
.bly-badge--rejected {
    background: var(--color-status-rejected-bg);
    color: var(--color-status-rejected-fg);
}
.bly-badge--high {
    background: var(--color-status-high-bg);
    color: var(--color-status-high-fg);
}
.bly-badge--med {
    background: var(--color-status-med-bg);
    color: var(--color-status-med-fg);
}

/* ===========================
   INPUT / TEXTAREA / SELECT
   =========================== */
.bly-field {
    width: 100%;
    background: rgba(255, 255, 255, 0.25);
    border: 1px solid var(--color-card-border);
    border-radius: var(--radius-md);
    padding: 0.85rem 1.1rem;
    color: var(--color-fg);
    font-family: var(--font-display);
    font-size: 0.95rem;
    transition: border-color 120ms ease, background 120ms ease;
}
.bly-field::placeholder {
    color: rgba(0, 0, 0, 0.35);
}
.bly-field:focus {
    outline: none;
    border-color: var(--color-fg);
    background: rgba(255, 255, 255, 0.4);
}
.bly-field--error { border-color: var(--color-accent); }

.bly-textarea {
    min-height: 120px;
    resize: vertical;
    line-height: 1.5;
    font-family: var(--font-display);
}
.bly-select {
    appearance: none;
    background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
                      linear-gradient(135deg, currentColor 50%, transparent 50%);
    background-position: calc(100% - 18px) 55%, calc(100% - 13px) 55%;
    background-size: 5px 5px, 5px 5px;
    background-repeat: no-repeat;
    padding-right: 2.5rem;
}

/* ===========================
   TABLE
   =========================== */
.bly-table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0 0.5rem;
}
.bly-table th {
    text-align: left;
    padding: 1rem;
    font-family: var(--font-mono);
    font-size: var(--label-font-size);
    text-transform: uppercase;
    letter-spacing: var(--label-letter-spacing);
    opacity: 0.5;
    font-weight: var(--weight-regular);
}
.bly-table td {
    padding: 1.25rem 1rem;
    background: rgba(255, 255, 255, 0.1);
    border-top: 1px solid var(--color-card-border);
    border-bottom: 1px solid var(--color-card-border);
    vertical-align: middle;
    font-size: 0.95rem;
}
.bly-table td:first-child {
    border-left: 1px solid var(--color-card-border);
    border-top-left-radius: var(--radius-md);
    border-bottom-left-radius: var(--radius-md);
    font-weight: var(--weight-semibold);
}
.bly-table td:last-child {
    border-right: 1px solid var(--color-card-border);
    border-top-right-radius: var(--radius-md);
    border-bottom-right-radius: var(--radius-md);
}

/* ===========================
   STATS STRIP (used on history page)
   =========================== */
.bly-stats {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 2rem;
    margin-bottom: 3rem;
}
.bly-stat {
    border-bottom: 2px solid var(--color-fg);
    padding-bottom: 1rem;
}
.bly-stat-value {
    font-size: 1.5rem;
    font-weight: var(--weight-bold);
    display: block;
    letter-spacing: -0.01em;
}

/* ===========================
   ACTIVE PROBLEM BAR (live indicator)
   =========================== */
.bly-active-problem {
    background: rgba(0, 0, 0, 0.05);
    padding: 0.5rem 1rem;
    border-radius: var(--radius-sm);
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.8rem;
    font-weight: var(--weight-semibold);
    margin-bottom: 1rem;
}
.bly-pulse {
    width: 6px;
    height: 6px;
    background: var(--color-accent);
    border-radius: 50%;
    animation: bly-pulse 1.6s ease-in-out infinite;
}
@keyframes bly-pulse {
    0%, 100% { opacity: 1; transform: scale(1); }
    50% { opacity: 0.55; transform: scale(1.4); }
}

/* ===========================
   PERSPECTIVE GRID (3 columns)
   =========================== */
.bly-perspective-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 2rem;
    align-items: start;
    position: relative;
    z-index: 5;
}
.bly-perspective-col {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
}
.bly-column-header {
    border-bottom: 1px solid var(--color-card-border);
    padding-bottom: 1rem;
}
.bly-column-header h2 {
    font-size: 1.1rem;
    font-weight: var(--weight-bold);
    margin: 0.25rem 0 0;
    letter-spacing: -0.01em;
}
.bly-viewpoint p {
    font-size: 0.95rem;
    line-height: 1.5;
    margin: 0 0 1.5rem;
    font-weight: var(--weight-medium);
}
.bly-evidence {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    background: #ffffff;
    padding: 0.75rem;
    border-radius: 10px;
    margin-top: 0.75rem;
    box-shadow: var(--shadow-card-soft);
}
.bly-evidence-icon {
    width: 24px;
    height: 24px;
    border-radius: 4px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.65rem;
    font-weight: var(--weight-bold);
    flex-shrink: 0;
}
.bly-evidence-text {
    font-size: 0.75rem;
    font-weight: var(--weight-semibold);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ===========================
   RECOMMENDATION LIST
   =========================== */
.bly-rec-list {
    list-style: none;
    margin: 1rem 0 0;
    padding: 0;
}
.bly-rec-item {
    display: flex;
    gap: 1rem;
    padding: 1rem;
    background: #ffffff;
    border-radius: var(--radius-md);
    margin-bottom: 0.75rem;
    font-size: 0.9rem;
    line-height: 1.45;
    border-left: 4px solid var(--color-accent);
}

/* ===========================
   DIALOG
   =========================== */
.bly-dialog-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(180, 197, 228, 0.5);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    z-index: 100;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 2rem;
}
.bly-dialog {
    background: var(--color-card-strong);
    border: 1px solid rgba(255, 255, 255, 0.3);
    border-radius: var(--radius-card-lg);
    padding: 2.5rem;
    backdrop-filter: var(--backdrop-blur);
    -webkit-backdrop-filter: var(--backdrop-blur);
    max-width: 500px;
    width: 100%;
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15);
}
.bly-dialog__title {
    font-size: 1.5rem;
    font-weight: var(--weight-bold);
    letter-spacing: var(--tight-tracking);
    margin: 0 0 1rem;
}

/* ===========================
   TABS
   =========================== */
.bly-tabs {
    display: flex;
    gap: 0;
    border-bottom: 1px solid var(--color-card-border);
}
.bly-tab {
    background: none;
    border: none;
    padding: 0.75rem 1.25rem;
    font-family: var(--font-display);
    font-size: 0.85rem;
    font-weight: var(--weight-semibold);
    color: var(--color-fg);
    opacity: 0.55;
    cursor: pointer;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    transition: opacity 120ms ease, border-color 120ms ease;
}
.bly-tab:hover { opacity: 0.85; }
.bly-tab.is-active {
    opacity: 1;
    border-bottom-color: var(--color-accent);
}

/* ===========================
   SWITCH
   =========================== */
.bly-switch {
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    cursor: pointer;
    font-size: 0.9rem;
    font-weight: var(--weight-medium);
}
.bly-switch__track {
    width: 38px;
    height: 22px;
    background: rgba(0, 0, 0, 0.15);
    border-radius: 11px;
    position: relative;
    transition: background 160ms ease;
}
.bly-switch__thumb {
    position: absolute;
    top: 2px;
    left: 2px;
    width: 18px;
    height: 18px;
    background: #ffffff;
    border-radius: 50%;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
    transition: left 160ms ease;
}
.bly-switch[data-checked="true"] .bly-switch__track {
    background: var(--color-accent);
}
.bly-switch[data-checked="true"] .bly-switch__thumb {
    left: 18px;
}

/* ===========================
   TOAST
   =========================== */
.bly-toast {
    background: var(--color-card-strong);
    border: 1px solid rgba(255, 255, 255, 0.3);
    border-radius: var(--radius-md);
    padding: 1rem 1.25rem;
    backdrop-filter: var(--backdrop-blur);
    -webkit-backdrop-filter: var(--backdrop-blur);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
    min-width: 240px;
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}
.bly-toast__title {
    font-weight: var(--weight-bold);
    font-size: 0.9rem;
}
.bly-toast__desc {
    font-size: 0.85rem;
    opacity: 0.7;
}
.bly-toast--success { border-left: 4px solid var(--color-status-validated-fg); }
.bly-toast--error { border-left: 4px solid var(--color-accent); }

/* ===========================
   RESPONSIVE
   =========================== */
@media (max-width: 900px) {
    .bly-shell {
        grid-template-columns: 1fr;
    }
    .bly-aside {
        width: 100%;
        border-right: none;
        border-bottom: 1px solid var(--color-divider);
        padding: 1.5rem 1.25rem;
    }
    .bly-vertical-text { display: none; }
    .bly-main { padding: 1.5rem 1.25rem; }
    .bly-perspective-grid { grid-template-columns: 1fr; }
    .bly-stats { grid-template-columns: 1fr 1fr; }
    .bly-score-big { font-size: 5.5rem; }
}

Step 5 — Wrap the section/page you want themed with <div data-system="bluey">:

  <div data-system="bluey">
    <Button>HELLO BLUEY</Button>
    <Card>...</Card>
  </div>

Done. Now <Button>, <Input>, <Card>, <Badge>, <Dialog>, <Tabs>, <Switch>, <Toast>, <Select>, <Textarea> render in Bluey.
Install the Wardrobe Bluey theme in this v0 project. Treat each step below as a concrete file or edit you must make.

Step 1 — Add this to globals.css:

/* Helvetica Neue + Courier New are system-installed on most platforms — no @import needed.
   If your stack lacks Helvetica Neue, swap in Inter or another neutral grotesk. */

/* =========================================================
   Wardrobe — BLUEY tokens
   Editorial SaaS calm. Composed authority. Powder blue
   surface, vermillion accent, glass cards, animated blobs,
   vertical Courier text in corners. Linear meets Stratechery.
   Activate via data-system="bluey".
   ========================================================= */

:where([data-system="bluey"]) {
    /* ---- Surface ---- */
    --color-bg: #B4C5E4;                    /* powder blue */
    --color-fg: #000000;                    /* deep ink for text + sort buttons */
    --color-bg-tint: rgba(255, 255, 255, 0.2);
    --color-card: rgba(255, 255, 255, 0.2); /* glass card surface */
    --color-card-soft: rgba(255, 255, 255, 0.15);
    --color-card-strong: rgba(255, 255, 255, 0.4);
    --color-card-solid: #ffffff;            /* white "data-tag" surface */
    --color-card-border: rgba(0, 0, 0, 0.1);
    --color-divider: rgba(0, 0, 0, 0.1);
    --color-divider-soft: rgba(0, 0, 0, 0.05);

    /* ---- Brand accent ---- */
    --color-accent: #FF3F14;                /* vermillion */
    --color-accent-soft: rgba(255, 63, 20, 0.1);
    --color-accent-shadow: rgba(255, 63, 20, 0.2);

    /* ---- Status palette (table + badges) ---- */
    --color-status-validated-bg: #E1F9EB;
    --color-status-validated-fg: #107C41;
    --color-status-needs-bg: #FFF4F2;
    --color-status-needs-fg: #FF3F14;
    --color-status-rejected-bg: #EEEEEE;
    --color-status-rejected-fg: #666666;
    --color-status-high-bg: rgba(0, 255, 0, 0.1);
    --color-status-high-fg: #006622;
    --color-status-med-bg: rgba(255, 200, 0, 0.1);
    --color-status-med-fg: #885500;

    /* ---- Typography ---- */
    --font-display: "Helvetica Neue", "Helvetica", "Arial", sans-serif;
    --font-mono: "Courier New", Courier, monospace;
    --weight-regular: 400;
    --weight-medium: 500;
    --weight-semibold: 600;
    --weight-bold: 700;

    --label-font-size: 0.65rem;
    --label-letter-spacing: 0.1em;
    --tight-tracking: -0.03em;
    --display-tracking: -0.05em;

    /* ---- Radii ---- */
    --radius-xs: 4px;
    --radius-sm: 8px;
    --radius-md: 12px;
    --radius-card: 16px;
    --radius-card-lg: 20px;
    --radius-hero: 24px;
    --radius-pill: 50px;

    /* ---- Shadows + glass ---- */
    --shadow-card-soft: 0 2px 8px rgba(0, 0, 0, 0.03);
    --shadow-accent-glow: 0 10px 30px rgba(255, 63, 20, 0.2);
    --backdrop-blur: blur(10px);

    /* ---- Layout ---- */
    --sidebar-width: 320px;
}


Step 2 — Create components/ui/wardrobe/cn.ts:

export function cn(...classes: Array<string | false | null | undefined>): string {
    return classes.filter(Boolean).join(" ");
}


Step 3 — Create the following 10 component files in components/ui/wardrobe/:

--- components/ui/wardrobe/Button.tsx ---

import * as React from "react";
import { cn } from "./cn";

type ButtonProps = {
    variant?: "primary" | "secondary" | "destructive" | "ghost";
    size?: "sm" | "md" | "lg";
    children: React.ReactNode;
} & React.ButtonHTMLAttributes<HTMLButtonElement>;

export function Button({
    variant = "primary",
    size = "md",
    className,
    children,
    ...props
}: ButtonProps) {
    return (
        <button
            className={cn("bly-btn", `bly-btn--${variant}`, `bly-btn--${size}`, className)}
            {...props}
        >
            {children}
        </button>
    );
}


--- components/ui/wardrobe/Input.tsx ---

import * as React from "react";
import { cn } from "./cn";

type InputProps = {
    size?: "sm" | "md" | "lg";
    variant?: "default" | "error";
    label?: string;
    hint?: string;
    numericBadge?: string;
} & React.InputHTMLAttributes<HTMLInputElement>;

export function Input({
    size = "md",
    variant = "default",
    label,
    hint,
    className,
    id,
    ...props
}: InputProps) {
    const inputId = id ?? React.useId();
    return (
        <div className="bly-field-wrap">
            {label && (
                <label htmlFor={inputId} className="bly-mono-label" style={{ marginBottom: "0.4rem" }}>
                    {label}
                </label>
            )}
            <input
                id={inputId}
                className={cn(
                    "bly-field",
                    variant === "error" && "bly-field--error",
                    className,
                )}
                {...props}
            />
            {hint && (
                <p style={{ fontSize: "0.8rem", opacity: 0.6, marginTop: "0.4rem" }}>{hint}</p>
            )}
        </div>
    );
}


--- components/ui/wardrobe/Textarea.tsx ---

import * as React from "react";
import { cn } from "./cn";

type TextareaProps = {
    size?: "sm" | "md" | "lg";
    variant?: "default" | "error";
    label?: string;
    hint?: string;
} & React.TextareaHTMLAttributes<HTMLTextAreaElement>;

export function Textarea({
    label,
    hint,
    variant = "default",
    className,
    id,
    ...props
}: TextareaProps) {
    const textareaId = id ?? React.useId();
    return (
        <div className="bly-field-wrap">
            {label && (
                <label htmlFor={textareaId} className="bly-mono-label" style={{ marginBottom: "0.4rem" }}>
                    {label}
                </label>
            )}
            <textarea
                id={textareaId}
                className={cn(
                    "bly-field",
                    "bly-textarea",
                    variant === "error" && "bly-field--error",
                    className,
                )}
                {...props}
            />
            {hint && (
                <p style={{ fontSize: "0.8rem", opacity: 0.6, marginTop: "0.4rem" }}>{hint}</p>
            )}
        </div>
    );
}


--- components/ui/wardrobe/Select.tsx ---

import * as React from "react";
import { cn } from "./cn";

type Option = { value: string; label: string };

type SelectProps = {
    options: Option[];
    value: string;
    onValueChange: (value: string) => void;
    placeholder?: string;
} & Omit<React.SelectHTMLAttributes<HTMLSelectElement>, "value" | "onChange">;

export function Select({
    options,
    value,
    onValueChange,
    placeholder,
    className,
    ...props
}: SelectProps) {
    return (
        <select
            className={cn("bly-field", "bly-select", className)}
            value={value}
            onChange={(e) => onValueChange(e.target.value)}
            {...props}
        >
            {placeholder && <option value="" disabled>{placeholder}</option>}
            {options.map((opt) => (
                <option key={opt.value} value={opt.value}>
                    {opt.label}
                </option>
            ))}
        </select>
    );
}


--- components/ui/wardrobe/Card.tsx ---

import * as React from "react";
import { cn } from "./cn";

type CardProps = {
    variant?: "default" | "soft" | "strong" | "solid" | "score";
    children: React.ReactNode;
} & React.HTMLAttributes<HTMLDivElement>;

export function Card({
    variant = "default",
    className,
    children,
    ...props
}: CardProps) {
    return (
        <div
            className={cn(
                "bly-card",
                variant !== "default" && `bly-card--${variant}`,
                className,
            )}
            {...props}
        >
            {children}
        </div>
    );
}


--- components/ui/wardrobe/Badge.tsx ---

import * as React from "react";
import { cn } from "./cn";

type BadgeProps = {
    variant?: "default" | "validated" | "needs-work" | "rejected" | "high" | "med";
    children: React.ReactNode;
} & React.HTMLAttributes<HTMLSpanElement>;

export function Badge({
    variant = "default",
    className,
    children,
    ...props
}: BadgeProps) {
    return (
        <span
            className={cn(
                "bly-badge",
                variant !== "default" && `bly-badge--${variant}`,
                className,
            )}
            {...props}
        >
            {children}
        </span>
    );
}


--- components/ui/wardrobe/Dialog.tsx ---

import * as React from "react";

type DialogProps = {
    open: boolean;
    onOpenChange: (open: boolean) => void;
    title: string;
    children: React.ReactNode;
};

export function Dialog({ open, onOpenChange, title, children }: DialogProps) {
    React.useEffect(() => {
        if (!open) return;
        function onKey(e: KeyboardEvent) {
            if (e.key === "Escape") onOpenChange(false);
        }
        document.addEventListener("keydown", onKey);
        return () => document.removeEventListener("keydown", onKey);
    }, [open, onOpenChange]);

    if (!open) return null;
    return (
        <div
            className="bly-dialog-backdrop"
            role="dialog"
            aria-modal="true"
            aria-label={title}
            onClick={(e) => {
                if (e.target === e.currentTarget) onOpenChange(false);
            }}
        >
            <div className="bly-dialog">
                <h2 className="bly-dialog__title">{title}</h2>
                {children}
            </div>
        </div>
    );
}


--- components/ui/wardrobe/Tabs.tsx ---

import * as React from "react";
import { cn } from "./cn";

type TabsProps = {
    tabs: Array<{ id: string; label: string }>;
    activeId: string;
    onTabChange: (id: string) => void;
};

export function Tabs({ tabs, activeId, onTabChange }: TabsProps) {
    return (
        <div className="bly-tabs" role="tablist">
            {tabs.map((tab) => (
                <button
                    key={tab.id}
                    type="button"
                    role="tab"
                    aria-selected={tab.id === activeId}
                    className={cn("bly-tab", tab.id === activeId && "is-active")}
                    onClick={() => onTabChange(tab.id)}
                >
                    {tab.label}
                </button>
            ))}
        </div>
    );
}


--- components/ui/wardrobe/Switch.tsx ---

import * as React from "react";

type SwitchProps = {
    checked: boolean;
    onCheckedChange: (checked: boolean) => void;
    label?: string;
};

export function Switch({ checked, onCheckedChange, label }: SwitchProps) {
    return (
        <label className="bly-switch" data-checked={checked}>
            <span className="bly-switch__track">
                <span className="bly-switch__thumb" />
            </span>
            <input
                type="checkbox"
                checked={checked}
                onChange={(e) => onCheckedChange(e.target.checked)}
                style={{ position: "absolute", opacity: 0, width: 0, height: 0 }}
            />
            {label && <span>{label}</span>}
        </label>
    );
}


--- components/ui/wardrobe/Toast.tsx ---

import * as React from "react";
import { cn } from "./cn";

type ToastProps = {
    title: string;
    description?: string;
    variant?: "default" | "success" | "error";
};

export function Toast({ title, description, variant = "default" }: ToastProps) {
    return (
        <div
            className={cn(
                "bly-toast",
                variant !== "default" && `bly-toast--${variant}`,
            )}
            role="status"
            aria-live="polite"
        >
            <span className="bly-toast__title">{title}</span>
            {description && <span className="bly-toast__desc">{description}</span>}
        </div>
    );
}


Step 4 — Add globals.css component styles. Append the following to globals.css below the tokens:

/* =========================================================
   Wardrobe — BLUEY globals
   Loads Helvetica Neue (system) + Courier New (system mono),
   then component + decoration styles.
   Only active under data-system="bluey".
   ========================================================= */


[data-system="bluey"] *,
[data-system="bluey"] *::before,
[data-system="bluey"] *::after {
    box-sizing: border-box;
}

[data-system="bluey"] {
    background-color: var(--color-bg);
    color: var(--color-fg);
    font-family: var(--font-display);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    min-height: 100vh;
}

/* ===========================
   LOGO
   =========================== */
.bly-logo {
    font-family: var(--font-display);
    font-weight: var(--weight-bold);
    font-size: 1.25rem;
    letter-spacing: -0.02em;
    color: var(--color-fg);
}

/* ===========================
   MONO LABEL (used everywhere)
   =========================== */
.bly-mono-label {
    font-family: var(--font-mono);
    font-size: var(--label-font-size);
    text-transform: uppercase;
    letter-spacing: var(--label-letter-spacing);
    opacity: 0.5;
    display: inline-block;
}

/* ===========================
   VERTICAL TEXT (corner caption)
   =========================== */
.bly-vertical-text {
    position: absolute;
    bottom: 2.5rem;
    left: 2rem;
    writing-mode: vertical-rl;
    text-orientation: mixed;
    font-family: var(--font-mono);
    font-size: var(--label-font-size);
    letter-spacing: 0.05em;
    opacity: 0.4;
    pointer-events: none;
}

/* ===========================
   ANIMATED BLOB
   =========================== */
.bly-blob {
    position: absolute;
    border-radius: 50%;
    background: var(--color-accent);
    filter: blur(100px);
    opacity: 0.18;
    z-index: 0;
    pointer-events: none;
    animation: bly-blob-morph 14s ease-in-out infinite;
}
.bly-blob--corner {
    bottom: -50px;
    right: -50px;
    width: 400px;
    height: 400px;
}
.bly-blob--center {
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 800px;
    height: 800px;
    background: radial-gradient(circle, var(--color-accent) 0%, transparent 70%);
    filter: blur(120px);
    opacity: 0.1;
}
.bly-blob--top-right {
    top: 20%;
    right: -10%;
    width: 600px;
    height: 600px;
    filter: blur(120px);
    opacity: 0.12;
}
.bly-blob--white {
    background: #ffffff;
    opacity: 0.22;
    filter: blur(120px);
}

@keyframes bly-blob-morph {
    0%, 100% { transform: translate(0, 0) scale(1); }
    33% { transform: translate(30px, -20px) scale(1.05); }
    66% { transform: translate(-20px, 25px) scale(0.97); }
}
.bly-blob--center {
    animation: bly-blob-morph-center 18s ease-in-out infinite;
}
@keyframes bly-blob-morph-center {
    0%, 100% { transform: translate(-50%, -50%) scale(1); }
    50% { transform: translate(-48%, -52%) scale(1.06); }
}

/* ===========================
   NAV SIDEBAR (320px)
   =========================== */
.bly-aside {
    width: var(--sidebar-width);
    border-right: 1px solid var(--color-divider);
    padding: 2.5rem 2rem;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    z-index: 10;
    background: transparent;
}
.bly-nav-group { margin-bottom: 2rem; }
.bly-nav-label {
    font-family: var(--font-mono);
    font-size: var(--label-font-size);
    text-transform: uppercase;
    letter-spacing: var(--label-letter-spacing);
    opacity: 0.5;
    margin-bottom: 1rem;
    display: block;
}
.bly-nav-item {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.75rem 0;
    text-decoration: none;
    color: var(--color-fg);
    font-weight: var(--weight-medium);
    font-size: 0.9rem;
    opacity: 0.7;
    transition: opacity 120ms ease;
}
.bly-nav-item:hover { opacity: 0.9; }
.bly-nav-item.is-active {
    opacity: 1;
    font-weight: var(--weight-semibold);
}

/* ===========================
   MAIN SHELL
   =========================== */
.bly-shell {
    display: grid;
    grid-template-columns: var(--sidebar-width) 1fr;
    min-height: 100vh;
    position: relative;
}
.bly-main {
    padding: 2.5rem 4rem;
    overflow: hidden;
    position: relative;
}
.bly-header-row {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    margin-bottom: 3rem;
    position: relative;
    z-index: 5;
}
.bly-workflow-title h1 {
    font-size: 2.5rem;
    font-weight: var(--weight-bold);
    letter-spacing: var(--tight-tracking);
    line-height: 1.05;
    margin: 0;
}

/* ===========================
   BUTTON
   =========================== */
.bly-btn {
    font-family: var(--font-display);
    font-weight: var(--weight-bold);
    border: none;
    cursor: pointer;
    border-radius: var(--radius-pill);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    transition: transform 120ms ease, opacity 120ms ease;
    line-height: 1;
}
.bly-btn:hover { transform: translateY(-1px); }
.bly-btn:active { transform: translateY(0); }
.bly-btn:disabled { opacity: 0.4; cursor: not-allowed; transform: none; }

.bly-btn--primary {
    background: var(--color-accent);
    color: #ffffff;
    box-shadow: var(--shadow-accent-glow);
}
.bly-btn--primary:hover { box-shadow: 0 12px 32px rgba(255, 63, 20, 0.3); }

.bly-btn--secondary {
    background: var(--color-fg);
    color: var(--color-bg);
}

.bly-btn--ghost {
    background: transparent;
    color: var(--color-fg);
    border: 1.5px solid var(--color-fg);
}
.bly-btn--ghost:hover { background: rgba(0, 0, 0, 0.04); }

.bly-btn--destructive {
    background: var(--color-accent);
    color: #ffffff;
}

.bly-btn--sm { padding: 0.5rem 1.25rem; font-size: 0.8rem; }
.bly-btn--md { padding: 0.8rem 1.6rem; font-size: 0.9rem; }
.bly-btn--lg { padding: 1.1rem 2.4rem; font-size: 1rem; }

/* ===========================
   CARD (glass-morphism)
   =========================== */
.bly-card {
    background: var(--color-card);
    border: 1px solid var(--color-card-border);
    border-radius: var(--radius-card-lg);
    padding: 2rem;
    backdrop-filter: var(--backdrop-blur);
    -webkit-backdrop-filter: var(--backdrop-blur);
}
.bly-card--soft {
    background: var(--color-card-soft);
    border: 1px solid rgba(255, 255, 255, 0.3);
    border-radius: var(--radius-card);
    padding: 1.5rem;
}
.bly-card--strong {
    background: var(--color-card-strong);
    border-radius: var(--radius-card);
    padding: 1.5rem;
    border: 1px solid rgba(255, 255, 255, 0.3);
    backdrop-filter: var(--backdrop-blur);
    -webkit-backdrop-filter: var(--backdrop-blur);
}
.bly-card--solid {
    background: var(--color-card-solid);
    border-radius: var(--radius-md);
    padding: 0.75rem;
    box-shadow: var(--shadow-card-soft);
}
.bly-card--score {
    background: var(--color-fg);
    color: var(--color-bg);
    border-radius: var(--radius-hero);
    padding: 3rem;
    border: none;
    backdrop-filter: none;
    position: relative;
    overflow: hidden;
}

/* ===========================
   SCORE BOX (sort hero number)
   =========================== */
.bly-score-meta {
    font-family: var(--font-mono);
    text-transform: uppercase;
    font-size: 0.8rem;
    letter-spacing: var(--label-letter-spacing);
    opacity: 0.7;
    display: block;
    margin-bottom: 0.75rem;
}
.bly-score-big {
    font-size: 8rem;
    font-weight: var(--weight-bold);
    line-height: 0.9;
    letter-spacing: var(--display-tracking);
}
.bly-score-conviction {
    margin-top: 1rem;
    font-weight: var(--weight-medium);
}
.bly-score-blurb {
    margin-top: 1.5rem;
    opacity: 0.65;
    font-size: 0.9rem;
    line-height: 1.5;
}
.bly-score-pill {
    font-family: var(--font-mono);
    font-weight: var(--weight-bold);
    background: var(--color-fg);
    color: var(--color-bg);
    padding: 0.2rem 0.6rem;
    border-radius: var(--radius-xs);
    display: inline-block;
}

/* ===========================
   BADGE / TAG (status variants)
   =========================== */
.bly-badge {
    font-family: var(--font-mono);
    font-size: 0.7rem;
    padding: 0.25rem 0.75rem;
    border-radius: var(--radius-xs);
    text-transform: uppercase;
    letter-spacing: 0.02em;
    font-weight: var(--weight-bold);
    display: inline-block;
    background: rgba(0, 0, 0, 0.1);
    color: var(--color-fg);
}
.bly-badge--validated {
    background: var(--color-status-validated-bg);
    color: var(--color-status-validated-fg);
}
.bly-badge--needs-work {
    background: var(--color-status-needs-bg);
    color: var(--color-status-needs-fg);
}
.bly-badge--rejected {
    background: var(--color-status-rejected-bg);
    color: var(--color-status-rejected-fg);
}
.bly-badge--high {
    background: var(--color-status-high-bg);
    color: var(--color-status-high-fg);
}
.bly-badge--med {
    background: var(--color-status-med-bg);
    color: var(--color-status-med-fg);
}

/* ===========================
   INPUT / TEXTAREA / SELECT
   =========================== */
.bly-field {
    width: 100%;
    background: rgba(255, 255, 255, 0.25);
    border: 1px solid var(--color-card-border);
    border-radius: var(--radius-md);
    padding: 0.85rem 1.1rem;
    color: var(--color-fg);
    font-family: var(--font-display);
    font-size: 0.95rem;
    transition: border-color 120ms ease, background 120ms ease;
}
.bly-field::placeholder {
    color: rgba(0, 0, 0, 0.35);
}
.bly-field:focus {
    outline: none;
    border-color: var(--color-fg);
    background: rgba(255, 255, 255, 0.4);
}
.bly-field--error { border-color: var(--color-accent); }

.bly-textarea {
    min-height: 120px;
    resize: vertical;
    line-height: 1.5;
    font-family: var(--font-display);
}
.bly-select {
    appearance: none;
    background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
                      linear-gradient(135deg, currentColor 50%, transparent 50%);
    background-position: calc(100% - 18px) 55%, calc(100% - 13px) 55%;
    background-size: 5px 5px, 5px 5px;
    background-repeat: no-repeat;
    padding-right: 2.5rem;
}

/* ===========================
   TABLE
   =========================== */
.bly-table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0 0.5rem;
}
.bly-table th {
    text-align: left;
    padding: 1rem;
    font-family: var(--font-mono);
    font-size: var(--label-font-size);
    text-transform: uppercase;
    letter-spacing: var(--label-letter-spacing);
    opacity: 0.5;
    font-weight: var(--weight-regular);
}
.bly-table td {
    padding: 1.25rem 1rem;
    background: rgba(255, 255, 255, 0.1);
    border-top: 1px solid var(--color-card-border);
    border-bottom: 1px solid var(--color-card-border);
    vertical-align: middle;
    font-size: 0.95rem;
}
.bly-table td:first-child {
    border-left: 1px solid var(--color-card-border);
    border-top-left-radius: var(--radius-md);
    border-bottom-left-radius: var(--radius-md);
    font-weight: var(--weight-semibold);
}
.bly-table td:last-child {
    border-right: 1px solid var(--color-card-border);
    border-top-right-radius: var(--radius-md);
    border-bottom-right-radius: var(--radius-md);
}

/* ===========================
   STATS STRIP (used on history page)
   =========================== */
.bly-stats {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 2rem;
    margin-bottom: 3rem;
}
.bly-stat {
    border-bottom: 2px solid var(--color-fg);
    padding-bottom: 1rem;
}
.bly-stat-value {
    font-size: 1.5rem;
    font-weight: var(--weight-bold);
    display: block;
    letter-spacing: -0.01em;
}

/* ===========================
   ACTIVE PROBLEM BAR (live indicator)
   =========================== */
.bly-active-problem {
    background: rgba(0, 0, 0, 0.05);
    padding: 0.5rem 1rem;
    border-radius: var(--radius-sm);
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.8rem;
    font-weight: var(--weight-semibold);
    margin-bottom: 1rem;
}
.bly-pulse {
    width: 6px;
    height: 6px;
    background: var(--color-accent);
    border-radius: 50%;
    animation: bly-pulse 1.6s ease-in-out infinite;
}
@keyframes bly-pulse {
    0%, 100% { opacity: 1; transform: scale(1); }
    50% { opacity: 0.55; transform: scale(1.4); }
}

/* ===========================
   PERSPECTIVE GRID (3 columns)
   =========================== */
.bly-perspective-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 2rem;
    align-items: start;
    position: relative;
    z-index: 5;
}
.bly-perspective-col {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
}
.bly-column-header {
    border-bottom: 1px solid var(--color-card-border);
    padding-bottom: 1rem;
}
.bly-column-header h2 {
    font-size: 1.1rem;
    font-weight: var(--weight-bold);
    margin: 0.25rem 0 0;
    letter-spacing: -0.01em;
}
.bly-viewpoint p {
    font-size: 0.95rem;
    line-height: 1.5;
    margin: 0 0 1.5rem;
    font-weight: var(--weight-medium);
}
.bly-evidence {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    background: #ffffff;
    padding: 0.75rem;
    border-radius: 10px;
    margin-top: 0.75rem;
    box-shadow: var(--shadow-card-soft);
}
.bly-evidence-icon {
    width: 24px;
    height: 24px;
    border-radius: 4px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.65rem;
    font-weight: var(--weight-bold);
    flex-shrink: 0;
}
.bly-evidence-text {
    font-size: 0.75rem;
    font-weight: var(--weight-semibold);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ===========================
   RECOMMENDATION LIST
   =========================== */
.bly-rec-list {
    list-style: none;
    margin: 1rem 0 0;
    padding: 0;
}
.bly-rec-item {
    display: flex;
    gap: 1rem;
    padding: 1rem;
    background: #ffffff;
    border-radius: var(--radius-md);
    margin-bottom: 0.75rem;
    font-size: 0.9rem;
    line-height: 1.45;
    border-left: 4px solid var(--color-accent);
}

/* ===========================
   DIALOG
   =========================== */
.bly-dialog-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(180, 197, 228, 0.5);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    z-index: 100;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 2rem;
}
.bly-dialog {
    background: var(--color-card-strong);
    border: 1px solid rgba(255, 255, 255, 0.3);
    border-radius: var(--radius-card-lg);
    padding: 2.5rem;
    backdrop-filter: var(--backdrop-blur);
    -webkit-backdrop-filter: var(--backdrop-blur);
    max-width: 500px;
    width: 100%;
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15);
}
.bly-dialog__title {
    font-size: 1.5rem;
    font-weight: var(--weight-bold);
    letter-spacing: var(--tight-tracking);
    margin: 0 0 1rem;
}

/* ===========================
   TABS
   =========================== */
.bly-tabs {
    display: flex;
    gap: 0;
    border-bottom: 1px solid var(--color-card-border);
}
.bly-tab {
    background: none;
    border: none;
    padding: 0.75rem 1.25rem;
    font-family: var(--font-display);
    font-size: 0.85rem;
    font-weight: var(--weight-semibold);
    color: var(--color-fg);
    opacity: 0.55;
    cursor: pointer;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    transition: opacity 120ms ease, border-color 120ms ease;
}
.bly-tab:hover { opacity: 0.85; }
.bly-tab.is-active {
    opacity: 1;
    border-bottom-color: var(--color-accent);
}

/* ===========================
   SWITCH
   =========================== */
.bly-switch {
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    cursor: pointer;
    font-size: 0.9rem;
    font-weight: var(--weight-medium);
}
.bly-switch__track {
    width: 38px;
    height: 22px;
    background: rgba(0, 0, 0, 0.15);
    border-radius: 11px;
    position: relative;
    transition: background 160ms ease;
}
.bly-switch__thumb {
    position: absolute;
    top: 2px;
    left: 2px;
    width: 18px;
    height: 18px;
    background: #ffffff;
    border-radius: 50%;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
    transition: left 160ms ease;
}
.bly-switch[data-checked="true"] .bly-switch__track {
    background: var(--color-accent);
}
.bly-switch[data-checked="true"] .bly-switch__thumb {
    left: 18px;
}

/* ===========================
   TOAST
   =========================== */
.bly-toast {
    background: var(--color-card-strong);
    border: 1px solid rgba(255, 255, 255, 0.3);
    border-radius: var(--radius-md);
    padding: 1rem 1.25rem;
    backdrop-filter: var(--backdrop-blur);
    -webkit-backdrop-filter: var(--backdrop-blur);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
    min-width: 240px;
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}
.bly-toast__title {
    font-weight: var(--weight-bold);
    font-size: 0.9rem;
}
.bly-toast__desc {
    font-size: 0.85rem;
    opacity: 0.7;
}
.bly-toast--success { border-left: 4px solid var(--color-status-validated-fg); }
.bly-toast--error { border-left: 4px solid var(--color-accent); }

/* ===========================
   RESPONSIVE
   =========================== */
@media (max-width: 900px) {
    .bly-shell {
        grid-template-columns: 1fr;
    }
    .bly-aside {
        width: 100%;
        border-right: none;
        border-bottom: 1px solid var(--color-divider);
        padding: 1.5rem 1.25rem;
    }
    .bly-vertical-text { display: none; }
    .bly-main { padding: 1.5rem 1.25rem; }
    .bly-perspective-grid { grid-template-columns: 1fr; }
    .bly-stats { grid-template-columns: 1fr 1fr; }
    .bly-score-big { font-size: 5.5rem; }
}

Step 5 — Wrap the section/page you want themed with <div data-system="bluey">:

  <div data-system="bluey">
    <Button>HELLO BLUEY</Button>
    <Card>...</Card>
  </div>

Done. Now <Button>, <Input>, <Card>, <Badge>, <Dialog>, <Tabs>, <Switch>, <Toast>, <Select>, <Textarea> render in Bluey.
Install the Wardrobe Bluey theme in my Lovable project. Each step below maps to a specific file or change.

Step 1 — Add this to globals.css:

/* Helvetica Neue + Courier New are system-installed on most platforms — no @import needed.
   If your stack lacks Helvetica Neue, swap in Inter or another neutral grotesk. */

/* =========================================================
   Wardrobe — BLUEY tokens
   Editorial SaaS calm. Composed authority. Powder blue
   surface, vermillion accent, glass cards, animated blobs,
   vertical Courier text in corners. Linear meets Stratechery.
   Activate via data-system="bluey".
   ========================================================= */

:where([data-system="bluey"]) {
    /* ---- Surface ---- */
    --color-bg: #B4C5E4;                    /* powder blue */
    --color-fg: #000000;                    /* deep ink for text + sort buttons */
    --color-bg-tint: rgba(255, 255, 255, 0.2);
    --color-card: rgba(255, 255, 255, 0.2); /* glass card surface */
    --color-card-soft: rgba(255, 255, 255, 0.15);
    --color-card-strong: rgba(255, 255, 255, 0.4);
    --color-card-solid: #ffffff;            /* white "data-tag" surface */
    --color-card-border: rgba(0, 0, 0, 0.1);
    --color-divider: rgba(0, 0, 0, 0.1);
    --color-divider-soft: rgba(0, 0, 0, 0.05);

    /* ---- Brand accent ---- */
    --color-accent: #FF3F14;                /* vermillion */
    --color-accent-soft: rgba(255, 63, 20, 0.1);
    --color-accent-shadow: rgba(255, 63, 20, 0.2);

    /* ---- Status palette (table + badges) ---- */
    --color-status-validated-bg: #E1F9EB;
    --color-status-validated-fg: #107C41;
    --color-status-needs-bg: #FFF4F2;
    --color-status-needs-fg: #FF3F14;
    --color-status-rejected-bg: #EEEEEE;
    --color-status-rejected-fg: #666666;
    --color-status-high-bg: rgba(0, 255, 0, 0.1);
    --color-status-high-fg: #006622;
    --color-status-med-bg: rgba(255, 200, 0, 0.1);
    --color-status-med-fg: #885500;

    /* ---- Typography ---- */
    --font-display: "Helvetica Neue", "Helvetica", "Arial", sans-serif;
    --font-mono: "Courier New", Courier, monospace;
    --weight-regular: 400;
    --weight-medium: 500;
    --weight-semibold: 600;
    --weight-bold: 700;

    --label-font-size: 0.65rem;
    --label-letter-spacing: 0.1em;
    --tight-tracking: -0.03em;
    --display-tracking: -0.05em;

    /* ---- Radii ---- */
    --radius-xs: 4px;
    --radius-sm: 8px;
    --radius-md: 12px;
    --radius-card: 16px;
    --radius-card-lg: 20px;
    --radius-hero: 24px;
    --radius-pill: 50px;

    /* ---- Shadows + glass ---- */
    --shadow-card-soft: 0 2px 8px rgba(0, 0, 0, 0.03);
    --shadow-accent-glow: 0 10px 30px rgba(255, 63, 20, 0.2);
    --backdrop-blur: blur(10px);

    /* ---- Layout ---- */
    --sidebar-width: 320px;
}


Step 2 — Create components/ui/wardrobe/cn.ts:

export function cn(...classes: Array<string | false | null | undefined>): string {
    return classes.filter(Boolean).join(" ");
}


Step 3 — Create the following 10 component files in components/ui/wardrobe/:

--- components/ui/wardrobe/Button.tsx ---

import * as React from "react";
import { cn } from "./cn";

type ButtonProps = {
    variant?: "primary" | "secondary" | "destructive" | "ghost";
    size?: "sm" | "md" | "lg";
    children: React.ReactNode;
} & React.ButtonHTMLAttributes<HTMLButtonElement>;

export function Button({
    variant = "primary",
    size = "md",
    className,
    children,
    ...props
}: ButtonProps) {
    return (
        <button
            className={cn("bly-btn", `bly-btn--${variant}`, `bly-btn--${size}`, className)}
            {...props}
        >
            {children}
        </button>
    );
}


--- components/ui/wardrobe/Input.tsx ---

import * as React from "react";
import { cn } from "./cn";

type InputProps = {
    size?: "sm" | "md" | "lg";
    variant?: "default" | "error";
    label?: string;
    hint?: string;
    numericBadge?: string;
} & React.InputHTMLAttributes<HTMLInputElement>;

export function Input({
    size = "md",
    variant = "default",
    label,
    hint,
    className,
    id,
    ...props
}: InputProps) {
    const inputId = id ?? React.useId();
    return (
        <div className="bly-field-wrap">
            {label && (
                <label htmlFor={inputId} className="bly-mono-label" style={{ marginBottom: "0.4rem" }}>
                    {label}
                </label>
            )}
            <input
                id={inputId}
                className={cn(
                    "bly-field",
                    variant === "error" && "bly-field--error",
                    className,
                )}
                {...props}
            />
            {hint && (
                <p style={{ fontSize: "0.8rem", opacity: 0.6, marginTop: "0.4rem" }}>{hint}</p>
            )}
        </div>
    );
}


--- components/ui/wardrobe/Textarea.tsx ---

import * as React from "react";
import { cn } from "./cn";

type TextareaProps = {
    size?: "sm" | "md" | "lg";
    variant?: "default" | "error";
    label?: string;
    hint?: string;
} & React.TextareaHTMLAttributes<HTMLTextAreaElement>;

export function Textarea({
    label,
    hint,
    variant = "default",
    className,
    id,
    ...props
}: TextareaProps) {
    const textareaId = id ?? React.useId();
    return (
        <div className="bly-field-wrap">
            {label && (
                <label htmlFor={textareaId} className="bly-mono-label" style={{ marginBottom: "0.4rem" }}>
                    {label}
                </label>
            )}
            <textarea
                id={textareaId}
                className={cn(
                    "bly-field",
                    "bly-textarea",
                    variant === "error" && "bly-field--error",
                    className,
                )}
                {...props}
            />
            {hint && (
                <p style={{ fontSize: "0.8rem", opacity: 0.6, marginTop: "0.4rem" }}>{hint}</p>
            )}
        </div>
    );
}


--- components/ui/wardrobe/Select.tsx ---

import * as React from "react";
import { cn } from "./cn";

type Option = { value: string; label: string };

type SelectProps = {
    options: Option[];
    value: string;
    onValueChange: (value: string) => void;
    placeholder?: string;
} & Omit<React.SelectHTMLAttributes<HTMLSelectElement>, "value" | "onChange">;

export function Select({
    options,
    value,
    onValueChange,
    placeholder,
    className,
    ...props
}: SelectProps) {
    return (
        <select
            className={cn("bly-field", "bly-select", className)}
            value={value}
            onChange={(e) => onValueChange(e.target.value)}
            {...props}
        >
            {placeholder && <option value="" disabled>{placeholder}</option>}
            {options.map((opt) => (
                <option key={opt.value} value={opt.value}>
                    {opt.label}
                </option>
            ))}
        </select>
    );
}


--- components/ui/wardrobe/Card.tsx ---

import * as React from "react";
import { cn } from "./cn";

type CardProps = {
    variant?: "default" | "soft" | "strong" | "solid" | "score";
    children: React.ReactNode;
} & React.HTMLAttributes<HTMLDivElement>;

export function Card({
    variant = "default",
    className,
    children,
    ...props
}: CardProps) {
    return (
        <div
            className={cn(
                "bly-card",
                variant !== "default" && `bly-card--${variant}`,
                className,
            )}
            {...props}
        >
            {children}
        </div>
    );
}


--- components/ui/wardrobe/Badge.tsx ---

import * as React from "react";
import { cn } from "./cn";

type BadgeProps = {
    variant?: "default" | "validated" | "needs-work" | "rejected" | "high" | "med";
    children: React.ReactNode;
} & React.HTMLAttributes<HTMLSpanElement>;

export function Badge({
    variant = "default",
    className,
    children,
    ...props
}: BadgeProps) {
    return (
        <span
            className={cn(
                "bly-badge",
                variant !== "default" && `bly-badge--${variant}`,
                className,
            )}
            {...props}
        >
            {children}
        </span>
    );
}


--- components/ui/wardrobe/Dialog.tsx ---

import * as React from "react";

type DialogProps = {
    open: boolean;
    onOpenChange: (open: boolean) => void;
    title: string;
    children: React.ReactNode;
};

export function Dialog({ open, onOpenChange, title, children }: DialogProps) {
    React.useEffect(() => {
        if (!open) return;
        function onKey(e: KeyboardEvent) {
            if (e.key === "Escape") onOpenChange(false);
        }
        document.addEventListener("keydown", onKey);
        return () => document.removeEventListener("keydown", onKey);
    }, [open, onOpenChange]);

    if (!open) return null;
    return (
        <div
            className="bly-dialog-backdrop"
            role="dialog"
            aria-modal="true"
            aria-label={title}
            onClick={(e) => {
                if (e.target === e.currentTarget) onOpenChange(false);
            }}
        >
            <div className="bly-dialog">
                <h2 className="bly-dialog__title">{title}</h2>
                {children}
            </div>
        </div>
    );
}


--- components/ui/wardrobe/Tabs.tsx ---

import * as React from "react";
import { cn } from "./cn";

type TabsProps = {
    tabs: Array<{ id: string; label: string }>;
    activeId: string;
    onTabChange: (id: string) => void;
};

export function Tabs({ tabs, activeId, onTabChange }: TabsProps) {
    return (
        <div className="bly-tabs" role="tablist">
            {tabs.map((tab) => (
                <button
                    key={tab.id}
                    type="button"
                    role="tab"
                    aria-selected={tab.id === activeId}
                    className={cn("bly-tab", tab.id === activeId && "is-active")}
                    onClick={() => onTabChange(tab.id)}
                >
                    {tab.label}
                </button>
            ))}
        </div>
    );
}


--- components/ui/wardrobe/Switch.tsx ---

import * as React from "react";

type SwitchProps = {
    checked: boolean;
    onCheckedChange: (checked: boolean) => void;
    label?: string;
};

export function Switch({ checked, onCheckedChange, label }: SwitchProps) {
    return (
        <label className="bly-switch" data-checked={checked}>
            <span className="bly-switch__track">
                <span className="bly-switch__thumb" />
            </span>
            <input
                type="checkbox"
                checked={checked}
                onChange={(e) => onCheckedChange(e.target.checked)}
                style={{ position: "absolute", opacity: 0, width: 0, height: 0 }}
            />
            {label && <span>{label}</span>}
        </label>
    );
}


--- components/ui/wardrobe/Toast.tsx ---

import * as React from "react";
import { cn } from "./cn";

type ToastProps = {
    title: string;
    description?: string;
    variant?: "default" | "success" | "error";
};

export function Toast({ title, description, variant = "default" }: ToastProps) {
    return (
        <div
            className={cn(
                "bly-toast",
                variant !== "default" && `bly-toast--${variant}`,
            )}
            role="status"
            aria-live="polite"
        >
            <span className="bly-toast__title">{title}</span>
            {description && <span className="bly-toast__desc">{description}</span>}
        </div>
    );
}


Step 4 — Add globals.css component styles. Append the following to globals.css below the tokens:

/* =========================================================
   Wardrobe — BLUEY globals
   Loads Helvetica Neue (system) + Courier New (system mono),
   then component + decoration styles.
   Only active under data-system="bluey".
   ========================================================= */


[data-system="bluey"] *,
[data-system="bluey"] *::before,
[data-system="bluey"] *::after {
    box-sizing: border-box;
}

[data-system="bluey"] {
    background-color: var(--color-bg);
    color: var(--color-fg);
    font-family: var(--font-display);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    min-height: 100vh;
}

/* ===========================
   LOGO
   =========================== */
.bly-logo {
    font-family: var(--font-display);
    font-weight: var(--weight-bold);
    font-size: 1.25rem;
    letter-spacing: -0.02em;
    color: var(--color-fg);
}

/* ===========================
   MONO LABEL (used everywhere)
   =========================== */
.bly-mono-label {
    font-family: var(--font-mono);
    font-size: var(--label-font-size);
    text-transform: uppercase;
    letter-spacing: var(--label-letter-spacing);
    opacity: 0.5;
    display: inline-block;
}

/* ===========================
   VERTICAL TEXT (corner caption)
   =========================== */
.bly-vertical-text {
    position: absolute;
    bottom: 2.5rem;
    left: 2rem;
    writing-mode: vertical-rl;
    text-orientation: mixed;
    font-family: var(--font-mono);
    font-size: var(--label-font-size);
    letter-spacing: 0.05em;
    opacity: 0.4;
    pointer-events: none;
}

/* ===========================
   ANIMATED BLOB
   =========================== */
.bly-blob {
    position: absolute;
    border-radius: 50%;
    background: var(--color-accent);
    filter: blur(100px);
    opacity: 0.18;
    z-index: 0;
    pointer-events: none;
    animation: bly-blob-morph 14s ease-in-out infinite;
}
.bly-blob--corner {
    bottom: -50px;
    right: -50px;
    width: 400px;
    height: 400px;
}
.bly-blob--center {
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 800px;
    height: 800px;
    background: radial-gradient(circle, var(--color-accent) 0%, transparent 70%);
    filter: blur(120px);
    opacity: 0.1;
}
.bly-blob--top-right {
    top: 20%;
    right: -10%;
    width: 600px;
    height: 600px;
    filter: blur(120px);
    opacity: 0.12;
}
.bly-blob--white {
    background: #ffffff;
    opacity: 0.22;
    filter: blur(120px);
}

@keyframes bly-blob-morph {
    0%, 100% { transform: translate(0, 0) scale(1); }
    33% { transform: translate(30px, -20px) scale(1.05); }
    66% { transform: translate(-20px, 25px) scale(0.97); }
}
.bly-blob--center {
    animation: bly-blob-morph-center 18s ease-in-out infinite;
}
@keyframes bly-blob-morph-center {
    0%, 100% { transform: translate(-50%, -50%) scale(1); }
    50% { transform: translate(-48%, -52%) scale(1.06); }
}

/* ===========================
   NAV SIDEBAR (320px)
   =========================== */
.bly-aside {
    width: var(--sidebar-width);
    border-right: 1px solid var(--color-divider);
    padding: 2.5rem 2rem;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    z-index: 10;
    background: transparent;
}
.bly-nav-group { margin-bottom: 2rem; }
.bly-nav-label {
    font-family: var(--font-mono);
    font-size: var(--label-font-size);
    text-transform: uppercase;
    letter-spacing: var(--label-letter-spacing);
    opacity: 0.5;
    margin-bottom: 1rem;
    display: block;
}
.bly-nav-item {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.75rem 0;
    text-decoration: none;
    color: var(--color-fg);
    font-weight: var(--weight-medium);
    font-size: 0.9rem;
    opacity: 0.7;
    transition: opacity 120ms ease;
}
.bly-nav-item:hover { opacity: 0.9; }
.bly-nav-item.is-active {
    opacity: 1;
    font-weight: var(--weight-semibold);
}

/* ===========================
   MAIN SHELL
   =========================== */
.bly-shell {
    display: grid;
    grid-template-columns: var(--sidebar-width) 1fr;
    min-height: 100vh;
    position: relative;
}
.bly-main {
    padding: 2.5rem 4rem;
    overflow: hidden;
    position: relative;
}
.bly-header-row {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    margin-bottom: 3rem;
    position: relative;
    z-index: 5;
}
.bly-workflow-title h1 {
    font-size: 2.5rem;
    font-weight: var(--weight-bold);
    letter-spacing: var(--tight-tracking);
    line-height: 1.05;
    margin: 0;
}

/* ===========================
   BUTTON
   =========================== */
.bly-btn {
    font-family: var(--font-display);
    font-weight: var(--weight-bold);
    border: none;
    cursor: pointer;
    border-radius: var(--radius-pill);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    transition: transform 120ms ease, opacity 120ms ease;
    line-height: 1;
}
.bly-btn:hover { transform: translateY(-1px); }
.bly-btn:active { transform: translateY(0); }
.bly-btn:disabled { opacity: 0.4; cursor: not-allowed; transform: none; }

.bly-btn--primary {
    background: var(--color-accent);
    color: #ffffff;
    box-shadow: var(--shadow-accent-glow);
}
.bly-btn--primary:hover { box-shadow: 0 12px 32px rgba(255, 63, 20, 0.3); }

.bly-btn--secondary {
    background: var(--color-fg);
    color: var(--color-bg);
}

.bly-btn--ghost {
    background: transparent;
    color: var(--color-fg);
    border: 1.5px solid var(--color-fg);
}
.bly-btn--ghost:hover { background: rgba(0, 0, 0, 0.04); }

.bly-btn--destructive {
    background: var(--color-accent);
    color: #ffffff;
}

.bly-btn--sm { padding: 0.5rem 1.25rem; font-size: 0.8rem; }
.bly-btn--md { padding: 0.8rem 1.6rem; font-size: 0.9rem; }
.bly-btn--lg { padding: 1.1rem 2.4rem; font-size: 1rem; }

/* ===========================
   CARD (glass-morphism)
   =========================== */
.bly-card {
    background: var(--color-card);
    border: 1px solid var(--color-card-border);
    border-radius: var(--radius-card-lg);
    padding: 2rem;
    backdrop-filter: var(--backdrop-blur);
    -webkit-backdrop-filter: var(--backdrop-blur);
}
.bly-card--soft {
    background: var(--color-card-soft);
    border: 1px solid rgba(255, 255, 255, 0.3);
    border-radius: var(--radius-card);
    padding: 1.5rem;
}
.bly-card--strong {
    background: var(--color-card-strong);
    border-radius: var(--radius-card);
    padding: 1.5rem;
    border: 1px solid rgba(255, 255, 255, 0.3);
    backdrop-filter: var(--backdrop-blur);
    -webkit-backdrop-filter: var(--backdrop-blur);
}
.bly-card--solid {
    background: var(--color-card-solid);
    border-radius: var(--radius-md);
    padding: 0.75rem;
    box-shadow: var(--shadow-card-soft);
}
.bly-card--score {
    background: var(--color-fg);
    color: var(--color-bg);
    border-radius: var(--radius-hero);
    padding: 3rem;
    border: none;
    backdrop-filter: none;
    position: relative;
    overflow: hidden;
}

/* ===========================
   SCORE BOX (sort hero number)
   =========================== */
.bly-score-meta {
    font-family: var(--font-mono);
    text-transform: uppercase;
    font-size: 0.8rem;
    letter-spacing: var(--label-letter-spacing);
    opacity: 0.7;
    display: block;
    margin-bottom: 0.75rem;
}
.bly-score-big {
    font-size: 8rem;
    font-weight: var(--weight-bold);
    line-height: 0.9;
    letter-spacing: var(--display-tracking);
}
.bly-score-conviction {
    margin-top: 1rem;
    font-weight: var(--weight-medium);
}
.bly-score-blurb {
    margin-top: 1.5rem;
    opacity: 0.65;
    font-size: 0.9rem;
    line-height: 1.5;
}
.bly-score-pill {
    font-family: var(--font-mono);
    font-weight: var(--weight-bold);
    background: var(--color-fg);
    color: var(--color-bg);
    padding: 0.2rem 0.6rem;
    border-radius: var(--radius-xs);
    display: inline-block;
}

/* ===========================
   BADGE / TAG (status variants)
   =========================== */
.bly-badge {
    font-family: var(--font-mono);
    font-size: 0.7rem;
    padding: 0.25rem 0.75rem;
    border-radius: var(--radius-xs);
    text-transform: uppercase;
    letter-spacing: 0.02em;
    font-weight: var(--weight-bold);
    display: inline-block;
    background: rgba(0, 0, 0, 0.1);
    color: var(--color-fg);
}
.bly-badge--validated {
    background: var(--color-status-validated-bg);
    color: var(--color-status-validated-fg);
}
.bly-badge--needs-work {
    background: var(--color-status-needs-bg);
    color: var(--color-status-needs-fg);
}
.bly-badge--rejected {
    background: var(--color-status-rejected-bg);
    color: var(--color-status-rejected-fg);
}
.bly-badge--high {
    background: var(--color-status-high-bg);
    color: var(--color-status-high-fg);
}
.bly-badge--med {
    background: var(--color-status-med-bg);
    color: var(--color-status-med-fg);
}

/* ===========================
   INPUT / TEXTAREA / SELECT
   =========================== */
.bly-field {
    width: 100%;
    background: rgba(255, 255, 255, 0.25);
    border: 1px solid var(--color-card-border);
    border-radius: var(--radius-md);
    padding: 0.85rem 1.1rem;
    color: var(--color-fg);
    font-family: var(--font-display);
    font-size: 0.95rem;
    transition: border-color 120ms ease, background 120ms ease;
}
.bly-field::placeholder {
    color: rgba(0, 0, 0, 0.35);
}
.bly-field:focus {
    outline: none;
    border-color: var(--color-fg);
    background: rgba(255, 255, 255, 0.4);
}
.bly-field--error { border-color: var(--color-accent); }

.bly-textarea {
    min-height: 120px;
    resize: vertical;
    line-height: 1.5;
    font-family: var(--font-display);
}
.bly-select {
    appearance: none;
    background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
                      linear-gradient(135deg, currentColor 50%, transparent 50%);
    background-position: calc(100% - 18px) 55%, calc(100% - 13px) 55%;
    background-size: 5px 5px, 5px 5px;
    background-repeat: no-repeat;
    padding-right: 2.5rem;
}

/* ===========================
   TABLE
   =========================== */
.bly-table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0 0.5rem;
}
.bly-table th {
    text-align: left;
    padding: 1rem;
    font-family: var(--font-mono);
    font-size: var(--label-font-size);
    text-transform: uppercase;
    letter-spacing: var(--label-letter-spacing);
    opacity: 0.5;
    font-weight: var(--weight-regular);
}
.bly-table td {
    padding: 1.25rem 1rem;
    background: rgba(255, 255, 255, 0.1);
    border-top: 1px solid var(--color-card-border);
    border-bottom: 1px solid var(--color-card-border);
    vertical-align: middle;
    font-size: 0.95rem;
}
.bly-table td:first-child {
    border-left: 1px solid var(--color-card-border);
    border-top-left-radius: var(--radius-md);
    border-bottom-left-radius: var(--radius-md);
    font-weight: var(--weight-semibold);
}
.bly-table td:last-child {
    border-right: 1px solid var(--color-card-border);
    border-top-right-radius: var(--radius-md);
    border-bottom-right-radius: var(--radius-md);
}

/* ===========================
   STATS STRIP (used on history page)
   =========================== */
.bly-stats {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 2rem;
    margin-bottom: 3rem;
}
.bly-stat {
    border-bottom: 2px solid var(--color-fg);
    padding-bottom: 1rem;
}
.bly-stat-value {
    font-size: 1.5rem;
    font-weight: var(--weight-bold);
    display: block;
    letter-spacing: -0.01em;
}

/* ===========================
   ACTIVE PROBLEM BAR (live indicator)
   =========================== */
.bly-active-problem {
    background: rgba(0, 0, 0, 0.05);
    padding: 0.5rem 1rem;
    border-radius: var(--radius-sm);
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.8rem;
    font-weight: var(--weight-semibold);
    margin-bottom: 1rem;
}
.bly-pulse {
    width: 6px;
    height: 6px;
    background: var(--color-accent);
    border-radius: 50%;
    animation: bly-pulse 1.6s ease-in-out infinite;
}
@keyframes bly-pulse {
    0%, 100% { opacity: 1; transform: scale(1); }
    50% { opacity: 0.55; transform: scale(1.4); }
}

/* ===========================
   PERSPECTIVE GRID (3 columns)
   =========================== */
.bly-perspective-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 2rem;
    align-items: start;
    position: relative;
    z-index: 5;
}
.bly-perspective-col {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
}
.bly-column-header {
    border-bottom: 1px solid var(--color-card-border);
    padding-bottom: 1rem;
}
.bly-column-header h2 {
    font-size: 1.1rem;
    font-weight: var(--weight-bold);
    margin: 0.25rem 0 0;
    letter-spacing: -0.01em;
}
.bly-viewpoint p {
    font-size: 0.95rem;
    line-height: 1.5;
    margin: 0 0 1.5rem;
    font-weight: var(--weight-medium);
}
.bly-evidence {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    background: #ffffff;
    padding: 0.75rem;
    border-radius: 10px;
    margin-top: 0.75rem;
    box-shadow: var(--shadow-card-soft);
}
.bly-evidence-icon {
    width: 24px;
    height: 24px;
    border-radius: 4px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.65rem;
    font-weight: var(--weight-bold);
    flex-shrink: 0;
}
.bly-evidence-text {
    font-size: 0.75rem;
    font-weight: var(--weight-semibold);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ===========================
   RECOMMENDATION LIST
   =========================== */
.bly-rec-list {
    list-style: none;
    margin: 1rem 0 0;
    padding: 0;
}
.bly-rec-item {
    display: flex;
    gap: 1rem;
    padding: 1rem;
    background: #ffffff;
    border-radius: var(--radius-md);
    margin-bottom: 0.75rem;
    font-size: 0.9rem;
    line-height: 1.45;
    border-left: 4px solid var(--color-accent);
}

/* ===========================
   DIALOG
   =========================== */
.bly-dialog-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(180, 197, 228, 0.5);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    z-index: 100;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 2rem;
}
.bly-dialog {
    background: var(--color-card-strong);
    border: 1px solid rgba(255, 255, 255, 0.3);
    border-radius: var(--radius-card-lg);
    padding: 2.5rem;
    backdrop-filter: var(--backdrop-blur);
    -webkit-backdrop-filter: var(--backdrop-blur);
    max-width: 500px;
    width: 100%;
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15);
}
.bly-dialog__title {
    font-size: 1.5rem;
    font-weight: var(--weight-bold);
    letter-spacing: var(--tight-tracking);
    margin: 0 0 1rem;
}

/* ===========================
   TABS
   =========================== */
.bly-tabs {
    display: flex;
    gap: 0;
    border-bottom: 1px solid var(--color-card-border);
}
.bly-tab {
    background: none;
    border: none;
    padding: 0.75rem 1.25rem;
    font-family: var(--font-display);
    font-size: 0.85rem;
    font-weight: var(--weight-semibold);
    color: var(--color-fg);
    opacity: 0.55;
    cursor: pointer;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    transition: opacity 120ms ease, border-color 120ms ease;
}
.bly-tab:hover { opacity: 0.85; }
.bly-tab.is-active {
    opacity: 1;
    border-bottom-color: var(--color-accent);
}

/* ===========================
   SWITCH
   =========================== */
.bly-switch {
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    cursor: pointer;
    font-size: 0.9rem;
    font-weight: var(--weight-medium);
}
.bly-switch__track {
    width: 38px;
    height: 22px;
    background: rgba(0, 0, 0, 0.15);
    border-radius: 11px;
    position: relative;
    transition: background 160ms ease;
}
.bly-switch__thumb {
    position: absolute;
    top: 2px;
    left: 2px;
    width: 18px;
    height: 18px;
    background: #ffffff;
    border-radius: 50%;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
    transition: left 160ms ease;
}
.bly-switch[data-checked="true"] .bly-switch__track {
    background: var(--color-accent);
}
.bly-switch[data-checked="true"] .bly-switch__thumb {
    left: 18px;
}

/* ===========================
   TOAST
   =========================== */
.bly-toast {
    background: var(--color-card-strong);
    border: 1px solid rgba(255, 255, 255, 0.3);
    border-radius: var(--radius-md);
    padding: 1rem 1.25rem;
    backdrop-filter: var(--backdrop-blur);
    -webkit-backdrop-filter: var(--backdrop-blur);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
    min-width: 240px;
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}
.bly-toast__title {
    font-weight: var(--weight-bold);
    font-size: 0.9rem;
}
.bly-toast__desc {
    font-size: 0.85rem;
    opacity: 0.7;
}
.bly-toast--success { border-left: 4px solid var(--color-status-validated-fg); }
.bly-toast--error { border-left: 4px solid var(--color-accent); }

/* ===========================
   RESPONSIVE
   =========================== */
@media (max-width: 900px) {
    .bly-shell {
        grid-template-columns: 1fr;
    }
    .bly-aside {
        width: 100%;
        border-right: none;
        border-bottom: 1px solid var(--color-divider);
        padding: 1.5rem 1.25rem;
    }
    .bly-vertical-text { display: none; }
    .bly-main { padding: 1.5rem 1.25rem; }
    .bly-perspective-grid { grid-template-columns: 1fr; }
    .bly-stats { grid-template-columns: 1fr 1fr; }
    .bly-score-big { font-size: 5.5rem; }
}

Step 5 — Wrap the section/page you want themed with <div data-system="bluey">:

  <div data-system="bluey">
    <Button>HELLO BLUEY</Button>
    <Card>...</Card>
  </div>

Done. Now <Button>, <Input>, <Card>, <Badge>, <Dialog>, <Tabs>, <Switch>, <Toast>, <Select>, <Textarea> render in Bluey.

Once it's installed, wrap whichever section you want themed:

<div data-system="bluey">
    <Button variant="primary">Run validation →</Button>
    <Card>Glass card</Card>
</div>

Want to see what it looks like in the wild? SuperYes →