/* ─────────────────────────────────────────────────────────────────
   css/library.css
   Saved Boards panel + topbar pill — Task #46 turn 2 + 2.5 NN/g
   patches. Imported by builder.html. Reuses .modal-overlay / .modal /
   .modal-btn from builder.css; only adds panel-specific surfaces.

   Naming note (turn 2.5): user-facing label is "Saved Boards" but
   the CSS class prefix stays .library-* — matches the JS module
   filename and the storage concept (window.TinkyLibrary). Keeps
   the codebase greppable without churning every selector.
   ───────────────────────────────────────────────────────────────── */

/* Topbar pill — info-toned, doesn't compete with the primary Push CTA. */
.topbar-library-btn{
  background:rgba(255,255,255,0.06);
  color:var(--nav-text);
  border:1px solid rgba(255,255,255,0.2);
}
.topbar-library-btn:hover{
  border-color:#7BB3FF;
  color:#7BB3FF;
}

/* Modal sizing — wider than default so list rows breathe on tablet. */
.library-modal{ max-width:600px; }

/* CTA row — Save and Import sit side-by-side. Save is the primary
   amber-filled action; Import is the secondary outlined path for
   parents loading a .tinkyboard from another device. NN/g
   consistency: both verbs read as "get a board into this list." */
.library-cta-row{
  display:flex;
  gap:0.55rem;
  margin:0.5rem 0 1rem;
}
.library-save-btn{
  flex:1 1 auto;
  padding:0.7rem 1rem;
  font-size:0.92rem;
  font-weight:600;
  background:var(--amber, #E8A838);
  color:#fff;
  border:0;
  border-radius:var(--radius-sm, 8px);
  cursor:pointer;
  transition:transform 0.12s ease, box-shadow 0.12s ease;
}
.library-save-btn:hover{
  transform:translateY(-1px);
  box-shadow:0 4px 14px rgba(232,168,56,0.35);
}
.library-save-btn:active{ transform:translateY(0); }

/* Import button — outlined cool-tone so it doesn't compete with
   Save. Same height as save for clean baseline. */
.library-import-btn{
  flex:0 0 auto;
  padding:0.7rem 0.95rem;
  font-size:0.88rem;
  font-weight:600;
  background:transparent;
  color:#2C7BE5;
  border:1px solid rgba(44,123,229,0.45);
  border-radius:var(--radius-sm, 8px);
  cursor:pointer;
  transition:background 0.12s ease, border-color 0.12s ease;
}
.library-import-btn:hover{
  background:rgba(44,123,229,0.08);
  border-color:#2C7BE5;
}
@media (max-width:480px){
  /* On narrow phones stack so neither label gets clipped. */
  .library-cta-row{ flex-direction:column; }
  .library-import-btn{ width:100%; }
}

/* List + rows */
.library-list{
  display:flex;
  flex-direction:column;
  gap:0.45rem;
  max-height:50vh;
  overflow-y:auto;
  margin:0.25rem 0 0.75rem;
}
.library-row{
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:0.8rem;
  padding:0.7rem 0.85rem;
  background:var(--surface-soft, #FAF7F1);
  border:1px solid rgba(0,0,0,0.06);
  border-radius:var(--radius-sm, 8px);
}
/* "● Current" row — the entry the active editor was loaded from
   (or last saved into). Tinted amber so the badge isn't the only
   signal — colour-blind users see the surface change too. */
.library-row-current{
  background:rgba(232,168,56,0.10);
  border-color:rgba(232,168,56,0.45);
}
.library-row-meta{ flex:1 1 auto; min-width:0; }
.library-row-name{
  font-size:0.95rem;
  font-weight:600;
  color:var(--ink, #1A1A2E);
  /* Long names truncate before they push the action buttons off-row. */
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.library-current-badge{
  display:inline-block;
  margin-right:0.4rem;
  padding:0.05rem 0.4rem;
  font-size:0.65rem;
  font-weight:700;
  text-transform:uppercase;
  letter-spacing:0.04em;
  color:#8a5a00;
  background:rgba(232,168,56,0.18);
  border:1px solid rgba(232,168,56,0.45);
  border-radius:999px;
  vertical-align:middle;
}
.library-row-sub{
  font-size:0.74rem;
  color:var(--ink-muted, #6B6B80);
  margin-top:0.15rem;
}
.library-row-actions{
  display:flex;
  gap:0.35rem;
  flex:0 0 auto;
  align-items:center;
}
/* Rename + Export — small icon buttons. Visible at all times so
   they're discoverable on touch (no hover affordance on phones).
   Subtle tone so Load remains the dominant action signal. */
.library-row-rename,
.library-row-export{
  padding:0.4rem 0.5rem;
  font-size:0.95rem;
  background:transparent;
  border:1px solid rgba(0,0,0,0.12);
  border-radius:6px;
  cursor:pointer;
  color:var(--ink, #1A1A2E);
  min-width:36px;
}
.library-row-rename:hover{
  background:rgba(232,168,56,0.10);
  border-color:rgba(232,168,56,0.45);
}
.library-row-export:hover{
  background:rgba(44,123,229,0.08);
  border-color:rgba(44,123,229,0.45);
}
/* Inline rename input — replaces the row name in place. Same
   width as the meta column so the buttons don't shift. */
.library-row-rename-input{
  width:100%;
  box-sizing:border-box;
  padding:0.35rem 0.5rem;
  font-size:0.95rem;
  font-weight:600;
  color:var(--ink, #1A1A2E);
  background:#fff;
  border:1px solid rgba(232,168,56,0.55);
  border-radius:6px;
  outline:none;
}
.library-row-rename-input:focus{
  border-color:var(--amber, #E8A838);
  box-shadow:0 0 0 2px rgba(232,168,56,0.20);
}
/* Load button — amber, matching the Save CTA. NN/g consistency:
   the two "use this board" verbs read as the same action family. */
.library-row-load{
  padding:0.45rem 0.85rem;
  font-size:0.82rem;
  font-weight:600;
  background:var(--amber, #E8A838);
  color:#fff;
  border:0;
  border-radius:6px;
  cursor:pointer;
}
.library-row-load:hover{ background:#c98c25; }
.library-row-delete{
  padding:0.4rem 0.55rem;
  font-size:0.95rem;
  background:transparent;
  color:#B23A48;
  border:1px solid rgba(178,58,72,0.25);
  border-radius:6px;
  cursor:pointer;
  min-width:36px;
}
.library-row-delete:hover{
  background:rgba(178,58,72,0.08);
  border-color:#B23A48;
}

/* Empty state — explains the value, doesn't just say "empty". */
.library-empty{
  text-align:center;
  padding:1.25rem 0.5rem 0.5rem;
  color:var(--ink-muted, #6B6B80);
}
.library-empty-icon{ font-size:2.4rem; margin-bottom:0.4rem; }
.library-empty h3{
  font-size:1.05rem;
  margin:0 0 0.35rem;
  color:var(--ink, #1A1A2E);
}
.library-empty p{
  font-size:0.85rem;
  line-height:1.45;
  margin:0;
  max-width:42ch;
  margin-left:auto;
  margin-right:auto;
}

/* ── Undo banner (toast-style soft-delete affordance) ────────────
   NN/g principle: undo > confirm. The Delete button takes immediate
   effect; this banner gives the user 8s to recover. Bottom-anchored,
   above the iOS home indicator, ARIA role=status so screen readers
   announce it. */
.library-undo-banner{
  position:fixed;
  left:50%;
  bottom:max(1rem, env(safe-area-inset-bottom, 0));
  transform:translateX(-50%) translateY(20px);
  display:flex;
  align-items:center;
  gap:0.75rem;
  padding:0.7rem 0.95rem;
  background:#1A1A2E;
  color:#fff;
  border-radius:var(--radius-sm, 8px);
  box-shadow:0 6px 24px rgba(0,0,0,0.25);
  font-size:0.88rem;
  z-index:10010;             /* above modal-overlay */
  opacity:0;
  pointer-events:none;
  transition:opacity 0.18s ease, transform 0.18s ease;
  max-width:calc(100vw - 2rem);
}
.library-undo-banner.show{
  opacity:1;
  transform:translateX(-50%) translateY(0);
  pointer-events:auto;
}
.library-undo-text{
  /* Truncate long names so the Undo button stays visible. */
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
  max-width:60vw;
}
.library-undo-btn{
  flex:0 0 auto;
  padding:0.4rem 0.85rem;
  min-height:36px;
  background:rgba(255,255,255,0.10);
  color:#FFD78A;
  border:1px solid rgba(255,215,138,0.45);
  border-radius:6px;
  font-weight:700;
  font-size:0.85rem;
  cursor:pointer;
}
.library-undo-btn:hover{
  background:rgba(255,215,138,0.18);
  border-color:#FFD78A;
}
.library-undo-btn:focus-visible{
  outline:2px solid #FFD78A;
  outline-offset:2px;
}

/* Mobile — phone breakpoint. Stack row meta over actions so the
   name can use the full width. Tap targets stay ≥44px via padding. */
@media (max-width:640px){
  .library-row{ flex-wrap:wrap; }
  .library-row-meta{ flex:1 1 100%; }
  .library-row-actions{ flex:1 1 100%; justify-content:flex-end; }
}

/* ── Share row button + sub-modal (turn 5) ──────────────────────
   The 📤 button reuses the same icon-button shape as ✏️ / ⬇️ but
   with a cool-blue hover tint to differentiate "send out" from
   "rename in place" / "save to disk." */
.library-row-share{
  padding:0.4rem 0.5rem;
  font-size:0.95rem;
  background:transparent;
  border:1px solid rgba(0,0,0,0.12);
  border-radius:6px;
  cursor:pointer;
  color:var(--ink, #1A1A2E);
  min-width:36px;
}
.library-row-share:hover{
  background:rgba(44,123,229,0.08);
  border-color:rgba(44,123,229,0.45);
}

/* Share sub-modal — layered above the Saved Boards list. z-index
   sits above the soft-delete undo banner (10010) so opening share
   while a recent delete is still undoable doesn't get blocked. */
.library-share-overlay{
  z-index:10020;
}
.library-share-modal{
  max-width:420px;
  text-align:center;
}

/* QR frame — fixed 168×168 box. Empty fallback (no QR lib) gets
   a labeled placeholder instead of an invisible div, so a
   degraded-share path still feels intentional. */
.library-share-qr{
  display:flex;
  align-items:center;
  justify-content:center;
  width:168px;
  height:168px;
  margin:0.75rem auto;
  background:#fff;
  border:1px solid rgba(0,0,0,0.08);
  border-radius:8px;
  /* Make the canvas/image generated by QRCode lib center cleanly. */
  padding:8px;
  box-sizing:content-box;
}
.library-share-qr-empty{
  font-size:0.78rem;
  color:var(--ink-muted, #6B6B80);
  text-align:center;
  padding:1.25rem 0.5rem;
  line-height:1.45;
}

/* URL display — read-only, monospace so the encoded hash reads as
   "this is data, not free text." Selectable in case the older-
   Safari clipboard fallback fires. */
.library-share-url{
  display:block;
  width:100%;
  box-sizing:border-box;
  margin:0.5rem 0 0.75rem;
  padding:0.55rem 0.7rem;
  font-family:ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size:0.78rem;
  color:var(--ink, #1A1A2E);
  background:#FAF7F1;
  border:1px solid rgba(0,0,0,0.08);
  border-radius:6px;
  text-overflow:ellipsis;
  white-space:nowrap;
  overflow-x:auto;
}

/* Action row under the URL — Copy is amber (primary), native Share
   is outlined cool-blue (secondary). Stack on narrow phones. */
.library-share-actions{
  display:flex;
  gap:0.5rem;
  justify-content:center;
  margin-bottom:0.75rem;
}
.library-share-copy{
  flex:1 1 auto;
  min-height:44px;
  padding:0.6rem 1rem;
  font-size:0.9rem;
  font-weight:600;
  background:var(--amber, #E8A838);
  color:#fff;
  border:0;
  border-radius:var(--radius-sm, 8px);
  cursor:pointer;
  transition:transform 0.12s ease, box-shadow 0.12s ease, background 0.12s ease;
}
.library-share-copy:hover{
  transform:translateY(-1px);
  box-shadow:0 4px 14px rgba(232,168,56,0.35);
}
.library-share-copy.copied{
  background:#5BA559;          /* green confirmation flash */
  transform:none;
  box-shadow:none;
}
.library-share-native{
  flex:0 0 auto;
  min-height:44px;
  padding:0.6rem 0.95rem;
  font-size:0.88rem;
  font-weight:600;
  background:transparent;
  color:#2C7BE5;
  border:1px solid rgba(44,123,229,0.45);
  border-radius:var(--radius-sm, 8px);
  cursor:pointer;
  transition:background 0.12s ease, border-color 0.12s ease;
}
.library-share-native:hover{
  background:rgba(44,123,229,0.08);
  border-color:#2C7BE5;
}
@media (max-width:480px){
  .library-share-actions{ flex-direction:column; }
  .library-share-native{ width:100%; }
}

/* Oversized board banner — replaces the QR + URL when the encoded
   payload would exceed QR_HARD_CAP. Warm-tone surface so it reads
   as actionable advisory, not a hard error. */
.library-share-oversized{
  margin:0.75rem auto;
  padding:0.75rem 0.9rem;
  font-size:0.85rem;
  line-height:1.5;
  color:#8a5a00;
  background:rgba(232,168,56,0.10);
  border:1px solid rgba(232,168,56,0.45);
  border-radius:var(--radius-sm, 8px);
  text-align:left;
}

/* ─── Sync status badge (sync-badge.js, Phase B 2026-05-04) ─── */
/* Mounted at the top of the Saved Boards modal. State-tinted to make
   each sync state read at a glance — colour + icon + text triple-encoded
   so colour-blind users still get the signal. */
.library-sync-badge{
  display:flex; align-items:flex-start; gap:.625rem;
  padding:.625rem .75rem; margin:.25rem 0 .5rem;
  border-radius:var(--radius-sm, 8px);
  border:1px solid rgba(0,0,0,.08);
  background:#f7f7f8; color:#222;
  font-size:.85rem; line-height:1.3;
}
.library-sync-badge .lsb-icon{ font-size:1.1rem; flex:0 0 auto; line-height:1.2; }
.library-sync-badge .lsb-body{ flex:1 1 auto; min-width:0; }
.library-sync-badge .lsb-title{ font-weight:600; }
.library-sync-badge .lsb-sub{ color:#555; font-size:.78rem; margin-top:.125rem; }
.library-sync-badge .lsb-action{
  flex:0 0 auto; align-self:center;
  padding:.375rem .625rem; border-radius:6px;
  border:1px solid rgba(0,0,0,.18); background:#fff; color:#222;
  font-size:.78rem; cursor:pointer;
}
.library-sync-badge .lsb-action:hover{ background:#f0f0f0; }
.library-sync-badge .lsb-action:focus-visible{
  outline:2px solid #2C7BE5; outline-offset:2px;
}

/* State tints — Fitzgerald-adjacent. Cool blue = informational/neutral,
   warm amber = action-needed, cool grey = transient process. */
.library-sync-badge.lsb-guest{   background:rgba(44,123,229,.06); border-color:rgba(44,123,229,.30); color:#1c4f99; }
.library-sync-badge.lsb-syncing{ background:rgba(120,120,120,.08); border-color:rgba(120,120,120,.25); color:#444; }
.library-sync-badge.lsb-online{  background:rgba(58,168,98,.08);  border-color:rgba(58,168,98,.30);  color:#1f6f3a; }
.library-sync-badge.lsb-offline{ background:rgba(232,168,56,.10); border-color:rgba(232,168,56,.45); color:#8a5a00; }

/* Spinner — pure CSS, no extra DOM. Reduced-motion respected. */
.library-sync-badge .lsb-spin{
  display:inline-block;
  animation:lsb-spin 1.1s linear infinite;
}
@keyframes lsb-spin{ to { transform:rotate(360deg); } }
@media (prefers-reduced-motion: reduce){
  .library-sync-badge .lsb-spin{ animation:none; }
}

/* Narrow viewports: stack action button below text. */
@media (max-width: 480px){
  .library-sync-badge{ flex-wrap:wrap; }
  .library-sync-badge .lsb-action{ width:100%; margin-top:.375rem; }
}
