702 lines
24 KiB
CSS
702 lines
24 KiB
CSS
/* See the Tailwind configuration guide for advanced usage
|
||
https://tailwindcss.com/docs/configuration */
|
||
|
||
@import "tailwindcss";
|
||
@source "../css";
|
||
@source "../js";
|
||
@source "../../lib/mv_web";
|
||
|
||
/* A Tailwind plugin that makes "hero-#{ICON}" classes available.
|
||
The heroicons installation itself is managed by your mix.exs */
|
||
@plugin "../vendor/heroicons";
|
||
|
||
/* daisyUI Tailwind Plugin. You can update this file by fetching the latest version with:
|
||
curl -sLO https://github.com/saadeghi/daisyui/releases/latest/download/daisyui.js
|
||
Make sure to look at the daisyUI changelog: https://daisyui.com/docs/changelog/ */
|
||
@plugin "../vendor/daisyui" {
|
||
themes: false;
|
||
}
|
||
|
||
/* daisyUI theme plugin. You can update this file by fetching the latest version with:
|
||
curl -sLO https://github.com/saadeghi/daisyui/releases/latest/download/daisyui-theme.js
|
||
We ship with two themes, a light one inspired on Phoenix colors and a dark one inspired
|
||
on Elixir colors. Build your own at: https://daisyui.com/theme-generator/ */
|
||
@plugin "../vendor/daisyui-theme" {
|
||
name: "dark";
|
||
default: false;
|
||
prefersdark: false;
|
||
color-scheme: "dark";
|
||
--color-base-100: oklch(30.33% 0.016 252.42);
|
||
--color-base-200: oklch(25.26% 0.014 253.1);
|
||
--color-base-300: oklch(20.15% 0.012 254.09);
|
||
--color-base-content: oklch(97.807% 0.029 256.847);
|
||
--color-primary: oklch(58% 0.233 277.117);
|
||
--color-primary-content: oklch(96% 0.018 272.314);
|
||
--color-secondary: oklch(58% 0.233 277.117);
|
||
--color-secondary-content: oklch(96% 0.018 272.314);
|
||
--color-accent: oklch(60% 0.25 292.717);
|
||
--color-accent-content: oklch(96% 0.016 293.756);
|
||
--color-neutral: oklch(37% 0.044 257.287);
|
||
--color-neutral-content: oklch(98% 0.003 247.858);
|
||
--color-info: oklch(58% 0.158 241.966);
|
||
--color-info-content: oklch(97% 0.013 236.62);
|
||
--color-success: oklch(60% 0.118 184.704);
|
||
--color-success-content: oklch(98% 0.014 180.72);
|
||
--color-warning: oklch(66% 0.179 58.318);
|
||
--color-warning-content: oklch(98% 0.022 95.277);
|
||
--color-error: oklch(58% 0.253 17.585);
|
||
--color-error-content: oklch(96% 0.015 12.422);
|
||
--radius-selector: 0.25rem;
|
||
--radius-field: 0.25rem;
|
||
--radius-box: 0.5rem;
|
||
--size-selector: 0.21875rem;
|
||
--size-field: 0.21875rem;
|
||
--border: 1.5px;
|
||
--depth: 1;
|
||
--noise: 0;
|
||
}
|
||
|
||
@plugin "../vendor/daisyui-theme" {
|
||
name: "light";
|
||
default: true;
|
||
prefersdark: false;
|
||
color-scheme: "light";
|
||
--color-base-100: oklch(98% 0 0);
|
||
--color-base-200: oklch(96% 0.001 286.375);
|
||
--color-base-300: oklch(92% 0.004 286.32);
|
||
--color-base-content: oklch(21% 0.006 285.885);
|
||
--color-primary: oklch(70% 0.213 47.604);
|
||
--color-primary-content: oklch(98% 0.016 73.684);
|
||
--color-secondary: oklch(55% 0.027 264.364);
|
||
--color-secondary-content: oklch(98% 0.002 247.839);
|
||
--color-accent: oklch(0% 0 0);
|
||
--color-accent-content: oklch(100% 0 0);
|
||
--color-neutral: oklch(44% 0.017 285.786);
|
||
--color-neutral-content: oklch(98% 0 0);
|
||
--color-info: oklch(62% 0.214 259.815);
|
||
--color-info-content: oklch(97% 0.014 254.604);
|
||
--color-success: oklch(70% 0.14 182.503);
|
||
--color-success-content: oklch(98% 0.014 180.72);
|
||
--color-warning: oklch(66% 0.179 58.318);
|
||
--color-warning-content: oklch(98% 0.022 95.277);
|
||
--color-error: oklch(58% 0.253 17.585);
|
||
--color-error-content: oklch(96% 0.015 12.422);
|
||
--radius-selector: 0.25rem;
|
||
--radius-field: 0.25rem;
|
||
--radius-box: 0.5rem;
|
||
--size-selector: 0.21875rem;
|
||
--size-field: 0.21875rem;
|
||
--border: 1.5px;
|
||
--depth: 1;
|
||
--noise: 0;
|
||
}
|
||
|
||
/* Add variants based on LiveView classes */
|
||
@custom-variant phx-click-loading (.phx-click-loading&, .phx-click-loading &);
|
||
@custom-variant phx-submit-loading (.phx-submit-loading&, .phx-submit-loading &);
|
||
@custom-variant phx-change-loading (.phx-change-loading&, .phx-change-loading &);
|
||
|
||
/* Make LiveView wrapper divs transparent for layout */
|
||
[data-phx-session] { display: contents }
|
||
|
||
/* Honeypot: off-screen and minimal size so bots fill it, humans never see it (best practice) */
|
||
.join-form-helper {
|
||
position: absolute;
|
||
left: -9999px;
|
||
width: 1px;
|
||
height: 1px;
|
||
overflow: hidden;
|
||
}
|
||
.join-form-helper .join-form-helper-input {
|
||
position: absolute;
|
||
left: -9999px;
|
||
}
|
||
|
||
/* WCAG 1.4.12 Text Spacing: allow user stylesheets to adjust text spacing in popovers.
|
||
Popover content (e.g. from DaisyUI dropdown) must not rely on non-overridable inline
|
||
spacing; use inherited values so custom stylesheets can override. */
|
||
[popover] {
|
||
line-height: inherit;
|
||
letter-spacing: inherit;
|
||
word-spacing: inherit;
|
||
}
|
||
|
||
/* WCAG 2 AA: success/error/warning text. Light theme: dark tones on light bg; dark theme: light tones on dark bg. */
|
||
.text-success-aa {
|
||
color: oklch(0.35 0.12 165);
|
||
}
|
||
|
||
.text-error-aa {
|
||
color: oklch(0.45 0.2 25);
|
||
}
|
||
|
||
.text-warning-aa {
|
||
color: oklch(0.45 0.14 75);
|
||
}
|
||
|
||
[data-theme="dark"] .text-success-aa {
|
||
color: oklch(0.72 0.12 165);
|
||
}
|
||
|
||
[data-theme="dark"] .text-error-aa {
|
||
color: oklch(0.75 0.18 25);
|
||
}
|
||
|
||
[data-theme="dark"] .text-warning-aa {
|
||
color: oklch(0.78 0.14 75);
|
||
}
|
||
|
||
/* WCAG 2.2 AA: Badge contrast. DaisyUI .badge-outline uses transparent bg; we use
|
||
Core Component <.badge style="outline"> which adds .bg-base-100. This rule ensures
|
||
outline badges always have a visible background in both themes. */
|
||
[data-theme="light"] .badge.badge-outline,
|
||
[data-theme="dark"] .badge.badge-outline {
|
||
background-color: var(--color-base-100);
|
||
}
|
||
|
||
/* WCAG 2.2 AA (4.5:1 for normal text): Badge text must contrast with badge background.
|
||
Theme tokens *-content are often too light on * backgrounds in light theme, and
|
||
badge-soft uses variant as text on a light tint (low contrast). We override
|
||
--badge-fg (and for soft, color) so badge text meets 4.5:1 in both themes. */
|
||
|
||
/* Light theme: use dark text on all colored badges (solid, soft, outline). */
|
||
[data-theme="light"] .badge.badge-primary {
|
||
--badge-fg: oklch(0.25 0.08 47);
|
||
}
|
||
[data-theme="light"] .badge.badge-primary.badge-soft {
|
||
color: oklch(0.38 0.14 47);
|
||
}
|
||
[data-theme="light"] .badge.badge-success {
|
||
--badge-fg: oklch(0.26 0.06 165);
|
||
}
|
||
[data-theme="light"] .badge.badge-success.badge-soft {
|
||
color: oklch(0.35 0.10 165);
|
||
}
|
||
[data-theme="light"] .badge.badge-error {
|
||
--badge-fg: oklch(0.22 0.08 25);
|
||
}
|
||
[data-theme="light"] .badge.badge-error.badge-soft {
|
||
color: oklch(0.38 0.14 25);
|
||
}
|
||
[data-theme="light"] .badge.badge-warning {
|
||
--badge-fg: oklch(0.28 0.06 75);
|
||
}
|
||
[data-theme="light"] .badge.badge-warning.badge-soft {
|
||
color: oklch(0.42 0.12 75);
|
||
}
|
||
[data-theme="light"] .badge.badge-info {
|
||
--badge-fg: oklch(0.26 0.08 250);
|
||
}
|
||
[data-theme="light"] .badge.badge-info.badge-soft {
|
||
color: oklch(0.38 0.12 250);
|
||
}
|
||
[data-theme="light"] .badge.badge-neutral {
|
||
--badge-fg: oklch(0.22 0.01 285);
|
||
}
|
||
[data-theme="light"] .badge.badge-neutral.badge-soft {
|
||
color: oklch(0.32 0.02 285);
|
||
}
|
||
[data-theme="light"] .badge.badge-outline.badge-primary,
|
||
[data-theme="light"] .badge.badge-outline.badge-success,
|
||
[data-theme="light"] .badge.badge-outline.badge-error,
|
||
[data-theme="light"] .badge.badge-outline.badge-warning,
|
||
[data-theme="light"] .badge.badge-outline.badge-info,
|
||
[data-theme="light"] .badge.badge-outline.badge-neutral {
|
||
--badge-fg: oklch(0.25 0.02 285);
|
||
}
|
||
|
||
/* Dark theme: ensure badge backgrounds are dark enough for light content (4.5:1).
|
||
Slightly darken solid variant backgrounds so theme *-content (light) passes. */
|
||
[data-theme="dark"] .badge.badge-primary:not(.badge-soft):not(.badge-outline) {
|
||
--badge-bg: oklch(0.42 0.20 277);
|
||
--badge-fg: oklch(0.97 0.02 277);
|
||
}
|
||
[data-theme="dark"] .badge.badge-success:not(.badge-soft):not(.badge-outline) {
|
||
--badge-bg: oklch(0.42 0.10 185);
|
||
--badge-fg: oklch(0.97 0.01 185);
|
||
}
|
||
[data-theme="dark"] .badge.badge-error:not(.badge-soft):not(.badge-outline) {
|
||
--badge-bg: oklch(0.42 0.18 18);
|
||
--badge-fg: oklch(0.97 0.02 18);
|
||
}
|
||
[data-theme="dark"] .badge.badge-warning:not(.badge-soft):not(.badge-outline) {
|
||
--badge-bg: oklch(0.48 0.14 58);
|
||
--badge-fg: oklch(0.22 0.02 58);
|
||
}
|
||
[data-theme="dark"] .badge.badge-info:not(.badge-soft):not(.badge-outline) {
|
||
--badge-bg: oklch(0.45 0.14 242);
|
||
--badge-fg: oklch(0.97 0.02 242);
|
||
}
|
||
[data-theme="dark"] .badge.badge-neutral:not(.badge-soft):not(.badge-outline) {
|
||
--badge-bg: oklch(0.32 0.02 257);
|
||
--badge-fg: oklch(0.96 0.01 257);
|
||
}
|
||
[data-theme="dark"] .badge.badge-soft.badge-primary { color: oklch(0.85 0.12 277); }
|
||
[data-theme="dark"] .badge.badge-soft.badge-success { color: oklch(0.82 0.08 165); }
|
||
[data-theme="dark"] .badge.badge-soft.badge-error { color: oklch(0.82 0.14 25); }
|
||
[data-theme="dark"] .badge.badge-soft.badge-warning { color: oklch(0.88 0.10 75); }
|
||
[data-theme="dark"] .badge.badge-soft.badge-info { color: oklch(0.85 0.10 250); }
|
||
[data-theme="dark"] .badge.badge-soft.badge-neutral { color: oklch(0.90 0.01 257); }
|
||
[data-theme="dark"] .badge.badge-outline.badge-primary,
|
||
[data-theme="dark"] .badge.badge-outline.badge-success,
|
||
[data-theme="dark"] .badge.badge-outline.badge-error,
|
||
[data-theme="dark"] .badge.badge-outline.badge-warning,
|
||
[data-theme="dark"] .badge.badge-outline.badge-info,
|
||
[data-theme="dark"] .badge.badge-outline.badge-neutral {
|
||
--badge-fg: oklch(0.92 0.02 257);
|
||
}
|
||
|
||
/* WCAG 2.2 AA: Member filter join buttons (All / Paid / Unpaid, group, boolean).
|
||
Inactive state uses base-content on a light/dark surface; active state ensures
|
||
*-content on * background meets 4.5:1. */
|
||
.member-filter-dropdown .join .btn {
|
||
/* Inactive: ensure readable text (theme base-content may be low contrast on btn default) */
|
||
border-color: var(--color-base-300);
|
||
}
|
||
[data-theme="light"] .member-filter-dropdown .join .btn:not(.btn-active) {
|
||
color: oklch(0.25 0.02 285);
|
||
background-color: var(--color-base-100);
|
||
}
|
||
[data-theme="light"] .member-filter-dropdown .join .btn.btn-success.btn-active {
|
||
background-color: oklch(0.42 0.12 165);
|
||
color: oklch(0.98 0.01 165);
|
||
}
|
||
[data-theme="light"] .member-filter-dropdown .join .btn.btn-error.btn-active {
|
||
background-color: oklch(0.42 0.18 18);
|
||
color: oklch(0.98 0.02 18);
|
||
}
|
||
[data-theme="dark"] .member-filter-dropdown .join .btn:not(.btn-active) {
|
||
color: oklch(0.92 0.02 257);
|
||
background-color: var(--color-base-200);
|
||
}
|
||
[data-theme="dark"] .member-filter-dropdown .join .btn.btn-success.btn-active {
|
||
background-color: oklch(0.42 0.10 165);
|
||
color: oklch(0.97 0.01 165);
|
||
}
|
||
[data-theme="dark"] .member-filter-dropdown .join .btn.btn-error.btn-active {
|
||
background-color: oklch(0.42 0.18 18);
|
||
color: oklch(0.97 0.02 18);
|
||
}
|
||
|
||
/* ============================================
|
||
Sidebar Base Styles
|
||
============================================ */
|
||
|
||
/* Desktop Sidebar Base */
|
||
.sidebar {
|
||
@apply flex flex-col bg-base-200 min-h-screen;
|
||
@apply transition-[width] duration-300 ease-in-out;
|
||
@apply relative;
|
||
width: 16rem; /* Expanded: w-64 */
|
||
z-index: 40;
|
||
}
|
||
|
||
/* Collapsed State */
|
||
[data-sidebar-expanded="false"] .sidebar {
|
||
width: 4rem; /* Collapsed: w-16 */
|
||
}
|
||
|
||
/* ============================================
|
||
Header - Logo Centering
|
||
============================================ */
|
||
|
||
/* Header container with smooth transition for gap */
|
||
.sidebar > div:first-child {
|
||
@apply transition-all duration-300;
|
||
}
|
||
|
||
/* ============================================
|
||
Text Labels - Hide in Collapsed State
|
||
============================================ */
|
||
|
||
.menu-label {
|
||
@apply transition-all duration-200 whitespace-nowrap;
|
||
transition-delay: 0ms; /* Expanded: sofort sichtbar */
|
||
}
|
||
|
||
[data-sidebar-expanded="false"] .sidebar .menu-label {
|
||
@apply opacity-0 w-0 overflow-hidden pointer-events-none;
|
||
transition-delay: 300ms; /* Warte bis Sidebar eingeklappt ist (300ms = duration der Sidebar width transition) */
|
||
}
|
||
|
||
/* ============================================
|
||
Toggle Button Icon Swap
|
||
============================================ */
|
||
|
||
.sidebar-collapsed-icon {
|
||
@apply hidden;
|
||
}
|
||
|
||
[data-sidebar-expanded="false"] .sidebar .sidebar-expanded-icon {
|
||
@apply hidden;
|
||
}
|
||
|
||
[data-sidebar-expanded="false"] .sidebar .sidebar-collapsed-icon {
|
||
@apply block;
|
||
}
|
||
|
||
/* ============================================
|
||
Menu Groups - Show/Hide Based on State
|
||
============================================ */
|
||
|
||
.expanded-menu-group {
|
||
@apply block;
|
||
}
|
||
|
||
.collapsed-menu-group {
|
||
@apply hidden;
|
||
}
|
||
|
||
[data-sidebar-expanded="false"] .sidebar .expanded-menu-group {
|
||
@apply hidden;
|
||
}
|
||
|
||
[data-sidebar-expanded="false"] .sidebar .collapsed-menu-group {
|
||
@apply block;
|
||
}
|
||
|
||
/* Collapsed menu group button: center icon under logo */
|
||
.sidebar .collapsed-menu-group button {
|
||
padding-left: 14px;
|
||
}
|
||
|
||
/* ============================================
|
||
Menu Groups - Disable hover and active on expanded-menu-group header
|
||
============================================ */
|
||
|
||
/* Disable all interactive effects on expanded-menu-group header (no href, not clickable)
|
||
Using [role="group"] to increase specificity and avoid !important */
|
||
.sidebar .menu > li.expanded-menu-group > div[role="group"]:not(a) {
|
||
pointer-events: none;
|
||
cursor: default;
|
||
}
|
||
|
||
/* Higher specificity selector to override DaisyUI menu hover styles
|
||
DaisyUI uses :where() which has 0 specificity, but the compiled CSS might have higher specificity
|
||
Using [role="group"] attribute selector increases specificity without !important */
|
||
.sidebar .menu > li.expanded-menu-group > div[role="group"]:not(a):hover,
|
||
.sidebar .menu > li.expanded-menu-group > div[role="group"]:not(a):active,
|
||
.sidebar .menu > li.expanded-menu-group > div[role="group"]:not(a):focus {
|
||
background-color: transparent;
|
||
box-shadow: none;
|
||
cursor: default;
|
||
color: inherit;
|
||
}
|
||
|
||
/* ============================================
|
||
Elements Only Visible in Expanded State
|
||
============================================ */
|
||
|
||
.expanded-only {
|
||
@apply block transition-opacity duration-200;
|
||
}
|
||
|
||
[data-sidebar-expanded="false"] .sidebar .expanded-only {
|
||
@apply hidden;
|
||
}
|
||
|
||
/* ============================================
|
||
Tooltip - Only Show in Collapsed State
|
||
============================================ */
|
||
|
||
.sidebar .tooltip::before,
|
||
.sidebar .tooltip::after {
|
||
@apply opacity-0 pointer-events-none;
|
||
}
|
||
|
||
[data-sidebar-expanded="false"] .sidebar .tooltip:hover::before,
|
||
[data-sidebar-expanded="false"] .sidebar .tooltip:hover::after {
|
||
@apply opacity-100;
|
||
}
|
||
|
||
/* ============================================
|
||
Menu Item Alignment - Icons Centered Under Logo
|
||
============================================ */
|
||
|
||
/* Base alignment: Icons centered under logo (32px from left edge)
|
||
- Logo center: 16px padding + 16px (half of 32px) = 32px
|
||
- Icon center should be at 32px: 22px start + 10px (half of 20px) = 32px
|
||
- Menu has p-2 (8px), so links need 14px additional padding-left */
|
||
|
||
.sidebar .menu > li > a,
|
||
.sidebar .menu > li > button,
|
||
.sidebar .menu > li.expanded-menu-group > div,
|
||
.sidebar .menu > div.collapsed-menu-group > button {
|
||
@apply transition-all duration-300;
|
||
padding-left: 14px;
|
||
}
|
||
|
||
/* Collapsed state: same padding to keep icons at same position
|
||
- Remove gap so label (which is opacity-0 w-0) doesn't create space
|
||
- Keep padding-left at 14px so icons stay centered under logo */
|
||
[data-sidebar-expanded="false"] .sidebar .menu > li > a,
|
||
[data-sidebar-expanded="false"] .sidebar .menu > li > button,
|
||
[data-sidebar-expanded="false"] .sidebar .menu > li.expanded-menu-group > div,
|
||
[data-sidebar-expanded="false"] .sidebar .menu > div.collapsed-menu-group > button {
|
||
@apply gap-0;
|
||
padding-left: 14px;
|
||
padding-right: 14px; /* Center icon horizontally in 64px sidebar */
|
||
}
|
||
|
||
|
||
|
||
|
||
/* ============================================
|
||
Footer Button Alignment - Left Aligned in Collapsed State
|
||
============================================ */
|
||
|
||
[data-sidebar-expanded="false"] .sidebar .dropdown > button {
|
||
@apply px-0;
|
||
/* Buttons stay at left position, only label disappears */
|
||
}
|
||
|
||
/* ============================================
|
||
User Menu Button - Focus Ring on Avatar
|
||
============================================ */
|
||
|
||
/* Focus ring appears on the avatar when button is focused */
|
||
.user-menu-button:focus .avatar > div {
|
||
@apply ring-2 ring-primary ring-offset-2 ring-offset-base-200;
|
||
}
|
||
|
||
/* ============================================
|
||
User Menu Button - Smooth Centering Transition
|
||
============================================ */
|
||
|
||
/* User menu button transitions smoothly to center */
|
||
.user-menu-button {
|
||
@apply transition-all duration-300;
|
||
}
|
||
|
||
/* In collapsed state, center avatar under logo
|
||
- Avatar is 32px (w-8), center it in 64px sidebar
|
||
- (64px - 32px) / 2 = 16px padding → avatar center at 32px (same as logo center) */
|
||
[data-sidebar-expanded="false"] .sidebar .user-menu-button {
|
||
@apply gap-0;
|
||
padding-left: 16px;
|
||
padding-right: 16px;
|
||
justify-content: center;
|
||
}
|
||
|
||
/* ============================================
|
||
User Menu Button - Hover Ring on Avatar
|
||
============================================ */
|
||
|
||
/* Smooth transition for avatar ring effects */
|
||
.user-menu-button .avatar > div {
|
||
@apply transition-all duration-200;
|
||
}
|
||
|
||
/* Hover ring appears on the avatar when button is hovered */
|
||
.user-menu-button:hover .avatar > div {
|
||
@apply ring-1 ring-neutral ring-offset-1 ring-offset-base-200;
|
||
}
|
||
|
||
/* ============================================
|
||
Mobile Drawer Width
|
||
============================================ */
|
||
|
||
/* Auf Mobile (< 1024px) ist die Sidebar immer w-64 (16rem) wenn geöffnet */
|
||
@media (max-width: 1023px) {
|
||
.drawer-side .sidebar {
|
||
width: 16rem; /* w-64 auch auf Mobile */
|
||
}
|
||
}
|
||
|
||
/* ============================================
|
||
Drawer Side Overflow Fix für Desktop
|
||
============================================ */
|
||
|
||
/* Im Desktop-Modus (lg:drawer-open) overflow auf visible setzen
|
||
damit Dropdowns und Tooltips über Main Content erscheinen können */
|
||
@media (min-width: 1024px) {
|
||
.drawer.lg\:drawer-open .drawer-side {
|
||
overflow: visible !important;
|
||
overflow-x: visible !important;
|
||
overflow-y: visible !important;
|
||
}
|
||
}
|
||
|
||
/* ============================================
|
||
Collapsed Sidebar: User Menu Dropdown Richtung
|
||
============================================ */
|
||
|
||
/* Bei eingeklappter Sidebar liegt der Avatar-Button am linken Rand.
|
||
dropdown-end würde das Menü nach links öffnen (off-screen).
|
||
Stattdessen nach rechts öffnen (in den Content-Bereich). */
|
||
#app-layout[data-sidebar-expanded="false"] .dropdown.dropdown-top > ul.dropdown-content {
|
||
right: auto !important;
|
||
left: 0 !important;
|
||
}
|
||
|
||
/* Sign-in: hide SSO button and "or" divider when OIDC is not configured.
|
||
Scoped to #sign-in-page to avoid hiding unrelated elements. */
|
||
#sign-in-page[data-oidc-configured="false"] [id*="oidc"] {
|
||
display: none !important;
|
||
}
|
||
#sign-in-page[data-oidc-configured="false"] a[href*="oidc"] {
|
||
display: none !important;
|
||
}
|
||
#sign-in-page[data-oidc-configured="false"] .divider {
|
||
display: none !important;
|
||
}
|
||
|
||
/* Sign-in: when OIDC-only mode is on, hide password form and "or" divider (show only SSO). */
|
||
#sign-in-page[data-oidc-configured="true"][data-oidc-only="true"] [id*="password"] {
|
||
display: none !important;
|
||
}
|
||
#sign-in-page[data-oidc-configured="true"][data-oidc-only="true"] .divider {
|
||
display: none !important;
|
||
}
|
||
|
||
/* ============================================
|
||
WCAG 1.4.3: Primary button contrast (AA)
|
||
============================================ */
|
||
|
||
/* Override DaisyUI theme --color-primary-content so text on btn-primary (brand)
|
||
meets 4.5:1. In DevTools: inspect .btn-primary, check computed --color-primary
|
||
and --color-primary-content; verify contrast at https://webaim.org/resources/contrastchecker/ */
|
||
|
||
/* Light theme: primary is orange (brand); primary-content must be dark. */
|
||
[data-theme="light"] {
|
||
--color-primary-content: oklch(0.18 0.02 47);
|
||
--color-error: oklch(55% 0.253 17.585);
|
||
--color-error-content: oklch(98% 0 0);
|
||
}
|
||
|
||
/* Dark theme: primary is purple; ensure content is light and meets 4.5:1. */
|
||
[data-theme="dark"] {
|
||
--color-error: oklch(55% 0.253 17.585);
|
||
--color-error-content: oklch(98% 0 0);
|
||
|
||
--color-primary: oklch(72% 0.17 45);
|
||
--color-primary-content: oklch(0.18 0.02 47);
|
||
|
||
--color-secondary: oklch(48% 0.233 277.117);
|
||
--color-secondary-content: oklch(98% 0 0);
|
||
}
|
||
|
||
/* ============================================
|
||
WCAG 2.2 AA: Tab list inactive tab text contrast (4.5:1)
|
||
============================================ */
|
||
#member-tablist .tab:not(.tab-active) {
|
||
color: oklch(0.35 0.02 285);
|
||
}
|
||
[data-theme="dark"] #member-tablist .tab:not(.tab-active) {
|
||
color: oklch(0.72 0.02 257);
|
||
}
|
||
|
||
/* ============================================
|
||
WCAG 2.2 AA: Link contrast - primary and accent
|
||
============================================ */
|
||
[data-theme="light"] .link.link-primary {
|
||
color: oklch(0.45 0.15 35);
|
||
}
|
||
[data-theme="light"] .link.link-primary:hover {
|
||
color: oklch(0.38 0.14 35);
|
||
}
|
||
[data-theme="dark"] .link.link-primary {
|
||
color: oklch(0.82 0.14 45);
|
||
}
|
||
[data-theme="dark"] .link.link-primary:hover {
|
||
color: oklch(0.88 0.12 45);
|
||
}
|
||
[data-theme="dark"] .link.link-accent {
|
||
color: oklch(0.82 0.18 292);
|
||
}
|
||
[data-theme="dark"] .link.link-accent:hover {
|
||
color: oklch(0.88 0.16 292);
|
||
}
|
||
|
||
/* ============================================
|
||
WCAG 2.2 AA: Danger zone heading contrast (dark theme)
|
||
============================================ */
|
||
[data-theme="dark"] #danger-zone-heading.text-error {
|
||
color: oklch(0.78 0.18 25);
|
||
}
|
||
|
||
/* ============================================
|
||
WCAG 2.2 AA: Blue link contrast in dark theme
|
||
============================================ */
|
||
[data-theme="dark"] a.text-blue-700,
|
||
[data-theme="dark"] a.text-blue-600,
|
||
[data-theme="dark"] a.hover\:text-blue-800 {
|
||
color: oklch(0.72 0.16 255);
|
||
}
|
||
[data-theme="dark"] a.text-blue-700:hover,
|
||
[data-theme="dark"] a.text-blue-600:hover {
|
||
color: oklch(0.82 0.14 255);
|
||
}
|
||
|
||
/* ============================================
|
||
WCAG 2.2 AA: Password / form label on light box in dark theme
|
||
============================================ */
|
||
[data-theme="dark"] .bg-gray-50 {
|
||
background-color: var(--color-base-200);
|
||
color: var(--color-base-content);
|
||
}
|
||
[data-theme="dark"] .bg-gray-50 .label,
|
||
[data-theme="dark"] .bg-gray-50 .mb-1.label,
|
||
[data-theme="dark"] .bg-gray-50 .text-gray-600,
|
||
[data-theme="dark"] .bg-gray-50 .text-gray-700,
|
||
[data-theme="dark"] .bg-gray-50 strong,
|
||
[data-theme="dark"] .bg-gray-50 p,
|
||
[data-theme="dark"] .bg-gray-50 li {
|
||
color: var(--color-base-content);
|
||
}
|
||
|
||
/* Dark mode: orange/red info boxes (admin note, OIDC warning) – dark bg, light text */
|
||
[data-theme="dark"] .bg-orange-50 {
|
||
background-color: oklch(0.32 0.06 55);
|
||
border-color: oklch(0.42 0.08 55);
|
||
color: var(--color-base-content);
|
||
}
|
||
[data-theme="dark"] .bg-orange-50 .text-orange-800,
|
||
[data-theme="dark"] .bg-orange-50 p,
|
||
[data-theme="dark"] .bg-orange-50 strong {
|
||
color: var(--color-base-content);
|
||
}
|
||
[data-theme="dark"] .bg-red-50 {
|
||
background-color: oklch(0.32 0.08 25);
|
||
border-color: oklch(0.42 0.12 25);
|
||
color: var(--color-base-content);
|
||
}
|
||
[data-theme="dark"] .bg-red-50 .text-red-800,
|
||
[data-theme="dark"] .bg-red-50 .text-red-700,
|
||
[data-theme="dark"] .bg-red-50 p,
|
||
[data-theme="dark"] .bg-red-50 strong {
|
||
color: var(--color-base-content);
|
||
}
|
||
|
||
/* This file is for your main application CSS */
|
||
|
||
/* ============================================
|
||
SortableList: drag-and-drop table rows
|
||
============================================ */
|
||
|
||
/* Ghost row: placeholder showing where the dragged item will be dropped.
|
||
Background fills the gap; text invisible so layout matches original row. */
|
||
.sortable-ghost {
|
||
background-color: var(--color-base-300) !important;
|
||
opacity: 0.5;
|
||
}
|
||
.sortable-ghost td {
|
||
border-color: transparent !important;
|
||
}
|
||
|
||
/* Chosen row: the row being actively dragged (follows the cursor). */
|
||
.sortable-chosen {
|
||
background-color: var(--color-base-200);
|
||
box-shadow: 0 4px 16px -2px oklch(0 0 0 / 0.18);
|
||
cursor: grabbing !important;
|
||
}
|
||
|
||
/* Drag handle button: only grab cursor, no hover effect for mouse users.
|
||
Keyboard outline is handled via JS outline style. */
|
||
[data-sortable-handle] button {
|
||
cursor: grab;
|
||
}
|
||
[data-sortable-handle] button:hover {
|
||
background-color: transparent !important;
|
||
color: inherit;
|
||
}
|