/* The store. Same night-time palette and type as the room — chroma lives in
   each plugin's own accent, never in the ink — but a page that reads and
   scrolls like a page. */
:root{
  --bg:#08090A; --panel:#0E0F11; --line:#1C1D20;
  --ink:#E8E6E1; --mid:#ADACA9; --dim:#7A7976;
  --mono:"DM Mono", ui-monospace, Menlo, monospace;
  --grot:"Archivo", system-ui, sans-serif;
  --w:1080px; --gut:clamp(16px, 4vw, 40px);
}
*{ box-sizing:border-box; }
html{ scroll-padding-top:64px; }
body{
  margin:0; background:var(--bg); color:var(--ink);
  font:400 16px/1.55 var(--grot); -webkit-font-smoothing:antialiased;
}
a{ color:inherit; }

/* ---- the curtain ----
   Over everything from the first frame (the markup is first in <body>, and
   this stylesheet blocks rendering), lifted by raiseCurtain() once the page
   is drawn. The failsafe animation lifts it anyway after 5s, so a script
   that never runs can only ever cost a few seconds, never the page. */
.curtain{
  position:fixed; inset:0; z-index:100; display:grid; place-items:center;
  background:var(--bg);
  transition:opacity .35s ease, visibility 0s linear .35s;
  animation:curtain-failsafe 0s linear 5s forwards;
}
.curtain.is-up{ opacity:0; visibility:hidden; }
@keyframes curtain-failsafe{ to{ opacity:0; visibility:hidden; } }
/* The intro: the SOMNA sign coming on like a tube set — a bright line that
   opens into the picture, then the neon catching with a stutter. */
.curtain__mark{
  margin:0; white-space:pre; text-align:left;
  font:400 clamp(6px, 1.5vw, 11px)/1.05 var(--mono);
  color:rgb(151, 219, 255);
  text-shadow:0 0 4px rgba(151, 219, 255, .9), 0 0 14px rgba(151, 219, 255, .55), 0 0 30px rgba(110, 180, 255, .35);
  transform-origin:50% 50%;
  animation:crt-on .9s cubic-bezier(.2, .7, .2, 1) both;
}
@keyframes crt-on{
  0%  { opacity:0; transform:scale(1.25, .006); filter:brightness(3); }
  10% { opacity:1; transform:scale(1.25, .006); filter:brightness(3); }
  30% { opacity:1; transform:scale(1, 1); filter:brightness(1.8); }
  44% { opacity:.2; } 50% { opacity:1; } 58% { opacity:.45; } 64% { opacity:1; filter:brightness(1); }
  100%{ opacity:1; transform:none; filter:none; }
}
/* After the first page of a visit: the cover only, no show. */
.intro-seen .curtain__mark{ display:none; }

/* The fireflies' canvas (fireflies.js), fixed behind everything. The page's
   own layers sit above it; cards and panels are opaque, so the flies only
   show in the margins and the gaps. */
.fireflies{ position:fixed; inset:0; width:100%; height:100%; pointer-events:none; z-index:0; }
main, .ticker, .promise, .foot{ position:relative; z-index:1; }
.sr{ position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0); }

/* ---- the ident ----
   The room's own header — wordmark, the time, on air — rather than a
   marketing hero. Mono and small: it is a broadcast caption, not a pitch. */
.top{
  position:sticky; top:0; z-index:5;
  display:grid; grid-template-columns:1fr auto 1fr; align-items:center;
  padding:16px var(--gut);
  background:var(--bg); border-bottom:1px solid var(--line);
}
.mark{
  justify-self:start; text-decoration:none; text-transform:uppercase;
  font-variation-settings:"wdth" 125, "wght" 500; letter-spacing:.32em; font-size:.8rem;
}
.top__live{
  display:inline-flex; align-items:center; gap:10px;
  font:400 .68rem var(--mono); letter-spacing:.2em; text-transform:uppercase; color:var(--mid);
}
.top__dot{ width:6px; height:6px; border-radius:50%; background:#E24B4B; box-shadow:0 0 8px rgba(226,75,75,.7); animation:onair 2.4s steps(1) infinite; }
@keyframes onair{ 0%,88%{ opacity:1; } 89%,100%{ opacity:.25; } }
.top__support{
  justify-self:end; text-decoration:none;
  font:400 .68rem var(--mono); letter-spacing:.2em; text-transform:uppercase; color:var(--mid);
}
.top__support:hover, .mark:hover{ color:var(--ink); }

/* The channel ticker, as it ran along the bottom of the room. */
.ticker{ overflow:hidden; border-bottom:1px solid var(--line); background:#060708; }
.ticker__run{
  display:inline-block; white-space:pre; padding:9px 0;
  font:400 .64rem var(--mono); letter-spacing:.2em; color:var(--dim);
  animation:ticker 48s linear infinite;
}
@keyframes ticker{ from{ transform:translateX(0); } to{ transform:translateX(-50%); } }

/* ---- the sale sign ----
   SALE in neon, the SOMNA sign's letters wired red like the ON AIR light, on
   a band with its own red spill. It buzzes rather than blinks: a tube that
   is mostly on, with the odd stutter, so it catches the eye without strobing. */
.sale{
  position:relative; z-index:1; overflow:hidden;
  display:flex; align-items:center; justify-content:center; gap:20px;
  padding:12px var(--gut);
  background:radial-gradient(ellipse 60% 120% at 50% 50%, rgba(255, 60, 60, .13), transparent 70%), #0B0607;
  border-bottom:1px solid rgba(255, 90, 90, .28);
}
.sale[hidden]{ display:none; }
/* text-align:left, always. The band centres its text on a phone, and the
   art's lines are different lengths (trailing spaces are trimmed) — centred
   one by one, the letters sheared apart. The block itself is centred by the
   flex layout instead. */
.sale__neon{
  margin:0; white-space:pre; text-align:left; font:400 5.5px/1.05 var(--mono);
  color:#FF5C5C;
  text-shadow:0 0 4px rgba(255, 92, 92, .95), 0 0 14px rgba(255, 60, 60, .65), 0 0 36px rgba(255, 40, 40, .45);
  animation:saleneon 4.6s infinite;
}
@keyframes saleneon{
  0%, 40%, 43%, 45.5%, 100%{ opacity:1; }
  41%{ opacity:.3; } 42%{ opacity:.9; } 44%{ opacity:.15; }
  78%{ opacity:1; } 79%{ opacity:.7; } 79.6%{ opacity:1; }
}
.sale__head{
  margin:0; text-transform:uppercase; color:#FFF4F2;
  font-variation-settings:"wdth" 125, "wght" 520; letter-spacing:.04em; line-height:1;
  font-size:clamp(1.05rem, 2vw, 1.3rem);
  text-shadow:0 0 22px rgba(255, 70, 70, .5);
}
.sale__sub{ margin:3px 0 0; max-width:60ch; font:400 .66rem/1.45 var(--mono); letter-spacing:.06em; color:var(--mid); }
/* One slim line everywhere — it was a full-height band on the store page,
   and the plugins are what the first screen is for. */

/* The tag on every reduced plugin: a little lit sign of its own. */
.tag-sale{
  position:absolute; top:10px; right:10px;
  padding:4px 8px 3px; border-radius:2px;
  font:500 .6rem var(--mono); letter-spacing:.22em; text-transform:uppercase;
  color:#FFE9E7; background:rgba(40, 6, 8, .78);
  box-shadow:inset 0 0 0 1px #FF5C5C, 0 0 14px rgba(255, 60, 60, .55);
  text-shadow:0 0 6px rgba(255, 92, 92, .9);
}
/* Mac only: plain and legible, not a warning sign — a fact about the plugin
   that sits beside its price and above its name. */
.tag-os{
  display:inline-flex; align-items:center; flex:none;
  padding:3px 8px 2px; border-radius:2px; white-space:nowrap;
  font:500 .58rem var(--mono); letter-spacing:.18em; text-transform:uppercase;
  color:var(--ink); box-shadow:inset 0 0 0 1px rgba(232, 230, 225, .32);
}
.hero__meta .tag-os{ margin-right:10px; vertical-align:1px; }
.item__meta{ display:flex; align-items:center; justify-content:space-between; gap:8px; flex-wrap:wrap; }
.tag-sale--inline{ position:static; align-self:center; margin-left:4px; }
.sale-now{ color:#FF7A72; text-shadow:0 0 12px rgba(255, 70, 70, .35); }
.sale-was{ margin-left:6px; font-size:.78em; color:var(--dim); }
.hero__price .hero__now{ color:inherit; }

/* One line of voice, then the guide. Deliberately not a giant headline: the
   plugins are the page, and the first screen is theirs. */
.intro{
  max-width:var(--w); margin:0 auto; padding:clamp(24px, 5vh, 48px) var(--gut) clamp(18px, 3vh, 28px);
  display:grid; grid-template-columns:minmax(0, 1fr) auto; align-items:center; gap:clamp(20px, 4vw, 56px);
}

/* ---- text art ----
   Cells are ~0.6em wide and line-height 1.2, i.e. twice as tall as wide —
   which is why ascii.js samples 2 x 4 per character: square in the picture. */
.tv{ padding:0; background:none; border:0; color:inherit; cursor:pointer; text-align:center; }
.tv[hidden]{ display:none; }
.tv__set{ position:relative; display:block; font:400 11px/1.2 var(--mono); }
/* text-align:left matters: the button centres its text, and the neon word's
   lines are different lengths — centred one by one, its letters would shear
   apart. (It first showed up as the old bezel's stand sliding off centre.) */
.tv pre{ margin:0; font:inherit; white-space:pre; text-align:left; }
/* No bezel: the art floats on the page, a screen's glow with no box round
   it. The dusting fades out toward the edges like a tube. */
.tv__screen, .ascii__screen{ display:block; }
/* Centred under the sign at every width: the sign reserves INSOMNIAC's width,
   which on a laptop is wider than the screen below it. */
.tv__screen{ width:max-content; margin:0 auto; }
.d{ color:rgba(var(--accent), .32); }
.i{ color:rgb(var(--accent)); text-shadow:0 0 6px rgba(var(--accent), .6); }
/* Glimmer's glitter: its own warm white, pushed well past ink brightness,
   with a double glow so each star flares like the pixel logo's. */
.g{
  color:#FFF8E8; font-weight:500;
  text-shadow:0 0 3px rgba(255, 248, 232, .95), 0 0 9px rgba(var(--accent), .9), 0 0 18px rgba(var(--accent), .55);
}

/* The neon sign, in the room's pale blue (its emission, normalised). It
   flickers like a tube near the end of its life: on, a stutter, on. */
.tv__neon{
  margin:0 auto 14px !important; width:max-content;
  font-size:.62em !important; line-height:1.05 !important;
  color:rgb(151, 219, 255);
  text-shadow:0 0 4px rgba(151, 219, 255, .9), 0 0 14px rgba(151, 219, 255, .55), 0 0 30px rgba(110, 180, 255, .35);
  animation:neon 5.5s infinite;
}
@keyframes neon{
  0%, 61%, 64.5%, 67%, 100%{ opacity:1; }
  62%{ opacity:.18; } 63.5%{ opacity:.85; } 64%{ opacity:.12; } 66%{ opacity:.4; }
  85%{ opacity:1; } 86%{ opacity:.55; } 86.6%{ opacity:1; }
}
.tv__label{
  display:block; margin-top:10px;
  font:400 .64rem var(--mono); letter-spacing:.2em; text-transform:uppercase; color:var(--mid);
}
.tv__ch{ color:rgb(var(--accent)); margin-right:10px; }
.tv:focus-visible{ outline:1px solid var(--ink); outline-offset:8px; }

/* Sized to its column: 60 characters at 0.6em each (DM Mono's advance,
   measured — an earlier guess of 0.52em ran the art 9% past its box, and on
   a phone past the edge of the screen), so 100cqw / 36 fills the width. The
   size goes on the text, not the box — cq units measure the nearest
   ANCESTOR container. */
.media--ascii{ position:relative; max-width:560px; container-type:inline-size; }
.media--ascii > pre{ margin:0; white-space:pre; font:400 calc(100cqw / 54) / 1.2 var(--mono); }

.intro__line{
  margin:0; max-width:38ch;
  font-variation-settings:"wdth" 110, "wght" 300; font-weight:300;
  font-size:clamp(1.15rem, 2vw, 1.5rem); line-height:1.3; color:var(--ink);
}
.intro__sub{ margin:8px 0 0; color:var(--dim); font:400 .74rem var(--mono); letter-spacing:.06em; }
.intro__line + .intro__sub{ margin-top:14px; }

/* ---- the grid ----
   Cards with each plugin's screen big, in place of the list's 76px tiles.
   auto-fill with a 290px floor: three across on a laptop, two on a tablet,
   one on a phone, with no breakpoints to keep in step. */
.list{ max-width:var(--w); margin:0 auto; padding:0 var(--gut); }
.list__items{
  list-style:none; margin:0; padding:0;
  display:grid; grid-template-columns:repeat(auto-fill, minmax(min(100%, 290px), 1fr));
  gap:18px; align-items:start;
}

.card{
  display:flex; flex-direction:column; overflow:hidden; cursor:pointer;
  background:var(--panel); border-radius:10px;
  box-shadow:0 0 0 1px var(--line);
  transition:box-shadow .2s ease, transform .2s ease;
}
.card:hover{ transform:translateY(-2px); box-shadow:0 0 0 1px rgba(var(--accent), .45), 0 18px 48px rgba(var(--accent), .12); }

.card__screen{ position:relative; display:block; width:100%; background:#050506; }
.card__screen:focus-visible{ outline:1px solid var(--ink); outline-offset:-4px; }
.card__ch{
  position:absolute; top:12px; left:14px;
  font:400 .62rem var(--mono); letter-spacing:.18em; color:rgba(255,255,255,.6);
}

/* The plugin's own CRT logo — the room's screen shader (crt.js). The
   background is the no-WebGL fallback: a plain lit screen in its colour. */
.crt{
  display:block; flex:none; width:76px; aspect-ratio:4/3; border-radius:7px;
  background:radial-gradient(circle at 50% 45%, rgba(var(--accent), .55), rgba(var(--accent), .12) 70%), #050506;
  box-shadow:0 0 0 1px rgba(255,255,255,.07), 0 0 24px rgba(var(--accent), .18);
}
.crt--card{ width:100%; border-radius:0; box-shadow:none; }
/* The still behind every logo canvas (set inline from store.js): seen only
   where the live logo cannot draw over it. */
.crt[style*="background-image"]{ background-size:cover; background-position:center; }

.card__body{ display:flex; flex-direction:column; gap:8px; padding:16px 18px 18px; flex:1; }
.card__head{ display:flex; align-items:center; justify-content:space-between; gap:12px; }
.item__name{
  text-decoration:none; text-transform:uppercase; font-variation-settings:"wdth" 125, "wght" 320;
  font-size:clamp(1.25rem, 2vw, 1.55rem); letter-spacing:.04em; line-height:1.05;
}
.item__promise{ margin:0; color:var(--mid); font-size:.92rem; min-height:2.9em; }
.card__foot{ display:flex; flex-direction:column; gap:12px; margin-top:6px; }
.item__price{ font:400 1.15rem var(--mono); }
.item__cta{ display:flex; gap:8px; }
.item__cta .btn{ flex:1; padding:0 10px; }
.item__cta .btn--solid{ flex:0 0 auto; padding:0 18px; }

/* Choosing a plugin. No arrow box: the whole card is the target. On hover
   the card lifts, its screen brightens, and a caption comes up on the glass
   like a channel ident — VIEW, with the arrow sliding in. */
.card__view{
  position:absolute; right:12px; bottom:12px; padding:5px 9px 4px; border-radius:2px;
  font:500 .6rem var(--mono); letter-spacing:.22em; text-transform:uppercase; color:#fff;
  background:rgba(0, 0, 0, .55); box-shadow:inset 0 0 0 1px rgba(var(--accent), .6);
  opacity:0; transform:translateY(4px); transition:opacity .2s ease, transform .2s ease;
}
.card__view::after{ content:" \2192"; display:inline-block; transition:transform .2s ease; }
.card:hover .card__view, .card:focus-within .card__view{ opacity:1; transform:none; }
.card:hover .card__view::after{ transform:translateX(3px); }
.crt--card{ transition:filter .25s ease; }
.card:hover .crt--card{ filter:brightness(1.15) saturate(1.1); }
.card--mini .card__view{ display:none; }
.item__name:focus-visible{ outline:1px solid var(--ink); outline-offset:3px; }

/* ---- buttons ---- */
.btn{
  display:inline-flex; align-items:center; justify-content:center; gap:8px;
  min-height:42px; padding:0 18px; border-radius:2px; border:0; cursor:pointer;
  font:500 .7rem var(--mono); letter-spacing:.16em; text-transform:uppercase;
  text-decoration:none; white-space:nowrap;
  transition:background .15s ease, color .15s ease, box-shadow .15s ease;
}
.btn--solid{ background:var(--ink); color:#0A0A0A; }
.btn--solid:hover{ background:#fff; }
.btn--ghost{ background:none; color:var(--ink); box-shadow:inset 0 0 0 1px rgba(var(--accent, 232,230,225), .55); }
.btn--ghost:hover{ box-shadow:inset 0 0 0 1px rgba(var(--accent, 232,230,225), 1); background:rgba(var(--accent, 232,230,225), .08); }
.btn--wide{ width:100%; min-height:50px; }
.btn:focus-visible{ outline:1px solid var(--ink); outline-offset:3px; }

/* ---- a plugin's own page (plugin.js) ----
   The demo and the decision side by side on the first screen, then one
   labelled section per question, each label in the margin like a log. */
.plugin{ max-width:var(--w); margin:0 auto; padding:0 var(--gut); }
.crumb{
  display:flex; justify-content:space-between; align-items:center; padding:22px 0 18px;
  font:400 .68rem var(--mono); letter-spacing:.18em; text-transform:uppercase; color:var(--mid);
}
.crumb a{ text-decoration:none; }
.crumb a:hover{ color:var(--ink); }
.crumb__ch{ color:rgb(var(--accent)); }

.hero{
  display:grid; grid-template-columns:minmax(0, 1.2fr) minmax(300px, 1fr); gap:clamp(24px, 5vw, 64px);
  align-items:center; padding:clamp(8px, 3vh, 32px) 0 clamp(36px, 6vh, 64px);
}
.hero__media{ min-width:0; display:flex; justify-content:center; }
.hero__media > .media{ width:100%; }
.hero__media > .media--ascii{ max-width:600px; }
.hero__meta{ margin:0 0 12px; font:400 .66rem var(--mono); letter-spacing:.16em; text-transform:uppercase; color:var(--dim); }
.hero__name{
  margin:0; text-transform:uppercase; font-weight:400;
  font-variation-settings:"wdth" 125, "wght" 380; letter-spacing:.03em; line-height:.95;
  font-size:clamp(2.4rem, 5.4vw, 4rem);
  text-shadow:0 0 28px rgba(var(--accent), .35);
}
.hero__promise{ margin:14px 0 0; font-size:clamp(1.05rem, 1.6vw, 1.2rem); line-height:1.4; max-width:34ch; }
.hero__note{ margin:12px 0 0; color:var(--mid); font-size:.9rem; max-width:44ch; }
.hero__price{ display:flex; align-items:baseline; gap:12px; margin-top:24px; }
.hero__now{ font:400 2rem var(--mono); }
.hero__was{ font:400 1.1rem var(--mono); color:var(--dim); }
.hero__cur{ font:400 .7rem var(--mono); letter-spacing:.14em; color:var(--dim); }
.hero__ends{ margin:4px 0 0; font:400 .72rem var(--mono); color:var(--mid); }
.hero__cta{ display:flex; flex-direction:column; gap:10px; margin-top:20px; max-width:380px; }
.hero__caution{ margin:16px 0 0; color:var(--dim); font-size:.8rem; }
.hero .box__list{ max-width:380px; }

/* ---- features: the plugin, with pictures ---- */
.feats{ padding:40px 0 12px; border-top:1px solid var(--line); }
.feats > .sec__k{ margin-bottom:34px; }
.feat{
  display:grid; grid-template-columns:minmax(0, 1.45fr) minmax(0, 1fr);
  gap:clamp(22px, 4.5vw, 56px); align-items:center; margin-bottom:clamp(40px, 7vh, 72px);
}
.feat--flip{ grid-template-columns:minmax(0, 1fr) minmax(0, 1.45fr); }
.feat--flip .feat__img{ order:2; }
.feat__img{ margin:0; }
.feat__img img{ display:block; width:100%; height:auto; }
.feat__title{
  margin:0 0 10px; font-weight:400; font-variation-settings:"wdth" 112, "wght" 460;
  font-size:clamp(1.15rem, 1.9vw, 1.45rem); line-height:1.2; letter-spacing:.005em;
}
.feat__text{ margin:0; color:var(--mid); font-size:.95rem; line-height:1.6; max-width:46ch; }
.feat-also{
  list-style:none; margin:4px 0 24px; padding:24px 0 0; border-top:1px solid var(--line);
  display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); gap:20px clamp(20px, 4vw, 48px);
}
.feat-also li{ color:var(--mid); font-size:.9rem; line-height:1.55; }
.feat-also b{ display:block; margin-bottom:3px; color:var(--ink); font-weight:500; }

/* ---- bevelled pictures ----
   Every picture of a plugin sits in a rounded frame with a bevelled edge:
   light catching the top-left lip, shade under the bottom-right, like a
   screen set into a cabinet. Drawn as an overlay because an inset shadow on
   an <img> itself is painted underneath the picture and never shows. */
.bevel{
  position:relative; overflow:hidden; border-radius:14px;
  box-shadow:0 0 0 1px rgba(255, 255, 255, .07), 0 20px 50px rgba(0, 0, 0, .45), 0 0 46px rgba(var(--accent, 232,230,225), .10);
}
.bevel::after{
  content:""; position:absolute; inset:0; border-radius:inherit; pointer-events:none;
  box-shadow:inset 1px 1px 0 rgba(255, 255, 255, .20), inset -1px -1px 0 rgba(0, 0, 0, .55),
             inset 0 0 0 1px rgba(255, 255, 255, .05), inset 0 0 18px rgba(0, 0, 0, .28);
  background:linear-gradient(135deg, rgba(255, 255, 255, .07), transparent 38%);
}
.card__screen::after{
  content:""; position:absolute; inset:0; pointer-events:none; border-radius:10px 10px 0 0;
  box-shadow:inset 1px 1px 0 rgba(255, 255, 255, .16), inset -1px 0 0 rgba(0, 0, 0, .4),
             inset 0 0 22px rgba(0, 0, 0, .32);
  background:linear-gradient(135deg, rgba(255, 255, 255, .06), transparent 40%);
}
.card--mini .card__screen::after{ border-radius:8px 8px 0 0; }
.media--video, .crt--big{ border-radius:14px; }

.sec{
  display:grid; grid-template-columns:170px minmax(0, 1fr); gap:clamp(16px, 4vw, 48px);
  padding:36px 0; border-top:1px solid var(--line);
}
.sec__k{ margin:0; padding-top:3px; font:400 .68rem var(--mono); letter-spacing:.2em; text-transform:uppercase; color:rgb(var(--accent)); }
.sec__body{ display:flex; flex-direction:column; gap:26px; min-width:0; }
.sec__split{ display:grid; grid-template-columns:minmax(0, 1fr) minmax(280px, 380px); gap:clamp(20px, 4vw, 48px); align-items:start; }
.sec--more{ grid-template-columns:minmax(0, 1fr); }
/* The other plugins as small tiles, one row, the same size at every width —
   on a narrow screen the row scrolls sideways rather than the tiles growing. */
.more{
  list-style:none; margin:0; padding:2px 2px 10px;
  display:grid; grid-auto-flow:column; grid-auto-columns:168px; gap:12px;
  overflow-x:auto; scroll-snap-type:x proximity; scrollbar-width:thin;
}
.card--mini{ scroll-snap-align:start; border-radius:8px; }
.card--mini .card__ch{ top:7px; left:9px; font-size:.52rem; }
.card--mini .card__body{ flex-direction:row; align-items:baseline; justify-content:space-between; gap:8px; padding:10px 12px 12px; }
.card--mini .item__name{ font-size:.85rem; letter-spacing:.04em; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.card--mini .item__price{ font-size:.78rem; color:var(--mid); }
.card--mini .sale-was{ display:none; }
.card--mini .tag-sale{ top:6px; right:6px; padding:2px 5px 1px; font-size:.48rem; letter-spacing:.16em; }
.spec{ width:100%; border-collapse:collapse; font-size:.9rem; }
.spec th, .spec td{ padding:11px 0; border-bottom:1px solid var(--line); text-align:left; vertical-align:top; }
.spec th{ width:34%; padding-right:16px; font:400 .66rem var(--mono); letter-spacing:.14em; text-transform:uppercase; color:var(--dim); }
.spec td{ color:var(--mid); }

.media--video{
  position:relative; aspect-ratio:16/9; border-radius:4px; overflow:hidden;
  background:radial-gradient(circle at 50% 50%, rgba(var(--accent), .22), #050506 70%);
  box-shadow:inset 0 0 0 1px var(--line);
}
.media--loop video{ display:block; width:100%; height:auto; background:#050506; }
.media--video iframe, .media--video video{ position:absolute; inset:0; width:100%; height:100%; border:0; background:#000; }
.hp{ position:absolute; left:-10000px; width:1px; height:1px; opacity:0; }
.media--screen{ max-width:440px; }
.crt--big{ width:100%; border-radius:14px; box-shadow:0 0 0 1px rgba(255,255,255,.08), 0 0 60px rgba(var(--accent), .22); }
.media__play{ position:absolute; inset:0; display:grid; place-items:center; background:none; border:0; cursor:pointer; }
.media__play span{
  width:64px; height:64px; border-radius:50%; background:rgba(232,230,225,.92);
  clip-path:polygon(38% 28%, 38% 72%, 74% 50%);
}

.claims{ list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:18px; }
.claims li{ color:var(--mid); font-size:.95rem; max-width:52ch; }
.claims b{ display:block; color:var(--ink); font-weight:500; font-size:1.02rem; margin-bottom:2px; }

/* before/after */
.ab{ display:flex; align-items:center; gap:14px; padding:14px 16px; border:1px solid var(--line); border-radius:4px; }
.ab__play{ width:40px; height:40px; border-radius:50%; border:0; background:var(--ink); cursor:pointer; display:grid; place-items:center; }
.ab__icon{ width:13px; height:15px; background:#0A0A0A; clip-path:polygon(10% 0, 10% 100%, 100% 50%); }
.ab__play[aria-pressed="true"] .ab__icon{ clip-path:polygon(0 0, 35% 0, 35% 100%, 0 100%, 0 0, 65% 0, 100% 0, 100% 100%, 65% 100%, 65% 0); }
.ab__switch{ display:flex; align-items:center; gap:10px; background:none; border:0; color:var(--mid); cursor:pointer; font:400 .68rem var(--mono); letter-spacing:.14em; text-transform:uppercase; }
.ab__knob{ width:34px; height:18px; border-radius:9px; background:rgba(var(--accent), .5); position:relative; }
.ab__knob::after{ content:""; position:absolute; top:2px; right:2px; width:14px; height:14px; border-radius:50%; background:var(--ink); transition:right .15s ease; }
.ab__switch[aria-pressed="false"] .ab__knob::after{ right:18px; }
.ab__status{ margin-left:auto; font:400 .66rem var(--mono); letter-spacing:.14em; text-transform:uppercase; color:var(--dim); }

/* the reassurances under the buttons, and the free option */
.box__list{ list-style:none; margin:18px 0 0; padding:0; display:flex; flex-direction:column; gap:9px; }
.box__list li{ position:relative; padding-left:20px; color:var(--mid); font-size:.88rem; }
.box__list li::before{ content:""; position:absolute; left:2px; top:.6em; width:8px; height:1px; background:rgba(var(--accent), .9); }

.free{ padding:22px; border-radius:4px; box-shadow:inset 0 0 0 1px rgba(var(--accent), .35); background:rgba(var(--accent), .04); }
.free__head{ margin:0; font-variation-settings:"wdth" 110, "wght" 500; font-size:1.05rem; }
.free__sub{ margin:6px 0 14px; color:var(--mid); font-size:.86rem; }
/* Stacked, not side by side: the button says exactly what arrives ("Email
   me the 7-day trial"), and beside it that label squeezed the address field
   to ten characters. Full width for both is also the bigger tap target. */
.free__row{ display:flex; flex-direction:column; gap:8px; }
.free__row .btn{ min-height:46px; }
.free input[type="email"]{
  flex:1; min-width:0; min-height:42px; padding:0 12px; border-radius:2px;
  background:#0A0B0C; color:var(--ink); border:1px solid #2A2B2E; font:400 .9rem var(--grot);
}
.free input[type="email"]:focus{ outline:none; border-color:rgba(var(--accent), 1); }
.free__opt{ display:flex; align-items:center; gap:8px; margin-top:12px; color:var(--dim); font-size:.78rem; cursor:pointer; }
.free__msg{ margin:12px 0 0; font-size:.86rem; color:var(--ink); min-height:1.2em; }
.free.is-sent .free__row, .free.is-sent .free__opt{ display:none; }

.faq{ margin:0; display:grid; grid-template-columns:minmax(0, 1fr); gap:0; }
.faq dt:first-child{ padding-top:0; }
.faq dt{ padding-top:18px; font-weight:500; font-size:.95rem; }
.faq dd{ margin:6px 0 0; padding-bottom:18px; border-bottom:1px solid var(--line); color:var(--mid); font-size:.9rem; max-width:70ch; }
.faq dd:last-child{ border-bottom:0; padding-bottom:0; }

/* ---- bundles (store.js) ----
   One wide panel per bundle under the grid: its plugins' own screens in a
   row, what it is, then the two ways to have it on the right. The only
   colour is the plugins' own light — the screens' glow and a lit dot by each
   name; the bundle itself is ink on panel, like everything else. */
.bundles{ max-width:var(--w); margin:0 auto; padding:56px var(--gut) 0; }
.bundles__head{ display:flex; align-items:baseline; gap:18px; flex-wrap:wrap; margin-bottom:18px; }
.bundles .sec__k{ color:var(--mid); }
.bundles__sub{ margin:0; color:var(--dim); font:400 .74rem var(--mono); letter-spacing:.06em; }
.bundles__items{ list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:18px; }

.bundle{
  display:grid; grid-template-columns:minmax(0, 1fr) minmax(240px, 300px);
  grid-template-areas:"screens buy" "body buy"; grid-template-rows:auto 1fr; gap:16px clamp(20px, 4vw, 48px);
  padding:20px 22px 22px; background:var(--panel); border-radius:10px; box-shadow:0 0 0 1px var(--line);
}
.bundle__screens{ grid-area:screens; display:flex; flex-wrap:wrap; gap:8px; }
.bundle__screen{ display:block; position:relative; border-radius:6px; }
.crt--bundle{ width:72px; border-radius:6px; box-shadow:0 0 0 1px rgba(255,255,255,.07), 0 0 18px rgba(var(--accent), .22); }
.bundle__screen:hover .crt--bundle{ filter:brightness(1.15) saturate(1.1); }
.bundle__body{ grid-area:body; min-width:0; }
.bundle__k{ margin:0 0 6px; font:400 .62rem var(--mono); letter-spacing:.2em; text-transform:uppercase; color:var(--dim); }
.bundle__name{
  margin:0; font-weight:400; text-transform:uppercase; font-variation-settings:"wdth" 125, "wght" 320;
  font-size:clamp(1.25rem, 2vw, 1.55rem); letter-spacing:.04em; line-height:1.05;
}
.bundle__blurb{ margin:8px 0 0; color:var(--mid); font-size:.92rem; max-width:52ch; }
.bundle__plugins{ list-style:none; margin:12px 0 0; padding:0; display:flex; flex-wrap:wrap; gap:6px 16px; }
.bundle__plugins li{ display:flex; align-items:center; gap:7px; font:400 .74rem var(--mono); letter-spacing:.08em; text-transform:uppercase; }
.bundle__plugins li::before{
  content:""; width:5px; height:5px; border-radius:50%;
  background:rgb(var(--accent)); box-shadow:0 0 6px rgba(var(--accent), .9);
}
.bundle__plugins a{ text-decoration:none; color:var(--ink); }
.bundle__plugins a:hover{ text-decoration:underline; text-underline-offset:3px; }
.bundle__plugins .tag-os{ margin-left:2px; padding:2px 6px 1px; font-size:.5rem; letter-spacing:.14em; }
.bundle__buy{ grid-area:buy; display:flex; flex-direction:column; gap:10px; align-self:center; }
.bundle__price{ margin:0; display:flex; align-items:baseline; gap:10px; flex-wrap:wrap; }
.bundle__now{ font:400 1.6rem var(--mono); }
.bundle__how{ font:400 .66rem var(--mono); letter-spacing:.16em; text-transform:uppercase; color:var(--dim); }
.bundle__worth{ margin:-4px 0 4px; color:var(--mid); font-size:.82rem; }
.bundle__fine{ margin:0; color:var(--dim); font-size:.76rem; line-height:1.45; }

/* A plugin page's line to the bundles it is in (plugin.js). */
.hero__bundles{ max-width:380px; margin-top:22px; padding-top:16px; border-top:1px solid var(--line); }
.hero__bundles-k{ margin:0 0 8px; font:400 .62rem var(--mono); letter-spacing:.2em; text-transform:uppercase; color:var(--dim); }
.hero__bundle{
  display:flex; justify-content:space-between; align-items:baseline; gap:12px; padding:6px 0;
  text-decoration:none; font-size:.9rem;
}
.hero__bundle span{ color:var(--mid); font:400 .72rem var(--mono); white-space:nowrap; }
.hero__bundle:hover{ text-decoration:underline; text-underline-offset:3px; }
.hero__bundle::after{ content:"\2192"; color:var(--dim); margin-left:-4px; }

/* ---- reassurance ---- */
.promise{
  max-width:var(--w); margin:0 auto; padding:64px var(--gut) 24px;
  display:grid; grid-template-columns:repeat(3, minmax(0, 1fr)); gap:28px;
}
.promise__item{ color:var(--mid); font-size:.9rem; }
.promise__k{ display:block; margin-bottom:6px; font:400 .7rem var(--mono); letter-spacing:.2em; text-transform:uppercase; color:var(--ink); }

.foot{
  max-width:var(--w); margin:0 auto; padding:40px var(--gut) 120px;
  display:flex; justify-content:space-between; gap:16px; flex-wrap:wrap;
  font:400 .7rem var(--mono); letter-spacing:.1em; color:var(--dim);
}
.foot a{ text-decoration:none; }

/* ---- sticky try/buy ---- */
.sticky{
  position:fixed; left:50%; bottom:18px; z-index:6; transform:translateX(-50%);
  display:flex; align-items:center; gap:14px;
  width:min(var(--w), calc(100% - 24px)); padding:10px 10px 10px 16px;
  background:rgba(14,15,17,.94); backdrop-filter:blur(10px);
  border:1px solid var(--line); border-radius:6px;
  box-shadow:0 12px 40px rgba(0,0,0,.5);
}
.sticky[hidden]{ display:none; }
.crt--sticky{ width:40px; border-radius:4px; }
.sticky__name{ min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; text-transform:uppercase; font-variation-settings:"wdth" 125, "wght" 360; letter-spacing:.06em; }
.sticky__price{ margin-right:auto; font:400 .9rem var(--mono); color:var(--mid); }

/* ---- small screens ---- */
.lbl-short{ display:none; }

@media (max-width: 760px){
  /* Two across on a phone. At ~165px a card cannot hold the two buttons side
     by side, so they stack and the try button takes its short label; the
     promise is held to three lines so every card in a row ends level. */
  .list__items{ grid-template-columns:repeat(2, minmax(0, 1fr)); gap:10px; }
  .card__body{ padding:10px 10px 12px; gap:6px; }
  .card__ch{ top:8px; left:9px; font-size:.54rem; }
  .item__name{ font-size:1rem; letter-spacing:.02em; }
  .item__promise{
    font-size:.78rem; line-height:1.35; min-height:3.2em;
    display:-webkit-box; -webkit-line-clamp:3; -webkit-box-orient:vertical; overflow:hidden;
  }
  .card__foot{ gap:8px; margin-top:2px; }
  .item__price{ font-size:.95rem; }
  .item__cta{ flex-direction:column; gap:6px; }
  .item__cta .btn, .item__cta .btn--solid{ flex:none; width:100%; min-height:36px; padding:0 6px; font-size:.62rem; letter-spacing:.12em; }
  .lbl-long{ display:none; }
  .lbl-short{ display:inline; }
  .hero{ grid-template-columns:minmax(0, 1fr); gap:22px; padding-top:0; }
  .hero__cta, .hero .box__list{ max-width:none; }
  .sec{ grid-template-columns:minmax(0, 1fr); gap:16px; padding:28px 0; }
  .feat, .feat--flip{ grid-template-columns:minmax(0, 1fr); gap:16px; margin-bottom:40px; }
  .feat--flip .feat__img{ order:0; }
  .feat-also{ grid-template-columns:minmax(0, 1fr); }
  .bevel{ border-radius:10px; }
  .sec__split{ grid-template-columns:minmax(0, 1fr); }
  /* The half-tile cut off at the screen's edge says "scrolls" on its own,
     so no scrollbar; name over price, so a name is never cut short. */
  .sale{ gap:12px; padding:10px var(--gut); }
  .sale__neon{ font-size:4px; }
  .sale__sub{ display:none; }
  .tag-os{ font-size:.5rem; padding:2px 6px 1px; letter-spacing:.14em; }
  .tag-sale{ top:7px; right:7px; padding:2px 5px 1px; font-size:.5rem; letter-spacing:.16em; }
  .more{ grid-auto-columns:132px; gap:10px; margin-right:calc(-1 * var(--gut)); padding-right:var(--gut); scrollbar-width:none; }
  .more::-webkit-scrollbar{ display:none; }
  .card--mini .card__body{ flex-direction:column; gap:2px; padding:8px 10px 10px; }
  .card--mini .item__name{ font-size:.8rem; }
  .crumb{ padding:16px 0 12px; }
  .promise{ grid-template-columns:minmax(0, 1fr); gap:20px; padding-top:48px; }
  .bundles{ padding-top:40px; }
  .bundle{ grid-template-columns:minmax(0, 1fr); grid-template-areas:"screens" "body" "buy"; grid-template-rows:none; padding:16px 14px 16px; }
  .crt--bundle{ width:54px; }
  .hero__bundles{ max-width:none; }
  .intro{ grid-template-columns:minmax(0, 1fr); }
  /* On a phone the TV keeps its own small size; only its dim dusting runs to
     the edges (the grid is widened in store.js). It breaks out of the page
     gutter so the dusting can reach the glass, and has no frame round it.
     A first pass scaled the whole thing to the width instead, which made the
     logo huge — the ask was for the edges, not a bigger picture. */
  .tv{ justify-self:stretch; width:100vw; margin-inline:calc(50% - 50vw); }
  .tv__set{ font-size:9px; }
  .tv__screen{ width:max-content; margin:0 auto; }
  .top{ padding:14px var(--gut); }
  .sticky{ bottom:0; width:100%; border-radius:0; border-width:1px 0 0; gap:10px; padding:10px 12px; }
  .sticky__price{ display:none; }
  .sticky__name{ margin-right:auto; font-size:.85rem; }
  .sticky .btn{ padding:0 12px; flex:none; }
}
@media (prefers-reduced-motion: reduce){
  *{ transition:none !important; scroll-behavior:auto !important; }
  .ticker__run, .top__dot, .tv__neon, .sale__neon, .curtain__mark{ animation:none; }
}
