/* FieldMatrix landing page: tour, "Watch a morning in FieldMatrix." (E5, SPEC 4.6)
   Desktop and tablet (>=760, motion allowed): an unpinned header, then a CSS-sticky scene (FM.scene) where a
   cursor clicks through the real app screens inside a device frame. Step rail at >=1100, a caption line under.
   Under 760, and in reduced motion at every width: five stacked cards (the app's own phone layout).
   Only transform and opacity move. The frame's shadow is the one static shadow on the page. */

#tour{--tv-bar:40px;--tv-foot:54px;--tv-app:#131815}
#tour.tv-mode-frame{padding-bottom:0}

/* ---------- header (not pinned) ---------- */
#tour .tv-head{display:flex;flex-direction:column;align-items:flex-start;gap:20px;padding-bottom:0}
#tour .tv-head .eyebrow{color:var(--ink-2)}
#tour .tv-head .h2{max-width:16ch}
#tour .tv-head .sub{margin-top:-4px}
/* the frame's line: two even lines, never "just scroll." alone on the second. The cards' (and no-JS) neutral
   line keeps "one step at a time." whole, so a phone breaks it at the comma */
#tour.tv-mode-frame [data-k=sub]{text-wrap:balance}
#tour .tv-nw{white-space:nowrap}

/* ---------- sticky stage ----------
   The stage is the page's own .wrap box (max 1320, gutter padding), so the rail starts on the content's left
   edge and the frame's right edge lands exactly on its right edge, like every other section.
   Frame width = the column after the rail and gap, or less when the viewport is short (then it stays
   right-aligned). The 1.08 zoom-open scales from the frame's right edge, so it only grows into the gap. */
#tour .tv-stage{position:relative;height:100%;width:100%;max-width:var(--wrap);margin-inline:auto;
  padding:calc(var(--top-safe) + 20px) var(--gutter) 20px;
  display:grid;grid-template-columns:minmax(0,260px) minmax(0,1fr);column-gap:clamp(56px,5.4vw,76px);align-items:center}
/* the gap is >= 8% of the frame's width at every desktop size, so the 1.08 open never reaches the rail */
#tour .tv-col{justify-self:end;display:flex;flex-direction:column;align-items:center;gap:14px;min-width:0;
  width:min(100%,calc((100vh - var(--top-safe) - 40px - var(--tv-bar) - 3px - 14px - var(--tv-foot)) * 1.6));
  width:min(100%,calc((100svh - var(--top-safe) - 40px - var(--tv-bar) - 3px - 14px - var(--tv-foot)) * 1.6))}

/* device frame: title bar with three dots and a mono address field */
#tour .tv-frame{position:relative;width:100%;background:var(--night-2);border:1px solid var(--hair-2);border-radius:var(--r-frame);overflow:clip;
  box-shadow:0 40px 120px rgba(0,0,0,.55);transform-origin:100% 50%}
#tour .tv-bar{position:relative;height:var(--tv-bar);display:flex;align-items:center;gap:8px;padding:0 16px;border-bottom:1px solid var(--hair)}
#tour .tv-bar i{display:block;flex:none;width:10px;height:10px;border-radius:50%;background:var(--hair-2)}
#tour .tv-addr{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);max-width:calc(100% - 140px);
  padding:5px 22px;border:1px solid var(--hair);border-radius:8px;background:var(--night);
  font:500 .875rem/1.2 var(--f-mono);letter-spacing:.02em;color:var(--ink-2);white-space:nowrap;overflow:clip;text-overflow:ellipsis}
#tour .tv-screen{position:relative;aspect-ratio:1440/900;overflow:clip;background:var(--tv-app);container:tv-screen / inline-size}

/* the 1440x900 app canvas, scaled to the screen by JS (--inv = 1 / scale keeps rings and tags at screen size) */
#tour .tv-canvas{position:absolute;left:0;top:0;width:1440px;height:900px;transform-origin:0 0;--inv:1}
#tour .tv-layer{position:absolute;inset:0;opacity:0;visibility:hidden}
#tour .tv-layer.is-first{opacity:1;visibility:visible}
#tour .tv-layer>img{position:absolute;left:0;top:0;width:1440px;height:900px;max-width:none}
#tour .tv-main{position:absolute;overflow:clip;background:var(--tv-app)}
#tour .tv-scroll{position:relative}
#tour .tv-scroll>img{display:block;max-width:none}

/* rings: 3px lime, 16px radius, a static 6px lime-soft halo that never animates. Sized at screen px via --inv.
   A tag outside the ring sits 8px clear of the halo (3 border + 6 halo + 8 = 17 from the padding box). tour.js
   picks the side per ring (above / below / inside) so a tag lands on empty app screen, never on a line of text. */
#tour .tv-ring{position:absolute;opacity:0;pointer-events:none;
  border:calc(3px * var(--inv)) solid var(--lime);border-radius:calc(16px * var(--inv));
  box-shadow:0 0 0 calc(6px * var(--inv)) var(--lime-soft)}
#tour .tv-tag{position:absolute;left:calc(-3px * var(--inv));bottom:calc(100% + 17px * var(--inv));white-space:nowrap;
  padding:calc(8px * var(--inv)) calc(13px * var(--inv));border-radius:calc(8px * var(--inv));
  background:var(--lime);color:var(--night);font:600 calc(16px * var(--inv))/1.15 var(--f-display);letter-spacing:-.01em}
#tour .tv-tag.below{bottom:auto;top:calc(100% + 17px * var(--inv))}
#tour .tv-tag.inside{bottom:auto;top:calc(12px * var(--inv));left:calc(12px * var(--inv))}
#tour .tv-tag.right{left:auto;right:calc(-3px * var(--inv))}
#tour .tv-tag.inside.right{left:auto;right:calc(12px * var(--inv))}
#tour .tv-tag.inside.low{top:auto;bottom:calc(12px * var(--inv))}
/* one column (760-1099), or a desktop frame whose app screen is under 720px wide (1100-1140, or a short
   window): the screen is small, so tags drop to the 14px floor to stay on empty space (the long step-4 tag
   would otherwise run onto the best-bid card's text) */
@media (max-width:1099px){
  #tour .tv-tag{padding:calc(7px * var(--inv)) calc(11px * var(--inv));font-size:calc(14px * var(--inv))}
}
@container tv-screen (max-width:720px){
  #tour .tv-tag{padding:calc(7px * var(--inv)) calc(11px * var(--inv));font-size:calc(14px * var(--inv))}
}

/* cursor (with a baked-in shadow, no filter) and click ripple */
/* the arrow's tip sits on the box origin, so the click squeeze scales the box around 0 0 (the svg never moves:
   an <svg> has no offsetParent, and GSAP's transform read on one forces extra layout passes) */
#tour .tv-cur{position:absolute;left:0;top:0;z-index:20;pointer-events:none;transform-origin:0 0}
#tour .tv-cur svg{width:calc(26px * var(--inv));height:calc(26px * var(--inv));overflow:visible}
#tour .tv-click{position:absolute;left:0;top:0;z-index:19;pointer-events:none;opacity:0}
#tour .tv-click i{display:block;width:calc(44px * var(--inv));height:calc(44px * var(--inv));margin:calc(-22px * var(--inv)) 0 0 calc(-22px * var(--inv));
  border-radius:50%;border:calc(2px * var(--inv)) solid #fff}

/* step rail (>=1100): five titles, each with a rule that fills with the playhead (lime while active, ink-3
   once passed), then one description slot that crossfades to the active step's line. */
#tour .tv-railbox{position:relative;align-self:center;max-height:calc(100vh - var(--top-safe) - 40px);max-height:calc(100svh - var(--top-safe) - 40px);overflow:clip}
#tour .tv-rail{display:flex;flex-direction:column}
#tour .tv-rail>li{position:relative;padding:12px 0 12px 22px}
#tour .tv-rail .tv-track{position:absolute;left:0;top:0;bottom:0;width:2px;background:var(--hair-2);overflow:clip}
#tour .tv-rail .tv-fill{position:absolute;inset:0;background:var(--lime);transform-origin:50% 0;transform:scaleY(0)}
#tour .tv-rail>li.is-past .tv-fill{background:var(--ink-3)}
#tour .tv-rail h3{color:var(--ink-3)}
#tour .tv-rail>li.is-on h3{color:var(--ink)}
#tour .tv-desc{display:grid;margin-top:28px;padding-left:22px}
#tour .tv-d{grid-area:1 / 1;color:var(--ink-2);line-height:1.5;opacity:0;transform:translateY(8px);
  transition:opacity .35s var(--ease-out),transform .35s var(--ease-out)}
#tour .tv-d.is-on{opacity:1;transform:none}
@media (max-height:540px){ #tour .tv-desc{display:none} }

/* caption line under the frame (760-1099): "{i} / 5 · {title}" */
#tour .tv-cap{display:none;min-height:60px;width:100%}
#tour .tv-cap .caps-text .cap{max-width:min(46ch,calc(100vw - 32px))}
#tour .tv-foot{max-width:84ch;min-height:var(--tv-foot);text-align:center;color:var(--ink-3)}

@media (max-width:1099px){
  #tour .tv-stage{grid-template-columns:minmax(0,1fr)}
  #tour .tv-railbox{display:none}
  #tour .tv-cap{display:flex;justify-content:center}
  /* one column: centred, narrowed by the zoom factor so the 1.08 open stays inside the gutters */
  #tour .tv-col{justify-self:center;
    width:min(100% / 1.08,calc((100vh - var(--top-safe) - 40px - var(--tv-bar) - 3px - 28px - 60px - var(--tv-foot)) * 1.6));
    width:min(100% / 1.08,calc((100svh - var(--top-safe) - 40px - var(--tv-bar) - 3px - 28px - 60px - var(--tv-foot)) * 1.6))}
  #tour .tv-frame{transform-origin:50% 50%}
  /* the footnote keeps its own measure (centred on the frame, wider than a short window's small frame),
     so it stays at three lines instead of a fourth that would run off the bottom */
  #tour .tv-foot{flex:none;width:calc(100vw - 2 * var(--gutter));max-width:84ch}
}

/* ---------- stacked cards (<760, and reduced motion at every width) ---------- */
#tour.tv-mode-cards .tv-head{padding-bottom:clamp(40px,6vh,64px)}
#tour .tv-cards{display:grid;grid-template-columns:minmax(0,1fr);gap:56px;list-style:none}
#tour .tv-card{min-width:0}
#tour .tv-cin{display:flex;flex-direction:column;gap:20px}
#tour .tv-ctext{display:flex;flex-direction:column;gap:10px}
#tour .tv-phone{width:100%;max-width:420px;padding:6px;border:1px solid var(--hair-2);border-radius:var(--r-frame);background:var(--night-2)}
/* a window of the 400x520 phone capture, composed on whole UI blocks (aspect set by tour.js from its window);
   the image is placed so the window's top is the screen's top. A cut edge fades into --night-2 (static). */
#tour .tv-pscreen{position:relative;aspect-ratio:400/420;border-radius:12px;overflow:clip;background:var(--tv-app)}
#tour .tv-pscreen img{position:absolute;left:0;top:0;display:block;width:100%;height:auto;max-width:none}
#tour .tv-pring{position:absolute;z-index:1;display:none;border:2px solid var(--lime);border-radius:12px;box-shadow:0 0 0 5px var(--lime-soft);pointer-events:none}
#tour .tv-pring.is-set{display:block}
#tour .tv-pscreen::before,#tour .tv-pscreen::after{content:"";position:absolute;left:0;right:0;z-index:2;height:32px;pointer-events:none;display:none}
#tour .tv-pscreen::before{top:0;background:linear-gradient(180deg,var(--night-2),rgba(17,22,18,0))}
#tour .tv-pscreen::after{bottom:0;background:linear-gradient(0deg,var(--night-2),rgba(17,22,18,0))}
#tour .tv-pscreen.cut-top::before,#tour .tv-pscreen.cut-bottom::after{display:block}
#tour .tv-ci{color:var(--ink-3)}
#tour .tv-card .body{color:var(--ink-2)}
#tour .tv-cards-foot{margin-top:40px}
#tour .tv-cards-foot .footnote{max-width:84ch}
/* phones: the stack is the page's longest block, so its spacing is tighter (the screens and every line of copy
   stay); each card still reads as its own unit: 40px between cards against 14px from screen to text */
@media (max-width:759px){
  #tour.tv-mode-cards .tv-head{padding-bottom:clamp(28px,4.5vh,40px)}
  #tour .tv-cards{gap:40px}
  #tour .tv-cin{gap:14px}
  #tour .tv-ctext{gap:6px}
  #tour .tv-cards-foot{margin-top:28px}
}
@media (min-width:760px){
  /* reduced motion on wide screens: a grid whose rows line up (screens bottom-aligned, titles on one line) */
  #tour .tv-cards{grid-template-columns:repeat(2,minmax(0,1fr));column-gap:var(--gap);row-gap:64px}
  #tour .tv-card{display:grid;grid-row:span 2;grid-template-rows:subgrid;row-gap:20px}
  #tour .tv-cin{display:contents}
  #tour .tv-phone{align-self:end}
}
@media (min-width:1100px){
  #tour .tv-cards{grid-template-columns:repeat(3,minmax(0,1fr))}
}
