/* ZOVFPV administration. GPL-3.0-or-later. */
.user-avatar{overflow:hidden}.user-avatar img{display:block;width:100%;height:100%;object-fit:cover}
#user-list{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px}.user-card{min-width:0;overflow-wrap:anywhere}.user-heading{display:flex;gap:14px;align-items:center}.user-avatar{width:54px;height:54px;flex:0 0 54px;display:grid;place-items:center;border-radius:12px;background:#2c4832;color:var(--sakura);font-size:26px;font-weight:800}.user-identity{min-width:0}.user-name{font-size:20px;font-weight:750;text-decoration:none}.user-identity>div:not(.badges){color:var(--slate);font:12px/1.5 var(--mono);margin-top:4px}.user-heading .badges{margin:8px 0 0;align-items:center;font-size:12px}.user-online{color:#a5ef8a}.user-offline{color:var(--slate);background:#223027}.user-metrics{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px;margin:16px 0}.user-metrics>div{padding:10px;background:#111e17;border:1px solid var(--line);border-radius:7px}.user-metrics dt{color:var(--slate);font-size:12px}.user-metrics dd{margin:3px 0 0;font-weight:750;font-size:19px}.user-details{border-top:1px solid var(--line);padding-top:12px;font-size:13px}.user-details summary{cursor:pointer;color:var(--sakura)}.user-details p{margin:8px 0}.user-actions{display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:12px;margin-top:18px}.user-profile-link{font-weight:650}.user-card>[role=status]{margin-bottom:0}@media(max-width:900px){#user-list{grid-template-columns:1fr}}@media(max-width:420px){.user-metrics{gap:6px}.user-metrics>div{padding:8px}.user-name{font-size:18px}.user-metrics dd{font-size:17px}}
:root{color-scheme:dark;--ink:#111b16;--cream:#f3ead4;--slate:#a6b7ad;--line:#314336;--amber:#ffcf5c;--sakura:#99e575;--mint:#89dd66;--mono:ui-monospace,monospace}*{box-sizing:border-box}body{margin:0;background:var(--ink);color:var(--cream);font:15px/1.55 system-ui,sans-serif}a{color:var(--sakura);text-underline-offset:4px}button,input,select,textarea{font:inherit}button,select,input,textarea{background:#1b2920;color:var(--cream);border:1px solid var(--line);border-radius:6px;padding:9px 12px}button{cursor:pointer}button:hover,a:hover{filter:brightness(1.2)}button:disabled{opacity:.55;cursor:wait}.primary{background:var(--sakura);color:var(--ink);font-weight:700}.danger{border-color:#b96a58;color:#ffc3ac}button:focus-visible,a:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible{outline:3px solid var(--amber);outline-offset:3px}[hidden]{display:none!important}.admin-wrap{max-width:1360px;margin:auto;padding:24px}.admin-head{display:flex;gap:24px;justify-content:space-between;align-items:center;border-bottom:1px solid var(--line);padding-bottom:20px}.mark{font-style:italic;font-weight:950;font-size:26px;text-decoration:none;color:var(--cream)}.mark span{color:var(--sakura)}h1{font-size:clamp(23px,3vw,34px);line-height:1.2;margin:8px 0}h2{font-size:23px;margin:0 0 16px}h3{font-size:17px}.muted,.meta{color:var(--slate);font-size:13px}.admin-nav{display:flex;flex-wrap:wrap;gap:8px;margin:24px 0}.admin-nav a{padding:10px 14px;border:1px solid var(--line);border-radius:6px;text-decoration:none}.admin-nav a[aria-current=page]{background:var(--sakura);color:var(--ink)}.panel{padding:20px;background:#17251d;border:1px solid var(--line);border-radius:10px}.notice{padding:14px;border-left:3px solid var(--amber);margin:16px 0}.error{color:#ffc3ac;white-space:pre-wrap}.summary-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:12px;margin-bottom:24px}.summary-grid a{color:inherit;text-decoration:none}.summary-grid strong{display:block;font-size:32px;color:var(--sakura)}.filters{display:flex;flex-wrap:wrap;gap:12px;padding:14px;background:#17251d;border:1px solid var(--line);border-radius:8px;margin:18px 0}.filters label{display:grid;gap:4px;font-size:13px}.filters input{width:220px}.admin-layout{display:grid;grid-template-columns:minmax(280px,.8fr) minmax(0,1.2fr);gap:20px;align-items:start}.ticket{display:block;text-align:left;width:100%;margin:0 0 8px;overflow-wrap:anywhere}.ticket strong{display:block}.ticket.on{border-color:var(--sakura)}.badges{display:flex;flex-wrap:wrap;gap:8px;margin:12px 0}.badge{padding:3px 8px;background:#243a2b;color:var(--sakura);border-radius:5px;font-size:12px}.sheet{overflow-wrap:anywhere}.sheet p{white-space:pre-wrap}.sheet pre{white-space:pre-wrap;max-height:300px;overflow:auto;font:12px/1.5 var(--mono)}.sheet label{display:grid;gap:6px;margin:14px 0}.sheet textarea{width:100%;min-height:90px;resize:vertical}.actions,.pagination{display:flex;gap:10px;align-items:center;flex-wrap:wrap;margin:16px 0}.history{padding-left:24px}.history li{margin:14px 0;font-size:13px}.tool-links{display:grid;gap:16px}.tool-links a{padding:16px;border:1px solid var(--line);border-radius:8px}footer{margin:40px 0 12px;border-top:1px solid var(--line);padding-top:16px}.empty{padding:20px;color:var(--slate)}.stats-head{display:flex;justify-content:space-between;gap:20px}.stats-row{display:grid;grid-template-columns:1fr 1fr;gap:16px}.stats-plate{margin:16px 0;padding:20px}.tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:12px}.tile{padding:16px;border:1px solid var(--line);border-radius:8px}.tile-value{font-size:30px}.tiles .label,.plate-note{color:var(--slate)}table{width:100%;border-collapse:collapse;font-size:13px}th,td{text-align:left;border-bottom:1px solid var(--line);padding:7px;overflow-wrap:anywhere}svg{max-width:100%;height:auto}.stats-fresh.stale{color:var(--amber)}#view-stats.stale .tiles,#view-stats.stale .stats-plate{opacity:.6}@media(max-width:760px){.admin-wrap{padding:16px}.admin-head{align-items:flex-start;flex-wrap:wrap}.admin-layout,.stats-row{grid-template-columns:1fr}.filters label{flex:1;min-width:130px}.filters input,.filters select{width:100%}.admin-nav a{flex:1;text-align:center}.stats-head{display:block}.panel{padding:16px}}

      #view-stats[hidden] { display: none; }
      #view-tracks[hidden] { display: none; }
      #view-maps[hidden] { display: none; }

      /* The footer's Site statistics link while the statistics are the
       * page. The mint rule is the chosen tab's own mark, moved to the link
       * that opened the page, so the one thing lit on it is the thing you
       * are looking at. */
      footer a.is-here {
        color: var(--cream);
        box-shadow: inset 0 -2px 0 var(--mint);
        padding-bottom: 2px;
      }

      /* The partner row: a label, then each partner's one colour mark over
         its role, one height for all three, in the same quiet type as the
         footer. It leads the footer and takes the whole width, so the
         footer's own line and links sit under it as before. */
      .partner-row {
        flex: 1 1 100%;
        display: flex;
        flex-wrap: wrap;
        align-items: flex-end;
        gap: 14px 34px;
        margin-bottom: 14px;
      }
      .partner-label {
        display: flex;
        align-items: center;
        gap: 12px;
        align-self: center;
        font-size: 10px;
        font-weight: 700;
        letter-spacing: 0.24em;
        text-transform: uppercase;
        color: var(--dim);
      }
      .partner-label::after { content: ""; width: 30px; height: 1px; background: var(--line); }
      footer a.pmark { display: grid; gap: 7px; text-decoration: none; }
      .pmark small {
        font-size: 9px;
        font-weight: 700;
        letter-spacing: 0.18em;
        text-transform: uppercase;
        color: var(--dim);
      }
      .pmark img { display: block; width: auto; height: 32px; opacity: 0.86; transition: opacity 120ms ease; }
      .pmark img.wide { height: 17px; margin: 7px 0 8px; }
      footer a.pmark:hover img, footer a.pmark:focus-visible img { opacity: 1; }
      footer a.pmark:hover small { color: var(--sakura); }

      /* The statistics' way back to Tracks, over their kicker, where a
         back link is looked for. */
      a.stats-back {
        display: inline-flex;
        align-items: center;
        gap: 6px;
        margin: 0 0 16px;
        color: var(--sakura);
      }
      a.stats-back:hover { color: var(--cream); }
      a.stats-back svg { width: 11px; height: 11px; flex: none; }

      /* ---------------------------------------------------------------
         The freestyle maps tab. It wears the tracks tab's classes, so
         what is here is only what a map has and a track does not: the
         named gaps, in the amber the drawing gives them.
         --------------------------------------------------------------- */
      .gaps {
        display: flex;
        flex-wrap: wrap;
        gap: 5px;
      }
      .gaps:empty { display: none; }
      .gaps span {
        padding: 2px 7px;
        border-radius: 999px;
        background: rgba(255, 212, 92, 0.08);
        box-shadow: inset 0 0 0 1px rgba(255, 212, 92, 0.26);
        color: var(--amber);
        font-size: 9px;
        font-weight: 700;
        letter-spacing: 0.12em;
        text-transform: uppercase;
      }
      .map-gaps {
        margin: 10px 0 0;
        padding: 0;
        list-style: none;
      }
      .map-gaps li {
        display: grid;
        grid-template-columns: 2.4em minmax(0, 1fr);
        gap: 10px;
        padding: 9px 0;
        border-bottom: 1px solid var(--line);
        color: var(--cream);
        font-size: 14px;
      }
      .map-gaps .rk {
        font-family: var(--mono);
        font-weight: 700;
        color: var(--amber);
      }
      .map-note {
        margin: 14px 0 0;
        color: var(--slate);
        font-size: 13px;
        line-height: 1.6;
      }

      .stats-head {
        display: flex;
        align-items: flex-end;
        justify-content: space-between;
        flex-wrap: wrap;
        gap: 14px;
        margin-bottom: 20px;
      }
      .stats-head h2 { margin: 8px 0 0; font-size: 22px; }
      .stats-lede {
        margin: 12px 0 0;
        max-width: 46em;
        color: var(--slate);
        font-size: 14px;
        line-height: 1.6;
      }
      .stats-fresh {
        margin: 0;
        color: var(--dim);
        font-size: 12px;
        line-height: 1.5;
        text-align: right;
      }
      .stats-fresh.stale { color: var(--amber); }

      /* A failed poll holds the last good render rather than throwing it
         away for a skeleton: one missed request should not empty a page of
         numbers that were right thirty seconds ago. Dimmed, so nobody reads
         a stale figure as a live one, with the line above saying how old. */
      #view-stats.stale .tiles,
      #view-stats.stale .stats-plate:not(.stats-privacy) { opacity: 0.55; }

      .stats-plate { padding: 18px 20px 20px; margin-bottom: 18px; }
      .stats-plate[hidden] { display: none; }
      .stats-plate h3 {
        margin: 8px 0 2px;
        font-size: 17px;
        font-weight: 700;
        color: var(--cream);
      }
      .stats-plate .plate-note {
        margin: 6px 0 16px;
        color: var(--slate);
        font-size: 13px;
        line-height: 1.55;
      }

      .stats-row {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 18px;
        align-items: start;
      }
      .stats-row[hidden] { display: none; }
      .stats-row .stats-plate { margin-bottom: 18px; }
      @media (max-width: 759px) {
        .stats-row { grid-template-columns: 1fr; gap: 0; }
      }

      /* The four tiles. PROPORTIONAL figures, not the tabular mono the rest
         of this page sets numbers in, and that is not an oversight: mono
         tabular gives every digit the width of a nought, which reads loose
         at display size. A lap time is a measurement and wears mono; a
         count is not and does not. */
      .tiles {
        display: grid;
        grid-template-columns: repeat(3, minmax(0, 1fr));
        gap: 12px;
        margin-bottom: 18px;
      }
      @media (max-width: 899px) {
        .tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
      }
      .tile-stat {
        padding: 14px 16px 16px;
        background: var(--panel);
        border-top: 2px solid var(--edge);
        border-radius: var(--radius);
        box-shadow: inset 0 0 0 1px var(--line);
      }
      .tile-stat .tile-label {
        display: block;
        font-size: 10px;
        font-weight: 700;
        letter-spacing: 0.16em;
        text-transform: uppercase;
        color: var(--sakura);
      }
      .tile-stat .tile-value {
        display: block;
        margin-top: 10px;
        font-family: var(--ui);
        font-variant-numeric: proportional-nums lining-nums;
        font-size: 32px;
        font-weight: 650;
        line-height: 1;
        color: var(--cream);
      }
      /* Flying now is an instrument reading rather than a total, and amber
         is what this product paints an instrument in. */
      .tile-stat.live { border-top-color: var(--amber); }
      .tile-stat.live .tile-label { color: var(--amber); }
      .tile-stat.live .tile-value { color: var(--amber); }
      .tile-stat .tile-note {
        display: block;
        margin-top: 8px;
        color: var(--slate);
        font-size: 12px;
        line-height: 1.45;
      }
      .tile-stat .tile-note:empty { display: none; }

      /* The charts. Measured and drawn at real pixels rather than scaled
         from a fixed viewBox, so a ten pixel axis label is ten pixels on a
         phone as well as on a desktop. paintStats redraws on resize. */
      .chart-wrap { position: relative; margin-bottom: 6px; }
      .chart-wrap:last-of-type { margin-bottom: 0; }
      .chart-title {
        margin: 0 0 6px;
        font-size: 13px;
        font-weight: 700;
        letter-spacing: 0.02em;
        color: var(--cream);
      }
      .chart-wrap svg { display: block; width: 100%; }
      .chart-wrap svg .bar-hit { fill: transparent; outline: none; }
      /* A column reached by Tab is drawn round as well as tinted: the tint
         alone was a sixth of the chrome colour on a dark plate. */
      .chart-wrap svg .bar-hit:focus-visible { fill: rgba(137, 221, 102, 0.16); stroke: var(--sakura); stroke-width: 1.5; }
      .chart-tip {
        position: absolute;
        z-index: 3;
        min-width: 150px;
        padding: 9px 11px;
        background: #0c120d;
        border: 1px solid var(--edge);
        border-radius: 3px;
        box-shadow: 0 10px 22px rgba(0, 0, 0, 0.5);
        color: var(--cream);
        font-size: 12px;
        line-height: 1.45;
        pointer-events: none;
        opacity: 0;
        transition: opacity 90ms ease;
      }
      .chart-tip.on { opacity: 1; }
      .chart-tip b { display: block; margin-bottom: 4px; color: var(--cream); }
      .chart-tip span { color: var(--slate); }
      .chart-tip i {
        font-style: normal;
        float: right;
        margin-left: 14px;
        font-family: var(--mono);
        color: var(--cream);
      }

      /* The table twin. Every chart has one, and it is where a value goes
         when a tooltip is not available: print, a screen reader, or
         somebody who simply wants the numbers. */
      .chart-table {
        margin-top: 12px;
        border-top: 1px solid var(--line);
        padding-top: 10px;
      }
      .chart-table summary {
        cursor: pointer;
        color: var(--slate);
        font-size: 12px;
        font-weight: 600;
        letter-spacing: 0.03em;
      }
      .chart-table summary:hover { color: var(--sakura); }
      .chart-table .scroll { max-height: 280px; overflow: auto; margin-top: 10px; }
      .chart-table table { width: 100%; border-collapse: collapse; font-size: 12px; }
      .chart-table th, .chart-table td {
        padding: 5px 8px;
        text-align: right;
        border-bottom: 1px solid var(--line);
        font-variant-numeric: tabular-nums lining-nums;
      }
      .chart-table th { color: var(--sakura); font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; }
      .chart-table th:first-child, .chart-table td:first-child { text-align: left; }
      .chart-table td { color: var(--slate); font-family: var(--mono); }
      .chart-table td:first-child { font-family: var(--ui); color: var(--cream); }

      /* A ranked list: a name, a bar and the numbers. One hue, because the
         rows are one series measured one way, and length already says which
         is bigger. */
      .rank { margin: 0; padding: 0; list-style: none; }
      .rank li { margin-bottom: 9px; }
      .rank li:last-child { margin-bottom: 0; }
      .rank-top {
        display: flex;
        align-items: baseline;
        justify-content: space-between;
        gap: 12px;
        margin-bottom: 4px;
      }
      .rank-name {
        font-size: 13px;
        color: var(--cream);
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
      }
      .rank-value {
        font-family: var(--mono);
        font-size: 12px;
        color: var(--slate);
        white-space: nowrap;
      }
      .rank-track {
        height: 6px;
        border-radius: 3px;
        background: rgba(157, 179, 200, 0.12);
        overflow: hidden;
      }
      .rank-fill {
        height: 100%;
        border-radius: 3px;
        background: var(--slate);
      }
      /* Unknown is not a place that did worse than Australia: it is the rows
         the edge could not name. It sits under a rule, unranked and quiet. */
      .rank li.unknown { margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--line); }
      .rank li.unknown .rank-name { color: var(--dim); }
      .rank li.unknown .rank-fill { background: var(--dim); }
      .rank-more { margin: 12px 0 0; color: var(--dim); font-size: 12px; }
      /* The countries that did not make the ranking, sitting where they
         belong: after the ranked ones and before the unranked Unknown. */
      .rank-rest { color: var(--dim); font-size: 12px; margin-bottom: 9px; }
      .rank-group { margin-bottom: 18px; }
      .rank-group:last-child { margin-bottom: 0; }
      .rank-group h4 {
        margin: 0 0 9px;
        font-size: 10px;
        font-weight: 700;
        letter-spacing: 0.16em;
        text-transform: uppercase;
        color: var(--sakura);
      }

      /* All time. One hero figure on this tab and this is it. Sans, for the
         same reason the tiles are: a display sized number with every digit
         a nought wide reads loose. */
      #view-stats .alltime {
        display: flex;
        flex-wrap: wrap;
        align-items: flex-end;
        gap: 26px 40px;
      }
      /* The facts are their own grid rather than more flex children, so a
         row that does not divide evenly wraps into a tidy second row
         instead of orphaning one number under the hero. */
      /* THREE columns, not auto-fit. There are six of these, and auto-fit
         can leave one on a row of its own under the hero looking like a
         mistake. Three is two clean rows. Named pilots and pilots back
         another day were taken off: a count of twenty names beside a day
         of hundreds of visitors pulled the eye to the wrong number. */
      #view-stats .facts {
        flex: 1 1 420px;
        display: grid;
        grid-template-columns: repeat(3, minmax(0, 1fr));
        gap: 20px 24px;
      }
      @media (max-width: 719px) {
        #view-stats .facts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
      }
      #view-stats .hero-box { flex: 0 0 auto; }
      #view-stats .hero {
        font-family: var(--ui);
        font-variant-numeric: proportional-nums lining-nums;
        font-size: 52px;
        font-weight: 650;
        line-height: 0.95;
        color: var(--mint);
      }
      #view-stats .hero-label {
        display: block;
        margin-top: 8px;
        font-size: 10px;
        font-weight: 700;
        letter-spacing: 0.16em;
        text-transform: uppercase;
        color: var(--sakura);
      }
      #view-stats .fact { min-width: 84px; }
      #view-stats .fact-value {
        display: block;
        font-family: var(--ui);
        font-variant-numeric: proportional-nums lining-nums;
        font-size: 22px;
        font-weight: 650;
        color: var(--cream);
        line-height: 1;
      }
      #view-stats .fact-label {
        display: block;
        margin-top: 6px;
        color: var(--dim);
        font-size: 11px;
      }

      /* What this counts. */
      .stats-privacy p {
        margin: 0 0 12px;
        max-width: 54em;
        color: var(--slate);
        font-size: 13px;
        line-height: 1.65;
      }
      .stats-optout { margin-top: 16px; }
      .optout-row {
        display: flex;
        align-items: center;
        gap: 12px;
        flex-wrap: wrap;
      }
      .optout-row input { width: 16px; height: 16px; accent-color: var(--mint); margin: 0; }
      .optout-row label { color: var(--cream); font-size: 13px; font-weight: 600; cursor: pointer; }
      .optout-said { margin: 0; color: var(--mint); font-size: 13px; line-height: 1.6; }
      .optout-note { margin: 8px 0 0; color: var(--dim); font-size: 12px; line-height: 1.55; }


#list{max-height:72vh;overflow:auto;padding-right:3px}.ticket{text-decoration:none}.sheet{scroll-margin-top:16px}dialog.panel{width:min(540px,calc(100vw - 32px));max-height:85vh;overflow:auto}dialog::backdrop{background:#0009}@media(max-width:760px){#list{max-height:45vh}.admin-layout{gap:16px}}

:root{--dim:#8a9a86;--edge:rgba(137,221,102,.28);--panel:#17251d;--radius:8px;--ui:system-ui,-apple-system,"Segoe UI",Arial,sans-serif}

/* The isolated viewer releases its context when leaving this section. */
#drone-studio-host iframe{width:100%;height:calc(100vh - 170px);min-height:760px;border:1px solid var(--line);border-radius:10px;background:#10181d}#section-drones{min-width:0}@media(max-width:760px){#drone-studio-host iframe{height:1100px;min-height:1100px}}


/* Numbered pages stay bounded and wrap on narrow screens. */
.page-numbers{display:flex;flex-wrap:wrap;align-items:center;gap:6px}.page-numbers button[aria-current="page"]{border-color:var(--mint);font-weight:700}.pagination{flex-wrap:wrap}
