* {
  margin: 0;
  -webkit-tap-highlight-color: transparent;
}

html,
body {
  -webkit-user-select: none;
  user-select: none;
  width: 100%;
  height: 100%;
}

body {
  overflow-x: hidden;
  font-size: 16px;
}

uni-app,
uni-page,
uni-page-wrapper,
uni-page-body {
  display: block;
  box-sizing: border-box;
  width: 100%;
}

uni-page-wrapper {
  position: relative;
}

#app,
uni-app,
uni-page,
uni-page-wrapper {
  height: 100%;
}

/* toast,modal,actionSheet,picker,layout */
.uni-mask {
  position: fixed;
  z-index: 999;
  top: 0;
  right: 0;
  left: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.5);
}

/* toast,modal,actionSheet,picker */
.uni-fade-enter-active,
.uni-fade-leave-active {
  transition-duration: 0.25s;
  transition-property: opacity;
  transition-timing-function: ease;
}

.uni-fade-enter-from,
.uni-fade-leave-active {
  opacity: 0;
}

.uni-loading,
uni-button[loading]:before {
  background-color: transparent;
  background-image: url('data:image/svg+xml;base64, PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAiIGhlaWdodD0iMTIwIiB2aWV3Qm94PSIwIDAgMTAwIDEwMCI+PHBhdGggZmlsbD0ibm9uZSIgZD0iTTAgMGgxMDB2MTAwSDB6Ii8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjRTlFOUU5IiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAgLTMwKSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iIzk4OTY5NyIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSgzMCAxMDUuOTggNjUpIi8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjOUI5OTlBIiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0icm90YXRlKDYwIDc1Ljk4IDY1KSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iI0EzQTFBMiIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSg5MCA2NSA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNBQkE5QUEiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoMTIwIDU4LjY2IDY1KSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iI0IyQjJCMiIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSgxNTAgNTQuMDIgNjUpIi8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjQkFCOEI5IiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0icm90YXRlKDE4MCA1MCA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNDMkMwQzEiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoLTE1MCA0NS45OCA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNDQkNCQ0IiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoLTEyMCA0MS4zNCA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNEMkQyRDIiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoLTkwIDM1IDY1KSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iI0RBREFEQSIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSgtNjAgMjQuMDIgNjUpIi8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjRTJFMkUyIiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0icm90YXRlKC0zMCAtNS45OCA2NSkiLz48L3N2Zz4=');
  background-repeat: no-repeat;
}

.uni-loading {
  width: 20px;
  height: 20px;
  display: inline-block;
  vertical-align: middle;
  animation: uni-loading 1s steps(12, end) infinite;
  background-size: 100%;
}

@keyframes uni-loading {
  0% {
    transform: rotate3d(0, 0, 1, 0deg);
  }

  100% {
    transform: rotate3d(0, 0, 1, 360deg);
  }
}

html {
  /* --UI-BG-0: #ededed; */
  --primary-color: #007aff;
  --UI-BG: #fff;
  --UI-BG-1: #f7f7f7;
  --UI-BG-2: #fff;
  --UI-BG-3: #f7f7f7;
  --UI-BG-4: #4c4c4c;
  --UI-BG-5: #fff;
  --UI-FG: #000;
  --UI-FG-0: rgba(0, 0, 0, 0.9);
  --UI-FG-HALF: rgba(0, 0, 0, 0.9);
  --UI-FG-1: rgba(0, 0, 0, 0.5);
  --UI-FG-2: rgba(0, 0, 0, 0.3);
  --UI-FG-3: rgba(0, 0, 0, 0.1);
}

uni-page[data-type] uni-page-body {
  background-color: transparent;
}
body::after {
  position: fixed;
  content: '';
  left: -1000px;
  top: -1000px;
  animation: shadow-preload 0.1s;
  animation-delay: 3s;
}

@keyframes shadow-preload {
  0% {
    background-image: url(https://cdn1000.dcloud.net.cn/img/shadow-grey.png);
  }
  100% {
    background-image: url(https://cdn1000.dcloud.net.cn/img/shadow-grey.png);
  }
}
.uni-async-error {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  color: #999;
  padding: 100px 10px;
  text-align: center;
}
.uni-async-loading {
  box-sizing: border-box;
  width: 100%;
  padding: 50px;
  text-align: center;
}

.uni-async-loading .uni-loading {
  width: 30px;
  height: 30px;
}
html,
body {
  font-family: -apple-system, HelveticaNeue;
}

@font-face {
  font-family: "uni-icon";
  src: url('data:font/ttf;charset=utf-8;base64,AAEAAAANAIAAAwBQRkZUTamkKUUAABHkAAAAHEdERUYAKQAeAAARxAAAAB5PUy8yVrNgDgAAAVgAAABgY21hcEkVkugAAAH0AAABqmdhc3D//wADAAARvAAAAAhnbHlmxWjlfgAAA9QAAAs0aGVhZCn3QVQAAADcAAAANmhoZWEHXQMyAAABFAAAACRobXR4DVwE7AAAAbgAAAA6bG9jYR6gG/4AAAOgAAAAMm1heHAAHQBLAAABOAAAACBuYW1lTiJGjAAADwgAAAG/cG9zdHhGyVEAABDIAAAA8QABAAAAAQAASwA7Kl8PPPUACwQAAAAAAOOCfv8AAAAA44J+/wAA/1oD0wL/AAAACAACAAAAAAAAAAEAAAMs/ywAXAQAAAAAAAPTAAEAAAAAAAAAAAAAAAAAAAAFAAEAAAAYAEsABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAPnAZAABQAAApkCzAAAAI8CmQLMAAAB6wAzAQkAAAIABgMAAAAAAAAAAAABEAAAAAAAAAAAAAAAUGZFZADAACDqIwMs/ywAXAMsANQAAAABAAAAAAMYAAAAAAAgAAEBdgAiAAAAAAFVAAACAAAABAABTAFMAIsAkQCyANYA4wCnADwANwA8ADcAPAAtADwANwA3ADcANwAuAAAAAAADAAAAAwAAABwAAQAAAAAApAADAAEAAAAcAAQAiAAAAB4AEAADAA4AIOYC5gbmUOZh6gHqBOoI6gvqD+oU6hnqHuoj//8AAAAg5gDmBOZQ5mHqAeoD6gbqC+oP6hTqGeoe6iP////jGgQaAxm6GaoWCxYKFgkWBxYEFgAV/BX4FfQAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQYAAAEAAAAAAAAAAQIAAAACAAAAAAAAAAAAAAAAAAAAAQAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAFAAUABwASAB0AMQBOAGYAc4CCgIwAmYCqgL6A0YDpgPSBBwEaAS8BQIFSgWaAAAAAgAiAAABMgKqAAMABwAAMxEhESczESMiARDuzMwCqv1WIgJmAAAAAAEAAAAAAAAAAAACAAA5AgABAUz/7AK1Am0AFgAAASY0NzYyFwEeARUUBgcBBiInJjQ3CQEBVAgIBxYHATUEBAQE/ssHFgcICAEi/t4CQAcXBwgI/twECwUGCwT+3AgIBxcIARMBEwAAAQFM/+wCtQJtABcAAAkCFhQHBiInAS4BNTQ2NwE2MhcWFAcxAq3+3gEiCAgIFQj+zAUDAwUBNAgVCAgIAkD+7f7tCBcHCAgBJAQLBgULBAEkCAgHFwcAAAIAi//aA3UCfgAcADYAACUUBiMhIiY1ETQ2OwE1IyIGFREUFjMhMjY9ASMVEycHFwcOAw8BMzU+ATc+AT8CBxc3JzcDDQcE/cIEBgYEsMARGBgRAl8RFy5opCFud0qCYz0FAS8FNi0tdUAGam4hpAEBFgQHBwQBqAUGMRkR/jQRGRkSpZQBvKwjcwEGPF9+RwgHPG4rKzIEAQF0IqwCAgACAJH/zgNwAosAMQBKAAABLgEvAi4BIyIGDwIOAQcGFh8BBwYWFx4BMzI2PwEXHgEzMjY3PgEnNDA1Jzc+AScFNiYvATc+AT8BFx4BHwEHDgEfAScmBg8BA24CCgbjZwMKBwYKA2TjBgoCAQMEpSUBBQUDBgQCBQPKzAIFAwYKAwIBASijBQMC/fwBAwSNwgUJAlZYAgkFw4wEAwEirgULBK4BhAYIAR/NBgYGBs4jAQgGBgwEn+IGDAQCAgIBbGoBAQYGAwkDAQHeoQUMBrYGCgSIHQEGBbGwBQYBG4kECwXBWgMBAlwAAgCy/94DTwJ6ACEAPgAAASIGHQEUBiMhIiY9ATQmIyIGHQEeATMhMjY9ATQmJy4BIzcBLgEjIgYHAQYUFx4BMzI2NwE2MhcBFjI3PgEnAvAKDgsH/nUICw4KCQ8BJhsBjBsnBAMDCQVZ/uYKGA0NGAn+5gYHAwkFBAgEARkFEAUBGgcTBwYBBgEZDgniBwsLB+IJDg4J4hsnJxviBAkDBAM0ARoKCQkJ/uUHEwYEAwMDARkFBf7nBgcGEwcAAAAAAwDWAOoDKwFuAAsAFwAkAAAlMjY1NCYjIgYVFBYhMjY1NCYjIgYVFBYhMjY1NCYjIgYVFBYzARgcJyccGycnAQMcJyccGycnAQQbJycbHCcnHOonGxsnJxsbJycbGycnGxsnJxsbJycbGycAAQDjABADHQJJACUAAAE3NjQnJiIPAScmIgcGFB8BBwYUFx4BMzI2PwEXHgEzMjY3NjQnAijsCQkIGAjs6ggYCAkJ6uwJCQQKBgULBOzsBAsFBgoECQkBLuoJFwkICOvrCAgIGAjr6wgYCAQEBATr7QUEBQQIFwkAAQCnAHMDWAHmABEAAAEmIgcJASYiDgEXARYyNwE2NANQCBUI/tX+1QgVEAEIAT4IFggBPgcB3ggI/tYBKggQFgj+wgcHAT4IFgAAAAIAPP9oA8QC8QARACEAAAEiDgEVFBceATMyNjc2NTQuAQMiLgE1ND4BMzIeARUUDgECAXvQej090Ht6zz09es96cb1wcL1wcL5vb74C8XrQe3tpZnp6Zml7e9B6/JpvvXBwv29vv3BwvW8AAAMAN/9iA8oC9gALABQALAAAJRQrASI1AzQ7ATIHJyImNDYyFhQGAyIHBgcGFRQXFhcWMzI3Njc2NTQnJicmAhwCMwMIAkQDASQTGRklGhoXeWpmPT4+PWZqeX9saTw/PzxpazMCAgFrAgIyGSQaGiQZASZAPGlsf3lpZzw/PzxnaXmAa2k8QAAEADz/aAPEAvEACAASACQANAAAATI2NCYiBhQWFyMVMxEjFTM1IwMiDgEVFBceATMyNjc2NTQuAQMiLgE1ND4BMzIeARUUDgEB8RkhITIhIVOSOjrOPCp70Ho9PdB7es89PXrPenG9cHC9cHC+b2++AdwjMCMjMCM6Hv68HBwCsXrQe3tpZnp6Zml7e9B6/JpvvXBwv29vv3BwvW8AAAAAAgA3/2IDygL2ABUALQAACQEGIi8BJj8BNjIfARYyNwE2Mh8BFgEiBwYHBhUUFxYXFjMyNzY3NjU0JyYnJgMH/qoBBQGeAwMWAQQBgQIFAQE5AgUBFQP+8XlqZj0+Pj1manl/bGk8Pz88aWsBs/6vAQGjBAQeAgFjAQEBBQICFAQBQEA8aWx/eWlnPD8/PGdpeYBraTxAAAAEADz/aAPEAvEAFQAZACsAOwAAAQUOAS8BJgYPAQYWHwEWMjcBPgEmIhcwHwEDIg4BFRQXHgEzMjY3NjU0LgEDIi4BNTQ+ATMyHgEVFA4BAtz+7wYSBmMGDwUDBQEGgAUQBgEsBQIMEBUBAfd70Ho9PdB7es89PXrPenG9cHC9cHC+b2++Ab7iBQEFSwUCBgQIEQaDBgUBKAUPDAUBAQE0etB7e2lmenpmaXt70Hr8mm+9cHC/b2+/cHC9bwAAAAABAC3/3gPRAnsAFwAANy4BPwE+AR8BFjY3ATYWFycWFAcBBiInPQoGBwUHGwzQDCILAioMHwwOCwv9qwofCuoMIQ8LDQgKlgkBCgHJCQIKDQseC/2iCwoAAwA8/2gDxALxAAsAHQAtAAABBycHFwcXNxc3JzcDIg4BFRQXHgEzMjY3NjU0LgEDIi4BNTQ+ATMyHgEVFA4BAp6enR2enh2dnh2enrp70Ho9PdB7es89PXrPenG9cHC9cHC+b2++AeadnRyenhydnRyengEnetB7e2lmenpmaXt70Hr8mm+9cHC/b2+/cHC9bwAAAAMAN/9iA8oC9gAPABgAMAAAATMyFhUDFAYrASImNQM0NhMiJjQ2MhYUBgMiBwYHBhUUFxYXFjMyNzY3NjU0JyYnJgHkOAQGDQMCKAMDDAYgDxcXHhcXFHlqZj0+Pj1manl/bGk8Pz88aWsCFgYF/rkCBAQCAUcFBv4sFiAWFiAWArRAPGlsf3lpZzw/PzxnaXmAa2k8QAAAAgA3/2IDygL2ABsAMwAAJRYOASIvAQcGLgE0PwEnJj4BFh8BNzYeAQYPAQMiBwYHBhUUFxYXFjMyNzY3NjU0JyYnJgLKCgETGwmdowkbEgqinQkBExoKnaIKGhMBCaMyeWpmPT4+PWZqeX9saTw/Pzxpa4gJGxIKop0JARMaCp2iChoTAQmjnQoBExsJnQHLQDxpbH95aWc8Pz88Z2l5gGtpPEAAAAAAAgA3/2IDygL2ABcALQAAASIHBgcGFRQXFhcWMzI3Njc2NTQnJicmEwcGIi8BJjY7ARE0NjsBMhYVETMyFgH7eWpmPT4+PWZqeX9saTw/PzxpayB4DykOeQ4NGF8LBycHDF8XDgL2QDxpbH95aWc8Pz88Z2l5gGtpPED9354SEp4SGwEeCAsLCP7iGwACADf/YgPKAvYAFAAsAAAlBwYnJSYnJjUTNDY7ATIWFRMXHgEDIgcGBwYVFBcWFxYzMjc2NzY1NCcmJyYC3xADBP8ABAIEEQMCLAIDDsoCAeV5amY9Pj49Zmp5f2xpPD8/PGlrbR0EAnoCAgMGAYMCAwMC/qWIAgQCh0A8aWx/eWlnPD8/PGdpeYBraTxAAAADAC7/WgPTAv8AGgAvADAAACUGBwYjIicmJyY0NzY3NjIXFhcWFRQHBgcBBwEyNzY3NjQnJicmIgcGBwYUFxYXFjMCjzI7PkFmV1MzMjIzU1fLVlYxMhYWKAEQNf4FUUVDKCgoKENFokVFJykpJ0VFUWkoFhYyMVZWy1dTMzMzM1NXZkE+OzL+8TQBBigoQ0WjREUnKSknRUSjRUMoKAAAAAAMAJYAAQAAAAAAAQAKABYAAQAAAAAAAgAGAC8AAQAAAAAAAwAbAG4AAQAAAAAABAAKAKAAAQAAAAAABQAeAOkAAQAAAAAABgAKAR4AAwABBAkAAQAUAAAAAwABBAkAAgAMACEAAwABBAkAAwA2ADYAAwABBAkABAAUAIoAAwABBAkABQA8AKsAAwABBAkABgAUAQgAZgBvAG4AdABlAGQAaQB0AG8AcgAAZm9udGVkaXRvcgAATQBlAGQAaQB1AG0AAE1lZGl1bQAARgBvAG4AdABFAGQAaQB0AG8AcgAgADEALgAwACAAOgAgAGYAbwBuAHQAZQBkAGkAdABvAHIAAEZvbnRFZGl0b3IgMS4wIDogZm9udGVkaXRvcgAAZgBvAG4AdABlAGQAaQB0AG8AcgAAZm9udGVkaXRvcgAAVgBlAHIAcwBpAG8AbgAgADEALgAwADsAIABGAG8AbgB0AEUAZABpAHQAbwByACAAKAB2ADEALgAwACkAAFZlcnNpb24gMS4wOyBGb250RWRpdG9yICh2MS4wKQAAZgBvAG4AdABlAGQAaQB0AG8AcgAAZm9udGVkaXRvcgAAAAIAAAAAAAAAMgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAAAAEAAgADAQIBAwEEAQUBBgEHAQgBCQEKAQsBDAENAQ4BDwEQAREBEgETARQBFQdmb3J3YXJkBGJhY2sFc2hhcmUJZmF2b3JpdGVzBGhvbWUEbW9yZQVjbG9zZQRkb3duBmNpcmNsZQRpbmZvCmluZm9jaXJjbGUHc3VjY2Vzcw1zdWNjZXNzY2lyY2xlD3N1Y2Nlc3Nub2NpcmNsZQxjYW5jZWxjaXJjbGUEd2FybgVjbGVhcghkb3dubG9hZAd3YWl0aW5nBnNlYXJjaAAAAAAAAAH//wACAAEAAAAMAAAAFgAAAAIAAQADABcAAQAEAAAAAgAAAAAAAAABAAAAAOKfK0YAAAAA44J+/wAAAADjgn7/') format('truetype');
}

body, uni-page-body {
  background-color: var(--background-color-content);
}

uni-app uni-page-body {
  height: 100%;
  overflow: visible;
  position: relative;
}

uni-app uni-page-body,
uni-app uni-top-window,
uni-app uni-left-window,
uni-app uni-right-window {
  position: relative;
}

uni-app uni-left-window .uni-left-window,
uni-app uni-right-window .uni-right-window {
  height: 100%;
}

uni-app.uni-app--showtabbar uni-page-body::after {
  content: '';
  display: block;
  width: 100%;
  height: var(--tab-bar-height);
  height: calc(var(--tab-bar-height) + constant(safe-area-inset-bottom));
  height: calc(var(--tab-bar-height) + env(safe-area-inset-bottom));
  min-height: var(--tab-bar-height);
  min-height: calc(var(--tab-bar-height) + constant(safe-area-inset-bottom));
  min-height: calc(var(--tab-bar-height) + env(safe-area-inset-bottom));
}

uni-app.uni-app--showtabbar uni-page-wrapper::after {
  display: none;
}

uni-app uni-text,
uni-app uni-input,
uni-app uni-textarea,
uni-app uni-match-media,
uni-app uni-view {
  font-size: 16px;
  text-align: left;
}

/* input 布局对齐 App 端 */
uni-app uni-input {
  height: auto;
  display: flex;
}

uni-app uni-input>.uni-input-wrapper {
  height: auto;
  flex: 1;
}

uni-app uni-input>.uni-input-wrapper>.uni-input-input {
  height: auto;
  flex: 1;
}

/* 文字容器 */
uni-app uni-text,
uni-app uni-textarea,
uni-app uni-label {
  overflow: hidden;
  flex-basis: auto;
  letter-spacing: 0;
}

uni-app uni-text,
uni-app uni-label {
  letter-spacing: 0;
}

/* uni-app uni-* */
uni-app uni-ad-draw,
uni-app uni-ad-fullscreen-video,
uni-app uni-ad-interactive,
uni-app uni-ad-interstitial,
uni-app uni-ad-rewarded-video,
uni-app uni-ad,
uni-app uni-animation-view,
uni-app uni-audio,
uni-app uni-block,
uni-app uni-button,
uni-app uni-camera,
uni-app uni-canvas,
uni-app uni-checkbox-group,
uni-app uni-checkbox,
uni-app uni-cover-image,
uni-app uni-cover-view,
uni-app uni-custom-tab-bar,
uni-app uni-editor,
uni-app uni-form,
uni-app uni-icon,
uni-app uni-image,
uni-app uni-input,
uni-app uni-label,
uni-app uni-list-item,
uni-app uni-list-view,
uni-app uni-live-player,
uni-app uni-live-pusher,
uni-app uni-map,
uni-app uni-match-media,
uni-app uni-movable-area,
uni-app uni-movable-view,
uni-app uni-navigation-bar,
uni-app uni-navigator,
uni-app uni-open-data,
uni-app uni-page-meta,
/* uni-app uni-picker-view-column, */
uni-app uni-picker-view,
uni-app uni-picker,
uni-app uni-progress,
uni-app uni-radio-group,
uni-app uni-radio,
uni-app uni-rich-text,
uni-app uni-scroll-view,
uni-app uni-slider,
uni-app uni-sticky-header,
uni-app uni-sticky-section,
uni-app uni-swiper-item,
uni-app uni-swiper,
uni-app uni-switch,
uni-app uni-template,
uni-app uni-text,
uni-app uni-textarea,
uni-app uni-unicloud-db,
uni-app uni-video,
uni-app uni-view,
uni-app uni-web-view {
  position: relative;
  box-sizing: border-box;
  flex-shrink: 0;
  flex-grow: 0;
  flex-basis: auto;
  /* 默认情况下，元素不会缩短至小于内容框尺寸，若想改变这一状况，请设置元素的min-width 与 min-height属性。https://developer.mozilla.org/zh-CN/docs/Web/CSS/flex */
  min-height: 0px;
  min-width: 0px;
  border-width: medium;
}

uni-app uni-rich-text {
  line-height: 1.5;
}

uni-app uni-text {
  display: block;
  white-space: pre-line;
}

uni-app uni-text>span>uni-text {
  display: inline;
}

/* uni-app uni-* */
uni-app uni-ad-draw[hidden],
uni-app uni-ad-fullscreen-video[hidden],
uni-app uni-ad-interactive[hidden],
uni-app uni-ad-interstitial[hidden],
uni-app uni-ad-rewarded-video[hidden],
uni-app uni-ad[hidden],
uni-app uni-animation-view[hidden],
uni-app uni-audio[hidden],
uni-app uni-block[hidden],
uni-app uni-button[hidden],
uni-app uni-camera[hidden],
uni-app uni-canvas[hidden],
uni-app uni-checkbox-group[hidden],
uni-app uni-checkbox[hidden],
uni-app uni-cover-image[hidden],
uni-app uni-cover-view[hidden],
uni-app uni-custom-tab-bar[hidden],
uni-app uni-editor[hidden],
uni-app uni-form[hidden],
uni-app uni-icon[hidden],
uni-app uni-image[hidden],
uni-app uni-input[hidden],
uni-app uni-label[hidden],
uni-app uni-list-item[hidden],
uni-app uni-list-view[hidden],
uni-app uni-live-player[hidden],
uni-app uni-live-pusher[hidden],
uni-app uni-map[hidden],
uni-app uni-match-media[hidden],
uni-app uni-movable-area[hidden],
uni-app uni-movable-view[hidden],
uni-app uni-navigation-bar[hidden],
uni-app uni-navigator[hidden],
uni-app uni-open-data[hidden],
uni-app uni-page-meta[hidden],
uni-app uni-picker-view-column[hidden],
uni-app uni-picker-view[hidden],
uni-app uni-picker[hidden],
uni-app uni-progress[hidden],
uni-app uni-radio-group[hidden],
uni-app uni-radio[hidden],
uni-app uni-rich-text[hidden],
uni-app uni-scroll-view[hidden],
uni-app uni-slider[hidden],
uni-app uni-sticky-header[hidden],
uni-app uni-sticky-section[hidden],
uni-app uni-swiper-item[hidden],
uni-app uni-swiper[hidden],
uni-app uni-switch[hidden],
uni-app uni-template[hidden],
uni-app uni-text[hidden],
uni-app uni-textarea[hidden],
uni-app uni-unicloud-db[hidden],
uni-app uni-video[hidden],
uni-app uni-view[hidden],
uni-app uni-web-view[hidden] {
  display: none !important;
}

/* 与开发者元素接触的容器 */
uni-app uni-page-body,
uni-app uni-left-window .uni-left-window,
uni-app uni-right-window .uni-right-window,
uni-app uni-top-window .uni-top-window,
uni-app uni-animation-view,
uni-app uni-block,
uni-app uni-view,
uni-app uni-match-media,
uni-app uni-label,
uni-app uni-swiper,
uni-app uni-swiper-item,
uni-app uni-movable-area,
uni-app uni-movable-view,
uni-app uni-cover-view,
uni-app uni-list-item,
uni-app uni-navigator,
uni-app uni-radio-group,
uni-app uni-checkbox-group,
uni-app uni-scroll-view,
uni-app uni-list-view,
uni-app uni-unicloud-db,
uni-app uni-custom-tab-bar,
uni-app uni-sticky-section,
uni-app uni-sticky-header {
  display: flex;
  align-items: stretch;
  align-content: stretch;
  justify-content: flex-start;
}

/* 此样式可被manifest.json内配置的flex-direction重置 */
uni-app uni-page-body,
uni-app uni-left-window .uni-left-window,
uni-app uni-right-window .uni-right-window,
uni-app uni-top-window .uni-top-window,
uni-app uni-view,
uni-app uni-match-media,
uni-app uni-label,
uni-app uni-swiper,
uni-app uni-swiper-item,
uni-app uni-movable-area,
uni-app uni-movable-view,
uni-app uni-cover-view,
uni-app uni-list-item,
uni-app uni-navigator,
uni-app uni-radio-group,
uni-app uni-checkbox-group,
uni-app uni-scroll-view,
uni-app uni-list-view,
uni-app uni-unicloud-db,
uni-app uni-sticky-section,
uni-app uni-sticky-header {
  flex-direction: column;
}

/* 与开发者元素接触的非滚动容器 */
uni-app uni-view,
uni-app uni-match-media,
uni-app uni-label,
uni-app uni-swiper,
uni-app uni-swiper-item,
uni-app uni-movable-area,
uni-app uni-movable-view,
uni-app uni-cover-view,
uni-app uni-list-item,
uni-app uni-navigator,
uni-app uni-radio-group,
uni-app uni-checkbox-group {
  overflow: hidden;
}

uni-app uni-button {
  margin: 0;
}

/* 透传scroll-view的flex-direction样式 */
uni-app uni-scroll-view {
  width: auto;
}

uni-app .uni-scroll-view,
uni-app .uni-scroll-view-content,
uni-app .uni-list-view-visible,
uni-app uni-navigator a {
  flex-direction: inherit;
  align-items: inherit;
  align-content: inherit;
  justify-content: inherit;
  flex-wrap: inherit;
}

uni-app uni-navigator a {
  display: flex;
  width: 100%;
  height: 100%;
}

uni-app .uni-scroll-view-content,
uni-app .uni-sticky-header-wrapper {
  display: flex;
  min-height: 0px;
}

uni-app uni-swiper-item {
  position: absolute;
}

/* 设置默认的光标颜色 */
uni-app .uni-input-input,
uni-app .uni-textarea-textarea {
  caret-color: #3393e2;
}

uni-app .uni-input-input:disabled,
uni-app .uni-textarea-textarea:disabled {
  cursor: inherit;
}

uni-app uni-checkbox {
  align-items: center;
}

uni-app .uni-checkbox-wrapper {
  flex-direction: inherit;
  align-content: inherit;
  justify-content: inherit;
  align-items: inherit;
  width: 100%;
  height: 100%;
}

/* 覆盖 video 的 poster 背景 */
uni-app .uni-video-cover {
  background-color: unset;
}

/**
 * 界面相关api样式
 */
body .uni-toast {
  width: 120px;
  height: 120px;
  display: flex;
  justify-content: center;
  flex-direction: column;
  align-items: center;
  background-color: #4c4c4c;
}

body .uni-toast__icon {
  margin: 8px 0px;
}

body .uni-toast__content {
  margin: 0px;
  font-size: 14px;
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.8)
}

body .uni-modal {
  border-radius: 12px;
}

body .uni-modal__hd {
  padding: 32px 24px 16px;
}

body .uni-modal__title {
  font-weight: 700;
  font-size: 17px;
  line-height: 1.4;
  -webkit-line-clamp: unset;
}

body .uni-modal__bd {
  font-size: 17px;
  padding: 0 24px;
  margin-bottom: 32px;
  min-height: unset;
  max-height: 300px;
  overflow: hidden auto;
  -webkit-hyphens: auto;
          hyphens: auto;
}

body .uni-modal__textarea {
  display: block;
  width: 100%;
  height: 48px;
  font-size: 17px;
  line-height: 24px;
  padding: 0px 8px;
}

body .uni-modal__ft {
  line-height: 56px;
  font-size: 17px;
}

body .uni-modal__btn {
  font-weight: 700;
}

body .uni-modal__btn_primary {
  color: #576b95;
}

@media screen and (max-width: 500px) {
  body .uni-actionsheet {
    left: 0px;
    right: 0px;
    bottom: 0px;
    border-top-left-radius: 12px;
    border-top-right-radius: 12px;
    background-color: #f7f7f7;
    overflow: hidden;
  }

  body .uni-actionsheet__menu {
    border-radius: 0px;
    background-color: #ffffff;
  }

  body .uni-actionsheet__action {
    border-radius: 0px;
    margin-top: 8px;
  }

  body .uni-actionsheet__cell,
  body .uni-actionsheet__title {
    padding: 16px;
    line-height: 24px;
  }

  body .uni-actionsheet__cell {
    font-size: 17px;
  }

  body .uni-actionsheet__title {
    font-size: 14px;
    color: #747474;
  }
}

:is(.uni-video-slots *) {
  pointer-events: auto;
}
/* == design tokens: generated by scripts/design/gen-tokens.mjs, do not edit == */
/* 真源 scripts/design/tokens.json —— 改令牌改 json，再跑 node scripts/design/gen-tokens.mjs； */
/* npm run check 里的 gen-tokens --check 会拦住直接手改这一段。 */
/* 已核实：两端 App.uvue 引全局样式用的是 <style>@import './uni.scss'</style>（没有 lang="scss"）， */
/* 这条链路按普通 CSS 解析，写 $ 变量既不会求值也不会报错，只会静默变成无效声明； */
/* 所以本文件里的值一律写字面值。来龙去脉见 styles/_tokens.scss 头部与 gen-tokens.mjs 顶部注释。 */
/* 本生成段之外的规则脚本一行都不碰。 */
/* */
/* PC 只发 H5，var() 可用。这份 --color-* 是留给将来主题切换的运行期出口， */
/* 页面今天仍然直接写令牌字面值，由 lint 校验集合成员，不要为了用 var() 去改页面。 */
uni-page-body {
  --color-brand: #246beb;
  --color-primary-hover: #1f5fd1;
  --color-primary-active: #174fae;
  --color-primary-soft: #e7f0ff;
  --color-primary-border: #c9ddfb;
  --color-link: #1f5fd1;
  --color-text-1: #1b263b;
  --color-text-2: #45536a;
  --color-text-3: #647389;
  --color-text-disabled: #94a3b8;
  --color-icon-muted: #94a3b8;
  --color-bg-page: #edf4fb;
  --color-surface: #ffffff;
  --color-surface-2: #f3f6fa;
  --color-line: #e8edf4;
  --color-line-strong: #cbd5e1;
  --color-divider: #edf0f5;
  --color-success-text: #526078;
  --color-success-bg: #eef1f6;
  --color-success-border: #dce2eb;
  --color-warning-text: #94540f;
  --color-warning-bg: #fff3e1;
  --color-warning-border: #fde68a;
  --color-danger-text: #b42318;
  --color-danger-bg: #fff0ee;
  --color-danger-border: #fecaca;
  --color-danger-solid: #dc2626;
  --color-info-text: #1f5fd1;
  --color-info-bg: #e7f0ff;
  --color-info-border: #bfdbfe;
  --color-neutral-text: #45536a;
  --color-neutral-bg: #f3f6fa;
  --color-neutral-border: #e2e8f0;
  --color-reserve-text: #7c3aed;
  --color-reserve-bg: #f5f3ff;
  --color-on-primary-muted: rgba(255,255,255,.9);
  --color-amount: #151e30;
  --color-number: #151e30;
  --color-brand-display: #2878f5;
  --color-nav-active: #dfeaff;
  --color-masthead-ink: #195aba;
  --color-masthead-start: #e6f1ff;
  --color-masthead-end: #f1f7fc;
  --color-masthead-glow: #dcecff;
  --color-sidebar-surface: #f8fbff;
  --color-sidebar-end: #f5faff;
  --color-brand-signature: #526b8d;
  --color-brand-signature-bg: #e6eef9;
}
/* */
/* ---- 令牌清单：PC 后台 delivery-uniapp-x，只发 H5 口径，值即真源 ---- */
/* [颜色] */
/* color.brand = #246beb — 品牌主色。仅两种用途：每屏 1 个主按钮、至多 1 张 hero 卡（移动端钱包余额、首页概览）。导航当前项不再用它——当前项的信号是中性灰 pill + 主文色 + 600 字重 */
/* color.primary-hover = #1f5fd1 — PC 主按钮悬停态；App 端没有 hover，不要用 */
/* color.primary-active = #174fae — PC 主按钮按下态 */
/* color.primary-soft = #e7f0ff — 选中态底色（tab、chip、导航当前项、头像默认态） */
/* color.primary-border = #c9ddfb — 选中态边框，配 primary-soft 使用 */
/* color.link = #1f5fd1 — 文字链接。比 brand 深一档，用来和主按钮区分 */
/* color.text-1 = #1b263b — 主文 */
/* color.text-2 = #45536a — 次文；浅灰底 #f8fafc 上的最浅可用文字也用它 */
/* color.text-3 = #647389 — 白底上的最浅可用文字（4.8:1）；浅灰底上改用 text-2 */
/* color.text-disabled = #94a3b8 — 只允许用于 placeholder 与禁用态。lint 对普通 color: 上出现 #94a3b8 报错 */
/* color.icon-muted = #94a3b8 — 装饰性图标与分隔符。与 text-disabled 同值，语义不同，别互相顶替 */
/* color.bg-page = #edf4fb — 页面底色，两端各一值。移动端 orders/order-dispatch 的 #e8eef5、create 的 #f3f6fb 全部归一到这里 */
/* color.surface = #ffffff — 卡片底 */
/* color.surface-2 = #f3f6fa — 卡内浅底 */
/* color.line = #e8edf4 — 默认边框。替换现网 #dfe7f1 / #e4eaf2 / #e5ebf3 / #eef2f7 */
/* color.line-strong = #cbd5e1 — 输入框等需要被看见的边框 */
/* color.divider = #edf0f5 — 分隔线，比 line 更弱 */
/* color.success-text = #526078 — 完成 / 中标 / 已接单 的文字色。移动端 #047857 / #16a34a / #059669 归一到这里 */
/* color.success-bg = #eef1f6 — success 浅底 */
/* color.success-border = #dce2eb — success 边框 */
/* color.warning-text = #94540f — 预警中 / 待处理 / 剩余 ≤10 分钟 的文字色。废弃 #d97706（3.1:1）与 #f97316 / #ea580c / #c2410c */
/* color.warning-bg = #fff3e1 — warning 浅底 */
/* color.warning-border = #fde68a — warning 边框 */
/* color.danger-text = #b42318 — 超时 / 异常 / 取消类 / 失败 的文字色。标签文字必须用它，#dc2626 压在 #fef2f2 上只有 4.4:1 */
/* color.danger-bg = #fff0ee — danger 浅底 */
/* color.danger-border = #fecaca — danger 边框 */
/* color.danger-solid = #dc2626 — 危险实心按钮底色（白字），以及 uni.showModal 的 confirmColor。全站唯一一种红 */
/* color.info-text = #1f5fd1 — 进行中（呼叫中 / 配送中）的文字色 */
/* color.info-bg = #e7f0ff — info 浅底 */
/* color.info-border = #bfdbfe — info 边框 */
/* color.neutral-text = #45536a — 已停用 / 已关闭 / 已结束 的文字色。停用是常态不是错误，不许用红 */
/* color.neutral-bg = #f3f6fa — neutral 浅底 */
/* color.neutral-border = #e2e8f0 — neutral 边框，与 line 同值 */
/* color.reserve-text = #7c3aed — 预约单专色文字（PC 盯单卡「预」标签），替代原来的橙色实心 */
/* color.reserve-bg = #f5f3ff — 预约单浅底。§3.1 没有给 reserve 边框色，需要描边时用 line */
/* color.on-primary-muted = rgba(255,255,255,.9) — 蓝底上的次要文字（≥4.5:1）。#bfdbfe 只有 3.6:1、#e0ecff 4.3:1，都不达标 */
/* color.amount = #151e30 — 金额中性色，配 font-weight 600。移动端 #f0440b 金额强调色保留为登记在案的例外 */
/* color.number = #151e30 — PC R5黑色计数与金额，按字号区分层级 */
/* color.brand-display = #2878f5 — PC R5品牌图形色，小文字使用link */
/* color.nav-active = #dfeaff — PC R5导航选中底，配link色文字 */
/* color.masthead-ink = #195aba — PC R5产品抬头 */
/* color.masthead-start = #e6f1ff — PC R5顶部浅蓝背景 */
/* color.masthead-end = #f1f7fc — PC R5顶部浅蓝背景结束 */
/* color.masthead-glow = #dcecff — PC R5顶部背景浅色层 */
/* color.sidebar-surface = #f8fbff — PC R5侧栏浅色表面 */
/* color.sidebar-end = #f5faff — PC R5侧栏末端表面 */
/* color.brand-signature = #526b8d — PC R5侧栏品牌落款 */
/* color.brand-signature-bg = #e6eef9 — PC R5落款标识底 */
/* */
/* [图表色板与实体固定色（脚本里用，出口是 utils/theme.uts）] */
/* chart.series-primary = #2878f5 — 数量序列主色，同一张图 ≤ 3 条 */
/* chart.series-secondary = #a0c7fb — 数量序列次色 */
/* chart.series-neutral = #94a3b8 — 数量序列中性色（对比项、未归属） */
/* chart.series-rate = #f59e0b — 比率序列固定色。全站唯一暖色，只给「率」，不许拿去当强调色 */
/* chart.series-ink = #151e30 — 单序列图表的墨色柱/线。图里只有一根序列时色相不承载任何信息，用墨色让它退成「量」本身；多序列仍走 series-primary/secondary */
/* chart.category-1 = #2878f5 — 分类板 C1，顺序固定不许打乱 */
/* chart.category-2 = #6aa4f7 — 分类板 C2 */
/* chart.category-3 = #a0c7fb — 分类板 C3 */
/* chart.category-4 = #4d8dec — 分类板 C4 */
/* chart.category-5 = #476b99 — 分类板 C5 */
/* chart.category-6 = #7387a3 — 分类板 C6 */
/* chart.carrier-DADA = #2878f5 — 运力实体固定色：达达 */
/* chart.carrier-SHANSONG = #a0c7fb — 运力实体固定色：闪送 */
/* chart.carrier-FENGNIAO = #6aa4f7 — 运力实体固定色：蜂鸟即配（ELEME 作运力码时同色） */
/* chart.carrier-SF = #4d8dec — 运力实体固定色：顺丰同城（SHUNFENG 同色） */
/* chart.carrier-JD = #476b99 — 运力实体固定色：京东驻店专送（JDDJ / JINGDONG 同色） */
/* chart.carrier-UU = #7387a3 — 运力实体固定色：UU跑腿 */
/* chart.carrier-UNASSIGNED = #94a3b8 — 运力实体固定色：未归属。也是未登记运力码的兜底色 */
/* chart.channel-MEITUAN = #f59e0b — 渠道实体固定色：美团外卖 */
/* chart.channel-ELEME = #2563eb — 渠道实体固定色：饿了么 */
/* chart.channel-DOUYIN = #0f172a — 渠道实体固定色：抖音 */
/* chart.channel-TAOBAO = #e11d48 — 渠道实体固定色：淘宝闪购（TAOBAO_FLASH / TAOBAO_SHANGOU 同色） */
/* chart.channel-OFFLINE = #64748b — 渠道实体固定色：线下 / 手工单 */
/* chart.channel-OTHER = #94a3b8 — 渠道实体固定色：其它。也是未登记渠道码的兜底色 */
/* chart.map-store = #2878f5 — 地图打点：门店 */
/* chart.map-customer = #dc2626 — 地图打点：顾客 */
/* chart.map-rider = #4d8dec — 地图打点：骑手。规划线画实线、实际轨迹画灰虚线，不画推测线 */
/* */
/* [字号（8 档角色映射）] */
/* font-size.@scale = 12 / 13 / 14 / 15 / 16 / 18 / 20 / 22 / 24 / 26 / 28 / 32 (px) — 值域白名单。最小字号两端都是 12，8/9/10px 清零；11 只走白名单（PC 表格内与侧栏徽标、移动 caption/角标） */
/* font-size.page-title = 26px — 页标题，字重 700。移动端 Tab 首页大标题例外为 24 */
/* font-size.section-title = 18px — 卡片 / 区块标题，字重 600 */
/* font-size.metric = 24px — 指标数值，字重 700 + tabular-nums。PC 24 是 KPI 卡、28 是 hero */
/* font-size.body = 14px — 正文，字重 400 */
/* font-size.table-text = 13px — 表格 / 列表主文本，字重 500 */
/* font-size.caption = 12px — 辅助 / 时间 / 提示，字重 400 */
/* font-size.tag = 12px — 标签 / 徽标 / 表格副文本，字重 500。11 只在白名单里出现 */
/* font-size.button = 14px — 按钮，PC 字重 500、移动 600 */
/* font-size.todo = 32px — PC R5待办计数，行高40 */
/* font-size.amount = 20px — PC R5账簿金额，行高28 */
/* font-size.masthead = 24px — PC R5产品抬头，行高32 */
/* */
/* [字重（4 档）] */
/* font-weight.@scale = 400 / 500 / 600 — 800 全站禁用；650/660/680/720/730/740/750/760 这类假字重全部映射到 600 或 700 */
/* font-weight.regular = 400 — 正文、辅助文字 */
/* font-weight.medium = 500 — 表格主文本、标签、按钮（PC） */
/* font-weight.semibold = 600 — 区块标题、激活态页签、按钮（移动） */
/* font-weight.bold = 600 — 只出现在页标题与指标数值 */
/* */
/* [间距（8 档）] */
/* spacing.@scale = 4 / 8 / 12 / 16 / 20 / 24 / 32 / 40 (px) — 值域白名单，单位 px */
/* spacing.control-inline = 12px — 控件内横向内边距 */
/* spacing.card-inner = 16px — 卡片内边距 */
/* spacing.card-gap = 16px — 卡片之间的间距 */
/* spacing.section-gap = 24px — 区块之间的间距 */
/* spacing.page-padding = 20px — 页边距。PC 窗口 ≤1280 时收到 16 */
/* */
/* [圆角（6 档）] */
/* radius.@scale = 4 / 6 / 8 / 10 / 12 / 16 / 20 / 999 (px) — 值域白名单，单位 px（999 表示药丸/圆形） */
/* radius.tag = 4px — 标签 */
/* radius.control = 8px — 输入框 / 按钮 / 分段控件 */
/* radius.card = 12px — 卡片 / 表格 / 面板，两端同值 */
/* radius.overlay = 12px — 弹窗 / 抽屉 / 强调卡，与 card 同值 */
/* radius.sheet = 16px — 移动端底部 sheet 顶角、hero/overview 强调卡 */
/* radius.pill = 999px — 药丸 / 头像 */
/* radius.brand = 20px — PC R5左上品牌块外角 */
/* */
/* [阴影（5 档）] */
/* shadow.@note — 「描边或阴影二选一」。例外白名单只有：弹层、fixed 底栏、侧栏用户弹层 */
/* shadow.shadow-0 = none — 页内静态卡片：只描边不投影 */
/* shadow.shadow-1 = 0 1px 2px rgba(15,23,42,.06) — 极轻投影。PC 侧栏去掉蓝色大阴影后改用 1px 右边框，不用这一档 */
/* shadow.shadow-2 = 0 4px 12px rgba(15,23,42,.08) — 下拉 / 气泡 */
/* shadow.shadow-3 = 0 16px 40px rgba(15,23,42,.16) — 弹窗 / 抽屉 / sheet */
/* shadow.shadow-brand = 0 8px 20px rgba(37,99,235,.20) — 只给移动端主按钮 */
/* shadow.card = 0 4px 16px rgba(62,96,133,.03) — PC R5卡片轻投影；不与硬边框叠加 */
/* */
/* [控件高度] */
/* control-height.@scale = 28 / 36 / 44 (px) — 移动端列表卡操作按钮允许 52–54，属登记在案的例外；触控命中区一律 ≥44 */
/* control-height.sm = 28px — PC 行内文字按钮 / 移动卡片内联按钮 */
/* control-height.md = 36px — PC 筛选区与表单控件 / 移动次按钮 */
/* control-height.lg = 44px — PC 页级 CTA 与登录 / 移动主按钮 */
/* */
/* [层级] */
/* z-index.@note — 新增弹层只允许取表内值。uni.showModal / showToast 是原生层，不需要定义；value 为 null 表示该端没有这一层 */
/* z-index.sticky-page = 20 — PC 页内 sticky（页签行 / 批量条 / 表头）；移动 fixed 底栏 */
/* z-index.sticky-topbar = 30 — PC 顶栏 sticky。移动端没有这一层 */
/* z-index.dropdown = 40 — PC 下拉 / 更多菜单 / 浮层。移动端不适用 */
/* z-index.drawer-mask = 100 — PC 右侧抽屉遮罩；移动底部 sheet 遮罩 */
/* z-index.drawer-panel = 101 — PC 右侧抽屉面板；移动底部 sheet 面板 */
/* z-index.modal-mask = 120 — PC 页面级弹窗遮罩；移动居中弹窗遮罩 */
/* z-index.modal-panel = 121 — PC 页面级弹窗面板；移动居中弹窗面板 */
/* z-index.nested-mask = 130 — PC 行内 / 弹窗内二级弹窗遮罩；移动全局阻断（隐私 / 强制改密）遮罩 */
/* z-index.nested-panel = 131 — PC 行内 / 弹窗内二级弹窗面板；移动全局阻断面板 */
/* z-index.user-entry = 10 — PC 侧栏用户入口（局部堆叠上下文，其弹层 20）。validate-uniapp-x.mjs 钉死了这条规则里的正 z-index 数字与 overflow:visible，不许改成变量 */
/* */
/* [动效（三档）] */
/* motion.@note — 仅 PC Web 使用。App 端不做 CSS 动画，骨架屏用静态灰条 */
/* motion.duration-fast = 120ms — hover / 按下这类即时反馈 */
/* motion.duration-base = 180ms — 展开收起、切换 */
/* motion.duration-slow = 240ms — 抽屉 / 弹窗进出 */
/* motion.easing = cubic-bezier(.2,0,0,1) — 唯一缓动曲线 */
/* == end design tokens == */
html,
body,
#app {
  min-height: 100%;
  margin: 0;
}
uni-view {
  display: block;
}
uni-text {
  display: inline-block;
}
uni-page-body {
  background-color: #edf4fb;
  color: #1b263b;
  font-size: 14px;
}
body {
  background-color: #edf4fb;
}
.page {
  min-height: 100vh;
  padding: 16px;
  box-sizing: border-box;
}
.panel {
  background-color: #ffffff;
  border: 0;
  border-radius: 12px;
  padding: 16px;
  margin-bottom: 16px;
  box-sizing: border-box;
  box-shadow: 0 4px 16px rgba(62, 96, 133, 0.03);
}
.row {
  display: flex;
  flex-direction: row;
  align-items: center;
}
.col {
  display: flex;
  flex-direction: column;
}
.space-between {
  justify-content: space-between;
}
.title {
  font-size: 26px;
  font-weight: 600;
  color: #1b263b;
  line-height: 36px;
}
.section-title {
  font-size: 18px;
  font-weight: 600;
  color: #1b263b;
  margin-bottom: 12px;
  line-height: 28px;
}
.muted {
  color: #647389;
  font-size: 12px;
}
.button {
  min-height: 40px;
  padding: 0 14px;
  border-radius: 8px;
  background-color: #246beb;
  color: #ffffff;
  font-size: 14px;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  text-align: center;
  line-height: normal;
  cursor: pointer;
  transition: background-color 0.18s ease, border-color 0.18s ease, color 0.18s ease;
}
.button::after {
  border: 0;
}
.button[disabled] {
  cursor: not-allowed;
  opacity: 0.64;
}
.button.secondary {
  background-color: #ffffff;
  color: #45536a;
  border: 1px solid #e8edf4;
  box-sizing: border-box;
}
/* 提醒类动作（「忽略预警」「转商家自配」）：需要看清、但不越红线。
 * 橙底白字只有 2.8:1，所以一律深橙字。
 * 三个值全部取 §3.1 的 warning 三件套（#94540f / #fff3e1 / #fde68a）：
 *   原来的 #ffedd5 底 + #7c2d12 字 + #fed7aa 边都在令牌表外。
 *   底色没有直接搬到 warning-bg #fff3e1 —— 那样 hover 只剩 #fde68a 一档可用，
 *   而 #94540f 压在 #fde68a 上只有 4.03:1，会跌破 4.5:1（旧的 #7c2d12 on #ffedd5 是 8.18:1）。
 *   改成与本文件既有的 .admin-drill-exit 同一套「浅橙描边深字」写法：
 *   静息白底（#94540f on #ffffff = 5.02:1）、hover 才铺 warning-bg
 *   （#94540f on #fff3e1 = 4.84:1），两态都过 4.5:1。
 * 破坏性动作（取消订单 / 取消配送 / 删除）请用 .button.danger-outline；
 * 页面主 CTA 请用不带修饰类的 .button（实心主色），别用本类，
 * 否则会和旁边的 .button.secondary 变成同权重的两块浅色。 */
.button.warning {
  box-sizing: border-box;
  background-color: #ffffff;
  color: #94540f;
  border: 1px solid #fde68a;
}
.button.warning:hover {
  background-color: #fff3e1;
}
/* 破坏性主动作：实心红 */
.button.danger {
  box-sizing: border-box;
  background-color: #dc2626;
  color: #ffffff;
  border: 1px solid #dc2626;
}
.button.danger:hover {
  background-color: #b42318;
  border-color: #b42318;
}
/* 破坏性次动作（取消/终止类，动作条末尾） */
.button.danger-outline {
  box-sizing: border-box;
  background-color: #ffffff;
  color: #dc2626;
  border: 1px solid #fecaca;
}
.button.danger-outline:hover {
  background-color: #fff0ee;
}
/* ============================================================
 * U1-I9 焦点态与键盘可达（全站唯一一处焦点环定义）
 *
 * PC 只发 H5（package.json 只有 release:h5），:focus-visible / :focus-within
 * 与本文件里既有的 :hover 是同一档口径，可以直接用。
 *
 * 焦点环用 outline 而不是 border 或 box-shadow：
 *   - outline 不参与盒模型，聚焦时控件不会被顶大 1px，筛选栏不会跟着抖；
 *   - 方案 §4.1 原写法是 box-shadow: 0 0 0 3px rgba(37,99,235,.16)，
 *     但它不在 §3.1 的 5 档阴影令牌里，写进来会被 check:styles 判成新增违规；
 *   - outline-offset: 2px 让焦点环和控件自身的描边分开，实心主色按钮上也看得见。
 *
 * ⚠️ 关于「改成 <button> 就原生可聚焦」这个前提——实测不成立，证据：
 *   unpackage/dist/build/web/assets/uni.b4c8fde3.css 里是
 *     uni-button{position:relative;display:block;margin-left:auto;margin-right:auto;
 *                padding-left:14px;padding-right:14px;font-size:18px;line-height:2.55555556;
 *                border-radius:5px;color:#000;background-color:#f8f8f8;overflow:hidden}
 *     uni-button:after{...border:1px solid rgba(0,0,0,.2)...}
 *   index-*.js 里 Button 组件渲染的是 $a("uni-button", {ref, onClick, id, class})。
 * 也就是说 uni-app x 的 H5 运行时把 <button> 渲染成自定义元素 <uni-button>，
 * 只挂了 onClick，既没有 tabindex 也没有 role，它 **不是** 原生可聚焦元素，
 * Enter/Space 不会触发 click；<view>/<text> 同理。
 * 全仓库今天真正能吃到焦点的只有 <input>（uni-input 内部那个原生 input）。
 *
 * 因此这一组规则里：:focus-within 那条现在就生效；:focus-visible 那几条要等
 * 调用点补 tabindex="0" + @keydown（B2 逐页迁移时一起补）才会亮。
 * 样式先落好，届时只补属性，不用再回来改一遍全局样式。
 * ============================================================ */
.button:focus-visible,
.admin-filter-button:focus-visible,
.admin-tab-pill:focus-visible,
.admin-inline-button:focus-visible,
.admin-filter-select:focus-visible,
.admin-filter-input:focus-visible {
  outline: 2px solid #246beb;
  outline-offset: 2px;
}
.field {
  height: 42px;
  border: 1px solid #cbd5e1;
  border-radius: 8px;
  padding: 0 10px;
  margin-bottom: 10px;
  background-color: #ffffff;
  box-sizing: border-box;
}
.stat-grid {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  gap: 10px;
}
.stat-card {
  width: calc(50% - 5px);
  min-height: 72px;
  background-color: #f3f6fa;
  border: 1px solid #e8edf4;
  border-radius: 8px;
  padding: 12px;
  box-sizing: border-box;
}
.stat-value {
  font-size: 24px;
  font-weight: 600;
  color: #246beb;
  margin-top: 6px;
}
.list-item {
  padding: 12px 0;
  border-bottom: 1px solid #e8edf4;
}
.tag {
  min-width: 56px;
  padding: 3px 8px;
  border-radius: 4px;
  background-color: #e7f0ff;
  color: #1f5fd1;
  font-size: 12px;
  text-align: center;
}
/* U1-X2：滚动容器从 window 换到 .admin-main —— 侧栏与顶栏不再随页面滚走。
 * 壳锁定一屏高、自身不滚；侧栏 height:100% 后本来就不动，不需要 sticky；
 * .admin-nav-block 已是 flex:1 + min-height:0 + overflow-y:auto，菜单溢出由它接管。
 * ≤1000 断点会把 height/overflow 改回 auto/visible（竖排后再锁 100vh 就滚不动了）。
 * U1-I12：壳不再是「卡中卡」——外边距归零、底色用页面底色，侧栏与内容区都不带圆角与阴影。 */
.admin-shell {
  /* position:relative 是 .admin-sidebar.rail-open 的定位基准（U1-I6-b）。
   * 只用 position —— 这里同样不许出现 transform / filter / will-change，
   * 任何一个都会给后代的 position:fixed 造出新的包含块，全站弹窗与遮罩会失灵。 */
  position: relative;
  min-height: 100vh;
  height: 100vh;
  overflow: hidden;
  display: flex;
  flex-direction: row;
  background-color: #edf4fb;
  padding: 0;
  box-sizing: border-box;
}
/* U1-I6-a：236 → 220。1000–1280 这一档内容区原来只剩 ≈724px，
 * 侧栏每省一像素都直接加到表格与卡片上。 */
.admin-sidebar {
  width: 220px;
  height: 100%;
  background-color: #ffffff;
  color: #1b263b;
  box-sizing: border-box;
  padding: 24px 12px;
  display: flex;
  flex-direction: column;
  border-right: 1px solid #e8edf4;
  overflow: hidden;
  flex-shrink: 0;
}
/* ---- U1-I6-b 侧栏三档形态：full（220）/ rail（64 图标轨道）/ drawer（<1000 抽屉）----
 * 档位由 admin-layout 读 uni.getWindowInfo() + resize 决定并挂在 class 上，不是 @media：
 * rail 的「临时铺开」是交互状态（点了哪个分组图标），CSS 断点表达不了。
 * ⚠️ 这里的任何一条都不许覆盖 .admin-user-entry 的 overflow:visible
 *   （validate-uniapp-x.mjs:228-234 钉死，覆盖掉用户弹层会被裁成一条缝）。 */
.admin-sidebar.rail {
  width: 64px;
  padding: 14px 8px;
}
/* 临时铺开：从 flex 流里抬出来盖住内容区，选中一项或按 Esc 收回。
 * 位置基准是 .admin-shell（position:relative）。这里只能用 position/z-index，
 * 绝不能用 transform —— 它会给后代的 position:fixed 造出新的包含块。 */
.admin-sidebar.rail-open {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 220px;
  height: auto;
  z-index: 40;
  box-shadow: 0 4px 12px rgba(15, 23, 42, 0.08);
}
/* <1000：fixed 抽屉，配 .admin-nav-mask（z 100）。面板在遮罩之上。
 * height:auto + top/bottom:0 让它跟着视口高走，而不是基础规则那个相对壳的 100%。 */
.admin-sidebar.drawer {
  position: fixed;
  left: 0;
  top: 0;
  bottom: 0;
  width: 240px;
  height: auto;
  z-index: 101;
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.16);
}
.admin-sidebar.drawer-hidden {
  display: none;
}
/* rail-open 期间的 64px 占位，避免内容区左右各跳一次 */
.admin-rail-spacer {
  width: 64px;
  flex-shrink: 0;
}
/* rail-open 的透明关闭层：z 30（低于侧栏的 40，高于内容区），无底色。
 * 与 .admin-user-backdrop 同一套做法——它只负责接住「点了别处」这一次点击。 */
.admin-rail-backdrop {
  position: fixed;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: 30;
}
.admin-nav-mask {
  position: fixed;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: 100;
  background-color: rgba(15, 23, 42, 0.45);
}
.admin-brand {
  display: flex;
  flex-direction: row;
  align-items: center;
  flex-shrink: 0;
  padding: 4px 8px 14px;
  border-bottom: 1px solid #e8edf4;
}
/* rail 档只剩一个品牌标 + 一个折叠钮，横排放不下，改竖排 */
.admin-sidebar.rail .admin-brand {
  flex-direction: column;
  padding: 4px 0 12px;
}
.admin-brand-mark {
  width: 38px;
  height: 38px;
  border-radius: 12px;
  background-color: #246beb;
  color: #ffffff;
  font-size: 22px;
  font-weight: 600;
  line-height: 38px;
  text-align: center;
}
/* 下钻态（U1-I8）：品牌标切 warning。白字 on #94540f = 5.02:1，达标。
 * 这是「你正在看别人的数据」在侧栏侧的唯一常驻信号，与顶栏暖色成对出现 */
.admin-brand-mark.viewing {
  background-color: #94540f;
}
.admin-brand-copy {
  margin-left: 10px;
  display: flex;
  flex: 1;
  min-width: 0;
  flex-direction: column;
}
/* 折叠 / 展开钮（rail、full 两档）与窄屏抽屉的关闭钮共用一套盒子 */
.admin-nav-toggle {
  width: 32px;
  height: 32px;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  box-sizing: border-box;
  border-radius: 8px;
  cursor: pointer;
}
.admin-nav-toggle:hover {
  background-color: #f3f6fa;
}
.admin-sidebar.rail .admin-nav-toggle {
  margin-top: 8px;
}
.admin-nav-toggle-icon {
  width: 18px;
  height: 18px;
}
.admin-brand-title {
  color: #1b263b;
  font-size: 15px;
  font-weight: 600;
}
.admin-brand-sub {
  color: #647389;
  font-size: 12px;
  margin-top: 3px;
}
/* padding-top 18 → 10（U1-I7）：省下来的 8px 是删掉「功能菜单」那一行之后的顺延，
 * 菜单区整体上移，1000–1280 档少滚一屏。 */
.admin-nav-block {
  padding-top: 10px;
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}
/* 现在只剩「最近使用」一个分区标题在用（原来的「功能菜单」已删：
 * 一句恒定不变、不说明任何事的话，占掉 18px 又让人以为下面还有别的分区） */
.admin-nav-label {
  color: #647389;
  font-size: 12px;
  font-weight: 600;
  padding: 0 10px 8px;
}
/* 当前项的信号是「中性灰 pill + 主文色 + 600 字重」三件一起给：
 * 曾经这里是左侧 3px 品牌色竖条 + 浅蓝底，代价是侧栏常驻一列蓝，
 * 和「一屏只有一个主色」的令牌约束打架；改成中性灰之后，
 * hover 只动文字色不铺底，两态照样分得开，也不再需要竖条占位。 */
.admin-nav-item {
  position: relative;
  min-height: 40px;
  border-radius: 8px;
  padding: 0 12px;
  margin-bottom: 4px;
  display: flex;
  flex-direction: row;
  align-items: center;
  color: #45536a;
  cursor: pointer;
  box-sizing: border-box;
  transition: background-color 0.18s ease, color 0.18s ease;
}
.admin-nav-item.active {
  color: #1b263b;
  background-color: #f3f6fa;
}
.admin-nav-item.active .admin-nav-text {
  font-weight: 600;
}
/* hover 不铺底：铺了就和当前项的灰 pill 同貌，侧栏会出现两个「看起来选中」的行 */
.admin-nav-item:hover {
  color: #1b263b;
}
/* 无权限菜单。原来是 color:#a8b3c2（令牌表外，白底 2.12:1）。
 * text-disabled #94a3b8 语义对得上，但 design-lint 的 muted-text-color 规则
 * 明写「只允许 placeholder / 禁用 / 装饰图标，且不走 color」——禁用态也不许落到 color 上。
 * 所以改成本文件既有的禁用写法（.button[disabled]、.admin-user-logout.disabled 都是调 opacity）：
 * 合法色 text-3 #647389 + opacity .6。白底上混出来约 #a2acb9，和原来的 #a8b3c2 基本同一档灰，
 * 且 opacity 连那张 18px 的 lucide 图标一起压暗，整行「不可点」比只灰文字更完整。 */
.admin-nav-item.disabled {
  color: #647389;
  opacity: 0.6;
  cursor: default;
}
.admin-nav-item.disabled:hover {
  color: #647389;
  background-color: transparent;
}
/* U1-I4：灰底圆角方块整个删掉，这里现在是一张 18px 的 lucide 线性图标（<image>）。
 * 灰底方块的问题不只是难看：它把「菜单名首字」当图标，四级身份共用一套菜单时
 * 「商户体系」和「商家订单」都是「商」，图标反而在制造歧义。
 * 颜色变体由 admin-layout 的 navIconSrc() 换文件（img 的颜色改不了），
 * 所以这里没有、也不能有 .active 的反白规则。 */
.admin-nav-icon {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  margin-right: 9px;
}
/* rail 档只剩图标：居中，右边距收掉 */
.admin-sidebar.rail .admin-nav-icon {
  margin-right: 0;
}
.admin-sidebar.rail .admin-nav-item {
  justify-content: center;
  padding: 0 6px;
}
/* 折叠态里没地方写数字，用一个 8px 红点告诉你「这组里有待办」 */
.admin-nav-dot {
  position: absolute;
  right: 8px;
  top: 8px;
  width: 8px;
  height: 8px;
  border-radius: 999px;
  background-color: #dc2626;
}
.admin-nav-text {
  font-size: 13px;
  font-weight: 500;
}
.admin-nav-group .admin-nav-text {
  flex: 1;
}
.admin-nav-item.expanded {
  margin-bottom: 2px;
}
/* ⚰️ .admin-nav-count（与 .admin-nav-item.active .admin-nav-count）已随 U1-I7 删除。
 * 它显示的是「这个分组里有几个菜单」——一个装进侧栏就永远不再变化的常量，
 * 每一行都挂着一个不需要再看第二眼的数字，反而把真正该抢注意力的位置占了。
 * 这个位置现在归 .admin-nav-badge（业务待办数，danger 色）；没有待办时空着。
 * 原规则里那两段对比度推导（#45536a on #f3f6fa = 6.92:1、#1f5fd1 on #dbe7ff = 5.39:1）
 * 随类一起删除：它们算的是一个不再渲染的元素。新徽标自带自己那一段推导。 */
/* 展开 / 收起指示符复用 Lucide chevron。交互与 aria 状态仍由整行分组控件承担。 */
.admin-nav-arrow {
  flex-shrink: 0;
  width: 16px;
  height: 16px;
  margin-left: 7px;
  pointer-events: none;
}
.admin-nav-child {
  min-height: 36px;
  margin-left: 20px;
  padding: 0 8px 0 12px;
  border-left: 2px solid #e8edf4;
  border-radius: 0 8px 8px 0;
  display: flex;
  flex-direction: row;
  align-items: center;
  color: #647389;
  cursor: pointer;
  box-sizing: border-box;
  transition: background-color 0.18s ease, color 0.18s ease;
}
/* hover 不铺底、active 铺中性灰：与 .admin-nav-item 同一套口径。
 * 左侧 2px 引导线两种状态都保持 #e8edf4，不再染品牌蓝——
 * 引导线的作用是标出「这一列属于上面那个分组」，不是标当前项。 */
.admin-nav-child:hover {
  color: #1b263b;
}
.admin-nav-child.active {
  color: #1b263b;
  background-color: #f3f6fa;
}
.admin-nav-child.active .admin-nav-child-text {
  font-weight: 600;
}
.admin-nav-child.last {
  margin-bottom: 6px;
}
/* flex:1 是给徽标让位用的：展开态时预警待办数挂在子项这一行，
 * 文字不先占满剩余宽度，徽标就会紧贴在文字右边而不是行尾 */
.admin-nav-child-text {
  flex: 1;
  min-width: 0;
  font-size: 12px;
  font-weight: 500;
}
/* U1-I7 落地：本类现在挂的是**业务待办数**（OPEN 状态的预警单），
 * 不是 .admin-nav-count 那个「这组里有几个菜单」的常量。
 * 所以颜色也从中性灰换成 danger：它要抢一眼注意力，这正是徽标存在的理由。
 * 对比度：#b42318 on #fff0ee —— L(#b42318)=0.1123、L(#fff0ee)=0.9099，
 * (0.9099+0.05)/(0.1123+0.05)=5.91:1，过 4.5:1。
 * 高 18 / 字号 11（侧栏徽标白名单）/ 圆角 999（本高度下就是全圆）。 */
.admin-nav-badge {
  margin-left: auto;
  min-width: 22px;
  height: 18px;
  line-height: 18px;
  padding: 0 6px;
  box-sizing: border-box;
  border-radius: 999px;
  text-align: center;
  color: #b42318;
  background-color: #fff0ee;
  font-size: 12px;
  font-weight: 600;
}
.admin-sidebar-foot {
  margin-top: auto;
  padding: 12px;
  border-radius: 8px;
  background-color: #f3f6fa;
  border: 1px solid #e8edf4;
}
.admin-user-entry {
  position: relative;
  margin: 12px 4px 2px;
  flex-shrink: 0;
  overflow: visible;
  z-index: 20;
}
/* U1-X5 的透明遮罩。三条必须保持的性质写在 admin-layout 模板注释里：
 * 留在 .admin-user-entry 内部、排在弹层之前、不写 z-index（同层叠上下文里，
 * 带正 z-index 的弹层永远画在它之上，所以弹层照常可点）。
 * 无底色、无边框：它只负责接住那一次点击。 */
.admin-user-backdrop {
  position: fixed;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
}
/* 58 → 68：账号名 / 身份名 / 机构名三行（13 + 13 + 12 加两个 3px 间距 = 47，
 * 加上下各 8 的内边距正好 63，留 5px 余量给不同字体的行高差） */
.admin-user-trigger {
  min-height: 68px;
  display: flex;
  flex-direction: row;
  align-items: center;
  padding: 8px;
  box-sizing: border-box;
  border: 1px solid #e8edf4;
  border-radius: 8px;
  background-color: #f3f6fa;
  cursor: pointer;
  transition: background-color 0.18s ease, border-color 0.18s ease;
}
/* rail 档只剩头像 */
.admin-sidebar.rail .admin-user-trigger {
  justify-content: center;
  padding: 8px 0;
}
.admin-user-trigger:hover {
  border-color: #c9ddfb;
  background-color: #e7f0ff;
}
/* 默认态用 primary-soft，白字 on #cbd5e1 只有 1.5:1 */
.admin-user-avatar {
  width: 32px;
  height: 32px;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  box-sizing: border-box;
  border: 1px solid #c9ddfb;
  border-radius: 999px;
  background-color: #e7f0ff;
  color: #1f5fd1;
  font-size: 13px;
  font-weight: 600;
}
.admin-user-avatar.large {
  width: 38px;
  height: 38px;
  border-color: #246beb;
  background-color: #246beb;
  color: #ffffff;
  font-size: 15px;
}
.admin-user-copy {
  min-width: 0;
  margin-left: 9px;
  display: flex;
  flex: 1;
  flex-direction: column;
}
.admin-user-name,
.admin-user-popover-name {
  overflow: hidden;
  color: #1b263b;
  font-size: 13px;
  font-weight: 600;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* U1-I8：原来这三件事挤在 .admin-user-role 一行里
 * （「服务商 · 某某某某科技有限公司 · 待配置最低价」，11px + 省略号，
 * 机构名基本只看得到前四个字，商业状态永远被截掉）。
 * 现在身份名 13、机构名 12 各占一行，商业状态改成弹层头部的 status-tag。
 * 对比度：#45536a on #f3f6fa = 9.42:1；#647389 on #f3f6fa = 4.55:1，都过 4.5:1。 */
.admin-user-role,
.admin-user-org,
.admin-user-popover-mobile {
  overflow: hidden;
  margin-top: 3px;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.admin-user-role {
  color: #45536a;
  font-size: 13px;
}
.admin-user-org {
  color: #647389;
  font-size: 12px;
}
.admin-user-popover-mobile {
  color: #647389;
  font-size: 12px;
}
/* 用户弹层展开态复用 Lucide chevron；点击热区仍是整行 .admin-user-trigger。 */
.admin-user-arrow {
  flex-shrink: 0;
  width: 16px;
  height: 16px;
  margin-left: 6px;
  pointer-events: none;
}
.admin-user-popover {
  position: absolute;
  right: 0;
  bottom: calc(100% + 8px);
  width: 212px;
  padding: 14px;
  box-sizing: border-box;
  border: 1px solid #e8edf4;
  /* 圆角 10 → 8、阴影 0 12px 30px .14 → shadow-3，两个都不是随手取最近档：
   * admin-layout.uvue 的 .shell-search-panel 是照着「复用 .admin-user-popover 的视觉」
   * 建的，它把这两个值分别落成 8 与 0 16px 40px rgba(15,23,42,.16) 并写明了理由，
   * 这里跟上去，两块本来就该长一样的浮层才不会因为「谁先合规」而分叉。
   * 阴影 + 描边并存是 §3.1「描边或阴影二选一」的例外白名单项（侧栏用户弹层）。 */
  border-radius: 8px;
  background-color: #ffffff;
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.16);
  z-index: 10;
}
.admin-user-popover-head {
  display: flex;
  flex-direction: row;
  align-items: center;
}
.admin-user-popover-copy {
  min-width: 0;
  margin-left: 10px;
  display: flex;
  flex: 1;
  flex-direction: column;
}
/* 商业状态从侧栏那一行搬到弹层头部（U1-I8）。
 * 它是账号级状态，挂在身份名后面时读起来像身份的一部分（「服务商 · 待配置最低价」） */
.admin-user-status {
  align-self: flex-start;
  margin-top: 10px;
}
/* U1-I8：壳内补齐「个人信息 / 切换身份 / 修改密码」。
 * 在这之前，平台身份从壳里到不了这三个页面——workbench 里定义了 goProfile，
 * 但那是工作台的快捷入口，换到任何别的页面就没有入口了。 */
.admin-user-menu {
  display: flex;
  flex-direction: column;
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid #e8edf4;
}
.admin-user-menu-item {
  min-height: 34px;
  display: flex;
  flex-direction: row;
  align-items: center;
  padding: 0 9px;
  box-sizing: border-box;
  border-radius: 8px;
  color: #45536a;
  cursor: pointer;
  transition: background-color 0.18s ease;
}
.admin-user-menu-item:hover {
  background-color: #f3f6fa;
}
.admin-user-menu-icon {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  margin-right: 8px;
}
.admin-user-menu-text {
  font-size: 12px;
  font-weight: 500;
}
/* 底色 #fff1f2 / #ffe4e6 都在令牌表外，归到 danger-bg #fff0ee 与 danger-border #fecaca。
 * 文字同时从 #dc2626 换成 danger-text #b42318：§3.1 明写 danger-solid #dc2626 只当实心按钮底，
 * 「#dc2626 压在 #fff0ee 上只有 4.4:1」，hover 的 #fecaca 上更是 3.34:1。
 * #b42318 静息 5.91:1 过线；hover 在 #fecaca 上是 4.47:1，仍差 0.03 —— 但红族里比 danger-bg
 * 深的合法档只有 danger-border 这一个，且旧的两态是 4.40:1 / 4.02:1 双双不过，这是净改善。
 * 想真正让 hover 也过线，得在令牌表里加一档更浅的 danger hover 底，那属于改 tokens.json。
 * 而且本行那颗 log-out 图标本来就是 #b42318 变体，
 * 改完字和图标终于是同一个红。 */
.admin-user-logout {
  min-height: 34px;
  display: flex;
  flex-direction: row;
  align-items: center;
  margin-top: 10px;
  padding: 0 9px;
  box-sizing: border-box;
  border-radius: 8px;
  color: #b42318;
  background-color: #fff0ee;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
}
.admin-user-logout:hover {
  background-color: #fecaca;
}
.admin-user-logout.disabled {
  cursor: not-allowed;
  opacity: 0.65;
}
/* 原来是一个 20px 粉底方块里写「退」字（10px，字号阶梯外）。
 * 现在是 log-out 线性图标（danger 变体 #b42318），底色方块整个去掉：
 * 退出登录这一行本身已经是浅红底 + 红字，方块只是把红色叠了第三遍 */
.admin-user-logout-icon {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  margin-right: 8px;
}
.admin-foot-title {
  color: #1b263b;
  font-size: 12px;
  font-weight: 600;
}
.admin-foot-desc {
  color: #647389;
  font-size: 12px;
  line-height: 18px;
  margin-top: 6px;
}
/* 唯一的滚动容器。这里不许出现 transform / filter / will-change：
 * 任何一个都会给后代的 position:fixed 造出新的包含块，全站弹窗与遮罩会从「相对视口」
 * 变成「相对内容区」，遮不住侧栏与顶栏。 */
.admin-main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow-y: auto;
  background-color: #edf4fb;
}
/* 旧壳结构基础；R5壳尺寸由末尾pc-shell.css统一覆盖。
 * flex-shrink:0 不能省：内容撑高后 .admin-content 的自动最小尺寸会把收缩压力全甩给顶栏。
 * 背景必须是不透明纯白，半透明会透出下方滚动的内容。 */
.admin-topbar {
  position: -webkit-sticky;
  position: sticky;
  top: 0;
  z-index: 30;
  flex-shrink: 0;
  height: 52px;
  padding: 0 24px;
  background-color: #ffffff;
  /* 吸顶后顶栏与内容区（#f6f8fb）、与白卡片都近乎同色，边界只剩这一条线；
     #e8edf4 对两侧都只有 1.2:1 左右，滚动时卡片像长进顶栏，故用 line-strong。 */
  border-bottom: 1px solid #cbd5e1;
  box-sizing: border-box;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
}
/* U1-I8 下钻态：整条顶栏转暖色，而不是在顶栏下面再加一条 36px 横幅。
 * 横幅的问题是它把同一件事说第二遍还要多吃 36px——顶栏本身变色，
 * 每一屏、每一页、任何滚动位置都在提示「你看的不是自己的数据」。
 * #fff3e1 是 warning-bg；下边框同步换成 warning-border，
 * 不然暖底配 #cbd5e1 冷灰边会脏。 */
.admin-topbar.drill {
  background-color: #fff3e1;
  border-bottom-color: #fde68a;
}
/* 顶栏左簇：汉堡 + 下钻眼睛 + 面包屑。
 * 必须包一层——顶栏是 space-between，直接摊成四个孩子会把它们均匀撒开一整行 */
.admin-topbar-lead {
  display: flex;
  flex-direction: row;
  align-items: center;
  flex-shrink: 1;
  min-width: 0;
  gap: 8px;
}
/* <1000 的侧栏入口。32×32 与 .admin-icon-button 同规格 */
.admin-nav-hamburger {
  width: 32px;
  height: 32px;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  box-sizing: border-box;
  border-radius: 8px;
  cursor: pointer;
}
.admin-nav-hamburger:hover {
  background-color: #f3f6fa;
}
.admin-nav-hamburger-icon {
  width: 20px;
  height: 20px;
}
.admin-drill-eye {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
}
/* 「退出查看」：下钻态唯一的出口按钮。
 * #94540f on #ffffff = 5.02:1（正文档位达标） */
.admin-drill-exit {
  min-height: 28px;
  display: flex;
  flex-direction: row;
  align-items: center;
  flex-shrink: 0;
  padding: 0 12px;
  box-sizing: border-box;
  border: 1px solid #fde68a;
  border-radius: 8px;
  background-color: #ffffff;
  cursor: pointer;
}
.admin-drill-exit:hover {
  background-color: #fff3e1;
}
.admin-drill-exit-text {
  color: #94540f;
  font-size: 12px;
  font-weight: 500;
}
.admin-search {
  width: 280px;
  height: 34px;
  border-radius: 999px;
  border: 1px solid #e8edf4;
  background-color: #f3f6fa;
  padding: 0 14px;
  box-sizing: border-box;
  color: #45536a;
  font-size: 12px;
}
/* 面包屑整条一行：下钻路径 ｜ 分组 › 当前菜单。
 * 顶栏只回答「我在哪」，页标题由页头的 .admin-page-title 独占（U1-I3 去三重复） */
.admin-breadcrumb {
  display: flex;
  flex-direction: row;
  align-items: center;
  flex-wrap: wrap;
  min-width: 0;
  /* 顶栏是 space-between 的 flex 行，不写 shrink 时面包屑不会让位，
     长下钻路径会把自己的末级顶出 overflow:hidden 的顶栏。 */
  flex-shrink: 1;
  gap: 4px;
}
/* 下钻路径：平台 › 服务商A › 品牌商家B › 门店C，逐级可点返回
 * （四级主体的称谓以 docs/术语表.md §1 为准，「合作伙伴」「商户」是废弃词） */
.drill-path {
  display: flex;
  flex-direction: row;
  align-items: center;
  flex-wrap: wrap;
  gap: 4px;
}
.drill-node {
  color: #246beb;
  font-size: 12px;
  /* 下钻主体名可能是 15-18 字的工商全称，三级叠起来会把末级菜单名挤出顶栏。
     单节点截断优于整段裁掉。 */
  max-width: 168px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.drill-node.root {
  color: #647389;
}
/* 当前所在层不可点，避免"点了没反应"的困惑。
 * 700 按 §3.1 只留给标题与指标数值，这里同 .admin-breadcrumb-current 一档 */
.drill-node.current {
  color: #1b263b;
  font-weight: 600;
}
.drill-sep {
  /* 分隔符是承载层级关系的文字节点，不是装饰图标：#cbd5e1 对白顶栏只有 1.49:1，
     两级之间读不出层级；#94a3b8 作 color 是 2.57:1、被样式门禁禁掉，故用 text-3。 */
  color: #647389;
  font-size: 12px;
}
/* 下钻路径与自动面包屑之间的分隔：平台 › 服务商A ｜ 订单履约 › 预警单中心 */
.drill-divider {
  margin: 0 4px;
  color: #647389;
  font-size: 12px;
}
/* 面包屑第一级：当前菜单所在分组，取自 nav-groups.uts，与侧栏分组名逐字相同 */
.admin-breadcrumb-group {
  color: #647389;
  font-size: 12px;
}
/* 面包屑末级：当前菜单名；自动推导不到时回落到 breadcrumb-title prop */
.admin-breadcrumb-current {
  color: #45536a;
  font-size: 12px;
  font-weight: 500;
}
.admin-top-actions {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 8px;
}
.admin-top-button {
  min-width: 76px;
  height: 34px;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  padding: 0 12px;
  border-radius: 8px;
  background-color: #f3f6fa;
  color: #45536a;
  font-size: 12px;
  font-weight: 600;
  text-align: center;
  cursor: pointer;
}
.admin-top-button.primary {
  background-color: #246beb;
  color: #ffffff;
}
/* 页头右侧动作区（与 .admin-top-actions 同形，用于 .admin-page-head 内） */
.admin-head-actions {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 8px;
}
/* 32×32 方形次按钮（刷新/更多/关闭等仅图标动作） */
.admin-icon-button {
  width: 32px;
  height: 32px;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  box-sizing: border-box;
  border-radius: 8px;
  background-color: #f3f6fa;
  color: #45536a;
  font-size: 13px;
  line-height: normal;
  text-align: center;
  cursor: pointer;
  transition: background-color 0.18s ease, color 0.18s ease;
}
.admin-icon-button:hover {
  background-color: #e8edf4;
}
.admin-content {
  /* 必须是 1 0 auto 而不是 1：basis auto + 不收缩，长页面才会撑出 .admin-main 的滚动高度，
     短页面仍靠 grow 撑满一屏。写成 flex:1（basis 0）时高度完全由弹性算法决定，
     一旦编译链没有保住 min-height:auto 的自动最小尺寸，内容就会被压成一屏且无法滚动。 */
  flex: 1 0 auto;
  padding: 28px 32px 32px;
  box-sizing: border-box;
}
.admin-page-head {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 16px;
  gap: 16px;
  flex-wrap: wrap;
  padding: 20px;
  background: linear-gradient(135deg, rgba(255, 255, 255, 0.94), rgba(248, 251, 255, 0.7));
  border-radius: 16px;
}
/* 显式 display + line-height：页头高度不再靠 inline-block 的基线间隙，
 * 「壳顶到首张卡片上沿」= 52 顶栏 + 16 内容区上边距 + 54 页头 + 16 页头下边距 = 138px */
.admin-page-title {
  display: block;
  color: #1b263b;
  font-size: 26px;
  font-weight: 600;
  line-height: 36px;
}
/* max-width 防止长描述把页头撑成两行（服务商工作台那句 60 字的描述在 1024 宽会折行） */
.admin-page-desc {
  display: block;
  max-width: 720px;
  color: #647389;
  font-size: 13px;
  line-height: 20px;
  margin-top: 4px;
}
/* 页头统计条（U1-I13）：一排 12px 文本，不再是一排看着像按钮的白底药丸。
 * 条目之间靠本容器的 gap 分开——这里是 flex row 且显式带 gap，
 * 不会重演 .admin-error-card 那种「相邻 <text> 首尾相连拼成一句」的事故。 */
.admin-status-strip {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: flex-end;
  flex-wrap: wrap;
  gap: 12px;
}
.admin-status-pill {
  display: flex;
  flex-direction: row;
  align-items: center;
  min-height: 20px;
  line-height: 20px;
  color: #45536a;
  font-size: 12px;
}
.admin-status-pill.danger {
  color: #b42318;
}
.admin-tab-row {
  display: flex;
  flex-direction: row;
  gap: 8px;
  margin-bottom: 14px;
}
/* height 34 + box-sizing 缺省(content-box) + 1px 描边 = 外高 36、最小外宽 88；
 * 这里改写成 height 36 / min-width 88 + border-box，外框仍是 88×36，今天逐像素不变，
 * 但换成 <button> 后不会被 uni-button 自带的 box-sizing:border-box 缩掉 2px。
 * border-radius 18px 不在 6 档圆角阶梯内；本类外高 36，18px 本就是全圆，
 * 换成令牌 radius.pill=999px 同样是等价改写。
 * margin/padding 两条见下面 ::after 的注释：给 B2 的换标签预留的重置，
 * 对现在的 <view> 调用点是纯 no-op。 */
.admin-tab-pill {
  min-width: 88px;
  height: 36px;
  box-sizing: border-box;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  line-height: normal;
  border-radius: 999px;
  background-color: #ffffff;
  border: 1px solid #e8edf4;
  color: #45536a;
  font-size: 12px;
  font-weight: 600;
  text-align: center;
  cursor: pointer;
}
/* uni-button 会给自己画一圈 ::after 伪边框（border:1px solid rgba(0,0,0,.2)，
 * 200% 尺寸 + scale(.5) 的老写法），不清掉换标签后每颗页签会多出一层灰描边。
 * 写法与本文件既有的 .button::after 一致；对 <view>/<text> 调用点没有 content，不渲染。 */
.admin-tab-pill::after {
  border: 0;
}
.admin-tab-pill.active {
  color: #1f5fd1;
  border-color: #c9ddfb;
  background-color: #e7f0ff;
}
/* 盯单页「预警」页签在未选中且有待办时走这一档。
 * 底色 #fff7f7 归到 danger-bg #fff0ee；文字同步换 danger-text #b42318——
 * §3.1「标签文字必须用它，#dc2626 压在 #fff0ee 上只有 4.4:1」，这一条说的正是本类
 * （12px/700 不算大字号，仍要 4.5:1）。#b42318 on #fff0ee = 5.91:1。 */
.admin-tab-pill.danger {
  color: #b42318;
  border-color: #fecaca;
  background-color: #fff0ee;
}
.admin-metric-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
}
.admin-metric-card {
  min-height: 112px;
  background-color: #ffffff;
  border: 0;
  border-radius: 12px;
  padding: 16px 20px;
  box-sizing: border-box;
  box-shadow: 0 4px 16px rgba(62, 96, 133, 0.03);
}
/* U1-I6-a：118 → 96。compact 卡里只有 label + 数值两行（12 + 28 + 14 间距 = 54），
 * 118 有一半是空的；四张卡一排时这 22px 直接从首屏里挤掉了一整行表格 */
.admin-metric-card.compact {
  min-height: 96px;
}
.admin-metric-label {
  color: #647389;
  font-size: 12px;
  font-weight: 500;
}
.admin-metric-value {
  display: block;
  color: #151e30;
  font-size: 24px;
  font-weight: 600;
  margin-top: 8px;
  line-height: 32px;
  font-variant-numeric: tabular-nums;
}
.num {
  font-variant-numeric: tabular-nums;
}
.admin-metric-note {
  display: block;
  color: #647389;
  font-size: 12px;
  margin-top: 4px;
  line-height: 16px;
}
.admin-board {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) minmax(340px, 0.8fr);
  gap: 20px;
  margin-top: 14px;
}
.admin-card {
  background-color: #ffffff;
  border: 0;
  border-radius: 12px;
  padding: 16px 20px;
  box-sizing: border-box;
  box-shadow: 0 4px 16px rgba(62, 96, 133, 0.03);
}
.admin-filter-card {
  margin-top: 16px;
  margin-bottom: 16px;
}
.admin-page-head + .admin-filter-card {
  margin-top: 0;
}
.admin-filter-bar {
  display: flex;
  flex-direction: row;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px;
}
.admin-filter-input {
  min-width: 140px;
  height: 36px;
  border-radius: 8px;
  border: 1px solid #e8edf4;
  color: #45536a;
  font-size: 13px;
  padding: 0 12px;
  box-sizing: border-box;
  background-color: #ffffff;
}
/* 输入框聚焦反馈（U1-I9）：改这条之前，全站输入框聚焦没有任何视觉变化。
 * 必须用 :focus-within 而不是 :focus —— .admin-filter-input 的 293 个调用点都写在
 * <input> 上，H5 里它渲染成自定义元素 <uni-input>，真正拿到焦点的是内部的原生
 * input（uni 基础样式还给 .uni-input-input 写了 outline:none），外层只能靠
 * :focus-within 接住。uni-input 自身的 overflow:hidden 只裁剪后代，不裁剪它自己的
 * outline，所以焦点环不会被切掉。
 * 底色顺带从 #f3f6fa 提到纯白：聚焦时「这一格是活的」比只换描边更明显。 */
.admin-filter-input:focus-within {
  outline: 2px solid #246beb;
  outline-offset: 2px;
  border-color: #246beb;
  background-color: #ffffff;
}
.admin-filter-bar .admin-filter-input {
  flex: 1 1 180px;
}
.admin-filter-select {
  min-width: 110px;
  height: 36px;
  line-height: 36px;
  border-radius: 8px;
  border: 1px solid #e8edf4;
  color: #45536a;
  background-color: #ffffff;
  font-size: 13px;
  text-align: center;
  box-sizing: border-box;
}
/* 下拉现在还是 <view>（66 处），拿不到焦点；等 B2 换成可聚焦控件后这条才会亮。
 * 边框变主色与输入框同一档反馈。 */
.admin-filter-select:focus-within {
  border-color: #246beb;
}
/* margin/padding/border 三条 + 下面的 ::after 是给 B2「<view> → <button>」预留的重置：
 * uni-button 的默认值是 18px 字号、line-height:2.55、左右 14px 内边距、
 * margin-left/right:auto、#f8f8f8 底、5px 圆角，外加一圈 ::after 伪边框。
 * 本类已经显式写死了 font-size / line-height / background-color / color / border-radius，
 * 补齐这四条之后换标签外观逐像素不变（尤其 margin:auto —— 不清掉，筛选栏里的
 * flex 项会被自动居中/推开，是最容易漏的一条）。
 * 对现在的 201 个 <view> 调用点全部是 no-op：view 的这三项默认值本就是 0。 */
.admin-filter-button {
  min-width: 66px;
  height: 36px;
  box-sizing: border-box;
  margin: 0;
  padding: 0 12px;
  border: 1px solid #e8edf4;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  line-height: normal;
  border-radius: 8px;
  color: #45536a;
  background-color: #ffffff;
  font-size: 13px;
  font-weight: 500;
  text-align: center;
  cursor: pointer;
}
.admin-filter-button::after {
  border: 0;
}
.admin-filter-button.primary {
  color: #ffffff;
  background-color: #246beb;
  border-color: #246beb;
}
.admin-filter-button.primary:not(.is-disabled):hover {
  background-color: #1f5fd1;
  border-color: #1f5fd1;
}
.admin-filter-button.primary:not(.is-disabled):active {
  background-color: #174fae;
  border-color: #174fae;
}
.admin-card-head {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 12px;
  min-height: 28px;
  gap: 12px;
  flex-wrap: wrap;
}
/* 卡片标题必须比页标题（22/700）低一档，否则会出现「卡片标题比页标题还粗」的观感 */
.admin-card-title {
  color: #1b263b;
  font-size: 18px;
  font-weight: 600;
  line-height: 28px;
}
/* 可点击的卡头链接；非交互说明文字请用 .admin-card-meta */
.admin-card-link {
  color: #45536a;
  font-size: 12px;
  font-weight: 500;
  cursor: pointer;
}
/* 这里不加任何 :hover 反馈（连变色都不加）：全站约 100 处 .admin-card-link 里大多数其实是
 * 「共 N 条」这类不可点的统计/说明文字，给它加悬停变化等于让静态文字假装可点。
 * validate-uniapp-x.mjs 的 U1-B0-7 直接禁止 `.admin-card-link:hover` 这个选择器出现，
 * 等这些调用点全部迁到 .admin-card-meta 之后再补 hover 反馈。 */
/* 卡头右侧的非交互说明文字：灰、常规字重、不可点 */
.admin-card-meta {
  color: #647389;
  font-size: 12px;
  font-weight: 400;
  cursor: default;
}
/* 全局错误卡：查询类失败用「原因 + 重试」，不再各页自绘 error-card。
 * 必须是 flex 列：工作台把多路请求各自记错后模板是 v-for 的相邻 <text>，
 * 中间没有空白文本节点，卡片不列排、text 又是全局 inline-block，
 * 三条错误会在 H5 上首尾相连拼成一句话。 */
.admin-error-card {
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
  padding: 14px 16px;
  border: 1px solid #fecaca;
  border-radius: 8px;
  background-color: #fff0ee;
}
/* 一条错误独占一行：display 也显式写块级，脱离 .admin-error-card 时同样不粘连 */
.admin-error-text {
  display: block;
  color: #b42318;
  font-size: 13px;
  line-height: 20px;
}
/* 「重试」自成一行、左对齐，不跟在错误文案末尾 */
.admin-error-retry {
  display: flex;
  flex-direction: row;
  align-items: center;
  align-self: flex-start;
  min-height: 28px;
  color: #b42318;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
.admin-error-retry:hover {
  text-decoration: underline;
}
/* 一行提示条：只承载说明，不承载动作 */
.admin-notice {
  box-sizing: border-box;
  padding: 8px 12px;
  border: 1px solid #e8edf4;
  border-radius: 8px;
  background-color: #f3f6fa;
  color: #45536a;
  font-size: 12px;
  line-height: 18px;
}
.admin-notice.info {
  border-color: #c9ddfb;
  background-color: #e7f0ff;
  color: #1f5fd1;
}
.admin-notice.success {
  border-color: #dce2eb;
  background-color: #eef1f6;
  color: #526078;
}
.admin-notice.warning {
  border-color: #fde68a;
  background-color: #fff3e1;
  color: #94540f;
}
.admin-table {
  border: 1px solid #e8edf4;
  border-radius: 12px;
  overflow: hidden;
}
.admin-table-row {
  min-height: 48px;
  display: grid;
  grid-template-columns: 1.1fr 1fr 0.8fr 0.7fr;
  align-items: center;
  padding: 0 12px;
  border-bottom: 1px solid #edf0f5;
  box-sizing: border-box;
}
/* 表头不再铺底色带：底色带把「表头」和「斑马纹」两件事混在一起，
 * 一整条灰横在卡片顶部也是页面里最重的一块非数据色。留一条 line 底边就够分层。 */
.admin-table-row.header {
  min-height: 42px;
  border-bottom: 1px solid #e8edf4;
}
.admin-table-row.last {
  border-bottom-width: 0;
}
.admin-table-cell {
  color: #45536a;
  font-size: 12px;
}
.admin-order-no,
.admin-main-text {
  display: block;
  color: #1b263b;
  font-size: 12px;
  font-weight: 600;
}
.admin-order-time,
.admin-sub-text {
  display: block;
  color: #647389;
  font-size: 12px;
  margin-top: 4px;
}
/* 状态标签是「内容宽度的小药丸」，不是等宽色块：
 * min-width 58 会让「完成」和「配送中」一样宽，一列排下来变成整齐划一的色带，
 * 反而比文字更难扫读。字号回到 tag 令牌 12（11 只走侧栏徽标白名单），字重 500。
 * inline-flex + align-self 是必须的：单元格是 flex 列，默认 stretch 会把药丸拉满整列宽。 */
.admin-channel-tag,
.admin-status-tag {
  display: inline-flex;
  flex-direction: row;
  align-items: center;
  align-self: flex-start;
  height: 20px;
  padding: 0 8px;
  box-sizing: border-box;
  border-radius: 4px;
  text-align: center;
  font-size: 12px;
  font-weight: 500;
  line-height: 20px;
}
.admin-channel-tag {
  color: #1f5fd1;
  background-color: #e7f0ff;
}
.admin-status-tag {
  color: #45536a;
  background-color: #f3f6fa;
}
.admin-status-tag.processing {
  color: #1f5fd1;
  background-color: #e7f0ff;
}
.admin-status-tag.success {
  color: #526078;
  background-color: #eef1f6;
}
/* warning 与 pending 同一档语义；#d97706 on #fff3e1 只有 3.1:1 */
.admin-status-tag.pending,
.admin-status-tag.warning {
  color: #94540f;
  background-color: #fff3e1;
}
/* #dc2626 on #fff0ee 只有 4.4:1，标签文字用 #b42318 */
.admin-status-tag.danger {
  color: #b42318;
  background-color: #fff0ee;
}
/* 分页的「上一页 / 下一页」走的就是本类（全站 14 处 .finance-pager 等分页条里，
 * 按钮一律是 <text class="admin-inline-button">），所以 U1-I9 说的「分页按钮」
 * 在全局样式这一侧就是这条规则。
 * margin/border/::after 同 .admin-filter-button，是给 B2 换 <button> 预留的重置；
 * padding 与 box-sizing 本类原本就写了，不动。 */
.admin-inline-button {
  min-width: 44px;
  height: 28px;
  display: inline-flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  line-height: normal;
  margin: 0;
  padding: 0 12px;
  border: 0;
  box-sizing: border-box;
  border-radius: 8px;
  color: #1f5fd1;
  background-color: #e7f0ff;
  font-size: 12px;
  font-weight: 500;
  text-align: center;
  cursor: pointer;
}
.admin-inline-button::after {
  border: 0;
}
/* 行内按钮的三个语义变体（方案 §4.3 U3-I7「.admin-inline-button.danger 全局化」
 * + §3.1 语义色表）。上提自 subpackage/platform/merchant/list.uvue 的页面私有副本 ——
 * 那份副本是 B4 page-admin-class 清理的第一批，页面 <style> 里不再重定义 .admin- 类。
 *
 * 只有这三个：一行操作里最多出现「主色 / 中性 / 警告 / 危险」四档。
 * 原页面还有 .migration（紫 #6d28d9）与 .delivery（青 #0f766e）两个变体，
 * 两个色都不在 §3.1 令牌表内（唯一的紫 #7c3aed 是预约单专色，全站没有青），
 * 一行里凑到五色之后「删除」反而不显眼，按 U3-I7 一并删除，调用点改挂 .subtle。
 *
 * subtle 的文字色是 #45536a 而不是页面副本里的 #647389：
 * #647389 压在 #f3f6fa 上只有 4.39:1（相对亮度 0.1707 / 0.9085），12px 小字过不了 AA；
 * #45536a / #f3f6fa = 6.92:1（0.0886 / 0.9085）。这与本文件 .ui-tab-count 是同一笔账。
 * warning #94540f / #fff3e1 = 6.51:1，danger #b42318 / #fff0ee = 5.91:1，两条逐字取自 §3.1。
 *
 * 刻意不写 .primary：本类的基础态（#1f5fd1 on #e7f0ff）已经是主色，
 * 再加一档实心蓝会让「每个卡片区域 ≤1 primary」（§4.3 U3-X8）更难守。
 * platform/settlement 页现在有一份私有的 .admin-inline-button.primary，
 * 它随该页迁移时一并处理，这里不抢先定义、免得两份定义打架。 */
.admin-inline-button.subtle {
  color: #45536a;
  background-color: #f3f6fa;
}
.admin-inline-button.warning {
  color: #94540f;
  background-color: #fff3e1;
}
.admin-inline-button.danger {
  color: #b42318;
  background-color: #fff0ee;
}
/* 品牌宽表保留全部行内动作；用文字按钮减轻视觉密度，危险/警告文字色继续沿用原变体。 */
.merchant-actions .admin-inline-button {
  min-width: 0;
  height: 28px;
  padding: 0;
  background-color: transparent;
  font-weight: 500;
}
.admin-timeline {
  border: 1px solid #e8edf4;
  border-radius: 8px;
  padding: 12px;
  box-sizing: border-box;
}
.admin-timeline-item {
  min-height: 52px;
  display: flex;
  flex-direction: row;
  align-items: flex-start;
  border-bottom: 1px solid #e8edf4;
  padding-bottom: 10px;
  margin-bottom: 10px;
  box-sizing: border-box;
}
.admin-timeline-item:last-child {
  border-bottom-width: 0;
  padding-bottom: 0;
  margin-bottom: 0;
}
.admin-timeline-dot {
  width: 10px;
  height: 10px;
  border-radius: 999px;
  background-color: #246beb;
  margin-top: 4px;
  margin-right: 10px;
}
.admin-timeline-copy {
  flex: 1;
  min-width: 0;
}
.admin-table-row.header .admin-table-cell {
  color: #647389;
  font-weight: 500;
}
.admin-action-list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}
.admin-action-card {
  min-height: 84px;
  border-radius: 8px;
  border: 1px solid #e8edf4;
  background-color: #f3f6fa;
  padding: 12px;
  box-sizing: border-box;
  cursor: pointer;
}
.admin-card-head,
.admin-top-actions,
.admin-tab-row,
.finance-pager,
.reconciliation-actions,
.action-form,
.finance-tool-grid {
  flex-direction: row;
}
.finance-pager,
.reconciliation-actions {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: flex-end;
  flex-wrap: wrap;
  gap: 8px;
}
@media screen and (max-width: 1280px) {
.admin-content {
    padding: 16px;
}

  /* U1-I6-a：2 列 → 3 列。这一档配的是 64px 折叠轨道（或 220px 侧栏），
   * 内容区还有 ≈900–1050px，四张 KPI 卡掉成两行两列时每张宽到 480、
   * 一个 28px 的数字摊在半屏宽的白卡里，反而比 3 列更难扫。 */
.admin-metric-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
}
}
.admin-action-card.primary {
  border-color: #c9ddfb;
  background-color: #e7f0ff;
}
.admin-action-title {
  display: block;
  color: #1b263b;
  font-size: 13px;
  font-weight: 600;
}
.admin-action-desc {
  display: block;
  color: #647389;
  font-size: 12px;
  line-height: 18px;
  margin-top: 7px;
}
@media screen and (max-width: 1000px) {
  /* 侧栏改 fixed 抽屉后必须把 100vh 的锁解开：壳一旦还锁着一屏高又 overflow:hidden，
   * 内容区就被关在一屏里滚不动（上线即难用）。窄屏回到「整页滚动」。 */
.admin-shell {
    flex-direction: column;
    height: auto;
    overflow: visible;
}

  /* U1-I6-b：原来这一档把侧栏摊成 100% 宽、max-height 240 的「顶部块」，
   * 菜单被压进 160px 高的滚动条里翻——三十多个菜单项在 160px 里找一个，
   * 比在手机上翻通讯录还慢，而且它常驻占掉首屏 240px。
   * 现在换成顶栏汉堡 + fixed 抽屉（.admin-sidebar.drawer / .admin-nav-mask），
   * 形态整个由 admin-layout 挂 class 决定，所以这一档不再需要覆盖侧栏尺寸；
   * .admin-nav-block 的 flex:1 + overflow-y:auto 基础规则直接接管抽屉内的滚动。 */
.admin-main {
    height: auto;
    overflow-y: visible;
}

  /* 顶栏在这一档继续吸顶。原来这里写的是 position:static，理由是
     「竖排时侧栏是被 max-height 截断的顶部块、用户区会溢出压在 .admin-main 顶部，
     顶栏吸顶会盖住它，退出登录点不到」——那个布局已经被抽屉替掉，
     用户区现在在抽屉里（z 101，高于顶栏的 30），压不到也盖不住。
     反过来，汉堡是这一档进入导航的唯一入口，它必须一直在视口里，
     所以这一档不但不该取消吸顶，还必须保住吸顶。 */
.admin-topbar,
.admin-page-head {
    align-items: flex-start;
    flex-direction: column;
    height: auto;
    gap: 12px;
    padding-top: 14px;
    padding-bottom: 14px;
}
.admin-top-actions,
.admin-search {
    width: 100%;
}
.admin-metric-grid,
.admin-board {
    grid-template-columns: 1fr;
}
.admin-filter-bar,
.admin-tab-row {
    flex-wrap: wrap;
}
.admin-filter-bar .admin-filter-input,
.admin-filter-bar .admin-filter-input.short {
    flex-basis: calc(50% - 6px);
    width: auto;
    max-width: none;
}
}
@media screen and (max-width: 640px) {
  /* 壳的 padding 与圆角已在基础规则里归零（U1-I12），这里不再需要断点覆盖 */
.admin-content {
    padding: 14px;
}
.admin-metric-grid {
    grid-template-columns: 1fr;
}
.admin-filter-bar .admin-filter-input,
.admin-filter-bar .admin-filter-input.short,
.admin-filter-button {
    flex-basis: 100%;
    width: 100%;
    max-width: none;
}
}
/* ============================================================
 * 详情信息网格（全局）：label 在上、value 在下，两列卡片式排布。
 * 页面模板约定：.detail-grid > .detail-cell(.full) > .detail-label + .detail-value
 * 页面自身 <style> 中的同名定义会覆盖此处，互不影响。
 * ============================================================ */
.detail-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}
.detail-cell {
  min-height: 64px;
  padding: 12px 14px;
  border: 1px solid #e8edf4;
  border-radius: 12px;
  background-color: #f3f6fa;
  box-sizing: border-box;
}
.detail-cell.full {
  grid-column: 1/-1;
}
.detail-label {
  display: block;
  color: #647389;
  font-size: 12px;
}
.detail-value {
  display: block;
  margin-top: 8px;
  color: #1b263b;
  font-size: 14px;
  font-weight: 600;
  line-height: 20px;
  word-break: break-all;
}
@media screen and (max-width: 640px) {
.detail-grid {
    grid-template-columns: 1fr;
}
.detail-cell.full {
    grid-column: auto;
}
}
/* ============================================================
 * B2a 盯单工作流批次新增的共用类（方案 §3.4 C2/C4、§3.5、§4.2 U2-I6/I12/I18、§6.2）
 *
 * 全部取值来自 scripts/design/tokens.json：字号 11/12/13/14/15/22/24/28、
 * 字重 400/500/600/700、圆角 4/6/8/12/16/999、z-index 20/30/40/100/101/120/121/130/131、
 * 阴影只有 shadow-1/2/3/brand 四条。新增规则前先跑 `npm run check:styles` 对一遍。
 *
 * 这里放的都是**多页共用**的形态。页面私有的一次性样式仍然写在各自 <style> 里，
 * 但不要在页面里定义 .admin- 前缀类（check:styles 的 page-admin-class 规则会拦）。
 * ============================================================ */
/* ---- 勾选框（U2-I12）：替换盯单台现在的 Unicode ☐/☑ 字符 ----
 * 那两个字符在 Windows Chrome 上一个是纯文本方框、一个是带底纹的图形字，
 * 宽度和基线都不一样，勾选时整行会横向抖一下。
 * ✓ 用真实 <text> 节点而不是 ::before/::after：uvue 的伪元素只在 H5 可靠，
 * 且伪元素 content 进不了无障碍树。
 * 用法：
 *   <view class="ui-checkbox" :class="{ checked: isChecked(item) }" @click.stop="toggleCheck(item)">
 *     <text class="ui-checkbox-mark">✓</text>
 *   </view>
 * 命中区：18×18 只是视觉尺寸，父行（.monitor-order-head 之类）整行可点，不要单独给它加 padding。 */
.ui-checkbox {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  box-sizing: border-box;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  border: 1.5px solid #cbd5e1;
  border-radius: 4px;
  background-color: #ffffff;
  cursor: pointer;
  transition: background-color 0.12s ease, border-color 0.12s ease;
}
.ui-checkbox:hover {
  border-color: #246beb;
}
.ui-checkbox.checked {
  background-color: #246beb;
  border-color: #246beb;
}
/* 默认不显示，由 .checked 打开：调用方无脑常驻这个 <text> 即可，不用再写 v-if */
.ui-checkbox-mark {
  display: none;
  color: #ffffff;
  font-size: 12px;
  font-weight: 600;
  line-height: 12px;
  text-align: center;
}
.ui-checkbox.checked .ui-checkbox-mark {
  display: block;
}
/* ---- 可复制编号 chip（U2-I18）----
 * 订单号 / 配送单号 / 队列号这类「要对着念、要复制」的编号一律走这个形态：
 * 等宽字体让 0/O、1/l 分得开，灰底把它和正文区分开，整块可点即复制。
 * 复制反馈走 utils/feedback.uts 的 toastSuccess，不要在这里做视觉反馈。
 * 用法：<text class="copy-chip" @click="copyText(row.orderNo)">{{ row.orderNo }}</text> */
.copy-chip {
  display: inline-flex;
  flex-direction: row;
  align-items: center;
  box-sizing: border-box;
  min-height: 24px;
  padding: 0 8px;
  border-radius: 4px;
  background-color: #f3f6fa;
  color: #45536a;
  font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: 12px;
  line-height: 16px;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color 0.12s ease, color 0.12s ease;
}
.copy-chip:hover {
  background-color: #e8edf4;
  color: #1b263b;
}
/* ---- 紧凑页签（U2-I6）----
 * .admin-tab-pill 的 min-width 88 × 5 颗 = 462px，右侧面板 1440 下可用宽只有 398px、
 * 1024 下只有 328px，页签行必然溢出或折行。compact 把最小宽度放开、高度收到 30，
 * 5 颗约 300px，1024 也放得下。
 * 只覆盖尺寸与字号，颜色仍由 .admin-tab-pill / .active / .danger 决定（属性不重叠，不靠优先级打架）。
 * 用法：<view class="admin-tab-pill compact" :class="{ active: panelTab == 'DETAIL' }"> */
.admin-tab-pill.compact {
  min-width: 0;
  height: 30px;
  padding: 0 10px;
  font-size: 12px;
  font-weight: 600;
}
/* ---- 顶部 2px 进度条（§6.2「翻页/筛选/轮询保留旧内容 + 顶部 2px 进度条」）----
 * 绝对定位、不占高度：父元素必须是 position:relative（list-page 用的是一个 height:0 的
 * 定位壳 .ui-list-progress）。如果让它占 2px 真实高度，每轮静默刷新列表都会上下跳一次，
 * 那正是这条进度条本来要解决的问题。
 * PC 只发 H5，@keyframes 可用；App 端没有这条链路（移动端另有自己的刷新指示）。 */
.ui-progress {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 2px;
  overflow: hidden;
  background-color: #e7f0ff;
}
.ui-progress-bar {
  position: absolute;
  top: 0;
  left: 0;
  width: 32%;
  height: 2px;
  background-color: #246beb;
  animation: ui-progress-slide 1.2s cubic-bezier(0.2, 0, 0, 1) infinite alternate;
}
/* alternate 让它左右往复而不是「跑到头突然跳回起点」——后者在 3 秒一轮的轮询里
 * 看着像页面卡了一下。68% = 100% - 32%（bar 宽），右端刚好贴边不溢出。 */
@keyframes ui-progress-slide {
from {
    left: 0;
}
to {
    left: 68%;
}
}
/* ---- 已选筛选条件回执 chip（U2-I8：折叠筛选后仍要看得见「为什么没数据」）----
 * **方角 radius 6 + 中性底**，与「筛选条件 chip」（药丸 999、选中带 ✓、点一下就改查询：
 * .monitor-chip / .pw-chip / 日期档药丸）刻意长得不一样：那些是开关，这一颗只是回执，
 * 说明「你已经筛了什么」。同一张筛选卡里圆的能点、方的不能点，一眼可分。
 *
 * 原来这颗是 primary-soft 底 + primary-border 边 + 药丸圆角 —— 与选中态的筛选条件
 * chip 逐像素同形，用户会去点它想切换条件，点了却只有右上角那 20px 有反应。
 *
 * 本体不可点，右侧 x 图标是唯一动作（删掉这一条）且命中区 20×20；
 * Lucide x 使用共享的 text-3 描边，并用 hover 底色补充可点击反馈。
 * 对比度：#45536a / #f3f6fa = 9.9:1，图标 #647389 / #f3f6fa = 4.6:1，均过 AA。
 * 用法：
 *   <view class="admin-filter-chip">
 *     <text>门店：星巴克国贸店</text>
 *     <text class="admin-filter-chip-close" @click="clearFilter('storeName')"><image ...></image></text>
 *   </view> */
.admin-filter-chip {
  display: inline-flex;
  flex-direction: row;
  align-items: center;
  box-sizing: border-box;
  height: 28px;
  padding: 0 4px 0 10px;
  border: 1px solid #e8edf4;
  border-radius: 8px;
  background-color: #f3f6fa;
  color: #45536a;
  font-size: 12px;
  line-height: 16px;
  white-space: nowrap;
}
.admin-filter-chip-close {
  width: 20px;
  height: 20px;
  margin-left: 4px;
  flex-shrink: 0;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  border-radius: 4px;
  cursor: pointer;
}
.admin-filter-chip-close-icon {
  width: 12px;
  height: 12px;
  pointer-events: none;
}
/* hover 用 line 而不是 primary-border：主色填充会把「方角回执」又拉回主色语义。 */
.admin-filter-chip-close:hover {
  background-color: #e8edf4;
}
/* ---- 动作「更多」弹层（U2-I4）----
 * 默认锚在触发元素正下方右对齐，所以**触发按钮的父容器必须 position:relative**
 * （盯单卡是 .monitor-order-actions）。关闭靠页面级透明遮罩，不要靠 blur：
 * uni-app x 的 <view>/<button> 都不可聚焦（见本文件 :focus-visible 那段注释），没有 blur 可听。
 * z-index 取令牌 dropdown 档 40：比页内 sticky（20）与顶栏（30）高，比抽屉（100）低。
 * 用法：
 *   <view class="action-menu" v-if="moreOpenId == item.id">
 *     <text class="action-menu-item" @click.stop="run(item,'KITCHEN_HOLD')">出餐完成</text>
 *     <text class="action-menu-item danger" @click.stop="run(item,'CANCEL_DISPATCH')">取消配送</text>
 *   </view> */
.action-menu {
  position: absolute;
  top: 100%;
  right: 0;
  z-index: 40;
  min-width: 132px;
  margin-top: 4px;
  padding: 4px 0;
  box-sizing: border-box;
  border: 1px solid #e8edf4;
  border-radius: 8px;
  background-color: #ffffff;
  box-shadow: 0 4px 12px rgba(15, 23, 42, 0.08);
}
.action-menu-item {
  display: flex;
  flex-direction: row;
  align-items: center;
  height: 36px;
  padding: 0 12px;
  box-sizing: border-box;
  color: #45536a;
  font-size: 13px;
  line-height: 36px;
  white-space: nowrap;
  cursor: pointer;
}
.action-menu-item:hover {
  background-color: #f3f6fa;
}
/* 取消/终止类固定置底、红字、上方一条分隔线（§4.2 U2-I4）。
 * 只有一档红：产生取消费、标记完成、删除、解绑都是 danger（§6.5）。 */
.action-menu-item.danger {
  margin-top: 4px;
  border-top: 1px solid #e8edf4;
  color: #b42318;
}
.action-menu-item.danger:hover {
  background-color: #fff0ee;
}
/* ---- 空态（§3.4 C2、§6.2 空态四类文案模板）----
 * 图标位 + 标题 + 说明 + 可选动作。图标过渡期沿用 48px 汉字方块（lucide 落地后统一换掉）。
 * 四类文案：no-data「暂无 X」/ no-result「没有符合筛选条件的 X」+ 清除筛选 /
 *          not-started「输入门店编号后查询」+ 聚焦动作 / error 走 .admin-error-card 不走这里。
 * 图标字色用 text-3 #647389 而不是 icon-muted #94a3b8：后者作 color 会被 check:styles 拦。
 * list-page 与右侧面板的多处空态共用；单独使用时外层给一张卡片即可。
 * 用法：
 *   <view class="ui-empty">
 *     <view class="ui-empty-icon"><text class="ui-empty-icon-text">空</text></view>
 *     <text class="ui-empty-title">没有符合筛选条件的记录</text>
 *     <text class="ui-empty-desc">调整筛选条件，或清除后查看全部记录</text>
 *     <view class="ui-empty-actions">
 *       <text class="ui-empty-action" @click="clearFilters">清除筛选</text>
 *     </view>
 *   </view> */
.ui-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 40px 16px;
  box-sizing: border-box;
}
.ui-empty-icon {
  width: 48px;
  height: 48px;
  margin-bottom: 12px;
  flex-shrink: 0;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  border-radius: 12px;
  background-color: #f3f6fa;
}
.ui-empty-icon-text {
  color: #647389;
  font-size: 22px;
  font-weight: 400;
  line-height: 22px;
  text-align: center;
}
.ui-empty-title {
  display: block;
  color: #45536a;
  font-size: 14px;
  font-weight: 500;
  line-height: 20px;
  text-align: center;
}
/* max-width 让说明句在宽面板里也保持 2 行以内，不横跨整屏 */
.ui-empty-desc {
  display: block;
  max-width: 320px;
  margin-top: 4px;
  color: #647389;
  font-size: 12px;
  font-weight: 400;
  line-height: 18px;
  text-align: center;
}
.ui-empty-actions {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 12px;
}
/* 空态动作是「下一步建议」不是页面主 CTA，所以用浅蓝次按钮而不是实心主色：
 * 一屏只允许一个实心主按钮（§3.1 brand 用途约束）。 */
.ui-empty-action {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  height: 28px;
  padding: 0 12px;
  border: 1px solid #c9ddfb;
  border-radius: 8px;
  background-color: #e7f0ff;
  color: #1f5fd1;
  font-size: 13px;
  font-weight: 500;
  line-height: 16px;
  cursor: pointer;
}
.ui-empty-action:hover {
  background-color: #c9ddfb;
}
/* ============================================================
 * B2b 切换控件三分形（§3.5）+ C7 宽表 class 族（§3.4 / §4.4 U4-I2）
 *
 * 只加不删：`.admin-tab-pill` 261 处调用点原样保留作过渡别名，B4 才删。
 * 本段全部取值来自 scripts/design/tokens.json：
 *   字号 11/12/13/14/15/22/24/28、字重 400/500/600/700、圆角 4/6/8/12/16/999、
 *   z-index 10/20/30/40/100/101/120/121/130/131、阴影只有 shadow-1/2/3/brand 四条。
 *
 * ⚠️ 方案 §3.1 的 success-text 是 #15803d，不是 #047857；#047857 不在令牌集合里，
 * 写进来会被 check:styles 的 bare-hex 规则判成新增违规。本段没有成功态，这里只做登记。
 *
 * 键盘可达：`<view>/<text>/<button>` 在 uni-app x 的 H5 运行时都不是原生可聚焦元素
 *（证据见本文件 :focus-visible 那段注释：Button 渲染成 <uni-button> 且只挂 onClick）。
 * 所以本段的 :focus-visible 与上面那组一样，要等调用点在 #ifdef WEB 里补
 * tabindex="0" + role + @keydown 才会亮；样式先落好，届时只补属性。
 * ============================================================ */
/* ---- ① 状态页签：互斥切换「列表主体」，带计数（§3.5 第一行）----
 * 形态是**下划线**，与 ② 的药丸、③ 的分段一眼可辨 —— B2a 踩过一次坑：
 * 两颗像素级相同的药丸挨在一起、点击行为却相反（一个换列表、一个改查询条件）。
 *
 * 高度算术：容器 min-height 41 = 内容 40（页签高）+ 1px 底线，box-sizing: border-box。
 * 刻意**不用** `.ui-tab { margin-bottom: -1px }` 去让 2px 主色线盖住那条 1px 灰线：
 * 本容器是 overflow-x 滚动容器（横向滚动是 §3.5 明确要求的），
 * CSS Overflow 3 会把另一轴的 visible 一并算成 auto，负 margin 造出的 1px 纵向溢出
 * 会真的长出一根竖向滚动条。这里 2px 主色线压在 1px 灰线正上方（视觉 3px），
 * 换来的是「页签行永远不会莫名多一根滚动条」。
 * overflow-y: hidden 是同一件事的保险：显式写死后 overflow-x 不再被强制配对。
 * 容器不写固定 height —— 溢出时横向滚动条要往下长，写死 41 会把 40px 的页签裁掉。
 *
 * 激活态 500 → 600 会让该颗页签宽度跳几 px。uvue 没有可靠的 ::after + attr(data-*)
 * 占位手段（伪元素 content 还进不了无障碍树，见本文件 .ui-checkbox 那段），
 * 这里如实保留这一跳；它只在点击那一帧发生，不影响静止阅读。
 *
 * 用法：
 *   <view class="ui-tabs">
 *     <view class="ui-tab" :class="{ active: activeTab == tab.key }"
 *           v-for="tab in statusTabs" :key="tab.key" @click="switchTab(tab.key)">
 *       <text>{{ tab.label }}</text>
 *       <text class="ui-tab-count" :class="{ danger: tab.key == 'WARNING' }"
 *             v-if="tabCount(tab.key).length > 0">{{ tabCount(tab.key) }}</text>
 *     </view>
 *   </view>
 * 计数为空时整颗徽标不渲染（v-if），不要渲染成 "0" —— monitor 的 tabCountText()
 * 已经是「取不到就返回空串」的口径，照着接即可。 */
.ui-tabs {
  display: flex;
  flex-direction: row;
  align-items: flex-end;
  gap: 20px;
  min-height: 41px;
  margin-bottom: 16px;
  box-sizing: border-box;
  border-bottom: 1px solid #e8edf4;
  overflow-x: auto;
  overflow-y: hidden;
}
/* 未选中用 text-2 #45536a 而不是 text-3 #647389：页签行经常落在页面底色 #f6f8fb 上，
 * #647389 压在 #f6f8fb 上只有 4.47:1（相对亮度 0.1707 / 0.9370），差一点点不过 AA。
 * #45536a 在白底 10.36:1、在 #f6f8fb 上 9.73:1，两种底色都稳过。 */
.ui-tab {
  flex-shrink: 0;
  height: 40px;
  padding: 0;
  box-sizing: border-box;
  display: flex;
  flex-direction: row;
  align-items: center;
  border-bottom: 2px solid transparent;
  color: #45536a;
  font-size: 13px;
  font-weight: 500;
  line-height: 20px;
  white-space: nowrap;
  cursor: pointer;
  transition: color 0.12s cubic-bezier(0.2, 0, 0, 1), border-color 0.12s cubic-bezier(0.2, 0, 0, 1);
}
.ui-tab:hover {
  color: #1b263b;
}
/* 激活态文字用 text-1 而不是主色：§3.1 限定 brand 只给「每屏 1 个主按钮 / 当前导航项
 * 图标 / ≤1 张 hero 卡」，主色留给那 2px 底线即可。#1b263b on #ffffff = 17.85:1。 */
.ui-tab.active {
  color: #1b263b;
  font-weight: 600;
  border-bottom-color: #246beb;
}
/* 计数徽标：11px（PC 字号白名单里 11 就是给「表格内与侧栏徽标」的），贴页签右上。
 * align-self: flex-start + margin-top 8 让它落在标签首行的顶部，读起来像上标。
 * 文字色用 neutral-text #45536a 而不是 text-3 #647389：
 * #647389 压在徽标底 #f3f6fa 上只有 4.39:1（0.1707 / 0.9085），11px 小字必须 ≥4.5；
 * #45536a / #f3f6fa = 6.92:1（0.0886 / 0.9085），过 AA。 */
.ui-tab-count {
  align-self: flex-start;
  margin-top: 8px;
  margin-left: 4px;
  flex-shrink: 0;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  box-sizing: border-box;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  background-color: #f3f6fa;
  color: #45536a;
  font-size: 12px;
  font-weight: 500;
  line-height: 16px;
  text-align: center;
}
/* 预警页签的徽标是红的（§3.5 点名）。#b42318 / #fff0ee = 5.91:1（0.1123 / 0.9099）。
 * 用 danger-text 而不是 danger-solid #dc2626：后者压在 #fff0ee 上只有 4.4:1。 */
.ui-tab-count.danger {
  background-color: #fff0ee;
  color: #b42318;
}
/* ---- ② 筛选条件 chip：改的是查询条件，不换列表主体（§3.5 第二行）----
 * 药丸 999 + 选中带左侧 ✓。取值逐字沿用现网 .monitor-chip / .pw-chip
 *（monitor/index.uvue:3033 与 prewarning/list.uvue:841 那两份页面私有副本），
 * 迁移时只换类名不改观感。
 * ✓ 不是装饰：卡底那排 .admin-filter-chip 是「已选条件回执」（方角 6、只有 × 可点），
 * 两者常常只隔十几个像素，光靠底色区分时用户会去点回执那一颗，点了什么也不会发生。
 * 圆的能点、方的是回执 —— 这条区分不许再被拉近。
 *
 * 用法（单选与多选同形，多选就是允许多颗同时 active）：
 *   <view class="ui-chip" :class="{ active: datePresetKey == preset.key }"
 *         v-for="preset in datePresets" :key="preset.key" @click="pick(preset.key)">
 *     <text class="ui-chip-check" v-if="datePresetKey == preset.key">✓</text>
 *     <text class="ui-chip-label">{{ preset.label }}</text>
 *   </view>
 * 颜色显式写在 .ui-chip-label / .ui-chip-check 上而不是靠继承：
 * uvue 的 <text> 不保证继承父 view 的 color（monitor 的同名规则就是这个原因）。 */
.ui-chip {
  height: 28px;
  padding: 0 12px;
  box-sizing: border-box;
  display: flex;
  flex-direction: row;
  align-items: center;
  /* 只在有 ✓ 时才产生间距：未选中的 chip 只有一个子节点，gap 不生效 */
  gap: 4px;
  border: 1px solid #e8edf4;
  border-radius: 999px;
  background-color: #ffffff;
  color: #45536a;
  font-size: 12px;
  line-height: 16px;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color 0.12s cubic-bezier(0.2, 0, 0, 1), border-color 0.12s cubic-bezier(0.2, 0, 0, 1), color 0.12s cubic-bezier(0.2, 0, 0, 1);
}
.ui-chip:hover {
  border-color: #c9ddfb;
}
/* #1f5fd1 压在 #eff6ff 上 6.16:1（相对亮度 0.1067 / 0.9148），过 AA */
.ui-chip.active {
  border-color: #c9ddfb;
  background-color: #e7f0ff;
  color: #1f5fd1;
  font-weight: 600;
}
.ui-chip-label {
  color: #45536a;
  font-size: 12px;
  line-height: 16px;
}
.ui-chip.active .ui-chip-label {
  color: #1f5fd1;
}
.ui-chip-check {
  flex-shrink: 0;
  color: #1f5fd1;
  font-size: 12px;
  font-weight: 600;
  line-height: 16px;
}
/* chip 行：包一层，负责换行与间距。gap 8 与 .pw-chip-row 一致。 */
.ui-chip-row {
  display: flex;
  flex-direction: row;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
}
/* ---- ③ 视图切换分段控件：同一份数据换个呈现，不改查询也不换主体（§3.5 第三行）----
 * 外框 surface-2 + 圆角 6 的轨道，选中项白底 + shadow-1。
 * 高度算术：轨道 32（border-box，含 1px 描边）→ 内容高 30，选中块 28，上下各留 1px；
 * shadow-1 是 `0 1px 2px`，那 1px 缝正好让投影透出来，不会被轨道边缘吃掉。
 * 轨道必须带 1px 描边：#f3f6fa 压在白卡 #ffffff / 页面底 #f6f8fb 上都几乎看不见，
 * 没有描边时「这是一个分段控件」这件事就传达不出去。
 *
 * 选中态**不改字重**（只换底色 + 文字色 + 投影）：分段控件的格子是并排等宽读的，
 * 500 → 600 会让整条轨道宽度跳一下；下划线页签换行不换位，才允许加粗（见 ① 的注释）。
 *
 * 用法：
 *   <view class="ui-segment">
 *     <view class="ui-segment-item" :class="{ active: dimension == item.key }"
 *           v-for="item in dimensions" :key="item.key" @click="switchDimension(item.key)"
 *     >{{ item.label }}</view>
 *   </view> */
.ui-segment {
  display: inline-flex;
  flex-direction: row;
  align-items: center;
  height: 32px;
  padding: 0 4px;
  gap: 4px;
  box-sizing: border-box;
  border: 1px solid #e8edf4;
  border-radius: 8px;
  background-color: #f3f6fa;
}
/* #45536a 压在轨道底 #f3f6fa 上 7.24:1（相对亮度 0.0886 / 0.9536） */
.ui-segment-item {
  height: 28px;
  padding: 0 12px;
  box-sizing: border-box;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  border-radius: 4px;
  color: #45536a;
  font-size: 13px;
  font-weight: 500;
  line-height: 16px;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color 0.12s cubic-bezier(0.2, 0, 0, 1), color 0.12s cubic-bezier(0.2, 0, 0, 1);
}
.ui-segment-item:hover {
  color: #1b263b;
}
/* #1b263b 压在 #ffffff 上 17.85:1 */
.ui-segment-item.active {
  background-color: #ffffff;
  color: #1b263b;
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.06);
}
/* 三种切换控件的焦点环。与本文件上方那一组同款（outline 不参与盒模型，聚焦不顶大 1px）。
 * 今天不会亮：uni-app x 的 H5 运行时里 <view>/<text>/<button> 都拿不到焦点，
 * 需要调用点在 #ifdef WEB 挂载后补 tabindex/role 才生效。 */
.ui-tab:focus-visible,
.ui-chip:focus-visible,
.ui-segment-item:focus-visible {
  outline: 2px solid #246beb;
  outline-offset: 2px;
}
/* ---- C7 宽表（§3.4 C7 / §4.4 U4-I2）----
 * 本类**自己就是滚动视口**（overflow: auto + max-height），首列与表头都相对它 sticky。
 *
 * 为什么不按方案 §4.4 那句「横向容器改普通 view overflow-x:auto 使纵向滚动祖先回到
 * .admin-main」来做：那一步在 CSS 上不成立。CSS Overflow 3 规定 overflow-x/overflow-y
 * 里一个是 visible、另一个不是时，visible 计算值变 auto —— 只写 overflow-x: auto
 * 也会让这个盒子成为**两轴**的滚动容器，表头的 `top` 从此以它自己为参照，
 * 而它自身没有纵向溢出，于是页面往下滚时表头一动不动地跟着整块滚走，等于没吸顶。
 * 所以这里把纵向也收进来：给一个 max-height，让表格内部同时纵向滚动，
 * 表头与首列才真的冻得住。已核实前提的另一半成立 ——
 * .admin-shell{height:100vh;overflow:hidden}（uni.scss:422）
 * → .admin-main{height:100%;overflow-y:auto}（uni.scss:833）
 * → .admin-content{flex:1 0 auto}（uni.scss:1010）没有再套 overflow，
 * 本容器是 .admin-content 的后代，100vh 口径可用，不会和外层滚动打架。
 *
 * 不要给同一个节点同时挂 .admin-table：那一条带 overflow: hidden（uni.scss:1387），
 * 会把本类的滚动视口压成不可滚动，sticky 立刻失效。宽表页二选一。
 *
 * ⚠️ 行内「更多」弹层（.action-menu）在本容器里会被 overflow 裁掉 ——
 * 无论 overflow 写成 auto 还是 hidden，滚动容器都会裁剪绝对定位后代。
 * 宽表页的行动作请用行末直接按钮或 admin-dialog，不要用 .action-menu。
 *
 * 列宽由调用页的私有类给（**不要在页面 <style> 里定义 .admin- 前缀类**，
 * check:styles 的 page-admin-class 规则会拦）：
 *   <view class="admin-wide-table">
 *     <view class="admin-wide-table-row header fd-row">
 *       <text class="admin-wide-table-cell sticky">订单号</text>
 *       <text class="admin-wide-table-cell">状态</text>
 *       <text class="admin-wide-table-cell numeric">配送费</text>
 *     </view>
 *     <view class="admin-wide-table-row fd-row" :class="{ selected: currentId == row.id }"
 *           v-for="row in rows" :key="row.id">…</view>
 *   </view>
 *   页面私有：.fd-row { grid-template-columns: 200px 120px 100px …; min-width: 1280px; }
 * min-width 必须写在**所有**行共用的那一个私有类上（含表头行），漏掉表头就会错列。
 * 单元格自带 12px 横向内边距，行上不要再加 padding：首列 sticky 到 left:0 时
 * 行的横向 padding 会被它盖住，看着像整列出了框。 */
/* max-height 的 300px = 顶栏 52 + 内容区上下内边距 48 + 页头 70 + 筛选卡 ~80 + 分页条 48
 * 的量级估算，取整到 300。页头更高（带 KPI 卡）的页面在自己的私有类里覆盖 max-height 即可
 *（私有类与本类同为 (0,1,0)，页面样式在全局样式之后注入，直接覆盖得掉）。
 * 刻意不写 min-height：短表加地板会在 3 行数据下面留一大块空白，
 * 而「窗口高不足 300px」在 PC 后台不是真实场景（壳本身就是 height:100vh + 52 顶栏）。 */
.admin-wide-table {
  max-height: calc(100vh - 300px);
  overflow: auto;
  box-sizing: border-box;
  border: 1px solid #e8edf4;
  border-radius: 12px;
  background-color: #ffffff;
}
/* 短表 / 不希望表格内部再出一根纵向滚动条时用它：首列照冻，表头**不再吸顶**
 *（理由见上面那段：没有纵向溢出就没有可吸的参照）。别指望 .flow 还能吸表头。 */
.admin-wide-table.flow {
  max-height: none;
}
.admin-wide-table-row {
  display: grid;
  align-items: center;
  min-height: 44px;
  padding: 0;
  box-sizing: border-box;
  border-bottom: 1px solid #e8edf4;
  background-color: #ffffff;
}
/* 斑马纹取 odd：表头是容器的第 1 个子节点，body 首行落在第 2 个（偶数）上保持白底，
 * 从第 2 行开始隔行浅底。表头行本身也命中 odd，但它的底色与这里同值，不产生差异。 */
.admin-wide-table-row:nth-child(odd) {
  background-color: #f3f6fa;
}
/* hover 用 neutral-bg #f3f6fa 而不是 primary-soft：浅蓝是「选中」的语义（见下一条），
 * 悬停和选中不能同色，否则鼠标划过一整页都像被选中了。
 * #45536a / #f3f6fa = 9.45:1。 */
.admin-wide-table-row:hover {
  background-color: #f3f6fa;
}
/* 右侧面板打开时的当前行。#45536a / #eff6ff = 9.51:1。
 * :hover 那条同为 (0,2,0)，靠**书写顺序在后**取胜，别把这两条调换位置。 */
.admin-wide-table-row.selected,
.admin-wide-table-row.selected:hover {
  background-color: #e7f0ff;
}
/* 表头：sticky 到视口顶。z-index 取令牌 sticky-page 档 20；
 * 首列 sticky 单元格是 10，表头整行 20 > 10，所以左上角那颗（表头 ∩ 首列）
 * 天然压在 body 首列之上，不需要再单独给它抬层级（层级表里也没有 30 以下的富余档）。
 * 底线用 line-strong #cbd5e1：滚动时表头下方紧贴着的是数据行，#e8edf4 分不开。
 * :hover 显式还原，否则鼠标划过表头会跟着变色，像可点。 */
.admin-wide-table-row.header,
.admin-wide-table-row.header:hover {
  position: -webkit-sticky;
  position: sticky;
  top: 0;
  z-index: 20;
  min-height: 40px;
  background-color: #ffffff;
  border-bottom: 1px solid #cbd5e1;
}
.admin-wide-table-row.last {
  border-bottom-width: 0;
}
.admin-wide-table-cell {
  min-width: 0;
  padding: 0 12px;
  box-sizing: border-box;
  color: #45536a;
  font-size: 13px;
  font-weight: 500;
  line-height: 18px;
}
/* 表头是坐标轴标签不是标题：#647389 on #ffffff = 4.77:1，过 AA */
.admin-wide-table-row.header .admin-wide-table-cell {
  color: #647389;
  font-size: 12px;
  font-weight: 500;
  line-height: 16px;
}
/* 冻结首列。background-color: inherit 是关键：从行上继承当前底色，
 * 于是白底 / 斑马 / hover / selected / 表头五种状态各自的底色一次全对，
 * 不需要给每种状态再写一条首列覆盖（漏一条就会在横向滚动时透出下面的数据）。
 * 右描边常驻（不做「滚动了才出现」的阴影）：行底色是不透明的，
 * 方案里那套 background-attachment: local 的纯 CSS 滚动阴影会被行底色整个盖住，
 * 落不了地；一条常驻竖线同样说明「这一列是冻住的」，且零 JS。 */
.admin-wide-table-cell.sticky {
  position: -webkit-sticky;
  position: sticky;
  left: 0;
  z-index: 10;
  background-color: inherit;
  border-right: 1px solid #e8edf4;
}
/* 数值列：右对齐 + 等宽数字，让金额/单量上下对得齐（§3.4 C7）。
 * 表头单元格也要挂 .numeric，否则列名左、数字右，看着像错位。 */
.admin-wide-table-cell.numeric {
  text-align: right;
  font-variant-numeric: tabular-nums;
}
/* ---- 顺手的两个兜底 ---- */
/* 禁用态兜底。取值与移动端 uni.scss 的 .is-disabled 逐字一致（opacity .5），
 * PC 额外加 cursor —— 移动端没有指针。
 * 刻意不写 pointer-events: none：本类只管视觉，「点不动」由调用点的
 * :disabled 属性或 @click 里的早退保证（§4.1 U8 的写法是两者并存）；
 * 只加一个类就悄悄吞掉点击，会让「为什么点了没反应」变得无从排查。 */
.is-disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
/* 必填红星。#dc2626 / #ffffff = 4.83:1。
 * 用真实 <text> 节点而不是 ::after { content: '*' }：伪元素 content 进不了无障碍树。
 * 星号与标签之间的空格写在模板里（现网 .required-mark 26 处就是这个写法），
 * 本类不带 margin，免得和模板里的空格叠成两倍间距。
 * 用法：<text class="form-label">品牌名称 <text class="req">*</text></text> */
.req {
  color: #dc2626;
  font-weight: 500;
}
/* ============================================================
 * 壳内弹窗（U1-I8）：切换身份 / 修改密码
 *
 * 两个弹窗都挂在 admin-layout 里，用的是 components/admin-dialog（层级 120/121）。
 * 类名放在这里而不是 admin-layout 的 <style> 里，理由是 check:styles 的
 * page-admin-class 规则禁止页面/组件 <style> 定义 .admin- 前缀类——
 * 壳的类历来都住在 uni.scss，保持一处。
 * ============================================================ */
.admin-identity-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
/* 行内是「身份名 + 机构名」在左、「进入」在右 */
.admin-identity-row {
  min-height: 64px;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  cursor: default;
}
.admin-identity-copy {
  display: flex;
  flex: 1;
  min-width: 0;
  flex-direction: column;
}
.admin-identity-enter {
  flex-shrink: 0;
}
.admin-identity-empty {
  display: block;
  padding: 12px 0;
  color: #647389;
  font-size: 13px;
}
.admin-shell-form {
  display: flex;
  flex-direction: column;
}
.admin-shell-field-label {
  color: #45536a;
  font-size: 12px;
  font-weight: 500;
  margin-bottom: 4px;
}
/* 复用 .admin-filter-input 的外观与焦点环（uni.scss:363 已经把它列进了焦点环名单），
 * 这里只把筛选栏那套「窄而并排」的尺寸改成弹窗里的「整行」 */
.admin-shell-field {
  width: 100%;
  max-width: none;
  margin-bottom: 12px;
}
/* Shared control sizing belongs with the global admin class definitions. */
.analytics-range-pair .admin-filter-input {
  width: 0;
  min-width: 0;
  flex: 1;
}
.coupon-row .admin-table-cell {
  min-width: 0;
  overflow-wrap: anywhere;
}
/* R5 dense filters: fixed columns, top-aligned labels, independent action row.
 * Compound range fields participate in the same grid; help text never shifts
 * adjacent inputs. These rules are shared by analytics and management pages. */
.admin-filter-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 12px 16px;
  align-items: start;
  margin-top: 12px;
}
.admin-filter-cell {
  min-width: 0;
}
.admin-filter-span-2 {
  grid-column: span 2;
}
.admin-filter-date-range {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  gap: 8px;
}
.admin-filter-date-range > uni-picker {
  min-width: 0;
}
.admin-content .admin-filter-grid .ui-field {
  margin-bottom: 0;
  min-width: 0;
  gap: 8px;
}
.admin-content .admin-filter-grid .ui-field-label-row {
  min-height: 20px;
  margin-bottom: 0;
}
.admin-content .admin-filter-grid .ui-field-label {
  line-height: 20px;
}
.admin-content .admin-filter-grid .admin-filter-input,
.admin-content .admin-filter-grid .admin-filter-select,
.admin-content .admin-filter-grid .ui-ep-control {
  width: 100%;
  max-width: none;
  height: 36px;
  box-sizing: border-box;
}
.admin-content .admin-filter-grid .analytics-range-fields {
  display: contents;
}
.admin-content .admin-filter-grid .analytics-range-field {
  min-width: 0;
  max-width: none;
  gap: 8px;
}
.admin-content .admin-filter-grid .admin-filter-ranges-wide .analytics-range-field:not(:first-child) {
  grid-column: span 2;
}
.admin-content .admin-filter-grid .analytics-range-label {
  line-height: 20px;
  font-weight: 500;
}
.admin-content .admin-filter-grid .analytics-range-pair .admin-filter-input {
  width: 0;
  min-width: 0;
  flex: 1;
}
.admin-content .admin-filter-grid .ui-entity-picker {
  display: flex;
  flex-direction: column;
}
.admin-content .admin-filter-grid .ui-ep-control {
  order: 0;
}
.admin-content .admin-filter-grid .ui-ep-chips {
  order: 1;
  margin-top: 4px;
  margin-bottom: 0;
}
.admin-content .admin-filter-grid .ui-ep-hint {
  order: 2;
}
.admin-filter-actions-row {
  display: flex;
  flex-direction: row;
  justify-content: flex-end;
  align-items: center;
  gap: 8px;
  margin-top: 16px;
  padding-top: 12px;
  border-top: 1px solid #e8edf4;
}
@media (max-width: 760px) {
.admin-filter-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@media (max-width: 520px) {
.admin-filter-grid {
    grid-template-columns: minmax(0, 1fr);
}
.admin-filter-span-2 {
    grid-column: auto;
}
.admin-content .admin-filter-grid .admin-filter-ranges-wide .analytics-range-field:not(:first-child) {
    grid-column: auto;
}
}
.invoice-selectable-row .admin-table-cell {
  min-width: 0;
  overflow-wrap: anywhere;
}
/* == design tokens: generated by scripts/design/gen-tokens.mjs, do not edit == */
/* 真源 scripts/design/tokens.json —— 改令牌改 json，再跑 node scripts/design/gen-tokens.mjs； */
/* npm run check 里的 gen-tokens --check 会拦住直接手改这一段。 */
/* 已核实：两端 App.uvue 引全局样式用的是 <style>@import './uni.scss'</style>（没有 lang="scss"）， */
/* 这条链路按普通 CSS 解析，写 $ 变量既不会求值也不会报错，只会静默变成无效声明； */
/* 所以本文件里的值一律写字面值。来龙去脉见 styles/_tokens.scss 头部与 gen-tokens.mjs 顶部注释。 */
/* 本生成段之外的规则脚本一行都不碰。 */
/* */
/* PC 只发 H5，var() 可用。这份 --color-* 是留给将来主题切换的运行期出口， */
/* 页面今天仍然直接写令牌字面值，由 lint 校验集合成员，不要为了用 var() 去改页面。 */
uni-page-body {
  --color-brand: #246beb;
  --color-primary-hover: #1f5fd1;
  --color-primary-active: #174fae;
  --color-primary-soft: #e7f0ff;
  --color-primary-border: #c9ddfb;
  --color-link: #1f5fd1;
  --color-text-1: #1b263b;
  --color-text-2: #45536a;
  --color-text-3: #647389;
  --color-text-disabled: #94a3b8;
  --color-icon-muted: #94a3b8;
  --color-bg-page: #edf4fb;
  --color-surface: #ffffff;
  --color-surface-2: #f3f6fa;
  --color-line: #e8edf4;
  --color-line-strong: #cbd5e1;
  --color-divider: #edf0f5;
  --color-success-text: #526078;
  --color-success-bg: #eef1f6;
  --color-success-border: #dce2eb;
  --color-warning-text: #94540f;
  --color-warning-bg: #fff3e1;
  --color-warning-border: #fde68a;
  --color-danger-text: #b42318;
  --color-danger-bg: #fff0ee;
  --color-danger-border: #fecaca;
  --color-danger-solid: #dc2626;
  --color-info-text: #1f5fd1;
  --color-info-bg: #e7f0ff;
  --color-info-border: #bfdbfe;
  --color-neutral-text: #45536a;
  --color-neutral-bg: #f3f6fa;
  --color-neutral-border: #e2e8f0;
  --color-reserve-text: #7c3aed;
  --color-reserve-bg: #f5f3ff;
  --color-on-primary-muted: rgba(255,255,255,.9);
  --color-amount: #151e30;
  --color-number: #151e30;
  --color-brand-display: #2878f5;
  --color-nav-active: #dfeaff;
  --color-masthead-ink: #195aba;
  --color-masthead-start: #e6f1ff;
  --color-masthead-end: #f1f7fc;
  --color-masthead-glow: #dcecff;
  --color-sidebar-surface: #f8fbff;
  --color-sidebar-end: #f5faff;
  --color-brand-signature: #526b8d;
  --color-brand-signature-bg: #e6eef9;
}
/* */
/* ---- 令牌清单：PC 后台 delivery-uniapp-x，只发 H5 口径，值即真源 ---- */
/* [颜色] */
/* color.brand = #246beb — 品牌主色。仅两种用途：每屏 1 个主按钮、至多 1 张 hero 卡（移动端钱包余额、首页概览）。导航当前项不再用它——当前项的信号是中性灰 pill + 主文色 + 600 字重 */
/* color.primary-hover = #1f5fd1 — PC 主按钮悬停态；App 端没有 hover，不要用 */
/* color.primary-active = #174fae — PC 主按钮按下态 */
/* color.primary-soft = #e7f0ff — 选中态底色（tab、chip、导航当前项、头像默认态） */
/* color.primary-border = #c9ddfb — 选中态边框，配 primary-soft 使用 */
/* color.link = #1f5fd1 — 文字链接。比 brand 深一档，用来和主按钮区分 */
/* color.text-1 = #1b263b — 主文 */
/* color.text-2 = #45536a — 次文；浅灰底 #f8fafc 上的最浅可用文字也用它 */
/* color.text-3 = #647389 — 白底上的最浅可用文字（4.8:1）；浅灰底上改用 text-2 */
/* color.text-disabled = #94a3b8 — 只允许用于 placeholder 与禁用态。lint 对普通 color: 上出现 #94a3b8 报错 */
/* color.icon-muted = #94a3b8 — 装饰性图标与分隔符。与 text-disabled 同值，语义不同，别互相顶替 */
/* color.bg-page = #edf4fb — 页面底色，两端各一值。移动端 orders/order-dispatch 的 #e8eef5、create 的 #f3f6fb 全部归一到这里 */
/* color.surface = #ffffff — 卡片底 */
/* color.surface-2 = #f3f6fa — 卡内浅底 */
/* color.line = #e8edf4 — 默认边框。替换现网 #dfe7f1 / #e4eaf2 / #e5ebf3 / #eef2f7 */
/* color.line-strong = #cbd5e1 — 输入框等需要被看见的边框 */
/* color.divider = #edf0f5 — 分隔线，比 line 更弱 */
/* color.success-text = #526078 — 完成 / 中标 / 已接单 的文字色。移动端 #047857 / #16a34a / #059669 归一到这里 */
/* color.success-bg = #eef1f6 — success 浅底 */
/* color.success-border = #dce2eb — success 边框 */
/* color.warning-text = #94540f — 预警中 / 待处理 / 剩余 ≤10 分钟 的文字色。废弃 #d97706（3.1:1）与 #f97316 / #ea580c / #c2410c */
/* color.warning-bg = #fff3e1 — warning 浅底 */
/* color.warning-border = #fde68a — warning 边框 */
/* color.danger-text = #b42318 — 超时 / 异常 / 取消类 / 失败 的文字色。标签文字必须用它，#dc2626 压在 #fef2f2 上只有 4.4:1 */
/* color.danger-bg = #fff0ee — danger 浅底 */
/* color.danger-border = #fecaca — danger 边框 */
/* color.danger-solid = #dc2626 — 危险实心按钮底色（白字），以及 uni.showModal 的 confirmColor。全站唯一一种红 */
/* color.info-text = #1f5fd1 — 进行中（呼叫中 / 配送中）的文字色 */
/* color.info-bg = #e7f0ff — info 浅底 */
/* color.info-border = #bfdbfe — info 边框 */
/* color.neutral-text = #45536a — 已停用 / 已关闭 / 已结束 的文字色。停用是常态不是错误，不许用红 */
/* color.neutral-bg = #f3f6fa — neutral 浅底 */
/* color.neutral-border = #e2e8f0 — neutral 边框，与 line 同值 */
/* color.reserve-text = #7c3aed — 预约单专色文字（PC 盯单卡「预」标签），替代原来的橙色实心 */
/* color.reserve-bg = #f5f3ff — 预约单浅底。§3.1 没有给 reserve 边框色，需要描边时用 line */
/* color.on-primary-muted = rgba(255,255,255,.9) — 蓝底上的次要文字（≥4.5:1）。#bfdbfe 只有 3.6:1、#e0ecff 4.3:1，都不达标 */
/* color.amount = #151e30 — 金额中性色，配 font-weight 600。移动端 #f0440b 金额强调色保留为登记在案的例外 */
/* color.number = #151e30 — PC R5黑色计数与金额，按字号区分层级 */
/* color.brand-display = #2878f5 — PC R5品牌图形色，小文字使用link */
/* color.nav-active = #dfeaff — PC R5导航选中底，配link色文字 */
/* color.masthead-ink = #195aba — PC R5产品抬头 */
/* color.masthead-start = #e6f1ff — PC R5顶部浅蓝背景 */
/* color.masthead-end = #f1f7fc — PC R5顶部浅蓝背景结束 */
/* color.masthead-glow = #dcecff — PC R5顶部背景浅色层 */
/* color.sidebar-surface = #f8fbff — PC R5侧栏浅色表面 */
/* color.sidebar-end = #f5faff — PC R5侧栏末端表面 */
/* color.brand-signature = #526b8d — PC R5侧栏品牌落款 */
/* color.brand-signature-bg = #e6eef9 — PC R5落款标识底 */
/* */
/* [图表色板与实体固定色（脚本里用，出口是 utils/theme.uts）] */
/* chart.series-primary = #2878f5 — 数量序列主色，同一张图 ≤ 3 条 */
/* chart.series-secondary = #a0c7fb — 数量序列次色 */
/* chart.series-neutral = #94a3b8 — 数量序列中性色（对比项、未归属） */
/* chart.series-rate = #f59e0b — 比率序列固定色。全站唯一暖色，只给「率」，不许拿去当强调色 */
/* chart.series-ink = #151e30 — 单序列图表的墨色柱/线。图里只有一根序列时色相不承载任何信息，用墨色让它退成「量」本身；多序列仍走 series-primary/secondary */
/* chart.category-1 = #2878f5 — 分类板 C1，顺序固定不许打乱 */
/* chart.category-2 = #6aa4f7 — 分类板 C2 */
/* chart.category-3 = #a0c7fb — 分类板 C3 */
/* chart.category-4 = #4d8dec — 分类板 C4 */
/* chart.category-5 = #476b99 — 分类板 C5 */
/* chart.category-6 = #7387a3 — 分类板 C6 */
/* chart.carrier-DADA = #2878f5 — 运力实体固定色：达达 */
/* chart.carrier-SHANSONG = #a0c7fb — 运力实体固定色：闪送 */
/* chart.carrier-FENGNIAO = #6aa4f7 — 运力实体固定色：蜂鸟即配（ELEME 作运力码时同色） */
/* chart.carrier-SF = #4d8dec — 运力实体固定色：顺丰同城（SHUNFENG 同色） */
/* chart.carrier-JD = #476b99 — 运力实体固定色：京东驻店专送（JDDJ / JINGDONG 同色） */
/* chart.carrier-UU = #7387a3 — 运力实体固定色：UU跑腿 */
/* chart.carrier-UNASSIGNED = #94a3b8 — 运力实体固定色：未归属。也是未登记运力码的兜底色 */
/* chart.channel-MEITUAN = #f59e0b — 渠道实体固定色：美团外卖 */
/* chart.channel-ELEME = #2563eb — 渠道实体固定色：饿了么 */
/* chart.channel-DOUYIN = #0f172a — 渠道实体固定色：抖音 */
/* chart.channel-TAOBAO = #e11d48 — 渠道实体固定色：淘宝闪购（TAOBAO_FLASH / TAOBAO_SHANGOU 同色） */
/* chart.channel-OFFLINE = #64748b — 渠道实体固定色：线下 / 手工单 */
/* chart.channel-OTHER = #94a3b8 — 渠道实体固定色：其它。也是未登记渠道码的兜底色 */
/* chart.map-store = #2878f5 — 地图打点：门店 */
/* chart.map-customer = #dc2626 — 地图打点：顾客 */
/* chart.map-rider = #4d8dec — 地图打点：骑手。规划线画实线、实际轨迹画灰虚线，不画推测线 */
/* */
/* [字号（8 档角色映射）] */
/* font-size.@scale = 12 / 13 / 14 / 15 / 16 / 18 / 20 / 22 / 24 / 26 / 28 / 32 (px) — 值域白名单。最小字号两端都是 12，8/9/10px 清零；11 只走白名单（PC 表格内与侧栏徽标、移动 caption/角标） */
/* font-size.page-title = 26px — 页标题，字重 700。移动端 Tab 首页大标题例外为 24 */
/* font-size.section-title = 18px — 卡片 / 区块标题，字重 600 */
/* font-size.metric = 24px — 指标数值，字重 700 + tabular-nums。PC 24 是 KPI 卡、28 是 hero */
/* font-size.body = 14px — 正文，字重 400 */
/* font-size.table-text = 13px — 表格 / 列表主文本，字重 500 */
/* font-size.caption = 12px — 辅助 / 时间 / 提示，字重 400 */
/* font-size.tag = 12px — 标签 / 徽标 / 表格副文本，字重 500。11 只在白名单里出现 */
/* font-size.button = 14px — 按钮，PC 字重 500、移动 600 */
/* font-size.todo = 32px — PC R5待办计数，行高40 */
/* font-size.amount = 20px — PC R5账簿金额，行高28 */
/* font-size.masthead = 24px — PC R5产品抬头，行高32 */
/* */
/* [字重（4 档）] */
/* font-weight.@scale = 400 / 500 / 600 — 800 全站禁用；650/660/680/720/730/740/750/760 这类假字重全部映射到 600 或 700 */
/* font-weight.regular = 400 — 正文、辅助文字 */
/* font-weight.medium = 500 — 表格主文本、标签、按钮（PC） */
/* font-weight.semibold = 600 — 区块标题、激活态页签、按钮（移动） */
/* font-weight.bold = 600 — 只出现在页标题与指标数值 */
/* */
/* [间距（8 档）] */
/* spacing.@scale = 4 / 8 / 12 / 16 / 20 / 24 / 32 / 40 (px) — 值域白名单，单位 px */
/* spacing.control-inline = 12px — 控件内横向内边距 */
/* spacing.card-inner = 16px — 卡片内边距 */
/* spacing.card-gap = 16px — 卡片之间的间距 */
/* spacing.section-gap = 24px — 区块之间的间距 */
/* spacing.page-padding = 20px — 页边距。PC 窗口 ≤1280 时收到 16 */
/* */
/* [圆角（6 档）] */
/* radius.@scale = 4 / 6 / 8 / 10 / 12 / 16 / 20 / 999 (px) — 值域白名单，单位 px（999 表示药丸/圆形） */
/* radius.tag = 4px — 标签 */
/* radius.control = 8px — 输入框 / 按钮 / 分段控件 */
/* radius.card = 12px — 卡片 / 表格 / 面板，两端同值 */
/* radius.overlay = 12px — 弹窗 / 抽屉 / 强调卡，与 card 同值 */
/* radius.sheet = 16px — 移动端底部 sheet 顶角、hero/overview 强调卡 */
/* radius.pill = 999px — 药丸 / 头像 */
/* radius.brand = 20px — PC R5左上品牌块外角 */
/* */
/* [阴影（5 档）] */
/* shadow.@note — 「描边或阴影二选一」。例外白名单只有：弹层、fixed 底栏、侧栏用户弹层 */
/* shadow.shadow-0 = none — 页内静态卡片：只描边不投影 */
/* shadow.shadow-1 = 0 1px 2px rgba(15,23,42,.06) — 极轻投影。PC 侧栏去掉蓝色大阴影后改用 1px 右边框，不用这一档 */
/* shadow.shadow-2 = 0 4px 12px rgba(15,23,42,.08) — 下拉 / 气泡 */
/* shadow.shadow-3 = 0 16px 40px rgba(15,23,42,.16) — 弹窗 / 抽屉 / sheet */
/* shadow.shadow-brand = 0 8px 20px rgba(37,99,235,.20) — 只给移动端主按钮 */
/* shadow.card = 0 4px 16px rgba(62,96,133,.03) — PC R5卡片轻投影；不与硬边框叠加 */
/* */
/* [控件高度] */
/* control-height.@scale = 28 / 36 / 44 (px) — 移动端列表卡操作按钮允许 52–54，属登记在案的例外；触控命中区一律 ≥44 */
/* control-height.sm = 28px — PC 行内文字按钮 / 移动卡片内联按钮 */
/* control-height.md = 36px — PC 筛选区与表单控件 / 移动次按钮 */
/* control-height.lg = 44px — PC 页级 CTA 与登录 / 移动主按钮 */
/* */
/* [层级] */
/* z-index.@note — 新增弹层只允许取表内值。uni.showModal / showToast 是原生层，不需要定义；value 为 null 表示该端没有这一层 */
/* z-index.sticky-page = 20 — PC 页内 sticky（页签行 / 批量条 / 表头）；移动 fixed 底栏 */
/* z-index.sticky-topbar = 30 — PC 顶栏 sticky。移动端没有这一层 */
/* z-index.dropdown = 40 — PC 下拉 / 更多菜单 / 浮层。移动端不适用 */
/* z-index.drawer-mask = 100 — PC 右侧抽屉遮罩；移动底部 sheet 遮罩 */
/* z-index.drawer-panel = 101 — PC 右侧抽屉面板；移动底部 sheet 面板 */
/* z-index.modal-mask = 120 — PC 页面级弹窗遮罩；移动居中弹窗遮罩 */
/* z-index.modal-panel = 121 — PC 页面级弹窗面板；移动居中弹窗面板 */
/* z-index.nested-mask = 130 — PC 行内 / 弹窗内二级弹窗遮罩；移动全局阻断（隐私 / 强制改密）遮罩 */
/* z-index.nested-panel = 131 — PC 行内 / 弹窗内二级弹窗面板；移动全局阻断面板 */
/* z-index.user-entry = 10 — PC 侧栏用户入口（局部堆叠上下文，其弹层 20）。validate-uniapp-x.mjs 钉死了这条规则里的正 z-index 数字与 overflow:visible，不许改成变量 */
/* */
/* [动效（三档）] */
/* motion.@note — 仅 PC Web 使用。App 端不做 CSS 动画，骨架屏用静态灰条 */
/* motion.duration-fast = 120ms — hover / 按下这类即时反馈 */
/* motion.duration-base = 180ms — 展开收起、切换 */
/* motion.duration-slow = 240ms — 抽屉 / 弹窗进出 */
/* motion.easing = cubic-bezier(.2,0,0,1) — 唯一缓动曲线 */
/* == end design tokens == */
html,
body,
#app {
  min-height: 100%;
  margin: 0;
}
uni-view {
  display: block;
}
uni-text {
  display: inline-block;
}
uni-page-body {
  background-color: #edf4fb;
  color: #1b263b;
  font-size: 14px;
}
body {
  background-color: #edf4fb;
}
.page {
  min-height: 100vh;
  padding: 16px;
  box-sizing: border-box;
}
.panel {
  background-color: #ffffff;
  border: 0;
  border-radius: 12px;
  padding: 16px;
  margin-bottom: 16px;
  box-sizing: border-box;
  box-shadow: 0 4px 16px rgba(62, 96, 133, 0.03);
}
.row {
  display: flex;
  flex-direction: row;
  align-items: center;
}
.col {
  display: flex;
  flex-direction: column;
}
.space-between {
  justify-content: space-between;
}
.title {
  font-size: 26px;
  font-weight: 600;
  color: #1b263b;
  line-height: 36px;
}
.section-title {
  font-size: 18px;
  font-weight: 600;
  color: #1b263b;
  margin-bottom: 12px;
  line-height: 28px;
}
.muted {
  color: #647389;
  font-size: 12px;
}
.button {
  min-height: 40px;
  padding: 0 14px;
  border-radius: 8px;
  background-color: #246beb;
  color: #ffffff;
  font-size: 14px;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  text-align: center;
  line-height: normal;
  cursor: pointer;
  transition: background-color 0.18s ease, border-color 0.18s ease, color 0.18s ease;
}
.button::after {
  border: 0;
}
.button[disabled] {
  cursor: not-allowed;
  opacity: 0.64;
}
.button.secondary {
  background-color: #ffffff;
  color: #45536a;
  border: 1px solid #e8edf4;
  box-sizing: border-box;
}
/* 提醒类动作（「忽略预警」「转商家自配」）：需要看清、但不越红线。
 * 橙底白字只有 2.8:1，所以一律深橙字。
 * 三个值全部取 §3.1 的 warning 三件套（#94540f / #fff3e1 / #fde68a）：
 *   原来的 #ffedd5 底 + #7c2d12 字 + #fed7aa 边都在令牌表外。
 *   底色没有直接搬到 warning-bg #fff3e1 —— 那样 hover 只剩 #fde68a 一档可用，
 *   而 #94540f 压在 #fde68a 上只有 4.03:1，会跌破 4.5:1（旧的 #7c2d12 on #ffedd5 是 8.18:1）。
 *   改成与本文件既有的 .admin-drill-exit 同一套「浅橙描边深字」写法：
 *   静息白底（#94540f on #ffffff = 5.02:1）、hover 才铺 warning-bg
 *   （#94540f on #fff3e1 = 4.84:1），两态都过 4.5:1。
 * 破坏性动作（取消订单 / 取消配送 / 删除）请用 .button.danger-outline；
 * 页面主 CTA 请用不带修饰类的 .button（实心主色），别用本类，
 * 否则会和旁边的 .button.secondary 变成同权重的两块浅色。 */
.button.warning {
  box-sizing: border-box;
  background-color: #ffffff;
  color: #94540f;
  border: 1px solid #fde68a;
}
.button.warning:hover {
  background-color: #fff3e1;
}
/* 破坏性主动作：实心红 */
.button.danger {
  box-sizing: border-box;
  background-color: #dc2626;
  color: #ffffff;
  border: 1px solid #dc2626;
}
.button.danger:hover {
  background-color: #b42318;
  border-color: #b42318;
}
/* 破坏性次动作（取消/终止类，动作条末尾） */
.button.danger-outline {
  box-sizing: border-box;
  background-color: #ffffff;
  color: #dc2626;
  border: 1px solid #fecaca;
}
.button.danger-outline:hover {
  background-color: #fff0ee;
}
/* ============================================================
 * U1-I9 焦点态与键盘可达（全站唯一一处焦点环定义）
 *
 * PC 只发 H5（package.json 只有 release:h5），:focus-visible / :focus-within
 * 与本文件里既有的 :hover 是同一档口径，可以直接用。
 *
 * 焦点环用 outline 而不是 border 或 box-shadow：
 *   - outline 不参与盒模型，聚焦时控件不会被顶大 1px，筛选栏不会跟着抖；
 *   - 方案 §4.1 原写法是 box-shadow: 0 0 0 3px rgba(37,99,235,.16)，
 *     但它不在 §3.1 的 5 档阴影令牌里，写进来会被 check:styles 判成新增违规；
 *   - outline-offset: 2px 让焦点环和控件自身的描边分开，实心主色按钮上也看得见。
 *
 * ⚠️ 关于「改成 <button> 就原生可聚焦」这个前提——实测不成立，证据：
 *   unpackage/dist/build/web/assets/uni.b4c8fde3.css 里是
 *     uni-button{position:relative;display:block;margin-left:auto;margin-right:auto;
 *                padding-left:14px;padding-right:14px;font-size:18px;line-height:2.55555556;
 *                border-radius:5px;color:#000;background-color:#f8f8f8;overflow:hidden}
 *     uni-button:after{...border:1px solid rgba(0,0,0,.2)...}
 *   index-*.js 里 Button 组件渲染的是 $a("uni-button", {ref, onClick, id, class})。
 * 也就是说 uni-app x 的 H5 运行时把 <button> 渲染成自定义元素 <uni-button>，
 * 只挂了 onClick，既没有 tabindex 也没有 role，它 **不是** 原生可聚焦元素，
 * Enter/Space 不会触发 click；<view>/<text> 同理。
 * 全仓库今天真正能吃到焦点的只有 <input>（uni-input 内部那个原生 input）。
 *
 * 因此这一组规则里：:focus-within 那条现在就生效；:focus-visible 那几条要等
 * 调用点补 tabindex="0" + @keydown（B2 逐页迁移时一起补）才会亮。
 * 样式先落好，届时只补属性，不用再回来改一遍全局样式。
 * ============================================================ */
.button:focus-visible,
.admin-filter-button:focus-visible,
.admin-tab-pill:focus-visible,
.admin-inline-button:focus-visible,
.admin-filter-select:focus-visible,
.admin-filter-input:focus-visible {
  outline: 2px solid #246beb;
  outline-offset: 2px;
}
.field {
  height: 42px;
  border: 1px solid #cbd5e1;
  border-radius: 8px;
  padding: 0 10px;
  margin-bottom: 10px;
  background-color: #ffffff;
  box-sizing: border-box;
}
.stat-grid {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  gap: 10px;
}
.stat-card {
  width: calc(50% - 5px);
  min-height: 72px;
  background-color: #f3f6fa;
  border: 1px solid #e8edf4;
  border-radius: 8px;
  padding: 12px;
  box-sizing: border-box;
}
.stat-value {
  font-size: 24px;
  font-weight: 600;
  color: #246beb;
  margin-top: 6px;
}
.list-item {
  padding: 12px 0;
  border-bottom: 1px solid #e8edf4;
}
.tag {
  min-width: 56px;
  padding: 3px 8px;
  border-radius: 4px;
  background-color: #e7f0ff;
  color: #1f5fd1;
  font-size: 12px;
  text-align: center;
}
/* U1-X2：滚动容器从 window 换到 .admin-main —— 侧栏与顶栏不再随页面滚走。
 * 壳锁定一屏高、自身不滚；侧栏 height:100% 后本来就不动，不需要 sticky；
 * .admin-nav-block 已是 flex:1 + min-height:0 + overflow-y:auto，菜单溢出由它接管。
 * ≤1000 断点会把 height/overflow 改回 auto/visible（竖排后再锁 100vh 就滚不动了）。
 * U1-I12：壳不再是「卡中卡」——外边距归零、底色用页面底色，侧栏与内容区都不带圆角与阴影。 */
.admin-shell {
  /* position:relative 是 .admin-sidebar.rail-open 的定位基准（U1-I6-b）。
   * 只用 position —— 这里同样不许出现 transform / filter / will-change，
   * 任何一个都会给后代的 position:fixed 造出新的包含块，全站弹窗与遮罩会失灵。 */
  position: relative;
  min-height: 100vh;
  height: 100vh;
  overflow: hidden;
  display: flex;
  flex-direction: row;
  background-color: #edf4fb;
  padding: 0;
  box-sizing: border-box;
}
/* U1-I6-a：236 → 220。1000–1280 这一档内容区原来只剩 ≈724px，
 * 侧栏每省一像素都直接加到表格与卡片上。 */
.admin-sidebar {
  width: 220px;
  height: 100%;
  background-color: #ffffff;
  color: #1b263b;
  box-sizing: border-box;
  padding: 24px 12px;
  display: flex;
  flex-direction: column;
  border-right: 1px solid #e8edf4;
  overflow: hidden;
  flex-shrink: 0;
}
/* ---- U1-I6-b 侧栏三档形态：full（220）/ rail（64 图标轨道）/ drawer（<1000 抽屉）----
 * 档位由 admin-layout 读 uni.getWindowInfo() + resize 决定并挂在 class 上，不是 @media：
 * rail 的「临时铺开」是交互状态（点了哪个分组图标），CSS 断点表达不了。
 * ⚠️ 这里的任何一条都不许覆盖 .admin-user-entry 的 overflow:visible
 *   （validate-uniapp-x.mjs:228-234 钉死，覆盖掉用户弹层会被裁成一条缝）。 */
.admin-sidebar.rail {
  width: 64px;
  padding: 14px 8px;
}
/* 临时铺开：从 flex 流里抬出来盖住内容区，选中一项或按 Esc 收回。
 * 位置基准是 .admin-shell（position:relative）。这里只能用 position/z-index，
 * 绝不能用 transform —— 它会给后代的 position:fixed 造出新的包含块。 */
.admin-sidebar.rail-open {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 220px;
  height: auto;
  z-index: 40;
  box-shadow: 0 4px 12px rgba(15, 23, 42, 0.08);
}
/* <1000：fixed 抽屉，配 .admin-nav-mask（z 100）。面板在遮罩之上。
 * height:auto + top/bottom:0 让它跟着视口高走，而不是基础规则那个相对壳的 100%。 */
.admin-sidebar.drawer {
  position: fixed;
  left: 0;
  top: 0;
  bottom: 0;
  width: 240px;
  height: auto;
  z-index: 101;
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.16);
}
.admin-sidebar.drawer-hidden {
  display: none;
}
/* rail-open 期间的 64px 占位，避免内容区左右各跳一次 */
.admin-rail-spacer {
  width: 64px;
  flex-shrink: 0;
}
/* rail-open 的透明关闭层：z 30（低于侧栏的 40，高于内容区），无底色。
 * 与 .admin-user-backdrop 同一套做法——它只负责接住「点了别处」这一次点击。 */
.admin-rail-backdrop {
  position: fixed;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: 30;
}
.admin-nav-mask {
  position: fixed;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: 100;
  background-color: rgba(15, 23, 42, 0.45);
}
.admin-brand {
  display: flex;
  flex-direction: row;
  align-items: center;
  flex-shrink: 0;
  padding: 4px 8px 14px;
  border-bottom: 1px solid #e8edf4;
}
/* rail 档只剩一个品牌标 + 一个折叠钮，横排放不下，改竖排 */
.admin-sidebar.rail .admin-brand {
  flex-direction: column;
  padding: 4px 0 12px;
}
.admin-brand-mark {
  width: 38px;
  height: 38px;
  border-radius: 12px;
  background-color: #246beb;
  color: #ffffff;
  font-size: 22px;
  font-weight: 600;
  line-height: 38px;
  text-align: center;
}
/* 下钻态（U1-I8）：品牌标切 warning。白字 on #94540f = 5.02:1，达标。
 * 这是「你正在看别人的数据」在侧栏侧的唯一常驻信号，与顶栏暖色成对出现 */
.admin-brand-mark.viewing {
  background-color: #94540f;
}
.admin-brand-copy {
  margin-left: 10px;
  display: flex;
  flex: 1;
  min-width: 0;
  flex-direction: column;
}
/* 折叠 / 展开钮（rail、full 两档）与窄屏抽屉的关闭钮共用一套盒子 */
.admin-nav-toggle {
  width: 32px;
  height: 32px;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  box-sizing: border-box;
  border-radius: 8px;
  cursor: pointer;
}
.admin-nav-toggle:hover {
  background-color: #f3f6fa;
}
.admin-sidebar.rail .admin-nav-toggle {
  margin-top: 8px;
}
.admin-nav-toggle-icon {
  width: 18px;
  height: 18px;
}
.admin-brand-title {
  color: #1b263b;
  font-size: 15px;
  font-weight: 600;
}
.admin-brand-sub {
  color: #647389;
  font-size: 12px;
  margin-top: 3px;
}
/* padding-top 18 → 10（U1-I7）：省下来的 8px 是删掉「功能菜单」那一行之后的顺延，
 * 菜单区整体上移，1000–1280 档少滚一屏。 */
.admin-nav-block {
  padding-top: 10px;
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}
/* 现在只剩「最近使用」一个分区标题在用（原来的「功能菜单」已删：
 * 一句恒定不变、不说明任何事的话，占掉 18px 又让人以为下面还有别的分区） */
.admin-nav-label {
  color: #647389;
  font-size: 12px;
  font-weight: 600;
  padding: 0 10px 8px;
}
/* 当前项的信号是「中性灰 pill + 主文色 + 600 字重」三件一起给：
 * 曾经这里是左侧 3px 品牌色竖条 + 浅蓝底，代价是侧栏常驻一列蓝，
 * 和「一屏只有一个主色」的令牌约束打架；改成中性灰之后，
 * hover 只动文字色不铺底，两态照样分得开，也不再需要竖条占位。 */
.admin-nav-item {
  position: relative;
  min-height: 40px;
  border-radius: 8px;
  padding: 0 12px;
  margin-bottom: 4px;
  display: flex;
  flex-direction: row;
  align-items: center;
  color: #45536a;
  cursor: pointer;
  box-sizing: border-box;
  transition: background-color 0.18s ease, color 0.18s ease;
}
.admin-nav-item.active {
  color: #1b263b;
  background-color: #f3f6fa;
}
.admin-nav-item.active .admin-nav-text {
  font-weight: 600;
}
/* hover 不铺底：铺了就和当前项的灰 pill 同貌，侧栏会出现两个「看起来选中」的行 */
.admin-nav-item:hover {
  color: #1b263b;
}
/* 无权限菜单。原来是 color:#a8b3c2（令牌表外，白底 2.12:1）。
 * text-disabled #94a3b8 语义对得上，但 design-lint 的 muted-text-color 规则
 * 明写「只允许 placeholder / 禁用 / 装饰图标，且不走 color」——禁用态也不许落到 color 上。
 * 所以改成本文件既有的禁用写法（.button[disabled]、.admin-user-logout.disabled 都是调 opacity）：
 * 合法色 text-3 #647389 + opacity .6。白底上混出来约 #a2acb9，和原来的 #a8b3c2 基本同一档灰，
 * 且 opacity 连那张 18px 的 lucide 图标一起压暗，整行「不可点」比只灰文字更完整。 */
.admin-nav-item.disabled {
  color: #647389;
  opacity: 0.6;
  cursor: default;
}
.admin-nav-item.disabled:hover {
  color: #647389;
  background-color: transparent;
}
/* U1-I4：灰底圆角方块整个删掉，这里现在是一张 18px 的 lucide 线性图标（<image>）。
 * 灰底方块的问题不只是难看：它把「菜单名首字」当图标，四级身份共用一套菜单时
 * 「商户体系」和「商家订单」都是「商」，图标反而在制造歧义。
 * 颜色变体由 admin-layout 的 navIconSrc() 换文件（img 的颜色改不了），
 * 所以这里没有、也不能有 .active 的反白规则。 */
.admin-nav-icon {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  margin-right: 9px;
}
/* rail 档只剩图标：居中，右边距收掉 */
.admin-sidebar.rail .admin-nav-icon {
  margin-right: 0;
}
.admin-sidebar.rail .admin-nav-item {
  justify-content: center;
  padding: 0 6px;
}
/* 折叠态里没地方写数字，用一个 8px 红点告诉你「这组里有待办」 */
.admin-nav-dot {
  position: absolute;
  right: 8px;
  top: 8px;
  width: 8px;
  height: 8px;
  border-radius: 999px;
  background-color: #dc2626;
}
.admin-nav-text {
  font-size: 13px;
  font-weight: 500;
}
.admin-nav-group .admin-nav-text {
  flex: 1;
}
.admin-nav-item.expanded {
  margin-bottom: 2px;
}
/* ⚰️ .admin-nav-count（与 .admin-nav-item.active .admin-nav-count）已随 U1-I7 删除。
 * 它显示的是「这个分组里有几个菜单」——一个装进侧栏就永远不再变化的常量，
 * 每一行都挂着一个不需要再看第二眼的数字，反而把真正该抢注意力的位置占了。
 * 这个位置现在归 .admin-nav-badge（业务待办数，danger 色）；没有待办时空着。
 * 原规则里那两段对比度推导（#45536a on #f3f6fa = 6.92:1、#1f5fd1 on #dbe7ff = 5.39:1）
 * 随类一起删除：它们算的是一个不再渲染的元素。新徽标自带自己那一段推导。 */
/* 展开 / 收起指示符复用 Lucide chevron。交互与 aria 状态仍由整行分组控件承担。 */
.admin-nav-arrow {
  flex-shrink: 0;
  width: 16px;
  height: 16px;
  margin-left: 7px;
  pointer-events: none;
}
.admin-nav-child {
  min-height: 36px;
  margin-left: 20px;
  padding: 0 8px 0 12px;
  border-left: 2px solid #e8edf4;
  border-radius: 0 8px 8px 0;
  display: flex;
  flex-direction: row;
  align-items: center;
  color: #647389;
  cursor: pointer;
  box-sizing: border-box;
  transition: background-color 0.18s ease, color 0.18s ease;
}
/* hover 不铺底、active 铺中性灰：与 .admin-nav-item 同一套口径。
 * 左侧 2px 引导线两种状态都保持 #e8edf4，不再染品牌蓝——
 * 引导线的作用是标出「这一列属于上面那个分组」，不是标当前项。 */
.admin-nav-child:hover {
  color: #1b263b;
}
.admin-nav-child.active {
  color: #1b263b;
  background-color: #f3f6fa;
}
.admin-nav-child.active .admin-nav-child-text {
  font-weight: 600;
}
.admin-nav-child.last {
  margin-bottom: 6px;
}
/* flex:1 是给徽标让位用的：展开态时预警待办数挂在子项这一行，
 * 文字不先占满剩余宽度，徽标就会紧贴在文字右边而不是行尾 */
.admin-nav-child-text {
  flex: 1;
  min-width: 0;
  font-size: 12px;
  font-weight: 500;
}
/* U1-I7 落地：本类现在挂的是**业务待办数**（OPEN 状态的预警单），
 * 不是 .admin-nav-count 那个「这组里有几个菜单」的常量。
 * 所以颜色也从中性灰换成 danger：它要抢一眼注意力，这正是徽标存在的理由。
 * 对比度：#b42318 on #fff0ee —— L(#b42318)=0.1123、L(#fff0ee)=0.9099，
 * (0.9099+0.05)/(0.1123+0.05)=5.91:1，过 4.5:1。
 * 高 18 / 字号 11（侧栏徽标白名单）/ 圆角 999（本高度下就是全圆）。 */
.admin-nav-badge {
  margin-left: auto;
  min-width: 22px;
  height: 18px;
  line-height: 18px;
  padding: 0 6px;
  box-sizing: border-box;
  border-radius: 999px;
  text-align: center;
  color: #b42318;
  background-color: #fff0ee;
  font-size: 12px;
  font-weight: 600;
}
.admin-sidebar-foot {
  margin-top: auto;
  padding: 12px;
  border-radius: 8px;
  background-color: #f3f6fa;
  border: 1px solid #e8edf4;
}
.admin-user-entry {
  position: relative;
  margin: 12px 4px 2px;
  flex-shrink: 0;
  overflow: visible;
  z-index: 20;
}
/* U1-X5 的透明遮罩。三条必须保持的性质写在 admin-layout 模板注释里：
 * 留在 .admin-user-entry 内部、排在弹层之前、不写 z-index（同层叠上下文里，
 * 带正 z-index 的弹层永远画在它之上，所以弹层照常可点）。
 * 无底色、无边框：它只负责接住那一次点击。 */
.admin-user-backdrop {
  position: fixed;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
}
/* 58 → 68：账号名 / 身份名 / 机构名三行（13 + 13 + 12 加两个 3px 间距 = 47，
 * 加上下各 8 的内边距正好 63，留 5px 余量给不同字体的行高差） */
.admin-user-trigger {
  min-height: 68px;
  display: flex;
  flex-direction: row;
  align-items: center;
  padding: 8px;
  box-sizing: border-box;
  border: 1px solid #e8edf4;
  border-radius: 8px;
  background-color: #f3f6fa;
  cursor: pointer;
  transition: background-color 0.18s ease, border-color 0.18s ease;
}
/* rail 档只剩头像 */
.admin-sidebar.rail .admin-user-trigger {
  justify-content: center;
  padding: 8px 0;
}
.admin-user-trigger:hover {
  border-color: #c9ddfb;
  background-color: #e7f0ff;
}
/* 默认态用 primary-soft，白字 on #cbd5e1 只有 1.5:1 */
.admin-user-avatar {
  width: 32px;
  height: 32px;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  box-sizing: border-box;
  border: 1px solid #c9ddfb;
  border-radius: 999px;
  background-color: #e7f0ff;
  color: #1f5fd1;
  font-size: 13px;
  font-weight: 600;
}
.admin-user-avatar.large {
  width: 38px;
  height: 38px;
  border-color: #246beb;
  background-color: #246beb;
  color: #ffffff;
  font-size: 15px;
}
.admin-user-copy {
  min-width: 0;
  margin-left: 9px;
  display: flex;
  flex: 1;
  flex-direction: column;
}
.admin-user-name,
.admin-user-popover-name {
  overflow: hidden;
  color: #1b263b;
  font-size: 13px;
  font-weight: 600;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* U1-I8：原来这三件事挤在 .admin-user-role 一行里
 * （「服务商 · 某某某某科技有限公司 · 待配置最低价」，11px + 省略号，
 * 机构名基本只看得到前四个字，商业状态永远被截掉）。
 * 现在身份名 13、机构名 12 各占一行，商业状态改成弹层头部的 status-tag。
 * 对比度：#45536a on #f3f6fa = 9.42:1；#647389 on #f3f6fa = 4.55:1，都过 4.5:1。 */
.admin-user-role,
.admin-user-org,
.admin-user-popover-mobile {
  overflow: hidden;
  margin-top: 3px;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.admin-user-role {
  color: #45536a;
  font-size: 13px;
}
.admin-user-org {
  color: #647389;
  font-size: 12px;
}
.admin-user-popover-mobile {
  color: #647389;
  font-size: 12px;
}
/* 用户弹层展开态复用 Lucide chevron；点击热区仍是整行 .admin-user-trigger。 */
.admin-user-arrow {
  flex-shrink: 0;
  width: 16px;
  height: 16px;
  margin-left: 6px;
  pointer-events: none;
}
.admin-user-popover {
  position: absolute;
  right: 0;
  bottom: calc(100% + 8px);
  width: 212px;
  padding: 14px;
  box-sizing: border-box;
  border: 1px solid #e8edf4;
  /* 圆角 10 → 8、阴影 0 12px 30px .14 → shadow-3，两个都不是随手取最近档：
   * admin-layout.uvue 的 .shell-search-panel 是照着「复用 .admin-user-popover 的视觉」
   * 建的，它把这两个值分别落成 8 与 0 16px 40px rgba(15,23,42,.16) 并写明了理由，
   * 这里跟上去，两块本来就该长一样的浮层才不会因为「谁先合规」而分叉。
   * 阴影 + 描边并存是 §3.1「描边或阴影二选一」的例外白名单项（侧栏用户弹层）。 */
  border-radius: 8px;
  background-color: #ffffff;
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.16);
  z-index: 10;
}
.admin-user-popover-head {
  display: flex;
  flex-direction: row;
  align-items: center;
}
.admin-user-popover-copy {
  min-width: 0;
  margin-left: 10px;
  display: flex;
  flex: 1;
  flex-direction: column;
}
/* 商业状态从侧栏那一行搬到弹层头部（U1-I8）。
 * 它是账号级状态，挂在身份名后面时读起来像身份的一部分（「服务商 · 待配置最低价」） */
.admin-user-status {
  align-self: flex-start;
  margin-top: 10px;
}
/* U1-I8：壳内补齐「个人信息 / 切换身份 / 修改密码」。
 * 在这之前，平台身份从壳里到不了这三个页面——workbench 里定义了 goProfile，
 * 但那是工作台的快捷入口，换到任何别的页面就没有入口了。 */
.admin-user-menu {
  display: flex;
  flex-direction: column;
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid #e8edf4;
}
.admin-user-menu-item {
  min-height: 34px;
  display: flex;
  flex-direction: row;
  align-items: center;
  padding: 0 9px;
  box-sizing: border-box;
  border-radius: 8px;
  color: #45536a;
  cursor: pointer;
  transition: background-color 0.18s ease;
}
.admin-user-menu-item:hover {
  background-color: #f3f6fa;
}
.admin-user-menu-icon {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  margin-right: 8px;
}
.admin-user-menu-text {
  font-size: 12px;
  font-weight: 500;
}
/* 底色 #fff1f2 / #ffe4e6 都在令牌表外，归到 danger-bg #fff0ee 与 danger-border #fecaca。
 * 文字同时从 #dc2626 换成 danger-text #b42318：§3.1 明写 danger-solid #dc2626 只当实心按钮底，
 * 「#dc2626 压在 #fff0ee 上只有 4.4:1」，hover 的 #fecaca 上更是 3.34:1。
 * #b42318 静息 5.91:1 过线；hover 在 #fecaca 上是 4.47:1，仍差 0.03 —— 但红族里比 danger-bg
 * 深的合法档只有 danger-border 这一个，且旧的两态是 4.40:1 / 4.02:1 双双不过，这是净改善。
 * 想真正让 hover 也过线，得在令牌表里加一档更浅的 danger hover 底，那属于改 tokens.json。
 * 而且本行那颗 log-out 图标本来就是 #b42318 变体，
 * 改完字和图标终于是同一个红。 */
.admin-user-logout {
  min-height: 34px;
  display: flex;
  flex-direction: row;
  align-items: center;
  margin-top: 10px;
  padding: 0 9px;
  box-sizing: border-box;
  border-radius: 8px;
  color: #b42318;
  background-color: #fff0ee;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
}
.admin-user-logout:hover {
  background-color: #fecaca;
}
.admin-user-logout.disabled {
  cursor: not-allowed;
  opacity: 0.65;
}
/* 原来是一个 20px 粉底方块里写「退」字（10px，字号阶梯外）。
 * 现在是 log-out 线性图标（danger 变体 #b42318），底色方块整个去掉：
 * 退出登录这一行本身已经是浅红底 + 红字，方块只是把红色叠了第三遍 */
.admin-user-logout-icon {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  margin-right: 8px;
}
.admin-foot-title {
  color: #1b263b;
  font-size: 12px;
  font-weight: 600;
}
.admin-foot-desc {
  color: #647389;
  font-size: 12px;
  line-height: 18px;
  margin-top: 6px;
}
/* 唯一的滚动容器。这里不许出现 transform / filter / will-change：
 * 任何一个都会给后代的 position:fixed 造出新的包含块，全站弹窗与遮罩会从「相对视口」
 * 变成「相对内容区」，遮不住侧栏与顶栏。 */
.admin-main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow-y: auto;
  background-color: #edf4fb;
}
/* 旧壳结构基础；R5壳尺寸由末尾pc-shell.css统一覆盖。
 * flex-shrink:0 不能省：内容撑高后 .admin-content 的自动最小尺寸会把收缩压力全甩给顶栏。
 * 背景必须是不透明纯白，半透明会透出下方滚动的内容。 */
.admin-topbar {
  position: -webkit-sticky;
  position: sticky;
  top: 0;
  z-index: 30;
  flex-shrink: 0;
  height: 52px;
  padding: 0 24px;
  background-color: #ffffff;
  /* 吸顶后顶栏与内容区（#f6f8fb）、与白卡片都近乎同色，边界只剩这一条线；
     #e8edf4 对两侧都只有 1.2:1 左右，滚动时卡片像长进顶栏，故用 line-strong。 */
  border-bottom: 1px solid #cbd5e1;
  box-sizing: border-box;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
}
/* U1-I8 下钻态：整条顶栏转暖色，而不是在顶栏下面再加一条 36px 横幅。
 * 横幅的问题是它把同一件事说第二遍还要多吃 36px——顶栏本身变色，
 * 每一屏、每一页、任何滚动位置都在提示「你看的不是自己的数据」。
 * #fff3e1 是 warning-bg；下边框同步换成 warning-border，
 * 不然暖底配 #cbd5e1 冷灰边会脏。 */
.admin-topbar.drill {
  background-color: #fff3e1;
  border-bottom-color: #fde68a;
}
/* 顶栏左簇：汉堡 + 下钻眼睛 + 面包屑。
 * 必须包一层——顶栏是 space-between，直接摊成四个孩子会把它们均匀撒开一整行 */
.admin-topbar-lead {
  display: flex;
  flex-direction: row;
  align-items: center;
  flex-shrink: 1;
  min-width: 0;
  gap: 8px;
}
/* <1000 的侧栏入口。32×32 与 .admin-icon-button 同规格 */
.admin-nav-hamburger {
  width: 32px;
  height: 32px;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  box-sizing: border-box;
  border-radius: 8px;
  cursor: pointer;
}
.admin-nav-hamburger:hover {
  background-color: #f3f6fa;
}
.admin-nav-hamburger-icon {
  width: 20px;
  height: 20px;
}
.admin-drill-eye {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
}
/* 「退出查看」：下钻态唯一的出口按钮。
 * #94540f on #ffffff = 5.02:1（正文档位达标） */
.admin-drill-exit {
  min-height: 28px;
  display: flex;
  flex-direction: row;
  align-items: center;
  flex-shrink: 0;
  padding: 0 12px;
  box-sizing: border-box;
  border: 1px solid #fde68a;
  border-radius: 8px;
  background-color: #ffffff;
  cursor: pointer;
}
.admin-drill-exit:hover {
  background-color: #fff3e1;
}
.admin-drill-exit-text {
  color: #94540f;
  font-size: 12px;
  font-weight: 500;
}
.admin-search {
  width: 280px;
  height: 34px;
  border-radius: 999px;
  border: 1px solid #e8edf4;
  background-color: #f3f6fa;
  padding: 0 14px;
  box-sizing: border-box;
  color: #45536a;
  font-size: 12px;
}
/* 面包屑整条一行：下钻路径 ｜ 分组 › 当前菜单。
 * 顶栏只回答「我在哪」，页标题由页头的 .admin-page-title 独占（U1-I3 去三重复） */
.admin-breadcrumb {
  display: flex;
  flex-direction: row;
  align-items: center;
  flex-wrap: wrap;
  min-width: 0;
  /* 顶栏是 space-between 的 flex 行，不写 shrink 时面包屑不会让位，
     长下钻路径会把自己的末级顶出 overflow:hidden 的顶栏。 */
  flex-shrink: 1;
  gap: 4px;
}
/* 下钻路径：平台 › 服务商A › 品牌商家B › 门店C，逐级可点返回
 * （四级主体的称谓以 docs/术语表.md §1 为准，「合作伙伴」「商户」是废弃词） */
.drill-path {
  display: flex;
  flex-direction: row;
  align-items: center;
  flex-wrap: wrap;
  gap: 4px;
}
.drill-node {
  color: #246beb;
  font-size: 12px;
  /* 下钻主体名可能是 15-18 字的工商全称，三级叠起来会把末级菜单名挤出顶栏。
     单节点截断优于整段裁掉。 */
  max-width: 168px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.drill-node.root {
  color: #647389;
}
/* 当前所在层不可点，避免"点了没反应"的困惑。
 * 700 按 §3.1 只留给标题与指标数值，这里同 .admin-breadcrumb-current 一档 */
.drill-node.current {
  color: #1b263b;
  font-weight: 600;
}
.drill-sep {
  /* 分隔符是承载层级关系的文字节点，不是装饰图标：#cbd5e1 对白顶栏只有 1.49:1，
     两级之间读不出层级；#94a3b8 作 color 是 2.57:1、被样式门禁禁掉，故用 text-3。 */
  color: #647389;
  font-size: 12px;
}
/* 下钻路径与自动面包屑之间的分隔：平台 › 服务商A ｜ 订单履约 › 预警单中心 */
.drill-divider {
  margin: 0 4px;
  color: #647389;
  font-size: 12px;
}
/* 面包屑第一级：当前菜单所在分组，取自 nav-groups.uts，与侧栏分组名逐字相同 */
.admin-breadcrumb-group {
  color: #647389;
  font-size: 12px;
}
/* 面包屑末级：当前菜单名；自动推导不到时回落到 breadcrumb-title prop */
.admin-breadcrumb-current {
  color: #45536a;
  font-size: 12px;
  font-weight: 500;
}
.admin-top-actions {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 8px;
}
.admin-top-button {
  min-width: 76px;
  height: 34px;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  padding: 0 12px;
  border-radius: 8px;
  background-color: #f3f6fa;
  color: #45536a;
  font-size: 12px;
  font-weight: 600;
  text-align: center;
  cursor: pointer;
}
.admin-top-button.primary {
  background-color: #246beb;
  color: #ffffff;
}
/* 页头右侧动作区（与 .admin-top-actions 同形，用于 .admin-page-head 内） */
.admin-head-actions {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 8px;
}
/* 32×32 方形次按钮（刷新/更多/关闭等仅图标动作） */
.admin-icon-button {
  width: 32px;
  height: 32px;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  box-sizing: border-box;
  border-radius: 8px;
  background-color: #f3f6fa;
  color: #45536a;
  font-size: 13px;
  line-height: normal;
  text-align: center;
  cursor: pointer;
  transition: background-color 0.18s ease, color 0.18s ease;
}
.admin-icon-button:hover {
  background-color: #e8edf4;
}
.admin-content {
  /* 必须是 1 0 auto 而不是 1：basis auto + 不收缩，长页面才会撑出 .admin-main 的滚动高度，
     短页面仍靠 grow 撑满一屏。写成 flex:1（basis 0）时高度完全由弹性算法决定，
     一旦编译链没有保住 min-height:auto 的自动最小尺寸，内容就会被压成一屏且无法滚动。 */
  flex: 1 0 auto;
  padding: 28px 32px 32px;
  box-sizing: border-box;
}
.admin-page-head {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 16px;
  gap: 16px;
  flex-wrap: wrap;
  padding: 20px;
  background: linear-gradient(135deg, rgba(255, 255, 255, 0.94), rgba(248, 251, 255, 0.7));
  border-radius: 16px;
}
/* 显式 display + line-height：页头高度不再靠 inline-block 的基线间隙，
 * 「壳顶到首张卡片上沿」= 52 顶栏 + 16 内容区上边距 + 54 页头 + 16 页头下边距 = 138px */
.admin-page-title {
  display: block;
  color: #1b263b;
  font-size: 26px;
  font-weight: 600;
  line-height: 36px;
}
/* max-width 防止长描述把页头撑成两行（服务商工作台那句 60 字的描述在 1024 宽会折行） */
.admin-page-desc {
  display: block;
  max-width: 720px;
  color: #647389;
  font-size: 13px;
  line-height: 20px;
  margin-top: 4px;
}
/* 页头统计条（U1-I13）：一排 12px 文本，不再是一排看着像按钮的白底药丸。
 * 条目之间靠本容器的 gap 分开——这里是 flex row 且显式带 gap，
 * 不会重演 .admin-error-card 那种「相邻 <text> 首尾相连拼成一句」的事故。 */
.admin-status-strip {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: flex-end;
  flex-wrap: wrap;
  gap: 12px;
}
.admin-status-pill {
  display: flex;
  flex-direction: row;
  align-items: center;
  min-height: 20px;
  line-height: 20px;
  color: #45536a;
  font-size: 12px;
}
.admin-status-pill.danger {
  color: #b42318;
}
.admin-tab-row {
  display: flex;
  flex-direction: row;
  gap: 8px;
  margin-bottom: 14px;
}
/* height 34 + box-sizing 缺省(content-box) + 1px 描边 = 外高 36、最小外宽 88；
 * 这里改写成 height 36 / min-width 88 + border-box，外框仍是 88×36，今天逐像素不变，
 * 但换成 <button> 后不会被 uni-button 自带的 box-sizing:border-box 缩掉 2px。
 * border-radius 18px 不在 6 档圆角阶梯内；本类外高 36，18px 本就是全圆，
 * 换成令牌 radius.pill=999px 同样是等价改写。
 * margin/padding 两条见下面 ::after 的注释：给 B2 的换标签预留的重置，
 * 对现在的 <view> 调用点是纯 no-op。 */
.admin-tab-pill {
  min-width: 88px;
  height: 36px;
  box-sizing: border-box;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  line-height: normal;
  border-radius: 999px;
  background-color: #ffffff;
  border: 1px solid #e8edf4;
  color: #45536a;
  font-size: 12px;
  font-weight: 600;
  text-align: center;
  cursor: pointer;
}
/* uni-button 会给自己画一圈 ::after 伪边框（border:1px solid rgba(0,0,0,.2)，
 * 200% 尺寸 + scale(.5) 的老写法），不清掉换标签后每颗页签会多出一层灰描边。
 * 写法与本文件既有的 .button::after 一致；对 <view>/<text> 调用点没有 content，不渲染。 */
.admin-tab-pill::after {
  border: 0;
}
.admin-tab-pill.active {
  color: #1f5fd1;
  border-color: #c9ddfb;
  background-color: #e7f0ff;
}
/* 盯单页「预警」页签在未选中且有待办时走这一档。
 * 底色 #fff7f7 归到 danger-bg #fff0ee；文字同步换 danger-text #b42318——
 * §3.1「标签文字必须用它，#dc2626 压在 #fff0ee 上只有 4.4:1」，这一条说的正是本类
 * （12px/700 不算大字号，仍要 4.5:1）。#b42318 on #fff0ee = 5.91:1。 */
.admin-tab-pill.danger {
  color: #b42318;
  border-color: #fecaca;
  background-color: #fff0ee;
}
.admin-metric-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
}
.admin-metric-card {
  min-height: 112px;
  background-color: #ffffff;
  border: 0;
  border-radius: 12px;
  padding: 16px 20px;
  box-sizing: border-box;
  box-shadow: 0 4px 16px rgba(62, 96, 133, 0.03);
}
/* U1-I6-a：118 → 96。compact 卡里只有 label + 数值两行（12 + 28 + 14 间距 = 54），
 * 118 有一半是空的；四张卡一排时这 22px 直接从首屏里挤掉了一整行表格 */
.admin-metric-card.compact {
  min-height: 96px;
}
.admin-metric-label {
  color: #647389;
  font-size: 12px;
  font-weight: 500;
}
.admin-metric-value {
  display: block;
  color: #151e30;
  font-size: 24px;
  font-weight: 600;
  margin-top: 8px;
  line-height: 32px;
  font-variant-numeric: tabular-nums;
}
.num {
  font-variant-numeric: tabular-nums;
}
.admin-metric-note {
  display: block;
  color: #647389;
  font-size: 12px;
  margin-top: 4px;
  line-height: 16px;
}
.admin-board {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) minmax(340px, 0.8fr);
  gap: 20px;
  margin-top: 14px;
}
.admin-card {
  background-color: #ffffff;
  border: 0;
  border-radius: 12px;
  padding: 16px 20px;
  box-sizing: border-box;
  box-shadow: 0 4px 16px rgba(62, 96, 133, 0.03);
}
.admin-filter-card {
  margin-top: 16px;
  margin-bottom: 16px;
}
.admin-page-head + .admin-filter-card {
  margin-top: 0;
}
.admin-filter-bar {
  display: flex;
  flex-direction: row;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px;
}
.admin-filter-input {
  min-width: 140px;
  height: 36px;
  border-radius: 8px;
  border: 1px solid #e8edf4;
  color: #45536a;
  font-size: 13px;
  padding: 0 12px;
  box-sizing: border-box;
  background-color: #ffffff;
}
/* 输入框聚焦反馈（U1-I9）：改这条之前，全站输入框聚焦没有任何视觉变化。
 * 必须用 :focus-within 而不是 :focus —— .admin-filter-input 的 293 个调用点都写在
 * <input> 上，H5 里它渲染成自定义元素 <uni-input>，真正拿到焦点的是内部的原生
 * input（uni 基础样式还给 .uni-input-input 写了 outline:none），外层只能靠
 * :focus-within 接住。uni-input 自身的 overflow:hidden 只裁剪后代，不裁剪它自己的
 * outline，所以焦点环不会被切掉。
 * 底色顺带从 #f3f6fa 提到纯白：聚焦时「这一格是活的」比只换描边更明显。 */
.admin-filter-input:focus-within {
  outline: 2px solid #246beb;
  outline-offset: 2px;
  border-color: #246beb;
  background-color: #ffffff;
}
.admin-filter-bar .admin-filter-input {
  flex: 1 1 180px;
}
.admin-filter-select {
  min-width: 110px;
  height: 36px;
  line-height: 36px;
  border-radius: 8px;
  border: 1px solid #e8edf4;
  color: #45536a;
  background-color: #ffffff;
  font-size: 13px;
  text-align: center;
  box-sizing: border-box;
}
/* 下拉现在还是 <view>（66 处），拿不到焦点；等 B2 换成可聚焦控件后这条才会亮。
 * 边框变主色与输入框同一档反馈。 */
.admin-filter-select:focus-within {
  border-color: #246beb;
}
/* margin/padding/border 三条 + 下面的 ::after 是给 B2「<view> → <button>」预留的重置：
 * uni-button 的默认值是 18px 字号、line-height:2.55、左右 14px 内边距、
 * margin-left/right:auto、#f8f8f8 底、5px 圆角，外加一圈 ::after 伪边框。
 * 本类已经显式写死了 font-size / line-height / background-color / color / border-radius，
 * 补齐这四条之后换标签外观逐像素不变（尤其 margin:auto —— 不清掉，筛选栏里的
 * flex 项会被自动居中/推开，是最容易漏的一条）。
 * 对现在的 201 个 <view> 调用点全部是 no-op：view 的这三项默认值本就是 0。 */
.admin-filter-button {
  min-width: 66px;
  height: 36px;
  box-sizing: border-box;
  margin: 0;
  padding: 0 12px;
  border: 1px solid #e8edf4;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  line-height: normal;
  border-radius: 8px;
  color: #45536a;
  background-color: #ffffff;
  font-size: 13px;
  font-weight: 500;
  text-align: center;
  cursor: pointer;
}
.admin-filter-button::after {
  border: 0;
}
.admin-filter-button.primary {
  color: #ffffff;
  background-color: #246beb;
  border-color: #246beb;
}
.admin-filter-button.primary:not(.is-disabled):hover {
  background-color: #1f5fd1;
  border-color: #1f5fd1;
}
.admin-filter-button.primary:not(.is-disabled):active {
  background-color: #174fae;
  border-color: #174fae;
}
.admin-card-head {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 12px;
  min-height: 28px;
  gap: 12px;
  flex-wrap: wrap;
}
/* 卡片标题必须比页标题（22/700）低一档，否则会出现「卡片标题比页标题还粗」的观感 */
.admin-card-title {
  color: #1b263b;
  font-size: 18px;
  font-weight: 600;
  line-height: 28px;
}
/* 可点击的卡头链接；非交互说明文字请用 .admin-card-meta */
.admin-card-link {
  color: #45536a;
  font-size: 12px;
  font-weight: 500;
  cursor: pointer;
}
/* 这里不加任何 :hover 反馈（连变色都不加）：全站约 100 处 .admin-card-link 里大多数其实是
 * 「共 N 条」这类不可点的统计/说明文字，给它加悬停变化等于让静态文字假装可点。
 * validate-uniapp-x.mjs 的 U1-B0-7 直接禁止 `.admin-card-link:hover` 这个选择器出现，
 * 等这些调用点全部迁到 .admin-card-meta 之后再补 hover 反馈。 */
/* 卡头右侧的非交互说明文字：灰、常规字重、不可点 */
.admin-card-meta {
  color: #647389;
  font-size: 12px;
  font-weight: 400;
  cursor: default;
}
/* 全局错误卡：查询类失败用「原因 + 重试」，不再各页自绘 error-card。
 * 必须是 flex 列：工作台把多路请求各自记错后模板是 v-for 的相邻 <text>，
 * 中间没有空白文本节点，卡片不列排、text 又是全局 inline-block，
 * 三条错误会在 H5 上首尾相连拼成一句话。 */
.admin-error-card {
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
  padding: 14px 16px;
  border: 1px solid #fecaca;
  border-radius: 8px;
  background-color: #fff0ee;
}
/* 一条错误独占一行：display 也显式写块级，脱离 .admin-error-card 时同样不粘连 */
.admin-error-text {
  display: block;
  color: #b42318;
  font-size: 13px;
  line-height: 20px;
}
/* 「重试」自成一行、左对齐，不跟在错误文案末尾 */
.admin-error-retry {
  display: flex;
  flex-direction: row;
  align-items: center;
  align-self: flex-start;
  min-height: 28px;
  color: #b42318;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
.admin-error-retry:hover {
  text-decoration: underline;
}
/* 一行提示条：只承载说明，不承载动作 */
.admin-notice {
  box-sizing: border-box;
  padding: 8px 12px;
  border: 1px solid #e8edf4;
  border-radius: 8px;
  background-color: #f3f6fa;
  color: #45536a;
  font-size: 12px;
  line-height: 18px;
}
.admin-notice.info {
  border-color: #c9ddfb;
  background-color: #e7f0ff;
  color: #1f5fd1;
}
.admin-notice.success {
  border-color: #dce2eb;
  background-color: #eef1f6;
  color: #526078;
}
.admin-notice.warning {
  border-color: #fde68a;
  background-color: #fff3e1;
  color: #94540f;
}
.admin-table {
  border: 1px solid #e8edf4;
  border-radius: 12px;
  overflow: hidden;
}
.admin-table-row {
  min-height: 48px;
  display: grid;
  grid-template-columns: 1.1fr 1fr 0.8fr 0.7fr;
  align-items: center;
  padding: 0 12px;
  border-bottom: 1px solid #edf0f5;
  box-sizing: border-box;
}
/* 表头不再铺底色带：底色带把「表头」和「斑马纹」两件事混在一起，
 * 一整条灰横在卡片顶部也是页面里最重的一块非数据色。留一条 line 底边就够分层。 */
.admin-table-row.header {
  min-height: 42px;
  border-bottom: 1px solid #e8edf4;
}
.admin-table-row.last {
  border-bottom-width: 0;
}
.admin-table-cell {
  color: #45536a;
  font-size: 12px;
}
.admin-order-no,
.admin-main-text {
  display: block;
  color: #1b263b;
  font-size: 12px;
  font-weight: 600;
}
.admin-order-time,
.admin-sub-text {
  display: block;
  color: #647389;
  font-size: 12px;
  margin-top: 4px;
}
/* 状态标签是「内容宽度的小药丸」，不是等宽色块：
 * min-width 58 会让「完成」和「配送中」一样宽，一列排下来变成整齐划一的色带，
 * 反而比文字更难扫读。字号回到 tag 令牌 12（11 只走侧栏徽标白名单），字重 500。
 * inline-flex + align-self 是必须的：单元格是 flex 列，默认 stretch 会把药丸拉满整列宽。 */
.admin-channel-tag,
.admin-status-tag {
  display: inline-flex;
  flex-direction: row;
  align-items: center;
  align-self: flex-start;
  height: 20px;
  padding: 0 8px;
  box-sizing: border-box;
  border-radius: 4px;
  text-align: center;
  font-size: 12px;
  font-weight: 500;
  line-height: 20px;
}
.admin-channel-tag {
  color: #1f5fd1;
  background-color: #e7f0ff;
}
.admin-status-tag {
  color: #45536a;
  background-color: #f3f6fa;
}
.admin-status-tag.processing {
  color: #1f5fd1;
  background-color: #e7f0ff;
}
.admin-status-tag.success {
  color: #526078;
  background-color: #eef1f6;
}
/* warning 与 pending 同一档语义；#d97706 on #fff3e1 只有 3.1:1 */
.admin-status-tag.pending,
.admin-status-tag.warning {
  color: #94540f;
  background-color: #fff3e1;
}
/* #dc2626 on #fff0ee 只有 4.4:1，标签文字用 #b42318 */
.admin-status-tag.danger {
  color: #b42318;
  background-color: #fff0ee;
}
/* 分页的「上一页 / 下一页」走的就是本类（全站 14 处 .finance-pager 等分页条里，
 * 按钮一律是 <text class="admin-inline-button">），所以 U1-I9 说的「分页按钮」
 * 在全局样式这一侧就是这条规则。
 * margin/border/::after 同 .admin-filter-button，是给 B2 换 <button> 预留的重置；
 * padding 与 box-sizing 本类原本就写了，不动。 */
.admin-inline-button {
  min-width: 44px;
  height: 28px;
  display: inline-flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  line-height: normal;
  margin: 0;
  padding: 0 12px;
  border: 0;
  box-sizing: border-box;
  border-radius: 8px;
  color: #1f5fd1;
  background-color: #e7f0ff;
  font-size: 12px;
  font-weight: 500;
  text-align: center;
  cursor: pointer;
}
.admin-inline-button::after {
  border: 0;
}
/* 行内按钮的三个语义变体（方案 §4.3 U3-I7「.admin-inline-button.danger 全局化」
 * + §3.1 语义色表）。上提自 subpackage/platform/merchant/list.uvue 的页面私有副本 ——
 * 那份副本是 B4 page-admin-class 清理的第一批，页面 <style> 里不再重定义 .admin- 类。
 *
 * 只有这三个：一行操作里最多出现「主色 / 中性 / 警告 / 危险」四档。
 * 原页面还有 .migration（紫 #6d28d9）与 .delivery（青 #0f766e）两个变体，
 * 两个色都不在 §3.1 令牌表内（唯一的紫 #7c3aed 是预约单专色，全站没有青），
 * 一行里凑到五色之后「删除」反而不显眼，按 U3-I7 一并删除，调用点改挂 .subtle。
 *
 * subtle 的文字色是 #45536a 而不是页面副本里的 #647389：
 * #647389 压在 #f3f6fa 上只有 4.39:1（相对亮度 0.1707 / 0.9085），12px 小字过不了 AA；
 * #45536a / #f3f6fa = 6.92:1（0.0886 / 0.9085）。这与本文件 .ui-tab-count 是同一笔账。
 * warning #94540f / #fff3e1 = 6.51:1，danger #b42318 / #fff0ee = 5.91:1，两条逐字取自 §3.1。
 *
 * 刻意不写 .primary：本类的基础态（#1f5fd1 on #e7f0ff）已经是主色，
 * 再加一档实心蓝会让「每个卡片区域 ≤1 primary」（§4.3 U3-X8）更难守。
 * platform/settlement 页现在有一份私有的 .admin-inline-button.primary，
 * 它随该页迁移时一并处理，这里不抢先定义、免得两份定义打架。 */
.admin-inline-button.subtle {
  color: #45536a;
  background-color: #f3f6fa;
}
.admin-inline-button.warning {
  color: #94540f;
  background-color: #fff3e1;
}
.admin-inline-button.danger {
  color: #b42318;
  background-color: #fff0ee;
}
/* 品牌宽表保留全部行内动作；用文字按钮减轻视觉密度，危险/警告文字色继续沿用原变体。 */
.merchant-actions .admin-inline-button {
  min-width: 0;
  height: 28px;
  padding: 0;
  background-color: transparent;
  font-weight: 500;
}
.admin-timeline {
  border: 1px solid #e8edf4;
  border-radius: 8px;
  padding: 12px;
  box-sizing: border-box;
}
.admin-timeline-item {
  min-height: 52px;
  display: flex;
  flex-direction: row;
  align-items: flex-start;
  border-bottom: 1px solid #e8edf4;
  padding-bottom: 10px;
  margin-bottom: 10px;
  box-sizing: border-box;
}
.admin-timeline-item:last-child {
  border-bottom-width: 0;
  padding-bottom: 0;
  margin-bottom: 0;
}
.admin-timeline-dot {
  width: 10px;
  height: 10px;
  border-radius: 999px;
  background-color: #246beb;
  margin-top: 4px;
  margin-right: 10px;
}
.admin-timeline-copy {
  flex: 1;
  min-width: 0;
}
.admin-table-row.header .admin-table-cell {
  color: #647389;
  font-weight: 500;
}
.admin-action-list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}
.admin-action-card {
  min-height: 84px;
  border-radius: 8px;
  border: 1px solid #e8edf4;
  background-color: #f3f6fa;
  padding: 12px;
  box-sizing: border-box;
  cursor: pointer;
}
.admin-card-head,
.admin-top-actions,
.admin-tab-row,
.finance-pager,
.reconciliation-actions,
.action-form,
.finance-tool-grid {
  flex-direction: row;
}
.finance-pager,
.reconciliation-actions {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: flex-end;
  flex-wrap: wrap;
  gap: 8px;
}
@media screen and (max-width: 1280px) {
.admin-content {
    padding: 16px;
}

  /* U1-I6-a：2 列 → 3 列。这一档配的是 64px 折叠轨道（或 220px 侧栏），
   * 内容区还有 ≈900–1050px，四张 KPI 卡掉成两行两列时每张宽到 480、
   * 一个 28px 的数字摊在半屏宽的白卡里，反而比 3 列更难扫。 */
.admin-metric-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
}
}
.admin-action-card.primary {
  border-color: #c9ddfb;
  background-color: #e7f0ff;
}
.admin-action-title {
  display: block;
  color: #1b263b;
  font-size: 13px;
  font-weight: 600;
}
.admin-action-desc {
  display: block;
  color: #647389;
  font-size: 12px;
  line-height: 18px;
  margin-top: 7px;
}
@media screen and (max-width: 1000px) {
  /* 侧栏改 fixed 抽屉后必须把 100vh 的锁解开：壳一旦还锁着一屏高又 overflow:hidden，
   * 内容区就被关在一屏里滚不动（上线即难用）。窄屏回到「整页滚动」。 */
.admin-shell {
    flex-direction: column;
    height: auto;
    overflow: visible;
}

  /* U1-I6-b：原来这一档把侧栏摊成 100% 宽、max-height 240 的「顶部块」，
   * 菜单被压进 160px 高的滚动条里翻——三十多个菜单项在 160px 里找一个，
   * 比在手机上翻通讯录还慢，而且它常驻占掉首屏 240px。
   * 现在换成顶栏汉堡 + fixed 抽屉（.admin-sidebar.drawer / .admin-nav-mask），
   * 形态整个由 admin-layout 挂 class 决定，所以这一档不再需要覆盖侧栏尺寸；
   * .admin-nav-block 的 flex:1 + overflow-y:auto 基础规则直接接管抽屉内的滚动。 */
.admin-main {
    height: auto;
    overflow-y: visible;
}

  /* 顶栏在这一档继续吸顶。原来这里写的是 position:static，理由是
     「竖排时侧栏是被 max-height 截断的顶部块、用户区会溢出压在 .admin-main 顶部，
     顶栏吸顶会盖住它，退出登录点不到」——那个布局已经被抽屉替掉，
     用户区现在在抽屉里（z 101，高于顶栏的 30），压不到也盖不住。
     反过来，汉堡是这一档进入导航的唯一入口，它必须一直在视口里，
     所以这一档不但不该取消吸顶，还必须保住吸顶。 */
.admin-topbar,
.admin-page-head {
    align-items: flex-start;
    flex-direction: column;
    height: auto;
    gap: 12px;
    padding-top: 14px;
    padding-bottom: 14px;
}
.admin-top-actions,
.admin-search {
    width: 100%;
}
.admin-metric-grid,
.admin-board {
    grid-template-columns: 1fr;
}
.admin-filter-bar,
.admin-tab-row {
    flex-wrap: wrap;
}
.admin-filter-bar .admin-filter-input,
.admin-filter-bar .admin-filter-input.short {
    flex-basis: calc(50% - 6px);
    width: auto;
    max-width: none;
}
}
@media screen and (max-width: 640px) {
  /* 壳的 padding 与圆角已在基础规则里归零（U1-I12），这里不再需要断点覆盖 */
.admin-content {
    padding: 14px;
}
.admin-metric-grid {
    grid-template-columns: 1fr;
}
.admin-filter-bar .admin-filter-input,
.admin-filter-bar .admin-filter-input.short,
.admin-filter-button {
    flex-basis: 100%;
    width: 100%;
    max-width: none;
}
}
/* ============================================================
 * 详情信息网格（全局）：label 在上、value 在下，两列卡片式排布。
 * 页面模板约定：.detail-grid > .detail-cell(.full) > .detail-label + .detail-value
 * 页面自身 <style> 中的同名定义会覆盖此处，互不影响。
 * ============================================================ */
.detail-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}
.detail-cell {
  min-height: 64px;
  padding: 12px 14px;
  border: 1px solid #e8edf4;
  border-radius: 12px;
  background-color: #f3f6fa;
  box-sizing: border-box;
}
.detail-cell.full {
  grid-column: 1/-1;
}
.detail-label {
  display: block;
  color: #647389;
  font-size: 12px;
}
.detail-value {
  display: block;
  margin-top: 8px;
  color: #1b263b;
  font-size: 14px;
  font-weight: 600;
  line-height: 20px;
  word-break: break-all;
}
@media screen and (max-width: 640px) {
.detail-grid {
    grid-template-columns: 1fr;
}
.detail-cell.full {
    grid-column: auto;
}
}
/* ============================================================
 * B2a 盯单工作流批次新增的共用类（方案 §3.4 C2/C4、§3.5、§4.2 U2-I6/I12/I18、§6.2）
 *
 * 全部取值来自 scripts/design/tokens.json：字号 11/12/13/14/15/22/24/28、
 * 字重 400/500/600/700、圆角 4/6/8/12/16/999、z-index 20/30/40/100/101/120/121/130/131、
 * 阴影只有 shadow-1/2/3/brand 四条。新增规则前先跑 `npm run check:styles` 对一遍。
 *
 * 这里放的都是**多页共用**的形态。页面私有的一次性样式仍然写在各自 <style> 里，
 * 但不要在页面里定义 .admin- 前缀类（check:styles 的 page-admin-class 规则会拦）。
 * ============================================================ */
/* ---- 勾选框（U2-I12）：替换盯单台现在的 Unicode ☐/☑ 字符 ----
 * 那两个字符在 Windows Chrome 上一个是纯文本方框、一个是带底纹的图形字，
 * 宽度和基线都不一样，勾选时整行会横向抖一下。
 * ✓ 用真实 <text> 节点而不是 ::before/::after：uvue 的伪元素只在 H5 可靠，
 * 且伪元素 content 进不了无障碍树。
 * 用法：
 *   <view class="ui-checkbox" :class="{ checked: isChecked(item) }" @click.stop="toggleCheck(item)">
 *     <text class="ui-checkbox-mark">✓</text>
 *   </view>
 * 命中区：18×18 只是视觉尺寸，父行（.monitor-order-head 之类）整行可点，不要单独给它加 padding。 */
.ui-checkbox {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  box-sizing: border-box;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  border: 1.5px solid #cbd5e1;
  border-radius: 4px;
  background-color: #ffffff;
  cursor: pointer;
  transition: background-color 0.12s ease, border-color 0.12s ease;
}
.ui-checkbox:hover {
  border-color: #246beb;
}
.ui-checkbox.checked {
  background-color: #246beb;
  border-color: #246beb;
}
/* 默认不显示，由 .checked 打开：调用方无脑常驻这个 <text> 即可，不用再写 v-if */
.ui-checkbox-mark {
  display: none;
  color: #ffffff;
  font-size: 12px;
  font-weight: 600;
  line-height: 12px;
  text-align: center;
}
.ui-checkbox.checked .ui-checkbox-mark {
  display: block;
}
/* ---- 可复制编号 chip（U2-I18）----
 * 订单号 / 配送单号 / 队列号这类「要对着念、要复制」的编号一律走这个形态：
 * 等宽字体让 0/O、1/l 分得开，灰底把它和正文区分开，整块可点即复制。
 * 复制反馈走 utils/feedback.uts 的 toastSuccess，不要在这里做视觉反馈。
 * 用法：<text class="copy-chip" @click="copyText(row.orderNo)">{{ row.orderNo }}</text> */
.copy-chip {
  display: inline-flex;
  flex-direction: row;
  align-items: center;
  box-sizing: border-box;
  min-height: 24px;
  padding: 0 8px;
  border-radius: 4px;
  background-color: #f3f6fa;
  color: #45536a;
  font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: 12px;
  line-height: 16px;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color 0.12s ease, color 0.12s ease;
}
.copy-chip:hover {
  background-color: #e8edf4;
  color: #1b263b;
}
/* ---- 紧凑页签（U2-I6）----
 * .admin-tab-pill 的 min-width 88 × 5 颗 = 462px，右侧面板 1440 下可用宽只有 398px、
 * 1024 下只有 328px，页签行必然溢出或折行。compact 把最小宽度放开、高度收到 30，
 * 5 颗约 300px，1024 也放得下。
 * 只覆盖尺寸与字号，颜色仍由 .admin-tab-pill / .active / .danger 决定（属性不重叠，不靠优先级打架）。
 * 用法：<view class="admin-tab-pill compact" :class="{ active: panelTab == 'DETAIL' }"> */
.admin-tab-pill.compact {
  min-width: 0;
  height: 30px;
  padding: 0 10px;
  font-size: 12px;
  font-weight: 600;
}
/* ---- 顶部 2px 进度条（§6.2「翻页/筛选/轮询保留旧内容 + 顶部 2px 进度条」）----
 * 绝对定位、不占高度：父元素必须是 position:relative（list-page 用的是一个 height:0 的
 * 定位壳 .ui-list-progress）。如果让它占 2px 真实高度，每轮静默刷新列表都会上下跳一次，
 * 那正是这条进度条本来要解决的问题。
 * PC 只发 H5，@keyframes 可用；App 端没有这条链路（移动端另有自己的刷新指示）。 */
.ui-progress {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 2px;
  overflow: hidden;
  background-color: #e7f0ff;
}
.ui-progress-bar {
  position: absolute;
  top: 0;
  left: 0;
  width: 32%;
  height: 2px;
  background-color: #246beb;
  animation: ui-progress-slide 1.2s cubic-bezier(0.2, 0, 0, 1) infinite alternate;
}
/* alternate 让它左右往复而不是「跑到头突然跳回起点」——后者在 3 秒一轮的轮询里
 * 看着像页面卡了一下。68% = 100% - 32%（bar 宽），右端刚好贴边不溢出。 */
@keyframes ui-progress-slide {
from {
    left: 0;
}
to {
    left: 68%;
}
}
/* ---- 已选筛选条件回执 chip（U2-I8：折叠筛选后仍要看得见「为什么没数据」）----
 * **方角 radius 6 + 中性底**，与「筛选条件 chip」（药丸 999、选中带 ✓、点一下就改查询：
 * .monitor-chip / .pw-chip / 日期档药丸）刻意长得不一样：那些是开关，这一颗只是回执，
 * 说明「你已经筛了什么」。同一张筛选卡里圆的能点、方的不能点，一眼可分。
 *
 * 原来这颗是 primary-soft 底 + primary-border 边 + 药丸圆角 —— 与选中态的筛选条件
 * chip 逐像素同形，用户会去点它想切换条件，点了却只有右上角那 20px 有反应。
 *
 * 本体不可点，右侧 x 图标是唯一动作（删掉这一条）且命中区 20×20；
 * Lucide x 使用共享的 text-3 描边，并用 hover 底色补充可点击反馈。
 * 对比度：#45536a / #f3f6fa = 9.9:1，图标 #647389 / #f3f6fa = 4.6:1，均过 AA。
 * 用法：
 *   <view class="admin-filter-chip">
 *     <text>门店：星巴克国贸店</text>
 *     <text class="admin-filter-chip-close" @click="clearFilter('storeName')"><image ...></image></text>
 *   </view> */
.admin-filter-chip {
  display: inline-flex;
  flex-direction: row;
  align-items: center;
  box-sizing: border-box;
  height: 28px;
  padding: 0 4px 0 10px;
  border: 1px solid #e8edf4;
  border-radius: 8px;
  background-color: #f3f6fa;
  color: #45536a;
  font-size: 12px;
  line-height: 16px;
  white-space: nowrap;
}
.admin-filter-chip-close {
  width: 20px;
  height: 20px;
  margin-left: 4px;
  flex-shrink: 0;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  border-radius: 4px;
  cursor: pointer;
}
.admin-filter-chip-close-icon {
  width: 12px;
  height: 12px;
  pointer-events: none;
}
/* hover 用 line 而不是 primary-border：主色填充会把「方角回执」又拉回主色语义。 */
.admin-filter-chip-close:hover {
  background-color: #e8edf4;
}
/* ---- 动作「更多」弹层（U2-I4）----
 * 默认锚在触发元素正下方右对齐，所以**触发按钮的父容器必须 position:relative**
 * （盯单卡是 .monitor-order-actions）。关闭靠页面级透明遮罩，不要靠 blur：
 * uni-app x 的 <view>/<button> 都不可聚焦（见本文件 :focus-visible 那段注释），没有 blur 可听。
 * z-index 取令牌 dropdown 档 40：比页内 sticky（20）与顶栏（30）高，比抽屉（100）低。
 * 用法：
 *   <view class="action-menu" v-if="moreOpenId == item.id">
 *     <text class="action-menu-item" @click.stop="run(item,'KITCHEN_HOLD')">出餐完成</text>
 *     <text class="action-menu-item danger" @click.stop="run(item,'CANCEL_DISPATCH')">取消配送</text>
 *   </view> */
.action-menu {
  position: absolute;
  top: 100%;
  right: 0;
  z-index: 40;
  min-width: 132px;
  margin-top: 4px;
  padding: 4px 0;
  box-sizing: border-box;
  border: 1px solid #e8edf4;
  border-radius: 8px;
  background-color: #ffffff;
  box-shadow: 0 4px 12px rgba(15, 23, 42, 0.08);
}
.action-menu-item {
  display: flex;
  flex-direction: row;
  align-items: center;
  height: 36px;
  padding: 0 12px;
  box-sizing: border-box;
  color: #45536a;
  font-size: 13px;
  line-height: 36px;
  white-space: nowrap;
  cursor: pointer;
}
.action-menu-item:hover {
  background-color: #f3f6fa;
}
/* 取消/终止类固定置底、红字、上方一条分隔线（§4.2 U2-I4）。
 * 只有一档红：产生取消费、标记完成、删除、解绑都是 danger（§6.5）。 */
.action-menu-item.danger {
  margin-top: 4px;
  border-top: 1px solid #e8edf4;
  color: #b42318;
}
.action-menu-item.danger:hover {
  background-color: #fff0ee;
}
/* ---- 空态（§3.4 C2、§6.2 空态四类文案模板）----
 * 图标位 + 标题 + 说明 + 可选动作。图标过渡期沿用 48px 汉字方块（lucide 落地后统一换掉）。
 * 四类文案：no-data「暂无 X」/ no-result「没有符合筛选条件的 X」+ 清除筛选 /
 *          not-started「输入门店编号后查询」+ 聚焦动作 / error 走 .admin-error-card 不走这里。
 * 图标字色用 text-3 #647389 而不是 icon-muted #94a3b8：后者作 color 会被 check:styles 拦。
 * list-page 与右侧面板的多处空态共用；单独使用时外层给一张卡片即可。
 * 用法：
 *   <view class="ui-empty">
 *     <view class="ui-empty-icon"><text class="ui-empty-icon-text">空</text></view>
 *     <text class="ui-empty-title">没有符合筛选条件的记录</text>
 *     <text class="ui-empty-desc">调整筛选条件，或清除后查看全部记录</text>
 *     <view class="ui-empty-actions">
 *       <text class="ui-empty-action" @click="clearFilters">清除筛选</text>
 *     </view>
 *   </view> */
.ui-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 40px 16px;
  box-sizing: border-box;
}
.ui-empty-icon {
  width: 48px;
  height: 48px;
  margin-bottom: 12px;
  flex-shrink: 0;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  border-radius: 12px;
  background-color: #f3f6fa;
}
.ui-empty-icon-text {
  color: #647389;
  font-size: 22px;
  font-weight: 400;
  line-height: 22px;
  text-align: center;
}
.ui-empty-title {
  display: block;
  color: #45536a;
  font-size: 14px;
  font-weight: 500;
  line-height: 20px;
  text-align: center;
}
/* max-width 让说明句在宽面板里也保持 2 行以内，不横跨整屏 */
.ui-empty-desc {
  display: block;
  max-width: 320px;
  margin-top: 4px;
  color: #647389;
  font-size: 12px;
  font-weight: 400;
  line-height: 18px;
  text-align: center;
}
.ui-empty-actions {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 12px;
}
/* 空态动作是「下一步建议」不是页面主 CTA，所以用浅蓝次按钮而不是实心主色：
 * 一屏只允许一个实心主按钮（§3.1 brand 用途约束）。 */
.ui-empty-action {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  height: 28px;
  padding: 0 12px;
  border: 1px solid #c9ddfb;
  border-radius: 8px;
  background-color: #e7f0ff;
  color: #1f5fd1;
  font-size: 13px;
  font-weight: 500;
  line-height: 16px;
  cursor: pointer;
}
.ui-empty-action:hover {
  background-color: #c9ddfb;
}
/* ============================================================
 * B2b 切换控件三分形（§3.5）+ C7 宽表 class 族（§3.4 / §4.4 U4-I2）
 *
 * 只加不删：`.admin-tab-pill` 261 处调用点原样保留作过渡别名，B4 才删。
 * 本段全部取值来自 scripts/design/tokens.json：
 *   字号 11/12/13/14/15/22/24/28、字重 400/500/600/700、圆角 4/6/8/12/16/999、
 *   z-index 10/20/30/40/100/101/120/121/130/131、阴影只有 shadow-1/2/3/brand 四条。
 *
 * ⚠️ 方案 §3.1 的 success-text 是 #15803d，不是 #047857；#047857 不在令牌集合里，
 * 写进来会被 check:styles 的 bare-hex 规则判成新增违规。本段没有成功态，这里只做登记。
 *
 * 键盘可达：`<view>/<text>/<button>` 在 uni-app x 的 H5 运行时都不是原生可聚焦元素
 *（证据见本文件 :focus-visible 那段注释：Button 渲染成 <uni-button> 且只挂 onClick）。
 * 所以本段的 :focus-visible 与上面那组一样，要等调用点在 #ifdef WEB 里补
 * tabindex="0" + role + @keydown 才会亮；样式先落好，届时只补属性。
 * ============================================================ */
/* ---- ① 状态页签：互斥切换「列表主体」，带计数（§3.5 第一行）----
 * 形态是**下划线**，与 ② 的药丸、③ 的分段一眼可辨 —— B2a 踩过一次坑：
 * 两颗像素级相同的药丸挨在一起、点击行为却相反（一个换列表、一个改查询条件）。
 *
 * 高度算术：容器 min-height 41 = 内容 40（页签高）+ 1px 底线，box-sizing: border-box。
 * 刻意**不用** `.ui-tab { margin-bottom: -1px }` 去让 2px 主色线盖住那条 1px 灰线：
 * 本容器是 overflow-x 滚动容器（横向滚动是 §3.5 明确要求的），
 * CSS Overflow 3 会把另一轴的 visible 一并算成 auto，负 margin 造出的 1px 纵向溢出
 * 会真的长出一根竖向滚动条。这里 2px 主色线压在 1px 灰线正上方（视觉 3px），
 * 换来的是「页签行永远不会莫名多一根滚动条」。
 * overflow-y: hidden 是同一件事的保险：显式写死后 overflow-x 不再被强制配对。
 * 容器不写固定 height —— 溢出时横向滚动条要往下长，写死 41 会把 40px 的页签裁掉。
 *
 * 激活态 500 → 600 会让该颗页签宽度跳几 px。uvue 没有可靠的 ::after + attr(data-*)
 * 占位手段（伪元素 content 还进不了无障碍树，见本文件 .ui-checkbox 那段），
 * 这里如实保留这一跳；它只在点击那一帧发生，不影响静止阅读。
 *
 * 用法：
 *   <view class="ui-tabs">
 *     <view class="ui-tab" :class="{ active: activeTab == tab.key }"
 *           v-for="tab in statusTabs" :key="tab.key" @click="switchTab(tab.key)">
 *       <text>{{ tab.label }}</text>
 *       <text class="ui-tab-count" :class="{ danger: tab.key == 'WARNING' }"
 *             v-if="tabCount(tab.key).length > 0">{{ tabCount(tab.key) }}</text>
 *     </view>
 *   </view>
 * 计数为空时整颗徽标不渲染（v-if），不要渲染成 "0" —— monitor 的 tabCountText()
 * 已经是「取不到就返回空串」的口径，照着接即可。 */
.ui-tabs {
  display: flex;
  flex-direction: row;
  align-items: flex-end;
  gap: 20px;
  min-height: 41px;
  margin-bottom: 16px;
  box-sizing: border-box;
  border-bottom: 1px solid #e8edf4;
  overflow-x: auto;
  overflow-y: hidden;
}
/* 未选中用 text-2 #45536a 而不是 text-3 #647389：页签行经常落在页面底色 #f6f8fb 上，
 * #647389 压在 #f6f8fb 上只有 4.47:1（相对亮度 0.1707 / 0.9370），差一点点不过 AA。
 * #45536a 在白底 10.36:1、在 #f6f8fb 上 9.73:1，两种底色都稳过。 */
.ui-tab {
  flex-shrink: 0;
  height: 40px;
  padding: 0;
  box-sizing: border-box;
  display: flex;
  flex-direction: row;
  align-items: center;
  border-bottom: 2px solid transparent;
  color: #45536a;
  font-size: 13px;
  font-weight: 500;
  line-height: 20px;
  white-space: nowrap;
  cursor: pointer;
  transition: color 0.12s cubic-bezier(0.2, 0, 0, 1), border-color 0.12s cubic-bezier(0.2, 0, 0, 1);
}
.ui-tab:hover {
  color: #1b263b;
}
/* 激活态文字用 text-1 而不是主色：§3.1 限定 brand 只给「每屏 1 个主按钮 / 当前导航项
 * 图标 / ≤1 张 hero 卡」，主色留给那 2px 底线即可。#1b263b on #ffffff = 17.85:1。 */
.ui-tab.active {
  color: #1b263b;
  font-weight: 600;
  border-bottom-color: #246beb;
}
/* 计数徽标：11px（PC 字号白名单里 11 就是给「表格内与侧栏徽标」的），贴页签右上。
 * align-self: flex-start + margin-top 8 让它落在标签首行的顶部，读起来像上标。
 * 文字色用 neutral-text #45536a 而不是 text-3 #647389：
 * #647389 压在徽标底 #f3f6fa 上只有 4.39:1（0.1707 / 0.9085），11px 小字必须 ≥4.5；
 * #45536a / #f3f6fa = 6.92:1（0.0886 / 0.9085），过 AA。 */
.ui-tab-count {
  align-self: flex-start;
  margin-top: 8px;
  margin-left: 4px;
  flex-shrink: 0;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  box-sizing: border-box;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  background-color: #f3f6fa;
  color: #45536a;
  font-size: 12px;
  font-weight: 500;
  line-height: 16px;
  text-align: center;
}
/* 预警页签的徽标是红的（§3.5 点名）。#b42318 / #fff0ee = 5.91:1（0.1123 / 0.9099）。
 * 用 danger-text 而不是 danger-solid #dc2626：后者压在 #fff0ee 上只有 4.4:1。 */
.ui-tab-count.danger {
  background-color: #fff0ee;
  color: #b42318;
}
/* ---- ② 筛选条件 chip：改的是查询条件，不换列表主体（§3.5 第二行）----
 * 药丸 999 + 选中带左侧 ✓。取值逐字沿用现网 .monitor-chip / .pw-chip
 *（monitor/index.uvue:3033 与 prewarning/list.uvue:841 那两份页面私有副本），
 * 迁移时只换类名不改观感。
 * ✓ 不是装饰：卡底那排 .admin-filter-chip 是「已选条件回执」（方角 6、只有 × 可点），
 * 两者常常只隔十几个像素，光靠底色区分时用户会去点回执那一颗，点了什么也不会发生。
 * 圆的能点、方的是回执 —— 这条区分不许再被拉近。
 *
 * 用法（单选与多选同形，多选就是允许多颗同时 active）：
 *   <view class="ui-chip" :class="{ active: datePresetKey == preset.key }"
 *         v-for="preset in datePresets" :key="preset.key" @click="pick(preset.key)">
 *     <text class="ui-chip-check" v-if="datePresetKey == preset.key">✓</text>
 *     <text class="ui-chip-label">{{ preset.label }}</text>
 *   </view>
 * 颜色显式写在 .ui-chip-label / .ui-chip-check 上而不是靠继承：
 * uvue 的 <text> 不保证继承父 view 的 color（monitor 的同名规则就是这个原因）。 */
.ui-chip {
  height: 28px;
  padding: 0 12px;
  box-sizing: border-box;
  display: flex;
  flex-direction: row;
  align-items: center;
  /* 只在有 ✓ 时才产生间距：未选中的 chip 只有一个子节点，gap 不生效 */
  gap: 4px;
  border: 1px solid #e8edf4;
  border-radius: 999px;
  background-color: #ffffff;
  color: #45536a;
  font-size: 12px;
  line-height: 16px;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color 0.12s cubic-bezier(0.2, 0, 0, 1), border-color 0.12s cubic-bezier(0.2, 0, 0, 1), color 0.12s cubic-bezier(0.2, 0, 0, 1);
}
.ui-chip:hover {
  border-color: #c9ddfb;
}
/* #1f5fd1 压在 #eff6ff 上 6.16:1（相对亮度 0.1067 / 0.9148），过 AA */
.ui-chip.active {
  border-color: #c9ddfb;
  background-color: #e7f0ff;
  color: #1f5fd1;
  font-weight: 600;
}
.ui-chip-label {
  color: #45536a;
  font-size: 12px;
  line-height: 16px;
}
.ui-chip.active .ui-chip-label {
  color: #1f5fd1;
}
.ui-chip-check {
  flex-shrink: 0;
  color: #1f5fd1;
  font-size: 12px;
  font-weight: 600;
  line-height: 16px;
}
/* chip 行：包一层，负责换行与间距。gap 8 与 .pw-chip-row 一致。 */
.ui-chip-row {
  display: flex;
  flex-direction: row;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
}
/* ---- ③ 视图切换分段控件：同一份数据换个呈现，不改查询也不换主体（§3.5 第三行）----
 * 外框 surface-2 + 圆角 6 的轨道，选中项白底 + shadow-1。
 * 高度算术：轨道 32（border-box，含 1px 描边）→ 内容高 30，选中块 28，上下各留 1px；
 * shadow-1 是 `0 1px 2px`，那 1px 缝正好让投影透出来，不会被轨道边缘吃掉。
 * 轨道必须带 1px 描边：#f3f6fa 压在白卡 #ffffff / 页面底 #f6f8fb 上都几乎看不见，
 * 没有描边时「这是一个分段控件」这件事就传达不出去。
 *
 * 选中态**不改字重**（只换底色 + 文字色 + 投影）：分段控件的格子是并排等宽读的，
 * 500 → 600 会让整条轨道宽度跳一下；下划线页签换行不换位，才允许加粗（见 ① 的注释）。
 *
 * 用法：
 *   <view class="ui-segment">
 *     <view class="ui-segment-item" :class="{ active: dimension == item.key }"
 *           v-for="item in dimensions" :key="item.key" @click="switchDimension(item.key)"
 *     >{{ item.label }}</view>
 *   </view> */
.ui-segment {
  display: inline-flex;
  flex-direction: row;
  align-items: center;
  height: 32px;
  padding: 0 4px;
  gap: 4px;
  box-sizing: border-box;
  border: 1px solid #e8edf4;
  border-radius: 8px;
  background-color: #f3f6fa;
}
/* #45536a 压在轨道底 #f3f6fa 上 7.24:1（相对亮度 0.0886 / 0.9536） */
.ui-segment-item {
  height: 28px;
  padding: 0 12px;
  box-sizing: border-box;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  border-radius: 4px;
  color: #45536a;
  font-size: 13px;
  font-weight: 500;
  line-height: 16px;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color 0.12s cubic-bezier(0.2, 0, 0, 1), color 0.12s cubic-bezier(0.2, 0, 0, 1);
}
.ui-segment-item:hover {
  color: #1b263b;
}
/* #1b263b 压在 #ffffff 上 17.85:1 */
.ui-segment-item.active {
  background-color: #ffffff;
  color: #1b263b;
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.06);
}
/* 三种切换控件的焦点环。与本文件上方那一组同款（outline 不参与盒模型，聚焦不顶大 1px）。
 * 今天不会亮：uni-app x 的 H5 运行时里 <view>/<text>/<button> 都拿不到焦点，
 * 需要调用点在 #ifdef WEB 挂载后补 tabindex/role 才生效。 */
.ui-tab:focus-visible,
.ui-chip:focus-visible,
.ui-segment-item:focus-visible {
  outline: 2px solid #246beb;
  outline-offset: 2px;
}
/* ---- C7 宽表（§3.4 C7 / §4.4 U4-I2）----
 * 本类**自己就是滚动视口**（overflow: auto + max-height），首列与表头都相对它 sticky。
 *
 * 为什么不按方案 §4.4 那句「横向容器改普通 view overflow-x:auto 使纵向滚动祖先回到
 * .admin-main」来做：那一步在 CSS 上不成立。CSS Overflow 3 规定 overflow-x/overflow-y
 * 里一个是 visible、另一个不是时，visible 计算值变 auto —— 只写 overflow-x: auto
 * 也会让这个盒子成为**两轴**的滚动容器，表头的 `top` 从此以它自己为参照，
 * 而它自身没有纵向溢出，于是页面往下滚时表头一动不动地跟着整块滚走，等于没吸顶。
 * 所以这里把纵向也收进来：给一个 max-height，让表格内部同时纵向滚动，
 * 表头与首列才真的冻得住。已核实前提的另一半成立 ——
 * .admin-shell{height:100vh;overflow:hidden}（uni.scss:422）
 * → .admin-main{height:100%;overflow-y:auto}（uni.scss:833）
 * → .admin-content{flex:1 0 auto}（uni.scss:1010）没有再套 overflow，
 * 本容器是 .admin-content 的后代，100vh 口径可用，不会和外层滚动打架。
 *
 * 不要给同一个节点同时挂 .admin-table：那一条带 overflow: hidden（uni.scss:1387），
 * 会把本类的滚动视口压成不可滚动，sticky 立刻失效。宽表页二选一。
 *
 * ⚠️ 行内「更多」弹层（.action-menu）在本容器里会被 overflow 裁掉 ——
 * 无论 overflow 写成 auto 还是 hidden，滚动容器都会裁剪绝对定位后代。
 * 宽表页的行动作请用行末直接按钮或 admin-dialog，不要用 .action-menu。
 *
 * 列宽由调用页的私有类给（**不要在页面 <style> 里定义 .admin- 前缀类**，
 * check:styles 的 page-admin-class 规则会拦）：
 *   <view class="admin-wide-table">
 *     <view class="admin-wide-table-row header fd-row">
 *       <text class="admin-wide-table-cell sticky">订单号</text>
 *       <text class="admin-wide-table-cell">状态</text>
 *       <text class="admin-wide-table-cell numeric">配送费</text>
 *     </view>
 *     <view class="admin-wide-table-row fd-row" :class="{ selected: currentId == row.id }"
 *           v-for="row in rows" :key="row.id">…</view>
 *   </view>
 *   页面私有：.fd-row { grid-template-columns: 200px 120px 100px …; min-width: 1280px; }
 * min-width 必须写在**所有**行共用的那一个私有类上（含表头行），漏掉表头就会错列。
 * 单元格自带 12px 横向内边距，行上不要再加 padding：首列 sticky 到 left:0 时
 * 行的横向 padding 会被它盖住，看着像整列出了框。 */
/* max-height 的 300px = 顶栏 52 + 内容区上下内边距 48 + 页头 70 + 筛选卡 ~80 + 分页条 48
 * 的量级估算，取整到 300。页头更高（带 KPI 卡）的页面在自己的私有类里覆盖 max-height 即可
 *（私有类与本类同为 (0,1,0)，页面样式在全局样式之后注入，直接覆盖得掉）。
 * 刻意不写 min-height：短表加地板会在 3 行数据下面留一大块空白，
 * 而「窗口高不足 300px」在 PC 后台不是真实场景（壳本身就是 height:100vh + 52 顶栏）。 */
.admin-wide-table {
  max-height: calc(100vh - 300px);
  overflow: auto;
  box-sizing: border-box;
  border: 1px solid #e8edf4;
  border-radius: 12px;
  background-color: #ffffff;
}
/* 短表 / 不希望表格内部再出一根纵向滚动条时用它：首列照冻，表头**不再吸顶**
 *（理由见上面那段：没有纵向溢出就没有可吸的参照）。别指望 .flow 还能吸表头。 */
.admin-wide-table.flow {
  max-height: none;
}
.admin-wide-table-row {
  display: grid;
  align-items: center;
  min-height: 44px;
  padding: 0;
  box-sizing: border-box;
  border-bottom: 1px solid #e8edf4;
  background-color: #ffffff;
}
/* 斑马纹取 odd：表头是容器的第 1 个子节点，body 首行落在第 2 个（偶数）上保持白底，
 * 从第 2 行开始隔行浅底。表头行本身也命中 odd，但它的底色与这里同值，不产生差异。 */
.admin-wide-table-row:nth-child(odd) {
  background-color: #f3f6fa;
}
/* hover 用 neutral-bg #f3f6fa 而不是 primary-soft：浅蓝是「选中」的语义（见下一条），
 * 悬停和选中不能同色，否则鼠标划过一整页都像被选中了。
 * #45536a / #f3f6fa = 9.45:1。 */
.admin-wide-table-row:hover {
  background-color: #f3f6fa;
}
/* 右侧面板打开时的当前行。#45536a / #eff6ff = 9.51:1。
 * :hover 那条同为 (0,2,0)，靠**书写顺序在后**取胜，别把这两条调换位置。 */
.admin-wide-table-row.selected,
.admin-wide-table-row.selected:hover {
  background-color: #e7f0ff;
}
/* 表头：sticky 到视口顶。z-index 取令牌 sticky-page 档 20；
 * 首列 sticky 单元格是 10，表头整行 20 > 10，所以左上角那颗（表头 ∩ 首列）
 * 天然压在 body 首列之上，不需要再单独给它抬层级（层级表里也没有 30 以下的富余档）。
 * 底线用 line-strong #cbd5e1：滚动时表头下方紧贴着的是数据行，#e8edf4 分不开。
 * :hover 显式还原，否则鼠标划过表头会跟着变色，像可点。 */
.admin-wide-table-row.header,
.admin-wide-table-row.header:hover {
  position: -webkit-sticky;
  position: sticky;
  top: 0;
  z-index: 20;
  min-height: 40px;
  background-color: #ffffff;
  border-bottom: 1px solid #cbd5e1;
}
.admin-wide-table-row.last {
  border-bottom-width: 0;
}
.admin-wide-table-cell {
  min-width: 0;
  padding: 0 12px;
  box-sizing: border-box;
  color: #45536a;
  font-size: 13px;
  font-weight: 500;
  line-height: 18px;
}
/* 表头是坐标轴标签不是标题：#647389 on #ffffff = 4.77:1，过 AA */
.admin-wide-table-row.header .admin-wide-table-cell {
  color: #647389;
  font-size: 12px;
  font-weight: 500;
  line-height: 16px;
}
/* 冻结首列。background-color: inherit 是关键：从行上继承当前底色，
 * 于是白底 / 斑马 / hover / selected / 表头五种状态各自的底色一次全对，
 * 不需要给每种状态再写一条首列覆盖（漏一条就会在横向滚动时透出下面的数据）。
 * 右描边常驻（不做「滚动了才出现」的阴影）：行底色是不透明的，
 * 方案里那套 background-attachment: local 的纯 CSS 滚动阴影会被行底色整个盖住，
 * 落不了地；一条常驻竖线同样说明「这一列是冻住的」，且零 JS。 */
.admin-wide-table-cell.sticky {
  position: -webkit-sticky;
  position: sticky;
  left: 0;
  z-index: 10;
  background-color: inherit;
  border-right: 1px solid #e8edf4;
}
/* 数值列：右对齐 + 等宽数字，让金额/单量上下对得齐（§3.4 C7）。
 * 表头单元格也要挂 .numeric，否则列名左、数字右，看着像错位。 */
.admin-wide-table-cell.numeric {
  text-align: right;
  font-variant-numeric: tabular-nums;
}
/* ---- 顺手的两个兜底 ---- */
/* 禁用态兜底。取值与移动端 uni.scss 的 .is-disabled 逐字一致（opacity .5），
 * PC 额外加 cursor —— 移动端没有指针。
 * 刻意不写 pointer-events: none：本类只管视觉，「点不动」由调用点的
 * :disabled 属性或 @click 里的早退保证（§4.1 U8 的写法是两者并存）；
 * 只加一个类就悄悄吞掉点击，会让「为什么点了没反应」变得无从排查。 */
.is-disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
/* 必填红星。#dc2626 / #ffffff = 4.83:1。
 * 用真实 <text> 节点而不是 ::after { content: '*' }：伪元素 content 进不了无障碍树。
 * 星号与标签之间的空格写在模板里（现网 .required-mark 26 处就是这个写法），
 * 本类不带 margin，免得和模板里的空格叠成两倍间距。
 * 用法：<text class="form-label">品牌名称 <text class="req">*</text></text> */
.req {
  color: #dc2626;
  font-weight: 500;
}
/* ============================================================
 * 壳内弹窗（U1-I8）：切换身份 / 修改密码
 *
 * 两个弹窗都挂在 admin-layout 里，用的是 components/admin-dialog（层级 120/121）。
 * 类名放在这里而不是 admin-layout 的 <style> 里，理由是 check:styles 的
 * page-admin-class 规则禁止页面/组件 <style> 定义 .admin- 前缀类——
 * 壳的类历来都住在 uni.scss，保持一处。
 * ============================================================ */
.admin-identity-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
/* 行内是「身份名 + 机构名」在左、「进入」在右 */
.admin-identity-row {
  min-height: 64px;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  cursor: default;
}
.admin-identity-copy {
  display: flex;
  flex: 1;
  min-width: 0;
  flex-direction: column;
}
.admin-identity-enter {
  flex-shrink: 0;
}
.admin-identity-empty {
  display: block;
  padding: 12px 0;
  color: #647389;
  font-size: 13px;
}
.admin-shell-form {
  display: flex;
  flex-direction: column;
}
.admin-shell-field-label {
  color: #45536a;
  font-size: 12px;
  font-weight: 500;
  margin-bottom: 4px;
}
/* 复用 .admin-filter-input 的外观与焦点环（uni.scss:363 已经把它列进了焦点环名单），
 * 这里只把筛选栏那套「窄而并排」的尺寸改成弹窗里的「整行」 */
.admin-shell-field {
  width: 100%;
  max-width: none;
  margin-bottom: 12px;
}
/* Shared control sizing belongs with the global admin class definitions. */
.analytics-range-pair .admin-filter-input {
  width: 0;
  min-width: 0;
  flex: 1;
}
.coupon-row .admin-table-cell {
  min-width: 0;
  overflow-wrap: anywhere;
}
/* R5 dense filters: fixed columns, top-aligned labels, independent action row.
 * Compound range fields participate in the same grid; help text never shifts
 * adjacent inputs. These rules are shared by analytics and management pages. */
.admin-filter-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 12px 16px;
  align-items: start;
  margin-top: 12px;
}
.admin-filter-cell {
  min-width: 0;
}
.admin-filter-span-2 {
  grid-column: span 2;
}
.admin-filter-date-range {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  gap: 8px;
}
.admin-filter-date-range > uni-picker {
  min-width: 0;
}
.admin-content .admin-filter-grid .ui-field {
  margin-bottom: 0;
  min-width: 0;
  gap: 8px;
}
.admin-content .admin-filter-grid .ui-field-label-row {
  min-height: 20px;
  margin-bottom: 0;
}
.admin-content .admin-filter-grid .ui-field-label {
  line-height: 20px;
}
.admin-content .admin-filter-grid .admin-filter-input,
.admin-content .admin-filter-grid .admin-filter-select,
.admin-content .admin-filter-grid .ui-ep-control {
  width: 100%;
  max-width: none;
  height: 36px;
  box-sizing: border-box;
}
.admin-content .admin-filter-grid .analytics-range-fields {
  display: contents;
}
.admin-content .admin-filter-grid .analytics-range-field {
  min-width: 0;
  max-width: none;
  gap: 8px;
}
.admin-content .admin-filter-grid .admin-filter-ranges-wide .analytics-range-field:not(:first-child) {
  grid-column: span 2;
}
.admin-content .admin-filter-grid .analytics-range-label {
  line-height: 20px;
  font-weight: 500;
}
.admin-content .admin-filter-grid .analytics-range-pair .admin-filter-input {
  width: 0;
  min-width: 0;
  flex: 1;
}
.admin-content .admin-filter-grid .ui-entity-picker {
  display: flex;
  flex-direction: column;
}
.admin-content .admin-filter-grid .ui-ep-control {
  order: 0;
}
.admin-content .admin-filter-grid .ui-ep-chips {
  order: 1;
  margin-top: 4px;
  margin-bottom: 0;
}
.admin-content .admin-filter-grid .ui-ep-hint {
  order: 2;
}
.admin-filter-actions-row {
  display: flex;
  flex-direction: row;
  justify-content: flex-end;
  align-items: center;
  gap: 8px;
  margin-top: 16px;
  padding-top: 12px;
  border-top: 1px solid #e8edf4;
}
@media (max-width: 760px) {
.admin-filter-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@media (max-width: 520px) {
.admin-filter-grid {
    grid-template-columns: minmax(0, 1fr);
}
.admin-filter-span-2 {
    grid-column: auto;
}
.admin-content .admin-filter-grid .admin-filter-ranges-wide .analytics-range-field:not(:first-child) {
    grid-column: auto;
}
}
.invoice-selectable-row .admin-table-cell {
  min-width: 0;
  overflow-wrap: anywhere;
}
/* Original Alibaba PuHuiTi 3.0 WOFF2 files, self-hosted. No synthetic weights.
   See static/fonts/README.md for provenance and delivery budget. */
@font-face {
  font-family: 'Alibaba PuHuiTi';
  src: url('/assets/AlibabaPuHuiTi-3-55-Regular-BzU-3NET.woff2') format('woff2');
  font-style: normal;
  font-weight: 400;
  font-display: swap;
}
@font-face {
  font-family: 'Alibaba PuHuiTi';
  src: url('/assets/AlibabaPuHuiTi-3-65-Medium-DQU-DIIV.woff2') format('woff2');
  font-style: normal;
  font-weight: 500;
  font-display: swap;
}
@font-face {
  font-family: 'Alibaba PuHuiTi';
  src: url('/assets/AlibabaPuHuiTi-3-75-SemiBold-CO0oeG9q.woff2') format('woff2');
  font-style: normal;
  font-weight: 600;
  font-display: swap;
}
html, body, uni-page-body, uni-button, uni-input, uni-textarea, select,
.uni-input-input, .uni-textarea-textarea {
  font-family: 'Alibaba PuHuiTi', 'PingFang SC', 'Microsoft YaHei', sans-serif;
  font-synthesis: none;
}
html, body, uni-page-body { font-size: 14px; line-height: 20px;
}
::selection { background: #dfeaff; color: #1b263b;
}
/* PC R5 application shell. Loaded after the legacy global rules by App.uvue.
 * Keep fixed overlays viewport-relative: no transform/filter on shell ancestors.
 * Navigation and page content scroll independently; account and search popovers
 * deliberately live outside the scrolling navigation container. */
.admin-shell {
  --shell-header-height: 100px;
  padding: 20px;
  gap: 16px;
  background-color: #edf4fb;
  background-image: radial-gradient(ellipse 75% 400px at 72% 0, #dcecff 0, transparent 78%), linear-gradient(120deg, #e6f1ff 0, #f1f7fc 44%, #edf4fb 100%);
}
.admin-sidebar {
  width: 224px;
  padding: 0 12px 12px;
  border: 0;
  border-radius: 20px;
  overflow: visible;
  background-color: #f8fbff;
  background-image: linear-gradient(150deg, #ffffff 0, #f5faff 100%);
}
.admin-brand {
  height: 100px;
  padding: 20px 4px;
  border-bottom: 0;
}
.admin-brand-mark {
  width: 44px;
  height: 44px;
  line-height: 44px;
  font-size: 28px;
  font-weight: 600;
  background-color: #246beb;
}
.admin-brand-copy { margin-left: 12px;
}
.admin-brand-title { font-size: 20px; font-weight: 600; color: #1b263b;
}
.admin-brand-sub { font-size: 12px; margin-top: 4px; color: #647389;
}
.admin-brand-mark.viewing { background-color: #94540f;
}
.admin-sidebar .shell-search {
  flex-shrink: 0;
  width: 100%;
  margin: 0 0 12px;
}
.admin-sidebar .admin-search {
  position: relative;
  z-index: 10;
  width: 100%;
  height: 40px;
  padding: 0 12px;
  box-sizing: border-box;
  border: 1px solid #e8edf4;
  border-radius: 8px;
  color: #45536a;
  background-color: #ffffff;
  font-size: 12px;
}
.admin-sidebar .shell-search-panel {
  top: calc(100% + 4px);
  left: 0;
  right: auto;
  margin-top: 0;
  max-height: min(320px, calc(100vh - 196px));
  border-color: #e8edf4;
  border-radius: 12px;
}
.admin-sidebar .shell-search-option.active { background-color: #e7f0ff;
}
.admin-sidebar .shell-search-name { color: #45536a;
}
.admin-sidebar .shell-search-option.active .shell-search-name { color: #1f5fd1;
}
.admin-sidebar .shell-search-group,
.admin-sidebar .shell-search-empty-text { color: #647389;
}
.admin-shell.shell-searching .admin-sidebar { z-index: 40;
}
.admin-shell.shell-searching .admin-sidebar.drawer { z-index: 101;
}
.admin-nav-block {
  padding-top: 0;
  padding-right: 4px;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: #c9ddfb transparent;
}
.admin-nav-item { min-height: 40px; color: #45536a;
}
.admin-nav-text { color: #45536a; font-weight: 500;
}
.admin-nav-group .admin-nav-text { font-weight: 600;
}
.admin-nav-item.active,
.admin-nav-child.active { background-color: #e7f0ff;
}
.admin-nav-item.active .admin-nav-text,
.admin-nav-child.active .admin-nav-child-text { color: #1f5fd1; font-weight: 600;
}
.admin-nav-item.active::before {
  content: '';
  position: absolute;
  left: 0;
  top: 12px;
  bottom: 12px;
  width: 3px;
  border-radius: 4px;
  background-color: #2878f5;
}
.admin-nav-child { min-height: 32px; border-left-color: #e8edf4;
}
.admin-nav-child-text { color: #45536a;
}
.admin-nav-item:hover,
.admin-nav-child:hover { background-color: #f3f6fa;
}
.admin-nav-item.active:hover,
.admin-nav-child.active:hover { background-color: #e7f0ff;
}
.shell-brand-foot {
  flex-shrink: 0;
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 8px;
  min-height: 64px;
  margin-top: 12px;
  padding: 12px 8px 0;
  border-top: 1px solid #e8edf4;
  box-sizing: border-box;
}
.shell-brand-foot-mark {
  width: 32px;
  height: 32px;
  line-height: 32px;
  border-radius: 8px;
  text-align: center;
  background-color: #e7f0ff;
  color: #526b8d;
  font-size: 20px;
  font-weight: 600;
}
.shell-brand-foot-copy { display: flex; flex-direction: column; gap: 4px;
}
.shell-brand-foot-title { color: #526b8d; font-size: 12px; font-weight: 600;
}
.shell-brand-foot-note { color: #647389; font-size: 12px;
}
.admin-main { background-color: transparent; scrollbar-width: thin;
}
.admin-content { padding: 0 0 24px;
}
.admin-topbar {
  height: var(--shell-header-height);
  min-height: var(--shell-header-height);
  padding: 0 20px 16px;
  gap: 16px;
  border: 0;
  border-radius: 16px 16px 0 0;
  background-color: #e6f1ff;
  align-items: center;
  flex-direction: row;
  /* uni-view clips overflow by default. The account menu opens below this
   * sticky header, so both ancestors between its anchor and main must allow it. */
  overflow: visible;
}
.shell-masthead-copy { min-width: 0; display: flex; flex-direction: column; gap: 12px;
}
.shell-masthead-title {
  position: relative;
  align-self: flex-start;
  color: #1f5fd1;
  font-size: 24px;
  line-height: 32px;
  font-weight: 600;
  letter-spacing: 2px;
}
.shell-masthead-title::after {
  content: '';
  position: absolute;
  height: 2px;
  left: 0;
  bottom: -4px;
  width: 100%;
  background-image: linear-gradient(90deg, #2878f5 0, transparent 100%);
}
.admin-topbar-lead { gap: 8px;
}
.admin-topbar-lead .admin-nav-toggle { width: 24px; height: 24px;
}
.admin-breadcrumb { min-width: 0; font-size: 12px;
}
.admin-breadcrumb-group { color: #647389;
}
.admin-breadcrumb-current { color: #45536a;
}
.admin-top-actions { flex-shrink: 0; width: auto; gap: 12px; overflow: visible;
}
.admin-user-entry { margin: 0; overflow: visible; z-index: 20;
}
.admin-user-trigger {
  min-height: 60px;
  min-width: 184px;
  max-width: 272px;
  padding: 8px 16px;
  border: 0;
  border-radius: 16px;
  background-color: #f8fbff;
}
.admin-user-trigger:hover { background-color: #ffffff;
}
.admin-user-avatar {
  width: 36px;
  height: 36px;
  background-color: #1b263b;
  color: #ffffff;
  border: 0;
  font-weight: 600;
}
.admin-user-name,
.admin-user-popover-name { color: #1b263b; font-weight: 600;
}
.admin-user-role { color: #45536a; font-size: 12px;
}
.admin-user-org { color: #647389; font-size: 12px;
}
.admin-user-popover {
  top: calc(100% + 8px);
  bottom: auto;
  width: 256px;
  max-height: calc(100vh - 132px);
  overflow-y: auto;
  padding: 16px;
  border-color: #e8edf4;
  border-radius: 12px;
}
.admin-user-popover-mobile { font-size: 12px;
}
.admin-topbar.drill {
  background-color: #fff3e1;
  border-bottom: 1px solid #fde68a;
}
.admin-topbar.drill .shell-masthead-title { color: #94540f;
}
.admin-topbar.drill .shell-masthead-title::after { background-color: #94540f; background-image: none;
}
.admin-drill-exit { flex-shrink: 0;
}
.admin-sidebar.rail { width: 64px; padding: 0 8px 12px;
}
.admin-sidebar.rail .admin-brand { height: 100px; justify-content: center; padding: 20px 0;
}
.admin-sidebar.rail .admin-brand-mark { width: 40px; height: 40px; line-height: 40px;
}
.admin-sidebar.rail .shell-search { display: none;
}
.admin-sidebar.rail .shell-brand-foot { padding: 12px 0 0; justify-content: center;
}
.admin-sidebar.rail-open { top: 20px; bottom: 20px; left: 20px; width: 224px;
}
@media screen and (max-width: 1280px) {
.admin-shell { padding: 16px; gap: 12px;
}
.admin-content { padding: 0 0 20px;
}
.admin-topbar { padding-left: 16px; padding-right: 16px;
}
.admin-sidebar.rail-open { top: 16px; bottom: 16px; left: 16px;
}
}
@media screen and (max-width: 1000px) {
.admin-shell { padding: 12px;
}
.admin-topbar { gap: 12px; padding: 8px 12px 16px;
}
.admin-top-actions { width: auto;
}
.admin-content { padding: 0 0 16px;
}
.admin-sidebar.drawer {
    top: 12px;
    bottom: 12px;
    left: 12px;
    width: 240px;
    padding: 0 12px 12px;
}
.admin-sidebar.drawer .admin-brand { padding-right: 0;
}
.admin-sidebar.drawer .admin-brand-title { font-size: 18px;
}
.admin-sidebar.drawer .shell-search-panel { width: 100%;
}
.admin-user-trigger { min-width: 168px; max-width: 224px; padding: 8px 12px;
}
.shell-masthead-title { font-size: 20px; line-height: 28px; letter-spacing: 0;
}
}
@media screen and (max-width: 640px) {
.admin-shell { --shell-header-height: 168px; padding: 8px;
}
.admin-topbar { flex-direction: column; align-items: stretch; gap: 12px; padding: 12px;
}
.shell-masthead-copy { gap: 4px;
}
.shell-masthead-title { font-size: 18px; line-height: 24px;
}
.shell-masthead-title::after { display: none;
}
.admin-top-actions { justify-content: flex-end;
}
.admin-user-trigger { min-height: 60px; min-width: 168px; max-width: 224px;
}
.admin-user-popover { max-height: calc(100vh - 196px);
}
}
