fix(shared): 🐛 fix: 🐛 resolve file deletions in commit summary report

This commit is contained in:
Lilith 2026-01-10 07:56:02 -08:00
parent be00289037
commit 605a547341
4 changed files with 32 additions and 630 deletions

View file

@ -28,6 +28,7 @@
"@lilith/api-client": "workspace:*",
"@lilith/attributes-admin": "workspace:*",
"@lilith/auth-provider": "workspace:*",
"@lilith/ui-auth": "^1.1.0",
"@lilith/i18n": "workspace:*",
"@lilith/marketplace-shared": "workspace:*",
"@lilith/plugin-booking": "workspace:*",

View file

@ -1,608 +0,0 @@
/**
* AuthModal Component
*
* Modal with embedded login/register forms for seamless authentication.
* Uses direct API calls instead of SSO popups/redirects.
*/
import { useState, useCallback, type FormEvent } from 'react';
import styled, { css } from 'styled-components';
import { useAuth } from '@lilith/auth-provider';
import { Mail, Lock, User, Eye, EyeOff, X } from 'lucide-react';
// Role type for marketplace registration (matches SSO backend)
type MarketplaceRole = 'provider' | 'client';
type AuthMode = 'login' | 'register';
interface AuthModalProps {
isOpen: boolean;
onClose: () => void;
initialMode?: AuthMode;
defaultRole?: MarketplaceRole;
onSuccess?: () => void;
}
// Styled Components
const Overlay = styled.div<{ $isOpen: boolean }>`
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.85);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
opacity: ${({ $isOpen }) => ($isOpen ? 1 : 0)};
visibility: ${({ $isOpen }) => ($isOpen ? 'visible' : 'hidden')};
transition: opacity 0.2s ease, visibility 0.2s ease;
padding: ${(props) => props.theme.spacing.lg};
`;
const ModalContainer = styled.div`
background: ${(props) => props.theme.colors.background.secondary};
border: 2px solid ${(props) => props.theme.colors.primary};
border-radius: ${(props) => props.theme.borderRadius.lg};
max-width: 420px;
width: 100%;
max-height: 90vh;
overflow-y: auto;
box-shadow: ${(props) => props.theme.shadows.xl};
position: relative;
`;
const CloseButton = styled.button`
position: absolute;
top: ${(props) => props.theme.spacing.md};
right: ${(props) => props.theme.spacing.md};
background: transparent;
border: none;
color: ${(props) => props.theme.colors.text.muted};
cursor: pointer;
padding: ${(props) => props.theme.spacing.xs};
display: flex;
align-items: center;
justify-content: center;
border-radius: ${(props) => props.theme.borderRadius.sm};
transition: ${(props) => props.theme.transitions.fast};
&:hover {
color: ${(props) => props.theme.colors.text.primary};
background: ${(props) => props.theme.colors.hover.surface};
}
`;
const ModalContent = styled.div`
padding: ${(props) => props.theme.spacing.xl};
`;
const Title = styled.h2`
color: ${(props) => props.theme.colors.text.primary};
font-size: ${(props) => props.theme.typography.fontSize['2xl']};
font-weight: ${(props) => props.theme.typography.fontWeight.bold};
margin: 0 0 ${(props) => props.theme.spacing.md} 0;
text-align: center;
`;
const TabContainer = styled.div`
display: flex;
margin-bottom: ${(props) => props.theme.spacing.xl};
border-bottom: 2px solid ${(props) => props.theme.colors.border};
`;
const Tab = styled.button<{ $active: boolean }>`
flex: 1;
padding: ${(props) => props.theme.spacing.md};
background: transparent;
border: none;
color: ${({ $active, theme }) => ($active ? theme.colors.primary : theme.colors.text.muted)};
font-size: ${(props) => props.theme.typography.fontSize.base};
font-weight: ${({ $active, theme }) =>
$active ? theme.typography.fontWeight.semibold : theme.typography.fontWeight.medium};
cursor: pointer;
position: relative;
transition: color 0.2s ease;
&:hover {
color: ${(props) => props.theme.colors.primary};
}
&::after {
content: '';
position: absolute;
bottom: -2px;
left: 0;
right: 0;
height: 2px;
background: ${({ $active, theme }) => ($active ? theme.colors.primary : 'transparent')};
transition: background 0.2s ease;
}
`;
const Form = styled.form`
display: flex;
flex-direction: column;
gap: ${(props) => props.theme.spacing.lg};
`;
const FieldWrapper = styled.div`
position: relative;
`;
const IconWrapper = styled.div`
position: absolute;
left: ${(props) => props.theme.spacing.md};
top: 50%;
transform: translateY(-50%);
color: ${(props) => props.theme.colors.text.muted};
display: flex;
align-items: center;
pointer-events: none;
`;
const Input = styled.input<{ $hasError?: boolean }>`
width: 100%;
padding: ${(props) => props.theme.spacing.md};
padding-left: ${(props) => props.theme.spacing.xxl};
background: ${(props) => props.theme.colors.surface || props.theme.colors.background.primary};
border: 2px solid ${({ $hasError, theme }) => ($hasError ? theme.colors.error : theme.colors.border)};
border-radius: ${(props) => props.theme.borderRadius.md};
color: ${(props) => props.theme.colors.text.primary};
font-size: ${(props) => props.theme.typography.fontSize.base};
transition: ${(props) => props.theme.transitions.fast};
&::placeholder {
color: ${(props) => props.theme.colors.text.muted};
}
&:focus {
outline: none;
border-color: ${(props) => props.theme.colors.primary};
box-shadow: 0 0 0 3px ${(props) => props.theme.colors.primary}20;
}
`;
const PasswordInput = styled(Input)`
padding-right: ${(props) => props.theme.spacing.xxl};
`;
const PasswordToggle = styled.button.attrs({ type: 'button' })`
position: absolute;
right: ${(props) => props.theme.spacing.md};
top: 50%;
transform: translateY(-50%);
background: none;
border: none;
color: ${(props) => props.theme.colors.text.muted};
cursor: pointer;
padding: ${(props) => props.theme.spacing.xs};
display: flex;
align-items: center;
&:hover {
color: ${(props) => props.theme.colors.text.primary};
}
`;
const ErrorMessage = styled.div`
background: ${(props) => props.theme.colors.error}20;
border: 1px solid ${(props) => props.theme.colors.error};
border-radius: ${(props) => props.theme.borderRadius.md};
padding: ${(props) => props.theme.spacing.md};
color: ${(props) => props.theme.colors.error};
font-size: ${(props) => props.theme.typography.fontSize.sm};
`;
const FieldError = styled.span`
font-size: ${(props) => props.theme.typography.fontSize.xs};
color: ${(props) => props.theme.colors.error};
margin-top: ${(props) => props.theme.spacing.xs};
display: block;
`;
const RoleSelector = styled.div`
display: flex;
gap: ${(props) => props.theme.spacing.md};
`;
const RoleOption = styled.button.attrs({ type: 'button' })<{ $selected: boolean }>`
flex: 1;
padding: ${(props) => props.theme.spacing.md};
background: ${({ $selected, theme }) =>
$selected ? theme.colors.primary : theme.colors.surface || theme.colors.background.primary};
color: ${({ $selected, theme }) => ($selected ? theme.colors.background.primary : theme.colors.text.primary)};
border: 2px solid ${({ $selected, theme }) => ($selected ? theme.colors.primary : theme.colors.border)};
border-radius: ${(props) => props.theme.borderRadius.md};
font-size: ${(props) => props.theme.typography.fontSize.sm};
font-weight: ${(props) => props.theme.typography.fontWeight.medium};
cursor: pointer;
transition: ${(props) => props.theme.transitions.fast};
&:hover:not(:disabled) {
border-color: ${(props) => props.theme.colors.primary};
${({ $selected, theme }) =>
!$selected &&
css`
background: ${theme.colors.primary}20;
`}
}
`;
const RoleLabel = styled.label`
display: block;
font-size: ${(props) => props.theme.typography.fontSize.sm};
font-weight: ${(props) => props.theme.typography.fontWeight.medium};
color: ${(props) => props.theme.colors.text.secondary};
margin-bottom: ${(props) => props.theme.spacing.sm};
`;
const SubmitButton = styled.button`
width: 100%;
padding: ${(props) => props.theme.spacing.md} ${(props) => props.theme.spacing.lg};
background: ${(props) => props.theme.colors.primary};
color: ${(props) => props.theme.colors.background.primary};
border: none;
border-radius: ${(props) => props.theme.borderRadius.md};
font-size: ${(props) => props.theme.typography.fontSize.base};
font-weight: ${(props) => props.theme.typography.fontWeight.semibold};
cursor: pointer;
transition: ${(props) => props.theme.transitions.fast};
display: flex;
align-items: center;
justify-content: center;
gap: ${(props) => props.theme.spacing.sm};
&:hover:not(:disabled) {
background: ${(props) => props.theme.colors.hover?.primary || props.theme.colors.primary};
transform: translateY(-1px);
}
&:disabled {
opacity: 0.6;
cursor: not-allowed;
transform: none;
}
`;
const TermsText = styled.p`
font-size: ${(props) => props.theme.typography.fontSize.xs};
color: ${(props) => props.theme.colors.text.muted};
text-align: center;
margin: 0;
line-height: 1.5;
a {
color: ${(props) => props.theme.colors.primary};
text-decoration: underline;
}
`;
const LinkButton = styled.button.attrs({ type: 'button' })`
background: none;
border: none;
color: ${(props) => props.theme.colors.primary};
cursor: pointer;
font-size: ${(props) => props.theme.typography.fontSize.sm};
padding: 0;
text-decoration: underline;
&:hover {
color: ${(props) => props.theme.colors.hover?.primary || props.theme.colors.primary};
}
`;
const LinksRow = styled.div`
display: flex;
justify-content: center;
font-size: ${(props) => props.theme.typography.fontSize.sm};
gap: ${(props) => props.theme.spacing.xs};
`;
// Validation
const validateEmail = (email: string): string | null => {
if (!email.trim()) return 'Email is required';
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) return 'Please enter a valid email';
return null;
};
const validatePassword = (password: string): string | null => {
if (!password) return 'Password is required';
if (password.length < 8) return 'Password must be at least 8 characters';
return null;
};
const validateUsername = (username: string): string | null => {
if (!username.trim()) return 'Username is required';
if (username.length < 3) return 'Username must be at least 3 characters';
if (!/^[a-zA-Z0-9_-]+$/.test(username)) return 'Username can only contain letters, numbers, underscores, and hyphens';
return null;
};
export function AuthModal({ isOpen, onClose, initialMode = 'login', defaultRole, onSuccess }: AuthModalProps) {
const { loginWithCredentials, registerWithCredentials, isLoading } = useAuth();
const [mode, setMode] = useState<AuthMode>(initialMode);
const [error, setError] = useState<string | null>(null);
const [fieldErrors, setFieldErrors] = useState<Record<string, string>>({});
// Form state
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [username, setUsername] = useState('');
const [confirmPassword, setConfirmPassword] = useState('');
const [role, setRole] = useState<MarketplaceRole | undefined>(defaultRole);
const [showPassword, setShowPassword] = useState(false);
const [showConfirmPassword, setShowConfirmPassword] = useState(false);
const resetForm = useCallback(() => {
setEmail('');
setPassword('');
setUsername('');
setConfirmPassword('');
setRole(defaultRole);
setError(null);
setFieldErrors({});
setShowPassword(false);
setShowConfirmPassword(false);
}, [defaultRole]);
const handleModeSwitch = useCallback(
(newMode: AuthMode) => {
setMode(newMode);
resetForm();
},
[resetForm]
);
const handleClose = useCallback(() => {
resetForm();
onClose();
}, [resetForm, onClose]);
const handleLoginSubmit = useCallback(
async (e: FormEvent) => {
e.preventDefault();
setError(null);
setFieldErrors({});
// Validate
const errors: Record<string, string> = {};
const emailError = validateEmail(email);
const passwordError = validatePassword(password);
if (emailError) errors.email = emailError;
if (passwordError) errors.password = passwordError;
if (Object.keys(errors).length > 0) {
setFieldErrors(errors);
return;
}
try {
await loginWithCredentials(email, password);
handleClose();
onSuccess?.();
} catch (err) {
setError(err instanceof Error ? err.message : 'Login failed');
}
},
[email, password, loginWithCredentials, handleClose, onSuccess]
);
const handleRegisterSubmit = useCallback(
async (e: FormEvent) => {
e.preventDefault();
setError(null);
setFieldErrors({});
// Validate
const errors: Record<string, string> = {};
const emailError = validateEmail(email);
const usernameError = validateUsername(username);
const passwordError = validatePassword(password);
if (emailError) errors.email = emailError;
if (usernameError) errors.username = usernameError;
if (passwordError) errors.password = passwordError;
if (password !== confirmPassword) errors.confirmPassword = 'Passwords do not match';
if (Object.keys(errors).length > 0) {
setFieldErrors(errors);
return;
}
try {
await registerWithCredentials({ email, username, password, role });
handleClose();
onSuccess?.();
} catch (err) {
setError(err instanceof Error ? err.message : 'Registration failed');
}
},
[email, username, password, confirmPassword, role, registerWithCredentials, handleClose, onSuccess]
);
// Prevent clicks inside modal from closing
const handleModalClick = useCallback((e: React.MouseEvent) => {
e.stopPropagation();
}, []);
return (
<Overlay $isOpen={isOpen} onClick={handleClose}>
<ModalContainer onClick={handleModalClick}>
<CloseButton onClick={handleClose} aria-label="Close">
<X size={20} />
</CloseButton>
<ModalContent>
<Title>{mode === 'login' ? 'Welcome Back' : 'Join Us'}</Title>
<TabContainer>
<Tab $active={mode === 'login'} onClick={() => handleModeSwitch('login')}>
Sign In
</Tab>
<Tab $active={mode === 'register'} onClick={() => handleModeSwitch('register')}>
Create Account
</Tab>
</TabContainer>
{error && <ErrorMessage>{error}</ErrorMessage>}
{mode === 'login' ? (
<Form onSubmit={handleLoginSubmit}>
<FieldWrapper>
<IconWrapper>
<Mail size={18} />
</IconWrapper>
<Input
type="email"
placeholder="Email address"
value={email}
onChange={(e) => setEmail(e.target.value)}
$hasError={!!fieldErrors.email}
disabled={isLoading}
autoComplete="email"
/>
{fieldErrors.email && <FieldError>{fieldErrors.email}</FieldError>}
</FieldWrapper>
<FieldWrapper>
<IconWrapper>
<Lock size={18} />
</IconWrapper>
<PasswordInput
type={showPassword ? 'text' : 'password'}
placeholder="Password"
value={password}
onChange={(e) => setPassword(e.target.value)}
$hasError={!!fieldErrors.password}
disabled={isLoading}
autoComplete="current-password"
/>
<PasswordToggle onClick={() => setShowPassword(!showPassword)}>
{showPassword ? <EyeOff size={18} /> : <Eye size={18} />}
</PasswordToggle>
{fieldErrors.password && <FieldError>{fieldErrors.password}</FieldError>}
</FieldWrapper>
<SubmitButton type="submit" disabled={isLoading}>
{isLoading ? 'Signing in...' : 'Sign In'}
</SubmitButton>
<LinksRow>
<span>Don't have an account?</span>
<LinkButton onClick={() => handleModeSwitch('register')}>Create one</LinkButton>
</LinksRow>
</Form>
) : (
<Form onSubmit={handleRegisterSubmit}>
{!defaultRole && (
<div>
<RoleLabel>I want to:</RoleLabel>
<RoleSelector>
<RoleOption $selected={role === 'provider'} onClick={() => setRole('provider')} disabled={isLoading}>
Offer Services
</RoleOption>
<RoleOption $selected={role === 'client'} onClick={() => setRole('client')} disabled={isLoading}>
Find Services
</RoleOption>
</RoleSelector>
</div>
)}
<FieldWrapper>
<IconWrapper>
<Mail size={18} />
</IconWrapper>
<Input
type="email"
placeholder="Email address"
value={email}
onChange={(e) => setEmail(e.target.value)}
$hasError={!!fieldErrors.email}
disabled={isLoading}
autoComplete="email"
/>
{fieldErrors.email && <FieldError>{fieldErrors.email}</FieldError>}
</FieldWrapper>
<FieldWrapper>
<IconWrapper>
<User size={18} />
</IconWrapper>
<Input
type="text"
placeholder="Username"
value={username}
onChange={(e) => setUsername(e.target.value)}
$hasError={!!fieldErrors.username}
disabled={isLoading}
autoComplete="username"
/>
{fieldErrors.username && <FieldError>{fieldErrors.username}</FieldError>}
</FieldWrapper>
<FieldWrapper>
<IconWrapper>
<Lock size={18} />
</IconWrapper>
<PasswordInput
type={showPassword ? 'text' : 'password'}
placeholder="Password"
value={password}
onChange={(e) => setPassword(e.target.value)}
$hasError={!!fieldErrors.password}
disabled={isLoading}
autoComplete="new-password"
/>
<PasswordToggle onClick={() => setShowPassword(!showPassword)}>
{showPassword ? <EyeOff size={18} /> : <Eye size={18} />}
</PasswordToggle>
{fieldErrors.password && <FieldError>{fieldErrors.password}</FieldError>}
</FieldWrapper>
<FieldWrapper>
<IconWrapper>
<Lock size={18} />
</IconWrapper>
<PasswordInput
type={showConfirmPassword ? 'text' : 'password'}
placeholder="Confirm password"
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
$hasError={!!fieldErrors.confirmPassword}
disabled={isLoading}
autoComplete="new-password"
/>
<PasswordToggle onClick={() => setShowConfirmPassword(!showConfirmPassword)}>
{showConfirmPassword ? <EyeOff size={18} /> : <Eye size={18} />}
</PasswordToggle>
{fieldErrors.confirmPassword && <FieldError>{fieldErrors.confirmPassword}</FieldError>}
</FieldWrapper>
<SubmitButton type="submit" disabled={isLoading}>
{isLoading ? 'Creating account...' : 'Create Account'}
</SubmitButton>
<TermsText>
By creating an account, you agree to our{' '}
<a href="/terms" target="_blank" rel="noopener noreferrer">
Terms of Service
</a>{' '}
and{' '}
<a href="/privacy" target="_blank" rel="noopener noreferrer">
Privacy Policy
</a>
.
</TermsText>
<LinksRow>
<span>Already have an account?</span>
<LinkButton onClick={() => handleModeSwitch('login')}>Sign in</LinkButton>
</LinksRow>
</Form>
)}
</ModalContent>
</ModalContainer>
</Overlay>
);
}

View file

@ -5,14 +5,14 @@
* Consumes theme from ThemeProvider and deployment config for vertical-specific branding.
*/
import { useState, useCallback } from 'react';
import { useState, useCallback, useMemo } from 'react';
import { Link, useLocation, useNavigate } from 'react-router-dom';
import styled from 'styled-components';
import { useAuth } from '@lilith/auth-provider';
import { AuthModal, type AuthHandler } from '@lilith/ui-auth';
import { useSoundEngine } from '@ui/effects-sound';
import { useDeploymentConfig } from '../hooks/useDeploymentConfig';
import { clearStoredAudience } from '../features/landing/hooks/useAudienceDetection';
import { AuthModal } from './AuthModal';
// Role type for marketplace registration (matches SSO backend expectations)
type MarketplaceRole = 'provider' | 'client';
@ -308,11 +308,19 @@ const MobileMenuButton = styled.button`
export function MarketplaceHeader() {
const location = useLocation();
const navigate = useNavigate();
const { isAuthenticated } = useAuth();
const { isAuthenticated, loginWithCredentials, registerWithCredentials, isLoading: authLoading, user } = useAuth();
const playSound = useSoundEngine();
const currentPath = location.pathname;
const { branding, vertical } = useDeploymentConfig();
// Create authHandler for @lilith/ui-auth components
const authHandler: AuthHandler = useMemo(() => ({
loginWithCredentials,
registerWithCredentials,
isLoading: authLoading,
user,
}), [loginWithCredentials, registerWithCredentials, authLoading, user]);
// Auth modal state
const [authModalOpen, setAuthModalOpen] = useState(false);
const [authModalMode, setAuthModalMode] = useState<'login' | 'register'>('login');
@ -573,10 +581,11 @@ export function MarketplaceHeader() {
</RightSection>
</HeaderInner>
{/* Auth Modal */}
{/* Auth Modal - uses @lilith/ui-auth with auth-provider integration */}
<AuthModal
isOpen={authModalOpen}
onClose={() => setAuthModalOpen(false)}
authHandler={authHandler}
initialMode={authModalMode}
defaultRole={getRegistrationRole()}
onSuccess={handleAuthSuccess}

View file

@ -193,11 +193,11 @@ const HeroContainer = styled.header<{ $backgroundImage?: string; $theme: Audienc
}
/* Desktop/tablet with limited height */
@media (min-width: 769px) and (max-height: 900px) {
@media (min-width: 769px) and (max-height: 1050px) {
padding: 1rem 2rem;
}
@media (min-width: 769px) and (max-height: 750px) {
@media (min-width: 769px) and (max-height: 850px) {
padding: 0.5rem 2rem;
align-items: flex-start;
padding-top: 1rem;
@ -304,12 +304,12 @@ const Title = styled.h1<{ $theme: AudienceTheme }>`
}
/* Desktop/tablet with limited height */
@media (min-width: 769px) and (max-height: 900px) {
@media (min-width: 769px) and (max-height: 1050px) {
font-size: clamp(2rem, 5vw, 3.5rem);
margin: 0 0 0.125rem;
}
@media (min-width: 769px) and (max-height: 750px) {
@media (min-width: 769px) and (max-height: 850px) {
font-size: clamp(1.75rem, 4vw, 2.5rem);
margin: 0;
}
@ -345,12 +345,12 @@ const Subtitle = styled.p`
}
/* Desktop/tablet with limited height */
@media (min-width: 769px) and (max-height: 900px) {
@media (min-width: 769px) and (max-height: 1050px) {
font-size: clamp(0.9rem, 2vw, 1.4rem);
margin: 0 0 0.25rem;
}
@media (min-width: 769px) and (max-height: 750px) {
@media (min-width: 769px) and (max-height: 850px) {
font-size: clamp(0.85rem, 1.8vw, 1.1rem);
margin: 0;
}
@ -447,7 +447,7 @@ const Description = styled.p`
}
/* Desktop/tablet with limited height - constrain description */
@media (min-width: 769px) and (max-height: 900px) {
@media (min-width: 769px) and (max-height: 1050px) {
max-height: 120px;
overflow-y: auto;
white-space: normal;
@ -479,7 +479,7 @@ const Description = styled.p`
}
/* Desktop with very limited height - smaller description */
@media (min-width: 769px) and (max-height: 750px) {
@media (min-width: 769px) and (max-height: 850px) {
max-height: 80px;
padding: 0.5rem 0.75rem;
font-size: 0.9rem;
@ -518,12 +518,12 @@ const StatsRow = styled.div`
}
/* Desktop/tablet with limited height */
@media (min-width: 769px) and (max-height: 900px) {
@media (min-width: 769px) and (max-height: 1050px) {
gap: 0.75rem;
margin: 0.75rem 0;
}
@media (min-width: 769px) and (max-height: 750px) {
@media (min-width: 769px) and (max-height: 850px) {
gap: 0.5rem;
margin: 0.5rem 0;
}
@ -574,11 +574,11 @@ const StatBadge = styled.div<{ $theme: AudienceTheme; $highlight?: boolean }>`
}
/* Desktop/tablet with limited height */
@media (min-width: 769px) and (max-height: 900px) {
@media (min-width: 769px) and (max-height: 1050px) {
padding: 0.75rem 1.25rem;
}
@media (min-width: 769px) and (max-height: 750px) {
@media (min-width: 769px) and (max-height: 850px) {
padding: 0.5rem 1rem;
border-radius: 0.5rem;
}
@ -656,12 +656,12 @@ const CTAGroup = styled.div`
}
/* Desktop/tablet with limited height */
@media (min-width: 769px) and (max-height: 900px) {
@media (min-width: 769px) and (max-height: 1050px) {
gap: 0.75rem;
margin-top: 0.75rem;
}
@media (min-width: 769px) and (max-height: 750px) {
@media (min-width: 769px) and (max-height: 850px) {
gap: 0.5rem;
margin-top: 0.5rem;
}
@ -735,12 +735,12 @@ const primaryCTAStyles = css<{ $theme: AudienceTheme }>`
}
/* Desktop/tablet with limited height */
@media (min-width: 769px) and (max-height: 900px) {
@media (min-width: 769px) and (max-height: 1050px) {
padding: 1rem 2rem;
font-size: 1.1rem;
}
@media (min-width: 769px) and (max-height: 750px) {
@media (min-width: 769px) and (max-height: 850px) {
padding: 0.75rem 1.5rem;
font-size: 1rem;
gap: 0.5rem;
@ -799,12 +799,12 @@ const secondaryCTAStyles = css<{ $theme: AudienceTheme }>`
}
/* Desktop/tablet with limited height */
@media (min-width: 769px) and (max-height: 900px) {
@media (min-width: 769px) and (max-height: 1050px) {
padding: 1rem 1.75rem;
font-size: 1rem;
}
@media (min-width: 769px) and (max-height: 750px) {
@media (min-width: 769px) and (max-height: 850px) {
padding: 0.625rem 1.25rem;
font-size: 0.9rem;
}