libra/resources/css/app.css

878 lines
23 KiB
CSS

/* Google Fonts - Cairo (Arabic) and Montserrat (English) */
@import url('https://fonts.googleapis.com/css2?family=Cairo:wght@300;400;600;700&family=Montserrat:wght@300;400;600;700&display=swap');
@import 'tailwindcss';
@import '../../vendor/livewire/flux/dist/flux.css';
@source '../views';
@source '../../vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php';
@source '../../vendor/livewire/flux-pro/stubs/**/*.blade.php';
@source '../../vendor/livewire/flux/stubs/**/*.blade.php';
@custom-variant dark (&:where(.dark, .dark *));
@theme {
/* Font definitions - to be updated in typography story */
--font-sans: 'Instrument Sans', ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
--font-arabic: 'Cairo', 'Tajawal', ui-sans-serif, system-ui, sans-serif;
--font-english: 'Montserrat', 'Lato', ui-sans-serif, system-ui, sans-serif;
/* Font Size Scale */
--font-size-xs: 0.75rem; /* 12px */
--font-size-sm: 0.875rem; /* 14px - Small text */
--font-size-base: 1rem; /* 16px - Body text */
--font-size-lg: 1.125rem; /* 18px */
--font-size-xl: 1.25rem; /* 20px */
--font-size-2xl: 1.5rem; /* 24px - H3 */
--font-size-3xl: 2rem; /* 32px - H2 */
--font-size-4xl: 2.5rem; /* 40px - H1 */
/* ==========================================================================
LIBRA Brand Palette - Olive Green (Story 12.2)
========================================================================== */
/* Primary Olive Green Palette */
--color-primary: #8AB357; /* Olive Green - primary brand color */
--color-primary-hover: #7AA347; /* Darker Olive - hover states */
--color-primary-dark: #6A9337; /* Dark Olive - active/pressed states */
--color-primary-light: #B5D88A; /* Bright Olive - highlights */
/* Secondary/Accent Colors */
--color-accent: #A5C87A; /* Light Olive - secondary accent */
--color-accent-light: #C5D9A5; /* Pale Olive - subtle backgrounds */
/* Neutrals (unchanged) */
--color-background: #E8E4DC; /* Off-White - light backgrounds */
--color-body: #1A1A1A; /* Deep Black - body text color */
/* Semantic Aliases - used by components */
--color-accent-content: #A5C87A; /* Light Olive */
--color-accent-foreground: #1A1A1A; /* Deep Black - text on accent backgrounds */
/* Brand Color Aliases (used in blade templates) */
--color-off-white: #E8E4DC; /* Off-White */
--color-warm-gray: var(--color-accent); /* Maps to Light Olive */
/* Backward Compatibility Aliases (legacy class names) */
--color-navy: var(--color-primary); /* Maps to Olive Green */
--color-gold: var(--color-accent); /* Maps to Light Olive */
--color-gold-light: var(--color-accent-light); /* Maps to Pale Olive */
--color-cream: var(--color-background); /* Maps to Off-White */
--color-charcoal: var(--color-primary); /* Maps to Olive Green */
/* Status Colors - unchanged per AC7 */
--color-success: #27AE60;
--color-danger: #E74C3C;
--color-warning: #F39C12;
}
@layer theme {
.dark {
--color-accent: var(--color-white);
--color-accent-content: var(--color-white);
--color-accent-foreground: var(--color-neutral-800);
}
}
@layer base {
*,
::after,
::before,
::backdrop,
::file-selector-button {
border-color: var(--color-gray-200, currentColor);
}
}
/* ==========================================================================
Logo Badge Styling (Story 12.2)
Creates "seal/stamp" effect for logo on olive green backgrounds
========================================================================== */
.logo-badge {
border: 2px solid var(--color-body);
box-shadow: 4px 4px 6px rgba(26, 26, 26, 0.5);
}
/* ==========================================================================
Flux UI Form Component Styling (Story 9.5)
========================================================================== */
/* Field wrapper - grid layout with gap */
[data-flux-field]:not(ui-radio, ui-checkbox) {
@apply grid gap-2;
}
/* Label styling - semibold weight per specs */
[data-flux-label] {
@apply !mb-0 !leading-tight font-semibold text-body;
}
/* Input, Textarea, Select base styling */
input[data-flux-control],
textarea[data-flux-control],
[data-flux-control] input,
select[data-flux-control],
[data-flux-select-button] {
@apply border-body/30 rounded-md transition-colors text-body;
}
/* Focus states - Warm Gray border with subtle ring */
input:focus[data-flux-control],
textarea:focus[data-flux-control],
select:focus[data-flux-control],
[data-flux-control] input:focus,
[data-flux-select-button]:focus {
@apply outline-hidden border-accent ring-2 ring-accent/20;
}
/* Textarea minimum height */
textarea[data-flux-control] {
@apply min-h-[120px] resize-y;
}
/* Checkbox styling - Light Olive accent when checked */
[data-flux-checkbox] input[type="checkbox"],
input[type="checkbox"][data-flux-control] {
@apply w-5 h-5 rounded border-body/30 text-accent focus:ring-accent focus:ring-offset-0;
}
/* Radio styling - Light Olive accent when selected */
[data-flux-radio] input[type="radio"],
input[type="radio"][data-flux-control] {
@apply w-5 h-5 border-body/30 text-accent focus:ring-accent focus:ring-offset-0;
}
/* Error state styling for Flux fields */
[data-flux-field]:has([data-flux-error]) input[data-flux-control],
[data-flux-field]:has([data-flux-error]) textarea[data-flux-control],
[data-flux-field]:has([data-flux-error]) select[data-flux-control],
[data-flux-field]:has([data-flux-error]) [data-flux-select-button] {
@apply border-danger;
}
[data-flux-field]:has([data-flux-error]) input:focus[data-flux-control],
[data-flux-field]:has([data-flux-error]) textarea:focus[data-flux-control],
[data-flux-field]:has([data-flux-error]) select:focus[data-flux-control],
[data-flux-field]:has([data-flux-error]) [data-flux-select-button]:focus {
@apply border-danger ring-danger/20;
}
/* Error message styling */
[data-flux-error] {
@apply text-sm text-danger mt-1;
}
/* RTL support for Flux components */
[dir="rtl"] [data-flux-label] {
@apply text-right;
}
[dir="rtl"] [data-flux-error] {
@apply text-right;
}
[dir="rtl"] input[data-flux-control],
[dir="rtl"] textarea[data-flux-control],
[dir="rtl"] select[data-flux-control] {
@apply text-right;
}
/* \[:where(&)\]:size-4 {
@apply size-4;
} */
/* Prose Brand styling for blog posts - Olive Green palette (Story 12.2) */
.prose-brand {
--tw-prose-headings: var(--color-body); /* Deep Black */
--tw-prose-links: var(--color-primary); /* Olive Green */
--tw-prose-bold: var(--color-body); /* Deep Black */
--tw-prose-body: var(--color-body); /* Deep Black */
}
.prose-brand a {
text-decoration: underline;
}
.prose-brand a:hover {
color: var(--color-primary-hover); /* Darker Olive */
}
/* Backward compatibility alias for prose-navy */
.prose-navy {
--tw-prose-headings: var(--color-body);
--tw-prose-links: var(--color-primary);
--tw-prose-bold: var(--color-body);
--tw-prose-body: var(--color-body);
}
.prose-navy a {
text-decoration: underline;
}
.prose-navy a:hover {
color: var(--color-primary-hover);
}
/* Dynamic Font Selection based on language */
html[lang="ar"] body {
font-family: var(--font-arabic);
}
html[lang="en"] body {
font-family: var(--font-english);
}
/* Typography Base Styles */
body {
font-size: var(--font-size-base);
line-height: 1.6;
}
h1, h2, h3, h4, h5, h6 {
line-height: 1.3;
}
h1 {
font-size: var(--font-size-4xl);
font-weight: 700;
}
h2 {
font-size: var(--font-size-3xl);
font-weight: 600;
}
h3 {
font-size: var(--font-size-2xl);
font-weight: 600;
}
small, .text-sm {
font-size: var(--font-size-sm);
}
/* ==========================================================================
Button Styling System (Story 9.4)
========================================================================== */
/* Primary button - Olive Green background with Off-White text */
.btn-primary {
@apply bg-primary text-off-white rounded-md px-6 py-3 font-semibold transition-colors;
@apply hover:bg-primary-hover;
@apply focus:outline-none focus:ring-2 focus:ring-accent focus:ring-offset-2;
}
/* Secondary button - Outlined with Light Olive border, Deep Black text */
.btn-secondary {
@apply bg-transparent border-2 border-accent text-body rounded-md px-6 py-3 font-semibold transition-colors;
@apply hover:bg-accent hover:text-body;
@apply focus:outline-none focus:ring-2 focus:ring-accent focus:ring-offset-2;
}
/* Danger button - Red background */
.btn-danger {
@apply bg-danger text-white rounded-md px-6 py-3 font-semibold transition-colors;
@apply hover:bg-danger/90;
@apply focus:outline-none focus:ring-2 focus:ring-danger focus:ring-offset-2;
}
/* Disabled state - applies to all button variants */
.btn-disabled,
.btn-primary:disabled,
.btn-secondary:disabled,
.btn-danger:disabled,
button.btn-primary:disabled,
button.btn-secondary:disabled,
button.btn-danger:disabled {
@apply !bg-[#CCCCCC] !text-[#666666] !cursor-not-allowed !border-transparent;
@apply hover:!bg-[#CCCCCC];
}
/* Size variants */
.btn-sm {
@apply px-4 py-2 text-sm;
}
.btn-lg {
@apply px-8 py-4 text-lg;
}
/* Full width for mobile */
.btn-full {
@apply w-full;
}
/* Loading state */
.btn-loading {
@apply relative pointer-events-none opacity-75;
}
/* Icon spacing within buttons */
.btn-icon-left {
@apply flex items-center gap-2;
}
.btn-icon-right {
@apply flex items-center gap-2 flex-row-reverse;
}
/* Button groups - adjust border-radius for grouped buttons */
.btn-group {
@apply flex;
}
.btn-group > .btn-primary:not(:first-child):not(:last-child),
.btn-group > .btn-secondary:not(:first-child):not(:last-child),
.btn-group > .btn-danger:not(:first-child):not(:last-child) {
@apply rounded-none;
}
.btn-group > .btn-primary:first-child,
.btn-group > .btn-secondary:first-child,
.btn-group > .btn-danger:first-child {
@apply rounded-e-none;
}
.btn-group > .btn-primary:last-child,
.btn-group > .btn-secondary:last-child,
.btn-group > .btn-danger:last-child {
@apply rounded-s-none;
}
/* RTL support for icon buttons */
[dir="rtl"] .btn-icon-left {
@apply flex-row-reverse;
}
[dir="rtl"] .btn-icon-right {
@apply flex-row;
}
/* ==========================================================================
Form Styling System (Story 9.5)
========================================================================== */
/* Input field styling */
.input-field {
@apply w-full border border-body/30 rounded-md px-4 py-3
focus:border-accent focus:ring-2 focus:ring-accent/20
transition-colors outline-none bg-white;
}
/* Input error state */
.input-error {
@apply border-danger focus:border-danger focus:ring-danger/20;
}
/* Form label styling */
.form-label {
@apply block text-sm font-semibold text-body mb-2;
}
/* Required field indicator - for manual class usage */
.form-label-required::after {
content: ' *';
@apply text-danger;
}
/* Required indicator styling for Flux labels with .required class */
[data-flux-label].required::after {
content: ' *';
@apply text-danger;
}
/* Error message styling */
.error-message {
@apply text-sm text-danger mt-1;
}
/* Textarea specific styling */
.textarea-field {
@apply w-full border border-body/30 rounded-md px-4 py-3
focus:border-accent focus:ring-2 focus:ring-accent/20
transition-colors outline-none bg-white
min-h-[120px] resize-y;
}
/* Select dropdown styling */
.select-field {
@apply w-full border border-body/30 rounded-md px-4 py-3
focus:border-accent focus:ring-2 focus:ring-accent/20
transition-colors outline-none bg-white;
}
/* Custom checkbox styling */
.checkbox-custom {
@apply w-5 h-5 rounded border-body/30 text-accent
focus:ring-accent focus:ring-offset-0;
}
/* Custom radio styling */
.radio-custom {
@apply w-5 h-5 border-body/30 text-accent
focus:ring-accent focus:ring-offset-0;
}
/* Checkbox/Radio with error state */
.checkbox-error,
.radio-error {
@apply border-danger;
}
/* RTL support for form labels */
[dir="rtl"] .form-label {
@apply text-right;
}
/* RTL support for error messages */
[dir="rtl"] .error-message {
@apply text-right;
}
/* RTL support for form fields - use logical properties */
[dir="rtl"] .input-field,
[dir="rtl"] .textarea-field,
[dir="rtl"] .select-field {
@apply text-right;
}
/* ==========================================================================
Card & Container Styling System (Story 9.6)
========================================================================== */
/* Container max-width - 1200px centered */
.container-max {
@apply max-w-[1200px] mx-auto px-4 sm:px-6 lg:px-8;
}
/* Card shadow values */
.shadow-card {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.shadow-card-hover {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
/* ==========================================================================
RTL/LTR Layout Utilities (Story 9.8)
========================================================================== */
/* RTL-aware icon flipping - use on directional icons like chevrons, arrows */
[dir="rtl"] .flip-rtl {
transform: scaleX(-1);
}
/* Force LTR for numbers, emails, code, and other content that should stay LTR */
.ltr-content {
direction: ltr;
unicode-bidi: embed;
text-align: inherit;
}
/* Inline LTR content within RTL text flow */
.ltr-inline {
direction: ltr;
unicode-bidi: isolate;
}
/* ==========================================================================
Responsive Design System (Story 9.9)
Breakpoints per PRD Section 7.4:
- Mobile: < 576px (single column, stacked layouts)
- Tablet: 576px - 991px (two columns where appropriate)
- Desktop: 992px - 1199px (full layouts with sidebars)
- Large Desktop: >= 1200px (max-width container: 1200px)
========================================================================== */
/* Prevent horizontal page scroll at any viewport */
html, body {
@apply overflow-x-hidden;
}
/* Ensure images/media don't overflow */
img, video, iframe {
@apply max-w-full h-auto;
}
/* Touch-friendly targets - minimum 44px for interactive elements */
.touch-target {
@apply min-h-[44px] min-w-[44px];
}
/* Dashboard grid - responsive column layout */
.dashboard-grid {
@apply grid gap-4;
@apply grid-cols-1; /* Mobile: single column */
@apply sm:grid-cols-2; /* Tablet: 2 columns */
@apply lg:grid-cols-3; /* Desktop: 3 columns */
@apply xl:grid-cols-4; /* Large: 4 columns */
}
/* Stats grid - responsive layout for stat cards */
.stats-grid {
@apply grid gap-4;
@apply grid-cols-1; /* Mobile: single column */
@apply sm:grid-cols-2; /* Tablet: 2 columns */
@apply lg:grid-cols-4; /* Desktop: 4 columns */
}
/* Widget grid - responsive layout for dashboard widgets */
.widget-grid {
@apply grid gap-6;
@apply grid-cols-1; /* Mobile: single column */
@apply lg:grid-cols-3; /* Desktop: 3 columns */
}
/* Responsive table wrapper - horizontal scroll for tables on mobile */
.table-responsive {
@apply overflow-x-auto -mx-4 px-4;
@apply sm:mx-0 sm:px-0; /* Remove negative margin on larger screens */
}
/* Table wrapper with shadow indicator for scrollable content */
.table-scroll-wrapper {
@apply relative overflow-x-auto;
-webkit-overflow-scrolling: touch;
}
/* Form layout - responsive form field arrangement */
.form-row {
@apply flex flex-col gap-4;
@apply sm:flex-row sm:items-end;
}
/* Form actions - responsive button placement */
.form-actions {
@apply flex flex-col gap-3;
@apply sm:flex-row sm:justify-end;
}
/* Mobile-first button - full width on mobile, auto on larger screens */
.btn-responsive {
@apply w-full sm:w-auto;
}
/* Card full-width on mobile */
.card-responsive {
@apply w-full;
}
/* Collapsible content - for accordion sections on mobile */
.collapsible-content {
@apply transition-all duration-200 ease-in-out overflow-hidden;
}
/* Modal responsive - full screen on mobile, centered on desktop */
.modal-responsive {
@apply fixed inset-0 sm:inset-auto sm:relative;
@apply w-full sm:max-w-lg sm:mx-auto;
@apply h-full sm:h-auto sm:max-h-[90vh];
@apply rounded-none sm:rounded-lg;
}
/* Charts container - responsive height */
.chart-container {
@apply h-64 sm:h-72 lg:h-80;
@apply w-full;
}
/* Header actions - stack on mobile, inline on larger screens */
.header-actions {
@apply flex flex-col gap-3 w-full;
@apply sm:flex-row sm:w-auto sm:items-center;
}
/* Page header - responsive layout */
.page-header {
@apply flex flex-col gap-4;
@apply sm:flex-row sm:items-center sm:justify-between;
}
/* Filter bar - responsive layout */
.filter-bar {
@apply flex flex-col gap-4;
@apply sm:flex-row sm:items-end sm:flex-wrap;
}
/* Content section - responsive padding */
.section-responsive {
@apply px-4 py-6;
@apply sm:px-6 sm:py-8;
@apply lg:px-8;
}
/* RTL-aware responsive sidebar */
@media (max-width: 991px) {
.sidebar-responsive {
@apply fixed inset-y-0 start-0 w-64;
@apply transform -translate-x-full transition-transform duration-200;
@apply z-40;
}
.sidebar-responsive.open {
@apply translate-x-0;
}
/* RTL: sidebar comes from right */
[dir="rtl"] .sidebar-responsive {
@apply end-0 start-auto translate-x-full;
}
[dir="rtl"] .sidebar-responsive.open {
@apply translate-x-0;
}
}
/* Sidebar overlay for mobile */
.sidebar-overlay {
@apply fixed inset-0 bg-black/50 z-30;
@apply transition-opacity duration-200;
}
/* Calendar responsive - smaller cells on mobile */
.calendar-grid {
@apply grid grid-cols-7 gap-1;
}
.calendar-cell {
@apply h-10 sm:h-12;
@apply text-sm sm:text-base;
}
/* Time slot grid - responsive columns */
.time-slots-grid {
@apply grid gap-2;
@apply grid-cols-2 sm:grid-cols-3 md:grid-cols-4;
}
/* Time slot button - touch-friendly */
.time-slot-btn {
@apply p-3 min-h-[44px];
@apply text-sm sm:text-base;
}
/* Post/blog grid - responsive layout */
.posts-grid {
@apply grid gap-6;
@apply grid-cols-1;
@apply sm:grid-cols-2;
@apply lg:grid-cols-3;
}
/* Timeline/case view - responsive layout */
.timeline-container {
@apply relative;
}
.timeline-line {
@apply absolute top-0 bottom-0 w-0.5 bg-zinc-200 dark:bg-zinc-700;
@apply start-4 sm:start-6;
}
.timeline-item {
@apply relative ps-10 sm:ps-14;
@apply pb-6;
}
.timeline-dot {
@apply absolute start-2 sm:start-4;
@apply w-4 h-4 sm:w-5 sm:h-5;
@apply rounded-full bg-accent;
@apply transform -translate-x-1/2;
}
/* Empty state - responsive sizing */
.empty-state {
@apply py-8 sm:py-12;
@apply text-center;
}
.empty-state-icon {
@apply w-12 h-12 sm:w-16 sm:h-16;
@apply mx-auto mb-4;
}
/* Pagination responsive */
.pagination-responsive {
@apply flex flex-wrap justify-center gap-1;
@apply sm:gap-2;
}
/* Hide on mobile / show on desktop utilities */
.hide-mobile {
@apply hidden sm:block;
}
.show-mobile {
@apply block sm:hidden;
}
/* Stack on mobile, inline on desktop */
.stack-mobile {
@apply flex flex-col;
@apply sm:flex-row sm:items-center;
}
/* Gap utilities for responsive spacing */
.gap-responsive {
@apply gap-3 sm:gap-4 lg:gap-6;
}
/* Text size responsive */
.text-responsive-sm {
@apply text-xs sm:text-sm;
}
.text-responsive-base {
@apply text-sm sm:text-base;
}
.text-responsive-lg {
@apply text-base sm:text-lg lg:text-xl;
}
.text-responsive-xl {
@apply text-lg sm:text-xl lg:text-2xl;
}
/* Heading responsive sizes */
.heading-responsive-page {
@apply text-xl sm:text-2xl lg:text-3xl;
@apply font-bold;
}
.heading-responsive-section {
@apply text-lg sm:text-xl;
@apply font-semibold;
}
/* ==========================================================================
Animations & Micro-interactions (Story 9.11)
Subtle, professional animations under 300ms
========================================================================== */
/* Base transitions */
.transition-default {
@apply transition-all duration-150 ease-in-out;
}
.transition-slow {
@apply transition-all duration-200 ease-in-out;
}
/* Button hover transition - 150ms ease */
.btn {
@apply transition-colors duration-150;
}
/* Card lift effect - 200ms ease */
.card-hover {
@apply transition-all duration-200;
}
.card-hover:hover {
@apply -translate-y-0.5;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
/* Link color transition */
.link-transition {
@apply transition-colors duration-150;
}
/* Skeleton loader - pulse animation */
.skeleton {
@apply animate-pulse bg-accent/30 rounded;
}
/* Toast animation classes */
.toast-enter {
@apply transform translate-x-full opacity-0;
}
.toast-enter-active {
@apply transform translate-x-0 opacity-100 transition-all duration-200;
}
/* RTL toast animation - slides from left */
[dir="rtl"] .toast-enter {
@apply -translate-x-full;
}
[dir="rtl"] .toast-enter-active {
@apply translate-x-0;
}
/* Success checkmark animation */
@keyframes checkmark {
0% { stroke-dashoffset: 100; }
100% { stroke-dashoffset: 0; }
}
.checkmark-animated path {
stroke-dasharray: 100;
animation: checkmark 0.3s ease-in-out forwards;
}
/* Error shake animation */
@keyframes shake {
0%, 100% { transform: translateX(0); }
25% { transform: translateX(-5px); }
75% { transform: translateX(5px); }
}
.shake {
animation: shake 0.3s ease-in-out;
}
/* Modal animation classes */
.modal-enter {
@apply opacity-0 scale-95;
}
.modal-enter-active {
@apply opacity-100 scale-100 transition-all duration-200;
}
.modal-backdrop-enter {
@apply opacity-0;
}
.modal-backdrop-enter-active {
@apply opacity-100 transition-opacity duration-200;
}
/* Progress bar animation */
.progress-bar {
@apply transition-all duration-200 ease-out;
}
/* ==========================================================================
Accessibility Styles (Story 9.10)
WCAG 2.1 AA Compliance
========================================================================== */
/* Focus styles - visible Light Olive outline for keyboard navigation */
:focus-visible {
@apply outline-2 outline-offset-2 outline-accent;
}
/* Skip link - hidden until focused, then appears at top-start */
.skip-link {
@apply sr-only focus:not-sr-only focus:absolute focus:top-4 focus:start-4
focus:bg-primary focus:text-off-white focus:px-4 focus:py-2 focus:rounded-md
focus:font-semibold focus:z-[100];
}
/* Reduced motion - respect user preference for reduced animations */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}