Studio · Journal
What's been shipping.
The studio's running record. Every release, the reasoning behind it, and what's next. Newest first.
2026-04-29
v1.3.0Marketing wave — v2 ecosystem nav + Kriya rename + recurring promise
Studio is mostly canonical already (the trademark roll-call was dropped in v1.2.3, the 5-second-test homepage rewrite landed in v1.2.0, ™ marks were restored in v1.2.1, PathsRow already does the "ecosystem map" job). This wave closes the cross-repo parity items: v2 ecosystem nav, the api → kriya rename in forward-facing links, and the recurring brand promise.
Embed v2 ecosystem nav
<iby-ecosystem-nav current="studio"> renders above SiteHeader on every page, fed by the web component hosted at urja.insightsbyomkar.com/api/v2/nav/ecosystem-nav.js. Brings studio in line with the other four siblings on the persistent cross-domain top bar.
app/layout.tsx—<script async>in<head>+<iby-ecosystem-nav>aboveSiteHeader.types/ecosystem-nav.d.ts— new. Custom-element JSX intrinsics viareact-module augmentation (React 19 / Next 16 namespace the JSX scope on the module, not globally).
Kriya rename — api.insightsbyomkar.com → kriya.insightsbyomkar.com
The astrology API has a name. Forward-facing links now point at the canonical Kriya hostname. The legacy host stays on the return-URL allowlist so a stale post-sign-in bounce from before the rename doesn't get rejected as an open-redirect attempt.
lib/palette/products.ts— palette card href.lib/keys/email.ts— Kriya-key delivery email's docs link.lib/return-url.ts— kriya added toDEFAULT_ORIGINS; legacy api kept for redirect compat (with a comment explaining why).urja.insightsbyomkar.comadded too — same compat reason for the Visual API → Urja rename.lib/env.tsalready led withKRIYA_BASE_URL; comment intact.
Recurring promise on landing
"One Stripe customer, one studio dashboard, one cancel button" — the canonical brand promise the other four products echo back to studio. Lands as a small line under the Sign in row in PathsRow. Studio is the source of the dashboard the others point at; the line makes that explicit.
Files changed
app/page.tsx— recurring promise.app/layout.tsx— v2 ecosystem nav embed.lib/palette/products.ts,lib/keys/email.ts,lib/return-url.ts— Kriya rename + legacy-host compat.types/ecosystem-nav.d.ts— new (custom-element typings).
2026-04-28
v1.2.4Closing-pass polish — lint clean, dead CSS gone, inbox tidy
A deep-dive sweep of studio looking for pending work surfaced exactly three concrete items. All three landed in this patch.
Fixed
app/components/mobile-header-menu.tsx:21— was callingsetOpen(false)insideuseEffect([pathname])to close the sheet on route change. React 19'sreact-hooks/set-state-in-effectrule flags this. Switched to the state-on-prop-change pattern (matching the netra equivalent): trackinglastPathand closing the menu whenpathname !== lastPath.app/components/account-menu.tsx:46— same fix, same reason.npm run lintis now clean.test:ci(which chains typecheck + eslint + vitest) passes end-to-end.
Removed
- ~80 lines of orphan CSS in
app/globals.cssfor the deleted Constellation hero diagram (component itself was deleted in v1.2.0 with the homepage rewrite; styles were left behind). Replaced with a single-line comment explaining the removal.
Cleaned up
docs/inbox/2026-04-27-footer-bottom-centered.md— described the centered-copyright change that already shipped in v1.2.2. Moved todocs/inbox/done/so the active inbox accurately reflects pending work. Only2026-04-26-pricing-bundles-LOCKED.mdremains as live reference (Kriya rebrand + pricing canonical).
Verified clean
- All 39 tests pass, none skipped/todo
- No
TODO/FIXME/XXXmarkers anywhere in code - No imports referencing deleted modules
- Build is clean, working tree pushed
- Chrome conforms to consumer-anchor spec (per v1.2.3 alignment)
- Studio side is at "nothing pending" — closing this work session.
2026-04-28
v1.2.3Trademark roll-call removed — wordmark ™ is enough
Per user direction (2026-04-28): wordmark-level ™ on the brand and product names is sufficient brand-identity treatment. An explicit "X, Y, Z are trademarks of…" paragraph belongs on /legal pages, not in chrome.
app/components/site-footer.tsx—<p className={styles.trademarkRollCall}>paragraph removed entirely. Replaced with a comment explaining the decision so a future contributor doesn't reintroduce it.app/components/site-footer.module.css—.trademarkRollCall+.trademarkRollCall suprules removed.- The wordmark TMs stay (
.brandTmon "Insights by Omkar",.brandProductTmon "Studio") in both header and footer brand blocks.
Companion sibling alerts revised
All four sibling inbox notes flipped to match. Each now reads "REMOVE roll-call paragraph" instead of the previous "trim/add" direction:
- consumer: simplified — just add ™ to header wordmark, no roll-call paragraph at all
- netra: REMOVE the roll-call paragraph (was 7-brand bundle)
- urja: confirmed correct as-is — was already without a roll-call
- kriya: REMOVE roll-call + reorder bottom strip (separate concern)
2026-04-27
v1.2.2Pricing fix + sibling-parity bottom strip + per-product roll-call
#### Pricing fix (the big one)
Studio's homepage advertised Netra at $29/mo while Netra's own homepage and the locked pricing doc (docs/inbox/2026-04-26-pricing- bundles-LOCKED.md) say $19/mo. Studio was wrong on its own homepage — fixed.
app/page.tsx:132Netra card price:$29/mo→$19/mo.- #### Bottom strip — sibling-parity 3-col centered grid
- Round-2 audit confirmed consumer is the canonical anchor and its footer bottom strip is a 3-col grid: memorial LEFT · copyright DEAD-CENTER · legal RIGHT. Every sibling diverged. Studio now matches consumer's
.bottomexactly: display: grid; grid-template-columns: 1fr auto 1fr;:nth-childjustify-self rules pin each cell to its column edge- Mobile collapses to 1-col stack at <=880px (matching consumer's breakpoint, not the previous 720px)
- Copy line now reads
© 2026 Omkar's Holistic Services LLC. All rights reserved. · Studio v1.2.2— picks up "All rights reserved" from anchor. .bottomLeftwrapper class deleted; memorial + copy + legal are now three peer children of.bottom.- #### Trademark roll-call — per-product
- The previous v1.2.1 roll-call listed all 7 brands in the family (
Insights by Omkar™, Studio™, Reading chambers™, Netra™, Kriya™, Urja™, Lucky™…). Per the user's direction, that's not how trademarks work — each surface only asserts marks it owns, and "Reading chambers" is descriptive English, not a coined mark. - Studio's footer now reads:
Insights by Omkar™ and Studio™ are trademarks of Omkar's Holistic Services LLC.Just the parent brand + the surface itself. Sibling repos each get the same treatment in their own surface (alert notes dropped). - #### Companion alerts updated
insights-by-omkar/docs/inbox/— new high-alert note: consumer's chrome needs ™ added to header + footer wordmark + per-product roll-call line (anchor doesn't have either yet).insights-by-omkar-netra/docs/inbox/— trim roll-call to justInsights by Omkar™ and Netra™….tuffys-visual-api/docs/inbox/— ADD a roll-call line (was missing entirely):Insights by Omkar™ and Urja™….tuffys-ai-astrology/docs/inbox/— trim roll-call to justInsights by Omkar™ and Kriya™…. Plus reorder bottom strip to match anchor.
2026-04-27
v1.2.1Trademarks restored + studio framing broadened + about polish
#### Trademarks restored on chrome
The v1.1 chrome rewrite stripped trademark treatment. v1.2.1 puts both back, on both wordmark zones.
<sup>™</sup>next to "Insights by Omkar" AND next to the product mark ("Studio") in site-header + site-footer. Two CSS-module classes —.brandTm(muted) and.brandProductTm(gold-soft) — match the kriya v9.8.x pattern so chrome reads consistent across the family.- Trademark roll-call line restored at the very bottom of the footer: "Insights by Omkar™, Studio™, Reading chambers™, Netra™, Kriya™, Urja™, and Lucky™ are trademarks of Omkar's Holistic Services LLC."
- #### Studio framing — broader than astrology
- Studio isn't a purely astrology studio; it's a software studio whose first wave happens to be astrology. Updated copy to reflect that:
- Homepage hero lede: "A workshop building software end-to-end. Astrology is the first wave — consumer readings, a pro workbench, and two builder APIs."
- Homepage philosophy strip: "software in 2026 should still be made by hand. Astrology is the first wave; the workshop is built to ship anything."
- /about manifesto: same broadening + a new closing thought ("the first wave is astrology because that's what I practice; future waves go where the work takes me").
- Footer brand tagline: "A software studio. Home-grown end-to-end. Astrology is the first wave."
- #### /about overlap fix + product links
- The
Roomrows on /about used agrid-cols-[7rem_1fr]left column that was too narrow forkriya.insightsbyomkar.com— the domain text overlapped into the body. Rewritten as a flex row with a 14rem (sm:basis-56) left zone, plus the whole left zone is now a real<a>to the product's domain (was plain text). Hover under- lines the product name. - Kriya domain corrected from
api.insightsbyomkar.comtokriya.insightsbyomkar.com(canonical post-rebrand). All four product cards on /about are now clickable links. - #### Env default — Kriya hostname
env.apiBaseUrldefault flipped fromhttps://api.insightsbyomkar.comtohttps://kriya.insightsbyomkar.com. Legacyapi.*redirects there but isn't the default any more — every link studio renders goes to the canonical domain. NewKRIYA_BASE_URLenv var recognized;API_BASE_URLkept as a backwards-compat fallback.- Companion alert: each sibling repo's
docs/inbox/2026-04-27-trademark-restoration-FROM-STUDIO.mdcarries the TM-restoration brief.
2026-04-27
v1.2.0Homepage rewrite — passes the 5-second test for direct landers
The previous brand-pose lead ("A studio for astrology software") failed the 5-second test for naive visitors. v1.2 leads with the user's intent, not the founder's craft narrative. Audience is direct landers (organic search, social, blog links); product-flow users (clicked Sign in / Account on a sibling) hit /sign-in or /account directly and bypass this page.
Layout (option 3 — hybrid)
- Top fold (concierge): "One account. Four products." + one-line lede + four product cards naming the user intent for each ("I want a reading" / "I'm a working astrologer" / "I'm building software" / "I need visuals"). Plain English, visible price anchor on every card, single CTA per card. "Already have an account? Sign in →" sits below as a quiet secondary path.
- Below the fold (brand pose): Lucky-grounded philosophy quote + workshop links to /about, /journal, /pipeline. The poetic brand voice still has a home — just not above the fold.
Removed
app/components/constellation.tsx— was the four-product diagram in the old hero. The four PathCards do the same job in plain language; the diagram added beauty without aiding decision.lib/studio-pulse.ts— sourced the "right now in the workshop" workbench panel (version / visual-layer ms / last event). These were founder-level signals, not customer-conversion content. Status / pipeline / changelog still live at /status, /pipeline, /journal.
Companion alerts dropped in sibling repos
Same 5-second test sweep needs to happen on netra, urja, kriya homepages. Each repo now carries a high-alert note in its docs/inbox/ with the framework + a concrete shape proposal:
insights-by-omkar-netra/docs/inbox/2026-04-27-homepage-5sec-test-FROM-STUDIO.mdtuffys-visual-api/docs/inbox/2026-04-27-homepage-5sec-test-FROM-STUDIO.md(mostly already shipped in urja v0.6.1 — kept as informational)tuffys-ai-astrology/docs/inbox/2026-04-27-homepage-5sec-test-FROM-STUDIO.md
2026-04-27
v1.1.0Canonical chrome + softer palette
Studio's header + footer rewritten to mirror consumer's chrome — the design source of truth across the ecosystem. Shifted off the editorial-dark palette onto editorial-light (cool pale near-white canvas with subtle umber/gold/violet undertones, the same surface language consumer uses). Same tones across the ecosystem; we can reintroduce a dark-mode toggle later as one wave when needed.
Studio's header + footer rewritten to mirror consumer's chrome — the design source of truth across the ecosystem (per the user's direction: consumer is the anchor; every other product surface follows). Same shape, studio content. Brand-led wordmark with per-product tag.
Added
app/components/site-header.tsx— sticky glass-blurred bar (3-col grid: brand | center nav | utility), reads apex Supabase session, shows avatar menu when authed and Sign in / Get started CTAs when not. Mobile menu at <=1080px.app/components/site-nav-menu.tsx— direct links only (Dashboard / Manifesto / Journal / Pipeline / Status). No mega menus — studio's surface is small enough that mega would feel like LARP.app/components/account-menu.tsx— avatar dropdown with identity block + sectioned account links + sign-out. Mirrors consumer pattern.app/components/product-launcher.tsx+.module.css— the "waffle" launcher (3×3 dot icon) in the header utility zone, click opens a panel listing all 5 ecosystem products. Current surface is highlighted with a "You're here" badge instead of being a link. Same component lives in every product surface so cross-product nav is one icon, everywhere.lib/navigation/products.ts— single source of truth for the launcher's product registry:chambers / studio / netra / kriya / urja. Mirrored across repos as we port each chrome.app/components/mobile-header-menu.tsx— single hamburger sheet for the collapsed center+utility zones at narrow viewports.lib/navigation/site-nav.ts— single source of truth forNAV_MENU,FOOTER_COLUMNS,FOOTER_LEGAL_LINKS,PRODUCT_MARK,APP_VERSION. Mirrors consumer'slib/navigation/site-nav.tsshape so chrome stays portable.- CSS modules (
.module.css) for header, footer, nav menu, account menu — studio uses--ds-tokens with consumer's hardcoded fallbacks for safety.
Changed
app/components/site-footer.tsx— full rewrite from the v0.14.0 Tailwind 3-column footer to the canonical 4-column + brand block pattern. Bottom strip now carries Lucky's memorial line (the brand's anchor sentiment, present on every surface in the ecosystem).app/layout.tsx— dropsiby-ecosystem-navv2 web component + StudioSubnav + NavBridge, mounts<SiteHeader />directly. Tokens + fonts + motion CSS loading unchanged.
Removed
app/components/studio-subnav.tsx— was the named-slot helper for the now-retired ecosystem-nav web component.app/components/nav-bridge.tsx— same.iby-ecosystem-navscript tag in<head>. The waffle launcher it provided is now reborn as<ProductLauncher />— server-free, CSS-modules, no shadow DOM. Cross-product identity stays solid: every product reads the same apex Supabase cookie via@supabase/ssr.- Pairs with the parallel chrome ports in netra v2.1, urja v0.6, and kriya (engine) v9.8 — same shell, per-product content. See the SSO contract memo for the cross-subdomain identity behavior.
2026-04-27
v1.0.1Pipeline page
The third brand-marketing surface alongside /about and /journal. Where journal looks back, pipeline looks forward — and is honest about what's deliberately not on the bench.
Added
/pipelinepage (static-prerendered) — four sections: Now shipping (current focus: ecosystem rollout), Next up (theme toggle, cross-product data export, sub-nav, workbench panel expansion, staff-auth role claim), Backlog (someday-maybes: newsletter, public roadmap voting,/atelierlive wall, etc.), Deferred (deliberate non-goals: mobile app, multi-tenant org accounts, vendor SDK glue, external icon kits, etc.). Brass-divider diamond ornament + four section blocks with gold bullet markers, mirroring/journal's typography.
Changed
- Footer Studio column —
Pipeline — soon→Pipeline(real link). The "soon" label promised something the visitor couldn't see; now they can. FooterMutedhelper removed fromsite-footer.tsx— was the only "soon" marker in the footer; no remaining usages after the pipeline link landed.
2026-04-27
v1.0.0Studio is shipped. API surface lock.
After 19 minor versions in roughly 36 hours of focused work, studio's public-facing surface is stable. v1.0.0 marks the API surface lock — from this point, the user-visible routes, the auth + webhook contracts, the schema, the design system, and the brand vocabulary won't break. Future work is additive (minor) or fixes (patch). A v2.0 happens only if a contract rename / route removal / webhook shape change becomes unavoidable. Hopefully never.
Stable from this point
- Public routes (17 user-visible + 8 API):
/,/sign-in,/auth/callback,/auth/forgot-password,/auth/reset-password,/dashboard,/account,/account/billing,/account/api-keys(+[keyId]/rotate,[keyId]/revoke),/account/security,/account/preferences,/account/data-export,/account/delete(+/done),/journal,/about,/status,/legal/data-deletion. APIs:/api/auth/{sign-in, sign-up, sign-out, oauth/[provider], forgot-password, reset-password},/api/account/data-export,/api/health/visual,/api/visual/[...path]. - Auth contract: shared cookie scoped to
.insightsbyomkar.com, multi-method sign-in (Google + Facebook OAuth + email/password + magic link), forgot/reset password flow, account deletion viaauth.admin.deleteUserwith FK cascade. - Post-signin webhook: HMAC-SHA256 envelope (
{nonce, issuedAt, userId, email, defaultNext}+x-signatureheader), 2.5s timeout, optionalredirectTooverride. Receiver atconsumer/api/internal/post-signin. - Schema:
public.studio_activity(cross-product event ledger, RLS own-row read),public.studio_profiles(studio-domain user profile, RLS own-row read+write). Both withON DELETE CASCADEonauth.users(id). Migrations checked intosupabase/migrations/. Cross-repo schema contracts (user_entitlements,engine_api_keys) documented insupabase/SCHEMA.md. - Design system: Cormorant Garamond + Inter from urja's
/api/v1/fonts, semantic tokens via/api/v1/tokens?palette= editorial-dark, ornaments via/api/v1/illustrate, motion via/api/v1/motion. Zero local copies. No third-party UI / icon / animation libraries. - Brand vocabulary: Insights by Omkar Studio. Five trademarks per the footer roll-call: Reading chambers, Netra, Kriya, Urja, Studio. ™ used at the legally-meaningful display points only — brand wordmark + copyright + roll-call. Not on every product nameplate.
What's v1.x territory
- Theme toggle (light variant — requires Urja palette work)
- Cross-product data export (today: studio-domain only)
- Sub-nav for
/account/*(Stripe-style left rail) - Pipeline page (footer says "soon" deliberately)
- Ecosystem rollout: 5 sibling
REPO_TODO.mdfiles — consumer's auth migration is the biggest. Until that lands, the studio-as-brand thesis is half-proven (works in isolation, not yet end-to-end through real cross-product traffic). - Admin / staff auth delegation to studio with role claims
Versioning convention from here
| Bump | When | |---|---| | Patch (v1.0.x) | Bug fixes, copy edits, polish | | Minor (v1.x.0) | New surfaces, new features, additive changes | | Major (v2.0.0) | Breaking changes — schema rename, route removal, webhook contract change. Hopefully never. |
Today's run, end to end
| Version | Theme | |---|---| | 0.7.1 → 0.8.0 | Billing surface + subscription cards + harden seams | | 0.8.0 → 0.8.1 | Tier 1 audit cleanup (a11y floor + token drift) | | 0.8.1 → 0.9.0 | Account-side visual elevation | | 0.9.0 → 0.9.1 | Brand assets + ™ + rights reserved | | 0.9.1 → 0.9.2 | Studio polish layer (audit loop closed) | | 0.9.2 → 0.10.0 | Multi-method auth (OAuth + password + reset) | | 0.10.0 → 0.11.0 | Account deletion | | 0.11.0 → 0.12.0 | Post-signin webhook to consumer | | 0.12.0 → 0.13.0 | Astrology API → Kriya rename | | 0.13.0 → 0.14.0 | Studio as the brand (repositioning wave) | | 0.14.0 → 0.15.0 | Workbench panel + constellation hierarchy | | 0.15.0 → 0.16.0 | Profile + Security | | 0.16.0 → 0.17.0 | Preferences + Data export | | 0.17.0 → 1.0.0 | API surface lock |
Changed
README.mdrewritten for v1.0.0 — reflects every shipped surface, includes Kriya / Urja with their canonical names, lists the v1.x deferrals honestly. The "What's in this repo (v0.7.1)" heading is updated to "(v1.0.0)" with the full route inventory.package.json+lib/version.tsat1.0.0.- The studio is shipped.
2026-04-27
v0.17.0Preferences + Data export — final account-depth wave before v1.0
Two surfaces, both deferred from v0.16.0 and now in: /account/preferences for locale + timezone, /account/data-export for a GDPR-style JSON download of every studio-domain row tied to the user. The dashboard greeting now honours the user's timezone + locale. Theme toggle still deferred — light variant requires real design work; choosing a theme that doesn't apply is bad UX.
Added
/account/preferencespage (new) — locale dropdown (English US/IN/UK, Hindi, Bengali, Tamil) + timezone dropdown (10 curated IANA zones from Asia/Kolkata to UTC). Both validated server-side against the curated list (no free-text injection). Save action upserts intostudio_profiles.locale+.timezone, revalidates/account/preferences+/dashboard./account/data-exportpage (new) — explains what's in / not in the export, then a gold "Download JSON" CTA pointing to/api/account/data-export./api/account/data-exportroute (new) — server-rendered JSON download. Bundles profile, entitlements, activity (the user's rows via RLS), and API key metadata (never tokens — they're not stored). SetsContent-Disposition: attachmentwith a unique filename per request,cache-control: private, no-store. Cross- product data (chambers readings, netra workspaces) explicitly scoped out — each product can ship its own export when ready.- Preferences / Data export buttons on
/accountaction row.
Changed
- Dashboard greeting honours user preferences —
today.toLocaleDateString("en-US", ...)→Intl.DateTimeFormat(locale ?? undefined, { timeZone: timezone ?? undefined, ... }).format(today). Users with no preferences see the runtime default (same as before); users who set a locale + timezone on/account/preferencessee the date in their format + zone.
Notes
- Cross-product data export is a v1.x extension — would require HMAC-signed webhooks to consumer, netra, and engine repos (similar to the post-signin webhook pattern). Today: studio-only.
- Theme toggle column exists on
studio_profiles.theme_preference(per the v0.16.0 migration) but no UI yet. Adding a real light variant requires building light-palette tokens at urja and threading them through studio'sSTUDIO_OVERRIDESblock inapp/layout.tsx— design work, not a follow-up patch. - After this lands, v1.0.0 cuts the API surface lock. All the user-visible surfaces, the auth + webhook contracts, the schema, and the design system are stable from this point.
2026-04-27
v0.16.0Profile + Security — account depth before v1.0
The "actually load-bearing" account depth: a real profile with an editable display name (so the dashboard stops saluting users as their email handle), and a Security page with change-password + sign-out-everywhere + connected-providers. Last big surface push before cutting v1.0.
Added
supabase/migrations/20260427000000_studio_profiles.sql— newstudio_profilestable onauth.users.idwithdisplay_name,avatar_url,locale,timezone,theme_preference,updated_at. Studio-domain only (consumer has its ownprofilestable for credits / ghost flag / payment history). RLS: own-row read + insert + update via the cookie-authed client. Trigger bumpsupdated_aton every UPDATE.lib/profiles.ts—readProfile(userId)/updateProfile( userId, patch)/profileLabel(profile, email). Patches honour field presence (only set what's in the patch). TheprofileLabelhelper resolves the best display name in priority order:studio_profiles.display_name→ email handle (if name-ish) → null./account/securitypage (new) — three sections:- Password — change-password form (verifies current via re-authentication round-trip, then
updateUser({ password })). For OAuth-only users without a password yet, renders a simpler set-password form. - Sessions —
signOutEverywhereActioncallssignOut({ scope: "global" })and redirects to/sign-in?signed_out_everywhere=1. Useful on shared machines. - Connected providers — read-only list pulled from Supabase's
auth.user.identities[]. Direct add/remove controls land later (today: re-sign-in with same email on the new provider merges). - Profile editing on
/account— replaces the read-only Identity section. Display name is editable inline (server action upserts the row, revalidates/account+/dashboard). Email + user ID stay read-only (Supabase email change requires re-confirmation; out of scope here). Securitybutton added to/accountaction row.SCHEMA.mdupdated with thestudio_profilescontract.
Changed
- Dashboard greeting now reads
studio_profiles.display_nameviaprofileLabel(profile, email). Users who set a display name see "Welcome back, {Name}." Long compound email handles (e.g.jaliparthiomkar15) are still dropped from the salutation — the resolver falls through to "Welcome back." instead of embarrassing the user.
Notes
- The migration is checked in; apply with
supabase db push(or via the Supabase SQL editor) against the shared project. - Password verification uses a re-authentication round-trip (
signInWithPasswordas the same user) — a stolen session cookie alone can't pivot to a password takeover. avatar_url,locale,timezone,theme_preferenceare columns on the table but not yet editable from the UI. Reserved for v0.17.0 (/account/preferences).- After v0.17.0 (preferences + data export), v1.0.0 cuts the API surface lock.
2026-04-26
v0.15.0Live workbench panel + constellation hierarchy
The two follow-ups deferred from v0.14.0. Together they convert the hero from "claim with decoration" to "claim with evidence" — the studio doesn't just say it's a workshop, it shows what's running.
Added
lib/studio-pulse.ts(new) — fetches three live signals for the public hero: studio version (fromAPP_VERSION), visual layer health (probes urja's tokens endpoint with 1.5s timeout), and ecosystem activity (count + most-recent timestamp fromstudio_activityvia service-role, aggregate only). Per-fetch 60s Next data cache so repeat visitors don't hammer the probe. Failures are non-fatal — any signal that doesn't resolve falls back to "—" so the workbench degrades gracefully.<Workbench>panel on the landing hero — replaces the static stats grid (4 / 1 / 0 / ∞). Three signals:Shipped(current version, gold pulse),Visual layer(live latency, gold pulse if ✓, warning amber if down),Last event(relative time). Each signal has a status dot using the same.sub-pulserhythm the constellation hero uses, so the language is consistent. Eyebrow reads"Right now in the workshop".
Changed
- Constellation hierarchy (
app/components/constellation.tsx) — studio's halo grew fromr="120"tor="180"(1.5× product halos), centre dot fromr="5"tor="10"with an additional inner glow circle for depth. Centre label changed from"YOU ARE HERE"to"STUDIO"— the audit's "concedes the centre to the visitor" critique addressed. .constellation-labelfont-size inglobals.css—18px→13px. Product star labels feel subordinate to the workshop centre; per the v0.14.0 audit's hierarchy fix..constellation-label-center—9.5px / 2.4px tracking→12px / 3px tracking, kept uppercase sans. The "STUDIO" wordmark now reads as identity, not decoration.- Constellation aria-label updated to reflect the new framing —
"Insights by Omkar Studio. Three products orbiting: Reading chambers, Netra, and Kriya."
Notes
- The activity count query requires the service-role client (the homepage is unauth so RLS doesn't apply); aggregate output only (no per-user data, no PII).
- Visual probe shares logic with
/api/health/visualbut runs inline with shorter timeout (1.5s vs 5s) — the homepage shouldn't wait on a slow urja. - Studio is now genuinely closed. Five sibling repos each ship a comprehensive
REPO_TODO.mdwith their parity work.
2026-04-26
v0.14.0Studio as the brand — repositioning wave
Three independent reviewers (visual, tone, fresh-user) converged on one diagnosis after the v0.12.0 push: studio is a product launcher dressed as a studio. The hero pitched SSO, the constellation gave products equal weight to the studio, the auth pages flattened the brand voice into Vercel-grade neutrality, and the studio had no surface where it talked about itself. This wave addresses the convergent findings.
Added
/journalpage (static-prerendered) — rendersCHANGELOG.mdas a public, editorial marketing surface with the studio's own voice. Each release is a separate entry with version + date eyebrow, display-md theme heading, and an editorial body (gold bullet markers, mono code spans with subtle gold accent, Cormorant italic emphasis, gold-underlined links). Minimal home-grown markdown parser — no third-party deps.app/journal/page.tsx+ new.prose-journalblock inglobals.css. The single highest-leverage move from the 3-agent review./aboutpage (static-prerendered) — first-person manifesto. Editorial layout: display-xl heading, lede paragraph, brass divider, four "Rooms" tiles (Reading chambers, Netra, Kriya, Urja with their domain + one-line description), Discipline + Why sections, the philosophy pull-quote signed "— Omkar," and a closing CTA row (Sign in / Read the journal / See pricing). Resolves the odd-user agent's flagged gap: "right now Omkar is a trademark, not a person."
Changed
- Hero rewrite (
app/page.tsx): - H1:
"One account. / Every product."→"A studio for / astrology software."— names the studio, not its SSO property. - Lede:
"A home-grown family of products at the edge of myth and code…"→"One person, one stack, one stubborn idea — that astrology software in 2026 should still be made by hand. The four products below are what comes out of the workshop." - Primary CTA:
"Sign in or create account"→"Sign in"(cleaner). - Secondary CTA:
"How it fits"(in-page anchor) →"Read the manifesto"(links/about). - EcosystemSection reframed —
"Studio is the front door"→"Studio is the workshop.". Centerpiece eyebrow"The front door"→"The workshop". Small change, big positioning shift. - Footer reorder — column order is now Brand → Studio (the brand surfaces: Manifesto, Journal, Pipeline — soon, Status) → Account (Sign in, Dashboard, Account, Pricing) → Products (Reading chambers, Netra, Kriya, Urja — de-emphasized). Privacy / Terms / Data deletion compress into the base row as inline links. The "Insights by Omkar" tagline moves from
"A home-grown family of products at the edge of myth and code"→"A studio for astrology software, home-grown end-to-end.". - ™ pruning — stripped from product tiles, subscription cards, api-key cards, dashboard headings, sign-in / forgot-password / reset-password eyebrows, and the footer Products column. Per the tone agent: "Linear doesn't put ™ on Linear." Kept on the footer brand wordmark + copyright row + trademark roll-call (legally load-bearing). The
Brandedhelper in site-footer is removed (dead code). - Sign-in / forgot-password / reset-password forms drop the
card-staticframe — the forms are now vertical columns on the starfield + aurora backdrop, no rectangle. The atmosphere becomes the surface. - Sign-in eyebrows updated
"Insights by Omkar™"→"Insights by Omkar Studio"(the canonical brand name + trademark dropped per pruning rule above).
Fixed
- Real Google + Facebook OAuth SVGs — the previous letter-mark chips (
Gandfin border boxes) were below the trust bar for sign-in surfaces. Replaced with Google's official 4-colour SVG (per their identity guidelines for sign-in buttons) and Facebook's solid-bluefmark.app/sign-in/sign-in-client.tsx ProviderMark. - Date.now() server-time greeting bug fixed — the dashboard greeting computed
partOfDayfrom the server's clock (today.getHours()), so a user in Sydney at 9pm could see "Good morning" rendered from a Virginia server. Dropped the time-of-day logic entirely; greeting is now"Welcome back, {name}."always (correct, since the dashboard is post-sign-in by definition). Lede also rewritten for the new positioning:"These are the rooms in the studio you have keys to. Open one and get to work.". prefers-reduced-motiongap oncard-surface:hover— the hover lift (transform: translateY(-4px) scale(1.012)) was firing even for users with reduced-motion preference. Added a@media (prefers-reduced-motion: reduce)rule that disables the transform.
Notes
- The constellation diagram still gives studio + 3 product stars equal weight. The visual agent's recommendation to make studio's halo 2.5× larger is a real follow-up but lower-priority than this wave's textual repositioning. Tracked.
- The "workbench" live-evidence panel (Tier 3 in the visual review) is the next bigger play — render
studio_activity+ version + build status as a live signal of what the studio is making right now. Bigger than this commit; deferred. Pipeline — soonremains in the footer Studio column. The manifesto + journal cover the immediate "what is studio" need; pipeline ships when there's a concrete process to show.
2026-04-26
v0.13.0Astrology API → Kriya — canonical brand rename
Kriya is the public-facing brand name for the astrology engine (internally engine, customer-facing previously Astrology API). Commandcenter and Netra were already using "Kriya" staff-side; studio + consumer + the engine repo were still on the older "Astrology API" descriptor. This commit aligns studio with the canonical name.
Changed
- Product label rename across 8 files / 13 references —
lib/api-keys/infer.ts:32(productLabel for engine keys),lib/keys/email.ts:37(rotation-email service label — "Your new Kriya API key"),lib/palette/products.ts:38(⌘K palette product registry),app/dashboard/page.tsx:152(ProductTile name),app/components/subscription-card.tsx:41,182(label + empty-state body),app/components/site-footer.tsx:56,96(footer Products column + trademark roll-call),app/components/constellation.tsx:15,27(hero diagram label + aria-label),app/account/api-keys/page.tsx:20,191(page metadata + empty-state body). - Test assertion updated —
lib/__tests__/api-keys.test.ts:51-53now assertsproductLabel("engine") === "Kriya". - Trademark roll-call line in the footer simplified — was "Reading chambers, Netra, Astrology API, Visual API, Urja, and Studio" (which double-listed urja); now "Reading chambers, Netra, Kriya, Urja, and Studio". Customer-facing brand list, no descriptor duplication.
Notes
- The technical subdomain stays at
api.insightsbyomkar.comfor now — the rename is brand-only.kriya.insightsbyomkar.commay exist on the DNS provider but is not yet serving content (returns ECONNREFUSED on 443 from external resolvers). - Sibling repos still need this rename — consumer has 5 files, Urja has 1, the engine repo (
tuffys-ai-astrology) has 3 (includingapp/api/v1/openapi.json/route.ts:208"Insights by Omkar — Astrology API" which is the public OpenAPI title). Tracked separately; ship per-repo. - The CHANGELOG (this file) is not retroactively renamed — history is history. New entries from v0.13.0 onward use "Kriya".
2026-04-26
v0.12.0Post-signin webhook to consumer — cross-repo orchestration
Studio is the canonical auth surface; commerce-domain hooks (ghost-profile merge, welcome email send, /welcome onboarding) live on consumer. Connecting them: studio's /auth/callback now fires a HMAC-signed webhook to consumer's /api/internal/post-signin after every successful code exchange. Synchronous-with-timeout (2.5s) so consumer's optional redirectTo (e.g. new users → /welcome) can override studio's default-next redirect. Same SSO_SHARED_SECRET / x-signature channel as provisionKey / revokeKey.
Added
lib/auth/post-signin.ts— HMAC-signed webhook caller. Same envelope shape (nonce+issuedAt+ payload) andx-signatureheader studio already uses for the engine + urja key-lifecycle channel. 2.5sAbortControllertimeout. Returns{ redirectTo: string | null }— null on any failure (unconfigured secret, network error, non-2xx, timeout, malformed response).
Changed
/auth/callbackextended — afterexchangeCodeForSessionsucceeds (and outside the recovery branch), studio reads the user viagetUser, firesnotifyPostSignin({ userId, email, defaultNext }), and honours the returnedredirectToif present. Otherwise falls through todefaultNext(resolved from thenextquery param via the open-redirect whitelist; defaults to/dashboard). Failures are non-fatal — sign-in still succeeds, the user just misses the consumer-side hooks for that session.
Notes for ops — deploy order matters
Studio + consumer have to roll together:
1. Consumer first: deploy app/api/internal/post-signin/route.ts (the webhook receiver). No behaviour change until studio calls it. 2. Studio next: deploy this version (v0.12.0). Webhook fires on every sign-in. If consumer's receiver is already live, hooks run normally. If not, fetch returns 404 → studio logs a warn and falls through to defaultNext (sign-in still works, no welcome email). 3. Future: consumer's /auth/login, /auth/signup, /auth/page.tsx, /auth/reset-password get replaced with redirects to studio. Tracked in AUTH_INTEGRATION_NEXT.md (dropped in consumer's repo this commit).
Notes for the unified-account thesis
This closes the architectural gap that came up while planning the auth migration. Studio is the IDENTITY surface — its callback exchanges the code, sets the cookie, decides where the user lands. Consumer is the COMMERCE surface — its webhook owns ghost-merge, welcome email, the onboarding redirect. Same Supabase project, same shared cookie, but each surface owns its own tables and logic. No coupling.
2026-04-26
v0.11.0Account deletion in studio + data deletion legal page
Studio takes over account deletion from consumer — myaccount pattern, so every account decision the user can make lives on studio.insightsbyomkar.com. New /account/delete flow with an email-typed confirmation (matches the api-key revoke pattern), a goodbye page, and the public /legal/data-deletion URL Meta App Review needs for Facebook OAuth.
Added
/account/deletepage + form + server action (app/account/delete/). User types their email exactly to confirm, action runssupabase.auth.admin.deleteUser(userId)(cascades via FK ON DELETE on every table referencingauth.users(id)), then signs out and redirects to/account/delete/done./account/delete/donepage (static) — brass-divider diamond + "Your account is deleted" + back-home link. No auth required — the session's already gone.- Danger zone on
/account— bottom of the page, top-bordered section with aDelete account →link in the danger-red colour. Single tap from the account hub. /legal/data-deletionpage (static) — short, public-facing instructions: sign in, go to/account/delete, type email, done. Email fallback for users who can't sign in. This is the URL to paste into Meta App Review's "User Data Deletion" field.
Changed
- Footer Company column picks up the legal trio: Privacy + Terms link out to consumer (
https://insightsbyomkar.com/legal/*— already shipped there), Data deletion is the studio-internal link. Status stays.
Notes for ops
- Meta App Review URLs to paste into the Facebook App Dashboard (Settings → Basic):
- Privacy Policy:
https://insightsbyomkar.com/legal/privacy - Terms of Service:
https://insightsbyomkar.com/legal/terms - User Data Deletion:
https://studio.insightsbyomkar.com/legal/data-deletion - Consumer's
/accountdeletion route is now redundant. Once every sibling repo flips its sign-in CTA to studio (per the myaccount pattern), the consumer's account UX can be removed entirely — studio is the canonical surface. - Account deletion relies on
auth.usersFK cascades being set up in every product-side table. If a product table doesn't cascade, rows will orphan after deletion. Worth auditing each repo's schema during the pivot.
2026-04-25
v0.10.0Multi-method auth — OAuth + password + reset flows
Studio's sign-in form expands from magic-link-only to a unified entry spanning OAuth (Google + Facebook), email + password sign-in, email + password sign-up, password recovery, and the original magic link as a fallback. The form mirrors the industry pattern (OAuth on top, email-with-password below, mode toggle, alternative magic link) and now uses the gold pill for the inevitable submit. The auth callback continues to be the single landing point for every flow, with a new branch for password recovery.
Added
- OAuth init route at
app/api/auth/oauth/[provider]/route.ts— POST with{ return? }initiates a SupabasesignInWithOAuth({ provider })call withskipBrowserRedirect: true, returns{ url }for the client to follow. Supportsgoogleandfacebook. Requires the matching provider to be enabled in the Supabase project (Authentication → Providers); without that config, the route returns a clear error message that surfaces in the sign-in form. - Password sign-up route at
app/api/auth/sign-up/route.ts— POST{ email, password, return? }calls Supabase'ssignUpand triggers a confirmation email. The sign-in form lands the user on a "check your email" confirmation card. - Forgot-password route at
app/api/auth/forgot-password/route.ts— POST{ email }triggersresetPasswordForEmail. Always returns{ ok: true }(doesn't disclose whether an email is registered). The reset link in the email points at/auth/callbackwithnext=/auth/reset-password, so the user lands on the new-password form once the recovery code is exchanged. - Reset-password route at
app/api/auth/reset-password/route.ts— POST{ password }callsupdateUser. Requires an active recovery session (set when /auth/callback exchanged the recovery code). /auth/forgot-passwordpage — atmospheric stage backdrop matching/sign-in, gold-CTA "Send reset link" form. Bounces to/accountif the visitor is already signed in./auth/reset-passwordpage + form — server-side guard that redirects to/auth/forgot-passwordif no session is present (prevents direct-URL hits without a recovery code). The form enforces 8-character minimum + confirm-password match on the client before posting; on success, navigates to/dashboard.
Changed
/api/auth/sign-inroute now handles both flows — withpasswordit callssignInWithPasswordand returns the next path to navigate to; without password it falls back to the original magic-linksignInWithOtpbehaviour. Wrong email or password returns a generic "Wrong email or password." (doesn't disclose which is wrong)./auth/callbackroute now branches ontype=recovery— password-reset flows route to/auth/reset-passwordafter the code exchange instead of falling through to the standardnextdestination.- Sign-in form (
app/sign-in/sign-in-client.tsx) rewritten — OAuth buttons (Google + Facebook with letter-mark chips, real vendor logos to follow when licensing cleared), divider, email + password fields, "Forgot password?" link, gold-pill submit button. Mode toggle ("Don't have an account? Create one" ↔ "Have an account? Sign in") and method toggle ("Send me a magic link instead" ↔ "Use a password instead"). Inline error surface for callback failures and per-flow errors. /sign-in?error=callback_failedis now caught by the page and rendered as an inline error in the form, so users who came back from a failed callback see why without losing the form state.
Notes for ops
- OAuth providers must be enabled in the Supabase dashboard before Google / Facebook buttons work. Authentication → Providers → enable, paste OAuth client id + secret, add
https://studio.insightsbyomkar.com/auth/callbackto "Redirect URLs". The form will surface a clear error message if a click hits an unconfigured provider. - Email confirmation defaults — Supabase by default requires email confirmation on sign-up. If you turn confirmation off in the dashboard, the "check your email" card still appears (matches the current UX) but the user is actually signed in already; consider redirecting straight to /dashboard in that case.
- Sibling repos can now route their sign-in CTAs to studio (
https://studio.insightsbyomkar.com/sign-in?return=<their-url>) and get the full multi-method flow for free.
2026-04-25
v0.9.2Studio polish layer — closing the loop on the audit
The remaining Tier 2 + Tier 3 items from the v0.8.0 design audit. Empty states for the zero-subscription path, mobile-friendly SubscriptionCard footer, gold framing on the rotate-flow token, and a real /status page now that the health probe ships. Plus a small refactor lifting <SectionCard> + <Row> out of two duplicated copies into a shared component.
Added
<SubscriptionsEmptyState>component inapp/components/subscription-card.tsx— brass-divider diamond + display heading + lede + gold CTA. Used on/accountand/account/billingwhen the user has zero active subscriptions, so those surfaces no longer render three identical "Free tier / Not subscribed / No active subscription" cards. Each page passes its own copy and CTA./statuspage (new) atapp/status/page.tsx— server-rendered live probe of the studio → urja dependency. Shows app version, visual layer endpoint, status badge, and round-trip latency. Reuses the same probe logic as/api/health/visual(which it links to as the JSON-formatted equivalent for external uptime monitors). Footer "Status" link now wired to it (was "soon").<SectionCard>+<Row>lifted to shared atapp/components/section-card.tsx. Was duplicated verbatim inapp/account/page.tsxandapp/account/billing/page.tsx(and was in api-keys before v0.9.0 stripped it). Both pages now import from the shared module.
Changed
- Mobile-friendly SubscriptionCard footer — the status row was
flex items-center justify-betweenwhich truncated long detail strings ("Included with Lucky Max") at iPhone SE width. Nowflex-col gap-3 sm:flex-row sm:items-center sm:justify-betweenso on mobile the action drops below the status line. - Token
<pre>in the rotate flow gets a gold hairline border (border border-[color:var(--ds-accent-gold)]/40) — the new key token is the most security-critical text on the studio surface, so the framing should signal "this is the artifact" rather than read as untreated chrome.app/account/api-keys/[keyId]/rotate/rotate-form.tsx. .sub-pulseslowed from 4400ms → 6800ms — was actually faster than the constellation hero's 5200ms, the wrong direction given the intent ("alive but at rest, slower than marketing"). Now visibly slower than the hero, which is what the editorial pairing was meant to convey.CardBodyin<SubscriptionCard>no longer declaredasync— it didn't actuallyawaitanything (RSC handles its async children fine without the keyword propagating up). Drop the misleading modifier./account/billing"Back to account" is now the only secondary button when the user has no subscriptions (no redundant outline primary). Same pattern v0.9.0 cleaned up for the active path.
2026-04-25
v0.9.1Brand assets + trademark notice + rights reserved
Studio inherits the canonical brand assets from the consumer apex (insights-by-omkar) so favicons, app icons, and the Insights by Omkar wordmark logo render identically across every surface in the ecosystem. Adds the trademark mark on product names where they appear as the canonical brand label, and the standard rights-reserved notice in the footer.
Added
- Brand assets copied from consumer (
insights-by-omkar): app/favicon.ico(15 KB, multi-size 16×16 + 32×32) — Next.js auto-discovers and serves at/favicon.ico.app/icon.png(140 KB) — Next 16 picks this up at/icon.pngfor higher-res favicon usage.app/apple-icon.png(24 KB, 180×180) — iOS home-screen icon.public/logo.png(227 KB, 710×342) — gold-on-navy wordmark with OM symbol, "INSIGHTS / BY OMKAR / AI PRODUCTS · TECHNOLOGY · REAL HUMAN IMPACT". The navy backdrop is baked into the asset, so it sits naturally on studio's dark observatory canvas with a hairline gold border (border-radius: md) framing it as an intentional logo chip rather than a visible navy rectangle.- Logo + brand wordmark in
<SiteFooter>(the brand column). Logo rendered vianext/imageat 160px wide, the framed gold hairline making the navy backdrop intentional. Below the logo, the text wordmark "Insights by Omkar™" with a sup-sized trademark. - Trademark superscript on product names at canonical-brand display points (legal-meaningful, not flowing prose):
- Footer Products column: Reading chambers™, Netra™, Astrology API™, Visual API™.
- Dashboard ProductTile headings (Reading chambers™ / Netra™ / Astrology API™).
- SubscriptionCard headings (Lucky™ / Netra™ / Astrology API™).
- ApiKeyCard headings — Astrology API™ / Urja™. The "Unscoped key" label stays plain (it's not a brand).
- Sign-in eyebrow (Insights by Omkar™).
- Footer brand wordmark and copyright row.
™isaria-hiddenin product headings so screen readers announce the bare brand name, not "Lucky trademark." The trademark remains visually present for sighted users. Footer legal text keeps the mark in the announcement (legal context).- "All rights reserved." + dynamic copyright year in the footer base row:
© 2026 Insights by Omkar™. All rights reserved.Year computed vianew Date().getFullYear()so the line stays correct without an annual code change. - Trademark roll-call line in the footer base: "Reading chambers, Netra, Astrology API, Visual API, Urja, and Studio are trademarks of Insights by Omkar." A single legal-style sentence covering every product mark in one place.
Note for sibling repos
The same four asset files (app/favicon.ico, app/icon.png, app/apple-icon.png, public/logo.png) need to land in every other ecosystem repo (consumer, netra, engine portal, urja portal, admin) for cross-product consistency. Studio's footer pattern (logo + ™ treatment + rights-reserved) is the template for those repos to mirror.
2026-04-25
v0.9.0Account-side visual elevation — one design language across the trio
The Tier 2 batch from the v0.8.0 design audit. Two highest-leverage moves bundled into one minor: the <ApiKeyCard> conversion brings /account/api-keys into the same dark-card vocabulary as /account + /account/billing, and the .btn-gold switch on account-side primary CTAs makes the inevitable action look inevitable on dark canvas (.btn-primary was a cream block — visually loud but lower-status than gold). With this wave, every authed account surface reads as the same product.
Added
app/components/api-key-card.tsx(new) — shared editorial card for API keys, modeled after<SubscriptionCard>but tuned for the data shape: per-product glyph (engine → mercury, urja → compass-rose; mercury mirrors the dashboard's API tile, compass-rose keeps urja-key glyphs in their own lane vs netra's chart-ring + lucky's moon-phase), gold plan chip, separate Revoked / Expired status chips, the existing UsageBlock (live counters + totals + last seen), dates row, and a footer with.sub-pulsestatus dot + Rotate / Revoke as min-44px tap-target inline links.
Changed
/account/api-keysrebuilt around<ApiKeyCard>— the bare<ul>-with-divide-y list inside a singleSectionCardis gone. Active and Revoked now each get a section heading + brass-divider + grid of card-static cards. Identical structural pattern to/account's subscriptions section. The localApiKeyItemandUsageBlock(~230 LOC) are deleted from the page; the component owns its own rendering.- Primary CTAs on the account-side now
.btn-gold:/account"Billing",/account/billing"Manage in Stripe" / "See pricing" (empty state),/account/api-keysempty-state "See developer plans". Gold pill with sheen sweep — same primitive the landing's hero CTAs use, so the editorial language reaches the authed surfaces..btn-primary(cream-fill, dark canvas) is now reserved for the sign-in form (where it's the only chrome on the card) and confirmation buttons in destructive flows.
2026-04-25
v0.8.1Tier 1 audit cleanup — floor-raising before the design pass
An independent design auditor probed v0.8.0 against the "industry standard by design + usability" bar and surfaced 28 findings across three tiers. v0.8.1 ships the Tier 1 batch — the things that were broken or below the accessibility floor. No design-language changes; those land in the Tier 2 pass next.
Fixed
- Token name drift —
--ds-status-warndoes not exist (urja exports--ds-status-warning). Fallback hex#a07838was reading brown-on-navy, not warning-amber. Two callsites:app/account/api-keys/page.tsx:173,app/account/api-keys/[keyId]/rotate/rotate-form.tsx:139. - Token name drift —
--ds-dangerdoes not exist (urja exports--ds-status-danger). Sign-in form errors were inheriting body cream — i.e. errors looked like ordinary text.app/sign-in/sign-in-client.tsx:75. - React 19 render-purity violations —
Date.now()andnew Date()called inside component bodies. Hoisted to the page-level async server component and passed down as props (now: numbertoApiKeyItem,today: DatetoDashboardGreeting). - Unused import —
type ApiKeyRowinapp/account/api-keys/[keyId]/rotate/actions.ts:5. - Destructive-button contrast — revoke button was a navy-on-red combo (
.btn-primaryon red bg, no foreground override). Now explicitly cream-on-red viacolor: var(--ds-text-strong). - Sign-in input nearly invisible — the input border was
--ds-border-softon the elevated card surface, computing to near-identical luminance with the surrounding card border. Bumped to--ds-border-strongand dropped the redundantoutline-none(the new global focus-visible covers it). - Duplicate "See pricing" on
/account/billing— the outline variant rendered alongside the Stripe-portal CTA when active. Removed;/accountalready carries the pricing link.
Added
:focus-visibleglobal ring — gold outline 2px with 2px offset, covering every interactive element. Keyboard users now have visible state on the account-side trio (was zero before).- Skip-to-content link —
<a href="#main">rendered first in<body>, visible only on focus. Tabbing from the URL bar no longer walks 10+ ecosystem nav stops before reaching page content. Wraps page content in<div id="main">(app/layout.tsx). - No-JS / reduced-motion FOUC fallback —
Revealsetsstyle="opacity:0"at SSR and lets a client-side observer fade content in. Without JS or withprefers-reduced-motion: reduce, the inline style would otherwise win. A<noscript>style block + aprefers-reduced-motionrule now force visibility. <SubscriptionCard>aria-label— whole-card links now announce concisely ("Lucky — Manage") instead of concatenating every text node inside the card.
2026-04-25
v0.8.0Studio as the destination — myaccount pattern + ecosystem hardening
Two themes shipped together. (1) Studio takes ownership of the canonical billing surface — until now /account linked outward to the consumer apex for "Manage billing"; that single hop broke the "myaccount.google.com is the only place" mental model. v0.8.0 closes that loop with /account/billing as the user-facing billing page, while leaving Stripe + PayPal webhook handlers and the portal-session endpoint on consumer (don't move what works). (2) The account-side trio (/account, /account/billing, /account/api-keys) had been falling below the bar set by the landing — passive cards, generic buttons, identical page shapes. The new shared <SubscriptionCard> elevates the densest data pattern across the account surfaces with the same hover choreography + breath-pulse rhythm the constellation hero uses. Plus a hardening pass on docs, env, return-URL safety, and schema visibility now that other repos are about to depend on studio.
Added
app/account/billing/page.tsx(new) — canonical billing surface. Subscription summary, renewal + payment source, "Manage in Stripe" CTA that bounces through consumer's existing portal-redirect endpoint. No new env, no Stripe SDK in studio — webhooks + customer ID lookup stay on the commerce apex.app/components/subscription-card.tsx(new) — shared editorial card with per-product glyph (mirrors the dashboard ProductTile mapping: Lucky → moon-phase, Netra → chart-ring, API → mercury), a gold tier chip (Pro / Max), a breath-pulsing status dot, and an optional inline CTA. Uses.card-surfaceon /account (interactive, whole-card link) and.card-staticon /account/billing (read-only status). One component, two contexts..sub-pulseutility inapp/globals.css— samestar-breathkeyframes the constellation hero uses, slowed to 4400ms so the active-subscription dot reads as "alive but at rest." Editorial language now connects the marketing surface to the account-side.app/api/health/visual/route.ts(new) — synthetic health probe for the studio → urja dependency. Hits a deterministic urja endpoint with the configured key, reports{ok, configured, status, latencyMs}. Wire to any external uptime monitor so a missing or expiredVISUAL_API_KEYsurfaces as a pageable signal instead of silently degrading visual identity to fallback fonts.supabase/SCHEMA.md(new) — documents theuser_entitlements,engine_api_keys, andstudio_activitycontracts studio reads against. The migration mirror lives in the consumer/engine repos; this is studio's view of the cross-repo schema contract.lib/__tests__/return-url.test.ts(new) — 18 tests pinning the open-redirect prevention contract: relative paths,//rejection, backslash rejection, allowed origins, foreign origins, look-alike subdomains,javascript:/data:/mailto:schemes. Total suite now 39 tests (was 21).
Changed
/accountsubscriptions section — replaces the row-based SectionCard with a 3-card grid. Each card is a clickable interactive surface; active cards lead to/account/billing, inactive cards lead to consumer pricing.validUntilrendered once as a footnote under the grid (the data model has a single global renewal date — per-card duplication would mislead)./account/billingsubscriptions section — same 3-card grid, but cards are status-only readouts (no per-card action). The page-level "Manage in Stripe" CTA still owns the action; cards just show plan + tier + status. "Renewal & payment" SectionCard kept for global renewal date + payment source.- Billing link callsites repointed —
app/account/page.tsx,app/dashboard/page.tsx:330, andlib/palette/actions.ts(⌘K "Billing" entry) now route to/account/billinginternally instead of bouncing out to the consumer apex. lib/return-url.tsenv-driven —ALLOWED_REDIRECT_ORIGINS(comma-separated). Falls back to the canonical six subdomains when unset. Launching a 7th sibling no longer requires a studio code deploy.README.md— refreshed from the v0.1.0 4-item list to v0.8.0 reality. New contributor onboarding doc no longer lies about what's actually shipped.
Removed
NEXT.md— the v0.3.0 nav-hub plan. The file's own footer said "Delete this file when v0.3.0 ships"; v0.3.0 through v0.7.1 all shipped.
2026-04-25
v0.7.1Tunings on the synthesis
Three refinements after seeing v0.7.0 land in screenshots. Not new direction — sharpening what's there.
Changed
- Constellation grew — hero right column max-width 520 → 680. The diagram now carries proper visual weight in the right column instead of feeling small relative to the brutalist text.
- Constellation lines brighter — connecting
<line>strokes bumped from 0.6/28% to 0.8/52% so the studio→product connection reads as deliberate. Orbit ring opacity 8% → 16%. - EcosystemSection centerpiece replaced — the compass-rose glyph with "STUDIO" label was a second centerpiece competing with the hero's Constellation. Replaced with a vertical hairline + italic Cormorant "Studio" wordmark + small horizontal hairline + uppercase eyebrow "The front door" + closing vertical hairline. Reads like a wax seal between the two columns of paths — quiet, ornamental, doesn't fight the hero.
2026-04-25
v0.7.0Synthesis reset — dark observatory + brutalist + constellation
The v0.4.x–v0.6.x line was incremental polish on a fundamentally SaaS-template composition: cards-on-cream-canvas with a navy hero inset. No amount of italic emphasis or sculpted shadows lifted that shape. v0.7.0 scraps the substrate and rebuilds on three blended lenses:
- Dark observatory as the BASE — studio runs on urja's
palette=editorial-dark(deep navy#0d1626canvas), with body-level starlight atmosphere. The brand is myth-coded; the surface should feel like night, not boutique-press. - Brutalist editorial as the TYPE — display-hero at clamp scale, italic gold emphasis on the substantive words, asymmetric grid composition (no centred-everything).
- Living interface as the ANCHOR — a single interactive
<Constellation>SVG replaces the old three-up product-card grid. Studio at the centre, three product stars orbiting, hairline gold lines connecting them. Each star is a real link; hover lights up the star + its line + label, and the dot brightens to gold. The whole thing breathes (idle scale-pulse on each dot, staggered timings, all CSS).
Removed
- ProductShowcase (the three-card "Reading chambers / Netra / Astrology API" grid). The Constellation supersedes it — one bold gesture instead of three obedient ones.
- The
.navy-hero-cardwrapper around the hero (no longer needed when the canvas IS dark) and around PhilosophySection.
Changed
app/layout.tsx— tokens link swaps topalette=editorial-dark.STUDIO_OVERRIDESblock rebuilt for night: faint warm radial gold + cool blue-violet glints + a corner vignette, all on top of the deep navy canvas.color-scheme: darkis set on<html>so form controls and scrollbars adopt dark UA chrome automatically.::selectioncolours selected text gold-on-canvas.app/globals.css— card system rebuilt for dark surfaces (warmer navy gradient base + cream-tinted top accent + multi-layer shadow with deep ambient + gold halo). New.constellationblock: SVG filter dropshadow, breathing keyframes for each dot with staggered delays, hover state choreography.app/page.tsx— Hero rebuilt as asymmetric brutalist: text column left (eyebrow, display-hero headline, lede with italic emphasis, CTA, stats grid), Constellation right (interactive product diagram). EcosystemSection adapted to dark (no morebg-subtleoverride; tokens drive colours). PhilosophySection becomes full-bleed: massive italic Cormorant pull-quote at clamp(2.5rem, 7vw, 5.5rem) on the dark canvas, with a subtle warm radial underneath so the type reads lit-from-within rather than floating cold.app/components/constellation.tsx(new) — server component, pure SVG, no JS. Four nodes (studio centre + three product stars). Halo + dot + label per node. Connecting lines as<line>elements behind the stars. Faint dashed orbit ring around the whole composition.
Note
The cards on dashboard / account / sign-in / api-keys pages automatically adopt the dark surface treatment via the token cascade — no per-page changes were needed.
2026-04-25
v0.6.0Closing the consumer beauty gap — italic emphasis + stats + a second navy block
Side-by-side compared with insightsbyomkar.com's pages, three specific gaps showed up: studio had only one navy block (the hero) so every section read cream-on-cream; headlines were flat-declarative without the editorial italic-gold emphasis consumer uses on words like computed / personal; and there was no concrete data grounding anywhere on the page. v0.6.0 closes those three.
Italic gold emphasis class
New .emph-gold utility — font-style: italic + Cormorant 600 + color: var(--ds-accent-gold). Pair around any word inside a display heading and it carries the magazine emphasis register.
Applied:
Heroalready had the.text-foil-goldshimmer on "Every product."ProductShowcase— "Three surfaces. One ethos. Built end-to-end."EcosystemSection— "Sign in once. Cross every threshold."PhilosophySection— "Home-grown end-to-end."
Hero stats row
Inside the navy hero card, below the CTAs, separated by a hairline rule: a four-column stats grid mirroring consumer's "49 / 5 / 14" pattern from the Astrology Pillar block:
`` 4 1 0 ∞ PRODUCTS ACCOUNT VENDOR SDKS ONE PERSON SHIPPING ``
Numbers in display-scale Cormorant + gold; labels in 10px uppercase sans with 0.18em tracking. Gives the hero concrete grounding without inventing fake metrics.
Philosophy converted to a navy block
The cream-after-cream rhythm broke at the bottom — every section between hero and footer was the same warm-near-white with no visual beat. PhilosophySection now renders inside .navy-hero-card (same sculpted depth treatment as the hero), so the page rhythm is now:
`` cream canvas → navy hero card (cream → navy moment) → cream ProductShowcase → cream EcosystemSection → navy PhilosophySection (cream → navy moment) → cream footer ``
Two navy moments anchor the page, like consumer's hero and "The Practice Behind Lucky" blocks. Italic Cormorant pull-quote on dark navy reads magazine-editorial, not blog-callout.
The CTAs in this block also get the upgraded treatment: Begin → becomes a .btn-gold pill with sheen-on-hover; "See pricing" becomes the same restrained underlined link the hero uses.
Changed
app/globals.css— adds.emph-goldutility.app/page.tsx— italic emphasis sweep on three headlines, newStatcomponent + stats grid inside Hero, full PhilosophySection rewrite as a navy card with .btn-gold CTA.
Untouched (next round if needed)
- Footer "soon" placeholders. Consumer's footer is dense with real category links; studio's still has 4 columns mostly with "soon" labels. Worth an audit pass once the new pages exist.
- Product cards still text + glyph — could grow atmospheric backdrops per product identity color (chambers warm, netra cool, api purple) if the page still reads thin.
2026-04-25
v0.5.0Bring surfaces alive — sculpted depth + animated interactions
The v0.4.x line landed clean composition + correct palette + matching ecosystem typography, but the surfaces still read flat and static — every card a hairline rectangle, every CTA a flat pill, every glyph a still ornament. Top-1% products do every surface in three layers (background + content + highlight) and every interaction in three changes (color + transform + shadow). v0.5.0 is that pass.
Card system v3 — three layers per card
Replaces the v3.1 minimal treatment with sculpted depth:
1. Background gradient — top-light → mid-elevated → bottom warmed with the gold token. Subtle but present, gives the card a sense of light direction. 2. Top 1px gold accent line — idle at 18% opacity, full reveal on hover. Gradient masks the ends so the line fades rather than cuts. 3. Multi-layer shadow — close inner highlight (1px white inset) + close ambient drop + warm gold-tinted ambient at 32px. Reads as a real surface with a real light source, not a hairline outline.
Coordinated hover on .card-surface (interactive cards):
- lift
translateY(-4px) scale(1.012) - shadow deepens, gold-tinted ambient grows
- top accent line reveals to full opacity
- inner radial glow fades in (warm gold from top-right)
.card-headinggets a gradient gold underline (idle 0 width, hover 100% width).card-glyphrotates 5° + scales 1.06 + drops a warm gold shadow.card-static(account sections, sign-in form, api-keys panels) gets the same depth without the hover state.
Navy hero card — sculpted, lit, alive
The <div class="navy-hero-card"> wrapper replaces the flat bg-[color:var(--ds-bg-inverse)] rectangle. New depth:
- Diagonal gradient base — 135° from gold-tinted navy at top-left to neutral navy at center, giving the card a sense of light angle.
- Inner highlight + inner shadow — 1px white at 5% on top, 1px black at 40% on bottom, sculpting the card edge.
- Warm-tinted outer shadow stack — three layers, the deepest at 80px ambient with a 22% gold tint so the card sits in a warm halo on the cool canvas.
- Top-left radial wash — 5% gold radial in the corner so the diagonal feels lit rather than baked.
Hero compass-rose — slow rotation, real presence
Bumped from 12% to 22% opacity (was nearly invisible, now reads as a deliberate watermark). New .hero-watermark class drives a 240s linear rotation — slow enough that it's barely perceptible but fast enough that the page never reads "static." Respects prefers-reduced-motion: reduce.
.btn-gold — sheen on hover
Replaces the inline gold-pill in the hero CTA with a real button class:
- Layered background — gold gradient base + a 200%-wide white sheen overlay positioned off-screen at idle.
- Inset highlight + outer warm-tinted shadow at idle.
- Hover — sheen sweeps from
-100%to100%over 700ms, lifttranslateY(-1px), shadow deepens. - Reduced-motion users get the lift + shadow but no sheen.
Changed
app/globals.css— net-rewrite of the card system (~140 lines), new.navy-hero-cardblock, new.hero-watermarkkeyframes, new.btn-goldblock. Existing.card-headingand.card-glyphhover behaviour upgraded with stronger transforms + drop-shadow.app/page.tsx Hero— wraps the navy block in.navy-hero-card, swaps the inlineinline-flex …button for.btn-gold, wraps the compass-rose Glyph in.hero-watermark.- Compass-rose opacity 12% → 22%, size 520 → 560 so the rotation is perceptible without dominating.
Untouched (next round if needed)
- Pull-quote-bracket / section-break / drop-cap ornaments from urja's v0.5.0 editorial set haven't landed yet — need to verify exact param shapes upstream before wiring. Worth a follow-up patch if the page still reads thin in the lower sections.
- Dashboard product tiles inherit the new card-surface treatment automatically (no per-component changes needed).
2026-04-25
v0.4.3Drop philosophy section glow
The Effect kind="glow" palette="aurora" behind the home page's PhilosophySection was rendering a candy green-sage gradient that clashed with v0.4.2's whitish + cool-undertone canvas. Highly visible on every screenshot of the lower home — read as a SaaS-y gradient backdrop pasted onto a boutique-editorial page.
Dropped the effect entirely. The PhilosophySection has plenty of substance (brass-divider, italic Cormorant pull-quote, lede, two CTAs); it doesn't need atmospheric backing. Type does the work.
Changed
app/page.tsx PhilosophySection— removes theEffectglow layer, drops thestage/stage-contentclass composition, removes the redundantbg-[color:var(--ds-bg-canvas)](the body background already supplies it). Section reads clean against the whitish canvas with the page's natural radial-gradient atmosphere doing the breath underneath.- Drops the now-unused
Effectimport fromapp/page.tsx.
2026-04-25
v0.4.2Whitish canvas + layered undertones
Urja's palette=editorial ships a warm peach-cream canvas (#fbf3e9) that read too cream against the navy hero card — specifically not matching insightsbyomkar.com's feel, which is near-white with subtle cool undertones layered on top. v0.4.2 overrides studio's canvas locally to that target.
Changed
app/layout.tsx— adds aSTUDIO_OVERRIDESinline<style>block emitted after the urja tokens<link>so the cascade resolves correctly. Block does two things:- Overrides
--ds-bg-canvasto#f5f6fb(cool near-white, matching consumer's--bg: #f2f5fcbaseline). Subtle/elevated and the border tint set re-pitched to the cooler base so hairlines read warm-correct. - Sets
body { background: ... }to a five-layer radial-gradient atmosphere on top of the canvas — pale gold top-left, pale blue top-right, pale umber bottom-center, pale violet right-mid, pale honey bottom-left, all at 3-5% opacity.background-attachment: fixedkeeps the wash in viewport position as the page scrolls. This is the "many undertones" feel.
Note for urja
The whitish-with-undertones treatment should ideally be a urja palette variant (palette=editorial-light or similar), not a studio-side override. Logged in NEXT_FROM_URJA.md as a follow-up — when urja ships it, this STUDIO_OVERRIDES block goes away.
Untouched (intentionally)
- Display weight, moon-phase params, navy hero, dashboard eyebrow — all v0.4.1 changes hold. This is purely a canvas tone shift.
- Philosophy section's
Effect kind="glow" palette="aurora"reads SaaS-y green-sage on the bottom of the home page; not changed in this patch (out of scope), but worth a future swap topalette="dusk"or removing the glow entirely.
2026-04-25
v0.4.1Polish on top of the urja migration
Four cumulative changes driven by post-v0.4.0 screenshot review.
Navy contrast hero on /
The home hero rebuilt as an embedded dark navy card on cream — mirroring the visual rhythm of insightsbyomkar.com's hero stat block. Uses var(--ds-bg-inverse) (urja's #0d1626 token) for the card background, var(--ds-text-inverse) for white text, and the new .text-foil-gold utility (also from urja's tokens CSS) for the "Every product." metallic shimmer.
The atmospheric stage treatment (full-bleed starfield + grain) is gone — the navy card is the visual anchor now. A compass-rose ornament watermark sits at 12% opacity in the bottom-right corner of the card as a quiet anchor, pulled out of view enough that the headline column breathes.
CTA shifts to a pill-shaped gold button (against navy this reads warmer than the previous black-on-cream slab) plus an underlined secondary link. Cleaner ecosystem rhythm: cream canvas → navy moment → cream sections → footer.
Display weight bumped to 600
Cormorant Garamond ships at 400 + 600 only. Everything between forces browser font-synthesis which renders flat/inconsistent. All larger display classes (.display-hero, .display-2xl, .display-xl, .display-lg) now use 600 for real presence at scale; smaller ones (.display-md, .display-sm) drop to 400 for an airier editorial feel. No more middling 500 weights.
Moon-phase params fixed
The Reading Chambers tile glyph was rendering as a flat gold disc (phase 0.42 = waning gibbous, mostly lit) — visually inconsistent with sibling glyphs (chart-ring openwork, mercury line-art). Changed to phase: 0.25 (first quarter, half-moon silhouette) and bumped ringOpacity to 0.55 so the surrounding ring reads. Three product glyphs now have balanced visual weight.
Dashboard "Your products" eyebrow
Filled the dead vertical zone between the greeting block and the tile grid with a small editorial moment: a 36px gold-rule + "Your products" eyebrow above the tiles. Tightens the spacing rhythm without padding the page with content that doesn't exist.
Changed
app/page.tsx— Hero rewritten to navy card. Drops thestage/stage-fade-bottomclasses, the starfield + grain layers, the large compass-rose centerpiece. Compass-rose returns as a watermark inside the card.app/dashboard/page.tsx—mt-14tile grid wrapper → eyebrow row +mt-6grid below. Moon-phase params updated.app/globals.css— display class weights remapped (600 for display-hero/2xl/xl/lg, 400 for display-md/sm).
2026-04-25
v0.4.0Studio adopts urja as the canonical visual layer
Urja v0.5.0 cleared studio's NEXT_FROM_URJA.md ask list — palette-aware semantic tokens, Cormorant Garamond on the fonts endpoint, color=var(--ds-*) resolution in illustrate, and the nav v2 subnav slot fix. Studio is the first repo to consume the canonical layer end-to-end.
Studio is now thin
Studio's local visual chrome shrinks to: a few studio-specific composition classes (.display-hero, .btn-lg, the .lucky-* reduced-motion override) and Tailwind theme bindings into urja's font tokens. Everything else — palette, colours, type stack, motion primitives, ornaments, atmospherics, nav — flows from urja.
Changed
app/layout.tsx— adds<link rel="stylesheet">tourja.insightsbyomkar.com/api/v1/tokens?format=css&layer=semantic&palette=editorial, swaps the fonts CSS tofamilies=display,sans,garamond, swaps the preload from Fraunces to Cormorant Garamond (garamond-400-normal-latin.woff2).app/globals.css— drops the local tokens import;@themenow binds--font-sanstovar(--ifv-font-sans)and--font-displaytovar(--ifv-font-garamond)so Tailwind utilities + studio's display classes resolve through urja's font tokens. Cormorant Garamond becomes studio's display face, matching consumer's editorial tone.- 15 Glyph
color="#b8860b"literals updated to#a17a0ato align with urja's editorial palette gold (slightly more copper than the legacy yellow-gold). The illustrate endpoint now also resolvescolor=var(--ds-*)server-side; studio sticks with hex literals pending a follow-up — see Known still-broken below.
Removed
app/brand-tokens.css— the hand-mirrored token file that drifted twice in v0.3.x. Gone. Single source of truth lives at urja.
Visual changes (no code change required to see them)
- Canvas warms from studio's local
#f7f3eato urja's editorial#fbf3e9(slight peach undertone, matchesinsightsbyomkar.com). - Body text shifts from local
#1a1611to urja's#2a1f10(deeper brown), text-soft to#5b4a30, gold to#a17a0acopper. - A new
--ds-bg-inverse: #0d1626token is now available for the hero / quote-card navy contrast moments — used in the next patch (v0.4.1) to anchor the home hero matching consumer's hero stat block treatment. - Display headlines now render in Cormorant Garamond. Same scale, warmer voice.
Known still-broken
- Glyph
color=var(--ds-accent-gold)resolves to the dark-mode gold (#d4a550) regardless ofmode=lightquery param. Looks like urja's mode resolution is reading the wrong side of the registry. Studio uses hex literals (#a17a0a) until urja patches. Logged inNEXT_FROM_URJA.md. - Subnav row visibility — urja v0.5.0 ships the slotchange-based fix (
data-has-subnav), but the legacy:has(slot:empty)rule still appears once in the bundle. Studio's Dashboard / Account tabs may or may not be visible depending on how the cascade resolves. Will validate on next deploy.
2026-04-24
v0.3.2Iterating on visual evidence — round one
First polish round driven by actual screenshots rather than blind "premium token" intuition. Three changes plus an upstream-asks doc.
Canvas warmed to cream
Pure-white canvas + pure-white cards collapsed into a Notion-clone white void at real rendered scale — the gold-tinted hairlines I added in v0.3.1 disappeared at production resolutions. Switched the --ds-bg-canvas token to a real warm cream (#f7f3ea) and re-tinted the rest of the warm-neutral set off the new base:
- canvas
#f7f3ea, subtle#efe9d9, elevated#fefcf7 - text-strong
#1a1611, text-soft#4a4338, muted#756c5c, faint#a59c87 - borders re-tinted as
rgba(26, 22, 17, *)so hairlines read warm against the cream base instead of slate-on-cream-as-broken - Cards on cream canvas now have real figure/ground separation without changing card chrome. One token shift, every surface lifts.
Hero atmosphere purged
Production studio.insightsbyomkar.com was reading as "purple haze" because the aurora layer ran at 70% opacity with the nebula palette — candy-bright on every visit. Cut entirely. Replaced with:
- The compass-rose centerpiece bumped from 16% to 32% opacity so it's actually anchoring the page, not lurking.
- Starfield re-tuned to
palette=ember,density=0.4,speed=0.3,mix-blend-screenat 25% — quiet parallax breath, no candy. - Grain layer at 30% for paper-like texture against the cream.
- The hero now reads as architecture (compass-rose + headline) with quiet atmospheric breath, instead of haze + tiny text.
Greeting fallback fixed
Good evening, Jaliparthiomkar15. was rendering because greet() took the entire email prefix as a name. Added an isNameish() guard: handle must be 2-12 chars, alpha-only, single word. Otherwise drops the name entirely (Good evening.). Real display_name from profiles is the long-term fix; this is the fallback while studio doesn't read that column.
Documented upstream-asks at NEXT_FROM_URJA.md
Eight items studio can't fix locally — restrained editorial palettes, the nav v2 subnav slot bug, the color param's silent CSS-variable rejection, texture/ornament gaps, a shared tokens CSS endpoint, gold-foil text treatment. Each entry calls out the workaround in place so urja can move at its own cadence without studio rotting in the meantime.
Known still-broken
- Subnav tabs invisible. Tracked as item #2 in
NEXT_FROM_URJA.md— nav v2 ships a CSS rule that hides the.subnav-rowwhenever the named<slot>has no fallback content, regardless of whether projected content is present. Studio renders Dashboard / Account into the slot correctly; they're just hidden by the nav's own CSS. No studio-side workaround. - Tile glyph weights inconsistent (filled-disc moon-phase, thin chart-ring, small mercury). Awaiting visual taste call — may require re-tuning glyph params per tile or asking urja for consistent default weights across the ornament track.
2026-04-24
v0.3.1Design polish wave — hero, cards, dashboard
The v0.3.1 wave is design depth. Three patches collapsed to one minor:
- Hero rebuild (pre.1) — centerpiece compass-rose silhouette, larger display type, refined gold-sweep gradient, simplified CTAs. Plus a silent rendering bug fix that lit up every ornament glyph across the studio (CSS variable refs were 400-rejected by urja).
- Card system overhaul (pre.2) —
.card-surfaceand.card-staticvariants; gold-tinted hairline + warm vertical gradient base; on hover, the interactive variant fades in a soft warm radial glow, reveals a gold underline beneath.card-heading, and rotates the.card-glyph4° at scale 1.04. Seven non-interactive panels swept to.card-staticso the hover-lift only fires where there's somewhere to go. - Dashboard redesign (this entry) — see below.
Dashboard redesign
The page authed users see most. Reads less like a settings panel and more like a studio you've come back to.
- Greeting block with day-of-week + month-day in a gold-rule eyebrow, a time-aware opener (Good morning / Welcome back / Good evening) wired to the visitor's local hour, and a one-line lede about how studio carries identity across products.
- Tile chrome — entitlement status moves from a floating top-right pill into the bottom of each tile, paired with a tiny gold dot (active) or neutral dot (inactive). Sits on a hairline border above the CTA, so the tile reads as one composed unit.
.card-glyphand.card-headingopted in for the new card hover treatment. - Recently strip — new
lib/activity/feed.tsreads the latest 7 rows fromstudio_activity(RLS-scoped), renders them as a horizontal-rule-separated list with a per-product badge, the event title, and a compact relative time. Empty state names what the table is for so day-1 visitors understand the surface.
Added
lib/activity/feed.ts—fetchRecentActivity,activityHref,activityFallbackTitle,relativeTime. Soft-fail on RLS / network errors (returns[]).
Changed
app/dashboard/page.tsx— full rewrite: greeting, integrated tile status, activity strip. ~190 lines, all in-page (no extra components — the layout is small enough).
v?0.3.1-pre.2] — 2026-04-24
Card system overhaul
Every card surface across studio now reads as one designed family rather than a flat repeated border-radius + 1px slate hairline. Two variants share the same base:
.card-surface— interactive (home product cards, dashboard tiles). Hover triggers a 3px lift, deeper sculpted shadow, the border pulses to full gold, a soft warm radial glow fades in from the top-right corner, the heading underlines with a gold rule, and the glyph rotates 4° while scaling 1.04×. Each transition tuned for ~250-320ms with the brand's soft easing curve..card-static— content cards (account sections, sign-in form, API-keys panels, rotate/revoke forms). Same base — gold-tinted hairline, vertical gradient warmed at the bottom edge — but no hover state. Reads cohesive with the interactive surfaces without performing a hover lift it can't act on.- Two opt-in classes pair with
.card-surface: .card-heading— gold underline reveals on the card's title..card-glyph— the 4° rotation + scale on a glyph wrapper.
Changed
app/globals.css— replaces the flatcard-surfacerule with the layered system above. ~70 lines net add.app/page.tsx(ProductCard) —.card-headingon<h3>,.card-glyphon the glyph wrapper, drops the inlinetransition-transform group-hover:scale-105(now CSS-driven).app/dashboard/page.tsx(ProductTile) — same treatment as ProductCard.- 7 files swept from
card-surfacetocard-staticfor non-interactive panels: account sections, sign-in form, api-keys list/empty/rotate/revoke.
v?0.3.1-pre.1] — 2026-04-24
Hero rebuild + a silent rendering bug fix
The marketing hero gets a real centerpiece: a 680px (clamped to 512 by urja) compass-rose silhouette anchors the headline, with the H1 typography pulled to a new .display-hero scale (clamp 3.5rem-8rem, weight 400, tighter tracking, line-height 0.94). The "Every product." gold-sweep gradient now ramps from strong at 0%, holds through 22%, peaks gold at 52%, and fades back — feels less saccharine, more brass- shimmer. Drops the "Scroll to explore" cue, simplifies CTAs to one big primary + one underlined link.
Silent bug fixed
Caught while rebuilding the hero: every Glyph passing color="var(--ds-accent-gold)" was rendering as an empty placeholder because urja's illustrate endpoint validates the color param and returns 400 for CSS variable references. Affected every ornament + planet glyph across home, dashboard, account, account/api-keys, and the footer brass-divider — the studio surface had been quietly missing visual content since the visual-api adoption in v0.2.0.
Swept all 15 sites to pass the literal hex #b8860b (matches the --ds-accent-gold token). Documented in lib/visual/components.tsx so the next person doesn't repeat the mistake.
Added
.display-heroand.btn-lgtypography classes inglobals.css.
Changed
app/page.tsxHero — atmospheric layers + centerpiece compass-rose via stage-layer pattern. Larger H1, refined gradient, simpler CTAs, dropped scroll cue.- 15 Glyph call sites updated from
var(--ds-accent-gold)to#b8860b.
2026-04-24
v0.3.0Ecosystem nav hub + command palette
The v0.3.0 wave lands as one release. Studio becomes the polished identity + navigation hub for the whole ecosystem: a shared app-launcher nav (waffle + avatar + search) served from urja, studio's own tabs (Dashboard · Account) riding in its subnav slot, and a ⌘K command palette that jumps across products, account actions, and recent activity. Full details in the pre.1, pre.2, pre.3 entries below — collapsed to one commit for the minor.
Changed
app/components/site-header.tsxremoved entirely. Its role is now covered by the ecosystem nav (global chrome) andStudioSubnav(per-product tabs).
Deferred
app/brand-tokens.cssstays as a local mirror for now. Moving to a live tokens endpoint on urja is worth doing later as a dedicated cross-repo patch, not smuggled into the nav/palette wave.- Dashboard depth (product tiles with activity summary, cross-product nudges, recent-activity strip) moves to v0.3.1 and rides on top of the new chrome — benefits from
studio_activityonce consumer + netra start writing rows.
v?0.3.0-pre.3] — 2026-04-24
Ecosystem command palette
⌘K (or the ecosystem nav's search button) now opens a centered command palette. Four result sources resolved in one Server Action round-trip, debounced at 180ms:
1. Products — local mirror of the ecosystem nav's product registry. Typing "netra" jumps straight to netra.insightsbyomkar.com. 2. Account actions — Manage account, API keys, Billing (Stripe portal on the consumer apex), Help (mailto), Sign out. The signout row dispatches ecosystem-nav:signout so the existing NavBridge handles the POST — no duplicate signout path. 3. Recent charts — last 5 studio_activity rows with kind LIKE 'chart.%', deep-linked to netra's studio surface. 4. Recent readings — last 5 studio_activity rows with kind LIKE 'reading.%', deep-linked to chambers. Empty section renders a "No recent readings yet." affordance while consumer v2.8.2 wires up the write path.
studio_activity is scoped via RLS (auth.uid() = user_id), so the session-authed Supabase client is the right surface — no service role.
Added
lib/palette/types.ts— sharedPaletteItem/PaletteSectionshapes so every source has the same render contract.lib/palette/products.ts— local product registry +matchProducts. Mirrors thePRODUCTSarray baked into the nav v2 bundle; keep in sync if upstream ships new products.lib/palette/actions.ts— static account commands.lib/palette/search.ts—"use server"action combining all four sources. Title-only ILIKE for activity rows (kind/ref aren't user-friendly search targets).app/components/palette.tsx— the client modal. Listens forecosystem-nav:search-open+ecosystem-nav:search, debounces the server action, tracks a flattened item list for arrow-key traversal, restores focus on close. Uses them-modal-entermotion primitive from urja.
Changed
app/layout.tsx— mounts<Palette />alongside<NavBridge />, gated onsession?.emailso anonymous visitors don't ship the component's bundle.
v?0.3.0-pre.2] — 2026-04-24
Adopt ecosystem nav v2 — waffle, avatar, search
The shared <iby-ecosystem-nav> web component now ships from urja's v2 endpoint (/api/v2/nav/ecosystem-nav.js). Same custom-element tag, new chrome: a waffle product launcher, an avatar menu with the session-resolved email + Sign out, and an inline search input that fires ecosystem-nav:search events for downstream consumers.
Studio's per-product tabs (Dashboard · Account) move from the legacy SiteHeader into the nav's <slot name="subnav">. The subnav only renders for signed-in users — anonymous visitors already have the ecosystem nav's waffle + Sign-in CTA, and the landing page itself is the Overview, so a back-reference tab was dead chrome. Active state is now driven by usePathname() rather than a current prop threaded through every page — cleaner and survives SiteHeader's eventual removal in Patch 4.
Added
app/components/studio-subnav.tsx— client component rendered into the ecosystem nav's subnav slot.usePathname()drives active styling.app/components/nav-bridge.tsx— client bridge between the nav web component and studio's routes. Two responsibilities:- Listens for
ecosystem-nav:signoutonwindow; on fire, submits a native form toPOST /api/auth/sign-outso the route's 303 redirect is followed naturally. - Sets the
return-urlattribute on the nav element towindow.location.hrefafter every navigation, so the waffle's product tiles + the anonymous Sign-in CTA forward the right origin URL into post-auth bounce-backs.
Changed
app/layout.tsx— async, runsreadSession()in parallel with the motion CSS fetch; passescurrent="studio",user-email, anduser-avatar-initial(first letter of email, uppercased) onto the nav element when signed in. Renders<StudioSubnav />inside the subnav slot, mounts<NavBridge />once.app/page.tsx,app/dashboard/page.tsx,app/account/page.tsx,app/sign-in/page.tsx,app/account/api-keys/page.tsx,app/account/api-keys/[keyId]/rotate/page.tsx,app/account/api-keys/[keyId]/revoke/page.tsx— drop the legacy<SiteHeader>render + import. The shared nav from layout now owns every page's top chrome.
Deferred
app/components/site-header.tsxis still on disk but no longer rendered anywhere. Patch 4 (cleanup) will delete the file.
v?0.3.0-pre.1] — 2026-04-24
Homegrown fonts + motion from urja (was visual-api)
Studio drops next/font/google and consumes Fraunces + Inter directly from urja's public fonts endpoint (/api/v1/fonts?format=css&families=display,sans). Motion primitives flip from a hand-mirrored local file to urja's scope-gated /api/v1/motion?format=css&set=all, fetched server-side and inlined into <head> for critical-path paint. The local app/motion-tokens.css mirror is gone — one source of truth across the ecosystem.
This is the first patch of the v0.3.0 wave (ecosystem nav hub + command palette per NEXT.md); subsequent patches in this minor will ship as pre.N until the wave lands as v0.3.0.
Changed
app/layout.tsx—<link rel="stylesheet">to urja's public fonts CSS, plus a<link rel="preload">for the display latin WOFF2 to keep first-paint tight. Motion CSS inlined as a<style>block via the newfetchVisualCsshelper.<link rel="preconnect">to urja warms DNS + TLS before the first asset request.app/globals.css—@themefont-family values now reference the literal family names ("Fraunces","Inter") rather than next/font's injected CSS variable. Addedprefers-reduced-motionoverride for the legacylucky-motion classes (upstream motion CSS only carries the override for the newerm-set).lib/visual/client.ts— addedfetchVisualCss(). Same soft-fail contract asfetchVisualSvg. Also bumped the defaultVISUAL_API_URLtohttps://urja.insightsbyomkar.com(the legacyvisual.*host now 307s — eating a redirect on every asset call).lib/env.ts— same default URL bump.
Removed
app/motion-tokens.css— replaced by inlined motion CSS from urja.next/font/googleimport + Fraunces / Inter font loaders.
Operational
VISUAL_API_KEYmust be set on Vercel (any project that consumes motion CSS — currently studio only). Set as a team-shared env var perECOSYSTEM_ENV.mdso the rest of the ecosystem inherits it when they start consuming.
2026-04-22
v0.2.0Visual refresh — studio becomes the brand face
The minimum-viable bootstrap is gone. Studio now reads as a real brand surface — atmospheric hero, full type hierarchy, product showcase with identity per product, an ecosystem diagram that explains how the four products fit together, and a philosophy section that names the home-grown ethos out loud.
Every visual asset on the site — atmospheres, ornaments, glyphs, icons, motion — is fetched from tuffys-visual-api. No external icon kits, no external illustration libraries, no third-party animation packages. Only the fonts (Fraunces + Inter) flow through next/font, matching the canonical face stacks documented at GET /api/v1/fonts.
Visual API consumption layer
lib/visual/client.ts— server-side fetcher (fetchVisualSvg,visualApiUrl,visualProxyUrl,forwardVisualRequest). Uses Next.js Data Cache (next: { revalidate: 86400, tags: ["visual"] }) so the visual API is hit at most once per asset per day per region.app/api/visual/[...path]/route.ts— public proxy that attaches the server-onlyx-api-keyand forwards tovisual.insightsbyomkar.com. Cache headers are public so the studio's CDN can dedupe across users.lib/visual/components.tsx— three server components:<Effect>— atmospheric SVGs (aurora,starfield,glow,grain) rendered as<img>so SMIL animations play natively.<Glyph>— illustrate-track SVGs (ornaments, scenes, planets, zodiac, aspects, patterns) inlined forcurrentColorstyling.<Icon>— convenience wrapper over<Glyph type="icon">.lib/visual/reveal.tsx— IntersectionObserver client wrapper that applies the canonicallucky-fade-upkeyframes on scroll. Reduced motion → instant reveal.app/motion-tokens.css— mirrored motion primitives (fade-up,parallax-drift,breath) from visual-api/api/v1/motion?format=css. Hand-synced for now; provenance header notes the canonical source.- Two new env vars (
VISUAL_API_URL,VISUAL_API_KEY) — see.env.example. The key is a JWT minted via visual-api'sPOST /api/admin/mint-keywith at leaststudio:v1:usescope.
Type system
globals.css now exports a Fraunces-based display scale (.display-2xl through .display-sm), an .eyebrow ornament with a gold variant, a .lede body face, and a .gold-rule divider. Card, button, and atmospheric .stage primitives round out the kit. All spacing, colour, motion, and typography references live behind the existing --ds-* tokens.
Shared chrome
app/components/site-header.tsx— single source of truth for the studio header. Sticky, blurred, links across overview / dashboard / pricing, account-pill on the right when signed-in.app/components/site-footer.tsx— four-column footer with brass divider flourish; surfaces upcoming pages (about / pipeline / journal / status) as "soon" so the IA reads from launch.
Ecosystem nav
The <iby-ecosystem-nav> web component served by visual-api is now embedded in app/layout.tsx (matches Netra's adoption pattern). Studio is the brand root, so no current attribute is set — the wordmark already points home.
Page rebuilds
/(home) — atmospheric hero (aurora + starfield + grain layers from visual-api effects), gradient gold-text on the headline, brass divider section labels, three product cards with bespoke glyphs (moon-phasefor chambers,chart-ringfor Netra,mercuryplanet glyph for the API), an ecosystem diagram with acompass-roseat the centre, and a philosophy pull-quote backed by a softglow./dashboard— same chrome + product glyphs on each tile; entitlement note rendered as a gold pill when active./account— sectioned cards with hairline brass dividers; status rows show a gold dot when active, neutral when not./sign-in— card lifted onto a soft starfield-dust + aurora backdrop; copy now references the shared-domain identity model.
Operational
next.config.ts—/api/visual/*exempted from the globalCache-Control: private, no-storeso the proxy can cache publicly.- New env keys (
VISUAL_API_URL,VISUAL_API_KEY) — set on Vercel prod scope before promoting this deploy. Without the key, every visual asset renders as an empty placeholder so the page still functions in dev.
2026-04-22
v0.1.3De-duplicate Supabase env vars
Dropped SUPABASE_URL — the URL isn't sensitive (it lives in every client request) so one NEXT_PUBLIC_SUPABASE_URL serves both the server-side admin client and the browser client. Fewer env slots to fill on every deploy.
Required env for studio: 1. NEXT_PUBLIC_SUPABASE_URL 2. NEXT_PUBLIC_SUPABASE_ANON_KEY 3. SUPABASE_SERVICE_ROLE_KEY 4. NEXT_PUBLIC_SUPABASE_COOKIE_DOMAIN = .insightsbyomkar.com (prod)
lib/env.ts:supabaseUrlnow readsNEXT_PUBLIC_SUPABASE_URL..env.example: drop the duplicate line + clarifying comment.
2026-04-22
v0.1.2Cross-subdomain sign-in bounce
Netra (and any other product repo) can now redirect an unauthenticated visitor to studio's sign-in and get them sent back afterwards. Flow:
`` netra.insightsbyomkar.com/studio/foo (no session) → 302 → studio.insightsbyomkar.com/sign-in?return=https://netra.insightsbyomkar.com/studio/foo → user clicks magic link → studio.insightsbyomkar.com/auth/callback?next=<same-url> → cookie set on .insightsbyomkar.com, 302 → netra.insightsbyomkar.com/studio/foo ``
lib/return-url.ts: new shared resolver that accepts either a relative path or a full URL on a whitelisted sibling origin. Anything else rejected (prevents open redirect).app/sign-in/page.tsx: reads?return=, passes to the client form.app/sign-in/sign-in-client.tsx: postsreturninstead ofnext.app/api/auth/sign-in/route.ts: threadsreturninto the magic-link callback URL.app/auth/callback/route.ts: validatesnextagainst the same whitelist and 302s back to the sibling subdomain.
2026-04-22
v0.1.1Shared-domain auth cookie
Reads NEXT_PUBLIC_SUPABASE_COOKIE_DOMAIN and passes it to both the server and browser Supabase clients. In production this is .insightsbyomkar.com so the auth cookie studio sets is visible to netra, consumer, api, and admin without a handoff step — that's the entire point of studio being the single sign-in surface. Unset locally → localhost default.
Supabase's dashboard has no "cookie domain" setting; that config lives in app code via @supabase/ssr's cookieOptions.
lib/supabase/server.ts: threadscookieOptions.domainthroughcreateServerClientwhen the env is set.lib/supabase/client.ts: same forcreateBrowserClient..env.example: new env var documented.
2026-04-22
v0.1.0Bootstrap. Studio is the new brand + identity root at studio.insightsbyomkar.com. v0.1.0 ships the minimal end-to-end identity + dashboard flow so every other repo in the ecosystem can start redirecting its auth traffic here.
Added
- Auth surface —
/sign-in(doubles as sign-up via Supabase magic link),/auth/callbackexchange,/api/auth/sign-inBFF (does not leak whether the email is known),/api/auth/sign-outthat clears the shared.insightsbyomkar.comcookie. /dashboard— signed-in home rendering product tiles fromuser_entitlements. Tiles flip between "Open →" and "Subscribe →" based on the relevant flag; unentitled tiles deep-link to consumer pricing./account— profile + subscription snapshot + deep-links to the Stripe Customer Portal via consumer's/api/billing/portal/redirect?return=…endpoint. Sign-out button.- Landing page — brand hero, three product rows (chambers / Netra / astrology API), footer. Signed-in visitors bypass it entirely.
- Core infrastructure — Next.js 16 App Router, Supabase SSR with the same cookie pattern used in consumer and Netra, design tokens mirrored from consumer until a shared package lives in visual-api, conservative security headers on every route,
X-Robots-Tag: noindexon every/api/*path.
Dependencies
@supabase/ssr,@supabase/supabase-js,next16.2.4,react19.2,tailwindcss4.2. No product-layer third-party UI libraries.
Supabase setup required (one-time, dashboard-only)
- Cookie domain:
.insightsbyomkar.com - Site URL:
https://studio.insightsbyomkar.com - Allowed redirect URLs:
/auth/callbackon every sibling subdomain that needs post-auth landing.
Known gaps (next patches)
- Marketing content is minimal — the brand / product-pipeline pages come in v0.2 (Phase 2 of the ecosystem plan).
- No shared nav component yet; that track lands in
tuffys-visual-apiunder Phase 2.1 and studio adopts it alongside netra + consumer. - Profile edit (name, timezone, preferences) is read-only for now. Edit surfaces ship with the next patch once there's a settled schema across ecosystem consumers.
Rendered live from the studio repo's CHANGELOG.md. Every commit lands here.
