/* === Fonts === */

/* Roboto — self-hosted (Apache 2.0) */
@font-face { font-display: swap; font-family: 'Roboto'; font-style: normal; font-weight: 300; src: url('/fonts/roboto-latin-300-normal.woff2') format('woff2'); }
@font-face { font-display: swap; font-family: 'Roboto'; font-style: normal; font-weight: 400; src: url('/fonts/roboto-latin-400-normal.woff2') format('woff2'); }
@font-face { font-display: swap; font-family: 'Roboto'; font-style: normal; font-weight: 500; src: url('/fonts/roboto-latin-500-normal.woff2') format('woff2'); }
@font-face { font-display: swap; font-family: 'Roboto'; font-style: normal; font-weight: 700; src: url('/fonts/roboto-latin-700-normal.woff2') format('woff2'); }
@font-face { font-display: swap; font-family: 'Roboto'; font-style: normal; font-weight: 900; src: url('/fonts/roboto-latin-900-normal.woff2') format('woff2'); }


/* === Global chrome === */

/* Progressive enhancement — <html> ships class="no-js"; theme.js swaps it to "js" at
   parse. Controls that hard-depend on JS carry .js-only; their no-JS fallbacks carry
   .no-js-only, and exactly one shows. Generic primitive — keep selectors element-agnostic
   (currently driving the GPG modal trigger vs. its direct-download fallback). */
.no-js .js-only    { display: none !important; }
.js    .no-js-only { display: none !important; }

/* Light-mode page tint — MDB leaves body and card surface both white (#fff), so
   cards vanish into the page. Tint the *body* (not the cards — a dark card under a
   drop shadow reads "fuzzy") so white cards sit above it, mirroring dark mode's
   elevation. Scoped to "not dark" so dark mode keeps MDB's #303030 body (the light
   state may be explicit "light" or the attribute absent). Sync with blog/static/style.css. */
html:not([data-mdb-theme="dark"]) body { background-color: var(--mdb-secondary-bg-subtle); }

/* Navbar */
/* Navbar is always bg-primary (blue), but MDB 9.2's `navbar-dark` is a no-op and the
   default foreground (--mdb-emphasis-color) flips dark-on-blue in light mode. Pin it
   light in both themes (mirrors MDB's dark-navbar values). Sync with blog/static/style.css. */
.navbar {
  --mdb-navbar-color: rgba(255, 255, 255, 0.55);
  --mdb-navbar-hover-color: rgba(255, 255, 255, 0.75);
  --mdb-navbar-active-color: #fff;
  --mdb-navbar-brand-color: #fff;
  --mdb-navbar-brand-hover-color: #fff;
}
/* The navbar's .btn-link buttons (search + desktop theme toggle) default to grey
   --mdb-btn-*-color, and :focus-visible makes that grey stick after a click. Force
   the navbar foreground with !important to override every btn color state (no MDB
   btn rule uses !important). Inert here (banasiak.com has no navbar .btn-link), but
   sync the file with blog/static/style.css regardless. */
.navbar .btn-link { color: var(--mdb-navbar-color) !important; }
.navbar .btn-link:hover { color: var(--mdb-navbar-hover-color) !important; }
.navbar-brand h1 { font-size: 1.5rem; font-weight: inherit; line-height: 1.25; }
/* Size the filled sun/moon glyphs down to match the blog toggle (they read large at
   MDB's default size). Sync with blog/static/style.css. */
.theme-toggle { font-size: 1rem; }


/* === Components === */

/* GPG modal — slides in vertically (from top on desktop, bottom on mobile).
   `.fade` rules set the off-screen start position; `.show` must come after
   so it wins specificity-for-specificity when both classes are present. */
.gpg-key { font-size: 0.75rem; white-space: pre-wrap; word-break: break-all; }
@media (min-width: 768px)    { #gpgModal.modal.fade .modal-dialog { transform: translateY(-100vh); } }
@media (max-width: 767.98px) { #gpgModal.modal.fade .modal-dialog { transform: translateY(100vh); } }
#gpgModal.modal.show .modal-dialog { transform: translateY(0); }

/* Image overlay mask */
.mask-light { background-color: rgba(0, 0, 0, 0.15); }

/* Blog preview card — mirrors the Pagefind search-result card on blog.banasiak.com.
   ⚠️ These `.search-card*` / `.badge-tag-N` rules are duplicated in blog/static/style.css
   (the blog's /embed/ emits these class names) — keep in sync. */
.search-card { color: var(--mdb-body-color); height: 10rem; overflow: hidden; transition: box-shadow 0.15s ease; }
.search-card:focus-visible { outline: none; box-shadow: 0 0 0 2px #3b71ca; }
.search-card-thumb-wrap { aspect-ratio: 16 / 10; flex-shrink: 0; position: relative; width: 16rem; }
/* Thumbnail darkens on hover — mirrors the .hover-overlay/.mask-light effect on the "Other Places" cards (same rgba as .mask-light). */
.search-card-thumb-wrap::after { background-color: rgba(0, 0, 0, 0.15); content: ""; inset: 0; opacity: 0; position: absolute; transition: opacity 0.3s ease; }
.search-card:hover .search-card-thumb-wrap::after { opacity: 1; }
.search-card-thumb { display: block; height: 100%; object-fit: cover; width: 100%; }
.search-card-chips { align-content: flex-start; display: flex; flex-wrap: wrap; gap: 0.25rem; height: 1.5rem; overflow: hidden; }
.search-card > .d-flex { flex: 1; }
.search-card .card-body { display: flex; flex-direction: column; }
.search-card .card-body > .text-muted { margin-top: auto; }
.search-card .card-title,
.search-card-summary {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
}
@media (max-width: 767.98px) {
  .search-card { height: auto; }
  .search-card > .d-flex { flex-direction: column; }
  .search-card-thumb-wrap { max-height: 12rem; width: 100%; }
}

/* Tag badge colors — matches blog.banasiak.com palette */
.badge-tag-0 { background-color: #3b71ca; color: #fff; }
.badge-tag-1 { background-color: #14a44d; color: #fff; }
.badge-tag-2 { background-color: #dc4c64; color: #fff; }
.badge-tag-3 { background-color: #9c27b0; color: #fff; }
.badge-tag-4 { background-color: #e65100; color: #fff; }
.badge-tag-5 { background-color: #00897b; color: #fff; }
.badge-tag-6 { background-color: #0277bd; color: #fff; }
.badge-tag-7 { background-color: #6a1b9a; color: #fff; }

/* Non-interactive skill pills (homepage tech stack strip) */
.badge-skill { background-color: rgba(0, 0, 0, 0.08); color: inherit; }
[data-mdb-theme="dark"] .badge-skill { background-color: rgba(255, 255, 255, 0.12); }
/* Group outline colors — chosen to be maximally distinct (red/gold/green/blue/purple),
   independent of the .badge-tag-N background fills the blog uses. */
.badge-skill.badge-tag-0 { border: 1px solid #3b71ca; } /* blue   — languages */
.badge-skill.badge-tag-1 { border: 1px solid #14a44d; } /* green  — Android */
.badge-skill.badge-tag-2 { border: 1px solid #e53935; } /* red    — architecture */
.badge-skill.badge-tag-3 { border: 1px solid #9c27b0; } /* purple — tooling */
.badge-skill.badge-tag-4 { border: 1px solid #e0a800; } /* gold   — domains */

/* Mobile tech-stack teaser — below md only the curated leader pills (those without
   .tech-stack-extra) show, followed by the solid "+N more" button; tapping reveals the rest
   in place (one-way, wired in theme.js). ≥md the full list is always visible and the
   button is hidden (d-md-none in the markup). */
@media (max-width: 767.98px) {
  /* Teaser hiding is scoped to html.js — no-JS visitors get the full list (and no
     dead button), matching the GPG modal's no-js fallback pattern. */
  .js #tech-stack:not(.tech-stack-expanded) .tech-stack-extra { display: none; }
  #tech-stack.tech-stack-expanded .tech-stack-extra { animation: pill-pop 0.25s ease; }
}
.no-js .tech-stack-more { display: none; }
.tech-stack-more {
  border: 1px solid #3b71ca;
  background-color: #3b71ca;
  color: #fff;
}
@keyframes pill-pop {
  from { opacity: 0; transform: scale(0.5); }
}
@media (prefers-reduced-motion: reduce) {
  .tech-stack-extra { animation: none !important; }
}

/* Tooltips are hover-only affordances — suppress them on touch devices */
@media (hover: none) {
  .tooltip { display: none !important; }
}
