/*
 * The design system: every page's tokens and shared components, in one file.
 *
 * Every page links it first — the public page as it lies, the staff's pages
 * ahead of their own built styles — so a button, a field or a chip is defined
 * once and looks the same wherever it appears. Three rules decide everything
 * here, and a new variant has to pass them:
 *
 *   1. Things that look alike claim to belong together. Things that do not,
 *      must not look alike.
 *   2. Every variant has a rule. If it cannot be said in one sentence when a
 *      variant is used, it does not exist.
 *   3. Density changes the rhythm, never the form. The operator gets more rows
 *      per screen, not a different product.
 *
 * Light only, on purpose: the same laptop is used by whoever is free that
 * morning, and a screen that is dark one day and light the next is one more
 * thing to reorient to mid-race. The wall clock is the exception and says so
 * itself.
 */

:root {
  /* Brand: the navy, the red and Figtree are kanotevent.se's own. */
  --navy: #1b3c5d;
  --navy-deep: #10263c;
  --navy-edge: #2c5b87;
  --navy-wash: #eaf0f6;
  --on-navy: #cfdde9;
  --on-navy-quiet: #9fbad2;
  --red: #cc272e;
  --red-deep: #a81f25;
  --red-wash: #fbe8e9;
  --go: #12703a;
  --go-wash: #e2f0e8;

  /* One cool neutral ramp, drawn toward the navy so the greys and the brand
     agree instead of arguing. n5 is for equipment and icons, never for text
     that has to be read: it fails contrast against white. */
  --n0: #ffffff;
  --n1: #f6f7f9;
  --n2: #eceef2;
  --n3: #dde1e7;
  --n4: #c4cad3;
  --n5: #8a94a1;
  --n6: #5a636f;
  --n7: #171b21;

  /* Medals. Only a placing carries them. */
  --gold: #e6c34a;
  --silver: #c9ced4;
  --bronze: #d1935a;

  /* One radius. 3 px read as a mistake and 12 px as soft; 6 px reads as a
     decision. The pill is for chips only. */
  --r: 6px;
  --r-pill: 999px;

  /* Spacing. Every step shrinks in the operator's density, the small ones
     included: density that only touches the big gaps is not density. */
  --s1: 0.25rem;
  --s2: 0.5rem;
  --s3: 0.75rem;
  --s4: 1rem;
  --s5: 1.5rem;
  --s6: 2rem;
  --s7: 3rem;

  /* Seven sizes, whole pixels at a 16 px root: 12 14 16 18 22 30 48. Figtree
     turns soft at fractional sizes, and this is read outdoors, against the
     light. */
  --face: Figtree, system-ui, -apple-system, 'Segoe UI', sans-serif;
  --t-label: 0.75rem;
  --t-small: 0.875rem;
  --t-body: 1rem;
  --t-lead: 1.125rem;
  --t-h2: 1.375rem;
  --t-h1: 1.875rem;
  --t-display: 3rem;

  /* Leading by what the text is for, not one number for the whole page. */
  --lh-display: 1.04;
  --lh-head: 1.2;
  --lh-body: 1.5;
  --lh-row: 1.3;

  /* The row rhythm: the single biggest lever on how much fits on a screen. */
  --row-y: 0.75rem;
  --row-x: 1rem;
  --hit: 2.75rem;

  --wrap-read: 40rem;

  color-scheme: light;
}

/*
 * The operator's density: a laptop on a table, all day. The whole scale steps
 * down together, so the rhythm stays in proportion and a whole heat fits
 * without scrolling — scrolling mid-race is looking away.
 */
[data-density='work'] {
  --s1: 0.2rem;
  --s2: 0.35rem;
  --s3: 0.5rem;
  --s4: 0.7rem;
  --s5: 1rem;
  --s6: 1.35rem;
  --s7: 2rem;

  --t-label: 0.6875rem;
  --t-small: 0.8125rem;
  --t-body: 0.875rem;
  --t-lead: 1rem;
  --t-h2: 1.125rem;
  --t-h1: 1.375rem;
  --t-display: 1.75rem;

  --lh-body: 1.4;
  --lh-row: 1.2;

  --row-y: 0.375rem;
  --row-x: 0.7rem;
  --hit: 2.25rem;
}

/* ---------- the page ---------- */

*,
*::before,
*::after {
  box-sizing: border-box;
}

/* hidden has to win even over a rule that sets display on the element. */
[hidden] {
  display: none !important;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--n2);
  color: var(--n7);
  font-family: var(--face);
  font-size: var(--t-body);
  font-weight: 400;
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
}

/* The operator's background is a step lighter: white cards on it still read
   as cards, and eight hours of it is easier on the eyes. */
body[data-density='work'] {
  background: var(--n1);
}

.wrap {
  width: 100%;
  max-width: var(--wrap-read);
  margin-inline: auto;
  padding-inline: var(--s4);
}

.link {
  color: var(--navy);
  font-weight: 600;
}

:focus-visible {
  outline: 2px solid var(--navy);
  outline-offset: 2px;
}

/* ---------- the masthead ---------- */

/*
 * The navy strip with the competition's name, on every page. It is the
 * cheapest possible way of saying "one system", and it is honest: it says you
 * are in the same competition, whichever page you are on.
 */
.masthead {
  background: var(--navy);
  color: var(--n0);
}

.masthead__eyebrow {
  margin: 0;
  color: var(--on-navy-quiet);
  font-size: var(--t-label);
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.masthead__title {
  margin: var(--s1) 0 0;
  font-size: var(--t-display);
  font-weight: 800;
  line-height: var(--lh-display);
  letter-spacing: -0.025em;
  overflow-wrap: anywhere;
  hyphens: auto;
  text-wrap: balance;
}

/* A championship's name does not fit at 48 px on a phone. The next size down
   rather than a fraction of the screen width: whole pixels stay sharp. */
@media (max-width: 30rem) {
  .masthead__title {
    font-size: var(--t-h1);
    letter-spacing: -0.02em;
  }
}

/* ---------- buttons: four, by consequence ---------- */

/*
 * The variant answers two questions: can it be undone, and does it move the
 * race forward?
 *
 *   primary  filled navy   moves the race forward. Exactly one per screen:
 *                          it is where the eye goes, and two is a choice.
 *   (plain)  white, framed anything that can be undone.
 *   danger   red frame     only what cannot be undone. Red means nothing else.
 *   quiet    thin frame    changes nothing in the competition: navigation,
 *                          signing out. It keeps its frame because it is a
 *                          button — form says what a thing is, weight says how
 *                          much it matters.
 */
.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s2);
  min-height: var(--hit);
  padding: var(--s2) var(--s4);
  border: 1px solid var(--n4);
  border-radius: var(--r);
  background: var(--n0);
  color: var(--n7);
  font: inherit;
  font-size: var(--t-small);
  font-weight: 600;
  line-height: var(--lh-head);
  text-align: center;
  text-decoration: none;
  cursor: pointer;
}

.button:hover {
  border-color: var(--n5);
  background: var(--n1);
}

.button--primary {
  border-color: var(--navy);
  background: var(--navy);
  color: var(--n0);
  font-weight: 700;
}

.button--primary:hover {
  border-color: var(--navy-deep);
  background: var(--navy-deep);
}

.button--danger {
  border-color: var(--red);
  color: var(--red-deep);
}

.button--danger:hover {
  border-color: var(--red);
  background: var(--red);
  color: var(--n0);
}

.button--quiet {
  border-color: var(--n3);
  background: none;
  color: var(--n6);
  font-weight: 500;
}

.button--quiet:hover {
  border-color: var(--n4);
  background: var(--n2);
}

/* On the navy strip the frame is drawn in the strip's own light blue. */
.masthead .button--quiet {
  border-color: rgb(255 255 255 / 30%);
  color: var(--on-navy);
}

.masthead .button--quiet:hover {
  border-color: rgb(255 255 255 / 60%);
  background: rgb(255 255 255 / 8%);
  color: var(--n0);
}

.button--wide {
  width: 100%;
}

/* Still there, plainly not working — and something beside it always says why.
   A button that disappears teaches nobody anything. */
.button:disabled,
.button:disabled:hover {
  border-color: var(--n3);
  background: var(--n2);
  color: var(--n5);
  cursor: not-allowed;
}

.icon-button {
  display: grid;
  place-items: center;
  width: var(--hit);
  height: var(--hit);
  padding: 0;
  border: 0;
  border-radius: var(--r);
  background: none;
  color: var(--n6);
  cursor: pointer;
}

.icon-button:hover:not(:disabled) {
  background: var(--n2);
  color: var(--red-deep);
}

.icon-button:disabled {
  opacity: 0.3;
  cursor: default;
}

.icon-button svg {
  width: 1.125rem;
  height: 1.125rem;
}

/* ---------- fields ---------- */

.control {
  display: block;
  margin-bottom: var(--s3);
}

.label {
  display: block;
  margin-bottom: var(--s1);
  color: var(--n6);
  font-size: var(--t-small);
  font-weight: 500;
}

/*
 * Empty is a hole to fill, grey; filled is a value, white. The difference is
 * what the eye runs down a column of boats looking for.
 */
.field {
  width: 100%;
  min-height: var(--hit);
  padding: var(--s2) var(--s3);
  border: 1px solid var(--n4);
  border-radius: var(--r);
  background: var(--n0);
  color: var(--n7);
  font: inherit;
  font-weight: 500;
}

.field:placeholder-shown {
  background: var(--n2);
}

.field:focus-visible {
  outline-offset: 0;
  border-color: var(--navy);
}

/* A phone zooms in on any field under 16 px the moment it is touched. */
@media (pointer: coarse) {
  .field {
    font-size: 1rem;
  }
}

/* A switch, for a setting that is simply on or off. */
.toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  font-size: var(--t-small);
  font-weight: 600;
  cursor: pointer;
}

.toggle input {
  position: relative;
  flex: none;
  width: 2.25rem;
  height: 1.35rem;
  margin: 0;
  border: 1px solid var(--n4);
  border-radius: var(--r-pill);
  background: var(--n3);
  appearance: none;
  cursor: pointer;
}

.toggle input::after {
  content: '';
  position: absolute;
  top: 2px;
  left: 2px;
  width: 1rem;
  height: 1rem;
  border-radius: 50%;
  background: var(--n0);
  box-shadow: 0 1px 2px rgb(16 38 60 / 30%);
}

.toggle input:checked {
  border-color: var(--navy);
  background: var(--navy);
}

.toggle input:checked::after {
  left: calc(100% - 1rem - 2px);
}

/* ---------- panels ---------- */

.panel {
  padding: var(--s4);
  border: 1px solid var(--n4);
  border-radius: var(--r);
  background: var(--n0);
}

.panel__title {
  margin: 0 0 var(--s3);
  color: var(--n6);
  font-size: var(--t-label);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* ---------- chips: where a race is, and nothing else ---------- */

/*
 * Outline while a stage is under way, fill once it is finished. Green is the
 * tower's work; navy is the public's, the masthead's own colour. Grey outline,
 * green outline, green fill, navy fill: the colour grows with how far the race
 * has got, so a list reads from a distance without reading the words.
 */
.chip {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.2rem 0.6rem;
  border: 1px solid var(--n4);
  border-radius: var(--r-pill);
  background: var(--n0);
  color: var(--n6);
  font-size: var(--t-label);
  font-weight: 700;
  letter-spacing: 0.02em;
  line-height: var(--lh-head);
  white-space: nowrap;
}

.chip--live {
  border-color: var(--go);
  color: var(--go);
}

.chip--held {
  border-color: var(--go);
  background: var(--go);
  color: var(--n0);
}

.chip--done {
  border-color: var(--navy);
  background: var(--navy);
  color: var(--n0);
}

/* Not a step in the chain: something is wrong. */
.chip--gone {
  border-color: #e3a9ac;
  background: var(--red-wash);
  color: var(--red-deep);
}

.chip__dot {
  width: 0.4rem;
  height: 0.4rem;
  border-radius: 50%;
  background: currentColor;
}

/*
 * Equipment — camera, clocks, by hand — is not state. No pill and no fill, so
 * it can never be read as how far a race has got.
 */
.kit {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  color: var(--n5);
  font-size: var(--t-label);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
}

.kit svg {
  flex: none;
  width: 0.85em;
  height: 0.85em;
}

/* ---------- words ---------- */

.status {
  margin: 0;
  color: var(--n6);
  font-size: var(--t-small);
}

.hint {
  margin: 0 0 var(--s3);
  color: var(--n6);
  font-size: var(--t-small);
}

/* Something is wrong and has to be seen: the one other use of red. */
.status--poor,
.clock__status--poor {
  color: var(--red-deep);
  font-weight: 600;
}

@media (prefers-reduced-motion: reduce) {
  * {
    animation: none !important;
    transition: none !important;
  }
}
