/* Layout only. Look and feel comes from the design system files; use their classes and tokens. */
.license-layout {
  display: grid;
  /* minmax(0, 1fr), never auto: an auto track grows to its widest child and the page scrolls sideways on phones. */
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-6);
  /* Both cards share a bottom edge. */
  align-items: stretch;
}

@media (min-width: 56rem) {
  .license-layout {
    grid-template-columns: minmax(0, 1fr) 20rem;
  }
}

[data-view] h1:focus {
  outline: none;
}

/* License: 32 px between the page header and the first card, as on the pages that sit in a stack. */
[data-view="license"] .page-header {
  margin-bottom: var(--space-8);
}

/* In the dashboard the view is a stack: its gap already sets the space under the header. */
.app-page [data-view="license"] .page-header {
  margin-bottom: 0;
}

/* A side card: no shadow and a sunken surface, so the card beside it reads as the main task. */
.card-quiet {
  background: var(--color-surface-sunken);
  box-shadow: none;
}

/* One card padding on a phone, whatever the page: 20 px. */
@media (max-width: 30rem) {
  .card {
    padding: var(--space-5);
  }
}

/* ---- dashboard page (public/app/): sign-up, log-in and Domains ---- */

/* Touch targets of 44 px on the dashboard; the shared controls are 40 px. */
.app-page .btn,
.app-page .input {
  min-height: 2.75rem;
}

.app-page .nav-link {
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
}

/* Long values (domains, DNS records, addresses, the token) wrap inside their box instead of widening the page. */
.wrap-any,
.domain-name,
.record-text,
.token {
  overflow-wrap: anywhere;
}

.auth-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-6);
  align-items: start;
}

@media (min-width: 56rem) {
  .auth-layout {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.token,
.record-text {
  display: block;
  min-width: 0;
  padding: var(--space-3) var(--space-4);
  background: var(--color-surface-sunken);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  user-select: all;
}

.token {
  font-size: var(--text-base);
  line-height: var(--leading-normal);
}

/* Input and its button side by side while there is room, stacked on a phone. */
.input-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
}

.input-row .input {
  flex: 1 1 14rem;
  width: auto;
  min-width: 0;
}

.input-row .btn {
  flex: 0 0 auto;
}

.copy-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}

.copy-row .record-text {
  flex: 1 1 14rem;
}

.domain-list {
  gap: var(--space-6);
}

.domain-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2) var(--space-4);
}

.domain-name:focus {
  outline: none;
}

.metrics-grid,
.domain-forms {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-6);
}

@media (min-width: 40rem) {
  .metrics-grid,
  .domain-forms {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.metrics-title {
  font-size: var(--text-base);
}

.metrics {
  margin: 0;
}

.metrics > div {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
  padding-block: var(--space-2);
  border-top: 1px solid var(--color-border);
  font-size: var(--text-sm);
}

.metrics dt {
  color: var(--color-text-muted);
}

.metrics dd {
  margin: 0;
  font-weight: var(--weight-semibold);
  font-variant-numeric: tabular-nums;
  text-align: right;
}

/* ---- header and page header, shared by every view ---- */

/* A heading (the H1 of a view, the H2 of the check result) and the sample-data pill sit on one line, 12 px apart. */
.page-title {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-1) var(--space-3);
}

/* A measure of 78ch, not 65ch: at 65ch three of the four subtitles still wrapped to a stranded ending; at 78ch they fit on one line. */
.app-page .page-header p {
  max-width: 78ch;
  text-wrap: pretty;
}

/* The auth slot is a button (Log out) or a link (Log in) that looks like the tabs. */
button.nav-link {
  border: 0;
  background: transparent;
  font-family: inherit;
  cursor: pointer;
}

.nav-auth {
  display: inline-flex;
}

.nav-auth .nav-link {
  white-space: nowrap;
}

@media (min-width: 40.0625rem) {
  /* The account action sits at the right end of the header, apart from the three pages. */
  .app-page .app-header .nav {
    flex: 1 1 auto;
  }

  .app-page .nav-auth {
    margin-left: auto;
    /* The button's own 12 px padding sits outside the label: pull it back so the label ends on the content edge. */
    margin-right: calc(var(--space-3) * -1);
  }
}

@media (max-width: 40rem) {
  /* 12 px above the brand, 8 px under the tabs, 4 px between the two rows; the tabs keep their 44 px. */
  .app-page .app-header-inner {
    min-height: 0;
    padding-block: var(--space-3) var(--space-2);
    row-gap: var(--space-1);
  }

  /* Brand and the account action share the top row, the four pages sit under it. The nav's children join the header grid
     (display: contents), so Log out can sit on the brand's row without leaving the nav in the markup. */
  .app-page .app-header-inner {
    display: grid;
    grid-template-columns: repeat(4, auto) minmax(0, 1fr);
    justify-content: start;
    column-gap: var(--space-1);
  }

  .app-page .app-header .nav {
    display: contents;
  }

  .app-page .brand {
    grid-area: 1 / 1 / 2 / 3;
  }

  /* The account action spans the last three columns, so Log in and Log out have room for one line whatever width the four tabs take. */
  .app-page .nav-auth {
    grid-area: 1 / 3 / 2 / 6;
    justify-self: end;
    margin-right: calc(var(--space-3) * -1);
  }

  .app-page .app-header .nav > .nav-link {
    grid-row: 2;
  }

  /* A header with no account action (Calculator, Check, Install, Pricing) has up to five links: its nav is one full-width row that
     wraps, not five grid cells squeezed into the four tab columns. */
  .app-page .app-header-inner:not(:has(.nav-auth)) .nav {
    display: flex;
    grid-area: 2 / 1 / 3 / -1;
  }

  /* The first label lines up with the 24 px page edge, not 12 px inside it. */
  .app-page .app-header .nav > .nav-link:first-of-type {
    margin-left: calc(var(--space-3) * -1);
  }
}

/* ---- Usage and Failures views ---- */

.usage-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2) var(--space-4);
}

/* One card-title style (--text-xl: the nearest token to 20 px) for every card on the page: the sign-up cards, the domain name, the usage cards and the failures count. */
.card-title,
.usage-title,
.domain-name {
  font-size: var(--text-xl);
  font-weight: var(--weight-semibold);
  line-height: var(--leading-snug);
}

.usage-period {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-1) var(--space-3);
}

.usage-shares {
  gap: var(--space-6);
}

.usage-domain {
  gap: var(--space-3);
}

.usage-domain-name {
  font-size: var(--text-base);
  overflow-wrap: anywhere;
}

.usage-row {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.usage-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-1) var(--space-4);
  font-size: var(--text-sm);
}

/* The label is regular and muted (text-muted); the figure is the number the reader came for: dark, semibold, aligned digits. */
.usage-label {
  font-weight: var(--weight-regular);
}

.usage-figure {
  color: var(--color-text);
  font-weight: var(--weight-semibold);
  font-variant-numeric: tabular-nums;
}

.usage-percent {
  font-weight: var(--weight-regular);
}

/* A native <progress>: the level (ok, high, full) is a data attribute, so no style is ever set from script. */
.usage-bar {
  appearance: none;
  display: block;
  width: 100%;
  height: 0.75rem;
  border: 0;
  border-radius: var(--radius-full);
  background: var(--color-surface-sunken);
  box-shadow: inset 0 0 0 1px var(--color-border);
  color: var(--color-accent);
  overflow: hidden;
}

/* Share bars are a lighter tint of the accent than the quota bars, so a share never reads as a used-up limit. */
.usage-bar-small {
  height: 0.5rem;
  color: color-mix(in srgb, var(--color-accent) 45%, transparent);
}

.usage-bar[data-level="high"] {
  color: var(--color-warn);
}

.usage-bar[data-level="full"] {
  color: var(--color-danger);
}

.usage-bar::-webkit-progress-bar {
  background: transparent;
}

.usage-bar::-webkit-progress-value {
  background: currentColor;
  border-radius: var(--radius-full);
}

.usage-bar::-moz-progress-bar {
  background: currentColor;
  border-radius: var(--radius-full);
}

/* Failures: one card. The wrapper has no padding, so the row dividers run edge to edge; the first and last cell and the heading
   take the card padding (--space-8), so the text lines up with the other cards. */
.app-page .table-wrap {
  padding: 0;
}

.table-head {
  padding: var(--space-8) var(--space-8) var(--space-2);
}

.table-head .card-title {
  margin: 0;
}

.failures-table {
  table-layout: fixed;
}

/* Fixed widths on the three short columns; the address takes the rest, so Reason sits close to it. */
.failures-table th:nth-child(2) {
  width: 12rem;
}

.failures-table th:nth-child(3) {
  width: 5rem;
}

.failures-table th:nth-child(4) {
  width: 10rem;
}

/* The narrow last column holds the Copy button. */
.failures-table th:nth-child(5) {
  width: 8rem;
}

.failures-table th:first-child,
.failures-table td:first-child {
  padding-left: var(--space-8);
}

.failures-table th:last-child,
.failures-table td:last-child {
  padding-right: var(--space-8);
}

.failures-table td {
  padding-block: var(--space-3);
  vertical-align: top;
  white-space: nowrap;
}

.failures-table td.cell-url {
  white-space: normal;
}

/* The address is clamped, never cut by the layout: the full text is in its title and behind the Copy button. */
.url-cell {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
}

.url-text {
  flex: 0 1 auto;
  min-width: 0;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
  overflow-wrap: break-word;
}

/* Copy is a button with an icon and its word, in its own column at every width. It is a 44 px target; the negative margin lets it
   hang above and below the 24 px first line, so a row is no taller than its address. */
.failures-table .url-copy {
  min-width: 2.75rem;
  min-height: 2.75rem;
  margin-block: calc(var(--space-5) / -2);
  padding: 0 var(--space-3);
}

.failures-table .url-copy svg {
  flex: 0 0 auto;
}

/* The last column is Copy: its header and button end on the card's content edge, like the heading's text starts on it. */
@media (min-width: 40.0625rem) {
  .failures-table th:last-child,
  .failures-table td:last-child {
    text-align: right;
  }
}

/* The column name is already in the table header; it is for screen readers on a phone only. */
.cell-label {
  display: none;
}

@media (max-width: 40rem) {
  /* A record is two lines: the address, then muted details such as 'Timed out · 1× · Oct 31, 03:27'. */
  .failures-table tbody tr {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    padding: var(--space-3) var(--space-8);
  }

  .failures-table td,
  .failures-table td:first-child,
  .failures-table td:last-child {
    display: block;
    width: auto;
    padding: 0;
    color: var(--color-text-muted);
    text-align: left;
  }

  .failures-table td::before {
    content: none;
  }

  /* The address leaves room on its right for the Copy button, which sits at the top right of the record. */
  .failures-table td.cell-url {
    flex: 1 0 100%;
    min-width: 0;
    margin-bottom: var(--space-2);
    padding-right: calc(var(--space-12) * 2);
    color: var(--color-text);
    font-size: var(--text-base);
  }

  .failures-table td.cell-copy {
    position: absolute;
    top: calc(var(--space-3) - 0.625rem);
    right: var(--space-8);
  }

  /* The cell itself hangs 10 px above the first line, so the button needs no hang of its own. */
  .failures-table .url-copy {
    margin-block: 0;
  }

  .failures-table td:nth-child(n + 3):not(.cell-copy)::before {
    content: "\00b7";
    margin-inline: var(--space-2);
  }

  .failures-table td.num::after {
    content: "\00d7";
  }

  .cell-label {
    display: inline;
  }

  /* The reason is the key fact of a record: dark and medium, while the count and the date stay muted. */
  .failures-table td:nth-child(2) {
    color: var(--color-text);
    font-weight: var(--weight-medium);
  }

  /* The host on its own muted line, the path under it; a word is only ever broken when it is wider than the row. */
  .url-text {
    flex: 1 1 auto;
    -webkit-line-clamp: 4;
    line-clamp: 4;
  }

  .url-origin {
    display: block;
  }
}

@media (max-width: 30rem) {
  /* The card's content inset is 20 px here, not 32, like every other card on a phone. The row dividers still run edge to edge. */
  .table-head {
    padding-inline: var(--space-5);
  }

  .failures-table tbody tr {
    padding-inline: var(--space-5);
  }

  .failures-table td.cell-copy {
    right: var(--space-5);
  }

  /* When every failed page is on one host, the card header names it once (a muted line under '200 failed pages') and each record shows only
     its path, in two lines at most. */
  .table-head [data-summary]::after {
    content: attr(data-host);
    display: block;
    color: var(--color-text-muted);
    font-size: var(--text-base);
    font-weight: var(--weight-regular);
  }

  [data-failures][data-single-host] .url-origin {
    display: none;
  }

  [data-failures][data-single-host] .url-text {
    -webkit-line-clamp: 2;
    line-clamp: 2;
  }
}

/* ---- install page (public/install/) ---- */

.install-page .values {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-4);
  margin: 0;
}

@media (min-width: 40rem) {
  .install-page .values {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-8);
  }
}

.value dt {
  font-weight: var(--weight-semibold);
  margin-bottom: var(--space-2);
}

.value dd {
  margin: 0;
  color: var(--color-text-muted);
}

.value dd + dd {
  margin-top: var(--space-3);
}

/* The helper under a heading has the same measure as the page lede, so a sentence of the page never ends alone on a second line. */
.app-page .section-lede {
  max-width: 78ch;
}

/* Inline code in a sentence (a header, a variable) never breaks inside its name. */
.install-page :not(pre) > code:not(.record-text) {
  max-width: 100%;
  white-space: nowrap;
}

/* The four setup buttons wrap while there is room; on a phone they are a 2 x 2 grid of equal buttons. A label never breaks inside its
   button. */
.switcher {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

@media (max-width: 30rem) {
  .switcher {
    display: grid;
    grid-template-columns: 1fr 1fr;
  }

  .switcher .btn {
    padding-inline: var(--space-2);
  }
}

.switcher .btn {
  white-space: nowrap;
  /* A 2 px edge on every option, so choosing one never moves the others; 1 px less padding keeps the width. */
  border-width: 2px;
  padding-inline: calc(var(--space-5) - 1px);
  color: var(--color-text-muted);
}

/* The chosen setup: the solid primary fill with its own text colour, so it is the one filled button of the four. On a phone a check
   mark joins it, at the left edge so the label keeps its width. */
.switcher .btn[aria-pressed="true"],
.switcher .btn[aria-pressed="true"]:hover:not(:disabled) {
  background: var(--color-primary);
  border-color: var(--color-primary);
  color: var(--color-on-primary);
  font-weight: var(--weight-semibold);
}

.switcher .btn[aria-pressed="true"]:hover:not(:disabled) {
  background: var(--color-primary-hover);
  border-color: var(--color-primary-hover);
}

@media (max-width: 30rem) {
  .switcher .btn {
    position: relative;
  }

  .switcher .btn[aria-pressed="true"]::before {
    content: "\2713";
    content: "\2713" / "";
    position: absolute;
    left: var(--space-2);
    font-size: var(--text-xs);
  }
}

.code-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

.code-head .btn {
  white-space: nowrap;
}

/* A snippet scrolls sideways inside its box; the page never does. */
.code-block {
  margin: 0;
  min-width: 0;
  max-width: 100%;
  padding: var(--space-4);
  overflow-x: auto;
  background: var(--color-surface-sunken);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
  tab-size: 2;
  /* A light fade on the right edge while there is more to scroll to; the cover (local) hides it at the end. */
  background:
    linear-gradient(to left, var(--color-surface-sunken), var(--color-surface-sunken)) 100% 0 / 1.5rem 100% no-repeat local,
    linear-gradient(to left, var(--color-border), transparent) 100% 0 / 1.5rem 100% no-repeat scroll,
    var(--color-surface-sunken);
}

/* A long snippet shows its first 16 lines (SNIPPET_LINES in install/model.js) until the button under it is pressed. The box is cut at
   a line: no bottom padding, or the top of the 17th line would show in it. */
.code-block[data-collapsed] {
  max-height: calc(16 * var(--text-sm) * var(--leading-normal) + var(--space-4) + 2px);
  padding-bottom: 0;
  overflow-y: hidden;
}

/* Only a phone has blocks wider than the box: the hint says so. */
.scroll-hint {
  display: none;
  margin-bottom: calc(var(--space-2) * -1);
}

@media (max-width: 40rem) {
  .scroll-hint {
    display: block;
  }
}

.code-block code {
  font-size: inherit;
}

/* ---- check page (public/check/) ---- */

/* The form is one card: address and crawler side by side while there is room, the button under them on a phone. */
.check-form {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-4);
  align-items: start;
}

.check-form .btn {
  white-space: nowrap;
}

/* The select is 44 px like the input and the button; the shared control is 40 px. */
.check-page .select {
  min-height: 2.75rem;
}

@media (min-width: 48rem) {
  .check-form {
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr) auto;
    /* The button lines up with the inputs, not with the hint under the address. */
    align-items: start;
  }

  .check-form .btn {
    margin-top: calc(var(--text-sm) * var(--leading-normal) + var(--space-2));
  }
}

@media (max-width: 30rem) {
  .check-form {
    padding: var(--space-5);
  }
}

.result-summary {
  font-size: var(--text-lg);
  max-width: 60ch;
  text-wrap: pretty;
}

#result-title:focus {
  outline: none;
}

/* Three columns: the measure and one number per view. The measure is plain text, not a small muted header, and may wrap;
   the numbers keep their width, so the table fits inside the card at 390 px. */
.app-page.check-page .table-wrap {
  padding: var(--space-3);
}

.check-table tbody th {
  padding: var(--space-4);
  color: var(--color-text);
  font-size: var(--text-sm);
  font-weight: var(--weight-regular);
  letter-spacing: normal;
  text-transform: none;
  white-space: normal;
  border-bottom: 0;
}

.check-table tbody tr + tr th {
  border-top: 1px solid var(--color-border);
}

.check-table td.num,
.check-table thead th.num {
  width: 6.5rem;
}

@media (max-width: 30rem) {
  .check-table th,
  .check-table td,
  .check-table tbody th {
    padding-inline: var(--space-3);
  }

  .check-table td.num,
  .check-table thead th.num {
    width: 5rem;
  }
}

.result-next {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3) var(--space-6);
}

.result-next p {
  flex: 1 1 18rem;
  max-width: 52ch;
}

.result-next .btn {
  white-space: nowrap;
}

/* ---- calculator page (public/calculator/) ---- */

/* One card: the volume field and the both-devices toggle side by side while there is room, stacked on a phone. */
.calc-form {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-6);
  align-items: start;
}

@media (min-width: 48rem) {
  .calc-form {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr);
  }
}

@media (max-width: 30rem) {
  .calc-form {
    padding: var(--space-5);
  }
}

/* The toggle is a 44 px target whose label starts level with 'Renders per month' beside it: the text sits at the top and the box on
   the first line of it, however many lines the label takes. */
.calc-toggle {
  align-items: flex-start;
  min-height: 2.75rem;
  font-weight: var(--weight-medium);
}

.calc-toggle input {
  margin-top: calc(var(--space-1) * 0.75);
}

/* The helper and the source line start under the label text, not under the box: the box's width plus the gap. */
.calc-toggle + .field-hint {
  padding-left: calc(1.125rem + var(--space-3));
}

/* The price tables are cards on a coloured surface with a border: the wrapper insets them, so no cell text sits against the
   border (the app pages' flush table card is for the failures list only). */
.app-page.calculator-page .table-wrap {
  padding: var(--space-3);
}

.calculator-page .field-hint {
  max-width: 60ch;
  text-wrap: pretty;
}

/* A printed source address and its read date. The address wraps anywhere, the date stays whole. */
.source {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 0 var(--space-3);
  overflow-wrap: anywhere;
}

.source-read {
  color: var(--color-text-muted);
  white-space: nowrap;
}

.source-cell {
  min-width: 0;
}

.source-line {
  display: block;
}

.source-line + .source-line {
  margin-top: var(--space-1);
}

.calculator-page .source a {
  color: var(--color-accent);
}

/* Four columns of words and one of money: the money keeps its width, the other three share the rest. */
.calc-result-table td.num,
.calc-result-table thead th.num {
  width: 9rem;
  white-space: nowrap;
}

/* The 9 rem above is for the table layout. On a phone the stacked row is a block, and the price cell takes the full row like the
   other cells (components.css: .table-stack td is width 100%, which the rule above would otherwise beat on specificity). */
@media (max-width: 40rem) {
  .calc-result-table td.num {
    width: 100%;
  }
}

.calc-result-table td:first-child {
  font-weight: var(--weight-medium);
}

/* ---- pricing page (public/pricing/) ---- */

/* The stacked table hides its header in a 1 px clipped box. Its cells keep table layout and stretch past the phone's width:
   make them blocks, so the hidden header takes no width. They stay on one line (nowrap): wrapped inside the 1 px box, each
   label would break into a line per word. */
@media (max-width: 40rem) {
  .table-stack thead th {
    display: block;
    white-space: nowrap;
  }
}

/* The plan table is one panel on a coloured surface, inset like the calculator's tables. */
.app-page.pricing-page .table-wrap {
  padding: var(--space-3);
}

.pricing-page .section-lede,
.pricing-page .pricing-note {
  max-width: 62ch;
  text-wrap: pretty;
}

/* The plan name and the price are the two cells a reader scans for. */
.pricing-table td:first-child,
.pricing-table td.num:nth-child(2) {
  font-weight: var(--weight-semibold);
}

/* The buy button and the legal links under it: a row while there is room, stacked on a phone. */
.pricing-buy {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-4) var(--space-6);
}

.pricing-links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-5);
  list-style: none;
  margin: 0;
  padding: 0;
}

.pricing-links a {
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
  color: var(--color-accent);
}

/* ---- status page (public/status/) ---- */

/* The three totals: a column on a phone, three across from 40rem. */
.status-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-6);
}

@media (min-width: 40rem) {
  .status-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

.status-page .status-note,
.status-window {
  max-width: 62ch;
  text-wrap: pretty;
}

.status-window {
  color: var(--color-text-muted);
  font-size: var(--text-sm);
}

/* ---- privacy and terms pages (public/privacy/, public/terms/) ---- */

/* One row per fact: the name beside the text from 40rem, stacked on a phone. A hairline separates the rows. */
.legal-facts {
  display: grid;
  gap: var(--space-5);
  margin: 0;
}

.legal-fact {
  display: grid;
  gap: var(--space-1);
  padding-top: var(--space-5);
  border-top: 1px solid var(--color-border);
}

.legal-fact dt {
  font-weight: var(--weight-semibold);
}

.legal-fact dd {
  margin: 0;
  max-width: 62ch;
  text-wrap: pretty;
}

@media (min-width: 40rem) {
  .legal-fact {
    grid-template-columns: 12rem minmax(0, 1fr);
    gap: var(--space-6);
  }
}

.legal-page .legal-note {
  max-width: 62ch;
  text-wrap: pretty;
}

.legal-page .legal-note a,
.legal-fact a {
  color: var(--color-accent);
}

.legal-links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-5);
  list-style: none;
  margin: 0;
  padding: 0;
}

.legal-links a {
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
  color: var(--color-accent);
}

/* ---- home page (public/index.html): a headline, the two-line settings diff, the sample, the fallback line, five links ---- */

.home-page .hero {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-6);
}

.home-page .hero h1 {
  max-width: 18ch;
  text-wrap: balance;
}

@media (min-width: 40rem) {
  .home-page .hero h1 {
    font-size: var(--text-3xl);
  }
}

.hero-lede {
  max-width: 56ch;
  font-size: var(--text-lg);
  line-height: var(--leading-normal);
  text-wrap: pretty;
}

.hero-link {
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
}

/* The settings diff: two changed lines on a sunken surface with a hairline edge, no shadow. */
.diff {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface-sunken);
  overflow: hidden;
}

.diff-line {
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
  margin: 0;
  padding: var(--space-3) var(--space-4);
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  background: var(--color-accent-subtle);
}

.diff-line + .diff-line {
  border-top: 1px solid var(--color-border);
}

.diff-mark {
  flex: none;
  color: var(--color-accent);
  font-weight: var(--weight-semibold);
}

.diff-line code {
  min-width: 0;
  overflow-wrap: anywhere;
}

.home-terms {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-4);
  margin: 0;
}

@media (min-width: 40rem) {
  .home-terms {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-8);
  }
}

.home-terms dt {
  font-weight: var(--weight-semibold);
  margin-bottom: var(--space-1);
}

.home-terms dd {
  margin: 0;
  color: var(--color-text-muted);
}

.home-terms code {
  overflow-wrap: anywhere;
}

/* With and without: two columns split by hairlines. The figure with RenderSwap carries the one accent. */
.compare {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  margin: 0;
}

@media (min-width: 40rem) {
  .compare {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.compare-col {
  padding: var(--space-5) 0;
  border-top: 1px solid var(--color-border);
}

@media (min-width: 40rem) {
  .compare-col + .compare-col {
    padding-left: var(--space-8);
    border-left: 1px solid var(--color-border);
  }
}

.compare-col dt {
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
}

.compare-col dd {
  margin: var(--space-1) 0 0;
}

.compare-figure {
  display: block;
  font-size: var(--text-3xl);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-display);
  line-height: var(--leading-tight);
  font-variant-numeric: tabular-nums;
}

.compare-col-with .compare-figure {
  color: var(--color-accent);
}

.fallback-line {
  max-width: 40ch;
  font-size: var(--text-xl);
  font-weight: var(--weight-medium);
  line-height: var(--leading-snug);
  letter-spacing: var(--tracking-heading);
  text-wrap: balance;
}

/* Five links, one row each, split by hairlines: the name on the left and what it does beside it, stacked on a phone. */
.home-links {
  list-style: none;
  margin: 0;
  padding: 0;
  border-bottom: 1px solid var(--color-border);
}

.home-links li {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--space-4) 0;
  border-top: 1px solid var(--color-border);
}

.home-links a {
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
  font-weight: var(--weight-semibold);
}

.home-links span {
  color: var(--color-text-muted);
}

@media (min-width: 40rem) {
  .home-links li {
    flex-direction: row;
    align-items: baseline;
    gap: var(--space-8);
  }

  .home-links a {
    flex: 0 0 11rem;
  }
}

/* Motion on a state change only: the ready or error block that replaces the loading one fades in over the state duration. Opacity
   alone, nothing is moved, and the first paint (the loading block) does not animate. */
.home-page [data-state="ready"]:not([hidden]),
.home-page [data-state="error"]:not([hidden]) {
  animation: home-state-in var(--dur-state) var(--ease);
}

@keyframes home-state-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .home-page [data-state="ready"]:not([hidden]),
  .home-page [data-state="error"]:not([hidden]) {
    animation: none;
  }
}

/* ---- site footer: the same links and owner line on every page, the dashboard included ---- */

.site-footer {
  border-top: 1px solid var(--color-border);
  padding-block: var(--space-4) var(--space-8);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

.site-footer-inner {
  display: grid;
  gap: var(--space-2);
}

/* The links wrap as a row; each is 44 px tall for a thumb and stays on one line. */
.site-footer-nav {
  display: flex;
  flex-wrap: wrap;
  column-gap: var(--space-6);
}

.site-footer-nav a {
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
  white-space: nowrap;
}

.site-footer-owner {
  max-width: 60ch;
}
