EcoTracker-II / frontend /src /index.css
Akash-Dragon's picture
feat: build React/Vite frontend client with TailwindCSS
687ebbb
Raw
History Blame Contribute Delete
13.8 kB
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Syne:wght@600;700;800&display=swap');
@tailwind base;
@tailwind components;
@tailwind utilities;
/* ── Skip Navigation Link (Accessibility) ───────────────────────── */
.skip-link {
position: absolute;
top: -100%;
left: 1rem;
z-index: 9999;
padding: 0.5rem 1rem;
background: #10b981;
color: #000;
font-weight: 600;
border-radius: 0 0 0.5rem 0.5rem;
text-decoration: none;
transition: top 0.2s;
}
.skip-link:focus {
top: 0;
}
@layer base {
:root {
--color-bg: #040815;
--color-surface: #0b1123;
--color-surface-2: #141c33;
--color-surface-3: #1e284a;
--color-border: rgba(255, 255, 255, 0.06);
--color-border-strong: rgba(255, 255, 255, 0.14);
--color-text: #f8fafc;
--color-text-muted: #94a3b8;
--color-text-faint: #475569;
--color-accent: #10b981;
--color-accent-dim: rgba(16, 185, 129, 0.1);
/* score colors */
--color-good: #10b981;
--color-warn: #f59e0b;
--color-danger: #ef4444;
}
* {
border-color: var(--color-border);
box-sizing: border-box;
}
html {
scroll-behavior: smooth;
font-size: 16px;
}
body {
font-family:
'Inter',
system-ui,
-apple-system,
sans-serif;
background-color: var(--color-bg);
color: var(--color-text);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
min-height: 100vh;
}
h1,
h2,
h3 {
font-family: 'Syne', 'Inter', sans-serif;
letter-spacing: -0.03em;
line-height: 1.1;
}
::-webkit-scrollbar {
width: 4px;
height: 4px;
}
::-webkit-scrollbar-track {
background: #000;
}
::-webkit-scrollbar-thumb {
background: #333;
border-radius: 2px;
}
::-webkit-scrollbar-thumb:hover {
background: #555;
}
input[type='number']::-webkit-outer-spin-button,
input[type='number']::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
input[type='number'] {
-moz-appearance: textfield;
}
}
@layer components {
/* ── Cards ── */
.glass-card {
background: var(--color-surface);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 1rem;
}
.glass-card-hover {
@apply glass-card transition-all duration-300 cursor-pointer;
}
.glass-card-hover:hover {
background: var(--color-surface-2);
border-color: rgba(255, 255, 255, 0.2);
transform: translateY(-2px);
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.8);
}
/* ── Typography ── */
.gradient-text {
background: linear-gradient(135deg, #10b981 0%, #06b6d4 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.gradient-text-warm {
background: linear-gradient(135deg, #f59e0b 0%, #ef4444 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
/* ── Glow ── */
.glow-eco {
box-shadow:
0 0 30px rgba(255, 255, 255, 0.1),
0 0 60px rgba(255, 255, 255, 0.04);
}
.glow-blue {
box-shadow: 0 0 30px rgba(255, 255, 255, 0.08);
}
/* ── Buttons ── */
.btn-primary {
@apply relative overflow-hidden inline-flex items-center justify-center gap-2;
@apply px-6 py-3 rounded-xl font-semibold transition-all duration-200;
background: linear-gradient(135deg, #10b981 0%, #059669 100%);
color: #ffffff;
font-size: 0.9375rem;
box-shadow: 0 4px 20px rgba(16, 185, 129, 0.25);
}
.btn-primary::after {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(135deg, rgba(255, 255, 255, 0.15), transparent);
opacity: 0;
transition: opacity 0.2s;
border-radius: inherit;
}
.btn-primary:hover::after {
opacity: 1;
}
.btn-primary:hover {
transform: translateY(-1px);
box-shadow: 0 8px 30px rgba(16, 185, 129, 0.45);
}
.btn-primary:active {
transform: translateY(0);
}
.btn-secondary {
@apply inline-flex items-center justify-center gap-2 px-6 py-3 rounded-xl font-semibold transition-all duration-200;
background: transparent;
border: 1px solid rgba(255, 255, 255, 0.15);
color: #ffffff;
font-size: 0.9375rem;
}
.btn-secondary:hover {
background: rgba(255, 255, 255, 0.06);
border-color: rgba(255, 255, 255, 0.35);
}
/* ── Form inputs ── */
.input-field {
@apply w-full rounded-xl px-4 py-3 transition-all duration-200 focus:outline-none;
background: var(--color-surface-2);
border: 1px solid rgba(255, 255, 255, 0.08);
color: #ffffff;
font-size: 0.9375rem;
}
.input-field:hover {
border-color: rgba(255, 255, 255, 0.15);
}
.input-field:focus {
background: var(--color-surface-3);
border-color: rgba(255, 255, 255, 0.4);
box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.05);
}
.input-field::placeholder {
color: rgba(255, 255, 255, 0.2);
}
.select-field {
@apply input-field cursor-pointer;
appearance: none;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23888' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: right 14px center;
padding-right: 42px;
}
.select-field option {
background: #111;
color: #fff;
}
.form-label {
@apply block text-sm font-medium mb-2;
color: #888;
letter-spacing: 0.01em;
}
/* ── Badges ── */
.eco-badge {
@apply inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-xs font-semibold;
background: rgba(255, 255, 255, 0.06);
border: 1px solid rgba(255, 255, 255, 0.15);
color: #ffffff;
letter-spacing: 0.05em;
text-transform: uppercase;
}
.badge-high {
@apply inline-flex items-center gap-1 px-2.5 py-0.5 rounded-full text-xs font-semibold;
background: rgba(255, 255, 255, 0.08);
border: 1px solid rgba(255, 255, 255, 0.15);
color: #ffffff;
}
.badge-medium {
@apply inline-flex items-center gap-1 px-2.5 py-0.5 rounded-full text-xs font-semibold;
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
color: #bbbbbb;
}
.badge-low {
@apply inline-flex items-center gap-1 px-2.5 py-0.5 rounded-full text-xs font-semibold;
background: rgba(255, 255, 255, 0.03);
border: 1px solid rgba(255, 255, 255, 0.08);
color: #777777;
}
/* ── Stat ── */
.stat-number {
@apply text-3xl font-bold;
font-family: 'Syne', sans-serif;
color: #ffffff;
}
/* ── Skeleton ── */
.skeleton {
background: linear-gradient(
90deg,
rgba(255, 255, 255, 0.03) 25%,
rgba(255, 255, 255, 0.07) 50%,
rgba(255, 255, 255, 0.03) 75%
);
background-size: 200% 100%;
animation: shimmer 1.8s ease-in-out infinite;
border-radius: 0.5rem;
}
/* ── Divider ── */
.section-divider {
height: 1px;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.1), transparent);
margin: 1.75rem 0;
}
/* ── Progress ── */
.progress-bar {
@apply h-1.5 rounded-full overflow-hidden;
background: rgba(255, 255, 255, 0.06);
}
.progress-bar-fill {
@apply h-full rounded-full transition-all duration-700 ease-out;
background: #ffffff;
}
/* ── Step indicator ── */
.step-active {
background: #ffffff;
box-shadow: 0 0 20px rgba(255, 255, 255, 0.25);
}
.step-complete {
background: rgba(255, 255, 255, 0.12);
border: 1px solid rgba(255, 255, 255, 0.3);
}
.step-inactive {
background: transparent;
border: 1px solid rgba(255, 255, 255, 0.1);
}
/* ── Nav ── */
.nav-link-active {
color: #ffffff;
background: rgba(255, 255, 255, 0.08);
border: 1px solid rgba(255, 255, 255, 0.15);
}
.nav-link {
color: #666666;
background: transparent;
border: 1px solid transparent;
transition: all 0.2s;
}
.nav-link:hover {
color: #ffffff;
background: rgba(255, 255, 255, 0.04);
}
/* ── Animated underline ── */
.animated-underline {
position: relative;
}
.animated-underline::after {
content: '';
position: absolute;
bottom: -2px;
left: 0;
width: 0;
height: 1px;
background: #ffffff;
transition: width 0.3s ease;
}
.animated-underline:hover::after {
width: 100%;
}
/* ── Ticker / animated number ── */
.ticker {
font-family: 'Syne', monospace;
font-variant-numeric: tabular-nums;
transition: all 0.6s ease;
}
/* ── Dynamic scan line ── */
.scan-line {
position: relative;
overflow: hidden;
}
.scan-line::before {
content: '';
position: absolute;
top: -100%;
left: 0;
right: 0;
height: 100%;
background: linear-gradient(
180deg,
transparent 0%,
rgba(255, 255, 255, 0.03) 50%,
transparent 100%
);
animation: scan 4s ease-in-out infinite;
}
@keyframes scan {
0% {
top: -100%;
}
100% {
top: 200%;
}
}
/* ── Blinking cursor ── */
.cursor-blink::after {
content: '|';
animation: blink 1s step-end infinite;
color: #ffffff;
margin-left: 2px;
}
@keyframes blink {
0%,
100% {
opacity: 1;
}
50% {
opacity: 0;
}
}
/* ── Animated border ── */
.animated-border {
position: relative;
}
.animated-border::before {
content: '';
position: absolute;
inset: -1px;
border-radius: inherit;
padding: 1px;
background: linear-gradient(
135deg,
rgba(255, 255, 255, 0.3),
transparent,
rgba(255, 255, 255, 0.1)
);
background-size: 200% 200%;
animation: borderRotate 4s linear infinite;
-webkit-mask:
linear-gradient(#fff 0 0) content-box,
linear-gradient(#fff 0 0);
-webkit-mask-composite: xor;
mask-composite: exclude;
opacity: 0;
transition: opacity 0.3s;
}
.animated-border:hover::before {
opacity: 1;
}
}
/* ── Keyframes ── */
@keyframes shimmer {
0% {
background-position: -200% 0;
}
100% {
background-position: 200% 0;
}
}
@keyframes borderRotate {
0% {
background-position: 0% 50%;
}
100% {
background-position: 200% 50%;
}
}
@keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes slide-up {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes slide-right {
from {
opacity: 0;
transform: translateX(-12px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes float {
0%,
100% {
transform: translateY(0px);
}
50% {
transform: translateY(-10px);
}
}
@keyframes pulse-slow {
0%,
100% {
opacity: 0.3;
}
50% {
opacity: 0.6;
}
}
@keyframes count-up {
from {
opacity: 0;
transform: translateY(8px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes expand-width {
from {
width: 0;
}
to {
width: var(--target-width, 100%);
}
}
.animate-fade-in {
animation: fade-in 0.4s ease-out forwards;
}
.animate-slide-up {
animation: slide-up 0.45s ease-out forwards;
}
.animate-slide-right {
animation: slide-right 0.4s ease-out forwards;
}
.animate-float {
animation: float 5s ease-in-out infinite;
}
.animate-pulse-slow {
animation: pulse-slow 3s ease-in-out infinite;
}
.animate-spin {
animation: spin 0.8s linear infinite;
}
.animate-count {
animation: count-up 0.5s ease-out forwards;
}
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
/* ── Recharts overrides ── */
.recharts-tooltip-wrapper .recharts-default-tooltip {
background: #111111 !important;
border: 1px solid rgba(255, 255, 255, 0.15) !important;
border-radius: 12px !important;
}
.recharts-default-tooltip .recharts-tooltip-label {
color: #888 !important;
font-size: 12px !important;
}
/* ── Focus rings ── */
*:focus-visible {
outline: 1px solid rgba(255, 255, 255, 0.5);
outline-offset: 2px;
border-radius: 6px;
}
/* ── Range input ── */
input[type='range'] {
-webkit-appearance: none;
height: 4px;
border-radius: 2px;
background: rgba(255, 255, 255, 0.08);
outline: none;
}
input[type='range']::-webkit-slider-thumb {
-webkit-appearance: none;
width: 16px;
height: 16px;
border-radius: 50%;
background: #ffffff;
cursor: pointer;
box-shadow: 0 0 8px rgba(255, 255, 255, 0.3);
transition: box-shadow 0.2s;
}
input[type='range']::-webkit-slider-thumb:hover {
box-shadow: 0 0 16px rgba(255, 255, 255, 0.5);
}
/* ── Dynamic grid bg ── */
.grid-bg {
background-image:
linear-gradient(rgba(255, 255, 255, 0.03) 1px, transparent 1px),
linear-gradient(90deg, rgba(255, 255, 255, 0.03) 1px, transparent 1px);
background-size: 48px 48px;
}
/* ── Progress fill (moved from inline dangerouslySetInnerHTML) ── */
@keyframes progressFill {
from {
width: 0%;
}
to {
width: 98%;
}
}
/* ── Accessibility: prefers-reduced-motion ── */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-delay: -1ms !important;
animation-duration: 1ms !important;
animation-iteration-count: 1 !important;
background-attachment: initial !important;
scroll-behavior: auto !important;
transition-duration: 0s !important;
transition-delay: 0s !important;
}
}