/* (c) 2026 netPanel Pty Ltd - ABN 98 643 001 610 - All rights reserved.
   Unauthorised copying, modification or distribution is prohibited. */
/*  netPanel — one stylesheet for the whole site.
    Extracted from the new homepage the moment there was a second page, so a
    colour or a weight is changed in ONE file and not five.
    ★ Montserrat only: display 100, body 400, labels 600 - the owner's rule,
      the same face the Hub and the devices use.                            */
/*  ── FONTS, SELF-HOSTED ────────────────────────────────────────────────────
    The product rule is OWN EVERYTHING: no third-party runtime in anything we
    ship. A webfont pulled from Google on every page load is exactly that, so
    these are served from our own box like the Hub's 219 faces are.          */
/*  ★★ MONTSERRAT IS THE BRAND FACE. Owner, 1 Oct 2026: "montserrat thin is the
    website, hub and device font". One family across the product - the website,
    the Hub's screens and the devices - so the page must not invent its own.
    ⚠ montserrat-100..700-latin.woff2 are ONE variable file (identical md5), so it
      is declared ONCE with the weight RANGE. Declared as separate static weights
      the browser picks a single instance and every weight renders the same.
    ★ THIN IS FOR THE BIG TYPE ONLY. At 100 a headline is elegant; a paragraph is
      unreadable, and on a dark ground it disappears. Display 100, body 400,
      labels 600 - all from the same file, so it is still one download.          */
@font-face{font-family:Montserrat;src:url(/main/assets/fonts/montserrat.woff2)format("woff2");font-weight:100 700;font-display:swap}

:root{
  /*  the wordmark's own rainbow, grown into the whole page  */
  --r1:#ff4d6d; --r2:#ff9f45; --r3:#ffd93d; --r4:#4ade80; --r5:#38bdf8; --r6:#6a86ff; --r7:#c084fc;
  --accent:#6a86ff;                 /* the brand blue, unchanged */
  --ink:#07070e;                    /* near-black with a blue bias, not grey */
  --panel:#101120;
  --line:rgba(255,255,255,.09);
  --text:#f2f3fa;
  --muted:#9aa1bd;
  --rainbow:linear-gradient(100deg,var(--r1),var(--r2),var(--r3),var(--r4),var(--r5),var(--r6),var(--r7));
  --maxw:1180px;
}
*{box-sizing:border-box}
html{scroll-behavior:smooth}
body{
  margin:0;background:var(--ink);color:var(--text);
  font:400 17px/1.7 Montserrat,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;
  -webkit-font-smoothing:antialiased;overflow-x:hidden;
}
.wrap{max-width:var(--maxw);margin:0 auto;padding:0 20px}
h1,h2{font-weight:100;line-height:1.04;letter-spacing:-.02em;text-wrap:balance;margin:0}
h3{font-weight:600;line-height:1.25;letter-spacing:-.01em;margin:0}
h1{font-size:clamp(2.9rem,7.8vw,5.9rem)}
h2{font-size:clamp(2.15rem,4.9vw,3.5rem)}
h3{font-size:1.22rem;letter-spacing:-.01em}
p{margin:0}
a{color:inherit}
.lede{font-size:clamp(1.05rem,1.9vw,1.3rem);color:var(--muted);max-width:56ch}
.eyebrow{font:600 11px/1 Montserrat,sans-serif;letter-spacing:.22em;text-transform:uppercase;color:var(--muted)}
.tint{background:var(--rainbow);-webkit-background-clip:text;background-clip:text;color:transparent}

/* ── header ───────────────────────────────────────────────────────────── */
header{position:fixed;inset:0 0 auto;z-index:50;backdrop-filter:blur(14px);
  background:linear-gradient(to bottom,rgba(7,7,14,.86),rgba(7,7,14,.3));border-bottom:1px solid transparent}
header.on{border-bottom-color:var(--line)}
.bar{display:flex;align-items:center;gap:22px;height:64px}
.mark{font-weight:600;font-size:1.22rem;letter-spacing:-.03em;text-decoration:none;flex:none}
nav{margin-left:auto;display:flex;gap:26px;align-items:center}
nav a{color:var(--muted);text-decoration:none;font-size:.95rem}
nav a:hover{color:var(--text)}
@media(max-width:720px){nav a.hide{display:none}}

.btn{display:inline-flex;align-items:center;gap:.55em;padding:.82em 1.5em;border-radius:999px;
  text-decoration:none;font-weight:600;font-size:.95rem;border:0;cursor:pointer;
  background:var(--rainbow);color:#0a0a12;background-size:220% 100%;transition:background-position .5s,transform .18s}
.btn:hover{background-position:100% 0;transform:translateY(-2px)}
.btn.ghost{background:transparent;color:var(--text);box-shadow:inset 0 0 0 1px rgba(255,255,255,.22)}
.btn.ghost:hover{box-shadow:inset 0 0 0 1px rgba(255,255,255,.5)}

/* ── hero: one screen, full bleed, alive ──────────────────────────────── */
.hero{position:relative;min-height:92svh;display:flex;align-items:flex-end;overflow:hidden;padding:0 0 clamp(40px,7vh,86px)}
.hero video,.hero .poster{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:0}
.hero .veil{position:absolute;inset:0;z-index:1;
  background:radial-gradient(118% 88% at 72% 18%,transparent 12%,rgba(7,7,14,.62) 56%,var(--ink) 94%),
             linear-gradient(to top,var(--ink) 2%,rgba(7,7,14,.2) 46%,rgba(7,7,14,.5))}
.hero .aura{position:absolute;z-index:1;width:min(130vw,1280px);aspect-ratio:1;left:-22%;top:-46%;
  background:conic-gradient(from 210deg,var(--r1),var(--r2),var(--r3),var(--r4),var(--r5),var(--r6),var(--r7),var(--r1));
  filter:blur(130px);opacity:.3;animation:spin 46s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.hero .wrap{position:relative;z-index:2}
.hero h1 span{display:block}
.hero .lede{margin-top:1.15rem}
.cta{display:flex;gap:14px;flex-wrap:wrap;margin-top:2.1rem}
.note{margin-top:1.4rem;font-size:.9rem;color:var(--muted)}

/* ── the moving wall of screens ───────────────────────────────────────── */
.belt{display:flex;gap:16px;width:max-content;animation:slide 150s linear infinite}
.belt:nth-child(2){animation-duration:190s;animation-direction:reverse}
@keyframes slide{to{transform:translateX(-50%)}}
.beltbox{overflow:hidden;mask-image:linear-gradient(90deg,transparent,#000 7%,#000 93%,transparent)}
.belt img{height:clamp(130px,17vw,210px);width:auto;border-radius:12px;display:block;
  border:1px solid var(--line);background:var(--panel)}
.beltbox:hover .belt{animation-play-state:paused}

/* ── sections ─────────────────────────────────────────────────────────── */
section{padding:clamp(66px,9vw,122px) 0;position:relative}
.head{max-width:62ch}
.head h2{margin:.5rem 0 1rem}
.grid{display:grid;gap:18px;margin-top:3rem}
@media(min-width:760px){.grid.c3{grid-template-columns:repeat(3,1fr)}.grid.c2{grid-template-columns:repeat(2,1fr)}}
.card{background:var(--panel);border:1px solid var(--line);border-radius:18px;padding:26px;position:relative;overflow:hidden}
.card::before{content:"";position:absolute;inset:0 0 auto;height:3px;background:var(--rainbow);opacity:.0;transition:opacity .3s}
.card:hover::before{opacity:1}
.card h3{margin:0 0 .5rem}
.card p{color:var(--muted);font-size:1rem}
.num{font:600 11px/1 Montserrat,sans-serif;letter-spacing:.2em;color:var(--muted);text-transform:uppercase}

.split{display:grid;gap:clamp(26px,5vw,64px);align-items:center}
@media(min-width:900px){.split{grid-template-columns:1.05fr 1fr}.split.flip>*:first-child{order:2}}
.shot{border-radius:18px;border:1px solid var(--line);width:100%;display:block;background:var(--panel)}
.framed{position:relative}
.framed::after{content:"";position:absolute;inset:-1px;border-radius:19px;padding:1px;
  background:var(--rainbow);-webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
  -webkit-mask-composite:xor;mask-composite:exclude;opacity:.55;pointer-events:none}

/* ── waitlist ─────────────────────────────────────────────────────────── */
.band{background:
  radial-gradient(90% 150% at 12% 0%,rgba(106,134,255,.22),transparent 58%),
  radial-gradient(80% 140% at 92% 100%,rgba(192,132,252,.18),transparent 60%),var(--panel);
  border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
form.join{display:flex;gap:10px;flex-wrap:wrap;margin-top:1.8rem}
form.join input{flex:1 1 260px;padding:.9em 1.15em;border-radius:999px;border:1px solid var(--line);
  background:rgba(0,0,0,.35);color:var(--text);font:400 1rem Montserrat,sans-serif}
form.join input:focus{outline:2px solid var(--accent);outline-offset:1px}

footer{padding:56px 0 70px;color:var(--muted);font-size:.93rem}
.fgrid{display:grid;gap:30px;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));margin-bottom:34px}
footer h4{font:600 11px/1 Montserrat,sans-serif;letter-spacing:.2em;text-transform:uppercase;color:var(--text);margin:0 0 .9rem}
footer a{display:block;text-decoration:none;margin-bottom:.5rem;color:var(--muted)}
footer a:hover{color:var(--text)}
.rule{height:1px;background:var(--rainbow);opacity:.35;margin:0 0 26px}

:focus-visible{outline:2px solid var(--accent);outline-offset:3px;border-radius:4px}
@media(prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.001ms!important;animation-iteration-count:1!important;transition-duration:.001ms!important}
  html{scroll-behavior:auto}
}

/* ══ shared page furniture, added when the site went past one page ══════════ */
.page-top{padding:calc(64px + clamp(44px,7vw,92px)) 0 clamp(30px,5vw,56px);position:relative;overflow:hidden}
.page-top .aura{position:absolute;z-index:0;width:min(120vw,1100px);aspect-ratio:1;left:-30%;top:-70%;
  background:conic-gradient(from 210deg,var(--r1),var(--r2),var(--r3),var(--r4),var(--r5),var(--r6),var(--r7),var(--r1));
  filter:blur(140px);opacity:.22;animation:spin 46s linear infinite}
.page-top .wrap{position:relative;z-index:1}
.page-top h1{font-size:clamp(2.4rem,6vw,4.4rem)}
.page-top .lede{margin-top:1.1rem}

/*  ⚠ PRICE CARDS CARRY MONEY, so nothing here may be decorative at the cost of
    clarity: the figure is the largest thing in the card and the period sits
    beside it, never under it where it can be read as part of the number.      */
.plans{display:grid;gap:18px;margin-top:2.6rem}
@media(min-width:820px){.plans{grid-template-columns:repeat(2,1fr)}}
.plan{background:var(--panel);border:1px solid var(--line);border-radius:18px;padding:28px;display:flex;flex-direction:column}
.plan.hero-plan{border-color:transparent;position:relative}
.plan.hero-plan::after{content:"";position:absolute;inset:-1px;border-radius:19px;padding:1px;background:var(--rainbow);
  -webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);-webkit-mask-composite:xor;mask-composite:exclude;pointer-events:none}
.plan .name{font:600 11px/1 Montserrat,sans-serif;letter-spacing:.2em;text-transform:uppercase;color:var(--muted)}
.plan .fig{font-weight:100;font-size:clamp(2.6rem,5vw,3.4rem);line-height:1;margin:.7rem 0 .1rem;letter-spacing:-.03em}
.plan .per{color:var(--muted);font-size:.95rem}
.plan ul{list-style:none;margin:1.5rem 0 1.8rem;padding:0;color:var(--muted);font-size:1rem}
.plan li{padding:.42rem 0 .42rem 1.5rem;position:relative}
.plan li::before{content:"";position:absolute;left:0;top:.95rem;width:8px;height:8px;border-radius:50%;background:var(--rainbow)}
.plan .btn{margin-top:auto;justify-content:center}

.rowlist{display:grid;gap:14px;margin-top:2.4rem}
@media(min-width:760px){.rowlist{grid-template-columns:repeat(2,1fr)}}
.row{display:flex;gap:16px;align-items:flex-start;background:var(--panel);border:1px solid var(--line);
  border-radius:16px;padding:20px 22px}
.row .dot{flex:none;width:10px;height:10px;border-radius:50%;margin-top:.55rem;background:var(--rainbow)}
.row h3{margin:0 0 .3rem}
.row p{color:var(--muted);font-size:.97rem;margin:0}

blockquote{margin:0;font-weight:100;font-size:clamp(1.5rem,3.4vw,2.3rem);line-height:1.3;letter-spacing:-.02em;
  max-width:24ch}
.story{display:grid;gap:clamp(24px,5vw,56px)}
@media(min-width:880px){.story{grid-template-columns:1fr 1fr;align-items:start}}
.story p{color:var(--muted);margin-bottom:1.1rem}

/* ══════════════════════════════════════════════════════════════════════════
   SECOND PASS — "much much better and higher"
   The first version was correct. Correct is not the same as good, and the
   owner is right that it stopped short. What follows is the craft layer.
   ══════════════════════════════════════════════════════════════════════════ */

/*  ★ GRAIN. A flat dark page reads as cheap on a good display - the gradients
    band and the blacks look plastic. A single tiling noise at 3% breaks the
    bands and gives the whole site the texture of a printed thing. It is one
    inline SVG, so it costs no request.                                      */
body::after{content:"";position:fixed;inset:0;z-index:999;pointer-events:none;opacity:.038;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/></filter><rect width='160' height='160' filter='url(%23n)'/></svg>");
  mix-blend-mode:overlay}

/*  ★★ THE HERO IS A STAGE, NOT A PICTURE. The whole product claim is "not one
    of them sits still" - so the hero must not sit still either. Real screens
    cross-fade behind the type, each one drifting slightly while it is up, so
    the page demonstrates the product instead of describing it.              */
.stage{position:absolute;inset:0;z-index:0;overflow:hidden}
.stage>*{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  opacity:0;transform:scale(1.05);transition:opacity 3s ease,transform 22s linear}
.stage>*.up{opacity:1;transform:scale(1.13)}
.hero{min-height:100svh}

/*  ★ A SCREEN IS A PRODUCT, NOT A JPEG. Floating rectangles read as stock art.
    A thin bezel with a real radius, a dark rim and a soft contact shadow makes
    every shot read as a panel hanging on a wall.                            */
.bezel{position:relative;border-radius:18px;padding:10px;background:
  linear-gradient(160deg,#2a2c3b,#0d0e16 42%,#1b1d29);
  box-shadow:0 1px 0 rgba(255,255,255,.07) inset,0 40px 80px -30px rgba(0,0,0,.95),
             0 0 0 1px rgba(255,255,255,.05)}
.bezel img{display:block;width:100%;border-radius:9px}
.bezel::after{content:"";position:absolute;inset:0;border-radius:18px;pointer-events:none;
  background:linear-gradient(145deg,rgba(255,255,255,.14),transparent 34%)}

/*  ★ THE WALL, GIVEN DEPTH. Flat on the page the belts are a filmstrip; laid
    back a few degrees they become a room full of screens.                   */
/*  ⚠ THE MASK AND THE 3D TRANSFORM MUST NOT SHARE AN ELEMENT. With
    overflow:hidden + mask-image + rotateX on the same box the belts rendered
    EMPTY - the tiles kept their borders and the pictures never painted. Caught
    in a render; it had worked the moment before the tilt was added. The tilt
    now lives on its own wrapper, above the element that does the masking.   */
.beltstage{perspective:1500px;perspective-origin:50% 30%}
.beltstage>.tilt{transform:rotateX(8deg);transform-origin:50% 0}
.belt img{box-shadow:0 22px 44px -24px rgba(0,0,0,.95);transition:transform .45s cubic-bezier(.2,.8,.2,1),box-shadow .45s}
.belt img:hover{transform:translateY(-10px) scale(1.04);box-shadow:0 34px 60px -26px rgba(0,0,0,1)}

/*  ⚠ REVEALS START VISIBLE. If the page's content depends on JavaScript to be
    seen, then a thumbnail, a shared link and a reader who scrolls fast all get
    an empty page. The class below is only ADDED by script, and only to move an
    element that is already there.                                           */
.js .rv{opacity:0;transform:translateY(22px)}
.js .rv.in{opacity:1;transform:none;transition:opacity .8s ease,transform .8s cubic-bezier(.2,.8,.2,1)}

/*  a quieter, larger type rhythm - the first pass was a touch timid          */
h1{font-size:clamp(3rem,8.4vw,6.6rem);letter-spacing:-.035em}
h2{font-size:clamp(2.2rem,5.2vw,3.9rem);letter-spacing:-.03em}
.lede{font-size:clamp(1.08rem,1.55vw,1.32rem);line-height:1.62}
section{padding:clamp(80px,11vw,152px) 0}

/*  the button gains a soft bloom of its own colour, so it looks lit rather
    than painted                                                             */
.btn{box-shadow:0 10px 30px -12px rgba(106,134,255,.75)}
.btn.ghost{box-shadow:none}

/*  the card's rainbow edge now sweeps instead of merely appearing            */
.card::before{background:var(--rainbow);background-size:260% 100%;animation:sweep 5s linear infinite;opacity:0}
@keyframes sweep{to{background-position:260% 0}}

@media(prefers-reduced-motion:reduce){
  .stage>*{transition:opacity .4s ease}
  .beltstage>.tilt{transform:none}
  .js .rv{opacity:1;transform:none}
}


/*  ⛔ THE SCRIM WAS SIZED FOR ONE DARK SCREEN AND THE STAGE SHOWS MANY. A flower
    calendar or a bright photo clock came up behind the headline and the white
    type lost its contrast - caught in a render, on the second slide.
    ★ So the text side carries its own gradient, strong enough for the BRIGHTEST
      screen in the set, and it sits under the type rather than over the picture:
      the right-hand side of the image stays clean.                           */
.hero .veil{background:
  linear-gradient(90deg,rgba(4,4,10,.94) 0%,rgba(4,4,10,.86) 26%,rgba(4,4,10,.45) 52%,rgba(4,4,10,.12) 74%,transparent 100%),
  linear-gradient(to top,var(--ink) 1%,rgba(4,4,10,.55) 26%,rgba(4,4,10,.15) 58%,rgba(4,4,10,.45) 100%)}
@media(max-width:760px){
  /*  no room to put the type beside the picture on a phone - it sits ON it,
      so the whole frame has to carry the scrim                               */
  .hero .veil{background:linear-gradient(to top,var(--ink) 2%,rgba(4,4,10,.84) 44%,rgba(4,4,10,.6) 100%)}
}
/*  and the type gets its own shadow, which costs nothing and survives any slide */
.hero h1,.hero .lede,.hero .eyebrow{text-shadow:0 2px 26px rgba(0,0,0,.72)}

/*  ⛔ THE HEADER BROKE ON A PHONE AND I HAD NEVER LOOKED AT ONE. At 390 px
    "Sign in" wrapped onto two lines and the pill pushed past the edge - the
    first thing a visitor sees, broken, on the device most of them use.
    ★ Sign in is in the footer of every page, so on a small screen it leaves the
      bar and the pill shrinks to fit.                                        */
@media(max-width:620px){
  .bar{gap:12px;height:58px}
  nav{gap:14px}
  nav a.signin{display:none}
  .mark{font-size:1.06rem}
  .btn{padding:.68em 1.05em;font-size:.86rem;box-shadow:none}
  h1{letter-spacing:-.03em}
  .cta{gap:10px}
  .plan{padding:22px}
}
/*  a phone is held in one hand: nothing may demand a sideways scroll          */
@media(max-width:620px){.beltstage{perspective:none}.beltstage>.tilt{transform:none}}

/*  ⛔ THE BRAND WAS 18 PIXELS IN A CORNER. Owner, 1 Oct 2026: "on home page we
    have just very small name of netPanel, is that right as a advertise?" - and
    no, it is not. A visitor who has never heard of netPanel could read the whole
    homepage and never once read the NAME. For a product nobody knows yet that is
    the one thing the page must do.
    ★ THE NAME IS SAID TWICE, PROPERLY: once as the lockup that opens the hero,
      and once very large as the page closes - the two moments a reader is
      actually looking. It is not shouted in between.                         */
.lockup{display:flex;align-items:baseline;gap:.85rem;flex-wrap:wrap;margin-bottom:1.4rem}
.lockup .nm{font-weight:200;font-size:clamp(1.9rem,3.5vw,2.9rem);letter-spacing:-.03em;line-height:1}
.lockup .by{font:600 11px/1.5 Montserrat,sans-serif;letter-spacing:.22em;text-transform:uppercase;
  color:var(--muted);padding-bottom:.25rem}

/*  the closing wordmark: big, thin, and cropped by the page edge on purpose so
    it reads as a mark rather than a heading                                   */
.signoff{padding:clamp(54px,8vw,104px) 0 0;overflow:hidden}
.signoff .big{font-weight:100;font-size:clamp(3.6rem,13.5vw,11rem);line-height:.86;letter-spacing:-.055em;
  white-space:nowrap;background:var(--rainbow);-webkit-background-clip:text;background-clip:text;
  color:transparent;opacity:.92}
.signoff .sub{color:var(--muted);margin-top:.9rem;font-size:1.02rem}

/*  ══ THE FLASH — the founder's rule, and the product's own code ═════════════
    Owner, 1 Oct 2026: "lighting flash on it same as others (my rull)", then
    "first flash is very weak" and "wide awake has flash as well so stop it,
    just netPanel".

    ⛔ MY FIRST VERSION PUT THE LIGHT ON .tint, AND .tint IS NOT THE WORDMARK.
       The headline's "Wide awake." uses the same class for its rainbow, so the
       sentence flashed too. The brand mark now has its own class, .wm, and
       .tint is plain rainbow text again: a word is coloured, a WORDMARK is lit.

    ★ The stops, the geometry and the loop are COPIED from display.html's
      npFlash - the animation that lights page 10's .ncc-wm and the placeholder
      signature - so every wordmark in the product reads as one effect.
    ★ TWO BACKGROUND LAYERS ON ONE ELEMENT, not an overlay: the mark is
      gradient-clipped TEXT, and both layers are clipped by the same
      background-clip, so the light lands on the letters and nowhere else.
    ⚠ -185% .. 285% IS NOT DECORATION. A 64%-wide layer at position p sits at
      p/100 x (container - layer); anything short of those ends PARKS a bright
      edge on the letters instead of clearing them.                           */
.tint{background:var(--rainbow);-webkit-background-clip:text;background-clip:text;color:transparent}

/*  ⛔⛔ I BUILT A DIFFERENT EFFECT THREE TIMES AND HE HAD TO SAY SO THREE TIMES.
    "not correct! it is not what we have on those devise. i ask you all must be
    same." He is right. I kept rebuilding the IDEA of a flash - a brighter band,
    a wider band, then a drop-shadow bloom I invented - instead of copying the
    one the product already has.

    ★ WHAT THE DEVICES ACTUALLY DO (display.html, .cty.ed2 .adlogo i /
      ctyAdSweep, the wordmark under CAPITAL and ATLAS): a separate BAR element
      lies over the mark - 38% wide, skewed -18deg, blurred 2px, brightened
      1.25 - and travels from -140% to 340% while the box clips it. The light is
      NOT clipped to the glyphs: it passes over the whole wordmark as a soft
      streak, which is why it reads from across a room.
    ⛔ A background layer clipped to the TEXT cannot do this. It can only repaint
      the letters, which is exactly why every version of mine looked weak.

    Everything below is copied from display.html: the width, the skew, the blur,
    the brightness, the gradient stops, the 4.5s/1.15s timing and the opacity
    gate at 2% and 14%. If the Hub's changes, this must change with it.       */
.wm{position:relative;display:inline-flex;overflow:hidden;line-height:1}
.wm>.t{display:inline-block;background:var(--rainbow);
  -webkit-background-clip:text;background-clip:text;color:transparent}
.wm>i{position:absolute;left:0;top:0;width:38%;height:100%;
  /*  ⚠ THE SHOULDERS ARE PULLED IN, AND THIS IS THE ONE DEPARTURE FROM THE HUB.
      The Hub's bar carries faint .14 shoulders from 24% to 76% because it lies
      over a PHOTOGRAPH, where they disappear. This page is flat near-black, and
      white at .14 over black is grey - the streak arrived as a visible grey
      RECTANGLE sliding across the mark, which is worse than no flash at all.
      mix-blend-mode does not help: semi-transparent white over black composites
      to the same grey whichever way it is blended.
      ★ So the shoulders fade to nothing by 34% and 66% and only the bright core
        survives. Width, skew, blur, brightness, the 4.5s/1.15s timing and the
        2%/14% opacity gate are all still the Hub's exactly.                   */
  background:linear-gradient(100deg,
    rgba(255,255,255,0)    0%,  rgba(255,255,255,0)   34%,
    rgba(225,240,255,.55) 44%,  rgba(255,255,255,.98) 50%,
    rgba(225,240,255,.55) 56%,  rgba(255,255,255,0)   66%,
    rgba(255,255,255,0)  100%);
  filter:blur(2px) brightness(1.25);opacity:0;pointer-events:none;mix-blend-mode:screen;
  animation:ctyAdSweep 4.5s ease-in-out 1.15s infinite}
@keyframes ctyAdSweep{
  0%  {transform:translateX(-140%) skewX(-18deg);opacity:0}
  2%  {opacity:1}
  14% {opacity:1}
  17% {transform:translateX(340%)  skewX(-18deg);opacity:0}
  100%{transform:translateX(340%)  skewX(-18deg);opacity:0}
}
/*  the closing mark is six times the size, so the same streak crosses it in the
    same 17% of a LONGER loop - the device's proportions, not a new effect      */
.signoff .wm>i{animation-duration:7s;animation-delay:1.6s}
@media(prefers-reduced-motion:reduce){.wm>i{animation:none;opacity:0}}

/* ══ THE FIVE-MONTH PASS ════════════════════════════════════════════════════
   Owner: "this home page must have 5 mounts inteligent ... look at page for
   harmony, details, pexil by pexil". Measured at 1920 and read at 1:1, these
   are the faults that were really there.                                    */

/*  ⛔ 1. THE PAGE CHANGED ITS VOICE MID-WAY. Every heading is Montserrat THIN,
    then the card titles arrive at weight 600 - heavier than anything around
    them and SMALLER than the lede they sit under (19.52 px against 21.12).
    Bold-but-smaller is the clearest sign of a hierarchy that was never
    designed. A card title now reads as a title: bigger than the body, lighter
    than before, and in the same family as the rest of the page.             */
h3,.row h3,.card h3{font-weight:500;font-size:1.35rem;letter-spacing:-.015em;line-height:1.3}
.card h3,.row h3{margin-bottom:.45rem}
.card .num{margin-bottom:.9rem;display:block}

/*  ⛔ 2. ONE GREY WAS DOING SIX JOBS. The lede, the eyebrow, the footnote, the
    card body, a nav link and a footer link were all rgb(154,161,189) at 7.85:1.
    With no tonal step between them the eye is given no order to read in.
    Three tones now: the lede and card body stay where they are, labels sit a
    step back, and the true minor text - footnotes, footer links, the plan's
    period - sits a step further. All three still pass AA on this ground.    */
:root{--muted2:#848bab;--faint:#7b82a0}   /* 4.48 -> 5.0 : AA with room */
.eyebrow,.num,footer h4{color:var(--muted2)}
p.note,footer a,.plan .per,.lockup .by,.signoff .sub{color:var(--faint)}
footer a:hover{color:var(--text)}

/*  ⛔ 3. A 1180 COLUMN IN A 1920 WINDOW. On a wide monitor the whole page was a
    narrow left-hand strip with half the screen empty beside it. The column
    opens up on big screens only - the reading measure of the lede is capped
    separately, so lines never get too long to read.                         */
@media(min-width:1600px){
  :root{--maxw:1340px}
  .lede{max-width:52ch}
}

/*  ⛔ A SPECIFICITY BUG THAT HAD BEEN THERE SINCE THE CARDS WERE WRITTEN.
    .card p {font-size:1rem; color:var(--muted)} is (0,1,1); .num is (0,1,0).
    So the card's generic paragraph rule BEAT the label rule, and 01..06 have
    been drawing at 16 px bold with 3.2 px of tracking instead of the 11 px
    small-caps they were designed as - and in the wrong grey.
    ⚠ This is why reading a stylesheet is not enough. The rule was right, the
      file was right, and the browser was correctly ignoring it. Only asking
      the BROWSER which rules matched the element found it.                  */
.card .num{font:600 11px/1 Montserrat,sans-serif;letter-spacing:.2em;
  text-transform:uppercase;color:var(--muted2);margin-bottom:.9rem;display:block}

/*  ⛔ EVERY SECTION HEADING WAS INDENTED FROM ITS OWN CONTENT, ON EVERY PAGE.
    .wrap centres a 1340 column. .head then set max-width:62ch on the SAME
    element - so the container itself shrank and re-centred, and the heading
    block drifted ~300 px to the right of the cards and belts below it. At 1920
    it is unmistakable once you look at the left edges; at 1440 it is a subtle
    wrongness you feel and cannot name.
    ★ The container keeps its full width and the MEASURE is limited on the text
      inside it, so the reading line is still short and the left edge is shared.  */
.wrap.head{max-width:var(--maxw)}
.wrap.head>h1,.wrap.head>h2,.wrap.head>p,.wrap.head>.lede{max-width:62ch}
.page-top .wrap{max-width:var(--maxw)}
.page-top h1,.page-top .lede{max-width:min(100%,24ch)}
.page-top .lede{max-width:min(100%,56ch)}

/*  ⛔ THE EMAIL FIELD GREW TO 1160 px. Removing the container's inline width
    fixed the alignment and let the form stretch the whole column with it - an
    address field a metre wide reads as a mistake, and the button drifts far
    from the thing it submits.
    ★ The form is capped at a human size and stays left-aligned with everything
      else in the section.                                                     */
form.join{max-width:520px}
form.join input{flex:1 1 220px;min-width:0}

/*  the headline swap: out, change, back in - on the same tick as the picture.
    ⚠ It moves a little as well as fades; a pure opacity change on type this
      large reads as a flicker rather than as a line being replaced.          */
#hl{transition:opacity .26s ease,transform .26s cubic-bezier(.2,.8,.2,1)}
#hl.swap{opacity:0;transform:translateY(14px)}
@media(prefers-reduced-motion:reduce){#hl{transition:none}#hl.swap{opacity:1;transform:none}}

/*  ⚠ A CHANGING <h1> IS A PROBLEM FOR A SCREEN READER - some announce it every
    time it changes, so the page would read its own headline six times a minute
    at the visitor. The h1 now holds ONE stable sentence for assistive software,
    and the rotating lines are aria-hidden decoration beside it.              */
.sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap;border:0}

/*  the six marks: a statement that there are more screens, not a control.    */
.dots{display:flex;gap:7px;margin-top:1.6rem}
.dots i{width:22px;height:2px;border-radius:2px;background:rgba(255,255,255,.17);
  transition:background .5s ease,width .5s ease}
.dots i.on{width:40px;background:var(--rainbow);background-size:600% 100%}
@media(prefers-reduced-motion:reduce){.dots i{transition:none}}

/*  ★ THE HERO TEXT MOVES INTO THE EMPTY LEFT. Owner, 2 Oct: "if you move text
    on left side which is empty much better". He is right about the composition:
    the scrim already darkens the left third for the type, so the words were
    sitting in the middle of their own dark panel with a wide empty margin
    beside them, while the picture was cropped harder than it needed to be.
    ⚠ THE HERO ONLY. Every section below keeps the centred column, because that
      is where the reading happens and a 1340 measure hugging the screen edge is
      not reading, it is scanning.
    ⚠ clamp, not a fixed number: at 20 px it still clears a phone's edge, and it
      never grows past 150 so the text does not drift back to the middle on a
      very wide monitor.                                                       */
.hero .wrap{max-width:none;padding-left:clamp(20px,7vw,150px);padding-right:20px}
.hero h1,.hero .lede{max-width:min(100%,21ch)}
.hero .lede{max-width:min(100%,46ch)}

/*  ★ AND THE PICTURE SHIFTS RIGHT TO MEET IT. With the words moved into the left
    margin, a centred screen puts its own subject - a clock face, a globe -
    directly behind the headline. object-position slides the crop so the screen's
    middle sits in the half the visitor can actually see, beside the type rather
    than under it. Nothing is lost: these are 16:9 pictures in a taller frame, so
    the crop was always discarding the sides.
    ⚠ Not on a phone, where the text sits ON the picture and centre is correct.  */
@media(min-width:900px){ .stage>*{object-position:66% center} }

/*  ★ THE LOCKUP MOVES TO THE BOTTOM RIGHT. Owner, 2 Oct: just the wordmark and
    "designed and built in Australia" - everything else stays where it is.
    It reads better there: the headline now opens the hero on its own, and the
    name signs it off in the corner the eye reaches last, like a maker's mark on
    the back of an object.
    ⚠ The hero's bottom LEFT already holds the buttons, the footnote and the six
      marks, so the right corner is the only clear one - and the panel keeps a
      gap from the edge so it never looks dropped off the page.               */
.hero .lockup{position:absolute;z-index:3;margin:0;justify-content:flex-end;
  right:clamp(20px,4.5vw,88px);bottom:clamp(22px,5vh,54px);text-align:right}
.hero h1{margin-top:.2rem}
@media(max-width:900px){
  .hero .lockup{position:static;justify-content:flex-start;text-align:left;
    margin:0 0 1.2rem;right:auto;bottom:auto}
  .hero h1{margin-top:0}
}

/*  ⛔ TWO WORDMARKS IN ONE VIEW. Moving the lockup to the bottom right put
    "netPanel" in the top-left header AND in the bottom-right corner at the same
    time - the same word twice on one screenful. That is the kind of thing you
    feel before you can name it, and it is why the hero stopped looking settled.
    ★ The header mark now fades in only once the hero has been scrolled past, so
      exactly ONE netPanel is on screen at any moment: the lockup signs the hero,
      the header carries the name everywhere after it.
    ⚠ It is hidden, not removed - it stays in the tab order and in the page for
      anything that reads the markup, and it is visible from the first scroll.  */
.hero~header .mark,header .mark{transition:opacity .45s ease}
body.at-top header .mark{opacity:0;pointer-events:none}
@media(prefers-reduced-motion:reduce){header .mark{transition:none}}

/* ══ THE PAGE BELOW THE HERO ════════════════════════════════════════════════
   Owner: "im not sure why i think there are some mistake ... im talking about
   page design, it is not hero". Read as a whole rather than section by section,
   two things are wrong and they are the kind you feel before you can name.   */

/*  ⛔ 1. THE TINTED BANDS WERE A BLUE HAZE. Two radial washes at .22 and .18 on
    a near-black page do not read as depth, they read as a different website
    pasted in - a big soft rectangle of blue and purple with the content
    floating in it. The colour on this site belongs to the SCREENS and to the
    wordmark; the page itself is near-black and should stay that way.
    ★ The wash drops to a quarter of its strength and sits on a ground only
      just above the ink, so a band now reads as a change of SURFACE rather
      than a change of brand.                                                 */
.band{background:
  radial-gradient(80% 130% at 10% 0%,rgba(106,134,255,.07),transparent 55%),
  radial-gradient(70% 120% at 92% 100%,rgba(192,132,252,.055),transparent 58%),
  #0b0c15}

/*  ⛔ 2. FIVE IDENTICAL BLOCKS IN A ROW. Every section was eyebrow, thin
    heading, grey paragraph, content - same width, same alignment, same 152 px
    of air above and below. Correct five times over is still monotonous: there
    is no rhythm, so the eye has nothing to measure progress against.
    ★ A hairline where each section begins gives the page joints. It is one
      pixel at 7% white - you do not see it, you feel the page has structure.
    ★ And the air comes down from 152 to 124, which is still generous but stops
      each block drifting alone in the middle of a screenful.                 */
section{padding:clamp(72px,9vw,124px) 0}
section+section::before,section.band::before{content:"";position:absolute;inset:0 0 auto;
  height:1px;background:linear-gradient(90deg,transparent,rgba(255,255,255,.075) 18%,
  rgba(255,255,255,.075) 82%,transparent)}
.signoff::before{display:none}

/*  ⛔ A CROSS-FADE BETWEEN TWO DETAILED SCREENS IS A DOUBLE EXPOSURE. Both slides
    faded over the same 3 s, so for a quarter of every cycle an antique clock and
    a star map were drawn on top of each other - unreadable, and it is exactly
    what a screenshot of the hero caught.
    ★ THE OUTGOING LEAVES FAST, THE INCOMING ARRIVES SLOWLY. An element takes the
      transition of the state it is moving INTO: removing .up uses the base rule
      (.5 s out), adding it uses the .up rule (1.25 s in). The result is a short
      dip toward the dark page and then one picture - a change, not a blend.
    ⚠ The drift still has to outlast the hold, or the picture freezes before the
      next one comes.                                                          */
.stage>*{transition:opacity .5s ease,transform 22s linear}
.stage>*.up{transition:opacity 1.25s ease,transform 22s linear}

/* FOUR price cards since 15 Oct 2026: Free, Benefits, Plus, Premium. The Plus tier
   ($15/mo, $150/yr) existed in the database and in PayPal but had never been put on
   the page, so nobody could buy it. Three-up left it orphaned on its own row, so the
   grid is 2-up from 820px and 4-up once there is room. .plans is used by the pricing
   page alone, so this touches nothing else. */
@media(min-width:1140px){.plans{grid-template-columns:repeat(4,1fr)}}
