/*
 * Component CSS — the handful of things that are not Tailwind utilities: a class contract shared
 * with a Stimulus controller, a third-party widget's markup we do not author, or a keyframe.
 *
 * Everything here reads Capsule's tokens (var(--color-*)), which are declared by the Tailwind
 * build in app/assets/tailwind/application.css and re-declared per theme there. So these follow
 * light and dark with no duplication and no second palette to keep in step. Never write a literal
 * colour in this file.
 *
 * Propshaft serves this alongside the Tailwind build via `stylesheet_link_tag :app`.
 */

/* ── Tabs ─────────────────────────────────────────────────────────────────────────────────
   The class contract tabs_controller.js toggles (`.active`), and the one the character and
   corporation pages render server-side.

   The selected tab differs from the others in four ways at once, because in light mode no one
   of them is enough on its own. A 13px label has to clear 4.5:1 on white, which caps the accent
   at roughly L 0.48 — and at that lightness cyan simply cannot hold much chroma, so `holo` as
   text sits only ΔE 11 from the slate the other labels are set in. Hence:

     - the label is holo, and the others are faint (secondary, and a step lighter);
     - the label is semibold, and the others are medium;
     - the underline is 3px rather than 2;
     - and it is drawn in holo-MARK, not holo. A rule is a graphical element, not text, so it
       answers to 3:1 rather than 4.5:1 — which buys back the chroma the label had to give up.
       #008bac against the strip's own #caccd0 rule is ΔE 27.5, where holo would have been 16.

   Height comes from the markup so the hit area stays at 44px on a phone. */
.tab-btn {
  border-bottom: 3px solid transparent;
  color: var(--color-faint);
  background: none;
  font-weight: 500;
  transition: color 0.12s, border-color 0.12s;
}

.tab-btn:hover,
.tab-btn:focus-visible {
  color: var(--color-text);
  border-bottom-color: var(--color-line-strong);
}

.tab-btn.active,
.tab-btn[aria-current="page"] {
  color: var(--color-holo);
  font-weight: 600;
  border-bottom-color: var(--color-holo-mark);
}

/* ── Sticky report headers ────────────────────────────────────────────────────────────────
   The class contract sticky_header_controller.js toggles (`data-stuck`), on the theads it
   marks with `data-sticky-header`.

   Stickiness is opt-in from JavaScript rather than a `sticky top-14` in the markup because
   `position: sticky` is only ever right when the PAGE is the header's scrollport. Every report
   table ships inside an `overflow-x-auto` wrapper so a wide one can be scrolled sideways, and
   that wrapper is its own scrollport — one that never scrolls vertically. A sticky thead in
   there is not merely inert, which is the easy thing to assume: `top` is still honoured, so the
   header is pushed 3.5rem DOWN from the top of a box that never moves and drawn over the first
   two rows of the table. That is exactly how /alliance_fats came to render its top member above
   its own column headings.

   So the controller sets `data-stuck` only on the tables whose scroller it was able to drop,
   and a page whose JavaScript never ran gets an ordinary header in its ordinary place.

   3.5rem is the navbar's h-14. */
thead[data-sticky-header][data-stuck] {
  position: sticky;
  top: 3.5rem;
  z-index: 10;
}

/* ── Pagy ─────────────────────────────────────────────────────────────────────────────────
   Pagy renders its own markup, so its nav is styled by selector rather than by utility. */
.pagy.nav {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 0.25rem;
  margin-top: 1.5rem;
  font-size: 0.8125rem;
}

.pagy.nav a,
.pagy.nav span,
.pagy.nav .current {
  border: 1px solid var(--color-line);
  border-radius: 0.25rem;
  background: var(--color-hull);
  color: var(--color-dim);
  /* 2.25rem so a page number is a 36px target rather than a 20px one. */
  min-width: 2.25rem;
  min-height: 2.25rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0 0.6em;
  transition: color 0.12s, border-color 0.12s, background 0.12s;
  cursor: pointer;
  text-decoration: none;
}

.pagy.nav a:hover:not([aria-current="page"]):not([aria-disabled="true"]) {
  border-color: var(--color-line-strong);
  color: var(--color-text);
  background: var(--color-raise);
}

.pagy.nav .current[aria-current="page"] {
  border-color: var(--color-holo);
  color: var(--color-holo);
  background: color-mix(in srgb, var(--color-holo) 10%, transparent);
  font-weight: 600;
  cursor: default;
  pointer-events: none;
}

.pagy.nav a[aria-disabled="true"] {
  opacity: 0.45;
  cursor: not-allowed;
  pointer-events: none;
}

.pagy.nav .gap {
  border-color: transparent;
  background: transparent;
  color: var(--color-faint);
  cursor: default;
}

/* ── Date and datetime inputs ─────────────────────────────────────────────────────────────
   No custom calendar glyph. There used to be a hand-drawn white-and-black SVG painted as the
   input's background, with the browser's own indicator hidden behind it — which meant a white
   icon on a white field the moment the page went light, and no way to recolour a data: URI per
   theme. <body> declares color-scheme now, so Chromium and Safari draw their own indicator in
   the right colour for whichever theme is showing, and it costs nothing to maintain.

   The invisible .date-picker__button overlay stays: it sits over the indicator and calls
   showPicker(), which is what makes the whole corner clickable in browsers that need it. */
.date-picker {
  position: relative;
}

.date-picker__input {
  width: 100%;
}

.date-picker__button {
  position: absolute;
  right: 0.35rem;
  top: 50%;
  transform: translateY(-50%);
  width: 1.8rem;
  height: 1.8rem;
  border-radius: 0.25rem;
  background: transparent;
  border: 0;
  cursor: pointer;
}

/* ── Animations ───────────────────────────────────────────────────────────────────────────
   Row transitions driven by mark_paid_controller.js and hide_paid_controller.js. */
@keyframes blink {
  0% { opacity: 1; }
  40% { opacity: 0.3; }
  70% { opacity: 1; }
  100% { opacity: 1; }
}

.animate-blink {
  animation: blink 0.35s linear;
}

.fade-in {
  animation: fadeInRow 0.3s;
}

.fade-out {
  animation: fadeOutRow 0.3s;
}

@keyframes fadeInRow {
  0% { opacity: 0; height: 0; padding-top: 0; padding-bottom: 0; }
  100% { opacity: 1; height: auto; padding-top: 0.5rem; padding-bottom: 0.5rem; }
}

@keyframes fadeOutRow {
  0% { opacity: 1; height: auto; padding-top: 0.5rem; padding-bottom: 0.5rem; }
  100% { opacity: 0; height: 0; padding-top: 0; padding-bottom: 0; }
}

/* Instant hide for the in-between states, where an animation would lag the click. */
.paid-row.opacity-0 {
  opacity: 0 !important;
  height: 0 !important;
  padding-top: 0 !important;
  padding-bottom: 0 !important;
  transition: all 0.3s;
}

/* Somebody who has asked their system to stop moving things gets no row animations. The
   opacity change still happens, so nothing becomes invisible-but-present. */
@media (prefers-reduced-motion: reduce) {
  .animate-blink,
  .fade-in,
  .fade-out {
    animation: none;
  }
}
