/* Clave landing page.

   Direction: the app's "Soft workspace", turned outward. Warm paper, a
   plum accent, white rounded cards, Outfit for text and Newsreader for
   the display type and the wordmark. The tokens below are the app's own
   (internal/webui/static/app.css) under the same names, so the front
   door and the workspace cannot drift apart: a visitor who signs in
   should arrive somewhere they recognise.

   Two rules the app pays for in production hold here too, and this page
   has no test runner behind it, so they are written down instead:

   - `style-src 'self'` covers inline style attributes as well as
     stylesheets. A template here may not carry one — it is dropped by
     the browser and the page still returns 200. Every position in the
     phone mock-up is therefore a rule in this file.
   - Only the latin subset of each face is vendored, so every arrow on
     this page is inline SVG. A typed one falls back mid-sentence.

   Light only, on purpose. The page carries one block that is dark for
   contrast, and a dark page under it would make that block disappear —
   so a dark palette is a design somebody draws, not a token swap. The
   app's dark tokens map to these one for one when that day comes.

   Faces come from internal/typeface, linked ahead of this file: one copy
   for every browser surface, so they cannot end up set in different
   type. */

/* ---- Tokens ---------------------------------------------------------- */

:root {
  color-scheme: light;

  /* Surfaces, from the page up. */
  --page: #f3ede6;
  --panel: #fbf8f4;
  --card: #ffffff;
  --line: #e7ded4;
  --line-strong: #d2c6b9;

  /* Text, from most to least. Faint is for tertiary labels only: it does
     not meet 4.5:1 and must never carry a sentence a reader has to
     read. */
  --ink: #2b2327;
  --muted: #6f6369;
  --faint: #9d9196;

  --accent: #6b2d5c;
  --accent-hover: #5c2750;
  --on-accent: #fffefc;
  --accent-tint: #f2e6ef;

  --ok: #2f7d4a;
  --ok-tint: #e3f1e7;
  --wait: #9a6a12;
  --wait-tint: #f8ecd2;

  /* The inverted block. It is a block, not a mode: these four are the
     only place on this page a dark ground appears. */
  --dark: #2b2327;
  --dark-card: #2c242a;
  --dark-line: #3a3037;
  --dark-well: #1a1417;
  --on-dark: #f4edf1;
  --on-dark-muted: #b5a8af;
  --on-dark-faint: #7f737a;
  --accent-on-dark: #d29ac4;

  --shadow-card: 0 1px 2px rgba(43, 35, 39, .05), 0 8px 24px -16px rgba(43, 35, 39, .18);

  --display: 'Newsreader', Georgia, 'Times New Roman', serif;
  --text: 'Outfit', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
  --mono: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;

  --wrap: 1120px;
  --gutter: clamp(20px, 5vw, 56px);

  /* An image slot with no picture in it yet. Stripes rather than a flat
     panel: a reader sees a place a picture goes, which is what it is,
     rather than a white rectangle that reads as a fault. */
  --stripes: repeating-linear-gradient(135deg, #efe7de 0 10px, #f7f2ec 10px 20px);
}

/* ---- Base ------------------------------------------------------------ */

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

body {
  margin: 0;
  background: var(--page);
  color: var(--ink);
  font-family: var(--text);
  font-size: 15px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2 { font-family: var(--display); font-weight: 400; margin: 0; }

h1 {
  font-size: clamp(46px, 7.2vw, 88px);
  line-height: 0.98;
  letter-spacing: -0.028em;
  text-wrap: balance;
}

h2 {
  font-size: clamp(28px, 3.4vw, 40px);
  line-height: 1.12;
  letter-spacing: -0.02em;
  max-width: 24ch;
  margin-bottom: 28px;
  text-wrap: balance;
}

h3 { font-family: var(--text); font-size: 17px; font-weight: 500; line-height: 1.3; margin: 0; }

p { margin: 0; }

a { color: var(--accent); }

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

/* 1120px of content, and the gutter outside it. The measure is the
   column a reader reads, not the column plus its own margins — which is
   what a plain max-width with padding inside it would give, one plate
   narrower on a wide screen. */
.wrap {
  max-width: calc(var(--wrap) + 2 * var(--gutter));
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* Every section but the hero and the closing one pays its own distance
   to the next, so a section that renders nothing takes no space. */
.section { padding-bottom: clamp(56px, 7vw, 96px); }

/* The small uppercase label, used above the inverted block's heading and
   inside the chat card. */
.label {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--faint);
}

/* Inline rather than a glyph: the vendored subset has no U+2192. */
.arrow {
  width: 1em;
  height: 1em;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.75;
  stroke-linecap: round;
  stroke-linejoin: round;
  flex: none;
}

/* The two dots that mean something, at the two sizes they appear in. The
   plum one says "this is Clave" and the green one says "this is up". */
.dot { width: 7px; height: 7px; border-radius: 50%; flex: none; }

.dot-ok { background: var(--ok); }

/* A status word in a pill: one shape, two meanings, never a third
   without a token behind it. */
.tag {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
}

.tag-accent { background: var(--accent-tint); color: var(--accent); }
.tag-ok { background: var(--ok-tint); color: var(--ok); }

/* ---- Header ---------------------------------------------------------- */

.topbar-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding-block: 22px;
}

/* The wordmark: the name in the display serif, and one plum dot sitting
   on the baseline after the "e" like a full stop. There is no symbol.

   Real text and one empty span rather than an image: it stays crisp at
   every size, a reader can select it, and the accessible name is the
   word "clave". The dot is decorative and carries aria-hidden. Every
   value is in em, so one rule serves the header and the footer and each
   follows its own font-size. */
.brand {
  display: inline-flex;
  align-items: baseline;
  gap: 0.05em;
  font-family: var(--display);
  font-size: 24px;
  font-weight: 500;
  letter-spacing: -0.03em;
  line-height: 1;
  color: var(--ink);
  text-decoration: none;
}

/* align-items: baseline puts the bottom edge of an empty span on the
   text baseline, which is what makes the dot read as punctuation rather
   than as a bullet beside the word. */
.brand-dot {
  width: 0.22em;
  height: 0.22em;
  border-radius: 50%;
  background: var(--accent);
  flex: none;
}

.topnav { display: flex; align-items: center; gap: 8px; }

.nav-link, .nav-pill {
  padding: 9px 16px;
  border-radius: 999px;
  font-size: 14px;
  font-weight: 500;
  text-decoration: none;
  transition: color 120ms ease, background-color 120ms ease;
}

.nav-link { padding-inline: 14px; color: var(--muted); }

.nav-link:hover { color: var(--ink); background: var(--panel); }

.nav-pill {
  color: var(--ink);
  background: var(--panel);
  border: 1px solid var(--line);
}

.nav-pill:hover { background: var(--card); }

/* ---- Hero ------------------------------------------------------------ */

.hero { padding-block: clamp(40px, 7vw, 88px) clamp(32px, 4vw, 48px); }

.hero-inner { display: grid; gap: 28px; max-width: 760px; }

/* The one thing on this page that changes by deployment, and it says the
   door is shut. It is absent where it is not true. */
.badge {
  justify-self: start;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 5px 12px;
  border-radius: 999px;
  background: var(--accent-tint);
  color: var(--accent);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.02em;
}

.badge-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--accent); flex: none; }

.lede {
  max-width: 560px;
  font-size: clamp(17px, 1.4vw, 20px);
  color: var(--muted);
  text-wrap: pretty;
}

.actions { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 20px; }

.cta {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 13px 22px;
  border-radius: 999px;
  background: var(--accent);
  color: var(--on-accent);
  font-size: 15px;
  font-weight: 500;
  text-decoration: none;
  transition: background-color 120ms ease;
}

.cta:hover { background: var(--accent-hover); color: var(--on-accent); }

.quiet { font-size: 14px; color: var(--muted); text-decoration: none; }

.quiet:hover { text-decoration: underline; }

.note { font-size: 14px; color: var(--faint); }

/* The quieter call to action: a plum link with an arrow, for the places
   where a filled button would be the second one in a row. */
.more {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 14px;
  font-weight: 500;
  color: var(--accent);
  text-decoration: none;
  white-space: nowrap;
}

.more:hover { text-decoration: underline; }

/* A box a finger can hit. This and the two links in the footer are the
   controls on this page that a line of 14px text left at 21px, under the
   24px a touch target needs. The words keep their size and the box grows
   around them. */
.more { min-height: 24px; }

/* ---- Cards ----------------------------------------------------------- */

.card {
  background: var(--card);
  border-radius: 18px;
  box-shadow: var(--shadow-card);
}

/* An image slot. The picture fills it; with no picture the stripes show
   through, which is a place a photograph goes rather than a blank. */
.slot { border-radius: 12px; background: var(--stripes); overflow: hidden; }

.slot img { display: block; width: 100%; height: 100%; object-fit: cover; }

/* ---- The exchange ---------------------------------------------------- */

/* Two cards: what somebody types, and what is standing on the internet
   afterwards. They wrap onto one column together, so the site never
   arrives above the sentence that asked for it. */
.exchange {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 14px;
  align-items: stretch;
}

.chat { padding: 22px; display: flex; flex-direction: column; gap: 16px; min-width: 0; }

.chat-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--line);
  font-size: 13px;
  color: var(--faint);
}

/* What the owner typed. Right-aligned and tinted, the way every chat
   window a reader has ever seen draws their own words. */
.said {
  align-self: flex-end;
  max-width: 86%;
  padding: 12px 16px;
  border-radius: 16px 16px 4px 16px;
  background: var(--accent-tint);
  line-height: 1.45;
}

.reply { display: grid; grid-template-columns: 26px minmax(0, 1fr); gap: 12px; max-width: 92%; }

.avatar {
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border-radius: 9px;
  background: var(--accent);
  color: var(--on-accent);
  font-family: var(--display);
  font-size: 15px;
  font-weight: 600;
}

.reply-body { display: grid; gap: 10px; }

.reply-body p { line-height: 1.45; }

.reply-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }

/* The chat card is a picture of a conversation, so the words that would
   be a link in a real one are not one here. A live href inside an
   illustration is a dead end wearing a call to action. */
.faux-link { font-size: 14px; font-weight: 500; color: var(--accent); }

.live {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 13px;
  font-weight: 500;
  color: var(--ok);
  white-space: nowrap;
}

.chat-later {
  margin-top: 6px;
  padding-top: 14px;
  border-top: 1px solid var(--line);
  display: grid;
  gap: 12px;
}

.chat-later .said { justify-self: end; }

.chat-input {
  margin: auto 0 0;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 16px;
  border-radius: 999px;
  background: var(--page);
  color: var(--faint);
  font-size: 14px;
}

.chat-input-dot {
  margin-left: auto;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--line-strong);
}

.site { padding: 10px; display: flex; flex-direction: column; gap: 10px; min-width: 0; }

.site-head { display: flex; align-items: center; gap: 10px; padding: 6px 6px 0; }

.url {
  flex: 1;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px;
  border-radius: 999px;
  background: var(--page);
  font-size: 13px;
  color: var(--muted);
  min-width: 0;
}

/* An address is long and a card is narrow, so it is cut rather than
   allowed to push the pill beside it off the row. */
.url-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.slot-site { flex: 1; min-height: 360px; }

.site-foot {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 12px;
  padding: 4px 8px 6px;
  font-size: 13px;
  color: var(--faint);
}

/* ---- Three steps ----------------------------------------------------- */

.steps {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 14px;
}

.steps li { padding: 22px; display: grid; gap: 14px; align-content: start; }

/* Only the first is filled. The other two are outlined because they are
   not yours to do: the page's whole claim is that step one is the work. */
.step-number {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  border: 1.5px solid var(--line-strong);
  color: var(--muted);
  font-size: 14px;
  font-weight: 600;
}

.step-now { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }

.steps p { font-size: 15px; color: var(--muted); text-wrap: pretty; }

/* ---- Showcase -------------------------------------------------------- */

.showcase-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 12px 32px;
  margin-bottom: 28px;
}

.showcase-head > div { display: grid; gap: 10px; }

.showcase-head h2 { margin-bottom: 0; }

/* An empty strip renders as the words and the link alone, and then the
   room kept for the plates is room kept for nothing. */
.showcase-head:last-child { margin-bottom: 0; }

.sub { font-size: 16px; color: var(--muted); }

.plates {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  gap: 14px;
}

.plate { padding: 10px; }

.plate a { display: grid; gap: 12px; color: inherit; text-decoration: none; }

/* The picture carries its own dimensions in the markup, so the row holds
   its shape before any of them arrive. A picture of another proportion
   is cropped rather than allowed to shove the row about. */
.plate img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: 12px;
  background: var(--stripes);
}

.plate-text { display: grid; gap: 3px; padding: 0 10px 10px; }

.plate-name { font-size: 16px; font-weight: 500; }

.plate-kind { font-size: 14px; color: var(--muted); }

.plate-address {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  margin-top: 6px;
  min-width: 0;
  font-size: 13px;
  color: var(--faint);
}

.plate a:hover .plate-name { text-decoration: underline; text-underline-offset: 3px; }

/* ---- What is included ------------------------------------------------ */

.included { padding: 8px; }

.included dl {
  margin: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 4px;
}

.included dl > div {
  padding: 18px 16px;
  border-radius: 12px;
  display: grid;
  gap: 6px;
  align-content: start;
  transition: background-color 120ms ease;
}

.included dl > div:hover { background: var(--panel); }

.included dt { font-size: 16px; font-weight: 500; }

.included dd { margin: 0; font-size: 14px; color: var(--muted); text-wrap: pretty; }

/* ---- Look before it is live, and work together ----------------------- */

.pair { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 14px; }

.pair > .card { padding: 26px; display: grid; gap: 22px; align-content: start; }

.pair-words { display: grid; gap: 10px; }

.pair-words h2 {
  font-size: clamp(26px, 2.8vw, 34px);
  max-width: none;
  margin-bottom: 0;
}

.pair-words p { font-size: 15px; color: var(--muted); text-wrap: pretty; }

.review {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.3fr);
  gap: 14px;
  align-items: end;
}

/* The phone is drawn rather than photographed: a picture of a handset
   would be a picture of a handset, and what matters is the box somebody
   drew on the page inside it. */
.phone {
  position: relative;
  overflow: hidden;
  aspect-ratio: 9 / 17;
  border: 6px solid var(--ink);
  border-radius: 22px;
  background: var(--panel);
}

.slot-phone { position: absolute; inset: 0; border-radius: 0; }

/* The comment box, where the owner pointed. Percentages rather than
   pixels, because the phone's own width is a fraction of the card. */
.phone-box {
  position: absolute;
  left: 12%;
  top: 38%;
  width: 56%;
  height: 18%;
  border: 2px solid var(--accent);
  border-radius: 6px;
  background: rgba(107, 45, 92, 0.08);
}

.phone-note {
  position: absolute;
  left: 8%;
  right: 8%;
  bottom: 8%;
  padding: 8px 10px;
  border-radius: 10px;
  background: var(--card);
  box-shadow: var(--shadow-card);
  font-size: 11px;
  line-height: 1.4;
}

.approve { background: var(--panel); border-radius: 14px; padding: 16px; display: grid; gap: 12px; }

.approve-who { font-size: 13px; color: var(--faint); }

.approve-ask { font-size: 18px; font-weight: 500; line-height: 1.25; }

.approve-pages { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; font-size: 13px; }

.approve-pages li { display: flex; justify-content: space-between; gap: 8px; }

.state { font-size: 12px; font-weight: 600; }

.state-ok { color: var(--ok); }
.state-wait { color: var(--wait); }
.state-same { color: var(--faint); }

.approve-buttons { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 4px; }

/* Drawn, not live: this is a picture of the approval page, which lives
   in the app behind a session. */
.button {
  padding: 8px 14px;
  border-radius: 999px;
  background: var(--card);
  border: 1px solid var(--line);
  font-size: 13px;
  font-weight: 500;
}

.button-accent { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }

.people { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }

.people li {
  display: grid;
  grid-template-columns: 34px minmax(0, 1fr) auto;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  border-radius: 12px;
  background: var(--panel);
}

.people .invite { grid-template-columns: 34px minmax(0, 1fr); background: none; border: 1.5px dashed var(--line-strong); }

.face {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  font-size: 13px;
  font-weight: 600;
}

.face-accent { background: var(--accent-tint); color: var(--accent); }
.face-wait { background: var(--wait-tint); color: var(--wait); }
.face-empty { border: 1.5px solid var(--line-strong); color: var(--faint); font-size: 16px; font-weight: 400; }

.person { display: grid; min-width: 0; }

.person-name { font-size: 15px; font-weight: 500; }

.person-role { font-size: 13px; color: var(--muted); }

.invite .person-role { font-size: 14px; }

/* ---- Yours to keep --------------------------------------------------- */

/* The one colour-block break, and full-bleed. It carries the argument
   the rest of the page only implies, so it gets the weight. */
.invert { background: var(--dark); color: var(--on-dark); }

/* One column, and it is minmax(0, 1fr) rather than auto: an auto track
   grows to the widest thing in it, and the clone command below does not
   wrap. Left alone, one unbreakable line makes the whole block wider
   than a phone and the page scrolls sideways — which is what the design
   reference does. */
.invert-inner {
  padding-block: clamp(56px, 7vw, 96px);
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 36px;
}

.invert-words { display: grid; gap: 12px; max-width: 640px; }

.invert .label { color: var(--on-dark-muted); }

.invert h2 {
  font-size: clamp(28px, 3.6vw, 44px);
  line-height: 1.1;
  letter-spacing: -0.022em;
  max-width: none;
  margin-bottom: 0;
}

.invert-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 14px; }

.invert-cards > div {
  background: var(--dark-card);
  border: 1px solid var(--dark-line);
  border-radius: 18px;
  padding: 22px;
  display: grid;
  gap: 8px;
  align-content: start;
}

.invert-cards h3 { font-size: 16px; font-weight: 500; }

.invert-cards p { font-size: 14px; color: var(--on-dark-muted); text-wrap: pretty; }

/* The one line of monospace on the page, and the only one that earns it:
   it is a command, and a command set in a proportional face is a
   command somebody mistypes. */
.clone {
  display: flex;
  min-width: 0;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 14px;
  padding: 14px 18px;
  border-radius: 14px;
  background: var(--dark-well);
  font-family: var(--mono);
  font-size: 13px;
  color: var(--accent-on-dark);
}

.prompt { color: var(--on-dark-faint); }

.command { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }

/* ---- Closing --------------------------------------------------------- */

.closing { padding-block: clamp(64px, 8vw, 112px); }

.closing-inner { display: grid; gap: 22px; max-width: 640px; }

.closing h2 {
  font-size: clamp(34px, 5vw, 60px);
  line-height: 1.02;
  letter-spacing: -0.025em;
  max-width: none;
  margin-bottom: 0;
}

.closing .lede { font-size: 17px; max-width: none; }

.closing .actions { justify-self: start; }

/* ---- Footer ---------------------------------------------------------- */

footer { border-top: 1px solid var(--line); }

.footer-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 16px 32px;
  padding-block: 28px 40px;
  color: var(--muted);
  font-size: 14px;
}

.footer-inner .brand { font-size: 18px; color: var(--muted); }

.footnav { display: flex; gap: 24px; }

.footnav a {
  color: var(--muted);
  text-decoration: none;
  transition: color 120ms ease;
  display: inline-flex;
  align-items: center;
  min-height: 24px;
}

.footnav a:hover { color: var(--ink); }

/* ---- Narrow screens -------------------------------------------------- */

/* The phone and the approval panel sit side by side inside one card, so
   they run out of room long before the page does. Below this they stack,
   and the phone stops being a full-height column. */
@media (max-width: 30rem) {
  .review { grid-template-columns: minmax(0, 1fr); }
  .phone { max-width: 220px; }
}

/* ---- Preferences ----------------------------------------------------- */

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