First Init
Deploy to Production / Build & Verify (push) Failing after 5m56s
Ping Search Engines / Notify Search Engines (push) Successful in 2s
Deploy to Production / Pre-Deploy Tests (push) Has been skipped
Deploy to Production / Deploy to Railway (push) Has been skipped
Deploy to Production / Deploy to Render (push) Has been skipped
Deploy to Production / Deploy to VPS (PM2) (push) Has been skipped
Deploy to Production / Deploy to Fly.io (push) Has been skipped
Deploy to Production / Post-Deploy Verification (push) Has been skipped
Deploy to Production / Notify on Failure (push) Successful in 2s
E2E Test Suite / Critical User Journeys (push) Has been skipped
E2E Test Suite / API Integration Tests (push) Has been skipped
E2E Test Suite / Smoke Tests (P0) (push) Failing after 11m26s
E2E Test Suite / Form Interaction Tests (push) Failing after 11m42s
E2E Test Suite / Destructive & Chaos Tests (push) Failing after 12m2s
E2E Test Suite / Cross-Browser Regression (chromium) (push) Failing after 16m14s
E2E Test Suite / Cross-Browser Regression (webkit) (push) Failing after 17m45s
E2E Test Suite / Cross-Browser Regression (firefox) (push) Failing after 25m23s
E2E Test Suite / Security Header Tests (push) Failing after 7m55s
E2E Test Suite / Test Report Summary (push) Failing after 20s
E2E Test Suite / Mobile Device Tests (push) Failing after 2h49m9s
Uptime Monitor / Health & Response Time (push) Failing after 2s
Uptime Monitor / SSL Certificate (push) Successful in 2s
Uptime Monitor / Send Alerts (push) Failing after 3s
Uptime Monitor / Record Uptime Success (push) Has been skipped
Deploy to Production / Build & Verify (push) Failing after 5m56s
Ping Search Engines / Notify Search Engines (push) Successful in 2s
Deploy to Production / Pre-Deploy Tests (push) Has been skipped
Deploy to Production / Deploy to Railway (push) Has been skipped
Deploy to Production / Deploy to Render (push) Has been skipped
Deploy to Production / Deploy to VPS (PM2) (push) Has been skipped
Deploy to Production / Deploy to Fly.io (push) Has been skipped
Deploy to Production / Post-Deploy Verification (push) Has been skipped
Deploy to Production / Notify on Failure (push) Successful in 2s
E2E Test Suite / Critical User Journeys (push) Has been skipped
E2E Test Suite / API Integration Tests (push) Has been skipped
E2E Test Suite / Smoke Tests (P0) (push) Failing after 11m26s
E2E Test Suite / Form Interaction Tests (push) Failing after 11m42s
E2E Test Suite / Destructive & Chaos Tests (push) Failing after 12m2s
E2E Test Suite / Cross-Browser Regression (chromium) (push) Failing after 16m14s
E2E Test Suite / Cross-Browser Regression (webkit) (push) Failing after 17m45s
E2E Test Suite / Cross-Browser Regression (firefox) (push) Failing after 25m23s
E2E Test Suite / Security Header Tests (push) Failing after 7m55s
E2E Test Suite / Test Report Summary (push) Failing after 20s
E2E Test Suite / Mobile Device Tests (push) Failing after 2h49m9s
Uptime Monitor / Health & Response Time (push) Failing after 2s
Uptime Monitor / SSL Certificate (push) Successful in 2s
Uptime Monitor / Send Alerts (push) Failing after 3s
Uptime Monitor / Record Uptime Success (push) Has been skipped
This commit is contained in:
@@ -0,0 +1,562 @@
|
||||
/* Google Fonts are loaded non-blocking via <link rel="preload"> in BaseLayout.astro.
|
||||
The @import is intentionally removed to avoid render-blocking font requests. */
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
/* ============================================================
|
||||
CSS CUSTOM PROPERTIES (Design Tokens)
|
||||
Single source of truth for values used outside Tailwind
|
||||
============================================================ */
|
||||
:root {
|
||||
/* Colors */
|
||||
--color-primary: #0891b2;
|
||||
--color-primary-dark: #0e7490;
|
||||
--color-primary-light: #22d3ee;
|
||||
--color-secondary: #1e293b;
|
||||
--color-accent: #f59e0b;
|
||||
--color-surface: #f8fafc;
|
||||
--color-surface-alt: #f1f5f9;
|
||||
--color-border: #e2e8f0;
|
||||
--color-border-strong: #cbd5e1;
|
||||
--color-text-primary: #1e293b;
|
||||
--color-text-secondary: #475569;
|
||||
--color-text-muted: #94a3b8;
|
||||
--color-text-inverse: #ffffff;
|
||||
|
||||
/* Typography */
|
||||
--font-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
|
||||
--font-mono: 'JetBrains Mono', monospace;
|
||||
|
||||
/* Border Radius */
|
||||
--radius-sm: 0.5rem; /* 8px */
|
||||
--radius-md: 0.75rem; /* 12px */
|
||||
--radius-lg: 1rem; /* 16px */
|
||||
--radius-xl: 1.5rem; /* 24px */
|
||||
--radius-full: 9999px;
|
||||
|
||||
/* Shadows */
|
||||
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
||||
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
|
||||
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
||||
--shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
|
||||
--shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / 0.25);
|
||||
--shadow-primary: 0 20px 25px -5px rgb(8 145 178 / 0.3);
|
||||
|
||||
/* Transitions */
|
||||
--transition-fast: 150ms ease;
|
||||
--transition-base: 200ms ease;
|
||||
--transition-slow: 300ms ease;
|
||||
--transition-slower: 500ms ease;
|
||||
|
||||
/* Spacing */
|
||||
--section-padding: 6rem; /* py-24 */
|
||||
--section-padding-sm: 4rem; /* py-16 */
|
||||
--container-max: 80rem; /* max-w-7xl */
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
BASE STYLES
|
||||
============================================================ */
|
||||
@layer base {
|
||||
html {
|
||||
font-family: var(--font-sans);
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
body {
|
||||
@apply bg-white text-secondary-800 antialiased;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
@apply font-bold tracking-tight;
|
||||
}
|
||||
|
||||
code, pre {
|
||||
font-family: var(--font-mono);
|
||||
}
|
||||
|
||||
/* Image optimization defaults */
|
||||
img {
|
||||
height: auto;
|
||||
max-width: 100%;
|
||||
/* Prevent images from causing layout shift */
|
||||
}
|
||||
|
||||
/* Improve rendering quality for scaled images */
|
||||
img[width][height] {
|
||||
aspect-ratio: attr(width) / attr(height);
|
||||
}
|
||||
|
||||
/* Focus visible for keyboard navigation */
|
||||
:focus-visible {
|
||||
@apply outline-none ring-2 ring-primary-400 ring-offset-2;
|
||||
}
|
||||
|
||||
/* Smooth selection highlight */
|
||||
::selection {
|
||||
@apply bg-primary-100 text-primary-900;
|
||||
}
|
||||
|
||||
/* Scrollbar (WebKit) */
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
::-webkit-scrollbar-track {
|
||||
@apply bg-secondary-100;
|
||||
}
|
||||
::-webkit-scrollbar-thumb {
|
||||
@apply bg-secondary-300 rounded-full;
|
||||
}
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
@apply bg-secondary-400;
|
||||
}
|
||||
|
||||
/* Reduced motion */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
animation-duration: 0.01ms !important;
|
||||
animation-iteration-count: 1 !important;
|
||||
transition-duration: 0.01ms !important;
|
||||
}
|
||||
html {
|
||||
scroll-behavior: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
COMPONENT CLASSES
|
||||
Reusable utility classes built on design tokens
|
||||
============================================================ */
|
||||
@layer components {
|
||||
|
||||
/* ----- Layout ----- */
|
||||
.container-wrapper {
|
||||
@apply mx-auto max-w-7xl px-4 sm:px-6 lg:px-8;
|
||||
}
|
||||
|
||||
/* ----- Buttons ----- */
|
||||
.btn-primary {
|
||||
@apply inline-flex items-center justify-center rounded-lg bg-primary px-6 py-3 font-semibold text-white transition-all hover:bg-primary-600 hover:shadow-lg hover:-translate-y-0.5 active:translate-y-0 active:shadow-none focus:outline-none focus:ring-2 focus:ring-primary-400 focus:ring-offset-2;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.btn-primary::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: radial-gradient(circle at var(--x, 50%) var(--y, 50%), rgba(255,255,255,0.2) 0%, transparent 60%);
|
||||
opacity: 0;
|
||||
transition: opacity 300ms ease;
|
||||
}
|
||||
|
||||
.btn-primary:hover::after {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
@apply inline-flex items-center justify-center rounded-lg border-2 border-secondary bg-transparent px-6 py-3 font-semibold text-secondary transition-colors hover:bg-secondary hover:text-white focus:outline-none focus:ring-2 focus:ring-secondary-400 focus:ring-offset-2;
|
||||
}
|
||||
|
||||
.btn-accent {
|
||||
@apply inline-flex items-center justify-center rounded-lg bg-accent px-6 py-3 font-semibold text-white transition-colors hover:bg-accent-600 focus:outline-none focus:ring-2 focus:ring-accent-400 focus:ring-offset-2;
|
||||
}
|
||||
|
||||
.btn-ghost {
|
||||
@apply inline-flex items-center justify-center rounded-lg border-2 border-white/30 bg-white/5 backdrop-blur-sm px-6 py-3 font-semibold text-white transition-all hover:bg-white/10 hover:border-white/50 focus:outline-none focus:ring-2 focus:ring-white/50 focus:ring-offset-2;
|
||||
}
|
||||
|
||||
.btn-primary-lg {
|
||||
@apply inline-flex items-center justify-center rounded-xl bg-gradient-to-r from-primary-500 to-primary-600 px-10 py-5 text-lg font-bold text-white transition-all hover:shadow-2xl hover:shadow-primary/50 hover:scale-105 focus:outline-none focus:ring-2 focus:ring-primary-400 focus:ring-offset-2;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.btn-primary-lg::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: radial-gradient(circle at var(--x, 50%) var(--y, 50%), rgba(255,255,255,0.2) 0%, transparent 60%);
|
||||
opacity: 0;
|
||||
transition: opacity 300ms ease;
|
||||
}
|
||||
|
||||
.btn-primary-lg:hover::after {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.btn-inverse-lg {
|
||||
@apply inline-flex items-center justify-center rounded-xl bg-white px-10 py-5 text-lg font-bold text-secondary-900 transition-all hover:shadow-2xl hover:scale-105 focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2;
|
||||
}
|
||||
|
||||
/* ----- Badges / Eyebrow Labels ----- */
|
||||
.badge {
|
||||
@apply inline-block px-4 py-2 rounded-full text-sm font-bold uppercase tracking-wider;
|
||||
}
|
||||
|
||||
.badge-primary {
|
||||
@apply badge bg-primary-50 text-primary-700;
|
||||
}
|
||||
|
||||
.badge-primary-dark {
|
||||
@apply badge bg-primary-400/20 text-primary-300;
|
||||
}
|
||||
|
||||
.badge-accent {
|
||||
@apply badge bg-accent-50 text-accent-700;
|
||||
}
|
||||
|
||||
.badge-secondary {
|
||||
@apply badge bg-secondary-100 text-secondary-700;
|
||||
}
|
||||
|
||||
/* ----- Form Elements ----- */
|
||||
.form-input {
|
||||
@apply w-full px-4 py-3 rounded-lg border border-secondary-300 focus:border-primary focus:ring-2 focus:ring-primary/20 transition-colors duration-200 text-secondary-900 placeholder-secondary-400 bg-white;
|
||||
}
|
||||
|
||||
.form-input-error {
|
||||
@apply border-red-500 focus:border-red-500 focus:ring-red-500/20;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
@apply block text-sm font-medium text-secondary-700 mb-2;
|
||||
}
|
||||
|
||||
.form-error {
|
||||
@apply mt-1 text-sm text-red-500 hidden;
|
||||
}
|
||||
|
||||
/* ----- Cards ----- */
|
||||
.card {
|
||||
@apply bg-white rounded-2xl border-2 border-secondary-100 transition-all duration-500;
|
||||
}
|
||||
|
||||
.card-hover {
|
||||
@apply card hover:border-primary/30 hover:shadow-2xl hover:-translate-y-2;
|
||||
}
|
||||
|
||||
.card-service {
|
||||
@apply bg-white rounded-3xl shadow-lg border-2 border-secondary-100 hover:border-primary-400 hover:shadow-2xl transition-all duration-500;
|
||||
}
|
||||
|
||||
.card-surface {
|
||||
@apply bg-secondary-50 rounded-xl border border-secondary-200 hover:shadow-lg transition-shadow duration-300;
|
||||
}
|
||||
|
||||
/* ----- Icon Containers ----- */
|
||||
.icon-container {
|
||||
@apply flex items-center justify-center bg-gradient-to-br from-primary-500 to-primary-600 shadow-lg;
|
||||
}
|
||||
|
||||
.icon-sm {
|
||||
@apply icon-container w-12 h-12 rounded-lg;
|
||||
}
|
||||
|
||||
.icon-md {
|
||||
@apply icon-container w-16 h-16 rounded-2xl;
|
||||
}
|
||||
|
||||
.icon-lg {
|
||||
@apply icon-container w-20 h-20 rounded-2xl;
|
||||
}
|
||||
|
||||
/* ----- Section Patterns ----- */
|
||||
.section-header {
|
||||
@apply text-center max-w-3xl mx-auto mb-20;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
@apply text-4xl sm:text-5xl font-bold text-secondary-900 mb-6;
|
||||
}
|
||||
|
||||
.section-title-inverse {
|
||||
@apply text-4xl sm:text-5xl font-bold text-white mb-6;
|
||||
}
|
||||
|
||||
.section-description {
|
||||
@apply text-xl text-secondary-600;
|
||||
}
|
||||
|
||||
.section-description-inverse {
|
||||
@apply text-xl text-secondary-300;
|
||||
}
|
||||
|
||||
/* ----- Decorative Background Blobs ----- */
|
||||
.blob {
|
||||
@apply absolute rounded-full blur-3xl pointer-events-none;
|
||||
}
|
||||
|
||||
.blob-primary {
|
||||
@apply blob bg-primary/20;
|
||||
}
|
||||
|
||||
.blob-accent {
|
||||
@apply blob bg-accent/10;
|
||||
}
|
||||
|
||||
/* ----- Dark Section Grid Overlay ----- */
|
||||
.grid-overlay {
|
||||
@apply absolute inset-0 bg-[linear-gradient(rgba(255,255,255,0.02)_1px,transparent_1px),linear-gradient(90deg,rgba(255,255,255,0.02)_1px,transparent_1px)] bg-[size:80px_80px] pointer-events-none;
|
||||
}
|
||||
|
||||
/* ----- Avatar Initials ----- */
|
||||
.avatar {
|
||||
@apply flex items-center justify-center bg-gradient-to-br from-primary-500 to-primary-600 text-white font-bold shadow-lg rounded-full;
|
||||
}
|
||||
|
||||
/* ----- Feature List Item ----- */
|
||||
.feature-item {
|
||||
@apply flex items-center text-secondary-700;
|
||||
}
|
||||
|
||||
/* ----- Gradient Text ----- */
|
||||
.gradient-text {
|
||||
@apply text-transparent bg-clip-text bg-gradient-to-r from-primary-400 via-primary-300 to-accent-400;
|
||||
}
|
||||
|
||||
.gradient-text-primary {
|
||||
@apply text-transparent bg-clip-text bg-gradient-to-r from-primary to-accent;
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
SCROLL-REVEAL & MICRO-INTERACTION ANIMATIONS
|
||||
Used with Intersection Observer for scroll-triggered effects
|
||||
============================================================ */
|
||||
|
||||
/* Base state: elements are hidden until observed */
|
||||
[data-animate] {
|
||||
opacity: 0;
|
||||
transition-property: opacity, transform;
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transition-duration: 600ms;
|
||||
will-change: opacity, transform;
|
||||
}
|
||||
|
||||
/* Animated-in state */
|
||||
[data-animate].is-visible {
|
||||
opacity: 1;
|
||||
transform: none !important;
|
||||
}
|
||||
|
||||
/* Animation variants */
|
||||
[data-animate="fade-up"] {
|
||||
transform: translateY(32px);
|
||||
}
|
||||
|
||||
[data-animate="fade-down"] {
|
||||
transform: translateY(-32px);
|
||||
}
|
||||
|
||||
[data-animate="fade-left"] {
|
||||
transform: translateX(-32px);
|
||||
}
|
||||
|
||||
[data-animate="fade-right"] {
|
||||
transform: translateX(32px);
|
||||
}
|
||||
|
||||
[data-animate="fade-in"] {
|
||||
transform: none;
|
||||
}
|
||||
|
||||
[data-animate="scale-up"] {
|
||||
transform: scale(0.92);
|
||||
}
|
||||
|
||||
[data-animate="zoom-in"] {
|
||||
transform: scale(0.85);
|
||||
transform-origin: center;
|
||||
}
|
||||
|
||||
/* Stagger delay variants */
|
||||
[data-delay="100"] { transition-delay: 100ms; }
|
||||
[data-delay="150"] { transition-delay: 150ms; }
|
||||
[data-delay="200"] { transition-delay: 200ms; }
|
||||
[data-delay="300"] { transition-delay: 300ms; }
|
||||
[data-delay="400"] { transition-delay: 400ms; }
|
||||
[data-delay="500"] { transition-delay: 500ms; }
|
||||
[data-delay="600"] { transition-delay: 600ms; }
|
||||
[data-delay="700"] { transition-delay: 700ms; }
|
||||
[data-delay="800"] { transition-delay: 800ms; }
|
||||
|
||||
/* Faster variant for subtle items */
|
||||
[data-animate][data-duration="fast"] {
|
||||
transition-duration: 400ms;
|
||||
}
|
||||
|
||||
/* Slower variant for larger elements */
|
||||
[data-animate][data-duration="slow"] {
|
||||
transition-duration: 900ms;
|
||||
}
|
||||
|
||||
/* ---- Hover micro-interactions ---- */
|
||||
|
||||
/* Magnetic button ripple effect */
|
||||
.btn-ripple {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.btn-ripple::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: radial-gradient(circle at var(--x, 50%) var(--y, 50%), rgba(255,255,255,0.25) 0%, transparent 60%);
|
||||
opacity: 0;
|
||||
transition: opacity 300ms ease;
|
||||
}
|
||||
|
||||
.btn-ripple:hover::after {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Card tilt + glow on hover */
|
||||
.card-interactive {
|
||||
transition: transform 400ms cubic-bezier(0.4, 0, 0.2, 1), box-shadow 400ms ease;
|
||||
transform-style: preserve-3d;
|
||||
}
|
||||
|
||||
.card-interactive:hover {
|
||||
transform: translateY(-6px) scale(1.01);
|
||||
box-shadow: 0 20px 40px -12px rgba(8, 145, 178, 0.2);
|
||||
}
|
||||
|
||||
/* Icon bounce on hover */
|
||||
.icon-bounce:hover svg {
|
||||
animation: icon-bounce 0.5s cubic-bezier(0.36, 0.07, 0.19, 0.97) both;
|
||||
}
|
||||
|
||||
/* Underline slide effect for links */
|
||||
.link-underline {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.link-underline::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: -2px;
|
||||
left: 0;
|
||||
width: 0;
|
||||
height: 2px;
|
||||
background: currentColor;
|
||||
transition: width 300ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.link-underline:hover::after {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Counter number pulse on enter */
|
||||
.stat-counter {
|
||||
transition: transform 200ms ease;
|
||||
}
|
||||
|
||||
.stat-counter.counting {
|
||||
animation: count-pulse 0.1s ease-out;
|
||||
}
|
||||
|
||||
/* Progress bar fill animation */
|
||||
.progress-bar {
|
||||
width: 0;
|
||||
transition: width 1.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.progress-bar.is-visible {
|
||||
width: var(--progress-width, 100%);
|
||||
}
|
||||
|
||||
/* Shimmer effect for skeleton/loading states */
|
||||
@keyframes shimmer {
|
||||
from { background-position: -200% 0; }
|
||||
to { background-position: 200% 0; }
|
||||
}
|
||||
|
||||
/* Page transition overlay */
|
||||
.page-transition-enter {
|
||||
animation: page-enter 500ms cubic-bezier(0.4, 0, 0.2, 1) forwards;
|
||||
}
|
||||
|
||||
/* Additional keyframes */
|
||||
@keyframes icon-bounce {
|
||||
0%, 100% { transform: translateY(0); }
|
||||
30% { transform: translateY(-6px); }
|
||||
60% { transform: translateY(2px); }
|
||||
}
|
||||
|
||||
@keyframes count-pulse {
|
||||
0%, 100% { transform: scale(1); }
|
||||
50% { transform: scale(1.08); }
|
||||
}
|
||||
|
||||
@keyframes page-enter {
|
||||
from { opacity: 0; transform: translateY(8px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
@keyframes draw-in {
|
||||
from { stroke-dashoffset: 100; }
|
||||
to { stroke-dashoffset: 0; }
|
||||
}
|
||||
|
||||
/* Respect reduced motion */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
[data-animate],
|
||||
[data-animate].is-visible,
|
||||
.card-interactive:hover,
|
||||
.link-underline::after,
|
||||
.btn-ripple::after,
|
||||
.progress-bar {
|
||||
transition: none !important;
|
||||
animation: none !important;
|
||||
transform: none !important;
|
||||
opacity: 1 !important;
|
||||
width: var(--progress-width, 100%) !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
UTILITY CLASSES
|
||||
One-off helpers that extend Tailwind
|
||||
============================================================ */
|
||||
@layer utilities {
|
||||
/* Consistent hero gradient backgrounds */
|
||||
.bg-hero-dark {
|
||||
@apply bg-gradient-to-br from-secondary-900 via-secondary-800 to-primary-900;
|
||||
}
|
||||
|
||||
.bg-cta-dark {
|
||||
@apply bg-gradient-to-br from-secondary-900 via-primary-900 to-primary-800;
|
||||
}
|
||||
|
||||
.bg-surface-gradient {
|
||||
@apply bg-gradient-to-b from-secondary-50 to-white;
|
||||
}
|
||||
|
||||
/* Tabular number rendering for stats/counters */
|
||||
.tabular-nums {
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
/* Line clamp utilities (supplement Tailwind's built-in) */
|
||||
.line-clamp-2 {
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
}
|
||||
|
||||
.line-clamp-3 {
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 3;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user