/* 感知 / 互动：使用 CSS3DSprite 嵌入粒子场景。
   位置随三维相机变化，保留温和的透视缩放；参数位于 smart_scene_config.js / perceptionLayout。 */
html.viewer_page .smart_perception {
    --perception-unit: 1vh;
    --perception-line-thickness: .85; /* 设计坐标线宽；JS 与卡片、文字一起按视窗比例缩放。 */
    --perception-card-deep: #02050B99; /* 半透明黑色基底；文字和图标保持原有亮度。 */
    --perception-card-blue: #005EFF; /* 饱和蓝色渐变。 */
    --perception-card-cyan: #32C7FF; /* 流光与内圈高光。 */
    /* 与 WebGL 画布使用同一定位容器，浏览器工具栏改变可视区域时一起移动。 */
    position: absolute;
    top: 0; right: 0; bottom: 0; left: 0; inset: 0;
    z-index: 65;
    color: #E5F1FF;
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
}
@supports (height: 1svh) {
    html.viewer_page .smart_perception { --perception-unit: 1vh; --perception-unit: 1svh; }
}
html.viewer_page .smart_perception, html.viewer_page .smart_perception * { box-sizing: border-box; }
html.viewer_page .smart_perception.is-visible { visibility: visible; }
html.viewer_page .smart_perception[inert] * { pointer-events: none !important; }
html.viewer_page .perception_stage { position: absolute; top: 0; right: auto; bottom: auto; left: 0; inset: 0 auto auto 0; pointer-events: auto; touch-action: none; }
html.viewer_page .perception_heading {
    position: absolute;
    z-index: 3;
    top: calc(var(--perception-unit) * 11);
    top: calc(var(--perception-unit) * 11 + env(safe-area-inset-top, 0rem));
    left: 50%;
    width: 88%; width: min(43rem, 88%);
    transform: translateX(-50%);
    text-align: center;
    text-shadow: 0 .12rem .9rem #000000;
}
html.viewer_page .perception_heading h2 { margin: 0; color: #F1F7FF; font-size: calc(var(--perception-unit) * 3.2);  font-weight: 500; line-height: 1.4; letter-spacing: .12em; }
@supports (width: clamp(1vh, 2vh, 3vh)) {
    html.viewer_page .perception_heading h2 { font-size: clamp(1.3rem, calc(var(--perception-unit) * 3.2), 2.2rem); }
}

html.viewer_page .perception_heading p { margin: .65em 0 0; color: #AFC7DE; font-size: calc(var(--perception-unit) * 1.65);  line-height: 1.7; letter-spacing: .06em; }
@supports (width: clamp(1vh, 2vh, 3vh)) {
    html.viewer_page .perception_heading p { font-size: clamp(.75rem, calc(var(--perception-unit) * 1.65), .98rem); }
}


/* 以下 rem 为 CSS3D 内部设计坐标，整体会由 JS 按实际画布宽高同比投影。
   圆形、图标、标题和说明字号一起缩放，屏幕上没有固定 rem 的大小上下限。
   保留当前渐变与流光边缘（参考用户提供的 Uiverse / MuhammadHasann 样式）。 */
html.viewer_page .perception_node { position: absolute; width: 18rem; height: 18rem; overflow: visible; pointer-events: none; }
/* 说明沿用卡片投影、尺寸和淡入淡出，显示层始终高于通讯光点及文字。 */
html.viewer_page .perception_description_layer { position: absolute; top: 0; right: 0; bottom: 0; left: 0; z-index: 1; pointer-events: none; }
html.viewer_page .perception_description_anchor { position: absolute; left: 0; top: 0; width: 18rem; height: 18rem; transform-origin: 0 0; pointer-events: none; }
html.viewer_page .perception_description { position: absolute; left: -30%; top: 100%; width: 160%; padding-top: .85rem; pointer-events: none; }
html.viewer_page .perception_card {
    position: relative; isolation: isolate; overflow: hidden;
    width: 18rem; min-height: 18rem; max-height: 18rem; aspect-ratio: 1; padding: 1.6rem; margin: 0;
    display: flex; align-items: stretch;
    border: 0; border-radius: 50%; outline: none;
    background: transparent; color: #EDF6FF;
    font-family: inherit; text-align: center; cursor: pointer; pointer-events: auto;
    box-shadow: 0 .7rem 2rem #00000060, 0 0 1.5rem #005EFF33;
    -webkit-appearance: none; appearance: none; -webkit-tap-highlight-color: transparent;
    transition: box-shadow 200ms ease;
}
html.viewer_page .perception_card_border { position: absolute; z-index: 0; top: 0; right: 0; bottom: 0; left: 0; inset: 0; overflow: hidden; border-radius: inherit; pointer-events: none; background: linear-gradient(145deg, #32B5FF40, #0054DA26); }
html.viewer_page .perception_card_border::before {
    content: ''; position: absolute; left: -50%; top: -50%; width: 200%; height: 200%;
    background: conic-gradient(from 0deg, #0088FF00 0deg, #0088FF00 245deg, var(--perception-card-blue) 285deg, var(--perception-card-cyan) 310deg, #C9F4FF 320deg, #0088FF00 340deg);
    opacity: .4; animation: perception-border 8s linear infinite; animation-delay: var(--card-border-phase, 0s); transition: opacity 240ms ease;
}
html.viewer_page .perception_card_surface {
    position: absolute; z-index: 1; top: .1rem; right: .1rem; bottom: .1rem; left: .1rem; inset: .1rem; border-radius: 50%; pointer-events: none;
    background-color: var(--perception-card-deep);
    background-image: radial-gradient(ellipse at 65% 12%, #000000B3 0%, #00000066 28%, #00000000 66%), radial-gradient(at 12% 100%, #005EFFB3 0%, #005EFF00 67%), radial-gradient(at 84% 100%, #0D8AFF80 0%, #0D8AFF00 65%);
    box-shadow: inset 0 .15rem .7rem #70D5FF1F;
}
html.viewer_page .perception_card_surface::before { content: ''; position: absolute; top: 0; right: 0; bottom: 0; left: 0; inset: 0; border-radius: inherit; pointer-events: none; background: radial-gradient(ellipse at 45% 12%, #71D6FF38, #2379FF12 52%, #005EFF00 82%); opacity: 0; transition: opacity 240ms ease; }
html.viewer_page .perception_card_surface::after { content: ''; position: absolute; top: .7rem; right: .7rem; bottom: .7rem; left: .7rem; inset: .7rem; border: .06rem solid #2D9DFF4D; border-radius: 50%; transition: border-color 240ms ease; }
/* 只移动内部内容，CSS3DSprite 持有的外层 transform / 圆周命中范围保持稳定。 */
html.viewer_page .perception_card_content { position: relative; z-index: 2; width: 100%; display: flex; flex-direction: column; justify-content: center; align-items: center; gap: .3rem; transition: transform 240ms cubic-bezier(.22, 1, .36, 1); }
html.viewer_page .perception_card_heading { display: flex; flex-direction: column; align-items: center; gap: .6rem; }
html.viewer_page .perception_card_titles { min-width: 0; display: flex; flex-direction: column; align-items: center; gap: .25rem; }
html.viewer_page .perception_visual { position: relative; flex: none; display: block; width: 6.5rem; height: 6.5rem; border: 0; border-radius: 50%; background: radial-gradient(circle, #1689FF44, #1689FF00 72%); }
html.viewer_page .perception_art { position: absolute; top: 3%; right: 3%; bottom: 3%; left: 3%; inset: 3%; display: block; color: #D9F4FF; transition: color 240ms ease; }
html.viewer_page .perception_art svg { display: block; width: 100%; height: 100%; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
html.viewer_page .perception_user_side { opacity: .5; }
html.viewer_page .perception_device_flow, html.viewer_page .perception_factory_signal { stroke: var(--perception-card-cyan); stroke-width: 2.5; }
html.viewer_page .perception_node_name { display: block; font-size: 2.1rem; font-weight: 500; line-height: 1.2; letter-spacing: .08em; color: #F2FAFF; }
html.viewer_page .perception_node_subtitle { display: block; font-size: 1.6rem; line-height: 1.3; color: #A9D5FF; }
/* 说明在投影层中跟随圆形，保持同样的缩放；关闭时延后 visibility，让淡出完整播放。 */
html.viewer_page .perception_node_description {
    width: 100%; margin: 0; padding: 1rem 1.15rem;
    border: .06rem solid #2794FF66; border-radius: .6rem;
    background: linear-gradient(145deg, #071D3CF5, #02050BF5 75%); box-shadow: 0 .6rem 1.5rem #00000066, inset 0 .06rem 0 #7CCAFF26;
    color: #D5EAFF; font-size: 2.1rem; line-height: 1.6; text-align: center; overflow-wrap: anywhere;
    opacity: 0; visibility: hidden; transform: translateY(.45rem); pointer-events: none;
    transition: opacity 260ms ease, transform 260ms ease, visibility 0s linear 260ms;
}
html.viewer_page .perception_description.is-selected .perception_node_description { opacity: 1; visibility: visible; transform: translateY(0); transition-delay: 0s; }
html.viewer_page .perception_card.is-selected { box-shadow: 0 0 0 .1rem #78D9FF, 0 0 2rem #006CFF80, inset 0 0 1.6rem #167BFF66; }
html.viewer_page .perception_card:focus-visible { box-shadow: 0 0 0 .16rem #D5F7FF, 0 0 1.8rem #006CFF80; }

/* 中心通讯模块只用光点和信号环，不创建模型。中心位置就是相机聚焦点。 */
html.viewer_page .perception_hub { position: absolute; width: 8rem; height: 8rem; }
html.viewer_page .perception_hub_core { position: absolute; top: 40%; right: 40%; bottom: 40%; left: 40%; inset: 40%; border-radius: 50%; background: #E9F6FF; box-shadow: 0 0 1.1rem #78BBFF, 0 0 2.6rem rgba(var(--perception-rgb, 34, 115, 215), .65); }
html.viewer_page .perception_hub_ring { position: absolute; top: 8%; right: 8%; bottom: 8%; left: 8%; inset: 8%; border: .12rem solid rgba(var(--perception-rgb, 34, 115, 215), .65); border-radius: 50%; animation: perception-broadcast 3.2s ease-out infinite; }
html.viewer_page .perception_hub_ring_second { animation-delay: -1.6s; }
/* 文字精灵固定在光点的三维中心；内部文字只使用屏幕像素偏移，保持原生字号及真实深度。 */
html.viewer_page .perception_hub_label { position: absolute; pointer-events: none; } /* JS 按当前字号同步真实宽高，避免零面积合成层裁掉文字。 */
html.viewer_page .perception_hub_name { display: block; color: #EEF7FF; text-align: center; white-space: nowrap; font-size: .95rem; font-weight: 500; line-height: 1.5; letter-spacing: .1em; text-shadow: 0 .05em .08em #000000B3; pointer-events: none; }
html.viewer_page .perception_hub_label .perception_hub_name { position: absolute; left: 0; top: 0; width: max-content; }

/* 线段使用独立 CSS3D 平面，朝向观察者保留可见厚度；卡片、光点与文字按真实深度共同排序。 */
html.viewer_page .perception_link { width: 40rem; height: 1rem; --perception-line-fade: 25%; }
html.viewer_page .perception_connection { position: absolute; top: 0; right: 0; bottom: 0; left: 0; inset: 0; opacity: 1; pointer-events: none; }
html.viewer_page .perception_connection > span { position: absolute; left: 0; top: 50%; width: 100%; border-radius: 999rem; transform: translateY(-50%); pointer-events: none; }
html.viewer_page .perception_path_halo { height: .6rem; background: linear-gradient(to right, #2273D700, rgba(var(--perception-rgb, 34, 115, 215), .25) var(--perception-line-fade), rgba(var(--perception-rgb, 34, 115, 215), .25) calc(100% - var(--perception-line-fade)), #2273D700); }
html.viewer_page .perception_path_base { height: .13rem; background: linear-gradient(to right, #6DB9FF00, #6DB9FF var(--perception-line-fade), #6DB9FF calc(100% - var(--perception-line-fade)), #6DB9FF00); }
html.viewer_page .perception_path_forward { height: .22rem; background: linear-gradient(to right, #E4F5FF00, #E4F5FF, #E4F5FF00); }
html.viewer_page .perception_path_backward { height: .16rem; background: linear-gradient(to right, #2273D700, var(--theme-accent, #2273D7), #2273D700); }

html.viewer_page .smart_perception *, html.viewer_page .smart_perception .perception_card_border::before { animation-play-state: paused !important; }
html.viewer_page .smart_perception.is-live *, html.viewer_page .smart_perception.is-live .perception_card_border::before { animation-play-state: running !important; }
@keyframes perception-border { to { transform: rotate(360deg); } }
@media (hover: hover) and (pointer: fine) {
/* 简单选择器回退；与下方 :is() 保持同一效果。 */
html.viewer_page .perception_card:hover:not(:disabled):not(.is-selected),
html.viewer_page .perception_card.is-hovered:not(:disabled):not(.is-selected) { box-shadow: 0 0 0 .08rem #72CDFF99, 0 .7rem 2rem #00000060, 0 0 2rem #006CFF70, inset 0 0 1.6rem #167BFF66; }

    html.viewer_page .perception_card:is(:hover, .is-hovered):not(:disabled):not(.is-selected) { box-shadow: 0 0 0 .08rem #72CDFF99, 0 .7rem 2rem #00000060, 0 0 2rem #006CFF70, inset 0 0 1.6rem #167BFF66; }
/* 简单选择器回退；与下方 :is() 保持同一效果。 */
html.viewer_page .perception_card:hover:not(:disabled) .perception_card_surface::before,
html.viewer_page .perception_card.is-hovered:not(:disabled) .perception_card_surface::before { opacity: 1; }

    html.viewer_page .perception_card:is(:hover, .is-hovered):not(:disabled) .perception_card_surface::before { opacity: 1; }
/* 简单选择器回退；与下方 :is() 保持同一效果。 */
html.viewer_page .perception_card:hover:not(:disabled) .perception_card_surface::after,
html.viewer_page .perception_card.is-hovered:not(:disabled) .perception_card_surface::after { border-color: #79D3FFB3; }

    html.viewer_page .perception_card:is(:hover, .is-hovered):not(:disabled) .perception_card_surface::after { border-color: #79D3FFB3; }
/* 简单选择器回退；与下方 :is() 保持同一效果。 */
html.viewer_page .perception_card:hover:not(:disabled) .perception_card_border::before,
html.viewer_page .perception_card.is-hovered:not(:disabled) .perception_card_border::before { opacity: .78; }

    html.viewer_page .perception_card:is(:hover, .is-hovered):not(:disabled) .perception_card_border::before { opacity: .78; }
/* 简单选择器回退；与下方 :is() 保持同一效果。 */
html.viewer_page .perception_card:hover:not(:disabled) .perception_card_content,
html.viewer_page .perception_card.is-hovered:not(:disabled) .perception_card_content { transform: translateY(-.18rem); }

    html.viewer_page .perception_card:is(:hover, .is-hovered):not(:disabled) .perception_card_content { transform: translateY(-.18rem); }
/* 简单选择器回退；与下方 :is() 保持同一效果。 */
html.viewer_page .perception_card:hover:not(:disabled) .perception_art,
html.viewer_page .perception_card.is-hovered:not(:disabled) .perception_art { color: #F4FCFF; }

    html.viewer_page .perception_card:is(:hover, .is-hovered):not(:disabled) .perception_art { color: #F4FCFF; }
}
html.viewer_page .perception_card:focus-visible .perception_card_surface::before { opacity: 1; }
@media (max-width: 62.25em), (max-width: 75em) and (max-aspect-ratio: 4/3), (max-width: 75em) and (pointer: coarse) {
    html.viewer_page .perception_heading { top: calc(var(--perception-unit) * 10); top: calc(var(--perception-unit) * 10 + env(safe-area-inset-top, 0rem)); width: 90%; }
    html.viewer_page .perception_heading h2 { font-size: calc(var(--perception-unit) * 2.9);  }
@supports (width: clamp(1vh, 2vh, 3vh)) {
    html.viewer_page .perception_heading h2 { font-size: clamp(1.15rem, calc(var(--perception-unit) * 2.9), 1.75rem); }
}

    html.viewer_page .perception_heading p { font-size: calc(var(--perception-unit) * 1.55);  letter-spacing: .02em; }
@supports (width: clamp(1vh, 2vh, 3vh)) {
    html.viewer_page .perception_heading p { font-size: clamp(.75rem, calc(var(--perception-unit) * 1.55), .9rem); }
}

}
@media (max-height: 30em) and (orientation: landscape) {
    html.viewer_page .perception_heading { top: calc(var(--perception-unit) * 8); }
    html.viewer_page .perception_heading h2 { font-size: 1.1rem; }
    html.viewer_page .perception_heading p { margin-top: .2em; font-size: .75rem; }
}
@media (prefers-reduced-motion: reduce) {
    html.viewer_page .smart_perception *, html.viewer_page .smart_perception .perception_card_border::before { animation: none !important; transition-duration: 100ms !important; }
}

@keyframes perception-broadcast { 0% { transform: scale(.4); opacity: .75; } 100% { transform: scale(1.4); opacity: 0; } }
