/* ===========================================================================
   "Sailplane" - the Jonker Sailplanes title-sponsor theme for the public site.

   Same layout as the Howden theme, different brand. Every structural rule here
   mirrors theme-howden.css, because the components (sponsor band, hero, photo
   banner, gallery, live strip, task panel, standings track) are shared and only
   the dressing changes. If you are changing a layout, change both.

   PALETTE. Four colours are measured from jonker-sailplanes.com's own :root
   custom properties, not sampled by eye:

       --main         #1987c6   brand blue
       --main-darker  #0069a8   deep blue
       --second       #00a7d3   cyan
       --gray         #4c4b4d   graphite

   plus #1e1f2d, their heading-black preset, as the body ink.

   Their site is dark-photography-led and publishes no pale tints, but a results
   table needs a header band, a zebra stripe and a hairline border. So the light
   end of this palette is DERIVED by one stated rule -- the brand blue composited
   on white at a fixed percentage -- rather than eyeballed:

       brand blue x  5%   #f4f9fc   zebra stripe
       brand blue x 12%   #e3f1f8   row hover
       brand blue x 18%   #d6e9f5   sponsor band, table header, photo grounds
       brand blue x 22%   #cce5f2   borders, HC badge
       brand blue x 40%   #a3cfe8   hairline under the table header
       graphite   x 80%   #706f71   soft muted text
       deep blue  x 85%   #00598f   brand hover (a shade, not a tint)

   test_theme_jonker_css.py recomputes that ladder and fails on any hex outside
   it, so a shade that "looks about right" cannot be added quietly.

   WHY THE BRAND BLUE IS NOT THE LINK COLOUR. #1987c6 on white is 3.95:1, below
   AA for body text, and links here are 14-16px. Text roles therefore take the
   deep blue #0069a8 (5.86:1 on white, 4.69:1 on the header band); the brand blue
   keeps the roles where 3:1 is the bar -- the sparkline, the focus ring, the
   header hairline -- and supplies the tint ladder above, so it is present on
   every surface without ever being unreadable.

   The cyan is the live dot and nothing else. It is 2.5:1 on white and 2.08:1 on
   the deep blue, which rules it out as text or as a badge ground; it is legible
   as decoration for a state the page also spells out in words.

   Loaded by templates/base.html only when Competition.theme == 'jonker', and
   every rule is scoped to body.theme-jonker so it cannot reach a vanilla page.
   The admin never extends base.html, so it cannot be reached at all.

   Deliberately NOT redefined here: --warn-*, --notam-*, --dht-* and the airspace
   panel. Those colours are read as a caution about flight safety, and a sponsor
   palette has no business changing them. See main.css.
   =========================================================================== */
body.theme-jonker {
    /* brand and links */
    --brand: #0069a8;
    --brand-hover: #00598f;
    --brand-ink: #ffffff;
    --brand-focus-ring: rgba(25, 135, 198, .28);
    --link: #0069a8;

    /* surfaces and text */
    --ink: #1e1f2d;
    --page-bg: #ffffff;
    --surface: #ffffff;
    --muted: #4c4b4d;
    --muted-soft: #706f71;

    /* tables: a pale blue header band with deep blue text, and a near-white
       blue zebra. Mirrors Howden's mint band; the logo needs a light ground for
       a different reason (a positive mark, not a knock-out) and gets one here. */
    --th-bg: #d6e9f5;
    --th-fg: #0069a8;
    --row-alt: #f4f9fc;
    --row-hover: #e3f1f8;
    --border: #cce5f2;

    /* forms */
    --border-input: #cce5f2;

    /* the day info bar reads as a quiet panel rather than a navy notice */
    --info-bg: #f4f9fc;
    --info-line: #cce5f2;
    --info-fg: #4c4b4d;

    /* the live dot: decoration for a state the page also spells out in words,
       so it can take the brand's brightest tone even though the cyan is far too
       pale to carry text. */
    --live: #00a7d3;

    /* score status in the brand's blues. Deep blue grounds the provisional
       badge because white on it is 5.86:1, where white on the brand blue is
       3.95:1 and the cyan is 2.5:1 -- neither is a legible badge. */
    --badge-prelim-bg: #0069a8;
    --badge-prelim-fg: #ffffff;
    --badge-prelim-edge: #00598f;
    --badge-final-bg: #d6e9f5;
    --badge-final-fg: #0069a8;
    --badge-unofficial-bg: #f4f9fc;
    --badge-unofficial-fg: #4c4b4d;
    --badge-hc-bg: #cce5f2;
    --badge-hc-fg: #4c4b4d;

    /* Graphite, not red -- Howden's reasoning, a different colour. A penalty is
       a fact about the score, not an alert to act on, so it needs to be findable
       rather than loud. Graphite reads as ink against the soft grey of "no
       penalty" without borrowing the link colour, which would make a deduction
       look clickable. */
    --pen: #4c4b4d;
    --pen-none: #706f71;

    /* tooling chrome */
    --tool-bg: #0069a8;
    --tool-bg-hover: #00598f;
    --tooltip-bg: #1e1f2d;
    --tooltip-fg: #ffffff;
}

/* Jonker set their whole site in Mulish, with headings bold, uppercase and
   tight. That shape carries more of the brand than any single colour, and it is
   reproducible without a webfont: no external request to fail in a briefing tent
   on airfield mobile data. Swap in Mulish itself if they supply the files -- this
   is a stand-in stack, exactly as theme-howden.css stands in for GT Ultra. */
body.theme-jonker h1,
body.theme-jonker h2,
body.theme-jonker h3 {
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
                 'Helvetica Neue', Arial, sans-serif;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: -.005em;
}

/* Numbers in a results column should line up, whatever the theme. */
body.theme-jonker table { font-variant-numeric: tabular-nums; }

/* The pale header band needs a hairline under it: at 18% tint on white there is
   too little contrast at the table edge to read as a boundary on its own. The
   brand blue at 40% is a border, not text, so 3:1 is the bar it has to clear. */
body.theme-jonker th { border-bottom: 1px solid #a3cfe8; }

/* ---------------------------------------------------------------------------
   Title-sponsor band.

   Sits directly under the nav so the mark is above the fold on every page, and
   on a FLAT colour. Howden's constraint was knock-out letters; Jonker's mark is
   a positive blue-and-graphite lockup on transparency, so it needs an even pale
   ground and would disappear into a photograph just as surely.
   --------------------------------------------------------------------------- */
body.theme-jonker .sponsor-band {
    display: flex;
    align-items: center;
    gap: 1.2rem;
    /* Taller than Howden's .62rem. This mark stacks a wing device above the
       wordmark, so it needs vertical room that a single-line wordmark does not. */
    padding: .75rem 2rem;
    background: #d6e9f5;
    color: #0069a8;
}
body.theme-jonker .sponsor-band__label {
    font-size: .7rem;
    letter-spacing: .14em;
    text-transform: uppercase;
    font-weight: 700;
    white-space: nowrap;
}
body.theme-jonker .sponsor-band__rule {
    flex: 1;
    height: 1px;
    background: currentColor;
    opacity: .3;
    min-width: 10px;
}
/* Taller than Howden's clamp(28px, 3.4vw, 42px) on purpose. That mark is 4.7:1
   wide; this one is 2.3:1 and two-tier, so at the same height it reads as half
   the presence and the word SAILPLANES starts to close up. Scales with the
   viewport so it keeps that presence on a phone. */
body.theme-jonker .sponsor-band__logo {
    height: clamp(34px, 4.4vw, 52px);
    width: auto;
    display: block;
    flex: none;
}
/* The lockup links out to the sponsor. The anchor is the flex child, so it
   carries flex:none; line-height:0 stops the inline image adding a stray
   baseline gap under the band. Opacity is the only hover affordance -- the mark
   sits on transparency, so anything that alters the background shows through it. */
body.theme-jonker .sponsor-band__link {
    display: block;
    flex: none;
    line-height: 0;
    transition: opacity .15s ease-in-out;
}
body.theme-jonker .sponsor-band__link:hover { opacity: .82; }
body.theme-jonker .sponsor-band__link:focus-visible {
    outline: 2px solid currentColor;
    outline-offset: 3px;
}

/* ---------------------------------------------------------------------------
   Competition hero. Replaces the plain header, so it carries the back link, the
   name and the venue/dates. Full-bleed: it sits inside .container, so negative
   margins pull it back out to the page edges.
   --------------------------------------------------------------------------- */
/* --bleed MUST equal .container's padding, at the same breakpoint.
   Every themed template drops `.container { padding: .75rem }` at max-width
   1000px, so this switches there too.

   Both full-bleed elements derive from this single value. Hardcoding it twice is
   what broke the Howden hero: the hero and banner both said -2rem and were
   corrected only at 700px, while the container changes at 1000px, so between
   those two breakpoints the hero over-bled 20px per side, scrolled the whole
   page sideways, and dragged its excess top pull over the sponsor band -- which
   sliced the logo in half on a phone. Stated once, it cannot drift. */
body.theme-jonker {
    --bleed: 2rem;
}
@media (max-width: 1000px) {
    body.theme-jonker {
        --bleed: .75rem;
    }
}
body.theme-jonker .comp-hero {
    position: relative;
    overflow: hidden;
    background: #d6e9f5;
    /* Negative top is deliberate here, unlike .comp-banner: the hero replaces the
       page header, so it has to sit flush under the sponsor band. It is only safe
       while it cancels the container's padding EXACTLY -- any excess lands on the
       band above. */
    margin: calc(-1 * var(--bleed)) calc(-1 * var(--bleed)) 1.4rem;
}
body.theme-jonker .comp-hero__img {
    display: block;
    width: 100%;
    height: clamp(200px, 26vw, 340px);
    object-fit: cover;
    object-position: center 46%;
}
/* Short and steep. These are pale skies; a long soft scrim floods the frame with
   blue and throws away the photograph. */
body.theme-jonker .comp-hero__copy {
    position: absolute;
    inset: auto 0 0 0;
    padding: 1.4rem clamp(1rem, 3vw, 2rem);
    background: linear-gradient(transparent, rgba(0, 74, 118, .62) 42%,
                                rgba(0, 74, 118, .93));
    color: #ffffff;
}
body.theme-jonker .comp-hero__copy h1 {
    color: #ffffff;
    margin: 0;
    font-size: clamp(1.5rem, 3.6vw, 2.5rem);
}
body.theme-jonker .comp-hero__back { margin: 0 0 .3rem; font-size: .82rem; }
body.theme-jonker .comp-hero__back a { color: #d6e9f5; }
body.theme-jonker .comp-hero__meta {
    margin: .35rem 0 0;
    color: #d6e9f5;
    font-size: .88rem;
}

/* ---------------------------------------------------------------------------
   Slim photo band for the day-results and standings pages, which had no imagery
   at all. Short deliberately: these pages are read for numbers, so this is a
   strip of context above the table, never a hero that pushes results off the
   screen. Full-bleed the same way the hero is.
   --------------------------------------------------------------------------- */
body.theme-jonker .comp-banner {
    overflow: hidden;
    background: #d6e9f5;
    /* No negative top margin. On the Howden page -1rem tucked the strip up under
       .page-header and covered the sibling-class links, which are the only
       navigation off this page. Only the sides are pulled out, to match the
       hero's full bleed. */
    margin: .4rem calc(-1 * var(--bleed)) 1.2rem;
}
body.theme-jonker .comp-banner img {
    display: block;
    width: 100%;
    height: clamp(86px, 11vw, 150px);
    object-fit: cover;
    object-position: center 48%;
}

/* ---------------------------------------------------------------------------
   "From the airfield". Static theme assets shared with every other theme, so the
   captions stay generic -- nothing here claims to be from the competition being
   viewed. The frames differ from another competition's because
   photo_rotation.py keys on the slug, not because the library does.
   --------------------------------------------------------------------------- */
body.theme-jonker .comp-gallery-wrap { margin-top: 2.2rem; }
body.theme-jonker .comp-gallery__eyebrow {
    font-size: .66rem;
    letter-spacing: .16em;
    text-transform: uppercase;
    font-weight: 700;
    color: #0069a8;
    margin: 0 0 .7rem;
}
body.theme-jonker .comp-gallery {
    display: grid;
    grid-template-columns: repeat(6, minmax(0, 1fr));
    gap: .5rem;
}
body.theme-jonker .comp-gallery figure {
    margin: 0;
    position: relative;
    overflow: hidden;
    border-radius: 6px;
    background: #d6e9f5;
}
body.theme-jonker .comp-gallery img {
    display: block;
    width: 100%;
    height: auto;
    aspect-ratio: 1;
    object-fit: cover;
    transition: transform .45s cubic-bezier(.4, 0, .2, 1);
}
body.theme-jonker .comp-gallery figure:hover img { transform: scale(1.06); }
body.theme-jonker .comp-gallery figcaption {
    position: absolute;
    inset: auto 0 0 0;
    padding: .5rem .5rem .35rem;
    font-size: .63rem;
    font-weight: 600;
    color: #ffffff;
    background: linear-gradient(transparent, rgba(0, 74, 118, .88));
}
@media (max-width: 760px) {
    body.theme-jonker .comp-gallery { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (prefers-reduced-motion: reduce) {
    body.theme-jonker .comp-gallery img { transition: none; }
}

/* ---------------------------------------------------------------------------
   "Flying now" strip. Deep blue ground so it reads as a band of live state
   rather than another card, with the brand's cyan on the pulse.
   --------------------------------------------------------------------------- */
body.theme-jonker .live-strip {
    display: flex;
    align-items: center;
    gap: .3rem .8rem;
    flex-wrap: wrap;
    background: #0069a8;
    color: #d6e9f5;
    padding: .6rem 1rem;
    border-radius: 8px;
    margin: 0 0 1.1rem;
    font-size: .88rem;
}
body.theme-jonker .live-strip strong { color: #ffffff; font-weight: 600; }
/* Not the brand blue: #1987c6 on this ground is 1.48:1, effectively invisible.
   The 18% tint is 4.69:1 and still reads as the same family. */
body.theme-jonker .live-strip a { color: #d6e9f5; }
body.theme-jonker .live-strip__item + .live-strip__item::before {
    content: '';
}
body.theme-jonker .live-strip__dot {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: #00a7d3;
    flex: none;
    animation: jonker-pulse 2.4s ease-out infinite;
}
@keyframes jonker-pulse {
    0%   { box-shadow: 0 0 0 0 rgba(0, 167, 211, .65); }
    70%  { box-shadow: 0 0 0 9px rgba(0, 167, 211, 0); }
    100% { box-shadow: 0 0 0 0 rgba(0, 167, 211, 0); }
}
/* The dot is decoration; "Flying now" is the message. Stop the animation and
   nothing is lost. */
@media (prefers-reduced-motion: reduce) {
    body.theme-jonker .live-strip__dot { animation: none; }
}

/* ---------------------------------------------------------------------------
   Task panel: the day's parameters as a labelled grid rather than a run of
   bullet-separated fragments. Same fields the vanilla info bar carries, plus a
   finisher count that reuses the competition page's rule.
   --------------------------------------------------------------------------- */
body.theme-jonker .task-panel {
    background: #f4f9fc;
    border: 1px solid #cce5f2;
    border-radius: 8px;
    padding: 1rem 1.2rem 1.1rem;
    margin: 0 0 1rem;
}
body.theme-jonker .task-panel__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    margin-bottom: .9rem;
}
/* Day details and the Task link sit together on the left; baseline-aligned so
   the link reads as part of the heading rather than floating above or below it. */
body.theme-jonker .task-panel__title {
    display: flex;
    align-items: baseline;
    gap: .75rem;
    flex-wrap: wrap;
}
body.theme-jonker .task-panel__head h2 {
    margin: 0;
    font-size: 1.15rem;
    color: #0069a8;
}
/* Styled like every other link on the page, which means specifying almost
   nothing: main.css already gives `a` the --link colour, bold weight, no
   underline, and an underline on hover, and this theme sets --link. Only the
   size is set here, so it sits with the date rather than at body size. */
body.theme-jonker .task-panel__tasklink {
    font-size: .875rem;
}
/* The date is a sibling of an uppercase heading, so it opts back out of the
   heading treatment -- an uppercase "Thursday 31 July" is shouting a fact. */
body.theme-jonker .task-panel__head h2 span {
    font-weight: 400;
    font-size: .82rem;
    color: #4c4b4d;
    text-transform: none;
    letter-spacing: 0;
}
/* One row, always. `grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr))`
   wrapped: a day with 8 facts needs 8 x 9.5rem plus gaps -- about 1330px -- and
   the container is nearer 1100px, so it broke into 5 + 3 and the panel became two
   rows deep.

   Flex with `nowrap` and `flex: 1 1 0` lets the columns shrink to whatever is
   available instead of forcing a minimum and wrapping. `min-width: 0` is
   load-bearing: a flex item's default `min-width: auto` refuses to shrink below
   its content, which silently reinstates the overflow this is meant to remove. */
body.theme-jonker .facts {
    display: flex;
    flex-wrap: nowrap;
    gap: .85rem 1rem;
    margin: 0;
}
body.theme-jonker .fact {
    flex: 1 1 0;
    min-width: 0;
}
body.theme-jonker .fact dt {
    font-size: .62rem;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: #706f71;
    font-weight: 700;
    margin-bottom: .1rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
body.theme-jonker .fact dd {
    margin: 0;
    font-size: .95rem;
    font-weight: 600;
    color: #0069a8;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
body.theme-jonker .fact dd small {
    font-weight: 400;
    font-size: .72rem;
    color: #4c4b4d;
}
/* Wrap below this width instead of ellipsising. Measured on the Howden panel,
   which has the identical grid: with 8 facts the labels start clipping at about
   an 870px container and are clean from roughly 1020px, so the cutover sits just
   above that -- a 1050px viewport is a ~970px container. Deliberately NOT the
   700px breakpoint used elsewhere in this file, which would leave 700-1050px
   showing a single row of truncated labels. */
@media (max-width: 1050px) {
    body.theme-jonker .facts {
        flex-wrap: wrap;
    }
    body.theme-jonker .fact {
        flex: 1 1 8rem;
    }
}
body.theme-jonker .task-panel__note {
    margin: .9rem 0 0;
    font-size: .82rem;
    color: #4c4b4d;
}

/* ---------------------------------------------------------------------------
   Position-by-day track on the standings table. A total says who is winning;
   this says who is climbing. Built in competitions/position_track.py, which
   shares one y scale across the whole class so two sparklines side by side can
   be read against each other.

   This is where the brand blue belongs: a 1.5px stroke is a graphic, so 3:1 is
   the bar and 3.95:1 clears it comfortably.
   --------------------------------------------------------------------------- */
body.theme-jonker .track {
    width: 74px;
    height: 20px;
    display: block;
    overflow: visible;
}
body.theme-jonker .track polyline {
    fill: none;
    stroke: #1987c6;
    stroke-width: 1.5;
    stroke-linejoin: round;
    stroke-linecap: round;
}
/* The endpoint is the latest day, which is the one being asked about. */
body.theme-jonker .track circle { fill: #0069a8; }

body.theme-jonker .sponsor-footer {
    display: flex;
    align-items: center;
    gap: 1.2rem;
    flex-wrap: wrap;
    background: #d6e9f5;
    color: #0069a8;
    padding: 1.7rem 2rem;
    margin-top: 2.5rem;
}
/* 44px, not Howden's 34px -- same two-tier reasoning as the band mark. */
body.theme-jonker .sponsor-footer__logo { height: 44px; width: auto; }
body.theme-jonker .sponsor-footer__note {
    margin-left: auto;
    font-size: .78rem;
    opacity: .85;
}

@media (max-width: 700px) {
    body.theme-jonker .sponsor-band { flex-wrap: wrap; gap: .5rem; padding: .6rem 1rem; }
    body.theme-jonker .sponsor-band__label { white-space: normal; font-size: .62rem; }
    body.theme-jonker .sponsor-band__rule { display: none; }
    body.theme-jonker .sponsor-footer { padding: 1.2rem 1rem; }
    body.theme-jonker .sponsor-footer__note { margin-left: 0; }
}
