/* LIVEPLAN — holding page, built to the supplied web and phone mockups.
 *
 * Standalone by design: this file is uploaded to OVH on its own, so it cannot
 * reach the app's `tokens.css`. The values below are copied from the
 * `--lp-mkt-*` marketing scope and must be kept in step with it by hand — see
 * deploy/coming-soon/README.md.
 *
 * Plain CSS with real media queries, unlike the app, where styling is inline
 * `React.CSSProperties` and responsiveness goes through `useIsMobile()`.
 */

:root {
  /* Sampled from LOGOTYP_POZYTYW_RED.png rather than copied from the token
     file. `--lp-mkt-red` is #D53619, a hair different, and every red on this
     page sits beside the logotype — two nearly-matching reds next to each
     other read as a mistake, one red reads as a decision. */
  --red: #D63327;

  /* The gif's own opaque background, sampled from its corner. The card behind
     the mark and the countdown cells are painted this so nothing shows a seam
     against it — the gif has no transparency to hide behind. */
  --cream: #FBEFE2;

  --font-display: "Titan One", "Impact", "Arial Black", sans-serif;
  --font-body:    "Open Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}

* { box-sizing: border-box; }

/* `hidden` is a UA style at the lowest specificity, so any `display` rule in
   this file silently beats it. Several elements here are laid out with flex
   and start life hidden — the countdown before it hydrates, the Instagram
   link before its URL is set, the email row and consent line after a
   successful sign-up — and all of them would flash into view without this. */
[hidden] { display: none !important; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--cream);
}

/* --- The opening ----------------------------------------------------------
 *
 * The photograph is the heaviest thing here and it sometimes arrives late,
 * which showed as the page assembling itself in front of the visitor. So the
 * page opens on cream, waits for the picture, and then plays itself in.
 *
 * `intro` is added by assets/intro.js before the first paint, and only when
 * JavaScript runs and only once a visit — without it none of this applies and
 * the page is simply itself. `intro-ready` follows once the gif has finished
 * downloading, which is when it is allowed to show.
 */
html.intro,
html.intro body {
  background: var(--cream);
}

/* The cream card becomes the whole screen and stays there while the
   photograph downloads — so the gif is not a decoration that appears once
   the wait is over, it *is* the wait. It keeps animating the entire time.
   Fixed and full-bleed, which needs no measuring, so it holds from the first
   paint rather than from whenever app.js gets its turn. */
html.intro .panel {
  position: fixed;
  inset: 0;
  z-index: 10;
  width: auto;
  aspect-ratio: auto;
  padding: 0;
}

/* Big enough that shrinking to the final size reads as a move.
 *
 * Held back until the file has finished downloading. A GIF paints as it
 * arrives, so without this the mark begins mid-assembly and then loops from
 * the top once the last frame lands — which reads as the animation starting
 * twice. `intro-ready` is added by app.js the moment the image is complete,
 * and the turn of the gif is timed from there. */
html.intro .mark {
  width: min(80vmin, 760px);
  opacity: 0;
}

html.intro.intro-ready .mark {
  opacity: 1;
  transition: opacity 260ms ease-out;
}

/* The copy waits for the card to finish travelling. `visibility` alongside
   `opacity`, so a keyboard cannot reach a form nobody can see. The
   photograph is *not* hidden — it sits behind the card, and uncovering it is
   what the shrink is for. */
html.intro .content {
  opacity: 0;
  visibility: hidden;
}

/* Taking the card out of the flow leaves the copy as the row's only item, so
   it slides to the left edge — and then jumps back the moment the intro ends,
   which is the one thing an intro must not do. This holds the gap the card
   will occupy. Below 900px the card sits under the copy and takes no width,
   so there is nothing to reserve. */
@media (min-width: 900px) {
  html.intro .stage {
    margin-left: calc(var(--card, clamp(280px, 28vw, 408px)) + var(--band));
  }
}

/* The same debt, paid in the other direction. On a phone the card sits under
   the copy, so out of the flow it is the copy's *height* that grows — the
   text centres itself against the whole screen and then jumps up when the
   card returns. `--card-h` is the card's natural height, measured by app.js
   before the greeting starts.
 *
 * Padding, not margin. A margin sits outside the box, so the photograph — which
 * is the stage's own background here, not the page's — stopped short of it and
 * left a band of cream along the bottom of the screen until the card arrived to
 * fill it. Padding is inside the painted area, so the picture covers the whole
 * screen while the reserved space still holds the copy where it belongs. */
@media (max-width: 899px) {
  html.intro .stage {
    padding-bottom: calc(30px + var(--card-h, 0px));
  }

  /* That padding is real height, so without this the page grows past the
     screen and the greeting becomes scrollable — a viewer could drag the
     cream card off the top while it is still playing. Capped instead. The
     fixed card is unaffected: `overflow` only clips descendants, and nothing
     here creates a containing block for it. */
  html.intro .page {
    height: 100dvh;
    overflow: hidden;
  }
}

body {
  font-family: var(--font-body);
  color: var(--red);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* --- The two halves -------------------------------------------------------
 *
 * Phone: the photograph fills the screen, the copy sits on it, and the cream
 * block with the mark comes last. Wide screen: the photograph goes full bleed
 * and the cream block becomes a square card floating to the left of the copy.
 * `order` does the swap, so the markup stays in reading order with the mark
 * last, where it is decoration.
 */

.page {
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
}

.panel {
  order: 2;
  background: var(--cream);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 26px 24px 34px;
}

/* The gif's background is opaque cream — the same cream as the card — so it
   dissolves into it instead of sitting on it. */
.mark {
  width: min(300px, 74%);
  height: auto;
  display: block;
}

.stage {
  order: 1;
  flex: 1;
  display: flex;
  align-items: center;
  padding: 34px 24px 30px;
  background-color: #F3D2C6;
  background-image: url("background-phone.jpg");
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

.content {
  width: 100%;
  max-width: 620px;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 14px;
}

@media (min-width: 900px) {
  /* The photograph runs the full width and the two blocks sit on it, as a row
     inset from the left rather than centred — which is where the mockup puts
     them. */
  .page {
    /* One value for the page's side padding *and* for the gap between the
       card and the copy. That is what centres the card horizontally in the
       band to its left: the distance from the viewport edge to the card and
       from the card to the copy are the same measurement, not two that happen
       to look alike. A check asserts they stay equal. */
    --band: clamp(32px, 7.7vw, 148px);

    flex-direction: row;
    align-items: center;
    justify-content: flex-start;
    gap: var(--band);
    padding: 48px var(--band);
    background-color: #F3D2C6;
    background-image: url("background.jpg");
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
  }

  /* A square card, not a full-height column. `--card` is measured by app.js —
     the card runs from the top of the headline to the bottom of the email
     field, which is a distance CSS has no way to ask for. The clamp is the
     fallback if that never runs, so the layout is never broken, only less
     exact. It stays vertically centred either way, from `align-items` on the
     row above. */
  .panel {
    order: 1;
    flex: 0 0 auto;
    width: var(--card, clamp(280px, 28vw, 408px));
    aspect-ratio: 1 / 1;
    padding: 0;
  }

  /* The gif is a square with a cream ground, and the card is a square of the
     same cream — so the gif simply *is* the card, filling it edge to edge.
     Anything less leaves the mark marooned in the middle of it. */
  .mark { width: 100%; }

  /* The photograph is on `.page` now, so the stage is only the copy column. */
  .stage {
    order: 2;
    flex: 0 1 620px;
    padding: 0;
    background: none;
  }

  .content { gap: 18px; }

  .lockup { margin-bottom: 30px; } /* 18 + 30 = 48, the date-to-countdown gap */
}

/* --- Brand lockup --------------------------------------------------------- */

/* The gap under the logotype is set to match the gap between the date and the
   countdown, which is `2 × column-gap + the hour line − its negative margin`.
   The column gap differs by breakpoint, so this does too; a check asserts the
   two gaps stay equal rather than trusting the arithmetic to survive edits. */
.lockup {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 26px; /* 14 + 26 = 40, the phone's date-to-countdown gap */
}

/* The supplied logotype, cropped to its ink and downscaled. Mark and wordmark
   are one file, so they cannot drift apart or be used separately. */
.logo {
  width: clamp(120px, 32vw, 160px);
  height: auto;
  display: block;
}

/* Pushed to the far end of the lockup row, where it reads as a brand bar
   rather than as a stray button in the middle of the copy. */
.ig {
  margin-left: auto;
  width: 44px;
  height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 12px;
  color: var(--red);
  transition: background-color 120ms ease;
}

.ig:hover { background: rgba(214, 51, 39, 0.10); }

.ig-glyph { width: 28px; height: 28px; display: block; }

/* --- Headline ------------------------------------------------------------- */

.headline {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 400;
  color: var(--red);
  font-size: clamp(27px, 7vw, 38px);
  line-height: 1.12;
  letter-spacing: 0.01em;
  text-transform: uppercase;
}

.date {
  display: block;
  font-size: clamp(38px, 10.4vw, 58px);
  line-height: 1.06;
  /* Nine glyphs that must never reflow mid-number. */
  white-space: nowrap;
}

.hour {
  margin: -6px 0 0;
  font-size: 13px;
  font-weight: 700;
  text-transform: uppercase;
  color: var(--red);
}

/* --- Countdown ------------------------------------------------------------ */

/* Four separate cards, not four cells in one bar: the row has no fill of its
   own, and each unit carries the cream and the red. */
.countdown {
  display: flex;
  gap: clamp(6px, 1.6vw, 12px);
}

.unit {
  flex: 1;
  background: var(--cream);
  border-radius: 10px;
  padding: 12px 4px 10px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1px;
}

.num {
  font-family: var(--font-display);
  font-size: clamp(22px, 6.4vw, 34px);
  line-height: 1.08;
  color: var(--red);
  /* Seconds tick every second; proportional digits make the box jitter. */
  font-variant-numeric: tabular-nums;
}

.lab {
  font-size: clamp(10px, 2.6vw, 12px);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--red);
}

/* --- Sign-up -------------------------------------------------------------- */

.signup-title {
  margin: 6px 0 0;
  font-family: var(--font-display);
  font-weight: 400;
  color: var(--red);
  font-size: clamp(17px, 4.4vw, 23px);
  line-height: 1.2;
  letter-spacing: 0.01em;
  text-transform: uppercase;
}

/* No `max-width` anywhere below: every block in the column runs the column's
   full width, so their right edges line up. A narrower measure on the copy
   reads as a ragged right margin against the countdown and the form. */
.signup-lede {
  margin: 0;
  font-size: clamp(13.5px, 3.4vw, 15px);
  line-height: 1.55;
  color: var(--red);
}

.form {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

/* The field and the button, side by side with nothing behind them — the coral
   bar they used to sit in is gone. */
.formbar {
  display: flex;
  gap: 8px;
}

.input {
  flex: 1;
  min-width: 0;
  min-height: 48px;
  padding: 12px 16px;
  border: 0;
  border-radius: 8px;
  background: var(--cream);
  color: var(--red);
  font-family: var(--font-body);
  font-size: 16px; /* under 16px iOS zooms the page on focus */
}

.input::placeholder { color: rgba(214, 51, 39, 0.55); }

.button {
  flex: 0 0 auto;
  min-height: 48px;
  padding: 12px clamp(14px, 3.4vw, 28px);
  border: 0;
  border-radius: 8px;
  background: var(--red);
  color: var(--cream);
  font-family: var(--font-body);
  font-size: clamp(13px, 3.4vw, 15px);
  font-weight: 700;
  white-space: nowrap;
  cursor: pointer;
  transition: filter 120ms ease, opacity 120ms ease;
}

.button:hover:not(:disabled) { filter: brightness(1.08); }
.button:disabled { opacity: 0.65; cursor: default; }

.input:focus-visible,
.button:focus-visible,
.checkbox:focus-visible,
.rodo summary:focus-visible,
a:focus-visible {
  outline: 3px solid var(--red);
  outline-offset: 2px;
}

.input[aria-invalid="true"] {
  box-shadow: 0 0 0 3px rgba(214, 51, 39, 0.45);
}

.consent {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--red);
}

.checkbox {
  /* 20px box, but the whole label is the target, and the label is taller than
     44px at every width. */
  width: 20px;
  height: 20px;
  margin: 1px 0 0;
  flex: 0 0 auto;
  accent-color: var(--red);
  cursor: pointer;
}

.status {
  margin: 0;
  min-height: 1.2em;
  font-size: 13.5px;
  line-height: 1.5;
  font-weight: 600;
  color: var(--red);
}

.status[data-tone="error"] { color: #8C1B0C; }
.status[data-tone="pending"] { opacity: 0.75; }

/* --- Privacy disclosure --------------------------------------------------- */

.rodo {
  font-size: 12.5px;
  color: var(--red);
}

.rodo summary {
  cursor: pointer;
  /* A disclosure is a tap target like any other; at 12.5px the padding alone
     left it at 41px. */
  padding: 13px 0;
  min-height: 44px;
  font-weight: 600;
  list-style-position: inside;
}

.rodo-body {
  /* Long enough that it needs its own scroll rather than pushing the poster
     off the screen when someone opens it. No `max-width`: it lines up with
     everything else in the column. */
  max-height: 340px;
  overflow-y: auto;
  padding-right: 16px;

  /* The default scrollbar is a grey system chrome sitting in the middle of a
     red-and-cream page. Firefox takes the two-colour shorthand; WebKit needs
     the pseudo-elements below. Both are given, so neither browser falls back
     to grey. */
  scrollbar-width: thin;
  scrollbar-color: var(--red) rgba(214, 51, 39, 0.16);
  /* Keeps the text from sliding sideways when the bar appears. */
  scrollbar-gutter: stable;
  overscroll-behavior: contain;
}

.rodo-body::-webkit-scrollbar {
  width: 8px;
}

.rodo-body::-webkit-scrollbar-track {
  background: rgba(214, 51, 39, 0.16);
  border-radius: 999px;
}

.rodo-body::-webkit-scrollbar-thumb {
  background: var(--red);
  border-radius: 999px;
}

.rodo-body::-webkit-scrollbar-thumb:hover {
  background: #B4261B;
}

/* The last line used to stop dead at the fold, which reads as the end of the
   text rather than as the middle of it. `data-fade` is set by app.js and
   removed once the bottom is reached, so nothing is dimmed when there is
   nothing left to read.
 *
 * A mask rather than a gradient overlay: the page behind this is a
 * photograph, and an overlay would have to fade to a colour that is not
 * there. */
.rodo-body[data-fade="on"] {
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 46px), transparent);
  mask-image: linear-gradient(to bottom, #000 calc(100% - 46px), transparent);
}

.rodo-body p {
  margin: 0 0 10px;
  line-height: 1.6;
}

a { color: inherit; text-underline-offset: 3px; }

/* --- Utilities ------------------------------------------------------------ */

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* The honeypot: off-screen rather than `display:none`, which the better bots
   know to skip. */
.hp {
  position: absolute;
  left: -9999px;
  top: auto;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

@media (prefers-reduced-motion: reduce) {
  * { transition-duration: 0.01ms !important; }
}
