/* ==========================================================================
   Factbox reader (read.html) — the ambient-sound control, and nothing else.

   No layout is owned here. Every rule below is position:fixed, so this file
   can be added to or removed from the build without moving a single pixel of
   the deck. It defines only .fb-sound and .fb-sound-note, both of which are
   created by js/audio-reader.js and exist nowhere else in the site.

   WHERE IT SITS
   -------------
   * TOP-RIGHT by default, which is where the composed story pages
     (story.html and its copies) still put it: the reader's "← Stories" pill
     is fixed top-LEFT (.topbar, z 31 in app.css) and this is its mirror —
     same rail (--top-safe), same glass, same pill radius, same press.
   * ON read.html it is a flex item in .fb-rail instead, the column at the
     foot of the right edge it now shares with the Save bookmark. That rule
     lives in css/reader-rail.css, which read.html loads after this file and
     which owns the rail's geometry; nothing here has to know about it beyond
     leaving position:fixed overridable. js/audio-reader.js picks the mount.
   * NOT the bottom of the viewport, in either home. --bottom-safe in app.css
     is max(13vh, toolbar + inset) for one reason: the Instagram and TikTok
     in-app browsers draw their own toolbar over the bottom of the viewport,
     and ~all of our traffic is in one of them. A control below that line is a
     control that cannot be tapped. The rail's floor sits ON the line.
   * z-index 32 — one above .topbar (31) and the progress bar (30), so a card's
     own stacking context can never bury it.
   ========================================================================== */

.fb-sound{
  position:fixed;
  right:12px;
  /* Same rail as the back pill. The fallback repeats app.css's own definition
     so this file is also correct if loaded standalone. */
  top:var(--top-safe, calc(env(safe-area-inset-top, 0px) + 12px));
  z-index:32;

  appearance:none;-webkit-appearance:none;
  font:inherit;cursor:pointer;
  /* Icon only, so a circle: 38px matches .back's height in app.css, and the
     button is the same glass pill as the back button with nothing written in
     it. The words came off because the control sits over a painting. */
  min-height:38px;width:38px;
  display:inline-flex;align-items:center;justify-content:center;
  padding:0;
  border-radius:var(--pill);
  border:0;
  /* Dark glass in both grounds: on read.html this sits on a painting, and on
     the composed story pages the whole document is night. */
  box-shadow:inset 0 0 0 1px var(--hair);
  background:var(--glass-deep);
  -webkit-backdrop-filter:blur(16px) saturate(1.2);
  backdrop-filter:blur(16px) saturate(1.2);
  color:var(--on-glass);
  font-family:var(--ui);
  font-size:var(--fs-meta);font-weight:var(--w-strong);letter-spacing:.01em;line-height:1;
  transition:background .2s ease, box-shadow .2s ease,
             transform .12s ease, opacity .3s ease;
}
.fb-sound:active{transform:scale(.96)}
/* app.css's :focus-visible already draws the site's ring in the site's ring
   colour, and --ring is a var() indirection that resolves to the writeable
   accent wherever it is used. This rule used to name --coral, which is the
   FILL and is 2.2:1 as a line. */

.fb-sound .ico{
  width:17px;height:17px;flex:none;display:block;
  color:var(--dimmer);
  transition:color .25s ease;
}
.fb-sound .ico svg{width:100%;height:100%;display:block;overflow:visible}
.fb-sound .ico .wav,
.fb-sound .ico .cut{transition:opacity .22s ease}
.fb-sound .ico .wav{opacity:0}
.fb-sound .ico .cut{opacity:1}

/* ---- on ----------------------------------------------------------------
   The state is the ICON, not the pill: waves instead of a cross, in the
   accent you may write in. --accent-ink is #8FC4FA on the reader's night
   ground (10.1:1) and the ring is the accent's own hairline. --coral is a
   fill and is never a 1px line. */
.fb-sound.is-on{
  box-shadow:inset 0 0 0 1px var(--accent-edge);
  background:var(--glass-deep);
}
.fb-sound.is-on .ico{color:var(--accent-ink)}
.fb-sound.is-on .ico .wav{opacity:1}
.fb-sound.is-on .ico .cut{opacity:0}

/* ---- loading ------------------------------------------------------------
   Between the tap and the first sound there is a JSON fetch and a bed fetch.
   On cellular that can be a second or two of nothing, which is exactly the
   moment a reader decides the page is broken — so the waves breathe while it
   is in flight, and stop the instant something decodes. */
.fb-sound.is-busy .ico .wav{animation:fb-breathe 1.15s ease-in-out infinite}
@keyframes fb-breathe{0%,100%{opacity:1}50%{opacity:.25}}

/* There is no "look at me" pulse any more: sound turns itself on with the
   reader's first swipe, so the control has nothing left to advertise. */

/* ---- dead: no beds on the server, or every fetch failed -----------------
   It says so once, then takes itself off the page rather than sitting there as
   a button that does nothing. */
.fb-sound.is-dead{
  pointer-events:none;
  color:var(--dimmer);
  box-shadow:inset 0 0 0 1px var(--hair);
}
.fb-sound.is-dead .ico{color:var(--dimmer)}
.fb-sound.is-gone{opacity:0;transform:translateY(-4px)}

/* --------------------------------------------------------------------------
   The note.

   One line of glass under the pill, for one job: iOS mutes web audio when the
   hardware silent switch is on, there is no API that can detect it, and a
   reader who taps Sound and hears nothing concludes the page is broken. So the
   moment sound actually starts we say where to look. Once per device, ever.
   -------------------------------------------------------------------------- */
.fb-sound-note{
  position:fixed;
  right:12px;
  top:calc(var(--top-safe, calc(env(safe-area-inset-top, 0px) + 12px)) + 46px);
  z-index:32;
  max-width:min(17em, calc(100vw - 24px));
  padding:.6em .85em;
  border-radius:14px;
  box-shadow:inset 0 0 0 1px var(--hair);
  background:var(--glass-deep);
  -webkit-backdrop-filter:blur(18px) saturate(1.2);
  backdrop-filter:blur(18px) saturate(1.2);
  color:var(--on-glass);
  font-family:var(--ui);
  font-size:var(--fs-fine);font-weight:var(--w-label);line-height:1.4;letter-spacing:.005em;
  text-align:right;
  pointer-events:none;
  opacity:0;transform:translateY(-6px);
  transition:opacity .3s ease, transform .3s cubic-bezier(.2,.75,.25,1);
}
.fb-sound-note.on{opacity:1;transform:none}

/* --------------------------------------------------------------------------
   Reduced motion. app.css reads it as "no animation"; this file reads it as a
   hint about this reader in general — the control stops drawing attention to
   itself, and the beds play at LEVEL_CALM (that part lives in the JS).
   Sound stays available: an explicit tap is still an explicit tap.
   -------------------------------------------------------------------------- */
html.no-motion .fb-sound,
html.no-motion .fb-sound .ico .wav{animation:none}
html.no-motion .fb-sound.is-busy{opacity:.72}
html.no-motion .fb-sound-note{transition:opacity .01s linear;transform:none}
@media (prefers-reduced-motion: reduce){
  .fb-sound,.fb-sound .ico .wav{animation:none}
  .fb-sound.is-busy{opacity:.72}
  .fb-sound-note{transition:opacity .01s linear;transform:none}
}

/* Very short viewports (a phone in landscape). The button is already a 38px
   circle at every width, so only the note needs to give ground. */
@media (max-height:420px), (max-width:340px){
  .fb-sound-note{font-size:.7rem}
}
