/* ui.css — shared COMPONENT layer for the whole product.
   ----------------------------------------------------------------------------
   Linked AFTER /tokens.css and BEFORE the page stylesheet from every HTML entry
   (index.html → the React PWA, map.html → the static map/admin, and the
   design-system.html gallery). One canonical home for the UI atoms that the app
   and the map both use, so they can never drift apart again.

   THE APP IS THE LEAD. These components are the React Field Guide's design
   language (formerly in src/styles/naturalist.css); the map adopts them rather
   than maintaining a parallel copy. When you add a new shared component, add it
   HERE and reference it from both sides — never redefine it in a page stylesheet.

   Only design TOKENS live in /tokens.css; this file consumes them and never
   redeclares :root vars. --------------------------------------------------- */

/* ── Buttons ────────────────────────────────────────────────────────────────
   .nbtn is the canonical button. Variants: --primary (gradient CTA), --flat
   (solid brand), --ghost (outlined), --danger (rust). --sm is a compact,
   auto-width variant for inline/popup buttons (used by the map's popups + the
   parent-code modal). */
.nbtn { font-family: var(--sans); font-weight: 800; font-size: 16px; border: none; border-radius: 12px; padding: 14px 20px; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; gap: 9px; transition: transform .12s, filter .12s; letter-spacing: .01em; }
.nbtn:active { transform: scale(.97); }
.nbtn svg, .nbtn .ic { width: 22px; height: 22px; }
.nbtn--primary { background: var(--cta-grad); color: var(--on-brand); box-shadow: var(--shadow), inset 0 1px 0 rgba(255,255,255,.25); width: 100%; }
.nbtn--primary:hover { filter: brightness(1.06); }
.nbtn--flat { background: var(--brand); color: var(--on-brand); box-shadow: var(--shadow); width: 100%; }
.nbtn--flat:hover { filter: brightness(1.06); }
.nbtn--ghost { background: var(--card); color: var(--ink); border: 1.5px solid var(--rule-d); }
/* Destructive action — used by the app's ConfirmDialog and any "delete / remove"
   primary. Rust accent so it reads as different from the green CTA. */
.nbtn--danger { background: var(--rust); color: var(--on-brand); box-shadow: var(--shadow), inset 0 1px 0 rgba(255,255,255,.18); }
.nbtn--danger:hover { filter: brightness(1.06); }
/* Compact variant — declared AFTER --flat/--primary so its width:auto wins when
   combined (e.g. `nbtn nbtn--flat nbtn--sm` on a map popup button). */
.nbtn--sm { width: auto; padding: 8px 14px; font-size: 13px; border-radius: 12px; }
.nbtn--sm svg, .nbtn--sm .ic { width: 15px; height: 15px; }

/* ── Segmented control / tabs ────────────────────────────────────────────────
   Inset pill group with one active segment. Used by the app's login tabs
   (Inloggen / Nieuw) and the map's top nav (Dashboard / Kaart / …). Active
   segment = brand fill (app-led). */
.seg { display: flex; gap: 4px; background: var(--card-2); border: 1px solid var(--rule-d); border-radius: 12px; padding: 4px; }
.seg__btn { flex: 1; border: 0; background: none; border-radius: 9px; padding: 9px 12px; font-family: var(--sans); font-weight: 800; font-size: 14px; color: var(--muted); cursor: pointer; display: inline-flex; align-items: center; justify-content: center; gap: 6px; transition: transform .12s; }
.seg__btn:active { transform: scale(.96); }
.seg__btn.on { background: var(--brand); color: var(--on-brand); box-shadow: 0 1px 3px rgba(70,58,34,.25); }

/* ── Pill toggle / chip ──────────────────────────────────────────────────────
   Standalone rounded chip with an on/off state — date presets, sort toggles,
   filter chips. Card surface by default; .on = brand fill. (The map's overview
   "Opnieuw tekenen" chip layers a rust .ovredraw variant on top of this.) */
.pill { display: inline-flex; align-items: center; gap: 6px; background: var(--card); color: var(--ink); border: 1.5px solid var(--rule-d); border-radius: 999px; padding: 5px 12px; font-family: var(--sans); font-weight: 800; font-size: 12px; cursor: pointer; transition: transform .12s; }
.pill:active { transform: scale(.96); }
.pill.on { background: var(--brand); color: var(--on-brand); border-color: var(--brand); }

/* ── Rarity / frequency meter ────────────────────────────────────────────────
   The 5-dot rarity meter (Algemeen → Legendarisch). Caller sets --c to the tier
   colour and adds `.on` to as many dots as the tier has stars. This is the
   canonical rarity component shown in the design-system gallery; the map's old
   single-dot `.rar` chip now renders this instead. */
.freq { display: inline-flex; align-items: center; gap: 7px; font-family: var(--mono); letter-spacing: .04em; color: var(--c); text-transform: uppercase; }
.freq__dots { display: inline-flex; gap: 2.5px; }
.freq__dot { width: 6px; height: 6px; border-radius: 50%; border: 1.3px solid var(--c); opacity: .5; }
.freq__dot.on { background: var(--c); opacity: 1; }

/* ── "Meer weten?" — external read-more links ────────────────────────────────
   Was duplicated byte-for-byte in naturalist.css AND map.css; now lives here
   once. Used by both the app's species detail and the map's detail sheet. */
.sources { margin: 12px 0 2px; text-align: left; }
.sources__label { font-family: var(--mono); font-size: 10px; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); display: block; margin-bottom: 8px; }
.sources__links { display: flex; flex-wrap: wrap; gap: 8px; }
.sources__link { display: inline-flex; align-items: center; gap: 6px; text-decoration: none; font-family: var(--sans); font-weight: 700; font-size: 13px; color: var(--brand-d); background: var(--card-2); border: 1.5px solid var(--rule-d); border-radius: 999px; padding: 7px 13px; transition: transform .12s; }
.sources__link:active { transform: scale(.97); }
.sources__link svg { flex: 0 0 auto; opacity: .85; }

/* ── Avatar (initial bubble) ─────────────────────────────────────────────────
   Round monogram bubble used across both surfaces: the app account chip, circle
   member rows + finders, and the map's player lists / leaderboard / circle cards.
   Brand fill by default; callers may override background/color inline (e.g. the
   map's per-person colours). Size variants --lg/--sm/--xs; --inline flows it
   next to text (the map's table cells). */
.avatar { display: grid; place-items: center; flex: 0 0 auto; border-radius: 50%; background: var(--brand); color: var(--on-brand); font-weight: 800; width: 28px; height: 28px; font-size: 14px; }
.avatar--lg { width: 30px; height: 30px; font-size: 15px; }
.avatar--sm { width: 22px; height: 22px; font-size: 11px; }
.avatar--xs { width: 20px; height: 20px; font-size: 10px; }
.avatar--inline { display: inline-grid; vertical-align: middle; }

/* ── Specimen tile (Field Book species card) ─────────────────────────────────
   The illustrated species card: number badge top-left, ×count badge top-right,
   image plate, name + Latin pair, rarity dots. Rendered by the app's grids
   (src/components/FieldGuide/shared.jsx → SpecimenCard) AND the map's Overzicht
   + dashboard grids (src/map/map.js → specimenCardHtml). App-only states
   (locked / favorite / "Nieuw" / "Nu actief") stay in naturalist.css; the
   per-tier border + glow lives in src/styles/rarity.css (bundled by both). */
.plate { position: relative; display: grid; place-items: center; background: var(--card-2); border-radius: 12px; overflow: hidden; padding: 8px; }
.plate__sil { position: relative; z-index: 1; object-fit: contain; }
/* No artwork yet → a friendly placeholder icon (Feather) instead of any art. */
.sil--placeholder { color: var(--muted); opacity: .5; }
/* No blanket flex gap — margins per slot, so the title + Latin name sit tightly
   together and the plate + rarity get their own breathing room.
   content-visibility: native virtualization — offscreen cards skip layout +
   paint entirely, so long grids stay fast. `auto` makes the browser remember
   each card's real size after first paint; 220px only seeds scroll geometry. */
.specimen { position: relative; background: var(--card); border: 1.5px solid var(--rule-d); border-radius: var(--radius); padding: 10px; cursor: pointer; font-family: inherit; color: var(--ink); display: flex; flex-direction: column; align-items: center; box-shadow: var(--shadow); transition: transform .12s; height: 100%; width: 100%; min-width: 0; max-width: 100%; content-visibility: auto; contain-intrinsic-size: auto 220px; }
.specimen:not(:disabled):active { transform: scale(.98); }
.specimen__no { position: absolute; top: 7px; left: 7px; z-index: 2; display: inline-flex; align-items: center; gap: 4px; background: var(--card-2); border: 1px solid var(--rule-d); border-radius: 999px; padding: 2px 7px 2px 6px; box-shadow: 0 1px 2px rgba(70,58,34,.10); }
.specimen__no i { font-style: normal; font-family: var(--sans); font-size: 7px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); }
.specimen__no b { font-family: var(--mono); font-size: 10px; font-weight: 600; color: var(--sepia); }
.specimen__count { position: absolute; top: 7px; right: 7px; z-index: 2; font-family: var(--mono); font-size: 10px; font-weight: 700; color: var(--on-brand); background: var(--brand); border-radius: 999px; padding: 2px 7px; box-shadow: 0 1px 2px rgba(70,58,34,.2); }
/* Recheck marker in the number spot — a card with no number is a genus-level
   "type" (not identified to species), so instead of a number it shows a red "?"
   you can tap to re-identify. Light rust fill, darker rust border. Used by the
   map's Overzicht + the app's Veldboek. */
.specimen__no--recheck { background: color-mix(in srgb, var(--rust) 16%, #fff); border-color: var(--rust); }
.specimen__no--recheck b { color: color-mix(in srgb, var(--rust) 78%, #000); }
/* Fixed-height text rows so every card ends up the same total height.
   Both name + Latin are ONE LINE each; overflow becomes an ellipsis (a `title`
   attr exposes the full text on long-press / hover). The plate is separated
   from the text block; rarity is always reserved (empty slot when absent). */
.specimen__plate { position: relative; width: 100%; margin-bottom: 8px; }
.specimen__plate .plate { width: 100%; aspect-ratio: 1; }
.specimen__name { font-family: var(--serif); font-weight: 600; font-size: 13.5px; text-align: center; line-height: 1.2; width: 100%; margin: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.specimen__sci { font-family: var(--serif); font-style: italic; font-size: 11px; color: var(--muted); text-align: center; line-height: 1.2; width: 100%; margin: 1px 0 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.specimen__rarity { width: 100%; min-height: 16px; display: flex; align-items: center; justify-content: center; margin-top: auto; padding-top: 8px; }

/* ── Modal animations ────────────────────────────────────────────────────────
   Canonical fade (backdrop) + pop (sheet) keyframes. The app's overlays
   (.nbackdrop / .logsheet / .guidepage / .confirm / .habscreen) and the map's
   overlays (.dback / .dsheet / .pcback / .pcsheet) all reference these, so the
   two surfaces animate identically. */
@keyframes nfade { from { opacity: 0; } to { opacity: 1; } }
@keyframes npop { 0% { transform: translateY(16px) scale(.94); opacity: 0; } 100% { transform: none; opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .nbackdrop, .logsheet, .guidepage, .confirm, .habscreen,
  .dback, .dsheet, .pcback, .pcsheet { animation: none !important; }
}
