/* Switchman's website.
 *
 * The design is @EVE's; this file is her reference implementation, adopted whole.
 * Comments below are hers unless marked otherwise.
 */

/* One world, one theme. The hero's night was always the best part of this page;
 * now the whole page lives in it. Light "enterprise" body sections were the
 * source of the brochure feel — gone. Light macOS screenshots glow on the dark
 * ground by nature; no framing apparatus needed. */
:root {
  --track-start: #3378f5;
  --track-end:   #7a59f7;
  --night:      #0a0c11;
  --night-2:    #0e1118;
  --fog:        rgba(244,246,250,.92);
  --fog-soft:   rgba(244,246,250,.64);
  /* .55, not .4 — measured, not chosen. Against --night that is 5.86:1; at .4 it was
     3.59:1, under the 4.5:1 that small text needs. This colour is used for the download
     line under the button and for every figure caption, which is exactly the text someone
     squints at before deciding whether to trust the thing. */
  --fog-faint:  rgba(244,246,250,.55);
  --hairline:   rgba(244,246,250,.08);
  --measure: 34rem;
  --page: 68rem;
}
* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--night);
  color: var(--fog);
  font: 17px/1.65 -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", system-ui, sans-serif;
  -webkit-font-smoothing: antialiased;
}
a { color: inherit; }
.wrap { width: 100%; max-width: var(--page); margin: 0 auto; padding: 0 2rem; }

/* ---------- header ---------- */
.top { display: flex; align-items: center; gap: 1rem; padding: 1.75rem 0; }
.wordmark { font-weight: 650; letter-spacing: -0.01em; font-size: 1.05rem; text-decoration: none; display: flex; align-items: center; gap: .55rem; color: #fff; }
.mark { width: 22px; height: 22px; flex: none; }
.top nav { margin-left: auto; display: flex; gap: 1.5rem; align-items: center; font-size: .9rem; }
.top nav a { color: var(--fog-soft); text-decoration: none; transition: color .15s ease; }
.top nav a:hover { color: #fff; }
.top nav .lang { display: inline-flex; align-items: center; gap: .35rem; padding-left: 1.5rem; border-left: 1px solid var(--hairline); }
.top nav .lang svg { width: 13px; height: 13px; opacity: .75; }

/* ---------- hero ---------- */
.stage {
  position: relative; overflow: hidden;
  background: url("/assets/img/hero-v4.5b1b3512.webp") center 34% / cover no-repeat, var(--night);
  min-height: 620px;
}
/* The illustration hands off to the flat night instead of ending at a hard line. */
.stage::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 200px;
  background: linear-gradient(180deg, transparent, var(--night));
  pointer-events: none;
}
/* Darkens the top-left corner only, where the heading sits. The illustration already
 * leaves sky there, so this is a floor under the contrast rather than the thing
 * providing it — a full-frame scrim would flatten the picture to buy nothing. */
.stage::before {
  content: ""; position: absolute; inset: 0;
  background: radial-gradient(120% 90% at 18% 12%, rgba(10,12,17,.55), transparent 55%);
  pointer-events: none;
}
.stage .wrap { position: relative; z-index: 1; }
.hero { padding: 4rem 0 0; max-width: 36rem; }
h1 {
  font-size: clamp(2.4rem, 5.5vw, 3.6rem);
  line-height: 1.08; letter-spacing: -0.03em;
  margin: 0 0 1rem; font-weight: 700; color: #fff;
  max-width: 15ch;
}
/* Brighter than the body copy, and shadowed: this paragraph is the one piece of text
 * sitting on the illustration rather than on the flat night, so --fog-soft against an
 * unknown pixel is not the same contrast it is everywhere else on the page. */
.lede { font-size: 1.15rem; color: var(--fog); max-width: var(--measure); margin: 0 0 2.25rem;
  text-shadow: 0 1px 8px rgba(10,12,17,.6); }
.cta { display: flex; flex-wrap: wrap; gap: .85rem; align-items: center; margin: 0; }
/* Only in the hero, where it is holding the illustration open below the buttons.
 * The same class in the closing block sits above the footer and wants none of it. */
.hero .cta { margin-bottom: 5rem; }
.button {
  display: inline-block; padding: .75rem 1.5rem; border-radius: 10px;
  background: linear-gradient(100deg, var(--track-start), var(--track-end));
  background-size: 160% 100%; background-position: 0% 0%;
  transition: background-position .5s ease, transform .12s ease;
  color: #fff; text-decoration: none; font-weight: 570; font-size: .95rem; border: 0;
}
.button:hover { background-position: 100% 0%; }
.button:active { transform: translateY(1px); }
.button[aria-disabled="true"] { opacity: .6; pointer-events: none; }
.cta small { color: var(--fog-faint); font-size: .85rem; }

/* ---------- the settings window, drawn rather than captured ----------
 * The offscreen renders of the settings pages carry the window's content only — no
 * title bar, no traffic lights. Drawing the frame keeps it identical across the two
 * languages (and the carousel below, when its slides are windows too), and the site
 * serves one picture where it would otherwise serve six.
 * The bar is translucent and the body blurs what passes behind it, the way a macOS
 * window does; the blur is a cheap fiction on a background that is mostly flat night,
 * but it is what keeps the window reading as glass rather than a sticker. */
.window {
  border-radius: 16px;
  background: linear-gradient(180deg, rgba(244,246,250,.11), rgba(244,246,250,.05));
  border: 1px solid rgba(244,246,250,.14);
  box-shadow: 0 30px 60px rgba(0,0,0,.5), inset 0 1px 0 rgba(244,246,250,.10);
  -webkit-backdrop-filter: blur(24px) saturate(1.5);
  backdrop-filter: blur(24px) saturate(1.5);
  overflow: hidden;
}
.window-bar {
  position: relative;
  display: flex; align-items: center;
  padding: .75rem 1rem;
  border-bottom: 1px solid rgba(244,246,250,.08);
}
.window-dots { display: flex; gap: .5rem; }
.window-dots .dot { width: 12px; height: 12px; border-radius: 50%; }
.window-dots .dot:nth-child(1) { background: #ff5f57; }
.window-dots .dot:nth-child(2) { background: #febc2e; }
.window-dots .dot:nth-child(3) { background: #28c840; }
/* Centred on the window, not on the bar: the lights sit at the left and the title
 * still holds the middle of the glass. A flex row with a spacer would chase the
 * centre around as the lights' width changes; absolute centring does not. */
.window-title {
  position: absolute; left: 0; right: 0; top: 0; bottom: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: .78rem; color: var(--fog-faint); font-weight: 550;
  pointer-events: none;
}
/* 15:17 is the render's own ratio (540×612pt at 2x). The body pins it so the window
 * holds its shape before the picture arrives and stays still while it does. */
.window-body { position: relative; aspect-ratio: 15 / 17; background: #232528; }
.window-body img { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }

/* The hero's window floats over the illustration, bottom right — where the picture is
 * not doing anything else. On screens narrower than the text column plus the window
 * they would collide, so below 60rem the window docks under the hero copy instead. */
.hero-window {
  position: absolute;
  right: max(1.5rem, calc((100% - var(--page)) / 2));
  bottom: 4.5rem;
  width: min(21.5rem, 34%);
  z-index: 2;  /* above the stage's fade and scrim, which would otherwise tint it */
}
@media (max-width: 60rem) {
  .hero-window {
    position: static;
    width: min(21rem, 100%);
    margin: 0 auto 2.5rem;
  }
  /* The five-rem gap under the buttons existed to hold the illustration open below
   * them; on a phone the window now fills that space and the gap is dead air. */
  .hero .cta { margin-bottom: 2rem; }
}

/* ---------- sections: space does the separating, not borders ---------- */
section { padding: 5.5rem 0 0; }
h2 {
  font-size: clamp(1.7rem, 3.2vw, 2.2rem);
  letter-spacing: -0.025em; line-height: 1.15;
  margin: 0 0 .75rem; font-weight: 660; color: #fff;
}
.section-lede { color: var(--fog-soft); max-width: var(--measure); margin: 0 0 3rem; font-size: 1.02rem; }

/* Screenshots sit directly on the night. A floating panel is a floating panel — bare,
 * with its own shadow. No cards, no glows, no stage-inside-a-stage.
 *
 * The `.chrome` rules that drew a fake macOS title bar around the settings window are
 * gone with the section that used them: the window screenshots due for the carousel are
 * captured with the real frame already in the picture. */
figure { margin: 0; }
figcaption { margin-top: 1rem; font-size: .85rem; color: var(--fog-faint); }

/* One frame, three pictures taking turns in it — instead of three blocks stacked down
 * the page. The frame has a fixed aspect ratio so the section does not change height
 * as the slides change, which would push everything below it around every 4.5s. */
.deck {
  position: relative; max-width: 52rem; margin: 0 auto;
  aspect-ratio: 16 / 10;
  background: linear-gradient(180deg, rgba(244,246,250,.045), rgba(244,246,250,.02));
  border: 1px solid var(--hairline); border-radius: 20px;
  overflow: hidden;
}
/* Two rows — picture, then caption — rather than a caption floated over the bottom of
 * the frame. The floated version looked right at desktop width and printed the caption
 * straight across the screenshot on a phone, where the frame is a third the height and
 * the caption wraps to three lines. Giving the caption a row of its own means the
 * picture is measured against what is actually left, at every width. */
.deck figure {
  position: absolute; inset: 0; margin: 0;
  display: grid; grid-template-rows: 1fr auto; justify-items: center; align-items: center;
  gap: 1rem; padding: 1.75rem 1.5rem 1.25rem; box-sizing: border-box;
  opacity: 0; transform: translateX(60px);
  transition: opacity .6s ease, transform .6s cubic-bezier(.22,1,.36,1);
}
.deck figure.active { opacity: 1; transform: translateX(0); }
.deck figure.leaving { opacity: 0; transform: translateX(-60px); }
/* min-height: 0 or the picture refuses to shrink below its natural size and pushes the
 * caption out of the frame instead — the grid default that turns "it fits" into
 * "it overflows, silently, only on small screens". */
.deck img {
  max-width: 100%; max-height: 100%; min-height: 0; width: auto; height: auto;
  border-radius: 12px; filter: drop-shadow(0 30px 55px rgba(0,0,0,.6));
}
.deck figcaption {
  margin: 0; text-align: center; font-size: .85rem; color: var(--fog-faint);
}

/* The indicators are a length of track with a node at each stop, not three loose dots
 * — the same figure the app icon and the page's own language are built on. */
.rail { display: flex; align-items: center; justify-content: center; gap: 0; margin-top: 1.5rem; }
.rail .seg { width: 56px; height: 2px; background: var(--hairline); }
.rail button {
  width: 12px; height: 12px; border-radius: 50%; border: 1.6px solid var(--fog-faint);
  background: none; padding: 0; cursor: pointer;
}
.rail button[aria-current="true"] {
  border-color: transparent;
  background: linear-gradient(90deg, var(--track-start), var(--track-end));
}
.rail button:focus-visible { outline: 2px solid var(--track-start); outline-offset: 3px; }

/* Reduce the motion and stop the rotation both. Taking the slide out but leaving the
 * frame swapping itself every 4.5s answers the letter of the request and none of it:
 * unrequested movement is the thing being asked about, and a crossfade is still
 * movement. The interval is cleared in JS to match; this half only covers the slide. */
/* On a phone the ratio stops being useful: 16:10 of a 340px column is 212px, and after
 * the padding and a three-line caption there is nothing left for the screenshot. A
 * fixed height instead — still fixed, so the page below it does not move when the
 * slide changes, which is the only reason the frame is sized at all. */
@media (max-width: 40rem) {
  .deck { aspect-ratio: auto; height: 26rem; border-radius: 16px; }
  .deck figure { padding: 1.25rem 1rem 1rem; }

  /* The corner scrim is a desktop shape: it assumes the text sits top left and the
   * illustration keeps the rest. On a phone the paragraph spans the full width and runs
   * across one of the signal lamps — 1.23:1 measured there, against the 4.5:1 small text
   * needs. A top-down scrim instead.
   *
   * Recropping was tried first and does nothing: the illustration is square, so under
   * `cover` on a 620px-tall stage it is scaled to exactly 620 tall and cropped only left
   * and right. There is no vertical slack for background-position to move, and the lamp
   * stays where it is however the value is written. Darkening is the only lever left,
   * and it costs the picture — flagged for @EVE with the numbers. */
  .stage::before {
    background: linear-gradient(180deg,
      rgba(10,12,17,.82) 0%, rgba(10,12,17,.80) 42%, rgba(10,12,17,.62) 62%, transparent 84%);
  }
}

@media (prefers-reduced-motion: reduce) {
  .deck figure { transition: opacity .3s ease; transform: none !important; }
}

/* Every screenshot sits on the identical stage: same width, same aspect, same
 * quiet tint, content centered. The screenshots are different shapes; the
 * stages are not — that one constant is what makes the page read as designed
 * rather than assembled. */
.figure-stage {
  width: 100%; max-width: 52rem;
  aspect-ratio: 16 / 10;
  background: linear-gradient(180deg, rgba(244,246,250,.045), rgba(244,246,250,.02));
  border: 1px solid rgba(244,246,250,.07);
  border-radius: 20px;
  display: grid; place-items: center;
  /* Definite tracks so the children's percentage max-height can resolve;
   * an auto track sized by the child is circular and the cap is ignored. */
  grid-template-rows: 100%; grid-template-columns: 100%;
  overflow: hidden;
}
.figure-stage .chrome { width: 76%; }
.figure-stage > img {
  max-width: 80%; max-height: 82%; width: auto; height: auto;
  border-radius: 12px;
  filter: drop-shadow(0 30px 55px rgba(0,0,0,.6));
}

/* ---------- privacy ---------- */
/* Flat night, same as the rest of the page: the illustration appears once, in
 * the hero, and stays special. Section identity comes from content, not a
 * background swap. */
.promise {
  position: relative;
  padding: 5.5rem 0 0;
}
.promise .wrap { position: relative; z-index: 1; }
/* Same axis as everything else: text column, then the picture. The one thing
 * that changes is the content. */
.promise-grid { display: grid; gap: 2.25rem; }
.promise ul { margin: 0; padding: 0; list-style: none; display: grid; gap: 1.1rem; max-width: var(--measure); }
.promise li { padding-left: 1.6rem; position: relative; font-size: .97rem; color: var(--fog-soft); }
.promise li::before {
  content: ""; position: absolute; left: 0; top: .58em; width: 9px; height: 9px; border-radius: 50%;
  background: linear-gradient(90deg, var(--track-start), var(--track-end));
}
.promise li b { color: #fff; font-weight: 600; }
.promise-figure { display: grid; gap: 0; }
.promise-figure figcaption { color: var(--fog-faint); margin-top: 1rem; }

/* ---------- faq ---------- */
#faq { max-width: 46rem; padding-bottom: 1rem; }
details { border-top: 1px solid var(--hairline); padding: 1.1rem 0; }
details:last-of-type { border-bottom: 1px solid var(--hairline); }
summary { cursor: pointer; font-weight: 570; list-style: none; display: flex; gap: .75rem; align-items: baseline; color: var(--fog); }
summary::-webkit-details-marker { display: none; }
summary::after { content: "+"; margin-left: auto; color: var(--fog-faint); font-weight: 400; }
details[open] summary::after { content: "\2013"; }
details p { color: var(--fog-soft); font-size: .95rem; margin: .75rem 0 0; max-width: var(--measure); }

/* ---------- closing ---------- */
.closing { text-align: center; padding: 6rem 0 2rem; }
.closing img { width: 112px; height: 112px; margin-bottom: 1.5rem; filter: drop-shadow(0 16px 32px rgba(0,0,0,.5)); }
.closing h2 { margin-bottom: .5rem; }
.closing p { color: var(--fog-soft); margin: 0 0 2rem; }
.closing .cta { justify-content: center; }

footer {
  margin-top: 4rem; padding: 2.25rem 0 3rem; border-top: 1px solid var(--hairline);
  color: var(--fog-faint); font-size: .87rem; display: flex; flex-wrap: wrap; gap: 1rem;
}
footer nav { margin-left: auto; display: flex; gap: 1.25rem; }
footer a { text-decoration: none; }
footer a:hover { color: #fff; }

@media (max-width: 34rem) {
  .top { gap: .75rem; }
  .top nav a:not(.lang) { display: none; }
  .top nav .lang { padding-left: 0; border-left: 0; }
  /* On a phone the fixed 16:10 stage would shrink the screenshots to
   * unreadable; keep the identical dressing, let height follow content. */
  .figure-stage { aspect-ratio: auto; grid-template-rows: auto; padding: 1.5rem 1rem; }
  .figure-stage .chrome { width: 100%; }
  .figure-stage > img { max-width: 100%; max-height: none; }
}
@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
}


/* ---------------------------------------------------------------- pricing */
/*
 * Design by @Rokcy. Only what is specific to this section lives here — the
 * button, the tokens and .section-lede already exist above, and a second copy
 * of any of them would be a second thing to keep in step.
 */
section.pricing { padding: 5.5rem 0 6rem; }
.pricing h2 {
  font-size: clamp(1.7rem, 3.2vw, 2.2rem);
  letter-spacing: -0.025em; line-height: 1.15;
  margin: 0 0 .75rem; font-weight: 660; color: #fff;
}

/* A square illustration cropped to a band. 62% down is where the track and the
 * signal box sit; the top of the frame is sky, which says nothing. */
.illust { position: relative; margin: 0 0 -1px; border-radius: 16px 16px 0 0; overflow: hidden; }
.illust img { width: 100%; height: 360px; object-fit: cover; object-position: center 62%; display: block; }
.illust-fade { position: absolute; inset: auto 0 0 0; height: 140px; background: linear-gradient(180deg, transparent, var(--night)); }

.plans { display: grid; grid-template-columns: 1fr 1fr; gap: 0; border-top: 1px solid var(--hairline); }
.plan { padding: 2.25rem 2.25rem 2.5rem 0; }
.plan + .plan { border-left: 1px solid var(--hairline); padding-left: 2.25rem; padding-right: 0; }

.plan .name { font-size: .9rem; font-weight: 640; letter-spacing: .06em; text-transform: uppercase; color: var(--fog-faint); margin: 0 0 1.1rem; }
.plan .price { font-size: 2.6rem; font-weight: 700; letter-spacing: -0.03em; color: #fff; line-height: 1; margin: 0 0 .35rem; }
.plan .price small { font-size: 1rem; font-weight: 500; letter-spacing: 0; color: var(--fog-soft); margin-left: .4rem; }
.plan .terms { font-size: .9rem; color: var(--fog-faint); margin: 0 0 1.75rem; }

.plan ul { list-style: none; margin: 0 0 2.25rem; padding: 0; display: grid; gap: .8rem; }
.plan li { position: relative; padding-left: 1.5rem; font-size: .95rem; color: var(--fog-soft); }
.plan li b { color: #fff; font-weight: 600; }
/* A track node rather than a tick: the same vocabulary as the rest of the page. */
.plan li::before {
  content: ""; position: absolute; left: 0; top: .5em; width: 8px; height: 8px;
  border-radius: 50%; border: 1.6px solid var(--fog-faint);
}
.plan.pro li::before { border-color: transparent; background: linear-gradient(90deg, var(--track-start), var(--track-end)); }
.plan li.soon { color: var(--fog-faint); }
.plan li.soon::before { border-style: dashed; background: none; border-color: var(--fog-faint); }
.plan li.soon i { font-style: normal; font-size: .78rem; border: 1px solid var(--hairline); border-radius: 99px; padding: .1rem .5rem; margin-left: .5rem; color: var(--fog-faint); }

/* The quiet variant of the button that already exists, for the secondary action. */
.button.quiet {
  background: none; border: 1px solid rgba(244,246,250,.18); color: var(--fog);
  transition: border-color .15s ease, transform .12s ease;
}
.button.quiet:hover { border-color: rgba(244,246,250,.4); }

/* Not bought yet, and saying so. The buy button has nowhere to go until the
 * payment endpoint exists, and a button that looks live and 404s is worse than
 * one that admits it — four dead `href="#"` links were just removed from this
 * site for exactly that reason. */
.button[aria-disabled="true"] {
  background: none; border: 1px dashed rgba(244,246,250,.22); color: var(--fog-faint);
  cursor: default; pointer-events: none;
}

.plan .fine { margin: 1rem 0 0; font-size: .84rem; color: var(--fog-faint); max-width: 24rem; }

.honesty { margin-top: 3.5rem; padding-top: 1.5rem; border-top: 1px solid var(--hairline); max-width: var(--measure); }
.honesty p { margin: 0; font-size: .9rem; color: var(--fog-faint); }
.honesty b { color: var(--fog-soft); font-weight: 600; }

@media (max-width: 34rem) {
  .plans { grid-template-columns: 1fr; }
  .plan { padding: 2rem 0; }
  .plan + .plan { border-left: 0; border-top: 1px solid var(--hairline); padding-left: 0; }
}
