/* TRAX core styles, shared by the public site and the signed-in application.

   Organised after CUBE CSS: global rules first, then Composition (layout
   with no opinion about what it contains) and Utility (one job each). Blocks
   shared by both audiences are here too; the rest, and their Exceptions,
   live with the audience that uses them (account.css, static/app/).

   Cascade layers fix the order regardless of which file loads first. A later
   layer wins, so a utility on an element always beats the block it sits in,
   and nothing here needs !important or a longer selector to be heard. */
@layer tokens, reset, elements, composition, block, exception, utility;

/* ---- Fonts ------------------------------------------------------------ */

@font-face { font-family: "IBM Plex Sans"; font-style: normal; font-weight: 400; font-display: swap; src: url("/static/fonts/ibm-plex-sans-400.woff2") format("woff2"); }
@font-face { font-family: "IBM Plex Sans"; font-style: normal; font-weight: 500; font-display: swap; src: url("/static/fonts/ibm-plex-sans-500.woff2") format("woff2"); }
@font-face { font-family: "IBM Plex Sans"; font-style: normal; font-weight: 600; font-display: swap; src: url("/static/fonts/ibm-plex-sans-600.woff2") format("woff2"); }
@font-face { font-family: "IBM Plex Sans"; font-style: normal; font-weight: 700; font-display: swap; src: url("/static/fonts/ibm-plex-sans-700.woff2") format("woff2"); }
@font-face { font-family: "IBM Plex Mono"; font-style: normal; font-weight: 400; font-display: swap; src: url("/static/fonts/ibm-plex-mono-400.woff2") format("woff2"); }
@font-face { font-family: "IBM Plex Mono"; font-style: normal; font-weight: 500; font-display: swap; src: url("/static/fonts/ibm-plex-mono-500.woff2") format("woff2"); }

/* ---- Tokens ----------------------------------------------------------- */

/* In the first layer, so any later rule may redefine a token for a subtree
   (the collapsed navigation narrows --nav-width, for example). */
@layer tokens {
  :root {
    /* Surfaces, darkest first. */
    --navy-950: #050b1a;
    --navy-900: #081126;
    --navy-850: #0a1632;
    --navy-800: #0e1d3d;
    --surface: var(--navy-950);
    --panel: var(--navy-800);
    --raised: rgb(255 255 255 / .05);
    --line: rgb(178 199 239 / .13);

    /* Text, strongest first. */
    --ink: #eef3ff;
    --ink-2: #c5d0e6;
    --muted: #8998b5;
    --muted-2: #60708e;

    /* Accent and status. Each status has a tint for backgrounds and a
       line for borders, so a badge or notice never invents its own. */
    --accent: #fa7835;
    --accent-hover: #ff8a4d;
    --accent-ink: #ffac7e;
    --accent-soft: rgb(250 120 53 / .14);
    --accent-line: rgb(250 120 53 / .3);
    --on-accent: #10131c;
    --ok: #4ed7aa;
    --ok-soft: rgb(78 215 170 / .12);
    --ok-line: rgb(78 215 170 / .25);
    --warn: #ffb359;
    --warn-soft: rgb(255 179 89 / .12);
    --warn-line: rgb(255 179 89 / .26);
    --danger: #f87171;
    --danger-soft: rgb(248 113 113 / .12);
    --danger-line: rgb(248 113 113 / .26);

    /* Sensor trace colours, shared by the timeline and its legends. */
    --data-pressure: #4ed7aa;
    --data-cells: #fa7a35;
    --data-maxcell: #ffe0c4;
    --data-accel: #5bc8ff;
    --data-gyro: #829cff;

    /* Type. The application reads at --text-s; headings step up from it. */
    --font-sans: "IBM Plex Sans", "Inter", system-ui, sans-serif;
    --font-mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, monospace;
    --text-2xs: .6875rem;
    --text-xs: .75rem;
    --text-s: .875rem;
    --text-m: 1rem;
    --text-l: 1.125rem;
    --text-xl: 1.5rem;
    --text-2xl: 1.875rem;
    --text-3xl: 2.25rem;
    --leading-tight: 1.2;
    --leading: 1.5;

    /* Space. One scale for padding, gaps and flow. */
    --space-3xs: .125rem;
    --space-2xs: .25rem;
    --space-xs: .5rem;
    --space-s: .75rem;
    --space-m: 1rem;
    --space-l: 1.5rem;
    --space-xl: 2rem;
    --space-2xl: 3rem;
    --space-3xl: 4rem;

    /* Shape and depth. */
    --radius-s: .25rem;
    --radius: .375rem;
    --radius-l: .5rem;
    --radius-pill: 999px;
    --shadow-s: 0 1px 2px rgb(0 0 0 / .05);
    --shadow-l: 0 14px 40px rgb(0 0 0 / .13);
    --focus-ring: 2px solid var(--accent);

    /* Layout. */
    --measure: 65ch;
    --nav-width: 18rem;
    --nav-width-collapsed: 4rem;
    --breakpoint-desktop: 64rem; /* documentation only: media queries cannot read it */

    color-scheme: dark;
  }
}

/* ---- Reset ------------------------------------------------------------ */

@layer reset {
  /* Every element starts with no margin, padding or border, so spacing only
     ever comes from a composition or a block. Borders default to solid so a
     rule only has to give a width and colour. */
  *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; border: 0 solid; }
  html { line-height: var(--leading); tab-size: 4; -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
  body { min-height: 100dvh; -webkit-font-smoothing: antialiased; }

  /* Headings and lists carry meaning, not appearance: blocks style them. */
  h1, h2, h3, h4, h5, h6 { font-size: inherit; font-weight: inherit; overflow-wrap: break-word; }
  p { overflow-wrap: break-word; }
  ul, ol, menu { list-style: none; }
  small { font-size: 80%; }
  code, kbd, samp, pre { font-size: 1em; }
  summary { display: list-item; }
  table { border-collapse: collapse; text-indent: 0; }

  img, picture, video, canvas, iframe { display: block; }
  img, video { max-width: 100%; height: auto; }
  svg { display: block; flex-shrink: 0; }

  /* Form controls inherit the page's type and start transparent. */
  button, input, select, optgroup, textarea {
    border-radius: 0;
    background-color: transparent;
    color: inherit;
    font: inherit;
    letter-spacing: inherit;
  }
  button { cursor: pointer; }
  textarea { resize: vertical; }
  ::placeholder { opacity: 1; color: color-mix(in oklab, currentcolor 50%, transparent); }

  [hidden] { display: none !important; }
  @media (prefers-reduced-motion: reduce) {
    *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; scroll-behavior: auto !important; }
  }
}

/* ---- Base elements ---------------------------------------------------- */

@layer elements {
  html { background-color: var(--surface); }
  body {
    background-color: var(--surface);
    background-image:
      radial-gradient(1100px 560px at 88% -8%, #16284f 0%, transparent 58%),
      linear-gradient(155deg, #0b1730 0%, #050b1a 62%);
    background-attachment: fixed;
    color: var(--ink);
    font-family: var(--font-sans);
  }
  a { color: inherit; text-decoration: none; }
  code, kbd, samp, pre { font-family: var(--font-mono); }
  hr { border: 0; border-top: 1px solid var(--line); }
  :focus-visible { outline: var(--focus-ring); outline-offset: 2px; }
  th { text-align: start; }
}

/* ---- Composition ------------------------------------------------------
   Layout only. Each takes its spacing from a custom property, so a block or
   an inline style can adjust it without a new class. */

@layer composition {
  /* Each composition declares its own spacing default on the element that
     uses it. That stops a value set on an outer composition leaking into
     the ones nested inside it; a u- utility on the same element still
     wins because the utility layer comes later. */

  /* Vertical rhythm between siblings. */
  .flow > * { --flow-space: var(--space-m); }
  .flow > * + * { margin-block-start: var(--flow-space); }

  /* A row of things that wraps: buttons, badges, meta. */
  .cluster {
    display: flex;
    flex-wrap: wrap;
    align-items: var(--cluster-align, center);
    justify-content: var(--cluster-justify, flex-start);
    --gutter: var(--space-s);
    gap: var(--gutter);
  }

  /* Two groups pushed to opposite ends, stacking when they cannot fit. */
  .repel {
    display: flex;
    flex-wrap: wrap;
    --gutter: var(--space-m);
    align-items: var(--repel-align, center);
    justify-content: space-between;
    gap: var(--gutter);
  }

  /* A fixed-width side and a flexible main that wraps under it when the
     main would drop below half the available width. */
  .sidebar {
    display: flex;
    --gutter: var(--space-l);
    flex-wrap: wrap;
    gap: var(--gutter);
  }
  .sidebar > :first-child { flex-basis: var(--sidebar-width, 20rem); flex-grow: 1; }
  .sidebar > :last-child { flex-basis: 0; flex-grow: 999; min-inline-size: var(--sidebar-min, 50%); }
  .sidebar[data-side="end"] > :first-child { flex-basis: 0; flex-grow: 999; min-inline-size: var(--sidebar-min, 50%); }
  .sidebar[data-side="end"] > :last-child { flex-basis: var(--sidebar-width, 20rem); flex-grow: 1; min-inline-size: 0; }

  /* As many equal columns as fit, none narrower than --grid-min. */
  .auto-grid {
    display: grid;
    --gutter: var(--space-m);
    --grid-min: 16rem;
    grid-template-columns: repeat(auto-fit, minmax(min(var(--grid-min), 100%), 1fr));
    gap: var(--gutter);
  }
  .auto-grid[data-columns="2"] { --grid-min: calc(50% - var(--gutter)); }
  .auto-grid[data-columns="3"] { --grid-min: calc(33.333% - var(--gutter)); }

  /* Centred column with side padding: the page's reading width. */
  .wrapper {
    inline-size: 100%;
    max-inline-size: var(--wrapper-max, 80rem);
    margin-inline: auto;
    padding-inline: var(--wrapper-gutter, var(--space-m));
  }
  .wrapper[data-width="narrow"] { --wrapper-max: 42rem; }
  .wrapper[data-width="prose"] { --wrapper-max: var(--measure); }

  /* Vertical breathing room for a page section. */
  .region { padding-block: var(--region-space, var(--space-l)); }

  /* Content wider than its container scrolls inside it, not the page. */
  .scroll-x { overflow-x: auto; -webkit-overflow-scrolling: touch; }

  /* Centre one thing in the available space: empty states, auth cards. */
  .center { display: grid; place-items: center; min-block-size: var(--center-min, 100%); }
}

/* ---- Utilities --------------------------------------------------------
   One declaration, one job. Written by hand and kept short: if a pattern
   needs three of these together more than a few times, it is a block. */

/* Blocks used on both sides of sign-in. Blocks that only the signed-in app
   uses live in static/app/app.css. */
@layer block {
  /* A link that performs or leads to the next action. */
  .action-link { font-weight: 600; color: var(--accent); }
  .action-link:hover { color: var(--accent-hover); }
  .action-link[data-tone="danger"] { color: var(--danger); }

  /* A link that is navigation rather than the next action. */
  .quiet-link { color: var(--muted); }
  .quiet-link:hover { color: var(--ink); }

  /* ---- Button ---------------------------------------------------------- */
  .button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-xs);
    padding: var(--space-xs) var(--space-s);
    border-radius: var(--radius);
    background: var(--accent);
    box-shadow: var(--shadow-s);
    color: var(--navy-950);
    font-size: var(--text-s);
    font-weight: 600;
    line-height: 1.25rem;
    white-space: nowrap;
  }
  .button:hover { background: var(--accent-hover); color: var(--navy-950); }
  .button[data-variant="quiet"] {
    background: var(--panel);
    box-shadow: inset 0 0 0 1px var(--line);
    color: var(--ink);
  }
  .button[data-variant="quiet"]:hover { background: color-mix(in srgb, var(--panel), white 6%); }
  .button[data-variant="danger"] { background: var(--danger); }
  .button[data-variant="danger"]:hover { background: color-mix(in srgb, var(--danger), white 12%); }
  .button[data-variant="danger-quiet"] {
    background: var(--panel);
    box-shadow: inset 0 0 0 1px var(--danger);
    color: var(--danger);
  }
  .button[data-variant="danger-quiet"]:hover { background: var(--danger-soft); }
  .button[data-size="small"] { padding-block: .375rem; }
  .button[data-size="tiny"] { padding: var(--space-2xs) var(--space-xs); box-shadow: none; }
  .button[data-size="tiny"][data-variant="quiet"] { box-shadow: inset 0 0 0 1px var(--line); font-weight: 400; }
  .button:disabled, .button[aria-disabled="true"] { opacity: .5; cursor: not-allowed; }

  /* ---- Badge -----------------------------------------------------------
     A short status or category label. Tone carries meaning; the default is
     neutral. */
  .badge {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2xs);
    padding: var(--space-2xs) var(--space-xs);
    border-radius: var(--radius);
    background: var(--raised);
    box-shadow: inset 0 0 0 1px var(--line);
    color: var(--muted);
    font-size: var(--text-xs);
    font-weight: 500;
    line-height: 1rem;
    letter-spacing: 0;
    white-space: nowrap;
  }
  .badge[data-tone="accent"] { background: var(--accent-soft); box-shadow: inset 0 0 0 1px var(--accent-line); color: var(--accent); }
  .badge[data-tone="ok"] { background: var(--ok-soft); box-shadow: inset 0 0 0 1px var(--ok-line); color: var(--ok); }
  .badge[data-tone="warn"] { background: var(--warn-soft); box-shadow: inset 0 0 0 1px var(--warn-line); color: var(--warn); }
  .badge[data-tone="danger"] { background: var(--danger-soft); box-shadow: inset 0 0 0 1px var(--danger-line); color: var(--danger); }

  /* ---- Panel -----------------------------------------------------------
     A bordered surface that groups related content. --panel-padding sets
     its padding; data-flush removes it so a table or list can run edge to edge under a
     panel__header. */
  .panel {
    --cell-inline: 1.25rem;
    border: 1px solid var(--line);
    border-radius: var(--radius-l);
    background: linear-gradient(150deg, #0e1d3ddb, #071023ed);
    padding: var(--panel-padding, var(--space-l));
    box-shadow: 0 14px 40px #00000021;
  }
  .panel[data-flush] { padding: 0; overflow: hidden; }
  .panel[data-tone="danger"] { border-color: var(--danger-line); }
  .panel__header { padding: var(--space-m) 1.25rem; border-block-end: 1px solid var(--line); }
  .panel__body { padding: var(--space-m) 1.25rem; }
  a.panel { display: block; }
  a.panel:hover { border-color: var(--accent-line); }
  a.panel[aria-current="true"] { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }

  /* ---- Forms -----------------------------------------------------------
     A field is a label, its control and an optional hint. */
  .field { display: flex; flex-direction: column; gap: var(--space-xs); }
  .field__label { display: block; font-weight: 500; line-height: 1.5rem; }
  .field__hint { font-size: var(--text-xs); color: var(--muted); }
  .input {
    display: block;
    inline-size: 100%;
    min-block-size: 2.25rem;
    padding: .375rem var(--space-s);
    border: 0;
    border-radius: var(--radius);
    background: var(--panel);
    outline: 1px solid var(--line);
    outline-offset: -1px;
    color: var(--ink);
    font-size: var(--text-s);
    line-height: 1.5rem;
  }
  .input::placeholder { color: var(--muted-2); }
  .input:focus { outline: 2px solid var(--accent); outline-offset: -2px; box-shadow: none; }
  .input[data-width="auto"] { inline-size: auto; }
  select.input { padding-inline-end: var(--space-xl); }
  textarea.input { resize: vertical; }
  .file-input { display: block; inline-size: 100%; color: var(--ink); }
  .file-input::file-selector-button {
    margin-inline-end: var(--space-m);
    padding: .375rem var(--space-s);
    border: 0;
    border-radius: var(--radius);
    background: var(--accent);
    color: var(--navy-950);
    font: inherit;
    font-weight: 600;
    cursor: pointer;
  }
  .check-row { display: flex; align-items: center; gap: var(--space-s); }
  .checkbox { inline-size: 1rem; block-size: 1rem; flex-shrink: 0; accent-color: var(--accent); }
  .form-actions { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: var(--space-m); }
  /* A group of fields under a rule. Floating the legend puts it inside the
     fieldset's padding instead of on top of its border. */
  .fieldset { padding-block-start: var(--space-m); border-block-start: 1px solid var(--line); }
  .fieldset > legend { float: inline-start; inline-size: 100%; margin-block-end: var(--space-s); }
  .fieldset > legend + * { clear: both; }

  /* ---- Notice ----------------------------------------------------------
     A message that belongs to the page, such as a form error. */
  .notice {
    padding: var(--space-m);
    border-radius: var(--radius);
    background: var(--raised);
    box-shadow: inset 0 0 0 1px var(--line);
  }
  .notice:has(> svg) { display: flex; gap: var(--space-s); }
  .notice > svg { inline-size: 1.25rem; block-size: 1.25rem; }
  .notice[data-tone="ok"] { background: var(--ok-soft); box-shadow: inset 0 0 0 1px var(--ok-line); color: var(--ok); }
  .notice[data-tone="warn"] { background: var(--warn-soft); box-shadow: inset 0 0 0 1px var(--warn-line); color: var(--warn); }
  .notice[data-tone="danger"] { background: var(--danger-soft); box-shadow: inset 0 0 0 1px var(--danger-line); color: var(--danger); }
}

/* ---- Utilities --------------------------------------------------------
   One declaration, one job, always prefixed u- so a utility is recognisable
   in markup and can never collide with a block. Written by hand and kept
   short: if a pattern needs three of these together more than a few times,
   it is a block. */

@layer utility {
  .u-visually-hidden {
    position: absolute; inline-size: 1px; block-size: 1px; overflow: hidden;
    clip-path: inset(50%); white-space: nowrap;
  }

  /* Text size. */
  .u-text-2xs { font-size: var(--text-2xs); }
  .u-text-xs { font-size: var(--text-xs); }
  .u-text-s { font-size: var(--text-s); }
  .u-text-m { font-size: var(--text-m); }
  .u-text-l { font-size: var(--text-l); }
  .u-text-xl { font-size: var(--text-xl); }
  .u-text-2xl { font-size: var(--text-2xl); }
  .u-text-3xl { font-size: var(--text-3xl); line-height: var(--leading-tight); }

  /* Text colour. */
  .u-ink { color: var(--ink); }
  .u-ink-2 { color: var(--ink-2); }
  .u-muted { color: var(--muted); }
  .u-muted-2 { color: var(--muted-2); }
  .u-accent { color: var(--accent); }
  .u-ok { color: var(--ok); }
  .u-warn { color: var(--warn); }
  .u-danger { color: var(--danger); }

  /* Weight and face. */
  .u-weight-medium { font-weight: 500; }
  .u-weight-semibold { font-weight: 600; }
  .u-weight-bold { font-weight: 700; }
  .u-mono { font-family: var(--font-mono); }
  .u-tabular { font-variant-numeric: tabular-nums; }
  .u-caps { text-transform: uppercase; letter-spacing: .12em; }

  /* Wrapping and alignment. */
  .u-underline { text-decoration: underline; }
  .u-inline { display: inline; }
  .u-wrap { white-space: normal; }
  .u-align-top { vertical-align: top; }
  .u-nowrap { white-space: nowrap; }
  .u-truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .u-break-anywhere { overflow-wrap: anywhere; }
  .u-text-center { text-align: center; }
  .u-text-end { text-align: end; }

  /* Spacing adjusters for the compositions above. */
  .u-flow-space-2xs > * { --flow-space: var(--space-2xs); }
  .u-flow-space-xs > * { --flow-space: var(--space-xs); }
  .u-flow-space-s > * { --flow-space: var(--space-s); }
  .u-flow-space-l > * { --flow-space: var(--space-l); }
  .u-flow-space-xl > * { --flow-space: var(--space-xl); }
  .u-gutter-2xs { --gutter: var(--space-2xs); }
  .u-gutter-xs { --gutter: var(--space-xs); }
  .u-gutter-s { --gutter: var(--space-s); }
  .u-gutter-l { --gutter: var(--space-l); }
  .u-gutter-xl { --gutter: var(--space-xl); }

  /* Sizing and flex behaviour inside a composition. */
  .u-measure { max-inline-size: 42rem; }
  .u-measure-wide { max-inline-size: 48rem; }
  .u-pre-wrap { white-space: pre-wrap; }
  .u-pre-line { white-space: pre-line; }
  .u-align-end { align-self: end; }
  .u-full-width { inline-size: 100%; }
  .u-grow { flex-grow: 1; }
  .u-no-shrink { flex-shrink: 0; }
  .u-push-end { margin-inline-start: auto; }

  /* Show only at one end of the desktop breakpoint. */
  @media (min-width: 64rem) { .u-below-desktop { display: none; } }
  @media (max-width: 63.999rem) { .u-from-desktop { display: none; } }
}
