html {
  font-size: 14px;
}

@media (min-width: 768px) {
  html {
    font-size: 16px;
  }
}

.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
  box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
}

html {
  position: relative;
  min-height: 100%;
}

body {
  margin-bottom: 60px;
}

.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
  color: var(--bs-secondary-color);
  text-align: end;
}

.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder {
  text-align: start;
}
/* --- Virtual Tag branding ------------------------------------------------ */

/* One place for the palette, taken from the logo and the hero that was already
   using it, so a colour is chosen once rather than typed into a rule each time
   somebody needs it. */
:root {
    --vt-ink: #10323f;          /* the dark teal of the logo */
    --vt-ink-2: #14404f;        /* one step lighter, for gradients */
    --vt-ink-3: #1d5468;        /* hover states on the dark bar */
    --vt-paper: #eef2f4;        /* the page behind the cards */
    --vt-paper-2: #f7f9fa;      /* card headers, table stripes */
    --vt-line: #dbe3e7;         /* borders that should not shout */
    --vt-accent: #3fa796;       /* the teal-green that reads as "go" */
}

/* The page is no longer a white sheet with white cards on it. A tinted ground
   is what makes a card look like a card, and it costs one declaration. */
body {
    background-color: var(--vt-paper);
    color: #21343c;
}

/* --- the top bar ---------------------------------------------------------- */

.site-navbar {
    background: linear-gradient(100deg, var(--vt-ink) 0%, var(--vt-ink-2) 100%);
    box-shadow: 0 .125rem .5rem rgba(16, 50, 63, .25);
}

.site-navbar .nav-link {
    color: rgba(255, 255, 255, .82);
    border-radius: .375rem;
    padding-left: .7rem;
    padding-right: .7rem;
}

.site-navbar .nav-link:hover,
.site-navbar .nav-link:focus,
.site-navbar .nav-link.show {
    color: #fff;
    background-color: rgba(255, 255, 255, .1);
}

/* The signed-in person's initial, so the menu reads as theirs before the name
   is even scanned. */
.account-initial {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.75rem;
    height: 1.75rem;
    border-radius: 50%;
    background: var(--vt-accent);
    color: #06222b;
    font-weight: 700;
    font-size: .85rem;
    text-transform: uppercase;
    flex-shrink: 0;
}

/* --- page furniture ------------------------------------------------------- */

/* Cards do the work of separating one thing from another, so they get a real
   edge rather than only a shadow — on a tinted ground a shadow alone goes
   muddy. */
.card {
    border: 1px solid var(--vt-line);
    border-radius: .5rem;
}

.card-header {
    background-color: var(--vt-paper-2);
    border-bottom-color: var(--vt-line);
    font-weight: 600;
}

/* A card-header told to be transparent means it: the tint above would
   otherwise override the intent at every call site that asked for none. */
.card-header.bg-transparent {
    background-color: transparent !important;
}

/* The statistic tiles on the admin and club pages. A left edge in the brand
   colour turns eight identical white boxes into a row that has a direction. */
.stat-card {
    border-left: .25rem solid var(--vt-accent);
}

.stat-card-warn { border-left-color: #d98324; }
.stat-card-bad  { border-left-color: #b3453b; }

/* Page titles get a short rule under them in the brand colour. Cheap, and it
   gives every page a top edge instead of text floating on a field. */
.page-head {
    border-bottom: 1px solid var(--vt-line);
    padding-bottom: .75rem;
    margin-bottom: 1.25rem;
}

.page-head h1 {
    position: relative;
    padding-left: .75rem;
}

.page-head h1::before {
    content: "";
    position: absolute;
    left: 0;
    top: .1em;
    bottom: .1em;
    width: .25rem;
    border-radius: .25rem;
    background: var(--vt-accent);
}

/* Tables on a tinted page. Zebra striping without Bootstrap's grey, which
   fights the ground colour. */
.table > tbody > tr:nth-of-type(odd) > * {
    background-color: rgba(16, 50, 63, .022);
}

.table > thead > tr > th {
    border-bottom-width: 2px;
    border-bottom-color: var(--vt-line);
}

/* Cards that are also links — a club in the grid, a statistic that opens its
   own page. Lifting on hover is what says so. */
.card-linked {
    transition: transform .12s ease, box-shadow .12s ease;
}

.card-linked:hover {
    transform: translateY(-2px);
    box-shadow: 0 .5rem 1.25rem rgba(16, 50, 63, .16) !important;
}

.footer {
    background-color: #fff;
    border-top-color: var(--vt-line) !important;
}

.hero {
    background: var(--vt-ink);
    color: #f4f9fb;
}

/* The banner is a fixed-width raster; crop rather than stretch it so the
   artwork keeps its proportions on wide screens. */
.hero-banner {
    max-height: 220px;
    object-fit: cover;
    object-position: center;
}

.hero-body {
    background: linear-gradient(180deg, var(--vt-ink) 0%, var(--vt-ink-2) 100%);
}

.hero-body .lead {
    color: #cfe3ea;
}

.tag-sample {
    max-width: 46%;
    height: auto;
    filter: drop-shadow(0 6px 14px rgba(0, 0, 0, .28));
}

.navbar-brand img {
    display: block;
}

.brand-mark {
    border-radius: .35rem;
    background: #fff;
    box-shadow: 0 1px 3px rgba(0, 0, 0, .3);
}

.brand-word {
    color: #fff;
    font-weight: 600;
    letter-spacing: .01em;
    white-space: nowrap;
}

/* A club's picture. Square-cropped rather than letterboxed: clubs upload
   everything from a logo to a photo of the practice basket, and a consistent
   shape is what keeps the club list from looking ragged. */
.club-badge {
    width: 4.5rem;
    height: 4.5rem;
    object-fit: cover;
    flex-shrink: 0;
}

.club-badge-large {
    width: 12rem;
    height: 12rem;
    object-fit: cover;
}

/* The club as the subject of its own page, and on the club list where picking
   one out by its logo is the whole job.

   max-width caps it at whatever it sits in — a card in the three-across grid is
   narrower than 24rem — and aspect-ratio keeps it square once that cap bites,
   which a fixed height would not. */
.club-badge-xl {
    width: 24rem;
    max-width: 100%;
    aspect-ratio: 1;
    height: auto;
    object-fit: cover;
}

/* Beside a club name in a list, where it identifies the club at a glance
   rather than being the subject itself. */
.club-badge-small {
    width: 2.25rem;
    height: 2.25rem;
    object-fit: cover;
    flex-shrink: 0;
}

/* --- tables that keep their headings ---------------------------------------
   A chain with sixty tags scrolls its own headings off the top, and then the
   columns are just numbers.

   The wrapper scrolls rather than the page. A sticky header inside an overflow
   container sticks to that container, not the viewport — and .table-responsive
   is already an overflow container, so sticking to the page was never going to
   work here. Giving the wrapper a height is what makes the header have
   something to stick to. */
.table-sticky {
    max-height: 70vh;
    overflow-y: auto;
}

.table-sticky thead th {
    position: sticky;
    top: 0;
    z-index: 2;
    /* Opaque, or the rows read straight through the heading as they pass. */
    background-color: var(--bs-body-bg);
}

/* An inset shadow rather than a border: a border on a sticky cell is painted
   at the cell's original position and scrolls away with the table. */
.table-sticky thead th::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    border-bottom: 2px solid var(--bs-border-color);
}

/* Shorter inside a modal, which is already height-capped — 70vh there would
   put a scrollbar inside a scrollbar. */
.modal-body .table-sticky {
    max-height: 55vh;
}

/* The player ledger is columns of lists rather than a table, so its headings
   are ordinary elements and stick on their own. The container has to carry a
   height for the same reason .table-sticky does: without one there is no
   vertical scrolling for them to stick against. */
.ledger-columns {
    max-height: 55vh;
}

.ledger-column-head {
    position: sticky;
    top: 0;
    z-index: 1;
    background-color: var(--bs-body-bg);
}

/* A player's name or a tag number that opens its detail modal. A button rather
   than a link because it acts on this page instead of going somewhere, but it
   has to read as clickable — a dotted underline says "there is more here"
   without competing with the real links beside it. */
.link-button {
    background: none;
    border: 0;
    padding: 0;
    color: inherit;
    font: inherit;
    text-align: inherit;
    cursor: pointer;
    text-decoration: underline;
    text-decoration-style: dotted;
    text-underline-offset: 2px;
}

.link-button:hover {
    color: var(--bs-success);
}

/* Wrapping a badge, where the badge's own shape already says it is a target
   and an underline would only smudge it. */
.link-button-plain {
    background: none;
    border: 0;
    padding: 0;
    font: inherit;
    cursor: pointer;
}

.link-button-plain:hover {
    filter: brightness(1.35);
}

/* --- the lightbox ----------------------------------------------------------
   Any picture the site shows small can be opened at 48rem — four times the
   12rem "large" size — so a club badge or a piece of tag artwork can actually
   be looked at rather than squinted at. */

.image-lightbox-dialog {
    /* 48rem — four times the 12rem "large" size — is the floor, not the cap.
       Uploads are around 1024px wide, so a dialog fixed at 48rem (768px) was
       shrinking every picture by a quarter, which is the opposite of what
       opening it full size is for. It takes the screen instead, and 48rem only
       decides how small it is allowed to get on a narrow one. */
    /* Bootstrap sizes a modal through this variable — setting it is what makes
       the override stick, rather than relying on beating its media query on
       source order. */
    --bs-modal-width: max(48rem, min(95vw, 90rem));
    max-width: none;
    width: var(--bs-modal-width);
}

.image-lightbox-img {
    /* Fills the dialog rather than stopping at the file's own pixel width, so
       the picture is as big as the screen allows. */
    width: 100%;
    max-width: none;
    height: auto;
    /* Leaves room for the caption bar, so a tall picture still fits on screen
       instead of running off the bottom of a laptop. contain rather than a bare
       max-height, which would squash the picture to fit rather than letterbox
       it. */
    max-height: 88vh;
    object-fit: contain;
    box-shadow: 0 1rem 3rem rgba(0, 0, 0, .5);
}

/* On a phone the floor is taller than the screen, so the width rule above
   would push the dialog off the side. */
@media (max-width: 48rem) {
    .image-lightbox-dialog {
        width: 95vw;
    }
}

/* Says the picture does something before it is clicked. */
[data-lightbox-src] {
    cursor: zoom-in;
}

/* --- the tag face ---------------------------------------------------------
   The chain's artwork, with the number plate and tier ring drawn on top. One
   picture per chain; everything else here is CSS, so a tag costs no storage
   and changes tier the moment it changes hands. */

.tag-face {
    position: relative;
    display: inline-block;
    flex-shrink: 0;
    border-radius: 50%;
    /* The ring IS the tier, so it is drawn as a border on the face itself
       rather than as an extra element to keep in sync. */
    border: 0.28rem solid #d7d2c4;
    background: #10323f;
    overflow: hidden;
}

.tag-face-sm { width: 3.25rem; height: 3.25rem; }
.tag-face-md { width: 6.5rem;  height: 6.5rem; }
.tag-face-lg { width: 10rem;   height: 10rem; }

/* Artwork that is not square. The size class still sets the width; the height
   comes from an aspect-ratio written inline from the file's own dimensions, so
   the frame matches the picture and background-size:cover has nothing left to
   crop. A wide illustration is then shown whole instead of as a circular
   cut-out of its middle.

   Rounded corners rather than a 50% radius, which on a rectangle is an
   ellipse. */
.tag-face-rect {
    height: auto;
    border-radius: .5rem;
}

.tag-face-rect.tag-face-sm { width: 5.5rem; }
.tag-face-rect.tag-face-md { width: 11rem; }
.tag-face-rect.tag-face-lg { width: 17rem; }

.tag-face-art {
    position: absolute;
    inset: 0;
    background-size: cover;
    background-position: center;
}

/* Without artwork the face is still a tag, not a hole in the page. */
.tag-face-art-plain {
    background: radial-gradient(circle at 50% 35%, #14404f 0%, #0b2531 100%);
}

/* The number sits on its own plate so it stays legible over busy artwork —
   the sample club badge has mountains and a basket right where it lands. */
.tag-face-plate {
    position: absolute;
    left: 50%;
    bottom: 8%;
    transform: translateX(-50%);
    display: flex;
    flex-direction: column;
    align-items: center;
    line-height: 1;
    padding: .18em .5em;
    border-radius: .28em;
    background: rgba(255, 255, 255, .93);
    color: #10323f;
    box-shadow: 0 1px 4px rgba(0, 0, 0, .35);
    white-space: nowrap;
}

.tag-face-number { font-weight: 700; }
.tag-face-of { opacity: .65; }

.tag-face-sm .tag-face-number { font-size: .8rem; }
.tag-face-sm .tag-face-of     { display: none; }   /* no room; the number is the point */
.tag-face-md .tag-face-number { font-size: 1.15rem; }
.tag-face-md .tag-face-of     { font-size: .6rem; margin-top: .12em; }
.tag-face-lg .tag-face-number { font-size: 1.7rem; }
.tag-face-lg .tag-face-of     { font-size: .75rem; margin-top: .15em; }

/* Tiers. Metallic rather than flat: a gradient border reads as a rim catching
   the light, which is what tells gold from a yellow line at a glance. */
.tier-none   { border-color: #d7d2c4; }
.tier-bronze { border-color: #a9703f; box-shadow: 0 0 0 1px #7d4f26; }
.tier-silver { border-color: #c9ccd1; box-shadow: 0 0 0 1px #8f959e; }
.tier-gold   { border-color: #d4af37; box-shadow: 0 0 0 1px #9c7c1d, 0 0 .55rem rgba(212, 175, 55, .55); }

/* The tier badge beside a number in a dense list, where a full face would be
   too much furniture. */
.tier-dot {
    display: inline-block;
    width: .55rem;
    height: .55rem;
    border-radius: 50%;
    vertical-align: baseline;
}
.tier-dot-bronze { background: #a9703f; }
.tier-dot-silver { background: #c9ccd1; }
.tier-dot-gold   { background: #d4af37; }

/* The number on a bag tag. Sized to be readable at arm's length on a phone,
   which is where a player actually checks what they are carrying. */
.bag-tag {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 2.75rem;
    height: 2.75rem;
    padding: 0 .4rem;
    border-radius: 50rem;
    background: #10323f;
    color: #f4f9fb;
    font-size: 1.15rem;
    font-weight: 700;
    line-height: 1;
    flex-shrink: 0;
}
