/*
 * Components. Loaded after application.css, whose tokens these depend on.
 */

/*
 * The action bar holds a page's primary action. It falls to the bottom of the
 * screen on short pages and stays pinned there on long ones, so the button is
 * always under the reader's thumb without ever covering the content.
 */
.action-bar {
  position: sticky;
  bottom: 0;
  z-index: 1;
  margin-top: auto;
  margin-inline: calc(var(--gutter) * -1);
  padding: var(--space-m) var(--gutter);
  padding-bottom: calc(var(--space-m) + env(safe-area-inset-bottom));
  background-color: var(--colour-white);
  box-shadow: 0 -0.125rem 0.5rem rgb(33 43 50 / 0.15);
}

.action-bar > * + * {
  margin-top: var(--space-s);
}

.button {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: var(--touch-target);
  padding: var(--space-s) var(--space-m);
  border: var(--border) solid transparent;
  border-radius: var(--radius);
  background-color: var(--colour-green);
  box-shadow: 0 0.25rem 0 var(--colour-green-dark);
  color: var(--colour-white);
  font-weight: bold;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
}

.button:hover {
  background-color: var(--colour-green-dark);
}

/* Pressing pushes the button down onto its own shadow. */
.button:active {
  transform: translateY(0.25rem);
  box-shadow: none;
}

.button:focus-visible {
  background-color: var(--colour-yellow);
  box-shadow: 0 0.25rem 0 var(--colour-black);
  color: var(--colour-black);
}

/* The button lays itself out with flex, which would otherwise outrank `hidden`. */
.button[hidden] {
  display: none;
}

.button--secondary {
  border-color: var(--colour-black);
  background-color: var(--colour-white);
  box-shadow: none;
  color: var(--colour-black);
}

.button--secondary:hover {
  background-color: var(--colour-grey-pale);
}

.button--secondary:active {
  transform: none;
}

/* Errors are announced at the top of the page, in the reader's own words. */
.error-summary {
  margin-bottom: var(--space-l);
  padding: var(--space-m);
  border: var(--border) solid var(--colour-red);
  color: var(--colour-red);
  font-weight: bold;
}

.error-summary > :last-child {
  margin-bottom: 0;
}

/* A labelled text field: the label sits above its full-width input. */
.field {
  margin-bottom: var(--space-l);
}

.field__label {
  display: block;
  margin-bottom: var(--space-xs);
  font-weight: bold;
}

.field__input {
  display: block;
  width: 100%;
  min-height: var(--touch-target);
  padding: var(--space-s) var(--space-m);
  border: var(--border) solid var(--colour-grey);
  border-radius: var(--radius);
  background-color: var(--colour-white);
  color: inherit;
}

/*
 * The shared focus style paints a yellow block over its element, which would
 * hide whatever is being typed. A field keeps its white background and wears
 * the yellow-and-black instead as a ring around the outside.
 */
.field__input:focus-visible {
  outline: var(--border) solid transparent;
  background-color: var(--colour-white);
  box-shadow: 0 0 0 var(--space-xs) var(--colour-yellow), 0 0 0 calc(var(--space-xs) + var(--border)) var(--colour-black);
  color: inherit;
}

/* An aside that must not be mistaken for the main instructions. */
.inset-text {
  margin-bottom: var(--space-l);
  padding: var(--space-xs) 0 var(--space-xs) var(--space-m);
  border-left: var(--space-xs) solid var(--colour-grey-light);
  color: var(--colour-grey);
}

.inset-text > :last-child {
  margin-bottom: 0;
}

/* Visible reassurance that a wait is progress rather than a broken page. */
.spinner {
  width: 3rem;
  height: 3rem;
  margin-bottom: var(--space-l);
  border: 0.375rem solid var(--colour-grey-light);
  border-top-color: var(--colour-blue);
  border-radius: 50%;
  animation: spin 1s linear infinite;
}

@keyframes spin {
  to {
    transform: rotate(1turn);
  }
}

@media (prefers-reduced-motion: reduce) {
  .spinner {
    animation-duration: 4s;
  }
}

/*
 * Upload. The file input is never seen: its labels are the visible controls,
 * so tapping one opens the camera without any JavaScript.
 */
.upload__input {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
}

/*
 * One primary action at a time - choose a file, or send the one you chose.
 * The input's own validity carries the state, so the swap happens with no
 * JavaScript and no second source of truth.
 */
.upload__input:invalid ~ * .upload__replace,
.upload__input:invalid ~ * .upload__submit,
.upload__input:valid ~ * .upload__choose {
  display: none;
}

/* Focus lands on the hidden input, so show it on the label standing in for it. */
.upload__input:focus-visible ~ * label.button {
  background-color: var(--colour-yellow);
  box-shadow: 0 0.25rem 0 var(--colour-black);
  color: var(--colour-black);
}

/* Appears only once JavaScript has something to put in it. */
.upload__preview {
  display: none;
  width: 100%;
  margin-bottom: var(--space-l);
  border: var(--border) solid var(--colour-grey-light);
  border-radius: var(--radius);
}

.upload__preview[src] {
  display: block;
}
