Mobile-audit batch 1. All fixes reuse cinny's own responsive primitives and are mobile-gated so desktop is unchanged. - Message tables: wrap <table> in an overflow-x container so a wide table scrolls instead of overflowing the message column / page body. - Composer toolbar: let the before|editable|after row and the toolbar wrap on phones (@media <=750px) instead of squeezing the editable to zero and pushing Send off-screen. - In-call control bar: collapse to the compact/stacked layout on a mobile viewport (ScreenSize.Mobile) too, not just when the bar's own container is <500px — fixes the 500-750px band where the control row overflowed. - URL-preview card: base width toRem(400) -> min(25rem, 92vw) so a single card fits a narrow phone (still exactly 400px on desktop). - Explore card grid: drop to one column at <=750px (was a fixed 3-col grid). Two review passes: desktop behavior provably unchanged (all gated by @media / ScreenSize.Mobile; the table wrapper only contains previously-overflowing tables). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
914 lines
20 KiB
TypeScript
914 lines
20 KiB
TypeScript
import { keyframes, style } from '@vanilla-extract/css';
|
||
import { DefaultReset, color, config, toRem } from 'folds';
|
||
|
||
export const UrlPreview = style([
|
||
DefaultReset,
|
||
{
|
||
// 25rem (=400px) on desktop, but shrink to fit narrow phones so a single
|
||
// card doesn't exceed the viewport (mirrors UrlPreviewWide's min()).
|
||
width: 'min(25rem, 92vw)',
|
||
minHeight: toRem(102),
|
||
backgroundColor: color.SurfaceVariant.Container,
|
||
color: color.SurfaceVariant.OnContainer,
|
||
border: `${config.borderWidth.B300} solid ${color.SurfaceVariant.ContainerLine}`,
|
||
borderRadius: config.radii.R300,
|
||
overflow: 'hidden',
|
||
},
|
||
]);
|
||
|
||
// Wider, responsive card for interactive embeds (video players, tweets, posts)
|
||
// so the player chrome / tweet content isn't cramped or clipped. Defined after
|
||
// UrlPreview so its width wins the cascade.
|
||
export const UrlPreviewWide = style({
|
||
width: 'min(38rem, 94vw)',
|
||
});
|
||
|
||
export const UrlPreviewImg = style([
|
||
DefaultReset,
|
||
{
|
||
width: toRem(100),
|
||
height: toRem(100),
|
||
objectFit: 'cover',
|
||
objectPosition: 'center',
|
||
flexShrink: 0,
|
||
overflow: 'hidden',
|
||
cursor: 'pointer',
|
||
|
||
':hover': {
|
||
filter: 'brightness(0.8)',
|
||
},
|
||
},
|
||
]);
|
||
|
||
export const UrlPreviewContent = style([
|
||
DefaultReset,
|
||
{
|
||
padding: config.space.S200,
|
||
},
|
||
]);
|
||
|
||
export const UrlPreviewDescription = style([
|
||
DefaultReset,
|
||
{
|
||
display: '-webkit-box',
|
||
WebkitLineClamp: 2,
|
||
WebkitBoxOrient: 'vertical',
|
||
overflow: 'hidden',
|
||
},
|
||
]);
|
||
|
||
// YouTube card styles
|
||
export const YouTubeThumbnailWrapper = style([
|
||
DefaultReset,
|
||
{
|
||
position: 'relative',
|
||
flexShrink: 0,
|
||
width: toRem(160),
|
||
height: toRem(90),
|
||
overflow: 'hidden',
|
||
cursor: 'pointer',
|
||
backgroundColor: color.Surface.Container,
|
||
|
||
':hover': {
|
||
filter: 'brightness(0.85)',
|
||
},
|
||
},
|
||
]);
|
||
|
||
export const YouTubeThumbnailImg = style([
|
||
DefaultReset,
|
||
{
|
||
width: '100%',
|
||
height: '100%',
|
||
objectFit: 'cover',
|
||
objectPosition: 'center',
|
||
display: 'block',
|
||
},
|
||
]);
|
||
|
||
export const YouTubePlayOverlay = style([
|
||
DefaultReset,
|
||
{
|
||
position: 'absolute',
|
||
inset: 0,
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
pointerEvents: 'none',
|
||
},
|
||
]);
|
||
|
||
export const YouTubePlayButton = style([
|
||
DefaultReset,
|
||
{
|
||
width: toRem(44),
|
||
height: toRem(44),
|
||
borderRadius: '50%',
|
||
backgroundColor: 'rgba(0, 0, 0, 0.75)',
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
color: '#ffffff',
|
||
},
|
||
]);
|
||
|
||
// GitHub card styles
|
||
export const GitHubIconWrapper = style([
|
||
DefaultReset,
|
||
{
|
||
flexShrink: 0,
|
||
width: toRem(72),
|
||
minHeight: toRem(72),
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
color: color.SurfaceVariant.OnContainer,
|
||
opacity: 0.8,
|
||
backgroundColor: color.Surface.ContainerHover,
|
||
},
|
||
]);
|
||
|
||
// Generic card favicon styles
|
||
export const GenericFaviconWrapper = style([
|
||
DefaultReset,
|
||
{
|
||
display: 'inline-flex',
|
||
alignItems: 'center',
|
||
gap: config.space.S100,
|
||
verticalAlign: 'middle',
|
||
},
|
||
]);
|
||
|
||
export const GenericFaviconImg = style([
|
||
DefaultReset,
|
||
{
|
||
width: toRem(16),
|
||
height: toRem(16),
|
||
flexShrink: 0,
|
||
},
|
||
]);
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Shared media-card thumbnail (VideoCard, Steam, etc.)
|
||
// ---------------------------------------------------------------------------
|
||
|
||
export const MediaThumbnailWrapper = style([
|
||
DefaultReset,
|
||
{
|
||
position: 'relative',
|
||
flexShrink: 0,
|
||
width: toRem(160),
|
||
height: toRem(90),
|
||
overflow: 'hidden',
|
||
cursor: 'pointer',
|
||
backgroundColor: color.Surface.Container,
|
||
|
||
':hover': {
|
||
filter: 'brightness(0.85)',
|
||
},
|
||
},
|
||
]);
|
||
|
||
export const MediaThumbnailImg = style([
|
||
DefaultReset,
|
||
{
|
||
width: '100%',
|
||
height: '100%',
|
||
objectFit: 'cover',
|
||
objectPosition: 'center',
|
||
display: 'block',
|
||
},
|
||
]);
|
||
|
||
export const MediaPlayOverlay = style([
|
||
DefaultReset,
|
||
{
|
||
position: 'absolute',
|
||
inset: 0,
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
pointerEvents: 'none',
|
||
},
|
||
]);
|
||
|
||
export const MediaPlayButton = style([
|
||
DefaultReset,
|
||
{
|
||
width: toRem(44),
|
||
height: toRem(44),
|
||
borderRadius: '50%',
|
||
backgroundColor: 'rgba(0, 0, 0, 0.75)',
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
color: '#ffffff',
|
||
},
|
||
]);
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Inline video embed (YouTube / Vimeo) — media-forward click-to-play facade
|
||
// ---------------------------------------------------------------------------
|
||
|
||
export const EmbedMediaLandscape = style([
|
||
DefaultReset,
|
||
{
|
||
position: 'relative',
|
||
width: '100%',
|
||
// 16:9 via the padding-top hack (56.25%), NOT `aspect-ratio`. An absolutely-
|
||
// positioned *replaced* element (the player <iframe>) collapses to its ~200px
|
||
// intrinsic size inside an `aspect-ratio` box; padding derives a definite height
|
||
// from the definite width so the iframe (inset:0) reliably fills it.
|
||
height: 0,
|
||
paddingTop: '56.25%',
|
||
overflow: 'hidden',
|
||
backgroundColor: color.Surface.Container,
|
||
selectors: {
|
||
'&:fullscreen': { width: '100vw', height: '100vh', paddingTop: 0 },
|
||
},
|
||
},
|
||
]);
|
||
|
||
export const EmbedMediaPortrait = style([
|
||
DefaultReset,
|
||
{
|
||
position: 'relative',
|
||
width: toRem(300),
|
||
maxWidth: '100%',
|
||
// 9:16 via the padding-top hack (177.78%) — see EmbedMediaLandscape.
|
||
height: 0,
|
||
paddingTop: '177.78%',
|
||
margin: '0 auto',
|
||
overflow: 'hidden',
|
||
backgroundColor: color.Surface.Container,
|
||
selectors: {
|
||
'&:fullscreen': { width: '100vw', height: '100vh', paddingTop: 0, margin: 0 },
|
||
},
|
||
},
|
||
]);
|
||
|
||
// Fills the aspect box; used for both the <button> facade and the <a> fallback.
|
||
export const EmbedFacade = style([
|
||
DefaultReset,
|
||
{
|
||
position: 'absolute',
|
||
inset: 0,
|
||
width: '100%',
|
||
height: '100%',
|
||
display: 'block',
|
||
padding: 0,
|
||
border: 'none',
|
||
background: 'none',
|
||
cursor: 'pointer',
|
||
|
||
':hover': {
|
||
filter: 'brightness(0.85)',
|
||
},
|
||
selectors: {
|
||
'&:focus-visible': {
|
||
outline: `2px solid ${color.Primary.Main}`,
|
||
outlineOffset: '-2px',
|
||
},
|
||
},
|
||
},
|
||
]);
|
||
|
||
export const EmbedIframe = style([
|
||
DefaultReset,
|
||
{
|
||
position: 'absolute',
|
||
inset: 0,
|
||
width: '100%',
|
||
height: '100%',
|
||
border: 0,
|
||
display: 'block',
|
||
},
|
||
]);
|
||
|
||
// Variable-height iframe that sizes itself (X/Twitter, Instagram, Reddit posts —
|
||
// height set inline). Capped ~550px (X/IG native max) + centered in the wide card.
|
||
export const EmbedIframeStatic = style([
|
||
DefaultReset,
|
||
{
|
||
width: '100%',
|
||
maxWidth: toRem(550),
|
||
margin: '0 auto',
|
||
border: 0,
|
||
display: 'block',
|
||
},
|
||
]);
|
||
|
||
export const EmbedPlaceholder = style([
|
||
DefaultReset,
|
||
{
|
||
position: 'absolute',
|
||
inset: 0,
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
backgroundColor: '#111111',
|
||
color: '#ffffff',
|
||
fontSize: toRem(28),
|
||
},
|
||
]);
|
||
|
||
// Audio embeds (Spotify / SoundCloud) — full-width, short fixed height (set inline).
|
||
export const EmbedMediaAudio = style([
|
||
DefaultReset,
|
||
{
|
||
position: 'relative',
|
||
width: '100%',
|
||
overflow: 'hidden',
|
||
backgroundColor: color.Surface.Container,
|
||
},
|
||
]);
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Shared square artwork thumbnail (Spotify, IMDb poster, Discord icon)
|
||
// ---------------------------------------------------------------------------
|
||
|
||
export const ArtworkThumbnail = style([
|
||
DefaultReset,
|
||
{
|
||
flexShrink: 0,
|
||
width: toRem(72),
|
||
height: toRem(72),
|
||
objectFit: 'cover',
|
||
objectPosition: 'center',
|
||
display: 'block',
|
||
},
|
||
]);
|
||
|
||
// IMDb portrait poster (60 × 90)
|
||
export const PosterThumbnail = style([
|
||
DefaultReset,
|
||
{
|
||
flexShrink: 0,
|
||
width: toRem(60),
|
||
height: toRem(90),
|
||
objectFit: 'cover',
|
||
objectPosition: 'center',
|
||
display: 'block',
|
||
},
|
||
]);
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Site-badge shared base
|
||
// ---------------------------------------------------------------------------
|
||
|
||
export const SiteBadge = style([
|
||
DefaultReset,
|
||
{
|
||
display: 'inline-flex',
|
||
alignItems: 'center',
|
||
gap: config.space.S100,
|
||
paddingLeft: config.space.S100,
|
||
paddingRight: config.space.S100,
|
||
paddingTop: '2px',
|
||
paddingBottom: '2px',
|
||
borderRadius: config.radii.R300,
|
||
fontSize: toRem(11),
|
||
fontWeight: 700,
|
||
lineHeight: '1.4',
|
||
letterSpacing: '0.03em',
|
||
flexShrink: 0,
|
||
},
|
||
]);
|
||
|
||
// Individual badge colour overrides (background / foreground)
|
||
export const BadgeVimeo = style({
|
||
backgroundColor: '#1ab7ea',
|
||
color: '#ffffff',
|
||
});
|
||
|
||
export const BadgeTwitter = style({
|
||
backgroundColor: '#000000',
|
||
color: '#ffffff',
|
||
});
|
||
|
||
export const BadgeReddit = style({
|
||
backgroundColor: '#ff4500',
|
||
color: '#ffffff',
|
||
});
|
||
|
||
export const BadgeSpotify = style({
|
||
backgroundColor: '#1db954',
|
||
color: '#ffffff',
|
||
});
|
||
|
||
export const BadgeTwitch = style({
|
||
backgroundColor: '#9146ff',
|
||
color: '#ffffff',
|
||
});
|
||
|
||
export const BadgeSteam = style({
|
||
backgroundColor: '#1b2838',
|
||
color: '#c7d5e0',
|
||
});
|
||
|
||
export const BadgeWikipedia = style({
|
||
backgroundColor: color.SurfaceVariant.ContainerLine,
|
||
color: color.SurfaceVariant.OnContainer,
|
||
});
|
||
|
||
export const BadgeDiscord = style({
|
||
backgroundColor: '#5865f2',
|
||
color: '#ffffff',
|
||
});
|
||
|
||
export const BadgeNpm = style({
|
||
backgroundColor: '#cb3837',
|
||
color: '#ffffff',
|
||
});
|
||
|
||
export const BadgeStackOverflow = style({
|
||
backgroundColor: '#f48024',
|
||
color: '#ffffff',
|
||
});
|
||
|
||
export const BadgeImdb = style({
|
||
backgroundColor: '#f5c518',
|
||
color: '#000000',
|
||
});
|
||
|
||
export const BadgeYouTubeShorts = style({
|
||
backgroundColor: '#FF0000',
|
||
color: '#ffffff',
|
||
});
|
||
|
||
export const BadgeTikTok = style({
|
||
backgroundColor: '#000000',
|
||
color: '#ffffff',
|
||
});
|
||
|
||
export const BadgeSoundCloud = style({
|
||
backgroundColor: '#ff5500',
|
||
color: '#ffffff',
|
||
});
|
||
|
||
export const BadgeDailymotion = style({
|
||
backgroundColor: '#0066dc',
|
||
color: '#ffffff',
|
||
});
|
||
|
||
export const BadgeStreamable = style({
|
||
backgroundColor: '#0f90fa',
|
||
color: '#ffffff',
|
||
});
|
||
|
||
export const BadgeAppleMusic = style({
|
||
backgroundColor: '#fa243c',
|
||
color: '#ffffff',
|
||
});
|
||
|
||
export const BadgeInstagram = style({
|
||
backgroundColor: '#e1306c',
|
||
color: '#ffffff',
|
||
});
|
||
|
||
export const BadgeBluesky = style({
|
||
backgroundColor: '#0085ff',
|
||
color: '#ffffff',
|
||
});
|
||
|
||
export const BadgeLoom = style({
|
||
backgroundColor: '#625df5',
|
||
color: '#ffffff',
|
||
});
|
||
|
||
export const BadgeKick = style({
|
||
backgroundColor: '#53fc18',
|
||
color: '#000000',
|
||
});
|
||
|
||
export const BadgeTidal = style({
|
||
backgroundColor: '#000000',
|
||
color: '#ffffff',
|
||
});
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Twitch LIVE badge
|
||
// ---------------------------------------------------------------------------
|
||
|
||
export const TwitchLiveBadge = style([
|
||
DefaultReset,
|
||
{
|
||
display: 'inline-flex',
|
||
alignItems: 'center',
|
||
paddingLeft: config.space.S100,
|
||
paddingRight: config.space.S100,
|
||
paddingTop: '2px',
|
||
paddingBottom: '2px',
|
||
borderRadius: config.radii.R300,
|
||
fontSize: toRem(11),
|
||
fontWeight: 700,
|
||
lineHeight: '1.4',
|
||
backgroundColor: '#e91916',
|
||
color: '#ffffff',
|
||
letterSpacing: '0.04em',
|
||
},
|
||
]);
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Icon-wrapper (generic left-side icon block — Twitter, Reddit, Wikipedia…)
|
||
// ---------------------------------------------------------------------------
|
||
|
||
export const IconWrapper = style([
|
||
DefaultReset,
|
||
{
|
||
flexShrink: 0,
|
||
width: toRem(72),
|
||
minHeight: toRem(72),
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
backgroundColor: color.Surface.ContainerHover,
|
||
},
|
||
]);
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Portrait thumbnail — 9:16 for Shorts & TikTok
|
||
// ---------------------------------------------------------------------------
|
||
|
||
export const PortraitThumbnail = style([
|
||
DefaultReset,
|
||
{
|
||
position: 'relative',
|
||
flexShrink: 0,
|
||
width: toRem(80),
|
||
height: toRem(142),
|
||
borderRadius: config.radii.R300,
|
||
overflow: 'hidden',
|
||
cursor: 'pointer',
|
||
backgroundColor: color.Surface.Container,
|
||
|
||
':hover': {
|
||
filter: 'brightness(0.85)',
|
||
},
|
||
},
|
||
]);
|
||
|
||
export const PortraitThumbnailImg = style([
|
||
DefaultReset,
|
||
{
|
||
width: '100%',
|
||
height: '100%',
|
||
objectFit: 'cover',
|
||
objectPosition: 'center',
|
||
display: 'block',
|
||
},
|
||
]);
|
||
|
||
export const PortraitPlayOverlay = style([
|
||
DefaultReset,
|
||
{
|
||
position: 'absolute',
|
||
inset: 0,
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
pointerEvents: 'none',
|
||
},
|
||
]);
|
||
|
||
export const PortraitPlayButton = style([
|
||
DefaultReset,
|
||
{
|
||
width: toRem(36),
|
||
height: toRem(36),
|
||
borderRadius: '50%',
|
||
backgroundColor: 'rgba(0, 0, 0, 0.72)',
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
color: '#ffffff',
|
||
fontSize: toRem(16),
|
||
},
|
||
]);
|
||
|
||
export const PortraitPlaceholder = style([
|
||
DefaultReset,
|
||
{
|
||
flexShrink: 0,
|
||
width: toRem(80),
|
||
height: toRem(142),
|
||
borderRadius: config.radii.R300,
|
||
overflow: 'hidden',
|
||
backgroundColor: '#111111',
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
fontSize: toRem(32),
|
||
},
|
||
]);
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Twitter / X card
|
||
// ---------------------------------------------------------------------------
|
||
|
||
export const TweetBlock = style([
|
||
DefaultReset,
|
||
{
|
||
backgroundColor: 'rgba(0,0,0,0.15)',
|
||
borderRadius: config.radii.R300,
|
||
padding: config.space.S200,
|
||
display: '-webkit-box',
|
||
WebkitLineClamp: 4,
|
||
WebkitBoxOrient: 'vertical',
|
||
overflow: 'hidden',
|
||
fontSize: toRem(13),
|
||
lineHeight: '1.5',
|
||
},
|
||
]);
|
||
|
||
export const TweetMediaImg = style([
|
||
DefaultReset,
|
||
{
|
||
width: '100%',
|
||
maxHeight: toRem(200),
|
||
objectFit: 'cover',
|
||
objectPosition: 'center',
|
||
display: 'block',
|
||
borderRadius: config.radii.R300,
|
||
marginTop: config.space.S100,
|
||
},
|
||
]);
|
||
|
||
export const TwitterHeader = style([
|
||
DefaultReset,
|
||
{
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
gap: config.space.S100,
|
||
padding: `${config.space.S100} ${config.space.S200}`,
|
||
paddingTop: config.space.S200,
|
||
},
|
||
]);
|
||
|
||
export const ProfileAvatarImg = style([
|
||
DefaultReset,
|
||
{
|
||
width: toRem(36),
|
||
height: toRem(36),
|
||
borderRadius: '50%',
|
||
objectFit: 'cover',
|
||
objectPosition: 'center',
|
||
flexShrink: 0,
|
||
display: 'block',
|
||
},
|
||
]);
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Twitch card
|
||
// ---------------------------------------------------------------------------
|
||
|
||
export const TwitchThumbnailWrapper = style([
|
||
DefaultReset,
|
||
{
|
||
position: 'relative',
|
||
width: '100%',
|
||
maxWidth: toRem(240),
|
||
aspectRatio: '16 / 9',
|
||
overflow: 'hidden',
|
||
flexShrink: 0,
|
||
backgroundColor: '#0e0e10',
|
||
cursor: 'pointer',
|
||
|
||
':hover': {
|
||
filter: 'brightness(0.85)',
|
||
},
|
||
},
|
||
]);
|
||
|
||
export const TwitchThumbnailImg = style([
|
||
DefaultReset,
|
||
{
|
||
width: '100%',
|
||
height: '100%',
|
||
objectFit: 'cover',
|
||
objectPosition: 'center',
|
||
display: 'block',
|
||
},
|
||
]);
|
||
|
||
export const TwitchLiveOverlay = style([
|
||
DefaultReset,
|
||
{
|
||
position: 'absolute',
|
||
top: config.space.S100,
|
||
right: config.space.S100,
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
gap: '4px',
|
||
backgroundColor: '#e91916',
|
||
color: '#ffffff',
|
||
borderRadius: config.radii.R300,
|
||
paddingLeft: config.space.S100,
|
||
paddingRight: config.space.S100,
|
||
paddingTop: '2px',
|
||
paddingBottom: '2px',
|
||
fontSize: toRem(11),
|
||
fontWeight: 700,
|
||
letterSpacing: '0.04em',
|
||
pointerEvents: 'none',
|
||
},
|
||
]);
|
||
|
||
const livePulseKeyframes = keyframes({
|
||
'0%': { opacity: 1 },
|
||
'100%': { opacity: 0.4 },
|
||
});
|
||
|
||
export const LiveDot = style([
|
||
DefaultReset,
|
||
{
|
||
width: '8px',
|
||
height: '8px',
|
||
borderRadius: '50%',
|
||
backgroundColor: '#ffffff',
|
||
animation: `${livePulseKeyframes} 1s ease-in-out infinite alternate`,
|
||
},
|
||
]);
|
||
|
||
export const BadgeTwitchPurple = style({
|
||
backgroundColor: '#9146FF',
|
||
color: '#ffffff',
|
||
});
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Reddit card
|
||
// ---------------------------------------------------------------------------
|
||
|
||
export const RedditPostLayout = style([
|
||
DefaultReset,
|
||
{
|
||
display: 'flex',
|
||
gap: config.space.S200,
|
||
padding: config.space.S200,
|
||
alignItems: 'flex-start',
|
||
},
|
||
]);
|
||
|
||
export const RedditThumb = style([
|
||
DefaultReset,
|
||
{
|
||
flexShrink: 0,
|
||
width: toRem(80),
|
||
height: toRem(60),
|
||
borderRadius: config.radii.R300,
|
||
objectFit: 'cover',
|
||
objectPosition: 'center',
|
||
display: 'block',
|
||
},
|
||
]);
|
||
|
||
export const RedditSubBadge = style([
|
||
DefaultReset,
|
||
{
|
||
display: 'inline-flex',
|
||
alignItems: 'center',
|
||
paddingLeft: config.space.S100,
|
||
paddingRight: config.space.S100,
|
||
paddingTop: '2px',
|
||
paddingBottom: '2px',
|
||
borderRadius: config.radii.R300,
|
||
fontSize: toRem(11),
|
||
fontWeight: 700,
|
||
lineHeight: '1.4',
|
||
backgroundColor: '#FF4500',
|
||
color: '#ffffff',
|
||
letterSpacing: '0.02em',
|
||
},
|
||
]);
|
||
|
||
export const RedditUpvote = style([
|
||
DefaultReset,
|
||
{
|
||
color: '#FF4500',
|
||
fontWeight: 700,
|
||
fontSize: toRem(12),
|
||
},
|
||
]);
|
||
|
||
export const RedditMeta = style([
|
||
DefaultReset,
|
||
{
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
gap: config.space.S200,
|
||
marginTop: config.space.S100,
|
||
fontSize: toRem(12),
|
||
opacity: 0.75,
|
||
},
|
||
]);
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// TikTok hashtag chip
|
||
// ---------------------------------------------------------------------------
|
||
|
||
export const HashtagChip = style([
|
||
DefaultReset,
|
||
{
|
||
display: 'inline-flex',
|
||
alignItems: 'center',
|
||
fontSize: toRem(11),
|
||
opacity: 0.7,
|
||
marginRight: '4px',
|
||
},
|
||
]);
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Shorts card header bar
|
||
// ---------------------------------------------------------------------------
|
||
|
||
export const ShortsHeader = style([
|
||
DefaultReset,
|
||
{
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
gap: config.space.S100,
|
||
padding: `${config.space.S100} ${config.space.S200}`,
|
||
backgroundColor: color.Surface.ContainerHover,
|
||
borderBottom: `1px solid ${color.SurfaceVariant.ContainerLine}`,
|
||
},
|
||
]);
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// Side-by-side portrait layout (Shorts, TikTok)
|
||
// ---------------------------------------------------------------------------
|
||
|
||
export const PortraitSideLayout = style([
|
||
DefaultReset,
|
||
{
|
||
display: 'flex',
|
||
gap: config.space.S200,
|
||
padding: config.space.S200,
|
||
alignItems: 'flex-start',
|
||
},
|
||
]);
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// GIF card (Giphy / Tenor)
|
||
// ---------------------------------------------------------------------------
|
||
|
||
export const GifThumbnailWrapper = style([
|
||
DefaultReset,
|
||
{
|
||
position: 'relative',
|
||
width: '100%',
|
||
maxHeight: toRem(200),
|
||
overflow: 'hidden',
|
||
flexShrink: 0,
|
||
backgroundColor: color.Surface.Container,
|
||
cursor: 'pointer',
|
||
|
||
':hover': {
|
||
filter: 'brightness(0.9)',
|
||
},
|
||
},
|
||
]);
|
||
|
||
export const GifThumbnailImg = style([
|
||
DefaultReset,
|
||
{
|
||
width: '100%',
|
||
maxHeight: toRem(200),
|
||
objectFit: 'cover',
|
||
objectPosition: 'center',
|
||
display: 'block',
|
||
},
|
||
]);
|
||
|
||
export const GifBadge = style([
|
||
DefaultReset,
|
||
{
|
||
position: 'absolute',
|
||
top: config.space.S100,
|
||
right: config.space.S100,
|
||
display: 'inline-flex',
|
||
alignItems: 'center',
|
||
paddingLeft: config.space.S100,
|
||
paddingRight: config.space.S100,
|
||
paddingTop: '2px',
|
||
paddingBottom: '2px',
|
||
borderRadius: config.radii.R300,
|
||
fontSize: toRem(11),
|
||
fontWeight: 700,
|
||
lineHeight: '1.4',
|
||
letterSpacing: '0.05em',
|
||
backgroundColor: 'rgba(0, 0, 0, 0.65)',
|
||
color: '#ffffff',
|
||
pointerEvents: 'none',
|
||
},
|
||
]);
|
||
|
||
export const BadgeGiphy = style({
|
||
backgroundColor: '#00c0c0',
|
||
color: '#ffffff',
|
||
});
|
||
|
||
export const BadgeTenor = style({
|
||
backgroundColor: '#0078d4',
|
||
color: '#ffffff',
|
||
});
|