/* ===========================================================================
   PORTFOLEO DESIGN SYSTEM v1 — "THE INSTRUMENT"  ·  COMPONENT LAYER
   ---------------------------------------------------------------------------
   Requires tokens.css then base.css. Every value here is a var() from the
   token layer; there are no raw hex literals except pure black/white inside
   rgba() shadow stacks, which the token layer cannot express.

   The two planes, restated because it governs every rule below:
     DATA PLANE     .dt, .win-body-data, chart canvas, .num
                    -> --s-void ground, --r-0, no shadow, no blur, no grain,
                       NO ANIMATION OF ANY KIND, EVER.
     INSTRUMENT     .win chrome, .palette, .rail, .tabs, .toast, .hintbar,
                       the marketing site
                    -> inset hairline rings, top-edge highlights, three-layer
                       shadow stacks, backdrop blur on overlays only, one
                       motion curve.

   Component index
     1  Window / panel chrome            9  Toasts
     2  Data table                      10  Modals
     3  Provenance / freshness          11  Empty states
     4  Command badge + kbd chip        12  Loading
     5  Buttons                         13  Error states
     6  Inputs + form controls          14  Marketing cards + chrome
     7  Tabs                            15  Command palette + hint bar
     8  Badges / pills / status         16  Right rail + tape + chart frame
   =========================================================================== */


/* ===========================================================================
   1. WINDOW / PANEL CHROME  (spec s7.1, s5.1, s5.3)

   +- 24px titlebar (--g-chrome) ------------------------------------------+
   | [CODE] Financials  NVDA US     In Millions - FY - YAHOO 15:59:42Z  _[]x|
   +- 22px tabstrip (optional) --------------------------------------------+
   |  Balance Sheet | Income | Cash Flow        Quarterly | Yearly          |
   +-----------------------------------------------------------------------+
   |  data well  (--s-void, zero padding, ring-inset)                       |
   +-----------------------------------------------------------------------+

   border:0 + inset ring means a focus change costs ZERO layout shift.
   Windows tile flush at --panel-gutter (1px). Radius is 0, always.
   =========================================================================== */
.win {
  position: relative;
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  background: var(--s-100);
  border: 0;
  border-radius: var(--r-0);
  box-shadow: var(--sh-panel);
  transition: box-shadow var(--dur-2) var(--ease);
}
.win.is-maximised { box-shadow: none; }

/* FOCUS. The single highest-leverage visual change in the product: the old
   behaviour flipped the whole titlebar to a solid amber gradient — a ~24px x
   panel-width block of full-chroma orange on every focus change. Godel
   signals focus with a ~2px inset stroke and leaves the titlebar dark.       */
.win.focused { box-shadow: var(--sh-focus-panel); }

.win-title {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  flex: 0 0 auto;
  height: var(--panel-title-h);
  padding: 0 var(--sp-2);
  background: var(--g-chrome);
  box-shadow: inset 0 -1px 0 0 var(--ln-200);
  font: var(--ti-md);
  font-weight: 500;
  letter-spacing: .06em;          /* NOT .16em — shouty tracking is a 1990s tell */
  color: var(--t-200);
  user-select: none;
  cursor: default;
  white-space: nowrap;
  min-width: 0;
  overflow: hidden;
}
.win.focused .win-title { background: var(--s-150); color: var(--ac); }
/* min-width: 0 is what makes the ellipsis actually fire. A flex item's
   automatic minimum size is its min-content width, so without this the long
   name simply pushes the units slot and the action cluster out of the panel
   instead of truncating. */
.win-title .name { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.win-title .sym { color: var(--t-100); font-weight: 600; }

/* The link glyph is the ticker-sync group control. It is coloured BY GROUP
   from the viz ramp, never amber — amber is not a value.                     */
.win-link {
  width: 12px; height: 12px;
  flex: 0 0 auto;
  border-radius: var(--r-pill);
  background: var(--group-color, var(--t-400));
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .55);
}
.win-link[data-group="1"] { --group-color: var(--viz-1); }
.win-link[data-group="2"] { --group-color: var(--viz-2); }
.win-link[data-group="3"] { --group-color: var(--viz-3); }
.win-link[data-group="4"] { --group-color: var(--viz-4); }
.win-link[data-group="5"] { --group-color: var(--viz-5); }
.win-link[data-group="6"] { --group-color: var(--viz-6); }
.win-link[data-group="7"] { --group-color: var(--viz-7); }
.win-link[data-group="8"] { --group-color: var(--viz-8); }

/* UNITS SLOT — units / basis / SOURCE / as-of, from the same prov.js payload.
   Godel prints "In Millions, Fiscal Years" inline; we go further and print
   the source and the as-of, because that is the brand.                       */
.win-units {
  margin-left: auto;
  font: var(--ti-micro);
  letter-spacing: var(--ti-micro-track);
  color: var(--t-300);
  text-transform: uppercase;
  white-space: nowrap;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

.win-actions { display: flex; flex: 0 0 auto; margin-left: var(--sp-2); }
.win-action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px; height: 24px;      /* 24px square hit targets                 */
  color: var(--t-300);
  cursor: pointer;
  border-radius: var(--r-0);
  transition: color var(--dur-1) var(--ease), background var(--dur-1) var(--ease);
}
.win-action:hover { color: var(--t-100); background: var(--s-300); }
.win-action[data-act="close"]:hover { color: var(--down); background: var(--down-a10); }

.win-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow: auto;
  padding: var(--panel-pad);
}
/* Table panels bleed to the ring: zero padding, and the well is recessed.    */
.win-body-data {
  flex: 1 1 auto;
  min-height: 0;
  overflow: auto;
  padding: var(--panel-pad-data);
  background: var(--s-void);
  box-shadow: var(--sh-well);
}

/* Raised objects — the three-layer stack (spec s5.2).                        */
.raised {
  background: var(--s-200);
  border-radius: var(--r-2);
  box-shadow: var(--sh-raised);
}
.well {
  background: var(--s-void);
  box-shadow: var(--sh-well);
}

/* The tiled workspace. 1px reads "terminal"; 8px reads "dashboard".          */
.workspace {
  display: grid;
  gap: var(--panel-gutter);
  background: var(--ln-100);
  min-height: 0;
}
.desktop {
  background: var(--g-desktop), var(--s-000);
  position: relative;
}


/* ===========================================================================
   2. DATA TABLE  (spec s4.3, s7.2)
   NO ZEBRA. NO PER-ROW BOTTOM BORDER. Two competing horizontal rhythms is
   what the old stylesheet shipped. Separation comes from VERTICAL column
   rules on a pure-black ground.
   Row pitch is set by height + line-height, NEVER by padding, so it is a
   metronome regardless of content.
   ZERO COLOUR BY DEFAULT: a financial statement is 100% --t-100. Colour
   appears only on .up/.dn cells and on the sort-active header arrow.
   =========================================================================== */
.dt {
  width: 100%;
  background: var(--s-void);
  font-size: var(--row-font);
  color: var(--t-100);
  border-radius: var(--r-0);
}

.dt thead th {
  position: sticky;
  top: 0;
  z-index: 2;
  height: var(--row-h);
  padding: 0 var(--cell-px);
  background: var(--s-150);
  border-bottom: var(--bw-hair) solid var(--ln-300);
  font-size: var(--row-head-font);
  font-weight: var(--ti-nano-wt);
  letter-spacing: var(--ti-nano-track);
  line-height: var(--row-h);
  text-transform: uppercase;
  color: var(--t-200);            /* NOT amber. Column headers are not values. */
  white-space: nowrap;
  user-select: none;
}
.dt thead th.sortable { cursor: pointer; }
.dt thead th.sortable:hover { color: var(--t-100); }
/* The sort-active arrow is one of the eleven rationed amber uses.            */
.dt thead th[aria-sort]:not([aria-sort="none"]) { color: var(--ac); }
.dt thead th[aria-sort="ascending"]::after  { content: "\25B2"; font-size: .8em; margin-left: .4em; }
.dt thead th[aria-sort="descending"]::after { content: "\25BC"; font-size: .8em; margin-left: .4em; }

.dt tbody tr { height: var(--row-h); }
.dt tbody td {
  height: var(--row-h);
  padding: 0 var(--cell-px);
  line-height: calc(var(--row-h) - 2px);
  background: var(--s-void);
  border-bottom: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.dt tbody td:not(:last-child),
.dt thead th:not(:last-child) { border-right: var(--bw-hair) solid var(--ln-100); }

/* The ONLY permitted rhythm break — one per semantic block.                  */
.dt tr.group-break { height: calc(var(--row-h) + 12px); }
.dt tr.group-break > td { border-top: var(--bw-hair) solid var(--ln-300); }

/* Column roles. Scoped to tbody ON PURPOSE: `.dt .c-num` is two classes
   (0,2,0) and would out-specify `.dt thead th` (0,1,2), silently repainting
   column headers --t-100 and breaking the "headers are --t-200, never amber,
   never primary" rule the moment an author puts the role class on the <th>
   for alignment -- which is the natural thing to do. Header alignment is
   handled separately below, with no colour.                                 */
.dt tbody .c-sym  { color: var(--t-100); font-weight: 600; min-width: 56px; }
.dt tbody .c-num  { text-align: right; font-variant-numeric: tabular-nums; color: var(--t-100); }
.dt tbody .c-meta { color: var(--t-200); }
.dt tbody .c-unit,
.dt tbody .c-age  { color: var(--t-300); font-size: var(--ti-micro-size); letter-spacing: .04em; }

/* Header alignment only -- geometry, never colour.                          */
.dt thead th.c-num,
.dt thead th.c-age  { text-align: right; }
.dt thead th.c-sym  { min-width: 56px; }

/* Hover is a LIFT OUT OF THE WELL, not an amber tint. Meta text steps up to
   --t-200 on --s-100/--s-300 because --t-300 measures 4.49:1 on --s-300 —
   below the AA floor (see tokens.css s4).                                    */
.dt tbody tr:hover > td { background: var(--s-100); }
.dt tbody tr:hover .c-unit,
.dt tbody tr:hover .c-age { color: var(--t-200); }

.dt tbody tr[aria-selected="true"] > td { background: var(--s-300); }
.dt tbody tr[aria-selected="true"] > td:first-child { box-shadow: inset 2px 0 0 0 var(--ac); }
.dt tbody tr[aria-selected="true"] .c-unit,
.dt tbody tr[aria-selected="true"] .c-age { color: var(--t-200); }

/* STALENESS. A stale price must still be READABLE: it is demoted, not hidden.
   --stale-opacity .54 composites --t-100 over black to 5.09:1 (measured with
   alpha compositing, not estimated). The .50 the spec proposed composites to
   4.46:1 and is BELOW the 4.5 AA floor it claimed to clear — the arithmetic in
   SPEC-DESIGN-SYSTEM s2.9 is off by a hair, and this is the corrected value.
   A stale row does not get to move (spec s6.3 rule 6).                       */
.dt tbody tr[data-stale="1"] > td { opacity: var(--stale-opacity); }
.dt tbody tr[data-stale="1"] * { animation: none !important; transition: none !important; }
.dt tbody tr[data-dead="1"] > td { opacity: var(--dead-opacity); }
.dt tbody tr[data-dead="1"] .c-age::after { content: " //"; }

/* THE AGE CELL IS EXEMPT FROM THE ROW DIM. It is the cell that EXPLAINS why the
   row is dimmed, and dimming it compounds two demotions: --down at 6.94:1 on
   black drops to 2.34:1 once the row opacity multiplies it, i.e. the one glyph
   that says "this number is old" becomes the least legible thing in the table.
   The freshness instrument stays at full strength; the values it is judging are
   what get demoted.                                                          */
.dt tbody tr[data-stale="1"] > td.c-age,
.dt tbody tr[data-dead="1"] > td.c-age { opacity: 1; }

/* Age-class colour is SEMANTIC and must survive hover and selection. The `tr`
   in the selector is not decoration: it raises the element count so these
   beat `.dt tbody tr:hover .c-age` on specificity rather than on source
   order, which a later edit could silently invert.                          */
.dt tbody tr td.c-age[data-age-class="delayed"] { color: var(--warn); }
.dt tbody tr td.c-age[data-age-class="stale"]   { color: var(--down); }

/* THE VALUE-CHANGE FLASH — the one permitted "live" cue (spec s6.4).
   Not a transition on the value: a decaying background tint BEHIND it. The
   glyph and the digits change instantly, on the same frame as the data.
   JS sets data-tick and removes it on animationend.                          */
@keyframes flash-up   { from { background: var(--up-a10);   } to { background: transparent; } }
@keyframes flash-down { from { background: var(--down-a10); } to { background: transparent; } }
.dt td[data-tick="up"]   { animation: flash-up   var(--dur-flash) var(--ease) 1; }
.dt td[data-tick="down"] { animation: flash-down var(--dur-flash) var(--ease) 1; }

/* Placeholder for a value that has not arrived. --t-ghost is NON-TEXT: an
   em-dash run carries no information, which is exactly the point.            */
.dt .pending { color: var(--t-ghost); }

/* Density knob: any subtree can be retuned without touching a rule.          */
.dt[data-density] { }


/* ===========================================================================
   3. PROVENANCE / FRESHNESS INDICATOR  (spec s7.15) — the brand made visible
   Three renderings of one object: a chip beside a value, the .win-units
   header slot, and an AGE/LAT column (2. above).
   It NEVER fades in. It is present from first paint, or the data is not shown.
   =========================================================================== */
.prov-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font: var(--ti-micro);
  letter-spacing: .05em;
  color: var(--t-300);
  background: transparent;
  border: var(--bw-hair) solid var(--ln-300);
  border-radius: var(--r-1);
  padding: 2px 5px;
  cursor: help;
  user-select: none;
  white-space: nowrap;
  text-transform: uppercase;
  animation: none;                /* explicit: never fades in                */
}
.prov-chip::before {
  content: "";
  width: 5px; height: 5px;
  flex: 0 0 auto;
  border-radius: var(--r-pill);
  background: var(--up);          /* fresh                                    */
}
.prov-chip[data-state="delayed"]::before { background: var(--warn); }
.prov-chip[data-state="stale"]::before   { background: var(--down); }
.prov-chip[data-state="pending"]::before { background: var(--t-400); }
.prov-chip[data-state="error"]::before   { background: var(--down); }
.prov-chip[data-state="stale"]  { border-color: var(--down-a45); color: var(--t-200); }
.prov-chip[data-state="error"]  { border-color: var(--down-a45); color: var(--down); }
.prov-chip[data-state="pending"] { color: var(--t-300); border-style: dashed; }
.prov-chip .src { color: var(--t-200); }


/* ===========================================================================
   4. COMMAND BADGE + KBD CHIP  (spec s7.6)
   ONE OBJECT, FOUR SURFACES: palette rows, window titlebars, marketing
   feature blocks, /commands docs. Learning the marketing page IS learning the
   product. The mnemonic is a first-class visual object, not text.
   =========================================================================== */
.cmd-badge {
  display: inline-flex;
  align-items: center;
  font: 700 10px/1 var(--f-mono);
  letter-spacing: .06em;
  color: var(--ac);
  background: var(--ac-a14);
  border: var(--bw-hair) solid var(--ac-a24);
  border-radius: var(--r-1);
  padding: 3px 6px;
  text-transform: uppercase;
  white-space: nowrap;
  flex: 0 0 auto;
}
.cmd-badge--lg { font-size: 12px; padding: 4px 8px; }
button.cmd-badge,
a.cmd-badge { cursor: pointer; transition: background var(--dur-1) var(--ease); }
button.cmd-badge:hover,
a.cmd-badge:hover { background: var(--ac-a24); color: var(--ac-bri); }

.kbd {
  display: inline-flex;
  align-items: center;
  font: var(--ti-micro);
  letter-spacing: .04em;
  color: var(--t-200);
  background: var(--s-300);
  border: var(--bw-hair) solid var(--ln-400);
  border-radius: var(--r-1);
  padding: 1px 5px;
  box-shadow: inset 0 -1px 0 0 rgba(0, 0, 0, .5);
  white-space: nowrap;
}


/* ===========================================================================
   5. BUTTONS  (spec s7.7)
   :active { transform: translateY(.5px) } is the ONLY transform on a button,
   and it is half a pixel. No springs, no scale, no overshoot.
   =========================================================================== */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  height: 26px;
  padding: 0 var(--sp-3);
  font: 700 11px/1 var(--f-mono);
  letter-spacing: .06em;
  text-transform: uppercase;
  border: 0;
  border-radius: var(--r-0);
  cursor: pointer;
  white-space: nowrap;
  user-select: none;
  transition:
    background var(--dur-1) var(--ease),
    color var(--dur-1) var(--ease),
    box-shadow var(--dur-2) var(--ease);
}
.btn:active { transform: translateY(.5px); }
.btn[disabled],
.btn[aria-disabled="true"] {
  cursor: not-allowed;
  opacity: .5;
  pointer-events: none;
}

.btn--primary { background: var(--ac); color: var(--on-ac); }
.btn--primary:hover { background: var(--ac-bri); }
.btn--primary:active { background: var(--ac-deep); }

.btn--secondary {
  background: var(--s-300);
  color: var(--t-100);
  box-shadow: var(--sh-btn-secondary);
}
.btn--secondary:hover { background: var(--s-400); }

.btn--ghost { background: transparent; color: var(--t-200); }
.btn--ghost:hover { background: var(--s-300); color: var(--t-100); }

.btn--danger {
  background: transparent;
  color: var(--down);
  box-shadow: inset 0 0 0 1px var(--down-a45);
}
.btn--danger:hover { background: var(--down); color: var(--on-ac); box-shadow: none; }

/* MARKETING variants — same colours, pill geometry, sans, larger targets.    */
.btn--mkt {
  height: 44px;
  padding: 0 26px;
  font: 600 15px/1 var(--f-sans);
  font-variation-settings: "wght" 600, "wdth" 100;
  letter-spacing: 0;
  text-transform: none;
  border-radius: var(--r-pill);
}
.btn--mkt.btn--secondary { backdrop-filter: blur(4px); }


/* ===========================================================================
   6. INPUTS + FORM CONTROLS  (spec s7.8)
   An input is a WELL: recessed into the housing, --s-void ground, --r-0.
   =========================================================================== */
.input,
.textarea,
.select {
  width: 100%;
  height: 28px;
  background: var(--s-void);
  color: var(--t-100);
  font: 400 12px/28px var(--f-mono);
  font-variant-numeric: tabular-nums;
  padding: 0 10px;
  border: 0;
  border-radius: var(--r-0);
  box-shadow: inset 0 0 0 1px var(--ln-400), inset 0 1px 0 0 rgba(0, 0, 0, .5);
  transition: box-shadow var(--dur-2) var(--ease);
}
.textarea { height: auto; min-height: 72px; line-height: 18px; padding: 8px 10px; resize: vertical; }

/* THE SELECT MUST NOT RENDER THE NATIVE OS CONTROL. Without `appearance: none`
   a <select> keeps the platform button and chevron, which on macOS is a
   rounded, light-grey, system-blue-on-focus widget — the single consumer
   artifact on a page whose whole argument is squareness and instrumentation.
   The chevron below is an inline data URI (no request, no CDN) in --t-300.   */
.select {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 28px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='9' height='6' viewBox='0 0 9 6'%3E%3Cpath d='M.6.9 4.5 4.8 8.4.9' fill='none' stroke='%238B867E' stroke-width='1.2'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 10px center;
  cursor: pointer;
}
.select:hover {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='9' height='6' viewBox='0 0 9 6'%3E%3Cpath d='M.6.9 4.5 4.8 8.4.9' fill='none' stroke='%23B5B1AA' stroke-width='1.2'/%3E%3C/svg%3E");
}
/* The option list itself is drawn by the OS and cannot be styled; forcing the
   colours here is what stops it rendering as white-on-white in dark mode.    */
.select option { background: var(--s-200); color: var(--t-100); }
.input::placeholder,
.textarea::placeholder { color: var(--t-400); }
.input:focus,
.textarea:focus,
.select:focus {
  outline: none;
  box-shadow: inset 0 0 0 1px var(--ac-a40), inset 0 -2px 0 0 var(--ac);
}
.input[aria-invalid="true"],
.textarea[aria-invalid="true"] {
  box-shadow: inset 0 0 0 1px var(--down-a45), inset 0 -2px 0 0 var(--down);
}
.input[disabled],
.textarea[disabled],
.select[disabled] { color: var(--t-400); cursor: not-allowed; }

/* Marketing inputs get the 6px radius and nothing else different.            */
.input--mkt { height: 44px; line-height: 44px; border-radius: var(--r-3); font-size: 14px; }

.field { display: block; }
.field > .label {
  display: block;
  font: var(--ti-nano);
  letter-spacing: var(--ti-nano-track);
  text-transform: uppercase;
  color: var(--t-300);
  margin-bottom: var(--sp-1);
}
.field > .hint { display: block; font: var(--ti-micro); color: var(--t-300); margin-top: var(--sp-1); }
.field > .error { display: block; font: var(--ti-micro); color: var(--down); margin-top: var(--sp-1); }


/* ===========================================================================
   7. TABS  (spec s7.9)
   24px tall. The active marker is a 2px amber underline that SLIDES. Godel's
   is a static 1px; the slide is ours. ONE amber underline per panel, maximum:
   secondary groups (Quarterly/Yearly) use --ln-400 instead.
   =========================================================================== */
.tabs {
  position: relative;
  display: flex;
  align-items: stretch;
  gap: var(--sp-4);
  height: var(--panel-tabs-h);
  padding: 0 var(--sp-2);
  background: var(--s-100);
  box-shadow: inset 0 -1px 0 0 var(--ln-200);
  font: var(--ti-xs);
  user-select: none;
}
.tab {
  display: inline-flex;
  align-items: center;
  color: var(--t-300);
  cursor: pointer;
  white-space: nowrap;
  background: none;
  transition: color var(--dur-1) var(--ease);
}
.tab:hover { color: var(--t-200); }
.tab[aria-selected="true"] { color: var(--t-100); }

/* The slider is one element positioned by JS — width + translateX only.      */
.tabs-marker {
  position: absolute;
  left: 0; bottom: 0;
  height: 2px;
  width: var(--tab-w, 0);
  background: var(--ac);
  transform: translateX(var(--tab-x, 0));
  transition:
    transform var(--dur-2) var(--ease),
    width var(--dur-2) var(--ease);
  pointer-events: none;
}
.tabs--secondary .tabs-marker { background: var(--ln-400); }
.tabs--secondary .tab[aria-selected="true"] { color: var(--t-200); }


/* ===========================================================================
   8. BADGES / PILLS / STATUS CHIPS  (spec s8.5)
   NO PULSING DOT. A pulsing dot is a consumer tic; the status chip is static.
   =========================================================================== */
.pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font: var(--ti-micro);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--t-200);
  background: var(--s-200);
  border: var(--bw-hair) solid var(--ln-300);
  border-radius: var(--r-pill);
  padding: 4px 10px;
  white-space: nowrap;
}
.pill::before {
  content: "";
  width: 5px; height: 5px;
  border-radius: var(--r-pill);
  background: var(--t-400);
}
.pill[data-kind="up"]::before   { background: var(--up); }
.pill[data-kind="warn"]::before { background: var(--warn); }
.pill[data-kind="down"]::before { background: var(--down); }
.pill[data-kind="info"]::before { background: var(--info); }
.pill[data-kind="ac"]::before   { background: var(--ac); }
.pill--bare::before { display: none; }

/* Square badge for in-table state. --r-0 because it lives on the data plane. */
.badge {
  display: inline-flex;
  align-items: center;
  font: var(--ti-micro);
  letter-spacing: .08em;
  text-transform: uppercase;
  padding: 2px 5px;
  border-radius: var(--r-0);
  border: var(--bw-hair) solid var(--ln-300);
  color: var(--t-200);
}
.badge[data-kind="up"]    { color: var(--up);   border-color: var(--up-a45);   background: var(--up-a10); }
.badge[data-kind="down"]  { color: var(--down); border-color: var(--down-a45); background: var(--down-a10); }
.badge[data-kind="warn"]  { color: var(--warn); border-color: var(--warn-a45); background: var(--warn-a10); }
.badge[data-kind="info"]  { color: var(--info); border-color: var(--info-a45); background: var(--info-a10); }

/* The SNAPSHOT-MODE badge is a product requirement, not a design suggestion:
   it is NON-DISMISSIBLE and must survive dismissing everything dismissible.  */
.badge--snapshot {
  color: var(--warn);
  border-color: var(--warn-a45);
  background: var(--warn-a10);
  font-weight: 700;
}


/* ===========================================================================
   9. TOASTS  (spec s7.10)
   AUTO-DISMISS ONLY FOR info / up. warn and down/err PERSIST until dismissed
   — a fail-closed product does not let a failure notice time out.
   =========================================================================== */
.toast-stack {
  position: fixed;
  right: var(--sp-3);
  bottom: var(--sp-3);
  z-index: var(--z-toast);
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  pointer-events: none;
}
.toast {
  pointer-events: auto;
  min-width: 280px;
  max-width: 420px;
  padding: var(--sp-2) var(--sp-3);
  background: var(--s-200);
  border-radius: var(--r-2);
  box-shadow: var(--sh-raised), inset 3px 0 0 0 var(--toast-edge, var(--ac));
  backdrop-filter: var(--blur-overlay);
  animation: toast-in var(--dur-3) var(--ease) 1;
}
.toast[data-kind="up"]    { --toast-edge: var(--up); }
.toast[data-kind="down"],
.toast[data-kind="err"]   { --toast-edge: var(--down); }
.toast[data-kind="warn"]  { --toast-edge: var(--warn); }
.toast[data-kind="info"]  { --toast-edge: var(--info); }
.toast .t-title { font: var(--ti-sm); font-weight: 600; color: var(--t-100); }
.toast .t-body  { font: var(--ti-xs); color: var(--t-200); margin-top: 2px; }
.toast .t-time  { font: var(--ti-micro); letter-spacing: .05em; color: var(--t-300); margin-top: 4px; }
.toast.is-out { animation: toast-out var(--dur-2) var(--ease) 1 forwards; }

@keyframes toast-in  { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
@keyframes toast-out { from { opacity: 1; } to { opacity: 0; } }


/* ===========================================================================
   10. MODALS  (spec s7.11)
   A confirm-gated destructive / order-staging dialog restates the EXACT
   action string in mono and disables its confirm button for 600ms after open.
   =========================================================================== */
.modal-scrim {
  position: fixed;
  inset: 0;
  z-index: var(--z-scrim);
  background: var(--scrim);
  backdrop-filter: var(--blur-scrim);
  animation: fade-in var(--dur-3) var(--ease) 1;
}
.modal {
  position: fixed;
  z-index: var(--z-modal);
  left: 50%; top: 12vh;
  transform: translateX(-50%);
  width: min(560px, calc(100vw - 2 * var(--sp-4)));
  max-height: 76vh;
  overflow: auto;
  background: var(--s-200);
  border-radius: var(--r-2);
  box-shadow: var(--sh-raised);
  animation: modal-in var(--dur-3) var(--ease) 1;
}
.modal-head {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  height: var(--panel-title-h);
  padding: 0 var(--sp-3);
  background: var(--g-chrome);
  box-shadow: inset 0 -1px 0 0 var(--ln-200);
  font: var(--ti-md);
  font-weight: 500;
  letter-spacing: .06em;
  color: var(--t-100);
}
.modal-body { padding: var(--sp-4); }
.modal-foot {
  display: flex;
  justify-content: flex-end;
  gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-4) var(--sp-4);
}
/* The restated action string. Mono, --t-100, never paraphrased.              */
.modal-action {
  font: var(--ti-md);
  color: var(--t-100);
  background: var(--s-void);
  box-shadow: var(--sh-well);
  padding: var(--sp-2) var(--sp-3);
  margin-bottom: var(--sp-3);
}

@keyframes fade-in  { from { opacity: 0; } to { opacity: 1; } }
@keyframes modal-in { from { opacity: 0; transform: translateX(-50%) scale(.985); }
                      to   { opacity: 1; transform: translateX(-50%) scale(1); } }


/* ===========================================================================
   11. EMPTY STATES  (spec s7.12)
   Never an illustration. Never "Nothing here yet!". Three lines in mono,
   left-aligned, and THE COMMAND THAT FILLS IT as real .cmd-badge elements.
   =========================================================================== */
.empty {
  padding: var(--sp-4);
  font: var(--ti-sm);
  color: var(--t-300);
  text-align: left;
  background: var(--s-void);
}
.empty .e-title {
  font: var(--ti-nano);
  letter-spacing: var(--ti-nano-track);
  text-transform: uppercase;
  color: var(--t-200);
  margin-bottom: var(--sp-1);
}
.empty .e-body { color: var(--t-300); }
.empty .e-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-4);
  margin-top: var(--sp-3);
  align-items: center;
}
.empty .e-actions .lbl { color: var(--t-300); font-size: var(--ti-xs-size); }


/* ===========================================================================
   12. LOADING  (spec s7.13)
   SKELETONS ARE BANNED ON NUMERIC SURFACES. A shimmering rectangle where a
   price will be is a claim that a price is arriving. It may not arrive.
   Fail-closed forbids it.
     numeric cell  -> static em-dash placeholder + a PENDING prov chip
     whole panel   -> a 2px indeterminate bar at the titlebar's top edge
     prose block   -> a genuine skeleton; prose has no truth value to protect
     copilot       -> a 1-char block cursor; no per-token fade-in
   NO SPINNERS ANYWHERE. A spinner communicates "something is happening" with
   zero information.
   =========================================================================== */
.pending-value {
  color: var(--t-ghost);
  font-variant-numeric: tabular-nums;
  letter-spacing: .1em;
}

.panel-loading { position: relative; }
.panel-loading::after {
  content: "";
  position: absolute;
  left: 0; top: 0;
  height: 2px;
  width: 30%;
  background: var(--ac);
  animation: indet 1.1s var(--ease-lin) infinite;
}
@keyframes indet {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(400%); }
}

/* Prose only. Never over a number.                                           */
.skeleton {
  background: linear-gradient(90deg, var(--s-300) 0%, var(--s-400) 50%, var(--s-300) 100%);
  background-size: 200% 100%;
  animation: sweep 1.4s var(--ease-lin) infinite;
  border-radius: var(--r-1);
  height: 12px;
}
.skeleton + .skeleton { margin-top: var(--sp-2); }
.skeleton--line-2 { width: 88%; }
.skeleton--line-3 { width: 64%; }
@keyframes sweep { from { background-position: 200% 0; } to { background-position: -200% 0; } }

/* The copilot stream cursor. One char, no fade.                              */
.stream-caret {
  display: inline-block;
  width: .55em;
  height: 1.05em;
  vertical-align: text-bottom;
  background: var(--ac);
}


/* ===========================================================================
   13. ERROR STATES  (spec s7.14)
   Three tiers, all mono, all NAMING THE FAILING THING.
   Never a generic "Something went wrong." Never a fallback value. Never a
   stale value presented as fresh — that is what --stale-opacity is for.
   =========================================================================== */

/* Tier 1 — cell level. The rest of the row still renders.                    */
.cell-error { color: var(--down); }
.cell-error::before { content: "\2A2F"; }

/* Tier 2 — panel level. The data well is REPLACED, not overlaid.             */
.win.has-error { box-shadow: var(--sh-panel), inset 2px 0 0 0 var(--down); }
.panel-error {
  padding: var(--sp-4);
  background: var(--s-void);
  font: var(--ti-sm);
  color: var(--t-200);
  text-align: left;
}
.panel-error .pe-title {
  font: var(--ti-nano);
  letter-spacing: var(--ti-nano-track);
  text-transform: uppercase;
  color: var(--down);
  margin-bottom: var(--sp-1);
}
.panel-error .pe-reason { color: var(--t-200); }
.panel-error .pe-actions { display: flex; gap: var(--sp-2); margin-top: var(--sp-3); }

/* Tier 3 — global. A 22px band under the cmdbar naming the degraded provider
   and the affected window codes.                                             */
.global-error {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  height: 22px;
  padding: 0 var(--sp-3);
  background: var(--warn-a10);
  box-shadow: inset 0 -1px 0 0 var(--warn-a45);
  font: var(--ti-xs);
  color: var(--warn);
  white-space: nowrap;
  overflow-x: auto;
}
.global-error[data-kind="down"] {
  background: var(--down-a10);
  box-shadow: inset 0 -1px 0 0 var(--down-a45);
  color: var(--down);
}


/* ===========================================================================
   14. MARKETING CARDS + SHARED SITE CHROME  (spec s8.5, s5.7)
   <=10px radius, pills for CTAs only. The card lighting is Godel's recipe
   retuned to amber and our surfaces.
   =========================================================================== */
.card {
  background: var(--g-card);
  border: var(--bw-hair) solid var(--ln-200);
  border-radius: var(--r-4);
  padding: var(--sp-6);
}
.card--pos { background: var(--g-card-pos); }
.card--featured { box-shadow: inset 0 0 0 1px var(--ac-a24); }
.card .c-title {
  font-family: var(--f-display);
  font-size: var(--td-4-size);
  font-variation-settings: "wght" var(--td-4-wght), "wdth" var(--td-4-wdth);
  letter-spacing: var(--td-4-track);
  line-height: var(--td-4-lh);
  color: var(--t-100);
}
.card .c-body {
  font-family: var(--f-sans);
  font-variation-settings: "wght" 400, "wdth" 100;
  font-size: var(--td-small-size);
  line-height: var(--td-small-lh);
  color: var(--t-200);
  margin-top: var(--sp-2);
}

.topbar {
  position: sticky;
  top: 0;
  z-index: var(--z-chrome);
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  height: var(--topbar-h);
  background: transparent;
  transition: background var(--dur-2) var(--ease), box-shadow var(--dur-2) var(--ease);
}
html[data-scrolled] .topbar {
  background: color-mix(in srgb, var(--s-000) 92%, transparent);
  backdrop-filter: var(--blur-overlay);
  box-shadow: inset 0 -1px 0 0 var(--ln-200);
}
.wordmark {
  font: 800 15px/1 var(--f-mono);
  letter-spacing: .14em;
  color: var(--ac);
  text-transform: uppercase;
  /* The wordmark is a link to /, so it is a pointer target: 15px of line-box
     is 9px under the SC 2.5.8 floor.                                         */
  display: inline-flex;
  align-items: center;
  min-height: 24px;
}
/* --t-300, not --t-400. tokens.css documents --t-400 as NON-TEXT ONLY and it
   measures 3.73:1 here; a logotype is WCAG-exempt but the design system may not
   contradict its own hard rule in its most-repeated element. --t-300 is 5.14:1
   on the topbar surface and still reads as a demoted suffix.                  */
.wordmark .tld { color: var(--t-300); }
.topbar nav {
  display: flex;
  /* center, not the flex default `stretch`: the aria-current underline is 4px
     tall, and under `stretch` it grew EVERY nav link on pages that have a
     current-page link (measured 22px) while pages without one stayed at 18px.
     The topbar's row height must not depend on which page you are reading.   */
  align-items: center;
  gap: var(--sp-5);
  font-family: var(--f-sans);
  font-variation-settings: "wght" 400, "wdth" 100;
  font-size: 14px;
}
/* WCAG 2.2 SC 2.5.8 — nav links are standalone targets, not inline prose, so
   the 24px minimum applies. 14px text needs the box grown deliberately.      */
.topbar nav a { color: var(--t-200); display: inline-flex; align-items: center; min-height: 24px; }
.topbar nav a:hover { color: var(--t-100); text-decoration: none; }

.site-footer {
  font: var(--ti-xs);
  color: var(--t-300);
  padding: var(--sp-10) 0;
  box-shadow: inset 0 1px 0 0 var(--ln-200);
}

/* The receipt strip — stats in a 1px rule, each linking to the command or
   file that regenerates it. Values are build-time injected, never typed.     */
.receipt {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-6);
  padding: var(--sp-4) var(--sp-6);
  border: var(--bw-hair) solid var(--ln-200);
  border-radius: var(--r-0);
  background: var(--s-100);
}
.receipt .r-item { display: flex; flex-direction: column; gap: 2px; }
.receipt .r-val { font: var(--ti-xl); color: var(--t-100); font-variant-numeric: tabular-nums; }
.receipt .r-lbl {
  font: var(--ti-micro);
  letter-spacing: var(--ti-micro-track);
  text-transform: uppercase;
  color: var(--t-300);
}


/* ===========================================================================
   15. COMMAND PALETTE + HINT BAR  (spec s7.4, s7.5)
   FAIL-CLOSED DETAIL NOBODY SHIPS: if the typed string matches nothing, the
   typed-progress underline turns --down and the empty state says so. It never
   guesses and never fuzzy-runs the nearest thing.
   =========================================================================== */
.palette-overlay {
  position: fixed;
  inset: 0;
  z-index: var(--z-palette);
  display: flex;
  justify-content: center;
  padding-top: calc(var(--cmdbar-h) + var(--sp-3));
}
.palette {
  width: min(680px, calc(100vw - 2 * var(--sp-4)));
  max-height: 62vh;
  overflow: auto;
  background: color-mix(in srgb, var(--s-200) 88%, transparent);
  backdrop-filter: var(--blur-overlay);
  border-radius: var(--r-2);
  box-shadow: var(--sh-raised);
  animation: palette-in var(--dur-3) var(--ease-in) 1;
}
@keyframes palette-in { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }

.palette-input {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-4) var(--sp-2);
}
.palette-input .prompt { color: var(--ac); font: var(--ti-3xl); font-weight: 600; }
.palette-input .typed {
  font: var(--ti-3xl);
  font-weight: 600;
  letter-spacing: var(--ti-3xl-track);
  color: var(--t-100);
}
/* A solid block caret. No blink at 32px — blink only when idle > 2s (JS adds
   .is-idle), because a blinking caret that size is noise.                    */
.palette-input .caret {
  display: inline-block;
  width: .55em;
  height: 1.05em;
  background: var(--ac);
  vertical-align: text-bottom;
}
.palette-input .caret.is-idle { animation: blink 1.06s steps(1, end) infinite; }
@keyframes blink { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0; } }

/* TYPED-PROGRESS UNDERLINE. Godel's is decorative at a fixed ~46%; ours is
   INFORMATIONAL — width = matchedPrefixLen / bestMatchLen, set by JS.        */
.palette-progress {
  height: 2px;
  width: var(--match-pct, 0%);
  margin: 0 var(--sp-4) var(--sp-2);
  background: var(--ac);
  transition: width var(--dur-1) var(--ease);
}
.palette.is-nomatch .palette-progress { width: 100%; background: var(--down); }

.palette-section {
  height: 20px;
  display: flex;
  align-items: center;
  padding: 0 var(--sp-4);
  background: var(--s-150);
  font: var(--ti-nano);
  letter-spacing: var(--ti-nano-track);
  text-transform: uppercase;
  color: var(--t-300);
}
.palette-row {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  height: 32px;
  padding: 0 var(--sp-4);
  font: var(--ti-sm);
  color: var(--t-100);
  cursor: pointer;
}
.palette-row .desc { color: var(--t-300); margin-left: var(--sp-2); }
.palette-row .kbd { margin-left: auto; }
.palette-row[aria-selected="true"] { background: var(--s-300); }
.palette-row[aria-selected="true"] .desc { color: var(--t-200); }
.palette-empty {
  padding: var(--sp-4);
  font: var(--ti-sm);
  color: var(--t-200);
}
.palette-empty .q { color: var(--down); }

/* THE PERMANENT HINT BAR. Godel spends 24px on a permanent keyboard hint and
   it converts the whole product. Ours fades to .dimmed after the third
   successful command and restores on 90s idle or on "?".                     */
.hintbar {
  display: flex;
  align-items: center;
  gap: var(--sp-1);
  height: var(--hintbar-h);
  padding: 0 var(--sp-3);
  background: var(--s-150);
  box-shadow: inset 0 -1px 0 0 var(--ln-200);
  font: 500 11px/var(--hintbar-h) var(--f-mono);
  color: var(--t-300);
  white-space: nowrap;
  min-width: 0;          /* same min-content trap as the tape -- clip, never widen */
  overflow: hidden;
}
.hintbar .p { color: var(--ac); font-weight: 700; }
.hintbar b { color: var(--t-200); font-weight: 600; }
.hintbar.dimmed { opacity: .42; transition: opacity var(--dur-3) var(--ease); }

.cmdbar {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  height: var(--cmdbar-h);
  padding: 0 var(--sp-3);
  background: var(--g-chrome);
  box-shadow: inset 0 -1px 0 0 var(--ln-200);
}
.cmdbar .prompt { color: var(--ac); font: 700 12px/1 var(--f-mono); }
.cmdbar input {
  flex: 1 1 auto;
  height: 100%;
  background: transparent;
  border: 0;
  box-shadow: none;
  color: var(--t-100);
  font: 400 12px/var(--cmdbar-h) var(--f-mono);
  caret-color: var(--ac);
  padding: 0;
}
.cmdbar input:focus { outline: none; box-shadow: none; }


/* ===========================================================================
   16. RIGHT RAIL + TAPE + CHART FRAME  (spec s7.16, s7.3)
   The rail is the single highest-value element in any marketing screenshot —
   it is what makes a frame instantly legible as "markets".
   =========================================================================== */
.rail {
  width: var(--rail-w);
  flex: 0 0 var(--rail-w);
  background: var(--s-100);
  overflow-y: auto;
}
.rail-tile {
  height: var(--rail-tile-h);
  padding: var(--sp-2) var(--sp-3);
  box-shadow: inset 0 -1px 0 0 var(--ln-200);
}
.rail-tile .lbl {
  font: var(--ti-nano);
  letter-spacing: var(--ti-nano-track);
  text-transform: uppercase;
  color: var(--t-300);
}
.rail-tile .px {
  font: var(--ti-2xl);
  font-weight: var(--ti-2xl-wt);
  letter-spacing: var(--ti-2xl-track);
  color: var(--t-100);
  font-variant-numeric: tabular-nums;
}
.rail-tile .delta { font: var(--ti-xs); font-variant-numeric: tabular-nums; }
.rail-tile .spark { border-bottom: var(--bw-hair) solid var(--ln-100); }

/* The track is ABSOLUTELY POSITIONED, and that is load-bearing, not styling.
   A `white-space: nowrap` marquee in normal flow contributes its full content
   width to its ancestors' min-content size. `overflow: hidden` on .tape does
   NOT stop that: the automatic minimum size of a flex item only collapses to
   zero when the FLEX ITEM ITSELF has a non-visible overflow, and the tape is
   usually a grandchild. The result is a tape that silently forces a flex or
   grid track ~1100px wide and blows the whole page out horizontally on
   mobile. Taking the track out of flow makes .tape's min-content zero, so it
   fills its track and clips, which is what a tape is supposed to do.        */
.tape {
  position: relative;
  height: 22px;
  min-width: 0;
  overflow: hidden;
  background: var(--s-150);
  box-shadow: inset 0 -1px 0 0 var(--ln-200);
  -webkit-mask-image: var(--m-fade-x);
  mask-image: var(--m-fade-x);
}
.tape-track {
  position: absolute;
  inset: 0 auto 0 0;
  display: flex;
  gap: var(--sp-6);
  align-items: center;
  height: 100%;
  white-space: nowrap;
  font: var(--ti-xs);
  color: var(--t-200);
  animation: tape 90s var(--ease-lin) infinite;
  will-change: transform;
}
@keyframes tape { from { transform: translateX(0); } to { transform: translateX(-50%); } }

/* CHART FRAME. Canvas is --s-void and the plot area bleeds to the panel ring
   — no internal margin box. The chart carries its OWN provenance strip: a
   16px bottom rail. Not a tooltip. Not a footnote.                           */
.chart {
  position: relative;
  min-width: 0;
  background: var(--s-void);
  border-radius: var(--r-0);
}
/* Same min-content trap as the tape: a nowrap strip must not be able to widen
   the panel it documents. It clips instead.                                 */
.chart-prov {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  height: 16px;
  min-width: 0;
  padding: 0 var(--sp-2);
  background: var(--s-150);
  font: var(--ti-micro);
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--t-300);
  white-space: nowrap;
  overflow: hidden;
}
.chart-crosshair { stroke: var(--t-300); stroke-width: 1; stroke-dasharray: 2 3; }
.chart-grid { stroke: var(--ln-100); stroke-width: 1; }
.chart-axis { stroke: var(--ln-300); stroke-width: 1; }
.chart-tick { font: var(--ti-micro); fill: var(--t-300); }
