/* 外榜宿主专属样式（页面外壳、顶栏让位、皮肤菜单裁剪、中文内置字体）：不进共享层 rank_ui。 */
.rank-skin-panel-themes,
.rank-skin-panel-vr{ display: none; }
@font-face{font-family:"CsgRank SC";font-style:normal;font-weight:400 700;font-display:swap;src:url("../fonts/OutrankSans-SC.woff2") format("woff2")}
body.csg-layout-outrank>main.or-rank,.or-rank{box-sizing:border-box;width:100%;max-width:1680px;margin:0 auto;padding:12px var(--gutter) 32px;--or-rank-gutter:calc(2 * var(--gutter))}
/* 页眉横幅（赞助/主办方图）。
   - 与标题、工具条、榜单同一版心：宽度铺满 main 的内容宽，左右边与下面各块对齐，作为页面的一部分而不是浮在中间的一张图。
   - 宽高比取图片固有尺寸（服务端读文件头写进 --or-banner-ar，见 files.go imageSize），首屏就占好位，图片到达前后不跳；
     读不出尺寸时按 5:1。高度封顶 220px：宽版心（题多、大屏）下横幅不至于压掉半屏榜单。
   - 封顶后图片按 contain 完整显示，两侧空出的部分用同一张图放大、高斯模糊垫底（ambient），像图片自然延展出去，
     不出现生硬的白边/黑边；白底的横幅垫出来是很淡的同色系，几乎看不出边界。同一地址，浏览器只下载一次。
     图片本身带一圈柔和投影，留边时像一张卡片浮在自己的底色上，接缝不显得是“被截断”。
   - 外框：大圆角 + 1px 发丝描边 + 两层柔和投影（近处收边、远处托起），顶部一道内高光；深色模式换成暗底、
     更深的投影，图片略压亮度，避免一块亮白横幅在暗页面上刺眼。
   - 窄屏（<768px）不封顶，按原比例完整显示，圆角与间距收小。 */
.or-banner{--or-banner-ar:5/1;position:relative;isolation:isolate;box-sizing:border-box;width:100%;margin:2px 0 18px;aspect-ratio:var(--or-banner-ar);max-height:220px;
  border-radius:14px;overflow:hidden;background:var(--surface-2,var(--surface));
  box-shadow:0 0 0 1px var(--rule),0 1px 2px rgba(16,24,40,.05),0 12px 32px -16px rgba(16,24,40,.28)}
.or-banner__ambient{position:absolute;z-index:-1;inset:-14%;width:128%;height:128%;object-fit:cover;filter:blur(34px) saturate(1.25);opacity:.62;pointer-events:none}
/* 封顶留边时图片自己带一圈柔和投影，像一张卡片放在自身延展出的底色上；不留边时投影被外框裁掉，看不到 */
.or-banner__img{display:block;width:100%;height:100%;object-fit:contain;filter:drop-shadow(0 6px 22px rgba(16,24,40,.22))}
.or-banner::after{content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;box-shadow:inset 0 1px 0 rgba(255,255,255,.55)}
[data-theme=dark] .or-banner{background:#0b0f17;box-shadow:0 0 0 1px rgba(255,255,255,.09),0 1px 2px rgba(0,0,0,.4),0 18px 44px -20px rgba(0,0,0,.85)}
[data-theme=dark] .or-banner__img{filter:brightness(.92) saturate(.96) drop-shadow(0 8px 28px rgba(0,0,0,.6))}
[data-theme=dark] .or-banner__ambient{opacity:.5;filter:blur(34px) saturate(1.15) brightness(.55)}
[data-theme=dark] .or-banner::after{box-shadow:inset 0 1px 0 rgba(255,255,255,.07)}
@media (max-width:767.98px){.or-banner{max-height:none;margin:0 0 12px;border-radius:10px}}
/* 首屏占位（rank.html）：核心脚本建好工具条之前，先画一条同尺寸的工具条外框；建好后 rank_adapter.js 移除。
   尺寸取核心工具条在默认疏密档下的实测高度（桌面 53px、窄屏 80px），外框颜色用同一组榜单令牌。 */
.or-prepaint-bar{box-sizing:border-box;height:53px;margin-bottom:8px;border:1px solid var(--rank-frame-line,#d7dde5);border-radius:var(--rank-radius-block,8px);background:var(--rank-bg-primary,#fff)}
@media (max-width:767.98px){.or-prepaint-bar{height:80px}}
/* 等数据时榜面至少一屏高：页脚始终在首屏之外，数据到达、榜单撑开时首屏里没有东西被推动（队伍很少的榜放开后页脚上移一次）。 */
body.csg-layout-outrank .rank-system .rank-content-wrapper.rank-awaiting-board{min-height:100vh}
.or-rank__head{display:flex;align-items:center;justify-content:space-between;gap:16px;margin:0 0 10px}
.or-rank__title{min-width:0}
.or-rank__title h1{margin:0 0 4px;font-size:18px;line-height:1.3;font-weight:650;letter-spacing:-.005em;overflow-wrap:anywhere}
.or-rank__meta{display:flex;flex-wrap:wrap;align-items:center;gap:4px 12px;color:var(--ink-3);font-size:12px}
.or-rank__meta .or-rank__time{display:inline-flex;align-items:center;gap:10px;font-family:var(--font-mono)}
.or-rank__actions{display:flex;align-items:center;gap:6px;flex:none}
/* 标题区操作只放图标（说明在悬停弹层里）：返回列表单独一个，滚榜与直播控制台拼成一组。
   滚榜在封榜时由核心脚本加 hidden，此时直播按钮单独成形，不留拼接的直角。 */
.or-rank__actions .btn--icon.btn--sm{width:28px;height:28px}
.or-rank__actions .btn--icon .ic{font-size:15px}
.or-actgroup{display:inline-flex}
.or-actgroup>#outrank-roll-entry:not([hidden]){border-top-right-radius:0;border-bottom-right-radius:0}
.or-actgroup>#outrank-roll-entry:not([hidden])+.btn{margin-left:-1px;border-top-left-radius:0;border-bottom-left-radius:0}
.or-actgroup>.btn:hover{position:relative}
/* 标题换行：中文没有空格，标题和右侧按钮同排时被挤到只剩一两字落到第二行（如“竞赛”）。
   balance 让各行等长；不支持的浏览器照常换行。
   .or-rank__title 用 display:contents 让 h1、meta 直接参与头部的弹性换行，不改模板结构（滚榜页同样适用）。 */
.or-rank__title h1{text-wrap:balance}
/* 窄屏（<768px，手机 360–430px）头部固定成四排，每排各管一件事，宽度变化只影响排内换行：
   1. 导航排：返回列表图标靠左、滚榜 / 直播按钮组靠右（order:-1 提到标题上方）。
      以前按钮排在级别/时间后面、margin-left:auto，meta 一换行按钮就单独落到一排右侧，左边空一大块，像浮着；
      放在最上面就是手机上常见的“返回 + 操作”栏，滚榜按钮隐藏（封榜）时右侧只剩直播按钮。
      返回按钮是 28px 宽的 ghost 图标按钮，用 -7px 外边距抵掉图标两侧留白，箭头与下面标题左边对齐。
   2. 标题：独占一排。
   3. 签：级别、热身赛、比赛状态同一排。状态签原来和时间一起包在 .or-rank__time 里，时间块两行高，
      状态签被垂直居中到两行中间，和上一排的级别/热身赛错开半行；这里让 .or-rank__time 不成盒（display:contents），
      状态签成为签排的一员，时间块另起一排。
   4. 时间：一行“开始 日期 时间  结束 时间  UTC+8”。同一天结束时日期本来就是淡色（is-dim），手机上直接省掉，
      一行放得下 360px；跨天时“结束”整对换到下一行（每对键值由 .rg__p 包成不可拆的组），不会把键和值拆开。
      共享层 rank_ui 的窄屏规则把 inline 时间改成两行网格并让时区签跨两行居中，那是给比赛站页眉用的，这里覆盖成 flex。
   桌面（≥768px）不进这个块，版式同改动前。 */
@media (max-width:767.98px){
  .or-rank__head{flex-wrap:wrap;align-items:center;gap:6px 10px}
  .or-rank__title{display:contents}
  .or-rank__title>h1,.or-rank__title>.kicker{flex:1 1 100%;margin:0}
  .or-rank__title>.kicker{margin-bottom:-6px}
  /* 标题按整排宽度自然折行。上面全局的 balance 是给桌面“标题与右侧按钮同排”用的：它把各行压成等长，
     手机上标题已独占一排，balance 反而把 23 字的标题拆成 11+12，首行右侧空出近半排。窄屏退回普通折行。 */
  .or-rank__title>h1{text-wrap:wrap}
  .or-rank__actions{order:-1;flex:1 1 100%;justify-content:space-between;align-items:center;margin:0 0 2px}
  .or-rank__actions>.btn--ghost:first-child{margin-left:-7px}
  .or-rank__meta{flex:1 1 100%;min-width:0;gap:6px 10px}
  .or-rank__meta .or-rank__time{display:contents}
  .or-rank__meta .rg--inline{display:flex;flex:1 1 100%;flex-wrap:wrap;align-items:center;gap:2px 12px}
  .or-rank__meta .rg__p{display:inline-flex;align-items:baseline;gap:6px;white-space:nowrap}
  .or-rank__meta .rg__v.is-dim .rg__d{display:none}
  .or-rank__meta .rg .tz{margin-left:0}
}
.or-rank__empty{padding:40px 20px;text-align:center;color:var(--ink-3);border:1px dashed var(--rule-2);border-radius:var(--r-lg);margin-bottom:12px;background:var(--surface)}
.or-rank__empty b{display:block;color:var(--ink);font-size:14px;margin-bottom:4px}
.or-rank .contest-rank-page-shell{min-width:0}
.or-rank .btn{line-height:1.2}
body.csg-layout-outrank:has(.rank-system.fullscreen) .topbar{display:none}
@media (min-width:768px){
  body.csg-layout-outrank .contest-rank-page-shell .rank-system:not(.fullscreen) .rank-header-row{top:var(--topbar-h)}
}
/* 宽屏居中（≥768px）。
   问题：榜行是满宽条，题少时题格挤在左边、右侧一大片空条纹，整页重心偏左。
   做法：榜单本体按“全场题目铺满”的宽度定宽，页面外壳收缩包住它并整体居中；标题行、横幅、工具条（进度条）、顶栏
   都对齐同一左右边，作为一个版心居中，而不是只把表格挪到中间。
   - 宽度只看全场总题数 --or-problem-total（服务端首屏写入，rank_adapter.js 随数据更新；含隐藏/CCPC 未揭示题），
     表头揭示、题目出列都不改变版面宽度；首屏即是最终宽度，不等数据下载再收窄。
   - 题少时不留空条纹：题格在基准宽与 1.5 倍之间放宽，让榜面接近 --or-board-target（约一块舒适阅读宽度）；
     放到 1.5 倍还不够就停在自然宽度，整体居中（再宽题格就散了，空白留给两侧页边比留在行尾好看）。
     题多（自然宽度已超过目标）时题格保持基准宽，不压缩。
   - 列宽、列间距、行内边距都引用核心榜单的同名变量，它们定义在 .rank-content-wrapper 上并随疏密档切换，
     所以公式放在 .rank-content-wrapper 自己身上；放宽后的题格宽经 --or-cell 传给后代（同名变量不能在同一元素上自引用）。
     宽度 = 行左右内边距 + 名次/题数/罚时三列 + N 个题格 + (N+2) 个列间距（三列与题组之间 3 个，题格之间 N-1 个）。
   - 上限是视口：不受 1680px 版心限制，26 题这类宽榜在 2560 屏上整体展开居中。
   - 题多到视口放不下时，外壳贴满视口，榜单仍按原来的方式向右溢出并横向滚动（与改动前一致）。
   - 标题行、横幅、空榜提示用 contain:inline-size 不参与外壳的收缩取宽：长标题只换行，不会把外壳撑宽。
   - 全屏、手机窄屏不走这套（全屏自己铺满视口；<768px 版式不变）。没有总题数（还没推过榜）时也不走，版面同改动前。 */
@media (min-width:768px){
  body.csg-layout-outrank>main.or-rank.or-rank--fit{--or-board-target:1200px;width:fit-content;max-width:100%}
  .or-rank--fit>.or-rank__head,.or-rank--fit>.or-banner,.or-rank--fit>.or-rank__empty{contain:inline-size}
  .or-rank--fit .contest-rank-page-shell:not([data-rank-fs="1"]) .rank-system:not(.fullscreen) .rank-content-wrapper{
    --or-fixed:calc(2 * var(--rank-padding-lg) + var(--rank-col-width) + var(--rank-solve-col-width) + var(--rank-penalty-col-width) + 3 * var(--rank-col-gap));
    --or-cell:clamp(var(--rank-problem-col-width),
      (var(--or-board-target) - 2px - var(--or-fixed) - (var(--or-problem-total) - 1) * var(--rank-col-gap)) / var(--or-problem-total),
      1.5 * var(--rank-problem-col-width));
    width:calc(var(--or-fixed) + var(--or-problem-total) * var(--or-cell) + (var(--or-problem-total) - 1) * var(--rank-col-gap))
  }
  .or-rank--fit .contest-rank-page-shell:not([data-rank-fs="1"]) .rank-system:not(.fullscreen) .rank-container{--rank-problem-col-width:var(--or-cell)}
  /* 顶栏同版心：--or-col-inset 由 rank.html 里的小脚本按 main 的内容边写入；页面窄于版心时退回原来的 gutter */
  body.csg-layout-outrank:has(main.or-rank--fit) .topbar{padding-inline:max(var(--gutter),var(--or-col-inset,var(--gutter)))}
}
/* 窄屏横滑（rank_mobile.css 的左侧冻结区）：
   - 队名行宽度按横滑容器真实可视宽度（rank_adapter.js 写的 --or-scroll-w）算，钉住块不再比容器宽，滑到最右时左端图标不被裁；
   - 首答星（::after，z-index 9999）原来压在冻结列上面，题格建立自己的层叠上下文后，星只在格内比较，滑到冻结列底下就被盖住；
   - 横向不回弹（iOS 橡皮筋会把钉住块一并拖出左缘）。 */
@media (max-width:767.98px){
  body.csg-layout-outrank .rank-system:not(.fullscreen):not([data-rank-mode="roll"]):not([data-rank-layout="plain"]){overscroll-behavior-x:contain}
  body.csg-layout-outrank .rank-system:not(.fullscreen):not([data-rank-mode="roll"]):not([data-rank-layout="plain"]) .rank-grid .problem-item{z-index:1}
  html.csg-rank-ui body.csg-layout-outrank .rank-system:not(.fullscreen):not([data-rank-mode="roll"]):not([data-rank-layout="plain"]) .team-info-section{
    width:calc(var(--or-scroll-w, calc(100vw - var(--or-rank-gutter, 24px) - 4px)) - 2 * var(--rank-m-pad));
    max-width:calc(var(--or-scroll-w, calc(100vw - var(--or-rank-gutter, 24px) - 4px)) - 2 * var(--rank-m-pad))}
}
