/**
 * @file     dcp-modal.css
 *           Basic CSS rules for laying out the modals implemented in src/dcp-client/dom-tk/modals.js.
 *           This stylesheet should be used in conjunction with an overall appearance stylesheet from
 *           the base application to set key details like the text colours, fonts, form element
 *           appearance, etc.
 * @author   Wes Garland, wes@distributive.network
 * @date     Nov 2024
 * @description
 * A generic modal has the following layout (see also dialogTemplateHtml in the implementation):
 * +----------------------------------------------+
 * |                                      CLOSE X |
 * |                   TITLE                      |
 * |                                              |
 * | ICON              BODY                       |
 * |                                              |
 * |                       BUTTONS PRIMARY_BUTTON |
 * +----------------------------------------------+
 *
 * The overall border of the box is grey with a slight drop shadow. The DIALOG is positioned on the page
 * via auto margins on all four sides; we pull it up to 10% for a more comfortable reading experience,
 * and to permit dialogs with a lot of information before scrolling.
 */
DIALOG#dcp-modal {
  position:      fixed;
  margin-top:    10%;
  padding:       0;
  max-width:     65%;
  border-radius: 4px;
  border:        1px solid rgb(138, 138, 138);
  box-shadow:    rgba(0, 0, 0, 0.4) 4px 4px 4px;
  text-align:    center;

  /* Animate the dialog whenever it is rendered so that users can tell when they dismiss a dialog that
   * gets immediately replaced by another identical dialog
   */
  & {
    transition: scale 0.3s, opacity 0.3s, margin-top 0.2s ease-out;
    opacity: 1;
    scale:   1;
    @starting-style {
      opacity: 0;
      scale:   0;
      margin-top: 50%;
    }
  }
}

/* Let the user resize alert boxes when the stack trace is visible */
DIALOG#dcp-modal.dcp-modal-alert {
  &:has(#dcp-modal-stack[show-toggle="on"]) {
    resize:        both;
    overflow-x:    clip;
    overflow-y:    auto;
  }
  /* Undo the side-effects of the resize attrib when the stack trace gets hidden */
  &:has(#dcp-modal-stack[show-toggle="off"]) {
    width:  revert !important;
    height: revert !important;
  }
}

/**
 * Trick Chrome into ignoring max-width when the user uses the resize corner.
 */
DIALOG#dcp-modal[style*=width] {
  max-width: unset;
}

DIALOG#dcp-modal:focus {
  outline:       none;
}

DIALOG#dcp-modal > * {
  text-align: left;
}

/**
 * The title section of the modal is optional; when it is not hidden, its background colour is
 * primary-hue-main; we assume this is a colour that is dark enough for white text. The unset width and
 * left/right padding ensure that titles wider than the body allow the overall box to grow without
 * crowding the edges.
 */
DIALOG#dcp-modal H3#dcp-modal-title {
  text-align:       center;
  overflow:         hidden;
  margin:           0;
  padding:          1em;
  background-color: var(--primary-hue-main);
  color:            white;
  overflow:         hidden;
}

/**
 * The close X is a DIV with the X in the background image that is always at the top right corner. When
 * the mouse hovers over it, we  make the background darker. When the is not hidden, we invert the
 * colour of the X, and re-invert the backdrop on hover to maintain the hover behaviour. The filters
 * assume that
 *  - the X is black with a transparent background
 *  - white looks good on the title
 *  - black looks on the default background
 */
DIALOG#dcp-modal #dcp-modal-close-x {
  background-image: url('/dcp-client/assets/x.svg');
  background-size:  contain;
  height:    0.6em;
  width:     0.6em;
  padding:   3px;
  margin:    2px;
  border:    none;
  position:  absolute;
  top:       0;
  right:     0;
}
DIALOG#dcp-modal #dcp-modal-close-x:hover {
  backdrop-filter: brightness(0.8);
}
DIALOG#dcp-modal #dcp-modal-title:not(.dcp-modal-hidden) + #dcp-modal-close-x {
  filter: invert(100%);
}
DIALOG#dcp-modal #dcp-modal-title:not(.dcp-modal-hidden) + #dcp-modal-close-x:hover {
  backdrop-filter: brightness(0.8) invert(100%);
}

/**
 * close-x is not used for modals immitating system modals
 */
DIALOG#dcp-modal.dcp-modal-alert   > #dcp-modal-close-x,
DIALOG#dcp-modal.dcp-modal-confirm > #dcp-modal-close-x,
DIALOG#dcp-modal.dcp-modal-prompt  > #dcp-modal-close-x {
  display: none;
}

/**
 * The content area exists so that the icon and the body can be vertically centered against each other.
 */
DIALOG#dcp-modal #dcp-modal-content-area {
  display:         flex;
  align-items:     center;
  padding:         1em;
}

/**
 * The modal icon, when present, displays to the left of all of the text.
 */
DIALOG#dcp-modal #dcp-modal-icon {
  background-position: center;
  background-size:     contain;
  background-repeat:   no-repeat;
  background-image:    url('/dcp-client/assets/dcp-logo.png');
  flex-shrink:         0;
  height:              2em;
  width:               2em;
  padding:             0px;
  margin:              0 0.75em 0 0;
  border:              none;
}
DIALOG#dcp-modal.dcp-modal-alert #dcp-modal-icon {
  background-image: url('/dcp-client/assets/lucide/triangle-alert.svg');
}
DIALOG#dcp-modal.dcp-modal-alert:has(#dcp-modal-stack) #dcp-modal-icon {
  background-image: url('/dcp-client/assets/lucide/bug.svg');
  cursor: pointer;
}
DIALOG#dcp-modal.dcp-modal-confirm #dcp-modal-icon {
  background-image: url('/dcp-client/assets/lucide/circle-alert.svg');
}
DIALOG#dcp-modal.dcp-modal-upload #dcp-modal-icon {
  background-image: url('/dcp-client/assets/lucide/hard-drive-upload.svg');
}

/**
 * Stack is hidden by default; clicking on the bug icon toggles the show-toggle attribute
 */
DIALOG#dcp-modal.dcp-modal-alert #dcp-modal-stack {
  font-size: 0.7em;
  display: none;
}
DIALOG#dcp-modal.dcp-modal-alert #dcp-modal-stack[show-toggle="on"] {
  display: block;
}

DIALOG#dcp-modal #dcp-modal-body[mode="text"] {
  white-space: pre-line;
}

/**
 * Overall dialog is overflow: hidden, but we set things up here so that really large content will add
 * scrollbars on the inside of the dialog, instead of becoming unmanageably large.
 */
DIALOG#dcp-modal #dcp-modal-body {
  width:       100%;
  overflow:    auto;
  max-height:  50vh;
}

DIALOG#dcp-modal.dcp-modal-prompt INPUT[type="number"],
DIALOG#dcp-modal.dcp-modal-prompt INPUT[type="password"],
DIALOG#dcp-modal.dcp-modal-prompt INPUT[type="text"] {
  width: 100%;
}

/**
 * The error section takes up no space unless it has content. It appears below the body.
 */
DIALOG#dcp-modal #dcp-modal-error {
  text-align: center;
  font-size:  0.75em;
  padding:    0 0 1em 1em;
  margin-top: -1em;
}
/**
 * The button area holds the elements passed as buttons to cm.showModalDialog. They are floated to the
 * right so that they appear in inverse order of declaration, putting the default primary button all the
 * way to the right. A centered-buttons class has been provided to center the buttons in the modal. This
 * class selector can be removed to make that the default behaviour. The centering happens by shrinking
 * button-area to only the necessary size so that the top-level text-align of #dcp-modal can center it.
 */
DIALOG#dcp-modal #dcp-modal-button-area {
  margin-left: 1em;
}
DIALOG#dcp-modal #dcp-modal-button-area > * {
  margin-bottom: 1em;
  margin-right:  1em;
}
DIALOG#dcp-modal #dcp-modal-button-area > * {
  float:    right;
  position: relative;
}
DIALOG#dcp-modal.centered-buttons #dcp-modal-button-area {
  display: inline-block;
}

/**
 * Class used to hide elements, eg title, in a way that we can use for sibling combinators.
 */
DIALOG#dcp-modal .dcp-modal-hidden {
  display: none;
}

/**
 * Create the dialog opening behaviour. We animate a quick fade in/our of the backdrop to make things
 * look smooth. Does not currently (Nov 2024) work in Firefox.
 */
DIALOG#dcp-modal[open]::backdrop {
  animation: backdrop-fade 150ms ease forwards;
}
DIALOG#dcp-modal:not([open])::backdrop {
  animation: backdrop-fade 50ms ease backwards;
  animation-direction: reverse;
}
@keyframes backdrop-fade {
  from { backdrop-filter: brightness(1.0); }
    to { backdrop-filter: brightness(0.7); }
}

/**
 * The upload modal has some unique positioning requirements. The icon is lifted from its normal
 * position and centered within the modal. This allows it to render on top of the drop zone. The
 * drop-zone uses a negative vertical position transformation to position the drop zone label. This
 * means that the padding at the top of the body content needs to be become a margin to avoid cutting
 * the top of the text off.
 */
DIALOG#dcp-modal.dcp-modal-upload #dcp-modal-icon {
  position:  absolute;
  left:      50%;
  transform: translate(-50%, 0.5em);
  z-index:   1;
}
DIALOG#dcp-modal.dcp-modal-upload #dcp-modal-body {
  text-align:  center;
  margin:      0;
  padding:     0;
  white-space: initial;
  width:       100%;
  z-index:     2;
}
DIALOG#dcp-modal.dcp-modal-upload:has(#dcp-modal-drop-target) #dcp-modal-content-area
{
  padding-top: 0;
}
DIALOG#dcp-modal.dcp-modal-upload #dcp-modal-drop-target {
  margin-top: 1em;
  display:    inline-block;
  border:     2px dashed #bbb;
  height:     6em;
  width:      calc(6em * 1.618);
}
DIALOG#dcp-modal.dcp-modal-upload #dcp-modal-drop-label {
  display:    inline-block;
  position:   relative;
  transform:  translateY(-0.9em);
  color:      grey;
  background: white;
  padding:    2px 4px 2px 4px;
  font-size:  0.75em;
}

/** Control the behaviour of the upload modal when drag/dropping to give user feedback */
DIALOG#dcp-modal.dcp-modal-upload #dcp-modal-icon {
  transition: all 100ms linear;
}
DIALOG#dcp-modal.dcp-modal-upload[drag-state="over"] #dcp-modal-drop-target {
  border-color: #777;
}
DIALOG#dcp-modal.dcp-modal-upload[drag-state="over"] #dcp-modal-icon {
  font-size: 1.5em;
}
DIALOG#dcp-modal.dcp-modal-upload[drag-state="invalid"] {
  cursor: not-allowed;
}
DIALOG#dcp-modal.dcp-modal-upload[drag-state="over"] {
  cursor: copy;
}
DIALOG#dcp-modal.dcp-modal-upload[drag-state="invalid"] #dcp-modal-drop-target {
  opacity: 0.35;
}
DIALOG#dcp-modal.dcp-modal-upload[drag-state="invalid"] #dcp-modal-icon {
  font-size: 0;
  opacity: 0;
}

/**
 * Password dialogs can have one or two label+input divs, depending on need (enter vs create).
 */
DIALOG#dcp-modal:has(#dcp-modal-password-prompt) {
  max-width: 45%;
  INPUT[type] {
    max-width: 50em;
  }

  LABEL {
    line-height: 37px; /* remove when fixing dcp-style.css */
    padding-right: 0.5em;
    width: 25ch;
  }
  LABEL::after {
    content: ":";
  }

  #dcp-modal-password-prompt,
  #dcp-modal-password-confirm-prompt {
    display: flex;
    flex-direction: row;
    flex-wrap: nowrap;
    justify-content: flex-start;

    & > DIV {
      display: flex;
      flex-grow: 1;
    }
  }

  #dcp-modal-password-preamble {
    &:not(:empty) {
      padding-bottom: 0.5em;
    }
  }
}

/**
 * Passphrase prompts with the showEye option are rendered as input[type="text"][obscured] instead of
 * input type="password". A click handler is added to toggle when the obscured attribute on the sibling
 * span element.
 */
DIALOG#dcp-modal DIV#dcp-modal-password-prompt,
DIALOG#dcp-modal DIV#dcp-modal-password-confirm-prompt {
  /**
   * INPUT[type="text"].with-eye is a password-like element with an eye icon that toggles password
   * visibility. Visibility toggling happens by adding/removing the 'obscured' attribute.
   */
  INPUT[type="text"].dcp-show-eye[obscured] {
    -webkit-text-security: disc;
  }
  INPUT[type="text"].dcp-show-eye[obscured] + SPAN {
    background-image: url("/dcp-client/assets/lucide/eye-off.svg");
  }
  INPUT[type="text"].dcp-show-eye + SPAN {
    background-image: url("/dcp-client/assets/lucide/eye.svg");
  }

  /** Appearance of the eye itself */
  INPUT.dcp-show-eye + SPAN {
    display:           inline-block;
    position:          relative;

    background-repeat: no-repeat;
    background-size:   cover;
    height:            16px;
    width:             16px;
    margin-left:       -16px;
    right:             8px;
    transform:         translateY(9px);
    opacity:           50%;
    cursor:            pointer;
  }
}
