/* Arena Growth Hub — 统一视觉 */
:root{
  --brand:#4C6EF5; --brand-dark:#364FC7; --brand-soft:#EDF2FF;
  --ok:#2F9E44; --warn:#F08C00; --danger:#E8590C; --info:#15AABF;
  --ink:#212529; --ink2:#495057; --mut:#868E96;
  --bg:#F4F6FB; --card:#fff; --line:#E7ECF5;
  --radius:12px; --shadow:0 2px 10px rgba(30,41,99,.07);
}
*{box-sizing:border-box;margin:0;padding:0}
html,body{height:100%}
body{
  font-family:"Microsoft YaHei","PingFang SC","Segoe UI",system-ui,sans-serif;
  background:var(--bg); color:var(--ink); font-size:14px; line-height:1.55;
}
button{font-family:inherit;cursor:pointer}
input,select,textarea{font-family:inherit;font-size:14px;color:var(--ink)}

/* ---------- 顶栏 ---------- */
.topbar{
  position:sticky;top:0;z-index:50;display:flex;align-items:center;gap:18px;
  background:linear-gradient(90deg,#232B4A,#364FC7 60%,#4C6EF5);
  color:#fff;padding:0 22px;height:56px;box-shadow:0 2px 12px rgba(20,30,80,.25);
}
.brand{font-size:18px;font-weight:800;letter-spacing:.5px;cursor:pointer;white-space:nowrap;display:flex;align-items:center;gap:8px}
.brand span{background:linear-gradient(120deg,#fff,#B9C7FF);-webkit-background-clip:text;background-clip:text;color:transparent}
nav{display:flex;gap:4px;flex:1;overflow-x:auto}
.nav-item{
  border:0;background:transparent;color:#D6DEFF;padding:8px 14px;border-radius:8px;
  font-size:14px;white-space:nowrap;transition:.15s;
}
.nav-item:hover{background:rgba(255,255,255,.12);color:#fff}
.nav-item.active{background:#fff;color:var(--brand-dark);font-weight:700}
/* 回收站入口的小红点：有几条快被永久清掉就显示数字 */
.nav-dot{
  display:none;margin-left:5px;min-width:16px;height:16px;line-height:16px;padding:0 4px;
  border-radius:8px;background:#FF6B6B;color:#fff;font-size:11px;font-style:normal;
  font-weight:700;text-align:center;vertical-align:middle;
}
.nav-item.active .nav-dot{background:#E03131}
.userbox{display:flex;align-items:center;gap:10px}
.user-name{font-size:13px;opacity:.95}
.ghost{background:transparent;border:1px solid rgba(255,255,255,.45);color:#fff;border-radius:7px;padding:4px 10px;font-size:12px}
.ghost:hover{background:rgba(255,255,255,.15)}

/* ---------- 布局 ---------- */
/* ⚠️ 防横向溢出的三条（少一条就会出现"左边空一块、右边要拖着看"）：
   1) 长网址/长单词必须能断行（情报出处全是 https://…，不断行就把容器顶宽）；
   2) 栅格与弹性子项允许收缩（grid/flex 子项默认 min-width:auto，会被内容撑住）；
   3) 容器宽度按视口收（min(1440px, 100%)）并居中，宽屏不靠左不靠右。            */
.container{width:100%;max-width:min(1440px,100%);margin:0 auto;padding:20px 22px 60px}
.grid>*{min-width:0}
.row>*{min-width:0}
.card{min-width:0;overflow-wrap:anywhere}
.card *,.modal *,.small,a,td,th,button{overflow-wrap:anywhere}
img,svg,canvas,video{max-width:100%;height:auto}
.table-scroll{overflow-x:auto;max-width:100%}
html,body{max-width:100%}
/* 弹窗打开时 <html> 会 overflow:hidden，竖向滚动条一消失，整页内容会横向抖 ~15px。
   钉住这条槽位，开/关弹窗时页面宽度不动（配合 ui.js 的记住/恢复滚动位置，
   关掉详情才不会"跳回顶部 + 闪一下"）。 */
html{scrollbar-gutter:stable}
/* ⚠️ 元素长这样：<div class="modal" id="modal-box">。以前写的是 .modal-box（class 选择器），
   从来没有匹配到任何东西 —— 于是 openModal({width:'860px'}) 那种**内联宽度**没有上界，
   窗口比它窄时弹窗直接横向溢出、右边的按钮掉到屏幕外（就是用户说的"往右拉还超屏"）。
   改成给 .modal 本身兜底：内联宽度仍然生效，但永远不会超过视口。 */
.modal{max-width:calc(100vw - 20px)}
.view h1.page-title{font-size:22px;margin-bottom:4px}
.page-sub{color:var(--mut);font-size:13px;margin-bottom:18px}
.grid{display:grid;gap:16px}
.grid.cols-2{grid-template-columns:repeat(2,1fr)}
.grid.cols-3{grid-template-columns:repeat(3,1fr)}
.grid.cols-4{grid-template-columns:repeat(4,1fr)}
@media(max-width:1080px){.grid.cols-4{grid-template-columns:repeat(2,1fr)}.grid.cols-3{grid-template-columns:repeat(2,1fr)}}
@media(max-width:720px){.grid.cols-2,.grid.cols-3,.grid.cols-4{grid-template-columns:1fr}}
/* ---------- 手机端（作者：「能够通过手机进行账号登录」，2026-09-29）----------
   三条各治一个实测症状：
   1) 输入框 font-size 必须 ≥16px —— iOS Safari 看到小于 16px 会**自动放大整页**，
      一放大就出现"输完密码看不见自己在打什么、要左右拖"；
   2) 按钮要有最小高度，手指点不准不是"体验差"，是"登不进来"；
   3) 登录卡片与容器按屏宽收窄，别把 420px 的卡片顶出 375px 的屏。            */
.auth-card input{font-size:16px}
.auth-forgot{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-top:12px;font-size:13px}
.auth-forgot a{color:var(--brand);text-decoration:none;font-weight:600}
.forgot-panel{margin-top:10px;padding:12px 14px;border:1px solid var(--line);
  border-radius:10px;background:rgba(255,255,255,.04)}
.forgot-panel label{display:block;margin-top:10px;font-size:13px}
.forgot-panel input{width:100%;margin-top:4px;padding:9px 11px;font-size:16px;
  border-radius:8px;border:1px solid var(--line);background:transparent;color:inherit}
@media(max-width:720px){
  .container{padding:14px 12px 48px}
  .auth-card{padding:18px 15px !important;max-width:100%;box-sizing:border-box}
  button,.btn-primary,.btn-ghost2{min-height:40px}
  .topbar{flex-wrap:wrap;gap:8px}
  .auth-tabs .tab{flex:1;min-width:0}
}

.card{background:var(--card);border:1px solid var(--line);border-radius:var(--radius);box-shadow:var(--shadow);padding:18px}
.card h3{font-size:15px;margin-bottom:12px;display:flex;align-items:center;gap:8px}
.card h3 .more{margin-left:auto;font-size:12px;font-weight:400}

/* ---------- 徽章/状态 ---------- */
.badge{display:inline-flex;align-items:center;gap:4px;padding:2px 9px;border-radius:20px;font-size:12px;font-weight:600;white-space:nowrap;flex:0 0 auto}
/* 卡片头部那行：状态徽标不许被标题挤成竖排（实测「🔥 报名倒计时」变成一列字盖到内容上），
   标题让位、可折行；两者都装不下时整行换行。 */
.comp-card .row.between{flex-wrap:wrap;row-gap:6px}
.comp-card .row.between > div{min-width:0;flex:1 1 auto}
.comp-card .badge{align-self:flex-start}
.badge.registering{background:#FFF0EB;color:#D6336C}
.badge.upcoming{background:var(--brand-soft);color:var(--brand)}
.badge.ongoing{background:#EBFBEE;color:var(--ok)}
.badge.archived{background:#F1F3F5;color:var(--mut)}
.badge.unscheduled{background:#FFF9DB;color:#B08900}
.tag{display:inline-block;background:#EEF2FF;color:var(--brand-dark);border-radius:6px;padding:1px 8px;font-size:12px;margin:2px 4px 2px 0}
.tag.scope{background:#E6FCF5;color:#087F5B}
.tag.form{background:#FFF4E6;color:#E8590C}
.tag.diff{background:#F3F0FF;color:#7048E8}
.pill{background:#F1F3F5;border-radius:14px;padding:1px 9px;font-size:12px;color:var(--ink2)}

/* ---------- 按钮 ---------- */
.btn-primary,.btn-soft,.btn-danger,.btn-ghost2{
  border:0;border-radius:8px;padding:7px 14px;font-size:13px;transition:.15s;display:inline-flex;align-items:center;gap:6px;
}
.btn-primary{background:var(--brand);color:#fff}
.btn-primary:hover{background:var(--brand-dark)}
.btn-soft{background:var(--brand-soft);color:var(--brand-dark)}
.btn-soft:hover{background:#DBE4FF}
.btn-danger{background:#FFF0EB;color:var(--danger)}
.btn-danger:hover{background:#FFE3DE}
.btn-ghost2{background:#fff;color:var(--ink2);border:1px solid var(--line)}
.btn-ghost2:hover{border-color:#B8C3E0;color:var(--ink)}
.block{width:100%;justify-content:center}
button:disabled{opacity:.5;cursor:not-allowed}

/* ---------- 输入 ---------- */
.field{margin-bottom:12px}
.field label{display:block;font-size:12.5px;color:var(--ink2);margin-bottom:4px;font-weight:600}
input[type=text],input[type=password],input[type=number],input[type=date],input[type=url],
select,textarea{
  width:100%;border:1px solid #D5DCEB;border-radius:8px;padding:7px 10px;background:#fff;outline:none;
}
input:focus,select:focus,textarea:focus{border-color:var(--brand);box-shadow:0 0 0 3px rgba(76,110,245,.15)}
textarea{resize:vertical;min-height:70px}
.inline{display:flex;gap:10px;flex-wrap:wrap}
.inline>*{flex:1;min-width:120px}
.hint{color:var(--mut);font-size:11.5px}
.row{display:flex;align-items:center;gap:8px}
.toolbar{display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin-bottom:16px}
.searchbox{flex:1;min-width:220px;position:relative}
.searchbox input{padding-left:32px}
.searchbox::before{content:"🔍";position:absolute;left:10px;top:8px;font-size:13px;opacity:.6}

/* ---------- 登录 ---------- */
.auth-screen{
  position:fixed;inset:0;z-index:200;display:flex;align-items:center;justify-content:center;
  background:linear-gradient(135deg,#1B2140 0%,#2B3A8C 55%,#4C6EF5 100%);
}
.auth-card{background:#fff;border-radius:18px;padding:32px 34px;width:400px;box-shadow:0 18px 60px rgba(0,0,0,.35)}
.auth-logo{font-size:22px;font-weight:800;color:var(--brand-dark);text-align:center}
.auth-sub{text-align:center;color:var(--mut);font-size:12.5px;margin:6px 0 18px}
.auth-tabs{display:flex;background:#F1F3F5;border-radius:10px;padding:4px;margin-bottom:16px}
.auth-tabs .tab{flex:1;border:0;background:transparent;padding:8px;border-radius:8px;font-size:14px}
.auth-tabs .tab.active{background:#fff;font-weight:700;color:var(--brand);box-shadow:0 1px 5px rgba(0,0,0,.08)}
.auth-card label{display:block;font-size:13px;color:var(--ink2);margin:10px 0 4px;font-weight:600}
.auth-card input{width:100%;border:1px solid #D5DCEB;border-radius:9px;padding:10px 12px;font-size:14px}
.auth-card .error{color:var(--danger);font-size:13px;min-height:18px;margin:6px 0}
.auth-card #auth-submit{margin-top:6px;padding:11px;font-size:15px}
.auth-demo{text-align:center;color:var(--mut);font-size:12px;margin-top:14px}
.hidden{display:none!important}

/* ---------- 比赛卡片 ---------- */
.comp-card{display:flex;flex-direction:column;gap:8px;transition:.18s;cursor:pointer}
.comp-card:hover{transform:translateY(-2px);box-shadow:0 6px 18px rgba(30,41,99,.13);border-color:#C9D6FF}
.comp-title{font-size:15px;font-weight:700;line-height:1.35;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;min-height:41px}
.comp-title a{color:inherit;text-decoration:none}
.comp-title a:hover{color:var(--brand)}
.comp-org{color:var(--mut);font-size:12px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.comp-dates{font-size:12px;color:var(--ink2)}
.countdown{font-weight:800;font-size:13px}
.countdown.red{color:#E03131}
.countdown.blue{color:var(--brand)}
.footer-bar{display:flex;justify-content:space-between;align-items:center;margin-top:auto;padding-top:8px;border-top:1px dashed var(--line)}

/* 进度条 */
.progress{height:8px;background:#EEF0F6;border-radius:6px;overflow:hidden}
.progress>i{display:block;height:100%;background:linear-gradient(90deg,var(--brand),#748FFC);border-radius:6px;transition:.4s}
.progress.warn>i{background:linear-gradient(90deg,#F08C00,#FFC078)}

/* 倒计时条 */
.countdown-strip{display:flex;gap:10px;overflow-x:auto;padding:2px}
.cd-item{flex:0 0 210px;background:var(--card);border:1px solid var(--line);border-left:4px solid var(--brand);border-radius:10px;padding:10px 12px}
.cd-item.urgent{border-left-color:#E03131;background:#FFF9FA}
.cd-item .cd-title{font-weight:700;font-size:13px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.cd-item .cd-days{font-size:22px;font-weight:800;color:var(--brand)}
.cd-item.urgent .cd-days{color:#E03131}

/* ---------- 表格 ---------- */
table{width:100%;border-collapse:collapse;font-size:13px}
th{text-align:left;color:var(--mut);font-weight:600;font-size:12px;padding:8px 10px;border-bottom:1px solid var(--line)}
td{padding:9px 10px;border-bottom:1px solid #F1F3F5;vertical-align:middle}
tr:hover td{background:#FAFBFF}

/* ---------- 模态 ---------- */
.mask{position:fixed;inset:0;background:rgba(20,25,50,.5);z-index:100;display:flex;align-items:flex-start;justify-content:center;padding:4vh 16px;overflow-y:auto;backdrop-filter:blur(2px)}
.modal{background:#fff;border-radius:16px;width:min(860px,96vw);box-shadow:0 20px 70px rgba(0,0,0,.35);margin-bottom:4vh}
.modal-head{display:flex;align-items:center;gap:10px;padding:16px 22px;border-bottom:1px solid var(--line);position:sticky;top:0;background:#fff;border-radius:16px 16px 0 0;z-index:5}
.modal-head h2{font-size:17px;flex:1}
.modal-close{border:0;background:#F1F3F5;border-radius:8px;width:30px;height:30px;font-size:15px}
.modal-body{padding:20px 22px}
.modal-foot{padding:14px 22px;border-top:1px solid var(--line);display:flex;justify-content:flex-end;gap:10px;border-radius:0 0 16px 16px}

/* ---------- 档案详情 ---------- */
.stage-row{display:flex;gap:12px;padding:14px;border:1px solid var(--line);border-radius:12px;margin-bottom:10px;background:#fff;transition:.15s}
.stage-row.done{border-color:#B2F2BB;background:#F6FFF8}
.stage-row.active{border-color:var(--brand);box-shadow:0 0 0 3px rgba(76,110,245,.12)}
.stage-idx{width:34px;height:34px;border-radius:50%;background:#F1F3F5;display:flex;align-items:center;justify-content:center;font-weight:800;flex:0 0 auto;color:var(--ink2)}
.stage-row.done .stage-idx{background:var(--ok);color:#fff}
.stage-main{flex:1;min-width:0}
.stage-label{font-weight:700}
.stage-hint{color:var(--mut);font-size:12px}
.stage-notes{margin-top:8px;display:grid;gap:10px}
.stage-notes .row2{display:flex;gap:8px}
.coord{display:inline-flex;align-items:center;gap:6px;background:#FFF4E6;border-radius:8px;padding:4px 10px;font-size:12px;margin-right:8px}
.coord b{color:#E8590C}
.mini-text{width:100%;border:1px solid #E3E8F2;border-radius:8px;padding:6px 9px;font-size:12.5px;outline:none}
.mini-text:focus{border-color:var(--brand)}
.evidence{display:flex;gap:8px;flex-wrap:wrap;align-items:center}
.thumb{border-radius:8px;width:76px;height:56px;object-fit:cover;border:1px solid var(--line);cursor:zoom-in;background:#F8F9FA}
.filechip{display:flex;align-items:center;gap:6px;background:#F1F3F5;border-radius:8px;padding:5px 10px;font-size:12px;max-width:200px}
.filechip span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.del-x{color:var(--danger);border:0;background:none;font-size:14px;cursor:pointer}
.slider-row{display:flex;align-items:center;gap:8px}
.slider-row input{flex:1}
.slider-row output{font-weight:800;color:var(--brand);width:16px}

/* 情绪与复盘的字段 */
.journal-field{border:1px solid #E3E8F2;border-radius:10px;padding:10px 12px;margin-bottom:10px}
.journal-field .jf-label{font-size:12px;font-weight:700;color:var(--ink2);display:flex;justify-content:space-between}
.journal-field textarea{border:0;padding:6px 0 0;font-size:13px;background:transparent}
.journal-field textarea:focus{box-shadow:none}

/* ---------- 分析页 ---------- */
.stat-tile{background:var(--card);border:1px solid var(--line);border-radius:var(--radius);padding:16px 18px;box-shadow:var(--shadow)}
.stat-tile .num{font-size:30px;font-weight:800;color:var(--brand-dark);line-height:1.2}
.stat-tile .lbl{color:var(--mut);font-size:12.5px;margin-top:2px}
.chart-box{background:var(--card);border:1px solid var(--line);border-radius:var(--radius);padding:14px;box-shadow:var(--shadow)}
.chart-box img{width:100%;height:auto;display:block}
.captain{background:linear-gradient(135deg,#FFF9DB,#FFF3BF);border:1px solid #FFE8A1;border-radius:14px;padding:16px 18px;margin-top:16px}
.captain h4{color:#9C6B00;margin-bottom:6px}

/* ---------- 履历 ---------- */
.portfolio-pick{display:flex;align-items:flex-start;gap:12px;border:1px solid var(--line);border-radius:12px;padding:12px 14px;margin-bottom:10px;cursor:pointer;transition:.15s}
.portfolio-pick:hover{border-color:#C9D6FF}
.portfolio-pick.checked{background:var(--brand-soft);border-color:var(--brand)}
.portfolio-pick input{margin-top:4px;accent-color:var(--brand)}
.portfolio-pick .pp-title{font-weight:700}
.portfolio-pick .pp-meta{font-size:12px;color:var(--mut);margin-top:3px}
.summary-cut{font-size:12.5px;color:var(--ink2);margin-top:6px;-webkit-line-clamp:2;display:-webkit-box;-webkit-box-orient:vertical;overflow:hidden}

/* ---------- toast ---------- */
.toasts{position:fixed;top:66px;right:18px;z-index:300;display:flex;flex-direction:column;gap:8px}
.toast{background:#1F2937;color:#fff;border-radius:10px;padding:10px 16px;font-size:13px;box-shadow:0 6px 20px rgba(0,0,0,.25);animation:slidein .25s;max-width:340px}
.toast.ok{background:#18794E}.toast.err{background:#C92A2A}.toast.warn{background:#B08900}
@keyframes slidein{from{transform:translateX(30px);opacity:0}to{transform:none;opacity:1}}

/* ---------- 空态 / misc ---------- */
.empty{text-align:center;color:var(--mut);padding:44px 10px;font-size:14px}
.empty .big{font-size:42px;margin-bottom:8px}
.chip-filter{display:flex;gap:6px;flex-wrap:wrap}
.chip{border:1px solid var(--line);background:#fff;border-radius:20px;padding:4px 12px;font-size:12.5px;color:var(--ink2);cursor:pointer}
.chip.active{background:var(--brand);border-color:var(--brand);color:#fff}
.chip:hover{border-color:var(--brand)}
a.link{color:var(--brand);text-decoration:none}
a.link:hover{text-decoration:underline}
.small{font-size:12px;color:var(--mut)}
.center{text-align:center}
.mt8{margin-top:8px}.mt12{margin-top:12px}.mt16{margin-top:16px}.mb8{margin-bottom:8px}.mb12{margin-bottom:12px}.mb16{margin-bottom:16px}
.flex{display:flex}.between{justify-content:space-between}.gap8{gap:8px}.gap16{gap:16px}.wrap{flex-wrap:wrap}
.loading{text-align:center;color:var(--mut);padding:50px 0}
.spin{display:inline-block;width:26px;height:26px;border:3px solid #DCE3F5;border-top-color:var(--brand);border-radius:50%;animation:rot .8s linear infinite;margin-bottom:8px}
@keyframes rot{to{transform:rotate(360deg)}}
.winbar{display:flex;flex-direction:column;height:100%}

.modal-foot:empty{display:none}
/* 右侧抽屉（openModal(..., {side:true})）：只是版式靠右、内部自己滚。
   ⚠️ 遮罩照常接事件（别再加 pointer-events:none）—— 用户明确要求：
   弹窗打开时滚轮不能带动背后的页面。背景锁定见下面 .noscroll。 */
.mask.side{
  background:rgba(20,25,50,.28);
  padding:0;
  align-items:stretch;
  justify-content:flex-end;
  overflow:hidden;
}
.mask.side .modal{
  width:min(980px,100vw);
  max-width:100vw;
  height:100vh;
  max-height:100vh;
  margin:0;
  border-radius:0;
  overflow-y:auto;
  box-shadow:-18px 0 60px rgba(0,0,0,.30);
  animation:slidedrawer .18s ease-out;
}
/* ⚠️ 名字不能再叫 slidein —— 上面 toast 那边已经有一个 @keyframes slidein，
   CSS 里同名动画后定义的会覆盖前面的，结果 toast 一直用抽屉那套 28px/0.6 透明度的关键帧。 */
@keyframes slidedrawer{from{transform:translateX(28px);opacity:.6}to{transform:none;opacity:1}}
/* 弹窗一开就锁背景滚动：滚轮只作用于弹窗内部；关闭时解锁，滚动位置由浏览器保留不会跳顶 */
html.noscroll,html.noscroll body{overflow:hidden}
/* 只在"外层滚动面"这一层截住滚动链：滚轮不会漏到背后的页面。
   ⚠️ 这里曾经把弹窗盒子连同它的**全部后代**（选择器末尾带一个 `*` 通配）
   一起加了 contain，带 `*` 会把弹窗内部每一个小滚动区（例如「➕ 添加比赛
   档案」里那个赛事候选列表）也截断：鼠标停在列表上、它滚到底之后链本该
   交给外层，外层却被自己那条 contain 挡死 —— 表现就是"有时候划不动，
   得把鼠标挪到别处才能滚"。内部小滚动区要用的是默认的自然接力。
   health_report.py 里有一条反向断言盯着这里别再加回盒子层。 */
.mask,.mask.side .modal{overscroll-behavior:contain}

/* 证据播放器覆盖层：刻意不复用 .mask/#modal-box —— 共用弹窗会把上一个
   弹窗的清理钩子排空执行（见 records.js 的 mediaOverlay 注释），
   在档案里播视频就会顺手 revoke 掉刚取到的 blob。 */
.lb-mask{position:fixed;inset:0;background:rgba(0,0,0,.72);z-index:1200;
  display:flex;align-items:center;justify-content:center;padding:18px;
  overscroll-behavior:contain;overflow:auto}
.lb-box{background:#fff;border-radius:12px;padding:14px 16px;max-width:min(1000px,96vw);
  box-shadow:0 18px 48px rgba(0,0,0,.35)}
.lb-box video{display:block;border-radius:8px;background:#000}


/* ---------- 赛事卡片：修"字重叠、空间挤"（作者 2026-09-30） ---------- */
/* ① 按钮行必须能换行：卡片里 6 颗按钮都是 white-space:nowrap，
      窄卡片（三列时约 300px）装不下就横向溢出，字压到相邻元素上。 */
.comp-card .row{flex-wrap:wrap}
/* ② 全局 .btn-ghost2/.btn-primary/.btn-soft 是 min-height:40px（给正常表单用的），
      卡片上那些 11.5px 的小按钮被顶成 40px 高：小字坐在高框里，又挤又空。 */
.comp-card .btn-ghost2,.comp-card .btn-primary,.comp-card .btn-soft{
  min-height:26px;padding:3px 9px;font-size:11.5px;line-height:1.35;gap:4px}
/* ③ 长标题要能折行：flex 子项默认 min-width:auto，不写 0 就撑破父容器 */
.comp-title{min-width:0;overflow-wrap:anywhere;word-break:normal;line-height:1.35}
.comp-card .tag,.comp-card .countdown,.comp-card .info-badge{flex:0 0 auto}
/* ④ 卡片内所有文字块都不许压到兄弟元素上；标签行允许换行 */
.comp-card{min-width:0;overflow:hidden}
.comp-card > div{min-width:0}
.comp-card .small{line-height:1.5}
/* ⑤ 倒计时/信息那一行的数字与文字之间留口气（先前贴在一起像重叠） */
.comp-card .row.gap8{gap:8px 10px}


/* 按钮那一坨自己占一行（作者 2026-09-30：「读通知那颗被挤到最右边，字都没显示全」）。
   根因：那个 span 带内联 flex-shrink:0 —— 它不许变窄，于是撑破卡片，
   再被我上一轮加的 overflow:hidden 裁掉，表现就是最右边那颗按钮文字缺失。
   必须用 !important 才压得住内联样式。 */
.comp-card .row.between{flex-wrap:wrap;row-gap:6px}
.comp-card .row.between > span.row{
  flex:1 1 100% !important; min-width:0 !important;
  display:flex; flex-wrap:wrap; justify-content:flex-end; gap:6px 7px}
/* 按钮文字不许被截：宁可换一行也不裁字 */
.comp-card .btn-ghost2,.comp-card .btn-primary,.comp-card .btn-soft{
  white-space:normal;overflow:visible;text-overflow:clip;max-width:100%}
/* 标题那行给按钮让出位置后，自己也要能收缩折行 */
.comp-card .row.between > div{min-width:0;flex:1 1 auto}


/* 筛选条那颗「🔥 报名倒计时」被压成一列竖字、还盖到卡片上（作者截图）：
   chip 没有 white-space:nowrap，容器一挤就一个字一行；
   它又是绝对/浮动定位的话会飘到列表上 —— 这里先保证它绝不竖排、且随条换行。 */
.chip{white-space:nowrap;flex:0 0 auto}
.row.wrap,.toolbar,.countdown-strip{flex-wrap:wrap}
/* 卡片里的按钮同理：宁可换行，不许把字压成竖排或裁掉 */
.comp-card .btn-ghost2,.comp-card .btn-primary,.comp-card .btn-soft{flex:0 0 auto}


/* ── 三列布局下卡片底部那行（作者：「我这边三个卡片并列，宽度没你预期的那么宽」）──
   .footer-bar 里塞了三样：状态徽标 + 来源(旧库导入/手动录入) + 6 颗 nowrap 按钮。
   450px 宽的卡片装不下 → 来源那几个字被压成"旧""入"竖排残字。
   之前我写的规则挂在 .row.between 上，容器其实叫 .footer-bar —— 所以完全没生效。 */
.footer-bar{display:flex;align-items:center;flex-wrap:wrap;gap:6px 8px}
.footer-bar > span.row{flex:1 1 100% !important;min-width:0 !important;
  justify-content:flex-end;row-gap:6px}
.footer-bar > span.small{flex:1 1 auto;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* 徽标与来源同一行放得下就同行，放不下各自换行，绝不再挤成竖排 */
.footer-bar .badge{flex:0 0 auto}


/* ── 卡片底部排版（作者：「优化一下排版」）──────────────────────────────
   上一版让按钮自己换行了，但 6 颗右对齐 → 最后一颗「读赛项」孤零零挂在右下角，
   而且每颗宽窄不一。改成三列网格：6 颗正好整齐两行，窄屏两列也不会错位。 */
.footer-bar > span.row{
  display:grid !important;grid-template-columns:repeat(3,minmax(0,1fr));
  gap:6px;flex:1 1 100% !important;min-width:0 !important}
.footer-bar > span.row > button{width:100%;justify-content:center;padding:5px 6px;
  font-size:11.5px;min-height:28px}
/* 徽标 + 来源那一行与按钮块之间给一条明确的间隔，别像散字飘着 */
.footer-bar{row-gap:9px}
.footer-bar > .badge{align-self:flex-start}
/* 来源文字（旧库导入/手动录入）跟在徽标后面，字号降一档、颜色压暗：
   它是次要信息，先前和徽标一样重，看着抢 */
.footer-bar > span.small{font-size:11.5px;color:#ADB5BD;flex:1 1 auto;min-width:0;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
@media(max-width:1080px){
  /* 三列卡片时每张只有 ~450px：按钮两列更好读，最后一颗不会单独悬着 */
  .footer-bar > span.row{grid-template-columns:repeat(2,minmax(0,1fr))}
}


/* ══ 赛事卡片：克制版（第二稿，作者否掉了彩色状态条那一版）══════════
   原则：颜色只用来表达状态，其余靠字号 / 字重 / 间距分层。 */
.comp-card{
  border-radius:12px;border:1px solid #E7EAF0;background:#fff;
  padding:14px 15px 12px;
  box-shadow:0 1px 2px rgba(16,24,40,.04);
  transition:border-color .16s,box-shadow .16s}
.comp-card:hover{border-color:#C9D4F0;box-shadow:0 2px 10px rgba(16,24,40,.07)}
.comp-card:hover{transform:none}
.comp-card:focus-within{border-color:#A5C4FF;box-shadow:0 0 0 3px rgba(76,110,245,.12)}

/* 标题是卡片唯一的主角：字号略升、字重收紧，其余全部降一档 */
.comp-title{font-size:16px;font-weight:650;letter-spacing:-.15px;color:#141A24;line-height:1.35}

/* 标签：一种中性底就够（上一版五种颜色 = 五个视觉焦点，眼睛没地方停） */
.comp-card .tag{border-radius:6px;padding:1px 8px;font-size:11.5px;line-height:1.75;
  border:1px solid transparent;background:#F5F6F8;color:#5A6472}
.comp-card .tag.diff{letter-spacing:.6px;color:#6B7280}
.comp-card .tag.trk-chip{background:#F5F6F8;color:#3F4A5A}

/* 主办方 / 日期：靠灰度和字号退到第二层，不靠颜色 */
.comp-card .comp-org{color:#98A2B3;font-size:12.5px}
.comp-dates{font-size:12.5px;color:#667085;font-variant-numeric:tabular-nums}

/* 资料进度条：只把圆角收干净，不加渐变 */
.comp-card > div[style*="border-radius"],
.comp-card > div[style*="border-radius"] > div{border-radius:999px !important}

/* 底部：一条极轻的分隔；按钮保持安静填充，主按钮只比别的重一点点 */
.footer-bar{border-top:1px solid #F1F3F5;padding-top:10px}
.footer-bar .btn-ghost2,.footer-bar .btn-soft{background:#F7F8FA;border-color:transparent;color:#4B5565}
.footer-bar .btn-ghost2:hover,.footer-bar .btn-soft:hover{background:#EDF0F5;color:#141A24}
.footer-bar .btn-primary{box-shadow:none}
.footer-bar .btn-primary:hover{box-shadow:none}
/* 删除：平时灰、悬停红 —— 这条与配色无关，是防误点，保留 */
.footer-bar .btn-ghost2[style*="C92A2A"]{color:#98A2B3 !important}
.footer-bar .btn-ghost2[style*="C92A2A"]:hover{color:#C92A2A !important;background:#FFF0F0}

@media (prefers-reduced-motion:reduce){.comp-card{transition:none}}

/* ──  窄屏（手机）· 2026-10-09 作者真机截图反馈  ─────────────────────────
   三件事：
   ① 顶栏溢出：上面那条 @media 让 .topbar flex-wrap:wrap，但 .topbar 的 height
      还钉在 56px ⇒ 换行出来的第二三排溢出盒子，压在页面标题上
      （作者手机上「免费版·档案 1/2」盖住「赛事雷达与情报中枢」就是这个）。
   ② 筛选器：外层（装 5 个筛选组）要换行，内层 .chip-filter 才横向滚。
      上一版我写成 `.card.mb16 .row.wrap` 这个后代选择器，两层一起命中 ⇒
      外层被迫不换行 ⇒ 赛道/难度/状态 挤成一条，三个「全部」叠在一起 ✗
   ③ 底部那条快捷键提示：手机上没有 Ctrl/Esc 按键，而且它 fixed 在底下会盖内容
      ⇒ 整条隐藏。代价说清：「密度 / 动效 / 主题」三颗开关在手机上暂时没入口，
        需要的话再单独挪一颗按钮到顶栏（不偷偷砍功能不吭声）。 */
@media(max-width:720px){
  .topbar{height:auto;min-height:56px;padding:8px 12px;flex-wrap:nowrap;gap:10px}
  .topbar .brand{flex:0 0 auto;font-size:16px}
  .topbar .brand span{display:none}
  #main-nav{flex:1 1 auto;min-width:0;display:flex;gap:6px;overflow-x:auto;
            -webkit-overflow-scrolling:touch;scrollbar-width:none}
  #main-nav::-webkit-scrollbar{display:none}
  .nav-item{padding:7px 10px;font-size:13px}
  .userbox{flex:0 0 auto;gap:6px}
  .userbox .pill{max-width:96px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

  /* ② 外层：每个筛选组独占一行（flex:1 1 100% 就是"我要一整行"） */
  .card.mb16 > .row.wrap{flex-wrap:wrap}
  .card.mb16 > .row.wrap > .field{flex:1 1 100%;min-width:0}
  /* 内层：chip 一行放不下就横滑，不换行堆高 */
  .chip-filter{flex-wrap:nowrap;overflow-x:auto;-webkit-overflow-scrolling:touch;
               scrollbar-width:none;padding-bottom:2px}
  .chip-filter::-webkit-scrollbar{display:none}
  .chip{flex:0 0 auto;padding:6px 12px;font-size:13px}

  /* ③ 只收快捷键提示（手机上没有 Ctrl/Esc 按键），三颗开关留着。
     上一版写的是 #agh-kbd{display:none} —— 那会把「密度/动效/主题」一起藏掉，
     手机上就没主题入口了（作者发现）。也别写成 .footer-bar，那是卡片底部操作按钮条。
     这条改成浮在底部标签栏上方的小胶囊：不盖内容，一点就切。 */
  /* bottom 要抬到标签栏之上并加权重：样式有四层，别处也定义了 #agh-kbd，
     上一版写 bottom:74px 被盖住 ⇒ 三颗开关压在标签栏上，点了没反应（实测被
     「📈 成长分析」那颗 nav 按钮 intercepts pointer events）。 */
  #agh-kbd{left:auto !important;right:10px !important;bottom:84px !important;top:auto !important;
           z-index:70 !important;padding:6px 10px;border-radius:999px;
           background:rgba(255,255,255,.96);border:1px solid #DEE2E6;
           box-shadow:0 2px 8px rgba(0,0,0,.16);font-size:12px}
  #agh-kbd .hk{display:none}
  #agh-kbd .agh-chip{margin-left:0;margin-right:6px}
  #agh-kbd .agh-chip:last-child{margin-right:0}
  .container{padding:14px 12px 40px}

  .page-title{font-size:20px;line-height:1.25}
  .page-sub{font-size:12px}
}

/* ──  手机：导航沉到底部当标签栏（作者反馈"顶部那一排太占显示空间"）
   做法是纯 CSS：把 #main-nav 从顶栏里"摘出来"固定到屏幕底部，
   顶栏于是只剩 🏆 与权益/退出 —— 不动结构、不动 JS、桌面完全不受影响。 */
@media(max-width:720px){
  #main-nav{position:fixed;left:0;right:0;bottom:0;top:auto;z-index:60;
            display:flex;overflow-x:auto;gap:2px;padding:5px 4px calc(5px + env(safe-area-inset-bottom));
            background:#fff;border-top:1px solid #DEE2E6;box-shadow:0 -2px 10px rgba(0,0,0,.07);
            scrollbar-width:none}
  #main-nav::-webkit-scrollbar{display:none}
  /* 六项要全放得下（上一版 min-width:56px + 12px 字号，回收站被挤到屏幕外要横滑）
     ⇒ 等分宽度 + 字号收到 11px + 左右内边距压到 2px */
  .nav-item{flex:1 1 0;min-width:0;text-align:center;padding:6px 2px;font-size:11px;
            line-height:1.25;color:#495057;border-radius:9px;white-space:nowrap}
  .nav-item.active{background:var(--brand,#364FC7);color:#fff;font-weight:700}
  .topbar{padding-bottom:8px}
  /* 回到顶部那颗按钮要让开底部标签栏，不然叠在一起 */
  #agh-top{bottom:76px !important}
  /* 内容底部要留出标签栏的高度 */
  body{padding-bottom:66px}
  .container{padding-bottom:76px}
}
/* 筛选折叠那颗按钮：只在窄屏出现，桌面永远展开、不显示按钮 */
#filter-toggle{display:none}
@media(max-width:720px){ #filter-toggle{display:inline-flex} }

/* ──  手机：卡片头部被挤成「一个字一行」的问题（作者截图「太夸张了」）
   量出来的因果：.row.between 里右列占掉 188px ⇒ 左列只剩 140px；
   左列里 .row.gap8 是 flex 且不换行，里面「🎯 赛项标签」不缩 ⇒
   标题 <b> 被压到 17px 宽、349px 高 —— 一个字一行。
   修：这两层在窄屏下允许换行，标题先独占一行，标签超长就省略号。 */
@media(max-width:720px){
  .row.between{flex-wrap:wrap;gap:8px}
  .row.between > *{min-width:0}
  .row.gap8{flex-wrap:wrap}
  .row.gap8 > b{flex:1 1 100%;min-width:0;font-size:15px;line-height:1.35}
  .row.gap8 > .pill, .row.gap8 > .chip, .row.gap8 > span{
    flex:0 1 auto;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .card.mb12 .small.mt8{flex:1 1 100%;min-width:0}
}

/* ──  窄屏：工具栏与表单（作者三张真机截图里的第①③件）
   ① 履历输出「操作」栏：.toolbar 里「操作」这一列只剩 ~110px，里面 .row 不换行
      ⇒ 两颗按钮各 ~55px ⇒ 「🖨 生成履历」被挤成一个字一行。
   ③ 表单页（AI 设置等）：字段与提示文字在窄屏溢出。
   统一做法：窄屏下 .toolbar 让每个 .field 占整行，按钮与提示文字允许折行。 */
@media(max-width:720px){
  .toolbar{flex-wrap:wrap}
  .toolbar > .field, .card .toolbar > .field{flex:1 1 100%;min-width:0}
  .toolbar .row{flex-wrap:wrap;gap:8px}
  .toolbar .row > button{flex:1 1 auto;min-width:0;white-space:normal;line-height:1.3}
  .field{min-width:0}
  .field input, .field select, .field textarea{width:100%;box-sizing:border-box}
  .field .hint, .field .small{white-space:normal;word-break:break-word}
  /* 回收站那段折叠：summary 做得像一行可点的提示，不要浏览器的默认三角 */
  .trash-explain{margin-top:6px}
  .trash-explain summary{cursor:pointer;font-weight:600;color:#8A6100;font-size:13px;
                         list-style:none;padding:6px 0}
  .trash-explain summary::-webkit-details-marker{display:none}
  .trash-explain summary::before{content:'▸ ';}
  .trash-explain[open] summary::before{content:'▾ ';}
  .trash-explain .small{white-space:normal;word-break:break-word}
}

/* ──  赛博风下的手机标签栏（作者：「赛格风时赛事库那颗是浅色、其他都是深色」）
   量出来的两层原因：① 我上一轮给窄屏写的 #main-nav{background:#fff} 只管浅色主题，
   赛博风下整条仍是白底；② cyber.css 给 .nav-item.active 的是浅青渐变，放在白底上
   亮成一片，而未选中项是深色渐变 ⇒ 选中态反而分不清。
   这里给赛博风单独一条深色标签栏，选中态改成「青色描边 + 青字 + 深色底」，
   与未选中项一眼能区分（不能只靠深浅一档）。 */
@media(max-width:720px){
  html.agh-cyber #main-nav{background:rgba(10,15,30,.97);border-top-color:#1B2A4A;
                           box-shadow:0 -2px 12px rgba(0,0,0,.5)}
  html.agh-cyber #main-nav .nav-item{color:#7FA6C8;background:transparent !important;
                                     border:1px solid transparent}
  html.agh-cyber #main-nav .nav-item:hover{color:#BFE9F7}
  html.agh-cyber #main-nav .nav-item.active{
    color:#E8FBFF !important;
    background:linear-gradient(180deg, rgba(24,44,78,.95), rgba(13,26,48,.95)) !important;
    border-color:#39C0FF !important;
    box-shadow:0 0 10px rgba(57,192,255,.30) inset, 0 0 6px rgba(57,192,255,.22)}
}

/* ──  「密度·紧凑」这一档要真的省得出地方（作者：按了没变化）
   原来只有 6 条规则，且没管手机上最占地方的东西。这里补的是首屏真正吃空间的几处：
   卡片内边距、chip、工具栏、字段间距、页面标题、卡片下边距、赛项标签。 */
.agh-compact .card{padding:9px 10px !important}
.agh-compact .card.mb12,.agh-compact .card.mb16{margin-bottom:8px !important}
.agh-compact .toolbar{gap:6px}
.agh-compact .chip{padding:4px 9px;font-size:12px}
.agh-compact .field{margin-bottom:6px !important}
.agh-compact .page-title{font-size:18px;margin-bottom:2px}
.agh-compact .page-sub{font-size:11.5px;margin-bottom:6px}
.agh-compact .pill{padding:1px 7px;font-size:11.5px}
.agh-compact button,.agh-compact .btn-primary,.agh-compact .btn-ghost2,.agh-compact .btn-soft{min-height:32px}
.agh-compact .pp-meta,.agh-compact .small{line-height:1.45}
@media(max-width:720px){
  .agh-compact #main-nav .nav-item{font-size:10.5px;padding:4px 2px}
  .agh-compact .chip-filter{padding-bottom:0}
}

/* 赛事库卡片上的「竞赛方向 / 官网摘录」两层 */
.cc-dir{align-items:center;flex-wrap:wrap;margin-top:6px}
.cc-desc{margin-top:6px;border-top:1px dashed #E9ECEF;padding-top:4px}
.cc-desc summary{cursor:pointer;font-size:12.5px;color:#1971C2;list-style:none;
                 white-space:nowrap;overflow:hidden;text-overflow:ellipsis;padding:2px 0}
.cc-desc summary::-webkit-details-marker{display:none}
.cc-desc summary::before{content:'▸ '}
.cc-desc[open] summary::before{content:'▾ '}
.cc-desc-body{font-size:12.5px;color:#495057;line-height:1.6;white-space:pre-wrap;
              word-break:break-word;background:#F8F9FA;border-radius:8px;
              padding:8px 10px;margin-top:4px;max-height:320px;overflow:auto}

/* 卡片上的身份行：主办 · 级别 · 形式 · 难度 · 赛项数（全部来自库里真字段） */
.cc-ident{margin-top:5px;font-size:12.5px;color:#495057;line-height:1.5;
          word-break:break-word}
/* 综测积分一行：卡片上只给一行，超了省略号，点进详情看全 */
.cc-reward{margin-top:4px;font-size:12.5px;line-height:1.5;display:flex;gap:6px;align-items:baseline}
.cc-rw-tag{flex:0 0 auto;color:#7C3AED;font-weight:700}
.cc-rw-txt{flex:1;min-width:0;color:#495057;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* 官网简介一行：两行为限，右侧「原文」链回官网核对 */
.cc-intro{margin-top:5px;font-size:12.5px;line-height:1.55;display:flex;gap:6px;align-items:baseline}
.cc-in-tag{flex:0 0 auto;color:#0B7285;font-weight:700}
.cc-in-txt{flex:1;min-width:0;color:#343A40;display:-webkit-box;-webkit-line-clamp:2;
           -webkit-box-orient:vertical;overflow:hidden}
.cc-in-src{flex:0 0 auto;font-size:11px;color:#1971C2;text-decoration:none;
           border:1px solid #D0EBFF;border-radius:6px;padding:0 5px}

/* 顶栏权益徽章：数字被省略号吃掉就等于这颗徽章没做（作者手机实拍：Pro · 剩 36···）
   ① 禁止被压缩、禁止折行 ⇒ 宁可挤别人也不截数字
   ② 窄屏让用户名先消失：首页本来就写着「你好，jeson」，顶栏那个是重复信息 */
#plan-badge{flex:0 0 auto;white-space:nowrap;max-width:none;overflow:visible;text-overflow:clip}
@media (max-width:430px){
  .userbox{gap:6px}
  .userbox .user-name{display:none}
  #plan-badge{font-size:12px;padding:2px 7px}
}
/* 底部导航：窄屏改叫两字短称。
   真问题不是"盒子重叠"（盒子一直是均分的），是**文字撑出盒子压到隔壁**：
   360px 下每颗只有 57px，而「🗂 我的档案」要 ~78px ⇒ 溢出 21px 盖住隔壁的图标 ✗
   图标全留（它是这排按钮的辨识度来源），只把字缩短；title 仍是全称，长按能看。 */
.nav-item .nl-short{display:none}
@media (max-width:430px){
  .nav-item .nl-full{display:none}
  .nav-item .nl-short{display:inline}
}
/* 档案详情弹窗（窄屏）两处横向溢出 —— 实测：.stage-notes 撑到 475px、阶段 chip 排到 567px，
   而弹窗只有 340px ⇒「🚀 冲刺交付」「🎤 答辩/公示」和第二个指数条整个在屏幕外 ✗
   ★ 作用域只写在 #modal-box 里：赛事库那排筛选 chip 的 flex-wrap:nowrap + overflow-x:auto
     是刻意设计（一行滚着挑），不能被这里带坏（§5.13 同一条规矩反过来也成立）。
   第一版我写成 .stage-row .chip-filter —— 弹窗里那排根本没有 .stage-row 这层，
   选择器空匹、检查又用了 every()（空数组恒为 true）⇒ 假绿 ✗ 现在按真 DOM 链改对。 */
#modal-box .chip-filter{flex-wrap:wrap;overflow-x:visible}
#modal-box .stage-notes{min-width:0}
#modal-box .stage-notes .row2{flex-wrap:wrap;min-width:0}
@media (max-width:430px){
  #modal-box .stage-notes .row2 .coord{margin-right:0;flex:1 1 100%}
}
/* 赛事库网格不拉伸卡片（作者 2026-10-11 反馈"卡片之间空白太多"）。
   真因不是卡片间距：.grid 默认 align-items:stretch ⇒ 同一行里矮的那张被拉到跟最高的
   一样高，而卡片底部那行 .row.between 带 flex:1 1 auto ⇒ 富余全被它吃掉 ⇒
   空洞正好顶在「报名倒计时 / 按钮」上面，看着像排版坏了 ✗
   改成 start：每张卡按自己内容的高度长，行内下边缘不齐是正常代价（信息密度优先）。 */
.grid.cols-3,.grid.cols-2,.grid.cols-4{align-items:start}


/* 页脚备案号：小、灰、不抢内容，但一定要在 ✓（合规要求，不是设计选择）
   padding-bottom 那 76px 是给移动端固定底部导航让位，否则会被压住 ✗ */
.icp{margin:28px auto 0;padding:14px 16px 76px;text-align:center;
     font-size:12px;color:var(--muted,#8A93A2);line-height:1.9}
.icp a{color:inherit;text-decoration:none;border-bottom:1px dashed rgba(138,147,162,.45)}
.icp a:hover{color:var(--brand,#4C6EF5)}
.icp .icp-sep{margin:0 6px;opacity:.55}
@media (min-width:721px){.icp{padding-bottom:26px}}


/* 登录卡里那一份：跟着卡片宽度走，别抢表单的视觉重心 */
.icp-auth{margin:14px 0 0;padding:0;text-align:center;font-size:11.5px;line-height:1.8}
