/* welle.om
   The app's design system, adapted to a browser.

   Everything colour, shape, motion and spacing comes from tokens.css, which is
   generated from packages/tokens. Nothing here invents a value.

   The four rules the app holds, held here too:
     1. One accent, and it is green. The wellbeing scale is the only other
        colour, it is ordered, and it appears exactly once on this page.
     2. Shape lock. Actions and chips are pills, cards 20, input wells 16,
        sheets 28. Nothing else.
     3. One border weight: 1px, --w-border.
     4. Nothing bounces. One curve, two durations.
*/

/* ------------------------------------------------------------------ fonts */
/* Self-hosted, subset, never a CDN. The app bundles these same six files. */

@font-face {
  font-family: 'InstrumentSerif';
  src: url('fonts/InstrumentSerif-Regular.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'InstrumentSerif';
  src: url('fonts/InstrumentSerif-Italic.woff2') format('woff2');
  font-weight: 400; font-style: italic; font-display: swap;
}
@font-face {
  font-family: 'PlusJakartaSans';
  src: url('fonts/PlusJakartaSans-Regular.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'PlusJakartaSans';
  src: url('fonts/PlusJakartaSans-Medium.woff2') format('woff2');
  font-weight: 500; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'PlusJakartaSans';
  src: url('fonts/PlusJakartaSans-Bold.woff2') format('woff2');
  font-weight: 700; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'JetBrainsMono';
  src: url('fonts/JetBrainsMono-Variable.woff2') format('woff2');
  font-weight: 400 700; font-style: normal; font-display: swap;
}

/* -------------------------------------------------------------------- base */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

body {
  margin: 0;
  background: var(--w-bg);
  color: var(--w-text);
  font-family: var(--w-font-sans);
  font-size: clamp(1rem, 0.96rem + 0.2vw, 1.0625rem);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-synthesis-weight: none;
  overflow-x: hidden;
}

img, svg { max-width: 100%; display: block; }
[hidden] { display: none !important; }

::selection { background: var(--w-accent); color: var(--w-on-accent); }

/* One focus treatment, everywhere, and it is visible in both themes. */
:focus-visible {
  outline: 2px solid var(--w-accent);
  outline-offset: 3px;
  border-radius: 4px;
}

.skip {
  position: absolute; left: var(--w-space-lg); top: -100px;
  z-index: 100;
  background: var(--w-action-bg); color: var(--w-action-text);
  padding: var(--w-space-md) var(--w-space-xl);
  border-radius: var(--w-radius-pill);
  font-weight: 700; text-decoration: none;
  transition: top var(--w-duration-tap) var(--w-ease-standard);
}
.skip:focus { top: var(--w-space-lg); }

/* -------------------------------------------------------------------- type */
/* Ten roles in the app. The web needs eight of them and no more. */

.display, h1 {
  font-family: var(--w-font-serif);
  font-weight: 400;
  font-size: clamp(2.75rem, 1.9rem + 3.9vw, 5.25rem);
  line-height: 1.04;
  letter-spacing: var(--w-track-display);
  margin: 0;
  text-wrap: balance;
}

.title, h2 {
  font-family: var(--w-font-serif);
  font-weight: 400;
  font-size: clamp(1.9375rem, 1.6rem + 1.55vw, 2.875rem);
  line-height: 1.14;
  letter-spacing: var(--w-track-title);
  margin: 0;
  text-wrap: balance;
}

h3 {
  font-family: var(--w-font-sans);
  font-weight: 700;
  font-size: clamp(1.125rem, 1.06rem + 0.3vw, 1.25rem);
  line-height: 1.3;
  margin: 0;
  letter-spacing: -0.01em;
}

/* The person's own words, quoted back. Always italic, always theirs. */
.quote {
  font-family: var(--w-font-serif);
  font-style: italic;
  font-size: clamp(1.25rem, 1.1rem + 0.7vw, 1.625rem);
  line-height: 1.42;
  color: var(--w-text);
  margin: 0;
  text-wrap: pretty;
}

/* Dates and metadata. Uppercase mono, letterspaced, a few words at most. */
.label {
  font-family: var(--w-font-mono);
  font-weight: 500;
  font-size: 0.6875rem;
  line-height: 1.36;
  letter-spacing: var(--w-track-label);
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
  color: var(--w-text-secondary);
  margin: 0;
}

.lead {
  font-size: clamp(1.0625rem, 0.98rem + 0.45vw, 1.3125rem);
  line-height: 1.52;
  color: var(--w-text-secondary);
  max-width: var(--w-measure);
  margin: 0;
  text-wrap: pretty;
}

p { margin: 0; color: var(--w-text-secondary); text-wrap: pretty; }
.ink { color: var(--w-text); }

a { color: inherit; text-decoration-color: var(--w-border-strong); text-underline-offset: 3px; }
a:hover { text-decoration-color: currentColor; }

/* ------------------------------------------------------------------ layout */

.page { width: 100%; max-width: var(--w-page); margin: 0 auto; padding-inline: var(--w-gutter); }

section { padding-block: clamp(64px, 9vw, 128px); }
section + section { border-top: 1px solid var(--w-border); }

.stack { display: flex; flex-direction: column; }
.stack-sm  { gap: var(--w-space-sm); }
.stack-md  { gap: var(--w-space-md); }
.stack-lg  { gap: var(--w-space-lg); }
.stack-xl  { gap: var(--w-space-xl); }
.stack-2xl { gap: var(--w-space-2xl); }
.stack-3xl { gap: var(--w-space-3xl); }

.measure { max-width: var(--w-measure); }

/* ---------------------------------------------------------------- controls */
/* Pill: min tap 54 (the app's MIN_TAP_TARGET + 10), radius pill, no shadow. */

/*
  The app's pill is 54pt because a thumb at the bottom of a phone screen needs
  it. A mouse does not, and 54px of black on a desktop page reads as shouting.
  So the size follows the pointing device rather than the platform: 46px with
  a mouse, the app's own 54 on anything touched. One rule, and it is the same
  reason the app chose 54 in the first place.
*/
.pill {
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--w-space-sm);
  min-height: 46px;
  padding: 11px var(--w-space-xl);
  border: 0; border-radius: var(--w-radius-pill);
  background: var(--w-action-bg); color: var(--w-action-text);
  font-family: var(--w-font-sans); font-weight: 700;
  font-size: 1rem; line-height: 1.3;
  text-decoration: none; cursor: pointer; white-space: nowrap;
  transition:
    transform var(--w-duration-tap) var(--w-ease-standard),
    opacity   var(--w-duration-tap) var(--w-ease-standard),
    background-color var(--w-duration-tap) var(--w-ease-standard);
}
.pill:hover { opacity: 0.9; }
.pill:active { transform: scale(0.98); }
.pill[disabled], .pill[aria-disabled='true'] { opacity: 0.35; cursor: not-allowed; }
.pill[disabled]:active { transform: none; }

/*
  Green is the wellbeing scale and the mark, and it means how a day went. It is
  not a button colour: the same action was green in the nav and black in the
  hero, which gave one action two identities. Every action is now the primary
  fill. This tone survives for the one moment that earns it, the TestFlight
  button that appears after a registration lands.
*/
.pill-accent { background: var(--w-accent); color: var(--w-on-accent); }
.pill-accent:hover { background: var(--w-accent-pressed); opacity: 1; }

.pill-quiet {
  background: transparent; color: var(--w-text);
  border: 1px solid var(--w-border);
}
.pill-quiet:hover { border-color: var(--w-border-strong); opacity: 1; }

/* The action that finishes a form keeps the app's size at every width. */
.pill-block { width: 100%; min-height: 54px; font-size: 1.0625rem; }

@media (pointer: coarse) {
  .pill { min-height: 54px; padding: var(--w-space-lg) var(--w-space-2xl); font-size: 1.0625rem; }
  .nav-cta { min-height: 44px; }
}

/* The quiet escape hatch under a primary action. Never styled as a button. */
.textbtn {
  background: none; border: 0; padding: var(--w-space-md) 0;
  font: inherit; color: var(--w-text-secondary);
  cursor: pointer; text-decoration: underline;
  text-decoration-color: var(--w-border-strong); text-underline-offset: 3px;
  min-height: var(--w-tap);
}
.textbtn:hover { color: var(--w-text); }

/* Chip: pill, hairline, accent fill when chosen. The app's Chip verbatim. */
.chip {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: var(--w-tap);
  padding-inline: var(--w-space-lg);
  border: 1px solid var(--w-border);
  border-radius: var(--w-radius-pill);
  background: transparent; color: var(--w-text-secondary);
  font: inherit; cursor: pointer;
  transition:
    background-color var(--w-duration-tap) var(--w-ease-standard),
    border-color     var(--w-duration-tap) var(--w-ease-standard),
    color            var(--w-duration-tap) var(--w-ease-standard);
}
.chip:hover { border-color: var(--w-border-strong); }
.chip[aria-pressed='true'], .chip:has(input:checked) {
  background: var(--w-accent); border-color: var(--w-accent); color: var(--w-on-accent);
}
.chip-row { display: flex; flex-wrap: wrap; gap: var(--w-space-sm); }

/* Card: radius 20, hairline. Used sparingly, never stacked. */
.card {
  border: 1px solid var(--w-border);
  border-radius: var(--w-radius-card);
  padding: clamp(20px, 3vw, 32px);
  background: transparent;
}

/* --------------------------------------------------------------- nav bar */

.nav {
  position: sticky; top: 0; z-index: 40;
  background: color-mix(in srgb, var(--w-bg) 88%, transparent);
  backdrop-filter: saturate(140%) blur(14px);
  border-bottom: 1px solid transparent;
  transition: border-color var(--w-duration-transition) var(--w-ease-standard);
}
.nav[data-stuck='true'] { border-bottom-color: var(--w-border); }
.nav-in {
  display: flex; align-items: center; gap: var(--w-space-lg);
  min-height: 64px;
}
.brand {
  display: inline-flex; align-items: center; gap: 10px;
  text-decoration: none; color: var(--w-text);
  margin-inline-end: auto;
  padding-block: var(--w-space-sm);
}
.brand svg { width: 26px; height: 26px; flex: none; }
.brand span {
  font-family: var(--w-font-serif); font-size: 1.5rem; line-height: 1;
  letter-spacing: -0.01em; padding-top: 3px;
}
.nav-links { display: flex; align-items: center; gap: var(--w-space-xs); }
.nav-link {
  padding: var(--w-space-md) var(--w-space-md);
  min-height: var(--w-tap); display: inline-flex; align-items: center;
  border-radius: var(--w-radius-pill);
  color: var(--w-text-secondary); text-decoration: none;
  font-size: 0.9375rem;
  background: none; border: 0; font-family: inherit; cursor: pointer;
  transition: color var(--w-duration-tap) var(--w-ease-standard);
}
.nav-link:hover { color: var(--w-text); }
.nav-cta { padding-inline: var(--w-space-lg); min-height: 40px; font-size: 0.9375rem; }
@media (max-width: 719px) {
  .nav-link-hide { display: none; }
}
@media (max-width: 419px) {
  /*
    At 390 the CTA label wrapped to two lines, and at 360 the row was 16px
    wider than the viewport. The nav on a phone has one job, which is the
    call to action, so the Feedback link steps aside: it is still in the
    footer, in its own section, and at /feedback.
  */
  .nav-in { gap: var(--w-space-sm); }
  .nav-cta { padding-inline: var(--w-space-lg); font-size: 1rem; }
  .nav-link:not(.nav-cta) { display: none; }
}

/* Appearance toggle. The app has one in Settings; the web keeps the promise. */
.theme-toggle {
  width: 44px; height: 44px; display: inline-grid; place-items: center;
  border: 1px solid var(--w-border); border-radius: var(--w-radius-pill);
  background: transparent; color: var(--w-text-secondary); cursor: pointer;
  transition: color var(--w-duration-tap) var(--w-ease-standard),
              border-color var(--w-duration-tap) var(--w-ease-standard);
}
.theme-toggle:hover { color: var(--w-text); border-color: var(--w-border-strong); }
.theme-toggle svg { width: 18px; height: 18px; }

/* ------------------------------------------------------------------- hero */

.hero { padding-block: clamp(48px, 7vw, 96px) clamp(56px, 8vw, 112px); }
.hero-grid {
  display: grid; gap: clamp(40px, 6vw, 72px);
  grid-template-columns: 1fr;
  align-items: center;
}
@media (min-width: 900px) {
  .hero-grid { grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr); }
}
.hero-actions {
  display: flex; flex-wrap: wrap; gap: var(--w-space-md); align-items: center;
}

/* --------------------------------------------------------------- devices */
/* A phone is hardware, not a card, so it keeps the real 1/9 corner radius
   and a single hairline. No shadow, no reflection, no floating angle. */

.phone {
  position: relative;
  border-radius: 11.1%/5.1%;
  border: 1px solid var(--w-border);
  overflow: hidden;
  background: var(--w-bg-raised);
  width: 100%;
}
.phone img { width: 100%; height: auto; display: block; }

.hero-phones {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(12px, 2.4vw, 26px);
  align-items: start;
  max-width: 520px;
  margin-inline: auto;
}
.hero-phones .phone:last-child { margin-top: clamp(20px, 4vw, 44px); }

/* --------------------------------------------------------- wellbeing scale */
/* The only place on this page the scale appears. Ordered, unlabelled and
   never a number, exactly as in the app. */

.scale { display: flex; gap: clamp(8px, 1.4vw, 14px); max-width: var(--w-measure); }
.scale i {
  flex: 1 1 0; height: clamp(56px, 9vw, 76px);
  border-radius: var(--w-radius-input);
  display: block;
}
.scale i:nth-child(1) { background: var(--w-well-heavy); }
.scale i:nth-child(2) { background: var(--w-well-low); }
.scale i:nth-child(3) { background: var(--w-well-okay); }
.scale i:nth-child(4) { background: var(--w-well-good); }
.scale i:nth-child(5) { background: var(--w-well-great); }

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

.steps {
  display: grid; gap: clamp(28px, 4vw, 44px);
  grid-template-columns: 1fr;
  counter-reset: step;
}
@media (min-width: 760px) { .steps { grid-template-columns: repeat(3, 1fr); } }
.step { display: flex; flex-direction: column; gap: var(--w-space-md); }
.step .label::before { counter-increment: step; content: counter(step, decimal-leading-zero) ' \00a0 '; color: var(--w-accent); }

/* ---------------------------------------------------------------- gallery */

.gallery {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(224px, 260px);
  gap: clamp(14px, 2vw, 24px);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  padding-block-end: var(--w-space-lg);
  /* Bleed to the viewport edge so the rail reads as a rail on a phone. */
  margin-inline: calc(var(--w-gutter) * -1);
  padding-inline: var(--w-gutter);
  scrollbar-width: thin;
  scrollbar-color: var(--w-border-strong) transparent;
}
.gallery > figure { scroll-snap-align: start; margin: 0; display: flex; flex-direction: column; gap: var(--w-space-md); }
.gallery figcaption { color: var(--w-text-secondary); }

/* ------------------------------------------------------------------ never */

.never { display: grid; gap: var(--w-space-xl); }
@media (min-width: 760px) { .never { grid-template-columns: repeat(3, 1fr); gap: var(--w-space-2xl); } }
.never > div { display: flex; flex-direction: column; gap: var(--w-space-sm); padding-top: var(--w-space-lg); border-top: 1px solid var(--w-border); }

/* ------------------------------------------------------------------ forms */

.field { display: flex; flex-direction: column; gap: var(--w-space-sm); }
.field > .label { color: var(--w-text-tertiary); }

.well {
  width: 100%;
  background: var(--w-bg-raised);
  border: 1px solid transparent;
  border-radius: var(--w-radius-input);
  color: var(--w-text);
  font-family: var(--w-font-sans);
  font-size: 1.0625rem;         /* >=16px so iOS never zooms the page */
  line-height: 1.5;
  padding: 15px var(--w-space-lg);
  min-height: 54px;
  transition: border-color var(--w-duration-tap) var(--w-ease-standard);
  -webkit-appearance: none; appearance: none;
}
.well::placeholder { color: var(--w-text-tertiary); }
.well:focus { border-color: var(--w-accent); outline: none; }
.well:focus-visible { outline: 2px solid var(--w-accent); outline-offset: 2px; }
textarea.well { min-height: 132px; resize: vertical; }
.well[aria-invalid='true'] { border-color: var(--w-well-heavy); }

.check {
  display: flex; gap: var(--w-space-md); align-items: flex-start;
  cursor: pointer; padding-block: var(--w-space-sm);
}
.check input {
  flex: none; width: 24px; height: 24px; margin: 1px 0 0;
  accent-color: var(--w-accent);
  cursor: pointer;
}
.check span { font-size: 0.9375rem; color: var(--w-text-secondary); }

.hint { font-size: 0.875rem; color: var(--w-text-tertiary); }

.err {
  font-size: 0.875rem; color: var(--w-well-heavy);
  display: flex; gap: 6px; align-items: baseline;
}
.err::before { content: '—'; opacity: 0.7; }

/* A form's own status line. Lives in the flow so nothing shifts. */
.formnote {
  border-radius: var(--w-radius-input);
  padding: var(--w-space-lg);
  background: var(--w-bg-raised);
  font-size: 0.9375rem; color: var(--w-text);
}
.formnote[data-tone='bad'] { color: var(--w-well-heavy); }

/* ------------------------------------------------------------------ sheet */
/* Radius 28, the app's sheet. Bottom sheet on a phone, centred on a desktop. */

dialog.sheet {
  border: 0; padding: 0; background: transparent;
  max-width: 100%; max-height: 100%;
  width: 100%; height: 100%;
  overflow: visible;
  color: var(--w-text);
}
dialog.sheet::backdrop { background: rgba(0, 0, 0, 0.5); }

.sheet-in {
  position: fixed; inset-inline: 0; bottom: 0;
  max-height: min(92dvh, 860px);
  overflow-y: auto; overscroll-behavior: contain;
  background: var(--w-bg);
  border-top: 1px solid var(--w-border);
  border-radius: var(--w-radius-sheet) var(--w-radius-sheet) 0 0;
  padding: var(--w-space-xl) var(--w-gutter) max(var(--w-space-2xl), env(safe-area-inset-bottom));
  animation: sheet-up var(--w-duration-settle) var(--w-ease-standard);
}
@media (min-width: 720px) {
  .sheet-in {
    position: relative; inset: auto;
    width: min(560px, 100%); margin: 6vh auto;
    border: 1px solid var(--w-border);
    border-radius: var(--w-radius-sheet);
    padding: var(--w-space-2xl);
    animation-name: sheet-in;
  }
}
@keyframes sheet-up { from { transform: translateY(24px); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes sheet-in { from { opacity: 0; } to { opacity: 1; } }

.sheet-head { display: flex; align-items: flex-start; gap: var(--w-space-lg); }
.sheet-head .title { flex: 1; }
.iconbtn {
  flex: none; width: 44px; height: 44px;
  display: inline-grid; place-items: center;
  border: 0; border-radius: var(--w-radius-pill);
  background: transparent; color: var(--w-text-secondary); cursor: pointer;
  transition: color var(--w-duration-tap) var(--w-ease-standard);
}
.iconbtn:hover { color: var(--w-text); }
.iconbtn svg { width: 20px; height: 20px; }

/* ----------------------------------------------------------------- footer */

footer { padding-block: clamp(48px, 6vw, 72px); border-top: 1px solid var(--w-border); }
.foot { display: flex; flex-wrap: wrap; gap: var(--w-space-xl) var(--w-space-2xl); justify-content: space-between; align-items: flex-start; }
.foot-links { display: flex; flex-wrap: wrap; gap: 0 var(--w-space-xl); }
.foot-links a, .foot-links button {
  display: inline-flex; align-items: center; min-height: var(--w-tap);
  color: var(--w-text-secondary); font-size: 0.9375rem;
  background: none; border: 0; padding: 0; font-family: inherit; cursor: pointer;
  text-decoration: none;
}
.foot-links a:hover, .foot-links button:hover { color: var(--w-text); }

/* ------------------------------------------------------------------ motion */
/* Text and phones arriving on scroll. One curve. Reduce Motion -> fades. */

.rise { opacity: 0; transform: translateY(14px); }
.rise[data-in='true'] {
  opacity: 1; transform: none;
  transition:
    opacity   var(--w-duration-settle) var(--w-ease-standard),
    transform var(--w-duration-settle) var(--w-ease-standard);
}
@media (prefers-reduced-motion: reduce) {
  .rise { opacity: 1; transform: none; }
  .rise[data-in='true'] { transition: opacity var(--w-duration-transition) linear; }
  .sheet-in { animation: none; }
  .pill:active { transform: none; }
  *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; }
}

/* The mark draws once, left to right, the way a wave travels. No bounce. */
@keyframes draw { from { stroke-dashoffset: 800; } to { stroke-dashoffset: 0; } }
.mark-draw path {
  stroke-dasharray: 800;
  animation: draw 900ms var(--w-ease-standard) both;
}
@media (prefers-reduced-motion: reduce) {
  .mark-draw path { animation: none; stroke-dashoffset: 0; }
}

/* ---------------------------------------------------------------- content */
/* The privacy and support pages: long-form, one column, same system. */

.prose { max-width: var(--w-measure); }
.prose h2 { margin-top: var(--w-space-3xl); }
.prose h3 { margin-top: var(--w-space-2xl); }
.prose p { margin-top: var(--w-space-md); }
.prose ul { margin: var(--w-space-md) 0 0; padding-inline-start: 1.25em; color: var(--w-text-secondary); }
.prose li { margin-top: var(--w-space-sm); }
.prose strong { color: var(--w-text); font-weight: 700; }

/* ------------------------------------------------------------ additions */

/* Off-screen but reachable by a screen reader when it needs to be, and by a
   bot always, which is the point of the honeypot. */
.offscreen {
  position: absolute; left: -9999px;
  width: 1px; height: 1px; overflow: hidden;
}

/* The chip is a real radio in a real fieldset, so arrow keys work and the
   group announces itself. The input is hidden, never removed. */
.chip input { position: absolute; opacity: 0; width: 1px; height: 1px; pointer-events: none; }
.chip:has(input:focus-visible) { outline: 2px solid var(--w-accent); outline-offset: 3px; }

.chip-field { border: 0; padding: 0; margin: 0; min-inline-size: 0; }
.chip-field legend { padding: 0; }
.chip-field .chip-row { margin-top: var(--w-space-sm); }

.sheet-body { margin-top: var(--w-space-xl); }

/* ------------------------------------------------------------ wide layout */
/*
  A 34rem column inside a 1120px page leaves half a desktop empty, and four
  sections in a row doing it reads as an unfinished layout rather than as
  restraint. Above 980px those sections become two columns: the eyebrow and
  the question on the left, what answers it on the right. One rule, no new
  decoration, and it collapses back to a single column on a phone where the
  narrow measure is correct.
*/
@media (min-width: 980px) {
  .split {
    display: grid;
    grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
    gap: clamp(40px, 5vw, 88px);
    align-items: start;
  }
  .split > .split-head { max-width: 24rem; }
  .split > .split-body { max-width: 36rem; }
}

/* A paragraph directly under a card's eyebrow. */
.card-body { margin-top: var(--w-space-md); }
