diff --git a/.env.example b/.env.example index e88813b6..cd120f1a 100644 --- a/.env.example +++ b/.env.example @@ -41,7 +41,7 @@ SESSION_ENCRYPT=false SESSION_PATH=/ SESSION_DOMAIN=null -# Skinbase Nova conditional public sessions +# Skinbase conditional public sessions SKINBASE_CONDITIONAL_SESSIONS_ENABLED=true SKINBASE_SKIP_ANONYMOUS_PUBLIC_GET_SESSIONS=true SKINBASE_SKIP_BOT_PUBLIC_GET_SESSIONS=true diff --git a/app/Http/Controllers/Api/UploadVisionSuggestController.php b/app/Http/Controllers/Api/UploadVisionSuggestController.php index 9b740ac6..2848f43e 100644 --- a/app/Http/Controllers/Api/UploadVisionSuggestController.php +++ b/app/Http/Controllers/Api/UploadVisionSuggestController.php @@ -30,15 +30,14 @@ final class UploadVisionSuggestController extends Controller public function __invoke(int $id, Request $request): JsonResponse { - if (! $this->vision->isEnabled()) { - return response()->json(['tags' => [], 'vision_enabled' => false]); - } - $artwork = Artwork::query()->findOrFail($id); $this->authorizeOrNotFound($request->user(), $artwork); - $limit = (int) $request->query('limit', 10); - return response()->json($this->vision->suggestTags($artwork, $this->normalizer, $limit)); + return response()->json([ + 'tags' => [], + 'vision_enabled' => false, + 'reason' => 'disabled', + ]); } private function authorizeOrNotFound(mixed $user, Artwork $artwork): void diff --git a/app/Http/Controllers/Settings/CollectionInsightsController.php b/app/Http/Controllers/Settings/CollectionInsightsController.php index 02864644..88ec54ff 100644 --- a/app/Http/Controllers/Settings/CollectionInsightsController.php +++ b/app/Http/Controllers/Settings/CollectionInsightsController.php @@ -108,7 +108,7 @@ class CollectionInsightsController extends Controller 'bulkActions' => route('settings.collections.bulk-actions'), ], 'seo' => [ - 'title' => 'Collections Dashboard — Skinbase Nova', + 'title' => 'Collections Dashboard — Skinbase', 'description' => 'Overview of collection lifecycle, quality, activity, and upcoming collection campaigns.', 'canonical' => route('settings.collections.dashboard'), 'robots' => 'noindex,follow', @@ -127,7 +127,7 @@ class CollectionInsightsController extends Controller 'historyUrl' => route('settings.collections.history', ['collection' => $collection->id]), 'dashboardUrl' => route('settings.collections.dashboard'), 'seo' => [ - 'title' => sprintf('%s Analytics — Skinbase Nova', $collection->title), + 'title' => sprintf('%s Analytics — Skinbase', $collection->title), 'description' => sprintf('Analytics and performance history for the %s collection.', $collection->title), 'canonical' => route('settings.collections.analytics', ['collection' => $collection->id]), 'robots' => 'noindex,follow', @@ -150,7 +150,7 @@ class CollectionInsightsController extends Controller 'analyticsUrl' => route('settings.collections.analytics', ['collection' => $collection->id]), 'restorePattern' => route('settings.collections.history.restore', ['collection' => $collection->id, 'history' => '__HISTORY__']), 'seo' => [ - 'title' => sprintf('%s History — Skinbase Nova', $collection->title), + 'title' => sprintf('%s History — Skinbase', $collection->title), 'description' => sprintf('Audit history and lifecycle changes for the %s collection.', $collection->title), 'canonical' => route('settings.collections.history', ['collection' => $collection->id]), 'robots' => 'noindex,follow', diff --git a/app/Http/Controllers/Settings/CollectionProgrammingController.php b/app/Http/Controllers/Settings/CollectionProgrammingController.php index 4563808a..39219afe 100644 --- a/app/Http/Controllers/Settings/CollectionProgrammingController.php +++ b/app/Http/Controllers/Settings/CollectionProgrammingController.php @@ -92,7 +92,7 @@ class CollectionProgrammingController extends Controller 'surfaces' => route('settings.collections.surfaces.index'), ], 'seo' => [ - 'title' => 'Collection Programming — Skinbase Nova', + 'title' => 'Collection Programming — Skinbase', 'description' => 'Staff programming tools for assignments, previews, eligibility diagnostics, and recommendation refreshes.', 'canonical' => route('staff.collections.programming'), 'robots' => 'noindex,follow', diff --git a/app/Http/Controllers/Settings/CollectionSurfaceController.php b/app/Http/Controllers/Settings/CollectionSurfaceController.php index 3f210338..3994f55a 100644 --- a/app/Http/Controllers/Settings/CollectionSurfaceController.php +++ b/app/Http/Controllers/Settings/CollectionSurfaceController.php @@ -66,7 +66,7 @@ class CollectionSurfaceController extends Controller 'batchEditorial' => route('settings.collections.surfaces.batch-editorial'), ], 'seo' => [ - 'title' => 'Collection Surfaces - Skinbase Nova', + 'title' => 'Collection Surfaces - Skinbase', 'description' => 'Staff tools for homepage, discovery, and campaign collection surfaces.', 'canonical' => route('settings.collections.surfaces.index'), 'robots' => 'noindex,follow', diff --git a/app/Http/Controllers/Settings/FeaturedArtworkAdminController.php b/app/Http/Controllers/Settings/FeaturedArtworkAdminController.php index f7697de0..7e5be798 100644 --- a/app/Http/Controllers/Settings/FeaturedArtworkAdminController.php +++ b/app/Http/Controllers/Settings/FeaturedArtworkAdminController.php @@ -43,7 +43,7 @@ class FeaturedArtworkAdminController extends Controller 'forceHeroEnabled' => $this->hasForceHeroColumn(), ], 'seo' => [ - 'title' => 'Featured Artworks — Skinbase Nova', + 'title' => 'Featured Artworks — Skinbase', 'description' => 'Editorial controls for homepage featured artworks and the current hero winner.', 'canonical' => route($routePrefix . 'main'), 'robots' => 'noindex,follow', diff --git a/app/Http/Controllers/Studio/StudioWorldController.php b/app/Http/Controllers/Studio/StudioWorldController.php index 74248f42..0249defc 100644 --- a/app/Http/Controllers/Studio/StudioWorldController.php +++ b/app/Http/Controllers/Studio/StudioWorldController.php @@ -40,7 +40,7 @@ final class StudioWorldController extends Controller return Inertia::render('Studio/StudioWorldsIndex', [ 'title' => 'Worlds', - 'description' => 'Create and manage seasonal, event, and campaign destinations across Skinbase Nova.', + 'description' => 'Create and manage seasonal, event, and campaign destinations across Skinbase.', 'listing' => $this->worlds->studioListing($request->only(['q', 'status', 'type', 'per_page'])), 'analytics' => $this->analytics->portfolioReport(), 'statusOptions' => [ @@ -435,7 +435,7 @@ final class StudioWorldController extends Controller $payload = $this->worlds->publicShowPayload($world, $request->user(), true); $seo = app(SeoFactory::class)->collectionPage( - $world->seo_title ?: ($world->title . ' — Skinbase Nova Preview'), + $world->seo_title ?: ($world->title . ' — Skinbase Preview'), $world->seo_description ?: ($world->summary ?: $world->description ?: 'Preview world page'), route('studio.worlds.preview', ['world' => $world]), $world->ogImageUrl(), diff --git a/app/Http/Controllers/User/ProfileCollectionController.php b/app/Http/Controllers/User/ProfileCollectionController.php index 279d606a..fb35d9fe 100644 --- a/app/Http/Controllers/User/ProfileCollectionController.php +++ b/app/Http/Controllers/User/ProfileCollectionController.php @@ -116,9 +116,9 @@ class ProfileCollectionController extends Controller $seo = app(SeoFactory::class)->collectionPage( $collection->is_featured - ? sprintf('Featured: %s by %s — Skinbase Nova', $collection->title, $collection->displayOwnerName()) - : sprintf('%s by %s — Skinbase Nova', $collection->title, $collection->displayOwnerName()), - $collection->summary ?: $collection->description ?: sprintf('Explore the %s collection by %s on Skinbase Nova.', $collection->title, $collection->displayOwnerName()), + ? sprintf('Featured: %s by %s — Skinbase', $collection->title, $collection->displayOwnerName()) + : sprintf('%s by %s — Skinbase', $collection->title, $collection->displayOwnerName()), + $collection->summary ?: $collection->description ?: sprintf('Explore the %s collection by %s on Skinbase.', $collection->title, $collection->displayOwnerName()), $collectionPayload['public_url'], $collectionPayload['cover_image'], $collection->visibility === Collection::VISIBILITY_PUBLIC, @@ -202,8 +202,8 @@ class ProfileCollectionController extends Controller $seriesDescription = $seriesMeta['description']; $seo = app(SeoFactory::class)->collectionListing( - sprintf('Series: %s — Skinbase Nova', $seriesKey), - sprintf('Explore the %s collection series on Skinbase Nova.', $seriesKey), + sprintf('Series: %s — Skinbase', $seriesKey), + sprintf('Explore the %s collection series on Skinbase.', $seriesKey), route('collections.series.show', ['seriesKey' => $seriesKey]) )->toArray(); diff --git a/app/Http/Controllers/User/SavedCollectionController.php b/app/Http/Controllers/User/SavedCollectionController.php index b291007c..21fab76d 100644 --- a/app/Http/Controllers/User/SavedCollectionController.php +++ b/app/Http/Controllers/User/SavedCollectionController.php @@ -155,8 +155,8 @@ class SavedCollectionController extends Controller 'libraryUrl' => route('me.saved.collections'), 'browseUrl' => route('collections.featured'), 'seo' => [ - 'title' => $activeList ? sprintf('%s — Saved Collections — Skinbase Nova', $activeList->title) : 'Saved Collections — Skinbase Nova', - 'description' => $activeList ? sprintf('Saved collections in the %s list on Skinbase Nova.', $activeList->title) : 'Your saved collections on Skinbase Nova.', + 'title' => $activeList ? sprintf('%s — Saved Collections — Skinbase', $activeList->title) : 'Saved Collections — Skinbase', + 'description' => $activeList ? sprintf('Saved collections in the %s list on Skinbase.', $activeList->title) : 'Your saved collections on Skinbase.', 'canonical' => $activeList ? route('me.saved.collections.lists.show', ['listSlug' => $activeList->slug]) : route('me.saved.collections'), 'robots' => 'noindex,follow', ], diff --git a/app/Http/Controllers/Web/AccountHelpPageController.php b/app/Http/Controllers/Web/AccountHelpPageController.php index fb0c7bd7..45622919 100644 --- a/app/Http/Controllers/Web/AccountHelpPageController.php +++ b/app/Http/Controllers/Web/AccountHelpPageController.php @@ -18,7 +18,7 @@ final class AccountHelpPageController extends Controller $seo = app(SeoFactory::class) ->collectionPage( 'Account Settings Help — Skinbase', - 'Learn how account settings, profile settings, email changes, password care, and creator preferences work on Skinbase Nova.', + 'Learn how account settings, profile settings, email changes, password care, and creator preferences work on Skinbase.', $canonical, ) ->toArray(); diff --git a/app/Http/Controllers/Web/AuthHelpPageController.php b/app/Http/Controllers/Web/AuthHelpPageController.php index f96aefa4..7a828b1d 100644 --- a/app/Http/Controllers/Web/AuthHelpPageController.php +++ b/app/Http/Controllers/Web/AuthHelpPageController.php @@ -18,7 +18,7 @@ final class AuthHelpPageController extends Controller $seo = app(SeoFactory::class) ->collectionPage( 'Signup and Login Help — Skinbase', - 'Learn how signup, login, password recovery, verification, and account access work on Skinbase Nova, with clear guidance for common access problems and practical next steps.', + 'Learn how signup, login, password recovery, verification, and account access work on Skinbase, with clear guidance for common access problems and practical next steps.', $canonical, ) ->toArray(); @@ -27,7 +27,7 @@ final class AuthHelpPageController extends Controller return Inertia::render('Help/AuthHelpPage', [ 'title' => 'Signup & Login Help', - 'description' => 'Get clear help for account creation, sign-in, password recovery, verification basics, and common access problems on Skinbase Nova.', + 'description' => 'Get clear help for account creation, sign-in, password recovery, verification basics, and common access problems on Skinbase.', 'seo' => $seo, 'links' => [ 'help_home' => route('help'), diff --git a/app/Http/Controllers/Web/BrowseGalleryController.php b/app/Http/Controllers/Web/BrowseGalleryController.php index 48fa842c..629bbd78 100644 --- a/app/Http/Controllers/Web/BrowseGalleryController.php +++ b/app/Http/Controllers/Web/BrowseGalleryController.php @@ -184,7 +184,7 @@ class BrowseGalleryController extends \App\Http\Controllers\Controller (object) ['name' => 'Explore', 'url' => '/browse'], (object) ['name' => $contentType->name, 'url' => '/' . $contentSlug], ]), - 'page_title' => $contentType->name . ' – Skinbase Nova', + 'page_title' => $contentType->name . ' – Skinbase', 'page_meta_description' => $contentType->description ?? ('Discover the best ' . $contentType->name . ' artworks on Skinbase'), 'page_meta_keywords' => strtolower($contentType->slug) . ', skinbase, artworks, wallpapers, skins, photography', 'page_canonical' => $seo['canonical'], @@ -264,7 +264,7 @@ class BrowseGalleryController extends \App\Http\Controllers\Controller 'hero_title' => $category->name, 'hero_description' => $category->description ?? ($contentType->name . ' artworks on Skinbase.'), 'breadcrumbs' => $breadcrumbs, - 'page_title' => $category->name . ' – Skinbase Nova', + 'page_title' => $category->name . ' – Skinbase', 'page_meta_description' => $category->description ?? ('Discover the best ' . $category->name . ' ' . $contentType->name . ' artworks on Skinbase'), 'page_meta_keywords' => strtolower($contentType->slug) . ', skinbase, artworks, wallpapers, skins, photography', 'page_canonical' => $seo['canonical'], diff --git a/app/Http/Controllers/Web/CardsHelpPageController.php b/app/Http/Controllers/Web/CardsHelpPageController.php index bebcf194..e3260a3e 100644 --- a/app/Http/Controllers/Web/CardsHelpPageController.php +++ b/app/Http/Controllers/Web/CardsHelpPageController.php @@ -18,7 +18,7 @@ final class CardsHelpPageController extends Controller $seo = app(SeoFactory::class) ->collectionPage( 'Cards Help — Skinbase', - 'Learn what Cards are on Skinbase Nova, how they differ from artworks, posts, and collections, and how to create, publish, and use them effectively in personal and Group workflows.', + 'Learn what Cards are on Skinbase, how they differ from artworks, posts, and collections, and how to create, publish, and use them effectively in personal and Group workflows.', $canonical, ) ->toArray(); @@ -27,7 +27,7 @@ final class CardsHelpPageController extends Controller return Inertia::render('Help/CardsHelpPage', [ 'title' => 'Cards Help', - 'description' => 'Understand Cards as a distinct creative format on Skinbase Nova, with guidance for creation, publishing, ownership, design quality, and real-world use cases.', + 'description' => 'Understand Cards as a distinct creative format on Skinbase, with guidance for creation, publishing, ownership, design quality, and real-world use cases.', 'seo' => $seo, 'links' => [ 'help_home' => route('help'), diff --git a/app/Http/Controllers/Web/CollectionDiscoveryController.php b/app/Http/Controllers/Web/CollectionDiscoveryController.php index d87c70de..ae7f8792 100644 --- a/app/Http/Controllers/Web/CollectionDiscoveryController.php +++ b/app/Http/Controllers/Web/CollectionDiscoveryController.php @@ -52,9 +52,9 @@ class CollectionDiscoveryController extends Controller $results = $this->search->publicSearch($filters, (int) config('collections.v5.search.public_per_page', 18)); $seo = app(SeoFactory::class)->collectionListing( - 'Search Collections — Skinbase Nova', + 'Search Collections — Skinbase', filled($filters['q'] ?? null) - ? sprintf('Search results for "%s" across public Skinbase Nova collections.', $filters['q']) + ? sprintf('Search results for "%s" across public Skinbase collections.', $filters['q']) : 'Browse public collections using filters for category, style, theme, color, quality tier, freshness, and programming metadata.', $request->fullUrl(), null, @@ -65,7 +65,7 @@ class CollectionDiscoveryController extends Controller 'eyebrow' => 'Search', 'title' => 'Search collections', 'description' => filled($filters['q'] ?? null) - ? sprintf('Search results for "%s" across public Skinbase Nova collections.', $filters['q']) + ? sprintf('Search results for "%s" across public Skinbase collections.', $filters['q']) : 'Browse public collections using filters for category, style, theme, color, quality tier, freshness, and programming metadata.', 'seo' => $seo, 'collections' => $this->collections->mapCollectionCardPayloads($results->items(), false, $request->user()), @@ -100,7 +100,7 @@ class CollectionDiscoveryController extends Controller viewer: $request->user(), eyebrow: 'Discovery', title: 'Featured collections', - description: 'A rotating set of standout galleries from across Skinbase Nova. Some are meticulously hand-sequenced. Others are smart collections that stay fresh as the creator publishes new work.', + description: 'A rotating set of standout galleries from across Skinbase. Some are meticulously hand-sequenced. Others are smart collections that stay fresh as the creator publishes new work.', collections: $featuredCollections->isNotEmpty() ? $featuredCollections : $this->discovery->publicFeaturedCollections((int) config('collections.discovery.featured_limit', 18)), communityCollections: $this->discovery->publicCollectionsByType(Collection::TYPE_COMMUNITY, 6), editorialCollections: $this->discovery->publicCollectionsByType(Collection::TYPE_EDITORIAL, 6), @@ -204,7 +204,7 @@ class CollectionDiscoveryController extends Controller abort_if(! $program || collect($landing['collections'])->isEmpty(), 404); $seo = app(SeoFactory::class)->collectionListing( - sprintf('%s — Skinbase Nova', $program['label']), + sprintf('%s — Skinbase', $program['label']), $program['description'], route('collections.program.show', ['programKey' => $program['key']]), )->toArray(); @@ -239,7 +239,7 @@ class CollectionDiscoveryController extends Controller $campaign = null, ) { $seo = app(SeoFactory::class)->collectionListing( - sprintf('%s — Skinbase Nova', $title), + sprintf('%s — Skinbase', $title), $description, url()->current(), )->toArray(); diff --git a/app/Http/Controllers/Web/GroupFaqPageController.php b/app/Http/Controllers/Web/GroupFaqPageController.php index 402645a2..f89f05f4 100644 --- a/app/Http/Controllers/Web/GroupFaqPageController.php +++ b/app/Http/Controllers/Web/GroupFaqPageController.php @@ -18,7 +18,7 @@ final class GroupFaqPageController extends Controller $seo = app(SeoFactory::class) ->collectionPage( 'Groups FAQ — Skinbase', - 'Fast answers to the most common Groups questions on Skinbase Nova, including roles, permissions, publishing, contributor credit, invites, workflows, and troubleshooting.', + 'Fast answers to the most common Groups questions on Skinbase, including roles, permissions, publishing, contributor credit, invites, workflows, and troubleshooting.', $canonical, ) ->toArray(); @@ -27,7 +27,7 @@ final class GroupFaqPageController extends Controller return Inertia::render('Group/GroupFaqPage', [ 'title' => 'Groups FAQ', - 'description' => 'Quick answers about Groups, roles, permissions, publishing, contributor credit, invites, workflows, and troubleshooting on Skinbase Nova.', + 'description' => 'Quick answers about Groups, roles, permissions, publishing, contributor credit, invites, workflows, and troubleshooting on Skinbase.', 'seo' => $seo, 'links' => [ 'groups_directory' => route('groups.index'), diff --git a/app/Http/Controllers/Web/GroupHelpPageController.php b/app/Http/Controllers/Web/GroupHelpPageController.php index c4f2d3f4..c092ed93 100644 --- a/app/Http/Controllers/Web/GroupHelpPageController.php +++ b/app/Http/Controllers/Web/GroupHelpPageController.php @@ -18,7 +18,7 @@ final class GroupHelpPageController extends Controller $seo = app(SeoFactory::class) ->collectionPage( 'Groups Guide, Help, and Best Practices — Skinbase', - 'Learn how Groups work on Skinbase Nova, how shared publishing preserves contributor credit, and how to manage roles, releases, reviews, projects, and team workflows with confidence.', + 'Learn how Groups work on Skinbase, how shared publishing preserves contributor credit, and how to manage roles, releases, reviews, projects, and team workflows with confidence.', $canonical, ) ->toArray(); @@ -27,7 +27,7 @@ final class GroupHelpPageController extends Controller return Inertia::render('Group/GroupHelpPage', [ 'title' => 'Groups Help & Guide', - 'description' => 'Everything creators need to understand Groups, publish collaboratively, preserve contributor credit, and build a healthy shared identity on Skinbase Nova.', + 'description' => 'Everything creators need to understand Groups, publish collaboratively, preserve contributor credit, and build a healthy shared identity on Skinbase.', 'seo' => $seo, 'links' => [ 'groups_directory' => route('groups.index'), diff --git a/app/Http/Controllers/Web/GroupQuickstartPageController.php b/app/Http/Controllers/Web/GroupQuickstartPageController.php index 116de44d..03d3e016 100644 --- a/app/Http/Controllers/Web/GroupQuickstartPageController.php +++ b/app/Http/Controllers/Web/GroupQuickstartPageController.php @@ -18,7 +18,7 @@ final class GroupQuickstartPageController extends Controller $seo = app(SeoFactory::class) ->collectionPage( 'Groups Quickstart — Skinbase', - 'A fast, creator-friendly Groups quickstart for Skinbase Nova. Learn when to use a Group, create one, invite members, and publish your first Group artwork with correct contributor credit.', + 'A fast, creator-friendly Groups quickstart for Skinbase. Learn when to use a Group, create one, invite members, and publish your first Group artwork with correct contributor credit.', $canonical, ) ->toArray(); diff --git a/app/Http/Controllers/Web/HelpCenterPageController.php b/app/Http/Controllers/Web/HelpCenterPageController.php index 6650ca3a..e0c30fde 100644 --- a/app/Http/Controllers/Web/HelpCenterPageController.php +++ b/app/Http/Controllers/Web/HelpCenterPageController.php @@ -18,7 +18,7 @@ final class HelpCenterPageController extends Controller $seo = app(SeoFactory::class) ->collectionPage( 'Help Center — Skinbase', - 'Find help, guides, quickstarts, FAQs, and troubleshooting for Skinbase Nova, including Groups, Studio, Upload, Cards, Profile, and account access.', + 'Find help, guides, quickstarts, FAQs, and troubleshooting for Skinbase, including Groups, Studio, Upload, Cards, Profile, and account access.', $canonical, ) ->toArray(); @@ -27,7 +27,7 @@ final class HelpCenterPageController extends Controller return Inertia::render('Help/HelpCenterPage', [ 'title' => 'Help Center', - 'description' => 'Find guides, quickstarts, FAQs, and troubleshooting for Skinbase Nova in one structured help hub.', + 'description' => 'Find guides, quickstarts, FAQs, and troubleshooting for Skinbase in one structured help hub.', 'seo' => $seo, 'links' => [ 'studio_help' => route('help.studio'), diff --git a/app/Http/Controllers/Web/NovaCardsController.php b/app/Http/Controllers/Web/NovaCardsController.php index 2623e0fc..4e04676a 100644 --- a/app/Http/Controllers/Web/NovaCardsController.php +++ b/app/Http/Controllers/Web/NovaCardsController.php @@ -60,12 +60,12 @@ class NovaCardsController extends Controller return view('cards.index', [ 'meta' => [ - 'title' => 'Nova Cards - Skinbase Nova', - 'description' => 'Browse featured, trending, and latest Nova Cards. Discover beautiful quote cards, mood cards, and visual text art by the Skinbase Nova community.', + 'title' => 'Cards - Skinbase', + 'description' => 'Browse featured, trending, and latest Cards. Discover beautiful quote cards, mood cards, and visual text art by the Skinbase community.', 'canonical' => route('cards.index'), 'robots' => 'index,follow', ], - 'heading' => 'Nova Cards', + 'heading' => 'Cards', 'subheading' => (string) config('nova_cards.brand.subtitle'), 'cards' => $this->presenter->cards($latest->items()), 'pagination' => $latest, @@ -90,13 +90,13 @@ class NovaCardsController extends Controller return view('cards.index', [ 'meta' => [ - 'title' => $category->name . ' Cards - Skinbase Nova', - 'description' => $category->description ?: ('Browse ' . strtolower($category->name) . ' Nova Cards on Skinbase Nova.'), + 'title' => $category->name . ' Cards - Skinbase', + 'description' => $category->description ?: ('Browse ' . strtolower($category->name) . ' Cards on Skinbase.'), 'canonical' => route('cards.category', ['categorySlug' => $category->slug]), 'robots' => 'index,follow', ], 'heading' => $category->name, - 'subheading' => $category->description ?: 'Explore this Nova Cards category.', + 'subheading' => $category->description ?: 'Explore this Cards category.', 'cards' => $this->presenter->cards($cards->items()), 'pagination' => $cards, 'featuredCards' => [], @@ -119,8 +119,8 @@ class NovaCardsController extends Controller return view('cards.index', [ 'meta' => [ - 'title' => 'Popular Cards - Skinbase Nova', - 'description' => 'Browse the most liked, saved, and viewed Nova Cards on Skinbase Nova.', + 'title' => 'Popular Cards - Skinbase', + 'description' => 'Browse the most liked, saved, and viewed Cards on Skinbase.', 'canonical' => route('cards.popular'), 'robots' => 'index,follow', ], @@ -153,13 +153,13 @@ class NovaCardsController extends Controller return view('cards.index', [ 'meta' => [ - 'title' => 'Rising Cards - Skinbase Nova', - 'description' => 'Discover Nova Cards that are gaining traction right now — fresh creators and fast-rising saves and remixes.', + 'title' => 'Rising Cards - Skinbase', + 'description' => 'Discover Cards that are gaining traction right now — fresh creators and fast-rising saves and remixes.', 'canonical' => route('cards.rising'), 'robots' => 'index,follow', ], 'heading' => 'Rising', - 'subheading' => 'Fresh Nova Cards gaining momentum right now.', + 'subheading' => 'Fresh Cards gaining momentum right now.', 'cards' => $this->presenter->cards($paginated->items(), false, $request->user()), 'pagination' => $paginated, 'featuredCards' => [], @@ -182,13 +182,13 @@ class NovaCardsController extends Controller return view('cards.index', [ 'meta' => [ - 'title' => 'Remixed Cards - Skinbase Nova', - 'description' => 'Discover Nova Cards remixed from community originals with attribution and lineage.', + 'title' => 'Remixed Cards - Skinbase', + 'description' => 'Discover Cards remixed from community originals with attribution and lineage.', 'canonical' => route('cards.remixed'), 'robots' => 'index,follow', ], 'heading' => 'Remixed cards', - 'subheading' => 'Community reinterpretations linked back to their original Nova Cards.', + 'subheading' => 'Community reinterpretations linked back to their original Cards.', 'cards' => $this->presenter->cards($cards->items(), false, $request->user()), 'pagination' => $cards, 'featuredCards' => [], @@ -214,8 +214,8 @@ class NovaCardsController extends Controller return view('cards.index', [ 'meta' => [ - 'title' => 'Best Remixes - Skinbase Nova', - 'description' => 'Browse standout Nova Card remixes ranked by remix traction, saves, and likes.', + 'title' => 'Best Remixes - Skinbase', + 'description' => 'Browse standout Card remixes ranked by remix traction, saves, and likes.', 'canonical' => route('cards.remix-highlights'), 'robots' => 'index,follow', ], @@ -295,13 +295,13 @@ class NovaCardsController extends Controller return view('cards.index', [ 'meta' => [ - 'title' => 'Editorial Picks - Nova Cards - Skinbase Nova', - 'description' => 'Browse editorial Nova Cards picks, featured collections, and highlighted challenges.', + 'title' => 'Editorial Picks - Cards - Skinbase', + 'description' => 'Browse editorial Cards picks, featured collections, and highlighted challenges.', 'canonical' => route('cards.editorial'), 'robots' => 'index,follow', ], 'heading' => 'Editorial picks', - 'subheading' => 'Curated Nova Cards, featured collections, and standout challenge surfaces chosen for quality and cohesion.', + 'subheading' => 'Curated Cards, featured collections, and standout challenge surfaces chosen for quality and cohesion.', 'cards' => $this->presenter->cards($cards->items(), false, $request->user()), 'pagination' => $cards, 'featuredCards' => [], @@ -329,13 +329,13 @@ class NovaCardsController extends Controller return view('cards.index', [ 'meta' => [ - 'title' => 'Seasonal Cards - Nova Cards - Skinbase Nova', - 'description' => 'Browse seasonal and event-aware Nova Cards grouped by recurring moods, holidays, and time-of-year themes.', + 'title' => 'Seasonal Cards - Cards - Skinbase', + 'description' => 'Browse seasonal and event-aware Cards grouped by recurring moods, holidays, and time-of-year themes.', 'canonical' => route('cards.seasonal'), 'robots' => 'index,follow', ], 'heading' => 'Seasonal cards', - 'subheading' => 'Discover Nova Cards grouped by recurring seasonal and campaign-style themes.', + 'subheading' => 'Discover Cards grouped by recurring seasonal and campaign-style themes.', 'cards' => $this->presenter->cards($cards->items(), false, $request->user()), 'pagination' => $cards, 'featuredCards' => [], @@ -363,13 +363,13 @@ class NovaCardsController extends Controller return view('cards.challenges', [ 'meta' => [ - 'title' => 'Card Challenges - Skinbase Nova', - 'description' => 'Browse active and completed Nova Cards challenges, prompts, and winners.', + 'title' => 'Card Challenges - Skinbase', + 'description' => 'Browse active and completed Cards challenges, prompts, and winners.', 'canonical' => route('cards.challenges'), 'robots' => 'index,follow', ], 'heading' => 'Card challenges', - 'subheading' => 'Official prompts and community challenge runs for Nova Cards creators.', + 'subheading' => 'Official prompts and community challenge runs for Cards creators.', 'challenges' => $challenges, ]); } @@ -388,8 +388,8 @@ class NovaCardsController extends Controller return view('cards.challenges', [ 'meta' => [ - 'title' => $challenge->title . ' - Skinbase Nova', - 'description' => $challenge->description ?: 'Browse entries for this Nova Cards challenge.', + 'title' => $challenge->title . ' - Skinbase', + 'description' => $challenge->description ?: 'Browse entries for this Cards challenge.', 'canonical' => route('cards.challenges.show', ['slug' => $challenge->slug]), 'robots' => 'index,follow', ], @@ -410,8 +410,8 @@ class NovaCardsController extends Controller { return view('cards.resources', [ 'meta' => [ - 'title' => 'Template Packs - Skinbase Nova', - 'description' => 'Browse official Nova Cards template packs and starting points.', + 'title' => 'Template Packs - Skinbase', + 'description' => 'Browse official Cards template packs and starting points.', 'canonical' => route('cards.templates'), 'robots' => 'index,follow', ], @@ -427,13 +427,13 @@ class NovaCardsController extends Controller { return view('cards.resources', [ 'meta' => [ - 'title' => 'Asset Packs - Skinbase Nova', - 'description' => 'Browse official Nova Cards asset packs for decorative and editorial layouts.', + 'title' => 'Asset Packs - Skinbase', + 'description' => 'Browse official Cards asset packs for decorative and editorial layouts.', 'canonical' => route('cards.assets'), 'robots' => 'index,follow', ], 'heading' => 'Asset packs', - 'subheading' => 'Official decorative and editorial pack sets for the Nova Cards v2 editor.', + 'subheading' => 'Official decorative and editorial pack sets for the Cards v2 editor.', 'packs' => collect($this->presenter->options()['asset_packs'] ?? []), 'templates' => collect(), 'resourceType' => 'asset', @@ -447,8 +447,8 @@ class NovaCardsController extends Controller return view('cards.index', [ 'meta' => [ - 'title' => '#' . $tag->name . ' Cards - Skinbase Nova', - 'description' => 'Browse Nova Cards tagged with #' . $tag->name . ' on Skinbase Nova.', + 'title' => '#' . $tag->name . ' Cards - Skinbase', + 'description' => 'Browse Cards tagged with #' . $tag->name . ' on Skinbase.', 'canonical' => route('cards.tag', ['tagSlug' => $tag->slug]), 'robots' => 'index,follow', ], @@ -480,13 +480,13 @@ class NovaCardsController extends Controller return view('cards.index', [ 'meta' => [ - 'title' => $mood['label'] . ' Mood Cards - Skinbase Nova', - 'description' => 'Browse Nova Cards grouped into the ' . strtolower((string) $mood['label']) . ' mood family on Skinbase Nova.', + 'title' => $mood['label'] . ' Mood Cards - Skinbase', + 'description' => 'Browse Cards grouped into the ' . strtolower((string) $mood['label']) . ' mood family on Skinbase.', 'canonical' => route('cards.mood', ['moodSlug' => $mood['key']]), 'robots' => 'index,follow', ], 'heading' => $mood['label'], - 'subheading' => 'Discover Nova Cards grouped by a curated mood family using durable tag mappings.', + 'subheading' => 'Discover Cards grouped by a curated mood family using durable tag mappings.', 'cards' => $this->presenter->cards($cards->items(), false, $request->user()), 'pagination' => $cards, 'featuredCards' => [], @@ -514,13 +514,13 @@ class NovaCardsController extends Controller return view('cards.index', [ 'meta' => [ - 'title' => $style['label'] . ' Style Cards - Skinbase Nova', - 'description' => 'Browse Nova Cards using the ' . strtolower((string) $style['label']) . ' style family on Skinbase Nova.', + 'title' => $style['label'] . ' Style Cards - Skinbase', + 'description' => 'Browse Cards using the ' . strtolower((string) $style['label']) . ' style family on Skinbase.', 'canonical' => route('cards.style', ['styleSlug' => $style['key']]), 'robots' => 'index,follow', ], 'heading' => $style['label'], - 'subheading' => 'Discover Nova Cards grouped by a shared visual style family.', + 'subheading' => 'Discover Cards grouped by a shared visual style family.', 'cards' => $this->presenter->cards($cards->items(), false, $request->user()), 'pagination' => $cards, 'featuredCards' => [], @@ -548,13 +548,13 @@ class NovaCardsController extends Controller return view('cards.index', [ 'meta' => [ - 'title' => $palette['label'] . ' Palette Cards - Skinbase Nova', - 'description' => 'Browse Nova Cards using the ' . strtolower((string) $palette['label']) . ' palette family on Skinbase Nova.', + 'title' => $palette['label'] . ' Palette Cards - Skinbase', + 'description' => 'Browse Cards using the ' . strtolower((string) $palette['label']) . ' palette family on Skinbase.', 'canonical' => route('cards.palette', ['paletteSlug' => $palette['key']]), 'robots' => 'index,follow', ], 'heading' => $palette['label'], - 'subheading' => 'Discover Nova Cards grouped by shared palette families and color direction.', + 'subheading' => 'Discover Cards grouped by shared palette families and color direction.', 'cards' => $this->presenter->cards($cards->items(), false, $request->user()), 'pagination' => $cards, 'featuredCards' => [], @@ -580,8 +580,8 @@ class NovaCardsController extends Controller return view('cards.index', array_merge($this->creatorPagePayload($request, $user), [ 'meta' => [ - 'title' => '@' . $user->username . ' Cards - Skinbase Nova', - 'description' => 'Browse Nova Cards created by @' . $user->username . ' on Skinbase Nova.', + 'title' => '@' . $user->username . ' Cards - Skinbase', + 'description' => 'Browse Cards created by @' . $user->username . ' on Skinbase.', 'canonical' => route('cards.creator', ['username' => strtolower((string) $user->username)]), 'robots' => 'index,follow', ], @@ -602,13 +602,13 @@ class NovaCardsController extends Controller return view('cards.index', array_merge($this->creatorPagePayload($request, $user), [ 'meta' => [ - 'title' => '@' . $user->username . ' Portfolio - Skinbase Nova', - 'description' => 'Browse the dedicated Nova Cards portfolio page for @' . $user->username . ' on Skinbase Nova.', + 'title' => '@' . $user->username . ' Portfolio - Skinbase', + 'description' => 'Browse the dedicated Cards portfolio page for @' . $user->username . ' on Skinbase.', 'canonical' => route('cards.creator.portfolio', ['username' => strtolower((string) $user->username)]), 'robots' => 'index,follow', ], 'heading' => '@' . $user->username . ' Portfolio', - 'subheading' => 'A dedicated Nova Cards portfolio view for ' . ($user->name ?: '@' . $user->username) . '.', + 'subheading' => 'A dedicated Cards portfolio view for ' . ($user->name ?: '@' . $user->username) . '.', 'context' => 'creator-portfolio', ])); } @@ -695,8 +695,8 @@ class NovaCardsController extends Controller return view('cards.collection', [ 'meta' => [ - 'title' => $collection->name . ' - Nova Cards Collection - Skinbase Nova', - 'description' => $collection->description ?: 'Browse this curated Nova Cards collection.', + 'title' => $collection->name . ' - Cards Collection - Skinbase', + 'description' => $collection->description ?: 'Browse this curated Cards collection.', 'canonical' => route('cards.collections.show', ['slug' => $collection->slug, 'id' => $collection->id]), 'robots' => 'index,follow', ], @@ -721,7 +721,7 @@ class NovaCardsController extends Controller return view('cards.lineage', [ 'meta' => [ - 'title' => $card->title . ' Lineage - Nova Cards - Skinbase Nova', + 'title' => $card->title . ' Lineage - Cards - Skinbase', 'description' => 'Browse the remix lineage and related variants for this Nova Card.', 'canonical' => route('cards.lineage', ['slug' => $card->slug, 'id' => $card->id]), 'robots' => 'index,follow', @@ -767,7 +767,7 @@ class NovaCardsController extends Controller return view('cards.show', [ 'card' => $this->presenter->card($card, true, $request->user()), 'meta' => [ - 'title' => $card->title . ' - Nova Cards - Skinbase Nova', + 'title' => $card->title . ' - Cards - Skinbase', 'description' => $card->description ?: $card->quote_text, 'canonical' => route('cards.show', ['slug' => $card->slug, 'id' => $card->id]), 'robots' => $card->visibility === NovaCard::VISIBILITY_PUBLIC ? 'index,follow' : 'noindex,follow', diff --git a/app/Http/Controllers/Web/ProfileHelpPageController.php b/app/Http/Controllers/Web/ProfileHelpPageController.php index 348680d5..2919244b 100644 --- a/app/Http/Controllers/Web/ProfileHelpPageController.php +++ b/app/Http/Controllers/Web/ProfileHelpPageController.php @@ -18,7 +18,7 @@ final class ProfileHelpPageController extends Controller $seo = app(SeoFactory::class) ->collectionPage( 'Profile Help — Skinbase', - 'Learn how profiles work on Skinbase Nova, how they differ from Groups, and how to build a stronger personal identity with better setup, presentation, and creator-facing profile habits.', + 'Learn how profiles work on Skinbase, how they differ from Groups, and how to build a stronger personal identity with better setup, presentation, and creator-facing profile habits.', $canonical, ) ->toArray(); diff --git a/app/Http/Controllers/Web/StudioHelpPageController.php b/app/Http/Controllers/Web/StudioHelpPageController.php index 0fec3be3..6d056753 100644 --- a/app/Http/Controllers/Web/StudioHelpPageController.php +++ b/app/Http/Controllers/Web/StudioHelpPageController.php @@ -18,7 +18,7 @@ final class StudioHelpPageController extends Controller $seo = app(SeoFactory::class) ->collectionPage( 'Studio Help — Skinbase', - 'Learn how Studio works on Skinbase Nova, including drafts, publishing, personal versus Group context, artworks, cards, collections, and collaboration workflows.', + 'Learn how Studio works on Skinbase, including drafts, publishing, personal versus Group context, artworks, cards, collections, and collaboration workflows.', $canonical, ) ->toArray(); @@ -27,7 +27,7 @@ final class StudioHelpPageController extends Controller return Inertia::render('Help/StudioHelpPage', [ 'title' => 'Studio Help', - 'description' => 'Understand Studio as the creative control center of Skinbase Nova, with guidance for drafts, publishing, artworks, cards, collections, and Group workflows.', + 'description' => 'Understand Studio as the creative control center of Skinbase, with guidance for drafts, publishing, artworks, cards, collections, and Group workflows.', 'seo' => $seo, 'links' => [ 'help_home' => route('help'), diff --git a/app/Http/Controllers/Web/TroubleshootingHelpPageController.php b/app/Http/Controllers/Web/TroubleshootingHelpPageController.php index 9e623531..e35a5c48 100644 --- a/app/Http/Controllers/Web/TroubleshootingHelpPageController.php +++ b/app/Http/Controllers/Web/TroubleshootingHelpPageController.php @@ -18,7 +18,7 @@ final class TroubleshootingHelpPageController extends Controller $seo = app(SeoFactory::class) ->collectionPage( 'Troubleshooting Help — Skinbase', - 'Use fast, support-oriented troubleshooting guidance for login issues, permissions confusion, publishing blockers, profile setup problems, and bug-report escalation on Skinbase Nova.', + 'Use fast, support-oriented troubleshooting guidance for login issues, permissions confusion, publishing blockers, profile setup problems, and bug-report escalation on Skinbase.', $canonical, ) ->toArray(); diff --git a/app/Http/Controllers/Web/UploadHelpPageController.php b/app/Http/Controllers/Web/UploadHelpPageController.php index e67a6733..25395d96 100644 --- a/app/Http/Controllers/Web/UploadHelpPageController.php +++ b/app/Http/Controllers/Web/UploadHelpPageController.php @@ -18,7 +18,7 @@ final class UploadHelpPageController extends Controller $seo = app(SeoFactory::class) ->collectionPage( 'Upload Help — Skinbase', - 'Learn how uploading works on Skinbase Nova, including draft creation, metadata review, previews, personal versus Group context, contributor credit, publishing, and troubleshooting.', + 'Learn how uploading works on Skinbase, including draft creation, metadata review, previews, personal versus Group context, contributor credit, publishing, and troubleshooting.', $canonical, ) ->toArray(); @@ -27,7 +27,7 @@ final class UploadHelpPageController extends Controller return Inertia::render('Help/UploadHelpPage', [ 'title' => 'Upload Help', - 'description' => 'Understand the full upload workflow on Skinbase Nova, from file submission and draft creation to metadata review, contributor credit, and final publish.', + 'description' => 'Understand the full upload workflow on Skinbase, from file submission and draft creation to metadata review, contributor credit, and final publish.', 'seo' => $seo, 'links' => [ 'help_home' => route('help'), diff --git a/app/Http/Controllers/Web/WorldController.php b/app/Http/Controllers/Web/WorldController.php index 9ac3ddde..391c2eda 100644 --- a/app/Http/Controllers/Web/WorldController.php +++ b/app/Http/Controllers/Web/WorldController.php @@ -22,7 +22,7 @@ final class WorldController extends Controller { $payload = $this->worlds->publicIndexPayload($request->user()); $seo = app(SeoFactory::class)->collectionListing( - 'Worlds — Skinbase Nova', + 'Worlds — Skinbase', $payload['description'], route('worlds.index'), )->toArray(); @@ -45,8 +45,8 @@ final class WorldController extends Controller $payload = $this->worlds->publicShowPayload($resolvedWorld, $request->user()); $seo = app(SeoFactory::class)->collectionPage( - $resolvedWorld->seo_title ?: ($resolvedWorld->title . ' — Skinbase Nova'), - $resolvedWorld->seo_description ?: ($resolvedWorld->summary ?: $resolvedWorld->description ?: 'Seasonal and editorial discovery world on Skinbase Nova.'), + $resolvedWorld->seo_title ?: ($resolvedWorld->title . ' — Skinbase'), + $resolvedWorld->seo_description ?: ($resolvedWorld->summary ?: $resolvedWorld->description ?: 'Seasonal and editorial discovery world on Skinbase.'), $this->worlds->canonicalPublicUrl($resolvedWorld), $resolvedWorld->ogImageUrl(), )->toArray(); @@ -69,8 +69,8 @@ final class WorldController extends Controller $payload = $this->worlds->publicShowPayload($resolvedWorld, $request->user()); $seo = app(SeoFactory::class)->collectionPage( - $resolvedWorld->seo_title ?: ($resolvedWorld->title . ' — Skinbase Nova'), - $resolvedWorld->seo_description ?: ($resolvedWorld->summary ?: $resolvedWorld->description ?: 'Seasonal and editorial discovery world on Skinbase Nova.'), + $resolvedWorld->seo_title ?: ($resolvedWorld->title . ' — Skinbase'), + $resolvedWorld->seo_description ?: ($resolvedWorld->summary ?: $resolvedWorld->description ?: 'Seasonal and editorial discovery world on Skinbase.'), $this->worlds->canonicalPublicUrl($resolvedWorld), $resolvedWorld->ogImageUrl(), )->toArray(); diff --git a/app/Http/Controllers/Web/WorldsHelpPageController.php b/app/Http/Controllers/Web/WorldsHelpPageController.php index 26d0b0f4..a809bf19 100644 --- a/app/Http/Controllers/Web/WorldsHelpPageController.php +++ b/app/Http/Controllers/Web/WorldsHelpPageController.php @@ -18,7 +18,7 @@ final class WorldsHelpPageController extends Controller $seo = app(SeoFactory::class) ->collectionPage( 'Worlds Help — Skinbase', - 'Learn how Worlds work on Skinbase Nova, including editorial purpose, attached content, section control, preview, publishing, recurrence, and homepage promotion.', + 'Learn how Worlds work on Skinbase, including editorial purpose, attached content, section control, preview, publishing, recurrence, and homepage promotion.', $canonical, ) ->toArray(); @@ -27,7 +27,7 @@ final class WorldsHelpPageController extends Controller return Inertia::render('Help/WorldsHelpPage', [ 'title' => 'Worlds Help', - 'description' => 'A complete guide to creating, attaching content to, previewing, and publishing Worlds on Skinbase Nova.', + 'description' => 'A complete guide to creating, attaching content to, previewing, and publishing Worlds on Skinbase.', 'seo' => $seo, 'links' => [ 'help_home' => route('help'), diff --git a/app/Jobs/GenerateArtworkEmbeddingJob.php b/app/Jobs/GenerateArtworkEmbeddingJob.php index 521efc4b..ecadd2b9 100644 --- a/app/Jobs/GenerateArtworkEmbeddingJob.php +++ b/app/Jobs/GenerateArtworkEmbeddingJob.php @@ -48,7 +48,7 @@ final class GenerateArtworkEmbeddingJob implements ShouldQueue public function handle( ArtworkEmbeddingClient $client, ArtworkVisionImageUrl $imageUrlBuilder, - VectorService|ArtworkVectorIndexService $vectors, + ArtworkVectorIndexService $vectors, ): void { if (! (bool) config('recommendations.embedding.enabled', true)) { @@ -128,7 +128,7 @@ final class GenerateArtworkEmbeddingJob implements ShouldQueue } private function upsertVectorIndex( - VectorService|ArtworkVectorIndexService $vectors, + ArtworkVectorIndexService $vectors, Artwork $artwork ): void { diff --git a/app/Services/AiBiography/AiBiographyPromptBuilder.php b/app/Services/AiBiography/AiBiographyPromptBuilder.php index dc69f395..d36ddb96 100644 --- a/app/Services/AiBiography/AiBiographyPromptBuilder.php +++ b/app/Services/AiBiography/AiBiographyPromptBuilder.php @@ -25,7 +25,7 @@ final class AiBiographyPromptBuilder private const MIN_WORDS = 30; private const SYSTEM_PROMPT = <<<'PROMPT' -You are a concise writing assistant for Skinbase Nova, a digital art platform. +You are a concise writing assistant for Skinbase, a digital art platform. Write short creator biographies using only the facts provided. Use a polished, factual, and slightly editorial tone. @@ -44,7 +44,7 @@ Rules: PROMPT; private const SYSTEM_PROMPT_STRICT = <<<'PROMPT' -You are a cautious writing assistant for Skinbase Nova, a digital art platform. +You are a cautious writing assistant for Skinbase, a digital art platform. Write a short, safe creator biography using only the facts provided. Be conservative. @@ -59,7 +59,7 @@ Rules: PROMPT; private const SYSTEM_PROMPT_SPARSE = <<<'PROMPT' -You are a cautious writing assistant for Skinbase Nova, a digital art platform. +You are a cautious writing assistant for Skinbase, a digital art platform. Write a short, modest creator introduction using only the facts provided. @@ -75,7 +75,7 @@ Rules: PROMPT; private const SYSTEM_PROMPT_SPARSE_STRICT = <<<'PROMPT' -You are a cautious writing assistant for Skinbase Nova, a digital art platform. +You are a cautious writing assistant for Skinbase, a digital art platform. Write a short, modest creator introduction using only the facts provided. Be conservative and precise. diff --git a/app/Services/CollectionAiCurationService.php b/app/Services/CollectionAiCurationService.php index 076f4593..bc4cacee 100644 --- a/app/Services/CollectionAiCurationService.php +++ b/app/Services/CollectionAiCurationService.php @@ -75,7 +75,7 @@ class CollectionAiCurationService ); $seo = sprintf( - '%s on Skinbase Nova: %d curated artworks%s.', + '%s on Skinbase: %d curated artworks%s.', $this->draftString($collection, $draft, 'title') ?: $collection->title, $context['artworks_count'], $context['theme_sentence'] !== '' ? ' exploring ' . $context['theme_sentence'] : '' diff --git a/app/Services/Images/ArtworkSquareThumbnailBackfillService.php b/app/Services/Images/ArtworkSquareThumbnailBackfillService.php index 2cdaee71..3b5d8952 100644 --- a/app/Services/Images/ArtworkSquareThumbnailBackfillService.php +++ b/app/Services/Images/ArtworkSquareThumbnailBackfillService.php @@ -238,7 +238,7 @@ final class ArtworkSquareThumbnailBackfillService 'timeout' => 30, 'ignore_errors' => true, 'header' => implode("\r\n", [ - 'User-Agent: Skinbase Nova square-thumb backfill', + 'User-Agent: Skinbase square-thumb backfill', 'Accept: image/*,*/*;q=0.8', 'Accept-Encoding: identity', 'Connection: close', diff --git a/app/Services/Ranking/ArtworkRankingService.php b/app/Services/Ranking/ArtworkRankingService.php index f07b3910..ab8f0a67 100644 --- a/app/Services/Ranking/ArtworkRankingService.php +++ b/app/Services/Ranking/ArtworkRankingService.php @@ -9,7 +9,7 @@ use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Schema; /** - * ArtworkRankingService — Skinbase Nova Ranking Engine V2 + * ArtworkRankingService — Skinbase Ranking Engine V2 * * Intelligent scoring system combining: * 1. Base engagement (views, downloads, favourites, comments, shares) diff --git a/app/Services/RankingService.php b/app/Services/RankingService.php index 9f90b113..f84c3961 100644 --- a/app/Services/RankingService.php +++ b/app/Services/RankingService.php @@ -11,7 +11,7 @@ use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Log; /** - * RankingService — Skinbase Nova rank_v2 + * RankingService — Skinbase rank_v2 * * Responsibilities: * 1. Score computation — turn raw artwork signals into three float scores. diff --git a/app/Services/Sitemaps/Builders/GoogleNewsSitemapBuilder.php b/app/Services/Sitemaps/Builders/GoogleNewsSitemapBuilder.php index 385a0dc0..66f5f5a9 100644 --- a/app/Services/Sitemaps/Builders/GoogleNewsSitemapBuilder.php +++ b/app/Services/Sitemaps/Builders/GoogleNewsSitemapBuilder.php @@ -33,7 +33,7 @@ final class GoogleNewsSitemapBuilder extends AbstractSitemapBuilder route('news.show', ['slug' => $article->slug]), trim((string) $article->title), $article->published_at, - (string) \config('sitemaps.news.google_publication_name', 'Skinbase Nova'), + (string) \config('sitemaps.news.google_publication_name', 'Skinbase'), (string) \config('sitemaps.news.google_language', 'en'), ); }) diff --git a/bootstrap/ssr/ssr.js b/bootstrap/ssr/ssr.js index 2616fd91..a70a5ce3 100644 --- a/bootstrap/ssr/ssr.js +++ b/bootstrap/ssr/ssr.js @@ -14042,7 +14042,7 @@ function HomepageAnnouncement({ announcement, mode = "live" }) { className: "inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/[0.06] px-4 py-2 text-sm font-semibold text-white/90 transition hover:border-white/20 hover:bg-white/[0.1]" }, /* @__PURE__ */ React.createElement("span", { "aria-hidden": "true" }, "✨"), - /* @__PURE__ */ React.createElement("span", null, "Show Skinbase Nova announcement") + /* @__PURE__ */ React.createElement("span", null, "Show Skinbase announcement") ))); } return /* @__PURE__ */ React.createElement("section", { className: "px-4 pt-8 sm:px-6 lg:px-8" }, /* @__PURE__ */ React.createElement("div", { className: "mx-auto max-w-7xl" }, /* @__PURE__ */ React.createElement("div", { className: cx$b("relative overflow-hidden rounded-[2rem] border shadow-[0_28px_90px_rgba(0,0,0,0.35)]", preset.shell) }, announcement.background_image_url ? /* @__PURE__ */ React.createElement("div", { className: "absolute inset-0" }, /* @__PURE__ */ React.createElement("img", { src: announcement.background_image_url, alt: "", className: "h-full w-full object-cover" }), /* @__PURE__ */ React.createElement("div", { className: "absolute inset-0 bg-slate-950", style: { opacity: overlayOpacity / 100 } })) : null, /* @__PURE__ */ React.createElement("div", { className: cx$b("pointer-events-none absolute inset-0 bg-gradient-to-br", preset.glow) }), /* @__PURE__ */ React.createElement("div", { className: "pointer-events-none absolute inset-0 bg-[linear-gradient(180deg,rgba(255,255,255,0.06),transparent_22%,rgba(2,6,23,0.15)_100%)]" }), announcement.is_dismissible && isLiveMode ? /* @__PURE__ */ React.createElement( @@ -29312,7 +29312,7 @@ function NovaConfirmDialog({ "aria-labelledby": "nova-confirm-title", className: "w-full max-w-md overflow-hidden rounded-3xl border border-white/10 bg-[linear-gradient(180deg,rgba(16,22,34,0.98),rgba(8,12,19,0.98))] shadow-[0_30px_80px_rgba(0,0,0,0.55)]" }, - /* @__PURE__ */ React.createElement("div", { className: "border-b border-white/[0.06] bg-white/[0.02] px-6 py-5" }, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.24em] text-white/35" }, "Skinbase Nova"), /* @__PURE__ */ React.createElement("h3", { id: "nova-confirm-title", className: "mt-2 text-lg font-semibold text-white" }, title)), + /* @__PURE__ */ React.createElement("div", { className: "border-b border-white/[0.06] bg-white/[0.02] px-6 py-5" }, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.24em] text-white/35" }, "Skinbase"), /* @__PURE__ */ React.createElement("h3", { id: "nova-confirm-title", className: "mt-2 text-lg font-semibold text-white" }, title)), /* @__PURE__ */ React.createElement("div", { className: "px-6 py-5" }, message ? /* @__PURE__ */ React.createElement("p", { className: "text-sm leading-6 text-white/70" }, message) : null, children ? /* @__PURE__ */ React.createElement("div", { className: message ? "mt-4" : "" }, children) : null), /* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-end gap-3 border-t border-white/[0.06] px-6 py-4" }, /* @__PURE__ */ React.createElement( "button", @@ -62786,7 +62786,7 @@ function CollectionAnalytics() { const range2 = analytics.range || {}; const topArtworks = Array.isArray(analytics.top_artworks) ? analytics.top_artworks : []; const seo = props.seo || {}; - return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Se, null, /* @__PURE__ */ React.createElement("title", null, seo.title || `${collection.title || "Collection"} Analytics — Skinbase Nova`), /* @__PURE__ */ React.createElement("meta", { name: "description", content: seo.description || "Collection analytics overview." }), seo.canonical ? /* @__PURE__ */ React.createElement("link", { rel: "canonical", href: seo.canonical }) : null, /* @__PURE__ */ React.createElement("meta", { name: "robots", content: seo.robots || "noindex,follow" })), /* @__PURE__ */ React.createElement("div", { className: "relative min-h-screen overflow-hidden pb-16" }, /* @__PURE__ */ React.createElement("div", { "aria-hidden": "true", className: "pointer-events-none absolute inset-x-0 top-0 -z-10 h-[32rem] opacity-95", style: { background: "radial-gradient(circle at 14% 14%, rgba(56,189,248,0.18), transparent 26%), radial-gradient(circle at 86% 18%, rgba(16,185,129,0.16), transparent 24%), linear-gradient(180deg, #07101d 0%, #0a1220 42%, #08111f 100%)" } }), /* @__PURE__ */ React.createElement("div", { "aria-hidden": "true", className: "pointer-events-none absolute inset-0 -z-10 opacity-[0.05]", style: { backgroundImage: "url(/gfx/noise.png)", backgroundSize: "180px" } }), /* @__PURE__ */ React.createElement("div", { className: "mx-auto max-w-7xl px-4 pt-8 md:px-6" }, /* @__PURE__ */ React.createElement("div", { className: "flex flex-wrap items-center gap-3 text-sm text-slate-300" }, props.dashboardUrl ? /* @__PURE__ */ React.createElement("a", { href: props.dashboardUrl, className: "inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/[0.04] px-4 py-2 transition hover:bg-white/[0.07] hover:text-white" }, /* @__PURE__ */ React.createElement("i", { className: "fa-solid fa-arrow-left fa-fw text-[11px]" }), "Dashboard") : null, props.historyUrl ? /* @__PURE__ */ React.createElement("a", { href: props.historyUrl, className: "inline-flex items-center gap-2 rounded-full border border-sky-300/20 bg-sky-400/10 px-4 py-2 font-semibold text-sky-100 transition hover:bg-sky-400/15" }, /* @__PURE__ */ React.createElement("i", { className: "fa-solid fa-timeline fa-fw text-[11px]" }), "History") : null, collection.manage_url ? /* @__PURE__ */ React.createElement("a", { href: collection.manage_url, className: "inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/[0.04] px-4 py-2 transition hover:bg-white/[0.07] hover:text-white" }, /* @__PURE__ */ React.createElement("i", { className: "fa-solid fa-pen-to-square fa-fw text-[11px]" }), "Manage") : null), /* @__PURE__ */ React.createElement("section", { className: "mt-6 rounded-[34px] border border-white/10 bg-white/[0.04] p-6 shadow-[0_30px_90px_rgba(2,6,23,0.28)] backdrop-blur-sm md:p-8" }, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.22em] text-sky-200/80" }, "Performance"), /* @__PURE__ */ React.createElement("h1", { className: "mt-3 text-4xl font-semibold tracking-[-0.05em] text-white md:text-5xl" }, collection.title || "Collection analytics"), /* @__PURE__ */ React.createElement("p", { className: "mt-4 max-w-3xl text-sm leading-relaxed text-slate-300 md:text-[15px]" }, "Review activity velocity, audience response, and the artworks carrying the most discovery value over the last ", range2.days || 30, " days.")), /* @__PURE__ */ React.createElement("section", { className: "mt-8 grid gap-5 md:grid-cols-2 xl:grid-cols-3" }, /* @__PURE__ */ React.createElement(MetricCard$1, { label: "Views", value: totals.views, delta: range2.views_delta, icon: "fa-eye" }), /* @__PURE__ */ React.createElement(MetricCard$1, { label: "Likes", value: totals.likes, delta: range2.likes_delta, icon: "fa-heart" }), /* @__PURE__ */ React.createElement(MetricCard$1, { label: "Follows", value: totals.follows, delta: range2.follows_delta, icon: "fa-bell" }), /* @__PURE__ */ React.createElement(MetricCard$1, { label: "Saves", value: totals.saves, delta: range2.saves_delta, icon: "fa-bookmark" }), /* @__PURE__ */ React.createElement(MetricCard$1, { label: "Comments", value: totals.comments, delta: range2.comments_delta, icon: "fa-comments" }), /* @__PURE__ */ React.createElement(MetricCard$1, { label: "Submissions", value: totals.submissions, delta: totals.submissions, icon: "fa-inbox" })), /* @__PURE__ */ React.createElement("div", { className: "mt-8 space-y-6" }, /* @__PURE__ */ React.createElement(TimelineChart, { timeline: analytics.timeline }), /* @__PURE__ */ React.createElement("section", { className: "rounded-[32px] border border-white/10 bg-white/[0.04] p-6 backdrop-blur-sm md:p-7" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-between gap-3" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.22em] text-sky-200/80" }, "Artworks"), /* @__PURE__ */ React.createElement("h2", { className: "mt-2 text-2xl font-semibold text-white" }, "Top artwork drivers")), /* @__PURE__ */ React.createElement("span", { className: "rounded-full border border-white/10 bg-white/[0.04] px-3 py-1 text-xs font-semibold text-slate-300" }, topArtworks.length)), topArtworks.length ? /* @__PURE__ */ React.createElement("div", { className: "mt-6 grid gap-4 md:grid-cols-2 xl:grid-cols-4" }, topArtworks.map((artwork) => /* @__PURE__ */ React.createElement("div", { key: artwork.id, className: "overflow-hidden rounded-[24px] border border-white/10 bg-slate-950/40" }, /* @__PURE__ */ React.createElement("div", { className: "aspect-square bg-slate-950/60" }, artwork.thumb ? /* @__PURE__ */ React.createElement("img", { src: artwork.thumb, alt: artwork.title, className: "h-full w-full object-cover" }) : /* @__PURE__ */ React.createElement("div", { className: "flex h-full w-full items-center justify-center text-slate-500" }, /* @__PURE__ */ React.createElement("i", { className: "fa-solid fa-image text-3xl" }))), /* @__PURE__ */ React.createElement("div", { className: "space-y-2 p-4" }, /* @__PURE__ */ React.createElement("div", { className: "truncate text-sm font-semibold text-white" }, artwork.title), /* @__PURE__ */ React.createElement("div", { className: "grid grid-cols-2 gap-2 text-xs text-slate-300" }, /* @__PURE__ */ React.createElement("div", { className: "rounded-2xl border border-white/10 bg-white/[0.04] px-3 py-2" }, "Views: ", Number(artwork.views || 0).toLocaleString()), /* @__PURE__ */ React.createElement("div", { className: "rounded-2xl border border-white/10 bg-white/[0.04] px-3 py-2" }, "Favs: ", Number(artwork.favourites || 0).toLocaleString()), /* @__PURE__ */ React.createElement("div", { className: "rounded-2xl border border-white/10 bg-white/[0.04] px-3 py-2" }, "Shares: ", Number(artwork.shares || 0).toLocaleString()), /* @__PURE__ */ React.createElement("div", { className: "rounded-2xl border border-white/10 bg-white/[0.04] px-3 py-2" }, "Rank: ", Number(artwork.ranking_score || 0).toFixed(1))))))) : /* @__PURE__ */ React.createElement("div", { className: "mt-6 rounded-[24px] border border-dashed border-white/12 bg-white/[0.03] px-6 py-12 text-sm text-slate-300" }, "Attach or publish more artworks before artwork-level ranking can be surfaced here.")))))); + return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Se, null, /* @__PURE__ */ React.createElement("title", null, seo.title || `${collection.title || "Collection"} Analytics — Skinbase`), /* @__PURE__ */ React.createElement("meta", { name: "description", content: seo.description || "Collection analytics overview." }), seo.canonical ? /* @__PURE__ */ React.createElement("link", { rel: "canonical", href: seo.canonical }) : null, /* @__PURE__ */ React.createElement("meta", { name: "robots", content: seo.robots || "noindex,follow" })), /* @__PURE__ */ React.createElement("div", { className: "relative min-h-screen overflow-hidden pb-16" }, /* @__PURE__ */ React.createElement("div", { "aria-hidden": "true", className: "pointer-events-none absolute inset-x-0 top-0 -z-10 h-[32rem] opacity-95", style: { background: "radial-gradient(circle at 14% 14%, rgba(56,189,248,0.18), transparent 26%), radial-gradient(circle at 86% 18%, rgba(16,185,129,0.16), transparent 24%), linear-gradient(180deg, #07101d 0%, #0a1220 42%, #08111f 100%)" } }), /* @__PURE__ */ React.createElement("div", { "aria-hidden": "true", className: "pointer-events-none absolute inset-0 -z-10 opacity-[0.05]", style: { backgroundImage: "url(/gfx/noise.png)", backgroundSize: "180px" } }), /* @__PURE__ */ React.createElement("div", { className: "mx-auto max-w-7xl px-4 pt-8 md:px-6" }, /* @__PURE__ */ React.createElement("div", { className: "flex flex-wrap items-center gap-3 text-sm text-slate-300" }, props.dashboardUrl ? /* @__PURE__ */ React.createElement("a", { href: props.dashboardUrl, className: "inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/[0.04] px-4 py-2 transition hover:bg-white/[0.07] hover:text-white" }, /* @__PURE__ */ React.createElement("i", { className: "fa-solid fa-arrow-left fa-fw text-[11px]" }), "Dashboard") : null, props.historyUrl ? /* @__PURE__ */ React.createElement("a", { href: props.historyUrl, className: "inline-flex items-center gap-2 rounded-full border border-sky-300/20 bg-sky-400/10 px-4 py-2 font-semibold text-sky-100 transition hover:bg-sky-400/15" }, /* @__PURE__ */ React.createElement("i", { className: "fa-solid fa-timeline fa-fw text-[11px]" }), "History") : null, collection.manage_url ? /* @__PURE__ */ React.createElement("a", { href: collection.manage_url, className: "inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/[0.04] px-4 py-2 transition hover:bg-white/[0.07] hover:text-white" }, /* @__PURE__ */ React.createElement("i", { className: "fa-solid fa-pen-to-square fa-fw text-[11px]" }), "Manage") : null), /* @__PURE__ */ React.createElement("section", { className: "mt-6 rounded-[34px] border border-white/10 bg-white/[0.04] p-6 shadow-[0_30px_90px_rgba(2,6,23,0.28)] backdrop-blur-sm md:p-8" }, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.22em] text-sky-200/80" }, "Performance"), /* @__PURE__ */ React.createElement("h1", { className: "mt-3 text-4xl font-semibold tracking-[-0.05em] text-white md:text-5xl" }, collection.title || "Collection analytics"), /* @__PURE__ */ React.createElement("p", { className: "mt-4 max-w-3xl text-sm leading-relaxed text-slate-300 md:text-[15px]" }, "Review activity velocity, audience response, and the artworks carrying the most discovery value over the last ", range2.days || 30, " days.")), /* @__PURE__ */ React.createElement("section", { className: "mt-8 grid gap-5 md:grid-cols-2 xl:grid-cols-3" }, /* @__PURE__ */ React.createElement(MetricCard$1, { label: "Views", value: totals.views, delta: range2.views_delta, icon: "fa-eye" }), /* @__PURE__ */ React.createElement(MetricCard$1, { label: "Likes", value: totals.likes, delta: range2.likes_delta, icon: "fa-heart" }), /* @__PURE__ */ React.createElement(MetricCard$1, { label: "Follows", value: totals.follows, delta: range2.follows_delta, icon: "fa-bell" }), /* @__PURE__ */ React.createElement(MetricCard$1, { label: "Saves", value: totals.saves, delta: range2.saves_delta, icon: "fa-bookmark" }), /* @__PURE__ */ React.createElement(MetricCard$1, { label: "Comments", value: totals.comments, delta: range2.comments_delta, icon: "fa-comments" }), /* @__PURE__ */ React.createElement(MetricCard$1, { label: "Submissions", value: totals.submissions, delta: totals.submissions, icon: "fa-inbox" })), /* @__PURE__ */ React.createElement("div", { className: "mt-8 space-y-6" }, /* @__PURE__ */ React.createElement(TimelineChart, { timeline: analytics.timeline }), /* @__PURE__ */ React.createElement("section", { className: "rounded-[32px] border border-white/10 bg-white/[0.04] p-6 backdrop-blur-sm md:p-7" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-between gap-3" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.22em] text-sky-200/80" }, "Artworks"), /* @__PURE__ */ React.createElement("h2", { className: "mt-2 text-2xl font-semibold text-white" }, "Top artwork drivers")), /* @__PURE__ */ React.createElement("span", { className: "rounded-full border border-white/10 bg-white/[0.04] px-3 py-1 text-xs font-semibold text-slate-300" }, topArtworks.length)), topArtworks.length ? /* @__PURE__ */ React.createElement("div", { className: "mt-6 grid gap-4 md:grid-cols-2 xl:grid-cols-4" }, topArtworks.map((artwork) => /* @__PURE__ */ React.createElement("div", { key: artwork.id, className: "overflow-hidden rounded-[24px] border border-white/10 bg-slate-950/40" }, /* @__PURE__ */ React.createElement("div", { className: "aspect-square bg-slate-950/60" }, artwork.thumb ? /* @__PURE__ */ React.createElement("img", { src: artwork.thumb, alt: artwork.title, className: "h-full w-full object-cover" }) : /* @__PURE__ */ React.createElement("div", { className: "flex h-full w-full items-center justify-center text-slate-500" }, /* @__PURE__ */ React.createElement("i", { className: "fa-solid fa-image text-3xl" }))), /* @__PURE__ */ React.createElement("div", { className: "space-y-2 p-4" }, /* @__PURE__ */ React.createElement("div", { className: "truncate text-sm font-semibold text-white" }, artwork.title), /* @__PURE__ */ React.createElement("div", { className: "grid grid-cols-2 gap-2 text-xs text-slate-300" }, /* @__PURE__ */ React.createElement("div", { className: "rounded-2xl border border-white/10 bg-white/[0.04] px-3 py-2" }, "Views: ", Number(artwork.views || 0).toLocaleString()), /* @__PURE__ */ React.createElement("div", { className: "rounded-2xl border border-white/10 bg-white/[0.04] px-3 py-2" }, "Favs: ", Number(artwork.favourites || 0).toLocaleString()), /* @__PURE__ */ React.createElement("div", { className: "rounded-2xl border border-white/10 bg-white/[0.04] px-3 py-2" }, "Shares: ", Number(artwork.shares || 0).toLocaleString()), /* @__PURE__ */ React.createElement("div", { className: "rounded-2xl border border-white/10 bg-white/[0.04] px-3 py-2" }, "Rank: ", Number(artwork.ranking_score || 0).toFixed(1))))))) : /* @__PURE__ */ React.createElement("div", { className: "mt-6 rounded-[24px] border border-dashed border-white/12 bg-white/[0.03] px-6 py-12 text-sm text-slate-300" }, "Attach or publish more artworks before artwork-level ranking can be surfaced here.")))))); } const __vite_glob_0_15 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({ __proto__: null, @@ -63239,7 +63239,7 @@ function CollectionDashboard() { setBulkState({ busy: false, error: error.message || "Bulk action failed.", notice: "" }); } } - return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Se, null, /* @__PURE__ */ React.createElement("title", null, seo.title || "Collections Dashboard — Skinbase Nova"), /* @__PURE__ */ React.createElement("meta", { name: "description", content: seo.description || "Collection lifecycle and performance dashboard." }), seo.canonical ? /* @__PURE__ */ React.createElement("link", { rel: "canonical", href: seo.canonical }) : null, /* @__PURE__ */ React.createElement("meta", { name: "robots", content: seo.robots || "noindex,follow" })), /* @__PURE__ */ React.createElement("div", { className: "relative min-h-screen overflow-hidden pb-16" }, /* @__PURE__ */ React.createElement("div", { "aria-hidden": "true", className: "pointer-events-none absolute inset-x-0 top-0 -z-10 h-[34rem] opacity-95", style: { background: "radial-gradient(circle at 12% 15%, rgba(56,189,248,0.18), transparent 28%), radial-gradient(circle at 84% 14%, rgba(245,158,11,0.16), transparent 26%), linear-gradient(180deg, #07101d 0%, #0a1220 42%, #08111f 100%)" } }), /* @__PURE__ */ React.createElement("div", { "aria-hidden": "true", className: "pointer-events-none absolute inset-0 -z-10 opacity-[0.05]", style: { backgroundImage: "url(/gfx/noise.png)", backgroundSize: "180px" } }), /* @__PURE__ */ React.createElement("div", { className: "mx-auto max-w-7xl px-4 pt-8 md:px-6" }, /* @__PURE__ */ React.createElement("section", { className: "overflow-hidden rounded-[34px] border border-white/10 bg-white/[0.04] p-6 shadow-[0_30px_90px_rgba(2,6,23,0.28)] backdrop-blur-sm md:p-8" }, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.22em] text-sky-200/80" }, "Operations"), /* @__PURE__ */ React.createElement("h1", { className: "mt-3 text-4xl font-semibold tracking-[-0.05em] text-white md:text-5xl" }, "Collections dashboard"), /* @__PURE__ */ React.createElement("p", { className: "mt-4 max-w-3xl text-sm leading-relaxed text-slate-300 md:text-[15px]" }, "A working view of collection health across lifecycle, submissions, quality, and campaign timing. Use it to decide what to publish, repair, archive, or promote next.")), /* @__PURE__ */ React.createElement("section", { className: "mt-8 grid gap-5 md:grid-cols-2 xl:grid-cols-3" }, /* @__PURE__ */ React.createElement(SummaryCard$4, { label: "Total Collections", value: summary.total ?? 0, icon: "fa-layer-group", tone: "sky" }), /* @__PURE__ */ React.createElement(SummaryCard$4, { label: "Drafts", value: summary.drafts ?? 0, icon: "fa-file", tone: "amber" }), /* @__PURE__ */ React.createElement(SummaryCard$4, { label: "Scheduled", value: summary.scheduled ?? 0, icon: "fa-calendar-days", tone: "emerald" }), /* @__PURE__ */ React.createElement(SummaryCard$4, { label: "Published", value: summary.published ?? 0, icon: "fa-globe", tone: "sky" }), /* @__PURE__ */ React.createElement(SummaryCard$4, { label: "Archived", value: summary.archived ?? 0, icon: "fa-box-archive", tone: "rose" }), /* @__PURE__ */ React.createElement(SummaryCard$4, { label: "Pending Submissions", value: summary.pending_submissions ?? 0, icon: "fa-inbox", tone: "amber" }), /* @__PURE__ */ React.createElement(SummaryCard$4, { label: "Needs Review", value: summary.needs_review ?? 0, icon: "fa-triangle-exclamation", tone: "amber" }), /* @__PURE__ */ React.createElement(SummaryCard$4, { label: "Duplicate Risk", value: summary.duplicate_risk ?? 0, icon: "fa-id-card", tone: "rose" }), /* @__PURE__ */ React.createElement(SummaryCard$4, { label: "Placement Blocked", value: summary.placement_blocked ?? 0, icon: "fa-ban", tone: "rose" })), /* @__PURE__ */ React.createElement("div", { className: "mt-8 space-y-6" }, /* @__PURE__ */ React.createElement("section", { className: "rounded-[32px] border border-white/10 bg-white/[0.04] p-6 shadow-[0_24px_80px_rgba(2,6,23,0.24)] backdrop-blur-sm md:p-7" }, /* @__PURE__ */ React.createElement("div", { className: "flex flex-wrap items-center justify-between gap-3" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.22em] text-sky-200/80" }, "Search"), /* @__PURE__ */ React.createElement("h2", { className: "mt-2 text-2xl font-semibold text-white" }, "Find the exact collections that need action")), searchState.busy ? /* @__PURE__ */ React.createElement("span", { className: "rounded-full border border-sky-300/20 bg-sky-400/10 px-3 py-1 text-xs font-semibold text-sky-100" }, "Searching...") : null), /* @__PURE__ */ React.createElement("form", { onSubmit: handleSearch, className: "mt-6 grid gap-4 lg:grid-cols-2 xl:grid-cols-4" }, /* @__PURE__ */ React.createElement(SearchField, { label: "Query", value: searchFilters.q, onChange: (event) => updateFilter("q", event.target.value) }, /* @__PURE__ */ React.createElement("input", { value: searchFilters.q, onChange: (event) => updateFilter("q", event.target.value), placeholder: "Title, slug, or campaign", className: "w-full rounded-2xl border border-white/10 bg-[#09111d] px-4 py-3 text-sm text-white outline-none transition placeholder:text-slate-500 focus:border-sky-300/40" })), /* @__PURE__ */ React.createElement(SearchField, { label: "Type" }, /* @__PURE__ */ React.createElement(NovaSelect, { value: searchFilters.type, onChange: (val) => updateFilter("type", val), placeholder: "Any type", options: (Array.isArray(filterOptions.types) ? filterOptions.types : []).map((o) => ({ value: o, label: titleize$1(o) })) })), /* @__PURE__ */ React.createElement(SearchField, { label: "Visibility" }, /* @__PURE__ */ React.createElement(NovaSelect, { value: searchFilters.visibility, onChange: (val) => updateFilter("visibility", val), placeholder: "Any visibility", options: (Array.isArray(filterOptions.visibilities) ? filterOptions.visibilities : []).map((o) => ({ value: o, label: titleize$1(o) })) })), /* @__PURE__ */ React.createElement(SearchField, { label: "Lifecycle" }, /* @__PURE__ */ React.createElement(NovaSelect, { value: searchFilters.lifecycle_state, onChange: (val) => updateFilter("lifecycle_state", val), placeholder: "Any lifecycle", options: (Array.isArray(filterOptions.lifecycleStates) ? filterOptions.lifecycleStates : []).map((o) => ({ value: o, label: titleize$1(o) })) })), /* @__PURE__ */ React.createElement(SearchField, { label: "Workflow" }, /* @__PURE__ */ React.createElement(NovaSelect, { value: searchFilters.workflow_state, onChange: (val) => updateFilter("workflow_state", val), placeholder: "Any workflow", options: (Array.isArray(filterOptions.workflowStates) ? filterOptions.workflowStates : []).map((o) => ({ value: o, label: titleize$1(o) })) })), /* @__PURE__ */ React.createElement(SearchField, { label: "Health" }, /* @__PURE__ */ React.createElement(NovaSelect, { value: searchFilters.health_state, onChange: (val) => updateFilter("health_state", val), placeholder: "Any health state", options: (Array.isArray(filterOptions.healthStates) ? filterOptions.healthStates : []).map((o) => ({ value: o, label: titleize$1(o) })) })), /* @__PURE__ */ React.createElement(SearchField, { label: "Placement" }, /* @__PURE__ */ React.createElement(NovaSelect, { value: searchFilters.placement_eligibility, onChange: (val) => updateFilter("placement_eligibility", val), placeholder: "Any placement state", searchable: false, options: [{ value: "1", label: "Eligible" }, { value: "0", label: "Blocked" }] })), /* @__PURE__ */ React.createElement("div", { className: "flex items-end gap-3 xl:col-span-1" }, /* @__PURE__ */ React.createElement("button", { type: "submit", disabled: searchState.busy, className: "inline-flex flex-1 items-center justify-center gap-2 rounded-2xl border border-sky-300/20 bg-sky-400/10 px-4 py-3 text-sm font-semibold text-sky-100 transition hover:bg-sky-400/15 disabled:cursor-not-allowed disabled:opacity-60" }, /* @__PURE__ */ React.createElement("i", { className: "fa-solid fa-magnifying-glass fa-fw text-[12px]" }), "Search"), /* @__PURE__ */ React.createElement("button", { type: "button", onClick: resetSearch, disabled: searchState.busy, className: "inline-flex items-center justify-center gap-2 rounded-2xl border border-white/10 bg-white/[0.04] px-4 py-3 text-sm font-semibold text-white transition hover:bg-white/[0.07] disabled:cursor-not-allowed disabled:opacity-60" }, "Reset"))), /* @__PURE__ */ React.createElement( + return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Se, null, /* @__PURE__ */ React.createElement("title", null, seo.title || "Collections Dashboard — Skinbase"), /* @__PURE__ */ React.createElement("meta", { name: "description", content: seo.description || "Collection lifecycle and performance dashboard." }), seo.canonical ? /* @__PURE__ */ React.createElement("link", { rel: "canonical", href: seo.canonical }) : null, /* @__PURE__ */ React.createElement("meta", { name: "robots", content: seo.robots || "noindex,follow" })), /* @__PURE__ */ React.createElement("div", { className: "relative min-h-screen overflow-hidden pb-16" }, /* @__PURE__ */ React.createElement("div", { "aria-hidden": "true", className: "pointer-events-none absolute inset-x-0 top-0 -z-10 h-[34rem] opacity-95", style: { background: "radial-gradient(circle at 12% 15%, rgba(56,189,248,0.18), transparent 28%), radial-gradient(circle at 84% 14%, rgba(245,158,11,0.16), transparent 26%), linear-gradient(180deg, #07101d 0%, #0a1220 42%, #08111f 100%)" } }), /* @__PURE__ */ React.createElement("div", { "aria-hidden": "true", className: "pointer-events-none absolute inset-0 -z-10 opacity-[0.05]", style: { backgroundImage: "url(/gfx/noise.png)", backgroundSize: "180px" } }), /* @__PURE__ */ React.createElement("div", { className: "mx-auto max-w-7xl px-4 pt-8 md:px-6" }, /* @__PURE__ */ React.createElement("section", { className: "overflow-hidden rounded-[34px] border border-white/10 bg-white/[0.04] p-6 shadow-[0_30px_90px_rgba(2,6,23,0.28)] backdrop-blur-sm md:p-8" }, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.22em] text-sky-200/80" }, "Operations"), /* @__PURE__ */ React.createElement("h1", { className: "mt-3 text-4xl font-semibold tracking-[-0.05em] text-white md:text-5xl" }, "Collections dashboard"), /* @__PURE__ */ React.createElement("p", { className: "mt-4 max-w-3xl text-sm leading-relaxed text-slate-300 md:text-[15px]" }, "A working view of collection health across lifecycle, submissions, quality, and campaign timing. Use it to decide what to publish, repair, archive, or promote next.")), /* @__PURE__ */ React.createElement("section", { className: "mt-8 grid gap-5 md:grid-cols-2 xl:grid-cols-3" }, /* @__PURE__ */ React.createElement(SummaryCard$4, { label: "Total Collections", value: summary.total ?? 0, icon: "fa-layer-group", tone: "sky" }), /* @__PURE__ */ React.createElement(SummaryCard$4, { label: "Drafts", value: summary.drafts ?? 0, icon: "fa-file", tone: "amber" }), /* @__PURE__ */ React.createElement(SummaryCard$4, { label: "Scheduled", value: summary.scheduled ?? 0, icon: "fa-calendar-days", tone: "emerald" }), /* @__PURE__ */ React.createElement(SummaryCard$4, { label: "Published", value: summary.published ?? 0, icon: "fa-globe", tone: "sky" }), /* @__PURE__ */ React.createElement(SummaryCard$4, { label: "Archived", value: summary.archived ?? 0, icon: "fa-box-archive", tone: "rose" }), /* @__PURE__ */ React.createElement(SummaryCard$4, { label: "Pending Submissions", value: summary.pending_submissions ?? 0, icon: "fa-inbox", tone: "amber" }), /* @__PURE__ */ React.createElement(SummaryCard$4, { label: "Needs Review", value: summary.needs_review ?? 0, icon: "fa-triangle-exclamation", tone: "amber" }), /* @__PURE__ */ React.createElement(SummaryCard$4, { label: "Duplicate Risk", value: summary.duplicate_risk ?? 0, icon: "fa-id-card", tone: "rose" }), /* @__PURE__ */ React.createElement(SummaryCard$4, { label: "Placement Blocked", value: summary.placement_blocked ?? 0, icon: "fa-ban", tone: "rose" })), /* @__PURE__ */ React.createElement("div", { className: "mt-8 space-y-6" }, /* @__PURE__ */ React.createElement("section", { className: "rounded-[32px] border border-white/10 bg-white/[0.04] p-6 shadow-[0_24px_80px_rgba(2,6,23,0.24)] backdrop-blur-sm md:p-7" }, /* @__PURE__ */ React.createElement("div", { className: "flex flex-wrap items-center justify-between gap-3" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.22em] text-sky-200/80" }, "Search"), /* @__PURE__ */ React.createElement("h2", { className: "mt-2 text-2xl font-semibold text-white" }, "Find the exact collections that need action")), searchState.busy ? /* @__PURE__ */ React.createElement("span", { className: "rounded-full border border-sky-300/20 bg-sky-400/10 px-3 py-1 text-xs font-semibold text-sky-100" }, "Searching...") : null), /* @__PURE__ */ React.createElement("form", { onSubmit: handleSearch, className: "mt-6 grid gap-4 lg:grid-cols-2 xl:grid-cols-4" }, /* @__PURE__ */ React.createElement(SearchField, { label: "Query", value: searchFilters.q, onChange: (event) => updateFilter("q", event.target.value) }, /* @__PURE__ */ React.createElement("input", { value: searchFilters.q, onChange: (event) => updateFilter("q", event.target.value), placeholder: "Title, slug, or campaign", className: "w-full rounded-2xl border border-white/10 bg-[#09111d] px-4 py-3 text-sm text-white outline-none transition placeholder:text-slate-500 focus:border-sky-300/40" })), /* @__PURE__ */ React.createElement(SearchField, { label: "Type" }, /* @__PURE__ */ React.createElement(NovaSelect, { value: searchFilters.type, onChange: (val) => updateFilter("type", val), placeholder: "Any type", options: (Array.isArray(filterOptions.types) ? filterOptions.types : []).map((o) => ({ value: o, label: titleize$1(o) })) })), /* @__PURE__ */ React.createElement(SearchField, { label: "Visibility" }, /* @__PURE__ */ React.createElement(NovaSelect, { value: searchFilters.visibility, onChange: (val) => updateFilter("visibility", val), placeholder: "Any visibility", options: (Array.isArray(filterOptions.visibilities) ? filterOptions.visibilities : []).map((o) => ({ value: o, label: titleize$1(o) })) })), /* @__PURE__ */ React.createElement(SearchField, { label: "Lifecycle" }, /* @__PURE__ */ React.createElement(NovaSelect, { value: searchFilters.lifecycle_state, onChange: (val) => updateFilter("lifecycle_state", val), placeholder: "Any lifecycle", options: (Array.isArray(filterOptions.lifecycleStates) ? filterOptions.lifecycleStates : []).map((o) => ({ value: o, label: titleize$1(o) })) })), /* @__PURE__ */ React.createElement(SearchField, { label: "Workflow" }, /* @__PURE__ */ React.createElement(NovaSelect, { value: searchFilters.workflow_state, onChange: (val) => updateFilter("workflow_state", val), placeholder: "Any workflow", options: (Array.isArray(filterOptions.workflowStates) ? filterOptions.workflowStates : []).map((o) => ({ value: o, label: titleize$1(o) })) })), /* @__PURE__ */ React.createElement(SearchField, { label: "Health" }, /* @__PURE__ */ React.createElement(NovaSelect, { value: searchFilters.health_state, onChange: (val) => updateFilter("health_state", val), placeholder: "Any health state", options: (Array.isArray(filterOptions.healthStates) ? filterOptions.healthStates : []).map((o) => ({ value: o, label: titleize$1(o) })) })), /* @__PURE__ */ React.createElement(SearchField, { label: "Placement" }, /* @__PURE__ */ React.createElement(NovaSelect, { value: searchFilters.placement_eligibility, onChange: (val) => updateFilter("placement_eligibility", val), placeholder: "Any placement state", searchable: false, options: [{ value: "1", label: "Eligible" }, { value: "0", label: "Blocked" }] })), /* @__PURE__ */ React.createElement("div", { className: "flex items-end gap-3 xl:col-span-1" }, /* @__PURE__ */ React.createElement("button", { type: "submit", disabled: searchState.busy, className: "inline-flex flex-1 items-center justify-center gap-2 rounded-2xl border border-sky-300/20 bg-sky-400/10 px-4 py-3 text-sm font-semibold text-sky-100 transition hover:bg-sky-400/15 disabled:cursor-not-allowed disabled:opacity-60" }, /* @__PURE__ */ React.createElement("i", { className: "fa-solid fa-magnifying-glass fa-fw text-[12px]" }), "Search"), /* @__PURE__ */ React.createElement("button", { type: "button", onClick: resetSearch, disabled: searchState.busy, className: "inline-flex items-center justify-center gap-2 rounded-2xl border border-white/10 bg-white/[0.04] px-4 py-3 text-sm font-semibold text-white transition hover:bg-white/[0.07] disabled:cursor-not-allowed disabled:opacity-60" }, "Reset"))), /* @__PURE__ */ React.createElement( BulkActionsPanel, { selectedCount: selectedIds.length, @@ -63410,7 +63410,7 @@ function CollectionFeaturedIndex() { const seo = props.seo || {}; const eyebrow = props.eyebrow || "Discovery"; const title = props.title || "Featured collections"; - const description = props.description || "A rotating set of standout galleries from across Skinbase Nova. Some are meticulously hand-sequenced. Others are smart collections that stay fresh as the creator publishes new work."; + const description = props.description || "A rotating set of standout galleries from across Skinbase. Some are meticulously hand-sequenced. Others are smart collections that stay fresh as the creator publishes new work."; const collections = Array.isArray(props.collections) ? props.collections : []; const communityCollections = Array.isArray(props.communityCollections) ? props.communityCollections : []; const editorialCollections = Array.isArray(props.editorialCollections) ? props.editorialCollections : []; @@ -63440,7 +63440,7 @@ function CollectionFeaturedIndex() { })) } } : null; - return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(SeoHead, { seo, title: seo?.title || `${title} — Skinbase Nova`, description: seo?.description || description, jsonLd: listSchema }), /* @__PURE__ */ React.createElement("div", { className: "relative min-h-screen overflow-hidden pb-16" }, /* @__PURE__ */ React.createElement( + return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(SeoHead, { seo, title: seo?.title || `${title} — Skinbase`, description: seo?.description || description, jsonLd: listSchema }), /* @__PURE__ */ React.createElement("div", { className: "relative min-h-screen overflow-hidden pb-16" }, /* @__PURE__ */ React.createElement( "div", { "aria-hidden": "true", @@ -63510,7 +63510,7 @@ function CollectionHistory() { setBusyId(null); } } - return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Se, null, /* @__PURE__ */ React.createElement("title", null, seo.title || `${collection.title || "Collection"} History — Skinbase Nova`), /* @__PURE__ */ React.createElement("meta", { name: "description", content: seo.description || "Collection audit history." }), seo.canonical ? /* @__PURE__ */ React.createElement("link", { rel: "canonical", href: seo.canonical }) : null, /* @__PURE__ */ React.createElement("meta", { name: "robots", content: seo.robots || "noindex,follow" })), /* @__PURE__ */ React.createElement("div", { className: "relative min-h-screen overflow-hidden pb-16" }, /* @__PURE__ */ React.createElement("div", { "aria-hidden": "true", className: "pointer-events-none absolute inset-x-0 top-0 -z-10 h-[32rem] opacity-95", style: { background: "radial-gradient(circle at 14% 14%, rgba(56,189,248,0.16), transparent 26%), radial-gradient(circle at 84% 20%, rgba(244,63,94,0.14), transparent 24%), linear-gradient(180deg, #07101d 0%, #0a1220 42%, #08111f 100%)" } }), /* @__PURE__ */ React.createElement("div", { "aria-hidden": "true", className: "pointer-events-none absolute inset-0 -z-10 opacity-[0.05]", style: { backgroundImage: "url(/gfx/noise.png)", backgroundSize: "180px" } }), /* @__PURE__ */ React.createElement("div", { className: "mx-auto max-w-6xl px-4 pt-8 md:px-6" }, /* @__PURE__ */ React.createElement("div", { className: "flex flex-wrap items-center gap-3 text-sm text-slate-300" }, props.dashboardUrl ? /* @__PURE__ */ React.createElement("a", { href: props.dashboardUrl, className: "inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/[0.04] px-4 py-2 transition hover:bg-white/[0.07] hover:text-white" }, /* @__PURE__ */ React.createElement("i", { className: "fa-solid fa-arrow-left fa-fw text-[11px]" }), "Dashboard") : null, props.analyticsUrl ? /* @__PURE__ */ React.createElement("a", { href: props.analyticsUrl, className: "inline-flex items-center gap-2 rounded-full border border-sky-300/20 bg-sky-400/10 px-4 py-2 font-semibold text-sky-100 transition hover:bg-sky-400/15" }, /* @__PURE__ */ React.createElement("i", { className: "fa-solid fa-chart-column fa-fw text-[11px]" }), "Analytics") : null, collection.manage_url ? /* @__PURE__ */ React.createElement("a", { href: collection.manage_url, className: "inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/[0.04] px-4 py-2 transition hover:bg-white/[0.07] hover:text-white" }, /* @__PURE__ */ React.createElement("i", { className: "fa-solid fa-pen-to-square fa-fw text-[11px]" }), "Manage") : null), /* @__PURE__ */ React.createElement("section", { className: "mt-6 rounded-[34px] border border-white/10 bg-white/[0.04] p-6 shadow-[0_30px_90px_rgba(2,6,23,0.28)] backdrop-blur-sm md:p-8" }, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.22em] text-sky-200/80" }, "Audit"), /* @__PURE__ */ React.createElement("h1", { className: "mt-3 text-4xl font-semibold tracking-[-0.05em] text-white md:text-5xl" }, collection.title || "Collection history"), /* @__PURE__ */ React.createElement("p", { className: "mt-4 max-w-3xl text-sm leading-relaxed text-slate-300 md:text-[15px]" }, "A chronological log of lifecycle transitions, editorial changes, artwork operations, and moderation-adjacent actions for this collection.")), /* @__PURE__ */ React.createElement("section", { className: "mt-8 space-y-4" }, notice ? /* @__PURE__ */ React.createElement("div", { className: "rounded-[24px] border border-rose-300/20 bg-rose-500/10 px-5 py-4 text-sm text-rose-100" }, notice) : null, entries.length ? entries.map((entry) => /* @__PURE__ */ React.createElement("article", { key: entry.id, className: "rounded-[30px] border border-white/10 bg-white/[0.04] p-6 backdrop-blur-sm" }, /* @__PURE__ */ React.createElement("div", { className: "flex flex-wrap items-start justify-between gap-4" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("div", { className: "flex flex-wrap items-center gap-2" }, /* @__PURE__ */ React.createElement("span", { className: "rounded-full border border-sky-300/20 bg-sky-400/10 px-3 py-1 text-[11px] font-semibold uppercase tracking-[0.18em] text-sky-100" }, String(entry.action_type || "updated").replace(/_/g, " ")), entry.actor?.username ? /* @__PURE__ */ React.createElement("span", { className: "rounded-full border border-white/10 bg-white/[0.04] px-3 py-1 text-[11px] font-semibold uppercase tracking-[0.18em] text-slate-300" }, "@", entry.actor.username) : /* @__PURE__ */ React.createElement("span", { className: "rounded-full border border-white/10 bg-white/[0.04] px-3 py-1 text-[11px] font-semibold uppercase tracking-[0.18em] text-slate-400" }, "System"), entry.can_restore ? /* @__PURE__ */ React.createElement("span", { className: "rounded-full border border-emerald-300/20 bg-emerald-400/10 px-3 py-1 text-[11px] font-semibold uppercase tracking-[0.18em] text-emerald-100" }, "Restorable") : null), /* @__PURE__ */ React.createElement("h2", { className: "mt-4 text-xl font-semibold text-white" }, entry.summary || "Collection updated"), entry.can_restore && Array.isArray(entry.restore_fields) && entry.restore_fields.length ? /* @__PURE__ */ React.createElement("p", { className: "mt-3 text-xs uppercase tracking-[0.18em] text-slate-400" }, "Restores: ", entry.restore_fields.join(", ")) : null), /* @__PURE__ */ React.createElement("div", { className: "flex flex-col items-end gap-3" }, /* @__PURE__ */ React.createElement("div", { className: "text-sm text-slate-400" }, formatDateTime$2(entry.created_at)), props.canRestoreHistory && entry.can_restore ? /* @__PURE__ */ React.createElement( + return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Se, null, /* @__PURE__ */ React.createElement("title", null, seo.title || `${collection.title || "Collection"} History — Skinbase`), /* @__PURE__ */ React.createElement("meta", { name: "description", content: seo.description || "Collection audit history." }), seo.canonical ? /* @__PURE__ */ React.createElement("link", { rel: "canonical", href: seo.canonical }) : null, /* @__PURE__ */ React.createElement("meta", { name: "robots", content: seo.robots || "noindex,follow" })), /* @__PURE__ */ React.createElement("div", { className: "relative min-h-screen overflow-hidden pb-16" }, /* @__PURE__ */ React.createElement("div", { "aria-hidden": "true", className: "pointer-events-none absolute inset-x-0 top-0 -z-10 h-[32rem] opacity-95", style: { background: "radial-gradient(circle at 14% 14%, rgba(56,189,248,0.16), transparent 26%), radial-gradient(circle at 84% 20%, rgba(244,63,94,0.14), transparent 24%), linear-gradient(180deg, #07101d 0%, #0a1220 42%, #08111f 100%)" } }), /* @__PURE__ */ React.createElement("div", { "aria-hidden": "true", className: "pointer-events-none absolute inset-0 -z-10 opacity-[0.05]", style: { backgroundImage: "url(/gfx/noise.png)", backgroundSize: "180px" } }), /* @__PURE__ */ React.createElement("div", { className: "mx-auto max-w-6xl px-4 pt-8 md:px-6" }, /* @__PURE__ */ React.createElement("div", { className: "flex flex-wrap items-center gap-3 text-sm text-slate-300" }, props.dashboardUrl ? /* @__PURE__ */ React.createElement("a", { href: props.dashboardUrl, className: "inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/[0.04] px-4 py-2 transition hover:bg-white/[0.07] hover:text-white" }, /* @__PURE__ */ React.createElement("i", { className: "fa-solid fa-arrow-left fa-fw text-[11px]" }), "Dashboard") : null, props.analyticsUrl ? /* @__PURE__ */ React.createElement("a", { href: props.analyticsUrl, className: "inline-flex items-center gap-2 rounded-full border border-sky-300/20 bg-sky-400/10 px-4 py-2 font-semibold text-sky-100 transition hover:bg-sky-400/15" }, /* @__PURE__ */ React.createElement("i", { className: "fa-solid fa-chart-column fa-fw text-[11px]" }), "Analytics") : null, collection.manage_url ? /* @__PURE__ */ React.createElement("a", { href: collection.manage_url, className: "inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/[0.04] px-4 py-2 transition hover:bg-white/[0.07] hover:text-white" }, /* @__PURE__ */ React.createElement("i", { className: "fa-solid fa-pen-to-square fa-fw text-[11px]" }), "Manage") : null), /* @__PURE__ */ React.createElement("section", { className: "mt-6 rounded-[34px] border border-white/10 bg-white/[0.04] p-6 shadow-[0_30px_90px_rgba(2,6,23,0.28)] backdrop-blur-sm md:p-8" }, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.22em] text-sky-200/80" }, "Audit"), /* @__PURE__ */ React.createElement("h1", { className: "mt-3 text-4xl font-semibold tracking-[-0.05em] text-white md:text-5xl" }, collection.title || "Collection history"), /* @__PURE__ */ React.createElement("p", { className: "mt-4 max-w-3xl text-sm leading-relaxed text-slate-300 md:text-[15px]" }, "A chronological log of lifecycle transitions, editorial changes, artwork operations, and moderation-adjacent actions for this collection.")), /* @__PURE__ */ React.createElement("section", { className: "mt-8 space-y-4" }, notice ? /* @__PURE__ */ React.createElement("div", { className: "rounded-[24px] border border-rose-300/20 bg-rose-500/10 px-5 py-4 text-sm text-rose-100" }, notice) : null, entries.length ? entries.map((entry) => /* @__PURE__ */ React.createElement("article", { key: entry.id, className: "rounded-[30px] border border-white/10 bg-white/[0.04] p-6 backdrop-blur-sm" }, /* @__PURE__ */ React.createElement("div", { className: "flex flex-wrap items-start justify-between gap-4" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("div", { className: "flex flex-wrap items-center gap-2" }, /* @__PURE__ */ React.createElement("span", { className: "rounded-full border border-sky-300/20 bg-sky-400/10 px-3 py-1 text-[11px] font-semibold uppercase tracking-[0.18em] text-sky-100" }, String(entry.action_type || "updated").replace(/_/g, " ")), entry.actor?.username ? /* @__PURE__ */ React.createElement("span", { className: "rounded-full border border-white/10 bg-white/[0.04] px-3 py-1 text-[11px] font-semibold uppercase tracking-[0.18em] text-slate-300" }, "@", entry.actor.username) : /* @__PURE__ */ React.createElement("span", { className: "rounded-full border border-white/10 bg-white/[0.04] px-3 py-1 text-[11px] font-semibold uppercase tracking-[0.18em] text-slate-400" }, "System"), entry.can_restore ? /* @__PURE__ */ React.createElement("span", { className: "rounded-full border border-emerald-300/20 bg-emerald-400/10 px-3 py-1 text-[11px] font-semibold uppercase tracking-[0.18em] text-emerald-100" }, "Restorable") : null), /* @__PURE__ */ React.createElement("h2", { className: "mt-4 text-xl font-semibold text-white" }, entry.summary || "Collection updated"), entry.can_restore && Array.isArray(entry.restore_fields) && entry.restore_fields.length ? /* @__PURE__ */ React.createElement("p", { className: "mt-3 text-xs uppercase tracking-[0.18em] text-slate-400" }, "Restores: ", entry.restore_fields.join(", ")) : null), /* @__PURE__ */ React.createElement("div", { className: "flex flex-col items-end gap-3" }, /* @__PURE__ */ React.createElement("div", { className: "text-sm text-slate-400" }, formatDateTime$2(entry.created_at)), props.canRestoreHistory && entry.can_restore ? /* @__PURE__ */ React.createElement( "button", { type: "button", @@ -64915,7 +64915,7 @@ function CollectionManage() { setMembers(payload?.members || []); setNotice("Collaborator removed by moderation action."); } - return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Se, null, /* @__PURE__ */ React.createElement("title", null, mode === "create" ? "Create Collection — Skinbase Nova" : `${collectionState?.title || "Collection"} — Manage Collection`), /* @__PURE__ */ React.createElement("meta", { name: "robots", content: "noindex,nofollow" })), /* @__PURE__ */ React.createElement("div", { className: "relative min-h-screen overflow-hidden pb-16" }, /* @__PURE__ */ React.createElement( + return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Se, null, /* @__PURE__ */ React.createElement("title", null, mode === "create" ? "Create Collection — Skinbase" : `${collectionState?.title || "Collection"} — Manage Collection`), /* @__PURE__ */ React.createElement("meta", { name: "robots", content: "noindex,nofollow" })), /* @__PURE__ */ React.createElement("div", { className: "relative min-h-screen overflow-hidden pb-16" }, /* @__PURE__ */ React.createElement( "div", { "aria-hidden": "true", @@ -65493,11 +65493,11 @@ function CollectionSeriesShow() { const { props } = X(); const seo = props.seo || {}; const title = props.title || `Collection Series: ${props.seriesKey || ""}`; - const description = props.description || "A connected sequence of public collections on Skinbase Nova."; + const description = props.description || "A connected sequence of public collections on Skinbase."; const collections = Array.isArray(props.collections) ? props.collections : []; const leadCollection = props.leadCollection || null; const stats = props.stats || {}; - return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(SeoHead, { seo, title: seo.title || `${title} — Skinbase Nova`, description: seo.description || description }), /* @__PURE__ */ React.createElement("div", { className: "relative min-h-screen overflow-hidden pb-16" }, /* @__PURE__ */ React.createElement("div", { "aria-hidden": "true", className: "pointer-events-none absolute inset-x-0 top-0 -z-10 h-[36rem] opacity-95", style: { background: "radial-gradient(circle at 10% 15%, rgba(59,130,246,0.18), transparent 28%), radial-gradient(circle at 84% 18%, rgba(34,197,94,0.16), transparent 24%), linear-gradient(180deg, #07101d 0%, #0a1220 42%, #08111f 100%)" } }), /* @__PURE__ */ React.createElement("div", { "aria-hidden": "true", className: "pointer-events-none absolute inset-0 -z-10 opacity-[0.05]", style: { backgroundImage: "url(/gfx/noise.png)", backgroundSize: "180px" } }), /* @__PURE__ */ React.createElement("div", { className: "mx-auto max-w-7xl px-4 pt-8 md:px-6" }, /* @__PURE__ */ React.createElement("div", { className: "flex flex-wrap items-center gap-3 text-sm text-slate-300" }, /* @__PURE__ */ React.createElement("a", { href: "/collections/featured", className: "inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/[0.04] px-4 py-2 transition hover:bg-white/[0.07] hover:text-white" }, /* @__PURE__ */ React.createElement("i", { className: "fa-solid fa-arrow-left fa-fw text-[11px]" }), "Back to collections"), leadCollection?.url ? /* @__PURE__ */ React.createElement("a", { href: leadCollection.url, className: "inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/[0.04] px-4 py-2 transition hover:bg-white/[0.07] hover:text-white" }, "Lead collection") : null), /* @__PURE__ */ React.createElement("section", { className: "mt-6 overflow-hidden rounded-[34px] border border-white/10 bg-white/[0.04] p-6 shadow-[0_30px_90px_rgba(2,6,23,0.28)] backdrop-blur-sm md:p-8" }, /* @__PURE__ */ React.createElement("div", { className: "grid gap-8 xl:grid-cols-[minmax(0,1.15fr)_400px] xl:items-end" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.22em] text-sky-200/80" }, "Series"), /* @__PURE__ */ React.createElement("h1", { className: "mt-3 text-4xl font-semibold tracking-[-0.05em] text-white md:text-5xl" }, title), /* @__PURE__ */ React.createElement("p", { className: "mt-4 max-w-3xl text-sm leading-relaxed text-slate-300 md:text-[15px]" }, description), props.seriesKey ? /* @__PURE__ */ React.createElement("div", { className: "mt-5 inline-flex rounded-full border border-white/10 bg-white/[0.05] px-4 py-2 text-xs font-semibold uppercase tracking-[0.18em] text-slate-300" }, props.seriesKey) : null), /* @__PURE__ */ React.createElement("div", { className: "grid gap-3 sm:grid-cols-3 xl:grid-cols-1" }, /* @__PURE__ */ React.createElement(StatCard$6, { icon: "fa-layer-group", label: "Collections", value: Number(stats.collections || collections.length).toLocaleString() }), /* @__PURE__ */ React.createElement(StatCard$6, { icon: "fa-user-group", label: "Creators", value: Number(stats.owners || 0).toLocaleString() }), /* @__PURE__ */ React.createElement(StatCard$6, { icon: "fa-images", label: "Artworks", value: Number(stats.artworks || 0).toLocaleString() })))), leadCollection ? /* @__PURE__ */ React.createElement("section", { className: "mt-8 rounded-[32px] border border-white/10 bg-white/[0.04] p-6 backdrop-blur-sm md:p-7" }, /* @__PURE__ */ React.createElement("div", { className: "flex flex-wrap items-end justify-between gap-4" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.22em] text-sky-200/80" }, "Lead Entry"), /* @__PURE__ */ React.createElement("h2", { className: "mt-2 text-2xl font-semibold text-white" }, "Start with the opening collection")), stats.latest_activity_at ? /* @__PURE__ */ React.createElement("div", { className: "text-xs uppercase tracking-[0.16em] text-slate-400" }, "Latest activity ", new Date(stats.latest_activity_at).toLocaleDateString()) : null), /* @__PURE__ */ React.createElement("div", { className: "mt-5 max-w-xl" }, /* @__PURE__ */ React.createElement(CollectionCard, { collection: leadCollection, isOwner: false }))) : null, /* @__PURE__ */ React.createElement("section", { className: "mt-8 pb-8" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-end justify-between gap-4" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.22em] text-sky-200/80" }, "Sequence"), /* @__PURE__ */ React.createElement("h2", { className: "mt-2 text-2xl font-semibold text-white" }, "Public collections in order"))), /* @__PURE__ */ React.createElement("div", { className: "mt-5 grid grid-cols-1 gap-5 md:grid-cols-2 xl:grid-cols-3" }, collections.map((collection) => /* @__PURE__ */ React.createElement(CollectionCard, { key: collection.id, collection, isOwner: false }))))))); + return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(SeoHead, { seo, title: seo.title || `${title} — Skinbase`, description: seo.description || description }), /* @__PURE__ */ React.createElement("div", { className: "relative min-h-screen overflow-hidden pb-16" }, /* @__PURE__ */ React.createElement("div", { "aria-hidden": "true", className: "pointer-events-none absolute inset-x-0 top-0 -z-10 h-[36rem] opacity-95", style: { background: "radial-gradient(circle at 10% 15%, rgba(59,130,246,0.18), transparent 28%), radial-gradient(circle at 84% 18%, rgba(34,197,94,0.16), transparent 24%), linear-gradient(180deg, #07101d 0%, #0a1220 42%, #08111f 100%)" } }), /* @__PURE__ */ React.createElement("div", { "aria-hidden": "true", className: "pointer-events-none absolute inset-0 -z-10 opacity-[0.05]", style: { backgroundImage: "url(/gfx/noise.png)", backgroundSize: "180px" } }), /* @__PURE__ */ React.createElement("div", { className: "mx-auto max-w-7xl px-4 pt-8 md:px-6" }, /* @__PURE__ */ React.createElement("div", { className: "flex flex-wrap items-center gap-3 text-sm text-slate-300" }, /* @__PURE__ */ React.createElement("a", { href: "/collections/featured", className: "inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/[0.04] px-4 py-2 transition hover:bg-white/[0.07] hover:text-white" }, /* @__PURE__ */ React.createElement("i", { className: "fa-solid fa-arrow-left fa-fw text-[11px]" }), "Back to collections"), leadCollection?.url ? /* @__PURE__ */ React.createElement("a", { href: leadCollection.url, className: "inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/[0.04] px-4 py-2 transition hover:bg-white/[0.07] hover:text-white" }, "Lead collection") : null), /* @__PURE__ */ React.createElement("section", { className: "mt-6 overflow-hidden rounded-[34px] border border-white/10 bg-white/[0.04] p-6 shadow-[0_30px_90px_rgba(2,6,23,0.28)] backdrop-blur-sm md:p-8" }, /* @__PURE__ */ React.createElement("div", { className: "grid gap-8 xl:grid-cols-[minmax(0,1.15fr)_400px] xl:items-end" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.22em] text-sky-200/80" }, "Series"), /* @__PURE__ */ React.createElement("h1", { className: "mt-3 text-4xl font-semibold tracking-[-0.05em] text-white md:text-5xl" }, title), /* @__PURE__ */ React.createElement("p", { className: "mt-4 max-w-3xl text-sm leading-relaxed text-slate-300 md:text-[15px]" }, description), props.seriesKey ? /* @__PURE__ */ React.createElement("div", { className: "mt-5 inline-flex rounded-full border border-white/10 bg-white/[0.05] px-4 py-2 text-xs font-semibold uppercase tracking-[0.18em] text-slate-300" }, props.seriesKey) : null), /* @__PURE__ */ React.createElement("div", { className: "grid gap-3 sm:grid-cols-3 xl:grid-cols-1" }, /* @__PURE__ */ React.createElement(StatCard$6, { icon: "fa-layer-group", label: "Collections", value: Number(stats.collections || collections.length).toLocaleString() }), /* @__PURE__ */ React.createElement(StatCard$6, { icon: "fa-user-group", label: "Creators", value: Number(stats.owners || 0).toLocaleString() }), /* @__PURE__ */ React.createElement(StatCard$6, { icon: "fa-images", label: "Artworks", value: Number(stats.artworks || 0).toLocaleString() })))), leadCollection ? /* @__PURE__ */ React.createElement("section", { className: "mt-8 rounded-[32px] border border-white/10 bg-white/[0.04] p-6 backdrop-blur-sm md:p-7" }, /* @__PURE__ */ React.createElement("div", { className: "flex flex-wrap items-end justify-between gap-4" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.22em] text-sky-200/80" }, "Lead Entry"), /* @__PURE__ */ React.createElement("h2", { className: "mt-2 text-2xl font-semibold text-white" }, "Start with the opening collection")), stats.latest_activity_at ? /* @__PURE__ */ React.createElement("div", { className: "text-xs uppercase tracking-[0.16em] text-slate-400" }, "Latest activity ", new Date(stats.latest_activity_at).toLocaleDateString()) : null), /* @__PURE__ */ React.createElement("div", { className: "mt-5 max-w-xl" }, /* @__PURE__ */ React.createElement(CollectionCard, { collection: leadCollection, isOwner: false }))) : null, /* @__PURE__ */ React.createElement("section", { className: "mt-8 pb-8" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-end justify-between gap-4" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.22em] text-sky-200/80" }, "Sequence"), /* @__PURE__ */ React.createElement("h2", { className: "mt-2 text-2xl font-semibold text-white" }, "Public collections in order"))), /* @__PURE__ */ React.createElement("div", { className: "mt-5 grid grid-cols-1 gap-5 md:grid-cols-2 xl:grid-cols-3" }, collections.map((collection) => /* @__PURE__ */ React.createElement(CollectionCard, { key: collection.id, collection, isOwner: false }))))))); } const __vite_glob_0_20 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({ __proto__: null, @@ -66860,7 +66860,7 @@ function CollectionShow() { const enabledModuleKeys = new Set(enabledModules.map((module) => module?.key).filter(Boolean)); const showIntroBlock = enabledModuleKeys.size === 0 || enabledModuleKeys.has("intro_block"); const metaOwnerName = owner?.name || owner?.username || collection?.owner?.name || "Skinbase Curator"; - const metaTitle = seo?.title || `${collection?.title} — Skinbase Nova`; + const metaTitle = seo?.title || `${collection?.title} — Skinbase`; const metaDescription = seo?.description || collection?.summary || collection?.description || ""; const collectionSchema = seo?.canonical ? { "@context": "https://schema.org", @@ -66871,7 +66871,7 @@ function CollectionShow() { image: seo?.og_image || collection?.cover_image || void 0, isPartOf: { "@type": "WebSite", - name: "Skinbase Nova", + name: "Skinbase", url: typeof window !== "undefined" ? window.location.origin : void 0 }, author: owner ? { @@ -67074,7 +67074,7 @@ function CollectionShow() { setCollection((current) => ({ ...current, shares_count: payload?.shares_count ?? current.shares_count })); await share({ title: collection?.title, - text: collection?.summary || collection?.description || `Explore ${collection?.title} on Skinbase Nova.`, + text: collection?.summary || collection?.description || `Explore ${collection?.title} on Skinbase.`, url: collection?.public_url }); } catch (error) { @@ -67589,7 +67589,7 @@ function CollectionStaffProgramming() { } const totalPrograms = Array.from(new Set(assignments.map((assignment) => assignment.program_key).filter(Boolean))).length; const eligibleAssignments = assignments.filter((assignment) => assignment.collection?.placement_eligibility === true).length; - return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Se, null, /* @__PURE__ */ React.createElement("title", null, seo.title || "Collection Programming — Skinbase Nova"), /* @__PURE__ */ React.createElement("meta", { name: "description", content: seo.description || "Staff programming tools for collections." }), seo.canonical ? /* @__PURE__ */ React.createElement("link", { rel: "canonical", href: seo.canonical }) : null, /* @__PURE__ */ React.createElement("meta", { name: "robots", content: seo.robots || "noindex,follow" })), /* @__PURE__ */ React.createElement( + return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Se, null, /* @__PURE__ */ React.createElement("title", null, seo.title || "Collection Programming — Skinbase"), /* @__PURE__ */ React.createElement("meta", { name: "description", content: seo.description || "Staff programming tools for collections." }), seo.canonical ? /* @__PURE__ */ React.createElement("link", { rel: "canonical", href: seo.canonical }) : null, /* @__PURE__ */ React.createElement("meta", { name: "robots", content: seo.robots || "noindex,follow" })), /* @__PURE__ */ React.createElement( ShareToast, { key: toast.id, @@ -67926,7 +67926,7 @@ function CollectionStaffSurfaces() { setBusy(""); } } - return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Se, null, /* @__PURE__ */ React.createElement("title", null, seo.title || "Collection Surfaces — Skinbase Nova"), /* @__PURE__ */ React.createElement("meta", { name: "description", content: seo.description || "Staff tools for collection surfaces." }), seo.canonical ? /* @__PURE__ */ React.createElement("link", { rel: "canonical", href: seo.canonical }) : null, /* @__PURE__ */ React.createElement("meta", { name: "robots", content: seo.robots || "noindex,follow" })), /* @__PURE__ */ React.createElement("div", { className: "relative min-h-screen overflow-hidden pb-16" }, /* @__PURE__ */ React.createElement("div", { "aria-hidden": "true", className: "pointer-events-none absolute inset-x-0 top-0 -z-10 h-[34rem] opacity-95", style: { background: "radial-gradient(circle at 15% 14%, rgba(245,158,11,0.16), transparent 26%), radial-gradient(circle at 82% 18%, rgba(56,189,248,0.16), transparent 24%), linear-gradient(180deg, #07101d 0%, #0a1220 42%, #08111f 100%)" } }), /* @__PURE__ */ React.createElement("div", { "aria-hidden": "true", className: "pointer-events-none absolute inset-0 -z-10 opacity-[0.05]", style: { backgroundImage: "url(/gfx/noise.png)", backgroundSize: "180px" } }), /* @__PURE__ */ React.createElement("div", { className: "mx-auto max-w-7xl px-4 pt-8 md:px-6" }, /* @__PURE__ */ React.createElement("section", { className: "rounded-[34px] border border-white/10 bg-white/[0.04] p-6 shadow-[0_30px_90px_rgba(2,6,23,0.28)] backdrop-blur-sm md:p-8" }, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.22em] text-amber-200/80" }, "Staff Surfaces"), /* @__PURE__ */ React.createElement("h1", { className: "mt-3 text-4xl font-semibold tracking-[-0.05em] text-white md:text-5xl" }, "Collections placement studio"), /* @__PURE__ */ React.createElement("p", { className: "mt-4 max-w-3xl text-sm leading-relaxed text-slate-300 md:text-[15px]" }, "Define reusable discovery surfaces, then place eligible public collections into manual or campaign-specific slots with clear timing and notes."), notice ? /* @__PURE__ */ React.createElement("p", { className: "mt-4 text-sm text-sky-100" }, notice) : null), /* @__PURE__ */ React.createElement("section", { className: "mt-8 grid gap-6 xl:grid-cols-[minmax(0,0.95fr)_minmax(0,1.05fr)]" }, /* @__PURE__ */ React.createElement("form", { onSubmit: handleDefinitionSubmit, className: "rounded-[32px] border border-white/10 bg-white/[0.04] p-6 backdrop-blur-sm md:p-7" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.22em] text-sky-200/80" }, "Surface Definition"), /* @__PURE__ */ React.createElement("h2", { className: "mt-2 text-2xl font-semibold text-white" }, "Rules and ranking")), definitionForm.id ? /* @__PURE__ */ React.createElement("p", { className: "mt-3 text-sm text-slate-300" }, "Editing ", /* @__PURE__ */ React.createElement("span", { className: "font-semibold text-white" }, definitionForm.surface_key)) : null, /* @__PURE__ */ React.createElement("div", { className: "mt-6 grid gap-4 md:grid-cols-2" }, /* @__PURE__ */ React.createElement(Field, { label: "Surface Key", help: definitionForm.id ? "Surface keys stay stable during edits so existing placements remain attached." : null }, /* @__PURE__ */ React.createElement("input", { value: definitionForm.surface_key, onChange: (event) => setDefinitionForm((current) => ({ ...current, surface_key: event.target.value })), disabled: Boolean(definitionForm.id), className: "w-full rounded-2xl border border-white/10 bg-white/[0.04] px-4 py-3 text-white outline-none disabled:cursor-not-allowed disabled:opacity-60", maxLength: 120 })), /* @__PURE__ */ React.createElement(Field, { label: "Title" }, /* @__PURE__ */ React.createElement("input", { value: definitionForm.title, onChange: (event) => setDefinitionForm((current) => ({ ...current, title: event.target.value })), className: "w-full rounded-2xl border border-white/10 bg-white/[0.04] px-4 py-3 text-white outline-none", maxLength: 160 })), /* @__PURE__ */ React.createElement(Field, { label: "Mode" }, /* @__PURE__ */ React.createElement(NovaSelect, { value: definitionForm.mode, onChange: (val) => setDefinitionForm((current) => ({ ...current, mode: val })), searchable: false, options: [{ value: "manual", label: "Manual" }, { value: "automatic", label: "Automatic" }, { value: "hybrid", label: "Hybrid" }] })), /* @__PURE__ */ React.createElement(Field, { label: "Ranking" }, /* @__PURE__ */ React.createElement(NovaSelect, { value: definitionForm.ranking_mode, onChange: (val) => setDefinitionForm((current) => ({ ...current, ranking_mode: val })), searchable: false, options: [{ value: "ranking_score", label: "Ranking score" }, { value: "recent_activity", label: "Recent activity" }, { value: "quality_score", label: "Quality score" }] })), /* @__PURE__ */ React.createElement(Field, { label: "Max Items" }, /* @__PURE__ */ React.createElement("input", { type: "number", min: "1", max: "24", value: definitionForm.max_items, onChange: (event) => setDefinitionForm((current) => ({ ...current, max_items: event.target.value })), className: "w-full rounded-2xl border border-white/10 bg-white/[0.04] px-4 py-3 text-white outline-none" })), /* @__PURE__ */ React.createElement(Field, { label: "Starts At", help: "Optional activation window for the full surface definition." }, /* @__PURE__ */ React.createElement(DateTimePicker, { value: definitionForm.starts_at, onChange: (nextValue) => setDefinitionForm((current) => ({ ...current, starts_at: nextValue })), placeholder: "Start time", clearable: true, className: "bg-white/[0.04]" })), /* @__PURE__ */ React.createElement(Field, { label: "Ends At", help: "Leave blank when the surface should stay live until staff changes it." }, /* @__PURE__ */ React.createElement(DateTimePicker, { value: definitionForm.ends_at, onChange: (nextValue) => setDefinitionForm((current) => ({ ...current, ends_at: nextValue })), placeholder: "End time", clearable: true, className: "bg-white/[0.04]" })), /* @__PURE__ */ React.createElement(Field, { label: "Fallback Surface Key", help: "Optional fallback when this definition is inactive, scheduled out, or resolves no items." }, /* @__PURE__ */ React.createElement("input", { value: definitionForm.fallback_surface_key, onChange: (event) => setDefinitionForm((current) => ({ ...current, fallback_surface_key: event.target.value })), className: "w-full rounded-2xl border border-white/10 bg-white/[0.04] px-4 py-3 text-white outline-none", maxLength: 120 })), /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-3 rounded-2xl border border-white/10 bg-white/[0.04] px-4 py-3 text-sm text-white" }, /* @__PURE__ */ React.createElement(Checkbox, { checked: definitionForm.is_active, onChange: (event) => setDefinitionForm((current) => ({ ...current, is_active: event.target.checked })), label: "Active" }))), /* @__PURE__ */ React.createElement(Field, { label: "Description", help: "Operational note for staff browsing this surface later." }, /* @__PURE__ */ React.createElement("textarea", { value: definitionForm.description, onChange: (event) => setDefinitionForm((current) => ({ ...current, description: event.target.value })), className: "mt-4 min-h-[96px] w-full rounded-2xl border border-white/10 bg-white/[0.04] px-4 py-3 text-white outline-none", maxLength: 400 })), /* @__PURE__ */ React.createElement(Field, { label: "Rules JSON", help: "Supported filters include campaign, event, season, type, presentation_style, theme_token, collaboration_mode, owner_username or owner_usernames, commercial_eligible_only, analytics_enabled_only, min_quality_score, min_ranking_score, include_collection_ids, exclude_collection_ids, and featured_only." }, /* @__PURE__ */ React.createElement("textarea", { value: definitionForm.rules_json, onChange: (event) => setDefinitionForm((current) => ({ ...current, rules_json: event.target.value })), className: "mt-4 min-h-[160px] w-full rounded-2xl border border-white/10 bg-slate-950/50 px-4 py-3 font-mono text-sm text-white outline-none", spellCheck: false })), /* @__PURE__ */ React.createElement("div", { className: "mt-5 flex flex-wrap items-center gap-3" }, /* @__PURE__ */ React.createElement("button", { type: "submit", disabled: busy === "definition", className: "inline-flex items-center gap-2 rounded-2xl border border-sky-300/20 bg-sky-400/10 px-5 py-3 text-sm font-semibold text-sky-100 transition hover:bg-sky-400/15 disabled:opacity-60" }, /* @__PURE__ */ React.createElement("i", { className: `fa-solid ${busy === "definition" ? "fa-circle-notch fa-spin" : "fa-layer-group"} fa-fw` }), definitionForm.id ? "Update Definition" : "Save Definition"), definitionForm.id ? /* @__PURE__ */ React.createElement("button", { type: "button", onClick: resetDefinitionForm, className: "inline-flex items-center gap-2 rounded-2xl border border-white/10 bg-white/[0.04] px-5 py-3 text-sm font-semibold text-white transition hover:bg-white/[0.07]" }, /* @__PURE__ */ React.createElement("i", { className: "fa-solid fa-rotate-left fa-fw" }), "Cancel Edit") : null)), /* @__PURE__ */ React.createElement("form", { onSubmit: handlePlacementSubmit, className: "rounded-[32px] border border-white/10 bg-white/[0.04] p-6 backdrop-blur-sm md:p-7" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.22em] text-amber-200/80" }, "Surface Placement"), /* @__PURE__ */ React.createElement("h2", { className: "mt-2 text-2xl font-semibold text-white" }, "Manual and campaign slots")), /* @__PURE__ */ React.createElement("div", { className: "mt-6 grid gap-4 md:grid-cols-2" }, /* @__PURE__ */ React.createElement(Field, { label: "Surface" }, /* @__PURE__ */ React.createElement(NovaSelect, { value: placementForm.surface_key, onChange: (val) => setPlacementForm((current) => ({ ...current, surface_key: val })), options: surfaceKeyOptions.map((o) => ({ value: o, label: o })) })), /* @__PURE__ */ React.createElement(Field, { label: "Collection" }, /* @__PURE__ */ React.createElement(NovaSelect, { value: String(placementForm.collection_id || ""), onChange: (val) => setPlacementForm((current) => ({ ...current, collection_id: val })), options: collectionOptions.map((o) => ({ value: String(o.id), label: o.title })) })), /* @__PURE__ */ React.createElement(Field, { label: "Placement Type" }, /* @__PURE__ */ React.createElement(NovaSelect, { value: placementForm.placement_type, onChange: (val) => setPlacementForm((current) => ({ ...current, placement_type: val })), searchable: false, options: [{ value: "manual", label: "Manual" }, { value: "campaign", label: "Campaign" }, { value: "scheduled_override", label: "Scheduled override" }] })), /* @__PURE__ */ React.createElement(Field, { label: "Priority" }, /* @__PURE__ */ React.createElement("input", { type: "number", min: "-100", max: "100", value: placementForm.priority, onChange: (event) => setPlacementForm((current) => ({ ...current, priority: event.target.value })), className: "w-full rounded-2xl border border-white/10 bg-white/[0.04] px-4 py-3 text-white outline-none" })), /* @__PURE__ */ React.createElement(Field, { label: "Starts At" }, /* @__PURE__ */ React.createElement(DateTimePicker, { value: placementForm.starts_at, onChange: (nextValue) => setPlacementForm((current) => ({ ...current, starts_at: nextValue })), placeholder: "Start time", clearable: true, className: "bg-white/[0.04]" })), /* @__PURE__ */ React.createElement(Field, { label: "Ends At" }, /* @__PURE__ */ React.createElement(DateTimePicker, { value: placementForm.ends_at, onChange: (nextValue) => setPlacementForm((current) => ({ ...current, ends_at: nextValue })), placeholder: "End time", clearable: true, className: "bg-white/[0.04]" })), /* @__PURE__ */ React.createElement(Field, { label: "Campaign Key", help: "Optional campaign label for reporting and grouped overrides." }, /* @__PURE__ */ React.createElement("input", { value: placementForm.campaign_key, onChange: (event) => setPlacementForm((current) => ({ ...current, campaign_key: event.target.value })), className: "w-full rounded-2xl border border-white/10 bg-white/[0.04] px-4 py-3 text-white outline-none", maxLength: 80 })), /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-3 rounded-2xl border border-white/10 bg-white/[0.04] px-4 py-3 text-sm text-white" }, /* @__PURE__ */ React.createElement(Checkbox, { checked: placementForm.is_active, onChange: (event) => setPlacementForm((current) => ({ ...current, is_active: event.target.checked })), label: "Active placement" }))), /* @__PURE__ */ React.createElement(Field, { label: "Notes", help: "Internal note for why this collection owns the slot." }, /* @__PURE__ */ React.createElement("textarea", { value: placementForm.notes, onChange: (event) => setPlacementForm((current) => ({ ...current, notes: event.target.value })), className: "mt-4 min-h-[110px] w-full rounded-2xl border border-white/10 bg-white/[0.04] px-4 py-3 text-white outline-none", maxLength: 1e3 })), /* @__PURE__ */ React.createElement("div", { className: "mt-5 flex flex-wrap items-center gap-3" }, /* @__PURE__ */ React.createElement("button", { type: "submit", disabled: busy === "placement", className: "inline-flex items-center gap-2 rounded-2xl border border-amber-300/20 bg-amber-400/10 px-5 py-3 text-sm font-semibold text-amber-100 transition hover:bg-amber-400/15 disabled:opacity-60" }, /* @__PURE__ */ React.createElement("i", { className: `fa-solid ${busy === "placement" ? "fa-circle-notch fa-spin" : "fa-thumbtack"} fa-fw` }), placementForm.id ? "Update Placement" : "Save Placement"), placementForm.id ? /* @__PURE__ */ React.createElement("button", { type: "button", onClick: resetPlacementForm, className: "inline-flex items-center gap-2 rounded-2xl border border-white/10 bg-white/[0.04] px-5 py-3 text-sm font-semibold text-white transition hover:bg-white/[0.07]" }, /* @__PURE__ */ React.createElement("i", { className: "fa-solid fa-rotate-left fa-fw" }), "Cancel Edit") : null))), /* @__PURE__ */ React.createElement("section", { className: "mt-8 rounded-[32px] border border-white/10 bg-white/[0.04] p-6 backdrop-blur-sm md:p-7" }, /* @__PURE__ */ React.createElement("div", { className: "flex flex-wrap items-center justify-between gap-3" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.22em] text-lime-200/80" }, "Batch Editorial Tools"), /* @__PURE__ */ React.createElement("h2", { className: "mt-2 text-2xl font-semibold text-white" }, "Campaign planning in one pass")), /* @__PURE__ */ React.createElement("span", { className: "rounded-full border border-white/10 bg-white/[0.04] px-3 py-1 text-xs font-semibold text-slate-300" }, batchForm.collection_ids.length, " selected")), /* @__PURE__ */ React.createElement("div", { className: "mt-6 grid gap-6 xl:grid-cols-[minmax(0,0.95fr)_minmax(0,1.05fr)]" }, /* @__PURE__ */ React.createElement("div", { className: "space-y-4" }, /* @__PURE__ */ React.createElement("div", { className: "rounded-[26px] border border-white/10 bg-slate-950/40 p-5" }, /* @__PURE__ */ React.createElement("p", { className: "text-sm font-semibold text-white" }, "Choose collections"), /* @__PURE__ */ React.createElement("p", { className: "mt-2 text-sm text-slate-300" }, "The selector uses current public discovery candidates so staff can quickly prepare a seasonal or editorial run."), /* @__PURE__ */ React.createElement("div", { className: "mt-4 grid gap-3 md:grid-cols-2" }, collectionOptions.map((option) => { + return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Se, null, /* @__PURE__ */ React.createElement("title", null, seo.title || "Collection Surfaces — Skinbase"), /* @__PURE__ */ React.createElement("meta", { name: "description", content: seo.description || "Staff tools for collection surfaces." }), seo.canonical ? /* @__PURE__ */ React.createElement("link", { rel: "canonical", href: seo.canonical }) : null, /* @__PURE__ */ React.createElement("meta", { name: "robots", content: seo.robots || "noindex,follow" })), /* @__PURE__ */ React.createElement("div", { className: "relative min-h-screen overflow-hidden pb-16" }, /* @__PURE__ */ React.createElement("div", { "aria-hidden": "true", className: "pointer-events-none absolute inset-x-0 top-0 -z-10 h-[34rem] opacity-95", style: { background: "radial-gradient(circle at 15% 14%, rgba(245,158,11,0.16), transparent 26%), radial-gradient(circle at 82% 18%, rgba(56,189,248,0.16), transparent 24%), linear-gradient(180deg, #07101d 0%, #0a1220 42%, #08111f 100%)" } }), /* @__PURE__ */ React.createElement("div", { "aria-hidden": "true", className: "pointer-events-none absolute inset-0 -z-10 opacity-[0.05]", style: { backgroundImage: "url(/gfx/noise.png)", backgroundSize: "180px" } }), /* @__PURE__ */ React.createElement("div", { className: "mx-auto max-w-7xl px-4 pt-8 md:px-6" }, /* @__PURE__ */ React.createElement("section", { className: "rounded-[34px] border border-white/10 bg-white/[0.04] p-6 shadow-[0_30px_90px_rgba(2,6,23,0.28)] backdrop-blur-sm md:p-8" }, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.22em] text-amber-200/80" }, "Staff Surfaces"), /* @__PURE__ */ React.createElement("h1", { className: "mt-3 text-4xl font-semibold tracking-[-0.05em] text-white md:text-5xl" }, "Collections placement studio"), /* @__PURE__ */ React.createElement("p", { className: "mt-4 max-w-3xl text-sm leading-relaxed text-slate-300 md:text-[15px]" }, "Define reusable discovery surfaces, then place eligible public collections into manual or campaign-specific slots with clear timing and notes."), notice ? /* @__PURE__ */ React.createElement("p", { className: "mt-4 text-sm text-sky-100" }, notice) : null), /* @__PURE__ */ React.createElement("section", { className: "mt-8 grid gap-6 xl:grid-cols-[minmax(0,0.95fr)_minmax(0,1.05fr)]" }, /* @__PURE__ */ React.createElement("form", { onSubmit: handleDefinitionSubmit, className: "rounded-[32px] border border-white/10 bg-white/[0.04] p-6 backdrop-blur-sm md:p-7" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.22em] text-sky-200/80" }, "Surface Definition"), /* @__PURE__ */ React.createElement("h2", { className: "mt-2 text-2xl font-semibold text-white" }, "Rules and ranking")), definitionForm.id ? /* @__PURE__ */ React.createElement("p", { className: "mt-3 text-sm text-slate-300" }, "Editing ", /* @__PURE__ */ React.createElement("span", { className: "font-semibold text-white" }, definitionForm.surface_key)) : null, /* @__PURE__ */ React.createElement("div", { className: "mt-6 grid gap-4 md:grid-cols-2" }, /* @__PURE__ */ React.createElement(Field, { label: "Surface Key", help: definitionForm.id ? "Surface keys stay stable during edits so existing placements remain attached." : null }, /* @__PURE__ */ React.createElement("input", { value: definitionForm.surface_key, onChange: (event) => setDefinitionForm((current) => ({ ...current, surface_key: event.target.value })), disabled: Boolean(definitionForm.id), className: "w-full rounded-2xl border border-white/10 bg-white/[0.04] px-4 py-3 text-white outline-none disabled:cursor-not-allowed disabled:opacity-60", maxLength: 120 })), /* @__PURE__ */ React.createElement(Field, { label: "Title" }, /* @__PURE__ */ React.createElement("input", { value: definitionForm.title, onChange: (event) => setDefinitionForm((current) => ({ ...current, title: event.target.value })), className: "w-full rounded-2xl border border-white/10 bg-white/[0.04] px-4 py-3 text-white outline-none", maxLength: 160 })), /* @__PURE__ */ React.createElement(Field, { label: "Mode" }, /* @__PURE__ */ React.createElement(NovaSelect, { value: definitionForm.mode, onChange: (val) => setDefinitionForm((current) => ({ ...current, mode: val })), searchable: false, options: [{ value: "manual", label: "Manual" }, { value: "automatic", label: "Automatic" }, { value: "hybrid", label: "Hybrid" }] })), /* @__PURE__ */ React.createElement(Field, { label: "Ranking" }, /* @__PURE__ */ React.createElement(NovaSelect, { value: definitionForm.ranking_mode, onChange: (val) => setDefinitionForm((current) => ({ ...current, ranking_mode: val })), searchable: false, options: [{ value: "ranking_score", label: "Ranking score" }, { value: "recent_activity", label: "Recent activity" }, { value: "quality_score", label: "Quality score" }] })), /* @__PURE__ */ React.createElement(Field, { label: "Max Items" }, /* @__PURE__ */ React.createElement("input", { type: "number", min: "1", max: "24", value: definitionForm.max_items, onChange: (event) => setDefinitionForm((current) => ({ ...current, max_items: event.target.value })), className: "w-full rounded-2xl border border-white/10 bg-white/[0.04] px-4 py-3 text-white outline-none" })), /* @__PURE__ */ React.createElement(Field, { label: "Starts At", help: "Optional activation window for the full surface definition." }, /* @__PURE__ */ React.createElement(DateTimePicker, { value: definitionForm.starts_at, onChange: (nextValue) => setDefinitionForm((current) => ({ ...current, starts_at: nextValue })), placeholder: "Start time", clearable: true, className: "bg-white/[0.04]" })), /* @__PURE__ */ React.createElement(Field, { label: "Ends At", help: "Leave blank when the surface should stay live until staff changes it." }, /* @__PURE__ */ React.createElement(DateTimePicker, { value: definitionForm.ends_at, onChange: (nextValue) => setDefinitionForm((current) => ({ ...current, ends_at: nextValue })), placeholder: "End time", clearable: true, className: "bg-white/[0.04]" })), /* @__PURE__ */ React.createElement(Field, { label: "Fallback Surface Key", help: "Optional fallback when this definition is inactive, scheduled out, or resolves no items." }, /* @__PURE__ */ React.createElement("input", { value: definitionForm.fallback_surface_key, onChange: (event) => setDefinitionForm((current) => ({ ...current, fallback_surface_key: event.target.value })), className: "w-full rounded-2xl border border-white/10 bg-white/[0.04] px-4 py-3 text-white outline-none", maxLength: 120 })), /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-3 rounded-2xl border border-white/10 bg-white/[0.04] px-4 py-3 text-sm text-white" }, /* @__PURE__ */ React.createElement(Checkbox, { checked: definitionForm.is_active, onChange: (event) => setDefinitionForm((current) => ({ ...current, is_active: event.target.checked })), label: "Active" }))), /* @__PURE__ */ React.createElement(Field, { label: "Description", help: "Operational note for staff browsing this surface later." }, /* @__PURE__ */ React.createElement("textarea", { value: definitionForm.description, onChange: (event) => setDefinitionForm((current) => ({ ...current, description: event.target.value })), className: "mt-4 min-h-[96px] w-full rounded-2xl border border-white/10 bg-white/[0.04] px-4 py-3 text-white outline-none", maxLength: 400 })), /* @__PURE__ */ React.createElement(Field, { label: "Rules JSON", help: "Supported filters include campaign, event, season, type, presentation_style, theme_token, collaboration_mode, owner_username or owner_usernames, commercial_eligible_only, analytics_enabled_only, min_quality_score, min_ranking_score, include_collection_ids, exclude_collection_ids, and featured_only." }, /* @__PURE__ */ React.createElement("textarea", { value: definitionForm.rules_json, onChange: (event) => setDefinitionForm((current) => ({ ...current, rules_json: event.target.value })), className: "mt-4 min-h-[160px] w-full rounded-2xl border border-white/10 bg-slate-950/50 px-4 py-3 font-mono text-sm text-white outline-none", spellCheck: false })), /* @__PURE__ */ React.createElement("div", { className: "mt-5 flex flex-wrap items-center gap-3" }, /* @__PURE__ */ React.createElement("button", { type: "submit", disabled: busy === "definition", className: "inline-flex items-center gap-2 rounded-2xl border border-sky-300/20 bg-sky-400/10 px-5 py-3 text-sm font-semibold text-sky-100 transition hover:bg-sky-400/15 disabled:opacity-60" }, /* @__PURE__ */ React.createElement("i", { className: `fa-solid ${busy === "definition" ? "fa-circle-notch fa-spin" : "fa-layer-group"} fa-fw` }), definitionForm.id ? "Update Definition" : "Save Definition"), definitionForm.id ? /* @__PURE__ */ React.createElement("button", { type: "button", onClick: resetDefinitionForm, className: "inline-flex items-center gap-2 rounded-2xl border border-white/10 bg-white/[0.04] px-5 py-3 text-sm font-semibold text-white transition hover:bg-white/[0.07]" }, /* @__PURE__ */ React.createElement("i", { className: "fa-solid fa-rotate-left fa-fw" }), "Cancel Edit") : null)), /* @__PURE__ */ React.createElement("form", { onSubmit: handlePlacementSubmit, className: "rounded-[32px] border border-white/10 bg-white/[0.04] p-6 backdrop-blur-sm md:p-7" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.22em] text-amber-200/80" }, "Surface Placement"), /* @__PURE__ */ React.createElement("h2", { className: "mt-2 text-2xl font-semibold text-white" }, "Manual and campaign slots")), /* @__PURE__ */ React.createElement("div", { className: "mt-6 grid gap-4 md:grid-cols-2" }, /* @__PURE__ */ React.createElement(Field, { label: "Surface" }, /* @__PURE__ */ React.createElement(NovaSelect, { value: placementForm.surface_key, onChange: (val) => setPlacementForm((current) => ({ ...current, surface_key: val })), options: surfaceKeyOptions.map((o) => ({ value: o, label: o })) })), /* @__PURE__ */ React.createElement(Field, { label: "Collection" }, /* @__PURE__ */ React.createElement(NovaSelect, { value: String(placementForm.collection_id || ""), onChange: (val) => setPlacementForm((current) => ({ ...current, collection_id: val })), options: collectionOptions.map((o) => ({ value: String(o.id), label: o.title })) })), /* @__PURE__ */ React.createElement(Field, { label: "Placement Type" }, /* @__PURE__ */ React.createElement(NovaSelect, { value: placementForm.placement_type, onChange: (val) => setPlacementForm((current) => ({ ...current, placement_type: val })), searchable: false, options: [{ value: "manual", label: "Manual" }, { value: "campaign", label: "Campaign" }, { value: "scheduled_override", label: "Scheduled override" }] })), /* @__PURE__ */ React.createElement(Field, { label: "Priority" }, /* @__PURE__ */ React.createElement("input", { type: "number", min: "-100", max: "100", value: placementForm.priority, onChange: (event) => setPlacementForm((current) => ({ ...current, priority: event.target.value })), className: "w-full rounded-2xl border border-white/10 bg-white/[0.04] px-4 py-3 text-white outline-none" })), /* @__PURE__ */ React.createElement(Field, { label: "Starts At" }, /* @__PURE__ */ React.createElement(DateTimePicker, { value: placementForm.starts_at, onChange: (nextValue) => setPlacementForm((current) => ({ ...current, starts_at: nextValue })), placeholder: "Start time", clearable: true, className: "bg-white/[0.04]" })), /* @__PURE__ */ React.createElement(Field, { label: "Ends At" }, /* @__PURE__ */ React.createElement(DateTimePicker, { value: placementForm.ends_at, onChange: (nextValue) => setPlacementForm((current) => ({ ...current, ends_at: nextValue })), placeholder: "End time", clearable: true, className: "bg-white/[0.04]" })), /* @__PURE__ */ React.createElement(Field, { label: "Campaign Key", help: "Optional campaign label for reporting and grouped overrides." }, /* @__PURE__ */ React.createElement("input", { value: placementForm.campaign_key, onChange: (event) => setPlacementForm((current) => ({ ...current, campaign_key: event.target.value })), className: "w-full rounded-2xl border border-white/10 bg-white/[0.04] px-4 py-3 text-white outline-none", maxLength: 80 })), /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-3 rounded-2xl border border-white/10 bg-white/[0.04] px-4 py-3 text-sm text-white" }, /* @__PURE__ */ React.createElement(Checkbox, { checked: placementForm.is_active, onChange: (event) => setPlacementForm((current) => ({ ...current, is_active: event.target.checked })), label: "Active placement" }))), /* @__PURE__ */ React.createElement(Field, { label: "Notes", help: "Internal note for why this collection owns the slot." }, /* @__PURE__ */ React.createElement("textarea", { value: placementForm.notes, onChange: (event) => setPlacementForm((current) => ({ ...current, notes: event.target.value })), className: "mt-4 min-h-[110px] w-full rounded-2xl border border-white/10 bg-white/[0.04] px-4 py-3 text-white outline-none", maxLength: 1e3 })), /* @__PURE__ */ React.createElement("div", { className: "mt-5 flex flex-wrap items-center gap-3" }, /* @__PURE__ */ React.createElement("button", { type: "submit", disabled: busy === "placement", className: "inline-flex items-center gap-2 rounded-2xl border border-amber-300/20 bg-amber-400/10 px-5 py-3 text-sm font-semibold text-amber-100 transition hover:bg-amber-400/15 disabled:opacity-60" }, /* @__PURE__ */ React.createElement("i", { className: `fa-solid ${busy === "placement" ? "fa-circle-notch fa-spin" : "fa-thumbtack"} fa-fw` }), placementForm.id ? "Update Placement" : "Save Placement"), placementForm.id ? /* @__PURE__ */ React.createElement("button", { type: "button", onClick: resetPlacementForm, className: "inline-flex items-center gap-2 rounded-2xl border border-white/10 bg-white/[0.04] px-5 py-3 text-sm font-semibold text-white transition hover:bg-white/[0.07]" }, /* @__PURE__ */ React.createElement("i", { className: "fa-solid fa-rotate-left fa-fw" }), "Cancel Edit") : null))), /* @__PURE__ */ React.createElement("section", { className: "mt-8 rounded-[32px] border border-white/10 bg-white/[0.04] p-6 backdrop-blur-sm md:p-7" }, /* @__PURE__ */ React.createElement("div", { className: "flex flex-wrap items-center justify-between gap-3" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.22em] text-lime-200/80" }, "Batch Editorial Tools"), /* @__PURE__ */ React.createElement("h2", { className: "mt-2 text-2xl font-semibold text-white" }, "Campaign planning in one pass")), /* @__PURE__ */ React.createElement("span", { className: "rounded-full border border-white/10 bg-white/[0.04] px-3 py-1 text-xs font-semibold text-slate-300" }, batchForm.collection_ids.length, " selected")), /* @__PURE__ */ React.createElement("div", { className: "mt-6 grid gap-6 xl:grid-cols-[minmax(0,0.95fr)_minmax(0,1.05fr)]" }, /* @__PURE__ */ React.createElement("div", { className: "space-y-4" }, /* @__PURE__ */ React.createElement("div", { className: "rounded-[26px] border border-white/10 bg-slate-950/40 p-5" }, /* @__PURE__ */ React.createElement("p", { className: "text-sm font-semibold text-white" }, "Choose collections"), /* @__PURE__ */ React.createElement("p", { className: "mt-2 text-sm text-slate-300" }, "The selector uses current public discovery candidates so staff can quickly prepare a seasonal or editorial run."), /* @__PURE__ */ React.createElement("div", { className: "mt-4 grid gap-3 md:grid-cols-2" }, collectionOptions.map((option) => { const checked = batchForm.collection_ids.includes(option.id); return /* @__PURE__ */ React.createElement("label", { key: option.id, className: `flex cursor-pointer items-start gap-3 rounded-[22px] border px-4 py-3 transition ${checked ? "border-lime-300/30 bg-lime-400/10" : "border-white/10 bg-white/[0.04] hover:bg-white/[0.07]"}` }, /* @__PURE__ */ React.createElement(Checkbox, { checked, onChange: () => toggleBatchCollection(option.id) }), /* @__PURE__ */ React.createElement("span", { className: "min-w-0" }, /* @__PURE__ */ React.createElement("span", { className: "block truncate text-sm font-semibold text-white" }, option.title), /* @__PURE__ */ React.createElement("span", { className: "mt-1 block text-xs text-slate-400" }, option.type || "collection", " · ", option.visibility || "public"))); }))), /* @__PURE__ */ React.createElement("div", { className: "rounded-[26px] border border-white/10 bg-slate-950/40 p-5" }, /* @__PURE__ */ React.createElement("p", { className: "text-sm font-semibold text-white" }, "Campaign metadata"), /* @__PURE__ */ React.createElement("div", { className: "mt-4 grid gap-4 md:grid-cols-2" }, /* @__PURE__ */ React.createElement(Field, { label: "Campaign Key" }, /* @__PURE__ */ React.createElement("input", { value: batchForm.campaign_key, onChange: (event) => setBatchForm((current) => ({ ...current, campaign_key: event.target.value })), className: "w-full rounded-2xl border border-white/10 bg-white/[0.04] px-4 py-3 text-white outline-none", maxLength: 80 })), /* @__PURE__ */ React.createElement(Field, { label: "Campaign Label" }, /* @__PURE__ */ React.createElement("input", { value: batchForm.campaign_label, onChange: (event) => setBatchForm((current) => ({ ...current, campaign_label: event.target.value })), className: "w-full rounded-2xl border border-white/10 bg-white/[0.04] px-4 py-3 text-white outline-none", maxLength: 120 })), /* @__PURE__ */ React.createElement(Field, { label: "Event Label" }, /* @__PURE__ */ React.createElement("input", { value: batchForm.event_label, onChange: (event) => setBatchForm((current) => ({ ...current, event_label: event.target.value })), className: "w-full rounded-2xl border border-white/10 bg-white/[0.04] px-4 py-3 text-white outline-none", maxLength: 120 })), /* @__PURE__ */ React.createElement(Field, { label: "Season Key" }, /* @__PURE__ */ React.createElement("input", { value: batchForm.season_key, onChange: (event) => setBatchForm((current) => ({ ...current, season_key: event.target.value })), className: "w-full rounded-2xl border border-white/10 bg-white/[0.04] px-4 py-3 text-white outline-none", maxLength: 80 }))), /* @__PURE__ */ React.createElement(Field, { label: "Editorial Notes", help: "Shared context recorded on each selected collection." }, /* @__PURE__ */ React.createElement("textarea", { value: batchForm.editorial_notes, onChange: (event) => setBatchForm((current) => ({ ...current, editorial_notes: event.target.value })), className: "mt-4 min-h-[120px] w-full rounded-2xl border border-white/10 bg-white/[0.04] px-4 py-3 text-white outline-none", maxLength: 4e3 })))), /* @__PURE__ */ React.createElement("div", { className: "space-y-4" }, /* @__PURE__ */ React.createElement("div", { className: "rounded-[26px] border border-white/10 bg-slate-950/40 p-5" }, /* @__PURE__ */ React.createElement("p", { className: "text-sm font-semibold text-white" }, "Optional placement plan"), /* @__PURE__ */ React.createElement("p", { className: "mt-2 text-sm text-slate-300" }, "If you set a surface, the preview shows which collections can safely be placed and which ones will be skipped."), /* @__PURE__ */ React.createElement("div", { className: "mt-4 grid gap-4 md:grid-cols-2" }, /* @__PURE__ */ React.createElement(Field, { label: "Surface" }, /* @__PURE__ */ React.createElement(NovaSelect, { value: batchForm.surface_key, onChange: (val) => setBatchForm((current) => ({ ...current, surface_key: val })), placeholder: "No placement", options: surfaceKeyOptions.map((o) => ({ value: o, label: o })) })), /* @__PURE__ */ React.createElement(Field, { label: "Placement Type" }, /* @__PURE__ */ React.createElement(NovaSelect, { value: batchForm.placement_type, onChange: (val) => setBatchForm((current) => ({ ...current, placement_type: val })), searchable: false, options: [{ value: "campaign", label: "Campaign" }, { value: "manual", label: "Manual" }, { value: "scheduled_override", label: "Scheduled override" }] })), /* @__PURE__ */ React.createElement(Field, { label: "Priority" }, /* @__PURE__ */ React.createElement("input", { type: "number", min: "-100", max: "100", value: batchForm.priority, onChange: (event) => setBatchForm((current) => ({ ...current, priority: event.target.value })), className: "w-full rounded-2xl border border-white/10 bg-white/[0.04] px-4 py-3 text-white outline-none" })), /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-3 rounded-2xl border border-white/10 bg-white/[0.04] px-4 py-3 text-sm text-white" }, /* @__PURE__ */ React.createElement(Checkbox, { checked: batchForm.is_active, onChange: (event) => setBatchForm((current) => ({ ...current, is_active: event.target.checked })), label: "Active placement" })), /* @__PURE__ */ React.createElement(Field, { label: "Starts At" }, /* @__PURE__ */ React.createElement(DateTimePicker, { value: batchForm.starts_at, onChange: (nextValue) => setBatchForm((current) => ({ ...current, starts_at: nextValue })), placeholder: "Start time", clearable: true, className: "bg-white/[0.04]" })), /* @__PURE__ */ React.createElement(Field, { label: "Ends At" }, /* @__PURE__ */ React.createElement(DateTimePicker, { value: batchForm.ends_at, onChange: (nextValue) => setBatchForm((current) => ({ ...current, ends_at: nextValue })), placeholder: "End time", clearable: true, className: "bg-white/[0.04]" }))), /* @__PURE__ */ React.createElement(Field, { label: "Placement Notes" }, /* @__PURE__ */ React.createElement("textarea", { value: batchForm.notes, onChange: (event) => setBatchForm((current) => ({ ...current, notes: event.target.value })), className: "mt-4 min-h-[110px] w-full rounded-2xl border border-white/10 bg-white/[0.04] px-4 py-3 text-white outline-none", maxLength: 1e3 })), /* @__PURE__ */ React.createElement("div", { className: "mt-5 flex flex-wrap gap-3" }, /* @__PURE__ */ React.createElement("button", { type: "button", onClick: () => handleBatchEditorial("preview"), disabled: busy === "batch-preview", className: "inline-flex items-center gap-2 rounded-2xl border border-lime-300/20 bg-lime-400/10 px-5 py-3 text-sm font-semibold text-lime-100 transition hover:bg-lime-400/15 disabled:opacity-60" }, /* @__PURE__ */ React.createElement("i", { className: `fa-solid ${busy === "batch-preview" ? "fa-circle-notch fa-spin" : "fa-flask"} fa-fw` }), "Preview Batch"), /* @__PURE__ */ React.createElement("button", { type: "button", onClick: () => handleBatchEditorial("apply"), disabled: busy === "batch-apply", className: "inline-flex items-center gap-2 rounded-2xl border border-amber-300/20 bg-amber-400/10 px-5 py-3 text-sm font-semibold text-amber-100 transition hover:bg-amber-400/15 disabled:opacity-60" }, /* @__PURE__ */ React.createElement("i", { className: `fa-solid ${busy === "batch-apply" ? "fa-circle-notch fa-spin" : "fa-wand-magic-sparkles"} fa-fw` }), "Apply Batch"))), batchResult ? /* @__PURE__ */ React.createElement("div", { className: "rounded-[26px] border border-white/10 bg-slate-950/40 p-5" }, /* @__PURE__ */ React.createElement("div", { className: "flex flex-wrap items-center justify-between gap-3" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", { className: "text-sm font-semibold text-white" }, "Preview results"), /* @__PURE__ */ React.createElement("p", { className: "mt-1 text-sm text-slate-300" }, batchResult.collections_count, " collections reviewed, ", batchResult.placement_eligible_count, " placement-ready."))), /* @__PURE__ */ React.createElement("div", { className: "mt-4 space-y-3" }, (batchResult.items || []).map((item) => /* @__PURE__ */ React.createElement("div", { key: item.collection?.id, className: "rounded-[22px] border border-white/10 bg-white/[0.04] p-4" }, /* @__PURE__ */ React.createElement("div", { className: "flex flex-wrap items-center justify-between gap-3" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", { className: "text-sm font-semibold text-white" }, item.collection?.title), /* @__PURE__ */ React.createElement("p", { className: "mt-1 text-xs text-slate-400" }, item.collection?.visibility, " · ", item.collection?.lifecycle_state, " · ", item.collection?.moderation_status)), item.placement ? /* @__PURE__ */ React.createElement("span", { className: `rounded-full border px-3 py-1 text-[11px] font-semibold uppercase tracking-[0.18em] ${item.placement.eligible ? "border-lime-300/20 bg-lime-400/10 text-lime-100" : "border-rose-300/20 bg-rose-400/10 text-rose-100"}` }, item.placement.eligible ? `ready for ${item.placement.surface_key}` : "placement skipped") : /* @__PURE__ */ React.createElement("span", { className: "rounded-full border border-white/10 bg-white/[0.04] px-3 py-1 text-[11px] font-semibold uppercase tracking-[0.18em] text-slate-300" }, "metadata only")), item.eligibility?.reasons?.length ? /* @__PURE__ */ React.createElement("p", { className: "mt-3 text-xs text-amber-100/80" }, "Campaign readiness: ", item.eligibility.reasons.join(" ")) : null, item.placement?.reasons?.length ? /* @__PURE__ */ React.createElement("p", { className: "mt-2 text-xs text-rose-100/80" }, "Placement: ", item.placement.reasons.join(" ")) : null)))) : null))), /* @__PURE__ */ React.createElement("section", { className: "mt-8 rounded-[32px] border border-white/10 bg-white/[0.04] p-6 backdrop-blur-sm md:p-7" }, /* @__PURE__ */ React.createElement("div", { className: "flex flex-wrap items-center justify-between gap-3" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.22em] text-sky-200/80" }, "Definitions"), /* @__PURE__ */ React.createElement("h2", { className: "mt-2 text-2xl font-semibold text-white" }, "Registered surfaces")), /* @__PURE__ */ React.createElement("span", { className: "rounded-full border border-white/10 bg-white/[0.04] px-3 py-1 text-xs font-semibold text-slate-300" }, definitions.length)), /* @__PURE__ */ React.createElement("div", { className: "mt-6 grid gap-4 lg:grid-cols-2" }, definitions.map((definition2) => /* @__PURE__ */ React.createElement("div", { key: definition2.id, className: "rounded-[24px] border border-white/10 bg-slate-950/40 p-5" }, /* @__PURE__ */ React.createElement("div", { className: "flex flex-wrap items-center gap-2" }, /* @__PURE__ */ React.createElement("span", { className: "rounded-full border border-sky-300/20 bg-sky-400/10 px-3 py-1 text-[11px] font-semibold uppercase tracking-[0.18em] text-sky-100" }, definition2.surface_key), /* @__PURE__ */ React.createElement("span", { className: "rounded-full border border-white/10 bg-white/[0.04] px-3 py-1 text-[11px] font-semibold uppercase tracking-[0.18em] text-slate-300" }, definition2.mode)), /* @__PURE__ */ React.createElement("h3", { className: "mt-4 text-lg font-semibold text-white" }, definition2.title), definition2.description ? /* @__PURE__ */ React.createElement("p", { className: "mt-2 text-sm text-slate-300" }, definition2.description) : null, /* @__PURE__ */ React.createElement("div", { className: "mt-4 flex flex-wrap gap-2 text-xs text-slate-400" }, /* @__PURE__ */ React.createElement("span", { className: "rounded-full border border-white/10 bg-white/[0.04] px-3 py-1" }, definition2.ranking_mode), /* @__PURE__ */ React.createElement("span", { className: "rounded-full border border-white/10 bg-white/[0.04] px-3 py-1" }, "max ", definition2.max_items), /* @__PURE__ */ React.createElement("span", { className: "rounded-full border border-white/10 bg-white/[0.04] px-3 py-1" }, definition2.is_active ? "active" : "inactive"), definition2.starts_at ? /* @__PURE__ */ React.createElement("span", { className: "rounded-full border border-white/10 bg-white/[0.04] px-3 py-1" }, "starts ", new Date(definition2.starts_at).toLocaleString()) : null, definition2.ends_at ? /* @__PURE__ */ React.createElement("span", { className: "rounded-full border border-white/10 bg-white/[0.04] px-3 py-1" }, "ends ", new Date(definition2.ends_at).toLocaleString()) : null, definition2.fallback_surface_key ? /* @__PURE__ */ React.createElement("span", { className: "rounded-full border border-white/10 bg-white/[0.04] px-3 py-1" }, "fallback ", definition2.fallback_surface_key) : null), /* @__PURE__ */ React.createElement("div", { className: "mt-4" }, /* @__PURE__ */ React.createElement("div", { className: "flex flex-wrap gap-2" }, /* @__PURE__ */ React.createElement("button", { type: "button", onClick: () => hydrateDefinition(definition2), className: "inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/[0.04] px-4 py-2 text-xs font-semibold text-white transition hover:bg-white/[0.07]" }, /* @__PURE__ */ React.createElement("i", { className: "fa-solid fa-pen fa-fw text-[10px]" }), "Edit Definition"), /* @__PURE__ */ React.createElement("button", { type: "button", onClick: () => handleDeleteDefinition(definition2), disabled: busy === `delete-definition-${definition2.id}`, className: "inline-flex items-center gap-2 rounded-full border border-rose-300/20 bg-rose-400/10 px-4 py-2 text-xs font-semibold text-rose-100 transition hover:bg-rose-400/15 disabled:opacity-60" }, /* @__PURE__ */ React.createElement("i", { className: `fa-solid ${busy === `delete-definition-${definition2.id}` ? "fa-circle-notch fa-spin" : "fa-trash"} fa-fw text-[10px]` }), "Delete"))))))), conflicts.length ? /* @__PURE__ */ React.createElement("section", { className: "mt-8 rounded-[32px] border border-rose-300/20 bg-rose-500/10 p-6 backdrop-blur-sm md:p-7" }, /* @__PURE__ */ React.createElement("div", { className: "flex flex-wrap items-center justify-between gap-3" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.22em] text-rose-100/80" }, "Conflicts"), /* @__PURE__ */ React.createElement("h2", { className: "mt-2 text-2xl font-semibold text-white" }, "Schedule overlaps need review")), /* @__PURE__ */ React.createElement("span", { className: "rounded-full border border-rose-300/20 bg-rose-400/10 px-3 py-1 text-xs font-semibold text-rose-100" }, conflicts.length)), /* @__PURE__ */ React.createElement("div", { className: "mt-6 grid gap-4 lg:grid-cols-2" }, conflicts.map((conflict, index2) => /* @__PURE__ */ React.createElement("div", { key: `${conflict.surface_key}-${index2}`, className: "rounded-[24px] border border-rose-300/20 bg-slate-950/40 p-5" }, /* @__PURE__ */ React.createElement("div", { className: "flex flex-wrap items-center gap-2" }, /* @__PURE__ */ React.createElement("span", { className: "rounded-full border border-rose-300/20 bg-rose-400/10 px-3 py-1 text-[11px] font-semibold uppercase tracking-[0.18em] text-rose-100" }, conflict.surface_key)), /* @__PURE__ */ React.createElement("p", { className: "mt-4 text-sm text-rose-50" }, conflict.summary), /* @__PURE__ */ React.createElement("p", { className: "mt-3 text-xs text-rose-100/70" }, "Window: ", conflict.window?.starts_at ? new Date(conflict.window.starts_at).toLocaleString() : "Immediate", " to ", conflict.window?.ends_at ? new Date(conflict.window.ends_at).toLocaleString() : "Open-ended"))))) : null, /* @__PURE__ */ React.createElement("section", { className: "mt-8 rounded-[32px] border border-white/10 bg-white/[0.04] p-6 backdrop-blur-sm md:p-7" }, /* @__PURE__ */ React.createElement("div", { className: "flex flex-wrap items-center justify-between gap-3" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.22em] text-amber-200/80" }, "Placements"), /* @__PURE__ */ React.createElement("h2", { className: "mt-2 text-2xl font-semibold text-white" }, "Active and scheduled slots")), /* @__PURE__ */ React.createElement("span", { className: "rounded-full border border-white/10 bg-white/[0.04] px-3 py-1 text-xs font-semibold text-slate-300" }, placements.length)), /* @__PURE__ */ React.createElement("div", { className: "mt-6 space-y-5" }, placements.map((placement) => /* @__PURE__ */ React.createElement("div", { key: placement.id, className: "rounded-[28px] border border-white/10 bg-slate-950/40 p-5" }, /* @__PURE__ */ React.createElement("div", { className: "flex flex-wrap items-center justify-between gap-3" }, /* @__PURE__ */ React.createElement("div", { className: "flex flex-wrap items-center gap-2" }, /* @__PURE__ */ React.createElement("span", { className: "rounded-full border border-amber-300/20 bg-amber-400/10 px-3 py-1 text-[11px] font-semibold uppercase tracking-[0.18em] text-amber-100" }, placement.surface_key), /* @__PURE__ */ React.createElement("span", { className: "rounded-full border border-white/10 bg-white/[0.04] px-3 py-1 text-[11px] font-semibold uppercase tracking-[0.18em] text-slate-300" }, placement.placement_type), /* @__PURE__ */ React.createElement("span", { className: "rounded-full border border-white/10 bg-white/[0.04] px-3 py-1 text-[11px] font-semibold uppercase tracking-[0.18em] text-slate-300" }, "priority ", placement.priority), conflictPlacementIds.has(placement.id) || placement.has_conflict ? /* @__PURE__ */ React.createElement("span", { className: "rounded-full border border-rose-300/20 bg-rose-400/10 px-3 py-1 text-[11px] font-semibold uppercase tracking-[0.18em] text-rose-100" }, "conflict") : null), /* @__PURE__ */ React.createElement("div", { className: "flex flex-wrap gap-2" }, /* @__PURE__ */ React.createElement("button", { type: "button", onClick: () => hydratePlacement(placement), className: "inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/[0.04] px-4 py-2 text-xs font-semibold text-white transition hover:bg-white/[0.07]" }, /* @__PURE__ */ React.createElement("i", { className: "fa-solid fa-pen fa-fw text-[10px]" }), "Edit"), /* @__PURE__ */ React.createElement("button", { type: "button", onClick: () => handleDeletePlacement(placement), disabled: busy === `delete-placement-${placement.id}`, className: "inline-flex items-center gap-2 rounded-full border border-rose-300/20 bg-rose-400/10 px-4 py-2 text-xs font-semibold text-rose-100 transition hover:bg-rose-400/15 disabled:opacity-60" }, /* @__PURE__ */ React.createElement("i", { className: `fa-solid ${busy === `delete-placement-${placement.id}` ? "fa-circle-notch fa-spin" : "fa-trash"} fa-fw text-[10px]` }), "Delete"))), /* @__PURE__ */ React.createElement("div", { className: "mt-4 grid gap-5 xl:grid-cols-[minmax(0,1fr)_280px]" }, /* @__PURE__ */ React.createElement("div", null, placement.collection ? /* @__PURE__ */ React.createElement(CollectionCard, { collection: placement.collection, isOwner: true }) : null), /* @__PURE__ */ React.createElement("div", { className: "space-y-3 text-sm text-slate-300" }, /* @__PURE__ */ React.createElement("div", { className: "rounded-[22px] border border-white/10 bg-white/[0.04] px-4 py-3" }, "Starts: ", placement.starts_at ? new Date(placement.starts_at).toLocaleString() : "Immediate"), /* @__PURE__ */ React.createElement("div", { className: "rounded-[22px] border border-white/10 bg-white/[0.04] px-4 py-3" }, "Ends: ", placement.ends_at ? new Date(placement.ends_at).toLocaleString() : "Open-ended"), /* @__PURE__ */ React.createElement("div", { className: "rounded-[22px] border border-white/10 bg-white/[0.04] px-4 py-3" }, "Campaign: ", placement.campaign_key || "None"), /* @__PURE__ */ React.createElement("div", { className: "rounded-[22px] border border-white/10 bg-white/[0.04] px-4 py-3" }, "Status: ", placement.is_active ? "Active" : "Inactive"), placement.notes ? /* @__PURE__ */ React.createElement("div", { className: "rounded-[22px] border border-white/10 bg-white/[0.04] px-4 py-3 text-slate-300" }, placement.notes) : null))))))))); @@ -68919,7 +68919,7 @@ function SavedCollections() { "@context": "https://schema.org", "@type": "CollectionPage", name: "Saved collections", - description: seo?.description || "Your saved collections on Skinbase Nova.", + description: seo?.description || "Your saved collections on Skinbase.", url: seo.canonical, mainEntity: { "@type": "ItemList", @@ -69056,7 +69056,7 @@ function SavedCollections() { setBusy(""); } } - return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(SeoHead, { seo, title: seo?.title || "Saved Collections — Skinbase Nova", description: seo?.description || "Your saved collections on Skinbase Nova.", jsonLd: listSchema }), /* @__PURE__ */ React.createElement("div", { className: "relative min-h-screen overflow-hidden pb-16" }, /* @__PURE__ */ React.createElement("div", { "aria-hidden": "true", className: "pointer-events-none absolute inset-x-0 top-0 -z-10 h-[34rem] opacity-95", style: { background: "radial-gradient(circle at 15% 14%, rgba(245,158,11,0.16), transparent 26%), radial-gradient(circle at 82% 18%, rgba(56,189,248,0.16), transparent 24%), linear-gradient(180deg, #07101d 0%, #0a1220 42%, #08111f 100%)" } }), /* @__PURE__ */ React.createElement("div", { "aria-hidden": "true", className: "pointer-events-none absolute inset-0 -z-10 opacity-[0.05]", style: { backgroundImage: "url(/gfx/noise.png)", backgroundSize: "180px" } }), /* @__PURE__ */ React.createElement("div", { className: "mx-auto max-w-7xl px-4 pt-8 md:px-6" }, /* @__PURE__ */ React.createElement("div", { className: "flex flex-wrap items-center gap-3 text-sm text-slate-300" }, /* @__PURE__ */ React.createElement("a", { href: browseUrl, className: "inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/[0.04] px-4 py-2 transition hover:bg-white/[0.07] hover:text-white" }, /* @__PURE__ */ React.createElement("i", { className: "fa-solid fa-arrow-left fa-fw text-[11px]" }), "Browse collections")), /* @__PURE__ */ React.createElement("section", { className: "mt-6 overflow-hidden rounded-[34px] border border-white/10 bg-white/[0.04] p-6 shadow-[0_30px_90px_rgba(2,6,23,0.28)] backdrop-blur-sm md:p-8" }, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.22em] text-amber-200/80" }, "Library"), /* @__PURE__ */ React.createElement("h1", { className: "mt-3 text-4xl font-semibold tracking-[-0.05em] text-white md:text-5xl" }, "Saved collections"), /* @__PURE__ */ React.createElement("p", { className: "mt-4 max-w-3xl text-sm leading-relaxed text-slate-300 md:text-[15px]" }, "A personal shortlist of collections worth revisiting. Organize them into saved lists, pivot by editorial or campaign relevance, and keep a working shelf of what should influence your next publish."), activeList ? /* @__PURE__ */ React.createElement("p", { className: "mt-4 inline-flex items-center gap-2 rounded-full border border-sky-300/20 bg-sky-400/10 px-4 py-2 text-sm font-semibold text-sky-100" }, /* @__PURE__ */ React.createElement("i", { className: "fa-solid fa-folder-open fa-fw" }), "Viewing list: ", activeList.title) : null, activeFilters.q ? /* @__PURE__ */ React.createElement("p", { className: "mt-4 inline-flex items-center gap-2 rounded-full border border-amber-300/20 bg-amber-400/10 px-4 py-2 text-sm font-semibold text-amber-100" }, /* @__PURE__ */ React.createElement("i", { className: "fa-solid fa-magnifying-glass fa-fw" }), "Search: ", activeFilters.q) : null, notice ? /* @__PURE__ */ React.createElement("p", { className: "mt-4 text-sm text-sky-100" }, notice) : null), /* @__PURE__ */ React.createElement("section", { className: "mt-8 grid gap-6 xl:grid-cols-[320px_minmax(0,1fr)]" }, /* @__PURE__ */ React.createElement("aside", { className: "space-y-5" }, /* @__PURE__ */ React.createElement("section", { className: "rounded-[30px] border border-white/10 bg-white/[0.04] p-5 backdrop-blur-sm" }, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.22em] text-sky-200/80" }, "Search"), /* @__PURE__ */ React.createElement("form", { method: "GET", action: buildSearchActionUrl(searchBaseUrl), className: "mt-4 space-y-3" }, /* @__PURE__ */ React.createElement("input", { name: "q", value: search2, onChange: (event) => setSearch(event.target.value), className: "w-full rounded-2xl border border-white/10 bg-white/[0.04] px-4 py-3 text-white outline-none transition focus:border-sky-300/35", placeholder: "Search titles, notes context, or curator", maxLength: 120 }), activeFilters.filter && activeFilters.filter !== "all" ? /* @__PURE__ */ React.createElement("input", { type: "hidden", name: "filter", value: activeFilters.filter }) : null, activeFilters.sort && activeFilters.sort !== "saved_desc" ? /* @__PURE__ */ React.createElement("input", { type: "hidden", name: "sort", value: activeFilters.sort }) : null, /* @__PURE__ */ React.createElement("div", { className: "flex gap-3" }, /* @__PURE__ */ React.createElement("button", { type: "submit", className: "inline-flex flex-1 items-center justify-center gap-2 rounded-2xl border border-sky-300/20 bg-sky-400/10 px-4 py-3 text-sm font-semibold text-sky-100 transition hover:bg-sky-400/15" }, /* @__PURE__ */ React.createElement("i", { className: "fa-solid fa-magnifying-glass fa-fw" }), "Apply"), activeFilters.q || search2 ? /* @__PURE__ */ React.createElement("a", { href: buildFilterUrl({ q: null }, searchBaseUrl), className: "inline-flex items-center justify-center rounded-2xl border border-white/10 bg-white/[0.04] px-4 py-3 text-sm font-semibold text-white transition hover:bg-white/[0.07]" }, "Clear") : null))), /* @__PURE__ */ React.createElement("section", { className: "rounded-[30px] border border-white/10 bg-white/[0.04] p-5 backdrop-blur-sm" }, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.22em] text-sky-200/80" }, "Filters"), /* @__PURE__ */ React.createElement("div", { className: "mt-4 space-y-3" }, filterOptions.map((option) => /* @__PURE__ */ React.createElement( + return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(SeoHead, { seo, title: seo?.title || "Saved Collections — Skinbase", description: seo?.description || "Your saved collections on Skinbase.", jsonLd: listSchema }), /* @__PURE__ */ React.createElement("div", { className: "relative min-h-screen overflow-hidden pb-16" }, /* @__PURE__ */ React.createElement("div", { "aria-hidden": "true", className: "pointer-events-none absolute inset-x-0 top-0 -z-10 h-[34rem] opacity-95", style: { background: "radial-gradient(circle at 15% 14%, rgba(245,158,11,0.16), transparent 26%), radial-gradient(circle at 82% 18%, rgba(56,189,248,0.16), transparent 24%), linear-gradient(180deg, #07101d 0%, #0a1220 42%, #08111f 100%)" } }), /* @__PURE__ */ React.createElement("div", { "aria-hidden": "true", className: "pointer-events-none absolute inset-0 -z-10 opacity-[0.05]", style: { backgroundImage: "url(/gfx/noise.png)", backgroundSize: "180px" } }), /* @__PURE__ */ React.createElement("div", { className: "mx-auto max-w-7xl px-4 pt-8 md:px-6" }, /* @__PURE__ */ React.createElement("div", { className: "flex flex-wrap items-center gap-3 text-sm text-slate-300" }, /* @__PURE__ */ React.createElement("a", { href: browseUrl, className: "inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/[0.04] px-4 py-2 transition hover:bg-white/[0.07] hover:text-white" }, /* @__PURE__ */ React.createElement("i", { className: "fa-solid fa-arrow-left fa-fw text-[11px]" }), "Browse collections")), /* @__PURE__ */ React.createElement("section", { className: "mt-6 overflow-hidden rounded-[34px] border border-white/10 bg-white/[0.04] p-6 shadow-[0_30px_90px_rgba(2,6,23,0.28)] backdrop-blur-sm md:p-8" }, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.22em] text-amber-200/80" }, "Library"), /* @__PURE__ */ React.createElement("h1", { className: "mt-3 text-4xl font-semibold tracking-[-0.05em] text-white md:text-5xl" }, "Saved collections"), /* @__PURE__ */ React.createElement("p", { className: "mt-4 max-w-3xl text-sm leading-relaxed text-slate-300 md:text-[15px]" }, "A personal shortlist of collections worth revisiting. Organize them into saved lists, pivot by editorial or campaign relevance, and keep a working shelf of what should influence your next publish."), activeList ? /* @__PURE__ */ React.createElement("p", { className: "mt-4 inline-flex items-center gap-2 rounded-full border border-sky-300/20 bg-sky-400/10 px-4 py-2 text-sm font-semibold text-sky-100" }, /* @__PURE__ */ React.createElement("i", { className: "fa-solid fa-folder-open fa-fw" }), "Viewing list: ", activeList.title) : null, activeFilters.q ? /* @__PURE__ */ React.createElement("p", { className: "mt-4 inline-flex items-center gap-2 rounded-full border border-amber-300/20 bg-amber-400/10 px-4 py-2 text-sm font-semibold text-amber-100" }, /* @__PURE__ */ React.createElement("i", { className: "fa-solid fa-magnifying-glass fa-fw" }), "Search: ", activeFilters.q) : null, notice ? /* @__PURE__ */ React.createElement("p", { className: "mt-4 text-sm text-sky-100" }, notice) : null), /* @__PURE__ */ React.createElement("section", { className: "mt-8 grid gap-6 xl:grid-cols-[320px_minmax(0,1fr)]" }, /* @__PURE__ */ React.createElement("aside", { className: "space-y-5" }, /* @__PURE__ */ React.createElement("section", { className: "rounded-[30px] border border-white/10 bg-white/[0.04] p-5 backdrop-blur-sm" }, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.22em] text-sky-200/80" }, "Search"), /* @__PURE__ */ React.createElement("form", { method: "GET", action: buildSearchActionUrl(searchBaseUrl), className: "mt-4 space-y-3" }, /* @__PURE__ */ React.createElement("input", { name: "q", value: search2, onChange: (event) => setSearch(event.target.value), className: "w-full rounded-2xl border border-white/10 bg-white/[0.04] px-4 py-3 text-white outline-none transition focus:border-sky-300/35", placeholder: "Search titles, notes context, or curator", maxLength: 120 }), activeFilters.filter && activeFilters.filter !== "all" ? /* @__PURE__ */ React.createElement("input", { type: "hidden", name: "filter", value: activeFilters.filter }) : null, activeFilters.sort && activeFilters.sort !== "saved_desc" ? /* @__PURE__ */ React.createElement("input", { type: "hidden", name: "sort", value: activeFilters.sort }) : null, /* @__PURE__ */ React.createElement("div", { className: "flex gap-3" }, /* @__PURE__ */ React.createElement("button", { type: "submit", className: "inline-flex flex-1 items-center justify-center gap-2 rounded-2xl border border-sky-300/20 bg-sky-400/10 px-4 py-3 text-sm font-semibold text-sky-100 transition hover:bg-sky-400/15" }, /* @__PURE__ */ React.createElement("i", { className: "fa-solid fa-magnifying-glass fa-fw" }), "Apply"), activeFilters.q || search2 ? /* @__PURE__ */ React.createElement("a", { href: buildFilterUrl({ q: null }, searchBaseUrl), className: "inline-flex items-center justify-center rounded-2xl border border-white/10 bg-white/[0.04] px-4 py-3 text-sm font-semibold text-white transition hover:bg-white/[0.07]" }, "Clear") : null))), /* @__PURE__ */ React.createElement("section", { className: "rounded-[30px] border border-white/10 bg-white/[0.04] p-5 backdrop-blur-sm" }, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.22em] text-sky-200/80" }, "Filters"), /* @__PURE__ */ React.createElement("div", { className: "mt-4 space-y-3" }, filterOptions.map((option) => /* @__PURE__ */ React.createElement( FilterLink, { key: option.key, @@ -73404,7 +73404,7 @@ function GroupHelpPage() { })) } ]; - return /* @__PURE__ */ React.createElement("main", { className: "min-h-screen bg-[radial-gradient(circle_at_top_left,_rgba(14,165,233,0.18),_transparent_24%),radial-gradient(circle_at_bottom_right,_rgba(250,204,21,0.14),_transparent_22%),linear-gradient(180deg,_#020617_0%,_#030712_100%)] px-4 py-8 sm:px-6 lg:px-8" }, /* @__PURE__ */ React.createElement(SeoHead, { seo: props.seo || {}, title: props.title, description: props.description, jsonLd: heroJsonLd }), /* @__PURE__ */ React.createElement("div", { className: "mx-auto max-w-[1500px]" }, /* @__PURE__ */ React.createElement("section", { id: "introduction", className: "rounded-[36px] border border-white/10 bg-[linear-gradient(135deg,rgba(15,23,42,0.92),rgba(15,23,42,0.72)),radial-gradient(circle_at_top_right,rgba(125,211,252,0.16),transparent_28%)] p-6 shadow-[0_30px_100px_rgba(2,6,23,0.35)] md:p-8 lg:p-10" }, /* @__PURE__ */ React.createElement("div", { className: "grid gap-8 xl:grid-cols-[minmax(0,1fr)_360px]" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.24em] text-sky-200/80" }, "Groups documentation"), /* @__PURE__ */ React.createElement("h1", { className: "mt-3 max-w-4xl text-4xl font-semibold tracking-[-0.04em] text-white md:text-5xl xl:text-6xl" }, "Build, manage, and publish through Groups without losing personal credit."), /* @__PURE__ */ React.createElement("p", { className: "mt-5 max-w-3xl text-base leading-8 text-slate-300 md:text-lg" }, "Groups on Skinbase Nova are shared creative identities for studios, collectives, release teams, and long-term collaborations. This guide explains when to use them, how to structure roles, how publishing works, and how to keep the public page clear, trustworthy, and easy to maintain."), /* @__PURE__ */ React.createElement("div", { className: "mt-6 flex flex-wrap gap-3" }, /* @__PURE__ */ React.createElement("a", { href: links.create_group, className: "rounded-full border border-sky-300/25 bg-sky-300/12 px-5 py-3 text-sm font-semibold text-sky-100 transition hover:border-sky-300/40 hover:bg-sky-300/18" }, "Create a Group"), /* @__PURE__ */ React.createElement("a", { href: links.group_studio, className: "rounded-full border border-white/10 bg-white/[0.04] px-5 py-3 text-sm font-semibold text-white transition hover:border-white/20 hover:bg-white/[0.07]" }, "Open Group Studio"), /* @__PURE__ */ React.createElement("a", { href: "#roles-and-permissions", className: "rounded-full border border-white/10 bg-black/20 px-5 py-3 text-sm font-semibold text-slate-200 transition hover:border-white/20 hover:bg-white/[0.05]" }, "Jump to roles and permissions")), links.quickstart ? /* @__PURE__ */ React.createElement("div", { className: "mt-4" }, /* @__PURE__ */ React.createElement("a", { href: links.quickstart, className: "text-sm font-semibold text-sky-200 underline underline-offset-4" }, "Prefer the shorter onboarding version? Open the Groups Quickstart.")) : null, links.faq ? /* @__PURE__ */ React.createElement("div", { className: "mt-2" }, /* @__PURE__ */ React.createElement("a", { href: links.faq, className: "text-sm font-semibold text-slate-300 underline underline-offset-4 hover:text-white" }, "Need faster answers instead? Open the Groups FAQ.")) : null), /* @__PURE__ */ React.createElement("div", { className: "grid gap-3 sm:grid-cols-3 xl:grid-cols-1" }, /* @__PURE__ */ React.createElement(HeroMetric$8, { label: "Shared identity", value: "One public home for team work", note: "Use a Group when a studio, crew, or release team needs its own visible brand." }), /* @__PURE__ */ React.createElement(HeroMetric$8, { label: "Preserved credit", value: "Authorship stays visible", note: "Published by, uploaded by, primary author, and contributors can still reflect the real humans behind the work." }), /* @__PURE__ */ React.createElement(HeroMetric$8, { label: "Studio workflow", value: "Roles, reviews, projects, releases", note: "Groups work best when the team needs structure, not just a different display name." })))), /* @__PURE__ */ React.createElement("div", { className: "mt-8 grid gap-6 lg:grid-cols-[240px_minmax(0,1fr)] xl:grid-cols-[240px_minmax(0,1fr)_280px]" }, /* @__PURE__ */ React.createElement(DocsSidebarNav, { sections: SECTION_ITEMS$9 }), /* @__PURE__ */ React.createElement("div", { className: "space-y-6" }, /* @__PURE__ */ React.createElement( + return /* @__PURE__ */ React.createElement("main", { className: "min-h-screen bg-[radial-gradient(circle_at_top_left,_rgba(14,165,233,0.18),_transparent_24%),radial-gradient(circle_at_bottom_right,_rgba(250,204,21,0.14),_transparent_22%),linear-gradient(180deg,_#020617_0%,_#030712_100%)] px-4 py-8 sm:px-6 lg:px-8" }, /* @__PURE__ */ React.createElement(SeoHead, { seo: props.seo || {}, title: props.title, description: props.description, jsonLd: heroJsonLd }), /* @__PURE__ */ React.createElement("div", { className: "mx-auto max-w-[1500px]" }, /* @__PURE__ */ React.createElement("section", { id: "introduction", className: "rounded-[36px] border border-white/10 bg-[linear-gradient(135deg,rgba(15,23,42,0.92),rgba(15,23,42,0.72)),radial-gradient(circle_at_top_right,rgba(125,211,252,0.16),transparent_28%)] p-6 shadow-[0_30px_100px_rgba(2,6,23,0.35)] md:p-8 lg:p-10" }, /* @__PURE__ */ React.createElement("div", { className: "grid gap-8 xl:grid-cols-[minmax(0,1fr)_360px]" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.24em] text-sky-200/80" }, "Groups documentation"), /* @__PURE__ */ React.createElement("h1", { className: "mt-3 max-w-4xl text-4xl font-semibold tracking-[-0.04em] text-white md:text-5xl xl:text-6xl" }, "Build, manage, and publish through Groups without losing personal credit."), /* @__PURE__ */ React.createElement("p", { className: "mt-5 max-w-3xl text-base leading-8 text-slate-300 md:text-lg" }, "Groups on Skinbase are shared creative identities for studios, collectives, release teams, and long-term collaborations. This guide explains when to use them, how to structure roles, how publishing works, and how to keep the public page clear, trustworthy, and easy to maintain."), /* @__PURE__ */ React.createElement("div", { className: "mt-6 flex flex-wrap gap-3" }, /* @__PURE__ */ React.createElement("a", { href: links.create_group, className: "rounded-full border border-sky-300/25 bg-sky-300/12 px-5 py-3 text-sm font-semibold text-sky-100 transition hover:border-sky-300/40 hover:bg-sky-300/18" }, "Create a Group"), /* @__PURE__ */ React.createElement("a", { href: links.group_studio, className: "rounded-full border border-white/10 bg-white/[0.04] px-5 py-3 text-sm font-semibold text-white transition hover:border-white/20 hover:bg-white/[0.07]" }, "Open Group Studio"), /* @__PURE__ */ React.createElement("a", { href: "#roles-and-permissions", className: "rounded-full border border-white/10 bg-black/20 px-5 py-3 text-sm font-semibold text-slate-200 transition hover:border-white/20 hover:bg-white/[0.05]" }, "Jump to roles and permissions")), links.quickstart ? /* @__PURE__ */ React.createElement("div", { className: "mt-4" }, /* @__PURE__ */ React.createElement("a", { href: links.quickstart, className: "text-sm font-semibold text-sky-200 underline underline-offset-4" }, "Prefer the shorter onboarding version? Open the Groups Quickstart.")) : null, links.faq ? /* @__PURE__ */ React.createElement("div", { className: "mt-2" }, /* @__PURE__ */ React.createElement("a", { href: links.faq, className: "text-sm font-semibold text-slate-300 underline underline-offset-4 hover:text-white" }, "Need faster answers instead? Open the Groups FAQ.")) : null), /* @__PURE__ */ React.createElement("div", { className: "grid gap-3 sm:grid-cols-3 xl:grid-cols-1" }, /* @__PURE__ */ React.createElement(HeroMetric$8, { label: "Shared identity", value: "One public home for team work", note: "Use a Group when a studio, crew, or release team needs its own visible brand." }), /* @__PURE__ */ React.createElement(HeroMetric$8, { label: "Preserved credit", value: "Authorship stays visible", note: "Published by, uploaded by, primary author, and contributors can still reflect the real humans behind the work." }), /* @__PURE__ */ React.createElement(HeroMetric$8, { label: "Studio workflow", value: "Roles, reviews, projects, releases", note: "Groups work best when the team needs structure, not just a different display name." })))), /* @__PURE__ */ React.createElement("div", { className: "mt-8 grid gap-6 lg:grid-cols-[240px_minmax(0,1fr)] xl:grid-cols-[240px_minmax(0,1fr)_280px]" }, /* @__PURE__ */ React.createElement(DocsSidebarNav, { sections: SECTION_ITEMS$9 }), /* @__PURE__ */ React.createElement("div", { className: "space-y-6" }, /* @__PURE__ */ React.createElement( DocsSection, { id: "what-are-groups", @@ -73616,7 +73616,7 @@ function GroupPromoCard({ group, eyebrow = "Groups spotlight", title, descriptio } function GroupDiscoveryCard({ group, className = "", compact = false }) { if (!group) return null; - const primarySummary = group.headline || group.bio_excerpt || "Collaborative publishing identity on Skinbase Nova."; + const primarySummary = group.headline || group.bio_excerpt || "Collaborative publishing identity on Skinbase."; return /* @__PURE__ */ React.createElement( "a", { @@ -74749,7 +74749,7 @@ const HERO_METRICS$6 = [ { label: "What this unlocks", value: "Identity and workspace access", - note: "Signup and login are how you reach your profile, enter Studio, and manage the rest of your creator workflow on Skinbase Nova." + note: "Signup and login are how you reach your profile, enter Studio, and manage the rest of your creator workflow on Skinbase." }, { label: "Most common blocker", @@ -75001,7 +75001,7 @@ function AuthHelpPage() { ...item, href: links[item.linkKey] })); - return /* @__PURE__ */ React.createElement("main", { className: "min-h-screen bg-[radial-gradient(circle_at_top_left,_rgba(56,189,248,0.18),_transparent_23%),radial-gradient(circle_at_bottom_right,_rgba(250,204,21,0.14),_transparent_22%),linear-gradient(180deg,_#020617_0%,_#030712_100%)] px-4 py-8 sm:px-6 lg:px-8" }, /* @__PURE__ */ React.createElement(SeoHead, { seo: props.seo || {}, title: props.title, description: props.description, jsonLd }), /* @__PURE__ */ React.createElement("div", { className: "mx-auto max-w-[1500px]" }, /* @__PURE__ */ React.createElement("section", { id: "introduction", className: "rounded-[36px] border border-white/10 bg-[linear-gradient(135deg,rgba(15,23,42,0.92),rgba(15,23,42,0.72)),radial-gradient(circle_at_top_right,rgba(125,211,252,0.16),transparent_28%)] p-6 shadow-[0_30px_100px_rgba(2,6,23,0.35)] md:p-8 lg:p-10" }, /* @__PURE__ */ React.createElement("div", { className: "grid gap-8 xl:grid-cols-[minmax(0,1fr)_360px]" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.24em] text-sky-200/80" }, "Signup and login help"), /* @__PURE__ */ React.createElement("h1", { className: "mt-3 max-w-4xl text-4xl font-semibold tracking-[-0.04em] text-white md:text-5xl xl:text-6xl" }, "Account access should feel clear, fixable, and much less stressful than it often does."), /* @__PURE__ */ React.createElement("p", { className: "mt-5 max-w-3xl text-base leading-8 text-slate-300 md:text-lg" }, "This page explains how signup, login, password recovery, and account verification basics work on Skinbase Nova so you can get into your account, recover it when needed, and separate true access problems from workflow or permission confusion."), /* @__PURE__ */ React.createElement("div", { className: "mt-6 flex flex-wrap gap-3" }, /* @__PURE__ */ React.createElement("a", { href: signedIn ? links.open_studio : links.login, className: "rounded-full border border-sky-300/25 bg-sky-300/12 px-5 py-3 text-sm font-semibold text-sky-100 transition hover:border-sky-300/40 hover:bg-sky-300/18" }, signedIn ? "Open Studio" : "Open login"), /* @__PURE__ */ React.createElement("a", { href: links.register, className: "rounded-full border border-white/10 bg-white/[0.04] px-5 py-3 text-sm font-semibold text-white transition hover:border-white/20 hover:bg-white/[0.07]" }, "Create account"), /* @__PURE__ */ React.createElement("a", { href: links.password_request, className: "rounded-full border border-white/10 bg-black/20 px-5 py-3 text-sm font-semibold text-slate-200 transition hover:border-white/20 hover:bg-white/[0.05]" }, "Reset password"), /* @__PURE__ */ React.createElement("a", { href: links.help_account, className: "rounded-full border border-white/10 bg-black/20 px-5 py-3 text-sm font-semibold text-slate-200 transition hover:border-white/20 hover:bg-white/[0.05]" }, "Account settings help"))), /* @__PURE__ */ React.createElement("div", { className: "grid gap-3 sm:grid-cols-3 xl:grid-cols-1" }, HERO_METRICS$6.map((metric) => /* @__PURE__ */ React.createElement(HeroMetric$6, { key: metric.label, label: metric.label, value: metric.value, note: metric.note }))))), /* @__PURE__ */ React.createElement("div", { className: "mt-8 grid gap-6 lg:grid-cols-[240px_minmax(0,1fr)] xl:grid-cols-[240px_minmax(0,1fr)_280px]" }, /* @__PURE__ */ React.createElement(DocsSidebarNav, { sections: SECTION_ITEMS$6, ariaLabel: "Signup and login help sections", selectLabel: "Jump to auth help section" }), /* @__PURE__ */ React.createElement("div", { className: "space-y-6" }, /* @__PURE__ */ React.createElement( + return /* @__PURE__ */ React.createElement("main", { className: "min-h-screen bg-[radial-gradient(circle_at_top_left,_rgba(56,189,248,0.18),_transparent_23%),radial-gradient(circle_at_bottom_right,_rgba(250,204,21,0.14),_transparent_22%),linear-gradient(180deg,_#020617_0%,_#030712_100%)] px-4 py-8 sm:px-6 lg:px-8" }, /* @__PURE__ */ React.createElement(SeoHead, { seo: props.seo || {}, title: props.title, description: props.description, jsonLd }), /* @__PURE__ */ React.createElement("div", { className: "mx-auto max-w-[1500px]" }, /* @__PURE__ */ React.createElement("section", { id: "introduction", className: "rounded-[36px] border border-white/10 bg-[linear-gradient(135deg,rgba(15,23,42,0.92),rgba(15,23,42,0.72)),radial-gradient(circle_at_top_right,rgba(125,211,252,0.16),transparent_28%)] p-6 shadow-[0_30px_100px_rgba(2,6,23,0.35)] md:p-8 lg:p-10" }, /* @__PURE__ */ React.createElement("div", { className: "grid gap-8 xl:grid-cols-[minmax(0,1fr)_360px]" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.24em] text-sky-200/80" }, "Signup and login help"), /* @__PURE__ */ React.createElement("h1", { className: "mt-3 max-w-4xl text-4xl font-semibold tracking-[-0.04em] text-white md:text-5xl xl:text-6xl" }, "Account access should feel clear, fixable, and much less stressful than it often does."), /* @__PURE__ */ React.createElement("p", { className: "mt-5 max-w-3xl text-base leading-8 text-slate-300 md:text-lg" }, "This page explains how signup, login, password recovery, and account verification basics work on Skinbase so you can get into your account, recover it when needed, and separate true access problems from workflow or permission confusion."), /* @__PURE__ */ React.createElement("div", { className: "mt-6 flex flex-wrap gap-3" }, /* @__PURE__ */ React.createElement("a", { href: signedIn ? links.open_studio : links.login, className: "rounded-full border border-sky-300/25 bg-sky-300/12 px-5 py-3 text-sm font-semibold text-sky-100 transition hover:border-sky-300/40 hover:bg-sky-300/18" }, signedIn ? "Open Studio" : "Open login"), /* @__PURE__ */ React.createElement("a", { href: links.register, className: "rounded-full border border-white/10 bg-white/[0.04] px-5 py-3 text-sm font-semibold text-white transition hover:border-white/20 hover:bg-white/[0.07]" }, "Create account"), /* @__PURE__ */ React.createElement("a", { href: links.password_request, className: "rounded-full border border-white/10 bg-black/20 px-5 py-3 text-sm font-semibold text-slate-200 transition hover:border-white/20 hover:bg-white/[0.05]" }, "Reset password"), /* @__PURE__ */ React.createElement("a", { href: links.help_account, className: "rounded-full border border-white/10 bg-black/20 px-5 py-3 text-sm font-semibold text-slate-200 transition hover:border-white/20 hover:bg-white/[0.05]" }, "Account settings help"))), /* @__PURE__ */ React.createElement("div", { className: "grid gap-3 sm:grid-cols-3 xl:grid-cols-1" }, HERO_METRICS$6.map((metric) => /* @__PURE__ */ React.createElement(HeroMetric$6, { key: metric.label, label: metric.label, value: metric.value, note: metric.note }))))), /* @__PURE__ */ React.createElement("div", { className: "mt-8 grid gap-6 lg:grid-cols-[240px_minmax(0,1fr)] xl:grid-cols-[240px_minmax(0,1fr)_280px]" }, /* @__PURE__ */ React.createElement(DocsSidebarNav, { sections: SECTION_ITEMS$6, ariaLabel: "Signup and login help sections", selectLabel: "Jump to auth help section" }), /* @__PURE__ */ React.createElement("div", { className: "space-y-6" }, /* @__PURE__ */ React.createElement( DocsSection, { id: "creating-an-account", @@ -75415,7 +75415,7 @@ function CardsHelpPage() { ...item, href: links[item.linkKey] })); - return /* @__PURE__ */ React.createElement("main", { className: "min-h-screen bg-[radial-gradient(circle_at_top_left,_rgba(56,189,248,0.18),_transparent_23%),radial-gradient(circle_at_bottom_right,_rgba(250,204,21,0.14),_transparent_22%),linear-gradient(180deg,_#020617_0%,_#030712_100%)] px-4 py-8 sm:px-6 lg:px-8" }, /* @__PURE__ */ React.createElement(SeoHead, { seo: props.seo || {}, title: props.title, description: props.description, jsonLd }), /* @__PURE__ */ React.createElement("div", { className: "mx-auto max-w-[1500px]" }, /* @__PURE__ */ React.createElement("section", { id: "introduction", className: "rounded-[36px] border border-white/10 bg-[linear-gradient(135deg,rgba(15,23,42,0.92),rgba(15,23,42,0.72)),radial-gradient(circle_at_top_right,rgba(125,211,252,0.16),transparent_28%)] p-6 shadow-[0_30px_100px_rgba(2,6,23,0.35)] md:p-8 lg:p-10" }, /* @__PURE__ */ React.createElement("div", { className: "grid gap-8 xl:grid-cols-[minmax(0,1fr)_360px]" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.24em] text-sky-200/80" }, "Cards help"), /* @__PURE__ */ React.createElement("h1", { className: "mt-3 max-w-4xl text-4xl font-semibold tracking-[-0.04em] text-white md:text-5xl xl:text-6xl" }, "Cards are for ideas that need design, presentation, and message to work together."), /* @__PURE__ */ React.createElement("p", { className: "mt-5 max-w-3xl text-base leading-8 text-slate-300 md:text-lg" }, "This page explains what Cards are on Skinbase Nova, how they differ from artworks, posts, and collections, how to create and publish them, and how to use them well in both personal and Group workflows."), /* @__PURE__ */ React.createElement("div", { className: "mt-6 flex flex-wrap gap-3" }, /* @__PURE__ */ React.createElement("a", { href: links.create_card, className: "rounded-full border border-sky-300/25 bg-sky-300/12 px-5 py-3 text-sm font-semibold text-sky-100 transition hover:border-sky-300/40 hover:bg-sky-300/18" }, "Create a Card"), /* @__PURE__ */ React.createElement("a", { href: links.studio_cards, className: "rounded-full border border-white/10 bg-white/[0.04] px-5 py-3 text-sm font-semibold text-white transition hover:border-white/20 hover:bg-white/[0.07]" }, "Open Cards workspace"), /* @__PURE__ */ React.createElement("a", { href: links.cards_index, className: "rounded-full border border-white/10 bg-black/20 px-5 py-3 text-sm font-semibold text-slate-200 transition hover:border-white/20 hover:bg-white/[0.05]" }, "Browse public Cards"))), /* @__PURE__ */ React.createElement("div", { className: "grid gap-3 sm:grid-cols-3 xl:grid-cols-1" }, HERO_METRICS$5.map((metric) => /* @__PURE__ */ React.createElement(HeroMetric$5, { key: metric.label, label: metric.label, value: metric.value, note: metric.note }))))), /* @__PURE__ */ React.createElement("div", { className: "mt-8 grid gap-6 lg:grid-cols-[240px_minmax(0,1fr)] xl:grid-cols-[240px_minmax(0,1fr)_280px]" }, /* @__PURE__ */ React.createElement(DocsSidebarNav, { sections: SECTION_ITEMS$5, ariaLabel: "Cards help sections", selectLabel: "Jump to Cards help section" }), /* @__PURE__ */ React.createElement("div", { className: "space-y-6" }, /* @__PURE__ */ React.createElement( + return /* @__PURE__ */ React.createElement("main", { className: "min-h-screen bg-[radial-gradient(circle_at_top_left,_rgba(56,189,248,0.18),_transparent_23%),radial-gradient(circle_at_bottom_right,_rgba(250,204,21,0.14),_transparent_22%),linear-gradient(180deg,_#020617_0%,_#030712_100%)] px-4 py-8 sm:px-6 lg:px-8" }, /* @__PURE__ */ React.createElement(SeoHead, { seo: props.seo || {}, title: props.title, description: props.description, jsonLd }), /* @__PURE__ */ React.createElement("div", { className: "mx-auto max-w-[1500px]" }, /* @__PURE__ */ React.createElement("section", { id: "introduction", className: "rounded-[36px] border border-white/10 bg-[linear-gradient(135deg,rgba(15,23,42,0.92),rgba(15,23,42,0.72)),radial-gradient(circle_at_top_right,rgba(125,211,252,0.16),transparent_28%)] p-6 shadow-[0_30px_100px_rgba(2,6,23,0.35)] md:p-8 lg:p-10" }, /* @__PURE__ */ React.createElement("div", { className: "grid gap-8 xl:grid-cols-[minmax(0,1fr)_360px]" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.24em] text-sky-200/80" }, "Cards help"), /* @__PURE__ */ React.createElement("h1", { className: "mt-3 max-w-4xl text-4xl font-semibold tracking-[-0.04em] text-white md:text-5xl xl:text-6xl" }, "Cards are for ideas that need design, presentation, and message to work together."), /* @__PURE__ */ React.createElement("p", { className: "mt-5 max-w-3xl text-base leading-8 text-slate-300 md:text-lg" }, "This page explains what Cards are on Skinbase, how they differ from artworks, posts, and collections, how to create and publish them, and how to use them well in both personal and Group workflows."), /* @__PURE__ */ React.createElement("div", { className: "mt-6 flex flex-wrap gap-3" }, /* @__PURE__ */ React.createElement("a", { href: links.create_card, className: "rounded-full border border-sky-300/25 bg-sky-300/12 px-5 py-3 text-sm font-semibold text-sky-100 transition hover:border-sky-300/40 hover:bg-sky-300/18" }, "Create a Card"), /* @__PURE__ */ React.createElement("a", { href: links.studio_cards, className: "rounded-full border border-white/10 bg-white/[0.04] px-5 py-3 text-sm font-semibold text-white transition hover:border-white/20 hover:bg-white/[0.07]" }, "Open Cards workspace"), /* @__PURE__ */ React.createElement("a", { href: links.cards_index, className: "rounded-full border border-white/10 bg-black/20 px-5 py-3 text-sm font-semibold text-slate-200 transition hover:border-white/20 hover:bg-white/[0.05]" }, "Browse public Cards"))), /* @__PURE__ */ React.createElement("div", { className: "grid gap-3 sm:grid-cols-3 xl:grid-cols-1" }, HERO_METRICS$5.map((metric) => /* @__PURE__ */ React.createElement(HeroMetric$5, { key: metric.label, label: metric.label, value: metric.value, note: metric.note }))))), /* @__PURE__ */ React.createElement("div", { className: "mt-8 grid gap-6 lg:grid-cols-[240px_minmax(0,1fr)] xl:grid-cols-[240px_minmax(0,1fr)_280px]" }, /* @__PURE__ */ React.createElement(DocsSidebarNav, { sections: SECTION_ITEMS$5, ariaLabel: "Cards help sections", selectLabel: "Jump to Cards help section" }), /* @__PURE__ */ React.createElement("div", { className: "space-y-6" }, /* @__PURE__ */ React.createElement( DocsSection, { id: "what-cards-are", @@ -75638,7 +75638,7 @@ const HIGHLIGHTED_GUIDES = [ { eyebrow: "Live now", title: "Profile help", - description: "A creator-friendly guide to personal identity, profile setup, profile-versus-Group clarity, and stronger public presentation on Skinbase Nova.", + description: "A creator-friendly guide to personal identity, profile setup, profile-versus-Group clarity, and stronger public presentation on Skinbase.", status: "Guide", tone: "white", primaryLinkKey: "help_profile", @@ -75855,7 +75855,7 @@ const HELP_CATEGORIES = [ id: "creation-and-publishing", label: "Creation & publishing", title: "Creation and publishing", - summary: "The main surfaces creators use to make, edit, organize, and publish work on Skinbase Nova.", + summary: "The main surfaces creators use to make, edit, organize, and publish work on Skinbase.", topics: [ { eyebrow: "Workspace", @@ -76330,7 +76330,7 @@ function HelpCenterPage() { })) } ]; - return /* @__PURE__ */ React.createElement("main", { className: "min-h-screen bg-[radial-gradient(circle_at_top_left,_rgba(56,189,248,0.18),_transparent_22%),radial-gradient(circle_at_bottom_right,_rgba(250,204,21,0.16),_transparent_22%),linear-gradient(180deg,_#020617_0%,_#030712_100%)] px-4 py-8 sm:px-6 lg:px-8" }, /* @__PURE__ */ React.createElement(SeoHead, { seo: props.seo || {}, title: props.title, description: props.description, jsonLd }), /* @__PURE__ */ React.createElement("div", { className: "mx-auto max-w-[1480px]" }, /* @__PURE__ */ React.createElement("section", { id: "introduction", className: "rounded-[38px] border border-white/10 bg-[linear-gradient(140deg,rgba(15,23,42,0.94),rgba(15,23,42,0.72)),radial-gradient(circle_at_top_right,rgba(125,211,252,0.18),transparent_26%)] p-6 shadow-[0_32px_100px_rgba(2,6,23,0.34)] md:p-8 lg:p-10" }, /* @__PURE__ */ React.createElement("div", { className: "grid gap-8 xl:grid-cols-[minmax(0,1fr)_360px]" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.24em] text-sky-200/80" }, "Skinbase Nova Help Center"), /* @__PURE__ */ React.createElement("h1", { className: "mt-3 max-w-4xl text-4xl font-semibold tracking-[-0.04em] text-white md:text-5xl xl:text-6xl" }, "Find the right guide, quickstart, FAQ, or fix without digging through scattered help."), /* @__PURE__ */ React.createElement("p", { className: "mt-5 max-w-3xl text-base leading-8 text-slate-300 md:text-lg" }, "This is the central help hub for Skinbase Nova. Use it to get started, find module-specific guidance, open the live Groups documentation set, and move quickly toward the next useful answer."), /* @__PURE__ */ React.createElement("div", { className: "mt-6 flex flex-wrap gap-3" }, /* @__PURE__ */ React.createElement("a", { href: "#featured-guides", className: "rounded-full border border-sky-300/25 bg-sky-300/12 px-5 py-3 text-sm font-semibold text-sky-100 transition hover:border-sky-300/40 hover:bg-sky-300/18" }, "Browse help topics"), /* @__PURE__ */ React.createElement("a", { href: links.groups_documentation, className: "rounded-full border border-white/10 bg-white/[0.04] px-5 py-3 text-sm font-semibold text-white transition hover:border-white/20 hover:bg-white/[0.07]" }, "Open Groups help"), /* @__PURE__ */ React.createElement("a", { href: links.studio_help, className: "rounded-full border border-white/10 bg-black/20 px-5 py-3 text-sm font-semibold text-slate-200 transition hover:border-white/20 hover:bg-white/[0.05]" }, "Read Studio help")), /* @__PURE__ */ React.createElement("div", { className: "mt-6 max-w-3xl" }, /* @__PURE__ */ React.createElement( + return /* @__PURE__ */ React.createElement("main", { className: "min-h-screen bg-[radial-gradient(circle_at_top_left,_rgba(56,189,248,0.18),_transparent_22%),radial-gradient(circle_at_bottom_right,_rgba(250,204,21,0.16),_transparent_22%),linear-gradient(180deg,_#020617_0%,_#030712_100%)] px-4 py-8 sm:px-6 lg:px-8" }, /* @__PURE__ */ React.createElement(SeoHead, { seo: props.seo || {}, title: props.title, description: props.description, jsonLd }), /* @__PURE__ */ React.createElement("div", { className: "mx-auto max-w-[1480px]" }, /* @__PURE__ */ React.createElement("section", { id: "introduction", className: "rounded-[38px] border border-white/10 bg-[linear-gradient(140deg,rgba(15,23,42,0.94),rgba(15,23,42,0.72)),radial-gradient(circle_at_top_right,rgba(125,211,252,0.18),transparent_26%)] p-6 shadow-[0_32px_100px_rgba(2,6,23,0.34)] md:p-8 lg:p-10" }, /* @__PURE__ */ React.createElement("div", { className: "grid gap-8 xl:grid-cols-[minmax(0,1fr)_360px]" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.24em] text-sky-200/80" }, "Skinbase Help Center"), /* @__PURE__ */ React.createElement("h1", { className: "mt-3 max-w-4xl text-4xl font-semibold tracking-[-0.04em] text-white md:text-5xl xl:text-6xl" }, "Find the right guide, quickstart, FAQ, or fix without digging through scattered help."), /* @__PURE__ */ React.createElement("p", { className: "mt-5 max-w-3xl text-base leading-8 text-slate-300 md:text-lg" }, "This is the central help hub for Skinbase. Use it to get started, find module-specific guidance, open the live Groups documentation set, and move quickly toward the next useful answer."), /* @__PURE__ */ React.createElement("div", { className: "mt-6 flex flex-wrap gap-3" }, /* @__PURE__ */ React.createElement("a", { href: "#featured-guides", className: "rounded-full border border-sky-300/25 bg-sky-300/12 px-5 py-3 text-sm font-semibold text-sky-100 transition hover:border-sky-300/40 hover:bg-sky-300/18" }, "Browse help topics"), /* @__PURE__ */ React.createElement("a", { href: links.groups_documentation, className: "rounded-full border border-white/10 bg-white/[0.04] px-5 py-3 text-sm font-semibold text-white transition hover:border-white/20 hover:bg-white/[0.07]" }, "Open Groups help"), /* @__PURE__ */ React.createElement("a", { href: links.studio_help, className: "rounded-full border border-white/10 bg-black/20 px-5 py-3 text-sm font-semibold text-slate-200 transition hover:border-white/20 hover:bg-white/[0.05]" }, "Read Studio help")), /* @__PURE__ */ React.createElement("div", { className: "mt-6 max-w-3xl" }, /* @__PURE__ */ React.createElement( HelpSearchBar, { value: query, @@ -76714,7 +76714,7 @@ function ProfileHelpPage() { ...item, href: links[item.linkKey] })); - return /* @__PURE__ */ React.createElement("main", { className: "min-h-screen bg-[radial-gradient(circle_at_top_left,_rgba(56,189,248,0.18),_transparent_23%),radial-gradient(circle_at_bottom_right,_rgba(250,204,21,0.14),_transparent_22%),linear-gradient(180deg,_#020617_0%,_#030712_100%)] px-4 py-8 sm:px-6 lg:px-8" }, /* @__PURE__ */ React.createElement(SeoHead, { seo: props.seo || {}, title: props.title, description: props.description, jsonLd }), /* @__PURE__ */ React.createElement("div", { className: "mx-auto max-w-[1500px]" }, /* @__PURE__ */ React.createElement("section", { id: "introduction", className: "rounded-[36px] border border-white/10 bg-[linear-gradient(135deg,rgba(15,23,42,0.92),rgba(15,23,42,0.72)),radial-gradient(circle_at_top_right,rgba(125,211,252,0.16),transparent_28%)] p-6 shadow-[0_30px_100px_rgba(2,6,23,0.35)] md:p-8 lg:p-10" }, /* @__PURE__ */ React.createElement("div", { className: "grid gap-8 xl:grid-cols-[minmax(0,1fr)_360px]" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.24em] text-sky-200/80" }, "Profile help"), /* @__PURE__ */ React.createElement("h1", { className: "mt-3 max-w-4xl text-4xl font-semibold tracking-[-0.04em] text-white md:text-5xl xl:text-6xl" }, "Your profile is the personal identity people remember when they discover your work."), /* @__PURE__ */ React.createElement("p", { className: "mt-5 max-w-3xl text-base leading-8 text-slate-300 md:text-lg" }, "This page explains what a profile is on Skinbase Nova, how it differs from a Group, how to set it up well, and how to build a stronger public creator presence without turning the page into noise."), /* @__PURE__ */ React.createElement("div", { className: "mt-6 flex flex-wrap gap-3" }, /* @__PURE__ */ React.createElement("a", { href: links.profile_settings, className: "rounded-full border border-sky-300/25 bg-sky-300/12 px-5 py-3 text-sm font-semibold text-sky-100 transition hover:border-sky-300/40 hover:bg-sky-300/18" }, "Open profile settings"), /* @__PURE__ */ React.createElement("a", { href: links.groups_help, className: "rounded-full border border-white/10 bg-white/[0.04] px-5 py-3 text-sm font-semibold text-white transition hover:border-white/20 hover:bg-white/[0.07]" }, "Read Groups help"), /* @__PURE__ */ React.createElement("a", { href: links.studio_help, className: "rounded-full border border-white/10 bg-black/20 px-5 py-3 text-sm font-semibold text-slate-200 transition hover:border-white/20 hover:bg-white/[0.05]" }, "Read Studio help"))), /* @__PURE__ */ React.createElement("div", { className: "grid gap-3 sm:grid-cols-3 xl:grid-cols-1" }, HERO_METRICS$4.map((metric) => /* @__PURE__ */ React.createElement(HeroMetric$4, { key: metric.label, label: metric.label, value: metric.value, note: metric.note }))))), /* @__PURE__ */ React.createElement("div", { className: "mt-8 grid gap-6 lg:grid-cols-[240px_minmax(0,1fr)] xl:grid-cols-[240px_minmax(0,1fr)_280px]" }, /* @__PURE__ */ React.createElement(DocsSidebarNav, { sections: SECTION_ITEMS$4, ariaLabel: "Profile help sections", selectLabel: "Jump to Profile help section" }), /* @__PURE__ */ React.createElement("div", { className: "space-y-6" }, /* @__PURE__ */ React.createElement( + return /* @__PURE__ */ React.createElement("main", { className: "min-h-screen bg-[radial-gradient(circle_at_top_left,_rgba(56,189,248,0.18),_transparent_23%),radial-gradient(circle_at_bottom_right,_rgba(250,204,21,0.14),_transparent_22%),linear-gradient(180deg,_#020617_0%,_#030712_100%)] px-4 py-8 sm:px-6 lg:px-8" }, /* @__PURE__ */ React.createElement(SeoHead, { seo: props.seo || {}, title: props.title, description: props.description, jsonLd }), /* @__PURE__ */ React.createElement("div", { className: "mx-auto max-w-[1500px]" }, /* @__PURE__ */ React.createElement("section", { id: "introduction", className: "rounded-[36px] border border-white/10 bg-[linear-gradient(135deg,rgba(15,23,42,0.92),rgba(15,23,42,0.72)),radial-gradient(circle_at_top_right,rgba(125,211,252,0.16),transparent_28%)] p-6 shadow-[0_30px_100px_rgba(2,6,23,0.35)] md:p-8 lg:p-10" }, /* @__PURE__ */ React.createElement("div", { className: "grid gap-8 xl:grid-cols-[minmax(0,1fr)_360px]" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.24em] text-sky-200/80" }, "Profile help"), /* @__PURE__ */ React.createElement("h1", { className: "mt-3 max-w-4xl text-4xl font-semibold tracking-[-0.04em] text-white md:text-5xl xl:text-6xl" }, "Your profile is the personal identity people remember when they discover your work."), /* @__PURE__ */ React.createElement("p", { className: "mt-5 max-w-3xl text-base leading-8 text-slate-300 md:text-lg" }, "This page explains what a profile is on Skinbase, how it differs from a Group, how to set it up well, and how to build a stronger public creator presence without turning the page into noise."), /* @__PURE__ */ React.createElement("div", { className: "mt-6 flex flex-wrap gap-3" }, /* @__PURE__ */ React.createElement("a", { href: links.profile_settings, className: "rounded-full border border-sky-300/25 bg-sky-300/12 px-5 py-3 text-sm font-semibold text-sky-100 transition hover:border-sky-300/40 hover:bg-sky-300/18" }, "Open profile settings"), /* @__PURE__ */ React.createElement("a", { href: links.groups_help, className: "rounded-full border border-white/10 bg-white/[0.04] px-5 py-3 text-sm font-semibold text-white transition hover:border-white/20 hover:bg-white/[0.07]" }, "Read Groups help"), /* @__PURE__ */ React.createElement("a", { href: links.studio_help, className: "rounded-full border border-white/10 bg-black/20 px-5 py-3 text-sm font-semibold text-slate-200 transition hover:border-white/20 hover:bg-white/[0.05]" }, "Read Studio help"))), /* @__PURE__ */ React.createElement("div", { className: "grid gap-3 sm:grid-cols-3 xl:grid-cols-1" }, HERO_METRICS$4.map((metric) => /* @__PURE__ */ React.createElement(HeroMetric$4, { key: metric.label, label: metric.label, value: metric.value, note: metric.note }))))), /* @__PURE__ */ React.createElement("div", { className: "mt-8 grid gap-6 lg:grid-cols-[240px_minmax(0,1fr)] xl:grid-cols-[240px_minmax(0,1fr)_280px]" }, /* @__PURE__ */ React.createElement(DocsSidebarNav, { sections: SECTION_ITEMS$4, ariaLabel: "Profile help sections", selectLabel: "Jump to Profile help section" }), /* @__PURE__ */ React.createElement("div", { className: "space-y-6" }, /* @__PURE__ */ React.createElement( DocsSection, { id: "what-profile-is", @@ -76978,7 +76978,7 @@ const COMMON_MISTAKES$2 = [ const FAQ_ITEMS$3 = [ { question: "What is Studio?", - answer: "Studio is the private creator workspace on Skinbase Nova. It is where you manage drafts, uploads, publishing, cards, collections, settings, and other operational parts of your creative work." + answer: "Studio is the private creator workspace on Skinbase. It is where you manage drafts, uploads, publishing, cards, collections, settings, and other operational parts of your creative work." }, { question: "Why do Personal Studio and Group Studio look different?", @@ -77144,7 +77144,7 @@ function StudioHelpPage() { ...item, href: links[item.linkKey] })); - return /* @__PURE__ */ React.createElement("main", { className: "min-h-screen bg-[radial-gradient(circle_at_top_left,_rgba(56,189,248,0.18),_transparent_23%),radial-gradient(circle_at_bottom_right,_rgba(250,204,21,0.14),_transparent_22%),linear-gradient(180deg,_#020617_0%,_#030712_100%)] px-4 py-8 sm:px-6 lg:px-8" }, /* @__PURE__ */ React.createElement(SeoHead, { seo: props.seo || {}, title: props.title, description: props.description, jsonLd }), /* @__PURE__ */ React.createElement("div", { className: "mx-auto max-w-[1500px]" }, /* @__PURE__ */ React.createElement("section", { id: "introduction", className: "rounded-[36px] border border-white/10 bg-[linear-gradient(135deg,rgba(15,23,42,0.92),rgba(15,23,42,0.72)),radial-gradient(circle_at_top_right,rgba(125,211,252,0.16),transparent_28%)] p-6 shadow-[0_30px_100px_rgba(2,6,23,0.35)] md:p-8 lg:p-10" }, /* @__PURE__ */ React.createElement("div", { className: "grid gap-8 xl:grid-cols-[minmax(0,1fr)_360px]" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.24em] text-sky-200/80" }, "Studio help"), /* @__PURE__ */ React.createElement("h1", { className: "mt-3 max-w-4xl text-4xl font-semibold tracking-[-0.04em] text-white md:text-5xl xl:text-6xl" }, "Studio is the creative control center of Skinbase Nova."), /* @__PURE__ */ React.createElement("p", { className: "mt-5 max-w-3xl text-base leading-8 text-slate-300 md:text-lg" }, "Use Studio to manage drafts, uploads, publishing, artworks, cards, collections, and collaborative work before and after it goes public. This page explains how Studio fits into the platform, how personal and Group contexts differ, and how to use the workspace without creating avoidable confusion."), /* @__PURE__ */ React.createElement("div", { className: "mt-6 flex flex-wrap gap-3" }, /* @__PURE__ */ React.createElement("a", { href: links.open_studio, className: "rounded-full border border-sky-300/25 bg-sky-300/12 px-5 py-3 text-sm font-semibold text-sky-100 transition hover:border-sky-300/40 hover:bg-sky-300/18" }, "Open Studio"), /* @__PURE__ */ React.createElement("a", { href: links.upload_help, className: "rounded-full border border-white/10 bg-white/[0.04] px-5 py-3 text-sm font-semibold text-white transition hover:border-white/20 hover:bg-white/[0.07]" }, "Read Upload help"), /* @__PURE__ */ React.createElement("a", { href: links.groups_help, className: "rounded-full border border-white/10 bg-black/20 px-5 py-3 text-sm font-semibold text-slate-200 transition hover:border-white/20 hover:bg-white/[0.05]" }, "Read Groups help"))), /* @__PURE__ */ React.createElement("div", { className: "grid gap-3 sm:grid-cols-3 xl:grid-cols-1" }, HERO_METRICS$3.map((metric) => /* @__PURE__ */ React.createElement(HeroMetric$3, { key: metric.label, label: metric.label, value: metric.value, note: metric.note }))))), /* @__PURE__ */ React.createElement("div", { className: "mt-8 grid gap-6 lg:grid-cols-[240px_minmax(0,1fr)] xl:grid-cols-[240px_minmax(0,1fr)_280px]" }, /* @__PURE__ */ React.createElement(DocsSidebarNav, { sections: SECTION_ITEMS$3, ariaLabel: "Studio help sections", selectLabel: "Jump to Studio help section" }), /* @__PURE__ */ React.createElement("div", { className: "space-y-6" }, /* @__PURE__ */ React.createElement( + return /* @__PURE__ */ React.createElement("main", { className: "min-h-screen bg-[radial-gradient(circle_at_top_left,_rgba(56,189,248,0.18),_transparent_23%),radial-gradient(circle_at_bottom_right,_rgba(250,204,21,0.14),_transparent_22%),linear-gradient(180deg,_#020617_0%,_#030712_100%)] px-4 py-8 sm:px-6 lg:px-8" }, /* @__PURE__ */ React.createElement(SeoHead, { seo: props.seo || {}, title: props.title, description: props.description, jsonLd }), /* @__PURE__ */ React.createElement("div", { className: "mx-auto max-w-[1500px]" }, /* @__PURE__ */ React.createElement("section", { id: "introduction", className: "rounded-[36px] border border-white/10 bg-[linear-gradient(135deg,rgba(15,23,42,0.92),rgba(15,23,42,0.72)),radial-gradient(circle_at_top_right,rgba(125,211,252,0.16),transparent_28%)] p-6 shadow-[0_30px_100px_rgba(2,6,23,0.35)] md:p-8 lg:p-10" }, /* @__PURE__ */ React.createElement("div", { className: "grid gap-8 xl:grid-cols-[minmax(0,1fr)_360px]" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.24em] text-sky-200/80" }, "Studio help"), /* @__PURE__ */ React.createElement("h1", { className: "mt-3 max-w-4xl text-4xl font-semibold tracking-[-0.04em] text-white md:text-5xl xl:text-6xl" }, "Studio is the creative control center of Skinbase."), /* @__PURE__ */ React.createElement("p", { className: "mt-5 max-w-3xl text-base leading-8 text-slate-300 md:text-lg" }, "Use Studio to manage drafts, uploads, publishing, artworks, cards, collections, and collaborative work before and after it goes public. This page explains how Studio fits into the platform, how personal and Group contexts differ, and how to use the workspace without creating avoidable confusion."), /* @__PURE__ */ React.createElement("div", { className: "mt-6 flex flex-wrap gap-3" }, /* @__PURE__ */ React.createElement("a", { href: links.open_studio, className: "rounded-full border border-sky-300/25 bg-sky-300/12 px-5 py-3 text-sm font-semibold text-sky-100 transition hover:border-sky-300/40 hover:bg-sky-300/18" }, "Open Studio"), /* @__PURE__ */ React.createElement("a", { href: links.upload_help, className: "rounded-full border border-white/10 bg-white/[0.04] px-5 py-3 text-sm font-semibold text-white transition hover:border-white/20 hover:bg-white/[0.07]" }, "Read Upload help"), /* @__PURE__ */ React.createElement("a", { href: links.groups_help, className: "rounded-full border border-white/10 bg-black/20 px-5 py-3 text-sm font-semibold text-slate-200 transition hover:border-white/20 hover:bg-white/[0.05]" }, "Read Groups help"))), /* @__PURE__ */ React.createElement("div", { className: "grid gap-3 sm:grid-cols-3 xl:grid-cols-1" }, HERO_METRICS$3.map((metric) => /* @__PURE__ */ React.createElement(HeroMetric$3, { key: metric.label, label: metric.label, value: metric.value, note: metric.note }))))), /* @__PURE__ */ React.createElement("div", { className: "mt-8 grid gap-6 lg:grid-cols-[240px_minmax(0,1fr)] xl:grid-cols-[240px_minmax(0,1fr)_280px]" }, /* @__PURE__ */ React.createElement(DocsSidebarNav, { sections: SECTION_ITEMS$3, ariaLabel: "Studio help sections", selectLabel: "Jump to Studio help section" }), /* @__PURE__ */ React.createElement("div", { className: "space-y-6" }, /* @__PURE__ */ React.createElement( DocsSection, { id: "what-is-studio", @@ -78070,7 +78070,7 @@ const SECTION_ITEMS_DETAIL = [ { title: "Challenge spotlight", body: "Challenges attached to the campaign or recent participation around it." }, { title: "Related events", body: "Upcoming or recent sessions, launches, and live moments." }, { title: "Release spotlights", body: "Projects and releases that belong in the campaign space." }, - { title: "Themed cards", body: "Nova Cards that extend the World identity into designed communication surfaces." } + { title: "Themed cards", body: "Cards that extend the World identity into designed communication surfaces." } ]; const RELATION_TYPE_ITEMS = [ "Artworks", @@ -78127,7 +78127,7 @@ const COMMON_MISTAKES = [ ]; const FAQ_ITEMS = [ { - question: "What is a World on Skinbase Nova?", + question: "What is a World on Skinbase?", answer: "A World is a curated editorial destination for a seasonal moment, event, tribute, or campaign. It combines one strong hero with a controlled set of attached modules and optional promotion across public surfaces." }, { @@ -78269,7 +78269,7 @@ function WorldsHelpPage() { ...item, href: links[item.linkKey] })); - return /* @__PURE__ */ React.createElement("main", { className: "min-h-screen bg-[radial-gradient(circle_at_top_left,_rgba(56,189,248,0.18),_transparent_23%),radial-gradient(circle_at_bottom_right,_rgba(249,115,22,0.16),_transparent_22%),linear-gradient(180deg,_#020617_0%,_#030712_100%)] px-4 py-8 sm:px-6 lg:px-8" }, /* @__PURE__ */ React.createElement(SeoHead, { seo: props.seo || {}, title: props.title, description: props.description, jsonLd }), /* @__PURE__ */ React.createElement("div", { className: "mx-auto max-w-[1500px]" }, /* @__PURE__ */ React.createElement("section", { id: "introduction", className: "rounded-[36px] border border-white/10 bg-[linear-gradient(135deg,rgba(15,23,42,0.92),rgba(15,23,42,0.72)),radial-gradient(circle_at_top_right,rgba(125,211,252,0.16),transparent_28%)] p-6 shadow-[0_30px_100px_rgba(2,6,23,0.35)] md:p-8 lg:p-10" }, /* @__PURE__ */ React.createElement("div", { className: "grid gap-8 xl:grid-cols-[minmax(0,1fr)_360px]" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.24em] text-sky-200/80" }, "Worlds help"), /* @__PURE__ */ React.createElement("h1", { className: "mt-3 max-w-4xl text-4xl font-semibold tracking-[-0.04em] text-white md:text-5xl xl:text-6xl" }, "Worlds are where Skinbase Nova turns curated content into a live campaign surface."), /* @__PURE__ */ React.createElement("p", { className: "mt-5 max-w-3xl text-base leading-8 text-slate-300 md:text-lg" }, "This guide explains what Worlds are, how attached content works, how section visibility and order shape the result, and how to preview, publish, promote, and reuse Worlds for recurring campaigns."), /* @__PURE__ */ React.createElement("div", { className: "mt-6 flex flex-wrap gap-3" }, /* @__PURE__ */ React.createElement("a", { href: links.create_world, className: "rounded-full border border-sky-300/25 bg-sky-300/12 px-5 py-3 text-sm font-semibold text-sky-100 transition hover:border-sky-300/40 hover:bg-sky-300/18" }, "Create a World"), /* @__PURE__ */ React.createElement("a", { href: links.studio_worlds, className: "rounded-full border border-white/10 bg-white/[0.04] px-5 py-3 text-sm font-semibold text-white transition hover:border-white/20 hover:bg-white/[0.07]" }, "Open Worlds workspace"), /* @__PURE__ */ React.createElement("a", { href: links.worlds_index, className: "rounded-full border border-white/10 bg-black/20 px-5 py-3 text-sm font-semibold text-slate-200 transition hover:border-white/20 hover:bg-white/[0.05]" }, "Browse public Worlds"))), /* @__PURE__ */ React.createElement("div", { className: "grid gap-3 sm:grid-cols-3 xl:grid-cols-1" }, HERO_METRICS.map((metric) => /* @__PURE__ */ React.createElement(HeroMetric, { key: metric.label, label: metric.label, value: metric.value, note: metric.note }))))), /* @__PURE__ */ React.createElement("div", { className: "mt-8 grid gap-6 lg:grid-cols-[240px_minmax(0,1fr)] xl:grid-cols-[240px_minmax(0,1fr)_280px]" }, /* @__PURE__ */ React.createElement(DocsSidebarNav, { sections: SECTION_ITEMS, ariaLabel: "Worlds help sections", selectLabel: "Jump to Worlds help section" }), /* @__PURE__ */ React.createElement("div", { className: "space-y-6" }, /* @__PURE__ */ React.createElement( + return /* @__PURE__ */ React.createElement("main", { className: "min-h-screen bg-[radial-gradient(circle_at_top_left,_rgba(56,189,248,0.18),_transparent_23%),radial-gradient(circle_at_bottom_right,_rgba(249,115,22,0.16),_transparent_22%),linear-gradient(180deg,_#020617_0%,_#030712_100%)] px-4 py-8 sm:px-6 lg:px-8" }, /* @__PURE__ */ React.createElement(SeoHead, { seo: props.seo || {}, title: props.title, description: props.description, jsonLd }), /* @__PURE__ */ React.createElement("div", { className: "mx-auto max-w-[1500px]" }, /* @__PURE__ */ React.createElement("section", { id: "introduction", className: "rounded-[36px] border border-white/10 bg-[linear-gradient(135deg,rgba(15,23,42,0.92),rgba(15,23,42,0.72)),radial-gradient(circle_at_top_right,rgba(125,211,252,0.16),transparent_28%)] p-6 shadow-[0_30px_100px_rgba(2,6,23,0.35)] md:p-8 lg:p-10" }, /* @__PURE__ */ React.createElement("div", { className: "grid gap-8 xl:grid-cols-[minmax(0,1fr)_360px]" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.24em] text-sky-200/80" }, "Worlds help"), /* @__PURE__ */ React.createElement("h1", { className: "mt-3 max-w-4xl text-4xl font-semibold tracking-[-0.04em] text-white md:text-5xl xl:text-6xl" }, "Worlds are where Skinbase turns curated content into a live campaign surface."), /* @__PURE__ */ React.createElement("p", { className: "mt-5 max-w-3xl text-base leading-8 text-slate-300 md:text-lg" }, "This guide explains what Worlds are, how attached content works, how section visibility and order shape the result, and how to preview, publish, promote, and reuse Worlds for recurring campaigns."), /* @__PURE__ */ React.createElement("div", { className: "mt-6 flex flex-wrap gap-3" }, /* @__PURE__ */ React.createElement("a", { href: links.create_world, className: "rounded-full border border-sky-300/25 bg-sky-300/12 px-5 py-3 text-sm font-semibold text-sky-100 transition hover:border-sky-300/40 hover:bg-sky-300/18" }, "Create a World"), /* @__PURE__ */ React.createElement("a", { href: links.studio_worlds, className: "rounded-full border border-white/10 bg-white/[0.04] px-5 py-3 text-sm font-semibold text-white transition hover:border-white/20 hover:bg-white/[0.07]" }, "Open Worlds workspace"), /* @__PURE__ */ React.createElement("a", { href: links.worlds_index, className: "rounded-full border border-white/10 bg-black/20 px-5 py-3 text-sm font-semibold text-slate-200 transition hover:border-white/20 hover:bg-white/[0.05]" }, "Browse public Worlds"))), /* @__PURE__ */ React.createElement("div", { className: "grid gap-3 sm:grid-cols-3 xl:grid-cols-1" }, HERO_METRICS.map((metric) => /* @__PURE__ */ React.createElement(HeroMetric, { key: metric.label, label: metric.label, value: metric.value, note: metric.note }))))), /* @__PURE__ */ React.createElement("div", { className: "mt-8 grid gap-6 lg:grid-cols-[240px_minmax(0,1fr)] xl:grid-cols-[240px_minmax(0,1fr)_280px]" }, /* @__PURE__ */ React.createElement(DocsSidebarNav, { sections: SECTION_ITEMS, ariaLabel: "Worlds help sections", selectLabel: "Jump to Worlds help section" }), /* @__PURE__ */ React.createElement("div", { className: "space-y-6" }, /* @__PURE__ */ React.createElement( DocsSection, { id: "what-worlds-are", @@ -78754,7 +78754,7 @@ const FALLBACK$1 = "https://files.skinbase.org/default/missing_lg.webp"; const HERO_SIZES = "100vw"; function HomeHero({ artwork }) { if (!artwork) { - return /* @__PURE__ */ React.createElement("section", { className: "relative flex min-h-[62vh] max-h-[420px] w-full items-end overflow-hidden bg-nova-900 md:min-h-[38vh] md:max-h-[460px]" }, /* @__PURE__ */ React.createElement("div", { className: "pointer-events-none absolute inset-0 bg-gradient-to-t from-nova-900 via-nova-900/60 to-transparent" }), /* @__PURE__ */ React.createElement("div", { className: "relative z-10 w-full px-6 pb-7 sm:px-10 lg:px-16" }, /* @__PURE__ */ React.createElement("h1", { className: "text-2xl font-bold tracking-tight text-white sm:text-4xl" }, "Skinbase Nova"), /* @__PURE__ */ React.createElement("p", { className: "mt-2 max-w-xl text-sm text-soft" }, "Discover. Create. Inspire."), /* @__PURE__ */ React.createElement("div", { className: "mt-4 flex flex-wrap gap-3" }, /* @__PURE__ */ React.createElement("a", { href: "/discover/trending", className: "btn-accent-solid rounded-xl px-5 py-2 text-sm font-semibold" }, "Explore Trending")))); + return /* @__PURE__ */ React.createElement("section", { className: "relative flex min-h-[62vh] max-h-[420px] w-full items-end overflow-hidden bg-nova-900 md:min-h-[38vh] md:max-h-[460px]" }, /* @__PURE__ */ React.createElement("div", { className: "pointer-events-none absolute inset-0 bg-gradient-to-t from-nova-900 via-nova-900/60 to-transparent" }), /* @__PURE__ */ React.createElement("div", { className: "relative z-10 w-full px-6 pb-7 sm:px-10 lg:px-16" }, /* @__PURE__ */ React.createElement("h1", { className: "text-2xl font-bold tracking-tight text-white sm:text-4xl" }, "Skinbase"), /* @__PURE__ */ React.createElement("p", { className: "mt-2 max-w-xl text-sm text-soft" }, "Discover. Create. Inspire."), /* @__PURE__ */ React.createElement("div", { className: "mt-4 flex flex-wrap gap-3" }, /* @__PURE__ */ React.createElement("a", { href: "/discover/trending", className: "btn-accent-solid rounded-xl px-5 py-2 text-sm font-semibold" }, "Explore Trending")))); } const src2 = artwork.thumb_lg || artwork.thumb || FALLBACK$1; const srcSet = artwork.thumb_srcset || null; @@ -87447,6 +87447,13 @@ function StudioLayout({ children, title, subtitle, actions }) { const [mobileOpen, setMobileOpen] = reactExports.useState(false); const [createOpen, setCreateOpen] = reactExports.useState(false); const pathname = url.split("?")[0]; + const pageTitle = title ? `${title} — Creator Studio` : "Creator Studio"; + const pageDescription = subtitle || "Manage your creator workspace from one shared Creator Studio surface."; + const pageSeo = { + title: pageTitle, + description: pageDescription, + robots: "noindex,nofollow" + }; const studioGroups = Array.isArray(props.studio_groups) ? props.studio_groups : []; const currentGroup = props.studioGroup || null; const userLabel = props.auth?.user?.name || props.auth?.user?.username || "Your creator workspace"; @@ -87539,7 +87546,7 @@ function StudioLayout({ children, title, subtitle, actions }) { navigateToStudioUrl(targetUrl); } }; - return /* @__PURE__ */ React.createElement("div", { className: "min-h-screen bg-[radial-gradient(circle_at_top,_rgba(14,165,233,0.12),_transparent_30%),radial-gradient(circle_at_bottom_right,_rgba(34,197,94,0.12),_transparent_35%),linear-gradient(180deg,_#06101d_0%,_#020617_45%,_#02040a_100%)]" }, /* @__PURE__ */ React.createElement("div", { className: "sticky top-16 z-30 border-b border-white/10 bg-slate-950/80 backdrop-blur-xl lg:hidden" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-between px-4 py-3" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.24em] text-sky-200/70" }, "Creator Studio"), /* @__PURE__ */ React.createElement("h1", { className: "text-lg font-bold text-white" }, title || "Creator Studio")), /* @__PURE__ */ React.createElement( + return /* @__PURE__ */ React.createElement("div", { className: "min-h-screen bg-[radial-gradient(circle_at_top,_rgba(14,165,233,0.12),_transparent_30%),radial-gradient(circle_at_bottom_right,_rgba(34,197,94,0.12),_transparent_35%),linear-gradient(180deg,_#06101d_0%,_#020617_45%,_#02040a_100%)]" }, /* @__PURE__ */ React.createElement(SeoHead, { seo: pageSeo }), /* @__PURE__ */ React.createElement("div", { className: "sticky top-16 z-30 border-b border-white/10 bg-slate-950/80 backdrop-blur-xl lg:hidden" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-between px-4 py-3" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.24em] text-sky-200/70" }, "Creator Studio"), /* @__PURE__ */ React.createElement("h1", { className: "text-lg font-bold text-white" }, title || "Creator Studio")), /* @__PURE__ */ React.createElement( "button", { onClick: () => setMobileOpen(!mobileOpen), @@ -102335,6 +102342,8 @@ function useUploadMachine({ draftId, filesCdnUrl, chunkSize, chunkRequestTimeout } function UploadPage({ draftId, filesCdnUrl, chunkSize, chunkRequestTimeoutMs }) { const { props } = X(); + const pageTitle = "Upload Artwork — Creator Studio"; + const pageDescription = "Submit a new artwork, complete the required metadata, and publish it from Skinbase Creator Studio."; const windowFlags = window?.SKINBASE_FLAGS || {}; const propFlagRaw = props?.feature_flags?.uploads_v2; const windowFlagRaw = (windowFlags?.uploads && windowFlags.uploads.v2) ?? windowFlags?.uploads_v2; @@ -102349,7 +102358,7 @@ function UploadPage({ draftId, filesCdnUrl, chunkSize, chunkRequestTimeoutMs }) }; const uploadsV2Enabled = toBooleanFlag(propFlagRaw) || toBooleanFlag(windowFlagRaw); if (uploadsV2Enabled) { - return /* @__PURE__ */ React.createElement("section", { className: "min-h-[calc(100vh-4rem)] bg-[#07111c] text-slate-100" }, /* @__PURE__ */ React.createElement("div", { className: "relative isolate" }, /* @__PURE__ */ React.createElement("div", { className: "pointer-events-none absolute inset-x-0 top-0 -z-10 h-[420px] bg-[radial-gradient(circle_at_top_left,_rgba(56,189,248,0.22),_transparent_32%),radial-gradient(circle_at_top_right,_rgba(251,146,60,0.16),_transparent_30%),linear-gradient(180deg,_rgba(8,17,28,0.98),_rgba(7,17,28,1))]" }), /* @__PURE__ */ React.createElement("div", { className: "mx-auto max-w-7xl px-4 py-6 sm:px-6 lg:px-8 lg:py-8" }, /* @__PURE__ */ React.createElement("div", { className: "rounded-[32px] border border-white/10 bg-[#08111c]/92 shadow-[0_30px_120px_rgba(2,8,23,0.38)]" }, /* @__PURE__ */ React.createElement("div", { className: "px-4 py-5 sm:px-6 lg:px-8 lg:py-8" }, /* @__PURE__ */ React.createElement( + return /* @__PURE__ */ React.createElement("section", { className: "min-h-[calc(100vh-4rem)] bg-[#07111c] text-slate-100" }, /* @__PURE__ */ React.createElement(SeoHead, { seo: { title: pageTitle, description: pageDescription, robots: "noindex, nofollow" } }), /* @__PURE__ */ React.createElement("div", { className: "relative isolate" }, /* @__PURE__ */ React.createElement("div", { className: "pointer-events-none absolute inset-x-0 top-0 -z-10 h-[420px] bg-[radial-gradient(circle_at_top_left,_rgba(56,189,248,0.22),_transparent_32%),radial-gradient(circle_at_top_right,_rgba(251,146,60,0.16),_transparent_30%),linear-gradient(180deg,_rgba(8,17,28,0.98),_rgba(7,17,28,1))]" }), /* @__PURE__ */ React.createElement("div", { className: "mx-auto max-w-7xl px-4 py-6 sm:px-6 lg:px-8 lg:py-8" }, /* @__PURE__ */ React.createElement("div", { className: "rounded-[32px] border border-white/10 bg-[#08111c]/92 shadow-[0_30px_120px_rgba(2,8,23,0.38)]" }, /* @__PURE__ */ React.createElement("div", { className: "px-4 py-5 sm:px-6 lg:px-8 lg:py-8" }, /* @__PURE__ */ React.createElement( UploadWizard, { initialDraftId: draftId ?? null, @@ -102462,7 +102471,7 @@ function UploadPage({ draftId, filesCdnUrl, chunkSize, chunkRequestTimeoutMs }) className: `rounded-xl border px-4 py-3 text-sm ${notice.type === "error" ? "border-red-500/40 bg-red-500/10 text-red-100" : notice.type === "warning" ? "border-amber-400/40 bg-amber-400/10 text-amber-100" : "border-emerald-400/40 bg-emerald-400/10 text-emerald-100"}` }, notice.message - ))), /* @__PURE__ */ React.createElement("div", { className: "grid gap-8 lg:grid-cols-[1.1fr,0.9fr]" }, /* @__PURE__ */ React.createElement("div", { className: "space-y-6" }, /* @__PURE__ */ React.createElement("div", { className: "rounded-2xl border border-white/10 bg-white/5 p-6 shadow-[0_0_50px_rgba(59,130,246,0.15)]" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ React.createElement("h1", { className: "text-3xl font-semibold tracking-tight" }, "Upload artwork"), /* @__PURE__ */ React.createElement("span", { className: "text-xs uppercase tracking-[0.25em] text-sky-300" }, "Secure pipeline")), /* @__PURE__ */ React.createElement("p", { className: "mt-2 text-sm text-white/70" }, "All uploads are scanned, re-encoded, and published through the Skinbase pipeline."), /* @__PURE__ */ React.createElement( + ))), /* @__PURE__ */ React.createElement("div", { className: "grid gap-8 lg:grid-cols-[1.1fr,0.9fr]" }, /* @__PURE__ */ React.createElement("div", { className: "space-y-6" }, /* @__PURE__ */ React.createElement(SeoHead, { seo: { title: pageTitle, description: pageDescription, robots: "noindex, nofollow" } }), /* @__PURE__ */ React.createElement("div", { className: "rounded-2xl border border-white/10 bg-white/5 p-6 shadow-[0_0_50px_rgba(59,130,246,0.15)]" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ React.createElement("h1", { className: "text-3xl font-semibold tracking-tight" }, "Upload artwork"), /* @__PURE__ */ React.createElement("span", { className: "text-xs uppercase tracking-[0.25em] text-sky-300" }, "Secure pipeline")), /* @__PURE__ */ React.createElement("p", { className: "mt-2 text-sm text-white/70" }, "All uploads are scanned, re-encoded, and published through the Skinbase pipeline."), /* @__PURE__ */ React.createElement( "div", { className: "mt-6 rounded-2xl border border-dashed border-white/30 bg-white/5 p-6 text-center transition hover:border-sky-400/60", @@ -102686,7 +102695,7 @@ function WorldIndex() { const { props } = X(); const hasSpotlight = Boolean(props.spotlightWorld); const featuredFallback = !hasSpotlight && Array.isArray(props.featuredWorlds) ? props.featuredWorlds : []; - return /* @__PURE__ */ React.createElement("main", { className: "min-h-screen bg-[radial-gradient(circle_at_top_left,_rgba(249,115,22,0.12),_transparent_28%),radial-gradient(circle_at_top_right,_rgba(56,189,248,0.12),_transparent_32%),linear-gradient(180deg,_#020617_0%,_#02040a_100%)] px-4 py-10 sm:px-6 lg:px-8" }, /* @__PURE__ */ React.createElement(SeoHead, { title: props.seo?.title || "Worlds - Skinbase Nova", description: props.seo?.description || props.description, image: props.seo?.image }), /* @__PURE__ */ React.createElement("div", { className: "mx-auto max-w-7xl" }, /* @__PURE__ */ React.createElement("section", { className: "rounded-[36px] border border-white/10 bg-white/[0.03] p-6 sm:p-8" }, /* @__PURE__ */ React.createElement("div", { className: "max-w-4xl" }, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.24em] text-sky-200/70" }, "Skinbase Nova Worlds"), /* @__PURE__ */ React.createElement("h1", { className: "mt-4 text-4xl font-semibold tracking-[-0.05em] text-white sm:text-5xl" }, "Curated spaces for seasonal culture, scene moments, and editorial campaigns."), /* @__PURE__ */ React.createElement("p", { className: "mt-5 max-w-3xl text-base leading-7 text-slate-300" }, "Worlds bundle together artworks, collections, creators, groups, cards, releases, events, challenges, and newsroom context into a single themed destination. They are not filters. They are editorial environments."))), hasSpotlight ? /* @__PURE__ */ React.createElement("section", { className: "mt-8" }, /* @__PURE__ */ React.createElement( + return /* @__PURE__ */ React.createElement("main", { className: "min-h-screen bg-[radial-gradient(circle_at_top_left,_rgba(249,115,22,0.12),_transparent_28%),radial-gradient(circle_at_top_right,_rgba(56,189,248,0.12),_transparent_32%),linear-gradient(180deg,_#020617_0%,_#02040a_100%)] px-4 py-10 sm:px-6 lg:px-8" }, /* @__PURE__ */ React.createElement(SeoHead, { title: props.seo?.title || "Worlds - Skinbase", description: props.seo?.description || props.description, image: props.seo?.image }), /* @__PURE__ */ React.createElement("div", { className: "mx-auto max-w-7xl" }, /* @__PURE__ */ React.createElement("section", { className: "rounded-[36px] border border-white/10 bg-white/[0.03] p-6 sm:p-8" }, /* @__PURE__ */ React.createElement("div", { className: "max-w-4xl" }, /* @__PURE__ */ React.createElement("p", { className: "text-[11px] font-semibold uppercase tracking-[0.24em] text-sky-200/70" }, "Skinbase Worlds"), /* @__PURE__ */ React.createElement("h1", { className: "mt-4 text-4xl font-semibold tracking-[-0.05em] text-white sm:text-5xl" }, "Curated spaces for seasonal culture, scene moments, and editorial campaigns."), /* @__PURE__ */ React.createElement("p", { className: "mt-5 max-w-3xl text-base leading-7 text-slate-300" }, "Worlds bundle together artworks, collections, creators, groups, cards, releases, events, challenges, and newsroom context into a single themed destination. They are not filters. They are editorial environments."))), hasSpotlight ? /* @__PURE__ */ React.createElement("section", { className: "mt-8" }, /* @__PURE__ */ React.createElement( ActiveWorldSpotlight, { spotlight: props.spotlightWorld, @@ -102712,7 +102721,7 @@ function WorldIndex() { WorldsIndexSection, { title: "Active Worlds", - description: "Live worlds and currently running campaign surfaces across Skinbase Nova.", + description: "Live worlds and currently running campaign surfaces across Skinbase.", items: props.activeWorlds, emptyMessage: "No worlds are currently live. Check upcoming programming below.", sourceSurface: "worlds_index", @@ -103020,7 +103029,7 @@ function WorldShow() { container.removeEventListener("click", clickHandler); }; }, [previewMode, world?.id]); - return /* @__PURE__ */ React.createElement("main", { ref: rootRef, className: "min-h-screen bg-[radial-gradient(circle_at_top,_rgba(56,189,248,0.12),_transparent_28%),linear-gradient(180deg,_#020617_0%,_#02040a_100%)] px-4 py-10 sm:px-6 lg:px-8" }, /* @__PURE__ */ React.createElement(SeoHead, { title: props.seo?.title || `${world?.title || "World"} - Skinbase Nova`, description: props.seo?.description || world?.summary, image: props.seo?.image }), /* @__PURE__ */ React.createElement("div", { className: "mx-auto max-w-7xl" }, previewMode ? /* @__PURE__ */ React.createElement("section", { className: "mb-6 rounded-[28px] border border-amber-300/20 bg-amber-400/10 px-5 py-4 text-sm text-amber-50" }, /* @__PURE__ */ React.createElement("div", { className: "flex flex-wrap items-center justify-between gap-3" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("div", { className: "text-[11px] font-semibold uppercase tracking-[0.18em] text-amber-100/75" }, "Studio preview"), /* @__PURE__ */ React.createElement("div", { className: "mt-1 font-semibold text-white" }, "You are viewing the editorial preview version of this world before or alongside public release.")), world?.public_url ? /* @__PURE__ */ React.createElement("a", { href: world.public_url, className: "inline-flex items-center gap-2 rounded-full border border-white/15 bg-white/10 px-4 py-2 text-xs font-semibold uppercase tracking-[0.16em] text-white" }, "Open canonical page ", /* @__PURE__ */ React.createElement("i", { className: "fa-solid fa-up-right-from-square" })) : null)) : null, /* @__PURE__ */ React.createElement(WorldArchiveNotice, { notice: archiveNotice }), recap ? /* @__PURE__ */ React.createElement(WorldRecapHero, { world, recap, previewMode }) : /* @__PURE__ */ React.createElement(WorldHero, { world, previewMode }), recap ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(WorldRecapSummaryCard, { recap }), /* @__PURE__ */ React.createElement(WorldRecapStatsGrid, { stats: recap.stats }), /* @__PURE__ */ React.createElement(WorldRecapArticleCard, { article: recap.article }), /* @__PURE__ */ React.createElement(WorldRecapFeaturedArtworks, { section: recap.featured_artworks }), /* @__PURE__ */ React.createElement(WorldChallengePanel, { section: linkedChallenge })) : /* @__PURE__ */ React.createElement(WorldChallengePanel, { section: linkedChallenge }), familySummary ? /* @__PURE__ */ React.createElement("section", { className: "mt-10" }, /* @__PURE__ */ React.createElement("div", { className: "mb-5" }, /* @__PURE__ */ React.createElement("h2", { className: "text-2xl font-semibold tracking-[-0.03em] text-white" }, "Recurring Family"), /* @__PURE__ */ React.createElement("p", { className: "mt-2 max-w-3xl text-sm leading-6 text-slate-400" }, "Each edition stays public, but the family route always resolves to the canonical current or latest edition.")), /* @__PURE__ */ React.createElement(WorldFamilyCard, { family: familySummary, sourceSurface: "navigation", sourceDetail: "family_summary" })) : null, sections.length > 0 ? sections.map((section) => /* @__PURE__ */ React.createElement(WorldSection, { key: section.key, section })) : null, /* @__PURE__ */ React.createElement(WorldChallengeEntriesRail, { section: linkedChallengeEntries, challengeId: linkedChallenge?.id || null }), /* @__PURE__ */ React.createElement(WorldChallengeWinnersPanel, { section: linkedChallengeWinners, challengeId: linkedChallenge?.id || null }), /* @__PURE__ */ React.createElement(WorldChallengeFinalistsGrid, { panel: linkedChallenge, section: linkedChallengeFinalists }), recap ? /* @__PURE__ */ React.createElement(WorldRecapCommunityHighlights, { section: recap.community_highlights }) : /* @__PURE__ */ React.createElement(RewardedContributors, { section: rewardedContributors, world }), recap ? /* @__PURE__ */ React.createElement(WorldRecapCreatorsPanel, { section: recap.creators }) : /* @__PURE__ */ React.createElement(WorldCommunitySubmissionsSection, { section: communitySubmissions }), currentEdition ? /* @__PURE__ */ React.createElement( + return /* @__PURE__ */ React.createElement("main", { ref: rootRef, className: "min-h-screen bg-[radial-gradient(circle_at_top,_rgba(56,189,248,0.12),_transparent_28%),linear-gradient(180deg,_#020617_0%,_#02040a_100%)] px-4 py-10 sm:px-6 lg:px-8" }, /* @__PURE__ */ React.createElement(SeoHead, { title: props.seo?.title || `${world?.title || "World"} - Skinbase`, description: props.seo?.description || world?.summary, image: props.seo?.image }), /* @__PURE__ */ React.createElement("div", { className: "mx-auto max-w-7xl" }, previewMode ? /* @__PURE__ */ React.createElement("section", { className: "mb-6 rounded-[28px] border border-amber-300/20 bg-amber-400/10 px-5 py-4 text-sm text-amber-50" }, /* @__PURE__ */ React.createElement("div", { className: "flex flex-wrap items-center justify-between gap-3" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("div", { className: "text-[11px] font-semibold uppercase tracking-[0.18em] text-amber-100/75" }, "Studio preview"), /* @__PURE__ */ React.createElement("div", { className: "mt-1 font-semibold text-white" }, "You are viewing the editorial preview version of this world before or alongside public release.")), world?.public_url ? /* @__PURE__ */ React.createElement("a", { href: world.public_url, className: "inline-flex items-center gap-2 rounded-full border border-white/15 bg-white/10 px-4 py-2 text-xs font-semibold uppercase tracking-[0.16em] text-white" }, "Open canonical page ", /* @__PURE__ */ React.createElement("i", { className: "fa-solid fa-up-right-from-square" })) : null)) : null, /* @__PURE__ */ React.createElement(WorldArchiveNotice, { notice: archiveNotice }), recap ? /* @__PURE__ */ React.createElement(WorldRecapHero, { world, recap, previewMode }) : /* @__PURE__ */ React.createElement(WorldHero, { world, previewMode }), recap ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(WorldRecapSummaryCard, { recap }), /* @__PURE__ */ React.createElement(WorldRecapStatsGrid, { stats: recap.stats }), /* @__PURE__ */ React.createElement(WorldRecapArticleCard, { article: recap.article }), /* @__PURE__ */ React.createElement(WorldRecapFeaturedArtworks, { section: recap.featured_artworks }), /* @__PURE__ */ React.createElement(WorldChallengePanel, { section: linkedChallenge })) : /* @__PURE__ */ React.createElement(WorldChallengePanel, { section: linkedChallenge }), familySummary ? /* @__PURE__ */ React.createElement("section", { className: "mt-10" }, /* @__PURE__ */ React.createElement("div", { className: "mb-5" }, /* @__PURE__ */ React.createElement("h2", { className: "text-2xl font-semibold tracking-[-0.03em] text-white" }, "Recurring Family"), /* @__PURE__ */ React.createElement("p", { className: "mt-2 max-w-3xl text-sm leading-6 text-slate-400" }, "Each edition stays public, but the family route always resolves to the canonical current or latest edition.")), /* @__PURE__ */ React.createElement(WorldFamilyCard, { family: familySummary, sourceSurface: "navigation", sourceDetail: "family_summary" })) : null, sections.length > 0 ? sections.map((section) => /* @__PURE__ */ React.createElement(WorldSection, { key: section.key, section })) : null, /* @__PURE__ */ React.createElement(WorldChallengeEntriesRail, { section: linkedChallengeEntries, challengeId: linkedChallenge?.id || null }), /* @__PURE__ */ React.createElement(WorldChallengeWinnersPanel, { section: linkedChallengeWinners, challengeId: linkedChallenge?.id || null }), /* @__PURE__ */ React.createElement(WorldChallengeFinalistsGrid, { panel: linkedChallenge, section: linkedChallengeFinalists }), recap ? /* @__PURE__ */ React.createElement(WorldRecapCommunityHighlights, { section: recap.community_highlights }) : /* @__PURE__ */ React.createElement(RewardedContributors, { section: rewardedContributors, world }), recap ? /* @__PURE__ */ React.createElement(WorldRecapCreatorsPanel, { section: recap.creators }) : /* @__PURE__ */ React.createElement(WorldCommunitySubmissionsSection, { section: communitySubmissions }), currentEdition ? /* @__PURE__ */ React.createElement( SupportingRail, { title: "Current Edition", diff --git a/config/ranking.php b/config/ranking.php index 7a069b0c..0fd8eb37 100644 --- a/config/ranking.php +++ b/config/ranking.php @@ -3,7 +3,7 @@ declare(strict_types=1); /** - * Ranking system configuration — Skinbase Nova rank_v1 + * Ranking system configuration — Skinbase rank_v1 * * All weights, half-lives, and thresholds are tunable here. * Increment model_version when changing weights so caches expire gracefully. diff --git a/config/sitemaps.php b/config/sitemaps.php index ed4874ee..d50e0cfa 100644 --- a/config/sitemaps.php +++ b/config/sitemaps.php @@ -75,7 +75,7 @@ return [ 'news' => [ 'google_variant_enabled' => (bool) env('SITEMAPS_NEWS_GOOGLE_VARIANT', true), 'google_variant_name' => 'news-google', - 'google_publication_name' => env('SITEMAPS_NEWS_GOOGLE_PUBLICATION', env('APP_NAME', 'Skinbase Nova')), + 'google_publication_name' => env('SITEMAPS_NEWS_GOOGLE_PUBLICATION', env('APP_NAME', 'Skinbase')), 'google_language' => env('SITEMAPS_NEWS_GOOGLE_LANGUAGE', env('APP_LOCALE', 'en')), 'google_lookback_hours' => (int) env('SITEMAPS_NEWS_GOOGLE_LOOKBACK_HOURS', 48), 'google_max_items' => (int) env('SITEMAPS_NEWS_GOOGLE_MAX_ITEMS', 1000), diff --git a/database/seeders/HomepageAnnouncementLaunchSeeder.php b/database/seeders/HomepageAnnouncementLaunchSeeder.php index 87b83a47..ac46268d 100644 --- a/database/seeders/HomepageAnnouncementLaunchSeeder.php +++ b/database/seeders/HomepageAnnouncementLaunchSeeder.php @@ -19,16 +19,16 @@ final class HomepageAnnouncementLaunchSeeder extends Seeder [ 'placement' => HomepageAnnouncement::PLACEMENT_HOMEPAGE_AFTER_FEATURED, 'type' => HomepageAnnouncement::TYPE_LAUNCH, - 'title' => 'Skinbase Nova is live.', + 'title' => 'Skinbase is live.', ], [ 'subtitle' => 'A new chapter for the Skinbase creative community.', 'badge_text' => 'Launch Day · 1 May 2026', 'content_html' => implode("\n", [ '

Today, 1 May 2026, Skinbase begins a new chapter.

', - '

Skinbase Nova is a modern reboot of our creative community for digital art, wallpapers, skins, photography, customization, and discovery.

', + '

Skinbase is a modern reboot of our creative community for digital art, wallpapers, skins, photography, customization, and discovery.

', '

We are bringing the spirit of classic Skinbase into a faster, cleaner, and more modern experience — built for creators, fans, and the future.

', - '

Welcome to Skinbase Nova.

', + '

Welcome to Skinbase.

', ]), 'status' => HomepageAnnouncement::STATUS_PUBLISHED, 'is_active' => true, diff --git a/database/seeders/NewsLaunchSeeder.php b/database/seeders/NewsLaunchSeeder.php index 8f3a5fd3..6ede0707 100644 --- a/database/seeders/NewsLaunchSeeder.php +++ b/database/seeders/NewsLaunchSeeder.php @@ -54,11 +54,11 @@ final class NewsLaunchSeeder extends Seeder $articles = [ [ 'slug' => 'welcome-to-skinbase-nova', - 'title' => 'Welcome to Skinbase Nova', + 'title' => 'Welcome to Skinbase', 'type' => NewsArticle::TYPE_PLATFORM_UPDATE, 'category' => $categories['platform'], 'excerpt' => 'A first look at the refreshed Skinbase experience and the editorial direction behind Nova.', - 'content' => "# Welcome to Skinbase Nova\n\nSkinbase Nova brings publishing, discovery, Groups, and editorial storytelling into a single platform experience.\n\n## What is new\n\n- a dedicated newsroom\n- stronger creator identity surfaces\n- deeper internal linking across Groups, releases, and profiles\n- cleaner editorial publishing tools inside Studio\n\nNova is designed to feel active, curated, and connected to the people making the work.", + 'content' => "# Welcome to Skinbase\n\nSkinbase brings publishing, discovery, Groups, and editorial storytelling into a single platform experience.\n\n## What is new\n\n- a dedicated newsroom\n- stronger creator identity surfaces\n- deeper internal linking across Groups, releases, and profiles\n- cleaner editorial publishing tools inside Studio\n\nNova is designed to feel active, curated, and connected to the people making the work.", 'tags' => [$tags['nova'], $tags['platform-update']], 'days_ago' => 10, 'featured' => true, diff --git a/database/seeders/NovaCardDemoSeeder.php b/database/seeders/NovaCardDemoSeeder.php index accfedcc..07ea8d52 100644 --- a/database/seeders/NovaCardDemoSeeder.php +++ b/database/seeders/NovaCardDemoSeeder.php @@ -32,7 +32,7 @@ class NovaCardDemoSeeder extends Seeder ['email' => (string) Arr::get($userConfig, 'email', 'nova-cards-demo@skinbase.test')], [ 'username' => (string) Arr::get($userConfig, 'username', 'nova.cards'), - 'name' => (string) Arr::get($userConfig, 'name', 'Nova Cards'), + 'name' => (string) Arr::get($userConfig, 'name', 'Cards'), 'password' => (string) Arr::get($userConfig, 'password', 'password'), 'role' => 'user', ] @@ -43,9 +43,9 @@ class NovaCardDemoSeeder extends Seeder 'slug' => 'official-spark', 'title' => 'Official Spark', 'quote_text' => 'Small moments of focus turn into visible momentum.', - 'quote_author' => 'Skinbase Nova', + 'quote_author' => 'Skinbase', 'quote_source' => 'Launch Collection', - 'description' => 'An official Nova Cards demo card for featured browse surfaces.', + 'description' => 'An official Cards demo card for featured browse surfaces.', 'category_slug' => 'motivation', 'template_slug' => 'neon-nova', 'format' => NovaCard::FORMAT_SQUARE, @@ -61,9 +61,9 @@ class NovaCardDemoSeeder extends Seeder 'slug' => 'soft-breath', 'title' => 'Soft Breath', 'quote_text' => 'Rest is not a pause from growth. It is part of it.', - 'quote_author' => 'Skinbase Nova', + 'quote_author' => 'Skinbase', 'quote_source' => 'Healing Notes', - 'description' => 'A calm demo card showing the softer side of Nova Cards.', + 'description' => 'A calm demo card showing the softer side of Cards.', 'category_slug' => 'healing', 'template_slug' => 'soft-pastel', 'format' => NovaCard::FORMAT_PORTRAIT, @@ -79,7 +79,7 @@ class NovaCardDemoSeeder extends Seeder 'slug' => 'night-echo', 'title' => 'Night Echo', 'quote_text' => 'Not every quiet room is empty. Some are full of answers.', - 'quote_author' => 'Skinbase Nova', + 'quote_author' => 'Skinbase', 'quote_source' => 'Dark Mood Study', 'description' => 'A darker official demo card for mood-oriented discovery blocks.', 'category_slug' => 'dark-mood', @@ -97,7 +97,7 @@ class NovaCardDemoSeeder extends Seeder 'slug' => 'editorial-glow', 'title' => 'Editorial Glow', 'quote_text' => 'Design with restraint, then let one accent do the speaking.', - 'quote_author' => 'Skinbase Nova', + 'quote_author' => 'Skinbase', 'quote_source' => 'Editorial Kit', 'description' => 'A crisp editorial-format demo card for official collections.', 'category_slug' => 'motivation', @@ -115,7 +115,7 @@ class NovaCardDemoSeeder extends Seeder 'slug' => 'story-bloom', 'title' => 'Story Bloom', 'quote_text' => 'If the layout breathes, the words can reach further.', - 'quote_author' => 'Skinbase Nova', + 'quote_author' => 'Skinbase', 'quote_source' => 'Story Vertical Pack', 'description' => 'A vertical story-oriented demo card for public browsing and challenges.', 'category_slug' => 'healing', @@ -133,7 +133,7 @@ class NovaCardDemoSeeder extends Seeder 'slug' => 'remix-launch-variant', 'title' => 'Remix Launch Variant', 'quote_text' => 'Take the spark and give it a new rhythm.', - 'quote_author' => 'Skinbase Nova', + 'quote_author' => 'Skinbase', 'quote_source' => 'Remix Lab', 'description' => 'A seeded remix showing lineage in demo content.', 'category_slug' => 'motivation', @@ -262,7 +262,7 @@ class NovaCardDemoSeeder extends Seeder ['user_id' => $user->id, 'slug' => 'editorial-favorites'], [ 'name' => 'Editorial Favorites', - 'description' => 'Officially curated Nova Cards spotlighting launch visuals, remixes, and story-first layouts.', + 'description' => 'Officially curated Cards spotlighting launch visuals, remixes, and story-first layouts.', 'visibility' => NovaCardCollection::VISIBILITY_PUBLIC, 'official' => true, 'featured' => true, diff --git a/deploy/nginx/upstream-error-pages.conf b/deploy/nginx/upstream-error-pages.conf index 96c7b65b..ddb27e3f 100644 --- a/deploy/nginx/upstream-error-pages.conf +++ b/deploy/nginx/upstream-error-pages.conf @@ -1,5 +1,5 @@ # --------------------------------------------------------------------------- -# Nginx upstream / gateway error pages for Skinbase Nova +# Nginx upstream / gateway error pages for Skinbase # --------------------------------------------------------------------------- # Purpose: # Serve a Nova-styled static HTML page for nginx-level upstream failures such diff --git a/docs/ai-biography.md b/docs/ai-biography.md index abcfdb6a..28b40f36 100644 --- a/docs/ai-biography.md +++ b/docs/ai-biography.md @@ -1,6 +1,6 @@ # AI Biography -AI Biography is the Skinbase Nova feature that generates short, grounded creator biographies from public profile data. It is designed to be conservative: it prefers a safe, concise summary over a flashy or speculative one. +AI Biography is the Skinbase feature that generates short, grounded creator biographies from public profile data. It is designed to be conservative: it prefers a safe, concise summary over a flashy or speculative one. This document explains how the feature works, what commands are available, where output is stored, and where users can see it. diff --git a/docs/realtime-messaging.md b/docs/realtime-messaging.md index dedcd17b..1540a63e 100644 --- a/docs/realtime-messaging.md +++ b/docs/realtime-messaging.md @@ -1,6 +1,6 @@ # Realtime Messaging -Skinbase Nova messaging now uses Laravel Reverb, Laravel Broadcasting, Laravel Echo, Redis-backed queues, and Laravel Horizon for queue visibility. +Skinbase messaging now uses Laravel Reverb, Laravel Broadcasting, Laravel Echo, Redis-backed queues, and Laravel Horizon for queue visibility. ## v2 capabilities diff --git a/resources/js/Layouts/StudioLayout.jsx b/resources/js/Layouts/StudioLayout.jsx index 994d12bf..9759f259 100644 --- a/resources/js/Layouts/StudioLayout.jsx +++ b/resources/js/Layouts/StudioLayout.jsx @@ -1,5 +1,6 @@ import React, { useEffect, useState } from 'react' import { Link, usePage } from '@inertiajs/react' +import SeoHead from '../components/seo/SeoHead' import NovaSelect from '../components/ui/NovaSelect' import { studioModule, studioSurface, trackStudioEvent } from '../utils/studioEvents' @@ -268,6 +269,13 @@ export default function StudioLayout({ children, title, subtitle, actions }) { const [mobileOpen, setMobileOpen] = useState(false) const [createOpen, setCreateOpen] = useState(false) const pathname = url.split('?')[0] + const pageTitle = title ? `${title} — Creator Studio` : 'Creator Studio' + const pageDescription = subtitle || 'Manage your creator workspace from one shared Creator Studio surface.' + const pageSeo = { + title: pageTitle, + description: pageDescription, + robots: 'noindex,nofollow', + } const studioGroups = Array.isArray(props.studio_groups) ? props.studio_groups : [] const currentGroup = props.studioGroup || null const userLabel = props.auth?.user?.name || props.auth?.user?.username || 'Your creator workspace' @@ -391,6 +399,7 @@ export default function StudioLayout({ children, title, subtitle, actions }) { return (
+
diff --git a/resources/js/Pages/Collection/CollectionAnalytics.jsx b/resources/js/Pages/Collection/CollectionAnalytics.jsx index 7ed1a013..b7acf46d 100644 --- a/resources/js/Pages/Collection/CollectionAnalytics.jsx +++ b/resources/js/Pages/Collection/CollectionAnalytics.jsx @@ -66,7 +66,7 @@ export default function CollectionAnalytics() { return ( <> - {seo.title || `${collection.title || 'Collection'} Analytics — Skinbase Nova`} + {seo.title || `${collection.title || 'Collection'} Analytics — Skinbase`} {seo.canonical ? : null} diff --git a/resources/js/Pages/Collection/CollectionDashboard.jsx b/resources/js/Pages/Collection/CollectionDashboard.jsx index 667b9653..c0c2d66f 100644 --- a/resources/js/Pages/Collection/CollectionDashboard.jsx +++ b/resources/js/Pages/Collection/CollectionDashboard.jsx @@ -527,7 +527,7 @@ export default function CollectionDashboard() { return ( <> - {seo.title || 'Collections Dashboard — Skinbase Nova'} + {seo.title || 'Collections Dashboard — Skinbase'} {seo.canonical ? : null} diff --git a/resources/js/Pages/Collection/CollectionFeaturedIndex.jsx b/resources/js/Pages/Collection/CollectionFeaturedIndex.jsx index 2cdbd77c..7cdb46d6 100644 --- a/resources/js/Pages/Collection/CollectionFeaturedIndex.jsx +++ b/resources/js/Pages/Collection/CollectionFeaturedIndex.jsx @@ -255,7 +255,7 @@ export default function CollectionFeaturedIndex() { const seo = props.seo || {} const eyebrow = props.eyebrow || 'Discovery' const title = props.title || 'Featured collections' - const description = props.description || 'A rotating set of standout galleries from across Skinbase Nova. Some are meticulously hand-sequenced. Others are smart collections that stay fresh as the creator publishes new work.' + const description = props.description || 'A rotating set of standout galleries from across Skinbase. Some are meticulously hand-sequenced. Others are smart collections that stay fresh as the creator publishes new work.' const collections = Array.isArray(props.collections) ? props.collections : [] const communityCollections = Array.isArray(props.communityCollections) ? props.communityCollections : [] const editorialCollections = Array.isArray(props.editorialCollections) ? props.editorialCollections : [] @@ -288,7 +288,7 @@ export default function CollectionFeaturedIndex() { return ( <> - +
- {seo.title || `${collection.title || 'Collection'} History — Skinbase Nova`} + {seo.title || `${collection.title || 'Collection'} History — Skinbase`} {seo.canonical ? : null} diff --git a/resources/js/Pages/Collection/CollectionManage.jsx b/resources/js/Pages/Collection/CollectionManage.jsx index 6ff39a8c..94c9691c 100644 --- a/resources/js/Pages/Collection/CollectionManage.jsx +++ b/resources/js/Pages/Collection/CollectionManage.jsx @@ -1766,7 +1766,7 @@ export default function CollectionManage() { return ( <> - {mode === 'create' ? 'Create Collection — Skinbase Nova' : `${collectionState?.title || 'Collection'} — Manage Collection`} + {mode === 'create' ? 'Create Collection — Skinbase' : `${collectionState?.title || 'Collection'} — Manage Collection`} diff --git a/resources/js/Pages/Collection/CollectionSeriesShow.jsx b/resources/js/Pages/Collection/CollectionSeriesShow.jsx index 3d5a130b..434f7bef 100644 --- a/resources/js/Pages/Collection/CollectionSeriesShow.jsx +++ b/resources/js/Pages/Collection/CollectionSeriesShow.jsx @@ -19,14 +19,14 @@ export default function CollectionSeriesShow() { const { props } = usePage() const seo = props.seo || {} const title = props.title || `Collection Series: ${props.seriesKey || ''}` - const description = props.description || 'A connected sequence of public collections on Skinbase Nova.' + const description = props.description || 'A connected sequence of public collections on Skinbase.' const collections = Array.isArray(props.collections) ? props.collections : [] const leadCollection = props.leadCollection || null const stats = props.stats || {} return ( <> - +