.btn { padding: var(--space-3) var(--space-6); border-radius: var(--radius-2xl); border: none; cursor: pointer; display: flex; align-items: center; justify-content: center; font-size: var(--text-base); font-weight: var(--weight-medium); gap: var(--space-2); transition: all 0.2s ease; } .btn i { font-size: 15px; } .btn-primary { background: var(--color-accent-gradient); color: var(--color-danger-text); box-shadow: 0 4px 15px var(--color-accent-shadow); } .btn-primary:hover { transform: translateY(-2px); box-shadow: 0 6px 20px var(--color-accent-shadow-lg); } .btn-primary:active { transform: translateY(0); box-shadow: 0 2px 10px var(--color-accent-shadow); } .btn-secondary { background-color: var(--color-bg-hover); color: var(--color-text-secondary); border: 2px solid var(--color-border); } .btn-secondary:hover { background-color: var(--color-bg-input-alt); border-color: var(--color-border-medium); transform: translateY(-2px); box-shadow: 0 4px 12px var(--color-shadow-sm); } .btn-secondary:active { transform: translateY(0); background-color: var(--color-border); } .btn-danger { background: var(--color-danger-gradient); color: var(--color-danger-text); box-shadow: 0 4px 15px var(--color-danger-ring); } .btn-danger:hover { transform: translateY(-2px); box-shadow: 0 6px 20px var(--color-danger-ring-lg); } .btn-danger:active { transform: translateY(0); box-shadow: 0 2px 10px var(--color-danger-ring); } /* ── State matrix: focus / disabled / loading ───────────────── */ /* Keyboard focus ring (explicit so the gradient variants get a crisp ring; mirrors the global a11y baseline). */ .btn:focus-visible { outline: 2px solid var(--color-focus-ring); outline-offset: 2px; } /* Disabled — dimmed, no hover lift, non-interactive. */ .btn:disabled, .btn[disabled], .btn.is-disabled { opacity: 0.5; cursor: not-allowed; box-shadow: none; transform: none; filter: none; pointer-events: none; } /* Loading — hide the label, show an inline spinner, block interaction. Toggle with the `.is-loading` class or `aria-busy="true"`. */ .btn.is-loading, .btn[aria-busy="true"] { position: relative; color: transparent; pointer-events: none; } .btn.is-loading::after, .btn[aria-busy="true"]::after { content: ""; position: absolute; top: 50%; left: 50%; width: 16px; height: 16px; margin: -8px 0 0 -8px; border: 2px solid var(--color-on-accent); border-top-color: transparent; border-radius: var(--radius-full); animation: spin var(--spin-duration) linear infinite; } /* The secondary button's text isn't white — tint its spinner to the text. */ .btn-secondary.is-loading::after, .btn-secondary[aria-busy="true"]::after { border-color: var(--color-text-secondary); border-top-color: transparent; } /* View Toggle Buttons */ .view-toggle { display: flex; gap: var(--space-0-5); padding: 3px; background-color: var(--color-bg-muted); border-radius: var(--radius-xl); border: 1px solid var(--color-border); } .toggle-btn { display: flex; align-items: center; justify-content: center; width: 36px; height: 32px; background-color: transparent; border: none; border-radius: var(--radius-lg); cursor: pointer; color: var(--color-text-faint); font-size: var(--text-base); transition: all 0.2s ease; } .toggle-btn:hover { background-color: var(--color-border); color: var(--color-text-subtle); } .toggle-btn.active { background-color: var(--color-border); color: var(--color-accent); box-shadow: 0 1px 3px var(--color-shadow); } .toggle-btn i { pointer-events: none; } /* ── Group-by selector (inside .view-toggle) ────────────── */ .view-toggle-separator { width: 1px; height: 20px; background: var(--color-border-medium); align-self: center; margin: 0 var(--space-0-5); } .view-toggle-separator.hidden { display: none; } .group-by-selector { display: flex; align-items: center; position: relative; } .group-by-selector.hidden { display: none; } .group-by-btn.active { color: var(--color-accent); } /* Sort direction button — rotate the SVG icon when order is reversed */ .sort-dir-btn .oxi-icon { transition: transform 0.2s ease; } .sort-dir-btn.active .oxi-icon { transform: rotate(180deg); } /* Active label shown inline next to the icon */ .group-by-label { display: none; font-size: 0.78rem; font-weight: var(--weight-semibold); white-space: nowrap; } /* When a group-by is selected the label has text — expand the button to fit */ .group-by-btn:has(.group-by-label:not(:empty)) { width: auto; padding: 0 var(--space-2); gap: 5px; } .group-by-btn:has(.group-by-label:not(:empty)) .group-by-label { display: inline; } .group-by-menu { position: absolute; top: calc(100% + 6px); left: 0; z-index: 200; min-width: 140px; background: var(--color-bg-surface); border: 1px solid var(--color-border); border-radius: var(--radius-lg); box-shadow: 0 4px 16px var(--color-shadow); padding: var(--space-1); display: flex; flex-direction: column; gap: var(--space-0-5); } .group-by-menu.hidden { display: none; } .group-by-option { display: flex; align-items: center; gap: var(--space-2); padding: var(--space-1-5) var(--space-2-5); border: none; background: transparent; border-radius: var(--radius-md); cursor: pointer; font-size: 0.85rem; color: var(--color-text); text-align: left; width: 100%; } .group-by-option:hover { background: var(--color-border); } .group-by-option.active { color: var(--color-accent); font-weight: var(--weight-semibold); }