/* Market Making Simulation — participant app styles.
 *
 * The sign-in screen is the console login screen, one design across every
 * app in this service. This app does not load console.css, so the blocks
 * are carried here the way portfolio-sim.css carries them for the
 * portfolio participant app: copied verbatim from that copy, tokens and
 * comments included. */

/* A narrower sidebar than the platform's 340px, so the book, the tickets
   and the chart get the width back (owner, 2026-08-25). This page is the
   only one that loads this file, and the rule is :root rather than a
   workspace selector so the header lockup, which is sized off the same
   variable, stays aligned with the sidebar's edge.

   What sets the floor: 16px of padding each side, and the longest
   label-and-value pair in the readings, which is Electronic market fills
   against its count. Narrower than this and that row is what breaks
   first, so the way to go further is to shorten the label rather than to
   keep cutting the width. */
/* Native controls follow the app's own theme, never the OS's. The theme
   toggle drives [data-theme]; without a root color-scheme the browser
   resolves the page's "dark light" meta against the OS preference, and a
   dark-OS machine drew dark checkboxes on the light theme (the street
   picker). The same pair portfolio-sim.css and console.css carry; this
   file was the one that never did. */
:root { color-scheme: dark; }
[data-theme="light"] { color-scheme: light; }

/* .num means a number, everywhere on this page (owner, 2026-08-25).
   components.css carries the same declaration but scoped to a data
   table's cells, so every .num outside a table silently read in the
   interface face and each region had to restate the rule. Regions that
   also want a weight or a colour still say so; they no longer have to
   say the face.

   Not on a th: the platform's own rule is values-only and leaves a
   numeric column's HEADER proportional, which is a text label. That
   copy is verbatim from the platform, so the rule lives here rather
   than being added to it. portfolio-sim.css and console.css want the
   same line whenever their surfaces are next opened. */
.num:not(th) {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

/* The platform's table wrap rounds its corners (components.css
   .data-table-wrap, --r-lg); square here, the way portfolio-sim.css
   squares them for the portfolio desk (owner, 2026-08-26). The border
   stays: a table inside a padded card still needs its edge. Unscoped
   because only this page loads this file, so it reaches the Session Info
   dialog as well, which mounts on the body rather than in the
   workspace. */
.data-table-wrap { border-radius: 0; }

/* NO COLOURED BAR DOWN THE LEFT EDGE of a hovered row, anywhere on this
   page (owner, 2026-09-12). The platform paints one as a 2px inset
   shadow on the first cell of every hovered .data-table row, in two
   rules, one per theme; both are named here because the light one is
   the more specific of the two and a single selector left the bar on
   the theme it is read on. Everything after the first cell is already
   cleared by the platform's own rule beside those two. Same reason as
   the wrap above: that copy is verbatim from the platform, so the rule
   lives here rather than being added to it. */
.data-table tbody tr:hover td:first-child,
[data-theme="light"] .data-table tbody tr:hover td:first-child {
  box-shadow: none;
}

:root {
  --sidebar-width: 260px;
  /* The tint that marks the reader's own row in the debrief ranking.
     One value per theme, because the accent is the same colour on both
     and 15% of it over the light page reads as a block of blue. */
  --mkm-tint: color-mix(in srgb, var(--color-accent) 15%, transparent);
}
[data-theme="light"] {
  --mkm-tint: color-mix(in srgb, var(--color-accent) 9%, transparent);
}

/* ── The eyebrow ────────────────────────────────────────────────────
   ONE LABEL TREATMENT FOR THE WHOLE SIMULATION: the desk's panel
   headings, the sign-in field labels, the class over a participant's
   name in the waiting room, the Sessions page's section headings and
   its state word, the day headings over the sessions log, and in the
   end report the block headings, the column headings and the weight
   under a score column's name. Declared once here, so the surfaces
   cannot drift apart (owner, 2026-09-10). It had been written eight
   times at three sizes, three letter-spacings and two weights.

   The markup wears .mkm-eyebrow wherever it can; the rest are named
   here because their elements carry a class of their own or are a
   table's own th. Layout stays with whatever carries it; this is type
   and ink only. The end report reads its BLOCK headings one step
   larger, which is the one size step in the block further down; its
   column headings stay at this size, so a column heading here and a
   column heading on the trainer's console are the same thing.

   THE VALUES ARE THE CONSOLE'S, to the declaration (console.css, the
   .data-table th rule): 11px, 700, 0.1em, uppercase, muted. The owner
   asked on 2026-09-13 for the participant debrief's column headings to
   read at the weight the trainer dashboard uses. They were already 700;
   what set them apart was the size, a 0.12em tracking against the
   console's 0.1em, and the report's own size step reaching the column
   headings as well as the block headings. */
.mkm-eyebrow,
.mkm-state,
.mkm-log-day,
.mkm-th-weight,
.mkm-attrib-heading,
.mkm-end-inner .data-table thead th {
    font-family: var(--font);
    font-size: 11px;
    font-weight: 700;
    line-height: 1.2;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-muted);
}

/* ── The plain button ───────────────────────────────────────────────
   A row or a heading that has to be reachable from the keyboard is a
   button, which means undoing what a button looks like before the
   surface's own layout goes on it. Three surfaces share the reset: the
   way back out of a debrief, a row in the sessions log, and a fold head
   in the end report. Each states its own padding, border, colour and
   layout after this. */
.mkm-back,
.mkm-log-row,
.mkm-end-fold {
  border: 0;
  background: none;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
/* The chevron: at the end of a log row, and turned around on the way
   back out of a debrief. It takes the accent when the pointer is on the
   row, so the whole row reads as the target. */
.mkm-back-go,
.mkm-log-go {
  color: var(--text-muted);
  font-size: 1.2rem;
  line-height: 1;
}
.mkm-back:hover .mkm-back-go,
.mkm-log-row:hover .mkm-log-go { color: var(--color-accent); }

/* ── A tipped label ────────────────────────────────────────────────
   The shared JS tooltip answers over anything carrying data-tip
   (wireTooltips); this is the affordance for it, once, on the two
   surfaces where every data-tip is on a label: the sidebar and the end
   report. Not page-wide, because the order book rows, the depth grip
   and the draggable seams carry a data-tip too and each already shows
   the cursor its own action needs. */
.params-sidebar [data-tip],
.mkm-end-inner [data-tip] { cursor: help; }

/* The header lockup sits in a column exactly as wide as the gutter plus
   the sidebar, so that the tab nav beside it starts where the desk
   content starts. Narrowing the sidebar narrowed that column too, and
   "Market Making Simulation" no longer fitted on one line at the
   platform's 22px: it broke after "Making" and the lockup read over
   three rows (owner, 2026-08-25).

   The name is sized down rather than the column widened, because the
   column's own width is what keeps the tab nav aligned with the desk,
   and its padding-left is what puts the lockup bar on the workspace
   divider. Both of those hold at any name size. The watermark stays at
   16px so the bar stays 4px wide and the alignment maths in
   components.css still describes what happens. */
.header-logo-mount .lockup-led { --led-name-size: 19px; }

/* ── The waiting room ───────────────────────────────────────────────
   The class over the participant's name, then a rule, then one line
   saying what they are waiting for (owner, 2026-09-10). The class used
   to stand in a tinted box of its own above the name, which read as two
   headings rather than as one person in one class. */
.mm-wait-class {
    text-align: center;
    margin-bottom: 10px;
}
/* Scoped to the card: the name also wears .join-title, which chrome.css
   declares after this file. */
.join-card .mm-wait-name {
    font-size: 26px;
    font-weight: 600;
    margin-bottom: 20px;
}
.mm-wait-line {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 9px;
    margin: 0 0 18px;
    padding-top: 18px;
    border-top: 1px solid var(--border);
    font-size: 14px;
    color: var(--text-muted);
}
.mm-wait-dot {
    flex: 0 0 auto;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--warning);
}

/* =====================================================================
   Trading desk (multiplayer port).
   Copied verbatim from the platform's css/market-making.css spot-desk
   styles (lines 1-985), plus the sharp terminal frame rules the spot
   skeleton shares with the options desk and the desktop-only notice.
   Left out with the features they style: the setup modal (the trainer
   configures the session), the fiction disclaimer that lived in it,
   the end screen's New session button, and the options desks.
   ===================================================================== */

/* The two header pages (owner, 2026-08-23): the Sessions page scrolls
   on its own while the desk keeps its own flex chain. The [hidden]
   guard beats the display rule, the mkm-grid pattern. */
#mm-sessions-host {
  flex: 1 1 0;
  min-height: 0;
  overflow-y: auto;
}
#mm-sessions-host[hidden] { display: none; }
/* The reading column, shared by the Sessions page and the end report.
   The end report used to take whatever the desk's frame gave it, so the
   two surfaces were named in one rule to stop them drifting apart
   (owner, 2026-08-26).

   Both fill from the left now (owner, 2026-09-05). The report was
   centred in a 1080px column, which left a gutter either side of it on a
   wide monitor and gave its pair of charts roughly half the width the
   desk they replace runs at. It went to the desk's own 1560px cap first
   and read too wide at it, so the column is a quarter narrower than that
   (owner, same day). The Sessions page had already been taken off the
   centred column for the same reading (owner, 2026-08-28), and its list
   keeps its own narrower cap below. */
.mkm-sessions,
#market-making-workspace .mkm-endscreen {
  max-width: 1170px;
  margin: 0;
  padding: 24px 20px 40px;
}
/* The list runs in a column of its own (owner, 2026-08-28). The page cap
   above is the debrief's, which opens into this same host and needs the
   width for its tables and its pair of charts; a live card and a log of
   short rows stretched to it read as mostly empty. */
.mkm-sessions-list { max-width: 820px; }
/* The type is the label treatment at the top of this file, which the
   markup carries; only the space belongs here. A heading sits 10px
   above its own section, the distance the end report reads at, and 28px
   below the section before it, which is the report's own column gap and
   is the clear break between the section a participant acts in and the
   one they only read (owner, 2026-08-26). The first heading needs no
   space above it: the page has its own padding. Scoped to the list, so
   the debrief that opens in this same host is not reached. */
.mkm-sessions-list h3 { margin: 0 0 10px; }
.mkm-sessions-list h3:not(:first-child) { margin-top: 28px; }
/* The live session's card. One row: what it is on the left, its state
   and the way in on the right. It carries the accent tint the platform
   puts on an accented badge, so the one thing on this page a participant
   can walk into reads as the way in rather than as another row (owner,
   2026-08-26).

   It states its own surface: a square accent edge, the accent tint the
   platform puts on an accented badge, and no padding of its own, since
   the row inside it carries the 16px the rest of the page reads at. The
   accent is the same colour on both themes, so one tint serves both.
   The markup still wears the shared .card, which is where the 20px it
   zeroes comes from; the two rules below are complete without that
   class and the last two declarations in the hover rule go with it. */
.mkm-session-live {
  padding: 0;
  border: 1px solid var(--color-accent);
  border-radius: 0;
  background: color-mix(in srgb, var(--color-accent) 10%, transparent);
  transition: background var(--transition);
}
.mkm-session-live .btn { border-radius: 0; }
/* Hover dims the blue and moves nothing else (owner, 2026-08-31). The
   shared .card:hover swaps the background for the plain surface, takes
   the accent border back to the ordinary one and raises a shadow, so
   this card washed from its own blue to near white and lost its edge on
   the way. Only the fill answers the pointer here; the solid accent
   border is what the card IS. The light-theme selector is named as well
   as the base one because the shared rule carries one. */
.mkm-session-live:hover,
[data-theme="light"] .mkm-session-live:hover {
  background: color-mix(in srgb, var(--color-accent) 16%, transparent);
  border-color: var(--color-accent);
  box-shadow: none;
}
.mkm-session-live-body {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 16px 18px;
}
.mkm-session-live-what { flex: 1 1 auto; min-width: 0; }
.mkm-session-live-name {
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--text);
}
/* Two lines under the instrument (owner, 2026-08-28): the session, then
   when it runs and for how long. */
.mkm-session-live-meta {
  margin-top: 3px;
  font-size: var(--text-meta);
  color: var(--text-muted);
}
/* The state reads as TEXT, not as a pill (owner, 2026-09-10): the word
   in the state's own colour, with no dot (owner, 2026-09-11). The colour
   comes from the state map in sessions.js, which is the badge
   component's own mapping unchanged; the .badge component itself is
   untouched, because other surfaces still read it.

   It never wraps. "Not started" broke over two lines as soon as the card
   came in from the page width.

   The type is the label treatment at the top of this file; only the
   layout belongs here. */
.mkm-state {
  display: inline-flex;
  align-items: center;
  flex: 0 0 auto;
  white-space: nowrap;
}
.mkm-session-debrief { margin-top: 14px; }

/* The way back out of a debrief. It reads like the row that opened it
   rather than like a form button (owner, 2026-08-28): the outlined ghost
   button sat at the top of a page of tables and charts and was the
   heaviest thing on it. Same quiet ink, same hover, same chevron
   turned around. */
.mkm-back {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 4px;
  padding: 7px 12px 7px 8px;
  border-radius: var(--r-md);
  /* The app's own size, where this read at 0.92rem (owner, 2026-09-13). */
  font-size: 16px;
  color: var(--text-secondary);
  transition: background var(--transition), color var(--transition);
}
.mkm-back:hover,
.mkm-back:focus-visible {
  background: var(--bg-elevated);
  color: var(--text);
}

/* ── The past sessions, as a log ────────────────────────────────────────
   A day heading over the sessions that ran on it, then one row each
   (owner, 2026-08-28). The table this replaced repeated the class name,
   the instrument and the length on every line, so a reader could pick
   out nothing but the timestamp, and it carried a button on every row.
   The row is the button now.

   The columns live on the list, not on the row, and each row takes them
   with `subgrid`. A row that sized its own columns would size them from
   its own content, and the times and scores would step in and out line
   by line.

   Every column is as wide as it reads and they pack to the left (owner,
   2026-08-28: too much white space). Giving the instrument the free
   width instead pushed everything after it to the far side of a
   1080px page, and a row that is three quarters empty reads as a table
   with nothing in it. Only the chevron takes the slack, so the row ends
   where the card above it ends. */
.mkm-log {
  display: grid;
  grid-template-columns: max-content max-content max-content 1fr;
  column-gap: 28px;
  border-top: 1px solid var(--border);
}
.mkm-log-day {
  grid-column: 1 / -1;
  /* Flush left, where the section heading above and the times below it
     start (owner, 2026-08-31). Only the right keeps an inset, so the
     chevron at the end of a row is not against the edge. */
  padding: 16px 10px 6px 0;
}
.mkm-log-day:first-child { padding-top: 10px; }
/* A row is a button so the keyboard reaches it, which means undoing what
   a button looks like before laying it on the columns. Every row carries
   the same padding, so the tracks stay aligned across all of them. */
.mkm-log-row {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: subgrid;
  align-items: baseline;
  width: 100%;
  padding: 11px 10px 11px 0;
  /* A hairline under every row, so the log reads as one bordered list
     rather than as a stack of separate rows (owner, 2026-09-10). Square,
     because the whole page is. */
  border-bottom: 1px solid var(--border);
  border-radius: 0;
  color: var(--text);
  transition: background var(--transition);
}
.mkm-log-row:hover,
.mkm-log-row:focus-visible {
  background: var(--bg-elevated);
}
.mkm-log-time { color: var(--text-secondary); }
.mkm-log-name { min-width: 0; }
/* The label is quiet and the number is not: the score is the one thing
   that differs between two sessions of the same instrument. It reads at
   the app's own 16px, where it had been 0.92rem, a size on no scale
   (owner, 2026-09-13). */
.mkm-log-score { color: var(--text-secondary); font-size: 16px; }
.mkm-log-score .num { color: var(--text); }
/* The way in, one per row instead of a button on each. It stands at the
   end of the row; its type and its hover are the shared chevron's. */
.mkm-log-go { justify-self: end; }

/* The class this record belongs to, at the top of the sidebar on the
   Sessions page. Same weight and rule as the instrument line the desk
   carries in that slot. */
#market-making-workspace .mkm-sb-class-name {
  margin: 0 0 8px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--border);
  font-size: var(--text-h4);
  font-weight: 600;
  color: var(--text-secondary);
}

/* The class record leads with its average, the way the desk's sidebar
   leads with the net position (owner, 2026-09-10). It was a list of
   equal-weight rows, and the number a participant came to read had no
   more weight than the count beside it. Mono is the numeral only; the
   words beside it are Inter. */
#market-making-workspace .mkm-record-lead {
  display: flex;
  align-items: baseline;
  gap: 8px;
  min-width: 0;
  padding: 4px 0 6px;
}
#market-making-workspace .mkm-record-mean {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 26px;
  font-weight: 700;
  line-height: 1.1;
  color: var(--text);
}
#market-making-workspace .mkm-record-of {
  font-family: var(--font);
  font-size: 14px;
  color: var(--text-muted);
}

/* What a hold is holding: the instrument over the time the session has
   left to run. */
/* What a pause is holding, under a hairline rather than in a box of its
   own (owner, 2026-09-10). The panel carries an icon, a title, a hint
   and this, and a filled card at the foot of four things read as a fifth
   thing rather than as the last line of the four. */
.mkm-hold-session {
  margin: 18px 0 0;
  padding-top: 14px;
  border-top: 1px solid var(--border);
}
.mkm-hold-instrument {
  font-size: 1rem;
  font-weight: 600;
  color: var(--text);
}
.mkm-hold-left {
  margin-top: 2px;
  font-size: var(--text-meta);
  color: var(--text-muted);
}

/* The desk fills the viewport under the header: the mount passes the
   app-wrapper's remaining height through to the workspace. */
#module-mount {
  flex: 1 1 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

/* =====================================================================
   EduMarkets — Market Making module
   Scoped to #market-making-workspace so nothing leaks into other modules.

   Layout contract (MM-DESIGN.md section 4): while a session is live the
   desk fills ONE viewport with no page scrolling; only the feed scrolls
   internally. The `mkm-desk-active` class on the workspace switches the
   platform's scrolling content area into a fixed fill-the-height layout;
   it is removed on the Reference tab and on the end screen, where normal
   scrolling returns.

   The order book visual is copied from the equities exchange pattern
   (.ex-ob-* in equities.css: depth bars via --depth-pct, user resting-order
   outline + tag), renamed to .mkm-ob-* and rearranged as a stacked book.
   ===================================================================== */

/* ── One-viewport mode ─────────────────────────────────────────────── */

#market-making-workspace.mkm-desk-active .workspace-content {
  overflow-y: hidden;
}
/* On the Sessions page the sidebar stays, and empties (owner,
   2026-08-26): every reading in it belongs to the session behind the
   page, and a desk's position and P&L beside a list of other sessions
   reads as though they were that list's. The chrome at the foot stays,
   so the column is still the page's left edge.

   Data Calendar and Shortcuts go with them (owner, 2026-09-10, from the
   browser): both open a reference for the session being traded, and
   neither belongs beside a list of other sessions. The row is what
   hides, not the two buttons, so the sidebar shows no empty strip where
   it stood. */
/* The desk's own debrief reads the same way (owner, 2026-09-11): once
   the end report is on the screen the session is over, so the live
   readings, the reference buttons and the floor sound come off there
   too and the class and record take the column. */
#market-making-workspace:is(.mkm-sessions-active, .mkm-debrief-active) .mkm-sb-top,
#market-making-workspace:is(.mkm-sessions-active, .mkm-debrief-active) #mkm-sb-live,
#market-making-workspace:is(.mkm-sessions-active, .mkm-debrief-active) .mkm-sb-btn-row,
#market-making-workspace:is(.mkm-sessions-active, .mkm-debrief-active) .mkm-floor {
  display: none;
}
/* The session slot is NOT in that list, and it is the one block that
   stays. What it holds belongs to whoever is running the session rather
   than to the session that has just ended: in a room of one the host page
   puts a way to open the next session there, and a debrief with no way
   out of it is a dead end. It is empty in a trainer-led room, so this
   reaches nothing there.

   What the column holds instead: the class and the participant's record
   across it (owner, 2026-08-28). It is in the sidebar on both pages and
   shown on one, which is the same shape as the readings above and needs
   nothing to clear it on the way out. */
#market-making-workspace #mkm-sb-class { display: none; }
#market-making-workspace:is(.mkm-sessions-active, .mkm-debrief-active) #mkm-sb-class {
  display: block;
}
/* The desk's surround matches the sidebar's surface, the portfolio desk's
   terminal-chrome rule (owner-approved there 2026-08-20, ported here on
   the owner's instruction 2026-08-22): with the panels tiled flat, the
   page ground framing the slab would read as a black border against the
   sidebar's grey. Painted on the scroll container so a monitor wider than
   the content cap does not show the ground beyond the cap. */
#market-making-workspace .workspace-content { background: var(--bg-surface); }
#market-making-workspace.mkm-desk-active .tab-panel.active {
  flex: 1 1 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
#market-making-workspace.mkm-desk-active .tab-content-area {
  flex: 1 1 0;
  min-height: 0;
  max-width: 1560px;   /* cap on wide monitors; the desk must stay dense */
  padding: 10px 16px 12px;
  display: flex;
  flex-direction: column;
}
/* The desk tab's content host is the flex column the .mkm-desk inside it
   stretches into (whichever engine mounted, spot or options). Without this the
   desk's grid collapses to zero height and the overflow:hidden left column clips
   away entirely. */
#market-making-workspace.mkm-desk-active #market-making-desk-content {
  flex: 1 1 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
#market-making-workspace .mkm-desk {
  flex: 1 1 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

/* ── Top of the sidebar: the instrument and the session clock on one row ─ */

/* Baseline, not centre: the instrument name and the clock are set at
   different sizes, and their baselines are what the eye reads as level. */
#market-making-workspace .mkm-sb-top {
  display: flex;
  flex-direction: column;
  /* Symmetric around the divider: 10px from the Apple/clock baseline down
     to the rule, and 10px from the rule down to the next block (owner,
     2026-08-30). */
  margin-bottom: 10px;
  padding-bottom: 10px;
  border-bottom: 3px solid var(--border);
}
/* The name and the clock sit on one baseline; the descriptive sub-line
   (owner, 2026-08-30) lands on its own row below, so it takes the full
   sidebar width and never has to compete with the clock for room. */
#market-making-workspace .mkm-sb-top-row {
  display: flex;
  align-items: baseline;
  gap: 8px;
}
#market-making-workspace .mkm-clock {
  margin-left: auto;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 1.1rem;
  font-weight: 700;
}

/* The disclaimer holds the foot of the sidebar. The content column fills
   the panel so the auto margin on the footer can push it all the way
   down whenever the readings above leave room; a sidebar taller than the
   panel scrolls and the footer follows the last reading. */
#market-making-workspace #market-making-params-content {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
}
/* The gap above it rides on the readings, not on the footer: an auto
   margin cannot also carry a minimum, and a sidebar tall enough to
   scroll would otherwise put the footer against the last row. */
#market-making-workspace #mkm-sb-live { margin-bottom: 12px; }

/* The copyright and the Disclaimer trigger close the sidebar, the line the
   trainer console carries at the foot of its own sidebar (trainer.html
   .sidebar-footer, styled in console.css, which this page does not load).
   The negative margins are the content column's own 16px padding, so the
   rule above the line runs the full width of the sidebar the way the
   console's does. The trigger needs no wiring: initDisclaimer() delegates
   [data-disclaimer] on the document. */
/* Placement only: the bleed cancels the sidebar's own inset so the rule
   runs the full width of the column, and the auto top margin holds the
   footer at the foot. Everything the footer looks like is one definition
   in chrome.css, shared with the console shells. */
#market-making-workspace .mkm-sb-footer {
  margin: auto -16px 0;
}

/* ── Scenario details expander (bottom of the sidebar) ─────────────── */
/* Uses the platform boxed collapsible (.sb-section-plain +
   .sb-collapsible-toggle from components.css). */

/* The traded instrument, pinned at the top of the sidebar above the session
   controls. */
/* The participant's own name in the header bar, before the theme toggle
   (owner, 2026-08-23: name, theme toggle, Sign Out, in that order). */
/* The size the header itself is set in: .tab-btn on the other side of
   the bar carries 1.05rem, so the participant's name reads as part of
   the header rather than as a note beside it (owner, 2026-08-28). */
.mm-header-name {
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--text-secondary);
  white-space: nowrap;
}
.mm-header-name:empty { display: none; }
/* The connection badge, before the participant's name. It is on screen
   only while the server has stopped answering, so a room that is
   working carries no chrome about its connection at all. It reads at
   the name's own size and weight beside it, and the dot carries the
   colour; the 12px between them is the header group's own gap
   (#mm-header-controls), not a margin of its own. */
.mm-header-conn {
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--text-secondary);
  white-space: nowrap;
}
/* The connection dot, copied from the trainer console stylesheet
   (css/console.css .status-dot). mm.html does not load console.css, so
   the rules come across as they are, class names included, the way
   portfolio-sim.css already carries them for the participant app. The
   keyframes are renamed because this sheet loads beside base.css and
   components.css. */
.status-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--text-muted);
}
.status-dot.online { background: var(--positive); }
.status-dot.active { background: var(--color-accent); }
.status-dot.warning { background: var(--warning); }
.status-dot.offline { background: var(--negative); }
.status-dot.reconnecting {
  background: var(--warning);
  animation: mkm-pulse-dot 1s ease-in-out infinite;
}
@keyframes mkm-pulse-dot { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } }
/* .status-dot carries no display of its own. It renders in the console
   because its parent is a flex container, which blockifies it; dropped
   into an inline badge it collapses to nothing. Same treatment the
   console gives it inside a table cell (console.css .teams-table
   .status-dot). */
.mm-header-conn .status-dot {
  display: inline-block;
  margin-right: 6px;
  vertical-align: middle;
}
#market-making-workspace .mkm-scenario-stock {
  font-size: var(--text-h4);
  font-weight: 600;
  color: var(--text-secondary);
  /* The parent .mkm-sb-top owns the space below the row (its padding-
     bottom to the divider, its margin-bottom to the next block). Adding
     a bottom margin here piled on top of both and pushed the divider off
     centre between Apple and POSITION. */
  margin: 0;
  min-width: 0;
}
/* The descriptive instrument list sits on its own row below the name +
   clock (owner, 2026-08-30), so it takes the full sidebar width and
   holds without truncation. Numeric runs read in the mono/tabular
   face; the words stay in the base font. */
#market-making-workspace .mkm-stock-sub {
  font-size: var(--text-meta);
  font-weight: 500;
  color: var(--text-muted);
  line-height: 1.2;
  margin-top: 2px;
}
#market-making-workspace .mkm-stock-sub[hidden] { display: none; }
#market-making-workspace .mkm-stock-sub .num {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

/* ── Main grid ─────────────────────────────────────────────────────── */

/* The panels tile edge to edge with the page ground showing through 1px
   gaps as the seam between them, the portfolio desk's terminal chrome.
   Every nested column carries the same gap and ground, so every seam on
   the desk is the same hairline. */
#market-making-workspace .mkm-grid {
  flex: 1 1 0;
  min-height: 0;
  display: grid;
  /* The book and the client calls take the width first (owner,
     2026-08-25): the ceiling rises and the chart, the news feed, the
     working orders and the blotter share what is left. Only the ceiling
     moves, so a screen too narrow to reach it splits exactly as it did
     and the right column keeps its own floor. A thin blank column runs
     between them (owner, 2026-08-29): the two columns read as two
     panels rather than as one tiled surface joined by a hairline seam.
     The seams INSIDE each column stay at 1px. The grid carries no
     background of its own, so the column-gap shows the workspace
     behind and reads as air rather than as a coloured band. */
  grid-template-columns: minmax(520px, 700px) 1fr;
  column-gap: 8px;
  row-gap: 1px;
  background: transparent;
}
/* The end screen hides the grid via the hidden attribute; the display:grid
   above would otherwise win over the UA [hidden] rule. */
#market-making-workspace .mkm-grid[hidden] { display: none; }
/* Left column: book, order entry, working orders, client calls. The calls
   panel takes whatever height is left and scrolls internally. */
#market-making-workspace .mkm-col-book {
  min-height: 0;
  display: flex;
  flex-direction: column;
  /* NO gap (owner, 2026-09-01: remove the divider above the client
     calls). The column's one gap showed the page ground between the book
     frame and the calls, and against two panels of the same surface it
     read as a rule drawn under the order entry. The panels meet. */
  gap: 0;
  background: var(--bg);
  overflow: hidden;
}
/* The client calls fill whatever is left of the book column and scroll
   inside (owner, 2026-08-23: the calls took the blotter's slot). */
#market-making-workspace .mkm-col-book .mkm-calls-wrap {
  flex: 1 1 auto;
  min-height: 0;
}
/* One stacked layout at every width: the chart first, the news feed
   under it, then the working orders, then the blotter taking whatever
   height is left. A plain flex column, the same construction as the
   left column (owner, 2026-08-23: the earlier grid distributed height
   between the rows in ways that painted blank bands between panels; a
   flex-start column physically cannot open space between its items).
   The DOM keeps the news wrap first for the release line; the visual
   order is set here. */
#market-making-workspace .mkm-col-right {
  min-height: 0;
  /* A 1fr grid track is minmax(auto, 1fr), and its automatic minimum is
     the column's own min-content width, so a long line anywhere in here
     widened the column and took the width off the book beside it. The
     release countdown did it visibly: the panel was one width while a
     release was pending and another once it had printed. With the floor
     at zero the column is its share of the row and nothing inside it
     votes on the width (owner, 2026-08-25). */
  min-width: 0;
  position: relative;
  display: flex;
  flex-direction: column;
  /* THE SEAMS HERE ARE THE BOOK'S OWN GRIP (owner, 2026-09-01: "exactly
     that same white strip"). The grip is 9px of the frame's own surface
     with a hairline along its top, so the gaps take the same three
     declarations: that height, that ground, and the hairline, which the
     .mkm-seam handle already lying over each gap carries.

     What this replaces, and why neither earlier attempt worked. The gaps
     used to show the page ground, which is DARKER than the panels over
     it (#0D1117 under #161B22) and read as no separation at all.
     Colouring the gap instead was wrong both ways round, because a
     foreground token inverts with the theme: too white on the dark desk
     and a grey line on the light one. Copying the grip needs no colour
     of its own and is right on both. */
  gap: 9px;
  background: var(--bg-surface);
}
/* The chart tile ends where the book's last level ends (owner,
   2026-08-28). The two columns start on the same line, so matching the
   bottoms is matching the heights, and the book's height is its own
   content: the levels shown, the taller top-of-book row, and whatever
   depth the reader has dragged to. desk_book.js measures the rendered
   book and writes it here on every paint; the fallback is what the tile
   opened at before the first one. A reader who drags the seams takes
   this over, in the .mkm-rows-manual rule below. */
/* THE CHART IS NOW THE PANEL THAT GROWS (owner, 2026-09-02: more
   default room for the chart, at the expense of the blotter and the
   working orders). The book's height is its FLOOR rather than its
   height: the panel still opens no shorter than the book beside it, and
   every pixel the column has spare goes to it three parts in four,
   against one to the blotter.
   THIS REVERSES the 2026-09-01 arrangement, which held the panel at
   exactly the book's height so the seam under the chart and the seam
   under the book sat on one line. A panel that grows cannot also end
   where another panel ends, and the four-pane grid the options desk
   draws needs the height more than the two seams need to align. */
#market-making-workspace .mkm-chart-panel {
  order: 0;
  flex: 3 1 var(--mkm-book-h, 268px);
  min-height: 0;
}
/* A fixed height, not a content height (owner, 2026-08-23): the panel
   used to open at the height of the headlines it held and grow with
   every one that arrived, so the whole right column moved through the
   session. The frame is sized here and the feed fills it, which also
   means the release line appearing above the feed takes its space from
   inside the frame rather than making the frame taller.

   280px, up from 200px (owner, 2026-08-28). The blotter is the only
   panel in this column that grows, so what the news and the working
   orders take at rest comes off it and nothing else moves.

   300px since the News heading arrived (owner, 2026-09-09): the basis
   sizes the FRAME and the feed inside it is what grows, so the head's
   own 26px is added here rather than taken off the headlines on screen,
   less the 6px of feed padding the head now carries instead. */
#market-making-workspace .mkm-news-wrap {
  order: 1;
  flex: 0 1 300px;
  min-height: 0;
  min-width: 0;
}
#market-making-workspace .mkm-col-right .mkm-working-frame {
  order: 2;
  flex: 0 1 auto;
  min-height: 0;
}
/* The blotter still grows, but it is no longer the only panel that
   does: it takes one part of the column's spare height where the chart
   above takes three (owner, 2026-09-02). Its basis is what it opens on
   in a column with nothing spare. */
#market-making-workspace .mkm-col-right .mkm-feed-wrap {
  order: 3;
  flex: 1 1 120px;
  min-height: 0;
}
#market-making-workspace .mkm-col-right .mkm-feed-wrap .mkm-feed {
  flex: 1 1 0;
  min-height: 80px;
}
/* Draggable seams (desk_resize.js): invisible handles over the 1px
   gaps; a drag replaces the panels' own sizing with the reader's
   shares, written as plain grow factors into the custom properties. */
#market-making-workspace .mkm-seam {
  position: absolute;
  z-index: 5;
  height: 9px;
  cursor: row-resize;
  /* The hairline along the top of the strip, the book grip's own. The
     handle is what carries it, because it already lies over every gap
     and the panels either side are ordered by CSS rather than by the
     DOM, so no sibling selector reaches the right edges. */
  border-top: 1px solid var(--border);
}
/* THE EXCEPTION ABOVE THE BLOTTER IS GONE (owner, 2026-09-10: every seam
   reads the same, and that one was the only visible strip on the
   column). It gave the strip above the blotter --bg-elevated on
   2026-09-01, when the blotter's feed started right at the panel's top
   and a frame-surface strip read as a band of a third colour. The
   Blotter heading now sits between the two, on the frame surface like
   every other panel's top, so the strip has the same neighbour the other
   seams have and needs no colour of its own. The drag is untouched: the
   handle still lies over the gap and still resizes. */
#market-making-workspace .mkm-seam:hover,
#market-making-workspace .mkm-seam--active {
  background: color-mix(in srgb, var(--color-accent) 22%, transparent);
}
body.mkm-desk-resizing { user-select: none; }
#market-making-workspace .mkm-col-right.mkm-rows-manual .mkm-chart-panel {
  flex: var(--mkm-r1, 1) 1 0;
}
#market-making-workspace .mkm-col-right.mkm-rows-manual .mkm-news-wrap {
  flex: var(--mkm-r2, 1) 1 0;
}
#market-making-workspace .mkm-col-right.mkm-rows-manual .mkm-working-frame {
  flex: var(--mkm-r3, 1) 1 0;
}
#market-making-workspace .mkm-col-right.mkm-rows-manual .mkm-feed-wrap {
  flex: var(--mkm-r4, 1) 1 0;
}
/* The working area fixes its own height in its rule below; a
   reader-sized panel owns it instead. The news feed needs nothing here:
   it fills its frame either way. */
#market-making-workspace .mkm-rows-manual .mkm-working {
  height: auto;
  flex: 1 1 0;
  min-height: 0;
  overflow-y: auto;
}
/* News and chart are frames themselves (their 8px gap is internal rhythm
   on the frame surface, not a seam). */
#market-making-workspace .mkm-chart-panel {
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
#market-making-workspace .mkm-news-wrap {
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
/* The news feed is a strip under the chart; headlines scroll inside it
   (owner, 2026-08-22: the news never needed the height the old side
   column gave it). It fills whatever the frame above gives it and
   scrolls, so its height never depends on how many headlines have
   landed. */
#market-making-workspace .mkm-news-wrap .mkm-feed {
  flex: 1 1 0;
  min-height: 0;
}
#market-making-workspace #mkm-news .mkm-feed-item,
#market-making-workspace #mkm-opt-news .mkm-feed-item,
#market-making-workspace #mkm-rt-news .mkm-feed-item { font-size: 0.95rem; }
/* A fresh headline holds a clear highlight for ten seconds, then fades
   (owner, 2026-08-23). One run per item; the reconnect backlog never
   carries the class. */
@keyframes mkm-news-flash {
  0% { background: color-mix(in srgb, var(--color-accent) 50%, transparent); }
  80% { background: color-mix(in srgb, var(--color-accent) 35%, transparent); }
  100% { background: transparent; }
}
#market-making-workspace #mkm-news .mkm-feed-item--new,
#market-making-workspace #mkm-opt-news .mkm-feed-item--new,
#market-making-workspace #mkm-rt-news .mkm-feed-item--new {
  animation: mkm-news-flash 10s ease-out 1;
}

/* ── Panel headings ────────────────────────────────────────────────
   News, Working orders and Blotter carry a heading (owner, 2026-09-09).
   The chart, the book, the order entry and the client calls still carry
   none: those name themselves and a heading over them is a row of
   height for nothing.

   The head sits on the frame's own surface, so it takes no border and no
   ground of its own. It also takes NO HEIGHT FROM THE PANEL CONTENT:
   each of these panels is a flex column whose scrolling child keeps
   `flex: 1 1 0`, so the head is fixed at its own height and the feed or
   the grid below still fills what is left.

   ONE DECLARED HEIGHT, AND NOTHING ELSE FEEDS IT (owner, 2026-09-10: the
   three rows read at three different heights). Three things were setting
   it before, and each of the three panels had its own combination:

     - the tallest child. A head sized by its contents grew on the News
       panel, where the countdown reads at --text-meta and the heading at
       11px, and baseline alignment stacked the difference on top.
     - the frame's own gap under the head. 8px on the news wrap, 6px on
       the blotter, none on the working frame.
     - the content's own top padding. 6px inside a feed, 8px inside the
       working grid.

   So the head declares a height and centres what it holds, and the two
   rules under it take the other two contributions off the panels that
   carry a head. The head is then the WHOLE distance from the panel's top
   edge to its first row, measured once here for all three. The other
   desks have no head and are untouched by any of it. */
#market-making-workspace .mkm-panel-head {
  flex: 0 0 auto;
  box-sizing: border-box;
  height: 26px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  min-width: 0;
  padding: 0 12px;
}
#market-making-workspace .mkm-panel-title {
  flex: 0 0 auto;
  white-space: nowrap;
}
/* The frame's gap and the content's top padding both sat under the head
   as a second and third inset. The head carries the whole of it. */
#market-making-workspace .mkm-opt-frame:has(> .mkm-panel-head) {
  gap: 0;
}
#market-making-workspace .mkm-opt-frame > .mkm-panel-head + .mkm-feed,
#market-making-workspace .mkm-opt-frame > .mkm-panel-head + .mkm-working {
  padding-top: 0;
}

/* Next-release indicator (FX): a compact always-visible line pinned above
   the news feed, counting down to the next scheduled release and showing
   the print through the post window. Hidden on equity sessions. */
#market-making-workspace .mkm-release-line {
  display: flex;
  align-items: baseline;
  gap: 8px;
  min-width: 0;
  font-size: var(--text-meta);
  color: var(--text-secondary);
}
/* Equity sessions hide the release line via the hidden attribute;
   display:flex above would otherwise win over the UA [hidden] rule (same
   guard as .mkm-grid and .mkm-entry-dark). Without it the empty line
   rendered as an invisible ~49px spacer on top of the news feed, which
   read as a blank band between the chart and the news. */
#market-making-workspace .mkm-release-line[hidden] { display: none; }
#market-making-workspace .mkm-release-label {
  flex-shrink: 0;
  font-size: var(--text-meta);
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-muted);
}
#market-making-workspace .mkm-release-text {
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
#market-making-workspace .mkm-release-line .num {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}
/* The final seconds before the print read as a warning. */
#market-making-workspace .mkm-release-line--soon .mkm-release-name,
#market-making-workspace .mkm-release-line--soon .mkm-release-text,
#market-making-workspace .mkm-release-line--soon .num {
  color: var(--warning);
}
/* On the spot desk the line rides the News heading row (owner,
   2026-09-09), so the row supplies the inset and the line carries none.
   The head's own uppercase and tracking are the HEADING's, not the
   countdown's, so both are put back here. The other desks keep the line
   above their feed, with the padding rule further down this file. */
#market-making-workspace .mkm-panel-head .mkm-release-line {
  flex: 0 1 auto;
  padding: 0;
  gap: 4px;
  text-transform: none;
  letter-spacing: normal;
  font-weight: 400;
}
/* Only the release NAME gives way. The countdown and the consensus
   number are the reading, so they keep their whole width whatever the
   name is called. */
#market-making-workspace .mkm-panel-head .mkm-release-name {
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
#market-making-workspace .mkm-panel-head .mkm-release-text {
  flex: 0 0 auto;
  overflow: visible;
}

#market-making-workspace .mkm-placeholder {
  font-size: 0.85rem;
  color: var(--text-muted);
  padding: 10px 2px;
}

/* ── Order book (copied ex-ob pattern, stacked) ────────────────────── */

/* The book takes its natural height: the levels renderBook draws, five by
   default and up to ten once the reader drags the grip. The height is
   stable between drags, so the order entry sits right under the last
   level (owner, 2026-08-23) and the client calls take what is left. */
#market-making-workspace #mkm-book .mkm-ob {
  height: 100%;
}
#market-making-workspace .mkm-ob {
  /* The top-of-book price size, and the price column derived from it,
     so the two can never drift apart. JetBrains Mono and Fira Code
     both advance 0.6em a character, and nine characters covers every
     price the pack can show with room over: the widest today are the
     index future and gold at eight ("7,743.75", "4,680.50"), and nine
     still holds a trainer-set opening price an order of magnitude up
     ("12,345.75", "1,000,000"). Eight characters need 115.2px, which
     is what a fixed 108px truncated on those two contracts (owner,
     2026-08-28); every other instrument fits in six or seven and
     never showed it. */
  --mkm-tob-price: 1.5rem;
  --mkm-ob-price-w: calc(var(--mkm-tob-price) * 0.6 * 9);
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  overflow: hidden;
}
/* ── Stacked books (owner design, 2026-08-30) ────────────────────────
   Every book's top of book is on screen and at most one shows depth. A
   chevron expands a closed book and collapses the one that was open,
   and the open book's own header closes it, so every book on the stack
   collapses (owner, 2026-08-31); the STACK ORDER NEVER CHANGES, so the
   eye keeps its place. A collapsed book's top of book still trades on a
   click, so a hedge in the other instrument costs no navigation. */
#market-making-workspace .mkm-ob--stacked .mkm-ob-inst + .mkm-ob-inst {
  border-top: 1px solid var(--border);
}
/* The WHOLE header row expands and collapses, not the chevron alone
   (owner, 2026-08-30): a chevron is too small a target to switch books
   at the speed a desk switches them. The row is filled with a subtle
   wash of its own book's accent and its text reads in the desk's own
   ink, so the band says which book without shouting. */
#market-making-workspace .mkm-ob-inst-head {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 5px 12px;
  border: 0;
  text-align: left;
  cursor: pointer;
  font-family: var(--font);
  font-size: 0.78rem;
  /* The filled band with the desk's own ink on it, both themes. Tried
     accent-coloured text on a near-black band instead and the owner
     read it as worse (2026-08-30), so the band carries the colour and
     the text stays legible. */
  background: color-mix(in srgb, var(--sidebar-accent) 14%, transparent);
  color: var(--text);
}
#market-making-workspace .mkm-ob-inst-head:hover {
  background: color-mix(in srgb, var(--sidebar-accent) 22%, transparent);
}
/* What one unit of the contract is worth sits on the same row as the
   book it belongs to (owner, 2026-08-30 for the DV01 a lot, 2026-09-10
   for the point value of an index future), pushed to the far end so the
   books' numbers line up under each other. */
#market-making-workspace .mkm-ob-inst-read {
  margin-left: auto;
  color: inherit;
}
#market-making-workspace .mkm-ob-inst-read .num {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-weight: 700;
}
#market-making-workspace .mkm-ob-inst-label {
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: inherit;
}
/* The chevron says which way the row goes; the row itself is the
   target. Nothing in the LADDER expands: a click there trades. */
#market-making-workspace .mkm-ob-chevron {
  flex: 0 0 auto;
  width: 12px;
  color: inherit;
  font-size: 0.7rem;
  line-height: 1;
}
/* The header row reads THE SAME open or collapsed (owner, 2026-08-30).
   Only the chevron's direction says which state it is in: recolouring
   the text as well made the band look like a different book rather
   than the same book in a different state. */
/* The second book takes its own accent so the two never read as one
   ladder. THE QUOTES ARE NOT RECOLOURED (owner, 2026-08-30): a price
   reads in the desk's own ink whichever book it is in. What carries the
   colour is the shading behind the liquidity and the border around a
   working order, which is what says WHERE you are.

   One variable does all of it. The depth bars, the working-order
   outline and inset edge, and the size a desk rests in all already
   read --sidebar-accent, so overriding it inside the book paints every
   one of them and touches nothing else. Orange to start; the owner
   rules on the shade from the screen. The primary book keeps the
   desk's own accent.

   A single flat colour cannot serve both themes: this app is
   dark-first, so :root is the dark palette and [data-theme="light"]
   overrides it, exactly as --sidebar-accent itself is defined in
   base.css. Each book accent is a PAIR on that same pattern, lighter
   on the dark ground and deeper on the white one.

   The hues are chosen to be far from each other AND from the meanings
   the sim already spends colour on: green is positive, red is
   negative, amber is warning, and the desk's own teal is book one. So
   book two takes VIOLET and book three orange (owner, 2026-08-30,
   after seeing both on screen): violet is the one that held up in both
   themes at once, and the two are the remaining hues that stay apart
   under the common red-green colour vision deficiencies. Books are never told apart by colour alone in
   any case: each carries its label and its place in the stack.

   On dark the accents are FULLY SATURATED at about half lightness,
   the trading terminal register (owner, 2026-08-30: Bloomberg orange).
   Two earlier attempts missed this by measuring the wrong thing. The
   first chased contrast ratio, and the orange it picked out-scored the
   teal beside it while still looking muddy. The second chased
   lightness, which only made it pale: at 72% lightness a colour washes
   out rather than lifts. What reads as a terminal accent is
   SATURATION, so #ff9900 is the orange and the other two are set the
   same way on their own hues.

   On white the same hues take a deep step instead, because a fully
   saturated mid-tone has almost no contrast against a white ground.

   THE FIRST BOOK'S TEAL IS OVERRIDDEN ONLY INSIDE THE STACK. It is
   --sidebar-accent from base.css and the whole platform reads it, so
   the token itself is left alone and only the book's own copy moves. */
#market-making-workspace .mkm-ob-inst--0 { --sidebar-accent: #14f5df; }
#market-making-workspace .mkm-ob-inst--1 { --sidebar-accent: #ab7aff; }
#market-making-workspace .mkm-ob-inst--2 { --sidebar-accent: #ff9900; }
[data-theme="light"] #market-making-workspace .mkm-ob-inst--0 {
  --sidebar-accent: #0d9488;
}
[data-theme="light"] #market-making-workspace .mkm-ob-inst--1 {
  --sidebar-accent: #7c3aed;
}
[data-theme="light"] #market-making-workspace .mkm-ob-inst--2 {
  --sidebar-accent: #c2410c;
}

/* Bids and asks side by side; the prices meet at the centre divider. */
#market-making-workspace .mkm-ob-cols {
  display: grid;
  grid-template-columns: 1fr 1fr;
}
#market-making-workspace .mkm-ob-col--bids { border-right: 1px solid var(--border); }
/* Both sides render the same number of levels (renderBook caps the
   merge), so they take their natural height and the order entry sits
   right under the last level (owner, 2026-08-23: no reserved space).

   There is ONE head row. BID and ASK used to have a row of their own
   above the column names; they sit in the price column of this one now
   (owner, 2026-09-01), which names the side once and gives the book back
   the row. */
#market-making-workspace .mkm-ob-subhead {
  display: grid;
  grid-template-columns: 1fr 1.2fr 1fr;
  gap: 6px;
  padding: 3px 12px 4px;
  font-family: var(--font);
  font-size: 0.64rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted);
  border-bottom: 1px solid var(--border);
  /* Every word centred in the row (owner, 2026-09-01). The default
     stretch gives each cell the row's full height and leaves its text at
     the top of it, which showed the moment BID and ASK grew: they set
     the row's height and Cum and Size hung above their middle. */
  align-items: center;
}
#market-making-workspace .mkm-ob-col--bids .mkm-ob-subhead span { text-align: right; }
#market-making-workspace .mkm-ob-col--asks .mkm-ob-subhead span { text-align: left; }
/* BID and ASK are the side, not a column name, so they read larger and
   bolder than Cum and Size beside them (owner, 2026-09-01). They sit in
   the price column, which is the widest of the three, so nothing has to
   give width for them. */
#market-making-workspace .mkm-ob-side {
  font-size: 0.82rem;
  font-weight: 800;
}

/* The price column has a fixed width, sized for the top-of-book font, so
   every column lines up on every row and the price can never truncate.
   The size column gets the larger flexible share of what is left. The
   prices stay hard against the centre divider either side, so widening
   this column moves the size and cum columns outward and leaves the two
   prices where they meet. */
/* CUM gets the wider share, not the narrower one (owner report,
   2026-08-31). The running total is by construction the larger of the
   two numbers and it grows down the ladder, so on a deep equity book it
   reached seven figures and truncated while the size column beside it
   sat half empty. They are equal now, with cum a shade wider. */
#market-making-workspace .mkm-ob-col--bids .mkm-ob-row,
#market-making-workspace .mkm-ob-col--bids .mkm-ob-subhead {
  grid-template-columns:
    minmax(0, 1.15fr) minmax(0, 0.95fr) var(--mkm-ob-price-w);
}
#market-making-workspace .mkm-ob-col--asks .mkm-ob-row,
#market-making-workspace .mkm-ob-col--asks .mkm-ob-subhead {
  grid-template-columns:
    var(--mkm-ob-price-w) minmax(0, 0.95fr) minmax(0, 1.15fr);
}

#market-making-workspace .mkm-ob-row {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1.2fr 1fr;
  gap: 5px;
  align-items: baseline;
  padding: 6px 10px;
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--text);
  overflow: hidden;
  isolation: isolate;
}
#market-making-workspace .mkm-ob-row::before {
  content: '';
  position: absolute;
  top: 0; bottom: 0;
  width: var(--depth-pct, 0%);
  z-index: -1;
  /* SCREENED onto the dark ground rather than faded into it. A
     saturated hue at low alpha over near-black turns muddy, because
     alpha blends TOWARD the background: the orange came out brown
     however vivid the hex was. Screen only adds light, so the hue
     survives at a low setting.
     0.4, not the 0.85 tried first (owner, 2026-08-30): the bar sits
     BEHIND the prices and sizes, so past about half it starts to eat
     them. The header band is what carries the book's identity; this
     only has to read as depth. */
  mix-blend-mode: screen;
  opacity: 0.4;
  pointer-events: none;
}
/* White has nothing to add light to, so the bar fades in as it did. */
/* White has nothing to add light to, so the bar fades in as it did. */
[data-theme="light"] #market-making-workspace .mkm-ob-row::before {
  mix-blend-mode: normal;
  opacity: 0.22;
}
/* Depth bars grow outward from the centre divider, each book in its own
   accent. */
#market-making-workspace .mkm-ob-row--bid::before {
  right: 0;
  background: linear-gradient(to left, var(--sidebar-accent), transparent);
}
#market-making-workspace .mkm-ob-row--ask::before {
  left: 0;
  background: linear-gradient(to right, var(--sidebar-accent), transparent);
}
#market-making-workspace .mkm-ob-row:nth-child(even) {
  background: rgba(255, 255, 255, 0.015);
}
[data-theme="light"] #market-making-workspace .mkm-ob-row:nth-child(even) {
  background: rgba(0, 0, 0, 0.02);
}
#market-making-workspace .mkm-ob-cell {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
#market-making-workspace .mkm-ob-col--bids .mkm-ob-cell { text-align: right; }
#market-making-workspace .mkm-ob-col--asks .mkm-ob-cell { text-align: left; }
#market-making-workspace .mkm-ob-cum {
  color: var(--text-muted);
  font-size: 0.92rem;
}
#market-making-workspace .mkm-ob-row--tob .mkm-ob-cum {
  font-size: 1rem;
  font-weight: 700;
}

/* Top of book: first row per side, markedly larger, clickable to trade
   the order-entry size at market. */
#market-making-workspace .mkm-ob-row--tob {
  font-weight: 800;
  padding-top: 8px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--border);
  cursor: pointer;
}
#market-making-workspace .mkm-ob-row--tob .mkm-ob-price {
  font-size: var(--mkm-tob-price);
}
#market-making-workspace .mkm-ob-row--tob .mkm-ob-size  { font-size: 1.15rem; }
/* FX top-of-book prices follow the dealer big-figure convention: the two pip
   digits read much larger than the big figure (and any pipette digit). */
#market-making-workspace .mkm-ob-row--tob .mkm-ob-bigfig { font-size: var(--text-h4); }
#market-making-workspace .mkm-ob-row--tob .mkm-ob-pips   { font-size: var(--text-h1); }
#market-making-workspace .mkm-ob-row--tob:hover {
  outline: 1px solid var(--text-muted);
  outline-offset: -1px;
}

/* A resting order of the desk's own, marked by an outline of even
   thickness all the way round (owner, 2026-09-10). It used to carry a
   3px inset bar down its outer edge as well, which read as one side of
   the rectangle drawn heavier than the other three.

   THE SIDE IS THE COLOUR (owner, 2026-09-10): the P&L green on a resting
   bid and the P&L red on a resting offer. Both sides read the sidebar
   teal before, so a participant could not tell their own bid from their
   own offer without reading which half of the book it was in. The
   column declares the colour once and the two marks below read it, so a
   mark added later cannot take a third colour by accident. */
#market-making-workspace .mkm-ob-col--bids { --mkm-mine: var(--positive); }
#market-making-workspace .mkm-ob-col--asks { --mkm-mine: var(--negative); }
#market-making-workspace .mkm-ob-row--user {
  outline: 1px solid var(--mkm-mine);
  outline-offset: -1px;
}
/* The size the desk rests in is marked on the number itself (owner,
   2026-08-23, replacing a "you" chip that cost the cell a quarter of its
   width). Colour is not carrying it alone: the row keeps the outline. */
#market-making-workspace .mkm-ob-size--mine {
  color: var(--mkm-mine);
  font-weight: 700;
}

/* ── Order entry ───────────────────────────────────────────────────── */

/* One card, stacked rows: the lit order entry (size on the left, then the
   bid and ask sides) on one full-width row, and on equities the dark-pool
   lay-off on its own full-width row beneath it. Side-by-side columns could
   not fit the one-row lit entry at the book column's width. FX hides the
   dark row and the card is just the lit row. */
#market-making-workspace .mkm-entry {
  /* One space for the whole panel, across and down; see .mkm-entry-lit
     below. The lit row and the dark row are one gap apart, and the rule
     between them sits in the middle of it (the dark row's padding-top is
     the same token). */
  --mkm-entry-gap: 8px;
  /* One width for every price field on the card, so the dark row's Limit
     is the same width as Place bid's price field over it (owner,
     2026-09-01). They can only be equal if they read one number: the lit
     fields used to absorb the row's spare width and the dark Limit was a
     fixed measure, so the two could never meet. The measure is the one
     the dark row already carried, which is the client ticket's own quote
     field. */
  --mkm-price-w: calc(8ch + 18px);
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  padding: 10px 12px 12px;
  display: flex;
  flex-direction: column;
  gap: var(--mkm-entry-gap);
}
/* A session that stacks books carries this panel for the single-book
   case and hides it, because each book has its own entry under its own
   ladder (owner, 2026-08-31). Written out beside the guards the FX
   release line and the dark row carry, though base.css's
   `[hidden] { display: none !important }` already settles it: the
   important flag beats any display this file sets. The corollary is the
   one that bites, and it cost a round on the grip (2026-09-01): an
   element that must RESERVE its space cannot be hidden with the
   attribute at all, because nothing here can put the box back. */
#market-making-workspace .mkm-entry[hidden],
#market-making-workspace .mkm-entry-lit[hidden] { display: none; }
/* And where the lit row has gone with it, the card is holding one button
   and is not a panel any more (owner, 2026-09-01). That is the stacked
   desks, whose order entry sits under each book: the ground and the
   border go and Call the street stands under the stack on the frame's
   own surface.

   NO left padding, so the button's edge is the BOOK's edge (owner,
   2026-09-01, on seeing it inset: "left aligned with the order book").
   The book box runs the full width of the frame, so aligning to it means
   aligning to the frame, not to the prices inside it.

   The button sits in EQUAL space above and below (owner, 2026-09-01,
   with every book collapsed). The space ABOVE is the grip's, which
   reserves its 9px whether or not it is drawn, so the card adds nothing
   of its own on top or the two sides can never meet. The space BELOW is
   that same 9px, carried here, with the calls panel's own top padding
   dropped under this card so nothing adds to it (the rule after the
   calls panel's own). Box-sizing is border-box, so the grip's 9px
   includes its hairline and these are the same number. */
#market-making-workspace .mkm-book-frame
    > .mkm-entry:has(> .mkm-entry-lit[hidden]) {
  background: none;
  border: 0;
  padding: 0 0 9px;
}

/* ONE ORDER ENTRY PER BOOK, under the book it belongs to (owner,
   2026-08-31), on a session that stacks more than one. It is a row
   inside the book's own bordered box rather than a second card: a rule
   above it and the ladder's own horizontal padding, so its left edge
   lines up with the prices above it. Nothing of .mkm-entry's card chrome
   belongs here, which is why this is its own class and not that one.

   The two tokens are restated because .mkm-entry is where they are
   declared and this row is not inside that panel. Every control in the
   row spaces itself by the gap and every price field takes the width. */
#market-making-workspace .mkm-ob-entry {
  --mkm-entry-gap: 8px;
  --mkm-price-w: calc(8ch + 18px);
  padding: 8px 10px;
  border-top: 1px solid var(--border);
  /* The interface face, because this row is INSIDE .mkm-ob and would
     otherwise inherit the ladder's mono (owner, 2026-09-01: the FX size
     label read mono, and its line box sat the text off the centre of the
     row). The fields re-declare mono in their own rules, so the numbers
     keep it and only the words lose it, which is the standing rule.
     Nothing showed on a single-book desk because the shared row sits
     outside the book box and always read in this face. */
  font-family: var(--font);
}
/* Lit order entry: one row, the size field on the left, then the bid and
   ask sides.

   One horizontal space runs through the whole entry panel: every gap
   between a label, a field and a button is --mkm-entry-gap, on both rows
   and inside every group. The panel used to mix 12px between the groups
   with 8px inside them, which read as unequal spacing along one row. */
#market-making-workspace .mkm-entry-lit {
  display: flex;
  align-items: center;
  gap: var(--mkm-entry-gap);
}
#market-making-workspace .mkm-entry-lit .mkm-entry-side { flex: 1 1 0; }
#market-making-workspace .mkm-entry-side {
  display: flex;
  gap: var(--mkm-entry-gap);
  min-width: 0;
}
#market-making-workspace .mkm-entry-side .sidebar-input {
  flex: 1;
  min-width: 0;
  font-family: var(--font-mono);
}
#market-making-workspace .mkm-entry-side .btn { flex-shrink: 0; }
/* The LIT row's price fields take the card's one price width, and the
   button beside each takes the row's spare pixels instead. Scoped to the
   lit row: the rates and options hedge entries share .mkm-entry-side and
   have no dark row under them to line up with.

   The field does not GROW past that width, which is what makes it equal
   to the Limit below it, but it still shrinks: at the book column's
   narrow end this row has always been tight, and a field that cannot
   give would push the row past its own box instead. The min-width rule
   below is the floor it shrinks to. */
#market-making-workspace .mkm-entry-lit .mkm-entry-side .sidebar-input {
  flex: 0 1 var(--mkm-price-w);
}
#market-making-workspace .mkm-entry-lit .mkm-entry-side .btn {
  flex: 1 1 auto;
}
#market-making-workspace .mkm-entry-size {
  display: flex;
  align-items: center;
  gap: var(--mkm-entry-gap);
  flex: 0 0 auto;
}
#market-making-workspace .mkm-entry-size .sb-label { margin: 0; }
/* The two left-edge labels on the entry card share one column so the
   dark-row inputs sit under the lit-row inputs (owner, 2026-08-30):
   Size (dark) under Size (lit), Limit (dark) under Bid price (lit).
   The wider of the two natural labels drives the shared width. */
#market-making-workspace .mkm-entry-size > .sb-label,
#market-making-workspace .mkm-entry-dark-head > .sb-label {
  min-width: 78px;
}
/* Narrow on purpose (owner, 2026-08-23): sensible order sizes stay in
   five digits and the freed width keeps the price fields readable. A
   longer number still edits fine, it scrolls within the field. */
#market-making-workspace .mkm-entry-size .sidebar-input {
  width: 82px;
  font-family: var(--font-mono);
}
/* The price fields never collapse below a readable price. */
#market-making-workspace .mkm-entry-side .sidebar-input {
  min-width: 74px;
}
/* Dark-pool lay-off (equities only): one row under the lit entry, divided by
   a neutral rule so the two ways to trade read as one panel with two rows. */
#market-making-workspace .mkm-entry-dark {
  display: flex;
  align-items: center;
  gap: var(--mkm-entry-gap);
  border-top: 1px solid var(--border);
  padding-top: var(--mkm-entry-gap);
}
/* FX hides the dark row via the hidden attribute; display:flex above would
   otherwise win over the UA [hidden] rule (same guard as .mkm-grid). */
#market-making-workspace .mkm-entry-dark[hidden] { display: none; }
/* A family with NO DARK POOL leaves Call the street alone on this row,
   and the rule and the padding above it were there to divide two ways of
   trading (owner, 2026-09-01: a whole row for one button). With nothing
   to divide they go, and the button reads as the last control of the
   entry rather than as a second panel under it. Keyed on the hidden
   attribute rather than on a class of its own, so the one place that
   decides whether a family has a dark pool stays the one place. */
#market-making-workspace .mkm-entry-dark:has(> #mkm-dark-group[hidden]) {
  border-top: 0;
  padding-top: 0;
}
/* And a room of one on a family with no dark pool has neither group, so
   the row goes rather than standing empty: the entry panel is a flex
   column with a gap, and an empty child still takes one of them. Two
   :has() chained on the one element, which is allowed where nesting one
   inside the other is not. Never met in a trainer-led room, where the
   street group is always shown. */
#market-making-workspace .mkm-entry-dark:has(> #mkm-dark-group[hidden]):has(> #mkm-street-group[hidden]) {
  display: none;
}

/* The row holds two groups, the dark pool and the street. On a family
   with no dark pool the first one goes and the second takes the row
   (owner, 2026-08-25). Each carries its own head and its own size,
   because they are two different ways to trade away from the lit book
   and a call is a bigger clip than a dark interest. */
#market-making-workspace .mkm-entry-group {
  display: flex;
  align-items: center;
  gap: var(--mkm-entry-gap);
  min-width: 0;
}
#market-making-workspace #mkm-dark-group { flex: 1 1 0; }
#market-making-workspace #mkm-street-group { flex: 0 1 auto; }
#market-making-workspace .mkm-entry-group[hidden] { display: none; }
/* Alone on the row, the street group spreads into the space the dark
   pool would have taken rather than huddling at one end. */
#market-making-workspace #mkm-dark-group[hidden] + #mkm-street-group {
  flex: 1 1 0;
}

/* The picker wears the platform's own dropdown chrome
   (components.css .settings-dropdown) but is positioned fixed, not
   absolute: the entry row is the last thing inside .mkm-opt-frame, which
   clips its overflow, so a menu anchored to the button opened outside the
   frame and was never drawn. Fixed takes it out of that clip; no ancestor
   here carries a transform, so it really is viewport-positioned. The
   coordinates come from the button's rectangle at open time. */
#market-making-workspace .mkm-street-wrap {
  position: relative;
  flex: 0 0 auto;
  /* Call the street matches Cancel resting's row-driven height (owner,
     2026-08-30): the wrap stretches to the row's tallest child (the size
     input on the street bar, or the lit-row inputs on the spot dark row),
     and the button fills the wrap. */
  align-self: stretch;
}
#market-making-workspace .mkm-street-wrap .btn { height: 100%; }
/* Shared minimum width so Cancel resting and Call the street end at the
   same width regardless of the two texts (owner, 2026-08-30).

   The spot and rates buttons are reached by CLASS, because a session
   that stacks books carries one per book and those have no id. The
   shared row's own button carries the class as well as its id. */
#market-making-workspace .lit-cancel,
#market-making-workspace .rt-cancel,
#market-making-workspace #mkm-opt-cancel-all,
#market-making-workspace #mkm-street-call,
#market-making-workspace #mkm-opt-street-call,
#market-making-workspace #mkm-rt-street-call {
  min-width: 118px;
}
/* Short bond-future label overlaid on the top-left of the rates futures
   book (owner, 2026-08-30): names the future and states its per-lot
   DV01, so a rates trader reads both facts against the book itself
   without hunting elsewhere. Absolute so it does not push the book
   down; the space to the LEFT of the right-aligned BID head is unused
   otherwise and this rides in it. pointer-events off so a click still
   reaches the book underneath. */
#market-making-workspace .mkm-rt-desk .mkm-book-frame { position: relative; }
#market-making-workspace .mkm-street-menu {
  position: fixed;
  top: auto;
  right: auto;
  left: 0;
  min-width: 220px;
  padding: 10px 12px 12px;
  z-index: var(--z-modal);
}
/* The axe picker carries no prose, so it takes the width of its own
   rows rather than the street picker's reading width (owner,
   2026-08-30). */
#market-making-workspace #mkm-rt-axe-menu {
  min-width: 0;
  width: max-content;
}
#market-making-workspace .mkm-street-menu-head {
  font-size: var(--text-meta);
  color: var(--text-muted);
  margin-bottom: 8px;
}
/* The second heading, where the picker asks for the market before the
   traders (owner, 2026-08-31). It follows a list rather than opening the
   menu, so it takes the space that separates the two groups. */
#market-making-workspace .mkm-street-option + .mkm-street-menu-head {
  margin-top: 10px;
}
#market-making-workspace .mkm-street-option {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 0;
  font-size: 0.9rem;
  color: var(--text);
  cursor: pointer;
}
/* The accent on the tick, the way the shared sliders take it. The radio
   that picks the market takes the same, because a rule keyed on the
   input's TYPE stops at the row it was written for. */
#market-making-workspace .mkm-street-option input[type="checkbox"],
#market-making-workspace .mkm-street-option input[type="radio"] {
  flex: 0 0 auto;
  width: 15px;
  height: 15px;
  margin: 0;
  accent-color: var(--color-accent);
  cursor: pointer;
}
#market-making-workspace .mkm-street-empty {
  font-size: 0.9rem;
  color: var(--text-muted);
}
#market-making-workspace .mkm-street-go { margin-top: 10px; width: 100%; }
/* The axe picker: one row per tenor, the tenor on the left and the two
   sides beside it, so posting an axe is one click on the side the desk
   wants (owner, 2026-08-30). The side already standing renders as the
   primary button and takes the axe down when clicked again, so one
   control both shows and pulls. */
#market-making-workspace .mkm-axe-row {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 4px 0;
}
/* The tenor takes only the width it needs, so the two sides sit right
   beside it (owner, 2026-08-30). Letting it absorb the row's spare
   width pushed the buttons to the far edge and made the menu read as a
   wide empty band. */
#market-making-workspace .mkm-axe-row .mkm-axe-tenor {
  flex: 0 0 auto;
  min-width: 34px;
  font-size: 0.9rem;
  color: var(--text);
}
#market-making-workspace .mkm-axe-row .mkm-axe-tenor .num {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}
#market-making-workspace .mkm-axe-row .btn { flex: 0 0 auto; min-width: 52px; }
/* The countdown takes the row's spare width instead of the tenor, so it
   sits at the right edge and the buttons stay next to the tenor. */
#market-making-workspace .mkm-axe-left {
  flex: 1 1 auto;
  min-width: 38px;
  text-align: right;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--text-meta);
  color: var(--text-muted);
}
/* The room's axe colour, above the news feed: what the market is
   talking about, in the feed's own muted register. Nothing here is
   clickable, which is the point (owner ruling, 2026-08-30). */
#market-making-workspace .mkm-room-axes {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 14px;
  padding: 6px 10px;
  font-size: var(--text-meta);
  color: var(--text-muted);
}
#market-making-workspace .mkm-room-axes[hidden] { display: none; }
#market-making-workspace .mkm-room-axe .num {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--text-secondary);
}
#market-making-workspace .mkm-entry-dark-head { flex: 0 0 auto; }
#market-making-workspace .mkm-entry-dark-head .sb-label { margin: 0; }
#market-making-workspace .mkm-entry-dark-row {
  flex: 0 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: var(--mkm-entry-gap);
}
/* The limit is a price, so it takes the width a price needs and no more
   (owner, 2026-08-25). It used to absorb the row's spare width, which
   was invisible while a size field sat beside it and turned it into a
   long empty box the moment that field went. That width is now the
   card's own price measure, which the lit row's price fields read too,
   so Limit and the Bid price over it are the same field width. */
#market-making-workspace .mkm-entry-dark-row .sidebar-input {
  flex: 0 0 auto;
  width: var(--mkm-price-w);
  font-family: var(--font-mono);
}
/* Sell and Buy take the row's own height, the way Place bid and Place
   ask take theirs from the stretching .mkm-entry-side above them (owner,
   2026-09-01). Centred, they sat at the .btn-sm height and read shorter
   than the row over them. */
#market-making-workspace .mkm-entry-dark-row .btn {
  flex-shrink: 0;
  align-self: stretch;
}
/* Both groups take the full height of the dark row, so Call the street
   can stretch inside its own. Its wrap already asks to stretch, but it
   was stretching to a group whose height was the wrap's own, which is
   the button's natural height and no taller. */
#market-making-workspace .mkm-entry-dark > .mkm-entry-group {
  align-self: stretch;
}
/* The street call button rides the dark row, right of the size field,
   and takes its size from it (owner, 2026-08-23). */
#market-making-workspace #mkm-street-call { flex-shrink: 0; }

/* ── Working orders ────────────────────────────────────────────────── */

/* Cancel all lives at the end of the lit entry row (owner, 2026-08-23:
   no header strip spending a row on one button); the working panel is
   pure content.

   It stretches rather than taking the .btn-sm height: Place bid and Place
   ask sit inside .mkm-entry-side, whose default stretch takes them to the
   price field's height, and the row's height is that same height. Reading
   it off the row is what keeps all three buttons equal without pinning a
   pixel value. The horizontal padding is tighter than .btn-sm's for the
   width it frees: the row is full at the column's narrow end, and the
   sides (flex: 1 1 0, min-width: 0) let Place ask overflow its own box
   into this button when it runs short.

   No auto margin: those two sides take every spare pixel in the row, so
   an auto margin here can only collect space when they cannot, and that
   space would show up as one wider gap in a row whose spacing is
   otherwise even. */
/* Spot only. The rates and options rows get the same stretch from
   `.mkm-opt-hedge-entry > .btn` further down, which is structural and
   already reaches the per-book buttons. */
#market-making-workspace .lit-cancel {
  flex-shrink: 0;
  align-self: stretch;
  padding: 0 var(--mkm-entry-gap);
}

/* A book closed to takers (owner request, 2026-08-25). Every price
   still reads: the whole point is that the desk goes on watching the
   market it may not hit. The top of book loses its click affordance and
   its larger type stays, so the shape of the book is unchanged. */
#market-making-workspace .mkm-book--locked .mkm-ob {
  opacity: 0.62;
}
#market-making-workspace .mkm-book--locked .mkm-ob-row--tob {
  cursor: default;
}
#market-making-workspace .mkm-book--locked .mkm-ob-row--tob:hover {
  background: none;
}

/* The grip that opens the book (venue design 2.2). The same invisible
   handle as the right column's seams, laid inside the book frame under
   the last level: dragging it down shows more of the priced book and
   takes the height from the client calls under it. */
#market-making-workspace .mkm-book-grip {
  height: 9px;
  cursor: row-resize;
  border-top: 1px solid var(--border);
}
#market-making-workspace .mkm-book-grip:hover {
  background: color-mix(in srgb, var(--color-accent) 22%, transparent);
}
/* A grip with nothing to drag goes invisible but KEEPS its 9px, so the
   distance from the book to the order entry reads the same whether or
   not the grip is live (owner, 2026-08-29).

   ON A CLASS, NOT ON `[hidden]`. base.css carries
   `[hidden] { display: none !important }`, so the attribute takes the
   element out of the layout and no rule here can put it back. The old
   rule tried and could not, and the space went with the grip: with every
   book collapsed, Call the street sat flush against the book above it
   (owner, 2026-09-01). Nothing that has to RESERVE space can be hidden
   with the attribute in this app. */
#market-making-workspace .mkm-book-grip--off {
  visibility: hidden;
}

/* ── Spot desk frames (same sharp terminal frames as the options desk) ── */
/* The book+entry frame and the working-orders frame keep their natural height;
   the blotter frame fills the rest (its .mkm-col-book .mkm-feed-wrap rule already
   flexes). The book and feeds run to the frame edge; the entry and working body
   get inner padding.

   The order entry sits close under the CLOB (owner, 2026-08-29): its
   padding-top matches the CLOB last row's own padding-bottom, so the
   distance from the last book row to the entry's top border equals the
   distance from that border to the entry's first control. Nothing else
   sits between the two, which is the yesterday behaviour restored. */
#market-making-workspace .mkm-book-frame,
#market-making-workspace .mkm-working-frame { flex: 0 0 auto; }
#market-making-workspace .mkm-book-frame .mkm-entry { padding: 6px 10px 8px; }
#market-making-workspace .mkm-working-frame .mkm-working { padding: 8px 0; }

/* Fixed-height two-column area (bids left, offers right) so the layout
   never shifts as orders are placed, filled or cancelled. 88px to 120px
   with the chart coming down (owner, 2026-08-23), then 168px (owner,
   2026-08-28) because a desk quoting both sides in size holds more
   working orders than either box showed.
   BACK TO 120px (owner, 2026-09-02: the chart wants the room, and this
   panel and the blotter are where it comes from). Nothing is hidden by
   the change: each column scrolls on its own, so a desk with more
   orders than fit reads them by scrolling rather than by taking the
   height off the chart all session.

   STILL 120px with the Working orders heading over it (owner,
   2026-09-09). The head is the frame's, not this grid's, and the frame
   is content-sized, so the head made the frame taller and took nothing
   off the rows on screen. Adding its height here would have shown MORE
   rows than before, not the same number. */
#market-making-workspace .mkm-working {
  flex: 0 0 auto;
  height: 120px;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  overflow: hidden;
}
#market-making-workspace .mkm-working-col {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
  overflow-y: auto;
}
/* The empty line starts where the panel's heading starts (owner,
   2026-09-10). It is text under text, so it takes the head's own 12px
   inset rather than the 2px the grid gave it; the rows that replace it
   are boxes and keep the panel's full width. */
#market-making-workspace .mkm-working-col .mkm-placeholder {
  padding: 4px 12px;
  font-size: 0.78rem;
}
#market-making-workspace .mkm-working-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 3px 10px;
  font-size: 0.82rem;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
}
#market-making-workspace .mkm-working-side {
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.04em;
}
#market-making-workspace .mkm-working-side--buy  { color: var(--positive); }
#market-making-workspace .mkm-working-side--sell { color: var(--negative); }
/* A resting dark interest is not a lit order; a dashed edge marks it apart. */
#market-making-workspace .mkm-working-row--dark { border-style: dashed; }
#market-making-workspace .mkm-working-cancel {
  margin-left: auto;
  border: none;
  background: transparent;
  color: var(--text-muted);
  font-size: 0.95rem;
  cursor: pointer;
  line-height: 1;
  padding: 2px 4px;
}
#market-making-workspace .mkm-working-cancel:hover { color: var(--negative); }
#market-making-workspace .mkm-working-note {
  margin-left: auto;
  font-size: 0.7rem;
  color: var(--text-muted);
  font-style: italic;
}
#market-making-workspace .mkm-row-working { opacity: 0.55; }

/* ── Price chart ───────────────────────────────────────────────────── */

/* The chart tile FILLS its frame, whatever height the row gives it
   (owner, 2026-08-23, the blank-band root cause: a tile shorter than
   its frame paints the difference as a blank strip). The 260px basis is
   what sizes the row when the row is content-sized; a bigger or smaller
   row just moves the tile edge, never opens a strip. The plot itself is
   responsive: #mkm-chart is an absolutely positioned box inside this
   wrap, Plotly autosizes into it, so no pixel height passes through JS.
   The basis came down from 300px with the news and working-orders
   panels going up (owner, 2026-08-23). */
#market-making-workspace .mkm-chart-wrap {
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  position: relative;
  flex: 1 1 260px;
  min-height: 120px;
}
#market-making-workspace #mkm-chart,
#market-making-workspace .mkm-chart-plot {
  position: absolute;
  top: 4px;
  left: 6px;
  right: 6px;
  bottom: 0;
}

/* The last price over the top-left of the plot (owner, 2026-09-09).
   Plotly owns the plot element, so the reading is a box of its own on
   the wrap around it, and desk_chart.js raises layout.margin.t by the
   height set here so no gridline and no y tick label runs under it.

   THE EXPAND BUTTON MOVES TO THE TOP-RIGHT to make room (owner,
   2026-09-09). A single pane with a series picker has the picker in
   that corner already, so the picker steps left of the button and the
   two stand side by side. A grid of panes puts its pickers top-left
   instead (the chart grid section). */
#market-making-workspace .mkm-chart-wrap > .chart-fullscreen-btn {
  left: auto;
  right: 8px;
}
#market-making-workspace .mkm-chart-wrap > .mkm-opt-corner {
  right: 42px;
}
/* ONE ROW: the label, the price and the change side by side (owner,
   2026-09-10). Stacked over two rows it took twice the top margin off
   the plot for the same three readings. */
#market-making-workspace .mkm-chart-last {
  position: absolute;
  top: 4px;
  left: 12px;
  z-index: 2;
  display: flex;
  align-items: baseline;
  gap: 7px;
  /* The hover and the drag belong to the plot under it. */
  pointer-events: none;
}
#market-making-workspace .mkm-chart-last-label {
  font-family: var(--font);
  font-size: 10px;
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-muted);
}
#market-making-workspace .mkm-chart-last-px {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 14px;
  font-weight: 600;
  line-height: 1.2;
  color: var(--text);
}
#market-making-workspace .mkm-chart-last-chg {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.2;
  color: var(--text-muted);
}
#market-making-workspace .mkm-chart-last-chg.positive { color: var(--positive); }
#market-making-workspace .mkm-chart-last-chg.negative { color: var(--negative); }

/* ── Client calls ──────────────────────────────────────────────────── */

#market-making-workspace .mkm-calls-wrap {
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
/* The calls area is a fixed two-column grid of pinned slots (owner,
   2026-08-23): every ticket takes the highest free cell on arrival and
   keeps it until it leaves (takeSlot in desk.js writes the grid row and
   column inline), so tickets never move while someone is quoting. */
#market-making-workspace .mkm-calls {
  flex: 1 1 0;
  min-height: 0;
  overflow-y: auto;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  align-content: start;
  gap: 10px;
}
#market-making-workspace .mkm-calls .mkm-placeholder {
  grid-column: 1 / -1;
}
/* Tight vertical padding on purpose: four tickets stand in the panel at
   once, so every row of a ticket costs one of them (owner, 2026-08-23).

   AN INCOMING CALL SHOWS NO EDGE (owner, 2026-09-10): the fill is what
   says a ticket is there. The border stays as a TRANSPARENT SLOT rather
   than going, because it is the ticket's state mark and four rules below
   fill it in - the accent while a quote is live, and the three outcome
   colours once the client has dealt or walked. A ticket that grew a
   border only when it resolved would move everything under it in the
   panel at the moment it resolved.

   ONE PIXEL, down from three (owner, 2026-09-10): three read as a slab
   around the card once it was the only edge on it, and 1px is the line
   every other mark on the desk is drawn at. */
#market-making-workspace .mkm-ticket,
#market-making-workspace .mkm-ticket-out {
  background: var(--bg-elevated);
  border: 1px solid transparent;
  padding: 8px 14px 10px;
  cursor: pointer;
}
/* The caller's own outgoing street ticket: an accent edge tells it apart
   from the incoming tickets around it. */
#market-making-workspace .mkm-ticket-out {
  border-color: var(--color-accent);
  cursor: default;
}
/* One grid for the whole block, not a grid per row: the rows are
   display: contents, so the name, the bid and the offer share three
   columns down the ticket and the Pass button in the head row lands over
   the offer column (owner, 2026-08-25). The row element stays in the DOM
   for the per-callee lookup that paints the prices. */
#market-making-workspace .mkm-street-rows {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: center;
  gap: 6px 8px;
  margin: 8px 0;
}
#market-making-workspace .mkm-street-row { display: contents; }
#market-making-workspace .mkm-street-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.9rem;
}
/* The deal buttons carry a price, so they take the mono face; Pass is a
   word and keeps the interface face. Both hold the column width. */
#market-making-workspace .mkm-street-row .btn { min-width: 74px; }
#market-making-workspace .mkm-street-row .btn[data-deal] {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}
#market-making-workspace .mkm-ticket-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 10px;
}
/* The client's name holds one line whatever its length (owner,
   2026-08-23): a ticket is half the calls panel wide, and the longest
   names in the cast ran onto a second line, which moved everything under
   the head down. Cut with an ellipsis, the way the street ticket already
   treats the participant names beside it. The first word is what
   identifies the client, and that is the part that always survives. */
#market-making-workspace .mkm-ticket-client {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 600;
  font-size: 1.02rem;
}
#market-making-workspace .mkm-ticket-timer {
  flex: 0 0 auto;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  font-size: 1rem;
  color: var(--text-secondary);
}
#market-making-workspace .mkm-ticket-urgent .mkm-ticket-timer {
  color: var(--warning);
}
#market-making-workspace .mkm-ticket-type {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  font-size: var(--text-meta);
  color: var(--text-muted);
  margin-top: 1px;
}
/* This row holds ONE line whatever it carries, for the reason the client's
   name above it does (owner, 2026-08-23), and the calls panel makes the
   cost higher here. A rates client type runs to "Sovereign reserve
   manager"; put the competition marker beside it and the outcome
   opposite, and the row wrapped to two lines the moment a ticket
   resolved. The panel is a grid, so the ticket next to it stretched to
   match and one resolved ticket made its whole row taller (owner,
   2026-08-28). The client type is what gives way: the marker and the
   outcome are short and stay whole. */
#market-making-workspace .mkm-ticket-who {
  display: flex;
  align-items: baseline;
  gap: 6px;
  min-width: 0;
}
#market-making-workspace .mkm-ticket-who > span:first-child {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* The trade outcome, from the client's side, shown top-right once the ticket
   resolves: the client sold (maker bought), the client bought (maker sold), or
   no deal (walked). */
#market-making-workspace .mkm-ticket-outcome {
  flex: 0 0 auto;
  white-space: nowrap;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
#market-making-workspace .mkm-outcome--sold   { color: var(--positive); }
#market-making-workspace .mkm-outcome--bought  { color: var(--negative); }
#market-making-workspace .mkm-outcome--none    { color: var(--text-muted); }
/* One fact per labeled row, readable top to bottom. */
#market-making-workspace .mkm-ticket-facts {
  display: grid;
  grid-template-columns: max-content 1fr;
  column-gap: 16px;
  row-gap: 5px;
  margin: 6px 0 8px;
  padding-top: 6px;
  border-top: 1px solid var(--border);
  /* Label and value share a text baseline so the smaller muted label lines up
     with the larger value on its right. */
  align-items: baseline;
}
/* TWO label/value pairs per line (must follow the rule above to win on source
   order). A ticket already had white space to the right of its values, so the
   trade's delta and vega ride there rather than costing rows: the risk reads at a
   glance while you are typing the vol. */
#market-making-workspace .mkm-ticket-facts--pairs {
  grid-template-columns: max-content minmax(0, 1fr) max-content max-content;
}
/* A SIZE'S UNIT IS A WORD (owner, 2026-09-10): lots, mm, BTC. It rides
   beside a mono number, often inside a cell that is mono itself, so it
   states the text face rather than relying on where it sits. */
#market-making-workspace .mkm-qty-unit,
.mkm-qty-unit {
  font-family: var(--font);
}
/* THE SPOT CLIENT TICKET READS AS ONE LINE OF VALUES (owner,
   2026-09-10): the contract, the size and what the client is asking
   for, with no labels between them. The direction sits at the right
   end, so the eye finds it in the same place down a stack of four
   tickets. Follows the base rule to win on source order, like the two
   modifiers around it. */
#market-making-workspace .mkm-ticket-facts--line {
  grid-template-columns: 1fr max-content 1fr;
  column-gap: 12px;
}
/* The size is centred on the TICKET, not between its two neighbours:
   the outer columns take an equal share of whatever is left, so the
   middle one sits on the ticket's centre line however long the
   contract's name is. */
#market-making-workspace .mkm-ticket-facts--line .mkm-fact-req,
#market-making-workspace .mkm-ticket-facts--line .mkm-fact-end {
  justify-self: end;
}
/* The outgoing street ticket carries Pass at the right end of its Size
   row (owner, 2026-08-25). Centred rather than on the baseline: a button
   sitting on the text's baseline hangs below the line it is on. Follows
   the base rule to win on source order, like the pairs modifier above. */
#market-making-workspace .mkm-ticket-facts--street {
  grid-template-columns: max-content minmax(0, 1fr) max-content;
  align-items: center;
}
#market-making-workspace .mkm-fact-label {
  font-size: var(--text-meta);
  color: var(--text-muted);
}
#market-making-workspace .mkm-fact-req {
  font-weight: 600;
}
/* Figures in a ticket (the delta, vega and size the clip carries) read mono and
   tabular, like every other number on the desk. There is no global .num rule, so
   each region states it. The labels, the structure / option name and the legs are
   TEXT and stay in the text face. */
#market-making-workspace .mkm-ticket-facts .num {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}
/* Prices and buttons on one line (owner, 2026-08-23). The line has room
   for both only because the parts are sized to what they hold: the
   fields to six digits, which is the longest price the cast quotes
   (102.11 on a stock, 1.0851 on a pair), and the buttons to their own
   labels rather than the standard .btn-sm inset. */
#market-making-workspace .mkm-ticket-form {
  display: flex;
  gap: 8px;
  align-items: stretch;             /* Send / Risk take the exact height of the
                                       price input and sit perfectly level */
}
/* Anchored to the right edge of the ticket, so Send and Risk are in the
   same place on a one-way call as on a two-way one (owner, 2026-08-23):
   a one-way ticket carries a single price field, and without the auto
   margin its buttons sat a field's width to the left of the two-way
   ones beside it. */
#market-making-workspace .mkm-ticket-actions {
  display: flex;
  gap: 6px;
  flex: 0 0 auto;                    /* the form stretches this wrapper to the
                                       input's height, giving the buttons a
                                       definite parent for height:100% */
  margin-left: auto;
}
#market-making-workspace .mkm-ticket-actions .btn { padding: 0 8px; }
#market-making-workspace .mkm-ticket-actions .btn { height: 100%; }
#market-making-workspace .mkm-quote-field {
  display: flex;
  flex-direction: column;
  gap: 2px;
  /* Sized to the price it holds and little wider: seven digits plus the
     input's 8px paddings and its border, capped a little above that so
     a spare pixel in the row never turns the field into a box a price
     rattles around in. Six digits is what the cast quotes on a stock
     (102.11) and seven on the wider pairs (16.0965), which is the one
     the field is cut to. The field carries the input's own font so the
     ch unit measures the digit the input actually renders. It went from
     six to seven once the book column took the width back (owner,
     2026-08-25). */
  flex: 1 1 0;
  font-family: var(--font-mono);
  font-size: 0.95rem;
  min-width: calc(7ch + 18px);
  max-width: calc(7ch + 26px);
}
/* Every input on the desk holds a number: the order size, the two lit
   prices, the dark limit and size, the street size, and the two quote
   fields on a client ticket. They all centre (owner, 2026-08-25), so a
   short price and a long one sit in the same place in their box.

   NO HORIZONTAL PADDING (owner, 2026-09-10). The shared field takes
   10px off each side, and on the index and metal contracts that is the
   room a grouped price needs: "29,546.75" is nine characters in a box
   measured in eight. The number centres in the box either way, so the
   padding bought nothing and cost a character. This replaces the
   per-field .sidebar-input--narrow-num class, which existed to tighten
   the same padding on the two longest contracts alone. */
#market-making-workspace .sidebar-input {
  text-align: center;
  padding-left: 0;
  padding-right: 0;
}

#market-making-workspace .mkm-ticket-form .sidebar-input {
  width: 100%;
  font-family: var(--font-mono);
  padding: 6px 0;
  font-size: 0.95rem;
}
/* The price the client dealt on: bold and full-strength even though the
   resolved ticket's inputs are disabled. */
#market-making-workspace .mkm-quote-dealt.sidebar-input {
  font-weight: 800;
  color: var(--text);
  opacity: 1;
}
/* A live quote the client is considering. */
#market-making-workspace .mkm-ticket-quoted { border-color: var(--color-accent); }
/* The call the keyboard is on. THE FILL IS THE CHANNEL, and the ticket
   keeps its one edge. The border already has three other meanings here
   (idle, live quote, and the three outcome colours), so a fourth border
   colour would read as a fifth outcome, and a second edge inside or
   outside the first reads as a double border. A picked ticket is never
   a resolved one, so the fill has only two states to stand apart from,
   and it does that on both of them.

   TWO RINGS WERE TRIED AND BOTH FAILED, in this order (owner reports,
   2026-09-08). An outset one was cut off down its left and right sides:
   the calls panel is a scroll container, `overflow-y: auto` computes
   overflow-x to auto with it, and a ticket in either column of the grid
   sits flush against the edge it clips at. An inset one survived that
   and read as a light border with a dark one inside it. Do not add a
   third. If the fill needs to be stronger, change the fill. */
#market-making-workspace .mkm-ticket-active {
    background: color-mix(in srgb, var(--color-accent) 12%, var(--bg-elevated));
}
/* The card takes focus itself while the engine holds the quote and every
   field on it is disabled, so the browser's own focus ring would draw a
   second mark over the one above. */
#market-making-workspace .mkm-ticket:focus { outline: none; }
/* Resolved ticket: outcome border, lingers a few seconds before closing.
   Green = you bought, red = you sold, grey = no trade (walked). */
#market-making-workspace .mkm-ticket-done { opacity: 1; }
/* The trade-outcome ring: green when the client bought, red when they sold, grey
   when they walked (below). All three are the same thickness so a no-trade reads
   as deliberately as a trade. */
#market-making-workspace .mkm-ticket-done--buy {
  border-color: var(--positive);
}
#market-making-workspace .mkm-ticket-done--sell {
  border-color: var(--negative);
}
#market-making-workspace .mkm-ticket-done--none {
  border-color: var(--text-muted);
}
/* ── Feed ──────────────────────────────────────────────────────────── */

#market-making-workspace .mkm-feed-wrap {
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
#market-making-workspace .mkm-feed {
  overflow-y: auto;              /* the one region allowed to scroll */
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: 6px 0;
}
#market-making-workspace .mkm-feed-item {
  display: flex;
  gap: 10px;
  padding: 4px 12px;
  font-size: 0.92rem;
  line-height: 1.5;
}
#market-making-workspace .mkm-feed-time {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
  flex-shrink: 0;
  min-width: 42px;
  text-align: right;
}
#market-making-workspace .mkm-feed-text { color: var(--text-secondary); }
#market-making-workspace .mkm-feed-item--news .mkm-feed-text {
  color: var(--text);
  font-weight: 600;
}
#market-making-workspace .mkm-feed-item--fill .mkm-feed-text { color: var(--text); }
#market-making-workspace .mkm-feed-item--flag .mkm-feed-text {
  color: var(--warning);
  font-weight: 600;
}
/* ── Sidebar: position / P&L / limits / stats ──────────────────────── */

#market-making-workspace .mkm-sb-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 8px;
  padding: 4px 0;
  font-size: 0.95rem;
  color: var(--text-secondary);
}
#market-making-workspace .mkm-sb-row .num {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  color: var(--text);
}
#market-making-workspace .mkm-sb-row .num.positive { color: var(--positive); }
#market-making-workspace .mkm-sb-row .num.negative { color: var(--negative); }
/* The value on its own line under the label, for a row whose two halves
   are both long (owner, 2026-08-25). The position against its limit is
   the one: the label carries the unit and the value carries two numbers,
   and side by side they set the width of the whole sidebar and wrapped
   the label onto a second line as soon as a position was taken. This
   block follows the base row rule rather than preceding it: the two
   carry the same specificity, so the later one wins. */
#market-making-workspace .mkm-sb-row--stack {
  display: block;
}
#market-making-workspace .mkm-sb-row--stack > span:first-child {
  white-space: nowrap;
}
/* Scoped to the direct value span (owner, 2026-08-30): a `.num` nested
   inside the label — the tenor prefix "10y" carries one for the mono
   run — is inline and stays on the label line. Only the row's own
   value drops to its own block. */
#market-making-workspace .mkm-sb-row--stack > .num {
  display: block;
  margin-top: 1px;
  /* Right, so it lines up with every other number in the sidebar, which
     the flex rows push to the same edge (owner, 2026-08-25). */
  text-align: right;
}
/* A secondary sidebar row that reads as a breakdown of the row above
   it (owner, 2026-08-29). The muted ink and the smaller size say
   "explanation of what's above, not a peer metric"; the left indent
   sets it apart from the flat list of rows around it. */
/* One treatment for all of them: the lots under a future, a swap's
   notional under its own DV01, and the differential at the open under
   the differential. The muted token and nothing on top of it - an
   opacity over it as well would take these under 4.5:1. */
#market-making-workspace .mkm-sb-row--sub {
  font-size: 12.5px;
  color: var(--text-muted);
  padding: 0 0 2px 12px;
}
#market-making-workspace .mkm-sb-row--sub .num {
  color: var(--text-muted);
}
/* Both-currency P&L (FX): the base-ccy equivalent reads as a lighter second
   line under the native quote-ccy figure. */
#market-making-workspace .mkm-sb-sub {
  display: block;
  text-align: right;
  font-size: var(--text-meta);
  font-weight: 500;
  color: var(--text-muted);
}

#market-making-workspace .mkm-meter {
  height: 5px;
  border-radius: 3px;
  background: var(--bg-surface);
  border: 1px solid var(--border);
  overflow: hidden;
  margin: 2px 0 6px;
}
/* A hairline for a row that is one of many (owner, 2026-09-10): the
   rates desk draws one under every tenor of its curve, and four full
   meters plus the net's filled a column that is already the longest of
   the four desks. No border, because a 1px edge on a 3px bar leaves one
   pixel of fill. Still centre-anchored, and the zero tick rides it. */
#market-making-workspace .mkm-meter--thin {
  height: 3px;
  border: 0;
  border-radius: 0;
  margin: 1px 0 5px;
}
#market-making-workspace .mkm-meter-fill {
  height: 100%;
  background: var(--color-accent);
}
#market-making-workspace .mkm-meter--breach .mkm-meter-fill {
  background: var(--negative);
}
/* Centre-anchored position meter: zero in the middle, the fill grows right
   (long) or left (short) toward the limit at each end. */
#market-making-workspace .mkm-meter--center { position: relative; }
#market-making-workspace .mkm-meter--center .mkm-meter-fill {
  position: absolute;
  top: 0;
  bottom: 0;
  height: 100%;
}
#market-making-workspace .mkm-meter-zero {
  position: absolute;
  left: 50%;
  top: 0;
  bottom: 0;
  width: 1px;
  transform: translateX(-0.5px);
  background: var(--text-muted);
}
/* Two states, two colours (owner, 2026-08-23). The line answers one
   question, whether the position is inside its limit, so it is green
   while it is and red once it is not. The meter keeps its continuous
   shading: a large position that is still inside its limit shades the
   bar toward red, and reading "IN LIMIT" in red said the opposite of
   what the words say. */
#market-making-workspace .mkm-limit-status {
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  color: var(--positive);
  margin-top: 2px;
}
#market-making-workspace .mkm-limit-status--out { color: var(--negative); }

/* ── A LEAD READING, and the total P&L ─────────────────────────────
   The reading a maker checks between quotes leads its section (owner,
   2026-09-09): a large figure over its meter, with the limit beside it
   at reading size. Everything else in the sidebar stays a label-left
   value-right row.

   ONE TREATMENT, THREE BLOCKS. The spot desk's net position was the
   first, and the options desk's net delta and vega took it on
   2026-09-10, which is why these are named for what they DO rather
   than for the position they started on. A fourth surface uses them
   rather than porting them, the rule the book, the units and the
   working orders already follow.

   Mono is the numerals and nothing else, so "of", "/" and "avg" read
   in the interface face, which is how desk_working.js already builds
   a row. */
/* Where the block carries a label of its own. The spot desk's position
   needs none: its section heading is the label, and it holds one lead.
   A block that holds two, as Risk does on the options desk, names each
   of them. The tip sits on this wrapper, so it answers over the label
   and the figure alike. */
#market-making-workspace .mkm-sb-lead-label {
  font-size: 0.95rem;
  color: var(--text-secondary);
}
/* A run of rows that belongs together under a block that has a heading,
   without taking a heading of its own: the FX desk's Skew and Wing sit
   under the limit line as vega-family readings rather than as limits. */
#market-making-workspace .mkm-sb-block {
  margin-top: 8px;
  padding-top: 6px;
  border-top: 1px solid var(--border);
}
#market-making-workspace .mkm-sb-lead-row {
  display: flex;
  align-items: baseline;
  gap: 8px;
  min-width: 0;
  padding: 2px 0 4px;
}
/* The theme's normal ink, NOT the P&L green and red: the sign in front
   of the figure is what says long or short, and colouring it as well
   read as a profit. */
#market-making-workspace .mkm-sb-lead {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 22px;
  font-weight: 700;
  line-height: 1.1;
  color: var(--text);
}
#market-making-workspace .mkm-sb-lead-of {
  font-family: var(--font);
  font-size: 14px;
  color: var(--text-muted);
  white-space: nowrap;
}
#market-making-workspace .mkm-sb-lead-of .num {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}
/* The rates desk is the one that colours its lead, because a DV01's sign
   says payer or receiver and that is the reading the desk works in. The
   other three leave theirs in the normal ink: a net position and a net
   delta say long or short by their sign alone, and green and red on
   those desks are money. */
#market-making-workspace .mkm-sb-lead.positive { color: var(--positive); }
#market-making-workspace .mkm-sb-lead.negative { color: var(--negative); }
/* One line under the meter carries both readings: whether the position
   is inside its limit, and what it was taken at. */
#market-making-workspace .mkm-pos-foot {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
}
/* Right-aligned whether or not the limit reading shares its line: on a
   multi-instrument desk each contract's foot has the average price only. */
#market-making-workspace .mkm-pos-avg {
  margin-left: auto;
  font-family: var(--font);
  font-size: 0.8rem;
  color: var(--text-muted);
  white-space: nowrap;
}
#market-making-workspace .mkm-pos-avg .num {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  color: var(--text-secondary);
}

#market-making-workspace .mkm-pnl-total {
  padding: 2px 0 8px;
}
/* The same size as the net position above it (owner, 2026-09-10): the two
   are peer readings and one of them set larger than the other read as a
   ranking they do not have. */
#market-making-workspace .mkm-pnl-total .num {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 22px;
  font-weight: 700;
  line-height: 1.1;
  color: var(--text);
}
#market-making-workspace .mkm-pnl-total .num.positive { color: var(--positive); }
#market-making-workspace .mkm-pnl-total .num.negative { color: var(--negative); }
#market-making-workspace .mkm-pnl-split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}
#market-making-workspace .mkm-pnl-cell {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 1px;
}
#market-making-workspace .mkm-pnl-label {
  font-family: var(--font);
  font-size: var(--text-meta);
  color: var(--text-muted);
}
#market-making-workspace .mkm-pnl-cell .num {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 0.95rem;
  font-weight: 600;
  line-height: 1.2;
  color: var(--text);
  white-space: nowrap;
}
#market-making-workspace .mkm-pnl-cell .num.positive { color: var(--positive); }
#market-making-workspace .mkm-pnl-cell .num.negative { color: var(--negative); }
/* The base-currency second line (FX) reads under the figure it belongs
   to. These blocks are left-aligned, unlike the rows above, where the
   same line sits right under a right-aligned value. */
#market-making-workspace .mkm-pnl-total .mkm-sb-sub,
#market-making-workspace .mkm-pnl-cell .mkm-sb-sub {
  text-align: left;
  line-height: 1.3;
}

/* ── End screen ────────────────────────────────────────────────────── */

/* The box the expand button hangs in, the desk's .mkm-chart-wrap pattern:
   Plotly owns the plot element, so the button sits on a wrap around it. */
.mkm-end-chartwrap { position: relative; }
/* A fixed slot, so the page never jumps as Plotly draws into it. Both
   debrief charts are the same box in the same grid and one rule holds
   them. */
.mkm-end-chart {
  height: 260px;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 4px 6px;
}

/* The report is a stack of blocks with one gap between them. It carries
   no width of its own: the page it renders into supplies the reading
   column, which is what makes the live end screen and the Sessions page
   replay the same page (owner, 2026-08-26). */
/* The report is a column of sections with air between them (owner,
   2026-09-12). At 10px the ranking, the score breakdown, the charts and
   the folds ran together as one wall of rules; the gap is what separates
   one reading from the next now that nothing else does. */
.mkm-end-inner {
  display: flex;
  flex-direction: column;
  gap: 28px;
}
/* A heading belongs to the section under it, so it keeps the column's
   gap above it and sits close to its own table. */
.mkm-end-inner h4 { margin-top: 0; margin-bottom: 2px; }
/* A SECTION IS A HEADING AND WHAT IT NAMES, and every one of them is
   the same column: the report's header with the ranking under it, a
   fold head with the panel it opens, and each cell of the chart grid.
   The heading sits 10px above its own content, so the report's 28px
   falls between sections rather than between a heading and its table. */
.mkm-end-section,
.mkm-end-head,
.mkm-end-chartgrid > div {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

/* ── The report's header: the heading and the room ──
   The ranking stands where it always stood, first after the heading; the
   heading joined it rather than standing over a section like any other
   (owner, 2026-09-10). */
.mkm-end-headline {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 24px;
}
/* THE ONE TITLE ON THE SCREEN. It had been taking the shared sheet's
   heading size, 1.1rem in a weight of 600, which is a size on no scale
   and a third weight on a screen that states two. At the report's
   reading size of 16px it would also have stood only a hair above the
   cells under it. 22px is what the trainer's console gives a page title
   (owner, 2026-09-13). */
.mkm-end-headline h3 {
  font-size: 22px;
  font-weight: 700;
}
/* EVERY ROW, and the box scrolls rather than the report (owner,
   2026-09-10). A class of twenty-five ranked in full is taller than the
   laptop the debrief is read on, and the report under it has to stay
   reachable. The header row stays put while the rows move, so a reader
   scrolled halfway down still knows which column they are in. */
.mkm-rank-box {
  max-height: 430px;
  overflow-y: auto;
  overflow-x: auto;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
}
/* Opaque, and in the ground the report is read on: a sticky header over
   scrolling rows shows whatever is behind it wherever it is not. */
.mkm-rank-box thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--bg-surface);
}
/* The reader's own row: a tint and a bold name, and NOTHING ELSE. No
   edge bar, no inset shadow, no border. The tint is on the page for as
   long as the page is, so it outlasts the pointer: the hovered state is
   named here with the resting one rather than replacing it further
   down. The colour is --mkm-tint, one value per theme at the top of
   this file. */
.mkm-end-inner .data-table tbody tr.mkm-rank-mine td,
.mkm-end-inner .data-table tbody tr.mkm-rank-mine:hover td {
  background: var(--mkm-tint);
}
.mkm-rank-mine td:nth-child(2) { font-weight: 700; }
/* Two charts across on a wide screen (owner, 2026-08-26). */
.mkm-end-chartgrid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  /* Air between the two charts, the column gap the report reads at
     (owner, 2026-09-12): they sat against each other and read as one
     picture in two halves. */
  gap: 28px 40px;
  align-items: start;
}

/* The score breakdown: one block per score component, each with its own
   heading and small table. The columns are stated by .mkm-end-scored
   below, which every one of these grids carries. */
.mkm-end-attrib {
  display: grid;
  gap: 24px;
}
/* A block heading and a column heading are one rank of type, so the
   report reads as one table rather than a page of small titles (owner,
   2026-09-11). The type is the label treatment at the top of this file
   at the report's own size; only the space under it belongs here. */
.mkm-attrib-heading { margin-bottom: 6px; }
/* The score's own section runs its four blocks on ONE row (owner,
   2026-09-11): the totals, then the three components that have a
   breakdown, read across together rather than wrapping into a second
   row. It falls to two columns before the tables would crush, and to
   one on a narrow screen, with the attribution grid. */
.mkm-end-attrib.mkm-end-scored {
  grid-template-columns: repeat(4, minmax(0, 1fr));
}
@media (max-width: 1180px) {
  .mkm-end-attrib.mkm-end-scored {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (max-width: 900px) {
  .mkm-end-attrib.mkm-end-scored { grid-template-columns: minmax(0, 1fr); }
}
/* Every table in the report starts where its heading starts (owner,
   2026-09-11, extended to the whole report 2026-09-12). The shared
   table pads every cell, so a first column sat indented under a heading
   that carries no padding of its own, and each section read as two
   edges instead of one. The ranking box is inside the report, so one
   pair of selectors reaches its table too. */
.mkm-end-inner .data-table td:first-child,
.mkm-end-inner .data-table th:first-child { padding-left: 0; }

/* A section that opens when it is asked for (owner, 2026-09-12): the
   clients and markouts tables, and the news review. The head carries
   the section's own eyebrow and the desk's fold chevron, and it reads
   as a heading rather than as a button: no fill, no border, the
   report's own left edge. */
.mkm-end-fold {
  display: flex;
  align-items: center;
  gap: 9px;
  width: 100%;
  color: inherit;
}
/* The chevron is the trainer console's own (console.css
   `.card-collapsible .card-title::before`, owner 2026-09-12): a solid
   triangle drawn in borders, pointing right when the section is closed
   and turned down when it is open, and taking the accent on hover. The
   text glyph it replaced was a hairline at this size and could barely
   be seen. */
.mkm-end-fold-go {
  flex-shrink: 0;
  width: 0;
  height: 0;
  border-style: solid;
  border-width: 4px 0 4px 7px;
  border-color: transparent transparent transparent var(--text-secondary);
  transition: transform 0.15s ease;
}
.mkm-end-fold[aria-expanded="true"] .mkm-end-fold-go {
  transform: rotate(90deg);
}
.mkm-end-fold:hover .mkm-eyebrow,
.mkm-end-fold:focus-visible .mkm-eyebrow { color: var(--text-secondary); }
.mkm-end-fold:hover .mkm-end-fold-go,
.mkm-end-fold:focus-visible .mkm-end-fold-go {
  border-left-color: var(--color-accent);
}

/* THE ONE SIZE STEP: inside the report a BLOCK heading reads at 13px,
   one step up from the 11px every other label takes, so a block is
   announced above the columns it contains.

   A COLUMN HEADING IS NOT A BLOCK HEADING and no longer takes the step
   (owner, 2026-09-13). It reads at 11px, which is the console's size
   for the same thing, so the two dashboards state a column the same
   way. The weight under a column's name keeps 11px as it always did:
   the name leads and the weight follows it (owner, 2026-09-11). */
.mkm-end-inner .mkm-eyebrow,
.mkm-attrib-heading { font-size: 13px; }

/* A headline is a sentence, not a number: it reads from the left and it
   wraps (owner, 2026-09-11). The shared data table right-aligns every
   cell and holds them on one line, which is right for a column of
   figures and pushed the news table off the screen on a long headline.
   The column takes the width the rest of the table does not need. */
.mkm-end-inner .data-table td.mkm-news-line,
.mkm-end-inner .data-table th.mkm-news-line {
  text-align: left;
  white-space: normal;
  width: 100%;
}
@media (max-width: 900px) {
  .mkm-end-chartgrid { grid-template-columns: minmax(0, 1fr); }
}
/* Both-currency P&L rows in the end report (FX), same pattern as the
   sidebar. A caption under a number, so it reads one step under the
   cell it belongs to; it had been 0.85rem in a weight of 500, a size
   and a weight the report uses nowhere else (owner, 2026-09-13). The
   report states two weights and no more: 700 for a label, the app's
   own for everything a reader reads. */
.mkm-end-sub {
  display: block;
  font-size: 13px;
  color: var(--text-muted);
}

/* ── The report's tables: rules, not boxes ──────────────────────────
   The shared .data-table-wrap draws a box around every table it holds,
   and a page of a dozen of them read as a page of boxes (owner,
   2026-09-10). Inside the report a table is its rules and nothing else.
   Every rule here is scoped to .mkm-end-inner, which the ranking box
   sits inside, so the trainer console and the platform's own tools read
   the shared component unchanged. The corners are already square for
   the whole page at the top of this file. */
.mkm-end-inner .data-table-wrap {
  border: 0;
  background: none;
}
/* THE READING SIZE. The debrief is read, not traded on, and the app it
   sits in sets its root at 16px (base.css). Its cells had been taking
   the shared table's 0.78rem, which renders at 12.5px, so the whole
   report read small against its own app (owner, 2026-09-13). A cell
   reads at the app's own size now. The numeric cells keep the
   monospace face the shared table gives them. */
.mkm-end-inner .data-table td {
  font-size: 16px;
}
/* The header is hairlines above and below, and its type is the label
   treatment at the top of this file, at the console's size for a column
   heading rather than the report's block-heading step. */
.mkm-end-inner .data-table thead th {
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  /* Every name starts at the top of the row, so a column carrying a
     weight under its name does not push the names beside it down the
     cell (owner, 2026-09-11). */
  vertical-align: top;
}
/* A score column's own weight, on its own line under the column's name
   (owner, 2026-09-11). The type is the label treatment's 11px. */
.mkm-th-weight { display: block; }
.mkm-end-inner .data-table tbody td {
  border-bottom: 1px solid var(--border);
}
/* A plain fill on hover, and no bar: the report marks the reader's own
   ranking row with a tint, and a bar answering the pointer read as a
   second mark of the same kind. The bar itself is off for the whole
   page at the top of this file, so this states the fill alone. */
.mkm-end-inner .data-table tbody tr:hover td {
  background: var(--bg-elevated);
}

/* ── Printing the debrief ───────────────────────────────────────────
   It prints as long as it needs. The ranking box scrolls on screen and
   must not on paper, and no table or heading is split across a page
   break (owner, 2026-09-10). */
@media print {
  .mkm-rank-box {
    max-height: none;
    overflow: visible;
  }
  .mkm-rank-box thead th { position: static; }
  .mkm-end-chartgrid > div,
  .mkm-end-attrib > div {
    break-inside: avoid;
  }
  .mkm-end-inner h4,
  .mkm-attrib-heading {
    break-after: avoid;
  }
}

/* ── Sharp terminal frames ──────────────────────────────────────────────
   Each panel is a thin square-cornered outline, no rounded corners and no
   shadow, so the dense desk reads as distinct regions without titles or cards.
   The inner data boxes drop their own frame so the panel border is the only
   one. Panels carry no header: the columns name themselves. */
#market-making-workspace .mkm-opt-frame {
  min-height: 0;
  display: flex;
  flex-direction: column;
  /* Flat tiled panel, the portfolio desk's terminal chrome (ported on the
     owner's instruction, 2026-08-22: the slate outlines read as dark grid
     lines). No border and no radius: the 1px grid gaps are the only
     separation, so the desk reads as one tiled surface. */
  background: var(--bg-surface);
  border: none;
  border-radius: 0;
  overflow: hidden;
}
#market-making-workspace .mkm-opt-frame .mkm-opt-chain,
#market-making-workspace .mkm-opt-frame .mkm-ob,
#market-making-workspace .mkm-opt-frame .mkm-feed,
#market-making-workspace .mkm-opt-frame .mkm-chart-wrap {
  border: none;
  border-radius: 0;
}
/* SQUARE CORNERS ON EVERY DESK SURFACE (owner, 2026-09-09). The frames
   were already square; the boxes, the tickets, the rows and the controls
   inside them still read the platform's 8px, and a rounded field on a
   square panel is what the desk read wrong on.
   Every border, rule and hairline stays: only the corner changes.

   Scoped to the desk grid and the desk sidebar, NOT to --r-md and not to
   the workspace as a whole. The platform's radius is what login, the
   sessions page, the end report and the trainer console still read in,
   and the end report is a panel of this same workspace, beside the
   grid. */
#market-making-workspace .mkm-grid .mkm-ob,
#market-making-workspace .mkm-grid .mkm-entry,
#market-making-workspace .mkm-grid .mkm-ob-entry,
#market-making-workspace .mkm-grid .mkm-chart-wrap,
#market-making-workspace .mkm-grid .mkm-feed,
#market-making-workspace .mkm-grid .mkm-ticket,
#market-making-workspace .mkm-grid .mkm-ticket-out,
#market-making-workspace .mkm-grid .mkm-working-row,
#market-making-workspace .mkm-grid .sidebar-input,
#market-making-workspace .mkm-grid .sidebar-select-sm,
#market-making-workspace .mkm-grid .btn,
#market-making-workspace .params-sidebar .sidebar-input,
#market-making-workspace .params-sidebar .btn,
#market-making-workspace .params-sidebar .sb-btn-secondary,
#market-making-workspace .params-sidebar .mkm-floor {
  border-radius: 0;
}
/* A control floated in a frame's top-right corner (the chart Price/Vol toggle,
   the client-requests info glyph), so no header bar is needed to hold it. */
#market-making-workspace .mkm-chart-panel .mkm-chart-wrap,
#market-making-workspace .mkm-calls-wrap.mkm-opt-frame {
  position: relative;
}
/* The scheduled-release line (earnings countdown) on the desks that have no
   News heading, where it sits flush to the frame and needs its own inset to
   clear the border and to line its label up with the news timers' left
   column below it.

   The row is one line tall and sits symmetrically between the frame's top
   edge and the first headline (owner, 2026-08-29). The news wrap puts its
   own 8px gap BELOW the line and nothing above it, so the line carries the
   matching 8px on top and no height of its own. Equal space either side of
   whatever the line box measures, rather than a fixed row the text is
   centred in and a gap under it that the centring cannot see.

   A DIRECT CHILD, which is the whole point of the combinator: the spot
   desk's line rides inside the News heading row, where the head supplies
   the inset. This rule outranks the head's on specificity and put its 8px
   back on top of a line the head was already spacing, which is what made
   the News row taller than the two under it (owner report, 2026-09-10). */
#market-making-workspace .mkm-news-wrap.mkm-opt-frame > .mkm-release-line {
  padding: 8px 12px 0;
  align-items: center;
}

/* The client calls run flush with the CLOB and entry above them (owner,
   2026-08-29): no horizontal inset, so the left ticket column aligns
   left with the CLOB and the right column aligns right with it. 8px
   above and below the tickets is the only inset the panel needs. Spot
   desk only: options and rates scope their own calls rules below. */
#market-making-workspace .mkm-col-book .mkm-calls-wrap.mkm-opt-frame .mkm-calls {
  padding: 8px 0;
}
/* Under the collapsed street card the calls add nothing of their own, so
   the space below Call the street is the card's alone and matches the
   grip's above it (owner, 2026-09-01). One :has() with a descendant
   argument rather than two nested ones, which the selector does not
   allow. Every other desk keeps this panel's own top padding, because
   there the entry above it is a real card with its own edge. */
#market-making-workspace
    .mkm-book-frame:has(> .mkm-entry > .mkm-entry-lit[hidden])
    + .mkm-calls-wrap .mkm-calls {
  padding-top: 0;
}

/* THE OPTIONS DESK LEFT THE FULL-WIDTH ROW on 2026-09-02 (owner), the
   last desk to. Its client requests ran along the bottom across both
   columns from 2026-08-29 and now sit in the LEFT COLUMN under the
   market the desk works, where every spot desk puts them. The rates
   desk went back one day earlier. Nothing is scoped to .mkm-opt-desk
   here any more: the panel is the shared .mkm-col-book one, two
   columns, and the right column keeps the height the row was taking. */

/* The rates curve panel took its NATURAL height through an override
   here from 2026-08-30. The rule it overrode now says the same thing,
   so the override is gone and the reasoning lives with it: letting the
   panel fill the column instead was tried for one round, and on a large
   monitor a two-tenor curve stretched its table surface down most of
   the screen, which reads as broken where bare desk reads as the same
   air the column gaps are made of. */


/* ── Desktop-only notice ───────────────────────────────────────────── */

#market-making-workspace .mkm-desktop-notice { display: none; }
@media (max-width: 1199px) {
  #market-making-workspace .mkm-desk { display: none; }
  #market-making-workspace .mkm-desktop-notice {
    display: block;
    padding: 24px 4px;
    max-width: 520px;
  }
  #market-making-workspace.mkm-desk-active .workspace-content {
    overflow-y: auto;
  }
}

/* ── Pause overlay ─────────────────────────────────────────────────────────
   The full-screen hold shown to every desk while the trainer has the session
   paused. Ported from the ALM sim (css/alm.css) so the two sims give the same
   participant a single pause experience. */
/* The hold host is always in the DOM and hidden by the attribute, and
   .pause-overlay sets display, which beats the UA [hidden] rule. Same
   guard as .mkm-grid and .mkm-entry-dark. */
.pause-overlay[hidden] { display: none; }
/* It covers the desk panel, not the viewport (owner, 2026-08-26). Fixed
   and inset from the viewport, it lay over the header too, so the tabs
   were unreachable behind it and a session opened by mistake could not
   be left. Absolute inside the panel leaves the header alone, which is
   the whole point of the header not going inert. */
#market-making-workspace #tab-desk { position: relative; }
#market-making-workspace #mkm-hold { position: absolute; }
.pause-overlay {
  position: fixed;
  inset: 0;
  z-index: 9999;
  background: rgba(11, 11, 12, 0.85);
  backdrop-filter: blur(6px);
  display: flex;
  /* `safe` centre rather than plain centre, with the overflow that makes
     it matter. A card taller than the window is centred by the plain
     keyword, which puts its top edge above the top of the screen where
     no scrolling can reach it. The lobby card is the one that grows: a
     session with a dozen instruments carries a table and an economic
     calendar and the shortcut list under them. Where the card fits,
     which is most sessions and every other hold this overlay carries,
     nothing about it changes. */
  align-items: safe center;
  justify-content: center;
  overflow-y: auto;
  /* No fade (owner, 2026-08-26). The hold is a state of the desk, not a
     notification about it: fading in from transparent meant the desk
     underneath read at full strength for the first 300ms every time the
     hold appeared, which is the desk flashing past on the way into a
     session that has not started. */
}
[data-theme="light"] .pause-overlay {
  background: rgba(245, 245, 247, 0.85);
}
/* Opaque, and no glass. The desk behind a session that has not opened
   holds nothing worth reading, and reading it through the blur is what
   made opening a session look like the desk arriving first. */
#market-making-workspace .pause-overlay--solid {
  background: var(--bg);
  backdrop-filter: none;
}
/* An awareness question covers the SIDEBAR as well as the desk (owner,
   2026-08-31). The hold is absolute inside the desk panel and the
   sidebar is a sibling of that panel, so the cover never reached it,
   and "what is your net DV01 right now" was answerable off the row
   beside the question.

   The content is blurred where the desk is covered, rather than hidden
   under a box of its own: the sidebar scrolls, so an absolutely
   positioned cover would scroll off the top of it. A real raster blur
   at this radius merges every glyph on a 0.95rem row, and the column
   keeps its width so nothing on the desk moves while the question is
   up. The sidebar is already inert under any hold, so there is nothing
   to reach by tabbing into it.

   BLOCK BY BLOCK, and the session slot is out of it, for the same reason
   `setDeskInert` marks the sidebar that way: what a host page puts there
   runs the session rather than plays it, and blurring the way out of a
   question is not what the cover is for. Empty in a trainer-led room. */
#market-making-workspace.mkm-hold-sidebar
    #market-making-params-content > *:not(#mkm-sb-session) {
  filter: blur(6px);
  opacity: 0.35;
  user-select: none;
}
.pause-overlay-content {
  text-align: center;
  max-width: 520px;
  padding: 48px 40px;
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
}
/* The card grows for the instruments table on a room that trades more
   than one (owner report, 2026-08-31). Six columns of content width run
   past 520px, and the table hung out over the card's right edge. Scoped
   to that table, so a single-instrument hold, the quiz and every other
   thing this overlay carries keep the width they had.

   EVERY instruments table, not only the six-column one (owner report,
   2026-09-02). The widening was keyed on the class the wide variant
   carried, so a rates room's four columns were still capped at 520px
   and its own table ran over the same right edge: "Millions of EUR
   notional" is a column on its own. Both variants carry the class now
   and the extra two columns ride a second one.

   AND FOR THE SHORTCUT LIST, which ran over the same edge on every
   lobby card (owner report, 2026-09-08). Its four tracks of content
   width are wider than the 440px a 520px card leaves inside its 40px
   paddings. The card is a shrink-to-fit flex item, so this number is a
   ceiling and never a width: the card takes exactly what its widest
   child measures, and a hold without a list or a table keeps the 520px
   it always had. One ceiling for both, so a room that shows an
   instruments table and the list cannot be given two. */
.pause-overlay-content:has(.mkm-cal-rows--instruments),
.pause-overlay-content:has(.mkm-keys) {
  max-width: min(92vw, 880px);
}
/* The pause reads quietly: the participant should look up at the trainer
   rather than at the screen (owner, 2026-09-10). The icon is muted ink
   at a smaller size and the title carries the weight of a heading rather
   than of an alarm. */
.pause-overlay-icon {
  font-size: 34px;
  margin-bottom: 12px;
  /* Both, because the glyph is Unicode: a font that renders it as text
     takes the ink and one that renders it in colour takes the opacity. */
  color: var(--text-muted);
  opacity: 0.7;
}
.pause-overlay-title {
  font-size: 26px;
  font-weight: 600;
  color: var(--warning);
  margin-bottom: 10px;
}
/* Label + formula button on one line (console.css carries the same rule;
   the MM page does not load that sheet). */
.fb-line {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.fb-line .formula-btn { margin-left: 0; }

/* ── Confirm modal shell ─────────────────────────────────────────────
   showDisclaimerModal() in shared/disclaimer.js builds .modal-overlay /
   .modal-dialog markup, which console.css carries and this page does not
   load. Without these rules the Disclaimer link appended an unstyled
   block at the foot of the page and read as a link that does nothing:
   the same failure the dialog shell below records. Copied from
   console.css "Confirm Modal", with its --radius-lg swapped for this
   page's --r-lg (both 12px) and its --fs-body written as the 16px it is
   set to there. */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(4px);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 10000;
  animation: modalFadeIn 150ms ease;
}
@keyframes modalFadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}
@keyframes modalSlideIn {
  from { opacity: 0; transform: translateY(-12px) scale(0.97); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}
/* Square and flat, the desk's own treatment (owner, 2026-09-10). The
   SCRIM IS UNTOUCHED: the overlay above keeps its ground and its blur,
   which is what tells a reader the desk behind is on hold. */
.modal-dialog {
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 28px 32px 24px;
  min-width: 380px;
  max-width: 460px;
  box-shadow: none;
  animation: modalSlideIn 200ms ease;
}
.modal-title {
  font-size: 18px;
  font-weight: 600;
  color: var(--text);
  padding-bottom: 12px;
  margin-bottom: 16px;
  border-bottom: 1px solid var(--border);
}
.modal-message {
  font-size: 16px;
  color: var(--text-secondary);
  line-height: 1.6;
  margin-bottom: 24px;
}
.modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
}
/* Square, like the dialog holding them (owner, 2026-09-10). These sit on
   the document body rather than inside the workspace, so the desk's own
   square-corner rules never reached them. */
.modal-actions .btn { border-radius: 0; }
/* The Data Calendar reuses the chrome above, which is cut to a paragraph
   of prose. This dialog holds a three-column grid instead, so it is wider
   and it needs the width for it (owner, 2026-08-29). Scoped to this one
   overlay: the Disclaimer keeps the shell as it stands.

   THE CENTRING IS GONE (owner, 2026-09-10). The title carries a rule
   under it across the whole dialog and the Close button holds the right
   edge, so a centred title over a centred grid read as a third alignment
   on a dialog that has two. */
#mkm-calendar-overlay .modal-dialog { max-width: 560px; }

/* ── Dialog shell ────────────────────────────────────────────────────
   openDialog() in shared/dialog.js builds .iro-dialog-overlay markup, and
   this page loads neither console.css nor portfolio-sim.css, which carry
   the base rules. Without them the About dialog rendered as unstyled text
   at the foot of the page, the same failure portfolio-sim.css records at
   its own copy of this block. Copied from there. */
.iro-dialog-overlay {
  position: fixed;
  inset: 0;
  z-index: var(--z-max);
  background: rgba(0,0,0,0.7);
  display: flex;
  align-items: center;
  justify-content: center;
  backdrop-filter: blur(var(--blur-sm));
}
.iro-dialog {
  background: var(--bg-surface, #151518);
  border: 1px solid var(--border, #333);
  border-radius: 12px;
  width: min(460px, 92vw);
  max-height: 85vh;
  display: flex;
  flex-direction: column;
  box-shadow: var(--shadow-lg);
}
.iro-dialog.iro-dialog-wide { width: min(1100px, 94vw); }
.iro-dialog-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 20px;
  border-bottom: 1px solid var(--border, #333);
  flex-shrink: 0;
}
.iro-dialog-header h3 { margin: 0; font-size: 1.1rem; font-weight: 700; }
.iro-dialog-close {
  background: none;
  border: none;
  color: var(--text-muted);
  font-size: 1.4rem;
  cursor: pointer;
  padding: 4px 8px;
  border-radius: 6px;
  transition: color 0.2s, background 0.2s;
}
.iro-dialog-close:hover { color: var(--text); background: var(--bg-elevated); }
.iro-dialog-body { flex: 1; overflow-y: auto; padding: 20px 24px; }

/* ── The market briefing (the lobby hold) ──────────────────────────
   THE PANEL SPANS THE WORKSPACE COLUMN, not a card in the middle of it
   (owner, 2026-09-10). The hold is already absolute inside the desk
   panel, so the sidebar beside it was never covered; what the
   participant could not do was read the clock, the position limit and
   the P&L block AND the briefing at the same time, because the briefing
   sat on a 520px card in the centre of the screen. It fills the cover
   now and the sidebar stays where it is.

   Scoped by what it holds rather than by a flag: the briefing is the one
   thing this overlay carries that wants the whole column, and the pause,
   the quiz and the two waiting screens keep the card they had. */
.pause-overlay-content:has(> .mkm-brief) {
  max-width: none;
  width: 100%;
  align-self: stretch;
  text-align: left;
  padding: 26px 28px;
  background: none;
  border: 0;
  box-shadow: none;
}
/* The status line is the most important thing on the screen and reads
   that way. The instrument sits under it. */
.pause-overlay-content:has(> .mkm-brief) .pause-overlay-title {
  font-size: 32px;
  font-weight: 700;
  margin-bottom: 4px;
}
/* TWO COLUMNS, and the shortcuts on a row of their own under them
   (owner, 2026-09-10). Three abreast left the session rows so narrow
   that a label wrapped and its value printed over it.

   The session column takes the width its own rows measure and the
   calendar takes the rest, so a label and its value can never be
   squeezed onto each other. */
.mkm-brief {
  text-align: left;
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  align-items: start;
  gap: 8px 48px;
}
.mkm-brief-title {
  grid-column: 1 / -1;
  font-size: 20px;
  font-weight: 600;
  color: var(--text);
  margin: 0 0 10px;
}
/* One column of the briefing, and one block within a column. */
.mkm-brief-col,
.mkm-brief-block {
  min-width: 0;
}
.mkm-brief-block { margin-top: 18px; }
.mkm-brief-col--keys {
  grid-column: 1 / -1;
  margin-top: 18px;
}
.mkm-brief-cal-head {
  margin: 0 0 8px;
}
/* ── The briefing reads at its own weight ──────────────────────────
   Bigger headings and darker ink throughout (owner, 2026-09-10). The
   panel fills the workspace column and is read once, standing still,
   before anything moves; the desk's own eyebrow and muted greys are
   sized and pitched for a live screen where they label something the
   reader is already looking at. Scoped to this panel, so the desk, the
   sign-in fields and the Sessions page keep theirs. */
.pause-overlay-content:has(> .mkm-brief) .mkm-brief-cal-head {
  font-size: 13px;
  letter-spacing: 0.1em;
  color: var(--text);
}
.pause-overlay-content:has(> .mkm-brief) .mkm-brief-label,
.pause-overlay-content:has(> .mkm-brief) .mkm-keys-action,
.pause-overlay-content:has(> .mkm-brief) .mkm-cal-label {
  color: var(--text-secondary);
}
.pause-overlay-content:has(> .mkm-brief) .mkm-cal-label {
  font-size: 12px;
}
@media (max-width: 1000px) {
  .mkm-brief { grid-template-columns: minmax(0, 1fr); }
  .mkm-brief-title,
  .mkm-brief-col--keys { grid-column: auto; }
}
/* The data card that replaced the prose blurb (owner ruling,
   2026-08-25). One key-value row per fact, values right-aligned so
   the eye can run down them.

   PLAIN ROWS ON HAIRLINES, not fact cards (owner, 2026-09-10): the
   column supplies the width, so the label takes the left of it and the
   value the right, the way every other key-value list on this desk
   reads. */
.mkm-brief-rows {
  display: grid;
  grid-template-columns: minmax(0, 1fr) max-content;
  column-gap: 24px;
  width: auto;
}
.mkm-brief-row {
  display: contents;
}
.mkm-brief-rows > .mkm-brief-row > * {
  padding: 6px 0;
  border-bottom: 1px solid var(--border);
}
.mkm-brief-label {
  color: var(--text-muted);
  font-size: 0.9rem;
}
/* The interface face carries the whole card and the .num span inside a
   value carries the number (owner, 2026-08-28). The face used to sit on
   this rule, which put "shares", "minutes" and "Millions of EUR" in the
   monospace one along with the numbers they follow. */
.mkm-brief-value {
  color: var(--text);
  font-size: 0.9rem;
  text-align: right;
}
/* The session's economic calendar, a column of the briefing panel since
   2026-09-10 (owner; it was under the instrument facts from 2026-08-28,
   when it moved off the mid-session dialog). Three columns on the same
   left edge as its own heading, a rule under the headers, and no table
   box around any of it. */
.mkm-cal-rows {
  display: grid;
  grid-template-columns: max-content max-content max-content max-content;
  row-gap: 6px;
  width: max-content;
}
/* The lobby card drops the outcome column, so the grid drops its track
   with it. Left in place the column would still claim its header width
   and the rule under the headers would run past the last number. */
.mkm-cal-rows--no-actual {
  grid-template-columns: max-content max-content max-content;
}
/* The instruments table on a room that trades several. It carries the
   tick and the limit as well, because those are per instrument the
   moment two of them disagree: EURUSD ticks in pips against a limit in
   euro and USDJPY in hundredths of a yen against one in dollars. */
/* Instrument, venue, size and the opening level. */
.mkm-cal-rows--instruments {
  grid-template-columns:
    max-content max-content max-content max-content;
}
/* And the tick and the limit where the instruments do not share them. */
.mkm-cal-rows--wide {
  grid-template-columns:
    max-content max-content max-content max-content max-content max-content;
}
/* Six columns at the calendar's own 32px cell padding spend 160px on
   gaps alone, which is most of what pushed the card past its width.
   Four columns keep the calendar's spacing, which is what they had. */
.mkm-cal-rows--wide > .mkm-cal-row > * {
  padding-right: 20px;
}
.mkm-cal-rows--wide > .mkm-cal-row > *:last-child {
  padding-right: 0;
}
.mkm-cal-row {
  display: contents;
}
/* The columns are set apart by cell padding rather than a column gap, so
   that the rule under the headers runs unbroken across all three. A gap
   would break it into three segments. */
.mkm-cal-rows > .mkm-cal-row > * {
  color: var(--text);
  font-size: 0.9rem;
  padding-right: 32px;
}
.mkm-cal-rows > .mkm-cal-row > *:last-child {
  padding-right: 0;
}
/* The header row, in the same uppercase Inter label the report's tables
   read (owner, 2026-09-10). Its cells carry the rule, because the row
   itself is display:contents and paints nothing of its own. */
.mkm-cal-rows > .mkm-cal-row > .mkm-cal-label {
  font-family: var(--font);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
  padding-bottom: 6px;
  border-bottom: 1px solid var(--border);
}
.mkm-cal-right {
  text-align: right;
}
/* The shortcut list, on the lobby card and in the dialog the sidebar
   opens. The calendar's own grid: columns of content width set apart by
   cell padding, so the lobby card carries one idiom rather than a second
   table dropped into it.

   UNSCOPED, like the calendar rows above and for the same reason. The
   dialog is appended to the document body, and a rule under the
   workspace id reaches the card on the lobby screen and nothing in the
   dialog. The key reads in the interface face, not the monospace one:
   mono is for numbers on this desk and a key is a word.

   TWO PAIRS PER LINE, on four tracks. The rows are display:contents, so
   two of them fill one line of the grid and the list stands half as
   tall as it has entries. One column of all of them ran the lobby card
   off the bottom of the screen on a session that also shows an
   instruments table and an economic calendar. The reader goes DOWN each
   column rather than across the lines (owner, 2026-09-08), which is a
   property of the order shortcutsHtml emits the rows in, not of these
   rules: the grid places whatever it is handed, two entries to a line. */
.mkm-keys {
  display: grid;
  grid-template-columns: repeat(4, max-content);
  row-gap: 6px;
  width: max-content;
}
.mkm-keys-row {
  display: contents;
}
/* A hairline under each LINE of the grid, which is what two
   display:contents rows make between them: all four cells of a line
   carry it, so the rule runs unbroken across the pair (owner,
   2026-09-10). */
.mkm-keys > .mkm-keys-row > * {
  font-size: 0.9rem;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--border);
}
/* A key combination is WORDS, so it reads in the interface face. Mono is
   for numbers on this desk and a key is not one. */
.mkm-keys-combo {
  color: var(--text);
  font-weight: 600;
  white-space: nowrap;
  padding-right: 14px;
}
.mkm-keys-action {
  color: var(--text-muted);
  padding-right: 36px;
}
/* The line's second pair ends the line, so it carries no trailing space
   and the grid is no wider than what it holds. */
.mkm-keys > .mkm-keys-row:nth-child(even) > .mkm-keys-action {
  padding-right: 0;
}
/* The dialog off the sidebar shows the same four tracks as the lobby
   card, and they are wider than the 396px the shared 460px dialog
   leaves inside its 32px paddings (owner report, 2026-09-08). The
   Data Calendar dialog above raises its own ceiling for the same
   reason. A dialog is a shrink-to-fit flex item, so this is a ceiling
   and never a width: it takes exactly what the grid measures. The title
   and the Close button hold the two edges, which is the arrangement the
   calendar dialog has too (owner, 2026-09-10). */
#mkm-keys-overlay .modal-dialog { max-width: min(92vw, 760px); }
/* A release that has printed. The row itself is display:contents and
   paints nothing, so the muted ink goes on its cells. */
.mkm-cal-rows > .mkm-cal-row--done > * {
  color: var(--text-muted);
}
.pause-overlay-hint {
  font-size: 15px;
  color: var(--text-muted);
  animation: pausePulse 2s ease-in-out infinite;
}
@keyframes pausePulse {
  0%, 100% { opacity: 0.5; }
  50% { opacity: 1; }
}

/* The awareness quiz rides the pause overlay: the question takes the
   title slot, the options stack under it, the countdown takes the hint
   slot. Option buttons are the global .btn variants; only the stack
   layout is new. */
/* The question keeps the size and weight every hold read at before the
   pause panel was quietened down (owner, 2026-09-10): a question is the
   one thing on this overlay a participant has to act on. */
.mkm-quiz .pause-overlay-title {
  color: var(--text);
  font-size: 24px;
  font-weight: 700;
}
/* The card grows to the width its answers need, from the 520px every
   other hold reads at (owner report, 2026-09-05). "What was the last
   headline?" offers four printed headlines, which run to 121 characters
   at the ninetieth percentile and 177 at the longest measured, so at the
   shared cap the answers ran out past the card's own edge. The wide
   bound is the instruments table's, one card and one number for both.
   The 520px floor is what the card measured before, so a question whose
   answers are short reads exactly as it did. */
.pause-overlay-content.mkm-quiz {
  width: max-content;
  min-width: 520px;
  max-width: min(92vw, 880px);
  /* The answer-window bar sits on this card's top edge, so the card is
     what positions it and what clips it to the card's own corners. */
  position: relative;
  overflow: hidden;
}
/* The answers take the width of the widest ANSWER, not of the question
   above them (owner, 2026-09-05). The card is sized by its title, and
   "How many client calls have walked away from you?" is wide, so four
   buttons each holding one digit ran the full width of the card and read
   as bands rather than as answers. The stack still shares one width, so
   no answer is a wider target than another.
   The floor holds the short sheets on one line: a position with its
   unit, a release name, and "No headline has printed yet" at 27
   characters, which is about 190px of Inter at this size once the
   button's own 36px of padding is counted. */
.mkm-quiz-options {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin: 0 auto 20px;
  width: max-content;
  min-width: 240px;
  max-width: 100%;
}
/* NOT A FLEX CONTAINER, which is what .btn makes it. A headline answer
   carries `<span class="num">` around every number it names, and inside
   a flex button each run of words and each of those spans became a flex
   item of its own: separately wrapped, centred against each other on one
   line, and set apart by .btn's 6px gap. One headline read as four
   columns of text (owner screenshot, 2026-09-05). As a block the answer
   is one paragraph again and the numbers are ordinary inline spans. */
.mkm-quiz-option {
  display: block;
  text-align: center;
  font-variant-numeric: tabular-nums;
  /* .btn holds its label on one line, which is right for Send and wrong
     for a headline: no card is wide enough for the longest of them, so
     the answer wraps at the cap rather than running past it. */
  white-space: normal;
  /* Square and flat, the desk's own treatment (owner, 2026-09-10).
     `pretty` keeps a wrapped answer off a one-word last line.

     A SLIGHT ACCENT TINT on every answer (owner, same day), so the four
     read as the things to click rather than as text on the card. Mixed
     into the card's own surface rather than laid over it as an alpha,
     which keeps them opaque and right in both themes. */
  border-radius: 0;
  border: 1px solid var(--border);
  background: color-mix(in srgb, var(--color-accent) 8%, var(--bg-surface));
  text-wrap: pretty;
}
/* The one that was chosen, filled so it cannot be mistaken for the three
   beside it. The class swap quizHold already makes is what carries it. */
.mkm-quiz-option.btn-primary {
  background: var(--color-accent);
  border-color: var(--color-accent);
  color: #ffffff;
  font-weight: 600;
}

/* ── The answer window ──────────────────────────────────────────────
   A bar across the TOP EDGE OF THE CARD, draining as the window runs
   out (owner, 2026-09-10). It reads the ACCENT and never amber: it is a
   timer, and amber on this desk is the release countdown and the limit
   meters, both of which say something is wrong. Its width is written by
   the quiz timer in desk.js, the same paint that writes the count, so
   there is one clock and a reconnect mid-question lands it where the
   server says it is. It keeps draining after an answer is chosen: the
   room is paused either way and the window is still running. */
.mkm-quiz-bar {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  background: var(--bg-elevated);
}
/* THE PAINT IS FOUR TIMES A SECOND AND THE BAR HAS TO LOOK CONTINUOUS,
   so each step is ridden out over the interval that produced it (owner,
   2026-09-10: it stepped). This is not a countdown in CSS: every width
   still comes from the server's own deadline, and the transition only
   carries the eye from one to the next. A reconnect writes a width the
   transition then runs to, which is what a jump would look like anyway.
   Linear, because a timer does not ease. */
.mkm-quiz-bar-fill {
  height: 100%;
  width: 100%;
  background: var(--color-accent);
  transition: width 250ms linear;
}
/* The seconds left are the pressure, so the number reads as a number and
   the sentence around it stays a hint. */
.mkm-quiz .pause-overlay-hint {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 7px;
}
.mkm-quiz #mkm-quiz-count {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 26px;
  font-weight: 700;
  line-height: 1.1;
  color: var(--text);
}

/* The signed-in waiting screen: the card sits at the top rather than
   centred. It used to carry a handbook below it, which was lifted from
   the platform's market-making module and never belonged to this sim
   (owner, 2026-08-28); both are gone. */
.join-screen.mm-waiting {
  min-height: auto;
  padding: 48px 20px 24px;
}

/* ── Header, right-hand controls ───────────────────────────────────── */

/* Copied verbatim from portfolio-sim.css (its copy of the Bank ALM console
   header: .header-controls, .theme-toggle and its glyph swap, .btn /
   .btn-secondary / .btn-sm), with only the controls id swapped to this
   app's. The header is hidden on the sign-in and waiting screens and
   belongs to the desk. */
#mm-header-controls {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-shrink: 0;
  padding-right: 24px;
}
#mm-header-controls .theme-toggle {
  background: transparent;
  border: 1px solid transparent;   /* invisible by default, shows on hover */
  color: var(--text-secondary);
  width: 32px;
  height: 32px;
  border-radius: var(--r-sm);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
  transition: var(--transition);
  /* Desaturate the colour emoji glyphs (yellow moon to grey). */
  filter: grayscale(1);
}
#mm-header-controls .theme-toggle:hover {
  background: var(--bg-elevated);
  border-color: var(--border);
  color: var(--text);
}
.icon-sun, .icon-moon { display: none; }
[data-theme="dark"] .icon-sun { display: inline; }
[data-theme="light"] .icon-moon { display: inline; }

#mm-header-controls .btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 8px 16px;
  border-radius: var(--r-sm);
  font-size: 13px;
  font-weight: 600;
  font-family: var(--font);
  cursor: pointer;
  transition: var(--transition);
  border: none;
}
#mm-header-controls .btn-secondary {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-secondary);
}
#mm-header-controls .btn-secondary:hover {
  background: var(--bg-elevated);
  color: var(--text);
}

/* The reference buttons stand on ONE ROW, Data Calendar and Shortcuts,
   half the sidebar each (owner, 2026-09-09; they were a stack until
   then). The row carries the 8px the sidebar spaces everything else by,
   and the buttons divide what is left equally.

   The label centres in its half and the horizontal padding comes down
   from the shared button's 14px (owner, 2026-09-10): the desk sidebar is
   260px wide (--sidebar-width at the top of this file), so each button is
   about 110px and "Data Calendar" needs nearly all of it. The label never
   wraps, because a wrapped label would make one button taller than the
   other. */
#market-making-workspace .mkm-sb-btn-row {
    display: flex;
    gap: 8px;
}
#market-making-workspace .mkm-sb-btn-row .sb-btn-secondary {
    flex: 1 1 0;
    min-width: 0;
    padding: 8px 6px;
    text-align: center;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Floor ambience control in the desk sidebar. Sits above Session Info and
   hides entirely when the trainer has blocked participant playback. */
.mkm-floor {
    display: flex;
    flex-direction: column;
    gap: 14px;
    padding: 12px 12px 14px;
    margin: 10px 0 14px;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: 6px;
}

/* The switch itself is the shared .toggle primitive in components.css.
   Only the row's own padding is trimmed, because the block already has it. */
.mkm-floor .toggle-row { padding: 0; }

.mkm-floor-level {
    width: 100%;
    accent-color: var(--color-accent);
    cursor: pointer;
}


/* ══════════════════════════════════════════════════════════════════════
   THE OPTIONS LAYOUT (desk_options.js)

   The options desk uses the SPOT desk's own containers (.mkm-grid,
   .mkm-col-book, .mkm-col-right, .mkm-book-frame, .mkm-entry,
   .mkm-calls-wrap, .mkm-news-wrap, .mkm-chart-panel,
   .mkm-working-frame, .mkm-feed-wrap), so the columns, their widths and
   the draggable seams all come from the rules above rather than from a
   second grid of its own (owner, 2026-08-28: the desk must match cash
   equities and FX spot, with the options part added where it sits).
   What follows is only what the options part adds: the chain board and
   its screen, the vol quote fields on a ticket, and the chart's
   price/vol toggle. Each rule is scoped to .mkm-opt-desk or to a class
   only this layout uses, so nothing here can reach a spot desk.

   Copied from the platform's single-player options desk
   (edumarkets/frontend/css/market-making.css), which is where the chain
   board's own measurements were settled.
   ══════════════════════════════════════════════════════════════════════ */

/* The book sits at the top of the left column, where every spot desk
   carries it and where desk_book.js measures what the chart tile follows.
   The chain runs under it and takes the height that is left, because the
   client requests moved out of this column (owner, 2026-08-29). */
/* THE PANEL TAKES ITS NATURAL HEIGHT, both desks that use it. A chain
   is as tall as its listed strikes and a curve is as tall as its
   tenors; neither has anything to show in extra height, so a panel that
   grew opened a band of empty board under the last row and took that
   height off the client requests below it (owner, 2026-09-02, with the
   requests back in this column). The rates desk ruled the same way on
   2026-08-30 and carried its own override until now. */
#market-making-workspace .mkm-opt-chain-panel {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    min-height: 0;
}
/* The chain's own entry ROW is gone (owner, 2026-09-02): its size field
   moved onto the band above the board, which is where .mkm-opt-chain-bar
   lays it out. */
#market-making-workspace .mkm-opt-chain-bar .mkm-entry-size .sidebar-input {
    width: 72px;
    text-align: center;
}
/* THE LABEL TAKES ITS OWN WIDTH HERE, plus one ordinary gap. The entry
   card pads this label to a shared 78px column so its dark row's inputs
   line up under its lit row's; this bar has one row and nothing to line
   up with, so the padding was just a space between the word and the
   field it names (owner, 2026-09-02). Dropping it alone put the two
   hard against each other, so the gap is set here rather than left to
   the card's own variable. */
#market-making-workspace .mkm-opt-chain-bar .mkm-entry-size {
    gap: 8px;
}
#market-making-workspace .mkm-opt-chain-bar .mkm-entry-size > .sb-label {
    min-width: 0;
}
#market-making-workspace .mkm-opt-chain-tools {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: 8px;
}
#market-making-workspace .mkm-opt-clip {
    font-size: var(--text-meta);
    color: var(--text-muted);
    white-space: nowrap;
}
#market-making-workspace .mkm-opt-clip .num {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
    font-weight: 700;
    color: var(--text-secondary);
}

/* The info glyph is GONE (owner, 2026-09-02: it said nothing that was
   not already obvious). What it explained about the screen walking past
   the dealer's clip is on each quote cell's own hover, which names the
   clip and says the fill deals wider. No layout carries the element any
   more, so its rules went with it. */

/* The street call takes the chain's size and the line picked on the
   board, so it sits under the chain rather than in the hedge entry,
   whose sizes are shares. */
#market-making-workspace .mkm-opt-street-bar {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 10px 8px;
}
/* WORDS IN THE INTERFACE FACE, NUMBERS IN THE MONO ONE (owner,
   2026-09-02). The whole line was mono, so "No option selected" read as
   data. The strike carries a `num` span, which is the desk's own way of
   saying a run of characters is a number, and the rule for it is
   already global. */
#market-making-workspace .mkm-opt-street-line {
    font-size: var(--text-meta);
    color: var(--text-secondary);
}
/* Only the LAST control floats right (owner, 2026-09-01). Both of them
   taking the auto margin left the street call stranded in the middle of
   the bar, a gap away from the size field it takes its size from. */
#market-making-workspace .mkm-opt-street-bar .mkm-street-wrap:last-child {
    margin-left: auto;
}

/* The compressed-week line under the instrument: the trading day and the
   days left to expiry. */
/* A ROW, not a fragment of the header above it (owner, 2026-09-10):
   where the session is in its week, and how long the options on the
   board have left. The two readings sit at the two edges. */
#market-making-workspace .mkm-opt-weekline {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 8px;
    margin: 0 0 8px;
    font-size: 13px;
    color: var(--text-muted);
}
#market-making-workspace .mkm-opt-weekline .num {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
    font-weight: 700;
    color: var(--text);
}

/* ── The options chain board (also the screen the maker trades on) ──── */

#market-making-workspace .mkm-opt-chain {
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden;
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--r-md);
}
#market-making-workspace .mkm-opt-chain-bar,
#market-making-workspace .mkm-opt-chain-subhead,
#market-making-workspace .mkm-opt-chain-row {
    display: grid;
    /* TWELVE columns (owner, 2026-09-02): each side carries what the
       desk HOLDS on the line (the delta of the position, then the
       contracts), then what the option IS and costs (its own delta,
       then the two-way quote). The strike and the vega sit between
       them; the call and the put share one vol, so one vega serves both
       sides.
       THE OUTER COLUMN IS THE WIDE ONE, which is not what a blank cell
       deserves and is what its HEADING needs: "Pos delta" is nine
       characters against a quote's four, and given an even share it
       broke onto two lines and clipped (owner, 2026-09-02). The width
       comes off the quote columns, which never carry more than a
       two-decimal volatility. */
    grid-template-columns:
        minmax(0, 1.5fr) minmax(0, 0.6fr) minmax(0, 0.7fr)
        minmax(0, 0.8fr) minmax(0, 0.8fr)
        minmax(0, 0.75fr) minmax(0, 0.9fr)
        minmax(0, 0.8fr) minmax(0, 0.8fr)
        minmax(0, 0.7fr) minmax(0, 0.6fr) minmax(0, 1.5fr);
    gap: 3px;
    align-items: center;
    padding: 3px 8px;
}
/* ONE STRIP ABOVE THE BOARD (owner, 2026-09-02), carrying the size the
   screen deals in, which half is which, and how much the dealer is firm
   for. It was two rows: a control row and a band holding two words. The
   two group names split the middle evenly, so each still sits over its
   own half of the board without the strip having to be the board's own
   grid, which it cannot be while it holds a field. */
/* IT IS THE BOARD'S OWN GRID, so CALLS sits exactly over the two
   columns a desk deals calls on and PUTS over the two it deals puts on
   (owner, 2026-09-02). Laid out as a flex row the two words were
   centred in the space left over by the controls either side of them,
   which is near the right place and never on it. The size control takes
   the three columns of the calls side that do not trade, and the clip
   the three of the puts side, so neither pushes a heading off its
   columns. */
#market-making-workspace .mkm-opt-chain-bar {
    align-items: center;
    padding: 4px 8px;
    background: var(--bg-surface);
    border-bottom: 1px solid var(--text-muted);
}
#market-making-workspace .mkm-opt-chain-bar .mkm-entry-size {
    grid-column: 1 / 4;
}
#market-making-workspace .mkm-opt-chain-bar .mkm-opt-chain-group--calls {
    grid-column: 4 / 6;
}
#market-making-workspace .mkm-opt-chain-bar .mkm-opt-chain-group--puts {
    grid-column: 8 / 10;
}
#market-making-workspace .mkm-opt-chain-bar .mkm-opt-chain-tools {
    grid-column: 10 / 13;
    justify-content: flex-end;
}
/* Clip in the middle of the strip (owner, 2026-09-03), on the two
   Strike + Vega columns between CALLS and PUTS. Explicit grid-row so
   auto-placement cannot flow it to a second row. */
#market-making-workspace .mkm-opt-chain-bar > .mkm-opt-clip {
    grid-column: 6 / 8;
    grid-row: 1;
    justify-self: center;
}
#market-making-workspace .mkm-opt-chain-bar .mkm-opt-chain-group {
    font-family: var(--font);
    font-size: var(--text-meta);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-secondary);
    text-align: center;
}
/* THE HEADING IS A HEADING, not a second coloured band (owner,
   2026-09-02). It carried a wash of --positive at 12%, which put it in
   the same family as the book's own header band a few pixels above it
   (--sidebar-accent at 14%) and the two read as one repeated device.
   The book's band is a CONTROL: it expands the book and names which one
   is open, so it keeps the colour. This one names columns, so it reads
   as structure: the panel's own ground, and a firm rule to sit the
   board under. */
#market-making-workspace .mkm-opt-chain-group { text-align: center; }
#market-making-workspace .mkm-opt-chain-subhead {
    font-family: var(--font);
    font-size: var(--text-meta);
    font-weight: 600;
    text-transform: uppercase;
    /* NO TRACKING ON THIS ROW. Twelve headings share the board's width
       and the longest of them is nine characters, so the letter-spacing
       every other band carries was what tipped "Pos delta" onto a
       second line (owner, 2026-09-02). The rates desk's own subhead
       keeps its spacing through the rule below, because six columns
       have the room for it. */
    color: var(--text-muted);
    border-bottom: 1px solid var(--border);
    padding-top: 3px;
    padding-bottom: 4px;
}
#market-making-workspace .mkm-opt-chain-subhead.mkm-rt-subhead {
    letter-spacing: 0.04em;
}
/* One line each, whatever the window. A heading that wraps takes the
   height off every row of the board below it and reads as two columns
   where there is one. */
#market-making-workspace .mkm-opt-chain-subhead span {
    text-align: right;
    white-space: nowrap;
}
/* The strike, its vega and the four quote columns are centred in the
   rows, so their headers are centred too (columns 4 to 9 of the twelve).
   The chain's own geometry, so the curve table's six-column subhead is
   excluded: every one of its columns after the line's name is a number
   and reads right, like the cells under it. */
#market-making-workspace .mkm-opt-chain-subhead:not(.mkm-rt-subhead) span:nth-child(n + 4):nth-child(-n + 9) {
    text-align: center;
}
#market-making-workspace .mkm-opt-chain-row {
    font-size: var(--text-meta);
    font-weight: 600;
    color: var(--text);
}
#market-making-workspace .mkm-opt-chain-row:not(:last-child) {
    border-bottom: 1px solid var(--border);
}
#market-making-workspace .mkm-opt-cc { text-align: right; }
#market-making-workspace .mkm-opt-cc.positive { color: var(--positive); }
#market-making-workspace .mkm-opt-cc.negative { color: var(--negative); }
#market-making-workspace .mkm-opt-cc.mkm-dim  { color: var(--text-muted); }
/* The position cells double as the street call's line picker, so they
   carry a pointer and a selected state. The rates desk picks the same
   way off its curve table, where the cell that carries it is the line's
   own name. */
#market-making-workspace .mkm-opt-cc[data-pick-strike],
#market-making-workspace .mkm-opt-cc[data-pick-tenor] {
    cursor: pointer;
    border-radius: var(--r-sm);
    border: 1px solid transparent;
}
#market-making-workspace .mkm-opt-cc[data-pick-tenor]:hover {
    border-color: var(--border);
}
/* THE WHOLE SIDE LIGHTS, not the one cell under the pointer (owner,
   2026-09-02). Three cells on each side pick the same option, so a
   hover that marked only one of them read as three small targets
   instead of one wide one, which is why the picker was never found.
   The chain's cells are named by side, so :has reaches every cell of
   the side the pointer is over. */
#market-making-workspace .mkm-opt-chain-row:has([data-cell^="call-"]:hover)
    [data-cell^="call-"],
#market-making-workspace .mkm-opt-chain-row:has([data-cell^="put-"]:hover)
    [data-cell^="put-"] {
    border-color: var(--border);
    background: color-mix(in srgb, var(--color-accent) 5%, transparent);
}
#market-making-workspace .mkm-opt-cc--picked {
    border-color: var(--color-accent);
    background: var(--bg-surface);
}
/* The strike is the spine of the board: bolder and a step larger than
   the rest of the row so the eye lands on it. */
#market-making-workspace .mkm-opt-strike {
    text-align: center;
    font-weight: 800;
    font-size: var(--text-h4);
    color: var(--text);
    background: var(--bg-surface);
    border-radius: var(--r-sm);
}
/* The vega a line hands you in the size set above the board. It is a
   reference number, not a tradable quote, so it reads quieter than the
   strike and the vols beside it. */
#market-making-workspace .mkm-opt-vega {
    text-align: center;
    color: var(--text-secondary);
}

/* The tradable vol quotes, on both options desks. Clicking a bid sells
   that option, clicking an ask buys it, both in the size set above the
   board. Everything below the geometry is per desk and per theme: this
   rule is the click target and the shape, nothing else.

   ONE COLOUR ON BOTH SIDES, everywhere (owner, 2026-09-02 on the FX
   ladder, 2026-09-05 on the chain). The two-way is one quote and reads
   as one control, and the side is already clear from the column
   heading. A cool bid against a warm ask was tried on the chain first
   and failed twice over on dark: mixed at 9% and 11% into the surface,
   the bid landed on rgb(24, 34, 46) against a rgb(28, 35, 44) board,
   DARKER than the ground it sits on, and the ask on rgb(47, 41, 31),
   brown rather than a warm chip.

   NOT GREEN AND RED, on either desk or theme. Green and red mean one
   thing only here, which is that you hold the line, and the position
   columns are the only place they appear.

   THREE FINDINGS FROM THE 2026-09-05 ROUNDS, none of them cheap to
   re-derive:

   1. A TINT MIXED INTO A NEAR-BLACK GROUND KEEPS ALMOST NONE OF ITS
      COLOUR. The same 24% that lifts a white ground to a clear blue chip
      left the dark one at a contrast of 1.16 against its board. This is
      what the order-book accents a few hundred lines above already say
      from the owner's own round on them (2026-08-30): what reads as a
      terminal accent is SATURATION, and dilution is what removes it.
   2. SO DARKEN BY LOWERING LIGHTNESS, NEVER BY MIXING INTO THE GROUND,
      AND MEASURE CHROMA RATHER THAN HSL SATURATION. Blending #ff9900
      three quarters into #161B22 to answer "less bright" dropped chroma
      from 0.174 to 0.140, a fifth of the colour gone while it also went
      darker, which is exactly what mud is. HSL saturation hid it by
      reporting 92%. Blending with pure black gives the same 0.140, so
      the ground's blue cast is not the culprit; dilution costs chroma
      whatever it is diluted with.
   3. OVER A WIDE CELL THE AREA MATTERS MORE THAN THE SHADE. An FX quote
      cell is 0.9fr of 5.1fr, about 118px at the left column's 700px
      ceiling, while "7.6" in the mono face asks for 43px. A saturated
      fill across all of it, ten times over, read as screaming whatever
      the shade. A chain cell is 50px against a 45px number, so the same
      fill there is proportionate, which is why the chain never had this
      problem.

   THE TWO DESKS DIVERGE ON DARK, and the owner ruled that acceptable
   (2026-09-05) after seeing both. Each block below says what its own
   desk does. Light is the same treatment on both and he has passed it
   on each; do not touch it.

   The numeral SIZE is the FX ladder's own, set with the rest of that
   desk's rules further down: five wide columns can carry the vol at the
   strike's size where the chain's twelve cannot. A chain quote column
   measures about 50px and "24.4" at --text-h4 asks for 49px with the
   chip's padding, so it clips on anything but a maximised wide window,
   and those columns are narrow on purpose (owner, 2026-09-02: the width
   came off them for the "Pos delta" heading). */
#market-making-workspace .mkm-opt-quote {
    text-align: center;
    cursor: pointer;
    border-radius: var(--r-sm);
    padding: 2px 4px;
    background: var(--bg-surface);
    border: 1px solid transparent;
}

/* ── The equity chain's quotes: a pill on dark, a tinted cell on light ──
   SETTLED, BOTH THEMES (owner, 2026-09-05: "everything in both dark and
   light is good, dont change it anymore").

   On dark the fill wraps the digits rather than the cell. #EB8D00 is the
   third order book's own #ff9900 one step down in lightness at full
   saturation, and black on it reads at 8.3:1. The CELL keeps its full
   width as the click target and still takes the hover outline; only the
   paint sits on the number. The pill is inline-block because vertical
   padding on an inline box does not open the line up, so two rows would
   overlap. */
#market-making-workspace .mkm-opt-chain-row .mkm-opt-quote--bid,
#market-making-workspace .mkm-opt-chain-row .mkm-opt-quote--ask {
    background: none;
}
#market-making-workspace .mkm-opt-chain-row .mkm-opt-quote .num {
    display: inline-block;
    padding: 1px 6px;
    border-radius: var(--r-sm);
    background: #EB8D00;
    color: #000;
    font-weight: 700;
}
[data-theme="light"] #market-making-workspace .mkm-opt-chain-row .mkm-opt-quote--bid,
[data-theme="light"] #market-making-workspace .mkm-opt-chain-row .mkm-opt-quote--ask {
    background: color-mix(in srgb, var(--color-accent) 24%,
                          var(--bg-surface));
}
[data-theme="light"] #market-making-workspace .mkm-opt-chain-row .mkm-opt-quote .num {
    display: inline;
    padding: 0;
    background: none;
    color: inherit;
    font-weight: inherit;
}

/* ── The FX ladder's quotes: a full-width button on both themes ────────
   The chain's pill was tried here first and the owner read the narrow
   boxes as silly on a board whose cells are more than twice as wide
   (2026-09-05). So this desk keeps the cell-wide button light already
   has, and takes a light blue on dark rather than the chain's orange.

   #4B9FD4 is --color-accent-light's own dark value, the platform's
   lighter accent and a fill token by base.css's contract. It carries a
   third less chroma than the orange (0.113 against 0.163) at much the
   same lightness, which is what lets it fill a 118px cell ten times over
   without shouting, and black on it reads at 7.2:1. It is written out
   rather than taken from the token because this value is the dark
   theme's alone. */
#market-making-workspace .mkm-fxo-row .mkm-opt-quote--bid,
#market-making-workspace .mkm-fxo-row .mkm-opt-quote--ask {
    background: #4B9FD4;
}
#market-making-workspace .mkm-fxo-row .mkm-opt-quote .num {
    color: #000;
}
[data-theme="light"] #market-making-workspace .mkm-fxo-row .mkm-opt-quote--bid,
[data-theme="light"] #market-making-workspace .mkm-fxo-row .mkm-opt-quote--ask {
    background: color-mix(in srgb, var(--color-accent) 24%,
                          var(--bg-surface));
}
[data-theme="light"] #market-making-workspace .mkm-fxo-row .mkm-opt-quote .num {
    color: inherit;
}
/* The chip stays under the pointer and only its edge answers. A hover
   that repainted the ground took the tint away at the moment the desk
   went to click it: the hover rule outranked the tint above by its
   pseudo-class, so the cell went flat exactly as it was aimed at. */
#market-making-workspace .mkm-opt-quote:hover {
    border-color: var(--border);
}
#market-making-workspace .mkm-opt-quote:active { transform: translateY(1px); }

/* ── Where the money is ─────────────────────────────────────────────── */
/* The row nearest the underlying is the one the desk works, so it lifts
   off the board and its strike carries the accent. The wings are the
   rows read past, so they dim. Both are read off the engine's own
   numbers (the strike nearest the mid, and a call delta past 0.85 or
   under 0.15), never off a distance in points, so they hold on a market
   at any level. */
#market-making-workspace .mkm-opt-row--atm {
    background: color-mix(in srgb, var(--color-accent) 6%, transparent);
}
#market-making-workspace .mkm-opt-row--atm .mkm-opt-strike {
    color: var(--color-accent);
    font-weight: 700;
}
#market-making-workspace .mkm-opt-row--wing .mkm-opt-cc {
    color: var(--text-secondary);
}
/* Never the position, whatever the row: a holding is the one thing on
   this board that must never fade. */
#market-making-workspace .mkm-opt-row--wing .mkm-opt-cc.positive { color: var(--positive); }
#market-making-workspace .mkm-opt-row--wing .mkm-opt-cc.negative { color: var(--negative); }

/* ── The line being priced ──────────────────────────────────────────── */
/* A client request marks its own line on the board while it is worked,
   the way the rates desk marks the client's tenor on the curve. The ROW
   carries which side is picked and the side's own cells take the mark,
   because a chain row holds two instruments and only one of them is
   being quoted. */
#market-making-workspace .mkm-opt-chain-row[data-picked] {
    background: color-mix(in srgb, var(--color-accent) 12%, transparent);
}
/* The side's cells read at full ink and the two chips take an accent
   edge. Weight and colour rather than a border on every cell, because
   only the chips and the position cells carry a border to colour and
   adding one to the rest would shift the row by two pixels. */
#market-making-workspace .mkm-opt-chain-row[data-picked="Call"] [data-cell^="call-"],
#market-making-workspace .mkm-opt-chain-row[data-picked="Put"] [data-cell^="put-"] {
    color: var(--text);
    font-weight: 700;
}
#market-making-workspace .mkm-opt-chain-row[data-picked="Call"] .mkm-opt-quote[data-cp="Call"],
#market-making-workspace .mkm-opt-chain-row[data-picked="Put"] .mkm-opt-quote[data-cp="Put"] {
    border-color: var(--color-accent);
}

/* ── The hedge entry ────────────────────────────────────────────────── */

/* The book itself carries NO rules here. It is the spot desk's own
   ladder, rendered by desk_book.js into the same .mkm-book element, so
   it takes the same rules as cash equities and FX spot and cannot drift
   from them (owner, 2026-08-28). Only the entry beneath it differs, and
   only because a hedge is sized in shares. */

/* One row: the size field, the market Sell / Buy, then the two resting
   sides (a price field plus its Place button each) and Cancel all. The
   size input is deliberately narrow so the price fields get the room. */
#market-making-workspace .mkm-opt-hedge-entry {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 8px;
}
#market-making-workspace .mkm-opt-hedge-entry .mkm-entry-size { flex: 0 0 auto; gap: 6px; }
#market-making-workspace .mkm-opt-hedge-entry .mkm-entry-size .sidebar-input {
    width: 68px;
    text-align: center;
}
#market-making-workspace .mkm-opt-hedge-entry .btn { padding: 6px 8px; }
/* A bare button directly inside the entry row (Cancel resting on options
   and rates) matches the height of the Place ask button beside it: those
   sit inside a stretching .mkm-entry-side and take the input's height,
   which this button used to miss (owner, 2026-08-30). */
#market-making-workspace .mkm-opt-hedge-entry > .btn {
  flex: 0 0 auto;
  align-self: stretch;
}
#market-making-workspace .mkm-opt-hedge-entry .mkm-entry-side {
    flex: 1 1 140px;
    min-width: 0;
}
#market-making-workspace .mkm-opt-hedge-entry .mkm-entry-side .sidebar-input {
    min-width: 68px;
}

/* ── The RFQ ticket: the vol quote fields ───────────────────────────── */

#market-making-workspace .mkm-optq-vol-wrap {
    position: relative;
    display: flex;
    align-items: center;
}
#market-making-workspace .mkm-optq-vol-wrap .sidebar-input {
    width: 100%;
    padding-right: 34px;
}
#market-making-workspace .mkm-optq-unit {
    position: absolute;
    right: 10px;
    font-size: var(--text-meta);
    color: var(--text-muted);
    pointer-events: none;
}

/* ── Chart toggle (price pane / vol pane) ───────────────────────────── */

/* The toggle floats in the chart's top-right corner. */
#market-making-workspace .mkm-opt-corner {
    position: absolute;
    top: 6px;
    right: 8px;
    z-index: 2;
}
/* The Price/Vol toggle that used to sit in this corner is GONE (owner,
   2026-09-02): the options desk draws the shared four-pane grid now, and
   a desk that reads the underlying, the volatility it is charging and
   the volatility it is delivering at the same time has nothing left for
   a toggle to switch between. The corner rule above stays, because the
   client-requests info glyph still uses it. */

/* ── The rates desk's curve table ──────────────────────────────────────
   The rates layout reuses the options desk's frames, panels, tickets and
   feeds wholesale, so the only rules it needs of its own are the ones
   the CURVE TABLE cannot inherit: the chain grid is ten columns wide for
   calls, strike and puts, and a curve is six for one line each. The
   first column is the line's name and reads left, the rest are numbers
   and read right, which is the reverse of the chain's all-numeric row.
   Everything else here is deliberately absent: it comes from
   .mkm-opt-* and is the same surface. */
#market-making-workspace .mkm-rt-subhead,
#market-making-workspace .mkm-rt-row {
    /* Seven columns since the single mid became a two-way (owner,
       2026-08-31): tenor, bid, ask, yield, duration, position, DV01. */
    grid-template-columns:
        minmax(0, 0.6fr) minmax(0, 0.9fr) minmax(0, 0.9fr)
        minmax(0, 0.9fr) minmax(0, 0.8fr) minmax(0, 1fr)
        minmax(0, 1.1fr);
}
/* Six on a swaps market: the bid and the ask ARE the rate, so the yield
   column would print the same number a third time and is dropped. The
   width it held goes to the two money columns beside it. */
#market-making-workspace .mkm-rt-subhead.mkm-rt--rate,
#market-making-workspace .mkm-rt-row.mkm-rt--rate {
    grid-template-columns:
        minmax(0, 0.7fr) minmax(0, 1fr) minmax(0, 1fr)
        minmax(0, 0.9fr) minmax(0, 1fr) minmax(0, 1.1fr);
}
/* Four in the SIDEBAR, where a forward points market states the two
   currencies' rates at each tenor it quotes (owner, 2026-09-01). The
   same component at the same scale, in a narrower column, so a rate
   curve reads the way the curve table beside it does. The two rate
   columns are wider than the tenor and the differential because they
   carry a per cent sign as well as four digits. */
#market-making-workspace .mkm-rt-subhead.mkm-rt--legs,
#market-making-workspace .mkm-rt-row.mkm-rt--legs {
    grid-template-columns:
        minmax(0, 0.6fr) minmax(0, 1fr) minmax(0, 1fr) minmax(0, 0.8fr);
    padding-left: 0;
    padding-right: 0;
}
/* The curve table reads at the SIDEBAR's scale (owner, 2026-08-28). The
   two panels carry the same kind of reading, so a row here is the size
   of a row there (.mkm-sb-row, 0.95rem) and the header takes the
   sidebar heading's own size, weight and tracking (.sb-heading, 0.82rem
   / 700 / 0.08em). The options chain keeps --text-meta, which is what
   ten columns of quotes need. */
#market-making-workspace .mkm-rt-row {
    font-size: 0.95rem;
    padding-top: 4px;
    padding-bottom: 4px;
}
#market-making-workspace .mkm-rt-subhead {
    font-size: 0.82rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    color: var(--text-secondary);
}
/* The name reads left, against the chain's right-aligned numeric cells,
   and in the INTERFACE face against the board's mono, because it is the
   one cell on the row that is not a number.

   It carries none of the strike's treatment. A strike is three digits
   and can take the spine's weight and size; a security's name is a
   phrase, and setting it two steps larger than its own row made the
   table read as two tables stacked (owner, 2026-08-28). The picker's
   pointer, hover edge and selected state come from the
   [data-pick-tenor] rules further up, which is all the cell needs to
   say it can be clicked. */
#market-making-workspace .mkm-rt-subhead span:first-child,
#market-making-workspace .mkm-rt-row .mkm-rt-name {
    text-align: left;
}
#market-making-workspace .mkm-rt-row .mkm-rt-name {
    font-family: var(--font);
}
/* Whole-row pick target (owner, 2026-08-30): a click anywhere on the
   tenor's row selects it for a street call, not only on the tenor
   label. A subtle teal-green wash marks the selected row; no separate
   hover wash. */
#market-making-workspace .mkm-rt-row[data-pick-tenor] {
    cursor: pointer;
}
#market-making-workspace .mkm-rt-row--picked {
    background: color-mix(in srgb, var(--color-accent) 12%, transparent);
}

/* The rates desk's competition marker: a ticket that went out to a
   panel, where only the best price deals. Sits beside the client type
   on the ticket, in the same muted register the type reads in. */
/* Red, and nothing else (owner, 2026-08-28). At 10px in the accent it
   was barely readable; a shaded pill in bold was the other way past it. */
#market-making-workspace .mkm-ticket-comp {
    flex: 0 0 auto;
    color: var(--negative);
    letter-spacing: 0.02em;
    white-space: nowrap;
}

/* ── Where a refusal lands ─────────────────────────────────────────────
   Top centre, inside the header band, for the market making desk only
   (owner, 2026-08-31). The platform default is the top right, which on
   this desk sits on top of the chart selectors. The middle of the
   header is empty on every screen the desk has, so nothing can be
   covered there.

   Scoped with :has() rather than a body class because the toast
   container is a direct child of body (shared/toast.js) and is built
   before any desk markup exists, so a descendant selector would never
   reach it. Every other page keeps the platform position. */
body:has(#market-making-workspace) .em-toast-container {
    top: 12px;
    right: auto;
    left: 50%;
    transform: translateX(-50%);
    align-items: center;
}
/* The default slides in from the right, which reads as wrong on a
   centred toast and fights the centring transform on the container.
   Square with it (owner, 2026-09-10): the platform's 8px radius is the
   one thing on this page that still read as a rounded card. Scoped the
   same way, so every other page keeps the platform toast. */
body:has(#market-making-workspace) .em-toast {
    animation: mkm-toast-in 0.3s ease;
    border-radius: 0;
}
@keyframes mkm-toast-in {
    from { opacity: 0; transform: translateY(-10px); }
    to { opacity: 1; transform: translateY(0); }
}

/* ── The chart grid ────────────────────────────────────────────────────
   One pane per instrument, stacked as rows (owner, 2026-08-31). The
   chart panel is already a flex column with an 8px gap, and
   .mkm-chart-wrap is already a row in it, so a multi-pane chart needs
   no layout of its own. Three things it does need.

   The plot box: the rule above lists the three layouts' plot elements
   by id, and a grid builds one per pane, so the class joins that same
   rule rather than repeating its declarations.

   The row's floor: a single tile stands at 120px so one chart is never
   squashed. Four of them cannot all hold that inside a panel the height
   of the order book, and the panel would overflow rather than divide,
   so a pane in a grid takes a lower floor and a zero basis. The
   reader's shares ride --mkm-c1 to --mkm-c4, written by the seams onto
   the panel and read by each pane's own grow factor.

   The seams: their handles are positioned against the panel, which is a
   flex item and not a containing block until it says so. */
#market-making-workspace .mkm-chart-panel { position: relative; }
#market-making-workspace .mkm-chart-panel.mkm-chart-rows .mkm-chart-wrap {
    flex-basis: 0;
    min-height: 44px;
}
/* Four panes two by two rather than four deep (owner, 2026-08-31): four
   stacked came out about fifty pixels each at a laptop height and the
   fourth ran off the screen. Wrapping the column into two lines doubles
   every pane's height for half its width, which a price path can spare
   and a legible axis cannot. Wrap rather than a second display type, so
   the panes stay the same flex children the stacked case sizes. */
#market-making-workspace .mkm-chart-panel.mkm-chart-2col {
    flex-flow: row wrap;
    /* Load-bearing, and the default: the two wrapped lines share the
       panel's height rather than sitting at their content height. */
    align-content: stretch;
}
#market-making-workspace .mkm-chart-panel.mkm-chart-2col .mkm-chart-wrap {
    flex: 1 1 calc(50% - 4px);
    min-height: 0;
}
/* The series picker sits where the chart's corner controls already sit.
   .sidebar-select-sm is a full-width sidebar field, and in a corner it
   reads at the width of its longest series name and carries none of the
   stacking margin a sidebar row needs. */
#market-making-workspace .mkm-opt-corner .mkm-chart-pick {
    width: auto;
    margin-top: 0;
}
/* In a grid of panes the picker moves to the TOP-LEFT and comes down to
   the panes' own tick size (owner, 2026-09-22): at the sidebar field's
   size beside the expand button it ran over the top of every plot. A
   pane in a grid draws no last-price reading, so that corner is free.
   The height is fixed because desk_chart.js reads it: PICK_MARGIN_T
   raises each pane's top margin by it, so no gridline and no y tick
   label runs under the picker. Change the two together. */
#market-making-workspace .mkm-chart-panel.mkm-chart-rows .mkm-chart-wrap > .mkm-opt-corner {
    top: 4px;
    left: 8px;
    right: auto;
}
#market-making-workspace .mkm-chart-panel.mkm-chart-rows .mkm-chart-pick {
    height: 16px;
    padding: 0 4px;
    font-size: 11px;
    line-height: 14px;
}

/* The contract a working order sits in, where the desk trades more than
   one (owner, 2026-08-31). Muted and ahead of the size, so the row still
   reads as a size at a price and the book is context rather than the
   headline. */
#market-making-workspace .mkm-working-inst {
    color: var(--text-muted);
    font-size: 0.85em;
}

/* ── The swaps desk: the street bar reads against the entry above it ──
   SWAPS ONLY (owner, 2026-09-01). The order entry and the street bar are
   two boxes in two frames, so nothing sizes them together; each control
   is pinned to the measure of the one above it instead. A bond desk has
   the curve table between the two rows, so they are not read against
   each other and keep today's widths.

   An earlier attempt put both rows in one grid by moving the bar into
   the entry card. It aligned, and it took the curve panel off the page
   with it: the chart tile is sized off this column, so the chart died
   and the right column went blank. Do not move the bar again. */

/* Restated because the measure is declared on .mkm-entry and this row
   is not inside that panel, the same reason .mkm-ob-entry restates it.
   The bar's own padding is the default (10px each side), which matches
   the entry row above so Show axe and Cancel resting stack exactly
   under one another (owner, 2026-09-04). An earlier 13px override was
   for a card with border+padding, which the frame no longer carries. */
#market-making-workspace .mkm-rt-desk--rate .mkm-opt-street-bar {
  --mkm-price-w: calc(8ch + 18px);
}
/* The size field is the entry's own 68px, not the 82px every other size
   field on the platform carries, and it sits the same 6px from its
   label. */
#market-making-workspace .mkm-rt-desk--rate .mkm-opt-street-bar
    .mkm-entry-size {
  gap: 6px;
}
#market-making-workspace .mkm-rt-desk--rate .mkm-opt-street-bar
    .mkm-entry-size .sidebar-input {
  width: 68px;
}
/* Bid and Ask stop absorbing the row's spare width and take the card's
   shared price measure, the one the dark row's Limit already reads, so
   there is a width for Call the street to match at all. */
#market-making-workspace .mkm-rt-desk--rate .mkm-opt-hedge-entry
    .mkm-entry-side .sidebar-input {
  flex: 0 0 var(--mkm-price-w);
  min-width: 0;
}
/* Call the street, the width of the price field over it. The measure is
   in `ch`, which resolves against the font of the element that READS it,
   so it is read on the wrapper at the price field's own size and family
   rather than on the button, whose type is smaller. The wrapper draws
   nothing; the button fills it and keeps its own type. */
#market-making-workspace .mkm-rt-desk--rate .mkm-opt-street-bar
    .mkm-street-wrap:first-of-type {
  font-family: var(--font);
  font-size: 0.88rem;
  width: var(--mkm-price-w);
}
#market-making-workspace .mkm-rt-desk--rate .mkm-opt-street-bar
    .mkm-street-wrap:first-of-type > .btn {
  width: 100%;
  min-width: 0;
}
/* Show axe and Cancel resting share the 118px the cancel button
   already carried as its minimum (owner, 2026-09-04). On a
   rate-quoted market the two sit one under the other and equal
   widths put them exactly over one another; on a bond market they
   sit in different columns and equal widths still read as one
   family. */
#market-making-workspace .mkm-rt-desk .rt-cancel,
#market-making-workspace .mkm-rt-desk #mkm-rt-axe {
  width: 118px;
  min-width: 118px;
}
/* Cancel resting floats to the card's right edge the same way Show
   axe does in the street bar below (owner, 2026-09-04). Without
   this it sits directly after the last flex item, which lands it
   short of the right edge on a --rate market where the price fields
   are pinned to a fixed width and do not grow to fill the row.
   Non-rate markets have flex-growing price fields that push Cancel
   resting to the right edge already, so this rule is scoped to
   --rate where the pin removes the natural push. */
#market-making-workspace .mkm-rt-desk--rate .mkm-opt-hedge-entry
    > .rt-cancel {
  margin-left: auto;
}

/* ══════════════════════════════════════════════════════════════════════
   THE FX OPTIONS DESK (desk_fx_options.js)
   ══════════════════════════════════════════════════════════════════════
   The FX options layout is the equity options one with a different board:
   a five-line DELTA LADDER whose strikes are derived, a surface strip of
   the three quotes the ladder is built from, and a list of what the desk
   HOLDS, which drifts off the ladder as spot moves. Everything else on
   the screen is shared and already styled: the containers are the spot
   desk's (.mkm-grid, .mkm-col-book, .mkm-col-right, .mkm-book-frame,
   .mkm-entry, .mkm-calls-wrap, .mkm-news-wrap, .mkm-chart-panel,
   .mkm-working-frame, .mkm-feed-wrap), the tickets are the shared ones,
   and the cells reuse .mkm-opt-cc / .mkm-opt-quote / .mkm-opt-strike /
   .mkm-opt-vega so the two boards read as one family.

   Each rule below is scoped to a class only this layout uses, so nothing
   here can reach the equity board or a spot desk.
   ══════════════════════════════════════════════════════════════════════ */

/* ── The strip above the board ──────────────────────────────────────── */
/* ONE STRIP, not two (the equity board's own ruling, 2026-09-02): the
   size the screen deals in, the three market quotes, and how much the
   dealer is firm for. It carries no column headings, so unlike the equity
   bar it is not laid out on the board's grid: the board's column names
   are the subhead row inside the ladder. */
#market-making-workspace .mkm-fxo-bar {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 4px 8px;
    background: var(--bg-surface);
    border-bottom: 1px solid var(--text-muted);
}
#market-making-workspace .mkm-fxo-bar .mkm-entry-size {
    gap: 8px;
}
#market-making-workspace .mkm-fxo-bar .mkm-entry-size > .sb-label {
    min-width: 0;
}
#market-making-workspace .mkm-fxo-bar .mkm-entry-size .sidebar-input {
    width: 72px;
    text-align: center;
}
#market-making-workspace .mkm-fxo-bar .mkm-opt-clip {
    margin-left: auto;
}
/* The street-call button rides this strip on the right (owner,
   2026-09-03): the row that used to hold it under the ladder was dead
   vertical space, so the button moves up here and the ladder gains the
   row's worth of height. No label carries the picked strike name; the
   picked line already reads on the board itself, and a duplicate on
   this strip pushed the button off the edge. */
#market-making-workspace .mkm-fxo-bar .mkm-fxo-street-wrap {
    margin-left: 8px;
}

/* The three quotes the ladder is built from. They are the market's own
   numbers, so they carry no colour: green and red on this desk mean that
   you hold something. Each cell stays on ONE line (owner, 2026-09-03):
   the strip was wrapping "25D RR" and "Firm in 20mm" into stacks when
   the street button joined the strip on the right. */
#market-making-workspace .mkm-fxo-surf {
    display: flex;
    align-items: baseline;
    gap: 14px;
    margin: 0 auto;
}
#market-making-workspace .mkm-fxo-surf-cell {
    display: inline-flex;
    align-items: baseline;
    gap: 4px;
    white-space: nowrap;
}
#market-making-workspace .mkm-fxo-bar .mkm-opt-clip {
    white-space: nowrap;
}
#market-making-workspace .mkm-fxo-surf-lbl {
    font-size: var(--text-meta);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted);
}
#market-making-workspace .mkm-fxo-surf-val {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
    font-weight: 800;
    color: var(--text);
}
/* The risk reversal's fixed notation rides beside it, quieter than the
   number: it says which side is the richer one. */
#market-making-workspace .mkm-fxo-surf-note {
    font-size: var(--text-meta);
    color: var(--text-secondary);
}

/* ── The delta ladder (also the screen the maker trades on) ─────────── */
/* Five lines, so the board takes its natural height and the client
   requests below it keep theirs. The equity chain grows into its column
   because it lists a strike grid; a delta ladder cannot grow. */
#market-making-workspace .mkm-fxo-ladder {
    flex: 0 0 auto;
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--r-md);
}
/* FIVE COLUMNS: the bucket's name, the two-way quote, the strike its
   delta points to, and the vega it hands over in the size above the
   board. The two tradable cells sit right beside the bucket (owner,
   2026-09-02); the strike and vega are references and follow. The
   bucket keeps the widest track because it carries a word where every
   other column carries a number. */
#market-making-workspace .mkm-fxo-subhead,
#market-making-workspace .mkm-fxo-row {
    display: grid;
    grid-template-columns:
        minmax(0, 1.2fr) minmax(0, 0.9fr) minmax(0, 0.9fr)
        minmax(0, 1.1fr) minmax(0, 1fr);
    gap: 3px;
    align-items: center;
    padding: 3px 8px;
}
#market-making-workspace .mkm-fxo-subhead {
    font-family: var(--font);
    font-size: var(--text-meta);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-muted);
    border-bottom: 1px solid var(--border);
    padding-top: 3px;
    padding-bottom: 4px;
}
/* One line each, whatever the window: a heading that wraps takes the
   height off every row below it. */
#market-making-workspace .mkm-fxo-subhead span {
    text-align: right;
    white-space: nowrap;
}
/* The bucket name reads left with its column; every other column
   (Strike, Vega, Bid, Ask) centres its value in the cell below, so the
   headings sit centred over their columns rather than crowding the
   right edge. */
#market-making-workspace .mkm-fxo-subhead span:first-child { text-align: left; }
#market-making-workspace .mkm-fxo-subhead span:nth-child(n + 2) {
    text-align: center;
}
#market-making-workspace .mkm-fxo-row {
    font-size: var(--text-meta);
    font-weight: 600;
    color: var(--text);
}
#market-making-workspace .mkm-fxo-row:not(:last-child) {
    border-bottom: 1px solid var(--border);
}
/* The line's name is a WORD, so it reads in the interface face. Every
   other cell on the row is a number and keeps the mono one. */
#market-making-workspace .mkm-fxo-line {
    font-family: var(--font);
    text-align: left;
    color: var(--text-secondary);
}
/* The strike is the spine of the board, the way it is on the equity
   chain: bolder and a step larger, so the eye lands on it. */
#market-making-workspace .mkm-fxo-row .mkm-opt-strike {
    padding: 1px 4px;
}

/* THE WHOLE NON-TRADING SIDE OF A ROW IS THE PICKER (the equity board's
   ruling, 2026-09-02): three cells pick the same line, so a hover that
   marked only the cell under the pointer read as three small targets
   instead of one wide one. */
#market-making-workspace .mkm-fxo-row [data-pick-bucket] {
    cursor: pointer;
    border-radius: var(--r-sm);
    border: 1px solid transparent;
}
#market-making-workspace .mkm-fxo-row:has([data-pick-bucket]:hover)
    [data-pick-bucket] {
    border-color: var(--border);
    background: color-mix(in srgb, var(--color-accent) 5%, transparent);
}
/* The street-call target the desk has picked, one row only. Strong. */
#market-making-workspace .mkm-fxo-row[data-picked] {
    background: color-mix(in srgb, var(--color-accent) 12%, transparent);
}
#market-making-workspace .mkm-fxo-row[data-picked] [data-pick-bucket] {
    color: var(--text);
    font-weight: 700;
}
#market-making-workspace .mkm-fxo-row[data-picked] .mkm-opt-quote {
    border-color: var(--color-accent);
}

/* The ladder buckets a client ticket is asking about right now. An
   outright names one bucket, a straddle the ATM row, a risk reversal
   the two 25-delta wings, a butterfly three lines. Softer than the
   street pick above: it reads as context, not as a target the desk is
   about to shed on. The :not() guards let a row that carries both
   marks read as the street target rather than double-highlighting. */
#market-making-workspace .mkm-fxo-row[data-priced]:not([data-picked]) {
    background: color-mix(in srgb, var(--color-accent) 5%, transparent);
}
#market-making-workspace .mkm-fxo-row[data-priced]:not([data-picked])
    [data-pick-bucket] {
    color: var(--text);
}

/* ── What the desk holds ────────────────────────────────────────────── */
/* A traded option keeps the strike it was struck at, so it drifts off the
   delta line it came from as spot moves: the ladder is what trades and
   this is what is held, and they are two different lists. Sits in the
   right column beside the blotter now (owner ruling, 2026-09-02, on a
   browser screenshot), where it fills its half of the log row and
   scrolls if the desk has struck more strikes than the row can show.
   The wrap around it carries the panel chrome, so this element is only
   the list. */
#market-making-workspace .mkm-fxo-positions-wrap {
    flex: 1 1 0;
    display: flex;
    flex-direction: column;
    min-width: 0;
    min-height: 0;
    overflow: hidden;
}
#market-making-workspace .mkm-fxo-positions {
    flex: 1 1 auto;
    overflow-y: auto;
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
}

/* The bottom row of the right column: positions on the left, the
   blotter on the right, two narrow lists sitting together. Positions
   is the shorter of the two, so the blotter takes a bit more of the
   width. A fixed row height keeps the chart tile above it stable; the
   blotter and the positions each scroll inside their share. */
/* Log row: positions + blotter side by side. It takes the role the
   blotter alone played on the other desks — the one panel in the right
   column that grows — so the chart above and the working orders below
   can be dragged against it (owner, 2026-09-03). Its default is grow=1
   with a 220px basis, and the manual-mode share maps to `--mkm-r3` in
   the block further down. */
#market-making-workspace .mkm-fxo-log-row {
    display: flex;
    flex: 1 1 220px;
    gap: 8px;
    min-height: 0;
}

/* Right-column stack order on THIS desk (owner, 2026-09-02): chart,
   news, log row, working orders. The shared .mkm-col-right rules set
   order 0/1/2/3 on chart/news/working-frame/feed-wrap, so the new log
   row inherits the default of 0 and sits tied with the chart in DOM
   order, which is the wrong slot. Both halves need FX-options-scoped
   order values: the log row goes to 2, the working orders to 3, and
   the chart and news keep their shared values. Nothing else moves,
   because the rules are scoped to .mkm-fxo-desk. */
#market-making-workspace .mkm-fxo-desk .mkm-fxo-log-row { order: 2; }
#market-making-workspace .mkm-fxo-desk .mkm-col-right
    .mkm-working-frame { order: 3; }

/* Manual-mode row shares on THIS desk (owner, 2026-09-03, after the
   drag on the seam between news and the log row moved everything but
   the log row itself). The shared column has four sibling panels
   (chart / news / working / blotter) and its manual rules map r1..r4
   to those four. The FX desk swaps in a log-row instead of the bare
   blotter, so the four rows are chart / news / log-row / working: r3
   is the log row and r4 is the working frame, both scoped here.
   The shared `.mkm-col-right.mkm-rows-manual .mkm-feed-wrap` rule
   would otherwise reach the blotter feed nested INSIDE the log row
   and overwrite its horizontal share; guarded by an explicit override
   below. */
#market-making-workspace .mkm-fxo-desk .mkm-col-right.mkm-rows-manual
    .mkm-fxo-log-row {
    flex: var(--mkm-r3, 1) 1 0;
}
#market-making-workspace .mkm-fxo-desk .mkm-col-right.mkm-rows-manual
    .mkm-working-frame {
    flex: var(--mkm-r4, 1) 1 0;
}
#market-making-workspace .mkm-fxo-desk .mkm-col-right.mkm-rows-manual
    .mkm-fxo-log-row > .mkm-feed-wrap {
    flex: 1 1 auto;
}

/* The FX ladder carried its own copy of the single accent tint from
   2026-09-02 until the equity chain took the same treatment (owner,
   2026-09-05). The tint comes from the shared `.mkm-opt-quote` rules
   now, so the two options desks cannot drift apart on it.

   The numeral size stays this desk's own. Five wide columns can carry
   the vol at the strike's size where the chain's twelve cannot; the
   reasoning is written out beside the shared rules. */
#market-making-workspace .mkm-fxo-row .mkm-opt-quote .num {
    font-size: var(--text-h4);
    font-weight: 700;
}
#market-making-workspace .mkm-fxo-log-row > .mkm-fxo-positions-wrap {
    flex: 0 0 44%;
}
#market-making-workspace .mkm-fxo-log-row > .mkm-feed-wrap {
    flex: 1 1 auto;
    min-width: 0;
}
#market-making-workspace .mkm-fxo-pos-sub,
#market-making-workspace .mkm-fxo-pos-row {
    display: grid;
    grid-template-columns:
        minmax(0, 0.9fr) minmax(0, 1.1fr) minmax(0, 1fr)
        minmax(0, 0.8fr) minmax(0, 1fr);
    gap: 3px;
    align-items: center;
    padding: 3px 8px;
    text-align: right;
}
/* The column headers take the 11px uppercase label the desk's other
   table headers use (owner, 2026-09-11): at the rows' own size "Bucket"
   ran into "Strike". */
#market-making-workspace .mkm-fxo-pos-sub {
    position: sticky;
    top: 0;
    z-index: 1;
    font-family: var(--font);
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-muted);
    background: var(--bg-elevated);
    border-bottom: 1px solid var(--border);
}
#market-making-workspace .mkm-fxo-pos-sub span:first-child,
#market-making-workspace .mkm-fxo-pos-row .mkm-fxo-pos-tag {
    text-align: left;
}
#market-making-workspace .mkm-fxo-pos-row {
    font-size: var(--text-meta);
    font-weight: 600;
    color: var(--text);
}
#market-making-workspace .mkm-fxo-pos-row:not(:last-child) {
    border-bottom: 1px solid var(--border);
}
/* Which delta line the strike sits on NOW, which is the thing that moved.
   A word-and-number tag, so it reads in the interface face. */
#market-making-workspace .mkm-fxo-pos-tag {
    font-family: var(--font);
    color: var(--text-secondary);
}
#market-making-workspace .mkm-fxo-pos-row .positive { color: var(--positive); }
#market-making-workspace .mkm-fxo-pos-row .negative { color: var(--negative); }
#market-making-workspace .mkm-fxo-pos-row .mkm-dim { color: var(--text-muted); }
#market-making-workspace .mkm-fxo-pos-empty {
    padding: 8px;
    font-family: var(--font);
    font-size: var(--text-meta);
    color: var(--text-muted);
    text-align: center;
}

