/* ============================================================================
   THE HELP DOCK, ON ITS OWN.

   Split out of hn.css so a page can carry the DOOR without carrying the whole
   crisis page behind it. hn.css is the crisis page's stylesheet: the line
   cards, the directory, the breathing circle, the companion panel. A page that
   only wants a tab down its left edge has no use for any of that, and asking
   every page in the app to download 45KB of it to show one control would be a
   tax on twenty pages to pay for one.

   So: this file plus hn-dock.js is what a page needs to have the door. The
   companion's own weight (hn.css, hn-data.js, hn-core.js) is fetched only if
   somebody actually presses "Talk it through", and after that it is cached.

   It depends on appts-shell.css for its tokens and nothing else.
   ============================================================================ */

/* its own pulse, rather than borrowing the one in hn.css: this file must stand
   up on a page that never loads that one */
@keyframes hd-pulse { 0% { transform: scale(.86); opacity: .6 }
  70% { transform: scale(1.18); opacity: 0 } 100% { opacity: 0 } }
/* ============================================================================
   THE HELP TAB THAT BECOMES AN ORB  (hn-dock.js)

   Two homes for the same door. Which one is showing is decided by `display`,
   never by opacity or a transform, so a stalled animation cannot leave BOTH
   hidden. This app has been bitten three times by content that depended on an
   animation running, once leaving a whole video call see-through, and the one
   place it must never happen again is the way out of a bad night.
   ============================================================================ */
.hd-tab, .hd-orb { position: fixed; z-index: 57; cursor: grab; color: #fff;
  border: none; touch-action: none; -webkit-user-select: none; user-select: none;
  box-shadow: 0 10px 30px rgba(0, 0, 0, .38) }
.hd-wrap.hd-dragging .hd-tab, .hd-wrap.hd-dragging .hd-orb { cursor: grabbing; transition: none }

/* THE TAB. Left edge, halfway up, out of the crowded bottom band entirely:
   the tab bar, Ask Rivo and the honesty banner all live at the bottom and this
   argues with none of them at any width. */
.hd-tab { left: 0; top: 46%; display: none; flex-direction: column; align-items: center;
  gap: 9px; padding: 16px 9px 15px; border-radius: 0 16px 16px 0;
  background: var(--secondary);
  transition: transform .34s var(--spring), padding .24s var(--ease) }
.hd-wrap.is-tab .hd-tab { display: flex }
.hd-tab:hover { padding-left: 13px; padding-right: 11px }
.hd-tab .ic { display: grid; place-items: center }
.hd-tab .tx { writing-mode: vertical-rl; font-size: 11px; font-weight: 700; letter-spacing: .16em;
  text-transform: uppercase }
/* the entrance is a MOVE, and the resting style is already visible, so nothing
   here depends on the keyframe running */
.hd-wrap.hd-flying.is-tab .hd-tab { animation: hd-in-tab .5s var(--spring) }
@keyframes hd-in-tab { from { transform: translateX(-120%) scale(.7); opacity: 0 } }

/* THE ORB. Sized and placed from the real Rivo widget by hn-dock.js, so the
   pair reads as a pair. Magenta and a life buoy against Rivo's spectrum and
   its spark: alike enough to belong together, different enough that nobody
   taps the wrong one at four in the morning. */
.hd-orb { display: none; width: 56px; height: 56px; border-radius: 50%;
  place-items: center; background: var(--secondary);
  transition: transform .3s var(--spring), box-shadow .24s var(--ease) }
.hd-wrap.is-orb .hd-orb { display: grid }
.hd-orb:hover { transform: translateY(-2px); box-shadow: 0 14px 38px rgba(0, 0, 0, .48) }
.hd-orb::before { content: ''; position: absolute; inset: -4px; border-radius: 50%;
  border: 2px solid var(--secondary); opacity: .45;
  animation: hd-pulse 2.8s var(--ease) infinite }
.hd-wrap.hd-flying.is-orb .hd-orb { animation: hd-in-orb .5s var(--spring) }
@keyframes hd-in-orb { from { transform: translate(-40vw, -22vh) scale(.6); opacity: 0 } }

/* what it says when it moves, or when a long press asks */
.hd-hint { position: fixed; z-index: 58; left: 50%; bottom: 168px; transform: translateX(-50%) translateY(8px);
  max-width: min(420px, calc(100vw - 32px)); padding: 11px 16px; border-radius: 999px;
  font-size: 12.5px; line-height: 1.45; text-align: center; color: var(--ink);
  background: var(--glass); -webkit-backdrop-filter: var(--blur); backdrop-filter: var(--blur);
  border: 1px solid var(--hair-2); box-shadow: var(--shadow-lg);
  opacity: 0; pointer-events: none; transition: opacity .24s var(--ease), transform .3s var(--spring) }
.hd-wrap.hd-saying .hd-hint { opacity: 1; transform: translateX(-50%) }
@media (max-width: 900px) { .hd-hint { bottom: 200px } }

/* it gives way to exactly what Rivo and the demo control give way to */
body.sheet-open .hd-tab, body.sheet-open .hd-orb,
body.hn-comp-open .hd-tab, body.hn-comp-open .hd-orb,
body.rivo-open .hd-orb, body.rail-open .hd-tab, body.rail-open .hd-orb,
body.tabbar-wide .hd-orb { opacity: 0; pointer-events: none }

@media (prefers-reduced-motion: reduce) {
  .hd-tab, .hd-orb { transition: none; animation: none !important }
  .hd-orb::before { animation: none; opacity: .3 }
  .hd-hint { transition: opacity .2s linear }
}


/* ---------------------------------------------------------------------------
   ONE PRESS, TWO DOORS.

   Pressing the tab or the orb opens a question rather than answering it. Some
   people want the page: the numbers, the list of what is near them, something
   to do with their hands. Some want a voice, and being handed a directory
   instead is the wrong answer to a question they never got to ask.

   Two plainly labelled buttons, never a guess with an undo. `hidden` decides
   whether it is in the document and the class only animates it, so a stalled
   transition cannot leave an invisible pair of buttons sitting over the page.
   --------------------------------------------------------------------------- */
.hd-ask { position: fixed; z-index: 59; display: flex; flex-direction: column; gap: 10px;
  opacity: 0; transform: translateY(6px) scale(.96);
  transition: opacity .2s var(--ease), transform .34s var(--spring) }
.hd-ask[hidden] { display: none }
.hd-wrap.hd-asking .hd-ask { opacity: 1; transform: none }
.hd-ask.right { transform-origin: left center }
.hd-ask.up { transform-origin: bottom right; align-items: flex-end }

.hd-choice { display: flex; align-items: center; gap: 12px; padding: 9px 16px 9px 9px;
  border-radius: 999px; cursor: pointer; text-align: left; color: var(--ink);
  background: var(--glass); -webkit-backdrop-filter: var(--blur); backdrop-filter: var(--blur);
  border: 1px solid var(--hair-2); box-shadow: var(--shadow-lg);
  transition: transform .16s var(--ease), border-color .16s var(--ease) }
.hd-ask.up .hd-choice { flex-direction: row-reverse; padding: 9px 9px 9px 16px; text-align: right }
.hd-choice:hover { transform: translateY(-2px); border-color: var(--secondary) }
.hd-choice:focus-visible { outline: 2px solid var(--secondary); outline-offset: 3px }
.hd-choice .o { width: 40px; height: 40px; border-radius: 50%; flex: none; display: grid;
  place-items: center; color: #fff }
.hd-choice.talk .o { background: var(--cyan) }
.hd-choice.page .o { background: var(--secondary) }
.hd-choice .lb { display: flex; flex-direction: column; min-width: 0 }
.hd-choice .lb b { font-size: 14px; font-weight: 600; letter-spacing: -.01em }
.hd-choice .lb i { font-style: normal; font-size: 11.5px; color: var(--ink-3); margin-top: 1px }

/* the two arrive one after the other, and their resting style is already
   visible, so nothing here depends on the keyframe running */
.hd-wrap.hd-asking .hd-choice { animation: hd-choice-in .38s var(--spring) both }
.hd-wrap.hd-asking .hd-choice:nth-child(2) { animation-delay: .06s }
@keyframes hd-choice-in { from { opacity: 0; transform: translateY(8px) scale(.94) } }

@media (max-width: 560px) {
  .hd-choice .lb i { display: none }
  .hd-choice { padding: 8px 14px 8px 8px }
  .hd-ask.up .hd-choice { padding: 8px 8px 8px 14px }
}
@media (prefers-reduced-motion: reduce) {
  .hd-ask { transition: opacity .18s linear }
  .hd-wrap.hd-asking .hd-choice { animation: none }
}


/* ---------------------------------------------------------------------------
   THE GHOST: where it is going to land.

   A drag needs something to aim at, or the only way to learn the gesture is to
   let go somewhere and find out. It appears the moment the control lifts and
   lights up when the pointer is over the drop zone, which is generous on
   purpose: precise dragging with a thumb, on a page you are only looking at
   because tonight is bad, is not a skill to ask anybody for.
   --------------------------------------------------------------------------- */
.hd-ghost { position: fixed; z-index: 56; pointer-events: none;
  border: 2px dashed var(--hair-2); background: rgba(181, 37, 85, .08);
  opacity: 0; transform: scale(.9);
  transition: opacity .18s var(--ease), transform .3s var(--spring),
    border-color .16s var(--ease), background .16s var(--ease) }
.hd-ghost[hidden] { display: none }
.hd-ghost.orb { border-radius: 50% }
.hd-ghost.tab { border-radius: 0 16px 16px 0 }
.hd-wrap.hd-ghosting .hd-ghost { opacity: 1; transform: none }
.hd-wrap.hd-ghost-hot .hd-ghost { border-color: var(--secondary);
  background: rgba(181, 37, 85, .26); transform: scale(1.06) }

/* the control being carried rides above everything, including its own ghost */
.hd-wrap.hd-lifted .hd-tab, .hd-wrap.hd-lifted .hd-orb { z-index: 60;
  transition: none; box-shadow: 0 18px 44px rgba(0, 0, 0, .5) }

@media (prefers-reduced-motion: reduce) {
  .hd-ghost { transition: opacity .15s linear }
}
