/* ============================================================================
 * landing-world.css — production layer (not a design-mirror file).
 * Chrome for the page-as-real-canvas: screen tabs, ports, wires between
 * screens, drag states, HUD additions, and the intro fly-in that replaces the
 * old zoom-and-vanish. Desktop-only: hidden ≤860px.
 * ========================================================================= */

/* every screen is a block */
.sblock{position:relative}

/* wires between screens (drawn by landing-world.js in world coordinates) */
.wwires{position:absolute;inset:0;width:100%;height:100%;overflow:visible;pointer-events:none;z-index:3}
.wwires .wpath{fill:none;stroke:var(--teal);stroke-width:1.6;opacity:.42;stroke-dasharray:5 7}
@media(prefers-reduced-motion:no-preference){.wwires .wpath{animation:wflow 1.15s linear infinite}}
@keyframes wflow{to{stroke-dashoffset:-12}}

/* screen tab: [• name.canvas ⠿] */
.stab{position:absolute;top:14px;left:16px;z-index:7;display:inline-flex;align-items:center;gap:8px;padding:5px 11px 5px 15px;font-family:var(--mono);font-size:10.5px;letter-spacing:.04em;color:var(--ink-2);background:var(--glass);backdrop-filter:blur(8px) saturate(140%);-webkit-backdrop-filter:blur(8px) saturate(140%);border:1px solid var(--line);border-radius:8px;box-shadow:var(--shadow);user-select:none;-webkit-user-select:none}
.stab b{font-weight:600;color:var(--ink)}
.stab .sport{position:absolute;left:-5px;top:50%;margin-top:-5px}
.stab.dk{background:rgba(18,21,26,.62);border-color:var(--dark-line-strong);color:var(--dark-muted)}
.stab.dk b{color:var(--dark-ink)}
.hero .stab{top:74px} /* clear the fixed nav on the first screen */

.sport{width:10px;height:10px;border-radius:3px;background:var(--teal);box-shadow:0 0 0 3px color-mix(in srgb,var(--teal) 16%,transparent)}
.sport.sout{position:absolute;bottom:-5px;background:var(--amber);box-shadow:0 0 0 3px color-mix(in srgb,var(--amber) 18%,transparent);z-index:7}

/* drag affordance + states */
.sgrip{color:var(--muted);font-size:12px;line-height:1;margin-left:2px}
.stab.grab{cursor:grab}
.stab.grab:hover{border-color:var(--line-strong)}
.stab.grab:hover .sgrip{color:var(--ink)}
body.wdragging{user-select:none;-webkit-user-select:none;cursor:grabbing}
.sblock.sdragging{z-index:55}
.sblock.sdragging .stab{cursor:grabbing;border-color:color-mix(in srgb,var(--amber) 60%,var(--line));box-shadow:var(--shadow-2)}
.sblock.sdragging{outline:1px dashed color-mix(in srgb,var(--amber) 45%,transparent);outline-offset:-1px}
.sblock.sreset{transition:transform .52s cubic-bezier(.3,1.35,.4,1)}

/* the old decorative joins are retired — real wires do that job now */
.join{display:none}

/* HUD: block/wire counters + reset (js appends into #hud) */
.hud .wmeta i{font-style:normal;color:var(--muted)}
.hud .wmeta .wn{min-width:0}
#wreset{display:none;pointer-events:auto;margin-left:4px;font-family:var(--mono);font-size:10px;padding:2px 9px;border:1px solid var(--line-strong);border-radius:6px;background:var(--card);color:var(--ink-2);cursor:pointer;transition:border-color .2s var(--ease),color .2s var(--ease)}
#wreset:hover{border-color:var(--amber);color:var(--ink)}
body.wmoved #wreset{display:inline-block}
body.wmoved .hud{opacity:1;transform:none}

/* ── intro integrates instead of vanishing ────────────────────────────────
 * .fly clears the overlay so the block the intro built travels over the real
 * page and docks into the hero block's title bar. */
.intro{transition:background .32s var(--ease)}
.intro.fly{background:transparent;pointer-events:none}
.intro.fly .igrid,.intro.fly .istack,.intro.fly .istatus,.intro.fly .iskip,.intro.fly .icur{opacity:0;transition:opacity .26s var(--ease)}
.intro.fly .irow{will-change:transform}

/* the hero block "accepts" the landing intro block */
.hblock.landed{animation:blockland .8s var(--ease) both}
@keyframes blockland{0%{box-shadow:0 0 0 0 color-mix(in srgb,var(--amber) 45%,transparent)}45%{box-shadow:0 0 0 16px transparent}100%{box-shadow:var(--shadow-2)}}
.hblock.landed .port-in,.hblock.landed .port-out{animation:portpop .5s cubic-bezier(.34,1.56,.64,1) .18s both}
@keyframes portpop{0%{transform:scale(.2)}60%{transform:scale(1.35)}100%{transform:scale(1)}}

/* LOG speaks during the boot — same voice as the pal bubble. The bubble sits
 * ABOVE the buddy so it never covers the word being typed. */
.isay{position:absolute;left:50%;bottom:calc(100% + 14px);width:max-content;max-width:300px;background:var(--card);color:var(--ink);border:1px solid var(--line);border-radius:10px;padding:8px 12px;font-family:var(--mono);font-size:12px;font-weight:400;line-height:1.45;letter-spacing:0;box-shadow:var(--shadow-2);opacity:0;transform:translate(-50%,6px);transition:opacity .25s var(--ease),transform .25s var(--ease);pointer-events:none;z-index:3;white-space:nowrap}
.isay::after{content:'';position:absolute;left:50%;bottom:-5px;width:8px;height:8px;background:var(--card);border-right:1px solid var(--line);border-bottom:1px solid var(--line);transform:translateX(-50%) rotate(45deg)}
.isay.on{opacity:1;transform:translate(-50%,0)}

/* ════════════════════════════════════════════════════════════════════════
 * CANVAS MODE — html[data-canvas]: the landing IS a canvas.
 * ═══════════════════════════════════════════════════════════════════════ */
/* свободное полотно: у документа нет скролла, вся навигация — камера */
html[data-canvas],html[data-canvas] body{overflow:hidden;height:100%;overscroll-behavior:none}

/* no will-change here: promoting a ~5000×9000 plane into one compositor layer
 * wedges raster (screenshots/first paint took seconds). Chrome tiles the
 * transformed layer on its own, and content-visibility prunes what's off
 * camera — that combination stays fast. */
html[data-canvas] #world{position:fixed;left:0;top:0;transform-origin:0 0;cursor:grab;will-change:auto}
/* the plane grid lives on a fixed body layer, synced to the camera via CSS
 * vars — keeping the giant #world layer cheap to rasterize */
html[data-canvas] body::before{content:'';position:fixed;inset:0;z-index:0;pointer-events:none;
  background-image:linear-gradient(to right,var(--canvas-line-strong) 1px,transparent 1px),linear-gradient(to bottom,var(--canvas-line-strong) 1px,transparent 1px);
  background-size:var(--wgs,128px) var(--wgs,128px);background-position:var(--wgx,0) var(--wgy,0)}
html[data-canvas] body.wpanning #world{cursor:grabbing}
/* до первого relayout секции не имеют координат — прячем план, чтобы не было
 * кадра «все экраны стопкой в углу». Однократно (.ready ставится один раз и
 * не снимается): opacity-переход на плане 5000×9000 промоутил бы слой на
 * каждом пере-лейауте. visibility вместо opacity — без композитинга. */
html[data-canvas] #world{visibility:hidden}
html[data-canvas] #world.ready{visibility:visible}
html[data-canvas] #world > [data-screen-label]{position:absolute;margin:0;cursor:auto}
html[data-canvas] #world.cv > [data-screen-label]{content-visibility:auto}

/* every screen reads as a block on the plane */
html[data-canvas] .sblock{border:1px solid var(--line-strong);border-radius:22px;box-shadow:var(--shadow-2)}
html[data-canvas] .sblock:not(.dark):not(.blade):not(.foot){background:var(--card)}
html[data-canvas] .sblock.dark,html[data-canvas] .sblock.foot{border-color:var(--dark-line-strong)}
html[data-canvas] .sblock>.grid-canvas,html[data-canvas] .sblock>.grid-dark{border-radius:22px}
html[data-canvas] .hero .stab{top:14px} /* the nav floats over the plane, not over the block */
html[data-canvas] .foot,html[data-canvas] .dark{overflow:hidden;border-radius:22px}
html[data-canvas] .foot .sport,html[data-canvas] .dark .sport,html[data-canvas] .foot .stab,html[data-canvas] .dark .stab{z-index:8}

/* the pinned scrollytelling can't pin inside a camera — the camera dwells
 * on the block instead and drives the steps itself */
html[data-canvas] .story{height:auto}
html[data-canvas] .story-track{height:auto}
html[data-canvas] .story-stage{position:relative;height:auto;min-height:640px;overflow:visible;padding:80px 0}

/* wires + reveal beat */
html[data-canvas] .wwires{z-index:0}
.wwires.wborn{animation:wfade .9s var(--ease) both}
@keyframes wfade{from{opacity:0}}

/* zoomed far out: drop every backdrop blur — LOD, like the real IDE */
body.lod-far #world *{backdrop-filter:none!important;-webkit-backdrop-filter:none!important}

/* HUD zoom readout + always-on in canvas mode */
html[data-canvas] .hud{opacity:1;transform:none}
#hudZ{color:var(--ink)}

/* minimap becomes a real 2D map */
html[data-canvas] .mmap.mm2d{width:104px;height:min(52vh,420px)}
.mm2d .mmb{left:auto;right:auto;border-radius:2px}
.mm2d .mmvp{border-radius:3px}

/* ── boot relic: the intro's landing site, a permanent block on the board ── */
.brelic{position:absolute;z-index:6;display:inline-flex;align-items:center;gap:9px;padding:10px 16px 10px 18px;font-family:var(--mono);font-size:12px;color:var(--ink-2);background:var(--card);border:1px solid var(--line-strong);border-radius:12px;box-shadow:var(--shadow-2);opacity:0;transform:scale(.92);transition:opacity .4s var(--ease),transform .5s cubic-bezier(.34,1.56,.64,1)}
.brelic.on{opacity:1;transform:none}
.brelic b{color:var(--ink);font-weight:600}
.brelic .brface{width:26px;height:26px;flex:none;display:grid;place-items:center;border-radius:7px;background:oklch(0.82 0.16 86);color:oklch(0.3 0.07 70);font-weight:700;font-size:10.5px;letter-spacing:-.05em}
.brelic .brok{color:var(--teal-ink)}
.brelic .sport{position:absolute;left:-5px;top:50%;margin-top:-5px}
.brelic .sport.bout{left:auto;right:-5px;background:var(--amber);box-shadow:0 0 0 3px color-mix(in srgb,var(--amber) 18%,transparent)}
/* boot-in-scene: пока блок печатается — курсор мигает, вердикта ещё нет */
.brelic .brword{min-width:2px}
.brelic .brcur{display:none;width:7px;height:14px;border-radius:2px;background:var(--amber)}
.brelic.building .brcur{display:inline-block;animation:blink 1s steps(1) infinite}
.brelic.building .brok{display:none}
.brelic.building .sport.bout{opacity:0}
.brelic .brok{transition:opacity .3s var(--ease)}
.brelic.landed .brface{animation:portpop .5s cubic-bezier(.34,1.56,.64,1)}
@media(prefers-reduced-motion:no-preference){.brelic.on .brface{animation:brblink 6s steps(1) infinite}}
@keyframes brblink{0%,96%{content:''}97%,99%{filter:brightness(.9)}}

/* canvas mode: the boot types over the LIVE board — a translucent scrim, not
 * a wall. The grid below is the real one; paint happens early (Speed Index). */
html[data-canvas] .intro{background:color-mix(in srgb,var(--dark) 62%,transparent)}
html[data-canvas] .intro .igrid{display:none}

/* hint chip: three verbs, shows once after the intro */
#whint{position:fixed;left:50%;bottom:26px;transform:translate(-50%,10px);z-index:85;display:inline-flex;align-items:center;gap:8px;font-family:var(--mono);font-size:11.5px;color:var(--ink-2);background:var(--glass);backdrop-filter:blur(10px) saturate(140%);-webkit-backdrop-filter:blur(10px) saturate(140%);border:1px solid var(--line);border-radius:10px;padding:9px 14px;box-shadow:var(--shadow);opacity:0;transition:opacity .4s var(--ease),transform .4s var(--ease);pointer-events:none}
#whint.on{opacity:1;transform:translate(-50%,0)}
#whint b{color:var(--ink);font-weight:600}
#whint i{font-style:normal;color:var(--muted)}

/* story dots become buttons on the free plane */
html[data-canvas] .dots i{cursor:pointer}
html[data-canvas] .stp{cursor:pointer}

/* mobile keeps the clean scroll — the canvas chrome is a desktop instrument */
@media(max-width:860px){.stab,.sport.sout,.wwires{display:none}}
