/* app.css - small utilities on top of Tailwind */
.fade-in { animation: fadeIn .18s ease-out; }
@keyframes fadeIn { from {opacity:0; transform: translateY(6px);} to {opacity:1; transform: translateY(0);} }

@media (prefers-reduced-motion: reduce){
  .fade-in{ animation: none; }
}

.modal-backdrop { backdrop-filter: blur(10px); }
.modal-scroll{ -webkit-overflow-scrolling: touch; }


.badge-online { background: rgba(34,197,94,.15); border: 1px solid rgba(34,197,94,.35); color: rgb(187,247,208); }
.badge-offline { background: rgba(239,68,68,.12); border: 1px solid rgba(239,68,68,.35); color: rgb(254,202,202); }

/* iPhone dialpad-ish */
.dialpad { width: 320px; max-width: 100%; }
.dial-display { letter-spacing: .12em; height: 2.2em; min-height: 2.2em; line-height: 1.2; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; display: flex; align-items: center; justify-content: center; font-variant-numeric: tabular-nums; }
.dial-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; justify-items: center; }
.dial-btn {
  width: 84px;
  height: 84px;
  border-radius: 9999px;
  background: rgba(255,255,255,.06);
  border: 1px solid rgba(255,255,255,.10);
}
@media (max-width: 420px){
  .dial-btn{ width: 76px; height: 76px; }
}
.dial-btn:hover { background: rgba(255,255,255,.10); }
.dial-btn:active { transform: scale(.98); }
.terminal { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; }


/* 隐藏所有滚动条（仍可滚动） */
*{scrollbar-width:none; -ms-overflow-style:none;}
*::-webkit-scrollbar{width:0;height:0;display:none;}
/* ---------- Banner / Ad slot (recommended 21:4, keep full image visible) ---------- */
.banner-slot{
  position: relative;
  width: 100%;
  aspect-ratio: 21 / 4;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  background: rgba(15,23,42,.35);
}

.banner-slot--fill{
  aspect-ratio: auto;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}
.banner-box{
  margin: auto;
  /* Size is computed in JS to fit a 21:4 rectangle inside the slot */
  width: 100%;
  aspect-ratio: 21 / 4;
  max-width: 100%;
  max-height: 100%;
  overflow: hidden;
}
.banner-slot__img{
  width: 100%;
  height: 100%;
  object-fit: contain; /* key: don't crop, always show full */
  object-position: center;
  transform: translateZ(0);
  transition: transform .2s ease, filter .2s ease;
}
.banner-slot:hover .banner-slot__img{
  transform: translateZ(0) scale(1.01);
  filter: saturate(1.05) contrast(1.02);
}

.banner-slot__bg{
  position:absolute;
  inset:0;
  background-size:cover;
  background-position:center;
  filter: blur(18px) saturate(1.08);
  transform: scale(1.12);
  opacity: .38;
  pointer-events:none;
}
.banner-box{
  margin: auto; position: relative; z-index: 1; }
.banner-slot::after{
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(60% 80% at 50% 10%, rgba(255,255,255,.10), transparent 60%),
    radial-gradient(80% 90% at 50% 110%, rgba(0,0,0,.35), transparent 55%);
}

@supports not (aspect-ratio: 1 / 1){
  .banner-slot{
    height: 0;
    padding-top: 19.1%; /* 21:4 fallback */
  }
}


/* ---------- Word cloud slot (16:9) ---------- */
.wordcloud-slot{
  width: 100%;
  aspect-ratio: 16 / 9;
  display: block;
}
@supports not (aspect-ratio: 16 / 9){
  .wordcloud-slot::before{
    content:"";
    display:block;
    padding-top: 19.1%; /* 21:4 fallback */
  }
}
/* ---------- Word cloud (canvas, screenshot-like) ---------- */
.wc2d{
  position: relative;
  background: transparent;
}

/* Make canvas fill the 16:9 slot */
.wc2d .wc-canvas{
  width: 100%;
  height: 100%;
  display: block;
}

/* Subtle, non-interactive ambience (keeps it "alive" without changing layout) */
.wc2d::before{
  content:"";
  position:absolute;
  inset:0;
  pointer-events:none;
  opacity:.25;
  background:
    radial-gradient(50% 60% at 30% 30%, rgba(99,102,241,.10), transparent 60%),
    radial-gradient(50% 60% at 70% 70%, rgba(236,72,153,.08), transparent 60%);
  animation: wcBg 10s ease-in-out infinite alternate;
  mix-blend-mode: screen;
}
@keyframes wcBg{
  from { transform: translate3d(-1.5%, -1%, 0); opacity:.18; }
  to   { transform: translate3d(1.5%, 1%, 0); opacity:.30; }
}

/* Keep a faint vignette for readability */
.wc2d::after{
  content:"";
  position:absolute;
  inset:0;
  pointer-events:none;
  background: radial-gradient(70% 90% at 50% 50%, transparent 55%, rgba(0,0,0,.05) 100%);
  opacity:.55;
}


@media (prefers-reduced-motion: reduce){
  .wc2d::before{ animation: none !important; }
  .banner-slot__img{ transition: none !important; }
}



/* ---------- Select dropdown (dark options) ---------- */
/* Helps prevent native option list from showing a white background in dark UI. */
html{ color-scheme: dark; }
select{
  color-scheme: dark;
}
select option{
  background-color: #0b1220; /* deep slate */
  color: rgb(226,232,240);  /* slate-200 */
}


/* Device list multi-select: click to toggle highlight (no checkboxes) */
.devSelectable { cursor: pointer; }
tr.devSelectable.is-selected{
  background: rgba(16,185,129,.14) !important;
  box-shadow: inset 0 0 0 1px rgba(16,185,129,.35);
}
tr.devSelectable.is-selected:hover{ background: rgba(16,185,129,.18) !important; }

div.devSelectable.is-selected{
  background: rgba(16,185,129,.10) !important;
  border-color: rgba(16,185,129,.45) !important;
  box-shadow: inset 0 0 0 1px rgba(16,185,129,.30);
}


/* ---------- App Shell (fixed frame, scroll inside #content) ---------- */
html.app-shell, body.app-shell{ height:100%; overflow:hidden; overscroll-behavior:none; }
body.app-shell{ overflow:hidden; }
html.app-shell{ overflow-x:hidden; }
body.app-shell{ overflow-x:hidden; }
#app{ height:100%; }


/* ---------- Scroll helpers (iOS friendly) ---------- */
.scroll-y{
  overflow-y:auto;
  overflow-x:hidden;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  touch-action: pan-y;
}
.scroll-x{
  overflow-x:auto;
  overflow-y:hidden;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  touch-action: pan-x;
}

/* Flex children should be allowed to shrink (prevents mobile horizontal overflow) */
.flex > *{ min-width: 0; }

/* ---------- Dashboard keyword cloud: square & not too large ---------- */
.kw-square{
  width: 100%;
  max-width: 600px;
  aspect-ratio: 1 / 1;
}
@media (max-width: 480px){
  .kw-square{ max-width: 360px; }
}

/* Safety: media should not cause horizontal overflow */
img, canvas, svg, video{ max-width:100%; }
