/* Hallmark · macrostructure: App shell (one column) · tone: atmospheric · anchor hue: 182 · seed: core */
/* dash.aisf.dev · brand source: www.aisf.dev commit 932326bf53f845268f2453f60854d0d509ed8ed3, read with
   `git show 932326b:site/styles.css`; nothing here comes from a working tree. The ported rules (ground and
   bloom, masthead, wordmark, .cta and .cta--quiet, .textlink, focus, .skip, type, the early-access .field
   family, the sending spinner, .done, .colophon, reduced motion) carry www's declarations at that commit.
   dash-only additions are marked "dash:". tokens.css is copied verbatim from the same commit and never
   edited here; every colour, including --rule, --rule-strong and --danger, comes from it. */

:root {
  /* dash: names for values www's styles.css already uses */
  --radius-surface: 0.875rem;
  --target: 2.75rem; /* 44px: the floor for every control */
  --column: 42rem;   /* the signed-in column (www's hero copy width) */
}

/* ---------- ported: reset and ground ---------- */

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

/* dash: .cta and friends set display, which would otherwise beat the hidden attribute */
[hidden] {
  display: none !important;
}

html {
  overflow-x: clip;
  background-color: var(--paper);
  color-scheme: dark;
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  /* dash: a column, so the colophon sits at the foot of a short page */
  display: flex;
  flex-direction: column;
  margin: 0;
  overflow-x: clip;
  min-block-size: 100svh;
  background-color: var(--paper);
  /* JS-off / no-WebGL ground: one fixed bloom where the object would be */
  background-image: radial-gradient(55% 42% at 70% 40%, var(--bloom), var(--scrim-soft) 72%);
  background-attachment: fixed;
  color: var(--ink-soft);
  font-family: var(--font-body);
  font-size: var(--step-body);
  font-weight: 380;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* ---------- ported: masthead (N9 edge-aligned) ---------- */

/* dash: in the flow. www fixes its masthead (position: fixed, a ::before scrim, pointer-events) because its
   copy scrolls over the WebGL object; dash has no object, and a fixed bar would cover the first lines of a
   short page at 320px. The box itself (flex, gap, safe-area padding, gutter) is www's. */
.masthead {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-m);
  padding-block: max(var(--space-m), env(safe-area-inset-top)) var(--space-m);
  padding-inline: var(--gutter);
}

.wordmark {
  /* dash: the 44px target */
  display: inline-flex;
  align-items: center;
  min-block-size: var(--target);
  min-inline-size: var(--target);
  font-family: var(--font-display);
  font-size: var(--step-lede);
  font-stretch: 75%;
  font-weight: 820;
  line-height: 1;
  letter-spacing: 0.02em;
  color: var(--ink);
  text-decoration: none;
  white-space: nowrap;
}

.wordmark:hover {
  color: var(--accent);
}

.wordmark:active {
  color: var(--ink-soft);
}

/* dash: the account, who is signed in, and the way out */
.account {
  display: flex;
  align-items: center;
  gap: var(--space-m);
  min-inline-size: 0;
  margin: 0;
}

.account__name {
  min-inline-size: 0;
  max-inline-size: 20ch;
  overflow: hidden;
  font-size: var(--step-small);
  color: var(--ink-muted);
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* phones: the greeting already names the account */
@media (max-width: 29.99rem) {
  .account__name {
    display: none;
  }
}

/* dash: the Account link, visible at every width (below 30rem the name is hidden, so a name-only link
   would strand phones). The board's visual layer owns its final styling. */
.nav__link {
  display: inline-flex;
  align-items: center;
  min-block-size: var(--target);
  color: var(--ink-soft);
  font-size: var(--step-small);
  text-decoration: none;
}

.nav__link:hover,
.nav__link[aria-current="page"] {
  color: var(--ink);
}

/* ---------- ported: actions ---------- */

.cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-block-size: 2.75rem;
  margin: 0; /* dash: button reset (www's .signup__main .cta carries border: 0 and cursor: pointer) */
  padding-inline: var(--space-l);
  border: 0;
  border-radius: var(--radius-pill);
  background-color: var(--accent);
  color: var(--accent-ink);
  font-family: var(--font-display);
  font-size: var(--step-body);
  font-stretch: 100%;
  font-weight: 650;
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition:
    background-color var(--dur-micro) var(--ease-out),
    transform var(--dur-micro) var(--ease-out);
}

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

.cta:active {
  transform: translateY(1px);
}

.cta[aria-disabled="true"] {
  opacity: 0.55;
  cursor: not-allowed;
}

/* sending: the label says so and the button holds still. dash marks a ceremony in flight aria-busy +
   aria-disabled + data-state=loading, never disabled, so the button keeps keyboard focus; this rule comes
   after the aria-disabled one, so a loading button shows as loading */
.cta:disabled,
.cta[data-state="loading"] {
  opacity: 0.7;
  cursor: progress;
  transform: none;
}

.cta[data-state="loading"]::before {
  content: "";
  inline-size: 0.875rem;
  block-size: 0.875rem;
  margin-inline-end: var(--space-xs);
  border: 2px solid currentColor;
  border-inline-end-color: transparent;
  border-radius: 50%;
  animation: spin 800ms linear infinite;
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

/* www's quiet pill. dash: no min-block-size of its own, so it keeps .cta's 44px floor (www sets 2.5rem) */
.cta--quiet {
  padding-inline: var(--space-m);
  background-color: var(--scrim);
  color: var(--ink);
  box-shadow: inset 0 0 0 1px var(--accent);
  transition:
    background-color var(--dur-micro) var(--ease-out),
    transform var(--dur-micro) var(--ease-out),
    opacity var(--dur-short) var(--ease-out),
    visibility 0s linear 0s;
}

.cta--quiet:hover {
  background-color: var(--paper-2);
}

/* dash: on a raised row, which is already paper-2, the quiet pill's hover sinks to paper instead */
.passkey .cta--quiet:hover {
  background-color: var(--paper);
}

/* dash: a pill that is not available keeps its resting colour under the pointer */
.cta[aria-disabled="true"]:hover {
  background-color: var(--accent);
}

.cta--quiet[aria-disabled="true"]:hover {
  background-color: var(--scrim);
}

/* dash: the quiet pill, ringed in the danger hue, for remove */
.cta--danger {
  box-shadow: inset 0 0 0 1px var(--danger);
}

.textlink {
  color: var(--ink);
  font-weight: 560;
  line-height: 1;
  text-decoration-line: underline;
  text-decoration-thickness: 1px;
  text-decoration-color: var(--ink-muted);
  text-underline-offset: 0.3em;
  white-space: nowrap;
  transition: text-decoration-color var(--dur-micro) var(--ease-out);
}

.textlink:hover {
  text-decoration-color: var(--accent);
}

.textlink:active {
  color: var(--ink-soft);
}

/* dash: a link on its own line gets the 44px target; one inside a sentence stays inline */
.textlink--alone {
  display: inline-flex;
  align-items: center;
  min-block-size: var(--target);
}

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

.skip {
  position: fixed;
  inset-block-start: var(--space-s);
  inset-inline-start: var(--space-s);
  z-index: var(--z-skip);
  padding: var(--space-xs) var(--space-m);
  border-radius: var(--radius-pill);
  background-color: var(--paper-2);
  color: var(--ink);
  text-decoration: none;
  transform: translateY(-300%);
}

/* dash: the skip link gets the 44px target every other control has (www's measures 43px) */
.skip {
  display: inline-flex;
  align-items: center;
  min-block-size: var(--target);
}

.skip:focus-visible {
  transform: none;
}

/* visually hidden, still read: "Remove" + the passkey's name */
.vh {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ---------- dash: page frames ---------- */

main {
  flex: 1 0 auto;
  padding-inline: var(--gutter);
  padding-block: var(--space-2xl) var(--space-3xl);
}

/* signed in: act one's register, a left column with the bloom beside it */
.page {
  display: grid;
  gap: var(--space-xl);
  max-inline-size: var(--column);
}

/* signed out (sign-in, sign-up, 404): the hero's register, centred */
.page--centred {
  max-inline-size: var(--measure);
  margin-inline: auto;
}

.page--centred .page__head {
  text-align: center;
}

.page--centred .lede {
  margin-inline: auto;
  max-inline-size: 40ch;
}

.page--centred .actions {
  justify-content: center;
}

/* dash: the 404 takes www's hero copy width (its .chapter--hero .copy), so the headline sets on one
   line as it does there */
.page--hero {
  max-inline-size: 64rem;
}

@media (min-width: 60rem) {
  .page--hero {
    max-inline-size: min(76rem, 100%);
  }
}

/* the one ceremony on a signed-out page spans the column, and its label may wrap: at 320px "Create account
   with a passkey" is wider than the column */
.page--centred .form .cta {
  inline-size: 100%;
  padding-block: var(--space-xs);
  line-height: 1.2;
  text-align: center;
  white-space: normal;
  text-wrap: balance;
}

.page > *,
.form > *,
.section > * {
  min-inline-size: 0;
}

/* www's copy rhythm: .copy > * + * { margin-block-start: var(--space-l) } */
.page__head {
  display: grid;
  gap: var(--space-l);
}

.page__head > * {
  margin: 0;
}

.page__foot {
  margin: 0;
  text-align: center;
  color: var(--ink-muted);
}

@media (min-width: 60rem) {
  main {
    padding-block-start: var(--space-3xl);
  }
}

/* ---------- ported: type ---------- */

.display {
  margin: 0;
  min-inline-size: 0;
  font-family: var(--font-display);
  font-size: var(--step-display);
  font-stretch: 84%;
  font-weight: 780;
  line-height: 0.98;
  letter-spacing: -0.02em;
  color: var(--ink);
  overflow-wrap: anywhere;
  text-wrap: balance;
}

.title {
  margin: 0;
  min-inline-size: 0;
  font-family: var(--font-display);
  font-size: var(--step-title);
  font-stretch: 86%;
  font-weight: 720;
  line-height: 1.02;
  letter-spacing: -0.015em;
  color: var(--ink);
  overflow-wrap: anywhere;
  text-wrap: balance;
}

/* dash: a heading that takes focus when a page swaps state (the sign-up link page), so screen
   readers start there. It is no tab stop and nothing to act on, so it shows no ring. */
.title[tabindex="-1"]:focus {
  outline: none;
}

.lede {
  font-size: var(--step-lede);
  line-height: 1.5;
  color: var(--ink-soft);
  text-wrap: pretty; /* dash: www sets this on .copy p, the box its ledes sit in; dash has no .copy */
}

/* dash: a section heading, in www's .signup-done__title setting */
.heading {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--step-sub);
  font-stretch: 88%;
  font-weight: 700;
  line-height: 1.1;
  color: var(--ink);
  text-wrap: balance;
}

.section {
  display: grid;
  gap: var(--space-m);
}

.section > * {
  margin: 0;
}

/* ---------- ported: www's early-access .field family, same names and values ---------- */

/* dash: the form around the fields and the ceremony (www's is .signup) */
.form {
  display: grid;
  gap: var(--space-l);
  margin: 0;
}

.field {
  display: grid;
  gap: var(--space-xs);
  min-inline-size: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

.field__label {
  padding: 0;
  font-family: var(--font-display);
  font-size: var(--step-body);
  font-stretch: 100%;
  font-weight: 600;
  line-height: 1.3;
  color: var(--ink);
}

.field__input {
  inline-size: 100%;
  min-block-size: 3rem;
  margin: 0; /* dash: input reset */
  padding: var(--space-s) var(--space-m);
  border: 1px solid var(--rule);
  border-radius: 0.75rem;
  background-color: var(--paper-2);
  color: var(--ink);
  font: inherit;
  line-height: 1.4;
  transition: border-color var(--dur-micro) var(--ease-out), background-color var(--dur-micro) var(--ease-out);
}

@media (hover: hover) {
  .field__input:hover {
    border-color: var(--rule-strong);
  }
}

/* focus shows at once, never eased in: the ring is the shared one, the edge goes to the accent */
.field__input:focus-visible {
  border-color: var(--accent);
  outline-offset: 2px;
  transition: none;
}

.field__input:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

.field__input[aria-invalid="true"] {
  border-color: var(--danger);
}

/* help or error under the field, in the same place; it always holds a line, so an error never moves
   the fields below it */
.field__msg {
  min-block-size: 1lh;
  margin: 0;
  font-size: var(--step-small);
  line-height: 1.45;
  color: var(--ink-muted);
}

.field__msg.is-error,
.status.status--error {
  color: var(--danger);
}

.field__msg.is-error::before,
.status.status--error::before {
  content: "! ";
  font-weight: 700;
}

/* ---------- ported: ceremony outcome lines (www's .signup__status) ---------- */

.status {
  margin: 0;
  font-size: var(--step-small);
  line-height: 1.45;
  color: var(--ink-soft);
}

.page--centred .status {
  text-align: center;
}

/* a ceremony: its button, then two live regions (role=status, role=alert). The regions are in the page
   from load and are never hidden (MDN: establish a live region before updating it; one that is display:
   none until it fills may never be established), so they carry no box: an empty one is zero high, and the
   line inside one brings its own space */
.ceremony {
  display: block;
}

.ceremony .status {
  margin-block-start: var(--space-s);
}

/* ---------- done: www's .signup-done panel, for the outcome of an action ---------- */

.done {
  max-inline-size: 36rem;
  margin: 0; /* dash: the panel is a <p> */
  padding: var(--space-l);
  border: 1px solid var(--accent);
  border-radius: 0.875rem;
  background-color: var(--paper-2);
  color: var(--ink); /* dash: www's panel holds a title in ink; dash's holds one line */
}

.done:focus {
  outline: none;
}

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

/* dash: the panel is focused on load (for screen readers), which matches :focus-visible after a
   navigation; the outline then stands in for the border instead of ringing it twice */
.done:focus-visible {
  border-color: transparent;
}

/* ---------- dash: passkeys, each row on www's .scenario surface ---------- */

.passkeys {
  display: grid;
  gap: var(--space-s);
  margin: 0;
  padding: 0;
  list-style: none;
}

.passkey {
  display: grid;
  gap: var(--space-m);
  padding: var(--space-m) var(--space-l);
  border-radius: var(--radius-surface);
  background-color: var(--paper-2);
}

@media (max-width: 23.99rem) {
  .passkey {
    padding-inline: var(--space-m);
  }
}

@media (min-width: 40rem) {
  .passkey {
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
  }
}

.passkey__main {
  display: grid;
  gap: var(--space-2xs);
  min-inline-size: 0;
}

/* the name, then its tags: the tags sit beside the h3, not in it, so the heading's name is the passkey's */
.passkey__title {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs) var(--space-s);
  align-items: baseline;
  min-inline-size: 0;
}

.passkey__tags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs) var(--space-s);
  margin: 0;
}

.passkey__name {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--step-body);
  font-stretch: 90%;
  font-weight: 700;
  line-height: 1.3;
  color: var(--ink);
  overflow-wrap: anywhere;
}

.passkey__meta,
.passkey__note {
  margin: 0;
  font-size: var(--step-small);
  color: var(--ink-muted);
}

.passkey__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-s);
  align-items: center;
  margin: 0;
}

/* a quiet outlined tag: the words carry the meaning, never colour alone */
.tag {
  display: inline-flex;
  align-items: center;
  padding: 0.125rem var(--space-xs);
  border-radius: var(--radius-pill);
  box-shadow: inset 0 0 0 1px var(--rule);
  font-family: var(--font-body);
  font-size: var(--step-small);
  font-stretch: 100%;
  font-weight: 460;
  line-height: 1.3;
  color: var(--ink-soft);
  white-space: nowrap;
}

.tag--current {
  box-shadow: inset 0 0 0 1px var(--accent);
  color: var(--ink);
}

/* ---------- ported: actions row ---------- */

.actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-m) var(--space-xl);
  margin: 0; /* dash: a <p> or <form> */
}

/* ---------- ported: footer (Ft2: one quiet line) ---------- */

.colophon {
  position: relative;
  z-index: var(--z-content);
  padding-block: var(--space-2xl) max(var(--space-xl), env(safe-area-inset-bottom));
  padding-inline: var(--gutter);
}

.colophon__meta {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--space-xs) var(--space-l);
  margin: 0;
  color: var(--ink-muted);
}

/* ---------- ported: reduced motion ---------- */

@media (prefers-reduced-motion: reduce) {
  /* transitions are 0s, not a token 1ms: every property transitions by default, so even 1ms would
     set something easing on its own */
  *,
  *::before,
  *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0s !important;
    scroll-behavior: auto !important;
  }

  .cta:active {
    transform: none;
  }

  /* the sending spinner holds still; the label already says what is happening */
  .cta[data-state="loading"]::before {
    animation: none;
  }
}
