/* ==========================================================
   I-05 / PROTOCOL 01 — OPEN PATH
   実験格子・節点体・状態パネル
   ========================================================== */

/* ---------- 観察窓を前面化（自己照明の区画） ---------- */
#obs.live{z-index:45;pointer-events:none}
#obs.live .obs-sheen{opacity:.55}

/* 観察窓ガラスの結露・汚れ（素材の左ペインを窓幅へ伸ばして使用） */
.obs-glass-ov{
  position:absolute;inset:-2% -3%;
  z-index:6;pointer-events:none;
  background-image:url("../assets/images/glass_condensation.webp");
  background-size:334% 104%;      /* 画像左端〜30% ＝ 左ペインだけを使う */
  background-position:0 0;
  background-repeat:no-repeat;
  opacity:0;
  mix-blend-mode:screen;
  transition:opacity 2.6s ease, filter 1.6s ease;
  /* 素材は明るいので、ガラスの霞として乗る強さまで落とす */
  filter:brightness(.26) saturate(.45) hue-rotate(150deg) contrast(1.12);
  /* 中央だけ拭われ、縁へ向かって結露が濃くなる
     （画像URLではなくグラデーションのマスクなので file:// でも読み込めない問題は起きない） */
  -webkit-mask-image:radial-gradient(58% 52% at 50% 46%, rgba(0,0,0,0) 0%, rgba(0,0,0,.35) 52%, rgba(0,0,0,.85) 78%, #000 100%);
  mask-image:radial-gradient(58% 52% at 50% 46%, rgba(0,0,0,0) 0%, rgba(0,0,0,.35) 52%, rgba(0,0,0,.85) 78%, #000 100%);
}
.obs-glass-ov.on{opacity:.52}
.obs-glass-ov.breathe{animation:glassBreathe 3.2s ease-in-out 1}
@keyframes glassBreathe{
  0%{opacity:.52;transform:scale(1)}
  38%{opacity:.66;transform:scale(1.014)}
  100%{opacity:.52;transform:scale(1)}
}

/* ---------- 格子ビュー（端末画面の中の映像） ---------- */
#gridView{
  position:absolute;inset:0;z-index:1;
  opacity:0;transition:opacity 2.4s ease;
  perspective:520px;
}
/* 格子を出している間は端末の文字面を空ける */
#screen.feed .scr-inner{opacity:0;transition:opacity 1.2s ease;pointer-events:none}
#screen.feed .scr-crt{z-index:4}
#gridView.on{opacity:1}
#gridView .tilt{
  position:absolute;inset:0;
  transform:rotateX(16deg) rotateZ(-1.6deg) scale(1.0);
  transform-origin:50% 46%;
  filter:blur(.15px) saturate(.95) contrast(1.12);   /* 監視カメラの映像 */
}
/* 実験基盤は絶対配置なので、SVGも配置して重なり順を明示する */
#gridView svg{position:absolute;inset:0;width:100%;height:100%;display:block;z-index:1}

/* 区画の空気: 基盤の奥行きと監視光 */
#gridView .gv-air{
  position:absolute;inset:0;pointer-events:none;
  background:
    radial-gradient(90% 70% at 50% 36%, rgba(56,120,116,.13), transparent 70%),
    radial-gradient(120% 90% at 50% 108%, rgba(2,5,7,.88), transparent 62%),
    radial-gradient(110% 80% at -14% 50%, rgba(2,5,7,.8), transparent 48%),
    radial-gradient(110% 80% at 114% 50%, rgba(2,5,7,.8), transparent 48%),
    linear-gradient(180deg, rgba(2,5,7,.9) 0%, transparent 22%);
}
/* 配管と枠による遮蔽 */
#gridView .gv-pipe{
  position:absolute;pointer-events:none;
  background:linear-gradient(90deg, rgba(3,6,8,.94), rgba(10,16,19,.78) 45%, rgba(3,6,8,.9));
  filter:blur(1px);
}
#gridView .gv-pipe.a{left:-5%;top:-6%;width:19%;height:114%;transform:rotate(3deg)}
#gridView .gv-pipe.b{right:-7%;top:22%;width:17%;height:92%;transform:rotate(-5deg)}

/* ガラス面の結露と汚れ（格子の一部を自然に隠す） */
#gridView .gv-cond{
  position:absolute;inset:0;pointer-events:none;
  background:
    radial-gradient(26% 16% at 32% 18%, rgba(186,214,214,.10), transparent 72%),
    radial-gradient(30% 12% at 70% 42%, rgba(176,206,208,.09), transparent 74%),
    radial-gradient(22% 18% at 24% 62%, rgba(190,216,216,.08), transparent 72%),
    radial-gradient(34% 14% at 62% 84%, rgba(170,200,204,.09), transparent 74%),
    linear-gradient(102deg, transparent 34%, rgba(200,224,226,.05) 44%, transparent 52%);
  filter:blur(5px);
  mix-blend-mode:screen;
  opacity:.35;
}
/* 流れ落ちた水滴の筋 */
#gridView .gv-cond::after{
  content:"";position:absolute;inset:0;opacity:.5;
  background:
    linear-gradient(180deg, rgba(198,222,224,.14), transparent 42%) 18% 0/2px 46% no-repeat,
    linear-gradient(180deg, rgba(198,222,224,.11), transparent 38%) 47% 12%/1.5px 40% no-repeat,
    linear-gradient(180deg, rgba(198,222,224,.12), transparent 44%) 78% 4%/2px 52% no-repeat;
  filter:blur(1.2px);
}

/* ---------- 実験基盤（画像） ---------- */
#gridView .gv-plate{
  position:absolute;inset:0;z-index:0;
  background-image:url("../assets/images/grid_base_plate.webp");
  background-size:168% auto;
  background-position:38% 30%;
  background-repeat:no-repeat;
  filter:brightness(.34) contrast(1.22) saturate(.5) hue-rotate(150deg);
}
#gridView .gv-plate::after{   /* 基盤の奥行きと湿り */
  content:"";position:absolute;inset:0;
  background:
    radial-gradient(80% 60% at 50% 30%, rgba(70,140,140,.10), transparent 72%),
    linear-gradient(180deg, rgba(2,6,8,.55), transparent 26%, rgba(2,5,7,.72));
}

/* ---------- SVG要素 ---------- */
.gv-sock{filter:brightness(.42) saturate(.36) hue-rotate(140deg);transition:filter .5s ease}
.gv-sock-hole{fill:rgba(2,5,7,.72)}
.gv-dress{opacity:.34}

/* 導管は等間隔の線に見せない: 太さ・濃さを段ごとにばらす */
.gv-conduit{
  fill:none;stroke:rgba(96,128,132,.11);stroke-width:1.2;
  stroke-linecap:round;
}
.gv-conduit.w0{stroke-width:.8;stroke:rgba(96,128,132,.07)}
.gv-conduit.w1{stroke-width:1.5;stroke:rgba(104,138,140,.13)}
.gv-conduit.w2{stroke-width:2.2;stroke:rgba(88,120,124,.16)}
.gv-conduit.frag{stroke-dasharray:9 6 3 8}

/* 開放経路の脈動 */
.gv-lib{
  fill:none;stroke-linecap:round;stroke-width:2;
  stroke:rgba(96,208,190,.0);
  transition:stroke .8s ease;
}
.gv-lib.open{
  stroke:rgba(96,208,190,.42);
  stroke-dasharray:3 7;
  animation:libFlow 2.6s linear infinite;
}
.gv-lib.dim{stroke:rgba(120,132,134,.16);animation:none}
.gv-lib.last{stroke:rgba(120,225,204,.6)}
.gv-lib.hint{stroke:rgba(150,235,215,.85);stroke-width:2.5}
@keyframes libFlow{from{stroke-dashoffset:20}to{stroke-dashoffset:0}}

/* 空き端子のガイド脈動（補助） */
.gv-sock.assist{animation:sockAssist 1.7s ease-out 1}
@keyframes sockAssist{
  0%{filter:brightness(.42) saturate(.36) hue-rotate(140deg)}
  32%{filter:brightness(1.35) saturate(.8) hue-rotate(140deg)}
  100%{filter:brightness(.42) saturate(.36) hue-rotate(140deg)}
}

/* ---------- I-05 節点体（培養組織） ---------- */
.nd{transform-box:fill-box;transform-origin:center}
.nd .nd-membrane{fill:url(#gvMembrane);opacity:.68}
.nd .nd-tendrils{opacity:.55}
.nd .nd-tendril{fill:none;stroke:rgba(96,150,146,.42);stroke-width:.75;stroke-linecap:round}
.nd .nd-tex image{filter:brightness(1.02) saturate(.30) hue-rotate(-8deg) contrast(1.34)}

/* 器: 盤面へ少し潰して沈ませる */
.ndw{transform-box:fill-box;transform-origin:center;transform:scaleY(.80)}
.ndw.pre .nd-contact,.ndw.pre .nd-sockrim{opacity:0}
.ndw .nd-contact{fill:rgba(2,5,7,.6);filter:blur(3.4px);transition:opacity .8s ease}
.ndw .nd-sockrim{
  filter:brightness(.5) saturate(.42) hue-rotate(140deg);
  opacity:.55;transition:opacity .8s ease;
}
.ndw.recall-w .nd-contact,.ndw.recall-w .nd-sockrim{opacity:0;transition:opacity 1.2s ease}
.nd .nd-edge{fill:url(#gvEdge);opacity:.34}
/* 膜の奥から透ける厚み */
.nd .nd-sub{fill:url(#gvSub);mix-blend-mode:screen;opacity:.62;transform-box:fill-box;transform-origin:center}
/* 施設光を受ける縁 */
.nd .nd-rimlight{
  fill:none;stroke:rgba(188,222,214,.5);stroke-width:2.6;
  filter:blur(1.1px);
}
.nd .nd-core{fill:rgba(4,9,10,.34);transform-box:fill-box;transform-origin:center}
.nd .nd-wet{fill:url(#gvWet);opacity:.82;transform-box:fill-box;transform-origin:center}
.nd .nd-wet.s{opacity:.5}
.nd .nd-rim{fill:none;stroke:rgba(110,168,162,.26);stroke-width:2.6;filter:blur(1.5px)}

/* 脈動は全体拡縮ではなく、内部の収縮と濡れた反射の移動で見せる */
.nd.beat .nd-core{animation:coreBeat .9s cubic-bezier(.3,0,.2,1) 1}
.nd.beat .nd-sub{animation:subBeat .9s ease-out 1}
.nd.beat .nd-wet{animation:wetBeat .9s ease-out 1}
.nd.beat{animation:ndBeat .9s cubic-bezier(.3,0,.2,1) 1}
@keyframes ndBeat{
  0%{transform:scale(1,1)}
  16%{transform:scale(.982,1.008)}
  40%{transform:scale(1.006,.996)}
  100%{transform:scale(1,1)}
}
@keyframes coreBeat{
  0%{transform:scale(1);opacity:.34}
  18%{transform:scale(.8);opacity:.62}
  46%{transform:scale(1.08);opacity:.28}
  100%{transform:scale(1);opacity:.34}
}
@keyframes subBeat{0%{opacity:.62}20%{opacity:.9}100%{opacity:.62}}
@keyframes wetBeat{
  0%{transform:translate(0,0) scale(1)}
  22%{transform:translate(.6px,-.5px) scale(1.14)}
  100%{transform:translate(0,0) scale(1)}
}
.nd.weak.beat{animation:ndBeatWeak 1.1s ease-out 1}
.nd.weak.beat .nd-core{animation:coreBeatWeak 1.1s ease-out 1}
@keyframes ndBeatWeak{0%{transform:scale(1)}26%{transform:scale(.992,1.004)}100%{transform:scale(1)}}
@keyframes coreBeatWeak{
  0%{transform:scale(1);opacity:.34}
  26%{transform:scale(.92);opacity:.46}
  100%{transform:scale(1);opacity:.34}
}

/* 注入 → にじむように形成される */
.nd.drop{transition:transform 1.05s cubic-bezier(.24,.6,.3,1), opacity .8s ease, filter .9s ease}
.nd.drop.pre{transform:scale(.22,.34);opacity:0;filter:blur(3px)}
.nd.settle{animation:ndSettle .9s cubic-bezier(.3,.02,.2,1) 1}
@keyframes ndSettle{
  0%{transform:scale(1.06,.9)}
  40%{transform:scale(.97,1.04)}
  70%{transform:scale(1.02,.99)}
  100%{transform:scale(1)}
}
/* 回収 = 定着せず、乾いて縮む */
.nd.recall{transition:transform 1.5s ease-in, opacity 1.4s ease, filter 1.3s ease;
  transform:scale(.3,.42);opacity:0;filter:blur(2.6px)}

/* ---------- 処置機構（上部アーム） ---------- */
.p01-arm{
  opacity:0;
  transform-box:fill-box;transform-origin:88% 78%;
  transform:translateY(-34px) rotate(-5deg);
  transition:opacity 1s ease, transform 1.15s cubic-bezier(.28,.5,.3,1);
  filter:brightness(.78) saturate(.45) hue-rotate(150deg) drop-shadow(0 6px 14px rgba(0,0,0,.75));
  pointer-events:none;
}
.p01-arm.in{opacity:.92;transform:translateY(0) rotate(0)}
.p01-arm.out{opacity:0;transform:translateY(-26px) rotate(-3deg);transition:opacity .9s ease, transform 1s ease}

/* 先行して伸びる細い繊維 */
.gv-strand{
  fill:none;stroke:rgba(120,200,186,.45);stroke-width:.9;stroke-linecap:round;
  transition:stroke-dashoffset .75s cubic-bezier(.3,.5,.4,1);
}

/* 繊維導管（接続） */
.gv-fiber{
  fill:none;stroke:url(#patTissue);stroke-width:7.5;stroke-linecap:round;
  opacity:.9;
  filter:blur(.5px) brightness(1.25) saturate(.5) drop-shadow(0 0 3px rgba(0,0,0,.55));
}
/* 膜の上を這う神経束 */
.gv-nerve{
  fill:none;stroke:rgba(150,214,200,.42);stroke-width:.9;stroke-linecap:round;
  transition:stroke-dashoffset 1.1s cubic-bezier(.3,.5,.4,1);
  filter:blur(.2px);
}
.gv-fiber.fill{transition:stroke-dashoffset 1.1s cubic-bezier(.4,.05,.3,1)}
.gv-fiber.sync{animation:fiberSync 1.1s ease-out 1}
@keyframes fiberSync{
  0%{stroke-width:2.2}
  30%{stroke-width:3;filter:drop-shadow(0 0 5px rgba(90,210,190,.5))}
  100%{stroke-width:2.2}
}

/* ---------- 淡色抑制体 ---------- */
.bk{transform-box:fill-box;transform-origin:center}
.bk .bk-halo{fill:rgba(150,145,130,.10)}
.bk .bk-base{filter:brightness(.98) saturate(.09) sepia(.55) contrast(1.06)}
.bk .bk-bone{mix-blend-mode:multiply;opacity:.8;filter:brightness(1.15) saturate(.18)}
.bk .bk-edge{fill:url(#gvEdge);opacity:.85}
.bk .bk-plate{fill:rgba(206,200,182,.12);stroke:rgba(90,86,76,.26);stroke-width:.4}
.bk .bk-crack{fill:none;stroke:rgba(38,36,31,.7);stroke-width:.6;stroke-linecap:round}
.bk .bk-dust{fill:url(#gvBlkDust);opacity:.5}
/* 乾いた硬化物が端子を塞ぐように広がる */
.bk.drop{transition:transform .9s cubic-bezier(.3,.5,.4,1), opacity .6s ease, filter .8s ease}
.bk.drop.pre{transform:scale(.3,.4);opacity:0;filter:blur(2px)}
.bk.stir{animation:bkStir 2.4s ease-in-out 1}
@keyframes bkStir{
  0%{transform:scale(1)}
  30%{transform:scale(1.018)}
  55%{transform:scale(.996)}
  74%{transform:scale(1.008)}
  100%{transform:scale(1)}
}

/* ---------- 候補端子 ---------- */
.gv-hit{fill:rgba(0,0,0,0);cursor:pointer;pointer-events:all}
.gv-cand-ring{
  fill:none;stroke:rgba(130,205,195,.0);stroke-width:1;
  transition:stroke .5s ease;
}
.gv-cand-ring.armed{stroke:rgba(130,205,195,.22)}
.gv-cand-ring.hover{stroke:rgba(150,228,212,.6)}
.gv-cand-ring.sel{stroke:rgba(160,235,218,.75);stroke-dasharray:2 3}

/* 予測プレビュー導管 */
.gv-lib.preview{stroke:rgba(120,215,198,.34);stroke-dasharray:2 6;animation:libFlow 2s linear infinite}

/* 内部空間スキャン */
.gv-scan-grp{opacity:0;transition:opacity .7s ease}
.gv-scan-grp.on{opacity:1}
.gv-scan-line{
  stroke:rgba(120,215,205,.5);stroke-width:.8;
  animation:scanSweep 1.5s linear 1;
}
@keyframes scanSweep{from{transform:translateY(-14px)}to{transform:translateY(14px)}}
.gv-scan-node{fill:rgba(10,16,18,.85);stroke:rgba(90,150,145,.3);stroke-width:.5}
.gv-scan-void{fill:none;stroke:rgba(130,220,205,.4);stroke-width:.7;stroke-dasharray:2 2.5}

/* ==========================================================
   状態パネル
   ========================================================== */
#p01Panel{
  position:absolute;right:max(12px,2.2vw);bottom:max(12px,3vh);z-index:88;
  width:236px;max-width:44vw;
  padding:10px 13px 11px;
  font-family:var(--mono);font-size:11.5px;line-height:1.62;letter-spacing:.06em;
  color:var(--term-fg);
  background:
    linear-gradient(180deg, rgba(7,17,15,.88), rgba(4,10,10,.92));
  border:1px solid rgba(110,170,150,.16);
  box-shadow:inset 0 0 22px rgba(0,0,0,.7), 0 4px 24px rgba(0,0,0,.6);
  opacity:0;transform:translateY(8px);
  transition:opacity 1.2s ease, transform 1.2s ease;
  pointer-events:none;
}
#p01Panel.on{opacity:1;transform:translateY(0)}
#p01Panel::after{ /* 走査線 */
  content:"";position:absolute;inset:0;pointer-events:none;
  background:repeating-linear-gradient(0deg, rgba(0,0,0,.16) 0 1px, transparent 1px 3px);
}
#p01Panel .p-head{
  color:var(--term-dim);font-size:10px;letter-spacing:.18em;margin-bottom:5px;
}
#p01Panel .p-row{white-space:pre}
#p01Panel .p-row .v{color:var(--term-hot)}
#p01Panel .p-row .v.crit{color:#cf8f6a}
#p01Wave{display:block;width:100%;height:26px;margin:7px 0 4px;opacity:.85}
#p01Msg{
  min-height:2.6em;margin-top:4px;
  color:var(--term-fg);
}
#p01Msg .m-line{opacity:0;transition:opacity .3s ease;white-space:pre-wrap}
#p01Msg .m-line.in{opacity:1}
#p01Msg .m-line.dim{color:var(--term-dim)}
#p01Msg .m-line.em{color:var(--term-hot)}
#p01Msg .m-line.warn{color:#c9a27a}

/* 予測表示ラベル */
#p01Proj{
  position:absolute;z-index:89;pointer-events:none;
  font-family:var(--mono);font-size:10.5px;letter-spacing:.12em;
  color:#bfe9d8;text-shadow:0 0 6px rgba(0,0,0,.95);
  background:rgba(4,10,10,.72);
  border:1px solid rgba(110,170,150,.2);
  padding:3px 7px;
  opacity:0;transition:opacity .25s ease;
  white-space:nowrap;
}
#p01Proj.on{opacity:1}

/* 終了時の注記は状態パネルを避ける */
#stage.p01-end #hint.note{bottom:auto;top:max(12px,2.6vh)}

/* ---------- 縦画面 ---------- */
@media (max-aspect-ratio: 1/1){
  #p01Panel{
    left:50%;right:auto;transform:translate(-50%,8px);
    bottom:max(10px,2.2vh);
    width:min(320px,92vw);max-width:92vw;
    font-size:11px;
  }
  #p01Panel.on{transform:translate(-50%,0)}
  #p01Proj{font-size:11px}
}

@media (prefers-reduced-motion: reduce){
  .gv-lib.open,.gv-lib.preview{animation:none}
}
