/* =========================================================
   Cuvee — landing page
   Type: Archivo (display + reading) / Montserrat (interface layer)
   ========================================================= */

:root{
  /* surfaces — near-black with a blue bias, never zero-chroma grey */
  --ink-950:#05070C;
  --ink-900:#070A10;
  --ink-850:#0E1420;
  --ink-800:#0A0E16;
  --ink-700:#0D121B;
  --ink-600:#111722;
  --line:rgba(255,255,255,.075);
  --line-strong:rgba(255,255,255,.14);

  /* text */
  --text:#EDF1F7;
  --text-2:#A5B0C2;
  --text-3:#7B8698;

  /* brand blue, sampled from the app icon */
  --blue:#3D6DF2;
  --blue-lift:#6E96FF;
  --blue-pale:#C9D8FF;

  --ease:cubic-bezier(.16,1,.3,1);
  --ease-quart:cubic-bezier(.25,1,.5,1);

  --gutter:clamp(20px,5vw,48px);
  --radius:16px;

  /* the value both sides of the banner/section join settle on, so the two can
     meet on the same colour and no edge reads as a cut */
  --seam:#080B12;
}

*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth}
body{
  margin:0;
  background:var(--ink-900);
  color:var(--text);
  font-family:"Archivo","Helvetica Neue",Arial,sans-serif;
  font-size:16px;
  line-height:1.6;
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
  /* hidden, then clip: `hidden` on body makes body itself a scroll container,
     so a poster that leans a few px past the edge on hover could still be
     scrolled into view and shift the whole page sideways. `clip` cuts the same
     overflow without ever becoming scrollable. */
  overflow-x:hidden;
  overflow-x:clip;
}
img{max-width:100%;display:block}
a{color:inherit;text-decoration:none}
h1,h2,h3,h4,p,figure,ul{margin:0}
ul{list-style:none;padding:0}
button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}
::selection{background:rgba(61,109,242,.35);color:#fff}
/* the svg that holds the shared gradients is 0x0, but an inline svg still opens
   a line box — 16px × 1.6 line-height of nothing sitting above the banner and
   pushing it 25.6px off the top of the page. taken out of flow entirely. */
.ico-defs{position:absolute;width:0;height:0;overflow:hidden;pointer-events:none}

:focus-visible{outline:2px solid var(--blue-lift);outline-offset:3px;border-radius:6px}

.wrap{width:100%;max-width:1240px;margin:0 auto;padding:0 var(--gutter)}

section[id],footer[id]{scroll-margin-top:96px}
[data-parallax]{translate:0 var(--py,0px);will-change:translate}

/* film grain — one texture pass, no glow stack */
.grain{
  position:fixed;inset:0;z-index:60;pointer-events:none;opacity:.032;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.8' numOctaves='3'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ─────────────── type ─────────────── */
/* two families, two jobs. archivo carries the reading text and the small UI
   labels; montserrat carries the display lines. montserrat is a geometric —
   round bowls, wide caps, a much larger x-height — so it needs its own
   tracking: the -.045em that suited archivo's flat-sided grotesque closes
   montserrat's round letters into each other. it also has no width axis, so
   the wdth variation only stays on the archivo headings. */
h1,h2,h3{font-weight:600;letter-spacing:-.028em}
h1,h2{font-family:"Montserrat",sans-serif}
h1{font-size:clamp(2.4rem,5.2vw,4.55rem);line-height:.98;letter-spacing:-.03em}
h2{font-size:clamp(2rem,4.2vw,3.4rem);line-height:1.06;letter-spacing:-.024em}
h3{font-size:1.06rem;font-weight:500;line-height:1.32;letter-spacing:-.012em;font-variation-settings:"wdth" 106}

.lead{
  font-size:clamp(1rem,1.1vw,1.075rem);
  line-height:1.7;
  color:var(--text-2);
  max-width:58ch;
  text-wrap:pretty;
}

/* ─────────────── buttons ─────────────── */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:8px;
  height:48px;padding:0 24px;border-radius:999px;
  font-family:"Montserrat",sans-serif;font-size:.875rem;font-weight:600;letter-spacing:.005em;
  white-space:nowrap;
  transition:transform .25s var(--ease-quart),box-shadow .25s var(--ease-quart),
             background-color .25s var(--ease-quart),border-color .25s var(--ease-quart),filter .25s;
  will-change:transform;
}
.btn-primary{
  color:#fff;
  background:linear-gradient(180deg,#5A85F8 0%,#2F5CE0 100%);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.22),0 12px 32px -14px rgba(61,109,242,.9);
}
.btn-primary:hover{transform:translateY(-1px);filter:brightness(1.07);box-shadow:inset 0 1px 0 rgba(255,255,255,.28),0 18px 40px -16px rgba(61,109,242,1)}
.btn-primary:active{transform:translateY(0) scale(.985);transition-duration:.1s}
.btn-ghost{border:1px solid var(--line-strong);color:var(--text)}
.btn-ghost:hover{background:rgba(255,255,255,.045);border-color:rgba(255,255,255,.24)}
.btn-sm{height:38px;padding:0 17px;font-size:.8rem;box-shadow:inset 0 1px 0 rgba(255,255,255,.2),0 6px 18px -10px rgba(61,109,242,.85)}

/* ─────────────── nav ─────────────── */
/* the bar never grows a plate — it stays a transparent label on the banner,
   and once the banner has finished its pull-back it simply rides the scroll
   away with the page (the offset is driven per frame in JS). */
.nav{
  position:fixed;inset:0 0 auto 0;z-index:100;
  background:transparent;
  backdrop-filter:none;-webkit-backdrop-filter:none;
  border-bottom:0;
  will-change:transform;
}
body.menu-open{overflow:hidden}
.nav-inner{display:flex;align-items:center;gap:24px;height:76px}
.brand{display:inline-flex;align-items:center;gap:11px;font-family:"Montserrat",sans-serif;font-size:.8rem;font-weight:600;text-transform:uppercase;letter-spacing:.14em}
.brand img{width:30px;height:30px;border-radius:9px;box-shadow:0 6px 18px -8px rgba(61,109,242,.8)}
.nav-links{display:flex;gap:36px;margin-left:auto}
.nav-links a{
  position:relative;font-family:"Montserrat",sans-serif;font-size:.85rem;font-weight:500;
  color:var(--text-2);transition:color .25s;
}
.nav-links a::after{
  content:"";position:absolute;left:0;right:0;bottom:-6px;height:1px;background:var(--blue-lift);
  transform:scaleX(0);transform-origin:left;transition:transform .35s var(--ease);
}
.nav-links a:hover{color:var(--text)}
.nav-links a:hover::after{transform:scaleX(1)}

.nav-toggle{display:none;width:40px;height:40px;position:relative;margin-left:auto}
.nav-toggle span{position:absolute;left:10px;right:10px;height:1.5px;background:var(--text);transition:transform .35s var(--ease),opacity .2s}
.nav-toggle span:nth-child(1){top:16px}
.nav-toggle span:nth-child(2){top:23px}
.nav-toggle[aria-expanded="true"] span:nth-child(1){transform:translateY(3.5px) rotate(45deg)}
.nav-toggle[aria-expanded="true"] span:nth-child(2){transform:translateY(-3.5px) rotate(-45deg)}

.mobile-menu[hidden]{display:none}
.mobile-menu{
  position:fixed;inset:0;z-index:99;padding:110px var(--gutter) 40px;
  background:rgba(7,10,16,.97);backdrop-filter:blur(20px);
  display:flex;flex-direction:column;
}
.mobile-menu nav{display:flex;flex-direction:column;gap:4px}
.mobile-menu nav a{display:flex;flex-direction:column;gap:2px;padding:16px 0;border-bottom:1px solid var(--line)}
.mobile-menu nav a span{font-size:1.5rem;font-weight:500;font-variation-settings:"wdth" 106;letter-spacing:-.02em}
.mobile-menu nav a em{font-style:normal;font-family:"Montserrat",sans-serif;font-size:.75rem;color:var(--text-3)}
.mobile-menu .btn{width:100%}

/* ─────────────── hero ─────────────── */
.hero{
  position:relative;
  display:flex;flex-direction:column;align-items:center;
  min-height:100svh;
  padding:0 0 clamp(10px,1.4vh,18px);
  overflow:hidden;text-align:center;
  z-index:3;
  /* no light in the room itself: the gradient lives on the panel, so when the
     set pulls back it leaves nothing behind but the dark it was standing in.
     a long, monotonic ramp still carries the banner into --seam, so the section
     below opens on the same value and the join has no step. */
  background:linear-gradient(180deg,var(--ink-950) 0%,var(--ink-950) 52%,var(--seam) 100%);
}

/* the banner's light is a picture, so there is no second layer to keep in
   step with it: no wash, no drifting sources, no mask, no keyframes. what used
   to live here — four blurred blobs on their own clocks — was the single most
   expensive thing on the page, and every fix for its flicker was another
   workaround for the same cost. a still frame of the mesh has none of it. */

.hero-glow{
  position:absolute;left:50%;top:-6%;width:min(1500px,132vw);height:78%;
  transform:translateX(-50%);
  background:radial-gradient(ellipse at 50% 0%,rgba(47,125,233,.26) 0%,rgba(33,69,121,.10) 40%,transparent 68%);
  filter:blur(46px);pointer-events:none;
}

/* the television — a full-bleed screen at rest that pulls back into a framed
   set as it tips over. Both end states are expressed in CSS, --p interpolates. */
.hero-stage{
  position:relative;z-index:1;
  width:100%;
  flex:none;
  display:flex;align-items:flex-end;justify-content:center;
  /* the stage keeps the height of the window, so nothing below it moves while
     the panel pulls back — the copy sits at the bottom edge the whole way. */
  min-height:100lvh;
  perspective:2400px;
  /* the vanishing point sits on the centre of the framed set, which is where
     the plane ends up — at rest nothing is rotated, so it costs nothing */
  perspective-origin:50% calc(100% - var(--th,292px) / 2);
}
.hero-tv{
  /* two states, interpolated by --p:
       0 — the whole window: the wash and the mark, edge to edge
       1 — the set: 16:9, framed, tipped back
     the box itself is what animates, so the mark stays round and the wash just
     stretches — nothing is scaled. --tw is the framed width. */
  --tw:min(1040px,90vw,max(260px,(100svh - 400px) * 1.7778));
  --th:calc(var(--tw) / 1.7778);
  /* the slab is ultra-thin — a modern panel, not a CRT. this is the depth that
     gets extruded on the lean, so the set reads as an object, not a card. */
  --depth:clamp(8px,.7vh,15px);
  position:relative;
  /* --q is the pull-back (eased out, so the window gives up its edges early);
     --p drives the lean, the corners and the bezel. */
  width:calc(100vw + (var(--tw) - 100vw) * var(--q,0));
  height:calc(100lvh + (var(--th) - 100lvh) * var(--q,0));
  /* square corners, panel and bezel alike: a right-angle rectangle can never
     leave a wedge of background between a rounded screen and a square frame */
  border-radius:0;
  /* the panel is re-rastered on every frame of the pull-back, so its shadow
     stays tight: a 110px bloom on a 3D-transformed box is what makes the
     compositor drop frames (and flicker) mid-scroll. the room's falloff is
     carried by the stage and the spill instead.

     the blur also grows with --p. while the window is still full-bleed the
     panel is the size of the screen, so a 46px blur on it is the most
     expensive thing on the page at the exact moment the pull-back starts —
     and it is invisible there anyway, because the shadow falls outside the
     window. starting it at zero and letting it arrive with the framing takes
     the cost out of the first, busiest part of the scroll. */
  box-shadow:
    0 0 calc(46px * var(--p,0)) 2px rgba(3,7,14,.55),
    0 calc(34px * var(--p,0)) calc(62px * var(--p,0)) -40px rgba(0,0,0,.95);
  transform-origin:50% 100%;
  transform:rotateX(calc(var(--p,0) * var(--p,0) * -58deg));
  transform-style:preserve-3d;
  /* promoted from the first frame. without this the layer is created the
     moment the page starts to move — and that one-time promotion is visible as
     a flicker right at the start of a scroll, then never again. */
  will-change:transform;
}
/* the back of the slab. it only exists once the plane tips, and it is what
   keeps the set from reading as a single sheet when you look along an edge.
   note there is no will-change here: an opacity hint promotes each of these to
   its own compositor layer, and at rest the panel is the size of the window —
   six full-screen surfaces for six flat fills. they are painted into the
   panel's layer instead, which is re-rastered on every frame of the pull-back
   anyway, so the hint bought nothing and cost a great deal of tile memory. */
.hero-tv::before{
  content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  background:linear-gradient(180deg,#0B1017 0%,#05080D 100%);
  transform:translateZ(calc(-1 * var(--depth)));
  opacity:min(1,calc(var(--p,0) * var(--p,0) * 3.4));
}
/* ultra-thin bezel with a faint matte-metal sheen. a real border (not a masked
   ring) matters: its inner edge rounds to R − border-width, concentric with the
   screen's corner, so the frame and the panel meet with no gap at the corners.
   per-side colours give the top rail light and the bottom rail shadow. */
.hero-tv::after{
  content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  border:clamp(2px,.18vw,2.5px) solid;
  border-color:#3E4855 #232B35 #0B0F15 #232B35;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.10);
  opacity:min(1,calc(var(--p,0) * var(--p,0) * 3.4));
}
/* the rails that show when the panel leans: extruded in 3D from all four
   edges, so their perspective is the panel's own, not a painted fake. at this
   lean the top and the two sides are the ones the room sees. */
.hero-tv-edge{
  position:absolute;pointer-events:none;
  opacity:min(1,calc(var(--p,0) * var(--p,0) * 3.4));
}
/* horizontal rails — top and bottom */
.hero-tv-edge--t,.hero-tv-edge--b{left:0;right:0;height:var(--depth)}
.hero-tv-edge--t{
  top:0;transform-origin:top center;transform:rotateX(-90deg);
  background:linear-gradient(180deg,#39424F 0%,#1B222B 50%,#0B0F15 100%);
  box-shadow:inset 0 -1px 0 rgba(255,255,255,.16); /* lit seam at the screen */
}
.hero-tv-edge--b{
  bottom:0;transform-origin:bottom center;transform:rotateX(90deg);
  background:linear-gradient(180deg,#0B0F15 0%,#1B222B 50%,#39424F 100%);
  box-shadow:inset 0 -1px 0 rgba(255,255,255,.18);
}
/* vertical rails — the side faces you see when the set is off-axis */
.hero-tv-edge--l,.hero-tv-edge--r{top:0;bottom:0;width:var(--depth)}
.hero-tv-edge--l{
  left:0;transform-origin:left center;transform:rotateY(-90deg);
  background:linear-gradient(90deg,#333C48 0%,#141A21 100%);
  box-shadow:inset 1px 0 0 rgba(255,255,255,.14);
}
.hero-tv-edge--r{
  right:0;transform-origin:right center;transform:rotateY(90deg);
  background:linear-gradient(270deg,#333C48 0%,#141A21 100%);
  box-shadow:inset -1px 0 0 rgba(255,255,255,.14);
}
.hero-tv-screen{
  position:absolute;inset:0;overflow:hidden;background:#04223A;
  border-radius:inherit;
  /* the mark is sized against the panel, not the window, so it keeps its share
     of the frame while the set pulls back */
  container-type:size;
}

/* the screen itself: the same mesh gradient as the room, framed as a panel
   rather than a room. the wash underneath is the fallback for a browser that
   will not give us WebGL. */
.screen-bg{
  position:absolute;inset:0;border-radius:inherit;overflow:hidden;
  container-type:size;
  background:
    radial-gradient(54% 46% at 100% 102%,#01050A 0%,rgba(1,5,10,.88) 22%,rgba(2,16,28,.4) 48%,rgba(2,20,32,.1) 68%,rgba(2,20,32,0) 84%),
    linear-gradient(90deg,#25497C 0%,#1B406E 9%,#0B2C4C 19%,#052745 27%,#04223A 42%,#04223A 60%,#03243F 72%,#031F35 86%,#021A2B 100%);
}
.screen-mesh{position:absolute;inset:0;width:100%;height:100%;display:block;opacity:0;transition:opacity .9s var(--ease)}
.screen-mesh.is-live{opacity:1}

/* the mark and the words sit together at the centre of the panel, and leave it
   as the set leans back — gone by the time the frame is on screen */
/* the mark sits dead centre of the panel — at rest and, more to the point, at
   the end of the pull-back, where it is the only thing left on the screen. the
   words hang below it out of flow, so their going does not drag it off centre. */
.screen-lockup{
  position:absolute;left:50%;top:50%;
  /* the last nudge is for the 3D: once the set has leaned back, the projected
     centre of the panel sits a little above the middle of its bounding box, so
     the lockup climbs by the same share to stay on the optical centre */
  transform:translate(-50%,-50%) translateY(calc(var(--p,0) * -4.6cqh));
  display:flex;align-items:center;justify-content:center;
  width:100%;padding:0 6%;pointer-events:none;
}
.screen-mark{
  height:clamp(64px,19cqh,196px);width:auto; /* sized to the plane, not the width —
     the box is far wider than it is tall */
  filter:drop-shadow(0 12px 30px rgba(24,74,168,.42));
}
.screen-title{
  position:absolute;left:50%;top:calc(100% + clamp(16px,2.6vh,32px));
  width:100%;
  font-family:"Montserrat",sans-serif;
  font-size:clamp(1.5rem,3.6vw,3.15rem);
  font-weight:600;line-height:1.06;letter-spacing:-.026em;
  color:#EDF3FF;text-align:center;text-wrap:balance;
  text-shadow:0 14px 46px rgba(6,26,58,.55);
  opacity:calc(1 - var(--p,0) * 3.6);
  transform:translate(-50%,calc(var(--p,0) * -26px));
}

.hero-tv-glare{
  position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(124deg,rgba(255,255,255,.03) 0%,rgba(255,255,255,.006) 18%,transparent 34%);
  opacity:calc(1 - var(--p,0) * .55); /* the sheen slips off as the plane tips away */
}

/* light leaving the set. the screen is the only source in the room, so once it
   has leaned back it throws a small, soft halo onto the floor — no fan, no hard
   edge, nothing bright. keyed to --p, so it is absent while still full-bleed. */
.hero-spill{
  position:absolute;left:50%;top:0;width:1px;height:1px;z-index:2;
  pointer-events:none;opacity:calc(var(--p,0) * var(--p,0));
  will-change:opacity;
}
.hero-spill::before{ /* the pool on the floor — small, but carrying the screen's blue */
  content:"";position:absolute;left:50%;top:100%;
  width:min(780px,53vw);height:min(260px,26vh);
  transform:translate(-50%,-12%);
  /* no filter:blur. these two sit directly on top of the copy, and a blurred
     layer is a separate render surface with its own filter region — two of them
     hovering over live text is exactly the kind of thing that repaints in
     pieces. the radial already has a soft falloff, so the blur was buying a
     smoothing nobody can see and costing a surface nobody needs. */
  background:radial-gradient(closest-side,rgba(48,118,232,.36) 0%,rgba(28,76,178,.16) 46%,rgba(10,38,104,0) 78%);
}
.hero-spill::after{ /* a whisper of bloom right under the bottom rail */
  content:"";position:absolute;left:50%;top:100%;
  width:min(580px,41vw);height:min(160px,17vh);
  transform:translate(-50%,-34%);
  background:radial-gradient(closest-side,rgba(66,138,244,.26) 0%,rgba(36,94,202,.12) 52%,rgba(12,46,126,0) 80%);
}
/* the copy lives in its own block after the banner — a plain sibling in the
   flow, on the same --seam ground the banner settles into. it inherits nothing
   from the banner: not the 3D context, not the overflow clip, not the scroll
   variables. there is nothing left for the panel's animation to disturb. */
.hero-foot{
  position:relative;
  z-index:1;
  background:var(--seam);
  padding:clamp(30px,4.2vh,54px) 0 clamp(48px,6.4vh,78px);
  text-align:center;
}
.hero-copy{position:relative;z-index:1}
/* the copy at the foot of the banner is never gated on anything. it is opaque
   in the base stylesheet, and the entrance is a plain keyframe with NO fill
   mode and NO delay — so the element can only be transparent while the
   animation is actually running, and if it never runs (or is cancelled, or the
   tab was restored) the base style simply applies and the words are there.
   nothing in main.js, no class, no observer and no load event is involved. */
.hero-copy > *{opacity:1;transform:none;animation:copyIn .85s var(--ease)}
@keyframes copyIn{
  from{opacity:0;transform:translateY(22px)}
  to{opacity:1;transform:none}
}
/* the banner's words are the page's top level, so they are set well clear of
   the section headings below rather than a hair above them: at every width the
   hero title runs about a third larger than an h2, and the hero's lead sits a
   step above a section lead. */
.hero-title{
  font-size:clamp(2.6rem,5.4vw,4.7rem);
  line-height:1.06;
  letter-spacing:-.03em;
  text-wrap:balance;
}
.hero-title .line{display:block}
.hero-lead{
  margin:clamp(18px,2.2vh,28px) auto 0;
  max-width:52ch;
  font-size:clamp(1.02rem,1.3vw,1.2rem);
  font-weight:500;
  line-height:1.68;
  text-wrap:pretty;
}

/* there used to be a fade strip here, painting --seam over the last 96px of
   the banner. it also painted over the bottom of the panel, which is why the
   set appeared to dissolve into the copy. the banner's own background already
   lands on --seam, so nothing is needed to join the two. */

/* ─────────────── sections ─────────────── */
.section{position:relative;padding:clamp(96px,10.4vw,164px) 0}
.section--tint{background:var(--ink-850)}
.sec-head{text-align:center;margin-bottom:clamp(46px,5.2vw,68px)}
.sec-head h2{margin-inline:auto;text-wrap:balance}
.sec-head .lead{margin:clamp(16px,1.7vw,22px) auto 0;max-width:56ch;text-wrap:balance}

/* ─────────────── every screen ─────────────── */
/* the one band that is still on --seam. the banner settles on that value and
   the sync section opens on it, so this sits flat between the two and neither
   join needs a ramp. the only light is a low pool behind the lineup, carried
   over from the panel above so the band does not read as a gap. */
.section-screens{
  background:var(--seam);
  /* the standard section pad on top, not a reduced one: the hero's copy block
     already carries 64px of its own foot, and with only 48–80px here the band
     started a breath under the last line of the banner. the sync section below
     still carries a deep pad of its own, so the foot stays tight — anything
     more and the two stack into a hole under the lineup. the foot is a touch
     deeper than it used to be because the three front devices now stand ~4%
     of the stage below the box, and that overhang has to land in this pad
     rather than on the next section. */
  padding:clamp(96px,10.4vw,164px) 0 clamp(52px,5.6vw,86px);
}
.section-screens::before{
  content:"";position:absolute;left:50%;top:34%;
  width:min(1040px,92vw);height:clamp(260px,32vw,420px);
  transform:translateX(-50%);pointer-events:none;
  background:radial-gradient(closest-side,rgba(66,138,244,.16),rgba(36,94,202,.055) 54%,rgba(12,46,126,0) 82%);
}

/* the lineup. a panel at the back, four devices standing in front of it on one
   floor line, all straight on.
   the proportions are taken off the reference shot, not off the hardware: the
   panel is 78.7% of the stage, the MacBook 38.6%, the iPad 31.5% and the phone
   9%. that is roughly twice life-size against the TV — a lineup
   at true scale puts the phone at a twentieth of the panel and it disappears,
   which is why product shots never use it either. */
.eco{
  position:relative;
  aspect-ratio:1080/612;
  margin-top:clamp(24px,2.8vw,46px);
}
/* the floor line sits below the stage box, not on its edge: the three front
   devices used to stand right on the box bottom, which buried the panel's
   whole bottom third — including the catalogue row. dropping them ~7% of the
   stage height hands that strip back to the screen and reads as a taller wall
   behind them. the overhang is paid for by the section's foot pad. */
.eco-dev{position:absolute;bottom:-4%}
.eco-body{display:block;width:100%;height:auto;position:relative;z-index:2}

/* the panels are cut out of their photographs — the glass is a hole, not a
   picture of a screen. this sits behind the hole and gives it something to be:
   a dark panel that is very slightly lighter than the page, so a switched-off
   screen still reads as a screen. dropping artwork in later means filling this
   box, nothing else. */
.eco-slot{
  position:absolute;z-index:1;
  background:
    linear-gradient(146deg,rgba(140,180,255,.055) 0%,rgba(140,180,255,0) 42%),
    linear-gradient(168deg,#101A2B 0%,#0A101C 58%,#0D1523 100%);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.06);
  border-radius:2px;
  overflow:hidden;
}
/* the slot is a hole in the cut-out body, so whatever sits in it is the
   screen. the screenshot is 16:9 and so is the glass, so cover is exact. */
.eco-slot img{display:block;width:100%;height:100%;object-fit:cover;border-radius:inherit}

/* the panel is the backdrop: it sits high and its lower third is covered by
   the four devices, exactly as in the reference. */
.eco-dev--tv{left:10.5%;top:3.3%;bottom:auto;width:78.7%;z-index:1}
.eco-dev--tv .eco-slot{left:.688%;top:1.532%;width:98.625%;height:97.046%;border-radius:.4%/.7%}
/* a black bezel on a near-black band needs a reason to be visible: the panel
   is lit, so a little of it lands on the wall around it. */
.eco-dev--tv .eco-body{
  filter:
    drop-shadow(0 0 .8px rgba(190,214,255,.55))
    drop-shadow(0 0 34px rgba(70,132,255,.16))
    drop-shadow(0 6px 10px rgba(0,0,0,.6))
    drop-shadow(0 26px 42px rgba(0,0,0,.6));
}

.eco-dev--ipad{left:3.7%;width:31.5%;z-index:2}
.eco-dev--ipad .eco-slot{left:3.6667%;top:5.0469%;width:92.75%;height:90.0235%;border-radius:1.89%/2.87%}

.eco-dev--mac{right:1.4%;width:38.6%;z-index:2}
.eco-dev--mac .eco-slot{left:9.7857%;top:4.4496%;width:80.4286%;height:82.4356%;border-radius:1.16%/1.85%}

.eco-dev--mac .eco-body,
.eco-dev--ipad .eco-body{
  filter:
    drop-shadow(0 0 .7px rgba(190,214,255,.5))
    drop-shadow(0 4px 7px rgba(0,0,0,.55))
    drop-shadow(0 20px 34px rgba(0,0,0,.55));
}

/* the phone leans on the tablet's right edge, a step forward in z, because a
   device that covers another one has to be in front of it. */
.eco-dev--phone{left:29.4%;width:9%;bottom:-5.8%;z-index:3}
.eco-dev--phone .eco-slot{left:4.375%;top:1.8196%;width:91.25%;height:96.4367%;border-radius:15.24%/7%}
.eco-dev--phone .eco-body{
  filter:
    drop-shadow(0 0 .7px rgba(200,222,255,.6))
    drop-shadow(0 3px 5px rgba(0,0,0,.6))
    drop-shadow(0 14px 24px rgba(0,0,0,.6));
}

/* the stage keeps its aspect down to a phone, so the ratios hold everywhere;
   only the gap to the copy above needs to come in. */
@media (max-width:760px){
  .eco{margin-top:18px}
}

/* ─────────────── sync ─────────────── */
/* the join with the banner is a long monotonic ramp on both sides of the
   boundary: the banner settles into --seam, this section opens on the very
   same value and lets it fall away over 340px. equal colours at the join, and
   nothing changes direction there, so no edge can read as a cut. */
.section-sync{
  padding-top:clamp(92px,9.6vw,142px);
  /* the section sits on its own panel so it reads as one block against the
     shelf below it. the ramp still opens on --seam, the exact value the banner
     settles on, and dissolves into the panel colour by 340px — the join is
     unchanged, the new floor simply emerges from it. */
  background-color:var(--ink-850);
  background-image:linear-gradient(180deg,var(--seam) 0%,rgba(8,11,18,.52) 46%,rgba(8,11,18,0) 100%);
  background-repeat:no-repeat;
  background-size:100% 340px;
}

/* three screens, one film. every device is drawn here — body, bezel, glare,
   deck — so the light can be keyed to the panel it lands on instead of being
   baked into a picture. the room's key light sits behind them. */
.sync-stage{
  position:relative;
  margin-top:clamp(16px,2.4vw,32px);
  aspect-ratio:16/7.1;
  perspective:1900px;
  perspective-origin:50% 44%;
  isolation:isolate;
}

/* every device is the hardware's own photograph, cut out of its backdrop. the
   panel is a hole in that cutout, so the film sits behind the body and the
   machine's bezel crops it: the glass can be lit, darkened and glinted
   without drawing a single edge of the hardware by hand. the four numbers on
   each device are that hole's position inside its cutout — left / top /
   width / height — measured off the file. */
.dev{position:absolute;margin:0;transform-style:preserve-3d;will-change:transform}
/* a soft pool of shade under each machine. the panel is nearly black, so a
   plain drop-shadow has nowhere to fall — it can only darken a colour that is
   already #0E1420, which reads as nothing at all. a wide, low ellipse sitting
   just under the deck gives the eye the one cue it needs: the light around the
   object is dimmer than the light beside it. it lives in the device's own
   plane, so it tilts and turns with the hardware instead of floating flat. */
.dev::after{
  content:"";position:absolute;z-index:0;pointer-events:none;
  left:var(--sh-x,-6%);right:var(--sh-x,-6%);
  bottom:var(--sh-y,-15%);height:var(--sh-h,30%);
  background:radial-gradient(ellipse at 50% 38%,
    rgba(0,0,0,.92) 0%,
    rgba(0,0,0,.6) 26%,
    rgba(0,0,0,.28) 46%,
    rgba(0,0,0,.09) 64%,
    rgba(0,0,0,0) 80%);
}
.dev-body{display:block;width:100%;height:auto;position:relative;z-index:2}
.dev-screen{
  position:absolute;z-index:1;overflow:hidden;border-radius:2px;background:#02050A;
}
.dev-screen img{
  display:block;width:100%;height:100%;object-fit:cover;
  filter:brightness(.17) saturate(.4) contrast(1.06);
  transition:filter 1.05s var(--ease);
}
/* a portrait panel letterboxes a 16:9 frame — the bars are the tell that it is
   the same file, not a second crop */
.dev-screen--fit img{object-fit:contain}

.dev-fill{
  position:absolute;inset:0;
  background:linear-gradient(180deg,rgba(7,16,30,.5),rgba(2,6,12,.74));
  transition:opacity 1.05s var(--ease);
}
.dev-glare{
  position:absolute;inset:0;
  background:linear-gradient(126deg,rgba(255,255,255,.15) 0%,rgba(255,255,255,.03) 24%,transparent 44%);
  opacity:.32;transition:opacity 1.05s var(--ease);
}
/* awake */
.dev.is-on .dev-screen img{filter:brightness(1) saturate(1) contrast(1)}
.dev.is-on .dev-fill{opacity:0}
.dev.is-on .dev-glare{opacity:.75}

/* laptop — set down a little off-square: turned towards the right, tipped
   forward, and rolled a degree or two so it sits like an object on a table
   rather than a diagram on a page. */
.dev--mac{
  left:4%;bottom:6%;width:46%;z-index:2;
  --sh-x:-4%;--sh-y:-13%;--sh-h:30%;
  transform:rotateY(14deg) rotateX(6deg) rotate(2.4deg);
}
.dev--mac .dev-body{
  /* three stacked drop-shadows instead of one: a tight contact line at the
     deck, a mid falloff that carries the machine's weight, and a wide ambient
     pool. one big blur alone reads as a grey halo on a dark panel — the stack
     is what makes it look like light falling off an object. */
  filter:
    drop-shadow(0 3px 4px rgba(0,0,0,.55))
    drop-shadow(0 18px 26px rgba(0,0,0,.5))
    drop-shadow(0 48px 76px rgba(0,0,0,.62));
}
/* the panel is a hole, and a hole has a radius. matching it keeps the film's
   square corners from poking out past the machine's rounded silhouette — the
   two radii are the hole's corner measured off the cutout, as a share of the
   panel's width and height (a circle stays a circle only in px, so both axes
   have to be given). */
.dev--mac .dev-screen{
  left:9.7857%;top:4.4496%;width:80.4286%;height:82.4356%;
  border-radius:1.16% / 1.85%;
}

/* tablet — landscape, turned a little into the light */
.dev--pad{right:24%;top:10%;width:25%;z-index:3;--sh-x:-7%;--sh-y:-20%;--sh-h:36%;transform:rotateY(-16deg) rotateX(4deg) rotate(1.6deg)}
.dev--pad .dev-body{
  filter:
    drop-shadow(0 2px 3px rgba(0,0,0,.5))
    drop-shadow(0 14px 20px rgba(0,0,0,.46))
    drop-shadow(0 40px 62px rgba(0,0,0,.56));
}
.dev--pad .dev-screen{
  left:3.6667%;top:5.0469%;width:92.75%;height:90.0235%;
  border-radius:1.89% / 2.87%;
}

/* phone — the nearest object, so it takes the strongest shadow. its island is
   part of the cutout, so it sits over the film for free: no drawn notch, and
   nothing to drift out of place when the frame is letterboxed. */
.dev--phone{right:6%;top:33%;width:12.5%;z-index:4;--sh-x:-18%;--sh-y:-17%;--sh-h:28%;transform:rotateY(-20deg) rotateX(3deg) rotate(6deg)}
.dev--phone .dev-body{
  /* the nearest object: the contact line is sharpest and the pool tightest,
     which is the one cue that keeps the three at different distances. */
  filter:
    drop-shadow(0 2px 3px rgba(0,0,0,.6))
    drop-shadow(0 12px 17px rgba(0,0,0,.55))
    drop-shadow(0 30px 46px rgba(0,0,0,.66));
}
/* the phone's glass is the roundest of the three — 15% of the panel's width —
   which is exactly why it needed its own radius: at 2px the film's corners sat
   well outside the body's silhouette and the picture leaked over the bezel. */
.dev--phone .dev-screen{
  left:4.375%;top:1.8196%;width:91.25%;height:96.4367%;
  border-radius:15.24% / 7.0%;
}

/* the spark: one small light, nothing trailing it */
.spark{
  position:absolute;left:0;top:0;z-index:6;pointer-events:none;
  width:9px;height:9px;margin:-4.5px 0 0 -4.5px;border-radius:50%;opacity:0;
  background:radial-gradient(circle,#FFFFFF 0%,#CFE0FF 34%,#5C8DFF 62%,rgba(92,141,255,0) 74%);
  box-shadow:0 0 10px 2px rgba(126,170,255,.9),0 0 30px 9px rgba(64,116,255,.45);
  will-change:transform,opacity;
}

.note-row{display:flex;flex-wrap:wrap;gap:14px 40px;margin-top:26px;justify-content:center}
.note-row li{display:flex;align-items:center;gap:9px;font-family:"Montserrat",sans-serif;font-size:.76rem;color:var(--text-3)}
.note-row li::before{content:"";width:14px;height:1px;background:var(--blue-lift);opacity:.6}

/* ─────────────── one shelf: a field of sources, the copy in its centre ─────────────── */
/* the block is not a panel. it is a field of square tiles with the headline
   sitting in the clear air at the middle. the tiles are no longer on a grid:
   each one is drawn at a size inside a narrow band, dropped somewhere in the
   field, and given a depth. depth is the only thing that is not chance — it
   decides how soft the tile is and whether it sits in front of or behind its
   neighbours, so the field reads as a stack with a focal plane instead of as a
   flat pattern. the draw itself happens in main.js, which rejects anything that
   would overlap the copy or a tile already placed. the numbers below are the
   fallback for a page without that script: a single centred column of marks. */
.hub{
  position:relative;
  max-width:1160px;margin:0 auto;
  aspect-ratio:1160/772;
}
.hub-grid{
  position:absolute;inset:0;list-style:none;margin:0;padding:0;
  /* the field contracts toward the middle while it is still ahead of the reader
     and opens out as it arrives. it is a uniform scale and not a per-tile pull
     for one reason: a uniform scale is the only move that keeps the air between
     tiles constant, so gathering can never create an overlap. */
  transform:scale(var(--g,1));transform-origin:50% 50%;
}

/* the hole the tiles keep clear. it is measured by the script, so it has a
   fixed width rather than one that follows the text — a hole that changes size
   with the copy would make the scatter unrepeatable between viewports. */
.hub-copy{
  position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  width:min(540px,52%);z-index:90;
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  text-align:center;
}
.hub-copy h2{margin:0}
.hub-copy .lead{
  margin:clamp(12px,1.2vw,16px) auto 0;
  max-width:56ch;font-size:clamp(1rem,1.05vw,1.05rem);line-height:1.62;
}

.src{
  position:absolute;
  left:calc(var(--x,50) * 1%);
  top:calc(var(--y,50) * 1%);
  width:calc(var(--w,13) * 1%);
  aspect-ratio:1;
  display:flex;align-items:center;justify-content:center;
  border-radius:50%;
  border:1px solid rgba(255,255,255,.07);
  background:
    linear-gradient(155deg,
      hsl(var(--tint,212) 56% 64% / .22) 0%,
      hsl(var(--tint,212) 46% 40% / .06) 58%,
      rgba(255,255,255,.006) 100%);
  overflow:hidden;
  z-index:var(--z,auto);
  /* the pointer lean. --mx/--my live on the block and are eased there, --k is
     each tile's own travel in px, so near tiles lean further than far ones. */
  translate:calc(var(--mx,0) * var(--k,0) * 1px) calc(var(--my,0) * var(--k,0) * 1px);
  /* depth of field. --blur is set per tile by the scatter, --bright pulls the
     far ones down so they sit behind the copy rather than beside it. */
  filter:blur(calc(var(--blur,0) * 1px)) brightness(var(--bright,1));
  transition:border-color .45s var(--ease),transform .55s var(--ease),box-shadow .55s var(--ease);
}
/* a lens, not a lamp — the sheen only catches the top-left corner */
.src::after{
  content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  background:linear-gradient(158deg,rgba(255,255,255,.075) 0%,rgba(255,255,255,.02) 34%,transparent 62%);
}
.src:hover{
  transform:scale(1.04);
  border-color:rgba(160,200,255,.32);
  box-shadow:0 26px 46px -30px rgba(0,0,0,.9);
  z-index:80; /* a tile pulled forward must clear the ones in front of it */
}
.src-logo{width:42%;max-width:36px;aspect-ratio:1;color:rgba(216,232,255,.90)}
.src-logo svg{display:block;width:100%;height:100%}
/* the word tiles carry no mark, so the word is the mark: heavy, tracked out,
   and sized from the tile itself (--fs is written by the scatter) so a large
   tile reads as a title and a small one still fits its own width. */
.src--word{
  font-family:"Montserrat",sans-serif;font-weight:700;
  font-size:var(--fs,16px);line-height:1.1;
  letter-spacing:.06em;text-transform:uppercase;text-align:center;white-space:nowrap;
  /* padding in px, never %: a percentage padding resolves against the block, so
     on a 60px tile it would force the box wider than the tile itself. */
  padding:0 6px;
  color:rgba(232,240,255,.86);
}

/* the tiles assemble in a scatter, not in reading order */
.js .hub .src{
  opacity:0;scale:.94;
  transition:opacity .7s var(--ease) var(--d,0s),scale .7s var(--ease) var(--d,0s),
             border-color .45s var(--ease),transform .55s var(--ease),box-shadow .55s var(--ease);
}
.js .hub.is-in .src{opacity:1;scale:1}

/* ─────────────── playback / marquee ─────────────── */
.section-playback{padding-bottom:clamp(70px,8vw,110px)}
.marquee-block{position:relative;display:flex;flex-direction:column;gap:10px;margin:8px 0 clamp(52px,6vw,76px)}
.marquee{position:relative;overflow:hidden;-webkit-mask-image:linear-gradient(90deg,transparent,#000 9%,#000 91%,transparent);mask-image:linear-gradient(90deg,transparent,#000 9%,#000 91%,transparent)}
/* the track is two identical halves. the gap is carried by each chip instead of
   by the flex container, so half of the track is exactly one set of chips — the
   loop can then move by precisely -50% and land on an identical frame. with the
   gap on the container, -50% fell a few pixels short of the real period and the
   strip crept a little further on every lap. each half is also wide enough on
   its own to cover the widest window, so there is never a blank at the end. */
.marquee-track{position:relative;z-index:1;display:flex;width:max-content;animation:slide 78s linear infinite}
.marquee--b .marquee-track{animation-duration:94s;animation-direction:reverse}
/* glass, dark. the same pane as the reference — a translucent fill, a hairline
   border, a top rule that fades out at both ends, a left rule that runs the
   height — but the fill is ink, not white: on a near-black page a 40% white
   body reads as a paper chip, not as glass. what is left of the light is kept
   where it belongs, on the edges. */
.marquee span{
  position:relative;flex:none;margin-right:12px;padding:12px 22px;
  border-radius:999px;white-space:nowrap;overflow:hidden;
  background:linear-gradient(180deg,rgba(255,255,255,.075) 0%,rgba(255,255,255,.028) 58%,rgba(255,255,255,.045) 100%);
  -webkit-backdrop-filter:blur(8px);
  backdrop-filter:blur(8px);
  border:1px solid rgba(255,255,255,.16);
  box-shadow:
    0 1px 3px rgba(0,0,0,.22),
    inset 0 1px 0 rgba(255,255,255,.30),
    inset 0 -1px 0 rgba(255,255,255,.08);
  font-family:"Montserrat",sans-serif;font-size:.875rem;
  color:rgba(226,236,250,.92);
}
.marquee span::before{
  content:"";position:absolute;top:0;left:0;right:0;height:1px;pointer-events:none;
  background:linear-gradient(90deg,transparent,rgba(255,255,255,.55),transparent);
}
.marquee span::after{
  content:"";position:absolute;top:0;left:0;width:1px;height:100%;pointer-events:none;
  background:linear-gradient(180deg,rgba(255,255,255,.5),transparent,rgba(255,255,255,.2));
}
/* a tag that carries a mark instead of a word. the mark is drawn at the same
   optical height as the type it replaces, so the pill keeps its rhythm.

   the mark is a flex child rather than a block, because a block sits on the
   top edge of the content box: with the pill stretched to the row height the
   wordmark ended up 13px from the top and 20px from the bottom. centred by
   flex it sits on the same optical line as the type beside it.

   each mark carries its own --lh. a two-line lockup (dolby digital, truehd)
   needs the height of both lines; a single-line wordmark only needs the cap
   height, otherwise it out-shouts the 14px text it is sitting next to. */
.marquee span.tag--logo{padding:12px 20px;display:flex;align-items:center;justify-content:center}
.tag-logo{display:block;height:var(--lh,15px);width:auto;fill:currentColor}
@keyframes slide{from{transform:translate3d(0,0,0)}to{transform:translate3d(-50%,0,0)}}

/* the three specs wear the card from procreate.com/dreams: one dark slab, one
   hairline border, a 44px glyph held well above the heading, and the heading
   sitting tight on top of its paragraph. the radius is large enough that the
   card reads as an object rather than a panel — that is the point of the layout
   it is borrowed from: the cards are the content, the page is only the ground
   they sit on. the old version was three columns of loose text under a rule. */
.spec-row{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(14px,1.5vw,20px)}
.spec{
  display:flex;flex-direction:column;
  padding:clamp(24px,2.5vw,30px);
  border-radius:clamp(26px,3.1vw,42px);
  border:1px solid rgba(255,255,255,.07);
  background:linear-gradient(180deg,#111722 0%,#0D121B 100%);
  transition:border-color .5s var(--ease),transform .5s var(--ease);
}
.spec:hover{border-color:rgba(160,200,255,.20);transform:translateY(-3px)}
/* the six spec glyphs are drawn as glass — no plate behind them and no lit
   edge, just a body that runs from a pale top to a deeper foot. the colour
   lives in the shared #ico-tint gradient in the page head. */
.spec-ico{
  display:block;width:44px;height:44px;
  margin-bottom:clamp(24px,3vw,36px);
  filter:drop-shadow(0 1px 2px rgba(0,0,0,.45));
}
.spec-ico svg{display:block;width:100%;height:100%;overflow:visible}
.spec h3{margin-bottom:6px}
.spec p{font-size:.9rem;line-height:1.62;color:var(--text-2)}

/* ─────────────── poster shelf ─────────────── */
/* the band runs the full width of the window and is cut off by both edges —
   six posters sized to fill it, not a centred grid with margins. the pointer is
   a lens: every card's weight --w falls off with the square of its distance
   from the cursor, and that one number drives depth, scale, tilt and light, so
   the band bulges around the cursor and settles flat behind it.

   --act is a separate 0..1 gate for "is the pointer inside the band". without
   it the un-hovered cards would have to sit dimmed all the time — at rest the
   band has to look like a plain, fully lit shelf. */
.section-posters{padding-bottom:clamp(70px,8vw,110px)}
/* no overflow:hidden here. the hovered card grows by a quarter and throws a
   70px shadow, and clipping it at the box edge cut both the top of the poster
   and the shadow under it. the padding is only breathing room; nothing is cut.

   the top pad is sized to the card's actual upward travel, not to taste: a
   hovered card lifts 18px, scales 1.17 and is pushed 150px down the z axis,
   which at 1600px perspective puts its top edge ~73px above where it rests at
   1440px wide. anything less than that and the poster runs up into the copy
   above it. the inline pad is the same sum on the horizontal axis — the outer
   posters grow past x=0 and x=100vw on hover, and with body{overflow-x:hidden}
   that growth was being shaved off the window edge. 2.7vw is just over the
   0.145 * cardwidth the scale throws, at every breakpoint. */
.shelf-viewport{
  position:relative;
  perspective:1600px;
  /* x is written every frame by the lens (see main.js); 50% is the resting
     centre it falls back to when the pointer is gone. */
  perspective-origin:var(--pox,50%) 46%;
  padding:clamp(56px,6.2vw,96px) 2.7vw clamp(52px,5.6vw,86px);
}
/* the dust the reveal sheds. it is a fixed, full-viewport layer rather than a
   band-sized one: motes are supposed to keep drifting after they leave the
   posters, cross the copy above and below, and burn out somewhere in the page.
   clipping them to the shelf turned them into a strip of sparkle that stopped
   dead at an invisible line. one canvas for the whole page, in screen
   coordinates, so a mote's position never has to be re-mapped on scroll. */
.shelf-motes{
  position:fixed;inset:0;z-index:70;
  pointer-events:none;
  mix-blend-mode:screen;
}
.shelf{
  --act:0;
  --tilt:0;
  /* the row fills whatever the viewport pad leaves it — the viewport's 2.7vw is
     the room the outer posters need to grow into on hover, not a design gutter. */
  position:relative;
  display:flex;align-items:flex-start;justify-content:center;
  gap:clamp(8px,1vw,15px);
  width:100%;
  transform-style:preserve-3d;
  transform:rotateX(calc(var(--tilt,0) * 1deg));
}
/* no transition on transform: --w is written every frame from js, and a css
   transition on top of that would re-start on each write and trail the cursor */
.poster{
  --w:0;
  position:relative;margin:0;
  flex:1 1 0;min-width:0;
  display:flex;flex-direction:column;gap:9px;
  transform-style:preserve-3d;
  transform:
    translate3d(0, calc(var(--w) * -18px), calc(var(--w) * 150px))
    rotateY(calc(var(--ry,0) * 1deg))
    scale(calc(1 + var(--w) * .17));
  will-change:transform;
}

/* the poster itself: the still, a scrim, and type set on top of it. the scrim
   is what makes a photograph read as a poster — without it the title has to
   fight the image, and the bottom of every still is where the detail lives. */
.poster-art{
  position:relative;width:100%;aspect-ratio:2/3;
  border-radius:12px;overflow:hidden;
  background:#0a0e15;
  /* three layers, because a drop shadow on a #05070b page is a shadow on
     nothing: the cast shadow does the lifting, the 1px ring is what actually
     separates the still from the background, and the tight contact shadow
     stops the card from floating free of the shelf. */
  box-shadow:
    0 calc(16px + var(--w) * 30px) calc(38px + var(--w) * 34px) -20px rgba(0,0,0,.95),
    0 0 0 1px rgba(255,255,255,calc(.045 + var(--w) * .085)),
    0 calc(var(--w) * 9px) calc(var(--w) * 24px) -10px rgba(0,0,0,.85);
  filter:brightness(calc(1 - var(--act) * (1 - var(--w)) * .32))
         saturate(calc(1 - var(--act) * (1 - var(--w)) * .2));
}
.poster-art img{width:100%;height:100%;object-fit:cover;display:block}
/* the blank cell. every poster in the shelf starts as the same dark film
   strip, and the shelf only gives up its artwork once it is on screen: one
   circle centred on the band grows out of the middle and carries the art with
   it, so the middle posters open first and the outer ones last. the mask
   centre and the radius are both written by js — the centre is fixed, the
   radius animates. */
.poster-cover{
  display:none;
  position:absolute;inset:0;z-index:1;pointer-events:none;
  background:#0a0e15 url("../img/posters/cover.jpg") center/cover no-repeat;
  -webkit-mask-image:radial-gradient(circle var(--tr,0px) at var(--tx,50%) var(--ty,50%),
    rgba(0,0,0,0) 0 46%,rgba(0,0,0,.5) 68%,#000 100%);
  mask-image:radial-gradient(circle var(--tr,0px) at var(--tx,50%) var(--ty,50%),
    rgba(0,0,0,0) 0 46%,rgba(0,0,0,.5) 68%,#000 100%);
}
/* only when the reveal is actually wired up — a phone, a touch screen or a
   reduced-motion visitor gets no cover at all, because they would be left
   staring at six blank cells with no way to open them. */
.shelf.is-reveal .poster-cover{display:block}
/* opened: the placeholder is removed, not just masked away */
.shelf.is-open .poster-cover{display:none}

/* the type belongs to the artwork, so it arrives with it — one fade per card,
   driven by how far the wave has crossed that card, not by a delay on the whole
   shelf. while the blank cell is up there is nothing on the poster at all; a
   title floating on a placeholder is what gave the old shelf away as a mock-up.
   --tt is written every frame from js, so there is no transition here to fight
   it. */
.shelf.is-reveal .poster-type{
  opacity:var(--tt,0);
  transform:translateY(calc((1 - var(--tt,0)) * 7px));
}
.poster-art::after{
  content:"";position:absolute;inset:0;z-index:2;pointer-events:none;
  background:linear-gradient(180deg,transparent 40%,rgba(3,6,12,.5) 72%,rgba(3,6,12,.92) 100%);
}
.poster--top .poster-art::after{
  background:linear-gradient(0deg,transparent 50%,rgba(3,6,12,.32) 78%,rgba(3,6,12,.86) 100%);
}

/* a real one-sheet is bottom-weighted: a small studio line, a tagline, the
   title, then the billing block — the dense grey bar of names that every
   poster carries and almost no web layout reproduces. that bar is what makes
   the block below read as a poster rather than as a caption on a photo, so
   every one of the six gets one. */
.poster-type{
  position:absolute;left:0;right:0;bottom:0;z-index:3;
  display:flex;flex-direction:column;gap:0;
  align-items:center;text-align:center;
  padding:0 clamp(10px,.9vw,16px) clamp(11px,1vw,17px);
  color:var(--title-color,#fff);
}
.poster--top .poster-type{bottom:auto;top:0;padding:clamp(11px,1vw,17px) clamp(10px,.9vw,16px) 0}
.poster--left .poster-type{align-items:flex-start;text-align:left}
.poster--right .poster-type{align-items:flex-end;text-align:right}

.p-kick{
  font-family:"Montserrat",sans-serif;
  font-size:clamp(5.6px,.5vw,7.6px);font-weight:600;
  letter-spacing:.32em;text-transform:uppercase;opacity:.62;
  text-indent:.32em;
  margin-bottom:clamp(6px,.7vw,10px);
}
.p-title{
  font-family:var(--title-font,"Montserrat",sans-serif);
  font-size:var(--title-size,clamp(15px,1.42vw,25px));
  font-weight:var(--title-w,700);
  letter-spacing:var(--title-ls,-.012em);
  line-height:var(--title-lh,.94);
  text-transform:var(--title-case,uppercase);
  text-shadow:0 1px 16px rgba(0,0,0,.6),0 0 40px rgba(0,0,0,.45);
}
.p-tag{
  font-family:"Archivo",sans-serif;
  font-size:clamp(6.6px,.56vw,9.4px);line-height:1.36;
  letter-spacing:.02em;opacity:.7;max-width:100%;text-wrap:balance;
  margin-top:clamp(4px,.45vw,6px);
}
/* the billing block: names in a tight, grey, tracked-out grid. it is texture,
   not reading matter — at this size the words only have to look like credits. */
.p-bill{
  font-family:"Archivo",sans-serif;
  font-size:clamp(4.2px,.38vw,5.8px);line-height:1.5;
  letter-spacing:.16em;opacity:.34;text-transform:uppercase;
  max-width:26ch;margin-top:clamp(6px,.7vw,10px);
  text-indent:.16em;
}
/* a hairline between the words and the title, for the one poster that wants a
   crest rather than a caption */
.p-rule{width:26px;height:1px;background:currentColor;opacity:.45;margin:clamp(4px,.45vw,6px) 0}

/* six stills, six different title treatments — same typeface, different weight,
   size, tracking, case and corner. a poster wall where every title is set the
   same way is a template, not a shelf. */
/* six films, six faces. a shelf where every title is set in the same face at a
   different weight reads as a template; these are five different typefaces
   across six posters, each placed where its own still leaves room. */
/* noir: a light geometric, opened up — the studio thriller */
.poster--noir{
  --title-font:"Montserrat";--title-size:clamp(13px,1.18vw,21px);
  --title-w:300;--title-ls:.135em;
}
/* sci-fi: monospace, set tight and left, the way a readout is set */
.poster--orbit{
  --title-font:"Space Mono";--title-size:clamp(13px,1.2vw,21px);
  --title-w:700;--title-ls:-.035em;--title-lh:1.02;
}
/* 70s road movie: condensed caps, huge, over the sky */
.poster--heat{
  --title-font:"Bebas Neue";--title-size:clamp(24px,2.6vw,46px);
  --title-w:400;--title-ls:.055em;--title-lh:.9;--title-color:#fff4ee;
}
/* period drama: a serif, tracked, with a hairline over it */
.poster--crown{
  --title-font:"Playfair Display";--title-size:clamp(15px,1.44vw,26px);
  --title-w:600;--title-ls:.03em;--title-lh:1.04;--title-color:#f1ddb6;
}
/* indie drama: archivo squeezed to its narrowest axis, mixed case */
.poster--field{
  --title-font:"Archivo";--title-size:clamp(15px,1.36vw,24px);
  --title-w:600;--title-ls:.035em;--title-lh:1;--title-case:none;--title-color:#f7e9d6;
}
.poster--field .p-title{font-variation-settings:"wdth" 62}
/* thriller: archivo at full width, heavy and tight, set to the right edge */
.poster--deep{
  --title-font:"Archivo";--title-size:clamp(15px,1.46vw,26px);
  --title-w:700;--title-ls:-.03em;--title-lh:.9;--title-color:#e4f5ff;
}

/* the shelf label sits under the poster, not on it — the still is the artwork,
   this is the catalogue entry.
   it travels with the card, so the focused one drops ~26px and widens by a
   quarter; beside six captions that all sit at the same opacity that reads as
   two labels fighting. while the lens is live the others step back almost to
   nothing and the focused entry is the only one you can read. */
.poster figcaption{
  /* title over year, stacked — a catalogue entry reads as a block, not a
     stretched row. left-aligned because the poster edge is the margin. */
  display:flex;flex-direction:column;align-items:flex-start;gap:1px;
  padding:0 clamp(2px,.25vw,5px);
  /* w cubed, so the falloff is sharp: the focused entry stays at full strength
     and its two neighbours — which still carry w~0.65 and so are the ones that
     would collide with it — are down to about a third. */
  opacity:calc((.7 + var(--w) * .3) *
    (1 - var(--act) * (1 - var(--w) * var(--w) * var(--w)) * .92));
}
.poster figcaption strong{font-family:"Montserrat",sans-serif;font-size:clamp(.72rem,.78vw,.82rem);font-weight:500;line-height:1.2;color:var(--text)}
.poster figcaption span{font-family:"Montserrat",sans-serif;font-size:clamp(.66rem,.7vw,.74rem);line-height:1.2;color:var(--text-3)}

/* a phone has no pointer to be the lens, and six posters squeezed into 390px
   are six slivers. below the breakpoint the stage is dropped and the band
   becomes a plain snap-scrolling strip. */
@media (max-width:760px), (hover:none){
  .shelf-viewport{
    perspective:none;overflow-x:auto;overflow-y:hidden;
    scroll-snap-type:x mandatory;scrollbar-width:none;
    padding:6px 0 18px;
  }
  .shelf-viewport::-webkit-scrollbar{display:none}
  .shelf{
    width:auto;margin-inline:0;transform:none;
    justify-content:flex-start;gap:12px;padding:0 var(--gutter);
  }
  .poster{
    flex:0 0 clamp(150px,46vw,208px);
    scroll-snap-align:center;transform:none;will-change:auto;
  }
  .poster-art{filter:none;box-shadow:0 16px 32px -20px rgba(0,0,0,.9)}
  .poster figcaption{opacity:1}
}

/* ─────────────── features bento ─────────────── */
.bento{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:14px}
.feat{
  grid-column:span 1;
  padding:30px 26px 28px;border-radius:var(--radius);
  border:1px solid var(--line);
  background:linear-gradient(180deg,rgba(255,255,255,.026),rgba(255,255,255,.006));
  transition:border-color .35s var(--ease),background-color .35s var(--ease),transform .35s var(--ease);
  text-align:left;
}
.feat--wide{grid-column:span 2}
.feat:hover{border-color:rgba(255,255,255,.16);transform:translateY(-2px)}
.feat-icon{
  display:grid;place-items:center;width:38px;height:38px;margin:0 0 18px;
  border-radius:10px;border:1px solid rgba(255,255,255,.09);background:rgba(255,255,255,.03);
}
.feat-icon svg{width:20px;height:20px;fill:none;stroke:var(--blue-pale);stroke-width:1.4;stroke-linecap:round;stroke-linejoin:round;opacity:.9}
.feat p{margin:9px 0 0;font-size:.845rem;line-height:1.62;color:var(--text-2);max-width:46ch}
.feat-tags{display:flex;gap:6px;margin-top:18px;justify-content:flex-start}
.feat-tags span{padding:4px 9px;border-radius:6px;border:1px solid rgba(255,255,255,.075);font-family:"Montserrat",sans-serif;font-size:.66rem;color:var(--text-3)}

/* ─────────────── download ─────────────── */
.section-download{position:relative;overflow:hidden}
.sec-head--download{margin-bottom:clamp(36px,4vw,52px)}

/* five platforms, five cards. the row used to be one ruled table, and the last
   line of each cell named the store — "App Store", "Google Play". the card is
   the link, so the store name was repeating what the hover already said. */
.dl-grid{position:relative;display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:12px}
/* glass, not a panel. no hard border: the edge is a 1px ring drawn by ::after
   that starts bright at the top lip and is gone by the bottom, so the card has
   a lit edge where light would actually catch and dissolves into the page
   everywhere else. the body is a translucent wash plus a backdrop blur, and a
   soft radial glow tracks the pointer inside it. the tilt is driven from js —
   --rx/--ry are written on pointermove and fall back to flat on leave, and the
   transform transition is what animates the way back. */
.dl{
  position:relative;
  display:flex;flex-direction:column;align-items:flex-start;text-align:left;
  padding:26px 22px 24px;
  border-radius:calc(var(--radius) + 4px);
  border:0;
  background:linear-gradient(180deg,rgba(255,255,255,.055),rgba(255,255,255,.016));
  /* no backdrop-filter here, and nothing is lost by leaving it out: the cards
     sit on a flat #070A10 surface, so blur(14px) had no backdrop to soften —
     it was a no-op that cost a composited snapshot. that snapshot is also what
     drew the bug: chromium bounds the blurred backdrop to the layer's raster
     rect and stops it at a hard edge, which showed up as a lighter vertical
     band across the right of a card the moment a sibling's hover forced the
     grid to repaint. the translucent wash alone gives the same glass read. */
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.13),
    0 22px 46px -30px rgba(0,0,0,.95);
  transform:
    perspective(760px)
    rotateX(var(--rx,0deg)) rotateY(var(--ry,0deg))
    translateY(calc(var(--lift,0) * -3px));
  transition:transform .5s var(--ease),box-shadow .5s var(--ease),background .5s var(--ease);
  will-change:transform;
}
.dl::before{
  content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;z-index:0;
  background:radial-gradient(circle 190px at var(--gx,50%) var(--gy,0%),
    rgba(150,196,255,.22),rgba(150,196,255,.07) 42%,transparent 72%);
  opacity:0;transition:opacity .45s var(--ease);
}
.dl::after{
  content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;z-index:2;
  padding:1px;
  background:linear-gradient(180deg,rgba(255,255,255,.32),rgba(255,255,255,.055) 40%,rgba(255,255,255,0) 76%);
  -webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
  -webkit-mask-composite:xor;
  mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
  mask-composite:exclude;
  transition:background .45s var(--ease);
}
.dl > *{position:relative;z-index:1}
/* hover is for the cards that are links. a platform that isn't out yet is a
   <div class="dl dl--soon">: same glass, but it doesn't lift or glow, because
   there is nothing to press. */
a.dl:hover{--lift:1;background:linear-gradient(180deg,rgba(255,255,255,.085),rgba(255,255,255,.026))}
a.dl:hover::before{opacity:1}
a.dl:hover::after{background:linear-gradient(180deg,rgba(255,255,255,.46),rgba(255,255,255,.09) 42%,rgba(255,255,255,0) 78%)}
.dl-glyph{width:22px;height:22px;margin-bottom:18px;fill:none;stroke:var(--blue-pale);stroke-width:1.35;stroke-linecap:round;stroke-linejoin:round;opacity:.85}
.dl-name{font-size:1rem;font-weight:500;font-variation-settings:"wdth" 104}
.dl-meta{font-family:"Montserrat",sans-serif;font-size:.71rem;line-height:1.5;color:var(--text-3);margin-top:4px}
/* the "coming soon" mark is tucked into the card's top-right corner, concentric
   with it: a pill of height h has a corner radius of h/2, so insetting it by
   (card radius − h/2) on both sides puts the pill's curve and the card's curve
   on one centre. the type is the .brand recipe (montserrat, caps, tracked) at
   label size; the right padding gives back the tracking after the last letter. */
.dl > .dl-soon{
  --soon-h:20px;
  position:absolute;
  top:calc(var(--radius) + 4px - var(--soon-h) / 2);
  right:calc(var(--radius) + 4px - var(--soon-h) / 2);
  display:inline-flex;align-items:center;height:var(--soon-h);
  padding:0 calc(9px - .14em) 0 9px;border-radius:calc(var(--soon-h) / 2);
  font-family:"Montserrat",sans-serif;font-size:.6rem;font-weight:600;line-height:1;
  letter-spacing:.14em;text-transform:uppercase;white-space:nowrap;
  color:var(--text-2);
  background:rgba(255,255,255,.05);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.12);
}
/* a platform that isn't out yet recedes as a whole: fainter glass and lip, the
   glyph drops its blue for the text grey, and the words step down a shade. */
.dl.dl--soon{
  background:linear-gradient(180deg,rgba(255,255,255,.032),rgba(255,255,255,.01));
  box-shadow:inset 0 1px 0 rgba(255,255,255,.07),0 22px 46px -30px rgba(0,0,0,.95);
}
.dl--soon::after{opacity:.55}
.dl--soon .dl-glyph{stroke:var(--text-3);opacity:.7}
.dl--soon .dl-name{color:var(--text-3)}
.dl--soon .dl-meta{opacity:.7}
/* the cards come in two rows, one grid each; the space between the rows is the
   grid's own gap so the two read as one wall. */
.dl-grid + .dl-grid{margin-top:12px}
/* two columns on a phone leave a ~160px card: tighten the mark so it still
   clears the glyph down to a 360px screen, and below that drop it into the
   flow under the glyph rather than let the two overlap. */
@media (max-width:640px){
  .dl > .dl-soon{--soon-h:18px;font-size:.55rem;letter-spacing:.1em;padding:0 calc(7px - .1em) 0 7px}
}
@media (max-width:359px){
  .dl > .dl-soon{position:relative;top:auto;right:auto;margin:-8px 0 10px}
}

/* ─────────────── document pages ─────────────── */
/* about, help, contact and the legal pages (generated from pages/ by
   tools/build_pages.py) share one reading column. they have no banner under the
   nav, so the bar gets a solid backing here; on the landing page it floats over
   the set and stays clear. type follows the landing page: montserrat for
   headings and the .brand-style kicker, archivo for reading, the same tokens. */
.doc-page .nav{background:rgba(7,10,16,.92);border-bottom:1px solid var(--line)}
.doc{padding:calc(76px + clamp(48px,6vw,88px)) 0 clamp(72px,8vw,120px)}
.doc-head,.doc-body{max-width:760px}
.doc-head{margin-bottom:clamp(32px,4vw,48px)}
.doc-kicker{
  display:block;margin-bottom:14px;
  font-family:"Montserrat",sans-serif;font-size:.7rem;font-weight:600;
  letter-spacing:.14em;text-transform:uppercase;color:var(--blue-pale);
}
.doc h1{font-family:"Montserrat",sans-serif;font-size:clamp(2rem,4.2vw,3rem);line-height:1.08;letter-spacing:-.024em;text-wrap:balance}
.doc-meta{margin-top:14px;font-family:"Montserrat",sans-serif;font-size:.75rem;color:var(--text-3)}
.doc-body{color:var(--text-2);line-height:1.75;overflow-wrap:break-word}
.doc-body .lead{margin-bottom:1.6em}
.doc-body h2{
  font-family:"Montserrat",sans-serif;font-size:clamp(1.2rem,1.7vw,1.45rem);line-height:1.3;
  letter-spacing:-.01em;color:var(--text);margin:2.6em 0 .8em;
}
.doc-body h3{font-size:1.02rem;font-weight:600;color:var(--text);margin:1.9em 0 .5em}
.doc-body p,.doc-body ul,.doc-body table{margin:0 0 1.1em}
.doc-body ul{list-style:disc;padding-left:1.3em}
.doc-body li{margin:.4em 0}
.doc-body li::marker{color:var(--text-3)}
.doc-body strong{color:var(--text);font-weight:600}
.doc-body code{font-size:.88em;padding:1px 6px;border-radius:6px;background:rgba(255,255,255,.06);color:var(--text)}
.doc-body a{
  color:var(--blue-lift);text-decoration:underline;text-underline-offset:3px;
  text-decoration-color:rgba(110,150,255,.4);transition:text-decoration-color .2s;
}
.doc-body a:hover{text-decoration-color:currentColor}
.doc-body table{width:100%;border-collapse:collapse;font-size:.9rem;line-height:1.55}
.doc-body th,.doc-body td{padding:11px 14px 11px 0;border-bottom:1px solid var(--line);text-align:left;vertical-align:top}
.doc-body th{font-family:"Montserrat",sans-serif;font-size:.7rem;font-weight:600;letter-spacing:.04em;color:var(--text-3)}
.doc-body td:first-child{color:var(--text)}
/* the "short version" box is the download card's glass: same wash, same lit lip. */
.doc-summary{
  margin:0 0 1.6em;padding:22px 24px 8px;border-radius:calc(var(--radius) + 4px);
  background:linear-gradient(180deg,rgba(255,255,255,.055),rgba(255,255,255,.016));
  box-shadow:inset 0 1px 0 rgba(255,255,255,.13),0 22px 46px -30px rgba(0,0,0,.95);
}
.doc-summary p{margin-bottom:.8em}

/* ─────────────── footer ─────────────── */
.footer{background:var(--ink-950);padding:clamp(56px,7vw,80px) 0 34px}
.footer-top{display:grid;grid-template-columns:1.1fr 2fr;gap:clamp(32px,5vw,64px)}
.footer-cols{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:24px}
.footer-cols h4{
  font-family:"Montserrat",sans-serif;font-size:.7rem;font-weight:600;letter-spacing:.04em;
  color:var(--text-3);margin:0 0 12px;
}
.footer-cols a{display:block;padding:5px 0;font-size:.83rem;color:var(--text-2);transition:color .2s}
.footer-cols a:hover{color:var(--text)}
.footer-bottom{
  display:flex;justify-content:space-between;gap:20px;flex-wrap:wrap;
  margin-top:clamp(40px,5vw,60px);padding-top:22px;border-top:1px solid var(--line);
  font-family:"Montserrat",sans-serif;font-size:.68rem;color:var(--text-3);line-height:1.6;
}

/* ─────────────── motion ─────────────── */
.js [data-reveal]{
  opacity:0;transform:translateY(26px);
  transition:opacity .8s var(--ease) var(--d,0s),transform .8s var(--ease) var(--d,0s);
}
.js [data-reveal].is-in{opacity:1;transform:none}

@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{animation-duration:.001ms!important;animation-iteration-count:1!important;transition-duration:.001ms!important}
  .js [data-reveal]{opacity:1;transform:none}
  .hero-title{opacity:1;translate:none}
}

/* ─────────────── responsive ─────────────── */
@media (max-height:800px){
  /* still a clear step above an h2 at 54.4px — the banner stays the loudest
     thing on the page even on a laptop screen */
  .hero-title{font-size:clamp(2.5rem,5.1vw,4.35rem)}
  .hero-lead{margin-top:14px}
  .hero-copy{padding-top:clamp(22px,3vh,34px)}
}

@media (max-width:1024px){
  .bento{grid-template-columns:repeat(2,minmax(0,1fr))}
  .spec-row{grid-template-columns:repeat(2,minmax(0,1fr));gap:14px}
  .spec p{max-width:52ch}
  .dl-grid{grid-template-columns:repeat(3,minmax(0,1fr))}
  .footer-top{grid-template-columns:1fr;gap:44px}
}

@media (max-width:860px){
  .nav-links{display:none}
  .nav-toggle{display:block}
  .hero-stage{perspective:2600px}
  .hero-tv{--tw:min(1040px,92vw,max(240px,(100svh - 380px) * 1.7778))}
  .hero-title{font-size:clamp(2.45rem,7.6vw,3.2rem)}
  .sync-stage{aspect-ratio:16/9.4}
  .dev--mac{left:0;bottom:13%;width:55%}
  .dev--pad{right:15%;top:3%;width:30%}
  .dev--phone{right:2%;top:25%;width:15%}
  /* the shelf is a scrolling strip down here, not a grid — it used to drop the
     last three posters because three columns could not hold six. a strip can. */

  /* the scatter needs a field wider than a phone. below the breakpoint the
     tiles go back to a plain two-column grid and drop their depth entirely —
     a 90px tile with blur on it is a smudge, not a depth cue. */
  .hub{aspect-ratio:auto}
  .hub-copy{position:static;transform:none;width:auto;padding:4px 2% 26px}
  .hub-copy .lead{max-width:34ch}
  .hub-grid{position:static;display:grid;grid-template-columns:repeat(auto-fill,minmax(92px,1fr));gap:10px;transform:none}
  .src{position:static;width:auto;filter:none;translate:none}
  .src--word{font-size:clamp(9px,2.9vw,12px);letter-spacing:.04em;padding:0 4px}
  .src-logo{max-width:52px}
}

@media (max-width:640px){
  .hero{padding-bottom:36px}
  .hero-tv{border-radius:0}
  .hero-lead{font-size:1.06rem;max-width:42ch}
  .sync-stage{aspect-ratio:4/3.1;perspective:1100px}
  .dev--mac{left:0;bottom:8%;width:68%}
  .dev--pad{right:0;top:0;width:36%}
  .dev--phone{right:4%;top:auto;bottom:5%;width:18%}
  .note-row{gap:12px 22px}
  .bento{grid-template-columns:1fr}
  .spec-row{grid-template-columns:1fr}
  .feat--wide{grid-column:span 1}
  .dl-grid{grid-template-columns:1fr 1fr}
  .dl:last-child{grid-column:1 / -1}
  .footer-cols{grid-template-columns:repeat(2,minmax(0,1fr));gap:28px}
}

