/* ============================================================================
   kontaks.io — all styles.
   Ember palette (kontaks-app/CLAUDE.md, D24, decided 2026-09-07). System font
   only: no display face, no webfont, no CDN. Dark-first, but both modes are
   normative — SPEC.md §14 requires the 4.5:1 text contrast floor to hold in
   each, so every token pairing below was measured rather than eyeballed.

   Measured 2026-09-08 with the sRGB relative-luminance formula (WCAG 2.1),
   floor 4.5:1 for text and 3:1 for controls:

     token pair                     dark    light
     text        on background      15.56   17.10
     text        on surface         14.75   18.24
     text        on raised          13.55   15.30
     text-2      on background       6.67    5.80
     text-2      on surface          6.32    6.18
     text-2      on raised           5.81    5.19
     brand-text  on background       6.56    5.75
     brand-text  on surface          6.21    6.13
     brand-text  on raised           5.71    5.14
     destructive on background       4.84    6.13
     destructive on surface          4.59    6.54
     destructive on raised           4.22*   5.48
     on-brand    on brand fill       4.95    4.95
     taupe       on background       2.55*   7.07
     taupe       on surface          2.42*   7.54

   Re-measured 2026-09-08 against every pairing this stylesheet actually
   produces; the numbers above reproduce exactly.

   * Three pairings sit under 4.5:1 and each is excluded by a rule rather than
     by luck:

     - destructive text on --c-raised, 4.22:1 in dark. Decided 2026-09-08:
       --c-destructive is never used as text on --c-raised. .card--warn
       therefore forces background: var(--c-surface), where it measures
       4.59:1, and is never combined with .card--raised. Exit condition: if
       --c-raised is ever darkened past #241C17 the pairing becomes usable
       again — re-measure before relying on it.
     - --c-taupe on either dark ground, 2.4-2.6:1. Per CLAUDE.md's D24 table,
       taupe is a BORDER token on dark and only a text tone on light. It is
       used in exactly one place in this file (.btn--ghost:hover border-color)
       and never as text in either mode. Do not introduce it as a text colour
       for dark; --c-text-2 is the secondary text token in both modes.

   Hairlines measure 1.3–1.5:1 against their grounds. That is deliberate and
   is not a §14 violation: they are decorative separators, never the sole
   indication of an interactive control. Every control on this site carries a
   text label at one of the passing pairings above.
   ============================================================================ */

/* ---------------------------------------------------------------- tokens */
/* Light is defined on bare :root so a colour is never defined only inside a
   media query. Dark is layered on top, guarded so an explicit light choice
   still wins if a data-theme attribute is ever introduced. */
:root {
  --c-brand: #AF5823;          /* identical in both modes — see CLAUDE.md */
  --c-brand-text: #9A4C1E;
  --c-on-brand: #FFFFFF;
  --c-taupe: #5E524B;
  --c-bg: #FBF7F2;
  --c-surface: #FFFFFF;
  --c-raised: #F2EAE0;
  --c-hairline: #E3D8CB;
  --c-text: #1A1410;
  --c-text-2: #6B5F56;
  --c-destructive: #B3261E;
  --c-shadow: rgba(26, 20, 16, 0.09);

  --space: 20px;
  --radius: 14px;
  --radius-lg: 20px;
  --measure: 34rem;            /* body-copy line length ceiling */
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",
          Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
  --font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --c-brand-text: #D4834E;
    --c-bg: #110E0B;
    --c-surface: #1A1410;
    --c-raised: #241C17;
    --c-hairline: #3A312B;
    --c-text: #EDE6DF;
    --c-text-2: #A2968C;
    --c-destructive: #D9534A;
    --c-shadow: rgba(0, 0, 0, 0.45);
  }
}

:root[data-theme="dark"] {
  --c-brand-text: #D4834E;
  --c-bg: #110E0B;
  --c-surface: #1A1410;
  --c-raised: #241C17;
  --c-hairline: #3A312B;
  --c-text: #EDE6DF;
  --c-text-2: #A2968C;
  --c-destructive: #D9534A;
  --c-shadow: rgba(0, 0, 0, 0.45);
}

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

/* The UA stylesheet hides [hidden] with `display: none`, which any component
   rule setting a display value silently beats — .btn's inline-flex, .stores'
   flex, .grid's grid. LOAD-BEARING: /d/'s Open-in-Kontaks button ships hidden
   and is unhidden by js/main.js only once its href carries the token, and
   without this rule .btn's inline-flex would render it regardless — showing a
   control with no href to anyone with JavaScript off. 2026-09-11. */
[hidden] { display: none !important; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--c-bg);
  color: var(--c-text);
  font-family: var(--font);
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

img, svg { max-width: 100%; height: auto; }

h1, h2, h3 { line-height: 1.2; letter-spacing: -0.02em; margin: 0 0 0.5em; }
h1 { font-size: clamp(2rem, 6vw, 3rem); font-weight: 700; }
h2 { font-size: clamp(1.4rem, 4vw, 1.9rem); font-weight: 700; }
h3 { font-size: 1.1rem; font-weight: 600; }
p  { margin: 0 0 1em; max-width: var(--measure); }

a { color: var(--c-brand-text); text-decoration: underline; text-underline-offset: 2px; }
a:hover { text-decoration-thickness: 2px; }

:focus-visible {
  outline: 3px solid var(--c-brand-text);
  outline-offset: 2px;
  border-radius: 4px;
}

code, kbd, samp, pre { font-family: var(--font-mono); font-size: 0.9em; }

hr { border: 0; border-top: 1px solid var(--c-hairline); margin: 2.5rem 0; }

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

.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--c-brand); color: var(--c-on-brand);
  padding: 12px 18px; border-radius: 0 0 var(--radius) 0; text-decoration: none;
}
.skip-link:focus { left: 0; }

/* ---------------------------------------------------------------- layout */
.container {
  width: 100%;
  max-width: 60rem;
  margin: 0 auto;
  padding: 0 var(--space);
}

.container--narrow { max-width: 44rem; }

.section { padding: clamp(2.5rem, 8vw, 5rem) 0; }
.section + .section { border-top: 1px solid var(--c-hairline); }

/* ---------------------------------------------------------------- nav */
.nav {
  border-bottom: 1px solid var(--c-hairline);
  background: var(--c-bg);
}
.nav__inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; min-height: 64px;
}
.nav__brand {
  display: inline-flex; align-items: center; gap: 10px;
  color: var(--c-text); text-decoration: none; font-weight: 700; font-size: 1.15rem;
  letter-spacing: -0.02em;
}
.nav__brand img { width: 30px; height: 30px; border-radius: 8px; display: block; }
.nav__links { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }
.nav__links a { color: var(--c-text-2); text-decoration: none; font-size: 0.95rem; }
.nav__links a:hover, .nav__links a:focus-visible { color: var(--c-text); text-decoration: underline; }

/* ---------------------------------------------------------------- hero */
.hero { padding: clamp(2.5rem, 9vw, 5.5rem) 0 clamp(2rem, 6vw, 3.5rem); }
.hero h1 { max-width: 18ch; }
.hero__sub {
  font-size: clamp(1.05rem, 2.6vw, 1.3rem);
  color: var(--c-text-2);
  max-width: 40ch;
}
.hero__note { font-size: 0.85rem; color: var(--c-text-2); }
/* The /d/ page centres the line under its Open-in-Kontaks button, as the
   DeviceLink artboard does. A class rather than an inline style, so the
   page keeps passing html-validate's no-inline-style rule. 2026-09-11. */
.hero__note--centred { text-align: center; }

/* ---------------------------------------------------------------- buttons */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 48px; padding: 12px 22px;
  border-radius: var(--radius); border: 1px solid transparent;
  font: inherit; font-weight: 600; font-size: 1rem;
  text-decoration: none; cursor: pointer;
}
.btn--primary { background: var(--c-brand); color: var(--c-on-brand); }
.btn--primary:hover { filter: brightness(1.08); }
.btn--ghost {
  background: var(--c-surface); color: var(--c-text); border-color: var(--c-hairline);
}
.btn--ghost:hover { border-color: var(--c-taupe); }

/* ---------------------------------------------------------------- store badges */
.stores { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; margin: 1.5rem 0 0.75rem; }
.stores img { display: block; }
.store-badge { display: inline-block; text-decoration: none; line-height: 0; }
/* js/main.js puts platform-ios / platform-android / platform-desktop on <body>.
   The visitor's own store is ordered first; the other is never hidden, because
   the page is read by someone who may be about to install on a second phone. */
body.platform-android .store-badge--play { order: -1; }
body.platform-ios .store-badge--app-store { order: -1; }

/* ---------------------------------------------------------------- cards */
.card {
  background: var(--c-surface);
  border: 1px solid var(--c-hairline);
  border-radius: var(--radius);
  padding: 18px;
}
.card h3 { margin-bottom: 6px; }
.card p:last-child { margin-bottom: 0; }
.card p { color: var(--c-text-2); font-size: 0.95rem; }

.card--raised { background: var(--c-raised); }

/* Destructive text is only ever placed on --c-surface, never on --c-raised:
   the raised pairing measures 4.22:1 in dark mode and fails SPEC §14. */
.card--warn { border-color: var(--c-destructive); background: var(--c-surface); }
.card--warn h3 { color: var(--c-destructive); }

.grid { display: grid; gap: 14px; grid-template-columns: 1fr; }
@media (min-width: 42rem) { .grid--2 { grid-template-columns: 1fr 1fr; } }
@media (min-width: 56rem) { .grid--3 { grid-template-columns: repeat(3, 1fr); } }

.note {
  background: var(--c-raised);
  border: 1px solid var(--c-hairline);
  border-radius: var(--radius);
  padding: 14px 16px;
  font-size: 0.9rem;
  line-height: 1.55;
  color: var(--c-text-2);
}
.note p { margin: 0; max-width: none; }
.note p + p { margin-top: 0.6em; }

/* ---------------------------------------------------------------- steps */
/* Each step is a two-column grid, not a flex row. The <b> title and the <span>
   description are SIBLINGS in the markup, so as flex children they laid out
   side by side — the title wrapped mid-phrase with the description beside it
   instead of under it, which is not what design/landing/ shows. Grid puts both
   in column 2 on their own rows and spans the numbered marker down the side,
   which gets the artboard's layout with no wrapper element in every <li>.
   Found by screenshot and fixed 2026-09-08. */
.steps { list-style: none; margin: 0; padding: 0; display: grid; gap: 18px; counter-reset: step; }
.steps li {
  display: grid;
  grid-template-columns: 28px 1fr;
  gap: 3px 14px;
  align-items: start;
  counter-increment: step;
}
.steps li::before {
  content: counter(step);
  grid-column: 1; grid-row: 1 / span 2;
  width: 28px; height: 28px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 999px;
  background: var(--c-raised); border: 1px solid var(--c-hairline);
  color: var(--c-brand-text); font-weight: 700; font-size: 0.85rem;
}
.steps b { grid-column: 2; grid-row: 1; font-weight: 600; }
.steps span { grid-column: 2; grid-row: 2; color: var(--c-text-2); font-size: 0.95rem; max-width: var(--measure); }

/* ---------------------------------------------------------------- tables */
.table-scroll { overflow-x: auto; margin: 0 0 1.5rem; }
table {
  border-collapse: collapse;
  width: 100%;
  min-width: 34rem;
  font-size: 0.95rem;
}
th, td {
  text-align: left; vertical-align: top;
  padding: 10px 12px;
  border-bottom: 1px solid var(--c-hairline);
}
th { font-weight: 600; color: var(--c-text); }
td { color: var(--c-text-2); }
td:first-child, th:first-child { color: var(--c-text); }
thead th { border-bottom-width: 2px; }

/* ---------------------------------------------------------------- prose (legal, security) */
.prose { max-width: var(--measure); }
.prose h2 { margin-top: 2.5rem; }
.prose h3 { margin-top: 2rem; }
.prose h4 { margin-top: 1.6rem; margin-bottom: 0.4em; font-size: 1rem; font-weight: 600; }
.prose ul, .prose ol { padding-left: 1.3em; max-width: var(--measure); }
.prose li { margin-bottom: 0.5em; }
.prose blockquote {
  margin: 1.5rem 0; padding: 14px 18px;
  border-left: 3px solid var(--c-brand);
  background: var(--c-raised);
  border-radius: 0 var(--radius) var(--radius) 0;
  color: var(--c-text-2);
}
.prose blockquote p:last-child { margin-bottom: 0; }
.prose .table-scroll table { min-width: 30rem; }
.prose .table-scroll { max-width: 100%; }
/* Tables in §12 are wide; the scroller keeps them off the body's own axis so
   the page never scrolls horizontally on a phone. */

/* security.html is ~15 tables of two and three columns inside a 34rem measure,
   which squeezed every cell to two or three words per line. .prose--wide lets
   the BLOCK-level containers use the full 60rem container while paragraphs,
   lists and quotes keep the measure, so running text stays readable and the
   tables stop wrapping mid-phrase. Added 2026-09-08 after looking at the
   rendered page. */
.prose--wide { max-width: none; }
.prose--wide > p,
.prose--wide > ul,
.prose--wide > ol,
.prose--wide > blockquote { max-width: var(--measure); }

.lede { font-size: 1.1rem; color: var(--c-text-2); max-width: var(--measure); }
.meta { font-size: 0.85rem; color: var(--c-text-2); }

.toc { padding-left: 1.2em; }
.toc li { margin-bottom: 0.35em; }

/* ---------------------------------------------------------------- invite page */
.invite { min-height: 100vh; display: flex; flex-direction: column; }
.invite__body { flex: 1 0 auto; padding: clamp(1.75rem, 6vw, 3rem) 0; }
.invite__cta { display: grid; gap: 10px; margin: 1.5rem 0 0.5rem; }
.invite__pin {
  display: flex; gap: 12px; align-items: flex-start;
  background: var(--c-surface); border: 1px solid var(--c-hairline);
  border-radius: var(--radius); padding: 16px;
  margin: 1.5rem 0;
}
.invite__pin-dots {
  font-family: var(--font-mono); font-size: 1.3rem; letter-spacing: 0.3em;
  color: var(--c-text-2);
}
/* Body copy inside the PIN callout: one tone down, tight to its heading. A
   class rather than an inline style so the page passes html-validate's
   no-inline-style rule — inline styles would also need a CSP style-src
   'unsafe-inline' if a CSP is ever added. Added 2026-09-08. */
.invite__pin p { margin: 4px 0 0; color: var(--c-text-2); font-size: 0.95rem; }
.invite__pin h3 { margin-bottom: 0; }
.invite__pin .invite__pin-dots { margin: 10px 0 0; }

/* The one spacing utility on the site. Used where a .note or .grid follows
   flow content and needs air that its own rules do not give it. Deliberately
   singular: a utility system is a build step in disguise. */
.u-mt { margin-top: 1.25rem; }

.qr-card {
  display: inline-block;
  background: #FFFFFF;             /* a QR must be dark-on-light in both modes */
  border: 1px solid var(--c-hairline);
  border-radius: var(--radius-lg);
  padding: 16px;
}
.qr-card canvas, .qr-card svg, .qr-card img { display: block; }

/* ---------------------------------------------------------------- footer */
.footer {
  border-top: 1px solid var(--c-hairline);
  padding: 2rem 0 2.5rem;
  font-size: 0.9rem;
  color: var(--c-text-2);
}
.footer__links { display: flex; flex-wrap: wrap; gap: 8px 18px; margin-bottom: 1rem; }
.footer__links a { color: var(--c-text-2); }
.footer p { max-width: none; margin: 0; }
.footer__emergency { color: var(--c-text-2); margin-bottom: 0.5rem !important; }

/* ---------------------------------------------------------------- motion */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ---------------------------------------------------------------- print */
@media print {
  .nav, .footer__links, .skip-link { display: none; }
  body { background: #fff; color: #000; }
  .table-scroll { overflow: visible; }
}
