/* Calmhaven custom emoji. Static glyphs are one <use> each; animated ones are cloned real nodes so these
   rules can reach them — a <use> shadow tree ignores document CSS. */
.ch-emoji{
  display:inline-block;
  width:1.55em;
  height:1.55em;
  vertical-align:-.42em;
  margin:0 .06em;
  flex-shrink:0;
  --ch-emoji-play:paused;
}
.ch-emoji:hover,
.ch-emoji:focus-visible,
.ch-choice:hover .ch-emoji,
.ch-choice:focus-visible .ch-emoji,
.ch-emoji.ch-playing{--ch-emoji-play:running}
@media (prefers-reduced-motion:reduce){
  .ch-emoji{--ch-emoji-play:paused!important}
  .ch-emoji [class^="ch-anim"]{animation-name:none!important}
}

/* Every animated part is a wrapper group: transform and opacity are inherited through <use> and land on
   the real clone, so nothing here needs to reach inside the referenced geometry. The longhand names below
   deliberately do NOT touch play-state — that stays here, last, so it cannot be reset by a shorthand. */
.ch-anim-beat{animation-name:chBeat;animation-duration:1.15s;animation-timing-function:cubic-bezier(.4,.1,.3,1)}
.ch-anim-streak{animation-name:chStreak;animation-duration:1.4s;animation-timing-function:linear}
.ch-anim-float{animation-name:chFloat;animation-duration:2.4s}
.ch-anim-twinkle{animation-name:chTwinkle;animation-duration:1.6s}
.ch-anim-flicker{animation-name:chFlicker;animation-duration:.42s;animation-direction:alternate}
.ch-anim-flash{animation-name:chFlash;animation-duration:1.1s;animation-timing-function:steps(1,end)}
.ch-anim-pulse{animation-name:chPulse;animation-duration:1s}
.ch-anim-spin{animation-name:chSpin;animation-duration:3.2s;animation-timing-function:linear}
.ch-anim-jerk{animation-name:chJerk;animation-duration:.8s;animation-timing-function:steps(1,end)}
.ch-anim-zzz{animation-name:chZzz;animation-duration:2.2s}
.ch-anim-puff{animation-name:chPuff;animation-duration:.7s;animation-direction:alternate}
.ch-anim-wave{animation-name:chWave;animation-duration:.9s}
.ch-emoji [class^="ch-anim"]{
  transform-box:fill-box;
  transform-origin:center;
  animation-iteration-count:infinite;
  animation-play-state:var(--ch-emoji-play,paused);
}

@keyframes chBeat{0%,100%{transform:scale(1)}18%{transform:scale(1.16)}32%{transform:scale(.97)}46%{transform:scale(1.08)}}
@keyframes chStreak{0%{transform:translateX(4px)}50%{transform:translateX(-5px)}100%{transform:translateX(4px)}}
@keyframes chFloat{0%,100%{transform:translateY(2px);opacity:.85}50%{transform:translateY(-4px);opacity:1}}
@keyframes chTwinkle{0%,100%{transform:scale(1) rotate(0)}45%{transform:scale(.82) rotate(-12deg)}70%{transform:scale(1.12) rotate(8deg)}}
@keyframes chFlicker{from{transform:scaleY(.9) scaleX(1.04)}to{transform:scaleY(1.06) scaleX(.95)}}
@keyframes chFlash{0%,62%,100%{opacity:1}66%,74%{opacity:.25}78%{opacity:1}}
@keyframes chPulse{0%,100%{transform:scale(1)}40%{transform:scale(1.12)}}
@keyframes chSpin{from{transform:rotate(0)}to{transform:rotate(360deg)}}
@keyframes chJerk{0%,100%{transform:translate(0)}20%{transform:translate(-2px,1px)}40%{transform:translate(2px,-1px)}60%{transform:translate(-1px,-2px)}80%{transform:translate(1px,2px)}}
@keyframes chZzz{0%{transform:translate(0,0);opacity:.35}40%{opacity:1}100%{transform:translate(6px,-8px);opacity:0}}
@keyframes chPuff{from{transform:translateY(1px) scale(.9)}to{transform:translateY(-2px) scale(1.1)}}
@keyframes chWave{0%,100%{transform:rotate(0)}35%{transform:rotate(16deg)}70%{transform:rotate(-10deg)}}

/* Picker: the pack is 40+ tiles, so the existing popup scrolls instead of running off the composer. */
.emoji-picker.ch-picker{
  flex-wrap:wrap;
  align-content:flex-start;
  width:min(22rem,calc(100vw - 2.4rem));
  max-height:min(15rem,45vh);
  overflow-y:auto;
  scrollbar-width:thin;
  gap:.15rem;
  padding:.4rem;
}
.emoji-picker.ch-picker .emoji-choice{width:2.4rem;height:2.4rem;font-size:1.5rem;background:none;border:1px solid transparent}
.emoji-picker.ch-picker .emoji-choice .ch-emoji{width:1.7rem;height:1.7rem;vertical-align:middle;margin:0}
.emoji-picker.ch-picker .emoji-choice:hover,
.emoji-picker.ch-picker .emoji-choice:focus-visible{--ch-emoji-play:running}
/* Standing message for a panel that is still waiting on the sheet, so an early click shows a state
   instead of an empty box. */
.ch-picker-note{display:flex;align-items:center;gap:.45rem;flex:1 1 100%;padding:.55rem .4rem;font-size:.82rem;color:var(--ivory-4)}

/* Inline panel variant for the post composer: a static grid under the textarea, so it needs no
   positioning context and no chat.css dependency. */
.ch-emoji-panel{display:none;flex-wrap:wrap;gap:.15rem;margin:.45rem 0;padding:.4rem;
  border:1px solid var(--hairline);border-radius:var(--r-lg);background:rgba(18,13,32,.72);
  max-height:min(13rem,40vh);overflow-y:auto;scrollbar-width:thin}
.ch-emoji-panel.open{display:flex}
.ch-emoji-panel .emoji-choice{width:2.4rem;height:2.4rem;display:grid;place-items:center;padding:0;cursor:pointer;
  border:1px solid transparent;border-radius:var(--r-sm);background:none}
.ch-emoji-panel .emoji-choice .ch-emoji{width:1.7rem;height:1.7rem;margin:0}
.ch-emoji-panel .emoji-choice:hover,.ch-emoji-panel .emoji-choice:focus-visible{
  background:rgba(167,139,250,.14);border-color:rgba(167,139,250,.35);--ch-emoji-play:running}
.ch-panel-toggle{display:inline-flex;align-items:center;gap:.4rem;margin-top:.4rem;padding:.32rem .72rem;
  border:1px solid var(--hairline);border-radius:var(--r-pill);background:none;color:var(--ivory-3);
  font-size:.76rem;cursor:pointer}
.ch-panel-toggle:hover,.ch-panel-toggle[aria-expanded="true"]{color:var(--aurora);border-color:rgba(167,139,250,.5)}

/* Composer mirror — shows the message the way the room will paint it, before it is sent. */
.ch-type-preview{margin:.45rem 0;padding:.42rem .68rem;border:1px dashed var(--hairline);border-radius:var(--r-md);
  background:rgba(18,13,32,.45);color:var(--ivory-2);font-size:.92rem;line-height:1.55;word-break:break-word}
.ch-type-preview[hidden]{display:none}
.ch-type-preview::before{content:"will post as";display:block;margin-bottom:.15rem;
  color:var(--ivory-3);font-size:.62rem;letter-spacing:.09em;text-transform:uppercase}
.ch-token-unknown{color:#f0a8c8;text-decoration:underline wavy rgba(240,168,200,.65);text-underline-offset:3px}

/* The composer mirror. The wrapper takes the exact slot the textarea held, so a send button or attachment
   control beside the field cannot shift; the textarea stays inside it, in sync and invisible, because the
   send path, the counter and the form all still read its value. */
.ch-rich-wrap{position:relative}
.ch-shadow-input{
  position:absolute;left:0;top:0;width:100%;
  margin:0;z-index:0;opacity:0;pointer-events:none;overflow:hidden;resize:none
}
.ch-rich{
  position:relative;z-index:1;display:block;cursor:text;outline:none;
  -webkit-user-select:text;user-select:text
}
.ch-rich.is-empty::before{content:attr(data-placeholder);color:var(--ivory-4);pointer-events:none}
.ch-rich.is-disabled{color:var(--ivory-4);cursor:not-allowed}
/* A mirrored single-line field stays one line and scrolls sideways like the input it replaced, so a long
   title with a glyph in it never reflows the row or hides the caret. */
.ch-rich.is-single{white-space:nowrap;overflow-x:auto;overflow-y:hidden;scrollbar-width:none}
.ch-rich.is-single::-webkit-scrollbar{display:none}
.ch-rich.is-single .ch-emoji{width:1.15em;height:1.15em;vertical-align:-.22em}

/* A token becomes one atomic tile: caret skips over it whole and backspace deletes the whole glyph, so what
   the member sees in the box is exactly the sequence the room will paint. The glyph is kept under the line
   box so dropping one into a single-row composer does not push the send button sideways. */
.ch-chip{
  display:inline-flex;align-items:center;padding:.02em .2em;margin:0 .05em;border-radius:.42em;line-height:1;
  vertical-align:-.26em;
  background:rgba(167,139,250,.14);box-shadow:inset 0 0 0 1px rgba(167,139,250,.3)
}
.ch-chip .ch-emoji{margin:0}
.ch-rich .ch-emoji{width:1.34em;height:1.34em;vertical-align:baseline;--ch-emoji-play:running}
