/* ============================================================================
   nextupalert.com — site.css
   One hand-written stylesheet. No framework, no preprocessor, no build.

   01 TOKENS        colour, type scale, spacing, radii, shadow
   02 RESET         minimal and opinionated
   03 BASE          html/body/links/focus/selection/headings
   04 LAYOUT        .wrap .section .grid
   05 HEADER        brand, nav, burger, theme toggle
   06 FOOTER
   07 PROSE         .prose — carries both legal pages and all long copy
   08 COMPONENTS    .btn .eyebrow .taskbar .states .card .shot .faq .cta .trust
   09 UTILITIES     .u-* only; the only place !important is allowed
   10 PRINT

   Rules of the house
     · Media queries live INSIDE the section they modify, never in one block at
       the bottom. That is how a stylesheet stays editable a year later.
     · Max two class selectors deep. No IDs. No !important outside section 09.
     · Only section 01 contains literal colour values.
     · Every time value on this site is set in the mono face with tabular-nums,
       so digits never jitter as they count down.

   Map the file:  grep -n '^   [0-9][0-9] ' css/site.css
   ============================================================================ */


/* == 01 TOKENS ============================================================= */

:root {
  color-scheme: light dark;

  /* Tier 1 — identity. The three states of the taskbar icon. These are the
     product's actual state machine, not decoration, which is why they are the
     only saturated colours on the site.

     MEASURED, not invented. Sampled pixel by pixel from the icon's coloured
     band in all three states in _src/img/nextup-screenshot-05.jpg:
       green  #34a853   yellow #fbbc05   red #ea4335
     The mid state is a true YELLOW at hue 45°. The earlier guess (#e9a83c)
     sat 8° toward orange, which is why it read muddy and never looked like
     the app. The site's prose says "yellow" everywhere for the same reason:
     the word was wrong before the hex was.

     Every state ships as a pair, and which one you reach for depends on how
     much of it you are about to draw:

       --*-500  the product colour. Use it as a FILL — chips, the icon band,
                dots, swatches — always carrying --c-state-in as its ink,
                exactly like the real icon's dark numerals on a coloured tile.
       --*-700  the same hue shaded down in linear light until it clears 4:1
                on the palest surface the site has (the hero taskbar strip,
                #eaeff6). Use it for anything drawn THIN — 4px rails,
                hairlines, rings — and it is the only one of the pair that may
                ever be a letterform on a light background.

     The split exists because of yellow. #fbbc05 is 1.7:1 on white: as a block
     of colour under dark text it is perfect and unmistakably the product, and
     as a stroke or a glyph it is invisible. Green and red get the same
     treatment so all three behave identically rather than yellow being a
     special case that the next person has to remember. */
  --go-500:   #34a853;  --go-700:   #278540;
  --soon-500: #fbbc05;  --soon-700: #956e02;
  --now-500:  #ea4335;  --now-700:  #d53c2f;

  /* Gold, and only for the ★★★★★ store rating. It looks adjacent to the
     yellow state but it is a different thing entirely: a rating is not "your
     meeting is close". Sharing --c-soon meant a change to the product's state
     machine silently repainted a review score — the same class of mistake as
     using green for a call to action. Deliberately softer and warmer than the
     signal yellow so the two never read as the same badge. */
  --gold-500: #eeb43f;  --gold-700: #9e7622;

  /* Tier 1 — interaction. Blue is the brand and every interactive thing:
     links, buttons, focus, icons. It is deliberately NOT green, because green
     already means "you have time" on the taskbar — one colour cannot carry a
     product state and a call to action without muddling both.

     Both values are pinned by contrast, not taste. The light blue clears 4.5:1
     against the palest surface (#eef2f8) so body links pass AA; the dark blue
     clears 4.5:1 against the near-black ground. `-solid` is the button fill,
     chosen so white text on it passes AA in both themes. */
  --blue-700: #1257b8;  /* light theme: 6.1:1 on #eef2f8, 6.8:1 under white */
  --blue-600: #1a6fd4;  /* dark theme button fill: 4.9:1 under white */
  --blue-400: #4d9bff;  /* dark theme text/links: 6.9:1 on #0a0e17 */

  /* Tier 1 — ground. A deep navy-black rather than #000: this is a Windows
     desktop utility, and the page should read like a screen at night. */
  --ink-950: #0a0e17;  --ink-900: #0e1420;  --ink-850: #131a28;
  --ink-800: #1a2233;  --ink-700: #232c3e;
  --paper-50: #f6f8fc; --paper-100: #eef2f8; --paper-200: #e0e6f0;
  --slate-500: #8b95ac; --slate-700: #4e5872; --slate-900: #0d1220;

  /* Tier 2 — semantic. Everything below section 01 references only these.
     light-dark() keeps both themes on one line so they cannot drift apart, and
     follows prefers-color-scheme automatically via color-scheme above. */
  --c-bg:        light-dark(var(--paper-50),  var(--ink-950));
  --c-surface:   light-dark(#ffffff,          var(--ink-850));
  --c-surface-2: light-dark(var(--paper-100), var(--ink-900));
  --c-raised:    light-dark(#ffffff,          var(--ink-800));
  --c-text:      light-dark(var(--slate-900), #e8ecf5);
  --c-text-mute: light-dark(var(--slate-700), var(--slate-500));
  --c-border:    light-dark(var(--paper-200), var(--ink-700));
  /* The state colour as a FILL. The same in both themes, because it is the
     product's colour and the product does not have a light mode for it. */
  --c-go:        var(--go-500);
  --c-soon:      var(--soon-500);
  --c-now:       var(--now-500);
  /* …and as a LINE: rails, hairlines, rings, and any future letterform. On a
     dark ground the product colour is already 5–10:1, so the pair collapses
     to one value and only the light theme pays for the split. */
  --c-go-line:   light-dark(var(--go-700),   var(--go-500));
  --c-soon-line: light-dark(var(--soon-700), var(--soon-500));
  --c-now-line:  light-dark(var(--now-700),  var(--now-500));
  /* The ink that sits on a state fill: the same near-black the real icon
     prints its numerals in. One value for all three states — 6.0:1 on green,
     10.8:1 on yellow, 4.7:1 on red — which is only possible because the fills
     are the bright product colours. White would fail on yellow at 1.7:1. */
  --c-state-in:  #10141d;
  --c-star:      light-dark(var(--gold-700), var(--gold-500));
  --c-accent:      light-dark(var(--blue-700), var(--blue-400));
  --c-accent-solid: light-dark(var(--blue-700), var(--blue-600));
  --c-accent-in:   #ffffff;
  /* 12% of the accent, for icon chips and glows. Derived, never hard-coded, so
     changing the accent above changes everything that echoes it. */
  --c-accent-wash: color-mix(in srgb, var(--c-accent) 12%, transparent);

  /* Type. The UI face is the reader's own system font — on Windows that is
     Segoe UI Variable, which is exactly right for a Windows utility. The mono
     face leads with Cascadia, Microsoft's own, for every numeral on the site. */
  --f-ui: ui-sans-serif, system-ui, -apple-system, "Segoe UI Variable Text",
          "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --f-mono: ui-monospace, "Cascadia Mono", "Cascadia Code", "SF Mono",
            "Segoe UI Mono", Menlo, Consolas, monospace;

  --step--1: clamp(0.82rem, 0.80rem + 0.10vw, 0.875rem);
  --step-0:  clamp(1rem, 0.96rem + 0.20vw, 1.0625rem);
  --step-1:  clamp(1.15rem, 1.08rem + 0.35vw, 1.3rem);
  --step-2:  clamp(1.4rem, 1.25rem + 0.75vw, 1.85rem);
  --step-3:  clamp(1.8rem, 1.5rem + 1.5vw, 2.6rem);
  --step-4:  clamp(2.25rem, 1.7rem + 2.8vw, 4rem);

  --space-1: 0.375rem;
  --space-2: 0.75rem;
  --space-3: clamp(1rem, 0.9rem + 0.5vw, 1.35rem);
  --space-4: clamp(1.5rem, 1.2rem + 1.5vw, 2.5rem);
  --space-5: clamp(2.5rem, 1.9rem + 3vw, 4.5rem);
  --space-6: clamp(3.5rem, 2.5rem + 5vw, 7rem);

  --r-sm: 6px;  --r-md: 10px;  --r-lg: 16px;  --r-xl: 22px;
  --shadow: 0 1px 2px light-dark(rgb(13 18 32 / 6%), rgb(0 0 0 / 40%)),
            0 8px 24px -8px light-dark(rgb(13 18 32 / 10%), rgb(0 0 0 / 55%));
  --shadow-lg: 0 2px 4px light-dark(rgb(13 18 32 / 8%), rgb(0 0 0 / 45%)),
               0 24px 60px -16px light-dark(rgb(13 18 32 / 16%), rgb(0 0 0 / 70%));
  --ring: 0 0 0 3px color-mix(in srgb, var(--c-accent) 40%, transparent);

  --wrap: 68rem;
  --wrap-narrow: 46rem;
}

/* The manual toggle. Two rules, because light-dark() does the rest. */
html[data-theme="light"] { color-scheme: light; }
html[data-theme="dark"]  { color-scheme: dark; }


/* == 02 RESET ============================================================== */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body, h1, h2, h3, h4, p, figure, blockquote, dl, dd, ul, ol {
  margin: 0;
}

ul[class], ol[class] { list-style: none; padding: 0; }

img, svg, video { display: block; max-width: 100%; height: auto; }

input, button, textarea, select { font: inherit; color: inherit; }

button { background: none; border: 0; cursor: pointer; }


/* == 03 BASE =============================================================== */

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--c-bg);
  color: var(--c-text);
  font-family: var(--f-ui);
  font-size: var(--step-0);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4 {
  line-height: 1.12;
  letter-spacing: -0.022em;
  font-weight: 680;
  text-wrap: balance;
  /* Clear the sticky header, or every in-page anchor lands underneath it. */
  scroll-margin-top: 5rem;
}

:target { scroll-margin-top: 5rem; }

h1 { font-size: var(--step-4); letter-spacing: -0.032em; }
h2 { font-size: var(--step-3); }
h3 { font-size: var(--step-1); letter-spacing: -0.012em; }

p { text-wrap: pretty; }

a { color: inherit; }

a:not([class]) {
  color: var(--c-accent);
  text-underline-offset: 0.18em;
  text-decoration-thickness: from-font;
}

a:not([class]):hover { text-decoration-thickness: 2px; }

:focus-visible {
  outline: 2px solid var(--c-accent);
  outline-offset: 3px;
  border-radius: 3px;
}

::selection {
  background: var(--c-accent-solid);
  color: var(--c-accent-in);
}

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  padding: var(--space-2) var(--space-3);
  background: var(--c-accent-solid);
  color: var(--c-accent-in);
  border-radius: 0 0 var(--r-sm) 0;
  font-weight: 600;
}
.skip:focus { left: 0; }

/* Every numeral on this site: monospaced and tabular so countdowns never jitter. */
.num, time, .taskbar__count {
  font-family: var(--f-mono);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}


/* == 04 LAYOUT ============================================================= */

.wrap {
  width: min(100% - 2 * var(--space-3), var(--wrap));
  margin-inline: auto;
}

.wrap--narrow { width: min(100% - 2 * var(--space-3), var(--wrap-narrow)); }

.section { padding-block: var(--space-6); }
.section--tight { padding-block: var(--space-5); }

.section--alt {
  background: var(--c-surface-2);
  border-block: 1px solid var(--c-border);
}

.section__head { margin-bottom: var(--space-4); max-width: 44rem; }
.section__head p { color: var(--c-text-mute); margin-top: var(--space-2); }

.grid {
  display: grid;
  gap: var(--space-3);
  grid-template-columns: 1fr;
}

@media (min-width: 40rem) {
  .grid--2, .grid--4 { grid-template-columns: repeat(2, 1fr); }
}

@media (min-width: 60rem) {
  .grid--3 { grid-template-columns: repeat(3, 1fr); }
  .grid--4 { grid-template-columns: repeat(4, 1fr); }
}

/* Text beside an image. Stacks below 60rem, which is most phones and tablets. */
.split {
  display: grid;
  gap: var(--space-4);
  align-items: center;
}

@media (min-width: 60rem) {
  .split { grid-template-columns: 1fr 1fr; gap: var(--space-5); }
  .split--flip > :first-child { order: 2; }
}


/* == 05 HEADER ============================================================= */

.site-head {
  position: sticky;
  top: 0;
  z-index: 50;
  background: light-dark(rgb(246 248 252 / 82%), rgb(10 14 23 / 82%));
  backdrop-filter: saturate(1.6) blur(12px);
  border-bottom: 1px solid var(--c-border);
}

.site-head__in {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: 3.75rem;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  text-decoration: none;
  font-weight: 700;
  letter-spacing: -0.02em;
  font-size: 1.05rem;
  flex: 0 0 auto;
}

/* The Store tile the mark comes from is 310px of which only the middle 102px
   is the icon — a 33% transparent margin the Store adds for its own plate.
   /img/brand-mark-56.png is that tile with the margin trimmed off, shipped at
   2x, so the glyph fills the box instead of floating in a corner of it.

   The mark is a WHITE card with a blue calendar bar, so its silhouette
   dissolves into the light theme's near-white ground. It gets the hairline
   every other white surface on this site gets (.card) rather than the dark
   chip that used to sit behind it — a chip the brand does not have. The
   radius matches the art's own 21.6% corner so the ring traces the tile. */
.brand__mark {
  width: 28px;
  height: 28px;
  border-radius: var(--r-sm);
  box-shadow: 0 0 0 1px var(--c-border);
}
.brand__accent { color: var(--c-accent); }

.site-nav { margin-inline-start: auto; }

.site-nav ul {
  display: flex;
  gap: var(--space-3);
  list-style: none;
  margin: 0;
  padding: 0;
}

.site-nav a {
  text-decoration: none;
  color: var(--c-text-mute);
  font-size: var(--step--1);
  font-weight: 550;
  padding-block: 0.5rem;
  border-bottom: 2px solid transparent;
  transition: color 0.15s ease, border-color 0.15s ease;
}

.site-nav a:hover { color: var(--c-text); }

.site-nav a[aria-current="page"] {
  color: var(--c-text);
  border-bottom-color: var(--c-accent);
}

.site-head__end {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex: 0 0 auto;
}

.themetoggle {
  /* 40px square — clears the WCAG 2.5.8 tap-target minimum without
     inflating the header row. */
  width: 2.5rem;
  height: 2.5rem;
  display: grid;
  place-items: center;
  border-radius: var(--r-sm);
  color: var(--c-text-mute);
  font-size: 1rem;
  line-height: 1;
  transition: background 0.15s ease, color 0.15s ease;
}

.themetoggle:hover { background: var(--c-surface); color: var(--c-text); }

/* The checkbox IS the menu control, so it must stay focusable and stay in the
   accessibility tree. `display: none` (or the `hidden` attribute) would remove
   it from the tab order entirely, leaving keyboard and screen-reader users with
   no way to open the mobile nav at all. Hide it visually, not semantically. */
.navtoggle {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  clip-path: inset(50%);
  overflow: hidden;
}

.burger { display: none; }

.navtoggle:focus-visible ~ .burger {
  outline: 2px solid var(--c-accent);
  outline-offset: 3px;
  border-radius: var(--r-sm);
}

/* Mobile: nav collapses behind a checkbox-driven burger, so it works with no JS. */
@media (max-width: 52rem) {
  .burger {
    display: grid;
    gap: 4px;
    margin-inline-start: auto;
    padding: 0.6rem 0.4rem;
    cursor: pointer;
    order: 3;
  }
  .burger__bar {
    display: block;
    width: 20px;
    height: 2px;
    border-radius: 2px;
    background: var(--c-text);
    transition: transform 0.2s ease, opacity 0.2s ease;
  }
  .site-head__in { flex-wrap: wrap; }
  .site-head__end { order: 2; margin-inline-start: auto; }
  .site-nav {
    order: 4;
    flex-basis: 100%;
    margin-inline-start: 0;
    display: none;
    padding-bottom: var(--space-2);
  }
  .navtoggle:checked ~ .site-nav { display: block; }
  .navtoggle:checked ~ .burger .burger__bar:nth-of-type(1) { transform: translateY(6px) rotate(45deg); }
  .navtoggle:checked ~ .burger .burger__bar:nth-of-type(2) { opacity: 0; }
  .navtoggle:checked ~ .burger .burger__bar:nth-of-type(3) { transform: translateY(-6px) rotate(-45deg); }
  .site-nav ul { flex-direction: column; gap: 0; }
  .site-nav a {
    display: block;
    padding: 0.6rem 0;
    border-bottom: 1px solid var(--c-border);
    font-size: var(--step-0);
  }
  .site-nav a[aria-current="page"] { border-bottom-color: var(--c-accent); }
}


/* == 06 FOOTER ============================================================= */

.site-foot {
  margin-top: var(--space-6);
  padding-block: var(--space-5) var(--space-4);
  background: var(--c-surface-2);
  border-top: 1px solid var(--c-border);
  font-size: var(--step--1);
}

.site-foot__grid {
  display: grid;
  gap: var(--space-4);
  grid-template-columns: 1fr;
}

@media (min-width: 40rem) { .site-foot__grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 68rem) { .site-foot__grid { grid-template-columns: 1.6fr repeat(4, 1fr); } }

.site-foot__pitch {
  color: var(--c-text-mute);
  margin-block: var(--space-2) var(--space-3);
  max-width: 26rem;
}

.site-foot__col h2 {
  font-size: var(--step--1);
  font-weight: 650;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--c-text-mute);
  margin-bottom: var(--space-2);
}

.site-foot__col ul { display: grid; gap: 0.1rem; list-style: none; margin: 0; padding: 0; }

/* Padding rather than list gap carries the spacing, so each link is a full-height
   tap target instead of a bare line of text with dead space between rows. */
.site-foot__col a {
  display: inline-block;
  padding-block: 0.25rem;
  text-decoration: none;
  color: var(--c-text);
  transition: color 0.15s ease;
}
.site-foot__col a:hover { color: var(--c-accent); text-decoration: underline; }

.site-foot__fine {
  margin-top: var(--space-4);
  padding-top: var(--space-3);
  border-top: 1px solid var(--c-border);
  color: var(--c-text-mute);
  display: grid;
  gap: var(--space-2);
}

.site-foot__tm { font-size: 0.75rem; line-height: 1.5; max-width: 62rem; }


/* == 07 PROSE ============================================================== */
/* Carries the two legal pages (~9,000 words) and every long-copy section. */

.prose { max-width: 68ch; }

.prose > * + * { margin-top: var(--space-3); }

.prose h2 {
  font-size: var(--step-2);
  margin-top: var(--space-5);
  padding-top: var(--space-3);
  border-top: 1px solid var(--c-border);
}

.prose h3 { font-size: var(--step-1); margin-top: var(--space-4); }

.prose h4 {
  font-size: var(--step-0);
  font-weight: 680;
  margin-top: var(--space-3);
}

.prose p, .prose li { line-height: 1.7; }

.prose ul, .prose ol { padding-inline-start: 1.35em; }
.prose li + li { margin-top: 0.4em; }
.prose li::marker { color: var(--c-text-mute); }

.prose strong { font-weight: 660; }

.prose a { color: var(--c-accent); text-underline-offset: 0.18em; }

.prose__meta {
  color: var(--c-text-mute);
  font-size: var(--step--1);
  font-family: var(--f-mono);
}

.prose__toc {
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  border-radius: var(--r-md);
  padding: var(--space-3);
}

/* Not a heading: it sits above the page's <h1>, so making it an <h2> would put
   the document's heading order out of sequence. The <nav> already carries
   aria-label="Contents", which is what actually names the region. */
.prose__toc__title {
  margin: 0 0 var(--space-2);
  font-weight: 650;
  font-size: var(--step-0);
  color: var(--c-text);
}

.prose__toc ul { padding-inline-start: 1.1em; }

.legal-toc {
  list-style: none;
  padding: 0;
  display: grid;
  gap: 0.3rem;
  font-size: var(--step--1);
}

.legal-toc a { text-decoration: none; }
.legal-toc a:hover { text-decoration: underline; }
.legal-toc__sub { padding-inline-start: 1.1rem; color: var(--c-text-mute); }

/* The numbered sections. The originals used an <ol>, which is why the text
   says things like "section 5 (Prohibited Uses)" — the numbers are list
   markers, never words, so they stay out of the verbatim comparison. */
.legal-sections { padding-inline-start: 2.2em; }

.legal-sections > li { margin-top: var(--space-4); }

.legal-sections > li::marker {
  font-family: var(--f-mono);
  font-weight: 700;
  color: var(--c-accent);
}

.legal-sections > li > h3:first-child { margin-top: 0; }

/* Tables scroll inside their own box rather than the page. The cell styles are
   scoped to .tablewrap — the box every table sits in — not .prose, because the
   comparison and compliance tables live outside any .prose column. */
.tablewrap {
  overflow-x: auto;
  border: 1px solid var(--c-border);
  border-radius: var(--r-md);
  background: var(--c-surface);
}

/* A four-column table does not fit the 68ch reading measure, so on wide screens
   let it break out of the prose column rather than squeezing every cell. */
@media (min-width: 64rem) {
  .prose .tablewrap { margin-inline: -5rem; }
}

.tablewrap table {
  border-collapse: collapse;
  width: 100%;
  min-width: 32rem;
  font-size: var(--step--1);
}

.tablewrap th, .tablewrap td {
  text-align: left;
  vertical-align: top;
  padding: 0.7rem 0.9rem;
  border-bottom: 1px solid var(--c-border);
}

.tablewrap thead th {
  background: var(--c-surface-2);
  font-weight: 650;
  white-space: nowrap;
}

.tablewrap tbody tr:last-child td { border-bottom: 0; }


/* == 08 COMPONENTS ========================================================= */

/* -- buttons -------------------------------------------------------------- */

.btn {
  --btn-bg: var(--c-accent-solid);
  --btn-fg: var(--c-accent-in);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.7rem 1.15rem;
  border-radius: var(--r-md);
  background: var(--btn-bg);
  color: var(--btn-fg);
  font-weight: 620;
  font-size: var(--step-0);
  line-height: 1.2;
  text-decoration: none;
  white-space: nowrap;
  transition: transform 0.12s ease, filter 0.15s ease, box-shadow 0.15s ease;
  box-shadow: var(--shadow);
}

.btn:hover { filter: brightness(1.07); transform: translateY(-1px); }
.btn:active { transform: translateY(0); }

.btn--lg { padding: 0.95rem 1.6rem; font-size: var(--step-1); border-radius: var(--r-lg); }
.btn--sm { padding: 0.5rem 0.85rem; font-size: var(--step--1); border-radius: var(--r-sm); }

.btn--ghost {
  --btn-bg: transparent;
  --btn-fg: var(--c-text);
  border: 1px solid var(--c-border);
  box-shadow: none;
}
.btn--ghost:hover { background: var(--c-surface); filter: none; }

.btnrow {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: center;
}

/* -- eyebrow -------------------------------------------------------------- */

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--f-mono);
  font-size: 0.75rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--c-text-mute);
  margin-bottom: var(--space-2);
}

.eyebrow::before {
  content: "";
  width: 1.5rem;
  height: 1px;
  background: currentColor;
  opacity: 0.5;
}

/* -- hero ----------------------------------------------------------------- */

.hero { padding-block: var(--space-5); position: relative; overflow: hidden; }

.hero::before {
  content: "";
  position: absolute;
  inset: -30% 20% auto -10%;
  height: 34rem;
  background: radial-gradient(
    ellipse at 30% 40%,
    var(--c-accent-wash),
    transparent 62%);
  pointer-events: none;
  z-index: -1;
}

.hero__in { max-width: 40rem; }

.hero h1 { margin-bottom: var(--space-3); }

.hero__accent { color: var(--c-accent); }

.lede {
  font-size: var(--step-1);
  line-height: 1.5;
  color: var(--c-text-mute);
  max-width: 34rem;
}

.hero .btnrow { margin-top: var(--space-4); }

.hero__fine {
  margin-top: var(--space-2);
  font-size: var(--step--1);
  color: var(--c-text-mute);
}

/* Two columns once there is room: the pitch on the left, the live taskbar
   demo on the right — in the seat a screenshot would normally take, except
   this one counts down and changes colour. Below 60rem it stacks, and the
   demo follows the copy exactly as before. */
@media (min-width: 60rem) {
  .hero .wrap {
    display: grid;
    grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr);
    gap: var(--space-5);
    align-items: center;
  }
  .hero .taskbar { margin-top: 0; }
}

/* -- the signature: a live Windows taskbar counting down ------------------ */

/* Staged as a miniature desktop: quiet wallpaper above, the strip pinned to
   the bottom edge, because that is where a taskbar lives. The empty space is
   deliberate — the product asks for none of your screen, and the vignette
   shows exactly what you give it: one tile. The caption narrates from that
   space, so in the markup it comes BEFORE the bar. */
.taskbar {
  margin-top: var(--space-4);
  display: flex;
  flex-direction: column;
  border: 1px solid var(--c-border);
  border-radius: var(--r-lg);
  background:
    radial-gradient(120% 100% at 78% 0%, var(--c-accent-wash), transparent 62%),
    var(--c-surface);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
}

.taskbar__bar {
  display: flex;
  align-items: center;
  gap: clamp(0.55rem, 2vw, 1.2rem);
  padding: 0.7rem clamp(0.7rem, 2vw, 1.25rem);
  background: light-dark(rgb(233 238 246 / 92%), rgb(24 31 46 / 92%));
  border-top: 1px solid var(--c-border);
  overflow-x: auto;
  scrollbar-width: none;
}
.taskbar__bar::-webkit-scrollbar { display: none; }

/* Windows taskbar icons are square. Colours come from modifier classes rather
   than inline style attributes, because the production CSP is `style-src 'self'`
   with no 'unsafe-inline' — inline styles would be dropped and every icon would
   fall back to the same grey. That failure is invisible in local preview, since
   tools/serve.py does not apply _headers. */
.taskbar__app {
  width: 32px;
  height: 32px;
  border-radius: 7px;
  flex: 0 0 auto;
  opacity: 0.4;
  background: var(--app, var(--c-text-mute));
}

/* Decoys, and deliberately all cool. One of these used to be a warm sand
   (#e6a23c) sitting two slots from the icon — eight degrees of hue from the
   yellow state, so the one thing on the strip that is supposed to mean
   something had a neighbour that looked like it meant the same thing. */
.taskbar__app--blue   { --app: #2f7fe0; }
.taskbar__app--grey   { --app: #8b95ac; }
.taskbar__app--slate  { --app: #3b4a63; }
.taskbar__app--teal   { --app: #2fb0c9; }
.taskbar__app--violet { --app: #6f5cd6; }

/* The NextUp icon itself: a calendar block whose colour is the whole product. */
.taskbar__icon {
  position: relative;
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  /* Square, like the real icon — it is a calendar tile, not a wide badge. The
     app shows short labels (1h+, 2m, 15s) precisely because it has a square to
     work in, so js/hero.js formats to match. */
  width: 2.6rem;
  height: 2.6rem;
  border-radius: 7px;
  background: light-dark(#fff, #f2f5fa);
  border: 2px solid var(--state, var(--c-go));
  border-top-width: 8px;
  transition: border-color 0.6s ease, box-shadow 0.6s ease;
  /* Two shadows, listed nearest-first. The 1px hairline in the LINE colour is
     what makes the tile perceivable: the yellow band itself is only 1.5:1 on
     the light taskbar strip — true to the product, but not a boundary — so a
     4:1 hairline supplies the edge and the fill is left free to be the actual
     product colour. The soft halo behind it is pure atmosphere. */
  box-shadow:
    0 0 0 1px var(--state-line, var(--c-go-line)),
    0 0 0 5px color-mix(in srgb, var(--state, var(--c-go)) 22%, transparent);
}

.taskbar__icon::after {
  content: "";
  position: absolute;
  bottom: -0.55rem;
  left: 50%;
  translate: -50% 0;
  width: 1.1rem;
  height: 3px;
  border-radius: 2px;
  background: var(--state, var(--c-go));
  transition: background-color 0.6s ease;
}

.taskbar__count {
  font-size: 0.95rem;
  font-weight: 700;
  color: var(--c-state-in);
  letter-spacing: -0.04em;
  line-height: 1;
  padding-top: 2px;
}

.taskbar__clock {
  margin-inline-start: auto;
  font-family: var(--f-mono);
  font-size: 0.78rem;
  color: var(--c-text-mute);
  text-align: right;
  line-height: 1.3;
  flex: 0 0 auto;
  padding-inline-start: var(--space-3);
}

/* Anchored top-left like a desktop annotation, so the dot never moves as the
   captions rotate — a centred block would re-seat itself on every beat. */
.taskbar__cap {
  flex: 1;
  display: flex;
  align-items: flex-start;
  gap: 0.55rem;
  min-height: 9rem;
  padding: var(--space-3);
  font-size: var(--step--1);
  color: var(--c-text-mute);
}

@media (min-width: 60rem) {
  .taskbar__cap { min-height: 13rem; }
}

/* Same trick as the icon: the product colour fills it, a hairline ring gives
   it an edge that survives on a pale ground. */
.taskbar__dot {
  width: 0.6rem;
  height: 0.6rem;
  border-radius: 50%;
  background: var(--state, var(--c-go));
  box-shadow: 0 0 0 1px var(--state-line, var(--c-go-line));
  flex: 0 0 auto;
  /* Centred on the first line of the caption, not the whole block, so it
     stays put when a caption wraps to a second line. */
  margin-top: calc((1lh - 0.6rem) / 2);
  transition: background-color 0.6s ease, box-shadow 0.6s ease;
}

.taskbar[data-state="go"]   { --state: var(--c-go);   --state-line: var(--c-go-line); }
.taskbar[data-state="soon"] { --state: var(--c-soon); --state-line: var(--c-soon-line); }
.taskbar[data-state="now"]  { --state: var(--c-now);  --state-line: var(--c-now-line); }

/* -- the three states ----------------------------------------------------- */

.states { display: grid; gap: var(--space-3); counter-reset: none; }

@media (min-width: 52rem) { .states { grid-template-columns: repeat(3, 1fr); } }

.state {
  position: relative;
  padding: var(--space-3) var(--space-3) var(--space-3) calc(var(--space-3) + 0.5rem);
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  border-radius: var(--r-md);
  box-shadow: var(--shadow);
}

.state::before {
  content: "";
  position: absolute;
  inset: var(--space-3) auto var(--space-3) 0;
  width: 4px;
  border-radius: 0 4px 4px 0;
  /* Four pixels is a line, not a fill — hence the LINE colour. */
  background: var(--state-line);
}

.state--go   { --state: var(--c-go);   --state-line: var(--c-go-line); }
.state--soon { --state: var(--c-soon); --state-line: var(--c-soon-line); }
.state--now  { --state: var(--c-now);  --state-line: var(--c-now-line); }

/* The countdown reads as a tile, not as coloured type: the product colour
   fills it and dark ink sits on top, which is exactly how the taskbar icon
   itself is drawn. Colouring the glyphs instead forces every state through
   whatever survives as text on white — which for yellow is a muddy ochre that
   looks nothing like the app. As a fill, the real #fbbc05 can appear at full
   strength and still carry 10.8:1 text. */
.state__time {
  font-family: var(--f-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--step-2);
  font-weight: 700;
  letter-spacing: -0.03em;
  line-height: 1.15;
  display: inline-block;
  padding: 0.1em 0.4em;
  border-radius: var(--r-sm);
  background: var(--state);
  color: var(--c-state-in);
  box-shadow: inset 0 0 0 1px var(--state-line);
}

.state h3 { margin-block: var(--space-1) var(--space-1); }
.state p { color: var(--c-text-mute); font-size: var(--step--1); }

/* -- cards ---------------------------------------------------------------- */

.card {
  padding: var(--space-3);
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  border-radius: var(--r-md);
  box-shadow: var(--shadow);
  height: 100%;
}

.card h3 { margin-bottom: var(--space-1); }
.card p { color: var(--c-text-mute); font-size: var(--step-0); }

.card__icon {
  width: 2.25rem;
  height: 2.25rem;
  display: grid;
  place-items: center;
  border-radius: var(--r-sm);
  background: var(--c-accent-wash);
  color: var(--c-accent);
  margin-bottom: var(--space-2);
}

.card__icon svg { width: 1.15rem; height: 1.15rem; }

.card--link { text-decoration: none; display: block; transition: transform 0.15s ease, border-color 0.15s ease; }
.card--link:hover { transform: translateY(-2px); border-color: var(--c-accent); }

/* -- screenshots ---------------------------------------------------------- */

.shot { margin: 0; }

.shot img {
  border-radius: var(--r-lg);
  border: 1px solid var(--c-border);
  box-shadow: var(--shadow-lg);
  background: var(--c-surface);
  width: 100%;
}

.shot figcaption {
  margin-top: var(--space-2);
  font-size: var(--step--1);
  color: var(--c-text-mute);
}

/* -- video ---------------------------------------------------------------- */

/* The two YouTube embeds on the home page. They were a click-to-play facade —
   a local poster in a <button> that swapped in the iframe — but that costs a
   second press: Safari and Firefox block audible autoplay in a cross-origin
   iframe however the gesture was delegated, so the visitor met our play button,
   then YouTube's. Real iframes, lazily loaded, so the one press is YouTube's.

   Radius and shadow sit on the stage, not the iframe: Safari does not clip
   iframe content to the iframe's own border-radius, so the corners have to be
   cut by an overflow:hidden parent.

   Deliberately not built on .shot: that styles its own <img> with a border and
   radius, which would draw the frame twice. This carries its own figure and
   caption instead. */

.video { margin: 0; }

.video__stage {
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-lg);
  background: var(--c-surface);
  overflow: hidden;
}

.video__frame {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

.video figcaption {
  margin-top: var(--space-2);
  font-size: var(--step--1);
  color: var(--c-text-mute);
}

/* -- checklist ------------------------------------------------------------ */

.ticks { display: grid; gap: 0.6rem; list-style: none; padding: 0; margin: 0; }

/* Absolutely positioned marker rather than a grid column: an <li> containing a
   link plus trailing text is several child nodes, and in a grid each of those
   becomes its own grid item — the text would land in the 1.1rem icon column and
   wrap one word per line. */
.ticks li {
  position: relative;
  padding-inline-start: 1.7rem;
}

.ticks li::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  top: 0.35em;
  width: 1.1rem;
  height: 1.1rem;
  border-radius: 50%;
  background: var(--c-accent-solid);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M6.2 11.4 3.3 8.5l1.1-1.1 1.8 1.8 5.4-5.4 1.1 1.1z' fill='%23000'/%3E%3C/svg%3E") center / 118% no-repeat,
          linear-gradient(#000, #000);
  -webkit-mask-composite: destination-out;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M6.2 11.4 3.3 8.5l1.1-1.1 1.8 1.8 5.4-5.4 1.1 1.1z' fill='%23000'/%3E%3C/svg%3E") center / 118% no-repeat,
        linear-gradient(#000, #000);
  mask-composite: exclude;
}

/* -- trust ---------------------------------------------------------------- */

.trust {
  display: grid;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  border-radius: var(--r-md);
  font-size: var(--step--1);
  color: var(--c-text-mute);
}

@media (min-width: 46rem) {
  .trust { grid-template-columns: 1.7fr 1fr 1fr; gap: var(--space-4); }
  .trust__stat + .trust__stat {
    border-inline-start: 1px solid var(--c-border);
    padding-inline-start: var(--space-4);
  }
}

.trust__stat { display: grid; gap: 0.15rem; align-content: start; }

.trust__big {
  font-family: var(--f-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--step-2);
  font-weight: 700;
  color: var(--c-text);
  letter-spacing: -0.04em;
  line-height: 1;
}

.trust__lead { display: flex; align-items: baseline; gap: 0.5rem; }

/* Its own gold, never the state yellow — see --gold-500 in section 01. */
.stars { color: var(--c-star); letter-spacing: 0.08em; font-size: 0.9em; }

/* -- logos ---------------------------------------------------------------- */

.logos {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-3);
  list-style: none;
  padding: 0;
  margin: 0;
}

.logos li {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.45rem 0.8rem;
  border: 1px solid var(--c-border);
  border-radius: 100px;
  background: var(--c-surface);
  font-size: var(--step--1);
  font-weight: 550;
}

.logos svg { width: 1.05rem; height: 1.05rem; flex: 0 0 auto; }

/* -- FAQ ------------------------------------------------------------------ */

.faq { display: grid; gap: 0.5rem; }

.faq details {
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  border-radius: var(--r-md);
  overflow: hidden;
}

.faq details[open] { border-color: light-dark(#c6d2e4, #2f3a50); }

.faq summary {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3);
  cursor: pointer;
  font-weight: 620;
  list-style: none;
}

.faq summary::-webkit-details-marker { display: none; }

.faq summary::after {
  content: "";
  flex: 0 0 auto;
  width: 0.6rem;
  height: 0.6rem;
  border-right: 2px solid var(--c-text-mute);
  border-bottom: 2px solid var(--c-text-mute);
  rotate: 45deg;
  transition: rotate 0.2s ease;
}

.faq details[open] summary::after { rotate: -135deg; }

.faq summary:hover { background: var(--c-surface-2); }

.faq__a {
  padding: 0 var(--space-3) var(--space-3);
  color: var(--c-text-mute);
}

.faq__a > * + * { margin-top: var(--space-2); }
.faq__a ul { padding-inline-start: 1.2em; }

/* -- call to action ------------------------------------------------------- */

.cta {
  text-align: center;
  background: var(--c-surface-2);
  border-block: 1px solid var(--c-border);
}

.cta h2 { margin-bottom: var(--space-2); }

.cta__sub {
  color: var(--c-text-mute);
  max-width: 34rem;
  margin-inline: auto;
  margin-bottom: var(--space-4);
}

.cta .btnrow { justify-content: center; }

.cta__fine { margin-top: var(--space-3); font-size: var(--step--1); color: var(--c-text-mute); }

/* -- callout -------------------------------------------------------------- */

.callout {
  padding: var(--space-3);
  border-radius: var(--r-md);
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  border-left: 4px solid var(--c-accent);
  font-size: var(--step--1);
}

.callout h3 { font-size: var(--step-0); margin-bottom: var(--space-1); }
.callout p { color: var(--c-text-mute); }

/* -- steps: used only where content really is a sequence ------------------ */

.steps { counter-reset: step; display: grid; gap: var(--space-3); list-style: none; padding: 0; }

.steps li {
  counter-increment: step;
  display: grid;
  grid-template-columns: 2rem 1fr;
  gap: var(--space-2);
}

.steps li::before {
  content: counter(step);
  font-family: var(--f-mono);
  font-size: var(--step--1);
  font-weight: 700;
  color: var(--c-accent);
  width: 2rem;
  height: 2rem;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 1px solid var(--c-border);
  background: var(--c-surface);
}

.steps h3 { font-size: var(--step-0); margin-bottom: 0.15rem; }
.steps p { color: var(--c-text-mute); font-size: var(--step--1); }


/* == 09 UTILITIES ========================================================== */

.u-center { text-align: center; }
.u-mute { color: var(--c-text-mute); }
.u-mt-3 { margin-top: var(--space-3); }
.u-mt-4 { margin-top: var(--space-4); }
.u-narrow { max-width: 40rem; }
.u-nowrap { white-space: nowrap; }

.u-visually-hidden {
  position: absolute !important;
  width: 1px !important;
  height: 1px !important;
  padding: 0 !important;
  margin: -1px !important;
  overflow: hidden !important;
  clip: rect(0, 0, 0, 0) !important;
  white-space: nowrap !important;
  border: 0 !important;
}


/* == 10 PRINT ============================================================== */

@media print {
  .site-head, .site-foot__grid, .cta, .taskbar, .skip { display: none; }
  body { background: #fff; color: #000; font-size: 11pt; }
  .prose { max-width: none; }
  .prose a::after { content: " (" attr(href) ")"; font-size: 9pt; word-break: break-all; }
  .faq details { border: 0; }
  .faq details > .faq__a { display: block !important; }
}
