// DiveDex — Dive Boutique screens + components
// ── Pearl glyph ────────────────────────────────────────────────────
function PearlIcon({ size = 14 }) {
return (
);
}
function PearlBalanceChip({ amount, big = false }) {
return (
{amount.toLocaleString()}Pearls
);
}
function ItemRarityBadge({ rarity }) {
return (
{rarity}
);
}
function EquippedBadge() {
return (
EQUIPPED
);
}
function LockedRequirementPill({ text }) {
return (
{text}
);
}
// ── Item thumbnail SVGs ────────────────────────────────────────────
function ItemArt({ kind, rarity = 'epic', size = 90 }) {
const palette = ({
common:['#B7CCDE','#7A93AB'], uncommon:['#63FFD2','#1FB6A0'], rare:['#82ECFF','#31D7FF'],
epic:['#C8B6FF','#8B7BFF'], legendary:['#FBE6A6','#D7B46A'], mythic:['#82ECFF','#FF7A6B'],
})[rarity] || ['#82ECFF','#31D7FF'];
const a = palette[0], b = palette[1];
return (
);
}
function Glyph({ kind, grad, a, b }) {
const g = `url(#${grad})`;
switch (kind) {
case 'suit-baroque': return
{[30,40,50,60,70].map(y=>)}
;
case 'suit-champagne': return ;
case 'suit-neon': return ;
case 'suit-stealth': return ;
case 'bcd-quilt': return
{[40,52,64].map(y=>)}
{[32,46,60,74].map(x=>)}
;
case 'bcd-gold': return ;
case 'bcd-tactical': return ;
case 'bcd-couture': return ;
case 'fins-pearl': case 'fins-coral': return ;
case 'mask-tokyo': case 'mask-gold': return ;
case 'acc-charm': return ;
case 'acc-camera': return ;
case 'acc-snack': return 7-11;
case 'acc-blanket': return
{[24,32,40,48,56,64,72].map(x=>)}
;
case 'title-shark': return WHISPERER;
case 'title-snack': return SNACKCHAMPION;
case 'title-zen': return AIR ZEN;
case 'title-crown': case 'crown': return ;
case 'frame-hammer': return ;
case 'frame-manta': return ;
case 'frame-tokyo': return ;
case 'frame-champ': return ;
case 'frame-zen': return ;
case 'trophy-shark': return ;
case 'crest': return RS;
case 'sash': return ;
case 'halo': return ;
default: return ;
}
}
// ── Card ───────────────────────────────────────────────────────────
function ShopItemCard({ item, onClick, compact = false }) {
const r = item.rarity;
const isEq = item.state === 'equipped';
const isLocked = item.state === 'locked';
const isAch = item.state === 'achievement';
const owned = item.state === 'owned' || isEq;
return (
{isLocked && (
)}
{/* When equipped, the EQUIPPED label takes the top — the card's
colored frame already communicates rarity, so we hide the rarity
badge to avoid an overlap on narrow phone widths. */}
{isEq
?
Unlocked through legendary encounters, expedition milestones and Air Zen streaks. No Pearls accepted.
{list.map(it => nav('item', it.id)}/>)}
);
}
function StoryFramePreview({ item }) {
// Show a mini fake story card with the frame applied
const r = item.rarity;
const isFrame = item.cat === 'frames';
return (