/*
 * The dashboard's stylesheet.
 *
 * This is an accessibility company's own product surface, so it is held to the
 * standard the company sells: real focus indicators, contrast that passes at
 * AA, nothing that depends on colour alone, nothing that moves unless the
 * visitor allows motion, and a layout that survives 200% zoom and 320px.
 *
 * No framework and no build step, matching the rest of the repository. The
 * widget is hand-written vanilla; a dashboard that needed a toolchain to render
 * a list of three sites would be the tail wagging the dog.
 */

@font-face {
  font-family: 'Inter';
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  src: url('/app/inter-400.woff2') format('woff2');
}
@font-face {
  font-family: 'Inter';
  font-weight: 600;
  font-style: normal;
  font-display: swap;
  src: url('/app/inter-600.woff2') format('woff2');
}

/*
 * The palette, shared with harboraccessibility.com.
 *
 * These are the marketing site's tokens
 * (`brand/site/src/styles/tokens.css` in the other repository), value for
 * value. They have to be: a visitor signs up on that site and lands here
 * thirty seconds later, and until now the two were a shade apart on every
 * surface - close enough to look like a mistake rather than a decision.
 *
 * The site calls the scheme "Daylight". It is light-first, and the teal moved
 * a shade when it stopped being asked to sit on navy: #12726B was tuned to
 * glow on a dark ground, and this one is tuned to read as ink on white.
 *
 * Every pair below is measured against the surface named, not eyeballed.
 */
:root {
  --harbour: #0f6b62;
  --harbour-ink: #0b544d; /* the teal, darkened enough to pass AA. 8.8:1 on paper */
  --shallow: #63d8c6;     /* the teal on dark. 9.6:1 on --deep */
  --ink: #12242c;         /* 16.0:1 on paper */
  --soft: #516670;        /* 6.0:1 on paper, 5.6:1 on raised */
  --line: #dde5e8;        /* hairlines between rows. Decorative - see --line-strong */
  --paper: #ffffff;
  --raised: #f3f7f8;
  --deep: #0e2b33;
  --danger: #a3261b;      /* 7.4:1 on paper */

  /* Harbour one step deeper, for the hover state of a filled button. Same hue,
     so a hover reads as pressure rather than as a different control. */
  --harbour-deep: #08423d;

  /* The boundary of a control - the edge of a text field, a checkbox, anything
     a person operates. SC 1.4.11 wants 3:1 against what is behind it and
     --line is 1.3:1, which is right for a hairline between two rows and wrong
     for the edge of an input. This is 4.2:1 on paper. The inputs on this page
     were drawn with --line until 2026-08-19, which is the exact non-text
     contrast failure this company reports against its clients. */
  --line-strong: #67808a;

  --radius: 10px;
}

@media (prefers-color-scheme: dark) {
  :root {
    --harbour: #63d8c6;
    --harbour-ink: #63d8c6;
    --ink: #eaf3f4;       /* 13.6:1 on paper, 11.3:1 on raised */
    --soft: #9db4ba;      /* 6.9:1 on paper, 5.7:1 on raised */
    --line: #23414a;
    --paper: #10262c;
    --raised: #17333a;
    --danger: #ff9b8f;
    --harbour-deep: #92e8db;
    --line-strong: #6a858e; /* 4.0:1 on paper, 3.4:1 on raised */
  }
}

* { box-sizing: border-box; }

html { color-scheme: light dark; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font: 16px/1.6 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  -webkit-font-smoothing: antialiased;
}

/*
 * A skip link that is genuinely reachable: off-screen until focused, never
 * `display:none`, which would take it out of the tab order entirely.
 */
.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--paper);
  color: var(--ink);
  padding: 12px 18px;
  z-index: 10;
  border: 2px solid var(--harbour-ink);
  border-radius: 0 0 var(--radius) 0;
}
.skip:focus { left: 0; }

/* One focus style everywhere, and it is never removed. */
:focus-visible {
  outline: 3px solid var(--harbour-ink);
  outline-offset: 2px;
  border-radius: 3px;
}

a { color: var(--harbour-ink); }
code {
  font-family: ui-monospace, 'Cascadia Mono', Consolas, monospace;
  font-size: 0.92em;
  background: var(--raised);
  padding: 0.1em 0.35em;
  border-radius: 4px;
}

/* ---------------------------------------------------------------- chrome */

.bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  padding: 18px 24px;
  border-bottom: 1px solid var(--line);
}
.brand {
  display: flex;
  align-items: center;
  /*
   * 4px, not the 10 this started at, and the arithmetic is the point.
   *
   * `mark.svg` draws its ink to r = 0.42 of the box, so 8% of the width on each
   * side is empty by construction - 2.4px at 30px. The 'h' then adds its own
   * 1px left sidebearing. A 10px CSS gap was therefore 13.4px of visible space
   * against a 30px mark: 0.45 of mark height, where the brand lockup in
   * `brand/assets/lockup-simple.svg` sits at 0.21. More than double, which is
   * why it read as two things beside each other rather than one lockup.
   *
   * 4 + 2.4 + 1 = 7.4px, or 0.25 of mark height. Slightly looser than the
   * lockup on purpose: at 30px the mark's counter is small, and the arcs bulge
   * outward at the crossbar, so the optical space is less than the measurement
   * suggests.
   */
  gap: 4px;
  font-weight: 600;
  font-size: 20px;
  letter-spacing: -0.5px;
  color: var(--ink);
  text-decoration: none;
}
.brand img { display: block; }

main {
  max-width: 720px;
  margin: 0 auto;
  padding: 34px 24px 80px;
}

h1 { font-size: 27px; font-weight: 600; letter-spacing: -0.5px; margin: 0 0 8px; }
h2 { font-size: 18px; font-weight: 600; margin: 40px 0 12px; }
.lede { color: var(--soft); margin: 0 0 8px; }
.fine { color: var(--soft); font-size: 14px; margin-top: 28px; }
.empty { color: var(--soft); }

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

.field { margin: 18px 0; }
label { display: block; font-weight: 600; margin-bottom: 4px; }
.hint { color: var(--soft); font-size: 14px; margin: 0 0 8px; }

input {
  display: block;
  width: 100%;
  max-width: 420px;
  font: inherit;
  color: inherit;
  background: var(--paper);
  padding: 11px 13px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
}
input:focus { border-color: var(--harbour-ink); }

/* A checkbox and its label on one line, with the label doing the clicking.
   The input keeps its own dimensions rather than inheriting the text-field
   rule above, which would stretch it to the full width of the form. */
.field-check {
  display: flex;
  align-items: flex-start;
  gap: 10px;
}
.field-check input[type='checkbox'] {
  width: 18px;
  height: 18px;
  min-width: 18px;
  margin: 2px 0 0;
  padding: 0;
  accent-color: var(--harbour-ink);
}
.field-check label {
  font-weight: 400;
  color: var(--soft);
  line-height: 1.45;
  cursor: pointer;
}

/* The agreement line. Deliberately not --soft: it is the sentence that makes
   the contract binding, so it is read at the same weight as everything else. */
.consent {
  color: var(--ink);
}

/*
 * An invalid field is marked three ways - a red border, a message, and
 * aria-invalid - because colour alone is not a way to tell somebody something.
 */
input[aria-invalid='true'] { border-color: var(--danger); border-width: 2px; }

.error { color: var(--danger); font-size: 14px; margin: 6px 0 0; font-weight: 600; }

button {
  font: inherit;
  font-weight: 600;
  color: var(--paper);
  background: var(--harbour-ink);
  border: 1px solid transparent;
  padding: 11px 18px;
  border-radius: var(--radius);
  cursor: pointer;
}
button:hover { background: var(--harbour-deep); }
button[disabled] { opacity: 0.55; cursor: not-allowed; }

@media (prefers-color-scheme: dark) {
  button { color: var(--deep); }
}

button.link {
  background: none;
  color: var(--harbour-ink);
  border: none;
  padding: 6px 2px;
  text-decoration: underline;
  text-underline-offset: 3px;
}
button.link:hover { background: none; color: var(--ink); }

button.quiet {
  background: var(--paper);
  color: var(--ink);
  border-color: var(--line-strong);
  padding: 8px 13px;
  font-size: 14px;
}
button.quiet:hover { background: var(--raised); }

/* ----------------------------------------------------------------- sites */

.sites { list-style: none; margin: 0; padding: 0; }

.site {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 18px;
  margin-bottom: 14px;
  background: var(--raised);
}
.site h3 { margin: 0 0 2px; font-size: 16px; font-weight: 600; overflow-wrap: anywhere; }
.site .meta { color: var(--soft); font-size: 13.5px; margin: 0 0 12px; }

.snippet-label { font-weight: 600; font-size: 14px; display: block; margin-bottom: 6px; }

/*
 * The snippet is a read-only textarea rather than a <pre>: it is meant to be
 * selected and copied, and a textarea is focusable, selectable with the
 * keyboard, and announced as an editable region a screen reader can read in
 * full. `overflow-x:auto` keeps a long snippet from widening the page.
 */
.snippet {
  width: 100%;
  font-family: ui-monospace, 'Cascadia Mono', Consolas, monospace;
  font-size: 13px;
  line-height: 1.5;
  padding: 11px 12px;
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  background: var(--paper);
  color: var(--ink);
  resize: vertical;
  overflow-x: auto;
  white-space: pre;
}

.site-actions { display: flex; gap: 10px; align-items: center; margin-top: 10px; flex-wrap: wrap; }
.copied { color: var(--harbour-ink); font-size: 14px; font-weight: 600; }

/* --------------------------------------------------------------- notices */

.status { color: var(--soft); }
.status:empty { display: none; }

.notice {
  padding: 13px 15px;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  background: var(--raised);
  margin: 0 0 18px;
}
.notice.error { border-color: var(--danger); border-left-width: 4px; }
.notice.sent { border-color: var(--harbour-ink); border-left-width: 4px; }

/* --------------------------------------------------------------- account */

.account dl { display: grid; grid-template-columns: auto 1fr; gap: 6px 20px; margin: 0; }
.account dt { color: var(--soft); }
.account dd { margin: 0; overflow-wrap: anywhere; }

/* ------------------------------------------------------------- sign-in page */

body.centred { display: flex; min-height: 100vh; align-items: center; justify-content: center; }
.card { max-width: 460px; width: 100%; padding: 34px 24px 60px; }
.card-mark { display: block; margin-bottom: 18px; }

/* ------------------------------------------------- published documents */

/*
 * The Service Terms, generated from Markdown by `scripts/build-legal.mjs`, and
 * the front door. Both are long-form prose rather than a form, so the rules
 * here are about reading rather than operating.
 *
 * `main` is already 720px and 16px/1.6, which is inside the 80-character
 * measure WCAG 2.2 1.4.8 asks for at this size. Nothing below widens it.
 */
.doc h2 { margin-top: 44px; }
.doc h3 { font-size: 16px; font-weight: 600; margin: 28px 0 8px; }
.doc p { margin: 0 0 16px; }
.doc ul, .doc ol { margin: 0 0 16px; padding-left: 24px; }
.doc li { margin-bottom: 8px; }
.doc li > ul, .doc li > ol { margin-top: 8px; }

.doc-version { color: var(--soft); margin: 0 0 8px; }

/*
 * The section rules the Markdown emits between clauses. A default <hr> is a
 * 2px inset groove that renders differently in every engine; this is a
 * hairline that reads as a division rather than as a control.
 */
.doc hr {
  border: 0;
  border-top: 1px solid var(--line);
  margin: 40px 0;
}

.doc pre {
  background: var(--raised);
  border-radius: var(--radius);
  padding: 14px 16px;
  overflow-x: auto;
}
.doc pre code { background: none; padding: 0; }

/*
 * Tables. The document has none today and this is here for the day it grows
 * one, because the generator already emits the scroll container and the
 * `scope` attributes for it - an unstyled table appearing on a published
 * contract is not the moment to write this.
 */
.table-scroll { overflow-x: auto; margin: 0 0 16px; }
.doc table { border-collapse: collapse; width: 100%; }
.doc th, .doc td {
  border-bottom: 1px solid var(--line);
  padding: 10px 12px;
  text-align: left;
  vertical-align: top;
}
.doc th { font-weight: 600; }

/* -------------------------------------------------------------- motion */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    transition-duration: 0.001ms !important;
  }
}
