fix: Thai line-height + add Kanit font variables
- Add --font-display, --font-body, --font-mono CSS variables in :root (they were referenced everywhere but never defined; Kanit wasn't loading) - Remove Noto Sans Thai import (Kanit handles Latin + Thai natively) - Fix hero/PageHero line-height: 1/1.1 → 1.3 to prevent Thai vowel clipping (was caused by overflow:hidden on .word-wrapper combined with line-height:1) - Replace .word-wrapper overflow:hidden with padding so Thai descenders stay visible during kinetic-title animation - Bump word translateY from 100% → 110% so word slides up cleanly - Bump global h1-h6 line-height from 1.1 → 1.25 Build: 18 pages, 0 errors
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
Audited for color conflicts (no button matches bg)
|
||||
============================================ */
|
||||
|
||||
@import url('https://fonts.googleapis.com/css2?family=Kanit:wght@400;500;600;700;800;900&family=Noto+Sans+Thai:wght@300;400;500;600;700&display=swap');
|
||||
@import url('https://fonts.googleapis.com/css2?family=Kanit:wght@300;400;500;600;700;800;900&display=swap');
|
||||
|
||||
/* ============================================
|
||||
CSS CUSTOM PROPERTIES — LIGHT THEME
|
||||
@@ -67,6 +67,13 @@
|
||||
--radius-lg: 16px;
|
||||
--radius-xl: 24px;
|
||||
--radius-full: 9999px;
|
||||
|
||||
/* Typography — Kanit is the only font (handles Latin + Thai natively).
|
||||
Use --font-display for headings, --font-body for paragraphs.
|
||||
Thai characters need ~1.4x line-height to avoid ascender/descender clipping. */
|
||||
--font-display: 'Kanit', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||
--font-body: 'Kanit', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||
--font-mono: 'SF Mono', Monaco, 'Cascadia Code', monospace;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
@@ -111,8 +118,9 @@ a:hover {
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-family: var(--font-display);
|
||||
font-weight: 800;
|
||||
line-height: 1.1;
|
||||
letter-spacing: -0.02em;
|
||||
/* Thai characters need extra leading to avoid descender clipping. */
|
||||
line-height: 1.25;
|
||||
letter-spacing: -0.01em;
|
||||
color: var(--color-black);
|
||||
}
|
||||
|
||||
@@ -479,6 +487,291 @@ p {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
REVEAL ANIMATIONS (used by lib/animations.ts)
|
||||
============================================ */
|
||||
|
||||
.reveal {
|
||||
opacity: 0;
|
||||
transform: translateY(40px);
|
||||
transition: opacity 0.8s var(--ease-out-expo),
|
||||
transform 0.8s var(--ease-out-expo);
|
||||
will-change: opacity, transform;
|
||||
}
|
||||
.reveal.revealed {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
/* Variants */
|
||||
.reveal-left {
|
||||
opacity: 0;
|
||||
transform: translateX(-50px);
|
||||
transition: opacity 0.8s var(--ease-out-expo),
|
||||
transform 0.8s var(--ease-out-expo);
|
||||
will-change: opacity, transform;
|
||||
}
|
||||
.reveal-left.revealed {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
.reveal-right {
|
||||
opacity: 0;
|
||||
transform: translateX(50px);
|
||||
transition: opacity 0.8s var(--ease-out-expo),
|
||||
transform 0.8s var(--ease-out-expo);
|
||||
will-change: opacity, transform;
|
||||
}
|
||||
.reveal-right.revealed {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
.reveal-scale {
|
||||
opacity: 0;
|
||||
transform: scale(0.92);
|
||||
transition: opacity 0.8s var(--ease-out-expo),
|
||||
transform 0.8s var(--ease-out-expo);
|
||||
will-change: opacity, transform;
|
||||
}
|
||||
.reveal-scale.revealed {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
/* Stagger container — children fade in sequentially */
|
||||
.stagger-children > * {
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
transition: opacity 0.6s var(--ease-out-expo),
|
||||
transform 0.6s var(--ease-out-expo);
|
||||
}
|
||||
.stagger-children > *.revealed {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
/* Kinetic headline — words animate in */
|
||||
.kinetic-title {
|
||||
display: block;
|
||||
/* Thai descenders need extra space when word slides up from translateY(100%). */
|
||||
line-height: 1.3;
|
||||
}
|
||||
.kinetic-title .word-wrapper {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
/* Padding instead of overflow:hidden so Thai vowels stay visible during reveal. */
|
||||
padding: 0.05em 0.02em;
|
||||
margin: -0.05em -0.02em;
|
||||
}
|
||||
.kinetic-title .word {
|
||||
display: inline-block;
|
||||
opacity: 0;
|
||||
transform: translateY(110%) skewY(8deg);
|
||||
animation: wordReveal 0.85s var(--ease-out-expo) forwards;
|
||||
animation-delay: var(--delay, 0s);
|
||||
}
|
||||
@keyframes wordReveal {
|
||||
0% { opacity: 0; transform: translateY(110%) skewY(8deg); }
|
||||
60% { opacity: 1; transform: translateY(-5%) skewY(-2deg); }
|
||||
100% { opacity: 1; transform: translateY(0) skewY(0); }
|
||||
}
|
||||
|
||||
/* Counter — used for stats, animated by lib/animations */
|
||||
.counter {
|
||||
display: inline-block;
|
||||
font-variant-numeric: tabular-nums;
|
||||
font-feature-settings: 'tnum';
|
||||
}
|
||||
|
||||
/* Magnetic button transition */
|
||||
[data-magnetic] {
|
||||
transition: transform 0.3s var(--ease-out-expo);
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
/* Scroll progress — paired with scrollProgress() in animations.ts */
|
||||
.scroll-indicator {
|
||||
--scroll-progress: 0%;
|
||||
/* CSS that uses it: e.g. width: var(--scroll-progress); */
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.reveal,
|
||||
.reveal-left,
|
||||
.reveal-right,
|
||||
.reveal-scale,
|
||||
.stagger-children > *,
|
||||
.kinetic-title .word {
|
||||
opacity: 1;
|
||||
transform: none;
|
||||
animation: none;
|
||||
transition: none;
|
||||
}
|
||||
[data-parallax] { transform: none !important; }
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
ICON WRAPPERS — for SVG icons replacing emojis
|
||||
Used by problem cards, value cards, channel cards, etc.
|
||||
All wrappers are square, centered, and use a subtle yellow tint
|
||||
to keep visual interest without competing with content.
|
||||
============================================ */
|
||||
|
||||
.icon-wrapper {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* Problem cards: red-tinted warning style on white card */
|
||||
.problem-icon {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: var(--color-primary);
|
||||
border-radius: 16px;
|
||||
color: var(--color-black);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.problem-icon :global(svg) { width: 28px; height: 28px; }
|
||||
|
||||
/* Value cards: dark icon on light bg */
|
||||
.value-icon {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: var(--color-black);
|
||||
color: var(--color-primary);
|
||||
border-radius: 16px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.value-icon :global(svg) { width: 28px; height: 28px; }
|
||||
|
||||
/* Channel picker (contact page): large icon */
|
||||
.channel-pick-icon {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: var(--color-primary);
|
||||
color: var(--color-black);
|
||||
border-radius: 50%;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.channel-pick-icon :global(svg) { width: 32px; height: 32px; }
|
||||
|
||||
/* Info column (contact page) */
|
||||
.info-icon {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: var(--color-bg-soft);
|
||||
color: var(--color-black);
|
||||
border-radius: 12px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.info-icon :global(svg) { width: 22px; height: 22px; }
|
||||
|
||||
/* Channel card (FAQ page) */
|
||||
.channel-icon {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: var(--color-primary);
|
||||
color: var(--color-black);
|
||||
border-radius: 50%;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.channel-icon :global(svg) { width: 28px; height: 28px; }
|
||||
|
||||
/* Category (FAQ page) */
|
||||
.category-icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
background: var(--color-primary);
|
||||
color: var(--color-black);
|
||||
border-radius: 8px;
|
||||
margin-right: 12px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.category-icon :global(svg) { width: 20px; height: 20px; }
|
||||
|
||||
/* Feature card (services page) */
|
||||
.feature-icon {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: var(--color-primary);
|
||||
color: var(--color-black);
|
||||
border-radius: 14px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.feature-icon :global(svg) { width: 28px; height: 28px; }
|
||||
|
||||
/* Target card */
|
||||
.target-icon {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: var(--color-black);
|
||||
color: var(--color-primary);
|
||||
border-radius: 14px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.target-icon :global(svg) { width: 28px; height: 28px; }
|
||||
|
||||
/* Success icon (form) */
|
||||
.success-icon {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #d1fae5;
|
||||
color: #059669;
|
||||
border-radius: 50%;
|
||||
margin: 0 auto 24px;
|
||||
}
|
||||
.success-icon :global(svg) { width: 44px; height: 44px; }
|
||||
|
||||
/* Footer contact icons (inline) */
|
||||
.contact-icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
flex-shrink: 0;
|
||||
color: var(--color-gray-600);
|
||||
}
|
||||
.contact-icon :global(svg) { width: 16px; height: 16px; }
|
||||
|
||||
/* Button-leading icon (paired with .btn) */
|
||||
.btn-icon {
|
||||
flex-shrink: 0;
|
||||
vertical-align: middle;
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
UTILITIES
|
||||
============================================ */
|
||||
|
||||
Reference in New Issue
Block a user