/* Drama Ling - 組件樣式 */ /* ======================================== 按鈕組件 (Buttons) ======================================== */ .btn { display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2); padding: var(--space-3) var(--space-6); border: none; border-radius: var(--radius-xl); font-size: var(--text-base); font-weight: var(--font-weight-semibold); text-decoration: none; cursor: pointer; transition: all var(--transition-fast); min-height: 2.75rem; position: relative; overflow: hidden; } .btn:disabled { opacity: 0.6; cursor: not-allowed; pointer-events: none; } /* 按鈕尺寸 */ .btn-sm { padding: var(--space-2) var(--space-4); font-size: var(--text-sm); min-height: 2rem; } .btn-lg { padding: var(--space-4) var(--space-8); font-size: var(--text-lg); min-height: 3.5rem; } /* 按鈕變體 */ .btn-primary { background: linear-gradient(135deg, var(--primary-teal), var(--secondary-purple)); color: var(--text-inverse); box-shadow: 0 4px 15px 0 var(--shadow-primary); } .btn-primary:hover { transform: translateY(-2px); box-shadow: 0 8px 25px 0 var(--shadow-primary); } .btn-secondary { background-color: var(--background-tertiary); color: var(--text-primary); border: 1px solid var(--border-light); } .btn-secondary:hover { background-color: var(--border-light); border-color: var(--border-medium); } .btn-outline { background-color: transparent; color: var(--primary-teal); border: 2px solid var(--primary-teal); } .btn-outline:hover { background-color: var(--primary-teal); color: var(--text-inverse); } .btn-ghost { background-color: transparent; color: var(--text-secondary); } .btn-ghost:hover { background-color: var(--background-tertiary); color: var(--text-primary); } .btn-danger { background-color: var(--text-error); color: var(--text-inverse); } .btn-danger:hover { background-color: #DC2626; transform: translateY(-1px); } /* ======================================== 卡片組件 (Cards) ======================================== */ .card { background-color: var(--background-secondary); border: 1px solid var(--border-light); border-radius: var(--radius-xl); padding: var(--space-6); box-shadow: 0 2px 8px 0 var(--shadow-light); transition: all var(--transition-fast); } .card:hover { box-shadow: 0 8px 25px 0 var(--shadow-medium); transform: translateY(-2px); } .card-header { margin-bottom: var(--space-4); padding-bottom: var(--space-4); border-bottom: 1px solid var(--border-light); } .card-title { font-size: var(--text-lg); font-weight: var(--font-weight-semibold); color: var(--text-primary); margin: 0; } .card-subtitle { font-size: var(--text-sm); color: var(--text-secondary); margin: var(--space-1) 0 0 0; } .card-body { color: var(--text-secondary); line-height: var(--leading-relaxed); } .card-footer { margin-top: var(--space-4); padding-top: var(--space-4); border-top: 1px solid var(--border-light); display: flex; gap: var(--space-3); justify-content: flex-end; } /* 卡片變體 */ .card-interactive { cursor: pointer; transition: all var(--transition-normal); } .card-interactive:hover { border-color: var(--primary-teal); box-shadow: 0 12px 30px 0 var(--shadow-primary); } .card-flat { box-shadow: none; border: 1px solid var(--border-light); } .card-elevated { box-shadow: 0 10px 25px 0 var(--shadow-medium); } /* ======================================== 表單組件 (Forms) ======================================== */ .form-group { margin-bottom: var(--space-4); } .form-label { display: block; font-size: var(--text-sm); font-weight: var(--font-weight-medium); color: var(--text-primary); margin-bottom: var(--space-2); } .form-label.required::after { content: '*'; color: var(--text-error); margin-left: var(--space-1); } .form-input, .form-textarea, .form-select { width: 100%; padding: var(--space-3) var(--space-4); border: 2px solid var(--border-light); border-radius: var(--radius-lg); font-size: var(--text-base); background-color: var(--background-secondary); color: var(--text-primary); transition: all var(--transition-fast); } .form-input:focus, .form-textarea:focus, .form-select:focus { outline: none; border-color: var(--primary-teal); box-shadow: 0 0 0 3px rgba(0, 229, 204, 0.1); } .form-input.error, .form-textarea.error, .form-select.error { border-color: var(--text-error); } .form-input.error:focus, .form-textarea.error:focus, .form-select.error:focus { box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1); } .form-textarea { resize: vertical; min-height: 6rem; } .form-help { font-size: var(--text-sm); color: var(--text-secondary); margin-top: var(--space-1); } .form-error { font-size: var(--text-sm); color: var(--text-error); margin-top: var(--space-1); display: flex; align-items: center; gap: var(--space-1); } /* 複選框和單選框 */ .form-checkbox, .form-radio { display: flex; align-items: center; gap: var(--space-2); cursor: pointer; } .form-checkbox input, .form-radio input { width: 1.25rem; height: 1.25rem; margin: 0; } /* ======================================== 徽章組件 (Badges) ======================================== */ .badge { display: inline-flex; align-items: center; padding: var(--space-1) var(--space-3); font-size: var(--text-xs); font-weight: var(--font-weight-semibold); border-radius: var(--radius-full); } .badge-primary { background-color: var(--primary-teal); color: var(--text-inverse); } .badge-secondary { background-color: var(--text-secondary); color: var(--text-inverse); } .badge-success { background-color: var(--text-success); color: var(--text-inverse); } .badge-warning { background-color: var(--text-warning); color: var(--text-inverse); } .badge-error { background-color: var(--text-error); color: var(--text-inverse); } .badge-outline { background-color: transparent; border: 1px solid currentColor; } /* ======================================== 彈窗組件 (Modal) ======================================== */ .modal-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.6); display: flex; align-items: center; justify-content: center; z-index: var(--z-modal-backdrop); opacity: 0; visibility: hidden; transition: all var(--transition-normal); } .modal-overlay.active { opacity: 1; visibility: visible; } .modal { background-color: var(--background-secondary); border-radius: var(--radius-2xl); box-shadow: 0 20px 50px 0 var(--shadow-heavy); max-width: 500px; width: 90%; max-height: 90vh; overflow-y: auto; transform: scale(0.95) translateY(20px); transition: transform var(--transition-normal); } .modal-overlay.active .modal { transform: scale(1) translateY(0); } .modal-header { padding: var(--space-6); border-bottom: 1px solid var(--border-light); display: flex; align-items: center; justify-content: space-between; } .modal-title { font-size: var(--text-xl); font-weight: var(--font-weight-semibold); color: var(--text-primary); margin: 0; } .modal-close { width: 2rem; height: 2rem; border-radius: var(--radius-full); display: flex; align-items: center; justify-content: center; color: var(--text-secondary); transition: all var(--transition-fast); } .modal-close:hover { background-color: var(--background-tertiary); color: var(--text-primary); } .modal-body { padding: var(--space-6); } .modal-footer { padding: var(--space-6); border-top: 1px solid var(--border-light); display: flex; gap: var(--space-3); justify-content: flex-end; } /* ======================================== 提示框組件 (Toast) ======================================== */ .toast-container { position: fixed; top: var(--space-4); right: var(--space-4); z-index: var(--z-tooltip); display: flex; flex-direction: column; gap: var(--space-3); } .toast { background-color: var(--background-secondary); border: 1px solid var(--border-light); border-radius: var(--radius-lg); padding: var(--space-4); box-shadow: 0 8px 25px 0 var(--shadow-medium); display: flex; align-items: center; gap: var(--space-3); max-width: 400px; animation: slideInRight var(--transition-normal) ease-out; } .toast.removing { animation: slideOutRight var(--transition-normal) ease-in; } .toast-icon { font-size: var(--text-lg); flex-shrink: 0; } .toast-content { flex: 1; } .toast-title { font-weight: var(--font-weight-semibold); color: var(--text-primary); margin-bottom: var(--space-1); } .toast-message { font-size: var(--text-sm); color: var(--text-secondary); } .toast-close { color: var(--text-secondary); cursor: pointer; padding: var(--space-1); border-radius: var(--radius-sm); transition: all var(--transition-fast); } .toast-close:hover { background-color: var(--background-tertiary); color: var(--text-primary); } /* 提示框類型 */ .toast-success { border-left: 4px solid var(--text-success); } .toast-success .toast-icon { color: var(--text-success); } .toast-warning { border-left: 4px solid var(--text-warning); } .toast-warning .toast-icon { color: var(--text-warning); } .toast-error { border-left: 4px solid var(--text-error); } .toast-error .toast-icon { color: var(--text-error); } .toast-info { border-left: 4px solid var(--primary-teal); } .toast-info .toast-icon { color: var(--primary-teal); } /* ======================================== 載入組件 (Loading) ======================================== */ .loading { display: inline-block; width: 1.5rem; height: 1.5rem; border: 2px solid var(--border-light); border-top-color: var(--primary-teal); border-radius: var(--radius-full); animation: spin 1s linear infinite; } .loading-sm { width: 1rem; height: 1rem; border-width: 1px; } .loading-lg { width: 2rem; height: 2rem; border-width: 3px; } @keyframes spin { to { transform: rotate(360deg); } } /* 載入覆蓋層 */ .loading-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(255, 255, 255, 0.8); display: flex; align-items: center; justify-content: center; z-index: var(--z-modal); } /* ======================================== 進度條組件 (Progress) ======================================== */ .progress { width: 100%; height: 0.5rem; background-color: var(--background-tertiary); border-radius: var(--radius-full); overflow: hidden; } .progress-bar { height: 100%; background: linear-gradient(90deg, var(--primary-teal), var(--secondary-purple)); border-radius: var(--radius-full); transition: width var(--transition-normal); position: relative; } .progress-bar::after { content: ''; position: absolute; top: 0; left: 0; bottom: 0; right: 0; background: linear-gradient(90deg, rgba(255, 255, 255, 0.2) 0%, rgba(255, 255, 255, 0.4) 50%, rgba(255, 255, 255, 0.2) 100%); animation: shimmer 2s infinite; } @keyframes shimmer { 0% { transform: translateX(-100%); } 100% { transform: translateX(100%); } } /* 進度條尺寸 */ .progress-sm { height: 0.25rem; } .progress-lg { height: 0.75rem; } /* ======================================== 標籤頁組件 (Tabs) ======================================== */ .tabs { display: flex; flex-direction: column; } .tab-list { display: flex; border-bottom: 2px solid var(--border-light); margin-bottom: var(--space-6); } .tab-button { padding: var(--space-3) var(--space-4); border: none; background: none; color: var(--text-secondary); font-weight: var(--font-weight-medium); cursor: pointer; position: relative; transition: all var(--transition-fast); } .tab-button:hover { color: var(--text-primary); } .tab-button.active { color: var(--primary-teal); } .tab-button.active::after { content: ''; position: absolute; bottom: -2px; left: 0; right: 0; height: 2px; background-color: var(--primary-teal); } .tab-panel { display: none; animation: fadeInUp var(--transition-normal) ease-out; } .tab-panel.active { display: block; } /* ======================================== 下拉選單組件 (Dropdown) ======================================== */ .dropdown { position: relative; display: inline-block; } .dropdown-toggle { display: flex; align-items: center; gap: var(--space-2); padding: var(--space-2) var(--space-3); border-radius: var(--radius-md); transition: background-color var(--transition-fast); } .dropdown-toggle:hover { background-color: var(--background-tertiary); } .dropdown-menu { position: absolute; top: 100%; left: 0; min-width: 200px; background-color: var(--background-secondary); border: 1px solid var(--border-light); border-radius: var(--radius-lg); box-shadow: 0 8px 25px 0 var(--shadow-medium); padding: var(--space-2); z-index: var(--z-dropdown); opacity: 0; visibility: hidden; transform: translateY(-10px); transition: all var(--transition-fast); } .dropdown.open .dropdown-menu { opacity: 1; visibility: visible; transform: translateY(0); } .dropdown-item { display: flex; align-items: center; gap: var(--space-3); width: 100%; padding: var(--space-2) var(--space-3); border-radius: var(--radius-md); color: var(--text-secondary); transition: all var(--transition-fast); cursor: pointer; } .dropdown-item:hover { background-color: var(--background-tertiary); color: var(--text-primary); } .dropdown-divider { height: 1px; background-color: var(--border-light); margin: var(--space-2) 0; } /* 響應式調整 */ @media (max-width: 767px) { .modal { width: 95%; margin: var(--space-4); } .toast-container { left: var(--space-4); right: var(--space-4); } .toast { max-width: none; } } /* Toast 動畫 */ @keyframes slideInRight { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } } @keyframes slideOutRight { to { transform: translateX(100%); opacity: 0; } }