/* Source Code Pro, self-hosted: the dashboard loads nothing external, so it
   renders the same whether or not Google is reachable, and no third party sees
   a request per page view. One variable file, latin only -- 21KB for every
   weight, against ~32KB a weight for the static cuts. */
@font-face {
  font-family: "Source Code Pro";
  src: url("/source-code-pro.woff2") format("woff2");
  font-weight: 200 900;
  font-style: normal;
  font-display: swap;
}

:root {
  --bg: #08090b;
  --panel: #0c0e12;
  --line: #1b1e24;
  --rule: #23272e;
  --text: #e6e9ed;
  --dim: #6a7078;
  --accent: #e6e2d8;
  /* Red and green for the numbers, by request -- every figure carries its own
     +/- sign, so the colour is a second channel rather than the only one.
     Brighter than the usual pair, and far apart in lightness, which is what
     keeps them apart for a red-green colourblind reader. */
  --ok: #6fbf73;
  --bad: #e06c5e;
  --idle: #565c65;
  /* The signal charts' cyan, reused wherever a figure is a total. */
  --series: #5fc9d6;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 14px/1.55 "Source Code Pro", ui-monospace, SFMono-Regular, Menlo, monospace;
  display: flex;
  min-height: 100vh;
}

nav {
  width: 250px;
  flex: none;
  background: var(--panel);
  border-right: 1px solid var(--line);
  padding: 20px 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

nav .brand {
  color: var(--accent);
  font-weight: 700;
  letter-spacing: .08em;
  padding: 0 20px 18px;
}

nav a {
  color: var(--dim);
  text-decoration: none;
  padding: 8px 20px;
  border-left: 2px solid transparent;
}

nav a:hover { color: var(--text); background: #1c212a; }
nav a.on { color: var(--text); border-left-color: var(--accent); }

/* Bottom of the column, away from the pages: logging out is not a place to go,
   and the nav is already a flex column so auto margin does it. */
nav a.foot { margin-top: auto; padding-top: 12px; border-top: 1px solid var(--line); }

main { flex: 1; padding: 28px 32px; max-width: 1000px; }

/* The login page has no nav, so `main` is the body's only flex child and has
   to grow to fill it before anything inside can be centred -- `flex: none`
   sized it to its content and pinned the form top-left. It becomes its own
   centring context instead. */
body.centred main {
  max-width: none;
  padding: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  /* `min-height` on the body lets main be as short as its content, so there is
     no vertical room to centre within. This gives it the height explicitly. */
  min-height: 100vh;
}

h1 { font-size: 18px; margin: 0 0 20px; font-weight: 600; }

/* The section title is white and heavier, the column header grey and plain:
   weight and brightness tell them apart rather than capitals. That leaves the
   accent free to mean one thing only -- which tab you are on. */
h2 { font-size: 15px; margin: 30px 0 10px; font-weight: 600; color: var(--text); }

table { width: 100%; border-collapse: collapse; margin: 0 0 8px; }

/* Sentence case rather than uppercase: a header is a label, not a shout, and
   SYMBOL / DESCRIPTION reads slower than Symbol / Description. */
th {
  text-align: left;
  font-weight: 400;
  color: var(--dim);
  font-size: 13px;
  padding: 0 12px 9px 0;
  border-bottom: 1px solid var(--rule);
}

td { padding: 9px 12px 9px 0; border-bottom: 1px solid var(--line); }
td.name { color: var(--text); }
.dim { color: var(--dim); }

.pill {
  display: inline-block;
  padding: 1px 8px;
  border-radius: 10px;
  font-size: 12px;
  border: 1px solid;
}

.pill.running { color: var(--ok); border-color: #1f4a27; }
.pill.failed { color: var(--bad); border-color: #5c2220; }
.pill.inactive, .pill.dead { color: var(--idle); border-color: var(--line); }

/* login */
.login {
  width: 280px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

/* Tighter tracking than the nav's brand: "Welcome to tuna farm" at .08em came
   to exactly the width of the box, with nothing spare for a narrower screen. */
.login h1 {
  color: var(--accent);
  text-align: center;
  letter-spacing: .04em;
  margin-bottom: 6px;
}
/* The label no longer wraps its input -- a mobile password manager wants an
   `id` and a `for` -- so the two are separate children of the form's flex
   column, and the label pulls itself back toward the field it names. */
.login label { color: var(--dim); font-size: 12px; margin-bottom: -8px; }

.login input {
  background: var(--panel);
  border: 1px solid var(--line);
  color: var(--text);
  padding: 9px 10px;
  border-radius: 4px;
  font: inherit;
}

.login input:focus { outline: none; border-color: var(--accent); }

.login button {
  background: var(--accent);
  color: #0d1014;
  border: 0;
  padding: 10px;
  border-radius: 4px;
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}

.login button:hover { filter: brightness(1.08); }
.error { color: var(--bad); font-size: 13px; margin: 0; text-align: center; }

/* Navigation, not metadata: inheriting .dim put it at the same weight as the
   timestamps beside it. */
a.back { color: var(--accent); text-decoration: none; }
a.back:hover { color: var(--text); }

/* Two tables on the Processes page and three on Portfolio, each of which
   would otherwise size its columns to its own content -- so a button lands in
   a different place in every table. Fixed layout plus a shared colgroup makes
   the widths a property of the page rather than of the rows. */
table.units, table.holdings { table-layout: fixed; }

table.units col.unit { width: 210px; }
table.units col.state { width: 130px; }
table.units col.when { width: 150px; }
table.units col.act { width: 150px; }

table.holdings col.holding { width: 190px; }
table.holdings col.account { width: 150px; }
table.holdings col.amount { width: 150px; }
table.holdings col.value { width: 140px; }
table.holdings col.share { width: 80px; }

/* A fixed column clips rather than widens, so anything that can outgrow its
   track has to say what to do instead. */
table.units td, table.holdings td {
  overflow: hidden;
  text-overflow: ellipsis;
}

/* actions */
/* Left-aligned in a fixed column, so the logs link starts in the same place
   in both tables. Right-aligned, a wider button ("run now" against "stop")
   shifted the whole group and the links no longer lined up. */
.actions { white-space: nowrap; text-align: left; }

/* Underlined and coloured: these were dim and unadorned, which reads as a
   label rather than as the link it is. */
.actions a {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 3px;
  margin-right: 12px;
}

.actions a:hover { color: var(--text); }

form.inline { display: inline; }

/* A filled panel with a readable border, rather than dim text on nothing --
   at rest these were hard to see as buttons at all. */
.actions button {
  background: #232a34;
  border: 1px solid #39424f;
  color: var(--text);
  padding: 3px 11px;
  border-radius: 4px;
  font: inherit;
  font-size: 12px;
  cursor: pointer;
  margin-left: 6px;
}

.actions button:hover { background: #2c3440; border-color: var(--dim); }

/* Stop is the one that cannot be undone from this page, so it is the one that
   carries the colour -- start and run now are recoverable and stay neutral. */
.actions button.stop { color: var(--bad); border-color: #5c2220; }
.actions button.stop:hover { background: #3a1f1e; border-color: var(--bad); }
.actions button.start:hover { color: var(--ok); border-color: var(--ok); }

.logs {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 4px;
  padding: 14px 16px;
  overflow-x: auto;
  font-size: 12px;
  line-height: 1.55;
  white-space: pre-wrap;
  word-break: break-word;
  max-height: 75vh;
  overflow-y: auto;
}

/* The line above each table: what it totals, then how old the figures are.
   The amounts carry the weight because they are what the line is for. */
.summary {
  margin: 22px 0 26px;
  display: flex;
  flex-wrap: wrap;
  gap: 4px 10px;
  align-items: baseline;
}

/* A separator between the parts rather than inside the markup, so a part that
   is conditional cannot leave a stray middot behind when it is absent. */
.summary > span + span::before {
  content: "·";
  color: var(--dim);
  margin-right: 10px;
}

/* Green, like the nav figures: the page total and the nav tag are the same
   number, so they should read as the same kind of thing. */
.summary .figure { color: var(--ok); font-size: 15px; }

/* The sentence under a table explaining how to read it. */
.caveat { margin: 30px 0 0; }

/* A boxed block, for a section that answers a different question from the
   page around it. Same treatment as a chart panel, so it reads as part of the
   same vocabulary rather than a one-off. */
.panel {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 4px 18px 16px;
  margin: 0 0 30px;
}

/* The heading is the box's own, so it sits at the top of it rather than
   carrying the 30px a section heading uses to separate itself from what is
   above. */
.panel > h2:first-child { margin-top: 16px; }

/* The last row's rule would sit against the box's padding. */
.panel table { margin-bottom: 0; }
.panel table tbody tr:last-child td { border-bottom: none; }

/* The sentence explaining the box, inside it. */
.panel .note { margin: 14px 0 0; font-size: 12.5px; }

/* charts */
.uplot {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 4px;
  padding: 2px 0 2px;
  margin: 2px 0 18px;
}

/* A chart's heading sits closer to it than a section heading does to a table:
   the two are one object, and 32px of h2 margin plus the panel's own gap read
   as a gap between unrelated things. */
h2 + .chart { margin-top: -6px; }

.u-title, .u-legend { display: none; }

/* The value rides the hovered point rather than sitting in a legend below:
   the eye is already on the line, and six charts stacked meant six legends
   repeating the same labels. */
.readout {
  position: absolute;
  transform: translate(-50%, -140%);
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 3px;
  padding: 3px 8px;
  font-size: 13px;
  color: var(--text);
  pointer-events: none;
  white-space: nowrap;
  opacity: 0;
  transition: opacity .08s;
  z-index: 10;
}

.readout.on { opacity: 1; }

/* Flipped under the point when the point is too near the top to sit above. */
.readout.below { transform: translate(-50%, 40%); }

.uplot .u-cursor-pt { border-width: 0; box-shadow: none; }

/* positions */
td.right, th.right { text-align: right; font-variant-numeric: tabular-nums; }

/* `td.up` rather than `.up`: the bare class loses to the `td` rule that sets
   the cell colour, so the pnl rendered in plain text. */
/* The numbers already carry a +/- sign, so the colour is a second channel
   rather than the only one. */
/* The subtotal closes its table rather than sitting in it: no rule under the
   last row, and the figures carry the weight the holdings above do not. */
tr.subtotal td {
  border-bottom: none;
  border-top: 1px solid var(--line);
  padding-top: 12px;
  font-weight: 600;
  color: var(--text);
}

/* Green on the figures a subtotal carries, like the page total above it: both
   are money the account holds rather than a figure that moved. */
tr.subtotal td.figure, table.margin td.figure { color: var(--ok); }

tr.subtotal td:first-child {
  color: var(--dim);
  font-weight: 500;
  font-size: 12px;
  letter-spacing: .03em;
}

td.up { color: var(--ok); }
td.down { color: var(--bad); }

/* A dot that pulses rather than a spinning glyph: no layout, no font
   dependency, and it stops when the content replaces it. */
.loading { color: var(--dim); }

.loading::before {
  content: "";
  display: inline-block;
  width: 7px;
  height: 7px;
  margin-right: 9px;
  border-radius: 50%;
  background: var(--accent);
  animation: pulse 1.1s ease-in-out infinite;
}

@keyframes pulse { 0%, 100% { opacity: .25; } 50% { opacity: 1; } }

/* The word alone inside a line that is already rendered: the dot belongs to a
   page waiting on its first content, not to a figure quietly being refreshed
   behind one that is already on screen. */
.summary .loading::before { display: none; }

@media (prefers-reduced-motion: reduce) {
  .loading::before { animation: none; opacity: .7; }
}

/* stablecoin flow */
/* Sized to its two columns rather than the page: four signals and their
   values do not need a thousand pixels. */
table.latest { width: auto; min-width: 220px; margin-bottom: 22px; }
table.latest th { padding-right: 26px; }
table.latest td { padding-right: 26px; }

/* The column is wide enough for a label and its figure on one line, so
   nothing wraps -- a two-line entry in a nav reads as two entries. */
nav a { white-space: nowrap; }
/* Green, so the figure separates from the label it sits beside and matches
   the colour money is written in elsewhere on the site. */
nav a .tag { color: var(--ok); }

/* range tabs */
/* Right-aligned, so the range sits over the right edge of the charts it
   controls rather than under the narrow table above it. */
.ranges { display: flex; gap: 6px; margin: 0 0 18px; justify-content: flex-end; }

.ranges button {
  background: transparent;
  border: 1px solid var(--line);
  color: var(--dim);
  padding: 3px 12px;
  border-radius: 4px;
  font: inherit;
  font-size: 12px;
  cursor: pointer;
}

.ranges button:hover { color: var(--text); border-color: var(--dim); }
.ranges button.on { color: var(--text); border-color: var(--accent); background: #1c212a; }

/* The cat, embedded as a data uri so the login page fetches nothing. */
.cat { margin: 0 0 4px; text-align: center; }

.cat img {
  width: 174px;
  height: auto;
  border-radius: 6px;
  border: 1px solid var(--line);
  display: block;
  margin: 0 auto;
}




/* --- Phones -------------------------------------------------------------
   A fixed side column beside a 1000px page is most of a phone screen spent on
   navigation, so the nav becomes a strip across the top and the page takes the
   full width underneath. Every selector appears once here: the block had grown
   two rules each for body, nav, main and h1, which is how an override starts
   contradicting the one above it. */
@media (max-width: 760px) {
  /* Stacked, and no longer a full viewport tall: `min-height: 100vh` exists so
     the side nav's panel reaches the bottom, which as a top strip means nav
     plus a full-height main -- a scrollbar on a page that ends above the fold. */
  body { flex-direction: column; min-height: 0; }

  /* Wrapped to the screen rather than sized to its content: at max-content the
     seven items went on one line and made the page 956px wide on their own.
     `sticky` keeps the background spanning the page when it scrolls sideways. */
  nav {
    width: auto;
    max-width: 100vw;
    position: sticky;
    left: 0;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    gap: 0 2px;
    padding: 4px 8px;
    border-right: none;
    border-bottom: 1px solid var(--line);
  }

  /* The brand names the site you are already looking at, and it costs most of
     a line. The tabs say where you are. */
  nav .brand { display: none; }

  /* The left border marks the current tab in a column; across a row it reads
     as a divider, so the marker moves underneath. */
  nav a {
    padding: 4px 7px;
    font-size: 13px;
    border-left: none;
    border-bottom: 2px solid transparent;
  }

  nav a.on { border-left-color: transparent; border-bottom-color: var(--accent); }

  /* `margin-top: auto` pushed log out to the bottom of a column; in a row it
     belongs at the end of the line. */
  nav a.foot { margin-top: 0; margin-left: auto; padding-top: 4px; border-top: none; }

  /* Sized to its widest child so a table can overflow the screen and the page
     itself scrolls -- `flex: 1` with `max-content` resolves against an
     unbounded basis and ran to 500,000px. */
  main {
    flex: none;
    width: fit-content;
    min-width: 100%;
    max-width: none;
    padding: 14px 14px 20px;
  }

  h1 { font-size: 17px; margin-bottom: 14px; }
  h2 { margin-top: 24px; }

  /* The fixed columns already fill the table, so the flexible one was squeezed
     to zero width and wrapped its text a letter at a time -- every row came out
     105px tall. A minimum gives it room and the page scrolls to the rest. */
  table.units { min-width: 700px; }
  table.holdings { min-width: 660px; }

  /* The description repeats what the unit name says, and it is what pushes the
     controls off the screen. */
  table.units col.desc,
  table.units th.desc,
  table.units td.desc { display: none; }

  .uplot { padding: 2px 0; }

  /* Centring the form in a full viewport is a screenful of space above it and
     a scrollbar under it. */
  body.centred main {
    min-height: 0;
    align-items: flex-start;
    padding: 28px 16px 16px;
  }

  .login { width: 100%; max-width: 320px; }
}

/* --- Coarse pointers ----------------------------------------------------
   A finger is not a mouse: the controls that start and stop a strategy want
   a target that does not need aiming. */
@media (pointer: coarse) {
  .actions a, .actions button { padding: 8px 12px; }
  .ranges button { padding: 8px 14px; }
}
