/* The card builder: the form on the left, the card in a phone on the right.
   Under 56rem the form shows, with the card's face in a strip that stays in sight (.b-peek);
   its button puts the whole preview in the form's place. */
.b-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  height: 4.25rem;
}

/* On a phone the mark stays and the name gives its place to the switches (still read aloud). */
@media (max-width: 33rem) {
  .b-top {
    gap: 0.5rem;
  }

  .b-top .brand {
    gap: 0;
    font-size: 0;
  }
}

.builder {
  display: grid;
  gap: 2rem;
  padding-bottom: max(3rem, env(safe-area-inset-bottom));
}

.builder[data-view="form"] .b-preview,
.builder[data-view="preview"] .b-form {
  display: none;
}

.b-preview {
  display: grid;
  place-items: center;
  gap: 0.75rem;
  padding: 1.5rem 0;
  border-radius: 2rem;
  background: var(--tint);
}

/* The way back from the whole preview, where it took the form's place: it floats at the bottom
   of the screen, over the phone, so it is in sight wherever the page is. */
#peek-close {
  position: sticky;
  bottom: max(1rem, env(safe-area-inset-bottom));
  box-shadow: var(--shadow);
}

@media (min-width: 56rem) {
  .builder {
    grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
    align-items: start;
    gap: 4rem;
  }

  .builder[data-view] .b-form,
  .builder[data-view] .b-preview {
    display: grid;
  }

  .b-preview {
    position: sticky;
    top: 1.5rem;
    padding: 2.5rem 0;
  }
}

/* Steps */
.b-form {
  display: grid;
  gap: 2rem;
  min-width: 0;
  max-width: 36rem;
}

.b-steps {
  display: flex;
  gap: 0.375rem;
  margin: 0;
  padding: 0;
  overflow-x: auto;
  list-style: none;
  scrollbar-width: none;
}

.b-steps button {
  min-height: 2.5rem;
  padding: 0 0.875rem;
  border: 0;
  border-radius: 999px;
  background: none;
  color: var(--muted);
  font: 600 0.9375rem/1 var(--sans);
  white-space: nowrap;
  cursor: pointer;
}

.b-steps button[aria-current] {
  background: var(--tint);
  color: var(--accent-text);
}

/* The strip: the card's face, small, under the steps of a narrow screen. It stays at the top of
   the screen while the page scrolls and while a keyboard is open, on the page's own colour so
   the fields pass under it. The card in it is drawn by renderCard like every card (card.css):
   only its layout is set here, a row in place of a column, and nothing but the photo, the name
   and the line under it. Its button, a round eye, lies over the right end of the card; a press
   anywhere on the strip does what the button does (builder.js). */
.b-peek {
  position: sticky;
  top: 0;
  z-index: 2;
  display: grid;
  align-items: center;
  margin-block: -1.25rem -1.125rem; /* nearer the steps and the title than the form's 2rem: the fields keep their place, or nearly */
  padding-block: 0.375rem;
  background: var(--bg);
  box-shadow: -0.5rem 0 var(--bg), 0.5rem 0 var(--bg); /* a field's focus ring is wider than the field */
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.b-peek > * {
  grid-area: 1 / 1;
  min-width: 0;
}

.b-peek .btn {
  z-index: 1;
  justify-self: end;
  margin-right: 0.5rem;
}

.b-peek .cv {
  display: block;
}

.b-peek .cv-face {
  grid-template-columns: auto minmax(0, 1fr);
  justify-items: stretch;
  align-content: center;
  column-gap: 0.75rem;
  min-height: 3.5rem;
  margin: 0;
  padding: 0.375rem 3.5rem 0.375rem 0.375rem; /* the right one: the button's room */
  border-radius: 1.75rem;
  outline: 1px solid var(--line); /* a card of the page's own colour still has an edge */
  outline-offset: -1px;
  text-align: start;
}

.b-peek:active .cv-face {
  filter: brightness(0.94); /* it can be pressed */
}

.b-peek .cv-avatar {
  grid-row: span 2;
  width: 2.75rem;
  border-width: 2px;
  box-shadow: none;
  font-size: 1rem;
}

.b-peek .cv-name,
.b-peek .cv-role {
  margin: 0;
  overflow: hidden;
  font-size: 1.0625rem;
  line-height: 1.25;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.b-peek .cv-role {
  font-size: 0.875rem;
}

.b-peek .cv-bio,
.b-peek .cv-actions,
.b-peek .cv-rows {
  display: none;
}

/* At the last step the strip says what it is, where the line under the name was: never a card
   taken for one that is online. The left margin is the photo's width and what is around it. */
.b-peek .state-pill {
  z-index: 1;
  align-self: end;
  justify-self: start;
  margin: 0 0 0.5rem 3.875rem;
  padding: 0.0625rem 0.5rem 0.0625rem 0.375rem;
  font-size: 0.75rem;
}

.b-peek.is-marked .cv-role {
  visibility: hidden;
}

/* A field the browser brings into sight (focus, a keyboard that opens) stops under the strip, not
   behind it: the strip's height and a small gap, no more, or the field ends under the keyboard.
   Nor does it stop at the very edge of a keyboard: some room stays under it.
   And the strip shows what the first step's sentence promises: the room goes to the fields. */
@media (max-width: 55.99rem) {
  html {
    scroll-padding-top: 4.75rem;
  }

  .b-form :is(.input, .slug input) {
    scroll-margin-bottom: 3rem;
  }

  .b-form section[data-step="0"] > .b-sub {
    display: none;
  }
}

/* A wide screen has the preview beside the form: no strip, and nothing to come back from.
   (After the rules above, which it must win over.) */
@media (min-width: 56rem) {
  .b-peek,
  #peek-close {
    display: none;
  }
}

.b-form section {
  display: grid;
  gap: 1.5rem;
}

.b-title {
  font-size: clamp(1.75rem, 2vw + 1rem, 2.5rem);
  font-weight: 700;
  line-height: 1.08;
  letter-spacing: -0.035em;
}

.b-sub {
  margin-top: -0.875rem;
  color: var(--muted);
  font-size: 1.0625rem;
  text-wrap: pretty;
}

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

.grid .wide {
  grid-column: 1 / -1;
}

.grid .error {
  margin-top: -0.5rem;
}

@media (max-width: 26rem) {
  .grid > * {
    grid-column: 1 / -1;
  }
}

textarea.input {
  resize: vertical;
}

/* Phone: a country, then the number typed the local way. The country list is the browser's own
   <select>, laid unseen over the flag and the calling code (like the language picker in base.css),
   so phones open their own list and the keyboard works. */
.tel {
  display: flex;
  gap: 0.5rem;
}

.tel .input {
  flex: 1;
  min-width: 0;
}

.tel-country {
  position: relative;
  display: flex;
  flex: none;
  align-items: center;
  gap: 0.5rem;
  padding: 0 0.75rem;
  border: 1.5px solid var(--line);
  border-radius: var(--r-input);
  background: var(--surface);
  font-weight: 600;
  white-space: nowrap;
}

/* A small arrow, so the flag reads as a list to open */
.tel-country::after {
  content: "";
  padding: 0.1875rem;
  border: solid var(--muted);
  border-width: 0 1.5px 1.5px 0;
  transform: translateY(-25%) rotate(45deg);
}

.tel-country select {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  font-size: 1rem; /* iPhones zoom the page on a field with smaller text */
  cursor: pointer;
}

.tel-country:hover {
  border-color: color-mix(in srgb, var(--ink) 35%, var(--line));
}

.tel-country:focus-within {
  border-color: var(--accent-text);
  outline: 2px solid var(--focus);
  outline-offset: 3px;
}

/* Windows has no flag emoji. This font draws the flags and nothing else (the range is the 26
   letters a flag is written with), so it is fetched only when a flag shows: on the Contact step. */
@font-face {
  font-family: "Twemoji Country Flags";
  src: url("fonts/TwemojiCountryFlags.woff2") format("woff2");
  unicode-range: U+1F1E6-1F1FF;
  font-display: swap;
}

.tel-country,
.tel-country select {
  font-family: "Twemoji Country Flags", var(--sans);
}

.check {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  margin-top: 0.875rem;
  font-weight: 500;
  cursor: pointer;
}

.check input {
  width: 1.25rem;
  height: 1.25rem;
  accent-color: var(--accent);
}

/* Photo: the round window shows exactly what the card will show */
.photo {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1.25rem;
}

.photo-view {
  display: grid;
  place-items: center;
  flex: none;
  width: 7.5rem;
  height: 7.5rem;
  overflow: hidden;
  border-radius: 50%;
  background: var(--tint);
  color: var(--accent-text);
}

.photo-view canvas,
.photo-view img {
  display: block;
  width: 100%;
  height: 100%;
}

.photo-view canvas {
  cursor: grab;
  touch-action: none;
}

.photo-view canvas:active {
  cursor: grabbing;
}

.photo-view .icon {
  width: 2rem;
  height: 2rem;
}

.photo-side {
  display: grid;
  flex: 1 1 12rem;
  gap: 0.5rem;
}

.photo-buttons {
  display: flex;
  align-items: center;
  gap: 1rem;
}

.photo-buttons input:focus-visible + label {
  outline: 2px solid var(--focus);
  outline-offset: 3px;
}

.photo-side .text-link {
  padding: 0;
  border: 0;
  background: none;
  font: 600 0.9375rem var(--sans);
  cursor: pointer;
}

.photo-side .label,
.photo-side .help,
.photo-side .error {
  margin: 0;
}

#zoom {
  width: min(100%, 14rem);
  accent-color: var(--accent);
}

.more-fields summary {
  width: fit-content;
  color: var(--accent-text);
  font-weight: 600;
  cursor: pointer;
}

.more-fields .help {
  margin: 0.75rem 0 1rem;
}

/* Style step */
.field-set {
  margin: 0;
  padding: 0;
  border: 0;
}

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

.swatch {
  position: relative;
  cursor: pointer;
}

.swatch span:first-of-type {
  display: block;
  width: 2.75rem;
  height: 2.75rem;
  border: 3px solid var(--bg);
  border-radius: 50%;
  outline: 1.5px solid var(--line);
  transition: transform 0.15s var(--ease);
}

/* The ninth swatch is the browser's own colour picker, laid unseen over its circle: a rainbow
   with a plus until a colour is picked there, then that colour (builder.js fills it). */
.swatch input[type="color"] {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  cursor: pointer;
}

.swatch input[type="color"] + span {
  background:
    linear-gradient(var(--ink), var(--ink)) center / 0.75rem 2px no-repeat,
    linear-gradient(var(--ink), var(--ink)) center / 2px 0.75rem no-repeat,
    radial-gradient(closest-side, var(--bg) 58%, transparent 60%),
    conic-gradient(red, yellow, lime, aqua, blue, magenta, red);
}

.swatch input:checked + span,
.swatch input[aria-current="true"] + span {
  outline: 2px solid var(--ink);
}

.swatch input:focus-visible + span {
  outline: 2px solid var(--focus);
  outline-offset: 3px;
}

.swatch:active span:first-of-type {
  transform: scale(0.94);
}

.slug {
  display: flex;
  align-items: center;
  min-height: 3rem;
  padding: 0 0.875rem;
  border: 1.5px solid var(--line);
  border-radius: var(--r-input);
  background: var(--surface);
}

.slug:focus-within {
  border-color: var(--accent-text);
}

.slug span {
  color: var(--muted);
  white-space: nowrap;
}

.slug input {
  flex: 1;
  width: 0; /* or the field's own default width keeps the row wider than a 320px phone */
  min-width: 0;
  height: 2.75rem;
  padding: 0;
  border: 0;
  outline: 0;
  background: none;
  color: var(--ink);
  font: 600 1rem var(--sans);
}

/* Panels: the account page's (account.css), and the row of small buttons of the last step */
.out {
  display: grid;
  justify-items: start;
  gap: 0.625rem;
  padding: 1.75rem;
  border: 1.5px solid var(--line);
  border-radius: var(--r-panel);
}

.out > p:not([class]) {
  color: var(--muted);
}

.out-url {
  max-width: 100%;
  padding: 0.375rem 0.75rem;
  overflow-wrap: anywhere;
  border-radius: 999px;
  background: var(--tint);
  color: var(--accent-text);
  font-weight: 600;
}

.out-buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 0.5rem;
}

/* A long label ("Enregistrer les modifications") goes on two lines on a narrow phone, where a
   button kept on one line would make the whole page wider than the screen */
.out .btn {
  padding-block: 0.5rem;
  line-height: 1.2;
  white-space: normal;
}

/* The sign-in form in a panel (the account page's "Delete my account"): the panel's width, up to its own limit */
.out .auth {
  justify-self: stretch;
  margin-top: 0.5rem;
}

/* Whether the card is online, in two or three words, then its address. An amber ring: not yet.
   A green dot: online. The same mark everywhere it is said (the reminder of base.css too). */
.state {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.375rem 0.625rem;
  min-width: 0;
  color: var(--muted);
  font-size: 0.9375rem;
  font-weight: 600;
}

.state-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.3125rem 0.75rem 0.3125rem 0.625rem;
  border-radius: 999px;
  background: color-mix(in srgb, var(--warn) 14%, var(--surface));
  color: var(--warn);
  font-size: 0.875rem;
  font-weight: 700;
  white-space: nowrap;
}

.state-pill::before {
  content: "";
  flex: none;
  width: 0.625rem;
  height: 0.625rem;
  border: 2px solid currentColor;
  border-radius: 50%;
}

.state-pill.is-on {
  background: color-mix(in srgb, var(--good) 14%, var(--surface));
  color: var(--good);
}

.state-pill.is-on::before {
  background: currentColor;
}

.state-url {
  min-width: 0;
}

/* Once the card is online its address is a link: as tall as a thumb needs */
.state a {
  padding-block: 0.625rem;
}

/* An address is written in two parts, the site then the card's own name (builder.js): a narrow
   screen breaks it after the slash, never in the middle of the name unless the name alone is too long.
   The email address that ends "Signed in as" is one such part: it goes to the next line whole. */
.url-part {
  display: inline-block;
  max-width: 100%;
  overflow-wrap: anywhere;
}

/* Over the phone that shows the card, so the preview cannot be taken for the card online.
   It sits in the panel's own top margin, so the phone hardly moves down. */
.b-preview .state-pill {
  margin-top: -0.75rem;
}

@media (min-width: 56rem) {
  .b-preview .state-pill {
    margin-top: -1.75rem;
  }
}

/* Last step. One question: its title is the label of its one field, the button is as wide as
   the field, and what the server answers shows between the two (under the button it would sit
   behind a phone's keyboard). */
.pub {
  gap: 1.25rem;
  scroll-margin-top: 0.75rem;
}

.pub-q {
  display: grid;
  grid-template-columns: minmax(0, 1fr); /* the bot check's box is 300px at least: on a 320px phone it must not widen the fields with it */
  gap: 0.875rem;
  max-width: 27rem;
}

.pub .b-title {
  text-wrap: balance;
}

/* A title the script moves to, so a screen reader says the new screen: nothing to press, no ring */
.pub .b-title:focus {
  outline: 0;
}

/* It may hold an email address, and a long one must break rather than widen the page */
.pub-q .b-sub {
  margin-top: -0.375rem;
  overflow-wrap: anywhere;
  font-size: 1rem;
}

.pub-q .input,
.pub-q .btn {
  min-height: 3.5rem;
  font-size: 1.0625rem;
}

.pub-q .btn {
  white-space: normal;
  line-height: 1.2;
}

.pub-q .help,
.pub-q .error,
.pub > .error,
.pub > .help {
  margin: 0;
}

/* "Your card stays in this browser" belongs to the refusal above it */
.pub-q .error + .help {
  margin-top: -0.5rem;
}

.pub-q .auth-code {
  font-size: 1.625rem;
}

.pub-q .auth-code::placeholder {
  opacity: 0.45;
}

#has-card {
  padding-top: 1rem;
}

.pub-free {
  color: var(--muted);
  font-size: 0.875rem;
  text-align: center;
}

/* The small things of the step are as tall as a thumb needs (2.75rem), whatever their text's height */
.pub-q .auth-check {
  min-height: 2.75rem;
  color: var(--muted);
  font-size: 0.9375rem;
}

.pub-q .text-link {
  display: inline-flex;
  align-items: center;
  justify-self: start;
  min-height: 2.75rem;
  margin-block: -0.375rem;
  padding: 0;
  border: 0;
  background: none;
  font: 600 0.9375rem var(--sans);
  text-align: start;
  cursor: pointer;
}

/* The way without an account and without a page: one quiet line, closed, under everything else */
.pub-offline {
  max-width: 27rem;
  margin-top: 0.5rem;
  padding-top: 0.375rem;
  border-top: 1.5px solid var(--line);
  color: var(--muted);
  font-size: 0.9375rem;
}

.pub-offline summary {
  width: fit-content;
  padding-block: 0.6875rem;
  font-weight: 600;
  cursor: pointer;
}

.pub-offline .out-buttons {
  margin-top: 0.75rem;
}

/* The end: the card is online. Centred on a phone, like a receipt; in line with the rest beside the preview. */
.pub-done {
  justify-items: center;
  gap: 1.25rem;
  padding-top: 0.5rem;
  text-align: center;
}

.done-tick {
  display: grid;
  place-items: center;
  width: 4rem;
  height: 4rem;
  border-radius: 50%;
  background: var(--good);
  color: var(--surface);
}

.done-tick .icon {
  width: 2.25rem;
  height: 2.25rem;
}

.pub-done .out-url {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 1rem;
  font-size: 1.0625rem;
  text-decoration: none;
}

/* The QR code, always black on white: a dark page does not change what a camera must read */
.pub-qr {
  width: 11rem;
  height: auto;
  padding: 0.5rem;
  border-radius: var(--r-panel);
  background: #fff;
  box-shadow: var(--shadow);
  image-rendering: pixelated;
}

.pub-done .out-buttons {
  justify-content: center;
  margin: 0;
}

.pub-done .btn-primary {
  width: min(100%, 22rem);
  min-height: 3.5rem;
  font-size: 1.0625rem;
}

.pub-done .help {
  margin: -0.5rem 0 0;
  overflow-wrap: anywhere;
}

@media (min-width: 56rem) {
  .pub-done {
    justify-items: start;
    text-align: start;
  }

  .pub-done .out-buttons {
    justify-content: flex-start;
  }
}

/* A tablet shows the form alone, in a column narrower than the page: the end stands in the middle of the page */
@media (max-width: 55.99rem) {
  .b-form:has(> .pub-done:not([hidden])) {
    margin-inline: auto;
  }
}

/* The narrowest phones: a long name stays whole in its address, and the two buttons share one row */
@media (max-width: 22rem) {
  .pub-done .out-url {
    gap: 0.375rem;
    padding-inline: 0.75rem;
    font-size: 0.9375rem;
  }

  .pub-done .out-buttons .btn {
    flex: 1;
    padding-inline: 0.75rem;
  }
}

.b-nav {
  display: flex;
  justify-content: space-between;
  gap: 0.75rem;
}

.b-nav #next {
  margin-left: auto;
}

@media (prefers-reduced-motion: no-preference) {
  .b-form section:not([hidden]) {
    animation: rise 0.45s var(--ease) both;
  }
}

/* "This account has 2 cards" (and its menus' twin): the account's own, each with its address and Edit, between two lines;
   then the button that makes a new one, or at the limit one amber sentence in its place */
.has-list {
  display: grid;
  margin: 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--line);
}

.has-list li {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 0 1rem;
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--line);
}

.has-list b {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.has-at {
  grid-column: 1;
  color: var(--muted);
  font-size: 0.875rem;
  overflow-wrap: anywhere;
}

.has-list .text-link {
  grid-area: 1 / 2 / span 2;
  margin-block: 0;
}

#has-sub {
  margin: 0;
  color: var(--muted);
}

.has-full {
  margin: 0;
  color: var(--warn);
  font-weight: 600;
}

/* "Create another card", under My account: a quiet second way on */
#done-another {
  min-height: 2.75rem;
  display: inline-flex;
  align-items: center;
}
