/* PlasticDB custom styles */

/* ─── Brand gradient contrast (WCAG 1.4.3) ──────────────────────────────────
   Every white-on-blue surface — the nav, the footer, the dashboard sidebar,
   the auth pages and the home CTA — paints `.bg-gradient-primary`, whose light
   end was #4e73df. White text on #4e73df is 4.34:1, under the 4.5:1 body-text
   minimum, so *no* amount of opacity tuning on the text could fix it: even
   100% white failed. The light end has to move instead.

   #3d5cb8 is the same hue and saturation, ~9% darker, and takes pure white to
   6.14:1 — clear at every point on the ramp, since the far end (#224abe) is
   darker still at 7.52:1. Keep any new stop at or below this luminance.
     python3 -c "print(0.2126*..., 'must stay <= 0.183 for 4.5:1 vs white')"
   Redefining the vendor rule rather than the elements means one edit covers
   every surface; this file loads after sb-admin-2, so the equal-specificity
   (0,1,0) tie resolves here. */
.bg-gradient-primary {
    background-color: #3d5cb8;
    background-image: linear-gradient(180deg, #3d5cb8 10%, #224abe 100%);
    background-size: cover;
}

/* ── Landing page ──────────────────────────────────────────────────────────── */
#mainNav {
    box-shadow: 0 0.15rem 1.75rem 0 rgba(58, 59, 69, 0.15);
}
#mainNav .navbar-brand {
    font-weight: 800;
    font-size: 1.4rem;
}
.landing-content {
    padding-top: 70px;
}

/* Hero section. The `.lead` here is 20px/300 — under the 24px large-text
   threshold, so it needs the full 4.5:1 and takes the darkened stop too. */
.hero-section {
    background: linear-gradient(135deg, #3d5cb8 0%, #224abe 100%);
    padding: 3rem 0;
}
.hero-section h1 {
    font-weight: 800;
}
.hero-section .lead {
    font-weight: 300;
}

/* Stat counter cards */
.stat-card {
    transition: transform 0.2s;
}
.stat-card:hover {
    transform: translateY(-3px);
}
.stat-card .stat-number {
    font-weight: 800;
}

/* Feature cards */
.feature-card {
    transition: transform 0.2s ease;
    border: none;
}
.feature-card:hover {
    transform: translateY(-5px);
}
.feature-card .icon-circle {
    width: 70px;
    height: 70px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    margin: 0 auto;
}
.feature-card .icon-circle i {
    font-size: 1.8rem;
}

/* Search/filter bar */
.filter-section {
    background-color: #f8f9fc;
    border-radius: 0.35rem;
}

/* News cards */
.news-card {
    transition: transform 0.2s, box-shadow 0.2s;
}
.news-card:hover {
    transform: translateY(-3px);
    box-shadow: 0 0.5rem 2rem rgba(0,0,0,0.15) !important;
}

/* Tool cards on dashboard */
.tool-card,
.stat-card {
    transition: transform 0.2s;
    cursor: pointer;
}
.tool-card:hover,
.stat-card:hover {
    transform: translateY(-3px);
}

/* Table tweaks */
.table-plasticdb th {
    background-color: #4e73df;
    color: white;
    border: none;
}
.table-plasticdb tbody tr:hover {
    background-color: #eaecf4;
}

/* Citation block */
.citation-block {
    border-left: 4px solid #4e73df;
    background: #f8f9fc;
}

/* Download cards */
.download-card i {
    transition: transform 0.2s;
}
.download-card:hover i {
    transform: scale(1.1);
}

/* Phylogenetic tree iframe */
.tree-iframe {
    width: 100%;
    height: 80vh;
    border: 1px solid #e3e6f0;
    border-radius: 0.35rem;
}

/* 3D viewer */
.structure-viewer {
    width: 100%;
    height: 500px;
    border: 1px solid #e3e6f0;
    border-radius: 0.35rem;
}

/* Clickable lineage badges */
.lineage-badge {
    transition: transform 0.15s, box-shadow 0.15s;
    text-decoration: none !important;
}
.lineage-badge:hover {
    transform: translateY(-1px);
    box-shadow: 0 2px 6px rgba(0,0,0,0.2);
    text-decoration: none;
}

/* Engineered version cards */
.engineered-version-card {
    transition: transform 0.15s, box-shadow 0.15s;
    border-left: 3px solid #36b9cc;
}
.engineered-version-card:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 12px rgba(0,0,0,0.1);
}

/* Carousel */
.carousel-item {
    height: 400px;
    background-size: cover;
    background-position: center;
}
.carousel-caption {
    background: rgba(0,0,0,0.6);
    border-radius: 0.5rem;
    padding: 2rem;
}
.carousel-caption h2 {
    font-weight: 800;
}

/* Statistic figure cards */
.figure-card img {
    max-height: 500px;
    object-fit: contain;
}
.figure-card .card-header {
    font-weight: 700;
}

/* Pulse animation for running jobs */
.job-pulse {
    animation: pulse 1.5s ease-in-out infinite;
}
@keyframes pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.4; }
}

/* Landing page override: angle the gradient across the section rather than
   down it. Same darkened stop as the base rule — this one only changes the
   direction, so it must not reintroduce #4e73df. */
.landing-content .bg-gradient-primary {
    background: linear-gradient(135deg, #3d5cb8 0%, #224abe 100%) !important;
}

/* ─── Text contrast (WCAG 1.4.3) ────────────────────────────────────────────
   Three vendor utilities sat under the 4.5:1 body-text minimum. Each is
   retargeted to a colour sb-admin-2 already ships, so the palette gains no new
   values — check any replacement against BOTH white and #f8f9fc, the default
   `.card-header`/`.bg-light` background, which is the stricter of the two. */

/* #858796 (gray-600) was 3.56:1 on white and 3.38:1 on #f8f9fc.
   #6e707e is the vendor's own gray-700: 4.90:1 and 4.66:1. Deliberately not
   gray-800 (#5a5c69) — at 6.63:1 it reads as body text and stops being muted. */
.text-muted {
    color: #6e707e !important;
}

/* #1cc88a was 2.17:1 on white. This class marks both the "Verified" glyph (a
   graphic, 3:1) and "Verified Subset" body text (4.5:1); #13855c clears the
   stricter bar at 4.63:1 and is already the vendor's `a.text-success:hover`.
   Scoped to the text utility only — `.bg-success`/`.btn-success` fills keep
   #1cc88a, where the contrast question is about white text on the fill. */
.text-success {
    color: #13855c !important;
}

/* Badge fills. sb-admin-2 overrides Bootstrap's `color-yiq()` and forces
   `color:#fff` on EVERY `.badge-*` variant, so all six carried white text at
   12px bold (`.badge{font-size:75%}` — not WCAG "large text", so 4.5:1
   applies, not 3:1). Every one of them failed:

     badge-info      #36b9cc   2.34:1
     badge-warning   #f6c23e   1.65:1   effectively illegible
     badge-success   #1cc88a   2.17:1
     badge-secondary #858796   3.56:1
     badge-danger    #e74a3b   3.86:1
     badge-primary   #4e73df   4.34:1

   Two strategies, both staying inside the vendor palette per the note above.
   Where the fill is light enough that dark text clears the bar, keep the fill
   and flip the text to #212529 (the vendor's own body colour): warning 9.33:1,
   success 7.11:1, info 6.59:1. Where it is not, keep white text and darken the
   fill to a value sb-admin-2 already ships — #be2617 is its
   `a.text-danger:hover` (6.04:1), #224abe its `a.text-primary:hover` (7.52:1),
   and #6e707e its gray-700, already used by `.text-muted` above (4.90:1).

   Enumerated deliberately rather than fixed one-at-a-time: a partial pass
   leaves the badge system inconsistent, where some badges are legible and
   others are not, which is harder to reason about than a uniform defect.
   `.badge-*` appears across 14 templates and every variant is in use. */
.badge-warning,
.badge-success,
.badge-info {
    color: #212529;
}

.badge-danger {
    background-color: #be2617;
}

.badge-secondary {
    background-color: #6e707e;
}

.badge-primary {
    background-color: #224abe;
}

/* rgba(255,255,255,.5) was 2.23:1 on the footer. At .85 it is 4.96:1 against
   the darkened light end and better past it, so the de-emphasis this class
   exists for survives instead of being flattened to plain white. */
.footer .text-white-50,
.footer a.text-white-50 {
    color: rgba(255, 255, 255, 0.85) !important;
}

/* The public nav links had the same translucency problem as the footer links,
   from a different rule: Bootstrap's `.navbar-dark .navbar-nav .nav-link` is
   rgba(255,255,255,.5), which is 2.79:1 on the gradient — worse than the footer
   and on 16px body text. sb-admin-2 ships a .8 rule that looks like it would
   cover this, but it is `.topbar.navbar-dark …`, so it only reaches the
   dashboard topbar and never the public nav.
   Scoped by #mainNav — the only navbar-dark on the site — so specificity (1,2,0)
   clears the vendor's :hover twin at (0,4,0) without an !important. .85 matches
   the footer links; hover goes to full white so the affordance survives. */
#mainNav .navbar-nav .nav-link {
    color: rgba(255, 255, 255, 0.85);
}
#mainNav .navbar-nav .nav-link:hover,
#mainNav .navbar-nav .nav-link:focus {
    color: #fff;
}

/* The hamburger's colour is baked into a data-URI SVG stroke, so the `color`
   above cannot reach it — the whole image has to be restated at .85. Only
   visible under 992px, but it is the sole nav control at that width. */
#mainNav .navbar-toggler {
    color: rgba(255, 255, 255, 0.85);
    border-color: rgba(255, 255, 255, 0.3);
}
#mainNav .navbar-toggler-icon {
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.85%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");
}

/* Skip link (WCAG 2.4.1). `.sr-only-focusable` ships in sb-admin-2 and already
   un-clips on focus, but it restores the link to `position: static`, which
   would shove the whole page down as it appears. Pin it over the nav instead. */
.skip-link:focus {
    position: fixed !important;
    top: 0.5rem;
    left: 0.5rem;
    z-index: 2000;
    padding: 0.75rem 1.25rem;
    background: #fff;
    color: #224abe;
    font-weight: 700;
    border-radius: 0.35rem;
    box-shadow: 0 0.15rem 1rem rgba(0, 0, 0, 0.3);
}

/* Override the sidebar toggle button color */
#sidebarToggle, #sidebarToggleTop {
    background-color: #4e73df;
    color: white;
}
#sidebarToggle:hover, #sidebarToggleTop:hover {
    background-color: #2e59d9;
}

/* ─── Keyboard focus indicator (WCAG 2.4.7) ─────────────────────────────────
   sb-admin-2/Bootstrap strip the native ring in 21 `:focus` rules and only
   compensate with a box-shadow on .btn/.form-control, so links, nav items and
   custom controls had no visible focus at all.

   Every selector below is the `:focus-visible` twin of one of those 21, at
   equal or higher specificity — a bare `:focus-visible` (0,1,0) is NOT enough,
   because even `a:focus{outline:0}` (0,1,1) outranks it. This file loads after
   the vendor CSS, so a tie resolves our way. If you add a rule here, check what
   it has to outrank first:
     grep -o '[^{}]*{[^{}]*outline:\s*0[^{}]*}' app/static/css/sb-admin-2.min.css
   `:focus-visible` rather than `:focus` keeps the ring off mouse clicks, which
   is why the outline was dropped in the first place. */
:focus-visible,
a:focus-visible,                            /* vs a:focus (0,1,1) — the brand link, footer and body links */
.btn:focus-visible,
.form-control:focus-visible,
.custom-select:focus-visible,
.custom-range:focus-visible,
.nav-link:focus-visible,
.navbar-toggler:focus-visible,
.close:focus-visible,
.dropdown-item:focus-visible,
.page-link:focus-visible,
a[class*="badge-"]:focus-visible,           /* vs a.badge-primary:focus etc (0,2,1) */
.carousel-control-prev:focus-visible,
.carousel-control-next:focus-visible,
.topbar .nav-item:focus-visible,            /* dashboard: vs .topbar .nav-item:focus (0,3,0) */
.topbar .nav-item .nav-link:focus-visible,  /* dashboard: vs (0,4,0) — outranks .nav-link:focus-visible */
.sidebar #sidebarToggle:focus-visible {     /* dashboard: vs .sidebar #sidebarToggle:focus (1,2,0) */
    outline: 2px solid #224abe;
    outline-offset: 2px;
}

/* The public nav is a blue gradient bar, so a dark ring would disappear. */
#mainNav :focus-visible {
    outline-color: #fff;
}

/* ...except inside the near-white search pill, where white would vanish in
   turn. The pill sets overflow:hidden, which clips an outset outline drawn on
   a child, so these ring inward instead. */
#mainNav .search-wrap :focus-visible {
    outline-color: #224abe;
    outline-offset: -2px;
}

/* Chips sit inside the pill's padding rather than against its clipped edge, so
   a small outset ring survives and keeps clear of the label text. */
#mainNav .search-wrap .filter-chip:focus-visible {
    outline-offset: 1px;
}

/* A selected chip and the submit button are both solid blue: ring them white. */
#mainNav .search-wrap .filter-chip[aria-pressed="true"]:focus-visible,
#mainNav .search-wrap .search-btn:focus-visible {
    outline-color: #fff;
}

/* ---- Mobile: stacked-card data tables (issue #238) ----
   Below Bootstrap's `sm` breakpoint the wide data tables (up to 8 columns on
   /microorganisms) can't show columns side-by-side, so each row becomes a
   stacked "Label: value" card. The label is pulled from each <td>'s data-label
   (set by the per-page JS renderers) via ::before, so no visible header row is
   needed. Desktop/tablet layout is untouched. */
@media (max-width: 575.98px) {
    .table-plasticdb {
        border: 0;
    }
    /* Hide the header row visually but keep it for screen readers. */
    .table-plasticdb thead {
        position: absolute;
        width: 1px;
        height: 1px;
        padding: 0;
        margin: -1px;
        overflow: hidden;
        clip: rect(0, 0, 0, 0);
        white-space: nowrap;
        border: 0;
    }
    .table-plasticdb tbody tr {
        display: block;
        margin-bottom: 0.85rem;
        padding: 0.15rem 0.9rem;
        border: 1px solid #e3e6f0;
        border-radius: 0.5rem;
        background: #fff;
    }
    .table-plasticdb tbody tr:hover {
        background: #fff;
    }
    .table-plasticdb tbody td {
        display: flex;
        justify-content: space-between;
        align-items: baseline;
        gap: 1rem;
        padding: 0.5rem 0;
        text-align: right;
        border: 0;
        border-bottom: 1px solid #f0f3fa;
        white-space: normal;
        word-break: break-word;
    }
    .table-plasticdb tbody tr td:last-child {
        border-bottom: 0;
    }
    .table-plasticdb tbody td::before {
        content: attr(data-label);
        flex-shrink: 0;
        font-weight: 700;
        color: #6e707e;
        text-align: left;
    }
    /* The "No results"/loading/error rows span all columns and carry no label. */
    .table-plasticdb tbody td[colspan] {
        display: block;
        text-align: center;
        border-bottom: 0;
    }
    .table-plasticdb tbody td[colspan]::before {
        content: none;
    }
    /* A full page's worth of pagination buttons (prev + 10 pages + next) is
       wider than a phone, so let the button row scroll horizontally instead of
       pushing the whole page sideways (issue #238). */
    #pageButtons {
        max-width: 100%;
        min-width: 0;
        overflow-x: auto;
    }
}
