/* ========================================================================== */ /* Components */ /* ========================================================================== */ /** * Dialog (Modal) * * Native element provides semantic modal functionality. * Structure:
...
content
...
* Close buttons should use aria-label="Close" for targeting. */ dialog { border: none; padding: 0; margin: auto; max-width: min(90vw, 600px); max-height: 90vh; background-color: var(--color-bg); border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); overflow: hidden; } dialog::backdrop { background-color: rgba(0, 0, 0, 0.5); backdrop-filter: blur(4px); } @media (prefers-color-scheme: dark) { dialog::backdrop { background-color: rgba(0, 0, 0, 0.7); } } dialog article { margin: 0; padding: 0; display: flex; flex-direction: column; max-height: 90vh; } dialog header { position: relative; border-bottom: 1px solid var(--color-border); padding: var(--space-lg); margin: 0; } dialog header h1, dialog header h2, dialog header h3, dialog header h4, dialog header h5, dialog header h6 { margin-top: 0; margin-bottom: 0; padding-right: var(--space-3xl); } dialog header button[aria-label="Close"], dialog header button[aria-label="close"] { position: absolute; top: var(--space-lg); right: var(--space-lg); background: none; border: none; font-size: 1.75rem; line-height: 1; padding: var(--space-xs); margin: 0; width: auto; color: var(--color-text-muted); cursor: pointer; transition: color var(--transition-fast), transform var(--transition-fast); } dialog header button[aria-label="Close"]:hover, dialog header button[aria-label="close"]:hover { color: var(--color-text); background: none; transform: scale(1.1); } dialog article > :not(header):not(footer) { padding: var(--space-lg); overflow-y: auto; flex: 1; } dialog form { margin: 0; max-width: none; } dialog footer { border-top: 1px solid var(--color-border); padding: var(--space-lg); margin: 0; display: flex; gap: var(--space-md); justify-content: flex-end; flex-wrap: wrap; } dialog footer button { margin: 0; } @media (max-width: 768px) { dialog { max-width: 95vw; max-height: 95vh; } dialog header, dialog article > :not(header):not(footer), dialog footer { padding: var(--space-md); } dialog header button[aria-label="Close"], dialog header button[aria-label="close"] { top: var(--space-md); right: var(--space-md); } } /** * Accordian * * implemented as details and summary */ details { margin: var(--space-lg) 0; padding: var(--space-md); border: 1px solid var(--color-border); border-radius: var(--radius-md); max-width: var(--content-width); } summary { font-weight: 700; cursor: pointer; user-select: none; padding: var(--space-sm); margin: calc(-1 * var(--space-sm)); transition: background-color var(--transition-fast); } summary:hover { background-color: var(--color-bg-alt); } details[open] summary { margin-bottom: var(--space-md); border-bottom: 1px solid var(--color-border); } /** * Tooltips * * Declarative tooltips using data-vx-tooltip attribute. * Placements: top (default), right, bottom, left * Structure: */ [data-vx-tooltip] { position: relative; cursor: help; } [data-vx-tooltip]::before, [data-vx-tooltip]::after { position: absolute; opacity: 0; pointer-events: none; transition: opacity var(--transition-fast), transform var(--transition-fast); z-index: 1000; } [data-vx-tooltip]::before { content: attr(data-vx-tooltip); background: var(--color-text); color: var(--color-bg); padding: var(--space-sm) var(--space-md); border-radius: var(--radius-sm); font-size: 0.875rem; white-space: normal; min-width: 200px; max-width: 300px; width: max-content; text-align: center; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 4; line-clamp: 4; overflow: hidden; text-overflow: ellipsis; line-height: 1.4; } [data-vx-tooltip]::after { content: ''; border: 6px solid transparent; } [data-vx-tooltip]:hover::before, [data-vx-tooltip]:hover::after, [data-vx-tooltip]:focus::before, [data-vx-tooltip]:focus::after, [data-vx-tooltip]:focus-visible::before, [data-vx-tooltip]:focus-visible::after { opacity: 1; } /* Placement: Top (default) */ [data-vx-tooltip]:not([data-placement])::before, [data-vx-tooltip][data-placement="top"]::before { bottom: calc(100% + 12px); left: 50%; transform: translateX(-50%) translateY(4px); } [data-vx-tooltip]:not([data-placement])::after, [data-vx-tooltip][data-placement="top"]::after { bottom: calc(100% + 6px); left: 50%; transform: translateX(-50%); border-top-color: var(--color-text); } [data-vx-tooltip]:not([data-placement]):hover::before, [data-vx-tooltip][data-placement="top"]:hover::before, [data-vx-tooltip]:not([data-placement]):focus::before, [data-vx-tooltip][data-placement="top"]:focus::before { transform: translateX(-50%) translateY(0); } /* Placement: Bottom */ [data-vx-tooltip][data-placement="bottom"]::before { top: calc(100% + 12px); left: 50%; transform: translateX(-50%) translateY(-4px); } [data-vx-tooltip][data-placement="bottom"]::after { top: calc(100% + 6px); left: 50%; transform: translateX(-50%); border-bottom-color: var(--color-text); } [data-vx-tooltip][data-placement="bottom"]:hover::before, [data-vx-tooltip][data-placement="bottom"]:focus::before { transform: translateX(-50%) translateY(0); } [data-vx-tooltip][data-placement="right"]::before { left: calc(100% + 12px); top: 50%; transform: translateY(-50%) translateX(-4px); } [data-vx-tooltip][data-placement="right"]::after { left: calc(100% + 6px); top: 50%; transform: translateY(-50%); border-right-color: var(--color-text); } [data-vx-tooltip][data-placement="right"]:hover::before, [data-vx-tooltip][data-placement="right"]:focus::before { transform: translateY(-50%) translateX(0); } [data-vx-tooltip][data-placement="left"]::before { right: calc(100% + 12px); top: 50%; transform: translateY(-50%) translateX(4px); } [data-vx-tooltip][data-placement="left"]::after { right: calc(100% + 6px); top: 50%; transform: translateY(-50%); border-left-color: var(--color-text); } [data-vx-tooltip][data-placement="left"]:hover::before, [data-vx-tooltip][data-placement="left"]:focus::before { transform: translateY(-50%) translateX(0); } @media (max-width: 768px) { [data-vx-tooltip]::before, [data-vx-tooltip]::after { display: none; } }