/* ═══════════════════════════════════════════════════════════════════════════
   patriot.plus, the page at /. The selling page.

   It is the house look's sky register, and only that: navy ground, orange
   horizon, a grid floor, Oswald for display and Inter for body. The tokens
   below are the same values live/assets/live.css carries in its :root, copied
   rather than imported on purpose. live.css is 350 lines of two registers, a
   projector, phone controls and result bars, none of which this page uses, and
   it belongs to the people working on the meeting. A selling page that breaks
   because somebody retuned a poll bar is a selling page nobody can trust.

   MOBILE FIRST, and the width it is written against is 390px, which is the
   iPhone the members in the room are holding. Every rule here is the phone's
   rule; the media queries only add room when there is room.

   NOTHING HERE SCROLLS SIDEWAYS except the looks strip, which is told to.
   ═══════════════════════════════════════════════════════════════════════════ */
:root {
  --blue: #0021A5;
  --orange: #FA4616;
  --gold: #F0A830;
  --navy: #001845;
  --dark: #0A0E1A;
  --sky-muted: #c7cfe6;
  /* Small print is body text. .74 is the alpha that clears the body contrast
     floor over this ground, measured, and it is the same value live.css and
     themes.js carry for --sky-faint. */
  --sky-faint: rgba(255, 255, 255, 0.74);
  --sky-line: rgba(255, 255, 255, 0.14);
  --panel: rgba(0, 12, 36, 0.72);
  --head: 'Oswald', 'Inter', sans-serif;
  --body: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
  --gut: 20px;
  --wide: 1080px;
}

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  position: relative;
  min-height: 100vh;
  font-family: var(--body);
  color: #fff;
  background: var(--dark);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
img { max-width: 100%; display: block; }
a { color: inherit; }
button, input, textarea { font: inherit; color: inherit; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* ── the ground ──────────────────────────────────────────────
   The two layers live.css paints, the sky with its horizon burn and the grid
   floor in perspective. Both are ABSOLUTE and both stop under the hero, which
   is the one thing here that differs from live.css, where they are fixed.

   Fixed was tried and measured. A grid floor that stays across the middle of
   the screen while somebody scrolls sits behind eight paragraphs of body copy,
   and body copy over the horizon burn measured 6.05:1 where the same copy over
   the flat ground measures 12.4:1. The look belongs to the top of the page.
   Everything under it reads on the flat navy, which is what a page somebody is
   deciding fifty dollars a month on should do. */
.ground {
  position: absolute; left: 0; right: 0; top: 0; height: 112vh;
  overflow: hidden; z-index: -3; pointer-events: none;
}
.sky {
  position: absolute; inset: 0;
  background:
    radial-gradient(ellipse 70% 36% at 50% 34%, rgba(250, 70, 22, .40), rgba(250, 70, 22, 0) 70%),
    radial-gradient(ellipse 90% 44% at 50% 42%, rgba(240, 168, 48, .14), transparent 70%),
    linear-gradient(180deg, #05070f 0%, #0b1240 22%, #1a1a5e 34%, #0A0E1A 56%);
}
.floor {
  position: absolute; left: -40vw; right: -40vw; top: 58vh; height: 54vh;
  background:
    repeating-linear-gradient(90deg, rgba(250, 70, 22, .8) 0 2px, transparent 2px 120px),
    repeating-linear-gradient(0deg, rgba(250, 70, 22, .8) 0 2px, transparent 2px 60px),
    linear-gradient(180deg, rgba(10, 14, 26, .2), #0A0E1A 92%);
  transform: perspective(520px) rotateX(58deg);
  transform-origin: 50% 0;
  /* Faded at both ends. The top fade is the horizon; the bottom fade is so the
     grid is gone by the time the first paragraph of body copy starts. */
  opacity: .55;
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 22%, #000 58%, transparent 94%);
  mask-image: linear-gradient(180deg, transparent, #000 22%, #000 58%, transparent 94%);
}

/* ── shared type ────────────────────────────────────────────────────────── */
.eyebrow {
  font-family: var(--head); font-weight: 600; font-size: .74rem;
  letter-spacing: .3em; text-transform: uppercase; color: var(--gold);
  text-shadow: 0 2px 10px rgba(0, 0, 0, .85);
}
h1, h2 {
  font-family: var(--head); font-weight: 700; line-height: 1.02;
  letter-spacing: .01em; text-transform: uppercase; text-wrap: balance;
  text-shadow: 0 0 22px rgba(255, 90, 31, .35), 3px 3px 0 var(--blue);
}
h1 { font-size: clamp(1.7rem, 6.2vw, 2.7rem); margin: 14px 0 16px; }
h2 { font-size: clamp(1.5rem, 5.6vw, 2.4rem); margin: 10px 0 12px; }
p { line-height: 1.55; }
.lede { color: var(--sky-muted); font-size: 1rem; max-width: 46ch; }
main { position: relative; z-index: 2; }
section { padding: 0 var(--gut); max-width: var(--wide); margin: 0 auto; }

/* ── buttons ────────────────────────────────────────────────────────────── */
.btn {
  font-family: var(--head); font-size: .82rem; font-weight: 600;
  letter-spacing: .15em; text-transform: uppercase;
  padding: 15px 24px; border: 0; cursor: pointer; border-radius: 0;
  background: var(--gold); color: var(--navy); text-decoration: none;
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
}
.btn:hover { background: #ffc35a; }
.btn:disabled { opacity: .5; cursor: default; }
.btn-ghost { background: transparent; color: #fff; border: 1px solid rgba(255, 255, 255, .4); }
.btn-ghost:hover { background: rgba(255, 255, 255, .08); }
.btn-block { width: 100%; }
:focus-visible { outline: 3px solid var(--gold); outline-offset: 3px; }

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 30;
  background: var(--gold); color: var(--navy); padding: 10px 14px;
  font: 600 .8rem var(--head); letter-spacing: .12em; text-transform: uppercase;
}
.skip:focus { left: 8px; top: 8px; }

/* ── the bar across the top ─────────────────────────────────────────────── */
.top {
  position: relative; z-index: 3;
  max-width: var(--wide); margin: 0 auto;
  padding: 16px var(--gut) 0;
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
}
.top-nav { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; justify-content: flex-end; }
.wordmark {
  font-family: var(--head); font-weight: 700; font-size: 1.1rem;
  letter-spacing: .04em; text-transform: uppercase;
}
.wordmark .dot, .foot-mark .dot { color: var(--orange); }
.top-join {
  font-family: var(--head); font-weight: 600; font-size: .72rem;
  letter-spacing: .16em; text-transform: uppercase; color: var(--sky-muted);
  text-decoration: none; border-bottom: 2px solid var(--gold); padding-bottom: 3px;
}
.top-join:hover { color: #fff; }

/* ── the hero ───────────────────────────────────────────────────────────── */
.hero { padding-top: 10vh; padding-bottom: 14vh; }
.hero h1 { max-width: 20ch; }
.hero-do { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 28px; }
.hero-do .btn { flex: 1 1 200px; }

/* The clip. Same frame as the screenshots further down, because the page
   should have one idea of what a screen looks like: a hard edge, a hard blue
   offset, no rounding.

   The aspect ratio and the flat ground under it are the reason the page does
   not jump: preload="none" means the browser has no idea how big the video is
   until somebody plays it, so the box has to be the right size before the
   first byte arrives, and the poster has to have something to sit on while it
   loads. Both are the projector's own 16 by 9. */
.hero-clip { margin: 34px 0 0; }
.hero-clip video {
  display: block; width: 100%; height: auto;
  aspect-ratio: 16 / 9;
  background: var(--dark);
  border: 1px solid var(--sky-line);
  box-shadow: 0 18px 50px rgba(0, 0, 0, .55), 6px 6px 0 rgba(0, 33, 165, .55);
}
/* --sky-muted rather than --sky-faint, because this caption is the lowest
   thing in the hero and it lands where the grid floor is still being drawn.
   Measured from pixels at both widths: 12.2:1 at 1280 by 800 and 12.2:1 at
   390 by 844, against a 4.5:1 floor for body text. */
.hero-clip figcaption {
  margin-top: 12px; color: var(--sky-muted);
  font-size: .82rem; line-height: 1.5; max-width: 60ch;
}

/* ── the room ───────────────────────────────────────────────────────────
   The one photograph on the page (index.html says why it sits here). It is
   the width of the page and not of a section, because a frame with a blue
   offset is how this page draws a SCREEN, and this is a room.

   THE BOX IS SIZED BY ASPECT-RATIO, NOT BY THE FILE. The image is lazy, so
   the box exists long before the bytes do, and a box that waited for them
   would push the three blocks down while somebody was reading them. 4:5 on a
   phone, the crop the phone's <source> carries; 16:9 wider, capped at 80vh so
   a laptop still sees where the page goes next, with object-fit taking the
   cap out of the ceiling and the front row rather than squashing anyone. */
.room { margin: 0 0 56px; }
.room-pic { position: relative; }
.room picture { display: block; }
.room img {
  width: 100%; height: auto;
  aspect-ratio: 4 / 5;
  object-fit: cover; object-position: 50% 40%;
  background: var(--dark);
}
/* THE WORDS SIT ON THE BOTTOM OF THE PICTURE, AND ONLY THERE. The top half
   of this photograph is a lit white projector screen, which is the one place
   on it white type could not be read, and the bottom third is the backs of
   heads, darker than the page's own ground. tools/check-landing.mjs measures
   every line from rendered pixels against 4.5:1 at 390, 768 and 1280.

   So the fade below is NOT what carries the ratio, and that was measured
   rather than assumed: with no fade at all and the type's own shadows
   removed, the eyebrow read 9.2 to 10.1 and the headline 19.5 to 20.0, and a
   first draft that laid the ground at .94 over the bottom half measured no
   better (9.3 to 9.6, 19.3 to 19.4), because this navy is lighter than the
   seats it would cover. The fade is here to take the top and bottom edges of
   the photograph into the ground, so it starts and ends rather than being
   pasted on. Anybody moving the words up the picture answers to the check,
   not to this layer. */
.room-pic::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background:
    linear-gradient(180deg, var(--dark) 0%, rgba(10, 14, 26, 0) 14%),
    linear-gradient(0deg, var(--dark) 0%, rgba(10, 14, 26, 0) 30%);
}
.room-words {
  position: absolute; z-index: 1; left: 0; right: 0; bottom: 0;
  max-width: var(--wide); margin: 0 auto;
  padding: 0 var(--gut) 22px;
}
.room-words h2 { max-width: 18ch; margin-bottom: 0; }
/* Under the picture, on the flat ground, so it is ordinary small print. */
.room figcaption {
  max-width: var(--wide); margin: 12px auto 0; padding: 0 var(--gut);
  color: var(--sky-muted); font-size: .82rem; line-height: 1.5;
}

/* ── the three blocks ───────────────────────────────────────────────────── */
.blocks { display: grid; gap: 64px; padding-top: 20px; padding-bottom: 20px; }
.block { display: grid; gap: 20px; }
.block-words p { color: var(--sky-muted); margin-top: 10px; max-width: 52ch; }

/* A screenshot in a frame that reads as a screen: a hard edge, a hard blue
   offset, no rounding. .shot-crop takes 52px off the bottom of a 1280 by 720
   projector capture, which is the join bar a developer machine printed its own
   host into. Nothing above it moves, and the crop is declared in the aspect
   ratio rather than by a negative margin so the box never disagrees with the
   picture inside it. */
.shot { margin: 0; }
.shot img {
  width: 100%; height: auto;
  border: 1px solid var(--sky-line);
  box-shadow: 0 18px 50px rgba(0, 0, 0, .55), 6px 6px 0 rgba(0, 33, 165, .55);
}
.shot-crop { position: relative; }
.shot-crop img {
  aspect-ratio: 1280 / 668;
  height: auto;
  object-fit: cover;
  object-position: 50% 0;
}
.shot figcaption {
  margin-top: 12px; color: var(--sky-faint);
  font-size: .82rem; line-height: 1.5;
}

/* ── the looks strip ────────────────────────────────────────────────────── */
.looks { padding-top: 56px; padding-bottom: 20px; }
.looks .lede { margin-bottom: 20px; }
.strip {
  display: flex; gap: 14px; list-style: none;
  overflow-x: auto; overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  padding-bottom: 10px;
  /* The strip is the one thing on this page allowed past the gutters, so it
     reads as a strip and not as a boxed carousel. */
  margin: 0 calc(var(--gut) * -1);
  padding-left: var(--gut); padding-right: var(--gut);
}
.strip li { flex: 0 0 auto; scroll-snap-align: start; }
.strip img {
  width: 150px; height: auto;
  border: 1px solid var(--sky-line);
  box-shadow: 0 14px 34px rgba(0, 0, 0, .55);
}
.strip-note { color: var(--sky-faint); font-size: .82rem; margin-top: 4px; }

/* ── pricing ────────────────────────────────────────────────────────────── */
.pricing { padding-top: 56px; padding-bottom: 20px; }
.price-grid { display: grid; gap: 14px; margin-top: 22px; }
.price-now, .price-then {
  background: var(--panel); border: 1px solid var(--sky-line);
  padding: 20px; backdrop-filter: blur(6px);
}
.price-then { border-color: var(--gold); }
.price-tag {
  font-family: var(--head); font-weight: 700; font-size: 2.6rem; line-height: 1;
  font-variant-numeric: tabular-nums; text-shadow: 3px 3px 0 var(--blue);
}
.price-tag .per {
  font-size: .9rem; letter-spacing: .16em; text-transform: uppercase;
  color: var(--gold); margin-left: 10px; text-shadow: none;
}
.price-when {
  font-family: var(--head); font-weight: 600; font-size: .74rem;
  letter-spacing: .2em; text-transform: uppercase; color: var(--gold);
  margin: 8px 0 10px;
}
.price-now p, .price-then p { color: var(--sky-muted); font-size: .94rem; }
.includes { list-style: none; display: grid; gap: 0; margin-top: 22px; }
.includes li {
  color: var(--sky-muted); font-size: .96rem; line-height: 1.5;
  padding: 14px 0; border-top: 1px solid var(--sky-line);
}
.includes li:last-child { border-bottom: 1px solid var(--sky-line); }
.includes strong { color: #fff; font-weight: 600; }

/* ── the request form ───────────────────────────────────────────────────── */
.request { padding-top: 56px; padding-bottom: 40px; scroll-margin-top: 20px; }
.form {
  display: grid; gap: 14px; margin-top: 24px; max-width: 640px;
  background: var(--panel); border: 1px solid var(--sky-line);
  padding: 20px; backdrop-filter: blur(6px);
}
.pair { display: grid; gap: 14px; }
.field { display: grid; gap: 6px; }
.label {
  font-family: var(--head); font-weight: 600; font-size: .68rem;
  letter-spacing: .18em; text-transform: uppercase; color: var(--gold);
}
.input {
  width: 100%; padding: 13px 14px;
  background: rgba(0, 0, 0, .45); border: 1px solid rgba(255, 255, 255, .32);
  color: #fff; font-family: var(--body); font-size: 1rem; border-radius: 0;
  outline: none;
}
.input::placeholder { color: rgba(255, 255, 255, .45); }
.input:focus { border-color: var(--gold); }
.input[aria-invalid="true"] { border-color: #ff9d8a; }
.textarea { min-height: 96px; resize: vertical; line-height: 1.5; }

/* The honeypot: off the page rather than display:none, because a filler that
   skips hidden fields is the filler this is for. */
.trap { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* One line under the form, in the form. Never a floating toast: the sentence
   is about the field the cursor is still in. */
.form-msg { display: none; font-size: .92rem; line-height: 1.5; padding: 12px 14px; border: 1px solid; }
.form-msg.on { display: block; }
.form-msg.bad { border-color: #ff9d8a; color: #ffd8d0; background: rgba(200, 37, 15, .18); }
.form-msg.good { border-color: #7dffb0; color: #d7ffe8; background: rgba(31, 138, 76, .18); }
.form-fine { color: var(--sky-faint); font-size: .8rem; }

/* ── the footer ─────────────────────────────────────────────────────────── */
.foot {
  position: relative; z-index: 2;
  max-width: var(--wide); margin: 0 auto;
  padding: 34px var(--gut) 56px;
  border-top: 1px solid var(--sky-line);
  display: grid; gap: 14px;
}
.foot-join {
  font-family: var(--head); font-weight: 600; font-size: .82rem;
  letter-spacing: .14em; text-transform: uppercase; color: var(--gold);
  text-decoration: none; justify-self: start;
  border-bottom: 2px solid var(--gold); padding-bottom: 3px;
}
.foot-join:hover { color: #fff; }
.foot-indep { color: var(--sky-muted); font-size: .84rem; max-width: 58ch; }
.foot-mark {
  font-family: var(--head); font-weight: 700; font-size: .95rem;
  letter-spacing: .04em; text-transform: uppercase; color: var(--sky-faint);
}
/* The row of links to the other pages. It lives here rather than in
   pages.css because this footer is on every page on the site, including this
   one, and one stylesheet for a footer is enough. */
.foot-links { display: flex; flex-wrap: wrap; gap: 6px 18px; }
.foot-links a {
  font-family: var(--head); font-weight: 600; font-size: .74rem;
  letter-spacing: .14em; text-transform: uppercase; color: var(--sky-faint);
  text-decoration: none;
}
.foot-links a:hover { color: #fff; }
.foot-links a[aria-current="page"] { color: var(--gold); }

/* ── wider than a phone ─────────────────────────────────────────────────── */
@media (min-width: 600px) {
  :root { --gut: 28px; }
  .pair { grid-template-columns: 1fr 1fr; }
  .price-grid { grid-template-columns: 1fr 1fr; }
  .form { padding: 26px; }
  .strip img { width: 190px; }
  .hero-do .btn { flex: 0 0 auto; }
  /* The wide file from here up: the same 600 the <source> in index.html
     switches at, so the box and the picture change shape together. */
  .room img { aspect-ratio: 16 / 9; max-height: 80vh; object-position: 50% 45%; }
  .room-words { padding-bottom: 34px; }
}

@media (min-width: 900px) {
  :root { --gut: 36px; }
  .hero { padding-top: 15vh; padding-bottom: 18vh; }
  .hero h1 { max-width: 26ch; }
  .blocks { gap: 90px; }
  .block { grid-template-columns: 1fr 1.25fr; gap: 40px; align-items: center; }
  .block-flip .block-words { order: 2; }
  .block-flip .shot { order: 1; }
  .looks, .pricing, .request { padding-top: 84px; }
  .room { margin-bottom: 84px; }
  .strip img { width: 210px; }
}
