/* Material-style form controls as used across Google Analytics: outlined fields, checkboxes, switches, dialogs. */

:root {
  --danger: #d93025;
  --danger-strong: #c5221f;
  /* Neither good nor bad: something being queried rather than undone. */
  --warn: #b06000;
  --warn-wash: #fef7e0;
  --danger-wash: #fce8e6;
  --switch-track: #bdc1c6;
  --switch-track-on: #8ab4f8;
}

/* ---- Buttons ---- */
.btn:disabled {
  cursor: default;
  opacity: 0.38;
}

.btn--text {
  padding-inline: 12px;
  border-color: transparent;
  background: none;
}

.btn--text:hover {
  background: var(--blue-wash);
}

.btn--danger {
  border-color: var(--danger);
  background: var(--danger);
  color: #fff;
}

.btn--danger:hover {
  border-color: var(--danger-strong);
  background: var(--danger-strong);
}

.btn--danger-text {
  color: var(--danger);
}

.btn--danger-text:hover {
  background: var(--danger-wash);
}

.btn--warn-text {
  color: var(--warn);
}

.btn--warn-text:hover {
  background: var(--warn-wash);
}

.btn--pill {
  border-radius: 999px;
}

.btn .ms {
  font-size: 18px;
}

/* ---- Outlined text field ---- */
.field {
  position: relative;
  display: grid;
}

.field__input {
  width: 100%;
  height: 56px;
  padding: 0 16px;
  border: 1px solid var(--ink-3);
  border-radius: 4px;
  outline: none;
  background: var(--surface);
  color: var(--ink);
  font-size: 16px;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.field__input:hover {
  border-color: var(--ink);
}

.field__input:focus {
  border-color: var(--blue);
  box-shadow: inset 0 0 0 1px var(--blue);
}

/* Shown for reference only, such as an email address that comes from an invitation. */
.field__input[readonly] {
  border-color: var(--line);
  color: var(--ink-2);
  cursor: default;
}

.field__input[readonly]:focus {
  border-color: var(--line);
  box-shadow: none;
}

.field__input[readonly]:focus + .field__label {
  color: var(--ink-2);
}

/* An optional profile photo: a round preview beside the hint and buttons. */
.photo-picker {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-top: 24px;
  text-align: left;
}

.photo-picker__preview {
  flex: none;
}

.photo-picker__preview .ms {
  font-size: 40px;
}

.photo-picker__body {
  display: grid;
  gap: 2px;
  min-width: 0;
}

.photo-picker__title {
  margin: 0;
  font-weight: 500;
}

.photo-picker__hint {
  margin: 0;
  color: var(--ink-2);
  font-size: 12px;
  line-height: 16px;
}

.photo-picker__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 8px;
}

/* The droppable variant: an outlined area that highlights while an image is dragged over it. */
.photo-picker--drop {
  margin: 0 0 20px;
  padding: 16px;
  border: 1px dashed var(--ink-3);
  border-radius: var(--radius);
  transition: border-color 0.15s ease, background 0.15s ease;
}

.photo-picker--drop.is-dragging {
  border-color: var(--blue);
  background: var(--blue-wash);
}

.photo-picker--drop .photo-picker__preview {
  background: var(--field);
  color: var(--ink-2);
}

.field__required {
  color: var(--danger);
}

.photo-picker__error {
  margin: 4px 0 0;
  color: var(--danger);
  font-size: 12px;
  line-height: 16px;
}

/* Groups of fields in a longer form, divided by a light rule. */
.form-section {
  display: grid;
  gap: 4px;
  min-width: 0;
}

.form-section + .form-section {
  margin-top: 12px;
  padding-top: 20px;
  border-top: 1px solid var(--grid);
}

.form-section > .form-section-title {
  margin-top: 0;
}

.form-section-title {
  margin: 12px 0 12px;
  color: var(--ink);
  font-size: 14px;
  font-weight: 500;
  line-height: 20px;
}

.field__input:disabled {
  border-color: var(--line);
  color: var(--ink-3);
}

textarea.field__input {
  height: auto;
  min-height: 104px;
  padding: 16px;
  resize: vertical;
  line-height: 24px;
}

.field__label {
  position: absolute;
  top: 28px;
  left: 12px;
  max-width: calc(100% - 24px);
  padding: 0 4px;
  overflow: hidden;
  background: var(--surface);
  color: var(--ink-2);
  font-size: 16px;
  line-height: 20px;
  white-space: nowrap;
  text-overflow: ellipsis;
  pointer-events: none;
  transform: translateY(-50%);
  transition: top 0.15s ease, font-size 0.15s ease, color 0.15s ease;
}

.field__input:focus + .field__label,
.field__input:not(:placeholder-shown) + .field__label,
.field--select .field__label {
  top: 0;
  font-size: 12px;
}

.field__input:focus + .field__label {
  color: var(--blue);
}

/* The bottom padding keeps helper text clear of the next field's floating label. */
.field__helper {
  min-height: 20px;
  margin: 0;
  padding: 4px 16px 8px;
  color: var(--ink-2);
  font-size: 12px;
  line-height: 16px;
}

.field--select .field__input {
  padding-right: 44px;
  appearance: none;
  cursor: pointer;
}

/*
 * Money field: the $ sits inside the box, so the label always floats above it.
 *   <div class="field field--money">
 *     <input class="field__input" id="…" name="…" type="text" inputmode="decimal" placeholder=" " data-mask="money">
 *     <label class="field__label" for="…">Hourly rate</label>
 *     <span class="field__prefix" aria-hidden="true">$</span>
 *     <p class="field__helper" data-part="helper"></p>
 *   </div>
 */
.field--money .field__input {
  padding-left: 32px;
  font-variant-numeric: tabular-nums;
}

.field--money .field__label {
  top: 0;
  font-size: 12px;
}

.field__prefix {
  position: absolute;
  top: 16px;
  left: 16px;
  color: var(--ink-2);
  font-size: 16px;
  line-height: 24px;
  pointer-events: none;
}

.field__icon {
  position: absolute;
  top: 16px;
  right: 12px;
  color: var(--ink-2);
  pointer-events: none;
}

.field.is-invalid .field__input {
  border-color: var(--danger);
  box-shadow: inset 0 0 0 1px var(--danger);
}

.field.is-invalid .field__label,
.field.is-invalid .field__helper {
  color: var(--danger);
}

.field.is-invalid .field__helper:not(:empty)::before,
.check.is-invalid .field__helper:not(:empty)::before {
  content: "error";
  margin-right: 6px;
  font-family: "Material Symbols Outlined";
  font-size: 16px;
  vertical-align: -3px;
}

/* ---- Checkbox ---- */
.check {
  display: grid;
  grid-template-columns: 18px 1fr;
  column-gap: 16px;
  align-items: start;
  padding-block: 4px;
}

.check input {
  display: grid;
  place-content: center;
  width: 18px;
  height: 18px;
  margin: 1px 0 0;
  border: 2px solid var(--ink-2);
  border-radius: 2px;
  appearance: none;
  cursor: pointer;
}

.check input:checked {
  border-color: var(--blue);
  background: var(--blue);
}

.check input:checked::after {
  content: "";
  width: 10px;
  height: 5px;
  border: 2px solid #fff;
  border-top: 0;
  border-right: 0;
  transform: translate(0, -1px) rotate(-45deg);
}

.check label {
  cursor: pointer;
}

.check .field__helper {
  grid-column: 2;
  padding: 0;
}

.check.is-invalid input {
  border-color: var(--danger);
}

.check.is-invalid .field__helper {
  color: var(--danger);
}

/* ---- Switch ---- */
.switch {
  position: relative;
  width: 36px;
  height: 14px;
  margin: 3px 2px;
  border-radius: 7px;
  background: var(--switch-track);
  appearance: none;
  cursor: pointer;
  transition: background 0.15s ease;
}

.switch::after {
  content: "";
  position: absolute;
  top: -3px;
  left: -2px;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 3px rgb(60 64 67 / 40%);
  transition: transform 0.15s ease, background 0.15s ease;
}

.switch:checked {
  background: var(--switch-track-on);
}

.switch:checked::after {
  background: var(--blue);
  transform: translateX(20px);
}

.switch:disabled {
  cursor: default;
  opacity: 0.38;
}

/* A switch with its label and explanation, as on GA's settings pages. */
.toggle-field {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 24px;
  padding-block: 4px;
}

.toggle-field__text {
  cursor: pointer;
}

.toggle-field__label {
  display: block;
}

.toggle-field__helper {
  display: block;
  margin-top: 2px;
  color: var(--ink-2);
  font-size: 12px;
  line-height: 16px;
}

.toggle-field .switch {
  flex: none;
}

/* ---- Form layout and messages ---- */
/* A heading for a handful of fields that belong together, inside a section that has its own title. */
.settings-group__title {
  margin: 8px 0 0;
  color: var(--ink);
  font-size: 13px;
  font-weight: 500;
}

.form-stack {
  display: grid;
  gap: 4px;
}

.form-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 8px 16px;
}

.form-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 8px;
}

.form-error,
.notice {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin: 0 0 16px;
  padding: 12px 16px;
  border-radius: 4px;
  font-size: 14px;
}

.form-error {
  background: var(--danger-wash);
  color: var(--danger-strong);
}

.notice {
  background: var(--blue-wash);
  color: var(--ink);
}

.notice .ms {
  color: var(--blue);
}

/* Something not set up yet, which will refuse work until it is. */
.notice--setup {
  align-items: center;
}

.notice__text {
  flex: 1;
  min-width: 0;
}

.notice__title {
  margin: 0;
  font-weight: 500;
}

.notice__line {
  margin: 2px 0 0;
  color: var(--ink-2);
  font-size: 13px;
}

/* ---- Dialog ---- */
.dialog {
  width: min(560px, calc(100vw - 32px));
  padding: 0;
  border: 0;
  border-radius: 8px;
  background: var(--surface);
  color: var(--ink);
  box-shadow: 0 11px 15px -7px rgb(0 0 0 / 20%), 0 24px 38px 3px rgb(0 0 0 / 14%), 0 9px 46px 8px rgb(0 0 0 / 12%);
}

/* Room for fields laid out in a row, such as how each service is priced and what it comes to. */
.dialog--wide {
  width: min(760px, calc(100vw - 32px));
}

.dialog::backdrop {
  background: rgb(32 33 36 / 60%);
}

.dialog__form {
  display: grid;
  gap: 16px;
  padding: 24px;
}

/* ---- A picture shown over the page it was opened from, rather than in a tab of its own ---- */
.lightbox {
  width: min(1120px, calc(100vw - 32px));
  max-width: none;
  max-height: calc(100vh - 32px);
  padding: 0;
  border: 0;
  border-radius: 8px;
  background: var(--surface);
  color: var(--ink);
  box-shadow: 0 11px 15px -7px rgb(0 0 0 / 20%), 0 24px 38px 3px rgb(0 0 0 / 14%), 0 9px 46px 8px rgb(0 0 0 / 12%);
  overflow: hidden;
}

.lightbox::backdrop {
  background: rgb(32 33 36 / 72%);
}

.lightbox__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  min-height: 56px;
  padding: 8px 8px 8px 20px;
  border-bottom: 1px solid var(--line);
}

.lightbox__title {
  margin: 0;
  overflow: hidden;
  font-size: 16px;
  font-weight: 500;
  line-height: 24px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.lightbox__actions {
  display: flex;
  flex: none;
  align-items: center;
  gap: 4px;
}

/* The picture sits on a plain ground, as large as the window allows and never larger than itself. */
.lightbox__stage {
  display: grid;
  place-items: center;
  padding: 16px;
  overflow: auto;
  background: var(--surface-alt);
}

.lightbox__image {
  max-width: 100%;
  max-height: calc(100vh - 120px);
  object-fit: contain;
}

.dialog__title {
  margin: 0;
  font-size: 22px;
  font-weight: 400;
  line-height: 28px;
}

.dialog__message {
  margin: 0;
  color: var(--ink-2);
}

.dialog__body:empty {
  display: none;
}

.dialog__form .form-error {
  margin: 0;
}

.dialog__actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
}

/* ---- Side panel: a sheet sliding in from the right, for adding something without leaving a form ---- */
.has-side-panel {
  overflow: hidden;
}

.side-panel {
  inset: 0 0 0 auto;
  width: min(720px, 100vw);
  max-width: none;
  height: 100%;
  max-height: none;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--ink);
  overflow: hidden;
}

/* Most of the window, for a sheet whose contents only make sense laid out across it. */
.side-panel--wide {
  width: min(max(65vw, 760px), 100vw);
}

.side-panel::backdrop {
  background: rgb(32 33 36 / 0%);
  transition: background 0.25s ease;
}

.side-panel.is-open::backdrop {
  background: rgb(32 33 36 / 60%);
}

.side-panel__sheet {
  display: flex;
  flex-direction: column;
  height: 100%;
  background: var(--surface);
  box-shadow: 0 8px 10px -5px rgb(0 0 0 / 20%), 0 16px 24px 2px rgb(0 0 0 / 14%), 0 6px 30px 5px rgb(0 0 0 / 12%);
  transform: translateX(100%);
  transition: transform 0.25s cubic-bezier(0.2, 0, 0, 1);
}

.side-panel.is-open .side-panel__sheet {
  transform: translateX(0);
}

.side-panel__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  min-height: 64px;
  padding: 8px 12px 8px 24px;
  border-bottom: 1px solid var(--line);
}

.side-panel__title {
  margin: 0;
  font-size: 22px;
  font-weight: 400;
  line-height: 28px;
}

.side-panel__body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}

/* A page form inside the sheet loses its card frame, stacks each section, and keeps Save in reach. */
.side-panel__body > .page-stack {
  min-height: 100%;
  /* Cards sit at the top rather than sharing out the leftover height between them. */
  align-content: start;
}

.side-panel__body .card {
  overflow: visible;
  border: 0;
  border-radius: 0;
}

/*
 * Only a form fills the sheet, so its Save stays at the foot of it rather than partway up with bare
 * sheet below it. A height in per cent is no use for that: the stack sizes its rows to what is in
 * them, so the form would be measuring itself. The stack holding a form lays itself out down the
 * column instead, and the form takes whatever height the sections leave. A sheet of several cards,
 * such as a work order, keeps each one to its own content.
 */
.side-panel__body > .page-stack:has(> form.card) {
  display: flex;
  flex-direction: column;
}

.side-panel__body > .page-stack > form.card {
  flex: 1 0 auto;
}

.side-panel__body .settings-section {
  grid-template-columns: minmax(0, 1fr);
  padding-inline: 24px;
}

.side-panel__body .detail-list:empty {
  display: none;
}

.side-panel__body form.card > .card__footer {
  position: sticky;
  bottom: 0;
  margin-top: auto;
  background: var(--surface);
}

.side-panel__body .repeatable {
  scroll-margin-bottom: 88px;
}

/*
 * A form filling a page keeps Cancel and Save in reach: the bar is fixed to the foot of the window,
 * across the whole page beside the rail, so it is in the same place whatever the form is and however
 * far down it you are. A form inside a side panel has its own bar, above.
 */
/* A card clips what is inside it, which would cut the bar off; a form's card doesn't. */
.content__inner form.card {
  overflow: visible;
}

.content__inner form.card > .card__footer {
  position: fixed;
  right: 0;
  bottom: 0;
  left: var(--rail-w);
  z-index: 30;
  padding: 8px 32px calc(8px + env(safe-area-inset-bottom, 0px));
  background: var(--surface);
  box-shadow: 0 -2px 8px rgb(60 64 67 / 12%);
}

/* The page ends above the bar rather than behind it. */
.content__inner:has(form.card > .card__footer) {
  padding-bottom: 68px;
}

/* With the rail out of the way, the bar runs the whole width. */
@media (max-width: 960px) {
  .content__inner form.card > .card__footer {
    left: 0;
    padding-inline: 16px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .side-panel__sheet,
  .side-panel::backdrop {
    transition: none;
  }
}

/* ---- A set of tick boxes in a form, such as the scope items a question is about ---- */

.checkset {
  border: 0;
  margin: 0;
  padding: 0;
}

.checkset__legend {
  padding: 0;
  color: var(--ink-2);
  font-size: 13px;
  font-weight: 500;
}

.checkset__hint {
  margin: 2px 0 8px;
  color: var(--ink-3, var(--ink-2));
  font-size: 12px;
}

.checkset__options {
  display: grid;
  gap: 6px;
  max-height: 220px;
  overflow-y: auto;
}

.checkset__option {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  padding: 6px 8px;
  border-radius: 8px;
  cursor: pointer;
}

.checkset__option:hover {
  background: var(--surface-alt);
}

.checkset__option input {
  margin-top: 2px;
}

.checkset__text {
  display: grid;
}

.checkset__note {
  color: var(--ink-2);
  font-size: 12px;
}

.checkset__empty {
  color: var(--ink-2);
  font-size: 13px;
}

/* A field the form fills in and nobody edits, such as the job a question belongs to. */
.field--readonly .field__input {
  background: var(--surface-alt);
  color: var(--ink-2);
}

.field-block__label {
  margin: 0 0 8px;
  color: var(--ink-2);
  font-size: 13px;
  font-weight: 500;
}

/* A picker with its line of help under it, rather than in the column beside it. */
.rfi-pick {
  grid-template-columns: minmax(0, 1fr);
  gap: 4px;
}
