# Kismet Glitter — design notes

Working notes for `kismetglitter.com`. Built 2026-09-05 by Brandon Harvey.
Companion to `brand/brand-guide.html`, which holds the full identity system. This file holds the
decisions, the tokens, the maintenance instructions and the things that still need producing.

---

## 1. What shipped

| File | What it is | Size |
|---|---|---|
| `index.html` | Homepage. Self-contained: inline CSS + JS, canvas glitter field, UV flip, raw-vs-applied scrubber, 27 curated products across 6 collections. | 73.1 KB |
| `shop.html` | Full catalogue — 74 products/variants, chip filtering with a real FLIP animation, price/name sorting, deep links (`shop.html#uv`). | 50.6 KB |
| `brand/brand-guide.html` | The brand system: naming, positioning, personas, voice, palette, type, three marks, motion, photography, packaging, social templates, family rules. | 99.5 KB |
| `docs/design-notes.md` | This file. | 21.7 KB |

No build step. No dependencies. No frameworks. Every page opens from `file://` and works.
Deployment is the existing GitHub Actions FTP workflow that pushes the repo root to `/public_html/`,
so `index.html` at the root is what goes live.

`data/` and `.github/` were not touched.

---

## 2. Decisions, and why

### 2.1 The naming hierarchy is settled
Three names were in play — **Kismetglitter** (domain, Etsy slug, TikTok, eBay), **Kismet Beauty**
(the voice in the Etsy announcement and About) and **Kismet Magic Glitter** (the product line).
The site commits to:

- **Kismet Glitter** — the brand. Domain, logo, handles, every headline.
- **Kismet Magic Glitter** — the hero product line (loose holographic pigments). Keeps its full Etsy
  title because that title is doing search work.
- **Kismet UV Glow / Prism Body Makeup / Kismet Studio** — the other lines.
- **Kismet Beauty** — retired to a *descriptor*, never a name. "Kismet Glitter — a beauty studio in
  Detroit." The argument is laid out in full in section 01 of the brand guide.

**Action for Courtney:** the Etsy shop title, announcement and About are the only three places where
the wrong name is load-bearing. Change those three. Listing titles can stay — they carry search
history and the line name in them is already correct.

### 2.2 Phase 1 is cart-less on purpose
There is no cart, no checkout, no inventory. Every Buy button is an outbound link to the Etsy shop
with the shade pre-filled as a search query:

```
https://www.etsy.com/shop/Kismetglitter
  ?utm_source=kismetglitter.com
  &utm_medium=referral
  &utm_campaign=<collection>
  &search_query=<shade name>
```

Etsy does not publish per-listing IDs in either data file we have, so shop-scoped search is the most
precise link available. It lands the customer inside the right shop with the right shade filtered.
Phase-2 replacement is one function — see §7.

### 2.3 Prices come from the live snapshot, images from the older export
`data/etsy-shop-snapshot-2026-09-05.md` is live (115 listings). `data/etsy-listings-2025-12-19.csv`
is nine months older (52 rows) but is the only place image URLs and descriptions exist offline.
So: **price = snapshot, image = CSV matched by shade name.** Where the two disagree on price
(e.g. Holographic Unicorn: $24 in the CSV, $56 live) the live number wins. A wrong price is worse
than a missing image.

Products with no CSV match carry `img:""` and show only their CSS swatch — that is a designed state,
not a failure. See §2.4.

### 2.4 Every product has a hand-authored CSS swatch
There are no product photographs available yet. Rather than ship grey placeholder boxes, every
product carries a `sw` CSS gradient authored to approximate its actual shade — a conic rainbow for
Rainbow, a violet-to-deep-purple linear for Amethyst Prism, a radial ember for Cosmic Ember. The
grid looks intentional with zero photography, and each swatch also carries a `uvc` blacklight colour
that drives its glow in UV mode.

Where an Etsy image URL exists it loads on top of the swatch and fades in (`onload` → `.ok`). If it
404s or Etsy blocks the hotlink, `onerror="kgImgFail(this)"` removes the `<img>` and the swatch
underneath is simply what you see. There is no broken-image state anywhere on either page.

### 2.5 The 1★ review drove a whole homepage section
One review reads: *"Expected all in one holographic glitter. This is 5 rainbow colors."* That is a
communication failure, not a product failure — the product genuinely is a multi-pigment blend that
needs a mixing medium and directional light. So the homepage carries an **"It's a blend, not a
shade"** section above the collections: a draggable raw-vs-applied comparison, a callout stating the
pigment count, six application steps, and a recommendation to start with the $12 mini. The 1★ review
itself is printed in the reviews strip with an honest response rather than hidden.

### 2.6 Motion is the product demo, not decoration
A holographic pigment only exists when light moves across it. A still photo structurally under-sells
it. So the site moves the light: the prism sweep, the UV flip, the glitter field, the pigment-catch
hover, and the raw→applied scrubber. Motion personality is documented in the brand guide as
**"Prismatic Premium"** — Premium base timings with Energetic accents on interaction.

### 2.7 Candles are linked, never sold here
The Etsy shop still lists Kismet Candles skull candles. On the web that stays split: kismetglitter.com
links to kismetcandles.com and says so explicitly in the shop footer, so a customer arriving from an
Etsy candle listing is not confused.

---

## 3. Tokens

All three pages define the same token block at `:root`. Change it in one place per file.

### Colour — "Prism Riot"

```css
/* holographic spectrum */
--aura:#FF4FD8;    /* Aura Pink      — spectrum head, primary accent          */
--flare:#FF2F92;   /* Fuchsia Flare  — SHARED with Kismet Candles. links, CTA */
--opal:#FFD85E;    /* Solar Opal     — SHARED. stars, low-stock               */
--jade:#00EAA7;    /* Electric Jade  — SHARED. success                        */
--cyan:#3FE8FF;    /* Cyan Prism     — glitter only. focus rings              */
--violet:#9C5BFF;  /* Holo Violet    — SHARED. ambient auras                  */

/* ground */
--void:#0A0710;    /* Obsidian Veil  — page ground (violet-leaning black)     */
--plum:#150E1E;    /* Midnight Plum  — cards, panels                          */
--quartz:#241A2E;  /* Smoke Quartz   — borders                                */
--ink:#F6F1FA;     /* Moonlight      — body text.  15.9:1 on Obsidian         */
--muted:#B9A8C9;   /* Ash Lilac      — secondary.   8.4:1 on Obsidian         */
/* text sitting ON the spectrum is always #100617, never white */

/* UV neons — only inside :root.uv */
--uv-magenta:#FF2BD6; --uv-cyan:#00F0FF; --uv-lime:#B6FF3C; --uv-violet:#7B2BFF;

/* the signature gradient — stops wrap so it loops seamlessly */
--holo:linear-gradient(100deg,#FF4FD8 0%,#FF2F92 16%,#FFD85E 34%,#00EAA7 52%,
                              #3FE8FF 70%,#9C5BFF 88%,#FF4FD8 100%);
```

**Rule:** never fill a large area with a single spectrum colour. The spectrum is a gradient; single
hues are for hairlines, small text, icons and glows only. The ground carries ~80% of surface area.

### Fonts

| Role | Family | Weights | Fallback |
|---|---|---|---|
| Display | **Bodoni Moda** | 400, 600, 400 italic | Didot, Bodoni MT, Georgia, serif |
| Accent | **Dancing Script** | 600 | Segoe Script, Brush Script MT, cursive |
| Body / UI | **Inter** | 400, 500, 600, 700 | system sans stack |
| Data (brand guide only) | JetBrains Mono | 400, 500 | ui-monospace, Consolas |

One Google Fonts request per page, `display=swap`, with `preconnect` to both font hosts.
Dancing Script is shared with Kismet Candles — it is the family's handwriting and must not change.

### Motion

```css
--dur-quick:140ms;   --dur-base:320ms;   --dur-slow:620ms;   --dur-reveal:900ms;
--ease-glow:cubic-bezier(.22,1,.36,1);        /* SIGNATURE — 80% of all motion */
--ease-smooth:cubic-bezier(.4,0,.2,1);        /* on-screen, colour             */
--ease-exit:cubic-bezier(.3,0,1,1);           /* leaving                       */
--ease-pop:cubic-bezier(.175,.885,.32,1.275); /* accents, ~12% overshoot       */
--ease-sine:cubic-bezier(.37,0,.63,1);        /* ambient loops                 */
--stagger:60ms;   /* 40ms in grids — total cascade budget never exceeds 500ms */
--shimmer:2400ms; /* one specular pass across a swatch */
--spectrum:18s;   /* one full loop of the holographic gradient */
```

Linear easing is banned for spatial movement. Two documented exceptions, both of which visibly
stutter at the loop seam otherwise: the marquee ticker and the holographic gradient loop.

### Layout

```css
--pad:clamp(1.1rem,4vw,3.5rem);
--maxw:1180px;   /* index + brand guide 1120px */
```

Mobile-first. Grid breakpoints at 560 / 720 / 760 / 820 / 900 px. The shop grid is
`repeat(auto-fill, minmax(min(100%,15.5rem), 1fr))` so it needs no breakpoints of its own.

---

## 4. How to add a product

The catalogue lives in **`shop.html`**, in the `var P = [...]` array inside the page's single
`<script>`. That is the source of truth. `index.html` carries a smaller curated array of homepage
highlights — add there only if the product should appear on the homepage.

Add one object:

```js
{
  n:   "Kismet Magic Glitter",        // line name — must match an existing line
  s:   "Nebula Drift",                // shade name, Title Case. Drives the Etsy search query.
  p:   24.99,                         // number, not a string. Live Etsy price.
  c:   "magic",                       // magic | uv | prism | face | studio | bath
  sw:  "linear-gradient(140deg,#E7D6FF,#9C5BFF 45%,#5B2E9E 75%)",  // any CSS background
  uvc: "#B07BFF",                     // colour it glows in blacklight mode
  uv:  1,                             // OPTIONAL — 1 if it actually fluoresces under UV
  low: 1,                             // OPTIONAL — 1 shows a "Low stock" badge
  img: "https://i.etsystatic.com/...",// OPTIONAL — "" is fine, the swatch shows instead
  note:"Two pigments, one shift."     // OPTIONAL — one short line under the name
}
```

Everything else is automatic: the card markup, the chip counts, the collection count in the group
heading, the Etsy URL with UTMs, the sort, the filter, the FLIP animation and the GA4 event payload.

**Authoring a swatch.** Two to four stops, pointed at the real shade. `linear-gradient(140deg, …)`
for most; `radial-gradient(70% 70% at 40% 35%, …)` for anything with a hot centre (embers, blushes);
`conic-gradient(from 210deg, …)` for rainbows and multichromes. Keep the lightest stop first so the
specular sweep has something to travel over.

**Adding a whole collection.** Add an entry to `COLLECTIONS` (`k`, `t`, `meta`, `d`) — a chip, a
group heading and a `#deep-link` anchor all appear from that one object.

**Removing a product.** Delete the object. Nothing else references it by index.

---

## 5. Analytics

GA4 is wired but dormant. Nothing loads until an ID exists:

```js
window.KG_GA_ID = window.KG_GA_ID || 'G-JE0Z9Q22LN';   // set 2026-09-05 — shared "Kismet Universe" property, cross-domain with rebirthritual.com + kismetcandles.com
```

Set it near the top of the `<script>` in each of `index.html` and `shop.html`. With it empty, no
network request is made and `track()` is a no-op — the pages are analytics-silent by default.

| Event | Fires when | Parameters |
|---|---|---|
| `outbound_etsy` | Any `[data-etsy]` link is clicked | `item_name`, `item_category`, `value`, `currency`, `link_url` |
| `select_item` | A card scrolls into view; a filter chip, sort or the UV toggle is used | `item_list_name`, `item_name` |
| `social_click` | Any `[data-social]` link | `method` (tiktok / etsy / ebay / instagram / pinterest), `link_url` |
| `generate_lead` | Newsletter form submitted with a valid address | `method: "newsletter"`, `currency`, `value` |

`item_list_name` values in use: `homepage_collections`, `shop_filter`, `shop_sort`,
`kismet_universe`, `ui_state`.

Mark `outbound_etsy` as a conversion in GA4. It is the only real conversion the site has in phase 1.

**UTMs.** Every outbound link carries `utm_source=kismetglitter.com&utm_medium=referral`, plus
`utm_campaign=<collection>` on product links and `utm_campaign=universe|footer|shop_footer|brand_guide`
on cross-brand links. This matches the Kismet Candles convention so the three properties report
consistently.

---

## 6. Image shot list for Courtney

This is the highest-leverage production task and it directly answers the 1★ review. The pattern for
every shade is a **triptych**: raw in the jar, applied on skin, and (where it applies) blacklight.

### Tier 1 — 18 images, unblocks the homepage and the top of the grid

Six hero shades × 3 frames each:

| # | Shade | Raw | Applied | Blacklight |
|---|---|---|---|---|
| 1 | Holographic Stardust ($45) | ✓ | ✓ | — |
| 2 | Rainbow ($45) | ✓ | ✓ | — |
| 3 | Amethyst Prism ($24.99) | ✓ | ✓ | — |
| 4 | Kismet UV Glow — Electric Pink ($28) | ✓ | ✓ | **✓ required** |
| 5 | Miami Prism Pigment Set ($110) | ✓ | ✓ (body, not face) | — |
| 6 | Holographic Pearl ($45) | ✓ | ✓ | — |

### Tier 2 — the rest of the UV line (blacklight is mandatory)
Rainbow Black Light, Rainbow Black Light large, Neon Black Light, UV Glow Silvertip, UV Glow set
($65), UV Glow set deluxe ($85), Glitter Gel glow-in-the-dark. **Same face, same shade, lights on
then lights off, camera locked off** — the pair is the whole sell.

### Tier 3 — one raw + one applied for every remaining shade
~34 more Magic Glitter shades, 4 Prism, 9 Face, 9 Studio, 3 Bath.

### Also needed
- **Process:** hands mixing, jars in a row mid-batch, the label being applied, the mailer being
  sealed. Three or four of these carry an entire month of social.
- **`assets/og-kismet-glitter.png`** — 1200×630 social preview card. Currently referenced by
  `index.html` and does not exist. Use the 1080×1080 template from the brand guide, cropped.
- **Favicon** is an inline SVG data URI — nothing to produce.

### Shooting rules
Dark saturated ground, never white seamless. Direct light — window, ring light or flash — never flat
overhead. Multiple skin tones. Catch a tilt: motion blur on a holographic swatch is honest, a static
one is not. Include the jar in at least one frame per shade for scale. Batch eight to twelve shades
per session; the studio is one person.

### Dropping the photos in
Save as `assets/products/<shade-slug>-raw.jpg`, `-applied.jpg`, `-uv.jpg`. Then set
`img:"assets/products/<shade-slug>-applied.jpg"` on the product object. The Etsy-hosted URLs are a
stopgap — Etsy can rotate or block them at any time, and the `onerror` fallback exists exactly
because they will eventually stop working.

---

## 7. Phase 2 — real commerce

Everything is designed so that replacing the Buy button is a one-function change. In `shop.html`
and `index.html`:

```js
function etsyUrl(p){ … }   // ← replace this
```

and the one `<a class="btn btn-sm" data-etsy …>` inside `cardHTML()`. The card markup, layout,
motion and events do not change.

### Option A — WooCommerce on the Namecheap cPanel account

**For:** one system for both product brands; Kismet Candles already runs WooCommerce, so Courtney
learns one admin, not two. Real inventory, variations (the bath bars already need XS/S/M/L),
coupons, wholesale pricing, abandoned-cart recovery. No per-transaction platform fee beyond the
payment processor.

**Against:** it is a WordPress install to host, update, back up and secure on shared cPanel hosting.
It replaces this static site's homepage with a theme, or requires the static site to live at the root
and WooCommerce at `/shop/` — a split that has to be maintained.

**If chosen:** put WordPress in a subdirectory (`/store/`), keep this static site at the root, and
point the Buy buttons at `https://kismetglitter.com/store/product/<slug>/`. That keeps the designed
homepage and gets a real cart. Note that the FTP deploy workflow pushes the repo root to
`/public_html/` — make sure it does not delete `/public_html/store/`. Also reuse
`data/woocommerce-products-import.csv` from the kismetcandles repo as the format template.

### Option B — Stripe Payment Links

**For:** zero hosting, zero maintenance, zero attack surface. One link per product, created in the
Stripe dashboard in about a minute, pasted into the product object as `buy:"https://buy.stripe.com/…"`.
Stripe handles tax, shipping rates, receipts and the hosted checkout page. The static site stays
static. Fee is standard Stripe processing only — cheaper than Etsy's ~9–11% all-in.

**Against:** no cart, so one product per checkout unless you build multi-item links by hand. No
inventory sync — a sold-out shade has to be deactivated manually. No customer accounts or order
history. At ~74 SKUs, creating and maintaining the links is real recurring admin.

### Recommendation

**Stripe Payment Links first, WooCommerce when volume justifies it.** At 82 lifetime sales the
maintenance cost of a WordPress store is not yet earned, and Payment Links can go live in an
afternoon with no infrastructure. Start with the ~15 best sellers as Payment Links, keep Etsy as the
long-tail channel and the review engine, and watch the `outbound_etsy` conversion numbers. When the
site is reliably driving more than roughly 30 orders a month, move to WooCommerce — at that point
the inventory and variation handling pays for itself.

Either way, keep the Etsy listings live. Etsy is a discovery channel with 88 admirers and 9 reviews
of accumulated trust; the goal is to add a direct channel, not to replace the side door.

### Newsletter
The form validates, animates and fires `generate_lead`, but posts nowhere. Wire it to whatever
Kismet Candles ends up using so the two lists live in one place. The lowest-friction options are a
Mailchimp or Buttondown embedded form action on the `<form>` element, or a Formspree endpoint —
all three work on static hosting with no server. Until then the success message is honest about the
state: the page says so in small print beneath the form.

---

## 8. Constraints checked

- **Static, no build step** — three plain `.html` files, no imports, no bundler, no npm.
- **Opens from disk** — no `fetch`, no ES modules, no absolute asset paths.
- **`prefers-reduced-motion`** — every animation and transition collapses to 0.001ms; reveals start
  visible; hero lines are already in place; the canvas draws one static frame; the marquee stops and
  wraps; the auto-scrubber never starts; the FLIP is skipped for a plain DOM swap. The pages are
  fully legible and fully shoppable with all motion removed.
- **Page weight** — 73.1 / 50.6 / 99.5 KB of HTML. Plus one Google Fonts request per page. Nothing
  else is fetched except the Etsy-hosted product images, which are remote and lazy-loaded. Well under
  the ~600 KB budget.
- **Verified in a real browser** (served over localhost, 2026-09-05): homepage renders the hero,
  canvas particle field, holographic wordmark and 27 product cards across 6 collection blocks; the UV
  toggle moves the ground from `#0A0710` to `#040109`, the accent from `#FF2F92` to `#FF2BD6`,
  cross-fades the demo swatches, updates `aria-pressed` and the lighting label, and reverses cleanly.
  `shop.html` builds all 74 cards with per-collection counts matching the chip counts exactly, no
  `NaN`/`undefined` in any card, and every Etsy URL carrying both UTM parameters plus a `search_query`.
  Removing an image via the `onerror` handler leaves the CSS swatch at full size — there is no broken
  image state. The brand guide resolves all 12 sections, every table-of-contents anchor, 3 logo
  directions, 4 social templates and all generated SVG. No horizontal overflow on any page.
- **Mobile-first** — base styles are the small-screen styles; every breakpoint is `min-width`.
- **Semantic HTML** — `header`/`nav`/`main`/`section`/`article`/`figure`/`footer`, one `h1` per page,
  `aria-labelledby` on sections, `aria-pressed` on toggles, `role="status"` on live counts, a skip
  link, and a visible `:focus-visible` ring on everything interactive.
- **`<title>` set** on all three pages.
- **Real copy only** — every product name, price, review quote and manifesto line comes from the Etsy
  snapshot or the listing export. No lorem, no invented shades, no invented reviews.

### Performance notes
- Canvas particle count scales with viewport area (1 per 12,000px², capped at 110) and DPR is clamped
  to 2. The loop is paused by `IntersectionObserver` when the hero leaves the viewport and by
  `visibilitychange` when the tab is hidden.
- Only `transform` and `opacity` animate in anything that loops.
- Scroll handlers are `{passive:true}` and rAF-throttled.
- Product images are `loading="lazy" decoding="async"`.

---

## 9. Placeholders and open items

| Item | State | Who |
|---|---|---|
| `window.KG_GA_ID` | Empty string. Analytics dormant until set. | Brandon |
| `assets/og-kismet-glitter.png` | Referenced by `index.html`, does not exist. | Brandon |
| Newsletter provider | Form validates and fires the event but posts nowhere. | Brandon |
| Instagram link | `href="#"` in the footer — account does not exist yet. | Courtney |
| Pinterest link | `href="#"` in the footer — account does not exist yet. | Courtney |
| Product photography | None. Every card is running on its CSS swatch plus 26 Etsy-hosted images. | Courtney |
| Per-listing Etsy URLs | Not available in either data file; links use shop-scoped search. | — |
| INCI / ingredient list | The label mock in the brand guide uses a placeholder ingredient string. | Courtney |
| Blacklight swatch colours | The three UV demo swatches on the homepage are colour renders, not photographs, and are labelled as such on the page. | Courtney |
| Etsy shop title / announcement / About | Still say "Kismet Beauty". Three fields to change. | Courtney |
| Mark selection | Three directions presented; A + C recommended. Not yet chosen. | Courtney |
| Prices | Snapshot of 2026-09-05. Re-check before launch — Etsy prices move. | Courtney |

Real, verified assets in use: TikTok `@kismetglitter`, eBay `kismetglitter`, Etsy shop
`Kismetglitter`, wholesale email `ladypunky@icloud.com`, and the cross-links to kismetcandles.com and
rebirthritual.com.

---

## 10. Provenance

- `data/etsy-shop-snapshot-2026-09-05.md` — live Etsy capture, 5 Sep 2026. Names, prices, the
  announcement and About verbatim, all 9 reviews. **Source of truth for prices and copy.**
- `data/etsy-listings-2025-12-19.csv` — 2025-12-19 Etsy listing export, 52 rows. **Source of truth
  for image URLs**, plus descriptions, tags and variations.
- `C:\github\www\kismetcandles.com\README.md` and `brand/` — the family palette, the Dancing Script
  accent, the brand-board format, the GA4 pattern and the footer credit convention.
- The shared relaunch brief for Rebirth Ritual + Kismet Glitter, 2026-09-05.

Designed by Brandon Harvey.
