/* ---------------------------------------------------------------------------
   The foundation every page of this site is built on: the typeface, the design
   tokens, the rules that set the defaults a browser would otherwise choose, and
   the handful of parts that appear on more than one page.

   Four pages load this file: the home page, the privacy notice, the terms and
   the accessibility statement. site.css and page.css hold what is particular to
   each, and nothing else. A value declared here is declared once for the whole
   site, which is the point: the two stylesheets used to carry their own copy of
   --ink, --muted, --hairline and the corner radius, and the copies had already
   drifted apart.

   Paths are relative to this file, not to the page that loads it.
   --------------------------------------------------------------------------- */

/* The typeface, served from this origin. Nothing about a visitor reaches a font
   host: no request, no IP address, no referrer. Latin and latin-ext only, which
   is what the copy uses.

   Instrument Sans is a variable font: a single file carries every weight from
   400 to 700, which is why two files replace the twelve static ones this site
   used to ship. It is licensed under the SIL Open Font License, whose text sits
   beside the woff2 in assets/fonts/OFL.txt, as that license requires. */
@font-face {
  font-family: "Instrument Sans";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("../fonts/InstrumentSans-latin.woff2") format("woff2");
  unicode-range:
    U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Instrument Sans";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("../fonts/InstrumentSans-latin-ext.woff2") format("woff2");
  unicode-range:
    U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* ---------------------------------------------------------------------------
   The design tokens. Every color, size, duration and shadow in this file is
   named here and referenced everywhere else, so a value appears once and a
   reader never has to guess what a number means.
   --------------------------------------------------------------------------- */
:root {
  /* One typeface for the whole site. Named here so that swapping it is a single
     line, and so that no rule anywhere else spells out a family. */
  --font-sans: "Instrument Sans", system-ui, sans-serif;

  /* The one exception, and it is not a design choice. Cookie names in the
     privacy notice are set in it, because an underscore in a proportional face
     is easy to miss and `_ga` has to read as a name rather than as a typo. The
     stack is whatever monospaced face the reader's system already has, so it
     costs no download and reaches no font host. */
  --font-code: ui-monospace, "SF Mono", Menlo, Consolas, monospace;

  /* --- The type scale -----------------------------------------------------
     Five sizes, two pixels apart. Below twenty pixels a single pixel of
     difference does not read as a second size, it reads as a hesitation, and
     the page carried six of them: 9, 12, 14, 16, 18 and 20 each sat one pixel
     from a neighbor doing the same job.

     Three kinds of number are deliberately NOT on this ladder.

     The text inside a chart. A chart is an SVG with its own coordinate system,
     so its 7px is not seven pixels on screen: it is whatever the width of the
     card decides. Putting chart text on a text scale would break the drawing.
     Twelve declarations, in .gauge-tick and in the .ch- and .fc- rules.

     The journal mastheads. Each one imitates the wordmark of the journal it
     names, down to the family and the size, which is where the single 12.5px
     comes from. Nine declarations, all named .journal-something.

     The headings, which grow with the window and are written as clamp(). */
  --text-fine: 11px;
  --text-label: 13px;
  --text-small: 15px;
  --text-body: 17px;
  --text-lead: 19px;

  /* --- The heading scale --------------------------------------------------
     Six sizes that grow with the window rather than stepping at a breakpoint.
     Each is a clamp: a floor for the phone, a slope read off the window width,
     and a ceiling so a wide screen does not turn a heading into a poster.

     Eleven headings used eleven different clamps, and three of those were pairs
     doing the same job a hair apart. A section title and the title of a legal
     page were the same number at every width below 1160px and parted only
     above it. A card title, a chart title and a legal subtitle sat within one
     pixel of each other on a phone. The two large figures shared a floor and a
     ceiling while climbing between them at different rates, so they matched at
     both ends and never in the middle.

     Two of these names carry a single use each, on purpose. A band title is a
     real rung between a page title and a card title, and the small figure is
     one between a card title and the large figure. Naming a rung is what stops
     the next person from inventing one beside it. */
  --title-hero: clamp(42px, 6.2vw, 86px);
  --title-page: clamp(30px, 3.8vw, 48px);
  --title-band: clamp(26px, 2.8vw, 38px);
  --title-card: clamp(20px, 2.2vw, 26px);
  --figure: clamp(38px, 4.6vw, 52px);
  --figure-small: clamp(24px, 2.6vw, 34px);

  /* --- Light ground -------------------------------------------------------
     Cool, never warm. The page stays calm; color lives in the dark sections. */
  --ground: #f5f6f8;
  --ground-rgb: 245, 246, 248;
  --ground-alt: #eaedf1;
  --surface: #ffffff;

  /* --- Ink ---------------------------------------------------------------- */
  --ink: #14171c;
  --muted: #4a505a;

  /* The charter asks for #8A9099 here. Measured, that is 2.97:1 against the
     ground, where WCAG AA wants 4.5:1 for text this size, and every small label
     on the page is set in it. This is the same grey walked
     down until the worst of the three light grounds clears the threshold:
     4.90:1 on --ground, 4.51:1 on --ground-alt, 5.29:1 on --surface. It still
     reads as the quietest of the three inks. */
  --faint: #666c75;

  /* --- Lines --------------------------------------------------------------
     Three weights of edge: a hairline for rules, a card border that matches it,
     and a heavier one that a ghost button needs in order to read as a button. */
  --hairline: #e4e7ec;
  --border-input: #dee2e8;
  --border-secondary: #c6cbd2;

  /* --- The one accent -----------------------------------------------------
     A single blue, in three values: the accent itself, a brighter top stop for
     gradients and hovers, and a deeper one for a pressed link.

     --accent-rgb is that same blue written as its three channels. A shadow and
     a gradient stop need it at partial opacity, and CSS gives no way to take a
     hex apart. Spelled out as rgba(10, 90, 212, ...) it is invisible to anyone
     searching this repository for 0a5ad4, which is how five of them sat here
     unnoticed. The two lines are one color: change one, change the other. */
  --accent: #0a5ad4;
  --accent-rgb: 10, 90, 212;
  --accent-hi: #2a86ff;
  --accent-hi-rgb: 42, 134, 255;
  --accent-deep: #084bb0;
  --accent-wash: #e7f0fb;

  /* The same blue is typed out by hand in seven files no stylesheet can reach.
     Changing it here does not change it there. The list, so nobody hunts:

       theme-color meta tag ......... index.html:23, privacy.html:13,
                                      terms.html:13, accessibility.html:13
       round brand mark, middle stop  privacy.html:28, terms.html:28,
                                      accessibility.html:28
       chemotherapy icon, stroke .... index.html:327
       about scene, gradient stop ... onc-about-scene.js:27
       globe, near-side continents .. oncometra-globe.js:16
       share card, --brand-blue ..... docs/share-card.html:34

     Two of those are not ours to edit: the scene files are imported whole. The
     share card is a build input, so a change there needs npm run build. And
     favicon.svg holds no copy of this blue at all, it is drawn in a palette of
     its own. */

  /* Secondary data emphasis, and the tail of the gradient. Neither is ever used
     as a flat brand color on its own.

     The two channel forms exist for the reason --accent-rgb does: a gradient
     stop at partial opacity, and no way in CSS to take a hex apart. Each pair
     is one color, so a change to either line has to be made to both. */
  --teal: #0e7490;
  --gradient-cyan: #18c4d6;
  --gradient-cyan-rgb: 24, 196, 214;
  /* Evidence Violet. The name is not decoration: it is the one this color
     carries in oncometra-globe.js, beside Outcome Cyan and Oncology Magenta,
     written by whoever set the palette. Until now the site ran two violets a
     hair apart. The brand mark in the bar ended on #6e4bff while the
     immunotherapy icon below it was drawn in #7157ff, twenty-four points of
     green between them: close enough that nobody saw it, far enough that the
     mark and the icon were never quite the same family. The named one won. */
  --gradient-violet: #7157ff;
  --gradient-violet-rgb: 113, 87, 255;
  --gradient-violet-deep: #5b34d6;

  /* The gradient is an accent, never a background field: hairlines, top rules,
     the two hero words, the brand mark. */
  --gradient: linear-gradient(
    90deg,
    var(--gradient-cyan),
    var(--accent) 52%,
    var(--gradient-violet)
  );
  --gradient-button: linear-gradient(
    135deg,
    var(--accent-hi),
    var(--accent) 60%,
    var(--gradient-violet-deep)
  );

  /* The round badge behind the chevron, in the bar and again in the footer.
     Those two were the same five lines typed twice, in two different files.
     The three legal pages carry a third copy, as an SVG gradient, which is
     beyond the reach of this one. */
  --gradient-mark: linear-gradient(
    150deg,
    var(--accent-hi),
    var(--accent) 55%,
    var(--gradient-violet)
  );

  /* --- Dark sections ------------------------------------------------------
     Four sections ship dark. Three grounds, because they are not the same
     darkness: the score and pilot sit on near-black, the biomarkers on navy,
     the footer lower than both. */
  --d-ground: #0b0e12;
  --d-ground-navy: #071528;
  /* The same navy in its three channels. A gradient has to fade it to nothing,
     and CSS gives no way to take a hex apart. The two lines are one color:
     change one, change the other. */
  --d-ground-navy-rgb: 7, 21, 40;
  --d-ground-deep: #070a0e;
  --d-surface: #14181e;
  --d-surface-panel: #0b1526;
  --d-border: #23272e;
  --d-ink: #f2f3ef;
  --d-muted: #8b94a0;
  --d-muted-hi: #aeb9c6;
  --d-accent: #4c9dff;
  --d-accent-rgb: 76, 157, 255;

  /* --- Response categories -------------------------------------------------
     RECIST states. The label carries the meaning, never the fill alone: a
     reader who cannot separate the three colors still reads the word. */
  --state-response-fill: #d3efe1;
  --state-response-ink: #0a6b48;
  --state-stable-fill: #e1e7ef;
  --state-stable-ink: #2b3648;
  --state-progression-fill: #f6d5d5;
  --state-progression-ink: #a31515;

  /* --- Space --------------------------------------------------------------
     One scale. A gap that is not on it is a mistake, not a nuance. */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-7: 32px;
  --space-8: 44px;
  --space-9: 64px;
  --space-10: 96px;

  /* The rhythm between sections, and the margin the page keeps from the edge
     of the screen. Both grow with the viewport rather than stepping at a
     breakpoint. */
  --section-rhythm: clamp(72px, 10vh, 120px);
  --gutter: clamp(20px, 4vw, 48px);
  --container: 1240px;

  /* Three line lengths, and no others. Prose that runs longer than this is
     harder to read, not more generous. */
  --measure-prose: 60ch;
  --measure-standfirst: 54ch;
  --measure-lead: 56ch;

  /* The reading column of a document page: the privacy notice, the terms, the
     accessibility statement. Wider than the prose measure because the column
     holds tables of retention periods as well as paragraphs, and a table
     squeezed to 60 characters wraps in every cell. */
  --container-document: 68ch;

  /* The rhythm between the parts of a document. Shorter than a section of the
     home page: a notice read start to finish needs its sections joined, not
     separated. */
  --rhythm-document: clamp(36px, 5vh, 56px);

  /* --- Shape --------------------------------------------------------------
     Two pixels, everywhere. The round brand mark is the single exception and
     spells out 50% at its own rule. */
  --radius: 2px;

  /* --- Depth --------------------------------------------------------------
     Three resting elevations, then the three states a primary button moves
     through. The premium is in these states, not in decoration. */
  --e1: 0 1px 2px rgba(20, 23, 28, 0.04);
  --e2: 0 8px 24px rgba(20, 23, 28, 0.06);
  --e3: 0 20px 44px rgba(20, 23, 28, 0.12);
  --button-rest:
    inset 0 1px 0 rgba(255, 255, 255, 0.3),
    0 8px 20px rgba(var(--accent-rgb), 0.3);
  --button-hover:
    inset 0 1px 0 rgba(255, 255, 255, 0.45),
    0 16px 34px rgba(var(--accent-rgb), 0.48);
  --button-active: inset 0 2px 8px rgba(0, 0, 0, 0.28);

  /* --- Motion -------------------------------------------------------------
     One easing curve, four durations. Anything that needs a fifth is doing too
     much for a clinical audience. */
  --ease: cubic-bezier(0.2, 0.7, 0.2, 1);
  --t-micro: 120ms;
  --t-control: 180ms;
  --t-element: 220ms;
  --t-reveal: 800ms;

  /* --- Layers -------------------------------------------------------------- */
  --z-nav: 60;
  --z-overlay: 100;
  --nav-height: 68px;

  /* The dark veil over the hero picture, as the three numbers of an rgb triple
     so that a rule can choose its own opacity. */
  --scrim: 4, 26, 58;
}
* {
  box-sizing: border-box;
}
html {
  -webkit-font-smoothing: antialiased;
}
body {
  margin: 0;
  padding: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--font-sans);
}
a {
  color: var(--accent);
  text-decoration: none;
}
a:hover {
  color: var(--accent-deep);
  text-decoration: underline;
}
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.om-skip,
.skip {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 100;
  transform: translateY(-120%);
  background: #ffffff;
  color: var(--accent);
  padding: 12px 20px;
  border-radius: var(--radius);
  font-size: var(--text-small);
  font-weight: 600;
  text-decoration: none;
  box-shadow: 0 8px 24px rgba(16, 24, 40, 0.12);
  transition: transform 0.15s ease-out;
}
.om-skip:focus,
.skip:focus {
  transform: translateY(0);
}
input,
textarea,
select,
button {
  font: inherit;
  color: inherit;
}
::placeholder {
  color: var(--muted);
}
::selection {
  background: var(--accent-wash);
}

/* ---------------------------------------------------------------------------
   Controls. Two of them, and no third: a filled call to action, and a link that
   reads as a link. Every button on the page is one of these, so a visitor learns
   the vocabulary once. There used to be a third, a hairline alternative to the
   filled button; no page ever used it and it was removed.

   The premium sits in the states rather than in decoration. A resting button is
   quiet; hovering lifts it two pixels, opens the gap so the arrow slides, and
   deepens the glow; pressing puts it back down and presses the shadow inward.
   --------------------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 14px 26px;
  border: none;
  border-radius: var(--radius);
  font-size: var(--text-small);
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
  transition:
    gap var(--t-control) var(--ease),
    transform var(--t-control) var(--ease),
    box-shadow var(--t-control) var(--ease),
    background var(--t-control) var(--ease),
    border-color var(--t-control) var(--ease),
    color var(--t-control) var(--ease);
}
.btn:hover {
  text-decoration: none;
}

/* The one filled control. Its gradient runs on the diagonal, unlike the
   hairline gradient, which runs flat: the two are never mistaken for each
   other. */
.btn--primary {
  background: var(--gradient-button);
  color: var(--surface);
  box-shadow: var(--button-rest);
}
.btn--primary:hover {
  gap: 16px;
  color: var(--surface);
  transform: translateY(-2px);
  box-shadow: var(--button-hover);
}
.btn--primary:active {
  transform: translateY(0);
  box-shadow: var(--button-active);
}

/* A link that stays a link. The rule under it is part of the type, not a
   button pretending to be text. */
.link-underline {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding-bottom: 3px;
  border-bottom: 1.5px solid rgba(20, 23, 28, 0.3);
  color: var(--ink);
  font-size: var(--text-small);
  font-weight: 600;
  text-decoration: none;
  transition:
    gap var(--t-control) var(--ease),
    color var(--t-control) var(--ease),
    border-color var(--t-control) var(--ease);
}
.link-underline:hover {
  gap: 16px;
  color: var(--accent);
  border-bottom-color: var(--accent);
  text-decoration: none;
}

/* The arrow inside a control. It carries no motion of its own: the gap opening
   on the parent is what slides it. */
.btn-arrow {
  display: inline-block;
  flex: none;
}

/* Motion turned off in the system settings. The site answers a pointer in color
   and in depth, never by moving: the filled button stops lifting, and every
   control changes state at once instead of easing into it.
   The skip link is the exception that has to be handled by hand. Its two
   positions are not decoration: off-screen is how it hides, on-screen is how a
   keyboard reaches it. Only the slide between them goes. */
@media (prefers-reduced-motion: reduce) {
  .om-skip,
  .skip,
  .btn,
  .link-underline {
    transition: none;
  }
  .btn--primary:hover,
  .btn--primary:active {
    transform: none;
  }
}
