@xhub-short/ui 0.1.0-beta.1 → 0.1.0-beta.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/CommentSheet.css-DyEc3Sro.d.ts +217 -0
- package/dist/VideoSlotPlayIndicator-DPs8Xt5C.d.ts +51 -0
- package/dist/chunk-3OB3OVYR.js +349 -0
- package/dist/{chunk-WKX2WBVO.js → chunk-3XPJHUYL.js} +1 -39
- package/dist/chunk-4RIMQOBR.js +58 -0
- package/dist/chunk-4TUBNA2X.js +180 -0
- package/dist/{chunk-4YDIRPIN.js → chunk-ANCP53F3.js} +3 -3
- package/dist/{chunk-UXMA4KJZ.js → chunk-CAWE42LH.js} +5 -3
- package/dist/{chunk-ANGBSV7L.js → chunk-CIIZ3IHV.js} +10 -5
- package/dist/chunk-DR7KR7OT.js +103 -0
- package/dist/chunk-DXLCQ4FH.js +102 -0
- package/dist/chunk-EDWS2IPH.js +1 -0
- package/dist/chunk-FR7UQSZP.js +570 -0
- package/dist/chunk-IWSBYOSS.js +91 -0
- package/dist/chunk-JEY6R4KJ.js +334 -0
- package/dist/chunk-KMJ3PQ7M.js +1262 -0
- package/dist/chunk-MFJS65C5.js +368 -0
- package/dist/{chunk-HW4LXTFT.js → chunk-OM4L7RE5.js} +18 -6
- package/dist/chunk-PBIH2F2Q.js +344 -0
- package/dist/chunk-PJ4NMVMY.js +326 -0
- package/dist/chunk-Q6MG7AVG.js +531 -0
- package/dist/chunk-QCKVF2DR.js +713 -0
- package/dist/chunk-QCRRF76W.js +75 -0
- package/dist/chunk-QUEJHA24.js +508 -0
- package/dist/chunk-VXW7AOGM.js +285 -0
- package/dist/chunk-YB7AXTX7.js +430 -0
- package/dist/chunk-ZGWSJ6Z5.js +601 -0
- package/dist/components/ActionBar/index.js +1 -1
- package/dist/components/AdvanceMenu/index.d.ts +78 -0
- package/dist/components/AdvanceMenu/index.js +1 -0
- package/dist/components/AuthorInfo/index.d.ts +5 -1
- package/dist/components/AuthorInfo/index.js +1 -1
- package/dist/components/BottomSheet/index.d.ts +82 -0
- package/dist/components/BottomSheet/index.js +1 -0
- package/dist/components/CleanModeOverlay/index.d.ts +60 -0
- package/dist/components/CleanModeOverlay/index.js +1 -0
- package/dist/components/CommentSheet/index.d.ts +164 -0
- package/dist/components/CommentSheet/index.js +1 -0
- package/dist/components/DetailView/index.d.ts +311 -0
- package/dist/components/DetailView/index.js +1 -0
- package/dist/components/ErrorBoundary/index.js +1 -1
- package/dist/components/ImageCarousel/index.d.ts +50 -0
- package/dist/components/ImageCarousel/index.js +1 -0
- package/dist/components/ImagePostSlot/index.d.ts +207 -0
- package/dist/components/ImagePostSlot/index.js +1 -0
- package/dist/components/ProgressBar/index.d.ts +30 -2
- package/dist/components/ProgressBar/index.js +1 -1
- package/dist/components/QualityPicker/index.d.ts +35 -0
- package/dist/components/QualityPicker/index.js +1 -0
- package/dist/components/ReportSheet/index.d.ts +68 -0
- package/dist/components/ReportSheet/index.js +1 -0
- package/dist/components/Skeleton/index.js +1 -1
- package/dist/components/SpeedPicker/index.d.ts +32 -0
- package/dist/components/SpeedPicker/index.js +1 -0
- package/dist/components/VideoFeed/index.d.ts +12 -1
- package/dist/components/VideoFeed/index.js +1 -1
- package/dist/components/VideoInfo/index.d.ts +4 -2
- package/dist/components/VideoInfo/index.js +1 -1
- package/dist/components/VideoPlayer/index.d.ts +14 -41
- package/dist/components/VideoPlayer/index.js +1 -1
- package/dist/components/VideoSlot/index.d.ts +84 -65
- package/dist/components/VideoSlot/index.js +2 -1
- package/dist/components/VirtualSlider/index.d.ts +339 -0
- package/dist/components/VirtualSlider/index.js +1 -0
- package/dist/components/icons/index.js +1 -1
- package/dist/index.d.ts +107 -95
- package/dist/index.js +84 -27
- package/package.json +51 -7
- package/dist/chunk-2PTMP65P.js +0 -738
- package/dist/chunk-4MN72OZH.js +0 -148
- package/dist/chunk-DHQJBXQW.js +0 -562
- package/dist/chunk-SSJDO24Q.js +0 -204
- package/dist/chunk-XAOEHLOX.js +0 -1326
- package/dist/chunk-YW23IBKF.js +0 -530
- package/dist/chunk-ZZDQKP4R.js +0 -418
- package/dist/use-gesture-react.esm-3SV4QLEJ.js +0 -1893
package/dist/index.d.ts
CHANGED
|
@@ -1,18 +1,28 @@
|
|
|
1
1
|
import { VideoItem, UIPlayerState, UIPlayerControls, UIInteractionState, UIInteractionActions } from '@xhub-short/contracts';
|
|
2
2
|
import * as react from 'react';
|
|
3
3
|
import { ReactNode, ReactElement } from 'react';
|
|
4
|
-
export { clsx } from 'clsx';
|
|
4
|
+
export { clsx, clsx as cn } from 'clsx';
|
|
5
5
|
export { ErrorBoundary, ErrorBoundaryProps, ErrorMode } from './components/ErrorBoundary/index.js';
|
|
6
6
|
export { Skeleton, SkeletonAnimation, SkeletonAvatar, SkeletonProps, SkeletonText, SkeletonVideo } from './components/Skeleton/index.js';
|
|
7
7
|
export { BookmarkFilledIcon, BookmarkIcon, CloseIcon, CommentIcon, HeartFilledIcon, HeartIcon, IconProps, MoreIcon, MusicIcon, PauseIcon, PlayIcon, PlusIcon, ShareIcon, UserCheckIcon, UserPlusIcon, VerifiedIcon, VolumeIcon, VolumeMutedIcon } from './components/icons/index.js';
|
|
8
|
+
export { DEFAULT_BUFFER_SIZE, DEFAULT_EMPTY_TEXT, DEFAULT_END_REACHED_THRESHOLD, DEFAULT_END_TEXT, DEFAULT_LOADING_TEXT, SLIDER_CLASS, SLIDER_CONTAINER_CLASS, SLIDER_CONTAINER_SNAPPING_CLASS, SLIDER_CONTAINER_SWIPING_CLASS, SLOT_ACTIVE_ATTR as SLIDER_SLOT_ACTIVE_ATTR, SLIDER_SLOT_ACTIVE_CLASS, SLOT_ACTIVE_DATASET_KEY as SLIDER_SLOT_ACTIVE_DATASET_KEY, SLIDER_SLOT_ADJACENT_CLASS, SLIDER_SLOT_CLASS, SLOT_INDEX_ATTR as SLIDER_SLOT_INDEX_ATTR, SLOT_INDEX_DATASET_KEY as SLIDER_SLOT_INDEX_DATASET_KEY, SLIDER_SLOT_TRANSITIONING_CLASS, SlotPosition as SliderSlotPosition, UseSliderPositionOptions, UseSliderPositionReturn, VIRTUAL_SLIDER_CSS, VirtualSlider, VirtualSliderContext, VirtualSliderContextValue, VirtualSliderProps, getSlotIndexFromPosition as getSliderIndexFromPosition, useOptionalVirtualSliderContext, useSliderActiveIndex, useSliderIsSwiping, useSliderPosition, useVirtualSliderContext } from './components/VirtualSlider/index.js';
|
|
9
|
+
export { IMAGE_CAROUSEL_CSS, ImageCarouselHeadless, ImageCarouselProps } from './components/ImageCarousel/index.js';
|
|
10
|
+
export { IMAGE_POST_ACTIVE_ATTR, IMAGE_POST_ID_ATTR, IMAGE_POST_SLOT_ACTIVE_CLASS, IMAGE_POST_SLOT_CLASS, IMAGE_POST_SLOT_CLEAN_MODE_CLASS, IMAGE_POST_SLOT_CSS, ImagePostSlotActions, ImagePostSlotActionsProps, ImagePostSlotBottom, ImagePostSlotBottomProps, ImagePostSlotCaption, ImagePostSlotCaptionProps, ImagePostSlotContextValue, ImagePostSlotHeadless, ImagePostSlotHeadlessProps, ImagePostSlotMusic, ImagePostSlotMusicProps, ImagePostSlotOverlay, ImagePostSlotOverlayProps, ImagePostSlotPlayIndicator, ImagePostSlotPlayIndicatorProps, ImagePostSlotReadMore, ImagePostSlotReadMoreProps, useImagePostSlotContext, useOptionalImagePostSlotContext } from './components/ImagePostSlot/index.js';
|
|
11
|
+
export { DETAIL_VIEW_CSS, DetailViewAuthor, DetailViewAuthorProps, DetailViewCaption, DetailViewCaptionProps, DetailViewContextValue, DetailViewGallery, DetailViewGalleryProps, DetailViewHeadless, DetailViewHeadlessProps, DetailViewMusic, DetailViewMusicProps, DetailViewStats, DetailViewStatsProps, useDetailViewContext } from './components/DetailView/index.js';
|
|
8
12
|
export { SLOT_ACTIVE_ATTR, SLOT_ACTIVE_DATASET_KEY, SLOT_INDEX_ATTR, SLOT_INDEX_DATASET_KEY, SlotPosition, UseVideoFeedPositionOptions, UseVideoFeedPositionReturn, VIDEO_FEED_CLASS_PREFIX, VIDEO_FEED_CSS, VideoFeedContext, VideoFeedContextValue, VideoFeedHeadless, VideoFeedHeadlessProps, getSlotIndexFromPosition, useOptionalVideoFeedContext, useVideoFeedContext, useVideoFeedPosition } from './components/VideoFeed/index.js';
|
|
9
|
-
export { HeartInstance, LOADING_ATTR, LOADING_DATASET_KEY, LikeAnimationStyle, PLAYER_STATE_ATTR, PLAYER_STATE_DATASET_KEY, SLOT_CLASS, SLOT_ERROR_CLASS, SLOT_LOADING_CLASS, SLOT_PAUSED_CLASS, SLOT_PLAYING_CLASS, VIDEO_ID_ATTR, VIDEO_ID_DATASET_KEY, VIDEO_SLOT_CSS, VIDEO_SLOT_LIKE_ANIMATION_CSS, VideoSlotContext, VideoSlotContextValue, VideoSlotHeadless, VideoSlotHeadlessExtendedProps, VideoSlotLikeAnimation, VideoSlotLikeAnimationProps, VideoSlotLikeAnimationRef, VideoSlotOverlay, VideoSlotOverlayProps, VideoSlotOverlayRegionProps, VideoSlotPoster, VideoSlotPosterProps, VideoSlotSkeleton, Z_INDEX, Z_INDEX_CSS_VARS, useOptionalVideoSlotContext, useVideoSlotContext, useVideoSlotIsActive, useVideoSlotIsPlaying, useVideoSlotPlayer, useVideoSlotResource, useVideoSlotVideo } from './components/VideoSlot/index.js';
|
|
13
|
+
export { HeartInstance, LOADING_ATTR, LOADING_DATASET_KEY, LikeAnimationStyle, PLAYER_STATE_ATTR, PLAYER_STATE_DATASET_KEY, ReportedVideoOverlay, ReportedVideoOverlayProps, SLOT_CLASS, SLOT_ERROR_CLASS, SLOT_LOADING_CLASS, SLOT_PAUSED_CLASS, SLOT_PLAYING_CLASS, VIDEO_ID_ATTR, VIDEO_ID_DATASET_KEY, VIDEO_SLOT_CSS, VIDEO_SLOT_LIKE_ANIMATION_CSS, VideoSlotContext, VideoSlotContextValue, VideoSlotHeadless, VideoSlotHeadlessExtendedProps, VideoSlotLikeAnimation, VideoSlotLikeAnimationProps, VideoSlotLikeAnimationRef, VideoSlotOverlay, VideoSlotOverlayProps, VideoSlotOverlayRegionProps, VideoSlotPoster, VideoSlotPosterProps, VideoSlotSkeleton, Z_INDEX, Z_INDEX_CSS_VARS, useOptionalVideoSlotContext, useVideoSlotContext, useVideoSlotIsActive, useVideoSlotIsPlaying, useVideoSlotPlayer, useVideoSlotResource, useVideoSlotVideo } from './components/VideoSlot/index.js';
|
|
14
|
+
export { V as VideoSlotPlayIndicator, a as VideoSlotPlayIndicatorProps } from './VideoSlotPlayIndicator-DPs8Xt5C.js';
|
|
10
15
|
export { BUFFERING_STATE_CLASS, ENDED_CLASS, ERROR_CLASS, ERROR_STATE_CLASS, LOADING_CLASS, LOADING_STATE_ATTR, LOADING_STATE_CLASS, PAUSED_CLASS, PLAYBACK_STATE_ATTR, PLAYER_CLASS, PLAYING_CLASS, POSTER_CLASS, READY_CLASS, UseAutoFirstFrameCaptureConfig, UseFirstFrameCaptureConfig, UseFirstFrameCaptureReturn, UseVideoElementConfig, UseVideoElementReturn, VIDEO_CLASS, VIDEO_PLAYER_CSS, Z_INDEX as VIDEO_PLAYER_Z_INDEX, Z_INDEX_CSS_VARS as VIDEO_PLAYER_Z_INDEX_CSS_VARS, VIDEO_TYPE_ATTR, VIDEO_WRAPPER_CLASS, VideoElementError, VideoErrorOrigin, VideoPlayerHeadless, VideoPlayerHeadlessExtendedProps, VideoSourceType, useAutoFirstFrameCapture, useFirstFrameCapture, useVideoElement } from './components/VideoPlayer/index.js';
|
|
11
16
|
export { PROGRESS_BAR_CSS, ProgressBarHeadless, ProgressBarHeadlessExtendedProps, calculateProgress, formatTime } from './components/ProgressBar/index.js';
|
|
12
17
|
export { ACTION_BAR_CSS, ActionBarBookmark, ActionBarComment, ActionBarHeadless, ActionBarHeadlessExtendedProps, ActionBarLike, ActionBarShare, ActionButton, ActionButtonExtendedProps, BookmarkButton, BookmarkButtonProps, CommentButton, CommentButtonProps, LikeButton, LikeButtonProps, ShareButton, ShareButtonProps } from './components/ActionBar/index.js';
|
|
13
18
|
export { AUTHOR_INFO_CSS, AuthorAvatar, AuthorAvatarProps, AuthorDescription, AuthorDescriptionProps, AuthorInfoContext, AuthorInfoContextValue, AuthorInfoHeadless, AuthorInfoHeadlessExtendedProps, AuthorInfoVariant, AuthorName, AuthorNameProps, AvatarSize, FollowButton, FollowButtonProps, FollowButtonSize, useAuthorInfoContext, useOptionalAuthorInfoContext } from './components/AuthorInfo/index.js';
|
|
14
19
|
export { VIDEO_INFO_CSS, VideoAuthorName, VideoAuthorNameProps, VideoCaption, VideoCaptionProps, VideoHashtags, VideoHashtagsProps, VideoInfoContext, VideoInfoContextValue, VideoInfoHeadless, VideoInfoHeadlessExtendedProps, VideoLocation, VideoLocationProps, VideoMusic, VideoMusicProps, useOptionalVideoInfoContext, useVideoInfoContext } from './components/VideoInfo/index.js';
|
|
15
|
-
|
|
20
|
+
export { n as COMMENT_SHEET_CSS, f as CommentInput, g as CommentInputProps, h as CommentItemComponent, i as CommentItemProps, d as CommentList, e as CommentListProps, C as CommentSheet, j as CommentSheetContext, l as CommentSheetContextValue, a as CommentSheetHeadless, b as CommentSheetHeadlessProps, m as CommentSheetI18n, R as ReplyTarget, S as SheetHeader, c as SheetHeaderProps, u as useCommentSheetContext, k as useOptionalCommentSheetContext } from './CommentSheet.css-DyEc3Sro.js';
|
|
21
|
+
export { ADVANCE_MENU_CSS, AdvanceMenuHeadless, AdvanceMenuHeadlessProps, AdvanceMenuItemProps, AdvanceMenuSectionTitleProps, AdvanceMenuSeparatorProps } from './components/AdvanceMenu/index.js';
|
|
22
|
+
export { DEFAULT_SPEEDS, SPEED_PICKER_CSS, SpeedPickerHeadless, SpeedPickerHeadlessProps } from './components/SpeedPicker/index.js';
|
|
23
|
+
export { QUALITY_PICKER_CSS, QualityPickerHeadless, QualityPickerHeadlessProps } from './components/QualityPicker/index.js';
|
|
24
|
+
export { CLEAN_MODE_OVERLAY_CSS, CleanModeOverlayHeadless, CleanModeOverlayHeadlessProps, injectCleanModeOverlayCSS } from './components/CleanModeOverlay/index.js';
|
|
25
|
+
export { REPORT_SHEET_CSS, ReportSheetHeadless, ReportSheetHeadlessProps, ReportSheetState, injectReportSheetCSS } from './components/ReportSheet/index.js';
|
|
16
26
|
import 'react/jsx-runtime';
|
|
17
27
|
|
|
18
28
|
/**
|
|
@@ -85,8 +95,26 @@ declare function areStylesInjected(): boolean;
|
|
|
85
95
|
* - Works with any bundler (Next.js, Vite, Webpack)
|
|
86
96
|
*
|
|
87
97
|
* Design Tokens from: User-provided tokens (Urbanist font, light/dark mode)
|
|
98
|
+
*
|
|
99
|
+
* ## CSS Layers
|
|
100
|
+
*
|
|
101
|
+
* SDK styles use `@layer sv` for low specificity. This allows host apps to
|
|
102
|
+
* override styles easily WITHOUT using `!important`.
|
|
103
|
+
*
|
|
104
|
+
* Host app can override by:
|
|
105
|
+
* 1. Using any CSS without @layer (higher priority)
|
|
106
|
+
* 2. Overriding CSS Variables (recommended for theming)
|
|
107
|
+
* 3. Using `@layer host { }` declared AFTER `sv` layer
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```css
|
|
111
|
+
* // Host app styles - no !important needed
|
|
112
|
+
* .my-custom-action-bar {
|
|
113
|
+
* gap: 20px; // Overrides SDK's gap easily
|
|
114
|
+
* }
|
|
115
|
+
* ```
|
|
88
116
|
*/
|
|
89
|
-
declare const CSS_CONTENT = "\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n XHub-short UI Styles - Auto-injected\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n FONT LOADING\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n@import url('https://fonts.googleapis.com/css2?family=Urbanist:wght@400;500;600;700&display=swap');\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n CSS VARIABLES - Light Mode (Default)\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n:root {\n /* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n COLOR TOKENS - Light Mode\n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n --sv-color-primary: #164c8e;\n --sv-color-primary-alpha: #164c8e5b;\n --sv-color-secondary: #9fc5e9;\n --sv-color-tertiary: #e9f8ff;\n --sv-color-quaternary: #164c8e5b;\n\n --sv-color-contrast-positive: #121212;\n --sv-color-contrast-negative: #ffffff;\n\n --sv-color-accent: #a2a2a2;\n --sv-color-accent-2: #6b7271;\n --sv-color-accent-stroke: #e5e6e6;\n\n --sv-color-error: #ff434e;\n --sv-color-success: #1da031;\n --sv-color-warning: #daa000;\n --sv-color-info: #29c8f0;\n\n /* Semantic aliases */\n --sv-color-background: var(--sv-color-contrast-negative);\n --sv-color-text: var(--sv-color-contrast-positive);\n --sv-color-text-secondary: var(--sv-color-accent-2);\n --sv-color-text-muted: var(--sv-color-accent);\n --sv-color-border: var(--sv-color-accent-stroke);\n\n /* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n TYPOGRAPHY TOKENS - Mobile (Default)\n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n --sv-font-family: 'Urbanist', system-ui, -apple-system, BlinkMacSystemFont, sans-serif;\n --sv-font-family-display: 'SF Pro Display', 'Urbanist', system-ui, sans-serif;\n\n --sv-font-size-xxs: 10px;\n --sv-font-size-xs: 12px;\n --sv-font-size-sm: 13px;\n --sv-font-size-md: 14px;\n --sv-font-size-lg: 16px;\n --sv-font-size-xl: 20px;\n\n --sv-font-weight-regular: 400;\n --sv-font-weight-medium: 500;\n --sv-font-weight-semibold: 600;\n --sv-font-weight-bold: 700;\n\n --sv-line-height-tight: 1.2;\n --sv-line-height-normal: 1.4;\n --sv-line-height-relaxed: 1.6;\n\n /* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n SPACING TOKENS\n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n --sv-spacing-xxs: 2px;\n --sv-spacing-xs: 4px;\n --sv-spacing-sm: 8px;\n --sv-spacing-md: 12px;\n --sv-spacing-lg: 16px;\n --sv-spacing-xl: 24px;\n --sv-spacing-xxl: 32px;\n\n /* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n BORDER RADIUS\n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n --sv-radius-sm: 4px;\n --sv-radius-md: 8px;\n --sv-radius-lg: 12px;\n --sv-radius-xl: 16px;\n --sv-radius-full: 9999px;\n\n /* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n TRANSITIONS\n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n --sv-transition-fast: 150ms ease;\n --sv-transition-normal: 250ms ease;\n --sv-transition-slow: 350ms ease;\n\n /* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Z-INDEX LAYERS\n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n --sv-z-base: 1;\n --sv-z-video: 1;\n --sv-z-overlay: 10;\n --sv-z-controls: 20;\n --sv-z-modal: 100;\n --sv-z-toast: 1000;\n\n /* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n SHADOWS\n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n --sv-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);\n --sv-shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);\n --sv-shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.15);\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n CSS VARIABLES - Dark Mode\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n/* System preference */\n@media (prefers-color-scheme: dark) {\n :root:not([data-theme=\"light\"]) {\n --sv-color-primary: #a6cec7;\n --sv-color-primary-alpha: #164c8e5b;\n --sv-color-secondary: #143a0c;\n --sv-color-tertiary: #252825;\n --sv-color-quaternary: #164c8e5b;\n\n --sv-color-contrast-positive: #ffffff;\n --sv-color-contrast-negative: #121212;\n\n --sv-color-accent: #6b7271;\n --sv-color-accent-2: #d2dddb;\n --sv-color-accent-stroke: #373737;\n\n --sv-color-error: #b62a32;\n --sv-color-success: #20a634;\n --sv-color-warning: #c29823;\n --sv-color-info: #1fa0c0;\n\n /* Semantic aliases update automatically */\n --sv-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.2);\n --sv-shadow-md: 0 4px 6px rgba(0, 0, 0, 0.3);\n --sv-shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.4);\n }\n}\n\n/* Explicit dark mode (override) */\n[data-theme=\"dark\"],\n.dark {\n --sv-color-primary: #a6cec7;\n --sv-color-primary-alpha: #164c8e5b;\n --sv-color-secondary: #143a0c;\n --sv-color-tertiary: #252825;\n --sv-color-quaternary: #164c8e5b;\n\n --sv-color-contrast-positive: #ffffff;\n --sv-color-contrast-negative: #121212;\n\n --sv-color-accent: #6b7271;\n --sv-color-accent-2: #d2dddb;\n --sv-color-accent-stroke: #373737;\n\n --sv-color-error: #b62a32;\n --sv-color-success: #20a634;\n --sv-color-warning: #c29823;\n --sv-color-info: #1fa0c0;\n\n --sv-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.2);\n --sv-shadow-md: 0 4px 6px rgba(0, 0, 0, 0.3);\n --sv-shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.4);\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n TABLET BREAKPOINT - Typography scaling\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n@media (min-width: 768px) {\n :root {\n --sv-font-size-xxs: 11px;\n --sv-font-size-xs: 13px;\n --sv-font-size-sm: 14px;\n --sv-font-size-md: 16px;\n --sv-font-size-lg: 18px;\n --sv-font-size-xl: 24px;\n }\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n BASE STYLES\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-root {\n font-family: var(--sv-font-family);\n font-size: var(--sv-font-size-md);\n font-weight: var(--sv-font-weight-regular);\n line-height: var(--sv-line-height-normal);\n color: var(--sv-color-text);\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n FEED CONTAINER\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-feed {\n position: relative;\n width: 100%;\n height: 100%;\n overflow: hidden;\n background: var(--sv-color-contrast-negative);\n touch-action: pan-y;\n -webkit-overflow-scrolling: touch;\n}\n\n.sv-feed::-webkit-scrollbar {\n display: none;\n}\n\n.sv-feed {\n -ms-overflow-style: none;\n scrollbar-width: none;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n VIDEO SLOT\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-slot {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--sv-color-contrast-negative);\n will-change: transform;\n}\n\n.sv-slot--active {\n z-index: var(--sv-z-video);\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n VIDEO PLAYER\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-player {\n position: relative;\n width: 100%;\n height: 100%;\n background: var(--sv-color-contrast-negative);\n}\n\n.sv-player__video {\n width: 100%;\n height: 100%;\n object-fit: cover;\n background: var(--sv-color-contrast-negative);\n}\n\n.sv-player__poster {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n object-fit: cover;\n z-index: 1;\n transition: opacity var(--sv-transition-normal);\n}\n\n.sv-player__poster--hidden {\n opacity: 0;\n pointer-events: none;\n}\n\n.sv-player__overlay {\n position: absolute;\n inset: 0;\n background: linear-gradient(\n to bottom,\n transparent 0%,\n transparent 50%,\n rgba(0, 0, 0, 0.3) 100%\n );\n pointer-events: none;\n z-index: var(--sv-z-overlay);\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n PROGRESS BAR\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-progress {\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 3px;\n background: rgba(255, 255, 255, 0.2);\n z-index: var(--sv-z-controls);\n}\n\n.sv-progress__bar {\n height: 100%;\n background: var(--sv-color-contrast-positive);\n transition: width 100ms linear;\n will-change: width;\n}\n\n.sv-progress__bar--buffered {\n position: absolute;\n top: 0;\n left: 0;\n height: 100%;\n background: rgba(255, 255, 255, 0.3);\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n INTERACTION BAR (Right side actions)\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-actions {\n position: absolute;\n right: var(--sv-spacing-md);\n bottom: 120px;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: var(--sv-spacing-xl);\n z-index: var(--sv-z-controls);\n}\n\n.sv-action-btn {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: var(--sv-spacing-xs);\n background: none;\n border: none;\n padding: 0;\n cursor: pointer;\n color: var(--sv-color-contrast-positive);\n transition: transform var(--sv-transition-fast);\n -webkit-tap-highlight-color: transparent;\n}\n\n.sv-action-btn:active {\n transform: scale(0.9);\n}\n\n.sv-action-btn__icon {\n width: 44px;\n height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: rgba(0, 0, 0, 0.3);\n border-radius: var(--sv-radius-full);\n backdrop-filter: blur(4px);\n -webkit-backdrop-filter: blur(4px);\n}\n\n.sv-action-btn__icon svg {\n width: 24px;\n height: 24px;\n fill: currentColor;\n}\n\n.sv-action-btn__count {\n font-size: var(--sv-font-size-xs);\n font-weight: var(--sv-font-weight-semibold);\n color: var(--sv-color-contrast-positive);\n}\n\n/* Like button states */\n.sv-action-btn--liked .sv-action-btn__icon {\n color: var(--sv-color-error);\n}\n\n.sv-action-btn--liked .sv-action-btn__icon svg {\n animation: sv-like-pop 0.3s ease;\n}\n\n@keyframes sv-like-pop {\n 0% { transform: scale(1); }\n 50% { transform: scale(1.3); }\n 100% { transform: scale(1); }\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n AUTHOR INFO (Bottom left)\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-author {\n position: absolute;\n left: var(--sv-spacing-md);\n bottom: 80px;\n display: flex;\n flex-direction: column;\n gap: var(--sv-spacing-md);\n max-width: calc(100% - 80px);\n z-index: var(--sv-z-controls);\n}\n\n.sv-author__row {\n display: flex;\n align-items: center;\n gap: var(--sv-spacing-md);\n}\n\n.sv-author__avatar {\n width: 48px;\n height: 48px;\n border-radius: var(--sv-radius-full);\n border: 2px solid var(--sv-color-contrast-positive);\n object-fit: cover;\n flex-shrink: 0;\n}\n\n.sv-author__info {\n display: flex;\n flex-direction: column;\n gap: var(--sv-spacing-xxs);\n min-width: 0;\n}\n\n.sv-author__name {\n font-size: var(--sv-font-size-lg);\n font-weight: var(--sv-font-weight-semibold);\n color: var(--sv-color-contrast-positive);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.sv-author__handle {\n font-size: var(--sv-font-size-sm);\n color: rgba(255, 255, 255, 0.8);\n}\n\n.sv-author__description {\n font-size: var(--sv-font-size-sm);\n color: var(--sv-color-contrast-positive);\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n line-height: var(--sv-line-height-relaxed);\n}\n\n/* Follow button */\n.sv-follow-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: var(--sv-spacing-xs) var(--sv-spacing-md);\n font-size: var(--sv-font-size-sm);\n font-weight: var(--sv-font-weight-semibold);\n font-family: var(--sv-font-family);\n color: var(--sv-color-contrast-negative);\n background: var(--sv-color-primary);\n border: none;\n border-radius: var(--sv-radius-sm);\n cursor: pointer;\n transition: all var(--sv-transition-fast);\n -webkit-tap-highlight-color: transparent;\n}\n\n.sv-follow-btn:active {\n transform: scale(0.95);\n}\n\n.sv-follow-btn--following {\n background: transparent;\n color: var(--sv-color-contrast-positive);\n border: 1px solid var(--sv-color-contrast-positive);\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n SPINNER / LOADING\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-spinner {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n}\n\n.sv-spinner__circle {\n width: 32px;\n height: 32px;\n border: 3px solid rgba(255, 255, 255, 0.2);\n border-top-color: var(--sv-color-contrast-positive);\n border-radius: var(--sv-radius-full);\n animation: sv-spin 0.8s linear infinite;\n}\n\n.sv-spinner--sm .sv-spinner__circle {\n width: 20px;\n height: 20px;\n border-width: 2px;\n}\n\n.sv-spinner--lg .sv-spinner__circle {\n width: 48px;\n height: 48px;\n border-width: 4px;\n}\n\n@keyframes sv-spin {\n to { transform: rotate(360deg); }\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n MUSIC INFO (Bottom - optional)\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-music {\n position: absolute;\n left: var(--sv-spacing-md);\n bottom: var(--sv-spacing-lg);\n display: flex;\n align-items: center;\n gap: var(--sv-spacing-sm);\n max-width: calc(100% - 80px);\n z-index: var(--sv-z-controls);\n}\n\n.sv-music__icon {\n width: 20px;\n height: 20px;\n flex-shrink: 0;\n}\n\n.sv-music__text {\n font-size: var(--sv-font-size-sm);\n color: var(--sv-color-contrast-positive);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.sv-music__marquee {\n animation: sv-marquee 10s linear infinite;\n}\n\n@keyframes sv-marquee {\n 0% { transform: translateX(0); }\n 100% { transform: translateX(-50%); }\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n UTILITIES\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n}\n\n.sv-tap-highlight-none {\n -webkit-tap-highlight-color: transparent;\n}\n\n/* Prevent text selection during gestures */\n.sv-no-select {\n -webkit-user-select: none;\n user-select: none;\n}\n\n/* Hardware acceleration hint */\n.sv-gpu {\n transform: translateZ(0);\n will-change: transform;\n}\n";
|
|
117
|
+
declare const CSS_CONTENT = "\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n XHub-short UI Styles - Auto-injected\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n CSS LAYER DECLARATION\n \n Declare the 'sv' layer first. All SDK component styles go into this layer.\n Host app styles WITHOUT @layer automatically have HIGHER priority.\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n@layer sv;\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n FONT LOADING (outside layer - needs to be global)\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n@import url('https://fonts.googleapis.com/css2?family=Urbanist:wght@400;500;600;700&display=swap');\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n CSS VARIABLES - Light Mode (Default)\n Outside layer so host app can easily override variables\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n:root {\n /* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n COLOR TOKENS - Light Mode\n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n --sv-color-primary: #164c8e;\n --sv-color-primary-alpha: #164c8e5b;\n --sv-color-secondary: #9fc5e9;\n --sv-color-tertiary: #e9f8ff;\n --sv-color-quaternary: #164c8e5b;\n\n --sv-color-contrast-positive: #121212;\n --sv-color-contrast-negative: #ffffff;\n\n --sv-color-accent: #a2a2a2;\n --sv-color-accent-2: #6b7271;\n --sv-color-accent-stroke: #e5e6e6;\n\n --sv-color-error: #ff434e;\n --sv-color-success: #1da031;\n --sv-color-warning: #daa000;\n --sv-color-info: #29c8f0;\n\n /* Semantic aliases */\n --sv-color-background: var(--sv-color-contrast-negative);\n --sv-color-text: var(--sv-color-contrast-positive);\n --sv-color-text-secondary: var(--sv-color-accent-2);\n --sv-color-text-muted: var(--sv-color-accent);\n --sv-color-border: var(--sv-color-accent-stroke);\n\n /* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n TYPOGRAPHY TOKENS - Mobile (Default)\n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n --sv-font-family: 'Urbanist', system-ui, -apple-system, BlinkMacSystemFont, sans-serif;\n --sv-font-family-display: 'SF Pro Display', 'Urbanist', system-ui, sans-serif;\n\n --sv-font-size-xxs: 10px;\n --sv-font-size-xs: 12px;\n --sv-font-size-sm: 13px;\n --sv-font-size-md: 14px;\n --sv-font-size-lg: 16px;\n --sv-font-size-xl: 20px;\n\n --sv-font-weight-regular: 400;\n --sv-font-weight-medium: 500;\n --sv-font-weight-semibold: 600;\n --sv-font-weight-bold: 700;\n\n --sv-line-height-tight: 1.2;\n --sv-line-height-normal: 1.4;\n --sv-line-height-relaxed: 1.6;\n\n /* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n SPACING TOKENS\n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n --sv-spacing-xxs: 2px;\n --sv-spacing-xs: 4px;\n --sv-spacing-sm: 8px;\n --sv-spacing-md: 12px;\n --sv-spacing-lg: 16px;\n --sv-spacing-xl: 24px;\n --sv-spacing-xxl: 32px;\n\n /* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n BORDER RADIUS\n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n --sv-radius-sm: 4px;\n --sv-radius-md: 8px;\n --sv-radius-lg: 12px;\n --sv-radius-xl: 16px;\n --sv-radius-full: 9999px;\n\n /* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n TRANSITIONS\n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n --sv-transition-fast: 150ms ease;\n --sv-transition-normal: 250ms ease;\n --sv-transition-slow: 350ms ease;\n\n /* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Z-INDEX LAYERS\n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n --sv-z-base: 1;\n --sv-z-video: 1;\n --sv-z-overlay: 10;\n --sv-z-controls: 20;\n --sv-z-modal: 100;\n --sv-z-toast: 1000;\n\n /* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n SHADOWS\n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n --sv-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);\n --sv-shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);\n --sv-shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.15);\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n CSS VARIABLES - Dark Mode\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n/* System preference */\n@media (prefers-color-scheme: dark) {\n :root:not([data-theme=\"light\"]) {\n --sv-color-primary: #a6cec7;\n --sv-color-primary-alpha: #164c8e5b;\n --sv-color-secondary: #143a0c;\n --sv-color-tertiary: #252825;\n --sv-color-quaternary: #164c8e5b;\n\n --sv-color-contrast-positive: #ffffff;\n --sv-color-contrast-negative: #121212;\n\n --sv-color-accent: #6b7271;\n --sv-color-accent-2: #d2dddb;\n --sv-color-accent-stroke: #373737;\n\n --sv-color-error: #b62a32;\n --sv-color-success: #20a634;\n --sv-color-warning: #c29823;\n --sv-color-info: #1fa0c0;\n\n /* Semantic aliases update automatically */\n --sv-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.2);\n --sv-shadow-md: 0 4px 6px rgba(0, 0, 0, 0.3);\n --sv-shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.4);\n }\n}\n\n/* Explicit dark mode (override) */\n[data-theme=\"dark\"],\n.dark {\n --sv-color-primary: #a6cec7;\n --sv-color-primary-alpha: #164c8e5b;\n --sv-color-secondary: #143a0c;\n --sv-color-tertiary: #252825;\n --sv-color-quaternary: #164c8e5b;\n\n --sv-color-contrast-positive: #ffffff;\n --sv-color-contrast-negative: #121212;\n\n --sv-color-accent: #6b7271;\n --sv-color-accent-2: #d2dddb;\n --sv-color-accent-stroke: #373737;\n\n --sv-color-error: #b62a32;\n --sv-color-success: #20a634;\n --sv-color-warning: #c29823;\n --sv-color-info: #1fa0c0;\n\n --sv-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.2);\n --sv-shadow-md: 0 4px 6px rgba(0, 0, 0, 0.3);\n --sv-shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.4);\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n TABLET BREAKPOINT - Typography scaling\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n@media (min-width: 768px) {\n :root {\n --sv-font-size-xxs: 11px;\n --sv-font-size-xs: 13px;\n --sv-font-size-sm: 14px;\n --sv-font-size-md: 16px;\n --sv-font-size-lg: 18px;\n --sv-font-size-xl: 24px;\n }\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n BASE STYLES - Inside @layer sv for easy host app overrides\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n@layer sv {\n\n.sv-root {\n font-family: var(--sv-font-family);\n font-size: var(--sv-font-size-md);\n font-weight: var(--sv-font-weight-regular);\n line-height: var(--sv-line-height-normal);\n color: var(--sv-color-text);\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n FEED CONTAINER\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-feed {\n position: relative;\n width: 100%;\n height: 100%;\n overflow: hidden;\n background: var(--sv-color-contrast-negative);\n touch-action: pan-y;\n -webkit-overflow-scrolling: touch;\n}\n\n.sv-feed::-webkit-scrollbar {\n display: none;\n}\n\n.sv-feed {\n -ms-overflow-style: none;\n scrollbar-width: none;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n VIDEO SLOT\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-slot {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--sv-color-contrast-negative);\n will-change: transform;\n}\n\n.sv-slot--active {\n z-index: var(--sv-z-video);\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n VIDEO PLAYER\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-player {\n position: relative;\n width: 100%;\n height: 100%;\n background: var(--sv-color-contrast-negative);\n}\n\n.sv-player__video {\n width: 100%;\n height: 100%;\n object-fit: cover;\n background: var(--sv-color-contrast-negative);\n}\n\n.sv-player__poster {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n object-fit: cover;\n z-index: 1;\n transition: opacity var(--sv-transition-normal);\n}\n\n.sv-player__poster--hidden {\n opacity: 0;\n pointer-events: none;\n}\n\n.sv-player__overlay {\n position: absolute;\n inset: 0;\n background: linear-gradient(\n to bottom,\n transparent 0%,\n transparent 50%,\n rgba(0, 0, 0, 0.3) 100%\n );\n pointer-events: none;\n z-index: var(--sv-z-overlay);\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n PROGRESS BAR\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-progress {\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 3px;\n background: rgba(255, 255, 255, 0.2);\n z-index: var(--sv-z-controls);\n}\n\n.sv-progress__bar {\n height: 100%;\n background: var(--sv-color-contrast-positive);\n transition: width 100ms linear;\n will-change: width;\n}\n\n.sv-progress__bar--buffered {\n position: absolute;\n top: 0;\n left: 0;\n height: 100%;\n background: rgba(255, 255, 255, 0.3);\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n INTERACTION BAR (Right side actions)\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-actions {\n position: absolute;\n right: var(--sv-spacing-md);\n bottom: 120px;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: var(--sv-spacing-xl);\n z-index: var(--sv-z-controls);\n}\n\n.sv-action-btn {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: var(--sv-spacing-xs);\n background: none;\n border: none;\n padding: 0;\n cursor: pointer;\n color: var(--sv-color-contrast-positive);\n transition: transform var(--sv-transition-fast);\n -webkit-tap-highlight-color: transparent;\n}\n\n.sv-action-btn:active {\n transform: scale(0.9);\n}\n\n.sv-action-btn__icon {\n width: 44px;\n height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: rgba(0, 0, 0, 0.3);\n border-radius: var(--sv-radius-full);\n backdrop-filter: blur(4px);\n -webkit-backdrop-filter: blur(4px);\n}\n\n.sv-action-btn__icon svg {\n width: 24px;\n height: 24px;\n fill: currentColor;\n}\n\n.sv-action-btn__count {\n font-size: var(--sv-font-size-xs);\n font-weight: var(--sv-font-weight-semibold);\n color: var(--sv-color-contrast-positive);\n}\n\n/* Like button states */\n.sv-action-btn--liked .sv-action-btn__icon {\n color: var(--sv-color-error);\n}\n\n.sv-action-btn--liked .sv-action-btn__icon svg {\n animation: sv-like-pop 0.3s ease;\n}\n\n@keyframes sv-like-pop {\n 0% { transform: scale(1); }\n 50% { transform: scale(1.3); }\n 100% { transform: scale(1); }\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n AUTHOR INFO (Bottom left)\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-author {\n position: absolute;\n left: var(--sv-spacing-md);\n bottom: 80px;\n display: flex;\n flex-direction: column;\n gap: var(--sv-spacing-md);\n max-width: calc(100% - 80px);\n z-index: var(--sv-z-controls);\n}\n\n.sv-author__row {\n display: flex;\n align-items: center;\n gap: var(--sv-spacing-md);\n}\n\n.sv-author__avatar {\n width: 48px;\n height: 48px;\n border-radius: var(--sv-radius-full);\n border: 2px solid var(--sv-color-contrast-positive);\n object-fit: cover;\n flex-shrink: 0;\n}\n\n.sv-author__info {\n display: flex;\n flex-direction: column;\n gap: var(--sv-spacing-xxs);\n min-width: 0;\n}\n\n.sv-author__name {\n font-size: var(--sv-font-size-lg);\n font-weight: var(--sv-font-weight-semibold);\n color: var(--sv-color-contrast-positive);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.sv-author__handle {\n font-size: var(--sv-font-size-sm);\n color: rgba(255, 255, 255, 0.8);\n}\n\n.sv-author__description {\n font-size: var(--sv-font-size-sm);\n color: var(--sv-color-contrast-positive);\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n line-height: var(--sv-line-height-relaxed);\n}\n\n/* Follow button */\n.sv-follow-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: var(--sv-spacing-xs) var(--sv-spacing-md);\n font-size: var(--sv-font-size-sm);\n font-weight: var(--sv-font-weight-semibold);\n font-family: var(--sv-font-family);\n color: var(--sv-color-contrast-negative);\n background: var(--sv-color-primary);\n border: none;\n border-radius: var(--sv-radius-sm);\n cursor: pointer;\n transition: all var(--sv-transition-fast);\n -webkit-tap-highlight-color: transparent;\n}\n\n.sv-follow-btn:active {\n transform: scale(0.95);\n}\n\n.sv-follow-btn--following {\n background: transparent;\n color: var(--sv-color-contrast-positive);\n border: 1px solid var(--sv-color-contrast-positive);\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n SPINNER / LOADING\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-spinner {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n}\n\n.sv-spinner__circle {\n width: 32px;\n height: 32px;\n border: 3px solid rgba(255, 255, 255, 0.2);\n border-top-color: var(--sv-color-contrast-positive);\n border-radius: var(--sv-radius-full);\n animation: sv-spin 0.8s linear infinite;\n}\n\n.sv-spinner--sm .sv-spinner__circle {\n width: 20px;\n height: 20px;\n border-width: 2px;\n}\n\n.sv-spinner--lg .sv-spinner__circle {\n width: 48px;\n height: 48px;\n border-width: 4px;\n}\n\n@keyframes sv-spin {\n to { transform: rotate(360deg); }\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n MUSIC INFO (Bottom - optional)\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-music {\n position: absolute;\n left: var(--sv-spacing-md);\n bottom: var(--sv-spacing-lg);\n display: flex;\n align-items: center;\n gap: var(--sv-spacing-sm);\n max-width: calc(100% - 80px);\n z-index: var(--sv-z-controls);\n}\n\n.sv-music__icon {\n width: 20px;\n height: 20px;\n flex-shrink: 0;\n}\n\n.sv-music__text {\n font-size: var(--sv-font-size-sm);\n color: var(--sv-color-contrast-positive);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.sv-music__marquee {\n animation: sv-marquee 10s linear infinite;\n}\n\n@keyframes sv-marquee {\n 0% { transform: translateX(0); }\n 100% { transform: translateX(-50%); }\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n UTILITIES\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.sv-sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n}\n\n.sv-tap-highlight-none {\n -webkit-tap-highlight-color: transparent;\n}\n\n/* Prevent text selection during gestures */\n.sv-no-select {\n -webkit-user-select: none;\n user-select: none;\n}\n\n/* Hardware acceleration hint */\n.sv-gpu {\n transform: translateZ(0);\n will-change: transform;\n}\n\n} /* End @layer sv */\n";
|
|
90
118
|
|
|
91
119
|
/**
|
|
92
120
|
* Styles Module
|
|
@@ -147,6 +175,7 @@ declare const Components: {
|
|
|
147
175
|
VideoFeedHeadless: () => null;
|
|
148
176
|
VideoSlotHeadless: () => null;
|
|
149
177
|
VideoPlayerHeadless: () => null;
|
|
178
|
+
CommentSheetHeadless: () => null;
|
|
150
179
|
ErrorBoundary: () => null;
|
|
151
180
|
Skeleton: () => null;
|
|
152
181
|
};
|
|
@@ -354,8 +383,12 @@ interface UseDoubleTapConfig {
|
|
|
354
383
|
onSingleTap?: () => void;
|
|
355
384
|
/** Callback for double tap with position */
|
|
356
385
|
onDoubleTap?: (position: TapPosition) => void;
|
|
386
|
+
/** Callback for long press (hold > longPressDelay without moving) */
|
|
387
|
+
onLongPress?: (position: TapPosition) => void;
|
|
357
388
|
/** Delay in ms to detect double tap (default: 300) */
|
|
358
389
|
doubleTapDelay?: number;
|
|
390
|
+
/** Delay in ms to detect long press (default: 500) */
|
|
391
|
+
longPressDelay?: number;
|
|
359
392
|
/** Whether the hook is disabled */
|
|
360
393
|
disabled?: boolean;
|
|
361
394
|
/**
|
|
@@ -369,6 +402,7 @@ interface UseDoubleTapReturn {
|
|
|
369
402
|
/** Event handlers to spread onto the target element */
|
|
370
403
|
handlers: {
|
|
371
404
|
onPointerDown: (e: React.PointerEvent) => void;
|
|
405
|
+
onPointerMove: (e: React.PointerEvent) => void;
|
|
372
406
|
onPointerUp: (e: React.PointerEvent) => void;
|
|
373
407
|
onClick: (e: React.MouseEvent) => void;
|
|
374
408
|
};
|
|
@@ -395,7 +429,7 @@ interface UseDoubleTapReturn {
|
|
|
395
429
|
* Returns tap position as percentage (0-100) relative to container.
|
|
396
430
|
* Falls back to center (50, 50) if container ref is null.
|
|
397
431
|
*/
|
|
398
|
-
declare function useDoubleTap({ containerRef, onSingleTap, onDoubleTap, doubleTapDelay, disabled, movementThreshold, }: UseDoubleTapConfig): UseDoubleTapReturn;
|
|
432
|
+
declare function useDoubleTap({ containerRef, onSingleTap, onDoubleTap, onLongPress, doubleTapDelay, longPressDelay, disabled, movementThreshold, }: UseDoubleTapConfig): UseDoubleTapReturn;
|
|
399
433
|
|
|
400
434
|
/**
|
|
401
435
|
* CustomLayout - Fully Composable Layout
|
|
@@ -563,6 +597,12 @@ interface DefaultLayoutProps {
|
|
|
563
597
|
error?: Error | null;
|
|
564
598
|
/** Retry callback */
|
|
565
599
|
onRetry?: () => void;
|
|
600
|
+
/** Network error text (default: "No internet connection") */
|
|
601
|
+
networkErrorText?: string;
|
|
602
|
+
/** Generic error text (default: "Video failed to load") */
|
|
603
|
+
genericErrorText?: string;
|
|
604
|
+
/** Retry button text (default: "Tap to retry") */
|
|
605
|
+
retryText?: string;
|
|
566
606
|
/** Additional class name */
|
|
567
607
|
className?: string;
|
|
568
608
|
/** Test ID */
|
|
@@ -633,6 +673,14 @@ interface MinimalLayoutProps {
|
|
|
633
673
|
error?: Error | null;
|
|
634
674
|
/** Retry callback */
|
|
635
675
|
onRetry?: () => void;
|
|
676
|
+
/** Error fallback text (default: "Video failed to load") */
|
|
677
|
+
errorFallbackText?: string;
|
|
678
|
+
/** Retry button text (default: "Retry") */
|
|
679
|
+
retryText?: string;
|
|
680
|
+
/** Play button aria-label (default: "Play") */
|
|
681
|
+
playAriaLabel?: string;
|
|
682
|
+
/** Pause button aria-label (default: "Pause") */
|
|
683
|
+
pauseAriaLabel?: string;
|
|
636
684
|
/** Called when play button is clicked */
|
|
637
685
|
onPlayClick?: () => void;
|
|
638
686
|
/** Additional class name */
|
|
@@ -640,7 +688,7 @@ interface MinimalLayoutProps {
|
|
|
640
688
|
/** Test ID */
|
|
641
689
|
testId?: string;
|
|
642
690
|
}
|
|
643
|
-
declare function MinimalLayout({ video: _video, index: _index, playerState, playerControls, renderPlayer, renderPoster, renderProgressBar, renderError, playIcon, pauseIcon, showPoster, showPlayButton, showProgressBar, autoHidePlayButton, hideDelay, error, onRetry, onPlayClick, className, testId, }: MinimalLayoutProps): ReactElement;
|
|
691
|
+
declare function MinimalLayout({ video: _video, index: _index, playerState, playerControls, renderPlayer, renderPoster, renderProgressBar, renderError, playIcon, pauseIcon, showPoster, showPlayButton, showProgressBar, autoHidePlayButton, hideDelay, error, onRetry, onPlayClick, className, testId, errorFallbackText, retryText, playAriaLabel, pauseAriaLabel, }: MinimalLayoutProps): ReactElement;
|
|
644
692
|
declare namespace MinimalLayout {
|
|
645
693
|
var displayName: string;
|
|
646
694
|
}
|
|
@@ -674,9 +722,36 @@ declare const Layouts: {
|
|
|
674
722
|
*
|
|
675
723
|
* Features:
|
|
676
724
|
* - Deduplication: Each component's CSS is injected only once
|
|
725
|
+
* - Persistent by default: CSS stays in DOM after injection (no cleanup overhead)
|
|
677
726
|
* - SSR-safe: Checks for document existence
|
|
678
|
-
* - Cleanup-ready: Returns remove function
|
|
679
727
|
* - Hydration-aware: Checks for existing styles from SSR
|
|
728
|
+
* - **CSS Layers**: All component CSS is wrapped in `@layer sv` for easy host overrides
|
|
729
|
+
*
|
|
730
|
+
* ## CSS Layers for Host App Overrides
|
|
731
|
+
*
|
|
732
|
+
* All SDK component styles are injected inside `@layer sv`. This means:
|
|
733
|
+
* - Host app CSS without @layer has HIGHER priority
|
|
734
|
+
* - No need for `!important` to override SDK styles
|
|
735
|
+
*
|
|
736
|
+
* @example
|
|
737
|
+
* ```css
|
|
738
|
+
* // Host app can easily override without !important
|
|
739
|
+
* .my-custom-button {
|
|
740
|
+
* background: blue; // Overrides SDK styles easily
|
|
741
|
+
* }
|
|
742
|
+
* ```
|
|
743
|
+
*
|
|
744
|
+
* ## Why No Auto-Cleanup?
|
|
745
|
+
*
|
|
746
|
+
* In a video feed app, components like VideoPlayer, ActionBar, etc. are
|
|
747
|
+
* continuously mounted/unmounted as user scrolls. Removing and re-injecting
|
|
748
|
+
* CSS would be wasteful since:
|
|
749
|
+
* 1. These components will be needed again immediately
|
|
750
|
+
* 2. CSS injection triggers style recalculation (performance cost)
|
|
751
|
+
* 3. The CSS payload is small (~5-10KB total for all components)
|
|
752
|
+
*
|
|
753
|
+
* CSS is only removed via explicit `removeComponentCSS()` or `removeAllComponentCSS()`
|
|
754
|
+
* calls, typically only needed for testing cleanup.
|
|
680
755
|
*
|
|
681
756
|
* @example
|
|
682
757
|
* ```tsx
|
|
@@ -694,17 +769,38 @@ declare const Layouts: {
|
|
|
694
769
|
* }
|
|
695
770
|
* ```
|
|
696
771
|
*/
|
|
772
|
+
/**
|
|
773
|
+
* Options for CSS injection
|
|
774
|
+
*/
|
|
775
|
+
interface InjectCSSOptions {
|
|
776
|
+
/**
|
|
777
|
+
* Whether to wrap CSS in @layer sv.
|
|
778
|
+
*
|
|
779
|
+
* - `true` (default): CSS wrapped in @layer sv, host app can override easily
|
|
780
|
+
* - `false`: CSS injected without layer, useful for critical components
|
|
781
|
+
* that need to resist global resets like `* { margin: 0; padding: 0; }`
|
|
782
|
+
*
|
|
783
|
+
* @default true
|
|
784
|
+
*/
|
|
785
|
+
layered?: boolean;
|
|
786
|
+
}
|
|
697
787
|
/**
|
|
698
788
|
* Inject CSS for a specific component.
|
|
699
789
|
*
|
|
790
|
+
* CSS is injected once and persists in the DOM. This is optimal for
|
|
791
|
+
* video feed apps where components are frequently mounted/unmounted.
|
|
792
|
+
*
|
|
700
793
|
* @param componentId - Unique identifier for the component (e.g., 'video-player')
|
|
701
794
|
* @param css - CSS string to inject
|
|
702
|
-
* @
|
|
795
|
+
* @param options - Injection options
|
|
796
|
+
* @returns Empty cleanup function (CSS persists intentionally)
|
|
703
797
|
*/
|
|
704
|
-
declare function injectComponentCSS(componentId: string, css: string): () => void;
|
|
798
|
+
declare function injectComponentCSS(componentId: string, css: string, options?: InjectCSSOptions): () => void;
|
|
705
799
|
/**
|
|
706
800
|
* Remove CSS for a specific component.
|
|
707
|
-
*
|
|
801
|
+
* Mainly used for testing cleanup.
|
|
802
|
+
*
|
|
803
|
+
* Note: In normal app usage, CSS persists and this is rarely needed.
|
|
708
804
|
*
|
|
709
805
|
* @param componentId - Component identifier to remove
|
|
710
806
|
*/
|
|
@@ -717,70 +813,6 @@ declare function removeComponentCSS(componentId: string): void;
|
|
|
717
813
|
*/
|
|
718
814
|
declare function isComponentCSSInjected(componentId: string): boolean;
|
|
719
815
|
|
|
720
|
-
/**
|
|
721
|
-
* Lazy Loading Wrapper for @use-gesture/react
|
|
722
|
-
*
|
|
723
|
-
* This module provides lazy loading for the gesture library (~8KB gzip).
|
|
724
|
-
* Only VideoFeed component needs gestures, so we don't want to bundle it
|
|
725
|
-
* for components that don't use it.
|
|
726
|
-
*
|
|
727
|
-
* @example
|
|
728
|
-
* ```tsx
|
|
729
|
-
* // In VideoFeed component
|
|
730
|
-
* import { useEffect, useState } from 'react';
|
|
731
|
-
* import { loadGesture, type GestureModule } from '../../utils/lazyGesture';
|
|
732
|
-
*
|
|
733
|
-
* export function VideoFeed() {
|
|
734
|
-
* const [gesture, setGesture] = useState<GestureModule | null>(null);
|
|
735
|
-
*
|
|
736
|
-
* useEffect(() => {
|
|
737
|
-
* loadGesture().then(setGesture);
|
|
738
|
-
* }, []);
|
|
739
|
-
*
|
|
740
|
-
* if (!gesture) {
|
|
741
|
-
* return <div>Loading...</div>;
|
|
742
|
-
* }
|
|
743
|
-
*
|
|
744
|
-
* const { useDrag } = gesture;
|
|
745
|
-
* // ... use gesture hooks
|
|
746
|
-
* }
|
|
747
|
-
* ```
|
|
748
|
-
*/
|
|
749
|
-
/** Type for the gesture module */
|
|
750
|
-
type GestureModule = typeof _use_gesture_react;
|
|
751
|
-
/**
|
|
752
|
-
* Lazy load @use-gesture/react library.
|
|
753
|
-
*
|
|
754
|
-
* Benefits:
|
|
755
|
-
* - Only loaded when actually needed
|
|
756
|
-
* - Cached after first load
|
|
757
|
-
* - Single pending promise prevents duplicate loads
|
|
758
|
-
*
|
|
759
|
-
* @returns Promise resolving to the gesture module
|
|
760
|
-
*/
|
|
761
|
-
declare function loadGesture(): Promise<GestureModule>;
|
|
762
|
-
/**
|
|
763
|
-
* Check if gesture library is loaded.
|
|
764
|
-
* Useful for conditional rendering.
|
|
765
|
-
*
|
|
766
|
-
* @returns true if module is loaded and cached
|
|
767
|
-
*/
|
|
768
|
-
declare function isGestureLoaded(): boolean;
|
|
769
|
-
/**
|
|
770
|
-
* Preload gesture library without awaiting.
|
|
771
|
-
* Call this early if you know gestures will be needed soon.
|
|
772
|
-
*
|
|
773
|
-
* @example
|
|
774
|
-
* ```tsx
|
|
775
|
-
* // In app initialization
|
|
776
|
-
* import { preloadGesture } from '@xhub-short/ui/utils/lazyGesture';
|
|
777
|
-
*
|
|
778
|
-
* // Start loading early
|
|
779
|
-
* preloadGesture();
|
|
780
|
-
* ```
|
|
781
|
-
*/
|
|
782
|
-
declare function preloadGesture(): void;
|
|
783
|
-
|
|
784
816
|
/**
|
|
785
817
|
* Format Count Utility
|
|
786
818
|
*
|
|
@@ -835,24 +867,4 @@ declare function formatCountWithSeparators(count: number, locale?: string): stri
|
|
|
835
867
|
*/
|
|
836
868
|
declare function parseFormattedCount(formatted: string): number;
|
|
837
869
|
|
|
838
|
-
|
|
839
|
-
* UI Utilities
|
|
840
|
-
*
|
|
841
|
-
* Internal utilities for the UI package.
|
|
842
|
-
* Most are not exported publicly - they're used internally by components.
|
|
843
|
-
*/
|
|
844
|
-
|
|
845
|
-
/**
|
|
846
|
-
* Merge class names with SDK prefix awareness.
|
|
847
|
-
* Wrapper around clsx for consistent className handling.
|
|
848
|
-
*
|
|
849
|
-
* @example
|
|
850
|
-
* ```tsx
|
|
851
|
-
* import { cn } from '../../utils';
|
|
852
|
-
*
|
|
853
|
-
* <div className={cn('sv-video-player', isActive && 'sv-video-player--active', className)} />
|
|
854
|
-
* ```
|
|
855
|
-
*/
|
|
856
|
-
declare function cn(...inputs: (string | undefined | null | false | Record<string, boolean>)[]): string;
|
|
857
|
-
|
|
858
|
-
export { CSS_CONTENT, CSS_VAR_PREFIX, type CacheStats, Components, CustomLayout, type CustomLayoutProps, DefaultLayout, type DefaultLayoutProps, type FirstFrameCacheConfig, type FormatCountOptions, type GestureModule, Layouts, MinimalLayout, type MinimalLayoutProps, type TapPosition, type Theme, type UseDoubleTapConfig, type UseDoubleTapReturn, areStylesInjected, cn, createFirstFrameCache, firstFrameCache, formatCount, formatCountWithSeparators, getTheme, injectComponentCSS, injectSDKStyles, isComponentCSSInjected, isDarkMode, isGestureLoaded, loadGesture, parseFormattedCount, preloadGesture, removeComponentCSS, removeStyles, setTheme, useCustomLayout, useDoubleTap, useStyles };
|
|
870
|
+
export { CSS_CONTENT, CSS_VAR_PREFIX, type CacheStats, Components, CustomLayout, type CustomLayoutProps, DefaultLayout, type DefaultLayoutProps, type FirstFrameCacheConfig, type FormatCountOptions, Layouts, MinimalLayout, type MinimalLayoutProps, type TapPosition, type Theme, type UseDoubleTapConfig, type UseDoubleTapReturn, areStylesInjected, createFirstFrameCache, firstFrameCache, formatCount, formatCountWithSeparators, getTheme, injectComponentCSS, injectSDKStyles, isComponentCSSInjected, isDarkMode, parseFormattedCount, removeComponentCSS, removeStyles, setTheme, useCustomLayout, useDoubleTap, useStyles };
|