Files
duty-teller/webapp-next/src/app/globals.css
Nikolay Tatarinov edf0186682 feat: enhance duty timeline styling for improved visibility
- Added horizontal stripe and vertical tick indicators for today's date in the duty timeline, enhancing visual distinction.
- Updated current duty card styling to ensure the left stripe matches the "Today" label, improving consistency in the user interface.
2026-03-03 17:36:05 +03:00

314 lines
11 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

@import "tailwindcss";
@import "tw-animate-css";
@import "shadcn/tailwind.css";
@custom-variant dark (&:is([data-theme="dark"] *));
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--font-sans: system-ui, -apple-system, sans-serif;
--font-mono: ui-monospace, monospace;
--color-chart-5: var(--chart-5);
--color-chart-4: var(--chart-4);
--color-chart-3: var(--chart-3);
--color-chart-2: var(--chart-2);
--color-chart-1: var(--chart-1);
--color-ring: var(--ring);
--color-input: var(--input);
--color-border: var(--border);
--color-destructive: var(--destructive);
--color-accent-foreground: var(--accent-foreground);
--color-accent: var(--accent);
--color-muted-foreground: var(--muted-foreground);
--color-muted: var(--muted);
--color-secondary-foreground: var(--secondary-foreground);
--color-secondary: var(--secondary);
--color-primary-foreground: var(--primary-foreground);
--color-primary: var(--primary);
--color-popover-foreground: var(--popover-foreground);
--color-popover: var(--popover);
--color-card-foreground: var(--card-foreground);
--color-card: var(--card);
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px);
--radius-2xl: calc(var(--radius) + 8px);
--radius-3xl: calc(var(--radius) + 12px);
--radius-4xl: calc(var(--radius) + 16px);
/* App design tokens (Telegram Mini App) */
--color-surface: var(--surface);
--color-duty: var(--duty);
--color-today: var(--today);
--color-unavailable: var(--unavailable);
--color-vacation: var(--vacation);
--color-error: var(--error);
--max-width-app: 420px;
}
/* App design tokens: use Telegram theme vars with dark fallbacks so TG vars apply before data-theme */
:root {
--bg: var(--tg-theme-bg-color, #17212b);
--surface: var(--tg-theme-secondary-bg-color, #232e3c);
--text: var(--tg-theme-text-color, #f5f5f5);
--muted: var(--tg-theme-hint-color, var(--tg-theme-subtitle-text-color, #708499));
--accent: var(--tg-theme-link-color, #6ab3f3);
--header-bg: var(--tg-theme-header-bg-color, #232e3c);
--card: var(--tg-theme-section-bg-color, var(--surface));
--section-header: var(--tg-theme-section-header-text-color, #f5f5f5);
--border: var(--tg-theme-section-separator-color, color-mix(in srgb, var(--text) 10%, transparent));
--primary: var(--tg-theme-button-color, var(--accent));
--primary-foreground: var(--tg-theme-button-text-color, #17212b);
--error: var(--tg-theme-destructive-text-color, #e06c75);
--accent-text: var(--tg-theme-accent-text-color, #6ab2f2);
--duty: #5c9b4a;
--today: var(--tg-theme-accent-text-color, var(--tg-theme-link-color, #6ab2f2));
--unavailable: #b8860b;
--vacation: #5a9bb8;
--timeline-date-width: 3.6em;
--timeline-track-width: 10px;
/* Reusable color-mix tokens (avoid repeating in Tailwind classes). */
--surface-hover: color-mix(in srgb, var(--accent) 15%, var(--surface));
--surface-hover-10: color-mix(in srgb, var(--accent) 10%, var(--surface));
--surface-today-tint: color-mix(in srgb, var(--today) 12%, var(--surface));
--surface-muted-tint: color-mix(in srgb, var(--muted) 8%, var(--surface));
--today-hover: color-mix(in srgb, var(--bg) 15%, var(--today));
--today-border: color-mix(in srgb, var(--today) 35%, transparent);
--today-border-selected: color-mix(in srgb, var(--bg) 50%, transparent);
--today-gradient-end: color-mix(in srgb, var(--today) 15%, transparent);
--muted-fade: color-mix(in srgb, var(--muted) 40%, transparent);
--handle-bg: color-mix(in srgb, var(--muted) 80%, var(--text));
--indicator-today-duty: color-mix(in srgb, var(--duty) 65%, var(--bg));
--indicator-today-unavailable: color-mix(in srgb, var(--unavailable) 65%, var(--bg));
--indicator-today-vacation: color-mix(in srgb, var(--vacation) 65%, var(--bg));
--indicator-today-events: color-mix(in srgb, var(--accent) 65%, var(--bg));
--shadow-card: 0 4px 12px color-mix(in srgb, var(--text) 12%, transparent);
--transition-fast: 0.15s;
--transition-normal: 0.25s;
--ease-out: cubic-bezier(0.32, 0.72, 0, 1);
--radius: 0.625rem;
--calendar-block-min-height: 260px;
/** Minimum height for the 6-row calendar grid so cells stay comfortably large. */
--calendar-grid-min-height: 264px;
/** Minimum height per calendar row (6 rows × 44px ≈ 264px). */
--calendar-row-min-height: 2.75rem;
/* Align Tailwind/shadcn semantic tokens with app tokens for Mini App */
--background: var(--bg);
--foreground: var(--text);
--card-foreground: var(--text);
--popover: var(--surface);
--popover-foreground: var(--text);
--secondary: var(--surface);
--secondary-foreground: var(--text);
--muted-foreground: var(--muted);
--accent-foreground: var(--bg);
--destructive: var(--error);
--input: color-mix(in srgb, var(--text) 15%, transparent);
--ring: var(--accent);
--chart-1: var(--duty);
--chart-2: var(--vacation);
--chart-3: var(--unavailable);
--chart-4: var(--today);
--chart-5: var(--accent);
}
/* Light theme: full Telegram themeParams (14 params) mapping */
[data-theme="light"] {
--bg: var(--tg-theme-bg-color, #f0f1f3);
--surface: var(--tg-theme-secondary-bg-color, #e0e2e6);
--text: var(--tg-theme-text-color, #343b58);
--muted: var(--tg-theme-hint-color, var(--tg-theme-subtitle-text-color, #6b7089));
--accent: var(--tg-theme-link-color, #2e7de0);
--header-bg: var(--tg-theme-header-bg-color, #e0e2e6);
--card: var(--tg-theme-section-bg-color, #e0e2e6);
--section-header: var(--tg-theme-section-header-text-color, #343b58);
--border: var(--tg-theme-section-separator-color, color-mix(in srgb, var(--text) 15%, transparent));
--primary: var(--tg-theme-button-color, #2e7de0);
--primary-foreground: var(--tg-theme-button-text-color, #ffffff);
--error: var(--tg-theme-destructive-text-color, #c43b3b);
--accent-text: var(--tg-theme-accent-text-color, #2481cc);
--duty: #587d0a;
--today: var(--tg-theme-accent-text-color, var(--tg-theme-link-color, #2481cc));
--unavailable: #b8860b;
--vacation: #0d6b9e;
}
/* Dark theme: full Telegram themeParams (14 params) mapping */
[data-theme="dark"] {
--bg: var(--tg-theme-bg-color, #17212b);
--surface: var(--tg-theme-secondary-bg-color, #232e3c);
--text: var(--tg-theme-text-color, #f5f5f5);
--muted: var(--tg-theme-hint-color, var(--tg-theme-subtitle-text-color, #708499));
--accent: var(--tg-theme-link-color, #6ab3f3);
--header-bg: var(--tg-theme-header-bg-color, #232e3c);
--card: var(--tg-theme-section-bg-color, #232e3c);
--section-header: var(--tg-theme-section-header-text-color, #f5f5f5);
--border: var(--tg-theme-section-separator-color, color-mix(in srgb, var(--text) 10%, transparent));
--primary: var(--tg-theme-button-color, #6ab3f3);
--primary-foreground: var(--tg-theme-button-text-color, #17212b);
--error: var(--tg-theme-destructive-text-color, #e06c75);
--accent-text: var(--tg-theme-accent-text-color, #6ab2f2);
--duty: #5c9b4a;
--today: var(--tg-theme-accent-text-color, var(--tg-theme-link-color, #6ab2f2));
--unavailable: #b8860b;
--vacation: #5a9bb8;
}
/* === Layout & base (ported from webapp/css/base.css) */
html {
scrollbar-gutter: stable;
scrollbar-width: none;
-ms-overflow-style: none;
overscroll-behavior: none;
}
html::-webkit-scrollbar {
display: none;
}
/* Container: max-width, padding, safe area. Use .container for main wrapper if needed. */
.container-app {
max-width: var(--max-width-app, 420px);
margin-left: auto;
margin-right: auto;
padding: 12px;
padding-top: 0;
padding-bottom: env(safe-area-inset-bottom, 12px);
border-radius: 12px;
}
/* Duty list: timeline date cell (non-today) — horizontal line and vertical tick to track */
.duty-timeline-date:not(.duty-timeline-date--today)::before {
content: "";
position: absolute;
left: 0;
bottom: 4px;
width: calc(100% + var(--timeline-track-width) / 2);
height: 2px;
background: linear-gradient(
to right,
var(--muted-fade) 0%,
var(--muted-fade) 50%,
var(--muted) 70%,
var(--muted) 100%
);
}
.duty-timeline-date:not(.duty-timeline-date--today)::after {
content: "";
position: absolute;
left: calc(100% + (var(--timeline-track-width) / 2) - 1px);
bottom: 2px;
width: 2px;
height: 6px;
background: var(--muted);
}
/* Duty list: timeline date cell (today) — horizontal stripe + vertical tick in today color (same geometry as non-today) */
.duty-timeline-date--today::before {
content: "";
position: absolute;
left: 0;
bottom: 5px;
width: calc(100% + var(--timeline-track-width) / 2);
height: 1px;
background: var(--today);
}
.duty-timeline-date--today::after {
content: "";
position: absolute;
left: calc(100% + (var(--timeline-track-width) / 2) - 1px);
bottom: 2px;
width: 2px;
height: 7px;
background: var(--today);
}
/* Duty list: current duty card — ensure left stripe uses --today (matches "Today" label and date stripe) */
[data-current-duty] .border-l-today {
border-left-color: var(--today);
border-left-width: 3px;
}
/* Duty list: flip card (front = duty info, back = contacts) */
.duty-flip-card {
perspective: 600px;
}
.duty-flip-inner {
transform-style: preserve-3d;
}
.duty-flip-front {
backface-visibility: hidden;
-webkit-backface-visibility: hidden;
}
.duty-flip-back {
backface-visibility: hidden;
-webkit-backface-visibility: hidden;
position: absolute;
inset: 0;
transform: rotateY(180deg);
}
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
/* Safe area for Telegram Mini App (notch / status bar). */
.pt-safe {
padding-top: env(safe-area-inset-top, 0);
}
/* Sticky calendar header: shadow when scrolled (useStickyScroll). */
.sticky.is-scrolled {
box-shadow: 0 1px 0 0 var(--border);
}
/* Calendar grid: 6 rows with minimum height so cells stay large (restore pre-audit look). */
.calendar-grid {
grid-template-rows: repeat(6, minmax(var(--calendar-row-min-height), 1fr));
}
/* Current duty card: entrance animation (respects prefers-reduced-motion via global rule). */
@keyframes card-appear {
from {
opacity: 0;
transform: translateY(16px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.current-duty-card {
box-shadow: var(--shadow-card);
animation: card-appear 0.3s var(--ease-out);
}
.current-duty-card--no-duty {
border-top-color: var(--muted);
}
@layer base {
* {
box-sizing: border-box;
@apply border-border outline-ring/50;
}
body {
margin: 0;
padding: 0;
min-height: 100vh;
background: var(--bg);
color: var(--text);
font-family: system-ui, -apple-system, sans-serif;
-webkit-tap-highlight-color: transparent;
}
}