/* ---- gallery (from build.py:GALLERY_CSS) ---- */
.page-head h2 { font-size: 46px; }
.head-right { display: flex; align-items: center; gap: 10px; padding-bottom: 4px; }
.counter {
  display: flex; align-items: center; gap: 8px; height: 36px; padding: 0 13px;
  border-radius: 12px; font-size: 12px; color: var(--ink-2);
  background: var(--chip); border: 1px solid var(--hair);
}
.counter b { color: var(--ink); font-weight: 620; font-variant-numeric: tabular-nums; }

/* ---- detail (from build.py:DETAIL_CSS) ---- */
.detail {
  display: grid; grid-template-columns: minmax(0, 1fr) 408px;
  gap: 20px; padding: 0 22px 40px; max-width: 1520px; margin: 0 auto;
}
.crumbs {
  max-width: 1520px; margin: 0 auto; padding: 16px 28px 12px;
  display: flex; align-items: center; gap: 12px; font-size: 12.5px; color: var(--ink-2);
  animation: rise .7s var(--ease-out) both;
}
.back {
  width: 34px; height: 34px; border-radius: 11px; display: grid; place-items: center;
  background: var(--chip); border: 1px solid var(--hair); color: var(--ink);
  cursor: pointer; transition: transform .12s var(--ease);
}
.back:active { transform: scale(.94); }
.back svg { width: 16px; height: 16px; }
.crumbs b { color: var(--ink); font-weight: 540; }

/* The photo sits directly on the wallpaper: no glass box around it, no frame.
   A panel behind the picture only competed with the picture itself. */
.stage {
  position: relative;
  display: grid; place-items: center;
  min-height: 520px; max-height: 760px;
  animation: rise .8s .04s var(--ease-out) both;
}
.stage img {
  max-width: 100%; max-height: 100%; width: auto; height: auto;
  object-fit: contain; border-radius: 16px;
  box-shadow: 0 40px 90px -34px rgba(8, 14, 30, .55), 0 2px 12px rgba(8, 14, 30, .16);
}
.stage-top {
  position: absolute; top: 16px; left: 16px; right: 16px;
  display: flex; align-items: center; justify-content: space-between; z-index: 3;
}

/* ---- top bar additions for the real app (search box, two-state theme) ---- */
.search-field {
  display: inline-flex; align-items: center; gap: 8px;
  height: 38px; padding: 0 13px; width: 236px;
  border-radius: 12px;
  background: var(--glass-2); border: 1px solid var(--hair);
  color: var(--ink-3);
  transition: border-color .22s var(--ease), background .22s var(--ease), width .28s var(--ease);
}
.search-field:focus-within {
  border-color: rgba(0, 113, 227, .55);
  background: var(--chip);
  width: 290px;
}
.search-field svg { width: 15px; height: 15px; flex: none; }
.search-field input {
  flex: 1; min-width: 0; border: 0; outline: 0; background: transparent;
  font: inherit; font-size: 12.5px; color: var(--ink);
}
.search-field input::placeholder { color: var(--ink-3); }
.search-field input::-webkit-search-cancel-button { -webkit-appearance: none; }
.theme-seg button { min-width: 46px; }

/* editable title */
.title-row { display: flex; align-items: flex-start; gap: 10px; }
.title-row h3 { flex: 1; min-width: 0; }
.title-row .icon-btn { flex: none; width: 28px; height: 28px; border-radius: 9px; }
.title-row .icon-btn svg { width: 14px; height: 14px; }
.title-row h3 { cursor: text; }
.title-input {
  width: 100%; border: 0; outline: 0; background: transparent;
  font: inherit; font-size: inherit; font-weight: inherit; letter-spacing: inherit;
  color: var(--ink);
  border-bottom: 1px solid rgba(0, 113, 227, .6);
  padding: 0 0 3px;
}

/* ---- upload: name + tags before the file leaves the browser ---- */
.meta-form {
  display: grid; grid-template-columns: 1fr 1fr; gap: 10px;
  max-width: 560px; margin: 18px auto 0;
}
.meta-field {
  display: flex; align-items: center; gap: 8px;
  height: 38px; padding: 0 12px; border-radius: 11px;
  background: var(--glass-2); border: 1px solid var(--hair);
  transition: border-color .22s var(--ease), background .22s var(--ease);
}
.meta-field:focus-within { border-color: rgba(0, 113, 227, .5); background: var(--chip); }
.meta-field > span { font-size: 11px; color: var(--ink-3); flex: none; }
.meta-field input {
  flex: 1; min-width: 0; border: 0; outline: 0; background: transparent;
  font: inherit; font-size: 12.5px; color: var(--ink);
}
.meta-field input::placeholder { color: var(--ink-3); }
#tagSuggest {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
  gap: 6px; max-width: 620px; margin: 10px auto 0;
  font-size: 11px; color: var(--ink-3);
}
#tagSuggest .tag { cursor: pointer; border: 0; font: inherit; font-size: 11px; }

/* finished uploads: a strip of thumbnails, one editor, then its six links */
.picked { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 12px; }
.pick {
  display: inline-flex; align-items: center; gap: 8px; max-width: 210px;
  padding: 4px 11px 4px 4px; border-radius: 11px; cursor: pointer;
  background: var(--glass-2); border: 1px solid var(--hair);
  font: inherit; font-size: 11.5px; color: var(--ink-2);
  transition: border-color .2s var(--ease), background .2s var(--ease);
}
.pick img { width: 26px; height: 26px; border-radius: 7px; object-fit: cover; flex: none; }
.pick span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pick.on { border-color: rgba(0, 113, 227, .55); color: var(--ink); background: var(--chip); }
.edit-panel {
  display: flex; align-items: center; gap: 8px; margin-top: 11px; flex-wrap: wrap;
}
.edit-panel .meta-field { flex: 1; min-width: 180px; height: 36px; }
.edit-panel .btn-glass { height: 36px; padding: 0 16px; font-size: 12px; }
#resultLinks { margin-top: 12px; }
.badge {
  font-size: 11px; font-weight: 600; letter-spacing: .02em; padding: 6px 11px;
  border-radius: 9px; color: #fff; background: rgba(14, 18, 28, .42);
  border: 1px solid rgba(255,255,255,.2); backdrop-filter: blur(16px) saturate(160%);
  display: inline-flex; align-items: center; gap: 6px;
}
.badge svg { width: 13px; height: 13px; }
/* The pager and its two arrows are one floating pill. The pill is the
   container, so it is what gets centred — the counter is a plain child. */
.stage-nav {
  position: absolute; bottom: 18px; left: 50%; transform: translateX(-50%);
  display: flex; align-items: center; gap: 7px;
  height: 40px; padding: 0 5px 0 14px;
  border-radius: 14px;
}
.pager {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 62px; height: 30px;
  font-size: 11.5px; color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.pager span { font-variant-numeric: tabular-nums; }
.pager .nav {
  width: 28px; height: 28px; border-radius: 9px; display: grid; place-items: center;
  background: var(--chip); border: 1px solid var(--hair); cursor: pointer;
}
.pager .nav svg { width: 14px; height: 14px; }

.side { display: flex; flex-direction: column; gap: 12px; animation: rise .8s .1s var(--ease-out) both; }
.panel { border-radius: 22px; padding: 19px 20px; }
.panel h2 { font-size: 23px; letter-spacing: -.028em; line-height: 1.15; font-weight: 660; }
.panel .path {
  margin-top: 7px; font-size: 11px; color: var(--ink-3); letter-spacing: .01em;
}
.tags { display: flex; gap: 6px; margin-top: 14px; flex-wrap: wrap; }
.tag {
  font-size: 11.5px; font-weight: 540; padding: 5px 10px; border-radius: 8px;
  background: var(--chip); border: 1px solid var(--hair); color: var(--ink-2);
  display: inline-flex; align-items: center; gap: 5px;
}
.tag svg { width: 12px; height: 12px; }

.spec { display: grid; grid-template-columns: 1fr 1fr; gap: 1px; margin-top: 18px;
  background: var(--hair-2); border-radius: 13px; overflow: hidden; }
.spec div { background: var(--glass-2); padding: 11px 13px; }
.spec dt { font-size: 10.5px; color: var(--ink-3); letter-spacing: .03em; }
.spec dd { font-size: 13px; font-weight: 560; margin-top: 4px; font-variant-numeric: tabular-nums; }

.links { display: flex; flex-direction: column; gap: 6px; margin-top: 12px; }
.linkrow {
  display: flex; align-items: center; gap: 7px; min-width: 0;
  padding: 7px 6px 7px 10px; border-radius: 11px;
  background: var(--glass-2); border: 1px solid var(--hair);
}
.linkrow .k { font-size: 10.5px; width: 56px; color: var(--ink-3); letter-spacing: .02em; flex: none; }
.linkrow .v {
  flex: 1; min-width: 0; font-size: 11.5px; color: var(--ink-2); overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap;
}
.linkrow .cp {
  flex: none; width: 24px; height: 24px; border-radius: 8px; display: grid; place-items: center;
  background: var(--chip); border: 1px solid var(--hair); color: var(--ink-2); cursor: pointer;
  transition: color .2s var(--ease), background .2s var(--ease);
}
.linkrow .cp svg { width: 13px; height: 13px; }
.linkrow .cp.ok { background: #34c759; border-color: #34c759; color: #fff; }

.actions { display: flex; gap: 8px; margin-top: 16px; }
.actions .big {
  flex: 1; height: 42px; border-radius: 13px; border: 0; font: inherit;
  font-size: 13px; font-weight: 590; display: inline-flex; align-items: center;
  justify-content: center; gap: 7px; cursor: pointer;
}
.actions .download { background: var(--accent); color: #fff; box-shadow: 0 12px 26px -14px var(--accent); }
.actions .ghost { background: var(--chip); border: 1px solid var(--hair); color: var(--ink); flex: none; width: 42px; }
.actions svg { width: 16px; height: 16px; }

.chips { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 13px; padding-top: 13px; border-top: 1px solid var(--hair-2); }
.chip {
  display: inline-flex; align-items: center; gap: 6px; height: 30px; padding: 0 11px;
  border-radius: 9px; font-size: 11.5px; font-weight: 540; color: var(--ink-3);
  background: var(--glass-2); border: 1px solid var(--hair-2);
}
.chip svg { width: 13px; height: 13px; }
.chip.on { color: var(--ink); background: var(--chip); border-color: var(--hair); }
.chip.on svg { color: #34c759; }
.toggles { display: grid; gap: 2px; margin-top: 8px; }
.trow {
  display: flex; align-items: center; justify-content: space-between;
  padding: 10px 2px; font-size: 12.5px; color: var(--ink-2);
  border-bottom: 1px solid var(--hair-2);
}
.trow:last-child { border-bottom: 0; }
.switch { width: 40px; height: 24px; border-radius: 999px; background: var(--track); position: relative; flex: none; }
.switch::after {
  content: ""; position: absolute; width: 18px; height: 18px; border-radius: 50%;
  top: 3px; left: 3px; background: #fff; box-shadow: 0 1px 3px rgba(0,0,0,.3);
  transition: transform .3s var(--ease);
}
.switch.on { background: #34c759; }
.switch.on::after { transform: translateX(16px); }
.panel .ptitle {
  font-size: 11px; letter-spacing: .09em; text-transform: uppercase;
  color: var(--ink-3); font-weight: 620;
}

/* ---- upload (from build2.py:UPLOAD_CSS) ---- */
.up { max-width: 1180px; margin: 0 auto; padding: 6px 22px 70px; }
.drop {
  border-radius: 26px; padding: 46px 32px 40px; text-align: center; position: relative;
  border: 1.5px dashed rgba(120, 140, 180, .42);
  background: var(--glass-2);
  backdrop-filter: blur(30px) saturate(170%);
  box-shadow: var(--shadow);
  transition: transform .3s var(--ease), border-color .3s var(--ease);
  animation: rise .8s .04s var(--ease-out) both;
  overflow: hidden;
}
.drop::before {
  content: ""; position: absolute; inset: -1px; border-radius: 26px; pointer-events: none;
  background: radial-gradient(70% 90% at 50% 0%, rgba(90,150,255,.16), transparent 70%);
}
.drop-icon {
  width: 74px; height: 74px; margin: 0 auto 18px; border-radius: 22px;
  display: grid; place-items: center;
  background: linear-gradient(160deg, rgba(255,255,255,.9), rgba(235,242,255,.55));
  border: 1px solid rgba(255,255,255,.8);
  box-shadow: 0 18px 34px -18px rgba(40,80,160,.5), inset 0 1px 0 #fff;
  color: #2b6cff;
}
body.theme-dark .drop-icon {
  background: linear-gradient(160deg, rgba(70,90,140,.6), rgba(30,40,70,.5));
  border-color: rgba(255,255,255,.12); color: #7fb0ff;
}
.drop-icon svg { width: 32px; height: 32px; }
.drop h3 { font-size: 25px; letter-spacing: -.028em; font-weight: 650; }
.drop p { margin-top: 8px; font-size: 12.5px; color: var(--ink-2); }
.fmt {
  display: flex; justify-content: center; flex-wrap: wrap; gap: 6px; margin-top: 20px;
}
.fmt span {
  font-size: 10.5px; font-weight: 620; letter-spacing: .04em; padding: 4px 9px;
  border-radius: 7px; color: var(--ink-2); background: var(--chip);
  border: 1px solid var(--hair);
}
.drop .cta { display: flex; justify-content: center; gap: 9px; margin-top: 24px; }
.drop .cta .ghost {
  height: 38px; padding: 0 15px; border-radius: 12px; font: inherit; font-size: 13px;
  font-weight: 550; color: var(--ink); background: var(--chip);
  border: 1px solid var(--hair); cursor: pointer;
  display: inline-flex; align-items: center; gap: 7px;
}
.drop .cta .ghost svg { width: 15px; height: 15px; }
.drop .hint {
  margin-top: 18px; font-size: 11px; color: var(--ink-3); display: flex;
  justify-content: center; gap: 8px; align-items: center;
}

.cols { display: grid; grid-template-columns: 1fr 348px; gap: 16px; margin-top: 16px; align-items: start; }
.sec-title {
  display: flex; align-items: center; justify-content: space-between;
  padding: 4px 6px 10px; font-size: 12px; color: var(--ink-2);
}
.sec-title b { color: var(--ink); font-size: 13px; font-weight: 600; }

.job {
  display: flex; gap: 13px; padding: 12px; border-radius: 18px; margin-bottom: 9px;
  background: var(--glass); backdrop-filter: blur(26px) saturate(160%);
  border: 1px solid var(--hair); box-shadow: var(--shadow-sm);
  animation: rise .7s var(--ease-out) both;
}
.job img { width: 62px; height: 62px; border-radius: 12px; object-fit: cover; flex: none; }
.job .body { flex: 1; min-width: 0; }
.job .top { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.job h4 { font-size: 12.5px; font-weight: 570; }
.job .sub { margin-top: 4px; font-size: 10.5px; color: var(--ink-3); display: flex; gap: 7px; align-items: center; }
.job .pct { font-size: 11px; font-variant-numeric: tabular-nums; color: var(--ink-2); }
.bar { height: 5px; border-radius: 999px; background: var(--track); margin-top: 9px; overflow: hidden; }
.bar i { display: block; height: 100%; border-radius: 999px; background: linear-gradient(90deg,#4c9bff,#8a6bff); }
.job.done .bar i { background: #34c759; }
.okbit {
  display: inline-flex; align-items: center; gap: 4px; font-size: 10.5px; font-weight: 600;
  color: #34c759;
}
.okbit svg { width: 12px; height: 12px; }

.result {
  border-radius: 20px; padding: 15px 16px 14px; margin-top: 9px;
  background: var(--glass); backdrop-filter: blur(30px) saturate(170%);
  border: 1px solid var(--hair); box-shadow: var(--shadow);
  animation: rise .8s .1s var(--ease-out) both;
}
.result .rh { display: flex; align-items: center; justify-content: space-between; }
.result .rh b { font-size: 13px; }
.result .all {
  border: 0; font: inherit; font-size: 11px; font-weight: 580; height: 27px; padding: 0 10px;
  border-radius: 8px; background: var(--accent); color: #fff; cursor: pointer;
  display: inline-flex; align-items: center; gap: 5px;
}
.result .all svg { width: 12px; height: 12px; }
.lrow {
  display: flex; align-items: center; gap: 9px; padding: 7px 7px 7px 10px;
  border-radius: 10px; background: var(--glass-2); border: 1px solid var(--hair);
  margin-top: 6px;
}
.lrow .k { font-size: 10px; width: 54px; color: var(--ink-3); flex: none; letter-spacing: .02em; }
.lrow .v { flex: 1; min-width: 0; font-size: 11px; color: var(--ink-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lrow .cp {
  flex: none; width: 24px; height: 24px; border-radius: 7px; display: grid; place-items: center;
  background: var(--chip); border: 1px solid var(--hair); color: var(--ink-2);
}
.lrow .cp svg { width: 12px; height: 12px; }

.sidepanel { border-radius: 20px; padding: 16px 17px; }

/* ---- admin (from build2.py:ADMIN_CSS) ---- */
body { --side: 264px; }
.admin {
  display: grid; grid-template-columns: var(--side) minmax(0, 1fr);
  min-height: calc(100vh - 0px); gap: 18px; padding: 18px;
}
.sidebar {
  position: sticky; top: 18px; align-self: start;
  border-radius: 24px; padding: 16px 12px; height: calc(100vh - 36px);
  display: flex; flex-direction: column;
  animation: slide-in .7s var(--ease-out) both;
}
@keyframes slide-in { from { opacity: 0; transform: translateX(-18px); } to { opacity: 1; transform: none; } }
.sidebar .brand { padding: 2px 6px 16px; }
.nav { display: flex; flex-direction: column; gap: 3px; }
.nav a {
  display: flex; align-items: center; gap: 10px; height: 38px; padding: 0 11px;
  border-radius: 11px; font-size: 12.5px; color: var(--ink-2); text-decoration: none;
  font-weight: 520; transition: background .2s var(--ease), color .2s var(--ease);
}
.nav a svg { width: 17px; height: 17px; opacity: .82; }
.nav a:hover { background: var(--chip); color: var(--ink); }
.nav a.on {
  background: var(--glass-strong); color: var(--ink); font-weight: 600;
  box-shadow: var(--shadow-sm);
}
.nav a .badge-n {
  margin-left: auto; font-size: 10px; font-weight: 650; padding: 2px 6px;
  border-radius: 6px; background: rgba(52,199,89,.16); color: #34c759;
}
.nav .grp { font-size: 10px; letter-spacing: .09em; color: var(--ink-3);
  padding: 14px 11px 6px; font-weight: 620; text-transform: uppercase; }
.side-foot { margin-top: auto; padding: 10px 4px 0; }
.storage {
  border-radius: 14px; padding: 11px 12px; background: var(--glass-2);
  border: 1px solid var(--hair);
}
.storage .l1 { display: flex; justify-content: space-between; font-size: 11px; color: var(--ink-2); }
.storage .l1 b { color: var(--ink); font-weight: 600; }
.storage .track { height: 5px; border-radius: 999px; background: var(--track); margin-top: 8px; }
.storage .track i { display: block; height: 100%; width: 63%; border-radius: 999px;
  background: linear-gradient(90deg,#4c9bff,#8a6bff); }
.storage p { font-size: 10px; color: var(--ink-3); margin-top: 7px; }

.main { padding: 4px 6px 40px; min-width: 0; }
.mhead { display: flex; align-items: flex-end; justify-content: space-between; gap: 18px;
  padding: 6px 6px 18px; animation: rise .7s var(--ease-out) both; }
.mhead h2 { font-size: 34px; letter-spacing: -.033em; font-weight: 700; }
.mhead p { margin-top: 7px; font-size: 12px; color: var(--ink-2); }

.kpis { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; }
.kpi {
  border-radius: 18px; padding: 15px 16px; animation: rise .8s var(--ease-out) both;
}
.kpi .lab { font-size: 10.5px; letter-spacing: .05em; color: var(--ink-3); text-transform: uppercase; }
.kpi .num { font-size: 27px; font-weight: 680; letter-spacing: -.02em; margin-top: 7px;
  font-variant-numeric: tabular-nums; display: flex; align-items: baseline; gap: 5px; }
.kpi .num span { font-size: 12px; font-weight: 550; color: var(--ink-3); letter-spacing: 0; }
.kpi .delta { margin-top: 7px; font-size: 10.5px; color: #34c759; display: flex; align-items: center; gap: 4px; }
.kpi .delta.down { color: #ff9f0a; }
.kpi .delta svg { width: 11px; height: 11px; }

.grid2 { display: grid; grid-template-columns: 1.35fr 1fr; gap: 12px; margin-top: 12px; }
.card2 { border-radius: 20px; padding: 16px 17px 14px; }
.card2 .ch { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; }
.card2 .ch b { font-size: 13px; }
.card2 .ch .seg button { font-size: 11px; height: 26px; padding: 0 10px; }

.chart { display: flex; align-items: flex-end; gap: 9px; height: 148px; margin-top: 16px; }
.chart .b { flex: 1; border-radius: 7px 7px 4px 4px; position: relative;
  background: linear-gradient(180deg, rgba(120,170,255,.92), rgba(110,130,255,.42));
  box-shadow: inset 0 1px 0 rgba(255,255,255,.35); }
.chart .b.hi { background: linear-gradient(180deg, #7fc0ff, #5a6bff); }
.chart .b span {
  position: absolute; bottom: -19px; left: 50%; transform: translateX(-50%);
  font-size: 9.5px; color: var(--ink-3);
}
.chart .b em {
  position: absolute; top: -17px; left: 50%; transform: translateX(-50%);
  font-size: 9.5px; color: var(--ink-2); font-style: normal; font-variant-numeric: tabular-nums;
}

.donut { display: flex; align-items: center; gap: 18px; margin-top: 12px; }
.ring {
  width: 108px; height: 108px; border-radius: 50%; flex: none; position: relative;
  background: conic-gradient(#5a9bff 0 46%, #9b7bff 46% 72%, #4cd3a5 72% 88%, #ffb84d 88% 100%);
  box-shadow: 0 10px 24px -14px rgba(80,120,255,.6);
}
.ring::after {
  content: ""; position: absolute; inset: 17px; border-radius: 50%;
  background: var(--glass-strong); backdrop-filter: blur(10px);
}
.ring .mid {
  position: absolute; inset: 0; display: grid; place-items: center; z-index: 2;
  font-size: 15px; font-weight: 680; letter-spacing: -.02em;
}
.ring .mid i { font-style: normal; font-size: 8.5px; color: var(--ink-3); font-weight: 550;
  display: block; text-align: center; margin-top: 2px; letter-spacing: .04em; }
.legend { display: flex; flex-direction: column; gap: 8px; font-size: 11.5px; color: var(--ink-2); }
.legend .li { display: flex; align-items: center; gap: 7px; }
.legend .sq { width: 8px; height: 8px; border-radius: 3px; }
.legend b { margin-left: auto; color: var(--ink); font-weight: 600; font-variant-numeric: tabular-nums; }

.tablecard { border-radius: 20px; padding: 16px 17px 8px; margin-top: 12px; }
table { width: 100%; border-collapse: collapse; }
th {
  text-align: left; font-size: 10px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--ink-3); font-weight: 620; padding: 9px 8px;
}
td { font-size: 12px; padding: 9px 8px; border-top: 1px solid var(--hair-2); vertical-align: middle; }
td .thumb { width: 34px; height: 34px; border-radius: 9px; object-fit: cover; display: block; }
td.nm { font-weight: 550; }
tr:last-child td { border-bottom: 0; }
.mono-s { font-size: 10.5px; color: var(--ink-3); }
.chipstat {
  display: inline-flex; align-items: center; gap: 5px; font-size: 10px; font-weight: 600;
  padding: 3px 8px; border-radius: 6px;
}
.chipstat.pub { background: rgba(52,199,89,.14); color: #2fbf55; }
.chipstat.priv { background: rgba(255,159,10,.14); color: #e08a00; }
body.theme-dark .chipstat.pub { color: #4cd97a; }
body.theme-dark .chipstat.priv { color: #ffb340; }

.appearance { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-top: 12px; }
.bgpreview {
  border-radius: 14px; height: 96px; overflow: hidden; position: relative;
  border: 1px solid var(--hair);
  background: url("assets/wall-light.jpg") center/cover;
}
.bgpreview .veil {
  position: absolute; inset: 0;
  background: radial-gradient(125% 95% at 50% -5%, rgba(255,255,255,.78), rgba(255,255,255,.34) 52%, rgba(240,244,255,.14) 100%);
}
.bgpreview .lg {
  position: absolute; inset: 0; display: grid; place-items: center;
}
.bgpreview .fakeglass {
  width: 78%; height: 34px; border-radius: 10px; background: rgba(255,255,255,.55);
  border: 1px solid rgba(255,255,255,.7); box-shadow: 0 8px 18px -10px rgba(20,40,80,.5);
}
.slider { display: flex; align-items: center; gap: 10px; margin-top: 11px; }
.slider .lab { font-size: 10.5px; color: var(--ink-3); width: 54px; flex: none; }
.slider .tr { flex: 1; height: 4px; border-radius: 999px; background: var(--track); position: relative; }
.slider .tr i { position: absolute; left: 0; top: 0; bottom: 0; border-radius: 999px;
  background: var(--accent); }
.slider .tr b {
  position: absolute; top: 50%; width: 13px; height: 13px; border-radius: 50%;
  background: #fff; box-shadow: 0 1px 4px rgba(0,0,0,.35); transform: translate(-50%,-50%);
  border: .5px solid rgba(0,0,0,.06);
}
.slider .v { font-size: 10.5px; color: var(--ink-2); width: 32px; text-align: right;
  font-variant-numeric: tabular-nums; }
.themepick { display: flex; gap: 7px; margin-top: 11px; }
.themepick span {
  flex: 1; height: 40px; border-radius: 10px; border: 1.5px solid var(--hair);
  font-size: 11px; font-weight: 550; display: grid; place-items: center; color: var(--ink-2);
}
.themepick span.on { border-color: var(--accent); color: var(--ink); background: var(--chip); }

/* ---- mobile (from build3.py:MOBILE_CSS) ---- */
body { --pad: 14px; }
.mtop {
  position: sticky; min-width: 0; top: 10px; z-index: 40; margin: 10px 12px 0;
  height: 52px; border-radius: 18px; display: flex; align-items: center;
  padding: 0 8px 0 12px; gap: 8px;
}
.mtop .brand-mark { width: 30px; height: 30px; border-radius: 9px; }
.mtop .brand-mark svg { width: 17px; height: 17px; }
.mtop h1 { font-size: 15px; font-weight: 650; letter-spacing: -.02em; }
.mtop .tools { margin-left: auto; display: flex; gap: 6px; min-width: 0; }
.mtop .icon-btn { width: 32px; height: 32px; border-radius: 10px; }
.mtop .icon-btn svg { width: 16px; height: 16px; }
.mtop .theme-toggle { border-radius: 10px; padding: 2px; }
.mtop .theme-toggle .ic { width: 24px; height: 24px; border-radius: 7px; }
.mtop .theme-toggle .ic svg { width: 14px; height: 14px; }

.msearch {
  margin: 10px 12px 0; height: 40px; border-radius: 14px; display: flex;
  align-items: center; gap: 9px; padding: 0 12px; font-size: 12.5px; color: var(--ink-3);
}
.msearch svg { width: 15px; height: 15px; }

.mcats { display: flex; gap: 6px; overflow: hidden; padding: 12px 12px 8px; }
.mcats .pill { height: 30px; padding: 0 12px; font-size: 12px; flex: none; }

.mgrid {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px; padding: 0 12px 96px; align-items: start;
}
.mgrid .card { margin: 0; border-radius: 14px; min-width: 0; }
.mgrid .card:nth-child(1) { grid-row: span 2; }
.mgrid .card .res { font-size: 8.5px; padding: 3px 6px; top: 7px; left: 7px; border-radius: 6px; }
.mgrid .card .meta { padding: 20px 9px 8px; }
.mgrid .card .meta h3 { font-size: 10.5px; }
.mgrid .card .meta p { font-size: 8.5px; margin-top: 2px; }
.mgrid .card .acts span,
.mgrid .card .acts a { width: 21px; height: 21px; border-radius: 7px; }
.mgrid .card .acts svg { width: 11px; height: 11px; }

.mtab {
  position: fixed; left: 12px; right: 12px; bottom: 12px; height: 60px;
  border-radius: 20px; display: flex; align-items: center; justify-content: space-around;
  padding: 0 6px; z-index: 50;
  animation: rise .9s .2s var(--ease-out) both;
}
.mtab a {
  flex: 1; display: flex; flex-direction: column; align-items: center; gap: 3px;
  font-size: 9.5px; color: var(--ink-3); text-decoration: none; font-weight: 540;
}
.mtab a.on { color: var(--accent); }
.mtab a svg { width: 19px; height: 19px; }
.mtab .fab {
  width: 46px; height: 46px; border-radius: 15px; flex: none;
  background: linear-gradient(160deg, #5fa8ff, #3d6bff);
  display: grid; place-items: center; color: #fff;
  box-shadow: 0 12px 24px -10px rgba(60,120,255,.9), inset 0 1px 0 rgba(255,255,255,.4);
  margin: 0 4px;
}
.mtab .fab svg { width: 21px; height: 21px; }
.msheet {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 45;
  border-radius: 22px 22px 0 0; padding: 10px 16px 92px;
  transform: translateY(0);
  animation: sheet-up .8s .35s var(--ease-out) both;
}
@keyframes sheet-up { from { opacity: 0; transform: translateY(60px); } to { opacity: 1; transform: none; } }
.msheet .grab { width: 36px; height: 4px; border-radius: 999px; background: var(--track); margin: 0 auto 10px; }
.msheet .row { display: flex; align-items: center; justify-content: space-between; font-size: 11.5px; color: var(--ink-2); }
.msheet b { color: var(--ink); font-weight: 600; }


/* ---------------------------------------------------------------- topbar tags
   A library can have dozens of tags; clipping them silently hides filters and
   looks like the row collides with the search button. Scroll instead, without a
   visible scrollbar (the overflow is discoverable by dragging / wheel). */
.cats {
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none;
  -ms-overflow-style: none;
  -webkit-overflow-scrolling: touch;
  scroll-behavior: smooth;
  mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 22px), transparent 100%);
  -webkit-mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 22px), transparent 100%);
}
.cats::-webkit-scrollbar { width: 0; height: 0; }
.cats .pill { flex: none; }
/* the right-edge cards must not look clipped when the row is scrolled to its end */
.cats.at-end {
  mask-image: none;
  -webkit-mask-image: none;
}

/* arrows inside the pager pill read as one control with the counter */
.stage-nav .icon-btn { box-shadow: none; }


/* ------------------------------------------------- missing shared classes
   These were page-level rules in the mockups (build2.py / build5.py) and did
   not travel with the extracted CSS, so `tools/audit-css.mjs` reports them. */

.row { display: flex; align-items: center; gap: 9px; }
.row.tight { padding: 0; gap: 8px; }

.tbl { width: 100%; border-collapse: collapse; }
.tbl th {
  text-align: left; font-size: 10px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--ink-3); font-weight: 620; padding: 9px 8px;
}
.tbl td {
  font-size: 12px; padding: 9px 8px; border-top: 1px solid var(--hair-2);
  vertical-align: middle;
}
.tbl td .thumb { width: 34px; height: 34px; border-radius: 9px; object-fit: cover; display: block; }
.tbl td.nm { font-weight: 550; }
.tbl tr:last-child td { border-bottom: 0; }

/* kicker for the "公开 / 私密" column */
.badge.off { opacity: .55; }

/* screen-reader-only (file inputs triggered by a styled button) */
.sr {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* toasts: one stack, bottom centre, above every layer */
.toast {
  position: fixed; left: 50%; bottom: 26px; transform: translate(-50%, 12px);
  z-index: 90;
  display: flex; align-items: center; gap: 9px;
  height: 40px; padding: 0 16px; border-radius: 13px;
  font-size: 12.5px; font-weight: 540; color: var(--ink);
  background: var(--glass-strong); border: 1px solid var(--hair);
  box-shadow: 0 18px 40px -18px rgba(10, 20, 45, .45);
  backdrop-filter: blur(22px) saturate(180%);
  -webkit-backdrop-filter: blur(22px) saturate(180%);
  opacity: 0; transition: opacity .22s var(--ease), transform .28s var(--ease);
  pointer-events: none;
}
.toast.on,
.toast.show { opacity: 1; transform: translate(-50%, 0); }
.toast.err { border-color: rgba(255, 90, 90, .4); }


/* KPI tiles: admin.js emits .k / .v / .n (same shape as the mockup's .pcard),
   while the extracted CSS only knew .lab / .num. Wire the markup that exists. */
.kpi .k {
  font-size: 10.5px; letter-spacing: .05em; color: var(--ink-3);
}
.kpi .v {
  font-size: 27px; font-weight: 680; letter-spacing: -.022em;
  margin-top: 7px; font-variant-numeric: tabular-nums;
  display: flex; align-items: baseline; gap: 4px;
}
.kpi .v small { font-size: 12px; font-weight: 550; color: var(--ink-3); letter-spacing: 0; }
.kpi .n { margin-top: 7px; font-size: 10.5px; color: var(--ink-3); }


/* secondary label used in card heads and audit rows; only .drop .hint existed,
   so everywhere else it fell back to full-size body text */
.hint { font-size: 10.5px; color: var(--ink-3); letter-spacing: .01em; }


/* The queue row ships .jmeta / .jname / .jline / .jpct, while the extracted CSS
   only knew .body / h4 / .sub / .pct — so the row body never took the remaining
   width and the progress bar rendered at a fraction of the row. */
.job .jmeta { flex: 1; min-width: 0; }
.job .jname {
  font-size: 12.5px; font-weight: 570; letter-spacing: -.005em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.job .jline {
  margin-top: 4px; font-size: 10.5px; color: var(--ink-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.job .jpct { flex: none; font-variant-numeric: tabular-nums; }
