/* ══════════════════════════════════════════════════════════════
   SIMULATION EXPERIENCE — phone-first layer over the case page
   ══════════════════════════════════════════════════════════════
   Loaded after styles.css so these rules win without !important.
   Everything here is either phone-scoped or additive; the desktop
   case layout is untouched.

   Read simRunner.js first — it owns the behaviour these styles
   dress: scroll ownership, the draft mirror, the vitals mirror and
   the body.kb-open signal.
   ══════════════════════════════════════════════════════════════ */

/* ── Transcript hygiene (all widths) ──────────────────────────────── */

/* Lab and vitals tables are the widest thing the model emits. Without
   this they stretch .ma and put the WHOLE case into horizontal scroll —
   the narrative goes off-screen to fix a table. Scroll the table
   instead, and let cells wrap. */
#chat .msg table { display: block; overflow-x: auto; max-width: 100%; }
#chat .msg th, #chat .msg td { white-space: normal; }
#chat .msg { overflow-wrap: anywhere; }

/* .ma is smooth-scrolling, which fights a programmatic jump to the
   bottom mid-stream. transcriptScroll.js opts into smooth only for the
   deliberate "jump to latest" press. */
#chat .ma { scroll-behavior: auto; overscroll-behavior-y: contain; }

/* ── Jump to latest ───────────────────────────────────────────────── */
/* Only appears when the learner has scrolled away from the bottom. It
   is the visible half of the scroll-ownership rule: new updates stop
   stealing the viewport, and this is how you get back.
   2026-10-04 (owner): a round down-arrow button, no text — the words are
   its accessible name and tooltip (simRunner.js). */
.sim-jump-latest {
  position: absolute; left: 50%; transform: translateX(-50%);
  bottom: calc(var(--sjl-bottom, 92px) + env(safe-area-inset-bottom, 0px));
  z-index: 6; display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; min-height: 44px; padding: 0;
  border: 1px solid var(--border); border-radius: 50%;
  background: var(--bg-card); color: var(--text-primary);
  box-shadow: 0 6px 20px rgba(0, 0, 0, .28); cursor: pointer;
  transition: background .15s, border-color .15s, color .15s;
}
.sim-jump-latest[hidden] { display: none; }
.sim-jump-latest:hover { background: var(--bg-card-hover, var(--bg-secondary)); }
.sim-jump-latest:focus-visible { outline: 3px solid var(--accent-cyan); outline-offset: 3px; }
.sim-jump-latest .sjl-arrow { display: block; width: 22px; height: 22px; }
.sim-jump-latest .sjl-label { display: none; }
/* Something actually arrived while they were reading — show how much, in
   the same cyan the app uses for "new to you". */
.sim-jump-latest.sjl-has-new { border-color: var(--accent-cyan); color: var(--accent-cyan); }
.sim-jump-latest .sjl-badge {
  position: absolute; top: -5px; right: -5px;
  min-width: 18px; height: 18px; padding: 0 4px; border-radius: 999px;
  background: var(--accent-cyan); color: #06222a;
  font-family: 'DM Sans', sans-serif; font-size: .62rem; font-weight: 800; line-height: 18px; text-align: center;
  box-shadow: 0 0 0 2px var(--bg-primary);
}
.sim-jump-latest .sjl-badge:empty { display: none; }

/* .chat-main is the positioning context for the pill. */
#chat .chat-main { position: relative; min-height: 0; }

/* ── Sticky vitals strip ──────────────────────────────────────────── */
/* Desktop keeps vitals in the transcript where there is room for them.
   This is a phone affordance, so it is hidden by default and switched
   on in the ≤600px block below. */
.sim-vitals-bar { display: none; }

/* ── Phones ───────────────────────────────────────────────────────── */
@media (max-width: 600px) {
  .sim-vitals-bar {
    display: flex; align-items: center; gap: .4rem;
    flex-shrink: 0; padding: .35rem .5rem;
    background: var(--bg-secondary);
    border-bottom: 1px solid var(--border);
  }
  .sim-vitals-bar[hidden] { display: none; }
  .sim-vitals-bar .svb-rail {
    display: flex; gap: .3rem; overflow-x: auto; flex: 1; min-width: 0;
    scrollbar-width: none; -webkit-overflow-scrolling: touch;
  }
  .sim-vitals-bar .svb-rail::-webkit-scrollbar { display: none; }
  .sim-vitals-bar .vs-item { flex: 0 0 auto; font-size: .7rem; padding: .2rem .45rem; }
  .sim-vitals-bar .svb-jump {
    flex: 0 0 auto; width: 34px; height: 34px; border-radius: 8px;
    border: 1px solid var(--border); background: var(--bg-card);
    color: var(--text-secondary); font-size: .9rem; line-height: 1; cursor: pointer;
  }
  .sim-vitals-bar .svb-jump:focus-visible { outline: 2px solid var(--accent-cyan); outline-offset: 2px; }

  /* Composer clears the home indicator. */
  #chat .input-area {
    padding: .5rem max(.6rem, env(safe-area-inset-right))
             max(.5rem, env(safe-area-inset-bottom)) max(.6rem, env(safe-area-inset-left));
  }
  /* Grid, not flex: the textarea gets every pixel the two buttons don't
     need, instead of flex-shrinking below a usable width when the
     "I'm not sure" label is long. */
  #chat .input-row { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: .35rem; align-items: end; }
  #chat #ci { width: 100%; min-width: 0; }
  /* 2026-10-12k: a helper row ABOVE the text box holds the two secondary
     actions as labelled chips — "🤔 I'm not sure" and the chart-question
     link — so neither is a mystery icon beside the box (users could not
     tell the two text boxes apart, nor what the 🤔 was). The field itself
     unfolds under them; the text box and Send keep the whole bottom row. */
  #chat .input-row { grid-template-areas: "uns help help" "clar clar clar" "ci ci send"; row-gap: .3rem; }
  #chat .ci-col { display: contents; }
  #chat .clarify-toggle-row { grid-area: help; justify-content: flex-start; min-width: 0; }
  #chat .clarify-row { grid-area: clar; width: 100%; margin: 0; }
  #chat #ci { grid-area: ci; }
  #chat .unsure-btn { grid-area: uns; align-self: center; }
  #chat #send-btn { grid-area: send; }
  #chat #send-btn { min-width: 48px; min-height: 48px; }
  #chat .msg table { font-size: .875rem; }
  #chat .msg th, #chat .msg td { min-width: 72px; }

  /* Pill sits above the composer; the composer is ~92px with one line
     of text plus the PHI notice. */
  .sim-jump-latest { --sjl-bottom: 100px; }
}

/* ── Keyboard open (phones) ───────────────────────────────────────── */
/* simRunner.js sets body.kb-open from visualViewport. The keyboard eats
   roughly 45% of a phone screen, so while it is up we spend what is
   left on the newest turn and the composer: the vitals mirror, the
   in-case utility rail and the standing PHI line all stand down. They
   return the moment the keyboard closes — nothing is permanently
   hidden, and nothing here removes a control the learner needs to
   finish the action they are typing. */
@media (max-width: 600px) {
  body.kb-open.page-chat .sim-vitals-bar { display: none; }
  body.kb-open.page-chat #chat .input-area .cph { display: none; }
  body.kb-open.page-chat .util-rail { display: none; }
  body.kb-open.page-chat .chat-theme-fab,
  body.kb-open.page-chat .chat-customize-fab { display: none; }
  /* The pill would otherwise sit under the keyboard. */
  body.kb-open.page-chat .sim-jump-latest { --sjl-bottom: 72px; }
}

/* ── Landscape phones ─────────────────────────────────────────────── */
/* A 375×812 phone on its side has ~320px of height, most of it
   keyboard. Trim the chrome rather than the case. */
@media (max-height: 500px) and (max-width: 900px) {
  #chat .chat-header { padding-top: 2px; padding-bottom: 2px; }
  .sim-vitals-bar { padding-top: .2rem; padding-bottom: .2rem; }
  .sim-jump-latest { --sjl-bottom: 76px; }
}

/* ── Reduced motion ───────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  #chat .ma { scroll-behavior: auto !important; }
  .sim-jump-latest { transition: none !important; }
}

/* ── Debrief contents rail ────────────────────────────────────────── */
/* Navigation, not disclosure: every section stays open. Feedback a
   learner never scrolls to is feedback they did not get — the rail only
   makes each part reachable in one tap. See enhanceFeedbackMessage() in
   simRunner.js. */
.msg-ai .fb-rail {
  display: flex; flex-wrap: wrap; gap: .35rem;
  justify-content: center; /* 2026-09-27: chips centred over the debrief */
  margin: 0 0 .85rem; padding-bottom: .7rem;
  border-bottom: 1px solid var(--border);
}
.msg-ai .fb-chip {
  min-height: 36px; padding: .3rem .7rem;
  border: 1px solid var(--border); border-radius: 999px;
  background: var(--bg-secondary); color: var(--text-secondary);
  font-family: 'DM Sans', sans-serif; font-size: .74rem; font-weight: 600;
  cursor: pointer; white-space: nowrap;
}
.msg-ai .fb-chip:hover { color: var(--text-primary); border-color: var(--accent-cyan); }
.msg-ai .fb-chip:focus-visible { outline: 2px solid var(--accent-cyan); outline-offset: 2px; }

/* Scroll the heading clear of the sticky vitals strip. */
.msg-ai .fb-section-head { scroll-margin-top: 64px; }
/* A jump that lands mid-message is disorienting without a confirmation
   that something moved — flash the heading you asked for. */
.msg-ai .fb-section-flash {
  animation: fbFlash 1.2s ease-out;
  border-radius: 6px;
}
@keyframes fbFlash {
  0%   { background: color-mix(in srgb, var(--accent-cyan) 28%, transparent); }
  100% { background: transparent; }
}
@media (prefers-reduced-motion: reduce) {
  .msg-ai .fb-section-flash { animation: none; outline: 2px solid var(--accent-cyan); outline-offset: 3px; }
}

@media (max-width: 600px) {
  /* The rail is worth a sticky row on a phone: the feedback is 6-10
     screens and the rail is how you move around it. */
  .msg-ai .fb-rail {
    position: sticky; top: 0; z-index: 2;
    flex-wrap: nowrap; overflow-x: auto;
    margin: -.2rem -.2rem .85rem; padding: .45rem .2rem .5rem;
    background: var(--bg-card); scrollbar-width: none;
  }
  .msg-ai .fb-rail::-webkit-scrollbar { display: none; }
  .msg-ai .fb-chip { flex: 0 0 auto; }
  /* A scrolling row must start at its left edge or the first chips are
     unreachable, so centre with auto margins instead: they collapse to 0
     the moment the chips overflow. */
  .msg-ai .fb-rail { justify-content: flex-start; }
  .msg-ai .fb-chip:first-child { margin-left: auto; }
  .msg-ai .fb-chip:last-child { margin-right: auto; }
}

/* ── In-case toolbar: one scrollable row of icons ─────────────────── */
/* Measured on a 375x812 phone before this rule: 243px of chrome above
   the transcript — 30% of the screen — because the seven tool buttons
   carry their text labels, wrap onto two rows, and the header grows to
   165px. The case itself got 477px.
   The buttons keep their 44px touch target and gain a real accessible
   name from aria-label in index.html (the emoji is the visible content
   once the label is hidden, and content beats title, so a screen reader
   would otherwise announce "book"). One row that scrolls beats two rows
   that wrap: nothing is removed, the row just does not eat the case. */
@media (max-width: 600px) {
  #chat .chat-header { padding-top: .35rem; padding-bottom: .35rem; gap: .35rem; }
  #chat .ch-right {
    display: flex; flex-wrap: nowrap; width: 100%; min-width: 0;
    overflow-x: auto; gap: .3rem; padding-bottom: 2px;
    scrollbar-width: none; -webkit-overflow-scrolling: touch;
  }
  #chat .ch-right::-webkit-scrollbar { display: none; }
  #chat .ch-right .hdr-btn {
    flex: 0 0 auto; min-width: 44px; min-height: 44px;
    justify-content: center; padding: .3rem .5rem; font-size: 1.05rem;
  }
  #chat .ch-right .hdr-btn-label { display: none; }
  /* The count chips stay — they are the reason to open those panels. */
  #chat .ch-right .fc-chip { margin-left: .15rem; }
}

/* A rail that scrolls should look like one. The mask fades the last chip
   rather than slicing a word in half, which reads as a layout bug. */
@media (max-width: 600px) {
  #chat .ch-right,
  #chat #ch-badges,
  .sim-vitals-bar .svb-rail,
  .msg-ai .fb-rail {
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 22px), transparent 100%);
    mask-image: linear-gradient(to right, #000 calc(100% - 22px), transparent 100%);
  }
  /* No fade once you are at the end of the rail. */
  #chat .ch-right.rail-end,
  #chat #ch-badges.rail-end,
  .sim-vitals-bar .svb-rail.rail-end,
  .msg-ai .fb-rail.rail-end { -webkit-mask-image: none; mask-image: none; }
}

/* ── Composer: the helper row ─────────────────────────────────────── */
/* The text box has the whole bottom row to itself now, so "I'm not sure"
   can afford its words again: it is a quiet labelled chip in the helper
   row above the box, beside the chart-question link, styled as a pair.
   (Before 2026-10-12k it was a bare 🤔 icon beside the box — nobody could
   tell it was the help button.) 34px chips keep the row to one line at
   375px; the touch target is padded by the row's own gap. */
@media (max-width: 600px) {
  #chat .unsure-btn { min-width: 0; min-height: 34px; padding: .25rem .65rem; border-radius: 999px; font-size: .74rem; font-weight: 700; gap: .25rem; white-space: nowrap; }
  #chat .unsure-btn-label { display: inline; }
  #chat .clarify-toggle { min-height: 34px; padding: .25rem .6rem; font-size: .72rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
}

/* Debrief section descriptions (2026-10-03): one quiet line under each
   heading saying what the section contains. */
.msg-ai .fb-section-head .fb-section-sub{display:block;margin-top:.12rem;font-size:.72rem;font-weight:500;letter-spacing:0;text-transform:none;color:var(--text-dim);}

/* ── Quick chart questions (2026-10-04, folded 2026-10-12k) ──────── */
/* The link adds a short row to the composer; the unfolded field adds a
   taller one. Keep the floating controls above whichever is showing
   (simulation_clarify.js sets body.sim-clarify-on while the link shows and
   body.sim-clarify-open while the field is unfolded). */
body.sim-clarify-on .sim-jump-latest { --sjl-bottom: 128px; }
body.sim-clarify-open .sim-jump-latest { --sjl-bottom: 172px; }
@media (max-width: 600px) {
  body.sim-clarify-on .sim-jump-latest { --sjl-bottom: 146px; }
  body.sim-clarify-open .sim-jump-latest { --sjl-bottom: 190px; }
  body.kb-open.page-chat.sim-clarify-on .sim-jump-latest { --sjl-bottom: 116px; }
  body.kb-open.page-chat.sim-clarify-open .sim-jump-latest { --sjl-bottom: 160px; }
  body.page-chat.sim-clarify-on .util-rail { bottom: calc(env(safe-area-inset-bottom, 0px) + 150px); }
  body.page-chat.sim-clarify-open .util-rail { bottom: calc(env(safe-area-inset-bottom, 0px) + 194px); }
}
@media (max-height: 500px) and (max-width: 900px) {
  body.sim-clarify-on .sim-jump-latest { --sjl-bottom: 118px; }
  body.sim-clarify-open .sim-jump-latest { --sjl-bottom: 160px; }
}

/* ══════════════════════════════════════════════════════════════
   2026-10-12k — PHONE CHROME: a header that reads, a tools sheet,
   and the keyboard fix. Appended last so it wins by order.
   ══════════════════════════════════════════════════════════════ */

/* ── Keyboard: pin the case page to the visible strip ─────────────── */
/* iOS pans the visual viewport to reveal the focused textarea BEFORE the
   page has shrunk to --app-vh; left alone, the shrunken page then sits
   scrolled half off the top — composer under the status bar, blank page
   background between it and the keyboard. simRunner.js publishes where
   the visible strip starts (--vv-top = visualViewport.offsetTop) while
   the keyboard is up; the page is pinned to exactly that strip. */
@media (max-width: 600px) {
  body.kb-open.page-chat #chat.active {
    position: fixed; left: 0; right: 0;
    top: var(--vv-top, 0px);
    height: var(--app-vh, 100dvh);
  }
  /* The same for the full-screen drawers (2026-10-13): the Debrief
     questions box, the orders search / custom-order box and the lookup
     panels' search fields sat behind the keyboard — each drawer is fixed
     top:0 / bottom:0, so its footer input was under the keys. Pinned to
     the visible strip, the input row sits right above the keyboard. */
  body.kb-open.page-chat .qs-panel:not(.qp-hide),
  body.kb-open.page-chat .ref-panel:not(.rp-hide),
  body.kb-open.page-chat .orders-panel:not(.op-hide),
  body.kb-open.page-chat .hist-panel:not(.hp-hide) {
    top: var(--vv-top, 0px); bottom: auto; height: var(--app-vh, 100dvh);
  }
  /* And the post-case flashcard editor (and its cousins): the overlay
     fills the visible strip and the dialog scrolls inside it, so the
     explanation box can always be brought above the keyboard. */
  body.kb-open .sim-fce-overlay,
  body.kb-open .fc-preview-overlay,
  body.kb-open .drills-overlay,
  body.kb-open .lib-note-modal-overlay {
    top: var(--vv-top, 0px); bottom: auto; height: var(--app-vh, 100dvh);
    align-items: flex-start; padding-top: .5rem;
  }
  body.kb-open .sim-fce { max-height: calc(var(--app-vh, 100dvh) - 1rem); }
  body.kb-open .fc-preview-overlay > .fc-preview-modal,
  body.kb-open .lib-note-modal-overlay > .lib-note-modal,
  body.kb-open .drills-overlay > .drills-modal { max-height: calc(var(--app-vh, 100dvh) - 1rem); }
}

/* ── Header (phones): two labelled buttons, one scrolling badge line ── */
@media (max-width: 600px) {
  /* Seven emoji with no words were the complaint. Everything but Orders
     folds into the Tools sheet (simMobileTools.js). */
  #chat .ch-right #ref-btn, #chat .ch-right #labref-btn, #chat .ch-right .qs-btn,
  #chat .ch-right .fc-btn, #chat .ch-right .hist-btn, #chat .ch-right .end-btn { display: none !important; }
  /* The right cluster no longer needs its own scrolling row: it sits on the
     title row, and the badges take the second row. */
  #chat .chat-header { align-items: center; }
  #chat .ch-left { flex: 1 1 0; min-width: 0; }
  #chat .ch-right {
    width: auto; flex: 0 0 auto; margin-left: auto; overflow: visible; padding-bottom: 0;
    -webkit-mask-image: none; mask-image: none;
  }
  #chat .ch-right .hdr-btn { font-size: .82rem; padding: .3rem .65rem; gap: .3rem; border-radius: 10px; }
  #chat .ch-right .orders-btn .hdr-btn-label,
  #chat .ch-right .sim-tools-btn .hdr-btn-label { display: inline; font-size: .74rem; font-weight: 700; letter-spacing: .01em; }
  #chat .ch-right .orders-btn { border-color: color-mix(in srgb, var(--accent-orange) 55%, var(--border)); color: var(--text-primary); }
  #chat .sim-tools-btn { position: relative; }
  #chat .sim-tools-btn .sim-tools-ic { display: block; }
  /* Badges: one line that scrolls sideways rather than three that wrap. */
  #chat #ch-badges { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; gap: .3rem; -webkit-overflow-scrolling: touch; }
  #chat #ch-badges::-webkit-scrollbar { display: none; }
  #chat #ch-badges .badge { flex: 0 0 auto; white-space: nowrap; }
  /* Theme and border circles stand down on phones: theme lives in the
     sheet, the border customizer stays a desktop / landing affordance. */
  body.page-chat .chat-theme-fab, body.page-chat .chat-customize-fab { display: none !important; }
  /* The floating ‹ rail nub too (2026-10-13, owner: "inappropriately
     placed" over the orders panel). Feedback is in the Tools sheet. */
  body.page-chat .util-rail { display: none !important; }
}
/* Desktop keeps the full toolbar. */
@media (min-width: 601px) {
  #chat .sim-tools-btn, .sim-tools-sheet, .sim-tools-backdrop { display: none !important; }
}

/* ── Tools sheet ──────────────────────────────────────────────────── */
/* The sheet lives inside #chat, whose own stacking context sits UNDER the
   body-level fixed chrome (the utility rail's ‹ nub, z 220). Stand that
   chrome down while the sheet is open so nothing floats over a row. */
body.sim-tools-open .util-rail, body.sim-tools-open .sim-jump-latest { display: none !important; }
.sim-tools-backdrop { position: fixed; inset: 0; z-index: 10590; background: rgba(5, 8, 14, .55); }
.sim-tools-backdrop[hidden], .sim-tools-sheet[hidden] { display: none; }
.sim-tools-sheet {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 10600;
  background: var(--bg-card); color: var(--text-primary);
  border: 1px solid var(--border); border-bottom: none; border-radius: 18px 18px 0 0;
  box-shadow: 0 -12px 40px rgba(0, 0, 0, .35);
  padding: .4rem .75rem calc(.8rem + env(safe-area-inset-bottom, 0px));
  max-height: min(78vh, calc(var(--app-vh, 100dvh) - 3rem)); overflow-y: auto;
  font-family: 'DM Sans', sans-serif;
}
.sim-tools-grip { width: 40px; height: 4px; border-radius: 999px; background: var(--border-light, var(--border)); margin: .25rem auto .6rem; }
.sim-tools-hdr { display: flex; align-items: center; justify-content: space-between; padding: 0 .15rem .45rem; }
.sim-tools-hdr h3 { margin: 0; font-family: 'JetBrains Mono', monospace; font-size: .8rem; font-weight: 700; letter-spacing: .02em; }
.sim-tools-x { width: 36px; height: 36px; border-radius: 50%; border: 1px solid var(--border); background: var(--bg-secondary); color: var(--text-secondary); font-size: .95rem; cursor: pointer; }
.sim-tools-x:focus-visible, .sim-tool:focus-visible { outline: 2px solid var(--accent-cyan); outline-offset: 2px; }
.sim-tools-list { display: flex; flex-direction: column; gap: .35rem; }
.sim-tool {
  display: grid; grid-template-columns: 40px minmax(0, 1fr) auto; align-items: center; gap: .7rem;
  width: 100%; min-height: 56px; padding: .5rem .65rem; border-radius: 12px;
  border: 1px solid var(--border); background: var(--bg-secondary); color: var(--text-primary);
  text-align: left; font-family: 'DM Sans', sans-serif; cursor: pointer;
}
.sim-tool:active { background: var(--bg-card-hover, var(--bg-secondary)); }
.sim-tool-ic { width: 40px; height: 40px; display: inline-flex; align-items: center; justify-content: center; border-radius: 10px; background: var(--bg-card); font-size: 1.15rem; }
.sim-tool-txt { display: flex; flex-direction: column; min-width: 0; gap: .1rem; }
.sim-tool-t { font-size: .86rem; font-weight: 700; line-height: 1.25; }
.sim-tool-s { font-size: .7rem; color: var(--text-dim); line-height: 1.35; }
.sim-tool-n { min-width: 24px; height: 24px; padding: 0 .45rem; border-radius: 999px; background: var(--accent-cyan); color: #06222a; font-size: .72rem; font-weight: 800; display: inline-flex; align-items: center; justify-content: center; }
.sim-tool-state { font-family: 'JetBrains Mono', monospace; font-size: .64rem; font-weight: 700; color: var(--accent-cyan); border: 1px solid color-mix(in srgb, var(--accent-cyan) 45%, var(--border)); border-radius: 999px; padding: .15rem .5rem; }
.sim-tool-chev { color: var(--text-dim); font-size: 1.15rem; padding-right: .2rem; }
.sim-tool.is-danger { border-color: color-mix(in srgb, var(--accent-red) 45%, var(--border)); }
.sim-tool.is-danger .sim-tool-t { color: var(--accent-red); }
.sim-tools-dot { position: absolute; top: 5px; right: 5px; width: 9px; height: 9px; border-radius: 50%; background: var(--accent-cyan); box-shadow: 0 0 0 2px var(--bg-secondary); }
.sim-tools-dot[hidden] { display: none; }
@media (prefers-reduced-motion: no-preference) {
  .sim-tools-sheet:not([hidden]) { animation: simSheetUp .22s ease-out; }
}
@keyframes simSheetUp { from { transform: translateY(24px); opacity: .6; } to { transform: none; opacity: 1; } }
