/* Dark is the default theme: an unset or unrecognised cookie renders this.
   Every colour on the page comes from here, because a literal anywhere else is
   one the light block below cannot reach.

   The --chart-* values are plain rgba rather than color-mix: app.js reads them
   with getPropertyValue, which hands back the token as written, and canvas
   cannot parse a color-mix(). */
:root {
  --bg: #0b0f18;
  --panel: #161a25;
  --panel-2: #1f2430;
  --border: #2c3341;
  --text: #dadee8;
  --strong: #e8ebf2;
  --dim: #81899c;
  --code: #c8cedb;
  --accent: #83bdf8;
  --eyebrow: var(--accent);
  --ok: #4eb068;
  --bad: #e45d58;
  --warn: #e1a035;
  --shadow: rgba(0, 0, 0, 0.45);
  --line-hl: rgba(131, 189, 248, 0.16);
  --heat-ink: #fff;
  --heat-strength: 100%;
  --cat-unaccounted: #232936;
  --cat-frame: #5b6376;
  --add: #3fb950;
  --add-wash: rgba(46, 160, 67, 0.15);
  /* The retention bar fades toward the page as it runs right: full traces are
     the prominent end, trends the thinning one. Prominent means light here and
     dark in the light theme, so the pair inverts between the two. */
  --trace: #83bdf8;
  --trend: #35618f;
  --glacier: url("/static/glacier.jpg");
  --glacier-flat: #0f1724;
  --glacier-opacity: .85;
  --chart-grid: rgba(255, 255, 255, 0.06);
  --chart-wash: rgba(131, 189, 248, 0.12);
  --chart-whisker: rgba(131, 189, 248, 0.55);
  --chart-band-fill: rgba(131, 189, 248, 0.18);
  --chart-band-line: rgba(131, 189, 248, 0.65);
  --chart-bar-hl: #ffffff;
}

/* Light. Only the colours differ, so this is an override block rather than a
   second theme: anything added to :root and forgotten here stays dark, which is
   visible immediately rather than silently wrong. */
:root[data-theme="light"] {
  /* The panel is warm and the page is cool, so a card is told apart by
     temperature and its border rather than by being brighter. There is only
     1.006:1 of luminance between them, which is why --border carries the
     structure here and must not be softened. */
  --bg: #f4f6fa;
  --panel: #f6f5f4;
  --panel-2: #deddda;
  --border: #deddda;
  --text: #1a2130;
  --strong: #0d1420;
  /* Darker than the dark theme's --dim is light, because the hero's secondary
     text sits straight on the glacier rather than on a panel, and a mid-tone
     photograph is the worst ground there is for text. 4.5:1 against the
     darkest 5% of the backdrop. */
  --dim: #3b414d;
  --code: #30384a;
  --accent: #1565c8;
  /* Sized against --panel-2, not the panel: the only place either is used as
     text is a badge, and a badge sits on the darker surface. Fully saturated
     and darkened only as far as that contrast needs, because dropping value to
     reach a ratio costs chroma and these go grey long before they go dark. */
  --ok: #007126;
  --bad: #c40800;
  --warn: #8a5a05;
  --shadow: rgba(16, 24, 40, 0.12);
  --line-hl: rgba(21, 101, 200, 0.12);
  /* Dark ink on the tint, so the strength is capped well short of a solid red
     the text could not sit on. */
  --heat-ink: #5c1410;
  --heat-strength: 45%;
  --cat-unaccounted: #e2e6ee;
  /* A frame is a container, not a category, so it reads as the surface the
     coloured bars sit on. Dark makes it lighter than the panel to do that;
     light has to go the other way, or it is a dark slab among bright bars. */
  --cat-frame: #c2cbd9;
  --add: #1a7f37;
  --add-wash: rgba(26, 127, 55, 0.14);
  /* Both bars have to stay darker than the light track to show against it at
     all, so the fade runs navy to blue rather than out to a pale tint. */
  --trace: #0a2850;
  --trend: #2f7cd8;
  /* A second grade of the same photograph, not the dark one filtered. The dark
     file is crushed into 46 of 256 luminance levels, so anything that lifts it
     back up bands and drags the JPEG artefacts with it. Both files are graded
     once from the full-range original instead.

     The file keeps the ice saturated and the opacity does the lightening.
     Grading it pale in the file instead desaturates as it lightens, which is
     what made it read as fog rather than ice. */
  --glacier: url("/static/glacier-light.jpg");
  --glacier-flat: #cfdcea;
  --glacier-opacity: .18;
  /* The eyebrow is the only accent-coloured text on the photograph, so it gets
     its own ink rather than the brand blue darkening everywhere. */
  --eyebrow: #0d407e;
  --chart-grid: rgba(16, 24, 40, 0.10);
  --chart-wash: rgba(21, 101, 200, 0.12);
  --chart-whisker: rgba(21, 101, 200, 0.55);
  --chart-band-fill: rgba(21, 101, 200, 0.14);
  --chart-band-line: rgba(21, 101, 200, 0.60);
  --chart-bar-hl: #10141c;
}
* { box-sizing: border-box; }
body {
  margin: 0;
  font: 14px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  background: var(--bg);
  color: var(--text);
}
code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12.5px; color: var(--code); }
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
.dim { color: var(--dim); }

/* The hamburger is a checkbox, not a <details>: a closed disclosure hides its
   own content and author CSS cannot force it back, which is what blanked the
   desktop nav. Here both states are ours to set. */
.burger-btn { display: none; }

.topbar {
  display: flex; align-items: center; gap: 32px;
  padding: 12px 24px; background: var(--panel); border-bottom: 1px solid var(--border);
  position: sticky; top: 0; z-index: 10;
}
/* The brand is a link to the landing page, so it has to opt out of link colour. */
.brand { font-weight: 600; letter-spacing: .2px; }
a.brand { color: inherit; }
a.brand:hover { text-decoration: none; }
.brand .logo { display: block; width: 28px; height: 28px; }
/* display:contents so the two navs sit in the topbar's own flex row; the auto
   margin moves the second one and the user menu to the right together. */
.nav-group { display: contents; }
.topbar nav { display: flex; gap: 18px; }
/* Colour, not an underline: nav links are already obviously interactive, and the
   underline is a prose convention the global a:hover rule drags in here. */
.topbar nav a { color: var(--text); }
.topbar nav a:hover { color: var(--accent); text-decoration: none; }
.topbar .nav-meta { margin-left: auto; }
.topbar .nav-meta a { color: var(--dim); }
.topbar .nav-meta a:hover { color: var(--text); text-decoration: none; }
.topbar .user { margin-left: 0; }

.wrap { max-width: 1180px; margin: 0 auto; padding: 24px; }
h1 { font-size: 20px; margin: 4px 0 20px; font-weight: 600; }
h2 { font-size: 14px; margin: 0 0 12px; font-weight: 600; color: var(--strong); }
.h2-link { margin-left: 8px; font-size: 12px; font-weight: 400; }
.cell-sub { margin-top: 2px; font-size: 11px; color: var(--dim); }
.back { display: inline-block; margin-bottom: 8px; font-size: 13px; }

.tiles { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; margin-bottom: 20px; }
.tile { background: var(--panel); border: 1px solid var(--border); border-radius: 10px; padding: 18px 20px; }
.tile-label { color: var(--dim); font-size: 12px; text-transform: uppercase; letter-spacing: .5px; }
.tile-value { font-size: 32px; font-weight: 650; margin-top: 6px; }
.tile-warn .tile-value { color: var(--warn); }

.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 20px; }
.card { background: var(--panel); border: 1px solid var(--border); border-radius: 10px; padding: 18px 20px; margin-bottom: 20px; }
.grid-2 canvas { max-height: 240px; } /* overview timeseries only; the waterfall sizes itself */
.chart-box { position: relative; height: 260px; } /* fixed-height wrapper for a standalone responsive chart */

table { width: 100%; border-collapse: collapse; font-size: 13px; }
/* A table with more columns than the card can hold scrolls in its own box, so
   the page body never scrolls sideways. min-width rather than width keeps it
   filling the card when there is room, because the box is a block. */
.table-scroll { overflow-x: auto; }
.table-scroll > table { min-width: 100%; width: auto; }
th, td { text-align: left; padding: 8px 10px; border-bottom: 1px solid var(--border); }
th { color: var(--dim); font-weight: 500; font-size: 12px; text-transform: uppercase; letter-spacing: .4px; }
tr:last-child td { border-bottom: none; }
td code { white-space: nowrap; }
.num { text-align: right; font-variant-numeric: tabular-nums; }
.ts { white-space: nowrap; font-variant-numeric: tabular-nums; }
/* build_id is a kaniko test name, up to ~95 characters, and sits in a nowrap
   code cell no column width can hold. Truncated with the full value in title. */
.trunc { max-width: 26ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Middle truncation. The tail never shrinks because that is where these ids
   differ; the head takes the ellipsis and gives up whatever width is short. */
.midtrunc { display: flex; max-width: 30ch; }
.midtrunc .mt-head { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.midtrunc .mt-tail { flex: 0 0 auto; white-space: nowrap; }
th.sortable { cursor: pointer; user-select: none; }
th.sortable:hover { color: var(--text); }
/* The runs table sorts by plain link rather than htmx, so it keeps working
   without JS and the chart above reloads with it. The anchor is the whole
   title, so it takes the header's colour instead of a link's. */
th.sortable a { color: inherit; text-decoration: none; }
/* Fixed-width caret slot so the ▲/▼ appearing doesn't shift the column border. */
.caret { display: inline-block; width: 1em; margin-left: 4px; text-align: center; }
.bad { color: var(--bad); }

.heat {
  display: inline-block; padding: 1px 7px; border-radius: 5px;
  background: color-mix(in srgb, var(--bad) calc(var(--v) * var(--heat-strength)), transparent);
  color: var(--heat-ink);
}

.badge { display: inline-block; padding: 1px 8px; border-radius: 20px; font-size: 11.5px; background: var(--panel-2); border: 1px solid var(--border); }
.badge.ok { color: var(--ok); border-color: color-mix(in srgb, var(--ok) 40%, var(--border)); }
.badge.bad { color: var(--bad); border-color: color-mix(in srgb, var(--bad) 40%, var(--border)); }
.btn { display: inline-block; padding: 3px 10px; border-radius: 6px; border: 1px solid var(--border); background: var(--panel-2); font-size: 12.5px; cursor: pointer; }
.btn:hover { border-color: var(--accent); text-decoration: none; }
/* Always a div inside the cell, never the cell: display:flex on a <td> takes it
   out of the table's formatting context, and its border-bottom then sits at its
   own height instead of the row's, which breaks the rule between rows.
   align-items keeps the buttons their natural height rather than stretching
   them to the row whenever another cell wraps. */
.row-actions { display: flex; gap: 6px; justify-content: flex-end; align-items: center; white-space: nowrap; }
.pager { display: flex; gap: 12px; align-items: center; justify-content: flex-end; margin-top: 14px; }
/* A filter as the column title: the column name, and its value below in plain
   case. The row's other titles top-align so all names share a line. */
tr:has(> th.filter) > th { vertical-align: top; }
th.filter label { display: block; }
th.filter select {
  display: block; max-width: 200px; padding: 2px 4px; margin: 4px 0 0 -5px; border: 1px solid transparent; border-radius: 5px;
  font: inherit; text-transform: none; letter-spacing: 0; color: inherit; background: transparent; cursor: pointer;
}
th.filter select:hover { color: var(--text); border-color: var(--border); }
th.filter select.active { color: var(--text); background: var(--panel-2); border-color: var(--border); }
th.filter option, th.filter optgroup { text-transform: none; letter-spacing: 0; color: var(--text); background: var(--panel-2); }
.btn.disabled { opacity: .4; pointer-events: none; }

.meta dl { display: grid; grid-template-columns: repeat(2, 1fr); gap: 4px 32px; margin: 0; }
.meta dl > div { display: flex; gap: 10px; padding: 4px 0; border-bottom: 1px solid var(--border); }
.meta dt { color: var(--dim); min-width: 82px; }
.meta dd { margin: 0; }

/* Category colours (shared by summary bar, legend, waterfall) */
.cat-build       { background: #3fb950; }
.cat-network     { background: #2d6fbe; }
.cat-kaniko      { background: #996b00; }
.cat-untraced    { background: repeating-linear-gradient(135deg, #996b00 0 6px, #634300 6px 12px); }
.cat-unaccounted { background: var(--cat-unaccounted); }
/* Keep in step with CAT_COLOR.frame in app.js: the chart colours frames there,
   the legend swatch is drawn here. */
.cat-frame       { background: var(--cat-frame); }

/* Summary "where the time went" stacked bar */
.summary-bar { display: flex; height: 22px; border-radius: 6px; overflow: hidden; background: var(--panel-2); }
.summary-bar .seg { height: 100%; }
.summary-bar .seg:hover { filter: brightness(1.15); }

.legend-summary { margin: 12px 0 0; }
.legend { display: flex; flex-wrap: wrap; gap: 16px; margin-bottom: 14px; font-size: 12.5px; color: var(--dim); }
.legend .key { display: inline-flex; align-items: center; gap: 6px; }
.legend .sw { width: 11px; height: 11px; border-radius: 3px; display: inline-block; }

/* The waterfall page runs wider than the default so the chart keeps room even
   with the Dockerfile panel beside it */
.wrap-wide { max-width: 1680px; }

/* Waterfall chart (Chart.js) — height is set by JS from the span count. Side by
   side with the Dockerfile source, which is capped narrow so the chart keeps the
   majority of the width; stacks below on narrow screens (see media query). */
.wf-layout { display: flex; gap: 16px; align-items: flex-start; }
.wf-chart { position: relative; flex: 1 1 0; min-width: 0; min-height: 120px; }

/* Dockerfile source panel, beside the chart: capped width, sticky so it stays in
   view while the tall waterfall scrolls; scrolls in both axes (long lines don't
   wrap); cross-linked with the chart on hover. */
.df-panel {
  flex: 0 1 auto; max-width: 460px;
  position: sticky; top: 8px;
  max-height: calc(100vh - 24px); overflow: auto;
  border: 1px solid var(--border); border-radius: 8px; background: var(--panel);
}
.df-head { position: sticky; top: 0; padding: 7px 12px; background: var(--panel); border-bottom: 1px solid var(--border); font-size: 11px; text-transform: uppercase; letter-spacing: .5px; color: var(--dim); }
.df-code { padding: 8px 0; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12.5px; }
.df-line { display: flex; padding: 1px 16px 1px 0; min-height: 1.5em; cursor: default; }
.df-line[data-hascmd] { cursor: pointer; }
.df-line:hover, .df-line.hl { background: var(--line-hl); box-shadow: inset 3px 0 0 var(--accent); }
.df-num { flex: 0 0 auto; width: 26px; padding-right: 10px; margin-right: 10px; text-align: right; color: var(--dim); border-right: 1px solid var(--border); user-select: none; }
.df-text { white-space: pre; color: var(--code); }

/* History page: Dockerfile heatmap — source tinted by build time, per-run stats
   pinned on the right, cache-buster flagged. */
.dfh { border: 1px solid var(--border); border-radius: 8px; overflow: hidden; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12.5px; }
.dfh-row { display: flex; align-items: center; gap: 12px; padding: 1px 12px 1px 0; min-height: 1.7em; }
.dfh-row .df-num { flex: 0 0 auto; }
.dfh-text { flex: 1 1 auto; min-width: 0; white-space: pre; overflow: hidden; text-overflow: ellipsis; color: var(--code); }
.dfh-row:not(.on) .dfh-text { color: var(--dim); }
.dfh-stats { flex: 0 0 auto; display: flex; align-items: center; gap: 12px; font-family: -apple-system, system-ui, sans-serif; font-size: 11.5px; color: var(--dim); }
.dfh-stat { white-space: nowrap; }
.dfh-stat.strong { color: var(--strong); font-weight: 600; }
.dfh-buster { white-space: nowrap; color: var(--bad); border: 1px solid color-mix(in srgb, var(--bad) 45%, var(--border)); border-radius: 20px; padding: 0 8px; font-size: 11px; }

@media (max-width: 900px) {
  .tiles, .grid-2 { grid-template-columns: 1fr; }
}

/* Waterfall stacks (Dockerfile below) before it gets too cramped side by side. */
@media (max-width: 1000px) {
  .wf-layout { flex-direction: column; }
  .df-panel { max-width: none; width: 100%; position: static; max-height: 60vh; }
}

@media (max-width: 640px) {
  .wrap { padding: 14px; }
  .topbar { gap: 14px; padding: 12px 14px; flex-wrap: wrap; }
  h1 { font-size: 18px; }
  .tile-value { font-size: 26px; }
  .meta dl { grid-template-columns: 1fr; }

  /* Wide content scrolls inside its own box so the page body never scrolls
     sideways: tables become horizontally scrollable, and the heatmap sizes its
     rows to content (full line + stats) and scrolls rather than truncating. */
  table { display: block; overflow-x: auto; white-space: nowrap; }
  /* One already in a .table-scroll box scrolls there, and has to stay a real
     table so its columns keep aligning with the header. */
  .table-scroll > table { display: table; }
  .dfh { overflow-x: auto; }
  .dfh-row { width: max-content; min-width: 100%; }
  .dfh-text { flex: 0 0 auto; overflow: visible; text-overflow: clip; }
}

/* Facts panel that follows the pointer over the Dockerfile source. */
.df-facts {
  display: none;
  position: fixed;
  z-index: 40;
  max-width: 380px;
  padding: 6px 9px;
  font-size: 12px;
  line-height: 1.45;
  color: var(--text);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 6px;
  box-shadow: 0 6px 18px var(--shadow);
  pointer-events: none;
}


/* Side tile: a card that stops at a column width instead of spanning the page. */
.side-tile { max-width: 420px; }
.side-tile table { font-size: 12px; }
.side-tile td:last-child { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }

/* Dockerfile lines whose stage was eliminated: present in the source, never run. */
.df-line.unbuilt .df-text { opacity: 0.38; }
.df-line.unbuilt .df-num { opacity: 0.28; }

/* The build plan, verbatim as kaniko renders it for --dryrun. */
.plan { margin: 0; max-height: 340px; overflow: auto; font-size: 12px; line-height: 1.5;
        font-family: ui-monospace, SFMono-Regular, Menlo, monospace; color: var(--text); }

/* Source panel tabs: Dockerfile as written, or the plan derived from it. */
.pane-tab { background: none; border: 0; padding: 2px 0; margin-right: 14px; cursor: pointer;
            font: inherit; font-size: 12px; color: var(--dim); border-bottom: 2px solid transparent; }
.pane-tab.active { color: var(--text); border-bottom-color: var(--accent); }

/* Signed-in user, pushed to the far right of the topbar. margin-left:auto rather
   than a fixed width so it stays put as the nav grows. */
.user { margin-left: auto; position: relative; display: flex; align-items: center; gap: 6px; font-size: 13px; }
.theme-form { display: flex; }
.theme-btn {
  display: grid; place-items: center; width: 30px; height: 30px; padding: 0;
  border: 1px solid transparent; border-radius: 999px;
  background: none; color: var(--dim); cursor: pointer;
}
.theme-btn:hover { color: var(--text); border-color: var(--border); background: var(--bg); }
.theme-icon { width: 15px; height: 15px; display: block; }
.user-menu > summary {
  display: flex; align-items: center; gap: 8px;
  cursor: pointer; list-style: none; padding: 4px 8px 4px 4px;
  border: 1px solid transparent; border-radius: 999px;
}
.user-menu > summary::-webkit-details-marker { display: none; }
.user-menu > summary:hover { border-color: var(--border); background: var(--bg); }
.user-menu[open] > summary { border-color: var(--border); background: var(--bg); }
.avatar {
  display: grid; place-items: center; width: 24px; height: 24px; border-radius: 50%;
  background: var(--accent); color: var(--panel); font-size: 11px; font-weight: 700;
}
.user-name { max-width: 14ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.user-panel {
  position: absolute; right: 0; top: calc(100% + 6px); min-width: 210px; z-index: 20;
  background: var(--panel); border: 1px solid var(--border); border-radius: 10px;
  padding: 10px; display: grid; gap: 6px;
}
.user-row { display: flex; justify-content: space-between; gap: 12px; }
.user-signout {
  margin-top: 4px; padding-top: 8px; border-top: 1px solid var(--border); color: var(--text);
}
/* The initial sits underneath as the fallback: if the remote avatar fails, the
   image is removed and the letter is already in place. */
.avatar { position: relative; overflow: hidden; }
.avatar img { position: absolute; inset: 0; width: 100%; height: 100%; border-radius: 50%; object-fit: cover; }
/* Admin mode: a ring on the avatar. Same signal, no extra box in the bar. */
.avatar.is-admin { box-shadow: 0 0 0 2px var(--warn); }

.signin {
  max-width: 340px; margin: 9vh auto; padding: 24px;
  display: grid; gap: 18px; justify-items: center; text-align: center;
}
/* The sign-in page carries the full lockup rather than the topbar mark. */
.signin-brand { display: grid; justify-items: center; gap: 14px; }
.signin-mark { display: block; width: 104px; height: auto; }
.signin-word { display: block; width: 132px; height: auto; }
.signin-btn { display: flex; align-items: center; justify-content: center; gap: 10px; }
.provider-icon { width: 16px; height: 16px; flex: 0 0 auto; fill: currentColor; }
/* Signed in: the same control, marked good rather than replaced by prose. */
.signin-btn.is-signed-in { border-color: var(--ok); }
.signin-btn.is-signed-in:hover { border-color: var(--ok); filter: brightness(1.1); }
.motto { margin: -6px 0 0; font-size: 13px; color: var(--dim); font-style: italic; }
.signin-msg {
  margin: 0; padding: 8px 12px; font-size: 13px; color: var(--text);
  background: var(--panel); border: 1px solid var(--border); border-radius: 8px;
}
.signin-actions { display: grid; gap: 10px; width: 100%; }
.signin-btn {
  display: block; padding: 10px 16px; border-radius: 8px; font-size: 13px;
  background: var(--panel); border: 1px solid var(--border); color: var(--text);
}
.signin-btn:hover { border-color: var(--accent); }
.signin-alt { margin: -4px 0 4px; font-size: 12px; color: var(--dim); }
/* A button, not a link: switching tenant changes session state, so it posts.
   Styled back to the plain row it reads as. */
.user-tenant-form { display: block; }
.user-tenant {
  display: block; width: 100%; padding: 4px 6px; border-radius: 6px; color: var(--text);
  background: none; border: 0; font: inherit; text-align: left; cursor: pointer;
}
.user-tenant:hover { background: var(--bg); }
.user-tenant.is-active { color: var(--accent); }
/* Reading someone else's tenant is marked wherever it can be reached or is in
   effect, so it is never mistaken for your own data. */
.user-tenant .foreign {
  font-size: 10px; text-transform: uppercase; letter-spacing: .04em;
  color: var(--warn); border: 1px solid color-mix(in srgb, var(--warn) 45%, var(--border));
  border-radius: 20px; padding: 0 6px;
}
.pending-count {
  display: inline-block; min-width: 16px; padding: 0 5px; border-radius: 20px;
  background: var(--warn); color: var(--panel); font-size: 11px; font-weight: 700; text-align: center;
}
.warn-msg { border-color: color-mix(in srgb, var(--warn) 45%, var(--border)); color: var(--warn); }

.access { max-width: 560px; }
.access-intro { text-align: left; }
.access-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; width: 100%; }
.access-item {
  display: grid; gap: 8px; padding: 12px; text-align: left;
  background: var(--panel); border: 1px solid var(--border); border-radius: 8px;
}
.access-account { display: flex; gap: 8px; align-items: baseline; }
.access-forge { font-weight: 600; }
.access-form { display: grid; gap: 8px; }
.access-note {
  padding: 6px 8px; border-radius: 6px; font: inherit; font-size: 12.5px;
  background: var(--bg); border: 1px solid var(--border); color: var(--text);
}
.access-form button { cursor: pointer; }

.user-admin { margin-top: 4px; padding-top: 8px; border-top: 1px solid var(--border); }
.user-admin button {
  all: unset; cursor: pointer; color: var(--warn); font: inherit; width: 100%; text-align: left;
}
.user-signout button {
  all: unset; cursor: pointer; color: var(--text); font: inherit; width: 100%; text-align: left;
}

/* Docs and landing: the app renders both, so these live here rather than in a
   second stylesheet. */
.docs-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; }
.docs-card { background: var(--panel); border: 1px solid var(--border); border-radius: 10px; padding: 14px 18px; }
.docs-meta { margin-bottom: 8px; font-size: 12px; }
.docs-notes { margin: 12px 0 0; padding-left: 18px; color: var(--dim); font-size: 12.5px; }

/* The snippet is wide and must not stretch the page: the pre scrolls on its own
   axis, and min-width:0 is what lets it shrink inside the card rather than
   forcing the card wider than the viewport. */
.docs-code {
  margin: 0; padding: 14px 16px; max-width: 100%; min-width: 0; overflow-x: auto;
  border-radius: 8px; background: var(--bg); border: 1px solid var(--border);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12.5px; line-height: 1.55;
}
.docs-code code { display: block; white-space: pre; color: inherit; background: none; padding: 0; }
/* A diff gutter as pseudo-content, so copying the snippet copies valid YAML. */
.docs-code .line::before { content: " "; flex: none; width: 2ch; color: var(--add); user-select: none; }
.docs-code.chroma .line.hl { background-color: var(--add-wash); }
.docs-code .line.hl::before { content: "+"; }

.prose h2 { font-size: 14px; margin: 22px 0 10px; }
.prose h2:first-child { margin-top: 0; }
.prose ol, .prose ul { padding-left: 20px; }
.prose li { margin: 4px 0; }
.prose blockquote {
  margin: 14px 0; padding: 8px 14px; color: var(--dim);
  border-left: 2px solid var(--border); background: var(--panel-2); border-radius: 0 6px 6px 0;
}
.prose code { background: var(--panel-2); padding: 1px 5px; border-radius: 4px; }

.landing { max-width: 1080px; margin: 0 auto; padding: 0 24px 64px; }
.hero {
  padding: 72px 0 40px;
  display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 56px; align-items: center;
}
.hero-mark { display: grid; justify-items: center; }
.hero-crystal { display: block; width: 260px; height: auto; }
/* The wordmark is the heading, so the h1 carries no type of its own. */
.hero-brand { margin: 0 0 10px; line-height: 0; }
.hero-brand img { display: block; width: 236px; height: auto; }
.hero-tag {
  margin: 0 0 22px; color: var(--dim);
  font-size: 12px; text-transform: uppercase; letter-spacing: .16em;
}

/* The glacier backdrop. Fixed behind the page, above the body fill but under
   the content. It carries a --depth that app.js multiplies scroll by, so it
   drifts slower than the page and reads as something the content moves over. */
.glacier { position: fixed; inset: 0; z-index: 0; overflow: hidden; pointer-events: none; }
/* The photographic layer sits deepest and moves least. Inset past the viewport
   so the parallax shift never exposes an edge, and masked so it fades out down
   the page rather than competing with the content below the hero. */
.glacier .ice {
  /* Taller than the viewport on purpose: it drifts up as the page scrolls, and
     a short layer would pull its own bottom edge into view. */
  position: absolute; left: -6%; right: -6%; top: -18%; bottom: -55%;
  /* The flat colour is the image's own mean tone. Until the file arrives the
     layer already paints the right value, so loading it adds texture rather
     than a visible jump in brightness. */
  background: var(--glacier-flat) var(--glacier) center / cover no-repeat;
  opacity: var(--glacier-opacity);
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 46%, transparent 82%);
  mask-image: linear-gradient(180deg, #000 0%, #000 46%, transparent 82%);
  transform: translate3d(0, calc(var(--sy, 0) * var(--depth) * -1px), 0);
  will-change: transform;
}
/* Content rides above the backdrop; the topbar keeps its own higher layer. */
.landing, .wrap, .signin { position: relative; z-index: 1; }

@media (prefers-reduced-motion: reduce) {
  .glacier .ice { transform: none; }
}
@media (max-width: 900px) {
  .hero { grid-template-columns: 1fr; gap: 32px; }
  .hero { grid-template-columns: 1fr; justify-items: center; text-align: center; }
  .hero-mark { order: -1; justify-self: center; }
  .hero-crystal { width: 150px; }
  .hero-brand img { width: 180px; margin: 0 auto; }
  .hero-sub { margin-inline: auto; }
  .hero-actions { justify-content: center; }
}
.eyebrow { color: var(--eyebrow); font-size: 12px; text-transform: uppercase; letter-spacing: .09em; margin: 0 0 14px; }
.hero h1 { font-size: 40px; line-height: 1.18; margin: 0 0 18px; font-weight: 650; letter-spacing: -.02em; }
.hero-sub { color: var(--dim); font-size: 16px; line-height: 1.6; margin: 0 0 28px; max-width: 60ch; }
.hero-actions { display: flex; gap: 12px; flex-wrap: wrap; }
.hero-btn {
  display: inline-block; padding: 10px 20px; border-radius: 8px; font-size: 13.5px; font-weight: 550;
  background: var(--accent); color: #fff; border: 1px solid var(--accent);
}
.hero-btn:hover { text-decoration: none; filter: brightness(1.08); }
.hero-btn.ghost { background: transparent; color: var(--text); border-color: var(--border); }
.hero-btn.ghost:hover { border-color: var(--accent); }

/* The waterfall capture, unframed: the picture is the point, and a border
   around it is chrome pretending to be product. */
.shot { margin: 0; padding: 8px 0 44px; }
.shot-svg { display: block; width: 100%; height: auto; padding: 14px 10px 4px; }
.shot-legend { display: flex; flex-wrap: wrap; gap: 16px; padding: 0 18px 16px; font-size: 11.5px; color: var(--dim); }
.shot-legend .key { display: inline-flex; align-items: center; gap: 6px; }
.shot-legend i { width: 10px; height: 10px; border-radius: 3px; display: inline-block; }
.shot figcaption { margin-top: 12px; font-size: 12.5px; color: var(--dim); }

.section-title { font-size: 20px; font-weight: 600; margin: 0 0 22px; }
.features { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 18px; padding: 44px 0; }
.feature h3 { font-size: 14px; margin: 0 0 8px; font-weight: 600; color: var(--strong); }
.feature p { color: var(--dim); font-size: 13.5px; line-height: 1.6; margin: 0; }
.feature code { font-size: 12px; }

.steps-section, .assurance { padding: 44px 0; border-top: 1px solid var(--border); }

/* One wide block, deliberately not a grid: it carries the argument the cards
   above cannot, so it should read as a paragraph rather than a fourth column. */
.statement { padding: 60px 0 64px; border-top: 1px solid var(--border); text-align: center; }
/* Heading, line, then the mark. A centred stack balances better than a row,
   where a small logo beside a wide paragraph leaves the section lopsided. */
.kaniko-link { display: block; width: max-content; margin: 24px auto 0; }
.kaniko-mark { display: block; height: 40px; width: auto; opacity: .85; }
.kaniko-link:hover .kaniko-mark { opacity: 1; }
/* No max-width: the claim is short and belongs on one line. */
.statement h2 {
  font-size: 30px; line-height: 1.25; font-weight: 640; letter-spacing: -.015em;
  margin: 0 auto 14px;
}
/* Centred, but the measure still caps at 66ch: a line that spans the full page
   is unreadable however wide the section is. */
.statement p { color: var(--dim); font-size: 16px; line-height: 1.7; margin: 0 auto; max-width: 66ch; }
.statement p:last-child { margin-bottom: 0; }
/* The snippet column is min-width:0 so the pre scrolls instead of widening the
   grid, which is what pushes a code block past the viewport. */
.steps { display: grid; grid-template-columns: minmax(260px, 1fr) minmax(0, 1.35fr); gap: 32px; align-items: start; }
.step-list { margin: 0; padding-left: 20px; color: var(--dim); font-size: 13.5px; line-height: 1.7; }
.step-list li { margin-bottom: 14px; }
.step-list strong { color: var(--text); }
.step-code { min-width: 0; }
.step-code .btn { margin-top: 12px; }
.assurance .features { padding: 0; }
.closing { padding: 52px 0 0; border-top: 1px solid var(--border); text-align: center; }
.closing h2 { font-size: 24px; margin: 0 0 22px; }
.closing .hero-actions { justify-content: center; }
.price-head { padding: 8px 0 34px; }
.price-head h1 { font-size: 34px; margin: 0 0 10px; letter-spacing: -.02em; }
.price-head .hero-sub { margin: 0; }

.tiers { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; align-items: stretch; }
.tier {
  position: relative; display: flex; flex-direction: column;
  background: var(--panel); border: 1px solid var(--border); border-radius: 12px;
  padding: 22px 20px 20px;
}
/* The middle card carries the accent the topbar mark uses, so the recommended
   plan is the one thing on the page wearing brand colour. */
.tier.is-featured { border-color: var(--accent); }
.tier-flag {
  position: absolute; top: -9px; left: 20px;
  background: var(--accent); color: var(--bg);
  font-size: 10.5px; font-weight: 650; letter-spacing: .06em; text-transform: uppercase;
  padding: 2px 8px; border-radius: 5px;
}
.tier h2 { font-size: 15px; margin: 0 0 12px; font-weight: 600; }
.tier-price { margin: 0 0 18px; display: flex; align-items: baseline; gap: 5px; }
.tier-price .amount { font-size: 32px; font-weight: 650; letter-spacing: -.02em; }
.tier-price .per { color: var(--dim); font-size: 13px; }
.tier-list { list-style: none; margin: 0 0 20px; padding: 0; flex: 1; }
.tier-list li {
  color: var(--dim); font-size: 13.5px; line-height: 1.5;
  padding: 7px 0 7px 20px; border-top: 1px solid var(--border); position: relative;
}
.tier-list li:first-child { border-top: 0; }
.tier-list li::before { content: "·"; position: absolute; left: 6px; color: var(--accent); font-weight: 700; }
.tier-list strong { color: var(--text); font-weight: 600; }
.tier .hero-btn { justify-content: center; text-align: center; }

.calc { padding: 46px 0 0; }
.calc h2 { font-size: 22px; margin: 0 0 16px; letter-spacing: -.01em; }
.calc-box { background: var(--panel); border: 1px solid var(--border); border-radius: 12px; padding: 20px; }
.calc-field { display: flex; justify-content: space-between; align-items: baseline; font-size: 13px; color: var(--dim); }
.calc-field output { color: var(--text); font-size: 17px; font-weight: 650; font-variant-numeric: tabular-nums; }
.calc input[type=range] { width: 100%; margin: 10px 0 4px; accent-color: var(--accent); }
.calc-result { display: flex; justify-content: space-between; align-items: baseline; gap: 16px; padding: 14px 0 16px; border-bottom: 1px solid var(--border); }
.calc-plan { font-size: 13px; color: var(--dim); }
.calc-total { display: flex; align-items: baseline; gap: 5px; font-size: 30px; font-weight: 650; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.calc-total .per { font-size: 13px; font-weight: 400; color: var(--dim); }
.rates { width: 100%; margin-top: 6px; font-size: 13px; }
.rates th { font-weight: 400; color: var(--dim); text-transform: none; letter-spacing: 0; font-size: 13px; padding-left: 0; }
.rates td { text-align: right; color: var(--text); padding-right: 0; }
.rates tr:last-child th, .rates tr:last-child td { border-bottom: none; }

.retention { padding: 52px 0 12px; }
.retention h2 { font-size: 22px; margin: 0 0 10px; letter-spacing: -.01em; }
.retention-lede { color: var(--dim); font-size: 14px; line-height: 1.65; margin: 0 0 26px; max-width: 72ch; }
.retention-lede strong { color: var(--text); font-weight: 600; }
  position: absolute; left: 0; top: 0; height: 100%; border-radius: 6px;
  display: flex; align-items: center; justify-content: flex-end;
}

.retention { padding: 52px 0 12px; }
.retention h2 { font-size: 22px; margin: 0 0 10px; letter-spacing: -.01em; }
.retention-lede { color: var(--dim); font-size: 14px; line-height: 1.65; margin: 0 0 26px; max-width: 72ch; }
.retention-lede strong { color: var(--text); font-weight: 600; }
.ret-chart { background: var(--panel); border: 1px solid var(--border); border-radius: 12px; padding: 20px; }
.ret-row { display: grid; grid-template-columns: 96px 1fr 170px; align-items: center; gap: 14px; margin-bottom: 12px; }
.ret-name { font-size: 13px; font-weight: 600; }
.ret-track { position: relative; height: 26px; background: var(--panel-2); border-radius: 6px; }
.ret-bar { position: absolute; left: 0; top: 0; height: 100%; border-radius: 6px; }
.ret-trends { background: var(--trend); }
.ret-traces { background: var(--trace); }
/* Labels sit outside the bars: on a linear scale the free trace window is under
   four per cent of the track and cannot hold its own text. */
.ret-labs { display: flex; gap: 14px; font-size: 12px; font-variant-numeric: tabular-nums; }
.ret-lab { display: inline-flex; align-items: center; gap: 6px; }
.ret-lab::before { content: ""; width: 9px; height: 9px; border-radius: 3px; }
.ret-lab.is-traces { color: var(--text); }
.ret-lab.is-traces::before { background: var(--trace); }
.ret-lab.is-trends { color: var(--dim); }
.ret-lab.is-trends::before { background: var(--trend); }
.ret-axis-row { margin-bottom: 4px; }
.ret-axis { position: relative; height: 16px; }
.ret-gridline { position: absolute; top: -14px; width: 1px; height: 14px; background: var(--border); }
.ret-axis-label { position: absolute; top: 1px; transform: translateX(-50%); font-size: 10.5px; color: var(--dim); white-space: nowrap; }
/* The last tick sits at 100%, where half of a centred label hangs off the end. */
.ret-axis-label:last-child { transform: translateX(-100%); }
.ret-key { display: flex; flex-wrap: wrap; align-items: center; gap: 16px; font-size: 11.5px; color: var(--dim); padding-top: 6px; }
.ret-key .key { display: inline-flex; align-items: center; gap: 6px; }
.ret-key i { width: 10px; height: 10px; border-radius: 3px; display: inline-block; }
.ret-key .sw-traces { background: var(--trace); }
.ret-key .sw-trends { background: var(--trend); }

.price-faq { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 18px 26px; padding: 46px 0 8px; }

@media (max-width: 760px) {
  .hero h1 { font-size: 30px; }
  .steps { grid-template-columns: 1fr; }
  .tiers { grid-template-columns: 1fr; gap: 22px; }
  /* The track needs the full width here, so the name and the numbers share the
     line above it. */
  .ret-row { grid-template-columns: auto 1fr; gap: 6px 10px; }
  .ret-name { grid-column: 1; grid-row: 1; }
  .ret-labs { grid-column: 2; grid-row: 1; justify-content: flex-end; }
  .ret-track { grid-column: 1 / -1; grid-row: 2; }
  /* Every span is labelled on its own row, so the axis is only clutter at a
     width where its four labels land on top of each other. */
  .ret-axis-row { display: none; }
}

/* Snippet highlighting: chroma's class palette, emitted by docs.HighlightCSS. */
/* Background */ .bg { color: #e6edf3; background-color: #0d1117; }
/* PreWrapper */ .chroma { color: #e6edf3; background-color: #0d1117; -webkit-text-size-adjust: none; }
/* Error */ .chroma .err { color: #f85149 }
/* LineLink */ .chroma .lnlinks { outline: none; text-decoration: none; color: inherit }
/* LineTableTD */ .chroma .lntd { vertical-align: top; padding: 0; margin: 0; border: 0; }
/* LineTable */ .chroma .lntable { border-spacing: 0; padding: 0; margin: 0; border: 0; }
/* LineHighlight */ .chroma .hl { background-color: #6e7681 }
/* LineNumbersTable */ .chroma .lnt { white-space: pre; -webkit-user-select: none; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #737679 }
/* LineNumbers */ .chroma .ln { white-space: pre; -webkit-user-select: none; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #6e7681 }
/* Line */ .chroma .line { display: flex; }
/* Keyword */ .chroma .k { color: #ff7b72 }
/* KeywordConstant */ .chroma .kc { color: #79c0ff }
/* KeywordDeclaration */ .chroma .kd { color: #ff7b72 }
/* KeywordNamespace */ .chroma .kn { color: #ff7b72 }
/* KeywordPseudo */ .chroma .kp { color: #79c0ff }
/* KeywordReserved */ .chroma .kr { color: #ff7b72 }
/* KeywordType */ .chroma .kt { color: #ff7b72 }
/* NameClass */ .chroma .nc { color: #f0883e; font-weight: bold }
/* NameConstant */ .chroma .no { color: #79c0ff; font-weight: bold }
/* NameDecorator */ .chroma .nd { color: #d2a8ff; font-weight: bold }
/* NameEntity */ .chroma .ni { color: #ffa657 }
/* NameException */ .chroma .ne { color: #f0883e; font-weight: bold }
/* NameLabel */ .chroma .nl { color: #79c0ff; font-weight: bold }
/* NameNamespace */ .chroma .nn { color: #ff7b72 }
/* NameProperty */ .chroma .py { color: #79c0ff }
/* NameTag */ .chroma .nt { color: #7ee787 }
/* NameVariable */ .chroma .nv { color: #79c0ff }
/* NameVariableClass */ .chroma .vc { color: #79c0ff }
/* NameVariableGlobal */ .chroma .vg { color: #79c0ff }
/* NameVariableInstance */ .chroma .vi { color: #79c0ff }
/* NameVariableMagic */ .chroma .vm { color: #79c0ff }
/* NameFunction */ .chroma .nf { color: #d2a8ff; font-weight: bold }
/* NameFunctionMagic */ .chroma .fm { color: #d2a8ff; font-weight: bold }
/* Literal */ .chroma .l { color: #a5d6ff }
/* LiteralDate */ .chroma .ld { color: #79c0ff }
/* LiteralString */ .chroma .s { color: #a5d6ff }
/* LiteralStringAffix */ .chroma .sa { color: #79c0ff }
/* LiteralStringBacktick */ .chroma .sb { color: #a5d6ff }
/* LiteralStringChar */ .chroma .sc { color: #a5d6ff }
/* LiteralStringDelimiter */ .chroma .dl { color: #79c0ff }
/* LiteralStringDoc */ .chroma .sd { color: #a5d6ff }
/* LiteralStringDouble */ .chroma .s2 { color: #a5d6ff }
/* LiteralStringEscape */ .chroma .se { color: #79c0ff }
/* LiteralStringHeredoc */ .chroma .sh { color: #79c0ff }
/* LiteralStringInterpol */ .chroma .si { color: #a5d6ff }
/* LiteralStringOther */ .chroma .sx { color: #a5d6ff }
/* LiteralStringRegex */ .chroma .sr { color: #79c0ff }
/* LiteralStringSingle */ .chroma .s1 { color: #a5d6ff }
/* LiteralStringSymbol */ .chroma .ss { color: #a5d6ff }
/* LiteralNumber */ .chroma .m { color: #a5d6ff }
/* LiteralNumberBin */ .chroma .mb { color: #a5d6ff }
/* LiteralNumberFloat */ .chroma .mf { color: #a5d6ff }
/* LiteralNumberHex */ .chroma .mh { color: #a5d6ff }
/* LiteralNumberInteger */ .chroma .mi { color: #a5d6ff }
/* LiteralNumberIntegerLong */ .chroma .il { color: #a5d6ff }
/* LiteralNumberOct */ .chroma .mo { color: #a5d6ff }
/* Operator */ .chroma .o { color: #ff7b72; font-weight: bold }
/* OperatorWord */ .chroma .ow { color: #ff7b72; font-weight: bold }
/* OperatorReserved */ .chroma .or { color: #ff7b72; font-weight: bold }
/* Comment */ .chroma .c { color: #8b949e; font-style: italic }
/* CommentHashbang */ .chroma .ch { color: #8b949e; font-style: italic }
/* CommentMultiline */ .chroma .cm { color: #8b949e; font-style: italic }
/* CommentSingle */ .chroma .c1 { color: #8b949e; font-style: italic }
/* CommentSpecial */ .chroma .cs { color: #8b949e; font-weight: bold; font-style: italic }
/* CommentPreproc */ .chroma .cp { color: #8b949e; font-weight: bold; font-style: italic }
/* CommentPreprocFile */ .chroma .cpf { color: #8b949e; font-weight: bold; font-style: italic }
/* GenericDeleted */ .chroma .gd { color: #ffa198; background-color: #490202 }
/* GenericEmph */ .chroma .ge { font-style: italic }
/* GenericError */ .chroma .gr { color: #ffa198 }
/* GenericHeading */ .chroma .gh { color: #79c0ff; font-weight: bold }
/* GenericInserted */ .chroma .gi { color: #56d364; background-color: #0f5323 }
/* GenericOutput */ .chroma .go { color: #8b949e }
/* GenericPrompt */ .chroma .gp { color: #8b949e }
/* GenericStrong */ .chroma .gs { font-weight: bold }
/* GenericSubheading */ .chroma .gu { color: #79c0ff }
/* GenericTraceback */ .chroma .gt { color: #ff7b72 }
/* GenericUnderline */ .chroma .gl { text-decoration: underline }
/* TextWhitespace */ .chroma .w { color: #6e7681 }

/* The same palette from chroma's "github" style, scoped to light and reduced to
   the colours: weight and style come from the dark rule above, which still
   matches. The nine rules under the rule block are token types github-dark
   names and github does not, so chroma emits nothing for them and they would
   otherwise stay dark on a light page. */
/* Background */ :root[data-theme="light"] .bg { color: #1f2328; background-color: #f7f7f7 }
/* PreWrapper */ :root[data-theme="light"] .chroma { color: #1f2328; background-color: #f7f7f7 }
/* Error */ :root[data-theme="light"] .chroma .err { color: #f6f8fa; background-color: #82071e }
/* LineLink */ :root[data-theme="light"] .chroma .lnlinks { color: inherit }
/* LineHighlight: deliberately not overridden. The only highlighted lines the
   app renders are the docs snippet's added ones, and .docs-code.chroma .line.hl
   above already carries their tint at a specificity this would tie and then win
   on order, turning the diff grey. */
/* LineNumbersTable */ :root[data-theme="light"] .chroma .lnt { color: #7f7f7f }
/* LineNumbers */ :root[data-theme="light"] .chroma .ln { color: #7f7f7f }
/* Keyword */ :root[data-theme="light"] .chroma .k { color: #cf222e }
/* KeywordConstant */ :root[data-theme="light"] .chroma .kc { color: #cf222e }
/* KeywordDeclaration */ :root[data-theme="light"] .chroma .kd { color: #cf222e }
/* KeywordNamespace */ :root[data-theme="light"] .chroma .kn { color: #cf222e }
/* KeywordPseudo */ :root[data-theme="light"] .chroma .kp { color: #cf222e }
/* KeywordReserved */ :root[data-theme="light"] .chroma .kr { color: #cf222e }
/* KeywordType */ :root[data-theme="light"] .chroma .kt { color: #cf222e }
/* NameAttribute */ :root[data-theme="light"] .chroma .na { color: #1f2328 }
/* NameClass */ :root[data-theme="light"] .chroma .nc { color: #1f2328 }
/* NameConstant */ :root[data-theme="light"] .chroma .no { color: #0550ae }
/* NameDecorator */ :root[data-theme="light"] .chroma .nd { color: #0550ae }
/* NameEntity */ :root[data-theme="light"] .chroma .ni { color: #6639ba }
/* NameLabel */ :root[data-theme="light"] .chroma .nl { color: #990000 }
/* NameNamespace */ :root[data-theme="light"] .chroma .nn { color: #24292e }
/* NameOther */ :root[data-theme="light"] .chroma .nx { color: #1f2328 }
/* NameTag */ :root[data-theme="light"] .chroma .nt { color: #0550ae }
/* NameBuiltin */ :root[data-theme="light"] .chroma .nb { color: #6639ba }
/* NameBuiltinPseudo */ :root[data-theme="light"] .chroma .bp { color: #6a737d }
/* NameVariable */ :root[data-theme="light"] .chroma .nv { color: #953800 }
/* NameVariableClass */ :root[data-theme="light"] .chroma .vc { color: #953800 }
/* NameVariableGlobal */ :root[data-theme="light"] .chroma .vg { color: #953800 }
/* NameVariableInstance */ :root[data-theme="light"] .chroma .vi { color: #953800 }
/* NameVariableMagic */ :root[data-theme="light"] .chroma .vm { color: #953800 }
/* NameFunction */ :root[data-theme="light"] .chroma .nf { color: #6639ba }
/* NameFunctionMagic */ :root[data-theme="light"] .chroma .fm { color: #6639ba }
/* LiteralString */ :root[data-theme="light"] .chroma .s { color: #0a3069 }
/* LiteralStringAffix */ :root[data-theme="light"] .chroma .sa { color: #0a3069 }
/* LiteralStringBacktick */ :root[data-theme="light"] .chroma .sb { color: #0a3069 }
/* LiteralStringChar */ :root[data-theme="light"] .chroma .sc { color: #0a3069 }
/* LiteralStringDelimiter */ :root[data-theme="light"] .chroma .dl { color: #0a3069 }
/* LiteralStringDoc */ :root[data-theme="light"] .chroma .sd { color: #0a3069 }
/* LiteralStringDouble */ :root[data-theme="light"] .chroma .s2 { color: #0a3069 }
/* LiteralStringEscape */ :root[data-theme="light"] .chroma .se { color: #0a3069 }
/* LiteralStringHeredoc */ :root[data-theme="light"] .chroma .sh { color: #0a3069 }
/* LiteralStringInterpol */ :root[data-theme="light"] .chroma .si { color: #0a3069 }
/* LiteralStringOther */ :root[data-theme="light"] .chroma .sx { color: #0a3069 }
/* LiteralStringRegex */ :root[data-theme="light"] .chroma .sr { color: #0a3069 }
/* LiteralStringSingle */ :root[data-theme="light"] .chroma .s1 { color: #0a3069 }
/* LiteralStringSymbol */ :root[data-theme="light"] .chroma .ss { color: #032f62 }
/* LiteralNumber */ :root[data-theme="light"] .chroma .m { color: #0550ae }
/* LiteralNumberBin */ :root[data-theme="light"] .chroma .mb { color: #0550ae }
/* LiteralNumberFloat */ :root[data-theme="light"] .chroma .mf { color: #0550ae }
/* LiteralNumberHex */ :root[data-theme="light"] .chroma .mh { color: #0550ae }
/* LiteralNumberInteger */ :root[data-theme="light"] .chroma .mi { color: #0550ae }
/* LiteralNumberIntegerLong */ :root[data-theme="light"] .chroma .il { color: #0550ae }
/* LiteralNumberOct */ :root[data-theme="light"] .chroma .mo { color: #0550ae }
/* Operator */ :root[data-theme="light"] .chroma .o { color: #0550ae }
/* OperatorWord */ :root[data-theme="light"] .chroma .ow { color: #0550ae }
/* OperatorReserved */ :root[data-theme="light"] .chroma .or { color: #0550ae }
/* Punctuation */ :root[data-theme="light"] .chroma .p { color: #1f2328 }
/* Comment */ :root[data-theme="light"] .chroma .c { color: #57606a }
/* CommentHashbang */ :root[data-theme="light"] .chroma .ch { color: #57606a }
/* CommentMultiline */ :root[data-theme="light"] .chroma .cm { color: #57606a }
/* CommentSingle */ :root[data-theme="light"] .chroma .c1 { color: #57606a }
/* CommentSpecial */ :root[data-theme="light"] .chroma .cs { color: #57606a }
/* CommentPreproc */ :root[data-theme="light"] .chroma .cp { color: #57606a }
/* CommentPreprocFile */ :root[data-theme="light"] .chroma .cpf { color: #57606a }
/* GenericDeleted */ :root[data-theme="light"] .chroma .gd { color: #82071e; background-color: #ffebe9 }
/* GenericEmph */ :root[data-theme="light"] .chroma .ge { color: #1f2328 }
/* GenericInserted */ :root[data-theme="light"] .chroma .gi { color: #116329; background-color: #dafbe1 }
/* GenericOutput */ :root[data-theme="light"] .chroma .go { color: #1f2328 }
/* TextWhitespace */ :root[data-theme="light"] .chroma .w { color: #ffffff }
/* Literal */ :root[data-theme="light"] .chroma .l { color: #0a3069 }
/* LiteralDate */ :root[data-theme="light"] .chroma .ld { color: #0550ae }
/* NameException */ :root[data-theme="light"] .chroma .ne { color: #1f2328 }
/* NameProperty */ :root[data-theme="light"] .chroma .py { color: #0550ae }
/* GenericError */ :root[data-theme="light"] .chroma .gr { color: #82071e }
/* GenericTraceback */ :root[data-theme="light"] .chroma .gt { color: #82071e }
/* GenericHeading */ :root[data-theme="light"] .chroma .gh { color: #0550ae }
/* GenericSubheading */ :root[data-theme="light"] .chroma .gu { color: #0550ae }
/* GenericPrompt */ :root[data-theme="light"] .chroma .gp { color: #57606a }

/* Mobile: the links fold behind a hamburger, and the topbar stays one row. */
@media (max-width: 760px) {
  /* nowrap: the hamburger exists so the bar stays one row. */
  .topbar { gap: 12px; padding: 10px 14px; flex-wrap: nowrap; }
  /* Hamburger left, mark centred, account right. */
  /* auto on the right: a fixed track wrapped the sign-in button onto four
     lines and stretched the bar. */
  .topbar { display: grid; grid-template-columns: 36px 1fr auto; align-items: center; }
  .topbar .burger-btn {
    display: grid; place-items: center; width: 34px; height: 34px;
    grid-column: 1; grid-row: 1; justify-self: start; cursor: pointer;
    border: 1px solid var(--border); border-radius: 8px; background: var(--panel-2);
  }
  /* Three bars from one element, so the button needs no icon file. */
  .burger, .burger::before, .burger::after {
    display: block; width: 15px; height: 2px; border-radius: 2px;
    background: var(--text); content: "";
  }
  .burger { position: relative; }
  .burger::before { position: absolute; top: -5px; }
  .burger::after  { position: absolute; top: 5px; }
  .topbar .brand { grid-column: 2; grid-row: 1; justify-self: center; }
  .topbar .user { grid-column: 3; grid-row: 1; justify-self: end; }
  .topbar .nav-group { display: none; }
  .nav-toggle:checked ~ .nav-group {
    display: grid; gap: 2px; position: absolute; left: 14px; top: 56px;
    min-width: 180px; z-index: 30; padding: 6px;
    background: var(--panel); border: 1px solid var(--border); border-radius: 10px;
  }
  .nav-group nav { display: grid; gap: 2px; }
  /* Stacked in one sheet, the two groups need a line between them instead of
     the distance they get side by side. */
  .topbar .nav-meta { margin-left: 0; }
  .nav-app + .nav-meta { border-top: 1px solid var(--border); margin-top: 4px; padding-top: 4px; }
  .topbar nav a { padding: 8px 10px; border-radius: 6px; }
  .topbar nav a:hover { background: var(--panel-2); text-decoration: none; }
  /* The avatar is identity enough at this width. */
  .user-name { display: none; }
  .wrap { padding: 18px 14px; }
  /* The capture is wider than any phone, so let it pan instead of shrinking
     into an unreadable strip. */
  /* No parallax on a phone: transforming a full-bleed image every frame is
     what makes the page feel heavy to scroll. */
  .glacier .ice { transform: none; will-change: auto; }
  .shot { overflow-x: auto; }
  .shot .shot-img { min-width: 620px; width: 620px; }
}

/* Docs version picker: sits above the walkthrough, so a reader sets their kaniko
   version before following steps that depend on it. */
.version-picker { display: flex; align-items: center; gap: 10px; margin: 0 0 22px; font-size: 13px; }
.version-picker label { color: var(--dim); }
.version-picker select {
  padding: 5px 8px; border-radius: 6px; font: inherit; font-size: 13px;
  background: var(--panel-2); border: 1px solid var(--border); color: var(--text);
}

/* Profile page. The token input is wide because an API key is long and a field
   that shows six characters of it invites a truncated paste. */
.profile h2 { margin: 0 0 .5rem; font-size: 1rem; }
.profile .card { margin-bottom: 1rem; }
.profile .card > .dim { margin: 0 0 .75rem; max-width: 62ch; }
.user-link { display: block; padding: .4rem .1rem; color: var(--link); text-decoration: none; }
.user-link:hover { text-decoration: underline; }
.profile-token { display: flex; gap: .5rem; margin-top: .75rem; }
.token-input {
  flex: 1; min-width: 0; padding: .45rem .6rem; font-family: var(--mono, monospace);
  color: inherit; background: var(--input-bg, rgba(0,0,0,.25));
  border: 1px solid var(--border, rgba(255,255,255,.15)); border-radius: 6px;
}
.profile-token-remove { margin-top: .5rem; }
.btn-quiet { background: none; border: 1px solid var(--border, rgba(255,255,255,.15)); opacity: .8; }
.btn-quiet:hover { opacity: 1; }

/* A report page. The body is goldmark output — h2/p/table/pre and nothing else,
   because raw HTML is disabled — so the whole Firn report style is these rules
   over generated markup. Nothing to keep in sync with a hand-written document.

   Prose in the product's sans, every measurement in mono: a report is mostly
   numbers, and the two faces are what separate the argument from the evidence. */
/* Centred in the wrap, not flush left: a report is a document, and a measure
   this narrow hard against the left edge of a 1180px page reads as a column
   that failed to lay out rather than one that was chosen. */
.report { max-width: 78ch; margin: 0 auto; }
.report h1 { font-size: 30px; line-height: 1.12; letter-spacing: -.02em; margin: 4px 0 6px; }
.report .report-meta { font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11.5px; letter-spacing: .08em; text-transform: uppercase; color: var(--dim);
  margin: 0 0 28px; }
.report h2 { font-size: 19px; font-weight: 600; letter-spacing: -.015em; color: var(--text);
  margin: 36px 0 12px; padding-top: 12px;
  /* Stratum rule: firn is layered snow under load, and the wordmark is a core
     sample. Every section opens on three compacted lines rather than one. */
  background:
    linear-gradient(var(--text), var(--text)) 0 0/100% 1px no-repeat,
    linear-gradient(var(--border), var(--border)) 0 3px/100% 1px no-repeat,
    linear-gradient(var(--panel-2), var(--panel-2)) 0 5px/100% 1px no-repeat; }
.report h3 { font-size: 15px; font-weight: 600; color: var(--text); margin: 24px 0 8px; }
.report p, .report li { color: var(--dim); font-size: 15.5px; line-height: 1.65; }
.report p { margin: 0 0 14px; }
.report strong { color: var(--text); font-weight: 600; }
.report ul, .report ol { margin: 0 0 14px; padding-left: 1.3em; }
.report li { margin-bottom: 6px; }
.report a { color: var(--accent); }

/* Tables carry the measurements, so they get the mono treatment and room to
   scroll rather than squeezing a column to nothing. */
/* Not display:block. That shrinks the internal table layout to its content
   while the block box still fills the column, which reads as a table hugging
   the left edge of its own background. */
.report table { width: 100%; margin: 0 0 20px;
  background: var(--panel); border: 1px solid var(--border); border-radius: 10px; }
.report thead th { font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 10.5px; letter-spacing: .1em; text-transform: uppercase; color: var(--dim);
  font-weight: 400; white-space: nowrap; }
.report tbody td { font-size: 13.5px; }
/* The label column carries instruction text, which is inline code, and the
   global td code rule pins that open. Left alone it drives the table past the
   column instead of wrapping inside it. */
.report td code { white-space: normal; overflow-wrap: anywhere; }
/* GFM writes its alignment as an inline style rather than an align attribute,
   so the substring match is what catches it. A right-aligned column is a number
   column, which is why it earns mono and tabular figures with no extra markup
   in the body. */
.report td[style*="right"], .report th[style*="right"] {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-variant-numeric: tabular-nums; white-space: nowrap; }
.report tbody tr:last-child td { border-bottom: none; }

.report pre { background: var(--panel-2); border: 1px solid var(--border); border-radius: 10px;
  padding: 14px 16px; overflow-x: auto; margin: 0 0 20px; }
.report pre code { font-size: 12.5px; line-height: 1.62; color: var(--text); }
.report :not(pre) > code { background: var(--panel-2); border: 1px solid var(--border);
  border-radius: 4px; padding: .08em .34em; }
.report blockquote { margin: 0 0 18px; padding: 2px 0 2px 16px;
  border-left: 2px solid var(--accent); color: var(--dim); }
.report hr { border: 0; border-top: 1px solid var(--border); margin: 32px 0; }

/* Diff rows fill the block. chroma tints the +/- span, which ends where the
   line's text ends, so the row carries the colour and the span's own background
   is dropped rather than stacking a darker stripe on top of it. */
.chroma .line:has(> .cl > .gd) { background-color: #490202; }
.chroma .line:has(> .cl > .gi) { background-color: #0f5323; }
.chroma .line > .cl > .gd,
.chroma .line > .cl > .gi { background-color: transparent; }
:root[data-theme="light"] .chroma .line:has(> .cl > .gd) { background-color: #ffebe9; }
:root[data-theme="light"] .chroma .line:has(> .cl > .gi) { background-color: #dafbe1; }
