/* Hoscorp — the whole site's look, in one file.
 *
 * It used to be five files with five copies of the same rules, because the
 * original note in UPLOAD.md said the CSS was inline "so a page cannot break
 * because a stylesheet failed to upload". That was a reasonable trade with two
 * pages. It stopped being one at five: the copies had already drifted — the
 * homepage was full-bleed with a fixed instrument bar, the other four were a
 * centred 860px column with a different type scale — so the site looked like
 * two sites wearing the same colours.
 *
 * Drift is certain over time. A failed upload is a one-off, it is visible the
 * instant you open the page, and check-site.py already resolves every
 * referenced asset against the folder before anything is uploaded. So: one
 * file, checked, and the risk that remains is the one you can see.
 *
 * Everything readable is 4.5:1 or better against its own background.
 * Atmosphere is not an excuse for text nobody can read. */

:root {
  --ink:    #030303;
  --raised: #0b0c0c;
  --paper:  #eef1f0;
  --dim:    #9aa09e;
  --faint:  #7c8280;
  --ghost:  #767c7a;
  --rule:   #171a19;
  --accent: #90e4f0;
  --warn:   #f0a890;
  --go:     #a8c47e;
  --void:   #c99a6e;

  /* Confidence tiers, the same three the app draws. A tier is a colour and a
     colour alone cannot be read by everyone or on every screen, so every
     surface that shows one also prints the margin it stands for. */
  --blue:   #6e93d6;
  --purple: #b084d8;
  --gold:   #d8b24a;

  /* The single measure that makes a page full-bleed rather than a column.
     Every section, the bar and the footer share it, so the left edge of a
     heading on one page lines up with the left edge of a heading on any
     other. That alignment is most of what "the same site" means. */
  --pad:    clamp(18px, 4.5vw, 68px);
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  margin: 0; background: var(--ink); color: var(--paper);
  font: 400 15px/1.7 "Roboto Mono", ui-monospace, SFMono-Regular, Menlo,
        Consolas, "Liberation Mono", monospace;
  -webkit-font-smoothing: antialiased; overflow-x: hidden;
}

/* Scanlines. Fixed, non-interactive, very faint — present rather than
   noticed, which is the point. */
body::after {
  content: ""; position: fixed; inset: 0; z-index: 40; pointer-events: none;
  background: repeating-linear-gradient(
    180deg, rgba(255,255,255,.022) 0 1px, transparent 1px 3px);
}

/* --- chrome --------------------------------------------------------------- */

.bar {
  position: fixed; inset: 0 0 auto; z-index: 30;
  display: flex; align-items: center; gap: 18px; flex-wrap: wrap;
  padding: 12px var(--pad);
  background: color-mix(in srgb, var(--ink) 88%, transparent);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--rule);
  font-size: 11px; letter-spacing: 0.16em; color: var(--faint);
}
.bar img { height: 17px; width: auto; display: block; }
.bar .sep { color: var(--rule); }
.bar .right { margin-left: auto; display: flex; align-items: center; gap: 18px; }

/* Navigation in the bar. Present on every page including the homepage, so
   the leaderboard and the status page are one tap from anywhere rather than
   only from the bottom of the front page. `aria-current` marks where you
   already are instead of offering it again. */
.bar nav { display: flex; gap: 16px; }
.bar nav a { color: var(--faint); border-bottom: 1px solid transparent; padding-bottom: 2px; }
.bar nav a:hover { color: var(--paper); border-bottom-color: var(--accent); }
.bar nav a[aria-current="page"] { color: var(--paper); border-bottom-color: var(--rule); }

.progress { position: fixed; top: 0; left: 0; z-index: 31;
            height: 1px; width: 0; background: var(--accent); }

/* --- type ----------------------------------------------------------------- */

.tag {
  display: block; margin: 0 0 20px;
  font-size: 11px; font-weight: 500; letter-spacing: 0.28em;
  text-transform: uppercase; color: var(--accent);
}
h1, h2 { margin: 0; font-weight: 700; letter-spacing: -0.025em;
         line-height: 1.06; text-wrap: balance; }
h1 { font-size: clamp(26px, 5.4vw, 62px); }
h2 { font-size: clamp(21px, 3.4vw, 40px); }

/* More than one topic in a single section.
 *
 * `h2 { margin: 0 }` above is correct on the homepage, where every heading
 * opens its own <section> and the section's own padding does the spacing. It
 * is wrong the moment a page puts several headings inside one section — the
 * dashboard has six — because then each one sits welded to the block above it
 * and the block below, which is exactly what it looked like.
 *
 * Adjacent margins collapse, so a following element that already carries its
 * own top margin (.note, .panel, .grid) keeps the larger of the two rather
 * than adding them. A plain wrapper like <div id="board"> gets the 18px.
 *
 * The .tag exception matters: an eyebrow label and its heading are one unit,
 * and pushing 84px between them would break every section on the front page. */
section h2 { margin: clamp(46px, 6vw, 84px) 0 18px; }
/* Except the one that opens a section, where the section's own padding is
   already the space and an eyebrow label belongs tight to its heading. Stated
   as two cases rather than one because a heading can open a section either
   under a .tag or on its own. */
section > .tag + h2,
section > h2:first-child { margin-top: 0; }
h3 { margin: clamp(30px, 3.4vw, 44px) 0 12px; font-size: 15px; font-weight: 500;
     letter-spacing: 0.14em; text-transform: uppercase; color: var(--faint); }

/* Long documents — the policy and the erasure page — set their h2 at the
   label scale instead of the display scale.
 *
 * The homepage has four h2s and each one opens a section, so 40px is right
 * there. The privacy policy has nine, one every few paragraphs, and at 40px
 * they stop being structure and become an obstacle course: the reader scrolls
 * past headline after headline looking for a sentence.
 *
 * The element stays an h2. Screen readers and the document outline should see
 * a policy with nine sections, because that is what it is; only the size
 * changes. Demoting them to h3 to get the look would have lied about the
 * structure to save a CSS rule. */
.doc h2 { font-size: 15px; font-weight: 500; letter-spacing: 0.14em;
          text-transform: uppercase; color: var(--faint);
          margin: clamp(36px, 4.4vw, 58px) 0 14px; }
.doc h2:first-of-type { margin-top: clamp(30px, 3.4vw, 44px); }

p { margin: 0 0 16px; color: var(--dim); max-width: 40em; }
p.lead { font-size: clamp(16px, 1.7vw, 19px); color: var(--paper); }
p:last-child { margin-bottom: 0; }
a { color: inherit; text-decoration: none; }
strong, b { color: var(--paper); font-weight: 500; }

ul, ol { margin: 0 0 16px; padding-left: 1.3em; color: var(--dim); max-width: 40em; }
li { margin: 0 0 7px; }

/* Prose links need to look like links. In the chrome they do not, because
   there the whole line is obviously navigation; in a paragraph of policy an
   unmarked link is a link nobody finds. */
.prose a, p a { border-bottom: 1px solid var(--rule); color: var(--paper); }
.prose a:hover, p a:hover { border-bottom-color: var(--accent); }

section { padding: clamp(64px, 9vw, 130px) var(--pad);
          border-top: 1px solid var(--rule); }
.hero { padding-top: clamp(110px, 16vh, 190px); border-top: 0; }
/* Inner pages start under the fixed bar without the homepage's full drop:
   there is no hero to breathe, and 190px of nothing above a privacy policy
   reads as a page that has not loaded. */
.head { padding-top: clamp(96px, 13vh, 150px); border-top: 0; }

.cursor { display: inline-block; width: 0.55em; height: 1em;
          background: var(--accent); vertical-align: -0.13em; margin-left: 4px;
          animation: blink 1.1s steps(1) infinite; }
@keyframes blink { 50% { opacity: 0; } }

.redact { background: var(--rule); color: transparent; user-select: none;
          padding: 0 2px; border-radius: 1px; }
.redact::selection { background: var(--rule); }

.stamp { margin: 0 0 8px; color: var(--faint); font-size: 13px;
         letter-spacing: 0.06em; }

/* --- reveal --------------------------------------------------------------- */

.up { opacity: 0; transform: translateY(18px);
      transition: opacity .8s ease, transform .8s cubic-bezier(.2,.7,.3,1); }
.up.in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .up { opacity: 1; transform: none; transition: none; }
  html { scroll-behavior: auto; }
  .marquee span { animation: none !important; }
  .cursor { animation: none; }
  body::after { display: none; }
}
/* Belt and braces: if the script fails or is blocked, everything marked for
   reveal must still be visible. A design that hides its own content until
   JavaScript says otherwise is a design with a blank page as a failure mode. */
.no-js .up { opacity: 1; transform: none; }

/* --- panel ---------------------------------------------------------------- */

.panel { margin: clamp(38px, 5vw, 64px) 0 0; border: 1px solid var(--rule);
         background: var(--raised); }
.panel:first-child { margin-top: 0; }
.panel-head { display: flex; justify-content: space-between; gap: 14px;
              padding: 11px 18px; border-bottom: 1px solid var(--rule);
              font-size: 11px; letter-spacing: 0.18em; color: var(--faint); }
.panel-body { padding: clamp(20px, 3vw, 32px); }

.figure { display: flex; align-items: baseline; gap: 12px; }
.figure b { font-size: clamp(42px, 7vw, 76px); font-weight: 700; line-height: 1;
            letter-spacing: -0.04em; font-variant-numeric: tabular-nums; }
.figure span { font-size: 12px; letter-spacing: 0.18em; color: var(--faint);
               text-transform: uppercase; }
.track { margin: 18px 0 0; height: 2px; background: var(--rule); }
.fill { height: 2px; width: 0; background: var(--accent); }
.telemetry { display: flex; flex-wrap: wrap; gap: 6px 26px; margin: 18px 0 0;
             font-size: 12px; color: var(--faint); letter-spacing: 0.06em; }
.telemetry b { color: var(--paper); font-weight: 500;
               font-variant-numeric: tabular-nums; }

/* --- marquee -------------------------------------------------------------- */

.marquee { display: flex; overflow: hidden; user-select: none;
           padding: 14px 0; white-space: nowrap;
           border-top: 1px solid var(--rule); border-bottom: 1px solid var(--rule); }
.marquee span { flex-shrink: 0; padding-right: 34px;
                font-size: clamp(12px, 1.5vw, 15px); letter-spacing: 0.24em;
                color: var(--ghost); text-transform: uppercase;
                animation: slide 44s linear infinite; }
@keyframes slide { to { transform: translateX(-100%); } }

/* --- rows and grid -------------------------------------------------------- */

.rows { margin: clamp(30px, 4vw, 48px) 0 0; }
.rows:first-child { margin-top: 0; }
.row { display: flex; gap: 22px; padding: 15px 0;
       border-top: 1px solid var(--rule); font-size: 14px; color: var(--dim);
       align-items: baseline; }
.row b { flex: 0 0 11em; font-weight: 400; font-size: 11px;
         letter-spacing: 0.18em; text-transform: uppercase; color: var(--faint); }
.row span { flex: 1; }

.grid { display: grid; gap: 1px; background: var(--rule);
        border: 1px solid var(--rule);
        grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
        margin-top: clamp(30px, 4vw, 52px); }
.grid:first-child { margin-top: 0; }
.cell { background: var(--ink); padding: clamp(22px, 2.6vw, 32px); }
.cell .k { font-size: 10px; letter-spacing: 0.18em; text-transform: uppercase;
           color: var(--faint); }
.cell .n { font-size: clamp(30px, 3.8vw, 46px); font-weight: 700;
           line-height: 1; letter-spacing: -0.03em;
           font-variant-numeric: tabular-nums; }
.cell .n small { font-size: .4em; font-weight: 400; margin-left: 5px;
                 letter-spacing: .06em; color: var(--faint); }
.cell .n.go { color: var(--go); }
.cell .n.void { color: var(--void); }
.cell p { margin: 13px 0 0; font-size: 12.5px; line-height: 1.65;
          color: var(--faint); max-width: none; letter-spacing: 0.04em; }
.cell em { font-style: normal; color: var(--dim); }

/* --- calls to action ------------------------------------------------------ */

.big { display: inline-block; margin: 22px 0 0;
       font-size: clamp(18px, 3vw, 34px); font-weight: 700;
       letter-spacing: -0.02em; border-bottom: 2px solid var(--rule);
       padding-bottom: 3px; transition: border-color .25s, color .25s; }
.big:hover { border-bottom-color: var(--accent); color: var(--accent); }

/* The pair under the hero. Bordered rather than filled: a solid button in
   this palette reads as a warning, and these are invitations. */
.actions { display: flex; flex-wrap: wrap; gap: 12px;
           margin: clamp(28px, 4vw, 40px) 0 0; }
.act { display: inline-flex; align-items: baseline; gap: 10px;
       padding: 13px 20px; border: 1px solid var(--rule);
       background: var(--raised); color: var(--paper);
       font-size: 12px; letter-spacing: 0.16em; text-transform: uppercase;
       transition: border-color .25s, color .25s, background .25s; }
.act i { font-style: normal; color: var(--faint); letter-spacing: 0.2em; }
.act:hover { border-color: var(--accent); color: var(--accent); }
.act:hover i { color: var(--accent); }
.act.primary { border-color: color-mix(in srgb, var(--accent) 45%, var(--rule)); }

.back { display: inline-block; margin: 0 0 26px; font-size: 12px;
        letter-spacing: 0.16em; text-transform: uppercase; color: var(--faint); }
.back:hover { color: var(--paper); }

/* --- tables --------------------------------------------------------------- */

table { width: 100%; border-collapse: collapse; margin: clamp(26px,3vw,40px) 0 16px;
        font-size: 14px; }
table:first-child { margin-top: 0; }
th, td { text-align: left; padding: 11px 14px 11px 0;
         border-top: 1px solid var(--rule); vertical-align: baseline; }
th { color: var(--faint); font-weight: 400; letter-spacing: 0.14em;
     text-transform: uppercase; font-size: 10px; }
td { color: var(--dim); }
td.n { text-align: right; color: var(--paper); font-variant-numeric: tabular-nums; }
td.reason { color: var(--void); font-size: 13px; }
td.rank { color: var(--faint); font-variant-numeric: tabular-nums; width: 3em; }
td.who { color: var(--paper); }
td.car { color: var(--dim); font-size: 13px; }
td.t { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap;
       font-size: 17px; font-weight: 500; }
td.t .pm { display: block; font-size: 11px; font-weight: 400; color: var(--faint);
           letter-spacing: 0.04em; }
/* The same figure in the other unit, beside rather than below: kW is what the
   register holds, pk is what people actually say to each other about cars. */
td.who .pm { font-size: 11.5px; color: var(--faint); margin-left: 7px;
             letter-spacing: 0.04em; }
.gold { color: var(--gold); } .purple { color: var(--purple); } .blue { color: var(--blue); }

.key { display: flex; flex-wrap: wrap; gap: 10px 22px; margin: 20px 0 0;
       font-size: 12.5px; color: var(--faint); letter-spacing: 0.04em; }
.key span::before { content: "\25A0  "; }

/* --- notes, forms, filters ------------------------------------------------ */

.note { background: var(--raised); border: 1px solid var(--rule);
        border-left: 2px solid var(--accent);
        padding: clamp(18px,2.4vw,26px); margin: clamp(26px,3vw,38px) 0 0; }
/* The same block, for something the reader cannot undo. Used once, on the
   erasure page, where the left edge changing colour is the only warning the
   layout gives before an irreversible form. */
.note.warn { border-left-color: var(--warn); }
.note.warn strong { color: var(--warn); }
.note p { max-width: 52em; }
.note p:last-child { margin-bottom: 0; }
.empty { color: var(--faint); }

label { display: block; margin: 0 0 6px; font-size: 10px; letter-spacing: 0.18em;
        text-transform: uppercase; color: var(--faint); }
input[type=text], input[type=password] {
  width: 100%; max-width: 26em; margin: 0 0 16px; padding: 13px 14px;
  background: var(--ink); color: var(--paper);
  border: 1px solid var(--rule); border-radius: 0;
  font: inherit; font-size: 16px;   /* 16px or iOS zooms the page on focus */
}
input:focus { outline: none; border-color: var(--accent); }

button {
  padding: 13px 22px; cursor: pointer; background: transparent;
  color: var(--accent); border: 1px solid var(--accent); border-radius: 0;
  font: inherit; font-size: 12px; letter-spacing: 0.16em; text-transform: uppercase;
  transition: background .2s, color .2s;
}
button:hover:not(:disabled) { background: var(--accent); color: var(--ink); }
button:disabled { color: var(--faint); border-color: var(--rule); cursor: default; }
button.danger { color: var(--warn); border-color: var(--warn); }
button.danger:hover:not(:disabled) { background: var(--warn); color: var(--ink); }

.filters { display: flex; flex-wrap: wrap; gap: 1px; background: var(--rule);
           border: 1px solid var(--rule); margin: 0 0 6px; }
.filters button { flex: 1 1 auto; min-width: 92px; padding: 12px 8px;
                  background: var(--raised); color: var(--faint);
                  border: 0; letter-spacing: 0.1em; }
.filters button:hover { background: var(--raised); color: var(--paper); }
.filters button[aria-pressed="true"] { color: var(--ink); background: var(--accent); }
.filterlabel { margin: 22px 0 7px; font-size: 10px; letter-spacing: 0.18em;
               text-transform: uppercase; color: var(--faint); }

.msg { margin: 14px 0 0; color: var(--void); }
.hidden { display: none; }

/* --- footer --------------------------------------------------------------- */

footer { padding: 26px var(--pad) 46px; border-top: 1px solid var(--rule);
         display: flex; flex-wrap: wrap; gap: 8px 26px;
         font-size: 11px; letter-spacing: 0.14em; color: var(--faint); }
footer a { border-bottom: 1px solid var(--rule); }
footer a:hover { border-bottom-color: var(--accent); color: var(--paper); }
footer .spacer { margin-left: auto; }

/* --- small screens -------------------------------------------------------- */

/* The bar is one flex row and it has to stay one row. Measured: at 375px the
   old three-link bar came to 371px — it fit by four pixels, which nobody
   noticed because nobody measured it. Adding MODELS and the EN/NL switch took
   it to 490px in English and 535px in Dutch, where `flex-wrap: wrap` sent the
   navigation onto a second line of a *fixed* bar, behind the page content.
   That reads as "the navigation is missing", and it is worse in Dutch only
   because KENTEKEN and MODELLEN are five characters longer than PLATE and
   MODELS.

   So below 700px the decoration goes and the type tightens, and the nav is
   allowed to scroll sideways as a last resort: a link that needs a swipe is
   recoverable, a link that has wrapped out of sight is not. */
@media (max-width: 700px) {
  .bar { gap: 10px; flex-wrap: nowrap; }
  .bar .hide-sm { display: none; }
  .bar #clock { display: none; }          /* decoration, first to go */
  .bar .right { gap: 10px; min-width: 0; }
  .bar nav { gap: 12px; font-size: 12px; min-width: 0;
             overflow-x: auto; scrollbar-width: none; }
  .bar nav::-webkit-scrollbar { display: none; }
  .bar nav a { white-space: nowrap; }
  .lang { margin-left: 8px; flex: 0 0 auto; }
}
@media (max-width: 430px) {
  .bar { padding-left: 14px; padding-right: 14px; }
  .bar img { height: 14px; }
  .bar nav { gap: 10px; font-size: 11px; }
}
@media (max-width: 620px) {
  .row { display: block; }
  .row b { display: block; margin-bottom: 5px; }
  /* The car column goes first on a narrow screen: the name and the time are
     what a leaderboard is for, and a three-line car string wrecks the row. */
  th.car, td.car { display: none; }
  .actions .act { flex: 1 1 100%; justify-content: center; }
}

/* --- language switch ------------------------------------------------------ */
/* Visible rather than automatic. Redirecting on Accept-Language would mean
   Googlebot, which crawls from the US, only ever sees the English side — and
   it traps anybody who actually wants the other one. */
.lang { display: inline-flex; gap: 7px; align-items: baseline;
        margin-left: 16px; font-size: 11px; letter-spacing: 0.16em; }
.lang b { color: var(--paper); font-weight: 500; }
.lang a { color: var(--faint); }
.lang a:hover { color: var(--accent); }
