/* ============================================================
   学生升学系统 — Component Primitives v1.0
   ============================================================
   所有原语组件的视觉规则,全部引用 tokens.css 变量。
   不允许出现裸 hex / 字号 / 间距字面量。

   命名约定: .ds-{component}[--{variant}][__{element}]
   - ds- 前缀避免与 Bootstrap / 旧 class 冲突
   - 双连字符 -- 表示 variant
   - 双下划线 __ 表示子元素

   依赖: tokens.css 必须先加载
   ============================================================ */


/* ============================================================
   1. BUTTON  (.ds-btn)
   ============================================================
   用法:
     <button class="ds-btn ds-btn--primary">保存</button>
     <button class="ds-btn ds-btn--danger ds-btn--sm">删除</button>
     <button class="ds-btn ds-btn--ghost" disabled>取消</button>
     <button class="ds-btn ds-btn--primary ds-btn--loading">提交中...</button>

   variants: primary / secondary / danger / ghost / link
   sizes:    sm / md (default) / lg
   states:   hover / focus / active / disabled / loading
   ============================================================ */
.ds-btn {
  /* 基础: 排版 / 布局 / 反馈 */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  font-family: var(--font-family-sans);
  font-size: var(--font-size-base);
  font-weight: var(--font-weight-semibold);
  line-height: var(--line-height-snug);
  border-radius: var(--radius-md);
  border: 1px solid transparent;
  background: transparent;
  color: inherit;
  cursor: pointer;
  text-decoration: none;
  white-space: nowrap;
  user-select: none;
  transition: var(--transition-colors), box-shadow var(--motion-duration-fast) var(--motion-easing-standard);
}
.ds-btn:focus-visible {
  outline: none;
  box-shadow: var(--shadow-focus);
}
.ds-btn:disabled,
.ds-btn[aria-disabled="true"] {
  cursor: not-allowed;
  opacity: 0.5;
  pointer-events: none;
}

/* —— sizes —— */
.ds-btn--sm {
  padding: var(--space-1) var(--space-3);
  font-size: var(--font-size-sm);
  border-radius: var(--radius-sm);
}
.ds-btn--lg {
  padding: var(--space-3) var(--space-6);
  font-size: var(--font-size-md);
}

/* —— variants —— */
.ds-btn--primary {
  background: var(--color-brand-600);
  color: var(--color-text-on-brand);
  border-color: var(--color-brand-600);
}
.ds-btn--primary:hover:not(:disabled) {
  background: var(--color-brand-700);
  border-color: var(--color-brand-700);
}
.ds-btn--primary:active:not(:disabled) {
  background: var(--color-brand-800);
  border-color: var(--color-brand-800);
}

.ds-btn--secondary {
  background: var(--color-surface-card);
  color: var(--color-text-primary);
  border-color: var(--color-border-strong);
}
.ds-btn--secondary:hover:not(:disabled) {
  background: var(--color-surface-subtle);
  border-color: var(--color-neutral-400);
}

.ds-btn--danger {
  background: var(--color-danger-600);
  color: var(--color-text-on-brand);
  border-color: var(--color-danger-600);
}
.ds-btn--danger:hover:not(:disabled) {
  background: var(--color-danger-700);
  border-color: var(--color-danger-700);
}
.ds-btn--danger:focus-visible {
  box-shadow: var(--shadow-focus-danger);
}

.ds-btn--ghost {
  background: transparent;
  color: var(--color-text-secondary);
  border-color: transparent;
}
.ds-btn--ghost:hover:not(:disabled) {
  background: var(--color-surface-subtle);
  color: var(--color-text-primary);
}

.ds-btn--link {
  padding: 0;
  background: transparent;
  color: var(--color-text-link);
  border-color: transparent;
  border-radius: 0;
  font-weight: var(--font-weight-medium);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.ds-btn--link:hover:not(:disabled) {
  color: var(--color-text-link-hover);
}

/* —— loading state —— */
.ds-btn--loading {
  position: relative;
  color: transparent !important; /* keep: 隐藏按钮原文字让 spinner 居中显示,需覆盖继承的 color */
  pointer-events: none;
}
.ds-btn--loading::after {
  content: '';
  position: absolute;
  inset: 0;
  margin: auto;
  width: 1em;
  height: 1em;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: var(--radius-full);
  color: var(--color-text-on-brand);
  animation: ds-spin var(--motion-duration-slower) linear infinite;
}
.ds-btn--secondary.ds-btn--loading::after,
.ds-btn--ghost.ds-btn--loading::after,
.ds-btn--link.ds-btn--loading::after {
  color: var(--color-text-secondary);
}

/* —— icon only (square button) —— */
.ds-btn--icon {
  padding: var(--space-2);
  width: 36px;
  height: 36px;
}
.ds-btn--icon.ds-btn--sm { width: 28px; height: 28px; padding: var(--space-1); }
.ds-btn--icon.ds-btn--lg { width: 44px; height: 44px; padding: var(--space-3); }


/* ============================================================
   2. STATUS BADGE  (.ds-badge)
   ============================================================
   用法:
     <span class="ds-badge ds-badge--success">已通过</span>
     <span class="ds-badge ds-badge--warning"><i class="bi bi-clock"></i> 待审核</span>
     <span class="ds-badge ds-badge--danger ds-badge--solid">已拒绝</span>

   variants: neutral (default) / brand / success / warning / danger / info
   styles:   soft (default — 浅底深字) / solid (实底白字) / outline (描边)
   ============================================================ */
.ds-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 2px var(--space-2);
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-semibold);
  line-height: var(--line-height-snug);
  border-radius: var(--radius-full);
  background: var(--color-surface-subtle);
  color: var(--color-text-secondary);
  border: 1px solid transparent;
  white-space: nowrap;
}
.ds-badge i,
.ds-badge svg {
  font-size: 0.95em;
}

/* —— soft (default) variants —— */
.ds-badge--brand   { background: var(--color-brand-100);   color: var(--color-brand-700); }
.ds-badge--success { background: var(--color-success-100); color: var(--color-text-on-success); }
.ds-badge--warning { background: var(--color-warning-100); color: var(--color-text-on-warning); }
.ds-badge--danger  { background: var(--color-danger-100);  color: var(--color-text-on-danger); }
.ds-badge--info    { background: var(--color-info-100);    color: var(--color-text-on-info); }
.ds-badge--neutral { background: var(--color-surface-subtle); color: var(--color-text-secondary); }

/* —— solid variants —— */
.ds-badge--solid.ds-badge--brand   { background: var(--color-brand-600);   color: var(--color-text-on-brand); }
.ds-badge--solid.ds-badge--success { background: var(--color-success-600); color: var(--color-text-on-brand); }
.ds-badge--solid.ds-badge--warning { background: var(--color-warning-600); color: var(--color-text-on-brand); }
.ds-badge--solid.ds-badge--danger  { background: var(--color-danger-600);  color: var(--color-text-on-brand); }
.ds-badge--solid.ds-badge--info    { background: var(--color-info-600);    color: var(--color-text-on-brand); }

/* —— outline variants —— */
.ds-badge--outline {
  background: transparent;
  border-color: currentColor;
}
.ds-badge--outline.ds-badge--brand   { color: var(--color-brand-600); }
.ds-badge--outline.ds-badge--success { color: var(--color-success-600); }
.ds-badge--outline.ds-badge--warning { color: var(--color-warning-600); }
.ds-badge--outline.ds-badge--danger  { color: var(--color-danger-600); }
.ds-badge--outline.ds-badge--info    { color: var(--color-info-600); }

/* —— with leading dot (代替 emoji 🔴🟡🟢) —— */
.ds-badge--dot::before {
  content: '';
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: var(--radius-full);
  background: currentColor;
  margin-right: var(--space-1);
}

/* —— size variant —— */
.ds-badge--lg {
  padding: var(--space-1) var(--space-3);
  font-size: var(--font-size-sm);
}


/* ============================================================
   3. EMPTY STATE  (.ds-empty)
   ============================================================
   用法:
     <div class="ds-empty">
       <i class="ds-empty__icon bi bi-inbox"></i>
       <div class="ds-empty__title">暂无数据</div>
       <div class="ds-empty__desc">还没有学生提交申请,试试创建一个吧</div>
       <button class="ds-btn ds-btn--primary ds-btn--sm">创建学生</button>
     </div>
   sizes: sm / md (default) / lg
   ============================================================ */
.ds-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: var(--space-8) var(--space-4);
  gap: var(--space-3);
  color: var(--color-text-tertiary);
}
.ds-empty__icon {
  font-size: var(--font-size-3xl);
  color: var(--color-text-tertiary);
  opacity: 0.7;
  margin-bottom: var(--space-1);
}
.ds-empty__title {
  font-size: var(--font-size-md);
  font-weight: var(--font-weight-semibold);
  color: var(--color-text-secondary);
}
.ds-empty__desc {
  font-size: var(--font-size-sm);
  color: var(--color-text-tertiary);
  max-width: 320px;
  line-height: var(--line-height-normal);
}
.ds-empty--sm {
  padding: var(--space-5) var(--space-3);
}
.ds-empty--sm .ds-empty__icon { font-size: var(--font-size-xl); }
.ds-empty--sm .ds-empty__title { font-size: var(--font-size-base); }
.ds-empty--lg {
  padding: var(--space-16) var(--space-6);
}
.ds-empty--lg .ds-empty__icon { font-size: var(--font-size-4xl); }
.ds-empty--lg .ds-empty__title { font-size: var(--font-size-lg); }


/* ============================================================
   4. LOADING — Skeleton & Spinner
   ============================================================
   用法:
     <div class="ds-skeleton" style="width:120px;height:14px"></div>
     <div class="ds-skeleton ds-skeleton--circle" style="width:40px;height:40px"></div>
     <div class="ds-skeleton ds-skeleton--text"></div>
     <div class="ds-spinner ds-spinner--lg" aria-label="加载中"></div>
   ============================================================ */
@keyframes ds-skeleton-shimmer {
  0%   { background-position: -400px 0; }
  100% { background-position:  400px 0; }
}
@keyframes ds-spin {
  to { transform: rotate(360deg); }
}

.ds-skeleton {
  display: block;
  background: linear-gradient(
    90deg,
    var(--color-surface-subtle) 0%,
    var(--color-surface-emphasis) 50%,
    var(--color-surface-subtle) 100%
  );
  background-size: 800px 100%;
  border-radius: var(--radius-xs);
  animation: ds-skeleton-shimmer 1.6s linear infinite;
}
.ds-skeleton--text {
  height: var(--font-size-base);
  margin: var(--space-1) 0;
  border-radius: var(--radius-xs);
}
.ds-skeleton--circle {
  border-radius: var(--radius-full);
}

.ds-spinner {
  display: inline-block;
  width: 20px;
  height: 20px;
  border: 2px solid var(--color-border-strong);
  border-top-color: var(--color-brand-600);
  border-radius: var(--radius-full);
  animation: ds-spin var(--motion-duration-slower) linear infinite;
  vertical-align: middle;
}
.ds-spinner--sm { width: 14px; height: 14px; border-width: 2px; }
.ds-spinner--lg { width: 32px; height: 32px; border-width: 3px; }

.ds-loading-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(255, 255, 255, 0.7);
  border-radius: inherit;
  z-index: var(--z-raised);
}
[data-theme="dark"] .ds-loading-overlay,
body.dark-mode .ds-loading-overlay {
  background: rgba(15, 23, 42, 0.65);
}


/* ============================================================
   5. CONFIRM DIALOG  (.ds-confirm)
   ============================================================
   通过 confirm-dialog.js / React ConfirmDialog 渲染,
   替代所有原生 alert() 和 confirm()。

   结构:
     <div class="ds-confirm-overlay" role="dialog" aria-modal="true">
       <div class="ds-confirm">
         <div class="ds-confirm__icon"><i class="bi bi-exclamation-triangle"></i></div>
         <div class="ds-confirm__title">确认删除?</div>
         <div class="ds-confirm__msg">删除后不可恢复</div>
         <div class="ds-confirm__actions">
           <button class="ds-btn ds-btn--secondary">取消</button>
           <button class="ds-btn ds-btn--danger">删除</button>
         </div>
       </div>
     </div>
   ============================================================ */
@keyframes ds-overlay-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes ds-confirm-in {
  from { opacity: 0; transform: translateY(-12px) scale(0.96); }
  to   { opacity: 1; transform: translateY(0)     scale(1); }
}

.ds-confirm-overlay {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
  background: var(--color-surface-overlay);
  animation: ds-overlay-in var(--motion-duration-fast) var(--motion-easing-standard);
}
.ds-confirm {
  width: 100%;
  max-width: 420px;
  background: var(--color-surface-card);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-xl);
  padding: var(--space-6) var(--space-6) var(--space-5);
  text-align: center;
  animation: ds-confirm-in var(--motion-duration-base) var(--motion-easing-spring);
}
.ds-confirm__icon {
  width: 48px;
  height: 48px;
  margin: 0 auto var(--space-3);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--font-size-2xl);
  border-radius: var(--radius-full);
  background: var(--color-warning-100);
  color: var(--color-warning-600);
}
.ds-confirm--danger .ds-confirm__icon {
  background: var(--color-danger-100);
  color: var(--color-danger-600);
}
.ds-confirm--info .ds-confirm__icon {
  background: var(--color-info-100);
  color: var(--color-info-600);
}
.ds-confirm--success .ds-confirm__icon {
  background: var(--color-success-100);
  color: var(--color-success-600);
}
.ds-confirm__title {
  font-size: var(--font-size-lg);
  font-weight: var(--font-weight-semibold);
  color: var(--color-text-primary);
  margin-bottom: var(--space-2);
}
.ds-confirm__msg {
  font-size: var(--font-size-sm);
  color: var(--color-text-secondary);
  line-height: var(--line-height-normal);
  margin-bottom: var(--space-5);
}
.ds-confirm__actions {
  display: flex;
  gap: var(--space-2);
  justify-content: center;
}
.ds-confirm__actions .ds-btn {
  min-width: 96px;
}


/* ============================================================
   6. TOAST  (.ds-toast / .ds-toast-host)
   ============================================================
   通过 toast.js / React Toast 渲染,统一替代:
     - alert('保存成功')
     - 散落的 Bootstrap alert 组件
     - 自制 .notification-toast

   结构:
     <div class="ds-toast-host"> <!-- 固定在右上 -->
       <div class="ds-toast ds-toast--success" role="status">
         <i class="ds-toast__icon bi bi-check-circle-fill"></i>
         <div class="ds-toast__body">
           <div class="ds-toast__title">已保存</div>
           <div class="ds-toast__msg">学生信息已更新</div>
         </div>
         <button class="ds-toast__close" aria-label="关闭">×</button>
       </div>
     </div>
   ============================================================ */
@keyframes ds-toast-in {
  from { opacity: 0; transform: translateX(20px); }
  to   { opacity: 1; transform: translateX(0); }
}
@keyframes ds-toast-out {
  from { opacity: 1; transform: translateX(0); }
  to   { opacity: 0; transform: translateX(20px); }
}

.ds-toast-host {
  position: fixed;
  top: var(--space-5);
  right: var(--space-5);
  z-index: var(--z-toast);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  pointer-events: none;
  max-width: 380px;
  width: calc(100vw - var(--space-10));
}
.ds-toast {
  pointer-events: auto;
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  background: var(--color-surface-card);
  border-radius: var(--radius-lg);
  border: 1px solid var(--color-border-default);
  border-left: 3px solid var(--color-neutral-400);
  box-shadow: var(--shadow-lg);
  animation: ds-toast-in var(--motion-duration-base) var(--motion-easing-spring);
}
.ds-toast--leaving {
  animation: ds-toast-out var(--motion-duration-fast) var(--motion-easing-exit) forwards;
}
.ds-toast--success { border-left-color: var(--color-success-600); }
.ds-toast--warning { border-left-color: var(--color-warning-600); }
.ds-toast--danger  { border-left-color: var(--color-danger-600);  }
.ds-toast--info    { border-left-color: var(--color-info-600);    }
.ds-toast__icon {
  flex-shrink: 0;
  font-size: var(--font-size-lg);
  line-height: 1;
  color: var(--color-text-tertiary);
  padding-top: 2px;
}
.ds-toast--success .ds-toast__icon { color: var(--color-success-600); }
.ds-toast--warning .ds-toast__icon { color: var(--color-warning-600); }
.ds-toast--danger  .ds-toast__icon { color: var(--color-danger-600);  }
.ds-toast--info    .ds-toast__icon { color: var(--color-info-600);    }
.ds-toast__body {
  flex: 1;
  min-width: 0;
}
.ds-toast__title {
  font-size: var(--font-size-base);
  font-weight: var(--font-weight-semibold);
  color: var(--color-text-primary);
  line-height: var(--line-height-snug);
}
.ds-toast__msg {
  font-size: var(--font-size-sm);
  color: var(--color-text-secondary);
  line-height: var(--line-height-normal);
  margin-top: 2px;
}
.ds-toast__close {
  flex-shrink: 0;
  background: transparent;
  border: none;
  font-size: var(--font-size-xl);
  line-height: 1;
  color: var(--color-text-tertiary);
  cursor: pointer;
  padding: 0 var(--space-1);
  margin: -2px -2px 0 0;
  border-radius: var(--radius-sm);
  transition: var(--transition-colors);
}
.ds-toast__close:hover {
  color: var(--color-text-primary);
  background: var(--color-surface-subtle);
}


/* ============================================================
   7. MODAL — Bootstrap modal 微调 (Phase 3a)
   ============================================================
   不重写 Bootstrap modal,只用 .ds-* 修饰统一以下:
   - modal-header: 统一 border-bottom + 间距 + 字号
   - modal-footer: 按钮间距 + 排列规则 (cancel 左 / primary 右)
   ============================================================ */
.modal-header {
  padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--color-border-default);
}
.modal-header .modal-title {
  font-size: var(--font-size-md);
  font-weight: var(--font-weight-semibold);
  color: var(--color-text-primary);
  margin: 0;
}
.modal-body { padding: var(--space-5); }
.modal-footer {
  padding: var(--space-3) var(--space-5);
  border-top: 1px solid var(--color-border-default);
  gap: var(--space-2);
  background: var(--color-surface-page);
}
.modal-footer > .btn,
.modal-footer > .ds-btn {
  min-width: 88px;
}


/* ============================================================
   8. FORM — 表单字段规范 (Phase 3b)
   ============================================================
   命名:
     .ds-form         — 表单容器 (统一字段间距)
     .ds-field        — 单个字段容器
     .ds-field__label — 字段 label
     .ds-field__hint  — 字段下方灰字 (说明文字)
     .ds-field__error — 字段下方红字 (校验错误)
     .ds-required     — 必填星号

   inline validation: 通过 DS.validateField(input, rules) 控制 .is-invalid

   用法:
     <div class="ds-form">
       <div class="ds-field">
         <label class="ds-field__label">姓名 <span class="ds-required">*</span></label>
         <input class="form-control" name="name" required>
         <div class="ds-field__hint">请填写护照上的英文姓名</div>
         <div class="ds-field__error" data-ds-error-for="name"></div>
       </div>
     </div>
   ============================================================ */
.ds-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}
.ds-field {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
.ds-field__label {
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-semibold);
  color: var(--color-text-primary);
  margin: 0;
}
.ds-required {
  color: var(--color-danger-600);
  margin-left: 2px;
  font-weight: var(--font-weight-bold);
}
.ds-field__hint {
  font-size: var(--font-size-xs);
  color: var(--color-text-tertiary);
  line-height: var(--line-height-snug);
}
.ds-field__error {
  font-size: var(--font-size-xs);
  color: var(--color-danger-600);
  line-height: var(--line-height-snug);
  min-height: 1em;
  display: none;
}
.ds-field.is-invalid .ds-field__error { display: block; }
.ds-field.is-invalid .ds-field__hint  { display: none; }

/* Bootstrap is-invalid 兼容 (现有 form-control + DS 字段两栈共用) */
.form-control.is-invalid,
.form-select.is-invalid {
  border-color: var(--color-danger-500);
  background-image: none; /* 干掉 Bootstrap 默认的小红 x icon (与我们的字段下错字重复) */
  padding-right: var(--space-3);
}
.form-control.is-invalid:focus,
.form-select.is-invalid:focus {
  border-color: var(--color-danger-600);
  box-shadow: var(--shadow-focus-danger);
}


/* ============================================================
   9. TABLE — 列表表格 (Phase 3c)
   ============================================================
   命名:
     .ds-table           — 表格容器
     .ds-table th[data-ds-sort] — 可排序表头
     .ds-table__toolbar  — 上方 (filter / search / 操作按钮)
     .ds-table__footer   — 下方 (count + 分页)
     .ds-pagination      — 分页控件

   渲染由 DS.table(container, {data, columns, ...}) 工厂负责
   ============================================================ */
.ds-table-wrap {
  background: var(--color-surface-card);
  border: 1px solid var(--color-border-default);
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: var(--shadow-xs);
}
.ds-table-wrap .ds-table__toolbar {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-5);
  border-bottom: 1px solid var(--color-border-default);
  background: var(--color-surface-card);
  flex-wrap: wrap;
}
.ds-table-wrap .ds-table__search {
  flex: 1;
  min-width: 180px;
  max-width: 320px;
}
.ds-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--font-size-base);
  color: var(--color-text-primary);
}
.ds-table thead th {
  background: var(--color-surface-subtle);
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-semibold);
  color: var(--color-text-secondary);
  text-align: left;
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--color-border-default);
  white-space: nowrap;
}
.ds-table thead th[data-ds-sort] {
  cursor: pointer;
  user-select: none;
  position: relative;
  padding-right: var(--space-6);
}
.ds-table thead th[data-ds-sort]:hover {
  color: var(--color-text-primary);
}
.ds-table thead th[data-ds-sort]::after {
  content: '↕';
  position: absolute;
  right: var(--space-3);
  opacity: 0.35;
  font-size: var(--font-size-xs);
}
.ds-table thead th[data-ds-sort-dir="asc"]::after { content: '↑'; opacity: 1; color: var(--color-brand-600); }
.ds-table thead th[data-ds-sort-dir="desc"]::after { content: '↓'; opacity: 1; color: var(--color-brand-600); }
.ds-table tbody td {
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--color-border-subtle);
  vertical-align: middle;
}
.ds-table tbody tr:hover {
  background: var(--color-surface-subtle);
}
.ds-table tbody tr:last-child td {
  border-bottom: none;
}
.ds-table-wrap .ds-table__footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-3) var(--space-5);
  border-top: 1px solid var(--color-border-default);
  background: var(--color-surface-page);
  font-size: var(--font-size-sm);
  color: var(--color-text-secondary);
  flex-wrap: wrap;
  gap: var(--space-3);
}
.ds-pagination {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
}
.ds-pagination__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 32px;
  height: 32px;
  padding: 0 var(--space-2);
  border: 1px solid var(--color-border-default);
  background: var(--color-surface-card);
  color: var(--color-text-secondary);
  border-radius: var(--radius-sm);
  font-size: var(--font-size-sm);
  cursor: pointer;
  transition: var(--transition-colors);
}
.ds-pagination__btn:hover:not(:disabled) {
  background: var(--color-surface-subtle);
  color: var(--color-text-primary);
}
.ds-pagination__btn.is-active {
  background: var(--color-brand-600);
  color: var(--color-text-on-brand);
  border-color: var(--color-brand-600);
}
.ds-pagination__btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}


/* ============================================================
   10. UTILITY — Visually Hidden (a11y)
   ============================================================ */
.ds-sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}


/* ============================================================
   11. PROGRESS BAR (.ds-progress) — VIS-P2-10
   ============================================================
   单色版本,替代 style.css 内 5 种 .progress-bar-gradient-* 渐变。
   渐变版本保留作兼容 (已加 @deprecated 注释),新代码请用 .ds-progress。

   用法:
     <div class="ds-progress">
       <div class="ds-progress__bar ds-progress--brand" style="width:60%"></div>
     </div>
   variants: brand / success / warning / danger / info / neutral

   注: 内层 width 由调用方通过 inline style 设置 (动态值,合理 inline)。
   ============================================================ */
.ds-progress {
  display: block;
  width: 100%;
  height: 6px;
  background: var(--color-surface-emphasis);
  border-radius: var(--radius-full);
  overflow: hidden;
}
.ds-progress--lg { height: 10px; }
.ds-progress--sm { height: 4px; }

.ds-progress__bar {
  display: block;
  height: 100%;
  border-radius: var(--radius-full);
  background: var(--color-brand-600); /* 默认 */
  transition: width var(--motion-duration-base) var(--motion-easing-standard);
}

.ds-progress--brand   .ds-progress__bar,
.ds-progress__bar.ds-progress--brand   { background: var(--color-brand-600); }
.ds-progress--success .ds-progress__bar,
.ds-progress__bar.ds-progress--success { background: var(--color-success-600); }
.ds-progress--warning .ds-progress__bar,
.ds-progress__bar.ds-progress--warning { background: var(--color-warning-600); }
.ds-progress--danger  .ds-progress__bar,
.ds-progress__bar.ds-progress--danger  { background: var(--color-danger-600); }
.ds-progress--info    .ds-progress__bar,
.ds-progress__bar.ds-progress--info    { background: var(--color-info-600); }
.ds-progress--neutral .ds-progress__bar,
.ds-progress__bar.ds-progress--neutral { background: var(--color-neutral-500); }


/* ============================================================
   12. CHIP (.ds-chip) — VIS-P2-11
   ============================================================
   单一 chip 样式,统一替代 style.css 内 .filter-chip / .chip 等
   零散定义。.filter-chip 已加 @deprecated 注释保留兼容。

   用法:
     <button class="ds-chip">全部</button>
     <button class="ds-chip ds-chip--active">英国</button>
     <button class="ds-chip ds-chip--filter ds-chip--active">活跃</button>

   variants:
     base       默认外观
     --filter   筛选器场景 (轻量 outline)
     --active   选中态
     --sm       紧凑尺寸
   ============================================================ */
.ds-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-full);
  border: 1px solid var(--color-border-default);
  background: var(--color-surface-card);
  color: var(--color-text-secondary);
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-medium);
  line-height: 1.4;
  cursor: pointer;
  transition: var(--transition-colors);
  white-space: nowrap;
  user-select: none;
}
.ds-chip:hover {
  border-color: var(--color-brand-300);
  color: var(--color-brand-700);
}
.ds-chip:focus-visible {
  outline: none;
  box-shadow: var(--shadow-focus);
  border-color: var(--color-brand-600);
}
.ds-chip.ds-chip--active,
.ds-chip[aria-pressed="true"] {
  background: var(--color-brand-600);
  border-color: var(--color-brand-600);
  color: var(--color-text-on-brand);
}
.ds-chip.ds-chip--active:hover,
.ds-chip[aria-pressed="true"]:hover {
  background: var(--color-brand-700);
  border-color: var(--color-brand-700);
  color: var(--color-text-on-brand);
}
.ds-chip--filter {
  background: transparent;
}
.ds-chip--sm {
  padding: 2px var(--space-2);
  font-size: var(--font-size-xs);
}
.ds-chip:disabled,
.ds-chip[aria-disabled="true"] {
  opacity: 0.5;
  cursor: not-allowed;
}

.ds-chip-group {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}
