/* landing.css — knocklet.com, on top of knocklet.css.
   A sticky masthead carrying the code field, then a run of bands: the presser-as-subject hero,
   what this is, why to trust it, what it costs, and the way to ask. Everything an owner does is
   on the other host, so the only control here is the masthead field — and it goes nowhere near
   the API.

   The document is full-bleed at every width. A band reaches both edges of the window and holds
   its own words to --band, so the change of ground is what separates one from the next. Every
   band starts its content on that same left edge: the reading measure is set on the sentences
   themselves (in ch, where a measure belongs) rather than on the block around them, which is what
   keeps a heading, a bullet and a form all hanging off one line down the page.

   /chambers, /intake and /studio load this file too. They are the same bands with no hero shots
   and no code field, so everything below is written to survive a masthead with only a wordmark in
   it and a band that is missing. */

/* ── The bands ──────────────────────────────────────────────────────────── */

/* The one in-page links (the what-this-is cue, the see-it-work CTA) glide instead of jumping,
   unless the reader has asked their machine for less motion. */
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}

/* The document fills the window and the foot holds its floor: a short page on a tall screen
   otherwise ends in a band of bare ground under the small print. */
body { min-height: 100svh; display: flex; flex-direction: column; }
.landing { flex: 1 0 auto; display: flex; flex-direction: column; }

/* One step for every band, so the page has a rhythm rather than a set of local decisions. It
   opens up with the window, because a band that reads well at 390 is a pinched stripe at 1920. */
.landing { --band-pad: clamp(var(--sp-8), 5vw, 4.5rem); }

.band { padding-block: var(--band-pad); padding-inline: var(--gutter); }
.band > * { inline-size: 100%; max-inline-size: var(--band); margin-inline: auto; }

/* One hairline between any two bands, wherever the grounds around it land: the verticals run
   band--hero straight into band--trust with no surface change, and two bands of the same ground
   with no rule between them read as one band that lost its thread. */
.band + .band { border-block-start: var(--hair) solid var(--line); }

/* Every band anchored from off-page (the masthead's own "what this is" link, a ?hint= redirect's
   #contact) lands below the sticky masthead rather than half under it. */
.band[id] { scroll-margin-block-start: var(--masthead-h, 4.5rem); }

/* ── Have a code? (the masthead) ────────────────────────────────────────── */

/* Carried on every scroll position rather than spent on the first screen only: a reader who
   followed a link straight past the hero still has the one thing this page is for within a tap. */
.masthead {
  position: sticky; inset-block-start: 0; z-index: 1;
  padding-block: var(--sp-3);
  padding-inline: var(--gutter);
  background: var(--bg);
  border-block-end: var(--hair) solid var(--line);
}
.masthead__row {
  inline-size: 100%; max-inline-size: var(--band); margin-inline: auto;
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--sp-4);
}
.masthead .wordmark { font-size: var(--t-headline); }
/* Below 48rem the form is the whole second row of the bar, spread across it: the question on the
   start edge under the wordmark, the box growing between, Go on the end edge. End-justified it
   hung as a cluster off the right with the left of the row bare. From 48rem it shares the
   wordmark's line and sits at the end of it. */
.masthead__form { display: flex; align-items: center; gap: var(--sp-3); flex: 1 1 100%; }
/* The question is the label: without it the box in the corner reads as search. It stays visible
   at every width — it is the one sentence that tells the person holding a code where to put it. */
.masthead__ask {
  font: 500 var(--t-subheadline)/1.3 var(--face); color: var(--ink2);
  white-space: nowrap;
}
/* Capitals whatever is typed, so the box matches the placeholder and the sign a code is read off.
   Nothing about what it accepts changes: landing.js normalizes on the way out and the Worker's
   own normalizeJoinCode takes lower case, spaces and dashes. The floor is what six tracked mono
   glyphs plus the padding actually measure — narrower and the placeholder loses its last letter,
   which on a box this size is the difference between an example and a mistake. On the phone row
   it grows to take whatever the question and the button leave. */
.masthead__form .field--code {
  flex: 1 1 auto; min-inline-size: 8.25rem; block-size: 44px;
  padding-inline: var(--sp-3); font-size: var(--t-callout);
  text-transform: uppercase;
}
.masthead__form .btn { flex: none; }

/* The bar steps out of the way while the page is read downward and comes back the moment the
   reader turns around. masthead.js drives the class off scroll direction; without the script the
   bar simply stays, which is the sticky behaviour this section already promises. The transition
   is scoped to no-preference so a reduced-motion machine gets the swap without the slide. */
.masthead--away { translate: 0 -100%; }
@media (prefers-reduced-motion: no-preference) {
  .masthead { transition: translate 180ms ease-out; }
}

/* What the page says back about a code, in a drawer under the masthead rather than a line across
   it: on a wide window it would otherwise sit a window's width to the left of the box it is
   answering, and on every window it would spend a row of the one bar carried down the whole page.
   Out of flow, so nothing below moves when it arrives, and drawn only when there is a sentence in
   it. Opacity rather than display, so a reader on the aria-live region hears it either way. */
.masthead__aside {
  position: absolute; inset-block-start: 100%; inset-inline: 0;
  padding: var(--sp-2) var(--gutter) var(--sp-3);
  box-sizing: border-box;
  background: var(--bg);
  border-block-end: var(--hair) solid var(--line);
  opacity: 0;
  pointer-events: none;
}
.masthead__aside > .hint {
  inline-size: 100%; max-inline-size: var(--band); margin: 0 auto;
  text-align: end;
}
.masthead__aside:has(.hint:not(:empty)) { opacity: 1; }
@media (prefers-reduced-motion: no-preference) {
  .masthead__aside { transition: opacity 120ms ease-out; }
}

/* ── The hero: one button that says, “I’m ready.” ───────────────────────── */

/* Sized by what is in it. The hero used to be pinned to the window's height with the content
   floated to the middle, which on a phone bought a screen of bare ground above the headline and
   another under the shots. */
/* Two rows on a phone — the wordmark, then the labelled code form the row wraps onto — and one
   row from 48rem. The scroll margin under .band[id] reads this, so an anchored band lands under
   whichever bar height is actually on screen. */
:root { --masthead-h: 7.5rem; }
.band--hero { padding-block: clamp(var(--sp-7), 4vw, var(--sp-9)) var(--band-pad); }

.hero {
  display: grid; justify-items: center; text-align: center;
  gap: clamp(var(--sp-7), 4vw, var(--sp-8));
}
.hero__say { display: flex; flex-direction: column; align-items: center; }

.hero__lead {
  margin: 0; max-inline-size: 16ch;
  font: 400 var(--t-display)/1.1 var(--face); letter-spacing: -.03em; text-wrap: balance;
}
.hero__sub {
  margin: var(--sp-4) 0 0; max-inline-size: 42ch;
  font: var(--t-body)/1.55 var(--face); color: var(--ink2); text-wrap: pretty;
}
.hero__demo { margin-block-start: var(--sp-6); }

/* The cue to keep reading, at the foot of the hero's own column rather than adrift at the bottom
   left of the band. A link and not a pill: the two things this page asks for are the demo and an
   account, and a third button beside them would make scrolling look like a decision. */
.hero__more { margin: 0; }
.hero__more a {
  display: inline-flex; align-items: center; gap: var(--sp-2); min-block-size: 44px;
  font: 500 var(--t-subheadline)/1.3 var(--face); color: var(--ink2); text-decoration: none;
}
.hero__more a:hover { color: var(--ink); }
.hero__more a:focus-visible { outline: 2px solid var(--switch-on); outline-offset: 3px; }

/* ── The two shots ──────────────────────────────────────────────────────── */

/* Two shots, not a video: what a presser sees on the page, and what an owner sees on their own
   phone. One scene rather than two pictures side by side — the banner lands across the corner of
   the phone, which is the sentence the hero just made — and the two captions sit on one baseline
   under it. Stacked and plain until there is room for the composition. */
.demo { display: grid; justify-items: center; gap: var(--sp-6); }
/* Centred by the figure rather than by the grid: a figure whose shot is sized against its own
   container has a max-content width of the whole column, so justify-items had nothing to shrink
   and the bezel sat against the start edge with its caption centred under the band. */
.demo > figure { margin: 0; display: flex; flex-direction: column; align-items: center; }

/* A quiet bezel rather than a device chrome: a rounded panel in --surface with a hairline ring,
   the same materials every card on this page is built from. It clips, so no corner of the shot
   inside it can show past the radius. */
/* A definite width rather than min(100%, …): the figure around it is centred, so its own width is
   shrink-to-fit, and a percentage measured against that collapses the bezel to nothing. */
.demo__phone {
  inline-size: 14rem; max-inline-size: 100%;
  padding: var(--sp-2);
  background: var(--surface);
  border-radius: 1.5rem;
  box-shadow: 0 0 0 var(--hair) var(--line);
  overflow: clip;
}
.demo__phone .demo__shot { border-radius: 1rem; }
.demo__lock { inline-size: 18rem; max-inline-size: 100%; }

.demo__shot { display: none; inline-size: 100%; block-size: auto; }
/* Follows the system scheme by default — the same rule theme.js documents for --bg's meta pair —
   and [data-theme] overrides it exactly the way every token in knocklet.css already does, because
   these are shots of the product and have to change scheme with the rest of the page around them. */
.demo__shot--light { display: block; }
@media (prefers-color-scheme: dark) {
  .demo__shot--light { display: none; }
  .demo__shot--dark { display: block; }
}
:root[data-theme="dark"] .demo__shot--dark { display: block; }
:root[data-theme="dark"] .demo__shot--light { display: none; }
:root[data-theme="light"] .demo__shot--light { display: block; }
:root[data-theme="light"] .demo__shot--dark { display: none; }

.demo__cap {
  margin-block-start: var(--sp-3);
  font: 500 var(--t-caption)/1.3 var(--face); letter-spacing: .08em; text-transform: uppercase;
  color: var(--ink3);
}

/* ── What this is ───────────────────────────────────────────────────────── */

.band--what { background: var(--surface); }

/* Every band below the hero leads with a heading and answers with a block, on one shape: the
   heading (and its supporting sentence, where it has one) in front, the list, pair or form after.
   At 64rem the pair becomes the page's one rail, heading column against answer column. */
.what, .ask, .trust { display: grid; gap: var(--sp-7); align-items: start; }

.what__lead {
  margin: 0; max-inline-size: 22ch;
  font: 400 var(--t-title1)/1.25 var(--face); letter-spacing: -.02em; text-wrap: balance;
}
.what__body {
  margin: var(--sp-4) 0 0; max-inline-size: 52ch;
  font: var(--t-callout)/1.55 var(--face); color: var(--ink2); text-wrap: pretty;
}

.what__pair { display: grid; grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); gap: var(--sp-6); }
.who__body {
  margin: 0; max-inline-size: 46ch;
  font: var(--t-callout)/1.55 var(--face); color: var(--ink2); text-wrap: pretty;
}

/* ── Trust ──────────────────────────────────────────────────────────────── */

.trust__list {
  margin: 0; padding: 0; list-style: none;
  display: grid; gap: var(--sp-4);
}
.trust__list li {
  position: relative; padding-inline-start: var(--sp-5); max-inline-size: 48ch;
  font: var(--t-callout)/1.55 var(--face); color: var(--ink2); text-wrap: pretty;
}
.trust__list li::before {
  content: ''; position: absolute; inset-inline-start: 0; inset-block-start: .6em;
  inline-size: .4em; block-size: .4em; border-radius: 999px; background: var(--ink3);
}

/* ── Ask for an account ─────────────────────────────────────────────────── */

/* The final band, on the base ground again: the reading is over and there is one thing to do,
   and it is an address rather than a form. Set in the mono the codes wear, big enough to be the
   object of the band, and a real mailto — the address costs the Worker nothing and has no budget
   to defend. Same rail as the bands above it, address in the answering column once there is room. */
.ask__mail { margin: 0; }
.ask__mail a {
  display: inline-flex; align-items: center; min-block-size: 44px;
  font: 500 var(--t-title2)/1.2 var(--face-mono); letter-spacing: .02em;
  color: var(--ink); text-decoration-color: var(--ink3); text-underline-offset: .3em;
}
.ask__mail a:hover { text-decoration-color: var(--ink); }
.ask__mail a:focus-visible { outline: 2px solid var(--switch-on); outline-offset: 3px; }

.landing noscript { display: block; padding: 0 var(--gutter) var(--band-pad);
                    max-inline-size: var(--band); margin-inline: auto; text-align: start; }

/* ── Wider than a phone ─────────────────────────────────────────────────── */

@media (min-width: 48rem) {
  :root { --masthead-h: 4rem; }

  /* One row again: the form gives up its full-width claim, sits at the end of the wordmark's
     line, and the box goes back to being exactly as wide as its placeholder needs. */
  .masthead__form { flex: 1 1 16rem; justify-content: flex-end; }
  .masthead__form .field--code { flex: none; inline-size: clamp(8.25rem, 24vw, 9.5rem); min-inline-size: 0; }

  /* The scene. Both figures hang off one bottom edge, so the two captions read as one row under
     it, and the banner is pulled back across the phone's lower corner instead of floating beside
     it with a hole above. The width here is the composition's, not a pair of columns: the phone
     takes the start of it and the banner the end, and they meet over the last third of the shot. */
  .demo {
    display: block; position: relative;
    inline-size: 25rem; margin-inline: auto;
    /* Box alignment reaches block layout in current browsers, so the stacked layout's centring
       has to be given back here or the phone sits in the middle of its own scene. */
    justify-items: normal;
  }
  /* The composition hangs both figures off edges of its own, so the centring the stacked layout
     needs comes back off and the captions can take the scene's two ends. */
  .demo > figure { align-items: stretch; }
  .demo__phone { inline-size: 15rem; }
  /* Pinned to the scene's own bottom edge, which is where the phone's caption sits: the banner
     lands across the corner of the shot and the two captions come out on one line. */
  .demo__you {
    position: absolute; inset-inline-end: 0; inset-block-end: 0;
    inline-size: 17rem;
  }
  .demo__they .demo__cap { text-align: start; }
  .demo__you .demo__cap { text-align: end; }
}

/* The lead and its answer side by side, on one rail for every band: the heading or the label in
   the narrow column, everything it introduces in the wide one. The hero stays a centred column,
   because the subject there is the layout and not a phone fallback. */
@media (min-width: 64rem) {
  .what, .ask, .trust {
    grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
    column-gap: var(--sp-9);
  }

  /* The hero joins the same conversation the bands below it hold: the words in the start column,
     the scene answering from the end one, instead of a phone-width strip down the middle of a
     desk-width window. Scoped to a hero that has a scene — the verticals ship words alone, and
     one column of words splits into a column and a hole. */
  .hero:has(.demo) {
    grid-template-columns: minmax(0, 6fr) minmax(0, 5fr);
    column-gap: var(--sp-9);
    align-items: center; justify-items: start; text-align: start;
  }
  .hero:has(.demo) .hero__say { align-items: flex-start; }
  .hero:has(.demo) .hero__lead { max-inline-size: 14ch; }
  .hero:has(.demo) .demo { justify-self: center; margin-inline: 0; }
  /* The cue keeps the page's centre: it speaks for the whole band, not for either column. */
  .hero:has(.demo) .hero__more { grid-column: 1 / -1; justify-self: center; }

  /* The scene grows with the window it is read on. A laptop is where somebody decides whether
     this is worth an email, and a 15rem phone across a 1920 desk is a thumbnail. */
  .demo { inline-size: 28rem; }
  .demo__phone { inline-size: 17rem; }
  .demo__you { inline-size: 19rem; }
}

/* ── No door here (404) ─────────────────────────────────────────────────── */

/* One band, centred, on both hosts: knocklet.com serves it for a mistyped path and
   app.knocklet.com for an address the console has no screen for, so nothing below may assume a
   masthead above it or a band beside it. The column is centred rather than hung off the reading
   rail every other band uses — there is one thing on the page and no second column to answer it,
   and a lone left-aligned block on a desk-width window reads as a page that failed to load the
   rest of itself. */
.band--gone {
  flex: 1 0 auto;
  display: grid; align-content: center; justify-items: center;
  padding-block: clamp(var(--sp-8), 8vh, var(--sp-9) * 1.5);
}
.gone {
  display: grid; justify-items: center; gap: var(--sp-4);
  max-inline-size: 34rem; text-align: center;
}

/* The mark at plate size with the button left as a socket, and two arcs knocking against it. The
   door is drawn in the same geometry as the wordmark's, so this reads as the product's own door
   and not a stock symbol. --ink3 because it is a picture nobody has to read. */
.gone__plate { color: var(--ink3); margin-block-end: var(--sp-2); }
.gone__door { inline-size: clamp(9rem, 40vw, 12rem); block-size: auto; }
.gone__slab { opacity: .85; }
.gone__socket { opacity: .7; }

/* Knock knock, then a rest long enough that the page is still a page and not a thing blinking in
   a corridor: two taps inside the first fifth of the cycle and nothing for the rest of it. The
   arcs sit at zero until the animation runs, so a machine asking for less motion gets a door with
   nobody knocking rather than two lines frozen mid-tap. */
.gone__arc { opacity: 0; }
@media (prefers-reduced-motion: no-preference) {
  .gone__arc { animation: gone-knock 4s ease-in-out infinite; }
  .gone__arc--far { animation-delay: .18s; }
}
@keyframes gone-knock {
  0%, 100% { opacity: 0; }
  4%  { opacity: .9; }
  10% { opacity: 0; }
  16% { opacity: .9; }
  24% { opacity: 0; }
}

.gone .eyebrow { margin: 0; }
.gone__lead {
  margin: 0; max-inline-size: 18ch;
  font: 400 var(--t-title1)/1.2 var(--face); letter-spacing: -.02em; text-wrap: balance;
}
.gone__body {
  margin: 0; max-inline-size: 46ch;
  font: var(--t-callout)/1.55 var(--face); color: var(--ink2); text-wrap: pretty;
}

/* The one control on the page. A wrong address in this product is nearly always a code somebody
   was holding, so the recovery is the same box the landing carries rather than a link back to a
   page they would have to find it on again. */
.gone__form { margin-block-start: var(--sp-5); inline-size: 100%; max-inline-size: 22rem; }
.gone__ask {
  display: block; margin-block-end: var(--sp-3);
  font: 500 var(--t-headline)/1.2 var(--face); color: var(--ink);
}
.gone__row { display: flex; gap: var(--sp-3); align-items: center; }
.gone__row .field--code { flex: 1 1 auto; min-inline-size: 0; }
.gone__row .btn { flex: none; }
/* Out of the flow's way: the hint is empty on every screen but a refusal, and a reserved line
   under the field would open a gap the page never fills. */
.gone__hint { text-align: start; }

.gone__more {
  margin: var(--sp-5) 0 0;
  display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: var(--sp-3);
  font: var(--t-footnote)/1.4 var(--face);
}
.gone__more a {
  display: inline-flex; align-items: center; min-block-size: 44px;
  color: var(--ink2); text-decoration-color: var(--ink3); text-underline-offset: .3em;
}
.gone__more a:hover { color: var(--ink); text-decoration-color: var(--ink); }
.gone__more a:focus-visible { outline: 2px solid var(--switch-on); outline-offset: 3px; }
.gone__dot { color: var(--ink3); }
