/**
 * 表单类组件：Button / Input / Select / Switch（开发清单 2.5）。
 *
 * 色值一律走 var(--color-*)，不硬编码（2.4）。
 * 依赖 tokens.css + base.css。
 */

/* ============ Button ============ */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  height: 32px;
  padding: 0 var(--space-4);
  border-radius: var(--radius-m);
  font-size: var(--text-body-2);
  line-height: 1;
  font-weight: var(--weight-medium);
  white-space: nowrap;
  border: 1px solid transparent;
  transition: background var(--duration-fast), border-color var(--duration-fast),
              color var(--duration-fast);
}

/*
 * 同 .field[hidden]（上面那条）：display:inline-flex 会压过浏览器默认的
 * [hidden]{display:none}，少了这条，JS 里对按钮写 `el.hidden = true` 不生效
 * 且不报错。布局配置页新建态要藏「进编辑器微调」按钮就靠它。
 */
.btn[hidden] { display: none; }

/* 同步态:JS 把按钮加上 .is-syncing 后,其内 svg 图标持续旋转
   —— 复用 components-data.css 里的 @keyframes spin。三个页面
   (工作台/接口配置/订单)统一走这个 class,不各写一遍动画 */
.btn.is-syncing > svg,
.ig-btn.is-syncing > svg {
  animation: spin 0.8s linear infinite;
  transform-origin: center;
}

.btn:disabled,
.btn[aria-disabled="true"] {
  cursor: not-allowed;
  /* 禁用态统一压到 60%，不逐个组件调色。
     纯灰会让"禁用的主按钮"和"禁用的危险按钮"长得一样，运营分不出刚才点的是什么 */
  opacity: 0.6;
}

/* 主按钮 */
.btn-primary {
  background: var(--color-primary-500);
  color: var(--color-text-inverse);
}
.btn-primary:not(:disabled):hover { background: var(--color-primary-600); }
.btn-primary:not(:disabled):active { background: var(--color-primary-700); }
/* 链接按钮同时命中全局 a:hover 时仍保持白色文字，避免蓝底蓝字看似空白。 */
a.btn.btn-primary,
a.btn.btn-primary:hover,
a.btn.btn-primary:focus-visible { color: var(--color-text-inverse) !important; }

/* 次按钮：描边 */
.btn-secondary {
  background: var(--color-neutral-0);
  border-color: var(--color-border-strong);
  color: var(--color-text-secondary);
}
.btn-secondary:not(:disabled):hover {
  border-color: var(--color-primary-500);
  color: var(--color-primary-500);
}

/* 文字按钮：表格行内操作用 */
.btn-text {
  height: auto;
  padding: 0 var(--space-1);
  color: var(--color-primary-500);
}
.btn-text:not(:disabled):hover { color: var(--color-primary-600); }

/* 危险按钮：删除、撤销发布 */
.btn-danger {
  background: var(--color-danger-500);
  color: var(--color-text-inverse);
}
.btn-danger:not(:disabled):hover { filter: brightness(0.92); }

/* 危险文字按钮：表格里的"删除" */
.btn-text-danger {
  height: auto;
  padding: 0 var(--space-1);
  color: var(--color-danger-500);
}

.btn-lg { height: 40px; padding: 0 var(--space-5); font-size: var(--text-body-1); }
.btn-sm { height: 24px; padding: 0 var(--space-3); font-size: var(--text-caption); }
.btn-block { width: 100%; }

/**
 * 按钮内的图标。**这条是必需的兜底，不是美化**：只带 viewBox、不带
 * width/height 的 svg 没有固有尺寸，浏览器按 300×150 铺开 ——
 * 在 flex 按钮里会把「导出」两个字挤出屏幕。
 * 稿件里按钮图标一律 15，所以在这里统一给，页面不必逐处写。
 */
.btn > svg { width: 15px; height: 15px; flex-shrink: 0; }

/* ============ Input ============ */

.field {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

/*
 * `display:flex` 会压过浏览器默认样式表里的 [hidden]{display:none}，
 * 所以这条必须显式写出来 —— 少了它，JS 里的 `el.hidden = true` 对任何
 * .field 都毫无作用，而且不报错：字段照样占位，只是没人知道为什么。
 *
 * 放在这里而不是各页面自己补：这个坑已经在四处分别踩过（活动编辑页的
 * H5 展示项、管理员抽屉的密码/启用块……）。谁都可能给 .field 加 hidden，
 * 补在组件层才不用每次重新发现一遍。
 */
.field[hidden] { display: none; }

.field-label {
  font-size: var(--text-body-2);
  color: var(--color-text-secondary);
}

/* 必填星号。放在 label 里而不是靠 placeholder 暗示 —— placeholder 一输入就没了 */
.field-label.required::before {
  content: "*";
  color: var(--color-danger-500);
  margin-right: var(--space-1);
}

.input,
.textarea,
.select {
  width: 100%;
  height: 32px;
  padding: 0 var(--space-3);
  background: var(--color-neutral-0);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-s);
  font-size: var(--text-body-2);
  color: var(--color-text-primary);
  transition: border-color var(--duration-fast);
}

.textarea {
  height: auto;
  min-height: 80px;
  padding: var(--space-2) var(--space-3);
  line-height: var(--text-body-2-lh);
  resize: vertical;
}

.input::placeholder,
.textarea::placeholder {
  color: var(--color-text-disabled);
}

.input:hover,
.textarea:hover,
.select:hover {
  border-color: var(--color-border-strong);
}

.input:disabled,
.textarea:disabled,
.select:disabled {
  background: var(--color-bg-disabled);
  color: var(--color-text-disabled);
  cursor: not-allowed;
}

/* 校验失败态。除了变红还要配 .field-error 文字 ——
   只靠颜色表达错误，色盲用户看不出哪一栏出了问题 */
.input.is-error,
.textarea.is-error,
.select.is-error {
  border-color: var(--color-danger-500);
}

.field-error {
  font-size: var(--text-caption);
  line-height: var(--text-caption-lh);
  color: var(--color-danger-500);
}

.field-hint {
  font-size: var(--text-caption);
  line-height: var(--text-caption-lh);
  color: var(--color-text-tertiary);
}

/**
 * 校验通过态（稿件 `rp1Xq` 的活动短码：绿边框 + 对勾 + 一行绿字）。
 *
 * 有 `.is-error` 就该有这一档：短码要查重，「查过了，能用」和
 * 「还没查」必须在界面上分得开 —— 否则用户不知道那次远端校验有没有发生。
 */
.input.is-success { border-color: var(--color-success-500); }

.field-success {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  font-size: var(--text-caption);
  line-height: var(--text-caption-lh);
  color: var(--color-success-500);
}

/* 输入框与它右侧的状态图标并排。稿件里短码框只有 200 宽，
   剩下的横向空间给对勾，不让输入框独占整行 */
.field-inline {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

/* 定宽输入框：短码、人数这类值域已知的字段，撑满整行反而显得能填很长 */
.input.is-narrow { width: 200px; flex-shrink: 0; }

/* 只读态：作为 <span> 显示已保存值时用。看着像 input 但不可编辑，也没光标 */
.input.is-readonly {
  background: var(--color-neutral-50);
  color: var(--color-text-secondary);
  cursor: default;
  user-select: text;
  word-break: break-all;
  display: block;
}
.input.is-readonly[hidden] { display: none; }

/* 等宽数字：短码、日期时间、金额。比例字体下 `2026-09-12 18:30`
   的数字宽窄不一，两个时间上下并排时对不齐，读不出「差了几小时」 */
.input.is-code {
  font-family: var(--font-num);
  font-variant-numeric: tabular-nums;
}

/**
 * 一行两栏的字段对（场馆/地址、开始/结束时间、预计/实际人数）。
 *
 * 不复用 `.form-grid`：抽屉里 `.form-grid` 被刻意压成单列
 * （components-page.css），而这三对**必须并排** —— 它们是成对读的，
 * 拆成上下两行就得靠 label 才知道哪个是开始哪个是结束。
 * 560 的抽屉减去内距还有 512，两栏各 244 够放 `2026-09-12 18:30`。
 */
.field-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-4);
}

.field-icon { width: 15px; height: 15px; flex-shrink: 0; }
.field-icon.is-success { color: var(--color-success-500); }

/**
 * 输入框内的前置图标（场馆的 map-pin、时间的 calendar-days）。
 *
 * 图标叠在 input 上并把 padding-left 让出来，而不是放在 input 外面：
 * 放外面时聚焦边框只框住输入框本体，图标被留在框外，看着像两个控件。
 */
.input-icon {
  position: relative;
  display: block;
}

.input-icon > svg {
  position: absolute;
  left: var(--space-3);
  top: 50%;
  width: 15px;
  height: 15px;
  transform: translateY(-50%);
  color: var(--color-text-disabled);
  pointer-events: none;      /* 点图标要能聚焦到输入框 */
}

/* 只在真有前置图标时让出左内距。`.input-icon` 也被「人数 + 人」这类
   只有后缀的字段当定位容器用，无条件加就会多出一段空白，
   光标落在框中间，像是里面已经有内容了 */
.input-icon:has(> svg) .input { padding-left: var(--space-8); }

/* 单位后缀（「人」「元」）。同样叠在框内右侧 */
.input-icon > .input-suffix {
  position: absolute;
  right: var(--space-3);
  top: 50%;
  transform: translateY(-50%);
  font-size: var(--text-body-2);
  color: var(--color-text-tertiary);
  pointer-events: none;
}

.input-icon:has(> .input-suffix) .input { padding-right: var(--space-8); }

/* ============ Select ============ */

/**
 * 箭头。
 *
 * 不能把箭头做成 .select 自己的 background-image ——
 * data URI 里的颜色是死的，CSS 变量进不去，于是箭头颜色永远脱离令牌体系。
 *
 * 改成外层 ::after + mask：SVG 只提供形状（mask 只看 alpha 通道），
 * 颜色由 background-color 从令牌取。这样箭头跟着 disabled、
 * 跟着将来可能的换色一起变，且不留任何字面色值。
 */
.select-wrap {
  position: relative;
  display: block;
  width: 100%;
}

/* 同 .field[hidden]：display:block 会压过默认 [hidden]{display:none}。
   布局配置页编辑态要藏关联活动下拉（改用只读 #event-fixed）就靠它。 */
.select-wrap[hidden] { display: none; }

.select-wrap::after {
  content: "";
  position: absolute;
  right: var(--space-3);
  top: 50%;
  width: 12px;
  height: 12px;
  transform: translateY(-50%);
  pointer-events: none;       /* 点箭头也要能展开下拉 */
  background-color: var(--color-text-tertiary);
  --arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M6 8.95 10.5 4.45 9.1 3.05 6 6.15 2.9 3.05 1.5 4.45Z'/%3E%3C/svg%3E");
  -webkit-mask-image: var(--arrow);
  mask-image: var(--arrow);
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}

.select-wrap:has(.select:disabled)::after {
  background-color: var(--color-text-disabled);
}

.select {
  appearance: none;
  -webkit-appearance: none;
  padding-right: var(--space-8);
}

/* ============ Switch（H5 展示项开关用，清单 8.1.6a）============ */

.switch {
  position: relative;
  display: inline-block;
  width: 40px;
  height: 22px;
  flex-shrink: 0;
}

.switch input {
  position: absolute;
  opacity: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  cursor: pointer;
}

.switch-track {
  display: block;
  width: 100%;
  height: 100%;
  background: var(--color-neutral-300);
  border-radius: var(--radius-full);
  transition: background var(--duration-base);
  pointer-events: none;
}

.switch-track::after {
  content: "";
  position: absolute;
  top: 3px;
  left: 3px;
  width: 16px;
  height: 16px;
  background: var(--color-neutral-0);
  border-radius: var(--radius-full);
  transition: transform var(--duration-base);
}

.switch input:checked + .switch-track {
  background: var(--color-primary-500);
}

.switch input:checked + .switch-track::after {
  transform: translateX(18px);
}

.switch input:focus-visible + .switch-track {
  box-shadow: var(--focus-ring);
}

/* ============ Checkbox（登录「记住我」、权限矩阵、批量勾选用）============ */

/**
 * 原生 input 藏起来但保留可聚焦，勾选框靠相邻的 .checkbox-box 画。
 *
 * 不直接 appearance:none 改 input：那样没法在勾选态叠自定义对勾，
 * 各浏览器原生勾的粗细也不一，和这套描边风格对不上。
 * input 用 opacity:0 而非 display:none —— 后者会让它退出 Tab 序，
 * 键盘用户就跳不到这个勾选框了。
 */
.checkbox {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  cursor: pointer;
  font-size: var(--text-body-2);
  color: var(--color-text-secondary);
}

.checkbox input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}

.checkbox-box {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  border-radius: var(--radius-s);
  border: 1px solid var(--color-border-strong);
  background: var(--color-neutral-0);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--color-text-inverse);
  transition: background var(--duration-fast), border-color var(--duration-fast);
}

/* 对勾常态收成 scale(0)，勾选时弹出 —— 有个短过渡，不是硬切 */
.checkbox-box svg {
  width: 12px;
  height: 12px;
  transform: scale(0);
  transition: transform var(--duration-fast);
}

.checkbox input:checked + .checkbox-box {
  background: var(--color-primary-500);
  border-color: var(--color-primary-500);
}
.checkbox input:checked + .checkbox-box svg { transform: scale(1); }

.checkbox input:focus-visible + .checkbox-box {
  box-shadow: var(--focus-ring);
}

.checkbox input:disabled + .checkbox-box {
  background: var(--color-bg-disabled);
  border-color: var(--color-border);
}
.checkbox input:disabled ~ * { color: var(--color-text-disabled); }

/* ============ 数字步进器（布局参数「排数 / 每排座位数」等，稿件 `jIajC`）============ */

/**
 * −│ 值 单位 │+ 一体框。两端按钮换浅底把点击区标出来 ——
 * 纯文字的 ± 在密排参数里容易点空。中间值用等宽数字：连点加减时
 * 「9 → 10 → 11」宽度不该跳，跳一下会让人以为点重了。
 */
.stepper {
  display: flex;
  align-items: center;
  height: 36px;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-m);
  background: var(--color-neutral-0);
  overflow: hidden;
}

.stepper-btn {
  width: 34px;
  height: 100%;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--color-neutral-50);
  color: var(--color-text-secondary);
  cursor: pointer;
}
.stepper-btn:hover { background: var(--color-neutral-100); color: var(--color-text-primary); }
.stepper-btn:disabled { color: var(--color-text-disabled); cursor: not-allowed; }
.stepper-btn svg { width: 14px; height: 14px; }

/* 值 + 单位居中并排。unit 淡一档，不和数值抢读 */
.stepper-val {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: var(--space-1);
}
.stepper-num {
  font-family: var(--font-num);
  font-variant-numeric: tabular-nums;
  font-size: var(--text-body-2);
  font-weight: var(--weight-semibold);
  color: var(--color-text-primary);
}
.stepper-unit { font-size: var(--text-caption); color: var(--color-text-tertiary); }
