/* The portal's entire stylesheet. No build step, no framework, one file.
 *
 * Colours are chosen for contrast first: body text and link text both clear
 * WCAG AA against their backgrounds, and the focus ring is a colour that
 * appears nowhere else, so "where am I?" is answerable at a glance.
 */

/* Contrast against --paper, in the ratio WCAG measures; AA wants 4.5:1 for
 * body text and 3:1 for the focus ring. --edge is border, never text. */
:root {
  --ink: #16191d;          /* 17.6:1 */
  --ink-quiet: #4a5158;    /*  8.1:1 */
  --paper: #ffffff;
  --link: #0b5cad;         /*  6.7:1 */
  --danger: #a3231b;       /*  7.5:1 */
  --edge: #d4d8dd;
  --focus: #b8500a;        /*  5.0:1 */
  --masthead: #14213d;     /* --paper on it is 16.0:1 */
  --wash: #f2f5f8;
  --wash-blue: #e4edf6;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font: 1rem/1.55 system-ui, -apple-system, "Segoe UI", sans-serif;
}

/* Off-screen until focused, then the first thing on the page. */
.skip-link {
  position: absolute;
  left: -100vw;
  top: 0;
  padding: 0.5rem 1rem;
  background: var(--paper);
  color: var(--link);
}

.skip-link:focus {
  left: 0;
  z-index: 1;
}

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

/* main is focusable so the skip link actually moves the keyboard, but it is
   not interactive, so it gets no ring of its own. */
main:focus {
  outline: none;
}

a {
  color: var(--link);
}

.masthead {
  display: flex;
  align-items: center;
  padding: 0.75rem 1.5rem;
  background: var(--masthead);
}

.masthead__brand {
  color: var(--paper);
  font-weight: 600;
  text-decoration: none;
}

.masthead__nav {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  margin-left: auto;
}

.masthead__nav a {
  color: var(--paper);
  font-size: 0.9375rem;
  font-weight: 600;
  text-decoration: none;
}

.masthead__nav form {
  margin: 0;
}

.link-button {
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--paper);
  cursor: pointer;
  font: inherit;
  font-size: 0.9375rem;
  font-weight: 600;
}

.masthead :focus-visible {
  outline-color: #f2aa61;
}

main {
  max-width: 44rem;
  margin: 0 auto;
  padding: 2rem 1.5rem;
}

.colophon {
  max-width: 44rem;
  margin: 0 auto;
  padding: 1rem 1.5rem 2rem;
  border-top: 1px solid var(--edge);
  color: var(--ink-quiet);
  font-size: 0.875rem;
}

/* The public landing page extends the same type, colour and focus system as
   the portal while using the wider canvas a product introduction needs. */

.page--landing main,
.page--landing .colophon {
  max-width: 72rem;
}

.landing-page h1,
.landing-page h2,
.landing-page h3,
.landing-page p {
  margin-top: 0;
}

.landing-page h1 {
  max-width: 14ch;
  margin-bottom: 1.25rem;
  font-size: clamp(2.5rem, 7vw, 4.75rem);
  line-height: 1.02;
  letter-spacing: -0.045em;
}

.landing-page h2 {
  margin-bottom: 1rem;
  font-size: clamp(1.75rem, 4vw, 2.75rem);
  line-height: 1.12;
  letter-spacing: -0.025em;
}

.landing-page h3 {
  margin-bottom: 0.5rem;
  font-size: 1.125rem;
}

.eyebrow {
  margin-bottom: 0.75rem;
  color: var(--link);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.hero {
  display: grid;
  grid-template-columns: minmax(0, 1.45fr) minmax(16rem, 0.55fr);
  gap: clamp(2rem, 6vw, 5rem);
  align-items: center;
  min-height: min(42rem, calc(100vh - 9rem));
  padding: 4rem 0 5rem;
}

.hero__lead {
  max-width: 40rem;
  margin-bottom: 1.75rem;
  color: var(--ink-quiet);
  font-size: clamp(1.125rem, 2.2vw, 1.375rem);
}

.hero__note {
  margin: 1rem 0 0;
  color: var(--ink-quiet);
  font-size: 0.875rem;
}

.button-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
}

.button {
  display: inline-flex;
  min-height: 2.75rem;
  box-sizing: border-box;
  align-items: center;
  justify-content: center;
  padding: 0.625rem 1rem;
  border: 2px solid var(--link);
  border-radius: 4px;
  font-weight: 700;
  line-height: 1.25;
  text-decoration: none;
}

.button--primary {
  background: var(--link);
  color: var(--paper);
}

.button--secondary {
  background: var(--paper);
  color: var(--link);
}

.button--wide {
  width: 100%;
}

.hero__facts {
  padding: 0.5rem 1.5rem;
  border-left: 1px solid var(--edge);
}

.fact-list {
  margin: 0;
}

.fact-list div {
  padding: 1.25rem 0;
}

.fact-list div + div {
  border-top: 1px solid var(--edge);
}

.fact-list dt {
  margin-bottom: 0.25rem;
  font-weight: 700;
}

.fact-list dd {
  margin: 0;
  color: var(--ink-quiet);
}

.landing-section {
  padding: 5rem 0;
  border-top: 1px solid var(--edge);
}

.section-heading {
  max-width: 46rem;
  margin-bottom: 2.5rem;
}

.section-heading--split {
  display: grid;
  max-width: none;
  grid-template-columns: minmax(0, 1fr) minmax(16rem, 0.55fr);
  gap: 3rem;
  align-items: end;
}

.section-heading--split > p {
  color: var(--ink-quiet);
}

.feature-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1rem;
}

.feature {
  padding: 1.5rem;
  background: var(--wash);
}

.feature p:last-child {
  margin-bottom: 0;
  color: var(--ink-quiet);
}

.feature__number {
  margin-bottom: 2.5rem;
  color: var(--link);
  font-size: 0.75rem;
  font-weight: 700;
}

.pricing-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1rem;
}

.plan {
  display: flex;
  min-height: 29rem;
  flex-direction: column;
  justify-content: space-between;
  padding: clamp(1.5rem, 4vw, 2.5rem);
  border: 1px solid var(--edge);
}

.plan--featured {
  border-top: 5px solid var(--masthead);
  background: var(--wash-blue);
}

.plan__name {
  margin-bottom: 1rem;
  font-weight: 700;
}

.plan__price {
  margin-bottom: 1rem;
  color: var(--ink-quiet);
}

.plan__price span {
  color: var(--ink);
  font-size: clamp(2.5rem, 5vw, 3.75rem);
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.04em;
}

.check-list {
  margin: 2rem 0;
  padding: 0;
  list-style: none;
}

.check-list li {
  padding: 0.6rem 0 0.6rem 1.5rem;
  border-top: 1px solid rgb(22 25 29 / 15%);
}

.check-list li::before {
  display: inline-block;
  width: 1.5rem;
  margin-left: -1.5rem;
  color: var(--link);
  content: "✓";
}

.pricing__addons {
  max-width: 52rem;
  margin: 1.5rem 0 0;
  color: var(--ink-quiet);
  font-size: 0.9375rem;
}

.upstream {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(16rem, 0.55fr);
  gap: 3rem;
  align-items: center;
  margin-bottom: 4rem;
  padding: clamp(2rem, 6vw, 4rem);
  background: var(--masthead);
  color: var(--paper);
}

.upstream .eyebrow {
  color: #a9d5ff;
}

.upstream p:last-child {
  margin-bottom: 0;
  color: #d8e1ec;
}

@media (max-width: 44rem) {
  .masthead {
    flex-wrap: wrap;
    gap: 0.75rem 1.25rem;
  }

  .masthead__nav {
    width: 100%;
    gap: 1rem;
    margin-left: 0;
    overflow-x: auto;
  }

  .page--landing main {
    padding-top: 0;
  }

  .hero {
    min-height: 0;
    grid-template-columns: 1fr;
    gap: 2.5rem;
    padding: 3rem 0 4rem;
  }

  .hero__facts {
    padding: 0;
    border-top: 1px solid var(--edge);
    border-left: 0;
  }

  .landing-section {
    padding: 4rem 0;
  }

  .section-heading--split,
  .feature-grid,
  .pricing-grid,
  .upstream {
    grid-template-columns: 1fr;
  }

  .section-heading--split,
  .upstream {
    gap: 1rem;
  }

  .plan {
    min-height: 0;
  }
}

/* What happened on the page before this one, announced at the top of this one.
   A left border rather than a filled panel, so the text keeps the body colour
   and its contrast, and so nothing depends on colour alone to be understood. */

.notices {
  margin: 0 0 1.5rem;
  padding: 0;
  list-style: none;
}

.notice {
  padding: 0.5rem 0.75rem;
  border-left: 4px solid var(--ink-quiet);
  background: #f4f6f8;
}

.notice + .notice {
  margin-top: 0.5rem;
}

.notice--error,
.notice--warning {
  border-left-color: var(--danger);
}

/* Form fields, as rendered by {% field %}. */

.field {
  margin-bottom: 1.25rem;
}

.field label,
.field legend {
  display: block;
  font-weight: 600;
  margin-bottom: 0.25rem;
}

.field__group {
  border: 0;
  margin: 0;
  padding: 0;
}

.field__hint {
  margin: 0 0 0.35rem;
  color: var(--ink-quiet);
  font-size: 0.875rem;
}

.field input,
.field select,
.field textarea {
  width: 100%;
  box-sizing: border-box;
  padding: 0.5rem;
  border: 1px solid var(--edge);
  border-radius: 4px;
  font: inherit;
  color: inherit;
  background: var(--paper);
}

.field input[type="checkbox"],
.field input[type="radio"] {
  width: auto;
  margin-right: 0.4rem;
}

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

.field--invalid input,
.field--invalid select,
.field--invalid textarea {
  border-color: var(--danger);
}

/* Django's own class name for the error list it renders. */
.errorlist {
  margin: 0 0 0.35rem;
  padding: 0;
  list-style: none;
  color: var(--danger);
  font-size: 0.875rem;
}

/* Authenticated portal pages. Components stay intentionally plain: their
   state and actions need to read before their decoration does. */

.page-heading,
.card__heading,
.card__actions {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
}

.page-heading {
  margin-bottom: 2rem;
}

.page-heading h1,
.card__heading h2 {
  margin: 0;
}

.card-list {
  display: grid;
  gap: 1.25rem;
}

.card,
.empty-state,
.choice,
.callout {
  padding: 1.25rem;
  border: 1px solid var(--edge);
  border-radius: 4px;
}

.card__actions {
  justify-content: flex-start;
  margin-top: 1.25rem;
}

.status {
  display: inline-block;
  margin: 0.25rem 0 0;
  color: var(--ink-quiet);
  font-size: 0.875rem;
  font-weight: 700;
  text-transform: uppercase;
}

.status--active {
  color: #27620d;
}

.status--failed,
.status--suspended {
  color: var(--danger);
}

/* Subscription states (PRD M9.1), kept apart from the instance lifecycle above
   even where the two share a word. Colour follows what the customer has to do
   about it, not the name: past-due and suspended both need a card updating, a
   trial and an active subscription need nothing, and a cancelled subscription
   is only a fact about the past — so it keeps the muted default deliberately
   rather than by having no rule. */
.status--subscription-trialing,
.status--subscription-active {
  color: #27620d;
}

.status--subscription-past-due,
.status--subscription-suspended {
  color: var(--danger);
}

.details {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1rem;
  margin: 1.25rem 0;
}

.details dt {
  color: var(--ink-quiet);
  font-size: 0.875rem;
}

.details dd {
  margin: 0.2rem 0 0;
  overflow-wrap: anywhere;
}

progress {
  width: 100%;
  height: 0.75rem;
}

.quiet {
  color: var(--ink-quiet);
  font-size: 0.875rem;
}

.callout {
  border-left: 5px solid var(--link);
  background: var(--wash);
}

.callout--danger,
.danger-zone {
  border-left-color: var(--danger);
}

.danger-zone {
  margin-top: 2.5rem;
  padding-left: 1.25rem;
  border-left-style: solid;
  border-left-width: 5px;
}

.button--danger {
  border-color: var(--danger);
  background: var(--danger);
  color: var(--paper);
}

.choice {
  margin-bottom: 1rem;
}

.choice--disabled,
button:disabled {
  opacity: 0.65;
}

.progress-bar {
  overflow: hidden;
  height: 0.75rem;
  border-radius: 999px;
  background: var(--edge);
}

.progress-bar span {
  display: block;
  height: 100%;
  background: var(--link);
}

.steps {
  padding-left: 1.5rem;
}

.step--done::marker,
.availability--yes {
  color: #27620d;
}

.availability--no {
  color: var(--danger);
}

table {
  width: 100%;
  border-collapse: collapse;
}

th,
td {
  padding: 0.75rem;
  border-bottom: 1px solid var(--edge);
  text-align: left;
}

code {
  overflow-wrap: anywhere;
}

/* An instance's published SSH host keys, one per line: they are compared by eye
   against a fingerprint, and two of them run together read as one. */
.host-keys {
  list-style: none;
  margin: 0;
  padding: 0;
}

.host-keys li + li {
  margin-top: 0.4rem;
}

@media (max-width: 44rem) {
  .page-heading,
  .card__heading,
  .details {
    display: block;
  }

  .page-heading .button,
  .details div + div {
    margin-top: 1rem;
  }

  table {
    display: block;
    overflow-x: auto;
  }
}

/* Published documents: the terms, the privacy pages, the Impressum. They keep
   the portal's ordinary 44rem measure, because that width was chosen for
   reading and these are the longest things the portal serves. What they add is
   the rhythm long prose needs and the browser's defaults do not give it. */

.legal h2 {
  margin: 2.5rem 0 0.75rem;
  font-size: 1.25rem;
  line-height: 1.3;
}

.legal p,
.legal li {
  max-width: 38rem;
}

.legal li + li {
  margin-top: 0.5rem;
}

.legal table {
  margin: 1.25rem 0;
}

.legal__crumb,
.legal__meta {
  color: var(--ink-quiet);
  font-size: 0.875rem;
}

.legal__meta {
  margin-top: -0.5rem;
}

/* A list of documents: a linked title and a sentence saying what it is for.
   Not .details, which is a two-column grid built for an instance's short
   facts and turns a sentence into a column an inch wide. */
.doc-list {
  display: grid;
  gap: 1rem;
  margin: 1.25rem 0;
}

.doc-list dt {
  font-weight: 600;
}

.doc-list dd {
  margin: 0.15rem 0 0;
  color: var(--ink-quiet);
}

.provider {
  margin-bottom: 0.25rem;
}

.provider__address {
  font-style: normal;
}

.colophon__nav {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.25rem;
  margin-top: 0.5rem;
}

/* Printing is how somebody keeps a copy of the agreement they signed up under,
   so the chrome that is navigation on screen and noise on paper comes off, and
   link targets are printed after the text that linked to them — a reference to
   "the subprocessor page" is unusable on paper without its address. */
@media print {
  .masthead,
  .colophon__nav,
  .legal__crumb,
  .skip-link {
    display: none;
  }

  main {
    max-width: none;
    padding: 0;
  }

  .legal a[href^="http"]::after,
  .legal a[href^="/"]::after {
    content: " (" attr(href) ")";
    font-size: 0.8em;
    word-break: break-all;
  }

  .callout {
    border-left: 3px solid #000;
  }
}
