/* ============================================================
   bt.css — the shared stylesheet (FE-03 §A2)

   Everything here is a PORT, not a design. Every colour, radius,
   size and spacing value below was lifted from the Apps Script
   source it replaces:

     .bt-auth-mode / #bt-auth   ← _authCardCss_()      BT_Auth.js:1348
     #bt-gate                   ← _shellBootstrapHtml_ BT_AuthWiring.js:151

   FE-00 §3.2 allows extracting duplicated CSS into one file
   because it changes BYTES, not PIXELS. It does not allow
   changing a value. If you find yourself improving a colour here,
   that is FE-05.

   The only additions are the skeleton rules at the bottom, which
   FE-03 §A2 pre-approves as the one parity exception ("today's
   blank-wait becomes a skeleton").
   ============================================================ */

/* ────────────────────────────────────────────────────────────
   THE AUTH CARD — login, auth-failed, forced PIN setup.

   _authCardCss_ styled a STANDALONE DOCUMENT, so it used bare
   `body`, `button`, `input`, `p`, `a` selectors. This front end is
   one document that also hosts the ported pages, and bare selectors
   would bleed into every one of them.

   So the same rules are scoped: body rules move onto
   `body.bt-auth-mode` (set by shell.js only while an auth view is
   showing, removed before any page renders), and everything else
   sits under `#bt-auth`. Same specificity relationships, same
   source order, same pixels.
   ──────────────────────────────────────────────────────────── */

/* ────────────────────────────────────────────────────────────
   THE SHELL CANVAS — added 2026-08-17 after iPhone testing.

   index.html carries NO page CSS. A page's own <style> only arrives
   when its fragment is injected, which is after the bundle returns
   (2.5s+). Until then the document is unstyled, so the skeleton sat
   on the browser default: WHITE.

   Both target pages are dark — #111 on the portal, #041e42 on weekly —
   so every single load opened with a white flash. On a phone that does
   not read as "loading", it reads as "broken", and it is the first
   thing a member sees on the slowest part of the app.

   Reported from iPhone Safari during FE-03a UAT. This is the same
   fill the old HtmlService pages got for free, because their CSS
   shipped inline in the document they were served as.

   Specificity note: each page's own `body { background: var(--bg) }`
   is the same specificity as this, and its <style> is appended to
   <head> AFTER this stylesheet, so source order hands the page the
   win the moment its fragment lands. Nothing here overrides a page.
   ──────────────────────────────────────────────────────────── */
html, body { background: #111; color: #eee; }

body.bt-auth-mode {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  background: #111; color: #eee; display: flex; align-items: center;
  justify-content: center; min-height: 100vh; margin: 0; padding: 1rem;
}

#bt-auth .card {
  background: #1e1e1e; border-radius: 12px; padding: 2rem; max-width: 420px;
  width: 100%; box-sizing: border-box; text-align: center;
  box-shadow: 0 4px 24px rgba(0,0,0,.5);
}
#bt-auth h1 { font-size: 1.4rem; margin-top: 0; }
#bt-auth p  { color: #aaa; line-height: 1.6; }
#bt-auth a  { color: #6ab0f5; }
#bt-auth input[type=email], #bt-auth input[type=password] {
  width: 100%; box-sizing: border-box; background: #2a2a2a;
  border: 1px solid #3a3a3a; border-radius: 8px; color: #eee;
  padding: .75rem .9rem; font-size: 1rem; margin: .5rem 0 1rem;
}
#bt-auth input[type=email]:focus, #bt-auth input[type=password]:focus {
  outline: none; border-color: #6ab0f5;
}
#bt-auth label {
  display: block; text-align: left; font-size: .85rem; color: #aaa; margin-bottom: -.25rem;
}
#bt-auth button {
  width: 100%; background: #6ab0f5; color: #111; font-weight: 600;
  border: 0; border-radius: 8px; padding: .8rem 1.4rem; font-size: 1rem;
  cursor: pointer;
}
#bt-auth button[disabled] { opacity: .55; cursor: default; }
#bt-auth button.secondary { background: #3a3a3a; color: #eee; }
#bt-auth .linkbtn {
  background: none; border: 0; color: #6ab0f5; font-size: .9rem;
  text-decoration: underline; cursor: pointer; padding: .5rem 0; width: auto;
}
#bt-auth .btn {
  display: inline-block; background: #6ab0f5; color: #111; font-weight: 600;
  text-decoration: none; padding: .7rem 1.4rem; border-radius: 8px; margin: .75rem 0;
}
#bt-auth .fine { font-size: .85rem; color: #888; }

/* pre-line so the echoed address can sit on its own line — see the
   "Sent to:" line in shell.js's link handler. */
#bt-auth .msg {
  margin-top: 1rem; font-size: .95rem; color: #9fd0a0; line-height: 1.5;
  display: none; white-space: pre-line;
}

/* ⚠️ .err MUST stay below .msg — the same rule that is already
   spelled out for #bt-gate further down, and for the same reason.
   Failures render class="msg err"; both selectors are one id plus
   one class, so specificity is IDENTICAL and source order is the
   only thing making red win.

   _loginPage_ in BT_Auth.js was never hit by DEFECT-1 purely because
   it happened to declare .msg before .err. That accident is now a
   written rule in both places. Do not "tidy" these together. */
#bt-auth .err { color: #f5a0a0; }


/* ────────────────────────────────────────────────────────────
   THE SHELL GATE — ported verbatim from _shellBootstrapHtml_.

   FE-00 §3.3: the gate and the login page are TWO SEPARATE
   SURFACES and a fix to one is not a fix to the other. They stay
   separate here for exactly that reason — do not merge these
   blocks into one set of shared classes just because they look
   alike. They have already drifted once (DEFECT-1), and the whole
   value of keeping them apart is that a change to one cannot
   silently move the other.
   ──────────────────────────────────────────────────────────── */

#bt-gate {
  position: fixed; inset: 0; z-index: 99999; background: #111; color: #eee;
  display: flex; align-items: center; justify-content: center; padding: 1rem;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}
#bt-gate .bt-card {
  background: #1e1e1e; border-radius: 12px; padding: 2rem; max-width: 420px;
  width: 100%; box-sizing: border-box; text-align: center;
  box-shadow: 0 4px 24px rgba(0,0,0,.5);
}
#bt-gate h1 { font-size: 1.4rem; margin-top: 0; }
#bt-gate p  { color: #aaa; line-height: 1.6; }
#bt-gate .bt-btn {
  display: inline-block; background: #6ab0f5; color: #111; font-weight: 600;
  text-decoration: none; padding: .7rem 1.4rem; border-radius: 8px; margin: .75rem .25rem;
}
#bt-gate .bt-fine { font-size: .85rem; color: #888; }
#bt-gate label {
  display: block; text-align: left; font-size: .85rem; color: #aaa; margin-bottom: -.25rem;
}
#bt-gate input[type=email], #bt-gate input[type=password] {
  width: 100%; box-sizing: border-box; background: #2a2a2a; border: 1px solid #3a3a3a;
  border-radius: 8px; color: #eee; padding: .75rem .9rem; font-size: 1rem; margin: .5rem 0 1rem;
}
#bt-gate input[type=email]:focus, #bt-gate input[type=password]:focus {
  outline: none; border-color: #6ab0f5;
}
#bt-gate button.bt-submit {
  width: 100%; background: #6ab0f5; color: #111; font-weight: 600;
  border: 0; border-radius: 8px; padding: .8rem 1.4rem; font-size: 1rem; cursor: pointer;
}
#bt-gate button.bt-submit[disabled] { opacity: .55; cursor: default; }
#bt-gate button.bt-link {
  background: none; border: 0; color: #6ab0f5; font-size: .9rem;
  text-decoration: underline; cursor: pointer; padding: .4rem 0;
}
#bt-gate .bt-msg {
  margin-top: 1rem; font-size: .95rem; color: #9fd0a0; line-height: 1.5;
  display: none; white-space: pre-line;
}
/* ⚠️ .bt-err MUST stay below .bt-msg. btGateFormMsg() emits
   class="bt-msg bt-err" for every failure, and both selectors are one
   id plus one class — identical specificity — so SOURCE ORDER is the
   only thing making red win. This block sat above .bt-msg until
   2026-08-08, which silently rendered every gate error (wrong PIN,
   lockout, junk email, enumeration response) in the green success
   colour. Found in UAT row 14. Do not "tidy" these back together. */
#bt-gate .bt-err { color: #f5a0a0; }


/* ────────────────────────────────────────────────────────────
   THE PIN OVERLAY — offerPin=1 and the "change" state.

   Ported from _authSuccessPage_'s pin-setup block. Rendered on top
   of a page that has ALREADY loaded, because the member is signed
   in and the offer is dismissible. The forced (reset) case is not
   this — it is its own full-page auth view at ?page=pin-setup,
   because there is nothing to render underneath it yet.
   ──────────────────────────────────────────────────────────── */

#bt-pin-overlay {
  position: fixed; inset: 0; z-index: 99998; background: rgba(0,0,0,.72);
  display: flex; align-items: center; justify-content: center; padding: 1rem;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}
#bt-pin-overlay .bt-card {
  background: #1e1e1e; border-radius: 12px; padding: 2rem; max-width: 420px;
  width: 100%; box-sizing: border-box; text-align: center; color: #eee;
  box-shadow: 0 4px 24px rgba(0,0,0,.5);
}
#bt-pin-overlay h1 { font-size: 1.4rem; margin-top: 0; }
#bt-pin-overlay p  { color: #aaa; line-height: 1.6; }
#bt-pin-overlay label {
  display: block; text-align: left; font-size: .85rem; color: #aaa; margin-bottom: -.25rem;
}
#bt-pin-overlay input[type=password] {
  width: 100%; box-sizing: border-box; background: #2a2a2a; border: 1px solid #3a3a3a;
  border-radius: 8px; color: #eee; padding: .75rem .9rem; font-size: 1rem; margin: .5rem 0 1rem;
}
#bt-pin-overlay input[type=password]:focus { outline: none; border-color: #6ab0f5; }
#bt-pin-overlay button.bt-submit {
  width: 100%; background: #6ab0f5; color: #111; font-weight: 600;
  border: 0; border-radius: 8px; padding: .8rem 1.4rem; font-size: 1rem; cursor: pointer;
}
#bt-pin-overlay button.bt-submit[disabled] { opacity: .55; cursor: default; }
#bt-pin-overlay button.bt-link {
  background: none; border: 0; color: #6ab0f5; font-size: .9rem;
  text-decoration: underline; cursor: pointer; padding: .5rem 0;
}
#bt-pin-overlay .bt-msg {
  margin-top: 1rem; font-size: .95rem; color: #9fd0a0; line-height: 1.5;
  display: none; white-space: pre-line;
}
/* ⚠️ Same order rule as the two blocks above. Third time it is
   written down in this file, because it has cost this project a
   work cycle once already. */
#bt-pin-overlay .bt-err { color: #f5a0a0; }


/* ────────────────────────────────────────────────────────────
   SKELETON — the one pre-approved parity exception (FE-03 §A2).

   Today a member watching a page load stares at a blank card
   reading "Loading…" for the 2.5-3.3s the bundle takes. The static
   shell now paints instantly from Cloudflare's edge, so that time
   is spent looking at page furniture instead of nothing. The real
   bundle latency is unchanged — this is FE-00 §2's "load feel"
   win, not a performance fix, and it should not be described as
   one.

   Deliberately shaped like the portal's own panels (same surface,
   border, radius) so the transition to real content is a fill, not
   a replacement.
   ──────────────────────────────────────────────────────────── */

#bt-skeleton { max-width: 1180px; margin: 0 auto; padding: 20px; }
#bt-skeleton .sk-row { display: flex; gap: 16px; flex-wrap: wrap; }
#bt-skeleton .sk-block {
  background: #1e1e1e; border: 1px solid #2a2a2a; border-radius: 12px;
  flex: 1 1 260px; min-height: 120px; position: relative; overflow: hidden;
}
#bt-skeleton .sk-block.tall { min-height: 220px; }
#bt-skeleton .sk-block::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent 0%, rgba(255,255,255,.045) 50%, transparent 100%);
  transform: translateX(-100%);
  animation: bt-sk 1.4s ease-in-out infinite;
}
@keyframes bt-sk { to { transform: translateX(100%); } }

/* Respect the OS setting. A shimmer that cannot be turned off is a
   vestibular-trigger complaint waiting to happen, and the skeleton
   reads fine as a flat block. */
@media (prefers-reduced-motion: reduce) {
  #bt-skeleton .sk-block::after { animation: none; }
}

/* HANDOFF A3 - the skeleton's words.
   Colour is a literal, not a var: the page fragment that defines
   --muted has not arrived yet when this is on screen, so a var()
   here would resolve to nothing. #8b96a5 on the #111 shell canvas
   is 6.3:1, which clears AA for the 15px line. */
#bt-sk-msg      { text-align: center; margin: 0 0 18px; }
#bt-sk-msg p    { margin: 0 0 6px; color: #8b96a5; font-size: 15px; }
#bt-sk-line2    { font-size: 13.5px; opacity: .85; }

/* Line 2 holds its own space while it waits, rather than collapsing and
   then shoving the blocks down when the 4s timer reveals it. A skeleton
   exists so nothing jumps; it must not jump itself.

   The `hidden` ATTRIBUTE stays in the markup, so the line is still hidden
   if this stylesheet never loads. This only changes HOW it hides, and
   shell.js still just flips el.hidden - no JS change.

   visibility:hidden keeps it out of the accessibility tree exactly as
   display:none does, so nothing is announced before its time.

   This replaces a min-height guess that held at 1180px and shifted the
   blocks 17px at every phone width, where the sentence wraps to two rows.
   Measured 0px shift at 1180/430/390/360/320, at 100% and 125% text, and
   with a line long enough to wrap to three rows. Do not swap this back
   for a fixed height: the next copy edit would silently reintroduce the
   shift, which is exactly how it got here. */
#bt-sk-line2[hidden] { display: block; visibility: hidden; }
