/* ============================================================================
   Kove landing page

   The tokens below are MIRRORED from web/src/index.css, which stays the single
   styling authority for the product. This page adds no colour, no radius step
   and no third elevation: if a value here disagrees with the app, the app is
   right and this file is stale.

   Two rules from DESIGN.md are load-bearing here and easy to undo by accident:

   1. The No Overlay Rule. No whole-viewport wash, gradient, glow, vignette or
      grain, however subtle. iOS paints its own strips adjacent to the page and
      any full-page film seams against them as a visible colour band.
   2. The Rationed Lamp Rule. One lit thing per view. The filled lime button is
      that thing. The receipt's lime is a 5% wash and a 30% border, which is how
      the app itself lets a receipt chip and a primary button share a screen.

   The hairline rules and the frozen left rail are the page's structure, not
   decoration: they are the notation of the record Kove keeps, and they organise
   real content. That is the one sanctioned reason to draw them.
   ============================================================================ */

/* ---------------------------------------------------------------- fonts */
/* Self-hosted variable fonts, copied from the app's own @fontsource packages.
   Nothing loads from a CDN, here or in the app. */
@font-face {
  font-family: "Inter Variable";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("./fonts/inter.woff2") format("woff2");
}
@font-face {
  font-family: "Space Grotesk Variable";
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url("./fonts/space-grotesk.woff2") format("woff2");
}
@font-face {
  font-family: "JetBrains Mono Variable";
  font-style: normal;
  font-weight: 100 800;
  font-display: swap;
  src: url("./fonts/jetbrains-mono.woff2") format("woff2");
}

/* ---------------------------------------------------------------- tokens */
:root {
  /* colour, mirrored from web/src/index.css */
  --background: #0a0b0a;
  --foreground: #f2f4f2;
  --card: #171917;
  --panel: #1e211e;
  --accent: #242824;
  --muted: #151715;
  --muted-foreground: #8e968f;
  --primary: #7ffa88;
  --primary-foreground: #07130a;
  --destructive: #f25e50;
  --border: #343933;
  --input: #4a514a;
  --selected: #233425;
  --selection: #335f36;

  /* shape: 12px base, laddered */
  --radius: 0.75rem;
  --radius-sm: calc(var(--radius) - 4px);
  --radius-md: calc(var(--radius) - 2px);
  --radius-lg: var(--radius);
  --radius-xl: calc(var(--radius) + 4px);

  /* type */
  --font-display: "Space Grotesk Variable", "Inter Variable", ui-sans-serif, system-ui, sans-serif;
  --font-sans: "Inter Variable", ui-sans-serif, system-ui, -apple-system, sans-serif;
  --font-mono: "JetBrains Mono Variable", ui-monospace, SFMono-Regular, Menlo, monospace;

  /* the pointer-density ramp, stepped once below */
  --text-xs: 0.75rem;
  --text-sm: 0.875rem;
  --text-base: 1rem;

  /* motion: three curves, ease-in deliberately absent */
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);

  /* elevation: exactly two steps exist in the system; this page needs one */
  --shadow-resting: inset 0 1px 0 0 color-mix(in oklab, var(--foreground) 5%, transparent),
    0 1px 2px 0 rgb(0 0 0 / 0.4), 0 12px 32px -16px rgb(0 0 0 / 0.55);

  /* layout */
  --sheet: 1152px; /* the Data grid's own column width, since this page is a sheet */
  --measure: 33rem; /* one reading column for every band below the hero, 72 characters */
  --gutter: 1rem;
  --rail-w: 5.5rem;
  --band-y: clamp(3.5rem, 7vw, 6.5rem);
}

/* The Pointer-Density Rule. Density is a property of the pointer, never the
   viewport: one ramp, stepped once, so every role moves by the same +2px and
   the body floor lands on 16px, which is the size below which iOS Safari zooms
   the page on input focus. This is why the email input is a plain --text-sm. */
@media (pointer: coarse) {
  :root {
    --text-xs: 0.875rem;
    --text-sm: 1rem;
  }
}

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* The header is sticky, so it covers the top of whatever an anchor scrolls to. One
     declaration on the scroll container fixes every in-page link at once, which is the
     reason to put it here rather than a scroll-margin on each target. The value is the
     header's own height (.topbar > .sheet plus its safe-area padding), so it stays right
     on a notched phone.

     It was measured as invisible at 1440px, where the hero's 64px of padding happens to
     be one pixel taller than the header, and as a 25px bite out of the headline at 390px
     and 530px, where that padding steps down to 40px. A defect that only appears on
     narrow windows is the kind a desktop review cannot see.

     The 1px is the header's bottom border, and it is not pedantry: without it every
     anchor lands exactly one pixel high, which measured as a 1px sliver of #waitlist
     sitting behind the bar. */
  scroll-padding-top: calc(4rem + 1px + env(safe-area-inset-top));
}

body {
  margin: 0;
  background: var(--background);
  color: var(--foreground);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  /* The canvas stays absolutely flat. See the No Overlay Rule above. */
}

::selection {
  /* Desktop only in practice: iOS ignores ::selection for regular text and
     there is no CSS fix for it. Documented in the app, not a bug here. */
  background: var(--selection);
  color: var(--foreground);
}

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

a {
  color: inherit;
}

.nums {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

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

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 10;
  padding: 0.5rem 0.75rem;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  font-size: var(--text-xs);
}
.skip:focus {
  left: var(--gutter);
  top: var(--gutter);
}

:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

/* Reduced motion means gentler, not none: travel and scale collapse, the
   change of state still reads. */
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 120ms !important;
  }
  .answer[data-entering] {
    animation: none !important;
  }
}

/* ---------------------------------------------------------------- the sheet */
.sheet {
  width: 100%;
  max-width: var(--sheet);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.band > .sheet {
  display: grid;
  grid-template-columns: 1fr;
  padding-block: var(--band-y);
}

/* One hairline per band boundary, spanning the sheet. Not per row. */
.band + .band > .sheet,
.footer > .sheet {
  border-top: 1px solid var(--border);
}

.rail {
  display: none;
}

.cells {
  min-width: 0;
}

@media (min-width: 768px) {
  .band > .sheet,
  .footer > .sheet {
    grid-template-columns: var(--rail-w) minmax(0, 1fr);
  }
  /* The frozen leading column, as the grid has one. It carries a row label
     where the band is about a day, and otherwise only the rule. */
  .rail {
    display: block;
    border-right: 1px solid var(--border);
    padding-right: 1rem;
  }
  .cells {
    padding-left: clamp(1.25rem, 3vw, 2.5rem);
  }
}

.rail-label {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--muted-foreground);
  display: block;
  text-align: right;
  white-space: nowrap;
}
.rail-new {
  color: var(--primary);
}

/* ---------------------------------------------------------------- type */
h1,
h2,
h3 {
  font-family: var(--font-display);
  font-weight: 600;
  letter-spacing: -0.02em;
  text-wrap: balance;
  margin: 0;
}

h1 {
  /* Display: 3rem, down to 2.25rem on a small screen. Both ends are the ramp's
     own steps, so the landing hero uses the size the app's hero moments use. */
  font-size: clamp(2.25rem, 5vw, 3rem);
  line-height: 1.05;
}

h2 {
  /* Headline, flat at 24px. A section heading's hierarchy is carried by the
     display face and its weight, not by reaching for a size off the ramp. */
  font-size: 1.5rem;
  line-height: 1.15;
  margin-bottom: 0.75rem;
}

h3 {
  font-size: 1.125rem;
  line-height: 1.25;
}

/* A sub-heading INSIDE a band, for a second thought that does not deserve its own band
   and its own rail label. The gap above is what says "new thought" (2.5rem, well clear of
   the 1.5rem the band's own blocks sit at) and the tight gap below is what binds it to
   the paragraph it introduces. .cells is a plain block, so this margin collapses against
   its neighbours exactly as the band's other blocks do. */
.sub {
  margin: 2.5rem 0 0.5rem;
}

/* One heading on the page wears a glyph, the band that names the mechanism, and it is
   the app's own Chat icon. One marked heading is a deliberate mark; the same glyph on
   every heading would be a grammar nobody chose. 16px, the size this system draws a
   Lucide glyph at when it sits inside something else.

   It hangs in its own column to the LEFT of the heading rather than sitting inside the
   text flow, so a heading that wraps keeps both of its lines aligned to one edge instead
   of the second line starting under the icon. That is what the flex row is for, and
   `align-items: baseline` places the glyph's bottom edge on the first line's baseline,
   which lands it on the cap height without a magic number to maintain.

   Signal Lime, on the owner's call (2026-08-20). It is worth knowing what that bends:
   the Rationed Lamp Rule gives a view one lit thing, and this band has no action, so by
   the letter of the rule a lime glyph here is decoration. What argues for it is that the
   app paints this exact glyph lime when the Chat tab is the current one, so it reads as
   the product's own mark for the conversation. It stays a 16px stroke and never a fill,
   which is what keeps it from competing with the filled CTA.

   The width and height are ALSO attributes on the element, and that is not redundancy.
   An inline SVG carrying only a viewBox has no intrinsic size, so the base `svg` rule's
   `max-width: 100%` lets it expand to the whole column: measured at 1424px across when
   this stylesheet was merely late, which is what a stale cache looks like. Attributes
   bound it before CSS is involved. */
h2:has(> .h2-glyph) {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
}

h2 > .h2-glyph + span {
  min-width: 0;
}

.h2-glyph {
  width: 1rem;
  height: 1rem;
  color: var(--primary);
  flex: none;
}

.lede {
  font-size: var(--text-base);
  line-height: 1.55;
  color: var(--foreground);
  max-width: 26rem;
  margin: 1rem 0 0;
}

.body {
  color: var(--muted-foreground);
  max-width: var(--measure);
  margin: 0 0 1.5rem;
  line-height: 1.6;
}
/* The one band that is pure argument carries its paragraph at reading size
   rather than caption size, because it is the only thing in the band. */
.body-lead {
  font-size: var(--text-base);
  color: var(--foreground);
  line-height: 1.6;
  margin-bottom: 0;
  /* Reading size, so a slightly narrower column holds the same character count. */
  max-width: 30rem;
}

.caption {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--muted-foreground);
  margin: 1rem 0 0;
  line-height: 1.5;
}

/* ---------------------------------------------------------------- topbar */
/* Solid, and the page's only separator here is the hairline under it. It was 88% opaque
   over a blur(12px), which this canvas gives nothing back for: the background is a
   dead-flat single colour, so the blur spent a GPU pass a frame compositing #0a0b0a
   against #0a0b0a, and at 88% the near-black content ghosting through was invisible
   anyway. The app reached the same conclusion for the gym dock (Training.tsx) and its own
   desktop header carries no background or blur at all, just `border-b`.

   It also removes a risk this codebase has already paid for once: iOS paints the
   status-bar strip ADJACENT to the page, no page layer can cover it, and a translucent
   blurred layer against that strip seams as a visible colour band. This element is the
   one that borders it (note the safe-area padding), so translucency here was the exact
   configuration DESIGN.md's canvas ruling warns about. */
.topbar {
  position: sticky;
  top: 0;
  z-index: 5;
  background: var(--background);
  border-bottom: 1px solid var(--border);
  padding-top: env(safe-area-inset-top);
}

.topbar > .sheet {
  height: 4rem; /* 64px, inside the 80px cap, one line at every width */
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

.wordmark {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  text-decoration: none;
  min-width: 0;
}

/* The mark is the app's icon FILE, so all this rules is the box it sits in: the artwork
   draws the tile and the letter.

   The radius restates the SVG's own corner as a proportion (rx="96" on a 512 viewBox =
   18.75%), which is what keeps the beacon ring tracing the artwork's edge instead of the
   element's square box, at whatever size the tile is ever set to. It was drawn in CSS at
   var(--radius-xl) before, and that is worth recording because it did not look like a
   token being slightly off: 16px of radius on a 24px box exceeds the side, so CSS scales
   both corners down to 12px and the mark rendered as a perfect CIRCLE, which is the one
   shape Kove's identity is not.

   The beacon is the app's own brand-mark treatment (.beacon in web/src/index.css) and the
   one place on this page a glow is allowed to exist. */
.mark {
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 18.75%;
  flex: none;
  box-shadow: 0 0 0 1px color-mix(in oklab, var(--primary) 35%, transparent),
    0 8px 30px -8px color-mix(in oklab, var(--primary) 55%, transparent);
}

.wordmark-text {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.125rem; /* Title tier */
  letter-spacing: -0.02em;
}

.topbar-right {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

/* Two segments, pill-shaped, marked the way the app marks a current tab:
   the label goes primary over Selected Tint, never a filled lime. */
.langswitch {
  display: inline-flex;
  padding: 2px;
  gap: 2px;
  border: 1px solid var(--border);
  border-radius: 9999px;
  background: color-mix(in oklab, var(--card) 60%, transparent);
}

.lang {
  appearance: none;
  border: 0;
  background: transparent;
  color: var(--muted-foreground);
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  font-weight: 500;
  padding: 0.25rem 0.625rem;
  border-radius: 9999px;
  cursor: pointer;
  transition: color 150ms var(--ease-out), background-color 150ms var(--ease-out);
}
.lang:hover {
  color: var(--foreground);
}
.lang[aria-pressed="true"] {
  background: var(--selected);
  color: var(--primary);
}

@media (max-width: 26.25rem) {
  /* A 420px phone keeps the wordmark and the language on one comfortable line by
     dropping the header's button, which the hero repeats immediately below it.
     Two class names, not one: .btn sets its own display later in this file, so at
     equal specificity source order was winning and this rule did nothing. */
  .topbar-right .topbar-cta {
    display: none;
  }
}

/* ---------------------------------------------------------------- buttons */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  height: 2.25rem; /* 36px comfortable: a primary CTA */
  padding-inline: 1rem;
  border-radius: var(--radius-md);
  border: 1px solid transparent;
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  font-weight: 500;
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color 150ms var(--ease-out), border-color 150ms var(--ease-out),
    color 150ms var(--ease-out), transform 150ms var(--ease-out);
}
.btn:active {
  transform: scale(0.98);
}

.btn-primary {
  background: var(--primary);
  color: var(--primary-foreground);
}
.btn-primary:hover {
  background: color-mix(in oklab, var(--primary) 90%, transparent);
}

.btn-outline {
  background: color-mix(in oklab, var(--input) 30%, transparent);
  border-color: var(--input);
  color: var(--foreground);
}
.btn-outline:hover {
  background: var(--accent);
}

.btn-sm {
  height: 2rem; /* 32px compact: secondary and toolbar actions */
  padding-inline: 0.75rem;
  font-size: var(--text-xs);
}

.btn:disabled,
.btn[aria-disabled="true"] {
  opacity: 0.55;
  cursor: not-allowed;
  transform: none;
}

.quiet-link {
  font-size: var(--text-sm);
  color: var(--muted-foreground);
  text-decoration: none;
  border-bottom: 1px solid var(--border);
  padding-bottom: 1px;
  transition: color 150ms var(--ease-out), border-color 150ms var(--ease-out);
}
.quiet-link:hover {
  color: var(--foreground);
  border-color: var(--input);
}

.actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem 1.5rem;
  margin-top: 2rem;
}

/* ---------------------------------------------------------------- hero */
.band-hero > .sheet {
  padding-top: clamp(2.5rem, 5vw, 4rem);
}

.hero {
  display: grid;
  gap: clamp(2.5rem, 5vw, 4rem);
  align-items: start;
}

@media (min-width: 62rem) {
  .hero {
    grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
    align-items: center;
  }
}

/* ---------------------------------------------------------------- the demo */
.demo {
  min-width: 0;
}

/* The chips lead, because they are the six things a chat can be asked to do and
   they have to be readable without tapping anything. */
.chiprow {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  padding-bottom: 1.25rem;
}

/* One turn of a conversation: the ask on the right the way a person's own message
   sits, the answer on the left. Enough to read as a chat at a glance, which is
   the entire claim of the page. */
.thread {
  display: grid;
  gap: 0.875rem;
}

.said {
  justify-self: end;
  max-width: 88%;
  margin: 0;
  background: var(--accent);
  border-radius: var(--radius-lg);
  border-end-end-radius: var(--radius-sm);
  padding: 0.625rem 0.875rem;
  font-size: var(--text-sm);
  line-height: 1.5;
}

.answer {
  display: grid;
  gap: 0.75rem;
  min-width: 0;
}

.answer[data-entering] {
  animation: receipt-in 200ms var(--ease-out);
}

/* A turn that consulted the record says so, muted and never in the accent: the
   accent marks something created or changed, and a read created nothing. */
.provenance {
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--muted-foreground);
}

.reply {
  margin: 0;
  font-size: var(--text-sm);
  line-height: 1.6;
  max-width: 40rem;
}

/* What the app leaves in the thread when a turn created or set something: a mono
   label and the thing's name. No fill, so it never competes with the CTA. */
.marker {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5rem 0.75rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--border);
}

.marker-label {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--muted-foreground);
  flex: none;
}

.marker-value {
  font-size: var(--text-sm);
  font-weight: 500;
  color: var(--primary);
  min-width: 0;
}

.chip {
  appearance: none;
  border: 1px solid transparent;
  background: var(--accent);
  color: var(--muted-foreground);
  border-radius: 9999px;
  padding: 0.25rem 0.75rem;
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  font-weight: 500;
  cursor: pointer;
  transition: color 150ms var(--ease-out), background-color 150ms var(--ease-out);
}
.chip:hover {
  color: var(--foreground);
}
/* Tint plus mark: the selected chip takes Selected Tint and its label goes
   primary. Never a lime fill, which would read as an action. */
.chip[aria-pressed="true"] {
  background: var(--selected);
  color: var(--primary);
}

/* The receipt chip, to the app's own spec: 5% lime wash, 30% lime border,
   12px radius, resting elevation, values in mono at body size. */
.receipt {
  background: color-mix(in oklab, var(--primary) 5%, var(--card));
  border: 1px solid color-mix(in oklab, var(--primary) 30%, transparent);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-resting);
  padding: 1rem;
}

@keyframes receipt-in {
  from {
    opacity: 0;
    transform: scale(0.985);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

.receipt-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  padding-bottom: 0.75rem;
}

.receipt-title {
  font-size: var(--text-xs);
  font-weight: 500;
  color: var(--foreground);
}

.receipt-date {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--muted-foreground);
}

.pills {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 0;
}

.pill {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  background: color-mix(in oklab, var(--background) 45%, transparent);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 0.375rem 0.625rem;
}

.pill dt {
  font-size: var(--text-xs);
  color: var(--muted-foreground);
}

.pill dd {
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

.receipt-note {
  margin: 0.875rem 0 0;
  padding-top: 0.875rem;
  border-top: 1px solid color-mix(in oklab, var(--primary) 18%, transparent);
  font-size: var(--text-sm);
  color: var(--muted-foreground);
  line-height: 1.55;
}
.receipt-note:empty {
  display: none;
}

/* The offer chip, to the app's spec: an offer wears a NEUTRAL dashed frame on a card
   wash, and the accent rides the header rather than a fill. That is what separates an
   offer from an action in this system, and it is why nothing here is a filled button.
   The pills stay neutral too, because an offered field has not been chosen yet, and
   Selected Tint would say it had. */
.thread-tight {
  gap: 0.625rem;
  margin-top: 1.5rem;
  max-width: var(--measure);
}

.offer {
  border: 1px dashed var(--border);
  background: color-mix(in oklab, var(--card) 40%, transparent);
  border-radius: var(--radius-lg);
  padding: 0.875rem 1rem 1rem;
}

.offer-head {
  margin: 0 0 0.75rem;
  font-size: var(--text-xs);
  font-weight: 500;
  color: var(--primary);
}

.offer-pills {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.offer-pill {
  background: var(--accent);
  border-radius: 9999px;
  padding: 0.25rem 0.75rem;
  font-size: var(--text-xs);
  font-weight: 500;
  color: var(--foreground);
}

/* ---------------------------------------------------------------- ledger */
.day {
  max-width: var(--measure);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  overflow: hidden;
}

.day > summary {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 0.75rem;
  padding: 0.875rem 1rem;
  cursor: pointer;
  list-style: none;
  transition: background-color 150ms var(--ease-out);
  min-height: 2.75rem;
}
.day > summary::-webkit-details-marker {
  display: none;
}
.day > summary:hover {
  background: color-mix(in oklab, var(--accent) 40%, transparent);
}
.day > summary:active {
  background: color-mix(in oklab, var(--accent) 60%, transparent);
}
.day[open] > summary {
  background: var(--selected);
}

.day-date {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--muted-foreground);
  white-space: nowrap;
}
.day[open] .day-date {
  color: var(--primary);
}

.day-peek {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--muted-foreground);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.day[open] .day-peek {
  opacity: 0;
}

/* A chevron drawn from a border, not an icon file: two edges of a square,
   rotated. Nothing in the system needs an SVG for this. */
.day-toggle {
  width: 0.5rem;
  height: 0.5rem;
  border-right: 1.5px solid var(--muted-foreground);
  border-bottom: 1.5px solid var(--muted-foreground);
  transform: rotate(45deg);
  transition: transform 200ms var(--ease-out);
  margin-right: 2px;
}
.day[open] .day-toggle {
  transform: rotate(-135deg);
}

.day-body {
  padding: 0 1rem 1.25rem;
  display: grid;
  gap: 1rem;
}

.day-said {
  display: grid;
  gap: 0.375rem;
}
.day-said p {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--foreground);
  line-height: 1.5;
}

.cells-out {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 0;
  padding-top: 0.25rem;
}

.cell {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  background: color-mix(in oklab, var(--background) 45%, transparent);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 0.375rem 0.625rem;
}
.cell dt {
  font-size: var(--text-xs);
  color: var(--muted-foreground);
}
.cell dd {
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

.day-note {
  margin: 0;
  display: grid;
  gap: 0.25rem;
  font-size: var(--text-sm);
  color: var(--muted-foreground);
  line-height: 1.55;
  border-top: 1px solid var(--border);
  padding-top: 0.875rem;
}
.day-note-label {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--muted-foreground);
}

/* ---------------------------------------------------------------- plate */
.plate {
  margin: 1.5rem 0 0;
  min-width: 0;
  max-width: var(--measure);
}

/* A reserved plate, not a fake screenshot and not a hole. An empty cell is
   ordinary in a ledger, so it is drawn as one and it states what belongs in it.
   The dimensions are inside the well because the person filling it needs them. */
.plate-well {
  border: 1px dashed var(--input);
  border-radius: var(--radius-lg);
  background: var(--muted);
  display: grid;
  place-items: center;
  padding: 1rem;
}

.plate-slug {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--muted-foreground);
  text-align: center;
  line-height: 1.6;
}
.plate-slug .nums {
  display: block;
  color: var(--input);
}

.plate-well {
  aspect-ratio: 16 / 10;
  /* Kept short on purpose: it is the one thing on the page still waiting for its
     content, and the live example day above it already makes the same argument. */
  max-height: 16rem;
}

.plate .caption {
  margin-top: 0.75rem;
  max-width: 28rem;
}

/* ---------------------------------------------------------------- waitlist */
.band-close > .sheet {
  padding-bottom: clamp(4rem, 8vw, 7rem);
}

/* The waitlist form moved to Tally, so the email field, its states and the status line
   that reported the POST are all gone with it. What is left in that band is one .btn. */

/* ---------------------------------------------------------------- footer */
.footer > .sheet {
  padding-block: clamp(2rem, 4vw, 3rem);
  display: grid;
  grid-template-columns: 1fr;
}

@media (min-width: 768px) {
  .footer > .sheet {
    grid-template-columns: var(--rail-w) minmax(0, 1fr);
  }
}

.footer-cells {
  display: grid;
  gap: 0.625rem;
  padding-bottom: env(safe-area-inset-bottom);
}

.footer-tag {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-base);
  letter-spacing: -0.02em;
  max-width: 28rem;
}

.footer-fine {
  margin: 0;
  font-size: var(--text-xs);
  color: var(--muted-foreground);
  max-width: 34rem;
  line-height: 1.55;
}
/* The credit is a NAME, so it sits at full --foreground rather than at the muted colour
   of the fine print around it. That is the app's own answer for the same line
   (`text-foreground underline` in Auth.tsx and Settings.tsx), and this rule had drifted
   off it: the link rested at --muted-foreground and only reached foreground on hover,
   which on a phone is a state nobody ever sees.

   The rule under it then has to firm up too. Left at --border (1.50:1) beneath white
   text it reads as a rendering artifact rather than as a link, so it rests at --input,
   the tier this system reserves for a boundary that must be identifiable, and comes up
   to the word itself on hover. That hover is the one this link has: the text cannot get
   any brighter. */
.footer-fine a {
  color: var(--foreground);
  text-decoration: underline;
  text-decoration-color: var(--input);
  text-underline-offset: 2px;
  transition: text-decoration-color 150ms var(--ease-out);
}
.footer-fine a:hover {
  text-decoration-color: currentColor;
}
