- 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.
314 lines
11 KiB
CSS
314 lines
11 KiB
CSS
@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;
|
||
}
|
||
} |