@casoon/dragonfly
Version:
Modular, lightweight CSS framework and design system for modern web projects. Optimized for Astro JS, LightningCSS and Container Queries with @layer-based architecture and comprehensive accessibility.
1,789 lines (1,526 loc) • 76 kB
CSS
/*
* Forms Module - Complete Form System
*
* Comprehensive form elements and controls for user input and interaction.
* This module combines all form-related components and provides both simple
* utility classes and advanced form system features.
*
* CONTENTS:
*
* 1. BASIC FORM ELEMENTS (Simple utility classes):
* - Buttons (interactive form controls)
* - Input fields (text, email, password, etc.)
* - Textarea (multi-line text input)
* - Select dropdowns (single and multiple selection)
* - Checkboxes (multiple selection)
* - Radio buttons (single selection from group)
* - Switches (toggle controls)
* - Sliders (range input controls)
*
* 2. ADVANCED FORM SYSTEM (Bootstrap-style components):
* - Form containers and layouts (.form, .form-group, .form-row)
* - Form controls (.form-control, .form-select, .form-check)
* - Labels and feedback (.form-label, .form-text, .feedback)
* - Validation states and feedback mechanisms
* - Input groups (.input-group, .input-group-text)
* - Responsive and adaptive layouts
* - RTL support and accessibility features
*
* @layer components.forms
*
* Accessibility Features:
* - Semantic HTML elements as foundation
* - Proper focus management and keyboard navigation
* - ARIA attributes where needed
* - High contrast focus indicators
* - Screen reader friendly labels and descriptions
*/
/**
* Form Elements Collection
*
* This file contains all form-related components:
* - Buttons (interactive form controls)
* - Input fields (text, email, password, etc.)
* - Textarea (multi-line text input)
* - Select dropdowns (single and multiple selection)
* - Checkboxes (multiple selection)
* - Radio buttons (single selection from group)
* - Switches (toggle controls)
* - Sliders (range input controls)
*
* @layer components.forms
*
* Accessibility Features:
* - Semantic HTML elements as foundation
* - Proper focus management and keyboard navigation
* - ARIA attributes where needed
* - High contrast focus indicators
* - Screen reader friendly labels and descriptions
*/
/* =================== ANIMATIONS =================== */
/* =================== BUTTONS =================== */
@layer components {
/* Base Button Style */
.button {
align-items: center;
border: none;
border-radius: var(--radius-md, 0.5rem);
cursor: pointer;
display: inline-flex;
font-size: var(--font-size-sm, 0.875rem);
font-weight: var(--font-weight-medium, 500);
justify-content: center;
line-height: 1.25;
padding-block: var(--space-2, 0.5rem);
padding-inline: var(--space-4, 1rem);
position: relative;
text-decoration: none;
transition: background-color var(--transition-duration-fast, 150ms) var(--transition-timing-ease, cubic-bezier(0.4, 0, 0.2, 1));
}
/* Button Variants */
.button--primary {
background-color: var(--color-primary, #06c);
color: white;
}
.button--primary:hover {
background-color: var(--color-primary-hover, #05a);
}
.button--secondary {
background-color: var(--color-secondary);
color: white;
}
.button--secondary:hover {
background-color: var(--color-secondary-hover);
}
.button--tertiary {
background-color: transparent;
border: 1px solid var(--color-border, #e5e7eb);
color: var(--color-text);
}
.button--tertiary:hover {
background-color: var(--color-background-alt, #f9fafb);
}
.button--success {
background-color: var(--color-success, #10b981);
color: white;
}
.button--success:hover {
background-color: var(--color-success-hover);
}
.button--warning {
background-color: var(--color-warning, #f59e0b);
color: var(--color-text);
}
.button--warning:hover {
background-color: var(--color-warning-hover);
}
.button--danger {
background-color: var(--color-error, #ef4444);
color: white;
}
.button--danger:hover {
background-color: var(--color-error-hover);
}
.button--info {
background-color: var(--color-info, #3b82f6);
color: white;
}
.button--info:hover {
background-color: var(--color-info-hover);
}
.button--link {
background-color: transparent;
color: var(--color-primary, #3b82f6);
padding: 0;
text-decoration: underline;
}
.button--link:hover {
color: var(--color-primary-hover, #2563eb);
text-decoration: none;
}
/* Button Sizes */
.button--xs {
font-size: var(--font-size-xs);
padding-block: var(--space-1);
padding-inline: var(--space-2);
}
.button--sm {
font-size: var(--font-size-sm, 0.875rem);
padding-block: var(--space-1);
padding-inline: var(--space-3);
}
.button--md {
font-size: var(--font-size-base, 1rem);
padding-block: var(--space-2);
padding-inline: var(--space-4);
}
.button--lg {
font-size: var(--font-size-lg);
padding-block: var(--space-3);
padding-inline: var(--space-6);
}
.button--xl {
font-size: var(--font-size-xl);
padding-block: var(--space-4);
padding-inline: var(--space-8);
}
/* Button States */
button:disabled,
.button:disabled {
cursor: not-allowed;
opacity: var(--opacity-50);
}
.button--loading {
color: transparent;
pointer-events: none;
}
.button--with-icon {
gap: var(--space-2);
}
.button--with-icon .icon {
flex-shrink: 0;
height: 1em;
width: 1em;
}
.button--icon-only {
aspect-ratio: 1;
padding: var(--space-2);
}
.button--icon-only .icon {
height: 1.25em;
width: 1.25em;
}
.button--loading::after {
animation: var(--ui-spin-animation, spin var(--animation-duration-slowest, 1000ms) var(--ease-linear, linear) infinite);
border: 2px solid transparent;
border-radius: var(--radius-full, 9999px);
border-top-color: currentColor;
content: "";
height: 1em;
left: 50%;
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
width: 1em;
}
}
/* =================== INPUT FIELDS =================== */
@layer components {
.input {
background-color: var(--color-white, #fff);
border: 1px solid var(--color-gray-300, #d1d5db);
border-radius: var(--radius-md, 0.375rem);
color: var(--color-gray-900, #111827);
display: block;
font-size: var(--font-size-base, 1rem);
padding: var(--space-2) var(--space-3);
transition: border-color var(--transition-fast, 150ms ease), background-color var(--transition-fast, 150ms ease);
width: 100%;
&:focus {
border-color: var(--color-primary, #3b82f6);
box-shadow: 0 0 0 2px color-mix(in srgb, var(--color-primary, #3b82f6) 50, transparent);
outline: none;
}
&.invalid {
background-color: color-mix(in srgb, var(--color-error, #ef4444) 5%, white);
border-color: var(--color-error, #ef4444);
}
&:disabled {
background-color: var(--color-gray-100, #f3f4f6);
color: var(--color-gray-500);
cursor: not-allowed;
}
&:read-only {
background-color: var(--color-gray-50);
}
/* Input Variants */
&.primary {
border-color: var(--color-primary, #3b82f6);
}
&.success {
border-color: var(--color-success, #10b981);
}
&.warning {
border-color: var(--color-warning, #f59e0b);
}
&.danger {
border-color: var(--color-danger);
}
/* Input Sizes */
&.sm {
font-size: var(--font-size-sm, 0.875rem);
padding: var(--space-1) var(--space-2);
}
&.lg {
font-size: var(--font-size-lg);
padding: var(--space-3) var(--space-4);
}
}
/* Input with Icon */
.input-wrapper {
align-items: center;
display: flex;
position: relative;
.input {
padding-left: var(--space-8);
}
.input-icon {
color: var(--color-gray-400);
left: var(--space-3);
pointer-events: none;
position: absolute;
}
}
}
/* =================== TEXTAREA =================== */
@layer components {
.textarea {
background-color: var(--color-white, #fff);
border: 1px solid var(--color-gray-300, #d1d5db);
border-radius: var(--radius-md, 0.375rem);
color: var(--color-gray-900, #111827);
font-size: var(--font-size-base, 1rem);
min-height: 6rem;
padding: var(--space-3);
resize: vertical;
transition: border-color var(--transition-fast, 150ms ease), box-shadow var(--transition-fast, 150ms ease);
width: 100%;
&:focus {
border-color: var(--color-primary, #3b82f6);
box-shadow: 0 0 0 2px color-mix(in srgb, var(--color-primary, #3b82f6) 50, transparent);
outline: none;
}
&:disabled {
background-color: var(--color-gray-100, #f3f4f6);
color: var(--color-gray-500);
cursor: not-allowed;
opacity: 0.7;
}
/* Textarea Sizes */
&.sm {
font-size: var(--font-size-sm, 0.875rem);
min-height: 4rem;
padding: var(--space-2);
}
&.lg {
font-size: var(--font-size-lg);
min-height: 8rem;
padding: var(--space-4);
}
/* Textarea States */
&.error {
background-color: color-mix(in srgb, var(--color-error, #ef4444) 3%, var(--color-white, #fff));
border-color: var(--color-error, #ef4444);
&:focus {
box-shadow: 0 0 0 2px color-mix(in srgb, var(--color-error, #ef4444) 30, transparent);
}
}
&.success {
background-color: color-mix(in srgb, var(--color-success, #10b981) 3%, var(--color-white, #fff));
border-color: var(--color-success, #10b981);
&:focus {
box-shadow: 0 0 0 2px color-mix(in srgb, var(--color-success, #10b981) 30, transparent);
}
}
&.readonly {
background-color: var(--color-gray-50);
cursor: default;
}
&.auto-resize {
overflow-y: hidden;
}
}
/* Textarea with Counter */
.textarea-container {
position: relative;
width: 100%;
.counter {
bottom: var(--space-2);
color: var(--color-gray-500);
font-size: var(--font-size-xs);
pointer-events: none;
position: absolute;
right: var(--space-3);
}
.textarea {
padding-bottom: calc(var(--space-3) + 1.5rem);
}
}
}
/* =================== SELECT DROPDOWNS =================== */
@layer components {
.select {
appearance: none;
background-color: var(--color-white, #fff);
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 20 20' fill='none' stroke='%23666' stroke-width='2' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6 8l4 4 4-4'/%3E%3C/svg%3E");
background-position: right var(--space-3) center;
background-repeat: no-repeat;
background-size: 1rem;
border: 1px solid var(--color-gray-300, #d1d5db);
border-radius: var(--radius-md, 0.375rem);
color: var(--color-gray-900, #111827);
cursor: pointer;
display: block;
font-size: var(--font-size-base, 1rem);
padding: var(--space-2) var(--space-3);
transition: border-color var(--transition-fast, 150ms ease), box-shadow var(--transition-fast, 150ms ease);
width: 100%;
&:focus {
border-color: var(--color-primary, #3b82f6);
box-shadow: 0 0 0 2px color-mix(in srgb, var(--color-primary, #3b82f6) 50, transparent);
outline: none;
}
&:disabled {
background-color: var(--color-gray-100, #f3f4f6);
color: var(--color-gray-500);
cursor: not-allowed;
opacity: 0.7;
}
/* Select Sizes */
&.sm {
background-position: right var(--space-2) center;
background-size: 0%.875rem;
font-size: var(--font-size-sm, 0.875rem);
padding: var(--space-1) var(--space-2);
}
&.lg {
background-position: right var(--space-4) center;
background-size: 1%.25rem;
font-size: var(--font-size-lg);
padding: var(--space-3) var(--space-4);
}
/* Select States */
&.error {
background-color: color-mix(in srgb, var(--color-error, #ef4444) 3%, var(--color-white, #fff));
border-color: var(--color-error, #ef4444);
&:focus {
box-shadow: 0 0 0 2px color-mix(in srgb, var(--color-error, #ef4444) 30, transparent);
}
}
&.success {
background-color: color-mix(in srgb, var(--color-success, #10b981) 3%, var(--color-white, #fff));
border-color: var(--color-success, #10b981);
&:focus {
box-shadow: 0 0 0 2px color-mix(in srgb, var(--color-success, #10b981) 30, transparent);
}
}
/* Multiple Selection */
&[multiple] {
background-image: none;
padding: var(--space-1);
option {
border-radius: var(--radius-sm, 0.125rem);
padding: var(--space-1) var(--space-2);
&:checked {
background-color: color-mix(in srgb, var(--color-primary, #3b82f6) 15%, transparent);
}
}
}
/* Option Groups */
optgroup {
color: var(--color-gray-700);
font-weight: var(--font-weight-medium, 500);
}
}
}
/* =================== CHECKBOXES =================== */
@layer elements {
.checkbox {
align-items: center;
cursor: pointer;
display: inline-flex;
font-size: var(--text-sm, 0.875rem);
gap: var(--space-2);
position: relative;
}
.checkbox .input {
appearance: none;
background-color: white;
border: 1px solid var(--color-neutral-400, #9ca3af);
border-radius: var(--radius-sm, 0.125rem);
cursor: pointer;
height: 1rem;
position: relative;
transition: all 0.2s;
width: 1rem;
}
.checkbox .input:checked {
background-color: var(--color-primary-500);
border-color: var(--color-primary-500);
}
.checkbox .input:checked::after {
border: solid white;
border-width: 0% 2px 2px 0;
content: "";
height: 6px;
left: 4px;
position: absolute;
top: 1px;
transform: rotate(45deg);
width: 3px;
}
.checkbox .label {
color: var(--color-text-700, #374151);
font-size: var(--text-sm, 0.875rem);
}
.checkbox .input:focus-visible {
outline: 2px solid var(--color-primary-300);
outline-offset: 2px;
}
.checkbox .input:hover:not(:disabled) {
border-color: var(--color-primary-500);
}
.checkbox .input:disabled {
background-color: var(--color-neutral-100, #f3f4f6);
border-color: var(--color-neutral-300, #d1d5db);
cursor: not-allowed;
opacity: var(--opacity-50);
}
.checkbox .input:disabled ~ .checkbox .label {
color: var(--color-text-400);
cursor: not-allowed;
}
/* Checkbox Sizes */
.checkbox--sm .input {
height: 0%.875rem;
width: 0%.875rem;
}
.checkbox--sm .input:checked::after {
height: 5px;
left: 3px;
top: 1px;
width: 2px;
}
.checkbox--sm .label {
font-size: var(--text-xs, 0.75rem);
}
.checkbox--lg .input {
height: 1%.25rem;
width: 1%.25rem;
}
.checkbox--lg .input:checked::after {
height: 8px;
left: 5px;
top: 2px;
width: 4px;
}
.checkbox--lg .label {
font-size: var(--text-base);
}
/* Checkbox Groups */
.checkbox-group {
display: flex;
flex-direction: column;
gap: var(--space-3);
}
.checkbox-group--horizontal {
flex-flow: row wrap;
gap: var(--space-4);
}
}
/* =================== RADIO BUTTONS =================== */
@layer components {
.radio {
align-items: center;
cursor: pointer;
display: inline-flex;
font-size: var(--font-size-sm, 0.875rem);
gap: var(--space-2);
input[type="radio"] {
appearance: none;
background-color: var(--color-white, #fff);
border: 2px solid var(--color-gray-400);
border-radius: 9px;
height: 1rem;
position: relative;
transition: all var(--transition-fast, 150ms ease);
width: 1rem;
&:checked {
background-color: var(--color-primary, #3b82f6);
border-color: var(--color-primary, #3b82f6);
&::after {
background-color: white;
border-radius: 9px;
content: "";
height: 0%.375rem;
left: 50%;
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
width: 0%.375rem;
}
}
&:focus-visible {
outline: 2px solid var(--color-primary, #3b82f6);
outline-offset: 2px;
}
&:disabled {
background-color: var(--color-gray-100, #f3f4f6);
border-color: var(--color-gray-300, #d1d5db);
cursor: not-allowed;
& ~ .label {
color: var(--color-gray-400);
cursor: not-allowed;
}
}
}
/* Radio Sizes */
&.sm {
font-size: var(--font-size-xs);
input[type="radio"] {
height: 0%.875rem;
width: 0%.875rem;
}
}
&.lg {
font-size: var(--font-size-base, 1rem);
input[type="radio"] {
height: 1%.25rem;
width: 1%.25rem;
&:checked::after {
height: 0%.5rem;
width: 0%.5rem;
}
}
}
}
.radio-group {
display: flex;
flex-direction: column;
gap: var(--space-2);
&.horizontal {
align-items: center;
flex-flow: row wrap;
}
}
}
/* =================== SWITCHES =================== */
@layer elements {
.switch {
align-items: center;
cursor: pointer;
display: inline-flex;
gap: var(--space-2);
position: relative;
}
.switch .input {
height: 0%;
opacity: 0%;
position: absolute;
width: 0%;
}
.switch .track {
background-color: var(--color-neutral-300, #d1d5db);
border-radius: var(--radius-full, 9999px);
display: inline-block;
height: var(--switch-height, 1.25rem);
position: relative;
transition: background-color 0.2s;
width: var(--switch-width, 2.5rem);
}
.switch .thumb {
background-color: white;
border-radius: var(--radius-full, 9999px);
box-shadow: 0 1px 2px rgb(0 0 0 / 1000%);
height: calc(var(--switch-height, 1.25rem) * 0.8);
left: calc(var(--switch-height, 1.25rem) * 0.1);
position: absolute;
top: calc(var(--switch-height, 1.25rem) * 0.1);
transition: transform 0.2s;
width: calc(var(--switch-height, 1.25rem) * 0.8);
}
.switch .label {
color: var(--color-text-700, #374151);
font-size: var(--text-sm, 0.875rem);
}
.switch .input:checked + .switch .track {
background-color: var(--color-primary-500);
}
.switch .input:checked + .switch .track .switch .thumb {
transform: translateX(calc(var(--switch-width, 2.5rem) - var(--switch-height, 1.25rem)));
}
.switch .input:focus-visible + .switch .track {
outline: 2px solid var(--color-primary-500);
outline-offset: 2px;
}
.switch .input:disabled + .switch .track {
background-color: var(--color-neutral-200, #e5e7eb);
cursor: not-allowed;
opacity: 0.7;
}
.switch .input:disabled + .switch .track .switch .thumb {
background-color: var(--color-neutral-400, #9ca3af);
}
.switch .input:disabled ~ .switch .label {
color: var(--color-text-400);
cursor: not-allowed;
}
/* Switch Sizes */
.switch--sm {
--switch-width: 2rem;
--switch-height: 1rem;
}
.switch--sm .label {
font-size: var(--text-xs, 0.75rem);
}
.switch--md {
--switch-width: 2.5rem;
--switch-height: 1%.25rem;
}
.switch--lg {
--switch-width: 3%.5rem;
--switch-height: 1%.75rem;
}
.switch--lg .label {
font-size: var(--text-base);
}
/* Switch Color Variants */
.switch--primary .input:checked + .switch .track {
background-color: var(--color-primary-500);
}
.switch--secondary .input:checked + .switch .track {
background-color: var(--color-secondary-500);
}
.switch--success .input:checked + .switch .track {
background-color: var(--color-success-500);
}
.switch--warning .input:checked + .switch .track {
background-color: var(--color-warning-500);
}
.switch--danger .input:checked + .switch .track {
background-color: var(--color-error-500);
}
}
/* =================== SLIDERS =================== */
@layer elements {
.slider {
appearance: none;
background-color: var(--color-neutral-200, #e5e7eb);
border-radius: var(--radius-full, 9999px);
cursor: pointer;
height: 0%.25rem;
margin: var(--space-2) 0;
width: 100%;
}
/* Slider Thumb - WebKit */
.slider::-webkit-slider-thumb {
appearance: none;
background-color: var(--color-primary-500);
border-radius: var(--radius-full, 9999px);
box-shadow: 0 1px 3px rgb(0 0 0 / 1000%);
cursor: pointer;
height: 1rem;
transition: transform 0.2s, background-color 0.2s;
width: 1rem;
}
/* Slider Thumb - Firefox */
.slider::-moz-range-thumb {
background-color: var(--color-primary-500);
border: none;
border-radius: var(--radius-full, 9999px);
box-shadow: 0 1px 3px rgb(0 0 0 / 1000%);
cursor: pointer;
height: 1rem;
transition: transform 0.2s, background-color 0.2s;
width: 1rem;
}
/* Slider Hover */
.slider:hover::-webkit-slider-thumb {
transform: scale(1.1%);
}
.slider:hover::-moz-range-thumb {
transform: scale(1.1%);
}
/* Slider Focus */
.slider:focus {
outline: none;
}
.slider:focus::-webkit-slider-thumb {
box-shadow: 0 0 0 3px var(--color-primary-200);
}
.slider:focus::-moz-range-thumb {
box-shadow: 0 0 0 3px var(--color-primary-200);
}
/* Slider Sizes */
.slider--sm {
height: 0%.125rem;
}
.slider--sm::-webkit-slider-thumb {
height: 0%.75rem;
width: 0%.75rem;
}
.slider--sm::-moz-range-thumb {
height: 0%.75rem;
width: 0%.75rem;
}
.slider--lg {
height: 0%.375rem;
}
.slider--lg::-webkit-slider-thumb {
height: 1%.25rem;
width: 1%.25rem;
}
.slider--lg::-moz-range-thumb {
height: 1%.25rem;
width: 1%.25rem;
}
/* Slider Color Variants */
.slider--primary::-webkit-slider-thumb {
background-color: var(--color-primary-500);
}
.slider--primary::-moz-range-thumb {
background-color: var(--color-primary-500);
}
.slider--secondary::-webkit-slider-thumb {
background-color: var(--color-secondary-500);
}
.slider--secondary::-moz-range-thumb {
background-color: var(--color-secondary-500);
}
.slider--success::-webkit-slider-thumb {
background-color: var(--color-success-500);
}
.slider--success::-moz-range-thumb {
background-color: var(--color-success-500);
}
.slider--danger::-webkit-slider-thumb {
background-color: var(--color-error-500);
}
.slider--danger::-moz-range-thumb {
background-color: var(--color-error-500);
}
.slider--warning::-webkit-slider-thumb {
background-color: var(--color-warning-500);
}
.slider--warning::-moz-range-thumb {
background-color: var(--color-warning-500);
}
/* Slider Container */
.slider-container {
display: flex;
flex-direction: column;
margin: var(--space-3) 0;
width: 100%;
}
.slider-container .labels {
color: var(--color-text-500, #6b7280);
display: flex;
font-size: var(--text-xs, 0.75rem);
justify-content: space-between;
margin-top: var(--space-1);
}
.slider-container .value {
align-self: flex-end;
color: var(--color-text-700, #374151);
font-size: var(--text-sm, 0.875rem);
font-weight: var(--font-medium, 500);
margin-top: var(--space-1);
}
/* Range Slider (dual thumbs) */
.slider-range {
height: 2rem;
margin: var(--space-3) 0;
position: relative;
width: 100%;
}
.slider-range .slider {
background: none;
pointer-events: none;
position: absolute;
top: 0%;
width: 100%;
z-index: 1;
}
.slider-range .slider::-webkit-slider-thumb {
pointer-events: auto;
}
.slider-range .slider::-moz-range-thumb {
pointer-events: auto;
}
.slider-range .fill {
background-color: var(--color-primary-500);
border-radius: var(--radius-full, 9999px);
height: 0%.25rem;
position: absolute;
top: 50%;
transform: translateY(-50%);
}
} /**
* Formular-Styling-System
*
* Diese Datei bietet ein umfassendes System für das Styling von Formularelementen,
* einschließlich Textfeldern, Auswahlfeldern, Checkboxen, Radios und mehr.
* Das System ist darauf ausgelegt, konsistente, zugängliche und responsive Formulare zu erzeugen.
*
* Hauptmerkmale:
* - Variablensystem für konsistentes Styling und einfache Anpassung
* - Flexible Layout-Optionen (vertikal, horizontal, mehrspaltig)
* - Validierungszustände und Feedback-Mechanismen
* - Umfangreiche Barrierefreiheit und Tastatur-Navigation
* - Responsive Anpassung für verschiedene Bildschirmgrößen
* - Kompatibilität mit dem Container-Query-System aus layout.css
* - Unterstützung für interpolate-size: allow-keywords mit fluid und adaptive Klassen
* - Optionale field-sizing: content für natürlichere Eingabefelder
* - Umfassende Unterstützung für alle HTML5 Input-Typen
* - RTL-Unterstützung für mehrsprachige Anwendungen
*
* @layer components
*/
@layer components {
/**
* Form Variables
*
* CSS-Variablen die das Formular-Styling steuern.
* Diese Variablen ermöglichen eine konsistente Darstellung und einfache Anpassung.
* Die Variablen basieren auf den globalen Design-Tokens aus tokens.css.
*/
:root {
/* Grundlegende Formular-Variablen */
--form-gap: var(--spacing-4); /* Abstand zwischen Formularelementen */
--form-padding: var(--spacing-4); /* Innenabstand des Formulars */
--form-padding-y: var(--spacing-2); /* Vertikaler Innenabstand */
--form-padding-x: var(--spacing-3); /* Horizontaler Innenabstand */
--form-font-size: var(--font-size-base, 1rem); /* Basisschriftgröße */
--form-line-height: var(--line-height-base, 1.5); /* Basiszeilenhöhe */
--form-color: var(--color-text-primary); /* Textfarbe */
--form-background: var(--color-background); /* Hintergrundfarbe */
--form-border-color: var(--color-border, #e5e7eb); /* Rahmenfarbe */
--form-border-radius: var(--border-radius-md); /* Rahmenradius */
--form-box-shadow: var(--shadow-sm, 0 1px 2px 0 rgb(0 0 0 / 0.05)); /* Schatten */
--form-transition: all var(--transition-normal); /* Übergangsanimation */
/* Input-spezifische Variablen */
--input-padding-y: var(--spacing-2); /* Vertikaler Innenabstand für Inputs */
--input-padding-x: var(--spacing-3); /* Horizontaler Innenabstand für Inputs */
--input-height: 2.5rem; /* Höhe von Eingabefeldern */
--input-font-size: var(--font-size-base, 1rem); /* Schriftgröße von Eingabefeldern */
--input-bg: var(--color-background); /* Hintergrundfarbe von Eingabefeldern */
--input-color: var(--color-text-primary); /* Textfarbe von Eingabefeldern */
--input-border-color: var(--color-border, #e5e7eb); /* Rahmenfarbe von Eingabefeldern */
--input-border-width: 1px; /* Rahmenstärke von Eingabefeldern */
--input-border-radius: var(--border-radius-md); /* Rahmenradius von Eingabefeldern */
/* Select-spezifische Variablen */
--select-padding-right: 2.5rem; /* Rechter Innenabstand für Dropdown-Pfeil */
--select-indicator-padding: 1.75rem; /* Abstand des Dropdown-Pfeils vom Rand */
--select-indicator-size: 0.75rem; /* Größe des Dropdown-Pfeils */
--select-indicator-color: var(--color-text-secondary); /* Farbe des Dropdown-Pfeils */
/* Checkbox/Radio-spezifische Variablen */
--control-indicator-size: 1.25rem; /* Größe von Checkboxen und Radios */
--control-indicator-bg: var(--color-background); /* Hintergrundfarbe */
--control-indicator-border-color: var(--color-border, #e5e7eb); /* Rahmenfarbe */
--control-indicator-checked-bg: var(--color-primary-500); /* Hintergrundfarbe bei Auswahl */
--control-indicator-checked-border-color: var(--color-primary-500); /* Rahmenfarbe bei Auswahl */
--control-indicator-checked-color: var(--color-white, #fff); /* Symbol-Farbe bei Auswahl */
/* Dark Mode Unterstützung */
color-scheme: light dark;
/* Dark Mode Fallback-Variablen */
--form-disabled-bg: var(--color-gray-100, #f3f4f6);
--form-group-text-bg: var(--color-gray-100, #f3f4f6);
--form-range-bg: var(--color-gray-200);
--form-file-button-bg: var(--color-gray-200);
--form-file-button-hover-bg: var(--color-gray-300, #d1d5db);
--form-button-bg: var(--color-gray-200);
--form-button-border: var(--color-gray-300, #d1d5db);
--form-button-hover-bg: var(--color-gray-300, #d1d5db);
@media (prefers-color-scheme: dark) {
--form-disabled-bg: var(--color-gray-800);
--form-group-text-bg: var(--color-gray-700);
--form-range-bg: var(--color-gray-700);
--form-file-button-bg: var(--color-gray-700);
--form-file-button-hover-bg: var(--color-gray-600);
--form-button-bg: var(--color-gray-700);
--form-button-border: var(--color-gray-600);
--form-button-hover-bg: var(--color-gray-600);
}
}
/**
* Modulare Komponenten-Hinweis
*
* Dieses Kommentar informiert über die verfügbaren spezialisierten Module,
* die erweiterte Funktionen für bestimmte Formularelemente bieten.
* Diese Module können zusammen mit dieser Basisdatei verwendet werden.
*/
/**
* Hinweis zu modularen Komponenten:
* Einige Formularkomponenten sind auch als separate Module verfügbar:
* - input.module.css - Für Input-Felder mit erweiterten Funktionen und Varianten
* - select.module.css - Für Select-Felder mit Suchfunktion, Mehrfachauswahl und mehr
* - checkbox.module.css - Für Checkboxen mit verschiedenen Stilen und Animationen
* - radio.module.css - Für Radio-Buttons mit anpassbaren Stilen
* - textarea.module.css - Für mehrzeilige Texteingaben mit automatischer Größenanpassung
* - switch.module.css - Für Toggle-Schalter mit verschiedenen Größen und Stilen
* - file.module.css - Für Datei-Upload-Felder mit Drag & Drop und Vorschau
* - input-group.module.css - Für Eingabegruppen mit Buttons/Icons und mehr
*
* Die Module bieten umfangreichere Funktionen und Varianten,
* während diese globalen Klassen für einfache Formulare ausreichen.
*/
/**
* Basis-Formularstile
*
* Definiert grundlegende Container und Layout-Optionen für Formulare.
* Verschiedene Klassen ermöglichen flexible Formularstrukturen.
*/
/* Form Base - Vertikales Layout */
.form {
background-color: var(--form-background);
color: var(--form-color);
display: flex;
flex-direction: column;
gap: var(--form-gap);
padding: var(--form-padding);
}
/* Form Inline - Horizontales Layout */
.form-layout-inline {
align-items: flex-end;
display: flex;
flex-flow: row wrap;
gap: var(--spacing-4);
}
.form-layout-inline .form-group {
flex: 1 0 auto;
margin-bottom: 0%;
min-width: 25%0px;
}
/* Form Group - Gruppierung zusammengehöriger Elemente */
.form-group {
display: flex;
flex-direction: column;
gap: var(--space-2);
margin-bottom: var(--spacing-4);
}
.form-group:last-child {
margin-bottom: 0%;
}
/* Form Row - Mehrspaltiges Layout innerhalb eines Formulars */
.form-row {
display: flex;
flex-wrap: wrap;
gap: var(--spacing-4);
}
.form-row > * {
flex: 1;
min-width: 20%0px;
}
/**
* Formular-Labels und Hilfstexte
*
* Definiert Stile für Beschriftungen, Pflichtfeldmarkierungen und Hilfstexte.
* Diese Elemente verbessern die Benutzererfahrung und Barrierefreiheit.
*/
/* Standard-Label */
.form-label {
color: var(--color-text-primary);
display: block;
font-size: var(--font-size-sm, 0.875rem);
font-weight: var(--font-weight-medium, 500);
margin-bottom: var(--spacing-1);
}
/* Pflichtfeld-Markierung mit Sternchen */
.form-label.required::after {
color: var(--color-error, #ef4444);
content: "*";
margin-left: var(--spacing-1);
}
[dir="rtl"] .form-label.required::after {
margin-left: 0%;
margin-right: var(--spacing-1);
}
/* Hilfetext unterhalb von Formularfeldern */
.form-text {
color: var(--color-text-secondary);
display: block;
font-size: var(--font-size-sm, 0.875rem);
margin-top: var(--spacing-1);
}
/* Feedback für Validierung */
.feedback {
font-size: var(--font-size-xs);
margin-top: var(--space-1);
}
/**
* Basis-Eingabefelder
*
* .form-control ist die Hauptklasse für Eingabefelder wie Input, Select, Textarea.
* Definiert Grundstil und verschiedene Zustände (Fokus, Deaktiviert, etc.).
*/
/* Basis-Eingabefeld */
.form-control {
background-color: var(--input-bg, #fff);
border: var(--input-border-width, 1px) solid var(--input-border-color, #d1d5db);
border-radius: var(--input-border-radius, 0.375rem);
box-shadow: var(--form-box-shadow);
color: var(--input-color);
display: block;
/* Experimentelle Eigenschaft für natürlichere Feldgrößen */
field-sizing: content; /* Optionale Eigenschaft */
font-size: var(--input-font-size, 0.875rem);
line-height: var(--form-line-height, 1.5);
padding: var(--input-padding-y, 0.5rem) var(--input-padding-x, 0.75rem);
transition: var(--form-transition);
width: 100%;
}
/* Fokus-Zustand mit hervorgehobener Umrandung */
.form-control:focus {
border-color: var(--color-primary-500);
box-shadow: 0 0 0 0.2rem rgb(var(--color-primary-rgb), 0.25);
outline: none;
}
/* Platzhaltertext in Eingabefeldern */
.form-control::placeholder {
color: var(--color-text-tertiary);
opacity: 1;
}
/* Deaktivierte und schreibgeschützte Eingabefelder */
.form-control:disabled,
.form-control[readonly] {
background-color: var(--form-disabled-bg); /* Fallback */
cursor: not-allowed;
opacity: 0.7;
}
/**
* Formular-Validierung
*
* Definiert Stile für gültige und ungültige Eingabefelder,
* sowie die zugehörigen Feedback-Meldungen.
* Kann sowohl manuell als auch mit .was-validated aktiviert werden.
*/
/* Gültiger Zustand */
.form-control.is-valid, .form-group.valid .form-control {
border-color: var(--color-success, #10b981);
}
.form-control.is-valid:focus, .form-group.valid .form-control:focus {
border-color: var(--color-success, #10b981);
box-shadow: 0 0 0 0.2rem rgb(var(--color-success-rgb), 0.25);
}
/* Ungültiger Zustand */
.form-control.is-invalid, .form-group.invalid .form-control {
border-color: var(--color-error, #ef4444);
}
.form-control.is-invalid:focus, .form-group.invalid .form-control:focus {
border-color: var(--color-error, #ef4444);
box-shadow: 0 0 0 0.2rem rgb(var(--color-error-rgb), 0.25);
}
/**
* Moderne Validierungsstile mit :has()
*
* Nutzt den modernen :has()-Selektor, um Validierungszustände
* auf Elternebene basierend auf dem Zustand der Kind-Inputs anzuzeigen.
* Bietet visuelle Indikatoren für Valid/Invalid ohne zusätzliche Klassen.
*/
.form-group:has(.form-control:invalid) {
border-left: 4px solid var(--color-error, #ef4444);
padding-left: var(--spacing-3);
}
[dir="rtl"] .form-group:has(.form-control:invalid) {
border-left: none;
border-right: 4px solid var(--color-error, #ef4444);
padding-left: 0%;
padding-right: var(--spacing-3);
}
.form-group:has(.form-control:valid:not(:placeholder-shown)) {
border-left: 4px solid var(--color-success, #10b981);
padding-left: var(--spacing-3);
}
[dir="rtl"] .form-group:has(.form-control:valid:not(:placeholder-shown)) {
border-left: none;
border-right: 4px solid var(--color-success, #10b981);
padding-left: 0%;
padding-right: var(--spacing-3);
}
/* Visuelle Indikatoren neben den Eingabefeldern */
.form-group:has(.form-control:invalid) .form-label::after {
content: "⚠️";
display: inline-block;
margin-left: var(--spacing-2);
vertical-align: middle;
}
[dir="rtl"] .form-group:has(.form-control:invalid) .form-label::after {
margin-left: 0%;
margin-right: var(--spacing-2);
}
.form-group:has(.form-control:valid:not(:placeholder-shown)) .form-label::after {
color: var(--color-success, #10b981);
content: "✓";
display: inline-block;
margin-left: var(--spacing-2);
vertical-align: middle;
}
[dir="rtl"] .form-group:has(.form-control:valid:not(:placeholder-shown)) .form-label::after {
margin-left: 0%;
margin-right: var(--spacing-2);
}
/* Fallback für Browser ohne :has() Unterstützung */
@supports not (selector(:has(*))) {
.form-group.invalid {
border-left: 4px solid var(--color-error, #ef4444);
padding-left: var(--spacing-3);
}
[dir="rtl"] .form-group.invalid {
border-left: none;
border-right: 4px solid var(--color-error, #ef4444);
padding-left: 0%;
padding-right: var(--spacing-3);
}
.form-group.valid {
border-left: 4px solid var(--color-success, #10b981);
padding-left: var(--spacing-3);
}
[dir="rtl"] .form-group.valid {
border-left: none;
border-right: 4px solid var(--color-success, #10b981);
padding-left: 0%;
padding-right: var(--spacing-3);
}
}
/* Feedback-Container für Validierungsmeldungen */
.valid-feedback {
color: var(--color-success, #10b981);
display: none;
font-size: var(--font-size-sm, 0.875rem);
margin-top: var(--spacing-1);
width: 100%;
}
.invalid-feedback {
color: var(--color-error, #ef4444);
display: none;
font-size: var(--font-size-sm, 0.875rem);
margin-top: var(--spacing-1);
width: 100%;
}
/* Feedback in der modularen Formularstruktur */
.form-group.valid .feedback {
color: var(--color-success, #10b981);
}
.form-group.invalid .feedback {
color: var(--color-error, #ef4444);
}
/* Anzeigen von Feedback-Meldungen bei Validierung */
.was-validated .form-control:valid ~ .valid-feedback,
.was-validated .form-control:invalid ~ .invalid-feedback,
.form-control.is-valid ~ .valid-feedback,
.form-control.is-invalid ~ .invalid-feedback {
display: block;
}
/**
* Größenvarianten für Eingabefelder
*
* Bietet verschiedene Größen für Eingabefelder:
* - Small (sm): kompakte Größe für platzsparende Layouts
* - Large (lg): größere Variante für bessere Lesbarkeit oder Touch-Bedienung
*/
/* Kleine Eingabefelder */
.form-control-sm {
border-radius: var(--border-radius-sm);
font-size: var(--font-size-sm, 0.875rem);
height: calc(var(--input-height, 2.5rem) * 0.85);
padding: var(--spacing-1) var(--spacing-2);
}
/* Große Eingabefelder */
.form-control-lg {
border-radius: var(--border-radius-lg);
font-size: var(--font-size-lg);
height: calc(var(--input-height, 2.5rem) * 1.15);
padding: var(--spacing-3) var(--spacing-4);
}
/**
* Select-Felder
*
* Angepasste Styles für Dropdown-Auswahlfelder mit eigenem Dropdown-Pfeil.
* Basiert auf .form-control mit zusätzlichen Select-spezifischen Anpassungen.
*/
/* Basis-Select mit angepasstem Dropdown-Pfeil */
.form-select {
appearance: none;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3E%3C/svg%3E");
background-position: right var(--input-padding-x, 0.75rem) center;
background-repeat: no-repeat;
background-size: var(--select-indicator-size);
display: block;
padding-right: var(--select-indicator-padding);
width: 100%;
}
[dir="rtl"] .form-select {
background-position: left var(--input-padding-x, 0.75rem) center;
padding-left: var(--select-indicator-padding);
padding-right: var(--input-padding-x, 0.75rem);
}
/* Kleine Select-Variante */
.form-select-sm {
background-position: right var(--spacing-2) center;
padding-right: calc(var(--select-indicator-padding) * 0.85);
}
/* Große Select-Variante */
.form-select-lg {
background-position: right var(--spacing-4) center;
padding-right: calc(var(--select-indicator-padding) * 1.15);
}
/**
* Textarea-Felder
*
* Mehrzeilige Textfelder mit angepassten Eigenschaften.
* Basiert auf .form-control mit spezifischen Textarea-Anpassungen.
*/
/* Mehrzeiliges Textfeld mit vertikaler Größenanpassung */
textarea.form-control {
min-height: 6rem;
resize: vertical;
}
/**
* Checkboxen und Radio-Buttons
*
* Angepasstes Styling für Checkboxen und Radio-Buttons mit SVG-Icons.
* Ermöglicht konsistentes Aussehen über verschiedene Browser hinweg.
*/
/* Container für Checkbox/Radio */
.form-check {
display: block;
margin-bottom: var(--spacing-2);
min-height: var(--control-indicator-size, 1rem);
padding-left: calc(var(--control-indicator-size, 1rem) + var(--spacing-2));
position: relative;
}
.form-check:last-child {
margin-bottom: 0%;
}
/* Inline-Variante für horizontale Anordnung */
.form-check-inline {
align-items: center;
display: inline-flex;
margin-right: var(--spacing-4);
}
/* Checkbox/Radio Input-Element */
.form-check-input {
appearance: none;
background-color: var(--control-indicator-bg);
border: var(--input-border-width, 1px) solid var(--control-indicator-border-color);
height: var(--control-indicator-size, 1rem);
margin-left: calc(-1 * (var(--control-indicator-size, 1rem) + var(--spacing-2)));
margin-top: calc((var(--form-line-height, 1.5) * var(--form-font-size) - var(--control-indicator-size, 1rem)) / 2);
position: absolute;
print-color-adjust: exact;
transition: var(--form-transition);
width: var(--control-indicator-size, 1rem);
}
[dir="rtl"] .form-check-input {
margin-left: 0%;
margin-right: calc(-1 * (var(--control-indicator-size, 1rem) + var(--spacing-2)));
}
/* Checkbox-spezifische Styles */
.form-check-input[type="checkbox"] {
border-radius: var(--border-radius-sm);
}
/* Radio-Button-spezifische Styles */
.form-check-input[type="radio"] {
border-radius: var(--radius-full, 9999px);
}
/* Aktiver Zustand (bei Mausklick) */
.form-check-input:active {
filter: brightness(90);
}
/* Fokus-Zustand */
.form-check-input:focus {
border-color: var(--color-primary-500);
box-shadow: 0 0 0 0.2rem rgb(var(--color-primary-rgb), 0.25);
outline: 0;
}
/* Ausgewählter Zustand */
.form-check-input:checked {
background-color: var(--control-indicator-checked-bg);
border-color: var(--control-indicator-checked-border-color);
}
/* SVG-Icon für ausgewählte Checkbox */
.form-check-input:checked[type="checkbox"] {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='white' d='M13.854 3.646a.5.5 0 0 1 0 .708l-7 7a.5.5 0 0 1-.708 0l-3.5-3.5a.5.5 0 1 1 .708-.708L6.5 10.293l6.646-6.647a.5.5 0 0 1 .708 0z'/%3E%3C/svg%3E");
background-position: center;
background-repeat: no-repeat;
background-size: var(--select-indicator-size);
}
/* SVG-Icon für ausgewählten Radio-Button */
.form-check-input:checked[type="radio"] {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Ccircle r='4' fill='white' cx='8' cy='8'/%3E%3C/svg%3E");
background-position: center;
background-repeat: no-repeat;
background-size: var(--select-indicator-size);
}
/* Deaktivierter Zustand */
.form-check-input:disabled {
filter: none;
opacity: var(--opacity-50);
pointer-events: none;
}
.form-check-input:disabled ~ .form-check-label {
cursor: default;
opacity: var(--opacity-50);
}
/* Beschriftung für Checkbox/Radio */
.form-check-label {
cursor: pointer;
display: inline-block;
}
/**
* Toggle-Schalter (Switch)
*
* Moderne Alternative zu Checkboxen für Ein/Aus-Optionen.
* Basiert auf .form-check, mit angepasstem Styling für Schalteroptik.
*/
/* Container für Toggle-Schalter */
.form-switch {
padding-left: calc(var(--control-indicator-size, 1rem) * 2);
}
[dir="rtl"] .form-switch {
padding-left: 0%;
padding-right: calc(var(--control-indicator-size, 1rem) * 2);
}
/* Toggle-Schalter-Input mit Schieberegler */
.form-switch .form-check-input {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Ccircle r='3' fill='rgb(0 0 0 / 0.25)' cx='3' cy='8'/%3E%3C/svg%3E");
background-position: left center;
background-repeat: no-repeat;
border-radius: calc(var(--control-indicator-size, 1rem) * 0.85);
height: calc(var(--control-indicator-size, 1rem) * 0.85);
transition: background-position var(--transition-normal);
width: calc(var(--control-indicator-size, 1rem) * 1.75);
}
/* Ausgewählter Zustand des Toggle-Schalters */
.form-switch .form-check-input:checked {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Ccircle r='3' fill='%23fff' cx='13' cy='8'/%3E%3C/svg%3E");
background-position: right center;
}
/**
* Datei-Upload
*
* Angepasste Darstellung für Datei-Upload-Felder mit benutzerdefiniertem Styling.
*/
/* Container für Datei-Upload */
.form-file {
position: relative;
}
/* Verstecktes natürliches File-Input */
.form-file-input {
height: var(--input-height, 2.5rem);
margin: 0;
opacity: 0%;
position: relative;
width: 100%;
z-index: 2;
}
/* Sichtbares Label für Datei-Upload */
.form-file-label {
background-color: var(--input-bg, #fff);
border: var(--input-border-width, 1px) solid var(--input-border-color, #d1d5db);
border-radius: var(--input-border-radius, 0.375rem);
display: flex;
height: var(--input-height, 2.5rem);
left: 0%;
position: absolute;
right: 0%;
top: 0%;
z-index: 1;
}
/* Textbereich für Dateipfad-Anzeige */
.form-file-text {
background-color: var(--input-bg, #fff);
border-right: none;
color: var(--color-text-tertiary);
flex: 1;
overflow: hidden;
padding: var(--input-padding-y, 0.5rem) var(--input-padding-x, 0.75rem);
text-overflow: ellipsis;
white-space: nowrap;
}
[dir="rtl"] .form-file-text {
border-left: none;
border-right: initial;
}
/* Button für Dateiauswahl */
.form-file-button {
background-color: var(--color-gray-200);
border-bottom-right-radius: var(--input-border-radius, 0.375rem);
border-left: inherit;
border-top-right-radius: var(--input-border-radius, 0.375rem);
color: var(--color-text-primary);
display: block;
padding: var(--input-padding-y, 0.5rem) var(--input-padding-x, 0.75rem);
z-index: 3;
}
[dir="rtl"] .form-file-button {
border-left: none;
border-radius: var(--input-border-radius, 0.375rem) 0 0 var(--input-border-radius, 0.375rem);
border-right: inherit;
}
/**
* Formular-Aktionen
*
* Container für Formular-Schaltflächen (Absenden, Abbrechen, etc.)
* Mit flexiblen Layout-Optionen für verschiedene Anordnungen.
*/
/* Container für Formular-Aktionsschaltflächen */
.form-actions {
display: flex;
gap: var(--spacing-3);
justify-content: flex-end;
margin-top: var(--spacing-6);
}
[dir="rtl"] .form-actions {
justify-content: flex-start;
}
.form-actions > * {
flex: 0 0 auto;
}
/**
* Input-Gruppen
*
* Ermöglicht die Kombination von Eingabefeldern mit Text oder Buttons.
* Nützlich für Währungsangaben, Suchfelder mit Buttons, etc.
*/
/**
* Input Groups - Enhanced Version
*
* Gruppierte Eingabeelemente für zusammengehörende Formularfelder.
* Input-Groups ermöglichen die Kombination von Eingabefeldern mit Addons, Buttons oder Labels.
*
* Grundlegende Verwendung:
* <div class="input-group">
* <span class="addon">https://</span>
* <input type="text" class="input" placeholder="example.com">
* </div>
*
* Mit Button:
* <div class="input-group">
* <input type="text" class="input" placeholder="Suchen...">
* <button class="button">Suchen</button>
* </div>
*
* Mit Icon:
* <div class="input-group">
* <span class="icon"><!-- Icon hier --></span>
* <input type="text" class="input" placeholder="Benutzername">
* </div>
*
* Größenvarianten:
* <div class="input-group sm">...</div>
* <div class="input-group md">...</div>
* <div class="input-group lg">...</div>
*/
/* Container für Input-Gruppe */
.input-group {
align-items: stretch;
border: var(--input-border-width, 1px) solid var(--color-border, var(--color-neutral-300, #d1d5db));
border-radius: var(--radius-input, var(--radius-md, 0.375rem));
display: flex;
overflow: hidden;
width: 100%;
/* Allgemeine Styles für alle Kinder-Elemente */
> * {
border: none;
font-size: var(--text-sm, var(--font-size-sm, 0.875rem));
outline: none;
padding: var(--space-2, 0.5rem) var(--space-3, 0.75rem);
}
/* Addon-Elemente */
.addon {
align-items: center;
background-color: var(--color-neutral-100, #f3f4f6);
color: var(--color-neutral-700, #374151);
display: flex;
font-size: var(--text-sm, var(--font-si